diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index fcf208ae94adf6157b64bc71410a7ed3bc147ee7..69ffa116a934b7d543c5871f9bfb632f02e29c46 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -241,7 +241,7 @@ export class MainThreadNotebookController implements IMainNotebookController { async createRawCell(uri: URI, index: number, language: string, type: CellKind): Promise { let cell = await this._proxy.$createEmptyCell(this._viewType, uri, index, language, type); if (cell) { - let mainCell = new NotebookCellTextModel(URI.revive(cell.uri), cell.handle, cell.source, cell.language, cell.cellKind, cell.outputs); + let mainCell = new NotebookCellTextModel(URI.revive(cell.uri), cell.handle, cell.source, cell.language, cell.cellKind, cell.outputs, cell.metadata); return mainCell; } diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index aade3d364a79b3cfd95c7c6f588bd730dc7d9ce6..96012a5c0288039eeb148acb3a4dd66c3cc0c7ff 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -580,7 +580,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN let editor = this._editors.get(URI.revive(uri).toString()); let document = this._documents.get(URI.revive(uri).toString()); - let rawCell = editor?.editor.createCell('', language, type, [], undefined) as ExtHostCell; + let rawCell = editor?.editor.createCell('', language, type, [], { editable: true }) as ExtHostCell; document?.insertCell(index, rawCell!); let allDocuments = this._documentsAndEditors.allDocuments(); diff --git a/src/vs/workbench/contrib/notebook/browser/constants.ts b/src/vs/workbench/contrib/notebook/browser/constants.ts index 2381b2bef49c98bdef58e65ad2698fe7474d3613..8f3861f589195adc8af19bb531ba4f23d4a4e582 100644 --- a/src/vs/workbench/contrib/notebook/browser/constants.ts +++ b/src/vs/workbench/contrib/notebook/browser/constants.ts @@ -26,5 +26,10 @@ export const EDITOR_BOTTOM_PADDING = 8; export const EDITOR_TOOLBAR_HEIGHT = 22; export const RUN_BUTTON_WIDTH = 20; -// Context Keys +// Cell context keys export const NOTEBOOK_CELL_TYPE_CONTEXT_KEY = 'notebookCellType'; +export const NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY = 'notebookCellEditable'; +export const NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY = 'notebookCellMarkdownEditMode'; + +// Notebook context keys +export const NOTEBOOK_EDITABLE_CONTEXT_KEY = 'notebookEditable'; diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts index fa3a12ba6ae1bea38b652f1be0983772527db258..c0f1929c31966a42938fb348e3c8b8668194716b 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts @@ -11,12 +11,21 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo import { InputFocusedContext, InputFocusedContextKey, IsDevelopmentContext } from 'vs/platform/contextkey/common/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { COPY_CELL_DOWN_COMMAND_ID, COPY_CELL_UP_COMMAND_ID, DELETE_CELL_COMMAND_ID, EDIT_CELL_COMMAND_ID, EXECUTE_CELL_COMMAND_ID, INSERT_CODE_CELL_ABOVE_COMMAND_ID, INSERT_CODE_CELL_BELOW_COMMAND_ID, INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID, INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, MOVE_CELL_DOWN_COMMAND_ID, MOVE_CELL_UP_COMMAND_ID, SAVE_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/constants'; +import { COPY_CELL_DOWN_COMMAND_ID, COPY_CELL_UP_COMMAND_ID, DELETE_CELL_COMMAND_ID, EDIT_CELL_COMMAND_ID, EXECUTE_CELL_COMMAND_ID, INSERT_CODE_CELL_ABOVE_COMMAND_ID, INSERT_CODE_CELL_BELOW_COMMAND_ID, INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID, INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, MOVE_CELL_DOWN_COMMAND_ID, MOVE_CELL_UP_COMMAND_ID, SAVE_CELL_COMMAND_ID, NOTEBOOK_CELL_TYPE_CONTEXT_KEY, NOTEBOOK_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY } from 'vs/workbench/contrib/notebook/browser/constants'; import { CellRenderTemplate, CellEditState, ICellViewModel, INotebookEditor, KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, NOTEBOOK_EDITOR_FOCUSED, CellRunState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService'; import { CellKind, NOTEBOOK_EDITOR_CURSOR_BOUNDARY } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +const enum CellToolbarOrder { + MoveCellUp, + MoveCellDown, + EditCell, + SaveCell, + InsertCell, + DeleteCell +} + registerAction2(class extends Action2 { constructor() { super({ @@ -29,7 +38,8 @@ registerAction2(class extends Action2 { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.Enter }, weight: KeybindingWeight.WorkbenchContrib - } + }, + icon: { id: 'codicon/play' } }); } @@ -417,7 +427,18 @@ registerAction2(class extends InsertCellCommand { super( { id: INSERT_CODE_CELL_BELOW_COMMAND_ID, - title: localize('notebookActions.insertCodeCellBelow', "Insert Code Cell Below") + title: localize('notebookActions.insertCodeCellBelow', "Insert Code Cell Below"), + icon: { id: 'codicon/add' }, + menu: { + id: MenuId.NotebookCellTitle, + order: CellToolbarOrder.InsertCell, + alt: { + id: INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, + title: localize('notebookActions.insertMarkdownCellBelow', "Insert Markdown Cell Below"), + icon: { id: 'codicon/add' }, + }, + when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true) + } }, CellKind.Code, 'below'); @@ -441,89 +462,13 @@ registerAction2(class extends InsertCellCommand { super( { id: INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, - title: localize('notebookActions.insertMarkdownCellBelow', "Insert Markdown Cell Below"), + title: localize('notebookActions.insertMarkdownCellBelow', "Insert Markdown Cell Below") }, CellKind.Markdown, 'below'); } }); -export class InsertCodeCellAboveAction extends MenuItemAction { - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @ICommandService commandService: ICommandService - ) { - super( - { - id: INSERT_CODE_CELL_ABOVE_COMMAND_ID, - title: localize('notebookActions.insertCodeCellAbove', "Insert Code Cell Above"), - icon: { id: 'codicon/add' } - }, - undefined, - { shouldForwardArgs: true }, - contextKeyService, - commandService); - } -} - -export class InsertCodeCellBelowAction extends MenuItemAction { - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @ICommandService commandService: ICommandService - ) { - super( - { - id: INSERT_CODE_CELL_BELOW_COMMAND_ID, - title: localize('notebookActions.insertCodeCellBelow', "Insert Code Cell Below"), - icon: { id: 'codicon/add' } - }, - { - id: INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, - title: localize('notebookActions.insertMarkdownCellBelow', "Insert Markdown Cell Below"), - icon: { id: 'codicon/add' } - }, - { shouldForwardArgs: true }, - contextKeyService, - commandService); - } -} - -export class InsertMarkdownCellAboveAction extends MenuItemAction { - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @ICommandService commandService: ICommandService - ) { - super( - { - id: INSERT_MARKDOWN_CELL_ABOVE_COMMAND_ID, - title: localize('notebookActions.insertMarkdownCellAbove', "Insert Markdown Cell Above"), - icon: { id: 'codicon/add' } - }, - undefined, - { shouldForwardArgs: true }, - contextKeyService, - commandService); - } -} - -export class InsertMarkdownCellBelowAction extends MenuItemAction { - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @ICommandService commandService: ICommandService - ) { - super( - { - id: INSERT_MARKDOWN_CELL_BELOW_COMMAND_ID, - title: localize('notebookActions.insertMarkdownCellBelow', "Insert Markdown Cell Below"), - icon: { id: 'codicon/add' } - }, - undefined, - { shouldForwardArgs: true }, - contextKeyService, - commandService); - } -} - registerAction2(class extends Action2 { constructor() { super( @@ -534,7 +479,15 @@ registerAction2(class extends Action2 { when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.not(InputFocusedContextKey)), primary: KeyCode.Enter, weight: KeybindingWeight.WorkbenchContrib - } + }, + menu: { + id: MenuId.NotebookCellTitle, + when: ContextKeyExpr.and( + ContextKeyExpr.equals(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'markdown'), + ContextKeyExpr.equals(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, true)), + order: CellToolbarOrder.EditCell + }, + icon: { id: 'codicon/pencil' } }); } @@ -550,30 +503,20 @@ registerAction2(class extends Action2 { } }); -export class EditCellAction extends MenuItemAction { - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @ICommandService commandService: ICommandService - ) { - super( - { - id: EDIT_CELL_COMMAND_ID, - title: localize('notebookActions.editCell', "Edit Cell"), - icon: { id: 'codicon/pencil' } - }, - undefined, - { shouldForwardArgs: true }, - contextKeyService, - commandService); - } -} - registerAction2(class extends Action2 { constructor() { super( { id: SAVE_CELL_COMMAND_ID, - title: localize('notebookActions.saveCell', "Save Cell") + title: localize('notebookActions.saveCell', "Save Cell"), + menu: { + id: MenuId.NotebookCellTitle, + when: ContextKeyExpr.and( + ContextKeyExpr.equals(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'markdown'), + ContextKeyExpr.equals(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, true)), + order: CellToolbarOrder.SaveCell + }, + icon: { id: 'codicon/save' } }); } @@ -589,30 +532,19 @@ registerAction2(class extends Action2 { } }); -export class SaveCellAction extends MenuItemAction { - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @ICommandService commandService: ICommandService - ) { - super( - { - id: SAVE_CELL_COMMAND_ID, - title: localize('notebookActions.saveCell', "Save Cell"), - icon: { id: 'codicon/save' } - }, - undefined, - { shouldForwardArgs: true }, - contextKeyService, - commandService); - } -} registerAction2(class extends Action2 { constructor() { super( { id: DELETE_CELL_COMMAND_ID, - title: localize('notebookActions.deleteCell', "Delete Cell") + title: localize('notebookActions.deleteCell', "Delete Cell"), + menu: { + id: MenuId.NotebookCellTitle, + order: CellToolbarOrder.DeleteCell, + when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true) + }, + icon: { id: 'codicon/x' } }); } @@ -628,26 +560,6 @@ registerAction2(class extends Action2 { } }); -export class DeleteCellAction extends MenuItemAction { - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @ICommandService commandService: ICommandService - ) { - super( - { - id: DELETE_CELL_COMMAND_ID, - title: localize('notebookActions.deleteCell', "Delete Cell"), - icon: { id: 'codicon/x' } - }, - undefined, - { shouldForwardArgs: true }, - contextKeyService, - commandService); - - this.class = 'codicon-x'; - } -} - async function moveCell(context: INotebookCellActionContext, direction: 'up' | 'down'): Promise { direction === 'up' ? context.notebookEditor.moveCellUp(context.cell) : @@ -665,7 +577,18 @@ registerAction2(class extends Action2 { super( { id: MOVE_CELL_UP_COMMAND_ID, - title: localize('notebookActions.moveCellUp', "Move Cell Up") + title: localize('notebookActions.moveCellUp', "Move Cell Up"), + icon: { id: 'codicon/arrow-up' }, + menu: { + id: MenuId.NotebookCellTitle, + order: CellToolbarOrder.MoveCellUp, + alt: { + id: COPY_CELL_UP_COMMAND_ID, + title: localize('notebookActions.copyCellUp', "Copy Cell Up"), + icon: { id: 'codicon/arrow-up' } + }, + when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true) + }, }); } @@ -681,34 +604,23 @@ registerAction2(class extends Action2 { } }); -export class MoveCellUpAction extends MenuItemAction { - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @ICommandService commandService: ICommandService - ) { - super( - { - id: MOVE_CELL_UP_COMMAND_ID, - title: localize('notebookActions.moveCellUp', "Move Cell Up"), - icon: { id: 'codicon/arrow-up' } - }, - { - id: COPY_CELL_UP_COMMAND_ID, - title: localize('notebookActions.copyCellUp', "Copy Cell Up"), - icon: { id: 'codicon/arrow-up' } - }, - { shouldForwardArgs: true }, - contextKeyService, - commandService); - } -} - registerAction2(class extends Action2 { constructor() { super( { id: MOVE_CELL_DOWN_COMMAND_ID, - title: localize('notebookActions.moveCellDown', "Move Cell Down") + title: localize('notebookActions.moveCellDown', "Move Cell Down"), + icon: { id: 'codicon/arrow-down' }, + menu: { + id: MenuId.NotebookCellTitle, + order: CellToolbarOrder.MoveCellDown, + alt: { + id: COPY_CELL_DOWN_COMMAND_ID, + title: localize('notebookActions.copyCellDown', "Copy Cell Down"), + icon: { id: 'codicon/arrow-down' } + }, + when: ContextKeyExpr.equals(NOTEBOOK_EDITABLE_CONTEXT_KEY, true) + }, }); } @@ -724,30 +636,6 @@ registerAction2(class extends Action2 { } }); -export class MoveCellDownAction extends MenuItemAction { - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @ICommandService commandService: ICommandService - ) { - super( - { - id: MOVE_CELL_DOWN_COMMAND_ID, - title: localize('notebookActions.moveCellDown', "Move Cell Down"), - icon: { id: 'codicon/arrow-down' } - }, - { - id: COPY_CELL_DOWN_COMMAND_ID, - title: localize('notebookActions.copyCellDown', "Copy Cell Down"), - icon: { id: 'codicon/arrow-down' } - }, - { shouldForwardArgs: true }, - contextKeyService, - commandService); - - this.class = 'codicon-arrow-down'; - } -} - registerAction2(class extends Action2 { constructor() { super( diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 2985e545bb49b64071197f395a29711a25f06ed1..7531d38820c43916a52a125643a86f0ade249739 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -16,7 +16,7 @@ import { FindMatch } from 'vs/editor/common/model'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { IModelDecorationsChangeAccessor, NotebookViewModel, CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; -import { CellKind, IOutput, IRenderOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, IOutput, IRenderOutput, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey('notebookFindWidgetFocused', false); @@ -73,6 +73,7 @@ export interface ICellViewModel { runState: CellRunState; focusMode: CellFocusMode; getText(): string; + metadata: NotebookCellMetadata | undefined; } export interface INotebookEditor { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts index 3f46e71b50335292fe41548ba59e8665016ffd57..6ae9de2a2150b077a8bce46760c65773cead4626 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts @@ -53,7 +53,7 @@ export class NotebookEditorModel extends EditorModel { let notebook = this.getNotebook(); if (notebook) { - let mainCell = new NotebookCellTextModel(URI.revive(cell.uri), cell.handle, cell.source, cell.language, cell.cellKind, cell.outputs); + let mainCell = new NotebookCellTextModel(URI.revive(cell.uri), cell.handle, cell.source, cell.language, cell.cellKind, cell.outputs, cell.metadata); this.notebook.insertNewCell(index, mainCell); this._dirty = true; this._onDidChangeDirty.fire(); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 42e5e6f3f58dacbbadc941566b2ca80d1ebcb0b4..dca0b07d2c67b2028c72b4e219da82cb5d073a09 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -18,22 +18,22 @@ import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { MenuItemAction } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING, NOTEBOOK_CELL_TYPE_CONTEXT_KEY } from 'vs/workbench/contrib/notebook/browser/constants'; -import { DeleteCellAction, EditCellAction, ExecuteCellAction, INotebookCellActionContext, InsertCodeCellBelowAction, MoveCellDownAction, MoveCellUpAction, SaveCellAction, InsertCodeCellAboveAction, InsertMarkdownCellAboveAction, InsertMarkdownCellBelowAction } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions'; -import { CellRenderTemplate, ICellViewModel, INotebookEditor, CellRunState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING, NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_TYPE_CONTEXT_KEY, NOTEBOOK_EDITABLE_CONTEXT_KEY } from 'vs/workbench/contrib/notebook/browser/constants'; +import { CellRenderTemplate, CellRunState, ICellViewModel, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus'; import { CodeCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/codeCell'; import { StatefullMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell'; +import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; +import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel'; +import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookCellActionContext, ExecuteCellAction } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions'; import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus'; -import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; -import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel'; -import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; const $ = DOM.$; @@ -121,37 +121,21 @@ abstract class AbstractCellRenderer { return menu; } - abstract getCellToolbarActions(element: CellViewModel): IAction[]; - - showContextMenu(listIndex: number | undefined, element: CellViewModel, x: number, y: number) { - const actions: IAction[] = [ - this.instantiationService.createInstance(InsertCodeCellAboveAction), - this.instantiationService.createInstance(InsertCodeCellBelowAction), - this.instantiationService.createInstance(InsertMarkdownCellAboveAction), - this.instantiationService.createInstance(InsertMarkdownCellBelowAction), - ]; - actions.push(...this.getAdditionalContextMenuActions()); - actions.push(...[ - this.instantiationService.createInstance(DeleteCellAction) - ]); - - this.contextMenuService.showContextMenu({ - getAnchor: () => { - return { - x, - y - }; - }, - getActions: () => actions, - getActionsContext: () => { - cell: element, - notebookEditor: this.notebookEditor - }, - autoSelectFirstItem: false - }); - } + getCellToolbarActions(scopedContextKeyService: IContextKeyService): IAction[] { + const viewModel = this.notebookEditor.viewModel; + + if (!viewModel) { + return []; + } + + const menu = this.createMenu().getCellTitleActions(scopedContextKeyService); + const actions: IAction[] = []; + for (let [, menuActions] of menu.getActions({ shouldForwardArgs: true })) { + actions.push(...menuActions); + } - abstract getAdditionalContextMenuActions(): IAction[]; + return actions; + } } export class MarkdownCellRenderer extends AbstractCellRenderer implements IListRenderer { @@ -165,7 +149,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR @IContextMenuService contextMenuService: IContextMenuService, @IKeybindingService keybindingService: IKeybindingService, @INotificationService notificationService: INotificationService, - @IContextKeyService contextKeyService: IContextKeyService + @IContextKeyService contextKeyService: IContextKeyService, ) { super(instantiationService, notehookEditor, contextMenuService, configurationService, keybindingService, notificationService, contextKeyService, 'markdown'); } @@ -219,7 +203,10 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR const contextKeyService = this.contextKeyService.createScoped(templateData.container); contextKeyService.createKey(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'markdown'); - const toolbarActions = this.getCellToolbarActions(element); + contextKeyService.createKey(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, element.metadata?.editable); + contextKeyService.createKey(NOTEBOOK_EDITABLE_CONTEXT_KEY, this.notebookEditor.viewModel?.metadata?.editable); + + const toolbarActions = this.getCellToolbarActions(contextKeyService); templateData.toolbar!.setActions(toolbarActions)(); if (templateData.focusIndicator) { @@ -238,51 +225,6 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR }; } - getCellToolbarActions(element: MarkdownCellViewModel): IAction[] { - const viewModel = this.notebookEditor.viewModel; - - if (!viewModel) { - return []; - } - - const menu = this.createMenu().getCellTitleActions(this.contextKeyService); - const actions: IAction[] = []; - for (let [, actions] of menu.getActions({ shouldForwardArgs: true })) { - actions.push(...actions); - } - - const metadata = viewModel.metadata; - - if (!metadata || metadata.editable) { - actions.push( - this.instantiationService.createInstance(MoveCellUpAction), - this.instantiationService.createInstance(MoveCellDownAction), - this.instantiationService.createInstance(InsertCodeCellBelowAction) - ); - } - - const cellMetadata = element.metadata; - if (!cellMetadata || cellMetadata.editable) { - actions.push( - this.instantiationService.createInstance(EditCellAction), - this.instantiationService.createInstance(SaveCellAction) - ); - } - - if (!metadata || metadata.editable) { - this.instantiationService.createInstance(DeleteCellAction); - } - - return actions; - } - - getAdditionalContextMenuActions(): IAction[] { - return [ - this.instantiationService.createInstance(EditCellAction), - this.instantiationService.createInstance(SaveCellAction), - ]; - } - disposeTemplate(templateData: CellRenderTemplate): void { // throw nerendererw Error('Method not implemented.'); @@ -307,7 +249,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende @IInstantiationService instantiationService: IInstantiationService, @IKeybindingService keybindingService: IKeybindingService, @INotificationService notificationService: INotificationService, - @IContextKeyService contextKeyService: IContextKeyService + @IContextKeyService contextKeyService: IContextKeyService, ) { super(instantiationService, notebookEditor, contextMenuService, configurationService, keybindingService, notificationService, contextKeyService, 'python'); } @@ -319,12 +261,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende renderTemplate(container: HTMLElement): CellRenderTemplate { const disposables = new DisposableStore(); const toolbar = this.createToolbar(container); - toolbar.setActions([ - this.instantiationService.createInstance(MoveCellUpAction), - this.instantiationService.createInstance(MoveCellDownAction), - this.instantiationService.createInstance(InsertCodeCellBelowAction), - this.instantiationService.createInstance(DeleteCellAction) - ])(); disposables.add(toolbar); const cellContainer = DOM.append(container, $('.cell.code')); @@ -393,7 +329,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende elementDisposable?.add(element.onDidChangeCellRunState(() => { if (element.runState === CellRunState.Running) { - templateData.progressBar?.infinite().show(); + templateData.progressBar?.infinite().show(500); } else { templateData.progressBar?.hide(); } @@ -408,7 +344,10 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende const contextKeyService = this.contextKeyService.createScoped(templateData.container); contextKeyService.createKey(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'code'); - const toolbarActions = this.getCellToolbarActions(element); + contextKeyService.createKey(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, element.metadata?.editable); + contextKeyService.createKey(NOTEBOOK_EDITABLE_CONTEXT_KEY, this.notebookEditor.viewModel?.metadata?.editable); + + const toolbarActions = this.getCellToolbarActions(contextKeyService); templateData.toolbar!.setActions(toolbarActions)(); templateData.toolbar!.context = toolbarContext; templateData.runToolbar!.context = toolbarContext; @@ -422,39 +361,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende } } - - getCellToolbarActions(element: CodeCellViewModel): IAction[] { - const viewModel = this.notebookEditor.viewModel; - - if (!viewModel) { - return []; - } - - const menu = this.createMenu().getCellTitleActions(this.contextKeyService); - const actions: IAction[] = []; - for (let [, actions] of menu.getActions({ shouldForwardArgs: true })) { - actions.push(...actions); - } - - const metadata = viewModel.metadata; - - if (!metadata || metadata.editable) { - actions.push( - this.instantiationService.createInstance(MoveCellUpAction), - this.instantiationService.createInstance(MoveCellDownAction), - this.instantiationService.createInstance(InsertCodeCellBelowAction), - this.instantiationService.createInstance(DeleteCellAction) - ); - } - - return actions; - } - - - getAdditionalContextMenuActions(): IAction[] { - return []; - } - disposeTemplate(templateData: CellRenderTemplate): void { templateData.disposables.clear(); } diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts index e11f76aadb71165b889881110dac5deed8caed03..6b05e1a0da0643a17116b979039c9ab54d683282 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { ICell, IOutput, NotebookCellOutputsSplice, CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ICell, IOutput, NotebookCellOutputsSplice, CellKind, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { PieceTreeTextBufferFactory, PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder'; import { URI } from 'vs/base/common/uri'; @@ -38,7 +38,8 @@ export class NotebookCellTextModel implements ICell { private _source: string[], public language: string, public cellKind: CellKind, - outputs: IOutput[] + outputs: IOutput[], + public readonly metadata: NotebookCellMetadata | undefined ) { this._outputs = outputs; } diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts index 9d6b3a0ec5b83d889ba23ded44fe027d48c026ce..490e4847e088e53bdc8d6d4fca1a8e23cd8a859b 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts @@ -72,7 +72,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel splices.reverse().forEach(splice => { let cellDtos = splice[2]; let newCells = cellDtos.map(cell => { - let mainCell = new NotebookCellTextModel(URI.revive(cell.uri), cell.handle, cell.source, cell.language, cell.cellKind, cell.outputs || []); + let mainCell = new NotebookCellTextModel(URI.revive(cell.uri), cell.handle, cell.source, cell.language, cell.cellKind, cell.outputs || [], cell.metadata); this._mapping.set(cell.handle, mainCell); let dirtyStateListener = mainCell.onDidChangeContent(() => { this._onDidChangeContent.fire(); diff --git a/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts b/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts index 9cc8e077e65580e3ad25719a0914926e448828a7..5c3093c461fd901439633e90d61f0423e35d07bc 100644 --- a/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts +++ b/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts @@ -33,14 +33,16 @@ suite('NotebookViewModel', () => { blukEditService, undoRedoService, [ - [['var a = 1;'], 'javascript', CellKind.Code, []], - [['var b = 2;'], 'javascript', CellKind.Code, []] + [['var a = 1;'], 'javascript', CellKind.Code, [], { editable: true }], + [['var b = 2;'], 'javascript', CellKind.Code, [], { editable: false }] ], (editor, viewModel) => { const cell = viewModel.insertCell(1, new TestCell(viewModel.viewType, 0, ['var c = 3;'], 'javascript', CellKind.Code, []), true); assert.equal(viewModel.viewCells.length, 3); assert.equal(viewModel.notebookDocument.cells.length, 3); assert.equal(viewModel.getViewCellIndex(cell), 1); + assert.equal(viewModel.viewCells[0].metadata?.editable, true); + assert.equal(viewModel.viewCells[0].metadata?.editable, false); viewModel.deleteCell(1, true); assert.equal(viewModel.viewCells.length, 2); @@ -56,8 +58,8 @@ suite('NotebookViewModel', () => { blukEditService, undoRedoService, [ - [['var a = 1;'], 'javascript', CellKind.Code, []], - [['var b = 2;'], 'javascript', CellKind.Code, []] + [['var a = 1;'], 'javascript', CellKind.Code, [], { editable: true }], + [['var b = 2;'], 'javascript', CellKind.Code, [], { editable: true }] ], (editor, viewModel) => { const firstViewCell = viewModel.viewCells[0]; diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index 397fb5ec38add66b02d3dffe4dde453fa9b1d1a5..dc57c7712c4624046e1167b4bc4670bb29e90c66 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -6,7 +6,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; import { PieceTreeTextBufferFactory } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder'; -import { CellKind, ICell, IOutput, NotebookCellOutputsSplice, CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, ICell, IOutput, NotebookCellOutputsSplice, CellUri, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookViewModel, IModelDecorationsChangeAccessor, CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput'; @@ -187,12 +187,12 @@ export class TestNotebookEditor implements INotebookEditor { // return createCellViewModel(instantiationService, viewType, notebookHandle, mockCell); // } -export function withTestNotebook(instantiationService: IInstantiationService, blukEditService: IBulkEditService, undoRedoService: IUndoRedoService, cells: [string[], string, CellKind, IOutput[]][], callback: (editor: TestNotebookEditor, viewModel: NotebookViewModel) => void) { +export function withTestNotebook(instantiationService: IInstantiationService, blukEditService: IBulkEditService, undoRedoService: IUndoRedoService, cells: [string[], string, CellKind, IOutput[], NotebookCellMetadata][], callback: (editor: TestNotebookEditor, viewModel: NotebookViewModel) => void) { const viewType = 'notebook'; const editor = new TestNotebookEditor(); const notebook = new NotebookTextModel(0, viewType, URI.parse('test')); notebook.cells = cells.map((cell, index) => { - return new NotebookCellTextModel(notebook.uri, index, cell[0], cell[1], cell[2], cell[3]); + return new NotebookCellTextModel(notebook.uri, index, cell[0], cell[1], cell[2], cell[3], cell[4]); }); const model = new NotebookEditorModel(notebook); const viewModel = new NotebookViewModel(viewType, model, instantiationService, blukEditService, undoRedoService);