<commit_before>// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import {
  Kernel, KernelMessage, nbformat
} from '@jupyterlab/services';

import {
  each, enumerate
} from 'phosphor/lib/algorithm/iteration';

import {
  indexOf
} from 'phosphor/lib/algorithm/searching';

import {
  MimeData as IClipboard
} from 'phosphor/lib/core/mimedata';

import {
  ICellModel, ICodeCellModel,
  CodeCellWidget, BaseCellWidget, MarkdownCellWidget
} from '../cells';

import {
  INotebookModel
} from './model';

import {
  Notebook, JUPYTER_CELL_MIME
} from './widget';


/**
 * A namespace for handling actions on a notebook.
 *
 * #### Notes
 * All of the actions are a no-op if there is no model on the notebook.
 * The actions set the widget `mode` to `'command'` unless otherwise specified.
 * The actions will preserve the selection on the notebook widget unless
 * otherwise specified.
 */
export
namespace NotebookActions {
  /**
   * Split the active cell into two cells.
   *
   * @param widget - The target notebook widget.
   *
   * #### Notes
   * It will preserve the existing mode.
   * The second cell will be activated.
   * The existing selection will be cleared.
   * The leading whitespace in the second cell will be removed.
   * If there is no content, two empty cells will be created.
   * Both cells will have the same type as the original cell.
   * This action can be undone.
   */
  export
  function splitCell(widget: Notebook): void {
    if (!widget.model || !widget.activeCell) {
      return;
    }
    widget.deselectAll();
    let nbModel = widget.model;
    let index = widget.activeCellIndex;
    let child = widget.widgets.at(index);
    let editor = child.editor;
    let position = editor.getCursorPosition();
    let offset = editor.getOffsetAt(position);
    let orig = child.model.value.text;

    // Create new models to preserve history.
    let clone0 = Private.cloneCell(nbModel, child.model);
    let clone1 = Private.cloneCell(nbModel, child.model);
    if (clone0.type === 'code') {
      (clone0 as ICodeCellModel).outputs.clear();
    }
    clone0.value.text = orig.slice(0, offset);
    clone1.value.text = orig.slice(offset).replace(/^\s+/g, '');

    // Make the changes while preserving history.
    let cells = nbModel.cells;
    cells.beginCompoundOperation();
    cells.set(index, clone0);
    cells.insert(index + 1, clone1);
    cells.endCompoundOperation();

    widget.activeCellIndex++;
    widget.scrollToActiveCell();
    widget.activate();
  }

  /**
   * Merge the selected cells.
   *
   * @param widget - The target notebook widget.
   *
   * #### Notes
   * The widget mode will be preserved.
   * If only one cell is selected, the next cell will be selected.
   * If the active cell is a code cell, its outputs will be cleared.
   * This action can be undone.
   * The final cell will have the same type as the active cell.
   * If the active cell is a markdown cell, it will be unrendered.
   */
  export
  function mergeCells(widget: Notebook): void {
    if (!widget.model || !widget.activeCell) {
      return;
    }
    let toMerge: string[] = [];
    let toDelete: ICellModel[] = [];
    let model = widget.model;
    let cells = model.cells;
    let primary = widget.activeCell;
    let index = widget.activeCellIndex;

    // Get the cells to merge.
    each(enumerate(widget.widgets), ([i, child]) => {
      if (widget.isSelected(child)) {
        toMerge.push(child.model.value.text);
        if (i !== index) {
          toDelete.push(child.model);
        }
      }
    });

    // Check for only a single cell selected.
    if (toMerge.length === 1) {
      // Bail if it is the last cell.
      if (index === cells.length - 1) {
        return;
      }
      // Otherwise merge with the next cell.
      let cellModel = cells.at(index + 1);
      toMerge.push(cellModel.value.text);
      toDelete.push(cellModel);
    }

    widget.deselectAll();

    // Create a new cell for the source to preserve history.
    let newModel = Private.cloneCell(model, primary.model);
    newModel.value.text = toMerge.join('\n\n');
    if (newModel.type === 'code') {
      (newModel as ICodeCellModel).outputs.clear();
    }

    // Make the changes while preserving history.
    cells.beginCompoundOperation();
    cells.set(index, newModel);
    each(toDelete, cell => {
      cells.remove(cell);
    });
    cells.endCompoundOperation();

    // If the original cell is a markdown cell, make sure
    // the new cell is unrendered.
    if (primary instanceof MarkdownCellWidget) {
      let cell = widget.activeCell as MarkdownCellWidget;
      cell.rendered = false;
    }
  }

