notebookEditor.ts 38.8 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.
 *--------------------------------------------------------------------------------------------*/

B
Benjamin Pasero 已提交
6
import 'vs/css!./media/notebook';
R
rebornix 已提交
7
import { getZoomLevel } from 'vs/base/browser/browser';
P
Peng Lyu 已提交
8
import * as DOM from 'vs/base/browser/dom';
R
rebornix 已提交
9
import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';
10 11 12
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { Color, RGBA } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
R
rebornix 已提交
13
import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
14
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
15
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
R
rebornix 已提交
16
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
17 18 19
import { Range } from 'vs/editor/common/core/range';
import { ICompositeCodeEditor, IEditor } from 'vs/editor/common/editorCommon';
import * as nls from 'vs/nls';
20
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
R
Rob Lourens 已提交
21
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
22
import { IResourceEditorInput } from 'vs/platform/editor/common/editor';
R
rebornix 已提交
23 24 25
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
26
import { contrastBorder, editorBackground, focusBorder, foreground, registerColor, textBlockQuoteBackground, textBlockQuoteBorder, textLinkActiveForeground, textLinkForeground, textPreformatForeground } from 'vs/platform/theme/common/colorRegistry';
R
rebornix 已提交
27 28
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
29 30
import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
import { EditorOptions, IEditorCloseEvent, IEditorMemento } from 'vs/workbench/common/editor';
31
import { CELL_MARGIN, CELL_RUN_GUTTER, EDITOR_TOP_MARGIN, EDITOR_TOP_PADDING, EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
R
rebornix 已提交
32
import { CellEditState, CellFocusMode, ICellRange, ICellViewModel, INotebookCellList, INotebookEditor, INotebookEditorMouseEvent, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, INotebookEditorContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
R
rebornix 已提交
33
import { NotebookEditorInput, NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
R
rebornix 已提交
34
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
35
import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList';
R
rebornix 已提交
36 37
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView';
R
Rob Lourens 已提交
38
import { CodeCellRenderer, MarkdownCellRenderer, NotebookCellListDelegate, CellDragAndDropController } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer';
R
rebornix 已提交
39
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
R
rebornix 已提交
40
import { NotebookEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
41 42
import { CellViewModel, IModelDecorationsChangeAccessor, INotebookEditorViewState, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { CellKind, CellUri, IOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
R
rebornix 已提交
43
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
44 45
import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
R
rebornix 已提交
46 47
import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions';
import { onUnexpectedError } from 'vs/base/common/errors';
P
Peng Lyu 已提交
48 49

const $ = DOM.$;
R
rebornix 已提交
50 51
const NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'NotebookEditorViewState';

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
export class NotebookEditorOptions extends EditorOptions {

	readonly cellOptions?: IResourceEditorInput;

	constructor(options: Partial<NotebookEditorOptions>) {
		super();
		this.overwrite(options);
		this.cellOptions = options.cellOptions;
	}

	with(options: Partial<NotebookEditorOptions>): NotebookEditorOptions {
		return new NotebookEditorOptions({ ...this, ...options });
	}
}

R
rebornix 已提交
67
export class NotebookCodeEditors implements ICompositeCodeEditor {
68

69
	private readonly _disposables = new DisposableStore();
70 71 72 73
	private readonly _onDidChangeActiveEditor = new Emitter<this>();
	readonly onDidChangeActiveEditor: Event<this> = this._onDidChangeActiveEditor.event;

	constructor(
R
rebornix 已提交
74
		private _list: INotebookCellList,
R
rebornix 已提交
75
		private _renderedEditors: Map<ICellViewModel, ICodeEditor | undefined>
76
	) {
77
		_list.onDidChangeFocus(_e => this._onDidChangeActiveEditor.fire(this), undefined, this._disposables);
78 79 80 81 82 83
	}

	dispose(): void {
		this._onDidChangeActiveEditor.dispose();
		this._disposables.dispose();
	}
84 85 86

	get activeCodeEditor(): IEditor | undefined {
		const [focused] = this._list.getFocusedElements();
R
rebornix 已提交
87
		return this._renderedEditors.get(focused);
88 89 90
	}
}

R
rebornix 已提交
91
export class NotebookEditor extends BaseEditor implements INotebookEditor {
P
Peng Lyu 已提交
92
	static readonly ID: string = 'workbench.editor.notebook';
R
rebornix 已提交
93
	private _rootElement!: HTMLElement;
P
Peng Lyu 已提交
94
	private body!: HTMLElement;
P
Peng Lyu 已提交
95
	private webview: BackLayerWebView | null = null;
R
rebornix 已提交
96
	private webviewTransparentCover: HTMLElement | null = null;
R
rebornix 已提交
97
	private list: INotebookCellList | undefined;
98
	private control: ICompositeCodeEditor | undefined;
R
rebornix 已提交
99
	private renderedEditors: Map<ICellViewModel, ICodeEditor | undefined> = new Map();
R
rebornix 已提交
100
	private eventDispatcher: NotebookEventDispatcher | undefined;
R
rebornix 已提交
101
	private notebookViewModel: NotebookViewModel | undefined;
102
	private localStore: DisposableStore = this._register(new DisposableStore());
R
rebornix 已提交
103
	private editorMemento: IEditorMemento<INotebookEditorViewState>;
R
rebornix 已提交
104
	private readonly groupListener = this._register(new MutableDisposable());
105
	private fontInfo: BareFontInfo | undefined;
106
	private dimension: DOM.Dimension | null = null;
R
rebornix 已提交
107
	private editorFocus: IContextKey<boolean> | null = null;
R
rebornix 已提交
108
	private editorEditable: IContextKey<boolean> | null = null;
109
	private editorExecutingNotebook: IContextKey<boolean> | null = null;
R
rebornix 已提交
110
	private outputRenderer: OutputRenderer;
R
rebornix 已提交
111
	protected readonly _contributions: { [key: string]: INotebookEditorContribution; };
P
Peng Lyu 已提交
112 113 114 115 116

	constructor(
		@ITelemetryService telemetryService: ITelemetryService,
		@IThemeService themeService: IThemeService,
		@IInstantiationService private readonly instantiationService: IInstantiationService,
P
Peng Lyu 已提交
117
		@IStorageService storageService: IStorageService,
R
rebornix 已提交
118
		@INotebookService private notebookService: INotebookService,
119
		@IEditorGroupsService editorGroupService: IEditorGroupsService,
R
rebornix 已提交
120
		@IConfigurationService private readonly configurationService: IConfigurationService,
R
rebornix 已提交
121
		@IContextKeyService private readonly contextKeyService: IContextKeyService
P
Peng Lyu 已提交
122 123
	) {
		super(NotebookEditor.ID, telemetryService, themeService, storageService);
R
rebornix 已提交
124 125

		this.editorMemento = this.getEditorMemento<INotebookEditorViewState>(editorGroupService, NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY);
R
rebornix 已提交
126
		this.outputRenderer = new OutputRenderer(this, this.instantiationService);
R
rebornix 已提交
127 128 129 130 131 132 133 134 135 136
		this._contributions = {};
	}

	private readonly _onDidChangeModel = new Emitter<void>();
	readonly onDidChangeModel: Event<void> = this._onDidChangeModel.event;


	set viewModel(newModel: NotebookViewModel | undefined) {
		this.notebookViewModel = newModel;
		this._onDidChangeModel.fire();
R
rebornix 已提交
137 138
	}

R
rebornix 已提交
139 140 141 142
	get viewModel() {
		return this.notebookViewModel;
	}

P
Peng Lyu 已提交
143 144 145 146 147 148 149 150
	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 已提交
151
	//#region Editor Core
R
rebornix 已提交
152

R
rebornix 已提交
153 154 155 156 157

	public get isNotebookEditor() {
		return true;
	}

P
Peng Lyu 已提交
158
	protected createEditor(parent: HTMLElement): void {
R
rebornix 已提交
159 160
		this._rootElement = DOM.append(parent, $('.notebook-editor'));
		this.createBody(this._rootElement);
161
		this.generateFontInfo();
R
rebornix 已提交
162
		this.editorFocus = NOTEBOOK_EDITOR_FOCUSED.bindTo(this.contextKeyService);
163
		this.editorFocus.set(true);
R
rebornix 已提交
164 165 166 167 168 169 170
		this._register(this.onDidFocus(() => {
			this.editorFocus?.set(true);
		}));

		this._register(this.onDidBlur(() => {
			this.editorFocus?.set(false);
		}));
R
rebornix 已提交
171 172 173

		this.editorEditable = NOTEBOOK_EDITOR_EDITABLE.bindTo(this.contextKeyService);
		this.editorEditable.set(true);
174
		this.editorExecutingNotebook = NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK.bindTo(this.contextKeyService);
R
rebornix 已提交
175 176 177 178 179 180 181 182 183 184 185

		const contributions = NotebookEditorExtensionsRegistry.getEditorContributions();

		for (const desc of contributions) {
			try {
				const contribution = this.instantiationService.createInstance(desc.ctor, this);
				this._contributions[desc.id] = contribution;
			} catch (err) {
				onUnexpectedError(err);
			}
		}
186 187 188 189 190
	}

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

	private createBody(parent: HTMLElement): void {
P
Peng Lyu 已提交
194
		this.body = document.createElement('div');
P
Peng Lyu 已提交
195 196 197
		DOM.addClass(this.body, 'cell-list-container');
		this.createCellList();
		DOM.append(parent, this.body);
P
Peng Lyu 已提交
198 199
	}

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

R
Rob Lourens 已提交
203
		const dndController = new CellDragAndDropController(this);
P
Peng Lyu 已提交
204
		const renders = [
R
Rob Lourens 已提交
205 206
			this.instantiationService.createInstance(CodeCellRenderer, this, this.contextKeyService, this.renderedEditors, dndController),
			this.instantiationService.createInstance(MarkdownCellRenderer, this.contextKeyService, this, dndController),
P
Peng Lyu 已提交
207 208
		];

J
João Moreno 已提交
209
		this.list = this.instantiationService.createInstance(
R
rebornix 已提交
210
			NotebookCellList,
P
Peng Lyu 已提交
211 212 213 214
			'NotebookCellList',
			this.body,
			this.instantiationService.createInstance(NotebookCellListDelegate),
			renders,
R
rebornix 已提交
215
			this.contextKeyService,
P
Peng Lyu 已提交
216 217
			{
				setRowLineHeight: false,
R
rebornix 已提交
218
				setRowHeight: false,
P
Peng Lyu 已提交
219 220 221
				supportDynamicHeights: true,
				horizontalScrolling: false,
				keyboardSupport: false,
R
rebornix 已提交
222
				mouseSupport: true,
P
Peng Lyu 已提交
223
				multipleSelectionSupport: false,
R
rebornix 已提交
224
				enableKeyboardNavigation: true,
225
				additionalScrollHeight: 0,
226
				styleController: (_suffix: string) => { return this.list!; },
P
Peng Lyu 已提交
227 228 229 230 231 232 233 234 235 236
				overrideStyles: {
					listBackground: editorBackground,
					listActiveSelectionBackground: editorBackground,
					listActiveSelectionForeground: foreground,
					listFocusAndSelectionBackground: editorBackground,
					listFocusAndSelectionForeground: foreground,
					listFocusBackground: editorBackground,
					listFocusForeground: foreground,
					listHoverForeground: foreground,
					listHoverBackground: editorBackground,
237 238
					listHoverOutline: focusBorder,
					listFocusOutline: focusBorder,
239 240 241 242
					listInactiveSelectionBackground: editorBackground,
					listInactiveSelectionForeground: foreground,
					listInactiveFocusBackground: editorBackground,
					listInactiveFocusOutline: editorBackground,
J
João Moreno 已提交
243 244 245
				},
				accessibilityProvider: {
					getAriaLabel() { return null; }
P
Peng Lyu 已提交
246
				}
R
rebornix 已提交
247
			},
P
Peng Lyu 已提交
248
		);
P
Peng Lyu 已提交
249

250
		this.control = new NotebookCodeEditors(this.list, this.renderedEditors);
251
		this.webview = this.instantiationService.createInstance(BackLayerWebView, this);
252 253 254 255 256
		this._register(this.webview.onMessage(message => {
			if (this.viewModel) {
				this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.viewModel.uri, message);
			}
		}));
R
rebornix 已提交
257
		this.list.rowsContainer.appendChild(this.webview.element);
R
rebornix 已提交
258

P
Peng Lyu 已提交
259
		this._register(this.list);
R
rebornix 已提交
260 261 262

		// transparent cover
		this.webviewTransparentCover = DOM.append(this.list.rowsContainer, $('.webview-cover'));
263
		this.webviewTransparentCover.style.display = 'none';
R
rebornix 已提交
264

R
rebornix 已提交
265
		this._register(DOM.addStandardDisposableGenericMouseDownListner(this._rootElement, (e: StandardMouseEvent) => {
R
rebornix 已提交
266 267 268 269 270
			if (DOM.hasClass(e.target, 'slider') && this.webviewTransparentCover) {
				this.webviewTransparentCover.style.display = 'block';
			}
		}));

R
rebornix 已提交
271
		this._register(DOM.addStandardDisposableGenericMouseUpListner(this._rootElement, (e: StandardMouseEvent) => {
R
rebornix 已提交
272 273
			if (this.webviewTransparentCover) {
				// no matter when
274
				this.webviewTransparentCover.style.display = 'none';
R
rebornix 已提交
275 276 277
			}
		}));

R
rebornix 已提交
278 279 280 281 282 283 284 285 286 287 288 289
		this._register(this.list.onMouseDown(e => {
			if (e.element) {
				this._onMouseDown.fire({ event: e.browserEvent, target: e.element });
			}
		}));

		this._register(this.list.onMouseUp(e => {
			if (e.element) {
				this._onMouseUp.fire({ event: e.browserEvent, target: e.element });
			}
		}));

P
Peng Lyu 已提交
290 291
	}

R
rebornix 已提交
292 293 294 295
	getDomNode() {
		return this._rootElement;
	}

296 297 298 299
	getControl() {
		return this.control;
	}

R
rebornix 已提交
300 301 302 303
	getInnerWebview(): Webview | undefined {
		return this.webview?.webview;
	}

304 305
	onWillHide() {
		if (this.input && this.input instanceof NotebookEditorInput && !this.input.isDisposed()) {
R
rebornix 已提交
306
			this.saveEditorViewState(this.input);
307 308
		}

R
rebornix 已提交
309
		this.editorFocus?.set(false);
310 311
		if (this.webview) {
			this.localStore.clear();
R
rebornix 已提交
312
			this.list?.rowsContainer.removeChild(this.webview?.element);
313 314 315 316
			this.webview?.dispose();
			this.webview = null;
		}

R
rebornix 已提交
317
		this.list?.clear();
318
		super.onHide();
P
Peng Lyu 已提交
319 320
	}

R
rebornix 已提交
321 322 323 324 325 326 327 328 329 330 331 332
	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) {
R
rebornix 已提交
333
			this.saveEditorViewState(editor);
334 335 336
		}
	}

R
rebornix 已提交
337 338 339
	focus() {
		super.focus();
		this.editorFocus?.set(true);
340
		this.list?.domFocus();
R
rebornix 已提交
341 342
	}

R
rebornix 已提交
343
	async setInput(input: NotebookEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
R
rebornix 已提交
344
		if (this.input instanceof NotebookEditorInput) {
R
rebornix 已提交
345
			this.saveEditorViewState(this.input);
R
rebornix 已提交
346 347
		}

R
rebornix 已提交
348 349
		await super.setInput(input, options, token);
		const model = await input.resolve();
P
Peng Lyu 已提交
350

351 352 353
		if (this.notebookViewModel === undefined || !this.notebookViewModel.equal(model) || this.webview === null) {
			this.detachModel();
			await this.attachModel(input, model);
R
rebornix 已提交
354
		}
P
Peng Lyu 已提交
355

356 357 358
		// reveal cell if editor options tell to do so
		if (options instanceof NotebookEditorOptions && options.cellOptions) {
			const cellOptions = options.cellOptions;
R
rebornix 已提交
359
			const cell = this.notebookViewModel!.viewCells.find(cell => cell.uri.toString() === cellOptions.resource.toString());
360
			if (cell) {
361
				this.selectElement(cell);
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
				this.revealInCenterIfOutsideViewport(cell);
				const editor = this.renderedEditors.get(cell)!;
				if (editor) {
					if (cellOptions.options?.selection) {
						const { selection } = cellOptions.options;
						editor.setSelection({
							...selection,
							endLineNumber: selection.endLineNumber || selection.startLineNumber,
							endColumn: selection.endColumn || selection.startColumn
						});
					}
					if (!cellOptions.options?.preserveFocus) {
						editor.focus();
					}
				}
377 378
			}
		}
R
rebornix 已提交
379
	}
380

R
rebornix 已提交
381 382 383 384
	clearInput(): void {
		super.clearInput();
	}

R
rebornix 已提交
385 386
	private detachModel() {
		this.localStore.clear();
R
rebornix 已提交
387
		this.list?.detachViewModel();
R
rebornix 已提交
388 389
		this.viewModel?.dispose();
		// avoid event
R
rebornix 已提交
390 391 392
		this.notebookViewModel = undefined;
		this.webview?.clearInsets();
		this.webview?.clearPreloadsCache();
R
rebornix 已提交
393
		this.list?.clear();
R
rebornix 已提交
394
	}
R
rebornix 已提交
395

R
rebornix 已提交
396 397
	private async attachModel(input: NotebookEditorInput, model: NotebookEditorModel) {
		if (!this.webview) {
398
			this.webview = this.instantiationService.createInstance(BackLayerWebView, this);
R
rebornix 已提交
399 400
			this.list?.rowsContainer.insertAdjacentElement('afterbegin', this.webview!.element);
		}
401

402 403
		await this.webview.waitForInitialization();

R
rebornix 已提交
404
		this.eventDispatcher = new NotebookEventDispatcher();
R
rebornix 已提交
405 406
		this.viewModel = this.instantiationService.createInstance(NotebookViewModel, input.viewType!, model, this.eventDispatcher, this.getLayoutInfo());
		this.editorEditable?.set(!!this.viewModel.metadata?.editable);
R
rebornix 已提交
407
		this.eventDispatcher.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]);
408

R
rebornix 已提交
409 410 411 412
		this.localStore.add(this.eventDispatcher.onDidChangeMetadata((e) => {
			this.editorEditable?.set(e.source.editable);
		}));

R
rebornix 已提交
413
		// restore view states, including contributions
R
rebornix 已提交
414
		const viewState = this.loadTextEditorViewState(input);
R
rebornix 已提交
415 416 417

		{
			// restore view state
R
rebornix 已提交
418
			this.viewModel.restoreEditorViewState(viewState);
R
rebornix 已提交
419 420

			// contribution state restore
R
rebornix 已提交
421 422 423 424 425 426 427 428 429 430

			const contributionsState = viewState?.contributionsState || {};
			const keys = Object.keys(this._contributions);
			for (let i = 0, len = keys.length; i < len; i++) {
				const id = keys[i];
				const contribution = this._contributions[id];
				if (typeof contribution.restoreViewState === 'function') {
					contribution.restoreViewState(contributionsState[id]);
				}
			}
R
rebornix 已提交
431
		}
432

R
rebornix 已提交
433
		this.webview?.updateRendererPreloads(this.viewModel.renderers);
R
rebornix 已提交
434 435 436

		this.localStore.add(this.list!.onWillScroll(e => {
			this.webview!.updateViewScrollTop(-e.scrollTop, []);
R
rebornix 已提交
437
			this.webviewTransparentCover!.style.top = `${e.scrollTop}px`;
R
rebornix 已提交
438 439 440
		}));

		this.localStore.add(this.list!.onDidChangeContentHeight(() => {
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
			DOM.scheduleAtNextAnimationFrame(() => {
				const scrollTop = this.list?.scrollTop || 0;
				const scrollHeight = this.list?.scrollHeight || 0;
				this.webview!.element.style.height = `${scrollHeight}px`;
				let updateItems: { cell: CodeCellViewModel, output: IOutput, cellTop: number }[] = [];

				if (this.webview?.insetMapping) {
					this.webview?.insetMapping.forEach((value, key) => {
						const cell = value.cell;
						const viewIndex = this.list?.getViewIndex(cell);

						if (viewIndex === undefined) {
							return;
						}

						const cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
						if (this.webview!.shouldUpdateInset(cell, key, cellTop)) {
							updateItems.push({
								cell: cell,
								output: key,
								cellTop: cellTop
							});
						}
					});

					if (updateItems.length) {
						this.webview?.updateViewScrollTop(-scrollTop, updateItems);
R
rebornix 已提交
468
					}
R
rebornix 已提交
469
				}
470
			});
R
rebornix 已提交
471 472
		}));

R
rebornix 已提交
473
		this.list!.attachViewModel(this.viewModel);
R
rebornix 已提交
474 475 476
		this.localStore.add(this.list!.onDidRemoveOutput(output => {
			this.removeInset(output);
		}));
477 478 479
		this.localStore.add(this.list!.onDidHideOutput(output => {
			this.hideInset(output);
		}));
R
rebornix 已提交
480 481

		this.list!.layout();
R
rebornix 已提交
482

R
rebornix 已提交
483
		// restore list state at last, it must be after list layout
484 485 486 487
		this.restoreTextEditorViewState(viewState);
	}

	private restoreTextEditorViewState(viewState: INotebookEditorViewState | undefined): void {
R
rebornix 已提交
488 489 490 491 492 493 494
		if (viewState?.scrollPosition !== undefined) {
			this.list!.scrollTop = viewState!.scrollPosition.top;
			this.list!.scrollLeft = viewState!.scrollPosition.left;
		} else {
			this.list!.scrollTop = 0;
			this.list!.scrollLeft = 0;
		}
495

496 497 498 499 500 501 502 503 504 505
		const focusIdx = typeof viewState?.focus === 'number' ? viewState.focus : 0;
		this.list!.setFocus([focusIdx]);
		this.list!.setSelection([focusIdx]);

		if (viewState?.editorFocused) {
			this.list?.focusView();
			const cell = this.notebookViewModel?.viewCells[focusIdx];
			if (cell) {
				cell.focusMode = CellFocusMode.Editor;
			}
506
		}
P
Peng Lyu 已提交
507 508
	}

R
rebornix 已提交
509
	private saveEditorViewState(input: NotebookEditorInput): void {
R
npe  
rebornix 已提交
510
		if (this.group && this.notebookViewModel) {
R
rebornix 已提交
511
			const state = this.notebookViewModel.geteEditorViewState();
R
rebornix 已提交
512 513
			if (this.list) {
				state.scrollPosition = { left: this.list.scrollLeft, top: this.list.scrollTop };
514
				let cellHeights: { [key: number]: number } = {};
R
rebornix 已提交
515
				for (let i = 0; i < this.viewModel!.length; i++) {
R
rebornix 已提交
516
					const elm = this.viewModel!.viewCells[i] as CellViewModel;
517 518 519 520 521 522 523 524
					if (elm.cellKind === CellKind.Code) {
						cellHeights[i] = elm.layoutInfo.totalHeight;
					} else {
						cellHeights[i] = 0;
					}
				}

				state.cellTotalHeights = cellHeights;
525 526 527

				const focus = this.list.getFocus()[0];
				if (focus) {
528 529 530 531 532 533 534 535
					const element = this.notebookViewModel!.viewCells[focus];
					const itemDOM = this.list?.domElementOfElement(element!);
					let editorFocused = false;
					if (document.activeElement && itemDOM && itemDOM.contains(document.activeElement)) {
						editorFocused = true;
					}

					state.editorFocused = editorFocused;
536 537
					state.focus = focus;
				}
R
rebornix 已提交
538 539
			}

R
rebornix 已提交
540
			// Save contribution view states
R
rebornix 已提交
541 542 543 544 545 546 547 548
			const contributionsState: { [key: string]: any } = {};

			const keys = Object.keys(this._contributions);
			for (const id of keys) {
				const contribution = this._contributions[id];
				if (typeof contribution.saveViewState === 'function') {
					contributionsState[id] = contribution.saveViewState();
				}
R
rebornix 已提交
549 550
			}

R
rebornix 已提交
551
			state.contributionsState = contributionsState;
R
rebornix 已提交
552
			this.editorMemento.saveEditorState(this.group, input.resource, state);
R
rebornix 已提交
553 554 555 556 557
		}
	}

	private loadTextEditorViewState(input: NotebookEditorInput): INotebookEditorViewState | undefined {
		if (this.group) {
R
rebornix 已提交
558
			return this.editorMemento.loadEditorState(this.group, input.resource);
R
rebornix 已提交
559 560 561 562 563 564 565
		}

		return;
	}

	layout(dimension: DOM.Dimension): void {
		this.dimension = new DOM.Dimension(dimension.width, dimension.height);
R
rebornix 已提交
566 567
		DOM.toggleClass(this._rootElement, 'mid-width', dimension.width < 1000 && dimension.width >= 600);
		DOM.toggleClass(this._rootElement, 'narrow-width', dimension.width < 600);
R
rebornix 已提交
568
		DOM.size(this.body, dimension.width, dimension.height);
569
		this.list?.updateOptions({ additionalScrollHeight: dimension.height });
R
rebornix 已提交
570
		this.list?.layout(dimension.height, dimension.width);
R
rebornix 已提交
571 572 573 574 575 576

		if (this.webviewTransparentCover) {
			this.webviewTransparentCover.style.height = `${dimension.height}px`;
			this.webviewTransparentCover.style.width = `${dimension.width}px`;
		}

R
rebornix 已提交
577
		this.eventDispatcher?.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]);
