Skip to content

Commit

Permalink
Notebook split cell command
Browse files Browse the repository at this point in the history
  • Loading branch information
dhuebner committed Sep 23, 2024
1 parent dedfe25 commit 43ae859
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ import {
import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
import { NotebookExecutionService } from '../service/notebook-execution-service';
import { NotebookCellOutputModel } from '../view-model/notebook-cell-output-model';
import { CellEditType, CellKind } from '../../common';
import { CellData, CellEditType, CellKind } from '../../common';
import { NotebookEditorWidgetService } from '../service/notebook-editor-widget-service';
import { NotebookCommands } from './notebook-actions-contribution';
import { changeCellType } from './cell-operations';
import { EditorLanguageQuickPickService } from '@theia/editor/lib/browser/editor-language-quick-pick-service';
import { NotebookService } from '../service/notebook-service';
import { Selection } from '@theia/monaco-editor-core/esm/vs/editor/common/core/selection';
import { Range } from '@theia/core/shared/vscode-languageserver-protocol';

export namespace NotebookCellCommands {
/** Parameters: notebookModel: NotebookModel | undefined, cell: NotebookCellModel */
Expand All @@ -55,7 +57,7 @@ export namespace NotebookCellCommands {
});
/** Parameters: notebookModel: NotebookModel, cell: NotebookCellModel */
export const SPLIT_CELL_COMMAND = Command.toDefaultLocalizedCommand({
id: 'notebook.cell.split-cell',
id: 'notebook.cell.split',
iconClass: codicon('split-vertical'),
});
/** Parameters: notebookModel: NotebookModel, cell: NotebookCellModel */
Expand Down Expand Up @@ -213,12 +215,12 @@ export class NotebookCellActionContribution implements MenuContribution, Command
order: '20'
});

// menus.registerMenuAction(NotebookCellActionContribution.ACTION_MENU, {
// commandId: NotebookCellCommands.SPLIT_CELL_COMMAND.id,
// icon: NotebookCellCommands.SPLIT_CELL_COMMAND.iconClass,
// label: nls.localizeByDefault('Split Cell'),
// order: '20'
// });
menus.registerMenuAction(NotebookCellActionContribution.ACTION_MENU, {
commandId: NotebookCellCommands.SPLIT_CELL_COMMAND.id,
icon: NotebookCellCommands.SPLIT_CELL_COMMAND.iconClass,
label: nls.localizeByDefault('Split Cell'),
order: '20'
});

menus.registerMenuAction(NotebookCellActionContribution.ACTION_MENU, {
commandId: NotebookCellCommands.DELETE_COMMAND.id,
Expand Down Expand Up @@ -293,7 +295,45 @@ export class NotebookCellActionContribution implements MenuContribution, Command
}]
, true);
}));
commands.registerCommand(NotebookCellCommands.SPLIT_CELL_COMMAND);
commands.registerCommand(NotebookCellCommands.SPLIT_CELL_COMMAND, this.editableCellCommandHandler(
async (notebookModel, cell) => {
// selection (0,0,0,0) should also be used in !cell.editing mode, but `cell.editing`
// is not properly implemented for Code cells.
const cellSelection: Range = cell.selection ?? { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } };
const textModel = await cell.resolveTextModel();

// Create new cell with the text after the cursor
const splitOffset = textModel.offsetAt({
line: cellSelection.start.line,
character: cellSelection.start.character
});
const newCell: CellData = {
cellKind: cell.cellKind,
language: cell.language,
outputs: [],
source: textModel.getText().substring(splitOffset),
};

// add new cell below
const index = notebookModel.cells.indexOf(cell);
notebookModel.applyEdits([{ editType: CellEditType.Replace, index: index + 1, count: 0, cells: [newCell] }], true);

// update current cell text (undo-able)
const selection = new Selection(cellSelection.start.line + 1, cellSelection.start.character + 1, cellSelection.end.line + 1, cellSelection.end.character + 1);
const endPosition = textModel.positionAt(textModel.getText().length);
const deleteOp = {
range: {
startLineNumber: selection.startLineNumber,
startColumn: selection.startColumn,
endLineNumber: endPosition.line + 1,
endColumn: endPosition.character + 1
},
// eslint-disable-next-line no-null/no-null
text: null
};
textModel.textEditorModel.pushEditOperations([selection], [deleteOp], _op => [selection]);
})
);

commands.registerCommand(NotebookCellCommands.EXECUTE_SINGLE_CELL_COMMAND, this.editableCellCommandHandler(
(notebookModel, cell) => {
Expand Down Expand Up @@ -508,6 +548,11 @@ export class NotebookCellActionContribution implements MenuContribution, Command
keybinding: 'M',
when: `!editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED} && ${NOTEBOOK_CELL_TYPE} == 'code'`,
},
{
command: NotebookCellCommands.SPLIT_CELL_COMMAND.id,
keybinding: KeyCode.createKeyCode({ first: Key.MINUS, modifiers: [KeyModifier.CtrlCmd, KeyModifier.Shift] }).toString(),
when: `editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`,
}
);
}
}
Expand Down
14 changes: 14 additions & 0 deletions packages/notebook/src/browser/view-model/notebook-cell-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export interface NotebookCell {
metadata: NotebookCellMetadata;
internalMetadata: NotebookCellInternalMetadata;
text: string;
/**
* The selection of the cell. Zero-based line/character coordinates.
*/
selection: Range | undefined;
onDidChangeOutputs?: Event<NotebookCellOutputsSplice>;
onDidChangeOutputItems?: Event<CellOutput>;
onDidChangeLanguage: Event<string>;
Expand Down Expand Up @@ -251,6 +255,16 @@ export class NotebookCellModel implements NotebookCell, Disposable {
}
}

protected _selection: Range | undefined = undefined;

get selection(): Range | undefined {
return this._selection;
}

set selection(selection: Range | undefined) {
this._selection = selection;
}

@postConstruct()
protected init(): void {
this._outputs = this.props.outputs.map(op => new NotebookCellOutputModel(op));
Expand Down
5 changes: 5 additions & 0 deletions packages/notebook/src/browser/view/notebook-cell-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {

this.toDispose.push(this.editor.getControl().onDidChangeCursorSelection(e => {
const selectedText = this.editor!.getControl().getModel()!.getValueInRange(e.selection);
// TODO handle secondary selections
this.props.cell.selection = {
start: { line: e.selection.startLineNumber - 1, character: e.selection.startColumn - 1 },
end: { line: e.selection.endLineNumber - 1, character: e.selection.endColumn - 1 }
};
this.props.notebookModel.selectedText = selectedText;
}));
this.toDispose.push(this.editor.getControl().onDidChangeCursorPosition(e => {
Expand Down

0 comments on commit 43ae859

Please sign in to comment.