  /**<commit_msg>Preserve location after merging cells<commit_after>// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import {
  Kernel, KernelMessage, nbformat
} from '@jupyterlab/services';

import {
  each, enumerate
} from 'phosphor/lib/algorithm/iteration';

import {
  indexOf
} from 'phosphor/lib/algorithm/searching';

import {
  MimeData as IClipboard
} from 'phosphor/lib/core/mimedata';

import {
  ICellModel, ICodeCellModel,
  CodeCellWidget, BaseCellWidget, MarkdownCellWidget
} from '../cells';

import {
  INotebookModel
} from './model';

import {
  Notebook, JUPYTER_CELL_MIME
} from './widget';


/**
 * A namespace for handling actions on a notebook.
 *
 * #### Notes
 * All of the actions are a no-op if there is no model on the notebook.
 * The actions set the widget `mode` to `'command'` unless otherwise specified.
 * The actions will preserve the selection on the notebook widget unless
 * otherwise specified.
 */
export
namespace NotebookActions {
  /**
   * Split the active cell into two cells.
   *
   * @param widget - The target notebook widget.
   *
   * #### Notes
   * It will preserve the existing mode.
   * The second cell will be activated.
   * The existing selection will be cleared.
   * The leading whitespace in the second cell will be removed.
   * If there is no content, two empty cells will be created.
   * Both cells will have the same type as the original cell.
   * This action can be undone.
   */
  export
  function splitCell(widget: Notebook): void {
    if (!widget.model || !widget.activeCell) {
      return;
    }
    widget.deselectAll();
    let nbModel = widget.model;
    let index = widget.activeCellIndex;
    let child = widget.widgets.at(index);
    let editor = child.editor;
    let position = editor.getCursorPosition();
    let offset = editor.getOffsetAt(position);
    let orig = child.model.value.text;

    // Create new models to preserve history.
    let clone0 = Private.cloneCell(nbModel, child.model);
    let clone1 = Private.cloneCell(nbModel, child.model);
    if (clone0.type === 'code') {
      (clone0 as ICodeCellModel).outputs.clear();
    }
    clone0.value.text = orig.slice(0, offset);
    clone1.value.text = orig.slice(offset).replace(/^\s+/g, '');

    // Make the changes while preserving history.
    let cells = nbModel.cells;
    cells.beginCompoundOperation();
    cells.set(index, clone0);
    cells.insert(index + 1, clone1);
    cells.endCompoundOperation();

    widget.activeCellIndex++;
    widget.scrollToActiveCell();
    widget.activate();
  }

  /**
   * Merge the selected cells.
   *
   * @param widget - The target notebook widget.
   *
   * #### Notes
   * The widget mode will be preserved.
   * If only one cell is selected, the next cell will be selected.
   * If the active cell is a code cell, its outputs will be cleared.
   * This action can be undone.
   * The final cell will have the same type as the active cell.
   * If the active cell is a markdown cell, it will be unrendered.
   */
  export
  function mergeCells(widget: Notebook): void {
    if (!widget.model || !widget.activeCell) {
      return;
    }
    let toMerge: string[] = [];
    let toDelete: ICellModel[] = [];
    let model = widget.model;
    let cells = model.cells;
    let primary = widget.activeCell;
    let index = widget.activeCellIndex;
    let offset = 0;

    // Get the cells to merge.
    each(enumerate(widget.widgets), ([i, child]) => {
      if (widget.isSelected(child)) {
        toMerge.push(child.model.value.text);
        if (i !== index) {
          toDelete.push(child.model);
          if (i < index) {
            offset += 1;
          }
        }
      }
    });

    // Check for only a single cell selected.
    if (toMerge.length === 1) {
      // Bail if it is the last cell.
      if (index === cells.length - 1) {
        return;
      }
      // Otherwise merge with the next cell.
      let cellModel = cells.at(index + 1);
      toMerge.push(cellModel.value.text);
      toDelete.push(cellModel);
    }

    widget.deselectAll();

    // Create a new cell for the source to preserve history.
    let newModel = Private.cloneCell(model, primary.model);
    newModel.value.text = toMerge.join('\n\n');
    if (newModel.type === 'code') {
      (newModel as ICodeCellModel).outputs.clear();
    }

    // Make the changes while preserving history.
    cells.beginCompoundOperation();
    cells.set(index, newModel);
    each(toDelete, cell => {
      cells.remove(cell);
    });
    cells.endCompoundOperation();

    // If the original cell is a markdown cell, make sure
    // the new cell is unrendered.
    if (primary instanceof MarkdownCellWidget) {
      let cell = widget.activeCell as MarkdownCellWidget;
      cell.rendered = false;
    }

    widget.activeCellIndex -= offset;
  }

  /**
{'fraction_non_alphanumeric': 0.11293184427512785, 'fraction_numerical': 0.0029224506836447134, 'mean_word_length': 2.7458952306489444, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7451918', 'n_tokens_mistral': 2897, 'n_tokens_neox': 2826, 'n_words': 928}