R
rebornix 已提交
578 579 580 581
	}

	protected saveState(): void {
		if (this.input instanceof NotebookEditorInput) {
R
rebornix 已提交
582
			this.saveEditorViewState(this.input);
R
rebornix 已提交
583 584 585 586 587 588 589
		}

		super.saveState();
	}

	//#endregion

R
rebornix 已提交
590 591
	//#region Editor Features

R
rebornix 已提交
592
	selectElement(cell: ICellViewModel) {
R
rebornix 已提交
593
		this.list?.selectElement(cell);
R
rebornix 已提交
594 595
	}

R
rebornix 已提交
596
	revealInView(cell: ICellViewModel) {
R
rebornix 已提交
597
		this.list?.revealElementInView(cell);
R
rebornix 已提交
598 599
	}

R
rebornix 已提交
600
	revealInCenterIfOutsideViewport(cell: ICellViewModel) {
R
rebornix 已提交
601
		this.list?.revealElementInCenterIfOutsideViewport(cell);
R
rebornix 已提交
602 603
	}

R
rebornix 已提交
604
	revealInCenter(cell: ICellViewModel) {
R
rebornix 已提交
605
		this.list?.revealElementInCenter(cell);
R
rebornix 已提交
606 607
	}

R
rebornix 已提交
608
	revealLineInView(cell: ICellViewModel, line: number): void {
R
rebornix 已提交
609
		this.list?.revealElementLineInView(cell, line);
R
rebornix 已提交
610
	}
