From e5ebccc65e3c07a5af169af8e71cce388202e1d7 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 6 Mar 2020 13:53:59 -0800 Subject: [PATCH] better folder organization --- src/vs/editor/contrib/find/findDecorations.ts | 4 +- .../browser/{ => contrib}/notebookActions.ts | 0 .../{ => contrib}/notebookFindWidget.ts | 61 +++++++----- .../notebook/browser/notebook.contribution.ts | 10 +- .../notebook/browser/notebookBrowser.ts | 22 ++++- .../notebook/browser/notebookEditor.ts | 32 ++++-- .../notebook/browser/{ => view}/notebook.css | 0 .../browser/{ => view}/notebookCellList.ts | 0 .../{ => view}/output/outputRenderer.ts | 0 .../output/transforms/errorTransform.ts | 0 .../output/transforms/richTransform.ts | 0 .../output/transforms/streamTransform.ts | 0 .../{ => view}/renderers/backLayerWebView.ts | 2 +- .../{ => view}/renderers/cellRenderer.ts | 6 +- .../browser/{ => view}/renderers/codeCell.ts | 4 +- .../{ => view}/renderers/markdownCell.ts | 4 +- .../{ => view}/renderers/mdRenderer.ts | 0 .../{ => view}/renderers/sizeObserver.ts | 0 .../notebookCellViewModel.ts} | 31 ++++-- .../{ => viewModel}/notebookViewModel.ts | 97 ++++++++++++++++++- .../notebook/test/notebookViewModel.test.ts | 2 +- .../notebook/test/testNotebookEditor.ts | 14 ++- 22 files changed, 225 insertions(+), 64 deletions(-) rename src/vs/workbench/contrib/notebook/browser/{ => contrib}/notebookActions.ts (100%) rename src/vs/workbench/contrib/notebook/browser/{ => contrib}/notebookFindWidget.ts (54%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/notebook.css (100%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/notebookCellList.ts (100%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/output/outputRenderer.ts (100%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/output/transforms/errorTransform.ts (100%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/output/transforms/richTransform.ts (100%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/output/transforms/streamTransform.ts (100%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/renderers/backLayerWebView.ts (99%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/renderers/cellRenderer.ts (98%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/renderers/codeCell.ts (99%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/renderers/markdownCell.ts (98%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/renderers/mdRenderer.ts (100%) rename src/vs/workbench/contrib/notebook/browser/{ => view}/renderers/sizeObserver.ts (100%) rename src/vs/workbench/contrib/notebook/browser/{renderers/cellViewModel.ts => viewModel/notebookCellViewModel.ts} (91%) rename src/vs/workbench/contrib/notebook/browser/{ => viewModel}/notebookViewModel.ts (58%) diff --git a/src/vs/editor/contrib/find/findDecorations.ts b/src/vs/editor/contrib/find/findDecorations.ts index ee93bccc3cf..52367aaeadc 100644 --- a/src/vs/editor/contrib/find/findDecorations.ts +++ b/src/vs/editor/contrib/find/findDecorations.ts @@ -276,7 +276,7 @@ export class FindDecorations implements IDisposable { } }); - private static readonly _FIND_MATCH_DECORATION = ModelDecorationOptions.register({ + public static readonly _FIND_MATCH_DECORATION = ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'findMatch', showIfCollapsed: true, @@ -290,7 +290,7 @@ export class FindDecorations implements IDisposable { } }); - private static readonly _FIND_MATCH_NO_OVERVIEW_DECORATION = ModelDecorationOptions.register({ + public static readonly _FIND_MATCH_NO_OVERVIEW_DECORATION = ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'findMatch', showIfCollapsed: true diff --git a/src/vs/workbench/contrib/notebook/browser/notebookActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts similarity index 100% rename from src/vs/workbench/contrib/notebook/browser/notebookActions.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts diff --git a/src/vs/workbench/contrib/notebook/browser/notebookFindWidget.ts b/src/vs/workbench/contrib/notebook/browser/contrib/notebookFindWidget.ts similarity index 54% rename from src/vs/workbench/contrib/notebook/browser/notebookFindWidget.ts rename to src/vs/workbench/contrib/notebook/browser/contrib/notebookFindWidget.ts index c9620c34143..296756fa37b 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookFindWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/notebookFindWidget.ts @@ -6,30 +6,20 @@ import { SimpleFindWidget } from 'vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/renderers/cellViewModel'; -import { FindMatch } from 'vs/editor/common/model'; - -export interface CellFindMatch { - cell: CellViewModel, - match: FindMatch -} - -export interface NotebookFindDelegate { - startFind(value: string): CellFindMatch[]; - stopFind(keepSelection?: boolean): void; - focus(): void; - focusNext(nextMatch: CellFindMatch): void; -} - +import { KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED, INotebookEditor, CellFindMatch, NotebookFindDelegate } 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'; +import { ICellModelDeltaDecorations, ICellModelDecorations } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; export class NotebookFindWidget extends SimpleFindWidget { protected _findWidgetFocused: IContextKey; private _findMatches: CellFindMatch[] = []; private _currentMatch: CellFindMatch | null = null; + private _decorations: ICellModelDecorations[] = []; constructor( - private readonly _delegate: NotebookFindDelegate, + private readonly _notebookEditor: INotebookEditor & NotebookFindDelegate, @IContextViewService contextViewService: IContextViewService, @IContextKeyService contextKeyService: IContextKeyService ) { @@ -40,16 +30,18 @@ export class NotebookFindWidget extends SimpleFindWidget { protected onInputChanged(): boolean { const val = this.inputValue; if (val) { - this._findMatches = this._delegate.startFind(val); + this._findMatches = this._notebookEditor.startFind(val); if (this._findMatches.length) { this._currentMatch = this._findMatches[0]; + this.set(this._findMatches); return true; } else { this._currentMatch = null; return false; } } else { - this._delegate.stopFind(false); + this.set([]); + this._notebookEditor.stopFind(false); } return false; } @@ -62,7 +54,7 @@ export class NotebookFindWidget extends SimpleFindWidget { let nextIndex = previous ? (index - 1 + len) % len : index + 1 % len; let nextMatch = this._findMatches[nextIndex]; - this._delegate.focusNext(nextMatch); + this._notebookEditor.focusNext(nextMatch); this._currentMatch = nextMatch; } @@ -71,8 +63,9 @@ export class NotebookFindWidget extends SimpleFindWidget { public hide() { super.hide(); - this._delegate.stopFind(true); - this._delegate.focus(); + this.set([]); + this._notebookEditor.stopFind(true); + this._notebookEditor.focus(); } protected findFirst(): void { } @@ -88,4 +81,28 @@ export class NotebookFindWidget extends SimpleFindWidget { protected onFindInputFocusTrackerFocus(): void { } protected onFindInputFocusTrackerBlur(): void { } + public set(cellFindMatches: CellFindMatch[]): void { + + this._notebookEditor.changeDecorations((accessor) => { + + let findMatchesOptions: ModelDecorationOptions = FindDecorations._FIND_MATCH_DECORATION; + + let deltaDecorations: ICellModelDeltaDecorations[] = cellFindMatches.map(cellFindMatch => { + const findMatches = cellFindMatch.matches; + + // Find matches + let newFindMatchesDecorations: IModelDeltaDecoration[] = new Array(findMatches.length); + for (let i = 0, len = findMatches.length; i < len; i++) { + newFindMatchesDecorations[i] = { + range: findMatches[i].range, + options: findMatchesOptions + }; + } + + return { ownerId: cellFindMatch.cell.handle, decorations: newFindMatchesDecorations }; + }); + + this._decorations = accessor.deltaDecorations(this._decorations, deltaDecorations); + }); + } } diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts index c8d96c3ce37..3340a92fbef 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebook.contribution.ts @@ -27,16 +27,16 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { assertType } from 'vs/base/common/types'; import { parse } from 'vs/base/common/marshalling'; +import { parseCellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon'; // Output renderers registration -import 'vs/workbench/contrib/notebook/browser/output/transforms/streamTransform'; -import 'vs/workbench/contrib/notebook/browser/output/transforms/errorTransform'; -import 'vs/workbench/contrib/notebook/browser/output/transforms/richTransform'; +import 'vs/workbench/contrib/notebook/browser/view/output/transforms/streamTransform'; +import 'vs/workbench/contrib/notebook/browser/view/output/transforms/errorTransform'; +import 'vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform'; // Actions -import 'vs/workbench/contrib/notebook/browser/notebookActions'; -import { parseCellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import 'vs/workbench/contrib/notebook/browser/contrib/notebookActions'; Registry.as(EditorExtensions.Editors).registerEditor( EditorDescriptor.create( diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 8d9edaa121b..b004fe1f326 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -7,15 +7,18 @@ import * as DOM from 'vs/base/browser/dom'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; -import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/renderers/cellViewModel'; -import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/output/outputRenderer'; +import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel'; +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 } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; +import { FindMatch } from 'vs/editor/common/model'; export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey('notebookFindWidgetFocused', false); export interface INotebookEditor { viewType: string | undefined; + viewModel: NotebookViewModel | undefined; insertEmptyNotebookCell(cell: CellViewModel, type: CellKind, direction: 'above' | 'below'): Promise; deleteNotebookCell(cell: CellViewModel): void; editNotebookCell(cell: CellViewModel): void; @@ -29,6 +32,7 @@ export interface INotebookEditor { getFontInfo(): BareFontInfo | undefined; getListDimension(): DOM.Dimension | null; getOutputRenderer(): OutputRenderer; + changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any; } export interface CellRenderTemplate { @@ -48,3 +52,17 @@ export interface IOutputTransformContribution { render(output: IOutput, container: HTMLElement, preferredMimeType: string | undefined): IRenderOutput; } + +export interface CellFindMatch { + cell: CellViewModel; + matches: FindMatch[]; +} + + +export interface NotebookFindDelegate { + startFind(value: string): CellFindMatch[]; + stopFind(keepSelection?: boolean): void; + focus(): void; + focusNext(nextMatch: CellFindMatch): void; +} + diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index 3474e9a619d..9115435c2fd 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -21,13 +21,12 @@ 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, ICompositeCodeEditor, IEditorCloseEvent } from 'vs/workbench/common/editor'; -import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { INotebookEditor, NotebookFindDelegate, CellFindMatch } 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/output/outputRenderer'; -import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/renderers/backLayerWebView'; -import { CodeCellRenderer, MarkdownCellRenderer, NotebookCellListDelegate } from 'vs/workbench/contrib/notebook/browser/renderers/cellRenderer'; -import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/renderers/cellViewModel'; +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 { CELL_MARGIN, NotebookCellsSplice, IOutput, parseCellUri, CellKind } 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'; @@ -36,10 +35,11 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IEditor } from 'vs/editor/common/editorCommon'; import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; import { Emitter, Event } from 'vs/base/common/event'; -import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/notebookCellList'; -import { NotebookFindWidget, NotebookFindDelegate, CellFindMatch } from 'vs/workbench/contrib/notebook/browser/notebookFindWidget'; -import { NotebookViewModel, INotebookEditorViewState } from 'vs/workbench/contrib/notebook/browser/notebookViewModel'; +import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList'; +import { NotebookFindWidget } from 'vs/workbench/contrib/notebook/browser/contrib/notebookFindWidget'; +import { NotebookViewModel, INotebookEditorViewState, IModelDecorationsChangeAccessor } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; +import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel'; const $ = DOM.$; const NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'NotebookEditorViewState'; @@ -144,6 +144,10 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor, Noteb this.findWidget.updateTheme(this.themeService.getColorTheme()); } + get viewModel() { + return this.notebookViewModel; + } + get minimumWidth(): number { return 375; } get maximumWidth(): number { return Number.POSITIVE_INFINITY; } @@ -403,12 +407,22 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor, Noteb //#endregion + //#region Decorations + + changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any { + return this.notebookViewModel?.changeDecorations(callback); + } + + //#endregion + //#region Find Delegate startFind(value: string): CellFindMatch[] { let matches: CellFindMatch[] = []; this.notebookViewModel!.viewCells.forEach(cell => { let cellMatches = cell.startFind(value); - matches.push(...cellMatches); + if (cellMatches) { + matches.push(cellMatches); + } }); return matches; diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.css b/src/vs/workbench/contrib/notebook/browser/view/notebook.css similarity index 100% rename from src/vs/workbench/contrib/notebook/browser/notebook.css rename to src/vs/workbench/contrib/notebook/browser/view/notebook.css diff --git a/src/vs/workbench/contrib/notebook/browser/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts similarity index 100% rename from src/vs/workbench/contrib/notebook/browser/notebookCellList.ts rename to src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts diff --git a/src/vs/workbench/contrib/notebook/browser/output/outputRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts similarity index 100% rename from src/vs/workbench/contrib/notebook/browser/output/outputRenderer.ts rename to src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts diff --git a/src/vs/workbench/contrib/notebook/browser/output/transforms/errorTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/errorTransform.ts similarity index 100% rename from src/vs/workbench/contrib/notebook/browser/output/transforms/errorTransform.ts rename to src/vs/workbench/contrib/notebook/browser/view/output/transforms/errorTransform.ts diff --git a/src/vs/workbench/contrib/notebook/browser/output/transforms/richTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts similarity index 100% rename from src/vs/workbench/contrib/notebook/browser/output/transforms/richTransform.ts rename to src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts diff --git a/src/vs/workbench/contrib/notebook/browser/output/transforms/streamTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/streamTransform.ts similarity index 100% rename from src/vs/workbench/contrib/notebook/browser/output/transforms/streamTransform.ts rename to src/vs/workbench/contrib/notebook/browser/view/output/transforms/streamTransform.ts diff --git a/src/vs/workbench/contrib/notebook/browser/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts similarity index 99% rename from src/vs/workbench/contrib/notebook/browser/renderers/backLayerWebView.ts rename to src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 877ba6e508b..78bc295ab14 100644 --- a/src/vs/workbench/contrib/notebook/browser/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -11,7 +11,7 @@ import * as UUID from 'vs/base/common/uuid'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService'; -import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/renderers/cellViewModel'; +import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel'; import { CELL_MARGIN, IOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewResourceScheme } from 'vs/workbench/contrib/webview/common/resourceLoader'; diff --git a/src/vs/workbench/contrib/notebook/browser/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts similarity index 98% rename from src/vs/workbench/contrib/notebook/browser/renderers/cellRenderer.ts rename to src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index a0b56ac3e24..f98fb2b7270 100644 --- a/src/vs/workbench/contrib/notebook/browser/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -17,9 +17,9 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CellRenderTemplate, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CodeCell } from 'vs/workbench/contrib/notebook/browser/renderers/codeCell'; -import { StatefullMarkdownCell } from 'vs/workbench/contrib/notebook/browser/renderers/markdownCell'; -import { CellViewModel } from './cellViewModel'; +import { CodeCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/codeCell'; +import { StatefullMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell'; +import { CellViewModel } from '../../viewModel/notebookCellViewModel'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING, CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; diff --git a/src/vs/workbench/contrib/notebook/browser/renderers/codeCell.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts similarity index 99% rename from src/vs/workbench/contrib/notebook/browser/renderers/codeCell.ts rename to src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts index 7bf886c19af..e98bafd4548 100644 --- a/src/vs/workbench/contrib/notebook/browser/renderers/codeCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts @@ -6,8 +6,8 @@ import * as nls from 'vs/nls'; import * as DOM from 'vs/base/browser/dom'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/renderers/cellViewModel'; -import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/renderers/sizeObserver'; +import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel'; +import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/sizeObserver'; import { CELL_MARGIN, IOutput, EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING, ITransformedDisplayOutputDto, IRenderOutput, CellOutputKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CellRenderTemplate, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { raceCancellation } from 'vs/base/common/async'; diff --git a/src/vs/workbench/contrib/notebook/browser/renderers/markdownCell.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts similarity index 98% rename from src/vs/workbench/contrib/notebook/browser/renderers/markdownCell.ts rename to src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts index c038e1cc5a9..c8a55f8ac51 100644 --- a/src/vs/workbench/contrib/notebook/browser/renderers/markdownCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/markdownCell.ts @@ -5,10 +5,10 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/renderers/cellViewModel'; +import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/renderers/sizeObserver'; +import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/sizeObserver'; import { CELL_MARGIN, EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookEditor, CellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; diff --git a/src/vs/workbench/contrib/notebook/browser/renderers/mdRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/mdRenderer.ts similarity index 100% rename from src/vs/workbench/contrib/notebook/browser/renderers/mdRenderer.ts rename to src/vs/workbench/contrib/notebook/browser/view/renderers/mdRenderer.ts diff --git a/src/vs/workbench/contrib/notebook/browser/renderers/sizeObserver.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/sizeObserver.ts similarity index 100% rename from src/vs/workbench/contrib/notebook/browser/renderers/sizeObserver.ts rename to src/vs/workbench/contrib/notebook/browser/view/renderers/sizeObserver.ts diff --git a/src/vs/workbench/contrib/notebook/browser/renderers/cellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel.ts similarity index 91% rename from src/vs/workbench/contrib/notebook/browser/renderers/cellViewModel.ts rename to src/vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel.ts index 9b6b80453f8..289c572b6e7 100644 --- a/src/vs/workbench/contrib/notebook/browser/renderers/cellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel.ts @@ -14,9 +14,9 @@ import { SearchParams } from 'vs/editor/common/model/textModelSearch'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { CellFindMatch } from 'vs/workbench/contrib/notebook/browser/notebookFindWidget'; -import { MarkdownRenderer } from 'vs/workbench/contrib/notebook/browser/renderers/mdRenderer'; +import { MarkdownRenderer } from 'vs/workbench/contrib/notebook/browser/view/renderers/mdRenderer'; import { CellKind, EDITOR_BOTTOM_PADDING, EDITOR_TOP_PADDING, ICell, IOutput, NotebookCellOutputsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellFindMatch } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; export class CellViewModel extends Disposable { @@ -78,6 +78,7 @@ export class CellViewModel extends Disposable { private _textEditor?: ICodeEditor; private _buffer: model.ITextBuffer | null; private _editorViewStates: editorCommon.ICodeEditorViewState | null; + private _initialDecorations: { oldDecorations: string[], newDecorations: model.IModelDeltaDecoration[] } | null = null; readonly id: string = UUID.generateUuid(); @@ -120,7 +121,7 @@ export class CellViewModel extends Disposable { private readonly _hasFindResult = this._register(new Emitter()); public readonly hasFindResult: Event = this._hasFindResult.event; - startFind(value: string): CellFindMatch[] { + startFind(value: string): CellFindMatch | null { let cellMatches: model.FindMatch[] = []; if (this.assertTextModelAttached()) { cellMatches = this._textModel!.findMatches(value, false, false, false, null, false); @@ -135,16 +136,16 @@ export class CellViewModel extends Disposable { const searchData = searchParams.parseSearchRequest(); if (!searchData) { - return []; + return null; } cellMatches = this._buffer.findMatchesLineByLine(fullRange, searchData, false, 1000); } - return cellMatches.map(match => ({ + return { cell: this, - match: match - })); + matches: cellMatches + }; } stopFind(keepSelection?: boolean | undefined): void { @@ -259,6 +260,11 @@ export class CellViewModel extends Disposable { if (this._editorViewStates) { this.restoreViewState(this._editorViewStates); } + + if (this._initialDecorations) { + this._textEditor.deltaDecorations(this._initialDecorations.oldDecorations, this._initialDecorations.newDecorations); + this._initialDecorations = null; + } } detachTextEditor() { @@ -266,6 +272,17 @@ export class CellViewModel extends Disposable { this._textEditor = undefined; } + deltaDecorations(oldDecorations: string[], newDecorations: model.IModelDeltaDecoration[]): string[] { + if (!this._textEditor) { + this._initialDecorations = { oldDecorations, newDecorations }; + return []; + } + + this._initialDecorations = null; + // how do we make sure all decorations are cleared? + return this._textEditor.deltaDecorations(oldDecorations, newDecorations); + } + getMarkdownRenderer() { if (!this._mdRenderer) { this._mdRenderer = this._instaService.createInstance(MarkdownRenderer); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts similarity index 58% rename from src/vs/workbench/contrib/notebook/browser/notebookViewModel.ts rename to src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts index 764d0e5d5c8..08039f28f5e 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts @@ -8,15 +8,34 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput'; -import { CellFindMatch } from 'vs/workbench/contrib/notebook/browser/notebookFindWidget'; -import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/renderers/cellViewModel'; +import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel'; import { NotebookCellsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { IModelDeltaDecoration } from 'vs/editor/common/model'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { CellFindMatch } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; export interface INotebookEditorViewState { editingCells: { [key: number]: boolean }; editorViewStates: { [key: number]: editorCommon.ICodeEditorViewState | null }; } +export interface ICellModelDecorations { + ownerId: number; + decorations: string[]; +} + +export interface ICellModelDeltaDecorations { + ownerId: number; + decorations: IModelDeltaDecoration[]; +} + +export interface IModelDecorationsChangeAccessor { + deltaDecorations(oldDecorations: ICellModelDecorations[], newDecorations: ICellModelDeltaDecorations[]): ICellModelDecorations[]; +} + +const invalidFunc = () => { throw new Error(`Invalid change accessor`); }; + + export class NotebookViewModel extends Disposable { private _localStore: DisposableStore = this._register(new DisposableStore()); private _viewCells: CellViewModel[] = []; @@ -79,11 +98,17 @@ export class NotebookViewModel extends Disposable { return this.viewCells.indexOf(cell); } + /** + * Search in notebook text model + * @param value + */ find(value: string): CellFindMatch[] { - let matches: CellFindMatch[] = []; + const matches: CellFindMatch[] = []; this.viewCells.forEach(cell => { - let cellMatches = cell.startFind(value); - matches.push(...cellMatches); + const cellMatches = cell.startFind(value); + if (cellMatches) { + matches.push(cellMatches); + } }); return matches; @@ -130,6 +155,68 @@ export class NotebookViewModel extends Disposable { }); } + /** + * Editor decorations across cells. For example, find decorations for multiple code cells + * The reason that we can't completely delegate this to CodeEditorWidget is most of the time, the editors for cells are not created yet but we already have decorations for them. + */ + changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): T | null { + const changeAccessor: IModelDecorationsChangeAccessor = { + deltaDecorations: (oldDecorations: ICellModelDecorations[], newDecorations: ICellModelDeltaDecorations[]): ICellModelDecorations[] => { + return this.deltaDecorationsImpl(oldDecorations, newDecorations); + } + }; + + let result: T | null = null; + try { + result = callback(changeAccessor); + } catch (e) { + onUnexpectedError(e); + } + + changeAccessor.deltaDecorations = invalidFunc; + + return result; + } + + deltaDecorationsImpl(oldDecorations: ICellModelDecorations[], newDecorations: ICellModelDeltaDecorations[]): ICellModelDecorations[] { + + const mapping = new Map(); + oldDecorations.forEach(oldDecoration => { + const ownerId = oldDecoration.ownerId; + + if (!mapping.has(ownerId)) { + const cell = this.viewCells.find(cell => cell.handle === ownerId); + mapping.set(ownerId, { cell: cell!, oldDecorations: [], newDecorations: [] }); + } + + const data = mapping.get(ownerId)!; + data.oldDecorations = oldDecoration.decorations; + }); + + newDecorations.forEach(newDecoration => { + const ownerId = newDecoration.ownerId; + + if (!mapping.has(ownerId)) { + const cell = this.viewCells.find(cell => cell.handle === ownerId); + mapping.set(ownerId, { cell: cell!, oldDecorations: [], newDecorations: [] }); + } + + const data = mapping.get(ownerId)!; + data.newDecorations = newDecoration.decorations; + }); + + const ret: ICellModelDecorations[] = []; + mapping.forEach((value, ownerId) => { + const cellRet = value.cell.deltaDecorations(value.oldDecorations, value.newDecorations); + ret.push({ + ownerId: ownerId, + decorations: cellRet + }); + }); + + return ret; + } + equal(model: NotebookEditorModel) { return this._model === model; } diff --git a/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts b/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts index e309654a66d..ae21f5697c3 100644 --- a/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts +++ b/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput'; -import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/notebookViewModel'; +import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { createTestCellViewModel, TestNotebook, withTestNotebook } from 'vs/workbench/contrib/notebook/test/testNotebookEditor'; diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index 55220a8c346..183e0d04ac6 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -8,13 +8,13 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { PieceTreeTextBufferFactory } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder'; import { CellKind, generateCellPath, ICell, INotebook, IOutput, NotebookCellOutputsSplice, NotebookCellsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/notebookViewModel'; +import { NotebookViewModel, IModelDecorationsChangeAccessor } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/renderers/cellViewModel'; +import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel'; import { NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput'; import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; -import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/output/outputRenderer'; +import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { Dimension } from 'vs/base/browser/dom'; @@ -89,6 +89,10 @@ export class TestNotebook extends Disposable implements INotebook { export class TestNotebookEditor implements INotebookEditor { + get viewModel() { + return undefined; + } + constructor( public viewType: string ) { @@ -138,6 +142,10 @@ export class TestNotebookEditor implements INotebookEditor { getOutputRenderer(): OutputRenderer { throw new Error('Method not implemented.'); } + + changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any { + throw new Error('Method not implemented.'); + } } export function createTestCellViewModel(instantiationService: IInstantiationService, viewType: string, notebookHandle: number, cellhandle: number, source: string[], language: string, cellKind: CellKind, outputs: IOutput[]) { -- GitLab