未验证 提交 5d792c19 编写于 作者: P Peng Lyu 提交者: GitHub

Merge pull request #93112 from microsoft/roblou/progress

Fixup progress, execution
......@@ -238,15 +238,10 @@ export class MainThreadNotebookController implements IMainNotebookController {
document?.textModel.updateRenderers(renderers);
}
updateNotebookActiveCell(uri: URI, cellHandle: number): void {
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
mainthreadNotebook?.textModel.updateActiveCell(cellHandle);
}
async createRawCell(uri: URI, index: number, language: string, type: CellKind): Promise<NotebookCellTextModel | undefined> {
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;
}
......@@ -263,12 +258,8 @@ export class MainThreadNotebookController implements IMainNotebookController {
return false;
}
async executeNotebookActiveCell(uri: URI): Promise<void> {
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
if (mainthreadNotebook && mainthreadNotebook.textModel.activeCell) {
return this._proxy.$executeNotebook(this._viewType, uri, mainthreadNotebook.textModel.activeCell.handle);
}
async executeNotebookCell(uri: URI, handle: number): Promise<void> {
return this._proxy.$executeNotebook(this._viewType, uri, handle);
}
async destoryNotebookDocument(notebook: INotebookTextModel): Promise<void> {
......
......@@ -665,7 +665,7 @@ export interface ICellDto {
language: string;
cellKind: CellKind;
outputs: IOutput[];
metadata?: NotebookCellMetadata;
metadata: NotebookCellMetadata;
}
export type NotebookCellsSplice = [
......
......@@ -33,7 +33,7 @@ export class ExtHostCell implements vscode.NotebookCell {
public cellKind: CellKind,
public language: string,
outputs: any[],
public metadata: vscode.NotebookCellMetadata | undefined,
public metadata: vscode.NotebookCellMetadata,
) {
this.source = this._content.split(/\r|\n|\r\n/g);
this._outputs = outputs;
......@@ -341,6 +341,10 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
}
}
const notebookCellMetadataDefaults: vscode.NotebookCellMetadata = {
editable: true
};
export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor {
private _viewColumn: vscode.ViewColumn | undefined;
private static _cellhandlePool: number = 0;
......@@ -382,6 +386,10 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
createCell(content: string, language: string, type: CellKind, outputs: vscode.CellOutput[], metadata: vscode.NotebookCellMetadata | undefined): vscode.NotebookCell {
const handle = ExtHostNotebookEditor._cellhandlePool++;
const uri = CellUri.generate(this.document.uri, handle);
metadata = {
...notebookCellMetadataDefaults,
...(metadata || {})
};
const cell = new ExtHostCell(handle, uri, content, type, language, outputs, metadata);
return cell;
}
......@@ -580,7 +588,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();
......
......@@ -26,5 +26,10 @@ export const EDITOR_BOTTOM_PADDING = 8;
export const EDITOR_TOOLBAR_HEIGHT = 22;
export const RUN_BUTTON_WIDTH = 20;
// Context Keys
export const NOTEBOOK_CELL_TYPE_CONTEXT_KEY = 'notebookCellType';
// Cell context keys
export const NOTEBOOK_CELL_TYPE_CONTEXT_KEY = 'notebookCellType'; // code, markdown
export const NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY = 'notebookCellEditable'; // bool
export const NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY = 'notebookCellMarkdownEditMode'; // bool
// Notebook context keys
export const NOTEBOOK_EDITABLE_CONTEXT_KEY = 'notebookEditable';
......@@ -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 { CellRenderTemplate, CellState, ICellViewModel, INotebookEditor, KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, NOTEBOOK_EDITOR_FOCUSED } 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, NOTEBOOK_CELL_TYPE_CONTEXT_KEY, NOTEBOOK_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_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' }
});
}
......@@ -41,7 +51,7 @@ registerAction2(class extends Action2 {
}
}
runCell(accessor, context);
runCell(context);
}
});
......@@ -159,6 +169,29 @@ registerAction2(class extends Action2 {
}
});
registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.executeNotebookCell',
title: localize('notebookActions.executeNotebookCell', "Execute Notebook Active Cell")
});
}
async run(accessor: ServicesAccessor): Promise<void> {
let editorService = accessor.get(IEditorService);
let editor = getActiveNotebookEditor(editorService);
if (!editor) {
return;
}
let activeCell = editor.getActiveCell();
if (activeCell) {
return editor.executeNotebookCell(activeCell);
}
}
});
registerAction2(class extends Action2 {
constructor() {
super({
......@@ -183,7 +216,7 @@ registerAction2(class extends Action2 {
let activeCell = editor.getActiveCell();
if (activeCell) {
if (activeCell.cellKind === CellKind.Markdown) {
activeCell.state = CellState.Preview;
activeCell.editState = CellEditState.Preview;
}
editor.focusNotebookCell(activeCell, false);
......@@ -300,73 +333,26 @@ function getActiveNotebookEditor(editorService: IEditorService): INotebookEditor
async function runActiveCell(accessor: ServicesAccessor): Promise<ICellViewModel | undefined> {
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;
}
const activeCell = editor.getActiveCell();
if (!activeCell) {
return;
}
const idx = editor.viewModel?.getViewCellIndex(activeCell);
if (typeof idx !== 'number') {
return;
}
const viewType = notebookProviders[0].id;
await notebookService.executeNotebookActiveCell(viewType, resource);
editor.executeNotebookCell(activeCell);
return activeCell;
}
async function runCell(accessor: ServicesAccessor, context: INotebookCellActionContext): Promise<void> {
const progress = context.cellTemplate?.progressBar;
if (progress) {
progress.infinite().show(500);
}
try {
const editorService = accessor.get(IEditorService);
const notebookService = accessor.get(INotebookService);
const resource = editorService.activeEditor?.resource;
if (!resource) {
async function runCell(context: INotebookCellActionContext): Promise<void> {
if (context.cell.runState === CellRunState.Running) {
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;
await notebookService.executeNotebookActiveCell(viewType, resource);
} finally {
if (progress) {
progress.hide();
}
}
return context.notebookEditor.executeNotebookCell(context.cell);
}
async function changeActiveCellToKind(kind: CellKind, accessor: ServicesAccessor): Promise<void> {
......@@ -464,7 +450,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');
......@@ -488,89 +485,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(
......@@ -581,7 +502,16 @@ 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_MARKDOWN_EDIT_MODE_CONTEXT_KEY, false),
ContextKeyExpr.equals(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, true)),
order: CellToolbarOrder.EditCell
},
icon: { id: 'codicon/pencil' }
});
}
......@@ -597,30 +527,21 @@ 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_MARKDOWN_EDIT_MODE_CONTEXT_KEY, true),
ContextKeyExpr.equals(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, true)),
order: CellToolbarOrder.SaveCell
},
icon: { id: 'codicon/save' }
});
}
......@@ -636,30 +557,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' }
});
}
......@@ -675,26 +585,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<void> {
direction === 'up' ?
context.notebookEditor.moveCellUp(context.cell) :
......@@ -712,7 +602,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)
},
});
}
......@@ -728,34 +629,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)
},
});
}
......@@ -771,30 +661,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(
......
......@@ -5,7 +5,7 @@
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, INotebookEditor, CellFindMatch, CellState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, INotebookEditor, CellFindMatch, CellEditState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { FindDecorations } from 'vs/editor/contrib/find/findDecorations';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { IModelDeltaDecoration } from 'vs/editor/common/model';
......@@ -118,7 +118,7 @@ export class NotebookFindWidget extends SimpleFindReplaceWidget {
}
private revealCellRange(cellIndex: number, matchIndex: number) {
this._findMatches[cellIndex].cell.state = CellState.Editing;
this._findMatches[cellIndex].cell.editState = CellEditState.Editing;
this._notebookEditor.selectElement(this._findMatches[cellIndex].cell);
this._notebookEditor.setCellSelection(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range);
this._notebookEditor.revealRangeInCenterIfOutsideViewport(this._findMatches[cellIndex].cell, this._findMatches[cellIndex].matches[matchIndex].range);
......
......@@ -5,18 +5,18 @@
import { Event } from 'vs/base/common/event';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { IOutput, CellKind, IRenderOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { NotebookViewModel, IModelDecorationsChangeAccessor, CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { FindMatch } from 'vs/editor/common/model';
import { Range } from 'vs/editor/common/core/range';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
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';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { Range } from 'vs/editor/common/core/range';
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, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey<boolean>('notebookFindWidgetFocused', false);
......@@ -69,9 +69,11 @@ export interface ICellViewModel {
handle: number;
uri: URI;
cellKind: CellKind;
state: CellState;
editState: CellEditState;
runState: CellRunState;
focusMode: CellFocusMode;
getText(): string;
metadata: NotebookCellMetadata;
}
export interface INotebookEditor {
......@@ -140,6 +142,11 @@ export interface INotebookEditor {
*/
focusNotebookCell(cell: ICellViewModel, focusEditor: boolean): void;
/**
* Execute the given notebook cell
*/
executeNotebookCell(cell: ICellViewModel): Promise<void>;
/**
* Get current active cell
*/
......@@ -274,7 +281,12 @@ export enum CellRevealPosition {
Center
}
export enum CellState {
export enum CellRunState {
Idle,
Running
}
export enum CellEditState {
/**
* Default state.
* For markdown cell, it's Markdown preview.
......
......@@ -22,13 +22,13 @@ import { contrastBorder, editorBackground, focusBorder, foreground, textBlockQuo
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { EditorOptions, IEditorMemento, IEditorCloseEvent } from 'vs/workbench/common/editor';
import { INotebookEditor, NotebookLayoutInfo, CellState, NOTEBOOK_EDITOR_FOCUSED, CellFocusMode, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditor, NotebookLayoutInfo, CellEditState, NOTEBOOK_EDITOR_FOCUSED, CellFocusMode, ICellViewModel, CellRunState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookEditorInput, NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView';
import { CodeCellRenderer, MarkdownCellRenderer, NotebookCellListDelegate } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer';
import { IOutput, CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IOutput, CellKind, CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview';
import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
......@@ -382,12 +382,6 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
}));
this.localStore.add(this.list!.onDidChangeFocus((e) => {
if (e.elements.length > 0) {
this.notebookService.updateNotebookActiveCell(input.viewType!, input.resource!, e.elements[0].handle);
}
}));
this.list?.splice(0, this.list?.length || 0);
this.list?.splice(0, 0, this.notebookViewModel!.viewCells as CellViewModel[]);
this.list?.layout();
......@@ -562,7 +556,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.list?.setFocus([insertIndex]);
if (type === CellKind.Markdown) {
newCell.state = CellState.Editing;
newCell.editState = CellEditState.Editing;
}
DOM.scheduleAtNextAnimationFrame(() => {
......@@ -600,13 +594,13 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
}
editNotebookCell(cell: CellViewModel): void {
cell.state = CellState.Editing;
cell.editState = CellEditState.Editing;
this.renderedEditors.get(cell)?.focus();
}
saveNotebookCell(cell: ICellViewModel): void {
cell.state = CellState.Preview;
cell.editState = CellEditState.Preview;
}
getActiveCell() {
......@@ -619,6 +613,22 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
return undefined;
}
async executeNotebookCell(cell: ICellViewModel): Promise<void> {
try {
cell.runState = CellRunState.Running;
const provider = this.notebookService.getContributedNotebookProviders(cell.uri)[0];
if (provider) {
const viewType = provider.id;
const notebookUri = CellUri.parse(cell.uri)?.notebook;
if (notebookUri) {
return await this.notebookService.executeNotebookCell(viewType, notebookUri, cell.handle);
}
}
} finally {
cell.runState = CellRunState.Idle;
}
}
focusNotebookCell(cell: ICellViewModel, focusEditor: boolean) {
const index = this.notebookViewModel!.getViewCellIndex(cell);
......@@ -627,7 +637,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.list?.setSelection([index]);
this.list?.focusView();
cell.state = CellState.Editing;
cell.editState = CellEditState.Editing;
cell.focusMode = CellFocusMode.Editor;
this.revealInCenterIfOutsideViewport(cell);
} else {
......@@ -636,7 +646,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
(document.activeElement as HTMLElement).blur();
}
cell.state = CellState.Preview;
cell.editState = CellEditState.Preview;
cell.focusMode = CellFocusMode.Editor;
this.list?.setFocus([index]);
......
......@@ -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();
......
......@@ -26,11 +26,10 @@ export const INotebookService = createDecorator<INotebookService>('notebookServi
export interface IMainNotebookController {
resolveNotebook(viewType: string, uri: URI): Promise<NotebookTextModel | undefined>;
executeNotebook(viewType: string, uri: URI): Promise<void>;
updateNotebookActiveCell(uri: URI, cellHandle: number): void;
createRawCell(uri: URI, index: number, language: string, type: CellKind): Promise<NotebookCellTextModel | undefined>;
deleteCell(uri: URI, index: number): Promise<boolean>
executeNotebookActiveCell(uri: URI): Promise<void>;
onDidReceiveMessage(uri: URI, message: any): void;
executeNotebookCell(uri: URI, handle: number): Promise<void>;
destoryNotebookDocument(notebook: INotebookTextModel): Promise<void>;
save(uri: URI): Promise<boolean>;
}
......@@ -46,10 +45,10 @@ export interface INotebookService {
getRendererInfo(handle: number): INotebookRendererInfo | undefined;
resolveNotebook(viewType: string, uri: URI): Promise<NotebookTextModel | undefined>;
executeNotebook(viewType: string, uri: URI): Promise<void>;
executeNotebookActiveCell(viewType: string, uri: URI): Promise<void>;
executeNotebookCell(viewType: string, uri: URI, handle: number): Promise<void>;
getContributedNotebookProviders(resource: URI): readonly NotebookProviderInfo[];
getNotebookProviderResourceRoots(): URI[];
updateNotebookActiveCell(viewType: string, resource: URI, cellHandle: number): void;
createNotebookCell(viewType: string, resource: URI, index: number, language: string, type: CellKind): Promise<ICell | undefined>;
deleteNotebookCell(viewType: string, resource: URI, index: number): Promise<boolean>;
destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void;
......@@ -242,14 +241,6 @@ export class NotebookService extends Disposable implements INotebookService {
return modelData.model;
}
updateNotebookActiveCell(viewType: string, resource: URI, cellHandle: number): void {
let provider = this._notebookProviders.get(viewType);
if (provider) {
provider.controller.updateNotebookActiveCell(resource, cellHandle);
}
}
async createNotebookCell(viewType: string, resource: URI, index: number, language: string, type: CellKind): Promise<NotebookCellTextModel | undefined> {
let provider = this._notebookProviders.get(viewType);
......@@ -280,11 +271,10 @@ export class NotebookService extends Disposable implements INotebookService {
return;
}
async executeNotebookActiveCell(viewType: string, uri: URI): Promise<void> {
let provider = this._notebookProviders.get(viewType);
async executeNotebookCell(viewType: string, uri: URI, handle: number): Promise<void> {
const provider = this._notebookProviders.get(viewType);
if (provider) {
await provider.controller.executeNotebookActiveCell(uri);
await provider.controller.executeNotebookCell(uri, handle);
}
}
......
......@@ -3,20 +3,19 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDisposable } from 'vs/base/common/lifecycle';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
import { IAction } from 'vs/base/common/actions';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
export class CellMenus implements IDisposable {
export class CellMenus {
constructor(
@IMenuService private readonly menuService: IMenuService,
@IContextMenuService private readonly contextMenuService: IContextMenuService
) { }
getCellTitleActions(contextKeyService: IContextKeyService): IMenu {
getCellTitleMenu(contextKeyService: IContextKeyService): IMenu {
return this.getMenu(MenuId.NotebookCellTitle, contextKeyService);
}
......@@ -31,8 +30,4 @@ export class CellMenus implements IDisposable {
return menu;
}
dispose(): void {
}
}
......@@ -16,24 +16,24 @@ 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 { MenuItemAction, IMenu } 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 } 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, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY } from 'vs/workbench/contrib/notebook/browser/constants';
import { CellRenderTemplate, CellRunState, ICellViewModel, INotebookEditor, CellEditState } 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.$;
......@@ -116,42 +116,38 @@ abstract class AbstractCellRenderer {
return toolbar;
}
protected createMenu(): CellMenus {
const menu = this.instantiationService.createInstance(CellMenus);
return menu;
private getCellToolbarActions(menu: IMenu): IAction[] {
const actions: IAction[] = [];
for (let [, menuActions] of menu.getActions({ shouldForwardArgs: true })) {
actions.push(...menuActions);
}
abstract getCellToolbarActions(element: CellViewModel): IAction[];
return actions;
}
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)
]);
protected setupCellToolbarActions(scopedContextKeyService: IContextKeyService, templateData: CellRenderTemplate, disposables: DisposableStore): void {
const cellMenu = this.instantiationService.createInstance(CellMenus);
const menu = disposables.add(cellMenu.getCellTitleMenu(scopedContextKeyService));
this.contextMenuService.showContextMenu({
getAnchor: () => {
return {
x,
y
};
},
getActions: () => actions,
getActionsContext: () => <INotebookCellActionContext>{
cell: element,
notebookEditor: this.notebookEditor
},
autoSelectFirstItem: false
});
const updateActions = () => {
const actions = this.getCellToolbarActions(menu);
templateData.toolbar.setActions(actions)();
if (templateData.focusIndicator) {
if (actions.length) {
templateData.focusIndicator.style.top = `24px`;
} else {
templateData.focusIndicator.style.top = `8px`;
}
}
};
abstract getAdditionalContextMenuActions(): IAction[];
updateActions();
disposables.add(menu.onDidChange(() => {
updateActions();
}));
}
}
export class MarkdownCellRenderer extends AbstractCellRenderer implements IListRenderer<MarkdownCellViewModel, CellRenderTemplate> {
......@@ -165,7 +161,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');
}
......@@ -213,22 +209,20 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
if (!this.disposables.has(element)) {
this.disposables.set(element, new DisposableStore());
}
let elementDisposable = this.disposables.get(element);
const elementDisposable = this.disposables.get(element)!;
elementDisposable!.add(new StatefullMarkdownCell(this.notebookEditor, element, templateData, this.editorOptions, this.instantiationService));
elementDisposable.add(new StatefullMarkdownCell(this.notebookEditor, element, templateData, this.editorOptions, this.instantiationService));
const contextKeyService = this.contextKeyService.createScoped(templateData.container);
contextKeyService.createKey(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'markdown');
const toolbarActions = this.getCellToolbarActions(element);
templateData.toolbar!.setActions(toolbarActions)();
contextKeyService.createKey(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, element.metadata.editable);
contextKeyService.createKey(NOTEBOOK_EDITABLE_CONTEXT_KEY, this.notebookEditor.viewModel?.metadata?.editable);
const editModeKey = contextKeyService.createKey(NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY, element.editState === CellEditState.Editing);
elementDisposable.add(element.onDidChangeCellEditState(() => {
editModeKey.set(element.editState === CellEditState.Editing);
}));
if (templateData.focusIndicator) {
if (!toolbarActions.length) {
templateData.focusIndicator.style.top = `8px`;
} else {
templateData.focusIndicator.style.top = `24px`;
}
}
this.setupCellToolbarActions(contextKeyService, templateData, elementDisposable);
}
templateData.toolbar!.context = <INotebookCellActionContext>{
......@@ -238,51 +232,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 +256,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 +268,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'));
......@@ -382,15 +325,23 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
this.disposables.set(element, new DisposableStore());
}
const elementDisposable = this.disposables.get(element);
const elementDisposable = this.disposables.get(element)!;
elementDisposable?.add(this.instantiationService.createInstance(CodeCell, this.notebookEditor, element, templateData));
elementDisposable.add(this.instantiationService.createInstance(CodeCell, this.notebookEditor, element, templateData));
this.renderedEditors.set(element, templateData.editor);
elementDisposable?.add(element.onDidChangeLayout(() => {
elementDisposable.add(element.onDidChangeLayout(() => {
templateData.focusIndicator!.style.height = `${element.layoutInfo.indicatorHeight}px`;
}));
elementDisposable.add(element.onDidChangeCellRunState(() => {
if (element.runState === CellRunState.Running) {
templateData.progressBar?.infinite().show(500);
} else {
templateData.progressBar?.hide();
}
}));
const toolbarContext = <INotebookCellActionContext>{
cell: element,
cellTemplate: templateData,
......@@ -400,51 +351,12 @@ 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);
templateData.toolbar!.setActions(toolbarActions)();
templateData.toolbar!.context = toolbarContext;
templateData.runToolbar!.context = toolbarContext;
contextKeyService.createKey(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, element.metadata.editable);
contextKeyService.createKey(NOTEBOOK_EDITABLE_CONTEXT_KEY, this.notebookEditor.viewModel?.metadata?.editable);
if (templateData.focusIndicator) {
if (!toolbarActions.length) {
templateData.focusIndicator.style.top = `8px`;
} else {
templateData.focusIndicator.style.top = `24px`;
}
}
}
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 [];
this.setupCellToolbarActions(contextKeyService, templateData, elementDisposable);
templateData.toolbar.context = toolbarContext;
templateData.runToolbar!.context = toolbarContext;
}
disposeTemplate(templateData: CellRenderTemplate): void {
......
......@@ -8,7 +8,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/sizeObserver';
import { INotebookEditor, CellRenderTemplate, CellFocusMode, CellState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditor, CellRenderTemplate, CellFocusMode, CellEditState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { raceCancellation } from 'vs/base/common/async';
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
......@@ -36,7 +36,7 @@ export class StatefullMarkdownCell extends Disposable {
this._register(this.localDisposables);
const viewUpdate = () => {
if (viewCell.state === CellState.Editing) {
if (viewCell.editState === CellEditState.Editing) {
// switch to editing mode
let width = viewCell.layoutInfo.editorWidth;
const lineNum = viewCell.lineCount;
......@@ -99,7 +99,7 @@ export class StatefullMarkdownCell extends Disposable {
notebookEditor.layoutNotebookCell(viewCell, this.editor!.getContentHeight() + 32 + clientHeight);
}));
if (viewCell.state === CellState.Editing) {
if (viewCell.editState === CellEditState.Editing) {
this.editor!.focus();
}
});
......@@ -190,7 +190,7 @@ export class StatefullMarkdownCell extends Disposable {
}
};
this._register(viewCell.onDidChangeCellState(() => {
this._register(viewCell.onDidChangeCellEditState(() => {
this.localDisposables.clear();
viewUpdate();
}));
......
......@@ -10,15 +10,17 @@ import * as editorCommon from 'vs/editor/common/editorCommon';
import * as model from 'vs/editor/common/model';
import { Range } from 'vs/editor/common/core/range';
import { ICell } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellState, CursorAtBoundary, CellFocusMode } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CursorAtBoundary, CellFocusMode, CellEditState, CellRunState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { EDITOR_TOP_PADDING, EDITOR_TOOLBAR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants';
import { SearchParams } from 'vs/editor/common/model/textModelSearch';
export abstract class BaseCellViewModel extends Disposable {
protected readonly _onDidDispose = new Emitter<void>();
readonly onDidDispose = this._onDidDispose.event;
protected readonly _onDidChangeCellState = new Emitter<void>();
readonly onDidChangeCellState = this._onDidChangeCellState.event;
protected readonly _onDidChangeCellEditState = new Emitter<void>();
readonly onDidChangeCellEditState = this._onDidChangeCellEditState.event;
protected readonly _onDidChangeCellRunState = new Emitter<void>();
readonly onDidChangeCellRunState = this._onDidChangeCellRunState.event;
protected readonly _onDidChangeFocusMode = new Emitter<void>();
readonly onDidChangeFocusMode = this._onDidChangeFocusMode.event;
protected readonly _onDidChangeEditorAttachState = new Emitter<boolean>();
......@@ -37,16 +39,34 @@ export abstract class BaseCellViewModel extends Disposable {
get metadata() {
return this.cell.metadata;
}
private _state: CellState = CellState.Preview;
get state(): CellState {
return this._state;
private _editState: CellEditState = CellEditState.Preview;
get editState(): CellEditState {
return this._editState;
}
set state(newState: CellState) {
if (newState === this._state) {
set editState(newState: CellEditState) {
if (newState === this._editState) {
return;
}
this._state = newState;
this._onDidChangeCellState.fire();
this._editState = newState;
this._onDidChangeCellEditState.fire();
}
private _runState: CellRunState = CellRunState.Idle;
get runState(): CellRunState {
return this._runState;
}
set runState(newState: CellRunState) {
if (newState === this._runState) {
return;
}
this._runState = newState;
this._onDidChangeCellRunState.fire();
}
private _focusMode: CellFocusMode = CellFocusMode.Container;
get focusMode() {
......
......@@ -9,7 +9,7 @@ import * as model from 'vs/editor/common/model';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer';
import { EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING, CELL_MARGIN, RUN_BUTTON_WIDTH } from 'vs/workbench/contrib/notebook/browser/constants';
import { CellState, ICellViewModel, CellFindMatch, NotebookViewLayoutAccessor, CodeCellLayoutChangeEvent, CodeCellLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellEditState, ICellViewModel, CellFindMatch, CodeCellLayoutChangeEvent, CodeCellLayoutInfo, NotebookViewLayoutAccessor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellKind, ICell, NotebookCellOutputsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { BaseCellViewModel } from './baseCellViewModel';
......@@ -137,7 +137,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
}
save() {
if (this._textModel && !this._textModel.isDisposed() && this.state === CellState.Editing) {
if (this._textModel && !this._textModel.isDisposed() && this.editState === CellEditState.Editing) {
let cnt = this._textModel.getLineCount();
this.cell.source = this._textModel.getLinesContent().map((str, index) => str + (index !== cnt - 1 ? '\n' : ''));
}
......@@ -159,7 +159,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
}
onDeselect() {
this.state = CellState.Preview;
this.editState = CellEditState.Preview;
}
updateOutputHeight(index: number, height: number) {
......
......@@ -8,7 +8,7 @@ import * as UUID from 'vs/base/common/uuid';
import * as model from 'vs/editor/common/model';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { CellState, ICellViewModel, CellFindMatch, NotebookViewLayoutAccessor, MarkdownCellLayoutInfo, MarkdownCellLayoutChangeEvent } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { ICellViewModel, CellFindMatch, NotebookViewLayoutAccessor, MarkdownCellLayoutInfo, MarkdownCellLayoutChangeEvent, CellEditState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { MarkdownRenderer } from 'vs/workbench/contrib/notebook/browser/view/renderers/mdRenderer';
import { BaseCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel';
import { CellKind, ICell } from 'vs/workbench/contrib/notebook/common/notebookCommon';
......@@ -77,7 +77,7 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
}
save() {
if (this._textModel && !this._textModel.isDisposed() && this.state === CellState.Editing) {
if (this._textModel && !this._textModel.isDisposed() && this.editState === CellEditState.Editing) {
let cnt = this._textModel.getLineCount();
this.cell.source = this._textModel.getLinesContent().map((str, index) => str + (index !== cnt - 1 ? '\n' : ''));
}
......@@ -111,7 +111,7 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie
}
onDeselect() {
this.state = CellState.Preview;
this.editState = CellEditState.Preview;
}
getMarkdownRenderer() {
......
......@@ -14,7 +14,7 @@ import { IModelDeltaDecoration } from 'vs/editor/common/model';
import { WorkspaceTextEdit } from 'vs/editor/common/modes';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { CellFindMatch, CellState, ICellViewModel, NotebookLayoutInfo, NotebookLayoutChangeEvent, NotebookViewLayoutAccessor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellFindMatch, CellEditState, ICellViewModel, NotebookLayoutChangeEvent, NotebookViewLayoutAccessor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
import { DeleteCellEdit, InsertCellEdit, MoveCellEdit } from 'vs/workbench/contrib/notebook/browser/viewModel/cellEdit';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
......@@ -137,7 +137,7 @@ export class NotebookViewModel extends Disposable implements NotebookViewLayoutA
hide() {
this._viewCells.forEach(cell => {
if (cell.getText() !== '') {
cell.state = CellState.Preview;
cell.editState = CellEditState.Preview;
}
});
}
......@@ -218,7 +218,7 @@ export class NotebookViewModel extends Disposable implements NotebookViewLayoutA
saveEditorViewState(): INotebookEditorViewState {
const state: { [key: number]: boolean } = {};
this._viewCells.filter(cell => cell.state === CellState.Editing).forEach(cell => state[cell.cell.handle] = true);
this._viewCells.filter(cell => cell.editState === CellEditState.Editing).forEach(cell => state[cell.cell.handle] = true);
const editorViewStates: { [key: number]: editorCommon.ICodeEditorViewState } = {};
this._viewCells.map(cell => ({ handle: cell.cell.handle, state: cell.saveEditorViewState() })).forEach(viewState => {
if (viewState.state) {
......@@ -241,7 +241,7 @@ export class NotebookViewModel extends Disposable implements NotebookViewLayoutA
const isEditing = viewState.editingCells && viewState.editingCells[cell.handle];
const editorViewState = viewState.editorViewStates && viewState.editorViewStates[cell.handle];
cell.state = isEditing ? CellState.Editing : CellState.Preview;
cell.editState = isEditing ? CellEditState.Editing : CellEditState.Preview;
cell.restoreEditorViewState(editorViewState);
});
}
......
......@@ -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
) {
this._outputs = outputs;
}
......
......@@ -19,7 +19,6 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
private _mapping: Map<number, NotebookCellTextModel> = new Map();
private _cellListeners: Map<number, IDisposable> = new Map();
cells: NotebookCellTextModel[];
activeCell: NotebookCellTextModel | undefined;
languages: string[] = [];
metadata: NotebookDocumentMetadata | undefined = undefined;
renderers = new Set<number>();
......@@ -47,10 +46,6 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
});
}
updateActiveCell(handle: number) {
this.activeCell = this._mapping.get(handle);
}
insertNewCell(index: number, cell: NotebookCellTextModel): void {
this._mapping.set(cell.handle, cell);
this.cells.splice(index, 0, cell);
......@@ -77,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();
......
......@@ -130,7 +130,7 @@ export interface ICell {
language: string;
cellKind: CellKind;
outputs: IOutput[];
metadata?: NotebookCellMetadata;
metadata: NotebookCellMetadata;
onDidChangeOutputs?: Event<NotebookCellOutputsSplice[]>;
resolveTextBufferFactory(): PieceTreeTextBufferFactory;
// TODO@rebornix it should be later on replaced by moving textmodel resolution into CellTextModel
......
......@@ -33,10 +33,13 @@ 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) => {
assert.equal(viewModel.viewCells[0].metadata.editable, true);
assert.equal(viewModel.viewCells[1].metadata.editable, false);
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);
......@@ -56,8 +59,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];
......
......@@ -6,11 +6,11 @@
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';
import { INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditor, NotebookLayoutInfo, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
......@@ -26,6 +26,11 @@ export class TestCell implements ICell {
onDidChangeOutputs: Event<NotebookCellOutputsSplice[]> = this._onDidChangeOutputs.event;
private _isDirty: boolean = false;
private _outputs: IOutput[];
get metadata(): NotebookCellMetadata {
return { editable: true };
}
get outputs(): IOutput[] {
return this._outputs;
}
......@@ -68,6 +73,10 @@ export class TestNotebookEditor implements INotebookEditor {
constructor(
) { }
executeNotebookCell(cell: ICellViewModel): Promise<void> {
throw new Error('Method not implemented.');
}
isNotebookEditor = true;
postMessage(message: any): void {
......@@ -183,12 +192,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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册