R
rebornix 已提交
611

R
rebornix 已提交
612
	revealLineInCenter(cell: ICellViewModel, line: number) {
R
rebornix 已提交
613
		this.list?.revealElementLineInCenter(cell, line);
R
rebornix 已提交
614 615
	}

R
rebornix 已提交
616
	revealLineInCenterIfOutsideViewport(cell: ICellViewModel, line: number) {
R
rebornix 已提交
617
		this.list?.revealElementLineInCenterIfOutsideViewport(cell, line);
R
rebornix 已提交
618 619
	}

R
rebornix 已提交
620
	revealRangeInView(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
621
		this.list?.revealElementRangeInView(cell, range);
R
rebornix 已提交
622 623
	}

R
rebornix 已提交
624
	revealRangeInCenter(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
625
		this.list?.revealElementRangeInCenter(cell, range);
R
rebornix 已提交
626 627
	}

R
rebornix 已提交
628
	revealRangeInCenterIfOutsideViewport(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
629
		this.list?.revealElementRangeInCenterIfOutsideViewport(cell, range);
R
rebornix 已提交
630 631
	}

R
rebornix 已提交
632
	setCellSelection(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
633
		this.list?.setCellSelection(cell, range);
R
rebornix 已提交
634 635
	}

R
rebornix 已提交
636 637 638 639
	changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {
		return this.notebookViewModel?.changeDecorations(callback);
	}

