notebookEditor.ts 22.5 KB
Newer Older
P
Peng Lyu 已提交
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

R
rebornix 已提交
6
import { getZoomLevel } from 'vs/base/browser/browser';
P
Peng Lyu 已提交
7
import * as DOM from 'vs/base/browser/dom';
P
Peng Lyu 已提交
8
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
R
rebornix 已提交
9
import { CancellationToken } from 'vs/base/common/cancellation';
R
rebornix 已提交
10
import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
R
rebornix 已提交
11
import 'vs/css!./notebook';
12
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
R
rebornix 已提交
13
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
14
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
R
rebornix 已提交
15
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
R
rebornix 已提交
16
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
R
rebornix 已提交
17 18 19 20 21 22
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { contrastBorder, editorBackground, focusBorder, foreground, textBlockQuoteBackground, textBlockQuoteBorder, textLinkActiveForeground, textLinkForeground, textPreformatForeground } from 'vs/platform/theme/common/colorRegistry';
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
R
rebornix 已提交
23
import { EditorOptions, IEditorMemento, ICompositeCodeEditor, IEditorCloseEvent } from 'vs/workbench/common/editor';
24
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
R
rebornix 已提交
25
import { NotebookEditorInput, NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
R
rebornix 已提交
26
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
R
rebornix 已提交
27
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/output/outputRenderer';
R
rebornix 已提交
28 29 30
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';
R
rebornix 已提交
31
import { CELL_MARGIN, NotebookCellsSplice, IOutput, parseCellUri, CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
R
rebornix 已提交
32 33 34
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';
J
Johannes Rieken 已提交
35
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
36
import { IEditor } from 'vs/editor/common/editorCommon';
37
import { IResourceEditorInput } from 'vs/platform/editor/common/editor';
38
import { Emitter, Event } from 'vs/base/common/event';
R
rebornix 已提交
39
import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/notebookCellList';
R
rebornix 已提交
40
import { NotebookFindWidget, NotebookFindDelegate, CellFindMatch } from 'vs/workbench/contrib/notebook/browser/notebookFindWidget';
R
rebornix 已提交
41
import { NotebookViewModel, INotebookEditorViewState } from 'vs/workbench/contrib/notebook/browser/notebookViewModel';
R
rebornix 已提交
42
import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
P
Peng Lyu 已提交
43 44

const $ = DOM.$;
R
rebornix 已提交
45 46
const NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'NotebookEditorViewState';

R
rebornix 已提交
47 48
export const NOTEBOOK_EDITOR_FOCUSED = new RawContextKey<boolean>('notebookEditorFocused', false);

R
rebornix 已提交
49
export class NotebookCodeEditors implements ICompositeCodeEditor {
50

51
	private readonly _disposables = new DisposableStore();
52 53 54 55
	private readonly _onDidChangeActiveEditor = new Emitter<this>();
	readonly onDidChangeActiveEditor: Event<this> = this._onDidChangeActiveEditor.event;

	constructor(
R
rebornix 已提交
56
		private _list: NotebookCellList<CellViewModel>,
57
		private _renderedEditors: Map<CellViewModel, ICodeEditor | undefined>
58
	) {
J
Johannes Rieken 已提交
59
		_list.onDidChangeFocus(e => this._onDidChangeActiveEditor.fire(this), undefined, this._disposables);
60 61 62 63 64 65
	}

	dispose(): void {
		this._onDidChangeActiveEditor.dispose();
		this._disposables.dispose();
	}
66 67 68 69 70 71 72 73

	get activeCodeEditor(): IEditor | undefined {
		const [focused] = this._list.getFocusedElements();
		return focused instanceof CellViewModel
			? this._renderedEditors.get(focused)
			: undefined;
	}

74
	activate(input: IResourceEditorInput): ICodeEditor | undefined {
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
		const data = parseCellUri(input.resource);
		if (!data) {
			return undefined;
		}
		// find the CellViewModel which represents the cell with the
		// given uri, scroll it into view so that the editor is alive,
		// and then set selection et al..
		for (let i = 0; i < this._list.length; i++) {
			const item = this._list.element(i);
			if (item.cell.uri.toString() === input.resource.toString()) {
				this._list.reveal(i, 0.2);
				this._list.setFocus([i]);
				const editor = this._renderedEditors.get(item);
				if (!editor) {
					break;
				}
				if (input.options?.selection) {
					const { selection } = input.options;
					editor.setSelection({
						...selection,
						endLineNumber: selection.endLineNumber || selection.startLineNumber,
						endColumn: selection.endColumn || selection.startColumn
					});
				}
				if (!input.options?.preserveFocus) {
					editor.focus();
				}
				return editor;
			}
		}
		return undefined;
	}
}

R
rebornix 已提交
109
export class NotebookEditor extends BaseEditor implements INotebookEditor, NotebookFindDelegate {
P
Peng Lyu 已提交
110 111 112
	static readonly ID: string = 'workbench.editor.notebook';
	private rootElement!: HTMLElement;
	private body!: HTMLElement;
P
Peng Lyu 已提交
113
	private webview: BackLayerWebView | null = null;
R
rebornix 已提交
114
	private list: NotebookCellList<CellViewModel> | undefined;
115
	private control: ICompositeCodeEditor | undefined;
J
Johannes Rieken 已提交
116
	private renderedEditors: Map<CellViewModel, ICodeEditor | undefined> = new Map();
R
rebornix 已提交
117
	private notebookViewModel: NotebookViewModel | undefined;
118
	private localStore: DisposableStore = this._register(new DisposableStore());
R
rebornix 已提交
119
	private editorMemento: IEditorMemento<INotebookEditorViewState>;
R
rebornix 已提交
120
	private readonly groupListener = this._register(new MutableDisposable());
121
	private fontInfo: BareFontInfo | undefined;
122
	private dimension: DOM.Dimension | null = null;
R
rebornix 已提交
123
	private editorFocus: IContextKey<boolean> | null = null;
R
rebornix 已提交
124
	private outputRenderer: OutputRenderer;
R
rebornix 已提交
125
	private findWidget: NotebookFindWidget;
P
Peng Lyu 已提交
126 127 128 129 130

	constructor(
		@ITelemetryService telemetryService: ITelemetryService,
		@IThemeService themeService: IThemeService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
P
Peng Lyu 已提交
131
		@IStorageService storageService: IStorageService,
R
rebornix 已提交
132
		@IWebviewService private webviewService: IWebviewService,
R
rebornix 已提交
133
		@INotebookService private notebookService: INotebookService,
134
		@IEditorGroupsService editorGroupService: IEditorGroupsService,
R
rebornix 已提交
135
		@IConfigurationService private readonly configurationService: IConfigurationService,
R
rebornix 已提交
136
		@IEnvironmentService private readonly environmentSerice: IEnvironmentService,
R
rebornix 已提交
137
		@IContextKeyService private readonly contextKeyService: IContextKeyService,
P
Peng Lyu 已提交
138 139
	) {
		super(NotebookEditor.ID, telemetryService, themeService, storageService);
R
rebornix 已提交
140 141

		this.editorMemento = this.getEditorMemento<INotebookEditorViewState>(editorGroupService, NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY);
R
rebornix 已提交
142
		this.outputRenderer = new OutputRenderer(this, this.instantiationService);
R
rebornix 已提交
143
		this.findWidget = this.instantiationService.createInstance(NotebookFindWidget, this);
144
		this.findWidget.updateTheme(this.themeService.getColorTheme());
R
rebornix 已提交
145 146
	}

P
Peng Lyu 已提交
147 148 149 150 151 152 153
	get minimumWidth(): number { return 375; }
	get maximumWidth(): number { return Number.POSITIVE_INFINITY; }

	// these setters need to exist because this extends from BaseEditor
	set minimumWidth(value: number) { /*noop*/ }
	set maximumWidth(value: number) { /*noop*/ }

R
rebornix 已提交
154 155
	get viewType() { return this.notebookViewModel?.viewType; }

P
Peng Lyu 已提交
156

R
rebornix 已提交
157 158
	//#region Editor

R
rebornix 已提交
159 160 161 162 163

	public get isNotebookEditor() {
		return true;
	}

P
Peng Lyu 已提交
164 165 166
	protected createEditor(parent: HTMLElement): void {
		this.rootElement = DOM.append(parent, $('.notebook-editor'));
		this.createBody(this.rootElement);
167
		this.generateFontInfo();
R
rebornix 已提交
168 169 170 171 172 173 174 175
		this.editorFocus = NOTEBOOK_EDITOR_FOCUSED.bindTo(this.contextKeyService);
		this._register(this.onDidFocus(() => {
			this.editorFocus?.set(true);
		}));

		this._register(this.onDidBlur(() => {
			this.editorFocus?.set(false);
		}));
176 177 178 179 180
	}

	private generateFontInfo(): void {
		const editorOptions = this.configurationService.getValue<IEditorOptions>('editor');
		this.fontInfo = BareFontInfo.createFromRawSettings(editorOptions, getZoomLevel());
P
Peng Lyu 已提交
181 182 183
	}

	private createBody(parent: HTMLElement): void {
P
Peng Lyu 已提交
184
		this.body = document.createElement('div');
P
Peng Lyu 已提交
185 186 187
		DOM.addClass(this.body, 'cell-list-container');
		this.createCellList();
		DOM.append(parent, this.body);
R
rebornix 已提交
188
		DOM.append(this.body, this.findWidget.getDomNode());
P
Peng Lyu 已提交
189 190
	}

P
Peng Lyu 已提交
191 192
	private createCellList(): void {
		DOM.addClass(this.body, 'cell-list-container');
P
Peng Lyu 已提交
193

P
Peng Lyu 已提交
194
		const renders = [
195
			this.instantiationService.createInstance(CodeCellRenderer, this, this.renderedEditors),
P
Peng Lyu 已提交
196
			this.instantiationService.createInstance(MarkdownCellRenderer, this),
P
Peng Lyu 已提交
197 198
		];

R
rebornix 已提交
199 200
		this.list = <NotebookCellList<CellViewModel>>this.instantiationService.createInstance(
			NotebookCellList,
P
Peng Lyu 已提交
201 202 203 204 205 206
			'NotebookCellList',
			this.body,
			this.instantiationService.createInstance(NotebookCellListDelegate),
			renders,
			{
				setRowLineHeight: false,
R
rebornix 已提交
207
				setRowHeight: false,
P
Peng Lyu 已提交
208 209 210
				supportDynamicHeights: true,
				horizontalScrolling: false,
				keyboardSupport: false,
R
rebornix 已提交
211
				mouseSupport: true,
P
Peng Lyu 已提交
212
				multipleSelectionSupport: false,
R
rebornix 已提交
213
				enableKeyboardNavigation: true,
P
Peng Lyu 已提交
214 215 216 217 218 219 220 221 222 223
				overrideStyles: {
					listBackground: editorBackground,
					listActiveSelectionBackground: editorBackground,
					listActiveSelectionForeground: foreground,
					listFocusAndSelectionBackground: editorBackground,
					listFocusAndSelectionForeground: foreground,
					listFocusBackground: editorBackground,
					listFocusForeground: foreground,
					listHoverForeground: foreground,
					listHoverBackground: editorBackground,
224 225
					listHoverOutline: focusBorder,
					listFocusOutline: focusBorder,
226 227 228 229
					listInactiveSelectionBackground: editorBackground,
					listInactiveSelectionForeground: foreground,
					listInactiveFocusBackground: editorBackground,
					listInactiveFocusOutline: editorBackground,
P
Peng Lyu 已提交
230 231 232
				}
			}
		);
P
Peng Lyu 已提交
233

234
		this.control = new NotebookCodeEditors(this.list, this.renderedEditors);
R
rebornix 已提交
235
		this.webview = new BackLayerWebView(this.webviewService, this.notebookService, this, this.environmentSerice);
R
rebornix 已提交
236
		this.list.rowsContainer.appendChild(this.webview.element);
P
Peng Lyu 已提交
237 238 239
		this._register(this.list);
	}

240 241 242 243
	getControl() {
		return this.control;
	}

P
Peng Lyu 已提交
244
	onHide() {
R
rebornix 已提交
245
		this.editorFocus?.set(false);
246 247
		if (this.webview) {
			this.localStore.clear();
R
rebornix 已提交
248
			this.list?.rowsContainer.removeChild(this.webview?.element);
249 250 251 252 253
			this.webview?.dispose();
			this.webview = null;
		}

		this.list?.splice(0, this.list?.length);
R
rebornix 已提交
254

R
rebornix 已提交
255 256 257
		if (this.notebookViewModel && !this.notebookViewModel.isDirty()) {
			this.notebookService.destoryNotebookDocument(this.viewType!, this.notebookViewModel!.notebookDocument);
			this.notebookViewModel = undefined;
R
rebornix 已提交
258 259
		}

260
		super.onHide();
P
Peng Lyu 已提交
261 262
	}

R
rebornix 已提交
263 264 265 266 267 268 269 270 271 272 273 274 275
	setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void {
		super.setEditorVisible(visible, group);
		this.groupListener.value = ((group as IEditorGroupView).onWillCloseEditor(e => this.onWillCloseEditorInGroup(e)));
	}

	private onWillCloseEditorInGroup(e: IEditorCloseEvent): void {
		const editor = e.editor;
		if (!(editor instanceof NotebookEditorInput)) {
			return; // only handle files
		}

		if (editor === this.input) {
			this.saveTextEditorViewState(editor);
276 277 278
		}
	}

R
rebornix 已提交
279 280 281 282 283
	focus() {
		super.focus();
		this.editorFocus?.set(true);
	}

R
rebornix 已提交
284
	async setInput(input: NotebookEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
R
rebornix 已提交
285 286 287 288
		if (this.input instanceof NotebookEditorInput) {
			this.saveTextEditorViewState(this.input);
		}

R
rebornix 已提交
289 290
		await super.setInput(input, options, token);
		const model = await input.resolve();
P
Peng Lyu 已提交
291

R
rebornix 已提交
292 293 294
		if (this.notebookViewModel !== undefined && this.notebookViewModel.equal(model) && this.webview !== null) {
			return;
		}
P
Peng Lyu 已提交
295

R
rebornix 已提交
296 297 298
		this.detachModel();
		await this.attachModel(input, model);
	}
299

R
rebornix 已提交
300 301 302 303 304 305 306 307
	clearInput(): void {
		if (this.input && this.input instanceof NotebookEditorInput && !this.input.isDisposed()) {
			this.saveTextEditorViewState(this.input);
		}

		super.clearInput();
	}

R
rebornix 已提交
308 309 310 311 312 313 314
	private detachModel() {
		this.localStore.clear();
		this.notebookViewModel?.dispose();
		this.notebookViewModel = undefined;
		this.webview?.clearInsets();
		this.webview?.clearPreloadsCache();
	}
R
rebornix 已提交
315

R
rebornix 已提交
316 317 318 319 320
	private async attachModel(input: NotebookEditorInput, model: NotebookEditorModel) {
		if (!this.webview) {
			this.webview = new BackLayerWebView(this.webviewService, this.notebookService, this, this.environmentSerice);
			this.list?.rowsContainer.insertAdjacentElement('afterbegin', this.webview!.element);
		}
321

R
rebornix 已提交
322 323
		this.notebookViewModel = this.instantiationService.createInstance(NotebookViewModel, input.viewType!, model);
		const viewState = this.loadTextEditorViewState(input);
R
rebornix 已提交
324
		this.notebookViewModel.restoreEditorViewState(viewState);
325

R
rebornix 已提交
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
		this.localStore.add(this.notebookViewModel.onDidChangeCells((e) => {
			this.updateViewCells(e);
		}));

		this.webview?.updateRendererPreloads(this.notebookViewModel.renderers);

		this.localStore.add(this.list!.onWillScroll(e => {
			this.webview!.updateViewScrollTop(-e.scrollTop, []);
		}));

		this.localStore.add(this.list!.onDidChangeContentHeight(() => {
			const scrollTop = this.list?.scrollTop || 0;
			const scrollHeight = this.list?.scrollHeight || 0;
			this.webview!.element.style.height = `${scrollHeight}px`;
			let updateItems: { cell: CellViewModel, output: IOutput, cellTop: number }[] = [];

			if (this.webview?.insetMapping) {
				this.webview?.insetMapping.forEach((value, key) => {
					let cell = value.cell;
					let index = this.notebookViewModel!.getViewCellIndex(cell);
					let cellTop = this.list?.getAbsoluteTop(index) || 0;
					if (this.webview!.shouldUpdateInset(cell, key, cellTop)) {
						updateItems.push({
							cell: cell,
							output: key,
							cellTop: cellTop
						});
R
rebornix 已提交
353
					}
R
rebornix 已提交
354
				});
355

R
rebornix 已提交
356 357 358 359 360 361
				if (updateItems.length) {
					this.webview?.updateViewScrollTop(-scrollTop, updateItems);
				}
			}
		}));

J
Johannes Rieken 已提交
362
		this.localStore.add(this.list!.onDidChangeFocus((e) => {
R
rebornix 已提交
363 364 365 366 367
			if (e.elements.length > 0) {
				this.notebookService.updateNotebookActiveCell(input.viewType!, input.resource!, e.elements[0].cell.handle);
			}
		}));

R
rebornix 已提交
368
		this.list?.splice(0, this.list?.length || 0);
R
rebornix 已提交
369 370
		this.list?.splice(0, 0, this.notebookViewModel!.viewCells);
		this.list?.layout();
P
Peng Lyu 已提交
371 372
	}

R
rebornix 已提交
373 374
	private saveTextEditorViewState(input: NotebookEditorInput): void {
		if (this.group) {
R
rebornix 已提交
375 376
			const state = this.notebookViewModel!.saveEditorViewState();
			this.editorMemento.saveEditorState(this.group, input.resource, state);
R
rebornix 已提交
377 378 379 380 381
		}
	}

	private loadTextEditorViewState(input: NotebookEditorInput): INotebookEditorViewState | undefined {
		if (this.group) {
R
rebornix 已提交
382
			return this.editorMemento.loadEditorState(this.group, input.resource);
R
rebornix 已提交
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
		}

		return;
	}

	layout(dimension: DOM.Dimension): void {
		this.dimension = new DOM.Dimension(dimension.width, dimension.height);
		DOM.toggleClass(this.rootElement, 'mid-width', dimension.width < 1000 && dimension.width >= 600);
		DOM.toggleClass(this.rootElement, 'narrow-width', dimension.width < 600);
		DOM.size(this.body, dimension.width, dimension.height);
		this.list?.layout(dimension.height, dimension.width);
	}

	protected saveState(): void {
		if (this.input instanceof NotebookEditorInput) {
			this.saveTextEditorViewState(this.input);
		}

		super.saveState();
	}

	//#endregion

R
rebornix 已提交
406 407 408
	//#region Find Delegate
	startFind(value: string): CellFindMatch[] {
		let matches: CellFindMatch[] = [];
R
rebornix 已提交
409
		this.notebookViewModel!.viewCells.forEach(cell => {
R
rebornix 已提交
410 411 412 413 414 415 416 417 418 419 420 421
			let cellMatches = cell.startFind(value);
			matches.push(...cellMatches);
		});

		return matches;
	}

	stopFind(keepSelection?: boolean | undefined): void {
	}

	focusNext(match: CellFindMatch) {
		let cell = match.cell;
R
rebornix 已提交
422
		let index = this.notebookViewModel!.viewCells.indexOf(cell);
R
rebornix 已提交
423 424 425 426 427 428 429 430 431 432 433 434 435 436

		this.list?.reveal(index);
	}

	public showFind() {
		this.findWidget.reveal();
	}

	public hideFind() {
		this.findWidget.hide();
	}

	//#endregion

R
rebornix 已提交
437
	//#region Cell operations
438
	layoutNotebookCell(cell: CellViewModel, height: number) {
R
rebornix 已提交
439
		let relayout = (cell: CellViewModel, height: number) => {
R
rebornix 已提交
440
			let index = this.notebookViewModel!.getViewCellIndex(cell);
R
rebornix 已提交
441
			if (index >= 0) {
R
rebornix 已提交
442
				this.list?.updateElementHeight(index, height);
R
rebornix 已提交
443
			}
R
rebornix 已提交
444 445
		};

R
rebornix 已提交
446
		DOM.scheduleAtNextAnimationFrame(() => {
R
rebornix 已提交
447
			relayout(cell, height);
R
rebornix 已提交
448
		});
449 450
	}

451
	updateViewCells(splices: NotebookCellsSplice[]) {
R
rebornix 已提交
452
		DOM.scheduleAtNextAnimationFrame(() => {
R
rebornix 已提交
453 454
			splices.reverse().forEach((diff) => {
				this.list?.splice(diff[0], diff[1], diff[2].map(cell => {
R
rebornix 已提交
455
					return this.instantiationService.createInstance(CellViewModel, this.viewType!, this.notebookViewModel!.handle, cell);
R
rebornix 已提交
456 457
				}));
			});
458
		});
R
rebornix 已提交
459 460
	}

R
rebornix 已提交
461
	async insertEmptyNotebookCell(cell: CellViewModel, type: CellKind, direction: 'above' | 'below'): Promise<void> {
R
rebornix 已提交
462 463 464
		const newLanguages = this.notebookViewModel!.languages;
		const language = newLanguages && newLanguages.length ? newLanguages[0] : 'markdown';
		const index = this.notebookViewModel!.getViewCellIndex(cell);
P
Peng Lyu 已提交
465
		const insertIndex = direction === 'above' ? index : index + 1;
R
rebornix 已提交
466
		const newModeCell = await this.notebookService.createNotebookCell(this.viewType!, this.notebookViewModel!.uri, insertIndex, language, type);
R
rebornix 已提交
467
		const newCell = this.instantiationService.createInstance(CellViewModel, this.viewType!, this.notebookViewModel!.handle, newModeCell!);
P
Peng Lyu 已提交
468

R
rebornix 已提交
469
		this.notebookViewModel!.insertCell(insertIndex, newCell);
P
Peng Lyu 已提交
470
		this.list?.splice(insertIndex, 0, [newCell]);
R
rebornix 已提交
471
		this.list?.setFocus([insertIndex]);
P
Peng Lyu 已提交
472

R
rebornix 已提交
473
		if (type === CellKind.Markdown) {
P
Peng Lyu 已提交
474 475
			newCell.isEditing = true;
		}
R
rebornix 已提交
476 477 478 479

		DOM.scheduleAtNextAnimationFrame(() => {
			this.list?.reveal(insertIndex, 0.33);
		});
P
Peng Lyu 已提交
480 481
	}

R
rebornix 已提交
482 483 484 485 486 487 488 489
	async deleteNotebookCell(cell: CellViewModel): Promise<void> {
		const index = this.notebookViewModel!.getViewCellIndex(cell);
		await this.notebookService.deleteNotebookCell(this.viewType!, this.notebookViewModel!.uri, index);
		this.notebookViewModel!.deleteCell(index);
		this.list?.splice(index, 1);
	}

	editNotebookCell(cell: CellViewModel): void {
P
Peng Lyu 已提交
490
		cell.isEditing = true;
R
rebornix 已提交
491 492

		this.renderedEditors.get(cell)?.focus();
P
Peng Lyu 已提交
493 494
	}

R
rebornix 已提交
495
	saveNotebookCell(cell: CellViewModel): void {
P
Peng Lyu 已提交
496
		cell.isEditing = false;
P
Peng Lyu 已提交
497 498
	}

R
rebornix 已提交
499 500 501 502 503 504 505 506 507 508
	getActiveCell() {
		let elements = this.list?.getFocusedElements();

		if (elements && elements.length) {
			return elements[0];
		}

		return undefined;
	}

R
rebornix 已提交
509
	focusNotebookCell(cell: CellViewModel, focusEditor: boolean) {
R
rebornix 已提交
510
		const index = this.notebookViewModel!.getViewCellIndex(cell);
R
rebornix 已提交
511 512 513 514

		if (focusEditor) {

		} else {
R
rebornix 已提交
515
			let itemDOM = this.list?.domElementAtIndex(index);
R
rebornix 已提交
516 517 518
			if (document.activeElement && itemDOM && itemDOM.contains(document.activeElement)) {
				(document.activeElement as HTMLElement).blur();
			}
519 520

			cell.isEditing = false;
R
rebornix 已提交
521 522 523
		}

		this.list?.setFocus([index]);
R
rebornix 已提交
524
		this.list?.focusView();
R
rebornix 已提交
525 526
	}

R
rebornix 已提交
527 528 529 530 531 532
	//#endregion

	//#region MISC

	getFontInfo(): BareFontInfo | undefined {
		return this.fontInfo;
P
Peng Lyu 已提交
533
	}
R
rebornix 已提交
534

R
rebornix 已提交
535 536 537
	getListDimension(): DOM.Dimension | null {
		return this.dimension;
	}
R
rebornix 已提交
538

R
rebornix 已提交
539 540
	triggerScroll(event: IMouseWheelEvent) {
		this.list?.triggerScrollFromMouseWheelEvent(event);
R
rebornix 已提交
541 542
	}

543
	createInset(cell: CellViewModel, output: IOutput, shadowContent: string, offset: number) {
R
rebornix 已提交
544 545
		if (!this.webview) {
			return;
R
rebornix 已提交
546 547
		}

R
rebornix 已提交
548
		let preloads = this.notebookViewModel!.renderers;
R
rebornix 已提交
549

550
		if (!this.webview!.insetMapping.has(output)) {
R
rebornix 已提交
551
			let index = this.notebookViewModel!.getViewCellIndex(cell);
552 553 554
			let cellTop = this.list?.getAbsoluteTop(index) || 0;

			this.webview!.createInset(cell, output, cellTop, offset, shadowContent, preloads);
R
rebornix 已提交
555
		} else {
R
rebornix 已提交
556
			let index = this.notebookViewModel!.getViewCellIndex(cell);
557
			let cellTop = this.list?.getAbsoluteTop(index) || 0;
R
rebornix 已提交
558 559
			let scrollTop = this.list?.scrollTop || 0;

560
			this.webview!.updateViewScrollTop(-scrollTop, [{ cell: cell, output: output, cellTop: cellTop }]);
R
rebornix 已提交
561
		}
R
rebornix 已提交
562
	}
R
rebornix 已提交
563

R
rebornix 已提交
564 565 566 567 568 569 570 571
	removeInset(output: IOutput) {
		if (!this.webview) {
			return;
		}

		this.webview!.removeInset(output);
	}

R
rebornix 已提交
572 573
	getOutputRenderer(): OutputRenderer {
		return this.outputRenderer;
R
rebornix 已提交
574
	}
575

R
rebornix 已提交
576
	//#endregion
P
Peng Lyu 已提交
577 578 579 580 581 582 583
}

const embeddedEditorBackground = 'walkThrough.embeddedEditorBackground';

registerThemingParticipant((theme, collector) => {
	const color = getExtraColor(theme, embeddedEditorBackground, { dark: 'rgba(0, 0, 0, .4)', extra_dark: 'rgba(200, 235, 255, .064)', light: '#f4f4f4', hc: null });
	if (color) {
R
rebornix 已提交
584 585
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .monaco-editor-background,
			.monaco-workbench .part.editor > .content .notebook-editor .cell .margin-view-overlays { background: ${color}; }`);
P
Peng Lyu 已提交
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
	}
	const link = theme.getColor(textLinkForeground);
	if (link) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor a { color: ${link}; }`);
	}
	const activeLink = theme.getColor(textLinkActiveForeground);
	if (activeLink) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor a:hover,
			.monaco-workbench .part.editor > .content .notebook-editor a:active { color: ${activeLink}; }`);
	}
	const shortcut = theme.getColor(textPreformatForeground);
	if (shortcut) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor code,
			.monaco-workbench .part.editor > .content .notebook-editor .shortcut { color: ${shortcut}; }`);
	}
	const border = theme.getColor(contrastBorder);
	if (border) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-editor { border-color: ${border}; }`);
	}
	const quoteBackground = theme.getColor(textBlockQuoteBackground);
	if (quoteBackground) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor blockquote { background: ${quoteBackground}; }`);
	}
	const quoteBorder = theme.getColor(textBlockQuoteBorder);
	if (quoteBorder) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor blockquote { border-color: ${quoteBorder}; }`);
	}
613 614 615 616 617 618

	const inactiveListItem = theme.getColor('list.inactiveSelectionBackground');

	if (inactiveListItem) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { background-color: ${inactiveListItem}; }`);
	}
619 620 621

	// Cell Margin
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > div.cell { padding: 8px ${CELL_MARGIN}px 8px ${CELL_MARGIN}px; }`);
622
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 8px ${CELL_MARGIN}px; }`);
P
Peng Lyu 已提交
623
});