Skip to content

Commit

Permalink
added alot more keybings to the notebook editor (eclipse-theia#13594)
Browse files Browse the repository at this point in the history
* addded alot more keybings to the notebook editor

Signed-off-by: Jonah Iden <jonah.iden@typefox.io>

* added z undo keybding as well

Signed-off-by: Jonah Iden <jonah.iden@typefox.io>

* align more to vscode

Signed-off-by: Jonah Iden <jonah.iden@typefox.io>

* added output collapsed message

Signed-off-by: Jonah Iden <jonah.iden@typefox.io>

---------

Signed-off-by: Jonah Iden <jonah.iden@typefox.io>
  • Loading branch information
jonah-iden authored Apr 11, 2024
1 parent 635eb5b commit 16982d3
Show file tree
Hide file tree
Showing 12 changed files with 292 additions and 26 deletions.
2 changes: 1 addition & 1 deletion packages/monaco/src/browser/monaco-editor-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ export class MonacoEditorProvider {
return editor;
}

protected updateReadOnlyMessage(options: MonacoEditor.IOptions, readOnly: boolean | MarkdownString ): void {
protected updateReadOnlyMessage(options: MonacoEditor.IOptions, readOnly: boolean | MarkdownString): void {
options.readOnlyMessage = MarkdownString.is(readOnly) ? readOnly : undefined;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { NotebookExecutionService } from '../service/notebook-execution-service'
import { NotebookEditorWidget } from '../notebook-editor-widget';
import { NotebookEditorWidgetService } from '../service/notebook-editor-widget-service';
import { NOTEBOOK_CELL_FOCUSED, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_HAS_OUTPUTS } from './notebook-context-keys';
import { NotebookClipboardService } from '../service/notebook-clipboard-service';

export namespace NotebookCommands {
export const ADD_NEW_CELL_COMMAND = Command.toDefaultLocalizedCommand({
Expand Down Expand Up @@ -66,6 +67,21 @@ export namespace NotebookCommands {
id: 'notebook.change-selected-cell',
category: 'Notebook',
});

export const CUT_SELECTED_CELL = Command.toDefaultLocalizedCommand({
id: 'notebook.cut-selected-cell',
category: 'Notebook',
});

export const COPY_SELECTED_CELL = Command.toDefaultLocalizedCommand({
id: 'notebook.copy-selected-cell',
category: 'Notebook',
});

export const PASTE_CELL = Command.toDefaultLocalizedCommand({
id: 'notebook.paste-cell',
category: 'Notebook',
});
}

export enum CellChangeDirection {
Expand All @@ -91,6 +107,9 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
@inject(NotebookEditorWidgetService)
protected notebookEditorWidgetService: NotebookEditorWidgetService;

@inject(NotebookClipboardService)
protected notebookClipboardService: NotebookClipboardService;

registerCommands(commands: CommandRegistry): void {
commands.registerCommand(NotebookCommands.ADD_NEW_CELL_COMMAND, {
execute: (notebookModel: NotebookModel, cellKind: CellKind = CellKind.Markup, index?: number | 'above' | 'below') => {
Expand Down Expand Up @@ -180,6 +199,39 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
execute: () => (this.shell.activeWidget as NotebookEditorWidget).redo()
});

commands.registerCommand(NotebookCommands.CUT_SELECTED_CELL, this.editableCommandHandler(
() => {
const model = this.notebookEditorWidgetService.focusedEditor?.model;
const selectedCell = model?.selectedCell;
if (selectedCell) {
model.applyEdits([{ editType: CellEditType.Replace, index: model.cells.indexOf(selectedCell), count: 1, cells: [] }], true);
this.notebookClipboardService.copyCell(selectedCell);
}
}));

commands.registerCommand(NotebookCommands.COPY_SELECTED_CELL, {
execute: () => {
const model = this.notebookEditorWidgetService.focusedEditor?.model;
const selectedCell = model?.selectedCell;
if (selectedCell) {
this.notebookClipboardService.copyCell(selectedCell);
}
}
});

commands.registerCommand(NotebookCommands.PASTE_CELL, {
isEnabled: () => !Boolean(this.notebookEditorWidgetService.focusedEditor?.model?.readOnly),
isVisible: () => !Boolean(this.notebookEditorWidgetService.focusedEditor?.model?.readOnly),
execute: (position?: 'above') => {
const copiedCell = this.notebookClipboardService.getCell();
if (copiedCell) {
const model = this.notebookEditorWidgetService.focusedEditor?.model;
const insertIndex = model?.selectedCell ? model.cells.indexOf(model.selectedCell) + (position === 'above' ? 0 : 1) : 0;
model?.applyEdits([{ editType: CellEditType.Replace, index: insertIndex, count: 0, cells: [copiedCell] }], true);
}
}
});

}

protected editableCommandHandler(execute: (notebookModel: NotebookModel) => void): CommandHandler {
Expand Down Expand Up @@ -234,7 +286,6 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
order: '30',
when: NOTEBOOK_HAS_OUTPUTS
});
// other items
}

registerKeybindings(keybindings: KeybindingRegistry): void {
Expand All @@ -251,6 +302,21 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
args: CellChangeDirection.Down,
when: `!editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`
},
{
command: NotebookCommands.CUT_SELECTED_CELL.id,
keybinding: 'ctrlcmd+x',
when: `!editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`
},
{
command: NotebookCommands.COPY_SELECTED_CELL.id,
keybinding: 'ctrlcmd+c',
when: `!editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`
},
{
command: NotebookCommands.PASTE_CELL.id,
keybinding: 'ctrlcmd+v',
when: `!editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED}`
},
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { NotebookCellModel } from '../view-model/notebook-cell-model';
import {
NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_TYPE,
NotebookContextKeys, NOTEBOOK_CELL_EXECUTING, NOTEBOOK_EDITOR_FOCUSED,
NOTEBOOK_CELL_FOCUSED, NOTEBOOK_CELL_EDITABLE
NOTEBOOK_CELL_FOCUSED
} from './notebook-context-keys';
import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
import { NotebookExecutionService } from '../service/notebook-execution-service';
Expand Down Expand Up @@ -110,14 +110,27 @@ export namespace NotebookCellCommands {
});

export const TO_CODE_CELL_COMMAND = Command.toLocalizedCommand({
id: 'notebook.cell.to-code-cell',
id: 'notebook.cell.changeToCode',
label: 'Change Cell to Code'
});

export const TO_MARKDOWN_CELL_COMMAND = Command.toLocalizedCommand({
id: 'notebook.cell.to-markdown-cell',
id: 'notebook.cell.changeToMarkdown',
label: 'Change Cell to Mardown'
});

export const COLLAPSE_CELL_OUTPUT = Command.toDefaultLocalizedCommand({
id: 'notebook.cell.collapseCellOutput',
category: 'Notebook',
label: 'Collapse Cell Output',
});

export const EXPAND_CELL_OUTPUT = Command.toDefaultLocalizedCommand({
id: 'notebook.cell.expandCellOutput',
category: 'Notebook',
label: 'Expand Cell Output',
});

}

@injectable()
Expand Down Expand Up @@ -237,8 +250,8 @@ export class NotebookCellActionContribution implements MenuContribution, Command
}

registerCommands(commands: CommandRegistry): void {
commands.registerCommand(NotebookCellCommands.EDIT_COMMAND, this.editableCellCommandHandler((_, cell) => cell.requestEdit()));
commands.registerCommand(NotebookCellCommands.STOP_EDIT_COMMAND, { execute: (_, cell: NotebookCellModel) => (cell ?? this.getSelectedCell()).requestStopEdit() });
commands.registerCommand(NotebookCellCommands.EDIT_COMMAND, this.editableCellCommandHandler((_, cell) => cell.requestFocusEditor()));
commands.registerCommand(NotebookCellCommands.STOP_EDIT_COMMAND, { execute: (_, cell: NotebookCellModel) => (cell ?? this.getSelectedCell()).requestBlurEditor() });
commands.registerCommand(NotebookCellCommands.DELETE_COMMAND,
this.editableCellCommandHandler((notebookModel, cell) => {
notebookModel.applyEdits([{
Expand Down Expand Up @@ -327,6 +340,25 @@ export class NotebookCellActionContribution implements MenuContribution, Command
commands.registerCommand(NotebookCellCommands.TO_MARKDOWN_CELL_COMMAND, this.editableCellCommandHandler((notebookModel, cell) => {
changeCellType(notebookModel, cell, CellKind.Markup);
}));

commands.registerCommand(NotebookCellCommands.COLLAPSE_CELL_OUTPUT, {
execute: () => {
const selectedCell = this.notebookEditorWidgetService.focusedEditor?.model?.selectedCell;
if (selectedCell) {
selectedCell.outputVisible = false;
}
}
});

commands.registerCommand(NotebookCellCommands.EXPAND_CELL_OUTPUT, {
execute: () => {
const selectedCell = this.notebookEditorWidgetService.focusedEditor?.model?.selectedCell;
if (selectedCell) {
selectedCell.outputVisible = true;
}
}
});

}

protected editableCellCommandHandler(execute: (notebookModel: NotebookModel, cell: NotebookCellModel, output?: NotebookCellOutputModel) => void): CommandHandler {
Expand All @@ -350,13 +382,18 @@ export class NotebookCellActionContribution implements MenuContribution, Command
{
command: NotebookCellCommands.EDIT_COMMAND.id,
keybinding: 'Enter',
when: `${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED} && ${NOTEBOOK_CELL_EDITABLE}`,
when: `${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`,
},
{
command: NotebookCellCommands.STOP_EDIT_COMMAND.id,
keybinding: KeyCode.createKeyCode({ first: Key.ENTER, modifiers: [KeyModifier.Alt] }).toString(),
when: `editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED}`,
},
{
command: NotebookCellCommands.STOP_EDIT_COMMAND.id,
keybinding: 'esc',
when: `editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED}`,
},
{
command: NotebookCellCommands.EXECUTE_SINGLE_CELL_COMMAND.id,
keybinding: KeyCode.createKeyCode({ first: Key.ENTER, modifiers: [KeyModifier.CtrlCmd] }).toString(),
Expand Down Expand Up @@ -386,7 +423,7 @@ export class NotebookCellActionContribution implements MenuContribution, Command
command: NotebookCellCommands.TO_MARKDOWN_CELL_COMMAND.id,
keybinding: 'M',
when: `!editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED} && ${NOTEBOOK_CELL_TYPE} == 'code'`,
}
},
);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// *****************************************************************************
// Copyright (C) 2024 TypeFox and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************

import { nls } from '@theia/core';
import { PreferenceSchema } from '@theia/core/lib/browser';

export const NOTEBOOK_LINE_NUMBERS = 'notebook.lineNumbers';

export const notebookPreferenceSchema: PreferenceSchema = {
properties: {
[NOTEBOOK_LINE_NUMBERS]: {
type: 'string',
enum: ['on', 'off'],
default: 'off',
description: nls.localizeByDefault('Controls the display of line numbers in the cell editor.')
},
}
};
2 changes: 2 additions & 0 deletions packages/notebook/src/browser/notebook-editor-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
this.commandRegistry.executeCommand(NotebookCellCommands.EDIT_COMMAND.id, model, model.cells[0]);
model.setSelectedCell(model.cells[0]);
}
model.cells.forEach(cell => cell.onWillBlurCellEditor(() => this.node.focus()));
model.onDidAddOrRemoveCell(e => e.newCellIds?.forEach(cellId => model.cells.find(cell => cell.handle === cellId)?.onWillBlurCellEditor(() => this.node.focus())));
});
}

Expand Down
7 changes: 6 additions & 1 deletion packages/notebook/src/browser/notebook-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import '../../src/browser/style/index.css';

import { ContainerModule } from '@theia/core/shared/inversify';
import { FrontendApplicationContribution, KeybindingContribution, LabelProviderContribution, OpenHandler, WidgetFactory } from '@theia/core/lib/browser';
import { FrontendApplicationContribution, KeybindingContribution, LabelProviderContribution, OpenHandler, PreferenceContribution, WidgetFactory } from '@theia/core/lib/browser';
import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution';
import { NotebookOpenHandler } from './notebook-open-handler';
import { CommandContribution, MenuContribution, ResourceResolver, } from '@theia/core';
Expand All @@ -43,6 +43,8 @@ import { NotebookMonacoTextModelService } from './service/notebook-monaco-text-m
import { NotebookOutlineContribution } from './contributions/notebook-outline-contribution';
import { NotebookLabelProviderContribution } from './contributions/notebook-label-provider-contribution';
import { NotebookOutputActionContribution } from './contributions/notebook-output-action-contribution';
import { NotebookClipboardService } from './service/notebook-clipboard-service';
import { notebookPreferenceSchema } from './contributions/notebook-preferences';

export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(NotebookColorContribution).toSelf().inSingletonScope();
Expand All @@ -64,6 +66,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(NotebookRendererMessagingService).toSelf().inSingletonScope();
bind(NotebookKernelHistoryService).toSelf().inSingletonScope();
bind(NotebookKernelQuickPickService).toSelf().inSingletonScope();
bind(NotebookClipboardService).toSelf().inSingletonScope();

bind(NotebookCellResourceResolver).toSelf().inSingletonScope();
bind(ResourceResolver).toService(NotebookCellResourceResolver);
Expand Down Expand Up @@ -100,4 +103,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(FrontendApplicationContribution).toService(NotebookOutlineContribution);
bind(NotebookLabelProviderContribution).toSelf().inSingletonScope();
bind(LabelProviderContribution).toService(NotebookLabelProviderContribution);

bind(PreferenceContribution).toConstantValue({ schema: notebookPreferenceSchema });
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// *****************************************************************************
// Copyright (C) 2024 Typefox and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************

import { inject, injectable } from '@theia/core/shared/inversify';
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
import { NotebookCellModel } from '../view-model/notebook-cell-model';
import { environment } from '@theia/core';
import { CellData } from '../../common';

@injectable()
export class NotebookClipboardService {

protected copiedCell: CellData | undefined;

@inject(ClipboardService)
protected readonly clipboardService: ClipboardService;

copyCell(cell: NotebookCellModel): void {
this.copiedCell = cell.getData();

if (environment.electron.is()) {
this.clipboardService.writeText(cell.text);
}
}

getCell(): CellData | undefined {
return this.copiedCell;
}

}
9 changes: 9 additions & 0 deletions packages/notebook/src/browser/style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,12 @@
background-color: var(--theia-notebook-focusedCellBorder);
width: 100%;
}

.theia-notebook-collapsed-output {
padding: 4px 8px;
color: var(--theia-foreground);
margin-left: 30px;
font-size: 14px;
line-height: 22px;
opacity: 0.7;
}
Loading

0 comments on commit 16982d3

Please sign in to comment.