R
rebornix 已提交
640
	setHiddenAreas(_ranges: ICellRange[]): boolean {
R
rebornix 已提交
641
		return this.list!.setHiddenAreas(_ranges, true);
R
rebornix 已提交
642 643
	}

R
rebornix 已提交
644 645
	//#endregion

R
rebornix 已提交
646 647 648 649 650 651 652 653 654
	//#region Mouse Events
	private readonly _onMouseUp: Emitter<INotebookEditorMouseEvent> = this._register(new Emitter<INotebookEditorMouseEvent>());
	public readonly onMouseUp: Event<INotebookEditorMouseEvent> = this._onMouseUp.event;

	private readonly _onMouseDown: Emitter<INotebookEditorMouseEvent> = this._register(new Emitter<INotebookEditorMouseEvent>());
	public readonly onMouseDown: Event<INotebookEditorMouseEvent> = this._onMouseDown.event;

	//#endregion

R
rebornix 已提交
655
	//#region Cell operations
656
	async layoutNotebookCell(cell: ICellViewModel, height: number): Promise<void> {
657 658 659 660 661 662
		const viewIndex = this.list!.getViewIndex(cell);
		if (viewIndex === undefined) {
			// the cell is hidden
			return;
		}

R
rebornix 已提交
663
		let relayout = (cell: ICellViewModel, height: number) => {
R
rebornix 已提交
664
			this.list?.updateElementHeight2(cell, height);
R
rebornix 已提交
665 666
		};

667
		let r: () => void;
R
rebornix 已提交
668
		DOM.scheduleAtNextAnimationFrame(() => {
R
rebornix 已提交
669
			relayout(cell, height);
670
			r();
R
rebornix 已提交
671
		});
672 673

		return new Promise(resolve => { r = resolve; });
674 675
	}

