From d404a5f0a499938bccb5a48692a77aa85a0db1aa Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 18 Mar 2020 18:04:06 -0700 Subject: [PATCH 1/3] Add Run button to notebook cells --- .../contrib/notebook/browser/constants.ts | 1 + .../browser/contrib/notebookActions.ts | 59 +++++++++++++++++-- .../contrib/notebook/browser/notebook.css | 15 ++++- .../notebook/browser/notebookBrowser.ts | 2 + .../notebook/browser/notebookEditor.ts | 6 +- .../browser/view/renderers/cellRenderer.ts | 26 +++++--- .../browser/view/renderers/codeCell.ts | 11 ++-- 7 files changed, 100 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/constants.ts b/src/vs/workbench/contrib/notebook/browser/constants.ts index 3a9456fab05dc..00f2bf86b6ff8 100644 --- a/src/vs/workbench/contrib/notebook/browser/constants.ts +++ b/src/vs/workbench/contrib/notebook/browser/constants.ts @@ -24,3 +24,4 @@ export const CELL_MARGIN = 32; export const EDITOR_TOP_PADDING = 8; export const EDITOR_BOTTOM_PADDING = 8; export const EDITOR_TOOLBAR_HEIGHT = 22; +export const RUN_BUTTON_WIDTH = 20; diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts index f33cec5c58f69..c0c5573934ce7 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts @@ -11,7 +11,7 @@ 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 { DELETE_CELL_COMMAND_ID, EDIT_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, COPY_CELL_UP_COMMAND_ID, COPY_CELL_DOWN_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/constants'; +import { DELETE_CELL_COMMAND_ID, EDIT_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, COPY_CELL_UP_COMMAND_ID, COPY_CELL_DOWN_COMMAND_ID, EXECUTE_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/constants'; import { INotebookEditor, KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, NOTEBOOK_EDITOR_FOCUSED, ICellViewModel, CellState } 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'; @@ -20,7 +20,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic registerAction2(class extends Action2 { constructor() { super({ - id: 'workbench.action.executeNotebookCell', + id: EXECUTE_CELL_COMMAND_ID, title: localize('notebookActions.execute', "Execute Notebook Cell"), keybinding: { when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, InputFocusedContext), @@ -33,11 +33,36 @@ registerAction2(class extends Action2 { }); } - async run(accessor: ServicesAccessor): Promise { - runActiveCell(accessor); + async run(accessor: ServicesAccessor, context?: INotebookCellActionContext): Promise { + if (!context) { + context = getActiveCellContext(accessor); + if (!context) { + return; + } + } + + runCell(accessor, context); } }); +export class ExecuteCellAction extends MenuItemAction { + constructor( + @IContextKeyService contextKeyService: IContextKeyService, + @ICommandService commandService: ICommandService + ) { + super( + { + id: EXECUTE_CELL_COMMAND_ID, + title: localize('notebookActions.executeCell', "Execute Cell"), + icon: { id: 'codicon/play' } + }, + undefined, + { shouldForwardArgs: true }, + contextKeyService, + commandService); + } +} + registerAction2(class extends Action2 { constructor() { super({ @@ -308,6 +333,32 @@ function runActiveCell(accessor: ServicesAccessor): ICellViewModel | undefined { return activeCell; } +function runCell(accessor: ServicesAccessor, context: INotebookCellActionContext): void { + const editorService = accessor.get(IEditorService); + const notebookService = accessor.get(INotebookService); + + const resource = editorService.activeEditor?.resource; + if (!resource) { + return; + } + + const editor = getActiveNotebookEditor(editorService); + if (!editor) { + return; + } + + const notebookProviders = notebookService.getContributedNotebookProviders(resource); + if (!notebookProviders.length) { + return; + } + + // Need to make active, maybe TODO + editor.focusNotebookCell(context.cell, false); + + const viewType = notebookProviders[0].id; + notebookService.executeNotebookActiveCell(viewType, resource); +} + async function changeActiveCellToKind(kind: CellKind, accessor: ServicesAccessor): Promise { const editorService = accessor.get(IEditorService); const editor = getActiveNotebookEditor(editorService); diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.css b/src/vs/workbench/contrib/notebook/browser/notebook.css index 808fee559397e..e4b211930f46d 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/notebook.css @@ -30,6 +30,10 @@ position: relative; } +.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .cell { + display: flex; +} + .monaco-workbench .part.editor > .content .notebook-editor .notebook-content-widgets { position: absolute; top: 0; @@ -122,11 +126,20 @@ cursor: pointer; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .monaco-toolbar { +.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar { visibility: hidden; margin-right: 24px; } +.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .cell .run-button-container .monaco-toolbar { + margin-top: 8px; + visibility: hidden; +} + +.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .cell .run-button-container .monaco-toolbar { + visibility: visible; +} + .monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.focused .monaco-toolbar, .monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .monaco-toolbar { visibility: visible; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index c3d724e887a50..8f00c632472da 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -195,9 +195,11 @@ export interface INotebookEditor { export interface CellRenderTemplate { container: HTMLElement; cellContainer: HTMLElement; + editorContainer?: HTMLElement; menuContainer?: HTMLElement; toolbar: ToolBar; focusIndicator?: HTMLElement; + runToolbar?: ToolBar; editingContainer?: HTMLElement; outputContainer?: HTMLElement; editor?: CodeEditorWidget; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index bfdd63c537339..024fcd1f4c93d 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -717,12 +717,12 @@ registerThemingParticipant((theme, collector) => { } const link = theme.getColor(textLinkForeground); if (link) { - collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell a { color: ${link}; }`); + collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .output a { color: ${link}; }`); } const activeLink = theme.getColor(textLinkActiveForeground); if (activeLink) { - collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell a:hover, - .monaco-workbench .part.editor > .content .notebook-editor .cell a:active { color: ${activeLink}; }`); + collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .output a:hover, + .monaco-workbench .part.editor > .content .notebook-editor .cell .output a:active { color: ${activeLink}; }`); } const shortcut = theme.getColor(textPreformatForeground); if (shortcut) { 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 64761922fe67d..38163327f869e 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -18,7 +18,7 @@ import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { InsertCodeCellAboveAction, INotebookCellActionContext, InsertCodeCellBelowAction, InsertMarkdownCellAboveAction, InsertMarkdownCellBelowAction, EditCellAction, SaveCellAction, DeleteCellAction, MoveCellUpAction, MoveCellDownAction } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions'; +import { InsertCodeCellAboveAction, INotebookCellActionContext, InsertCodeCellBelowAction, InsertMarkdownCellAboveAction, InsertMarkdownCellBelowAction, EditCellAction, SaveCellAction, DeleteCellAction, MoveCellUpAction, MoveCellDownAction, ExecuteCellAction } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions'; import { CellRenderTemplate, INotebookEditor, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CodeCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/codeCell'; import { StatefullMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell'; @@ -30,7 +30,9 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; -export class NotebookCellListDelegate implements IListVirtualDelegate { +const $ = DOM.$; + +export class NotebookCellListDelegate implements IListVirtualDelegate { private _lineHeight: number; private _toolbarHeight = EDITOR_TOOLBAR_HEIGHT; @@ -291,10 +293,16 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende ])(); disposables.add(toolbar); - const cellContainer = document.createElement('div'); - DOM.addClasses(cellContainer, 'cell', 'code'); - container.appendChild(cellContainer); - const editor = this.instantiationService.createInstance(CodeEditorWidget, cellContainer, { + const cellContainer = DOM.append(container, $('.cell.code')); + const runButtonContainer = DOM.append(cellContainer, $('.run-button-container')); + const runToolbar = this.createToolbar(runButtonContainer); + runToolbar.setActions([ + this.instantiationService.createInstance(ExecuteCellAction) + ])(); + disposables.add(runToolbar); + + const editorContainer = DOM.append(cellContainer, $('.cell-editor-container')); + const editor = this.instantiationService.createInstance(CodeEditorWidget, editorContainer, { ...this.editorOptions, dimension: { width: 0, @@ -314,9 +322,11 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende return { container, cellContainer, + editorContainer, menuContainer, focusIndicator, toolbar, + runToolbar, outputContainer, editor, disposables @@ -364,10 +374,12 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende templateData.focusIndicator!.style.height = `${element.getIndicatorHeight()}px`; })); - templateData.toolbar!.context = { + const toolbarContext = { cell: element, notebookEditor: this.notebookEditor }; + templateData.toolbar!.context = toolbarContext; + templateData.runToolbar!.context = toolbarContext; } getAdditionalContextMenuActions(): IAction[] { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts index 2492477fab868..ee05ead40cbfb 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts @@ -14,7 +14,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService'; import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel'; -import { CELL_MARGIN, EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; +import { CELL_MARGIN, EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING, RUN_BUTTON_WIDTH } from 'vs/workbench/contrib/notebook/browser/constants'; interface IMimeTypeRenderer extends IQuickPickItem { index: number; @@ -34,7 +34,8 @@ export class CodeCell extends Disposable { let width: number; const listDimension = notebookEditor.getLayoutInfo(); - width = listDimension.width - CELL_MARGIN * 2; + width = listDimension.width - CELL_MARGIN * 2 - RUN_BUTTON_WIDTH; + const lineNum = viewCell.lineCount; const lineHeight = notebookEditor.getLayoutInfo().fontInfo.lineHeight; const totalHeight = lineNum * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING; @@ -59,7 +60,7 @@ export class CodeCell extends Disposable { let realContentHeight = templateData.editor?.getContentHeight(); let width: number; const listDimension = notebookEditor.getLayoutInfo(); - width = listDimension.width - CELL_MARGIN * 2; + width = listDimension.width - CELL_MARGIN * 2 - RUN_BUTTON_WIDTH; if (realContentHeight !== undefined && realContentHeight !== totalHeight) { templateData.editor?.layout( @@ -84,7 +85,7 @@ export class CodeCell extends Disposable { } })); - let cellWidthResizeObserver = getResizesObserver(templateData.cellContainer, { + let cellWidthResizeObserver = getResizesObserver(templateData.editorContainer!, { width: width, height: totalHeight }, () => { @@ -267,7 +268,7 @@ export class CodeCell extends Disposable { let clientHeight = outputItemDiv.clientHeight; let listDimension = this.notebookEditor.getLayoutInfo(); let dimension = listDimension ? { - width: listDimension.width - CELL_MARGIN * 2, + width: listDimension.width - CELL_MARGIN * 2 - RUN_BUTTON_WIDTH, height: clientHeight } : undefined; const elementSizeObserver = getResizesObserver(outputItemDiv, dimension, () => { From 1344cb6c497e1e760afedf3b206dc7b159900699 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 18 Mar 2020 19:13:25 -0700 Subject: [PATCH 2/3] Remove gear icon --- .../contrib/notebook/browser/notebook.css | 3 +- .../notebook/browser/notebookBrowser.ts | 1 - .../browser/view/renderers/cellRenderer.ts | 89 ++----------------- 3 files changed, 9 insertions(+), 84 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.css b/src/vs/workbench/contrib/notebook/browser/notebook.css index e4b211930f46d..c3c20bfcefeff 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/notebook.css @@ -136,7 +136,8 @@ visibility: hidden; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .cell .run-button-container .monaco-toolbar { +.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .cell .run-button-container .monaco-toolbar, +.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.focused .cell .run-button-container .monaco-toolbar { visibility: visible; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 8f00c632472da..a0f4c534bbfb6 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -196,7 +196,6 @@ export interface CellRenderTemplate { container: HTMLElement; cellContainer: HTMLElement; editorContainer?: HTMLElement; - menuContainer?: HTMLElement; toolbar: ToolBar; focusIndicator?: HTMLElement; runToolbar?: ToolBar; 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 38163327f869e..9deeaa6477744 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -15,20 +15,20 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; 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 { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { InsertCodeCellAboveAction, INotebookCellActionContext, InsertCodeCellBelowAction, InsertMarkdownCellAboveAction, InsertMarkdownCellBelowAction, EditCellAction, SaveCellAction, DeleteCellAction, MoveCellUpAction, MoveCellDownAction, ExecuteCellAction } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions'; -import { CellRenderTemplate, INotebookEditor, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +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 } from 'vs/workbench/contrib/notebook/browser/constants'; +import { DeleteCellAction, EditCellAction, ExecuteCellAction, INotebookCellActionContext, InsertCodeCellBelowAction, MoveCellDownAction, MoveCellUpAction, SaveCellAction } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions'; +import { CellRenderTemplate, ICellViewModel, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CodeCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/codeCell'; import { StatefullMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell'; import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CellViewModel } from '../../viewModel/notebookCellViewModel'; -import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { MenuItemAction } from 'vs/platform/actions/common/actions'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; const $ = DOM.$; @@ -110,34 +110,6 @@ abstract class AbstractCellRenderer { return toolbar; } - 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 - }); - } - abstract getAdditionalContextMenuActions(): IAction[]; } @@ -183,16 +155,11 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR DOM.addClasses(innerContent, 'cell', 'markdown'); container.appendChild(innerContent); - const action = document.createElement('div'); - DOM.addClasses(action, 'menu', 'codicon-settings-gear', 'codicon'); - container.appendChild(action); - DOM.append(container, DOM.$('.notebook-cell-focus-indicator')); return { container: container, cellContainer: innerContent, - menuContainer: action, editingContainer: codeInnerContent, disposables, toolbar @@ -214,23 +181,6 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR } let elementDisposable = this.disposables.get(element); - elementDisposable!.add(DOM.addStandardDisposableListener(templateData.menuContainer!, 'mousedown', e => { - const { top, height } = DOM.getDomNodePagePosition(templateData.menuContainer!); - e.preventDefault(); - - const listIndexAttr = templateData.menuContainer?.parentElement?.getAttribute('data-index'); - const listIndex = listIndexAttr ? Number(listIndexAttr) : undefined; - this.showContextMenu(listIndex, element, e.posx, top + height); - })); - - elementDisposable!.add(DOM.addStandardDisposableListener(templateData.menuContainer!, DOM.EventType.MOUSE_LEAVE, e => { - templateData.menuContainer?.classList.remove('mouseover'); - })); - - elementDisposable!.add(DOM.addStandardDisposableListener(templateData.menuContainer!, DOM.EventType.MOUSE_ENTER, e => { - templateData.menuContainer?.classList.add('mouseover'); - })); - elementDisposable!.add(new StatefullMarkdownCell(this.notebookEditor, element, templateData, this.editorOptions, this.instantiationService)); } @@ -281,9 +231,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende renderTemplate(container: HTMLElement): CellRenderTemplate { const disposables = new DisposableStore(); - const toolbarContainer = document.createElement('div'); - container.appendChild(toolbarContainer); - DOM.addClasses(toolbarContainer, 'menu', 'codicon-settings-gear', 'codicon'); const toolbar = this.createToolbar(container); toolbar.setActions([ this.instantiationService.createInstance(MoveCellUpAction), @@ -309,9 +256,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende height: 0 } }, {}); - const menuContainer = document.createElement('div'); - DOM.addClasses(menuContainer, 'menu', 'codicon-settings-gear', 'codicon'); - container.appendChild(menuContainer); const focusIndicator = DOM.append(container, DOM.$('.notebook-cell-focus-indicator')); @@ -323,7 +267,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende container, cellContainer, editorContainer, - menuContainer, focusIndicator, toolbar, runToolbar, @@ -349,24 +292,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende const elementDisposable = this.disposables.get(element); - elementDisposable?.add(DOM.addStandardDisposableListener(templateData.menuContainer!, 'mousedown', e => { - let { top, height } = DOM.getDomNodePagePosition(templateData.menuContainer!); - e.preventDefault(); - - const listIndexAttr = templateData.menuContainer?.parentElement?.getAttribute('data-index'); - const listIndex = listIndexAttr ? Number(listIndexAttr) : undefined; - - this.showContextMenu(listIndex, element, e.posx, top + height); - })); - - elementDisposable!.add(DOM.addStandardDisposableListener(templateData.menuContainer!, DOM.EventType.MOUSE_LEAVE, e => { - templateData.menuContainer?.classList.remove('mouseover'); - })); - - elementDisposable!.add(DOM.addStandardDisposableListener(templateData.menuContainer!, DOM.EventType.MOUSE_ENTER, e => { - templateData.menuContainer?.classList.add('mouseover'); - })); - elementDisposable?.add(this.instantiationService.createInstance(CodeCell, this.notebookEditor, element, templateData)); this.renderedEditors.set(element, templateData.editor); From 95ba0b1e68e17cd2855176e1cb2192551514ee41 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 18 Mar 2020 21:47:59 -0700 Subject: [PATCH 3/3] Add progress bar --- .../api/browser/mainThreadNotebook.ts | 4 ++-- .../browser/contrib/notebookActions.ts | 21 ++++++++++++------- .../contrib/notebook/browser/notebook.css | 8 +++++++ .../notebook/browser/notebookBrowser.ts | 2 ++ .../notebook/browser/notebookEditor.ts | 6 ++++-- .../notebook/browser/notebookService.ts | 2 +- .../browser/view/renderers/cellRenderer.ts | 7 +++++++ 7 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 9330413e36a86..ace6e0e3623e7 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -227,11 +227,11 @@ export class MainThreadNotebookController implements IMainNotebookController { return false; } - executeNotebookActiveCell(uri: URI): void { + async executeNotebookActiveCell(uri: URI): Promise { let mainthreadNotebook = this._mapping.get(URI.from(uri).toString()); if (mainthreadNotebook && mainthreadNotebook.textModel.activeCell) { - this._proxy.$executeNotebook(this._viewType, uri, mainthreadNotebook.textModel.activeCell.handle); + return this._proxy.$executeNotebook(this._viewType, uri, mainthreadNotebook.textModel.activeCell.handle); } } diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts index c0c5573934ce7..5aaedcffc8f0f 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts @@ -11,8 +11,8 @@ 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 { DELETE_CELL_COMMAND_ID, EDIT_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, COPY_CELL_UP_COMMAND_ID, COPY_CELL_DOWN_COMMAND_ID, EXECUTE_CELL_COMMAND_ID } from 'vs/workbench/contrib/notebook/browser/constants'; -import { INotebookEditor, KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, NOTEBOOK_EDITOR_FOCUSED, ICellViewModel, CellState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +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 { CellRenderTemplate, CellState, ICellViewModel, INotebookEditor, KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, NOTEBOOK_EDITOR_FOCUSED } 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'; @@ -78,7 +78,7 @@ registerAction2(class extends Action2 { async run(accessor: ServicesAccessor): Promise { const editorService = accessor.get(IEditorService); - const activeCell = runActiveCell(accessor); + const activeCell = await runActiveCell(accessor); if (!activeCell) { return; } @@ -118,7 +118,7 @@ registerAction2(class extends Action2 { async run(accessor: ServicesAccessor): Promise { const editorService = accessor.get(IEditorService); - const activeCell = runActiveCell(accessor); + const activeCell = await runActiveCell(accessor); if (!activeCell) { return; } @@ -298,7 +298,7 @@ function getActiveNotebookEditor(editorService: IEditorService): INotebookEditor return activeEditorPane?.isNotebookEditor ? activeEditorPane : undefined; } -function runActiveCell(accessor: ServicesAccessor): ICellViewModel | undefined { +async function runActiveCell(accessor: ServicesAccessor): Promise { const editorService = accessor.get(IEditorService); const notebookService = accessor.get(INotebookService); @@ -328,12 +328,15 @@ function runActiveCell(accessor: ServicesAccessor): ICellViewModel | undefined { } const viewType = notebookProviders[0].id; - notebookService.executeNotebookActiveCell(viewType, resource); + await notebookService.executeNotebookActiveCell(viewType, resource); return activeCell; } -function runCell(accessor: ServicesAccessor, context: INotebookCellActionContext): void { +async function runCell(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise { + const progress = context.cellTemplate!.progressBar!; + progress.infinite().show(500); + const editorService = accessor.get(IEditorService); const notebookService = accessor.get(INotebookService); @@ -356,7 +359,8 @@ function runCell(accessor: ServicesAccessor, context: INotebookCellActionContext editor.focusNotebookCell(context.cell, false); const viewType = notebookProviders[0].id; - notebookService.executeNotebookActiveCell(viewType, resource); + await notebookService.executeNotebookActiveCell(viewType, resource); + progress.hide(); } async function changeActiveCellToKind(kind: CellKind, accessor: ServicesAccessor): Promise { @@ -392,6 +396,7 @@ async function changeActiveCellToKind(kind: CellKind, accessor: ServicesAccessor } export interface INotebookCellActionContext { + cellTemplate?: CellRenderTemplate; cell: ICellViewModel; notebookEditor: INotebookEditor; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.css b/src/vs/workbench/contrib/notebook/browser/notebook.css index c3c20bfcefeff..7682262b20830 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/notebook.css @@ -141,6 +141,14 @@ visibility: visible; } +.monaco-workbench .part.editor > .content .notebook-editor .cell .cell-editor-container { + position: relative; +} + +.monaco-workbench .part.editor > .content .notebook-editor .cell .monaco-progress-container { + top: 0px; +} + .monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.focused .monaco-toolbar, .monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .monaco-toolbar { visibility: visible; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index a0f4c534bbfb6..8620dfc45b68b 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -16,6 +16,7 @@ import { Range } from 'vs/editor/common/core/range'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey('notebookFindWidgetFocused', false); @@ -202,6 +203,7 @@ export interface CellRenderTemplate { editingContainer?: HTMLElement; outputContainer?: HTMLElement; editor?: CodeEditorWidget; + progressBar?: ProgressBar; disposables: DisposableStore; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index 024fcd1f4c93d..636a3a0631d8a 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -42,7 +42,7 @@ import { NotebookViewModel, INotebookEditorViewState, IModelDecorationsChangeAcc import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel'; import { Range } from 'vs/editor/common/core/range'; -import { CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants'; +import { CELL_MARGIN, RUN_BUTTON_WIDTH } from 'vs/workbench/contrib/notebook/browser/constants'; import { Color, RGBA } from 'vs/base/common/color'; const $ = DOM.$; @@ -756,5 +756,7 @@ registerThemingParticipant((theme, collector) => { // Cell Margin collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > div.cell { padding: 8px ${CELL_MARGIN}px 8px ${CELL_MARGIN}px; }`); - collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 8px ${CELL_MARGIN}px; }`); + collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 8px ${CELL_MARGIN}px 8px ${CELL_MARGIN + RUN_BUTTON_WIDTH}px }`); + + collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .cell-editor-container { width: calc(100% - ${RUN_BUTTON_WIDTH}px); }`); }); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookService.ts b/src/vs/workbench/contrib/notebook/browser/notebookService.ts index 2746196d2c658..7aab5fe54cac1 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookService.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookService.ts @@ -29,7 +29,7 @@ export interface IMainNotebookController { updateNotebookActiveCell(uri: URI, cellHandle: number): void; createRawCell(uri: URI, index: number, language: string, type: CellKind): Promise; deleteCell(uri: URI, index: number): Promise - executeNotebookActiveCell(uri: URI): void; + executeNotebookActiveCell(uri: URI): Promise; destoryNotebookDocument(notebook: INotebookTextModel): Promise; save(uri: URI): Promise; } 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 9deeaa6477744..4624b3fa3f52e 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -29,6 +29,7 @@ import { CodeCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/c import { StatefullMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell'; import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CellViewModel } from '../../viewModel/notebookCellViewModel'; +import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; const $ = DOM.$; @@ -263,10 +264,15 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende DOM.addClasses(outputContainer, 'output'); container.appendChild(outputContainer); + const progressBar = new ProgressBar(editorContainer); + progressBar.hide(); + disposables.add(progressBar); + return { container, cellContainer, editorContainer, + progressBar, focusIndicator, toolbar, runToolbar, @@ -301,6 +307,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende const toolbarContext = { cell: element, + cellTemplate: templateData, notebookEditor: this.notebookEditor }; templateData.toolbar!.context = toolbarContext;