676
	insertNotebookCell(cell: ICellViewModel, type: CellKind, direction: 'above' | 'below', initialText: string = ''): CellViewModel {
R
rebornix 已提交
677 678
		const newLanguages = this.notebookViewModel!.languages;
		const language = newLanguages && newLanguages.length ? newLanguages[0] : 'markdown';
R
rebornix 已提交
679
		const index = this.notebookViewModel!.getCellIndex(cell);
P
Peng Lyu 已提交
680
		const insertIndex = direction === 'above' ? index : index + 1;
R
rebornix 已提交
681
		const newCell = this.notebookViewModel!.createCell(insertIndex, initialText.split(/\r?\n/g), language, type, true);
P
Peng Lyu 已提交
682

R
rebornix 已提交
683
		if (type === CellKind.Markdown) {
684
			newCell.editState = CellEditState.Editing;
P
Peng Lyu 已提交
685
		}
R
rebornix 已提交
686

687
		return newCell;
P
Peng Lyu 已提交
688 689
	}

690
	async deleteNotebookCell(cell: ICellViewModel): Promise<boolean> {
691
		(cell as CellViewModel).save();
R
rebornix 已提交
692
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
693
		this.notebookViewModel!.deleteCell(index, true);
694
		return true;
R
rebornix 已提交
695 696
	}

697
	async moveCellDown(cell: ICellViewModel): Promise<boolean> {
R
rebornix 已提交
698
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
699
		if (index === this.notebookViewModel!.length - 1) {
700
			return false;
R
rebornix 已提交
701 702
		}

703
		const newIdx = index + 1;
704
		return this.moveCellToIndex(index, newIdx);
705 706
	}

707
	async moveCellUp(cell: ICellViewModel): Promise<boolean> {
R
rebornix 已提交
708
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
709
		if (index === 0) {
710
			return false;
R
rebornix 已提交
711 712
		}

713
		const newIdx = index - 1;
714
		return this.moveCellToIndex(index, newIdx);
715 716
	}

717
	async moveCell(cell: ICellViewModel, relativeToCell: ICellViewModel, direction: 'above' | 'below'): Promise<boolean> {
R
Rob Lourens 已提交
718
		if (cell === relativeToCell) {
719
			return false;
R
Rob Lourens 已提交
720 721 722 723 724 725 726 727 728
		}

		const originalIdx = this.notebookViewModel!.getCellIndex(cell);
		const relativeToIndex = this.notebookViewModel!.getCellIndex(relativeToCell);

		const newIdx = direction === 'above' ? relativeToIndex : relativeToIndex + 1;
		return this.moveCellToIndex(originalIdx, newIdx);
	}

729
	private async moveCellToIndex(index: number, newIdx: number): Promise<boolean> {
R
rebornix 已提交
730
		if (!this.notebookViewModel!.moveCellToIdx(index, newIdx, true)) {
731
			throw new Error('Notebook Editor move cell, index out of range');
732 733
		}

734
		let r: (val: boolean) => void;
735
		DOM.scheduleAtNextAnimationFrame(() => {
736
			this.list?.revealElementInView(this.notebookViewModel!.viewCells[newIdx]);
737
			r(true);
738
		});
739 740

		return new Promise(resolve => { r = resolve; });
741 742
	}

R
rebornix 已提交
743
	editNotebookCell(cell: CellViewModel): void {
744
		cell.editState = CellEditState.Editing;
R
rebornix 已提交
745 746

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

R
rebornix 已提交
749
	saveNotebookCell(cell: ICellViewModel): void {
750
		cell.editState = CellEditState.Preview;
P
Peng Lyu 已提交
751 752
	}

R
rebornix 已提交
753 754 755 756 757 758 759 760 761 762
	getActiveCell() {
		let elements = this.list?.getFocusedElements();

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

		return undefined;
	}

763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
	cancelNotebookExecution(): void {
		if (!this.notebookViewModel!.currentTokenSource) {
			throw new Error('Notebook is not executing');
		}


		this.notebookViewModel!.currentTokenSource.cancel();
		this.notebookViewModel!.currentTokenSource = undefined;
	}

	async executeNotebook(): Promise<void> {
		// return this.progressService.showWhile(this._executeNotebook());
		return this._executeNotebook();
	}

	async _executeNotebook(): Promise<void> {
		if (this.notebookViewModel!.currentTokenSource) {
			return;
		}

		const tokenSource = new CancellationTokenSource();
		try {
			this.editorExecutingNotebook!.set(true);
			this.notebookViewModel!.currentTokenSource = tokenSource;

			for (let cell of this.notebookViewModel!.viewCells) {
				if (cell.cellKind === CellKind.Code) {
					await this._executeNotebookCell(cell, tokenSource);
				}
			}
		} finally {
			this.editorExecutingNotebook!.set(false);
			this.notebookViewModel!.currentTokenSource = undefined;
			tokenSource.dispose();
		}
	}

	cancelNotebookCellExecution(cell: ICellViewModel): void {
		if (!cell.currentTokenSource) {
			throw new Error('Cell is not executing');
		}

		cell.currentTokenSource.cancel();
		cell.currentTokenSource = undefined;
	}

809
	async executeNotebookCell(cell: ICellViewModel): Promise<void> {
810
		const tokenSource = new CancellationTokenSource();
811 812 813 814 815 816 817
		try {
			this._executeNotebookCell(cell, tokenSource);
		} finally {
			tokenSource.dispose();
		}
	}

R
Rob Lourens 已提交
818
	private async _executeNotebookCell(cell: ICellViewModel, tokenSource: CancellationTokenSource): Promise<void> {
819
		try {
820
			cell.currentTokenSource = tokenSource;
R
rebornix 已提交
821
			const provider = this.notebookService.getContributedNotebookProviders(this.viewModel!.uri)[0];
822 823 824 825
			if (provider) {
				const viewType = provider.id;
				const notebookUri = CellUri.parse(cell.uri)?.notebook;
				if (notebookUri) {
826
					return await this.notebookService.executeNotebookCell(viewType, notebookUri, cell.handle, tokenSource.token);
827 828 829
				}
			}
		} finally {
830
			cell.currentTokenSource = undefined;
831 832 833
		}
	}

R
rebornix 已提交
834
	focusNotebookCell(cell: ICellViewModel, focusEditor: boolean) {
R
rebornix 已提交
835
		if (focusEditor) {
R
rebornix 已提交
836
			this.selectElement(cell);
R
rebornix 已提交
837
			this.list?.focusView();
R
rebornix 已提交
838

839
			cell.editState = CellEditState.Editing;
R
rebornix 已提交
840
			cell.focusMode = CellFocusMode.Editor;
841
			this.revealInCenterIfOutsideViewport(cell);
R
rebornix 已提交
842
		} else {
R
rebornix 已提交
843
			let itemDOM = this.list?.domElementOfElement(cell);
R
rebornix 已提交
844 845 846
			if (document.activeElement && itemDOM && itemDOM.contains(document.activeElement)) {
				(document.activeElement as HTMLElement).blur();
			}
847

848
			cell.editState = CellEditState.Preview;
849
			cell.focusMode = CellFocusMode.Container;
R
rebornix 已提交
850

R
rebornix 已提交
851
			this.selectElement(cell);
852
			this.revealInCenterIfOutsideViewport(cell);
R
rebornix 已提交
853
			this.list?.focusView();
R
rebornix 已提交
854 855 856
		}
	}

R
rebornix 已提交
857 858 859 860
	//#endregion

	//#region MISC

R
rebornix 已提交
861 862 863 864 865 866 867 868 869 870 871
	getLayoutInfo(): NotebookLayoutInfo {
		if (!this.list) {
			throw new Error('Editor is not initalized successfully');
		}

		return {
			width: this.dimension!.width,
			height: this.dimension!.height,
			fontInfo: this.fontInfo!
		};
	}
R
rebornix 已提交
872

R
rebornix 已提交
873 874
	triggerScroll(event: IMouseWheelEvent) {
		this.list?.triggerScrollFromMouseWheelEvent(event);
R
rebornix 已提交
875 876
	}

R
rebornix 已提交
877
	createInset(cell: CodeCellViewModel, output: IOutput, shadowContent: string, offset: number) {
R
rebornix 已提交
878 879
		if (!this.webview) {
			return;
R
rebornix 已提交
880 881
		}

R
rebornix 已提交
882
		let preloads = this.notebookViewModel!.renderers;
R
rebornix 已提交
883

884
		if (!this.webview!.insetMapping.has(output)) {
R
rebornix 已提交
885
			let cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
886
			this.webview!.createInset(cell, output, cellTop, offset, shadowContent, preloads);
R
rebornix 已提交
887
		} else {
R
rebornix 已提交
888
			let cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
R
rebornix 已提交
889 890
			let scrollTop = this.list?.scrollTop || 0;

891
			this.webview!.updateViewScrollTop(-scrollTop, [{ cell: cell, output: output, cellTop: cellTop }]);
R
rebornix 已提交
892
		}
R
rebornix 已提交
893
	}
R
rebornix 已提交
894

R
rebornix 已提交
895 896 897 898 899 900 901 902
	removeInset(output: IOutput) {
		if (!this.webview) {
			return;
		}

		this.webview!.removeInset(output);
	}

903 904 905 906 907 908 909 910
	hideInset(output: IOutput) {
		if (!this.webview) {
			return;
		}

		this.webview!.hideInset(output);
	}

R
rebornix 已提交
911 912
	getOutputRenderer(): OutputRenderer {
		return this.outputRenderer;
R
rebornix 已提交
913
	}
914

915 916 917 918
	postMessage(message: any) {
		this.webview?.webview.sendMessage(message);
	}

R
rebornix 已提交
919
	//#endregion
920

R
rebornix 已提交
921 922 923 924 925 926
	//#region Editor Contributions
	public getContribution<T extends INotebookEditorContribution>(id: string): T {
		return <T>(this._contributions[id] || null);
	}

	//#endregion
R
rebornix 已提交
927

R
rebornix 已提交
928 929 930 931 932 933 934 935 936 937
	dispose() {
		const keys = Object.keys(this._contributions);
		for (let i = 0, len = keys.length; i < len; i++) {
			const contributionId = keys[i];
			this._contributions[contributionId].dispose();
		}

		super.dispose();
	}

938 939 940 941 942
	toJSON(): any {
		return {
			notebookHandle: this.viewModel?.handle
		};
	}
P
Peng Lyu 已提交
943 944 945 946
}

const embeddedEditorBackground = 'walkThrough.embeddedEditorBackground';

947 948 949 950 951 952
export const focusedCellIndicator = registerColor('notebook.focusedCellIndicator', {
	light: new Color(new RGBA(102, 175, 224)),
	dark: new Color(new RGBA(12, 125, 157)),
	hc: new Color(new RGBA(0, 73, 122))
}, nls.localize('notebook.focusedCellIndicator', "The color of the focused notebook cell indicator."));

953 954 955 956 957 958 959
export const notebookOutputContainerColor = registerColor('notebook.outputContainerBackgroundColor', {
	dark: new Color(new RGBA(255, 255, 255, 0.06)),
	light: new Color(new RGBA(228, 230, 241)),
	hc: null
}
	, nls.localize('notebook.outputContainerBackgroundColor', "The Color of the notebook output container background."));

R
Rob Lourens 已提交
960
// TODO currently also used for toolbar border, if we keep all of this, pick a generic name
R
rebornix 已提交
961 962 963 964 965 966
export const CELL_TOOLBAR_SEPERATOR = registerColor('notebook.cellToolbarSeperator', {
	dark: Color.fromHex('#808080').transparent(0.35),
	light: Color.fromHex('#808080').transparent(0.35),
	hc: contrastBorder
}, nls.localize('cellToolbarSeperator', "The color of seperator in Cell bottom toolbar"));

967

P
Peng Lyu 已提交
968 969 970
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 已提交
971
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .monaco-editor-background,
R
Rob Lourens 已提交
972 973
			.monaco-workbench .part.editor > .content .notebook-editor .cell .margin-view-overlays,
			.monaco-workbench .part.editor > .content .notebook-editor .cell .cell-statusbar-container { background: ${color}; }`);
974
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-drag-image .cell-editor-container > div { background: ${color} !important; }`);
P
Peng Lyu 已提交
975 976 977
	}
	const link = theme.getColor(textLinkForeground);
	if (link) {
R
Rob Lourens 已提交
978
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .output a { color: ${link}; }`);
P
Peng Lyu 已提交
979 980 981
	}
	const activeLink = theme.getColor(textLinkActiveForeground);
	if (activeLink) {
R
Rob Lourens 已提交
982 983
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .output a:hover,
			.monaco-workbench .part.editor > .content .notebook-editor .cell .output a:active { color: ${activeLink}; }`);
P
Peng Lyu 已提交
984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001
	}
	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}; }`);
	}
1002

1003 1004 1005
	const containerBackground = theme.getColor(notebookOutputContainerColor);
	if (containerBackground) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { background-color: ${containerBackground}; }`);
1006
	}
1007

R
Rob Lourens 已提交
1008 1009 1010
	const editorBackgroundColor = theme.getColor(editorBackground);
	if (editorBackgroundColor) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-statusbar-container { border-top: solid 1px ${editorBackgroundColor}; }`);
R
Rob Lourens 已提交
1011
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar { background-color: ${editorBackgroundColor}; }`);
R
Rob Lourens 已提交
1012
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.cell-drag-image { background-color: ${editorBackgroundColor}; }`);
1013 1014
	}

R
rebornix 已提交
1015 1016 1017 1018
	const cellToolbarSeperator = theme.getColor(CELL_TOOLBAR_SEPERATOR);
	if (cellToolbarSeperator) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-bottom-toolbar-container .seperator { background-color: ${cellToolbarSeperator} }`);
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-bottom-toolbar-container .seperator-short { background-color: ${cellToolbarSeperator} }`);
R
Rob Lourens 已提交
1019
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar { border: solid 1px ${cellToolbarSeperator}; }`);
R
Rob Lourens 已提交
1020 1021 1022 1023 1024 1025
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .notebook-cell-focus-indicator { border-color: ${cellToolbarSeperator}; }`);
	}

	const focusedCellIndicatorColor = theme.getColor(focusedCellIndicator);
	if (focusedCellIndicatorColor) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.focused .notebook-cell-focus-indicator { border-color: ${focusedCellIndicatorColor}; }`);
1026
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .notebook-cell-focus-indicator { border-color: ${focusedCellIndicatorColor}; }`);
R
Rob Lourens 已提交
1027
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .notebook-cell-insertion-indicator-top { background-color: ${focusedCellIndicatorColor}; }`);
R
Rob Lourens 已提交
1028
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.cell-editor-focus .cell-editor-part:before { outline: solid 1px ${focusedCellIndicatorColor}; }`);
R
rebornix 已提交
1029 1030
	}

1031
	// Cell Margin
R
rebornix 已提交
1032 1033
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row  > div.cell { margin: 0px ${CELL_MARGIN}px 0px ${CELL_MARGIN}px; }`);
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row { padding-top: ${EDITOR_TOP_MARGIN}px; }`);
1034
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 0px ${CELL_MARGIN}px 0px ${CELL_MARGIN + CELL_RUN_GUTTER}px }`);
R
rebornix 已提交
1035
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-bottom-toolbar-container { width: calc(100% - ${CELL_MARGIN * 2 + CELL_RUN_GUTTER}px); margin: 0px ${CELL_MARGIN}px 0px ${CELL_MARGIN + CELL_RUN_GUTTER}px }`);
R
Rob Lourens 已提交
1036

1037
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .markdown-cell-row .cell .cell-editor-part { margin-left: ${CELL_RUN_GUTTER}px; }`);
R
rebornix 已提交
1038
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row  > div.cell.markdown { padding-left: ${CELL_RUN_GUTTER}px; }`);
R
Rob Lourens 已提交
1039
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .run-button-container { width: ${CELL_RUN_GUTTER}px; }`);
R
Rob Lourens 已提交
1040
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list .monaco-list-row .notebook-cell-insertion-indicator-top { left: ${CELL_MARGIN + CELL_RUN_GUTTER}px; right: ${CELL_MARGIN}px; }`);
1041
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-drag-image .cell-editor-container > div { padding: ${EDITOR_TOP_PADDING}px 16px ${EDITOR_BOTTOM_PADDING}px 16px; }`);
P
Peng Lyu 已提交
1042
});