notebookEditor.ts 39.7 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';
32
import { NotebookFindWidget } from 'vs/workbench/contrib/notebook/browser/contrib/notebookFindWidget';
R
rebornix 已提交
33
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 已提交
34
import { NotebookEditorInput, NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
R
rebornix 已提交
35
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
36
import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList';
R
rebornix 已提交
37 38
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 已提交
39
import { CodeCellRenderer, MarkdownCellRenderer, NotebookCellListDelegate, CellDragAndDropController } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer';
R
rebornix 已提交
40
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
R
rebornix 已提交
41
import { NotebookEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
42 43
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 已提交
44
import { Webview } from 'vs/workbench/contrib/webview/browser/webview';
45 46
import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
R
rebornix 已提交
47 48
import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions';
import { onUnexpectedError } from 'vs/base/common/errors';
P
Peng Lyu 已提交
49 50

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

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
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 已提交
68
export class NotebookCodeEditors implements ICompositeCodeEditor {
69

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

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

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

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

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

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

		this.editorMemento = this.getEditorMemento<INotebookEditorViewState>(editorGroupService, NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY);
R
rebornix 已提交
130
		this.outputRenderer = new OutputRenderer(this, this.instantiationService);
R
rebornix 已提交
131
		this.findWidget = this.instantiationService.createInstance(NotebookFindWidget, this);
132
		this.findWidget.updateTheme(this.themeService.getColorTheme());
R
rebornix 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153

		this._contributions = {};
		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);
			}
		}
	}

	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 已提交
154 155
	}

R
rebornix 已提交
156 157 158 159
	get viewModel() {
		return this.notebookViewModel;
	}

P
Peng Lyu 已提交
160 161 162 163 164 165 166 167
	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 已提交
168
	//#region Editor Core
R
rebornix 已提交
169

R
rebornix 已提交
170 171 172 173 174

	public get isNotebookEditor() {
		return true;
	}

P
Peng Lyu 已提交
175 176 177
	protected createEditor(parent: HTMLElement): void {
		this.rootElement = DOM.append(parent, $('.notebook-editor'));
		this.createBody(this.rootElement);
178
		this.generateFontInfo();
R
rebornix 已提交
179
		this.editorFocus = NOTEBOOK_EDITOR_FOCUSED.bindTo(this.contextKeyService);
180
		this.editorFocus.set(true);
R
rebornix 已提交
181 182 183 184 185 186 187
		this._register(this.onDidFocus(() => {
			this.editorFocus?.set(true);
		}));

		this._register(this.onDidBlur(() => {
			this.editorFocus?.set(false);
		}));
R
rebornix 已提交
188 189 190

		this.editorEditable = NOTEBOOK_EDITOR_EDITABLE.bindTo(this.contextKeyService);
		this.editorEditable.set(true);
191
		this.editorExecutingNotebook = NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK.bindTo(this.contextKeyService);
192 193 194 195 196
	}

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

	private createBody(parent: HTMLElement): void {
P
Peng Lyu 已提交
200
		this.body = document.createElement('div');
P
Peng Lyu 已提交
201 202 203
		DOM.addClass(this.body, 'cell-list-container');
		this.createCellList();
		DOM.append(parent, this.body);
R
rebornix 已提交
204
		DOM.append(parent, this.findWidget.getDomNode());
P
Peng Lyu 已提交
205 206
	}

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

R
Rob Lourens 已提交
210
		const dndController = new CellDragAndDropController(this);
P
Peng Lyu 已提交
211
		const renders = [
R
Rob Lourens 已提交
212 213
			this.instantiationService.createInstance(CodeCellRenderer, this, this.contextKeyService, this.renderedEditors, dndController),
			this.instantiationService.createInstance(MarkdownCellRenderer, this.contextKeyService, this, dndController),
P
Peng Lyu 已提交
214 215
		];

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

257
		this.control = new NotebookCodeEditors(this.list, this.renderedEditors);
258
		this.webview = this.instantiationService.createInstance(BackLayerWebView, this);
259 260 261 262 263
		this._register(this.webview.onMessage(message => {
			if (this.viewModel) {
				this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.viewModel.uri, message);
			}
		}));
R
rebornix 已提交
264
		this.list.rowsContainer.appendChild(this.webview.element);
R
rebornix 已提交
265

P
Peng Lyu 已提交
266
		this._register(this.list);
R
rebornix 已提交
267 268 269

		// transparent cover
		this.webviewTransparentCover = DOM.append(this.list.rowsContainer, $('.webview-cover'));
270
		this.webviewTransparentCover.style.display = 'none';
R
rebornix 已提交
271 272 273 274 275 276 277 278 279 280

		this._register(DOM.addStandardDisposableGenericMouseDownListner(this.rootElement, (e: StandardMouseEvent) => {
			if (DOM.hasClass(e.target, 'slider') && this.webviewTransparentCover) {
				this.webviewTransparentCover.style.display = 'block';
			}
		}));

		this._register(DOM.addStandardDisposableGenericMouseUpListner(this.rootElement, (e: StandardMouseEvent) => {
			if (this.webviewTransparentCover) {
				// no matter when
281
				this.webviewTransparentCover.style.display = 'none';
R
rebornix 已提交
282 283 284
			}
		}));

R
rebornix 已提交
285 286 287 288 289 290 291 292 293 294 295 296
		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 已提交
297 298
	}

299 300 301 302
	getControl() {
		return this.control;
	}

R
rebornix 已提交
303 304 305 306
	getInnerWebview(): Webview | undefined {
		return this.webview?.webview;
	}

307 308
	onWillHide() {
		if (this.input && this.input instanceof NotebookEditorInput && !this.input.isDisposed()) {
R
rebornix 已提交
309
			this.saveEditorViewState(this.input);
310 311
		}

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

R
rebornix 已提交
320
		this.list?.clear();
321
		super.onHide();
P
Peng Lyu 已提交
322 323
	}

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

R
rebornix 已提交
340 341 342
	focus() {
		super.focus();
		this.editorFocus?.set(true);
343
		this.list?.domFocus();
R
rebornix 已提交
344 345
	}

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

R
rebornix 已提交
351 352
		await super.setInput(input, options, token);
		const model = await input.resolve();
P
Peng Lyu 已提交
353

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

359 360 361
		// reveal cell if editor options tell to do so
		if (options instanceof NotebookEditorOptions && options.cellOptions) {
			const cellOptions = options.cellOptions;
R
rebornix 已提交
362
			const cell = this.notebookViewModel!.viewCells.find(cell => cell.uri.toString() === cellOptions.resource.toString());
363
			if (cell) {
364
				this.selectElement(cell);
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
				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();
					}
				}
380 381
			}
		}
R
rebornix 已提交
382
	}
383

R
rebornix 已提交
384 385 386 387
	clearInput(): void {
		super.clearInput();
	}

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

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

406 407
		await this.webview.waitForInitialization();

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

R
rebornix 已提交
413 414 415 416
		this.localStore.add(this.eventDispatcher.onDidChangeMetadata((e) => {
			this.editorEditable?.set(e.source.editable);
		}));

R
rebornix 已提交
417
		// restore view states, including contributions
R
rebornix 已提交
418
		const viewState = this.loadTextEditorViewState(input);
R
rebornix 已提交
419 420 421

		{
			// restore view state
R
rebornix 已提交
422
			this.viewModel.restoreEditorViewState(viewState);
R
rebornix 已提交
423 424

			// contribution state restore
R
rebornix 已提交
425 426 427 428 429 430 431 432 433 434

			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 已提交
435
		}
436

R
rebornix 已提交
437
		this.webview?.updateRendererPreloads(this.viewModel.renderers);
R
rebornix 已提交
438 439 440

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

		this.localStore.add(this.list!.onDidChangeContentHeight(() => {
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
			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 已提交
472
					}
R
rebornix 已提交
473
				}
474
			});
R
rebornix 已提交
475 476
		}));

R
rebornix 已提交
477
		this.list!.attachViewModel(this.viewModel);
R
rebornix 已提交
478 479 480
		this.localStore.add(this.list!.onDidRemoveOutput(output => {
			this.removeInset(output);
		}));
481 482 483
		this.localStore.add(this.list!.onDidHideOutput(output => {
			this.hideInset(output);
		}));
R
rebornix 已提交
484 485

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

R
rebornix 已提交
487
		// restore list state at last, it must be after list layout
488 489 490 491
		this.restoreTextEditorViewState(viewState);
	}

	private restoreTextEditorViewState(viewState: INotebookEditorViewState | undefined): void {
R
rebornix 已提交
492 493 494 495 496 497 498
		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;
		}
499

500 501 502 503 504 505 506 507 508 509
		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;
			}
510
		}
P
Peng Lyu 已提交
511 512
	}

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

				state.cellTotalHeights = cellHeights;
529 530 531

				const focus = this.list.getFocus()[0];
				if (focus) {
532 533 534 535 536 537 538 539
					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;
540 541
					state.focus = focus;
				}
R
rebornix 已提交
542 543
			}

R
rebornix 已提交
544
			// Save contribution view states
R
rebornix 已提交
545 546 547 548 549 550 551 552
			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 已提交
553 554
			}

R
rebornix 已提交
555
			state.contributionsState = contributionsState;
R
rebornix 已提交
556
			this.editorMemento.saveEditorState(this.group, input.resource, state);
R
rebornix 已提交
557 558 559 560 561
		}
	}

	private loadTextEditorViewState(input: NotebookEditorInput): INotebookEditorViewState | undefined {
		if (this.group) {
R
rebornix 已提交
562
			return this.editorMemento.loadEditorState(this.group, input.resource);
R
rebornix 已提交
563 564 565 566 567 568 569 570 571 572
		}

		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);
573
		this.list?.updateOptions({ additionalScrollHeight: dimension.height });
R
rebornix 已提交
574
		this.list?.layout(dimension.height, dimension.width);
R
rebornix 已提交
575 576 577 578 579 580

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

R
rebornix 已提交
581
		this.eventDispatcher?.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]);
R
rebornix 已提交
582 583 584 585
	}

	protected saveState(): void {
		if (this.input instanceof NotebookEditorInput) {
R
rebornix 已提交
586
			this.saveEditorViewState(this.input);
R
rebornix 已提交
587 588 589 590 591 592 593
		}

		super.saveState();
	}

	//#endregion

R
rebornix 已提交
594 595
	//#region Editor Features

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

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

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

R
rebornix 已提交
608
	revealInCenter(cell: ICellViewModel) {
R
rebornix 已提交
609
		this.list?.revealElementInCenter(cell);
R
rebornix 已提交
610 611
	}

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

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

R
rebornix 已提交
620
	revealLineInCenterIfOutsideViewport(cell: ICellViewModel, line: number) {
R
rebornix 已提交
621
		this.list?.revealElementLineInCenterIfOutsideViewport(cell, line);
R
rebornix 已提交
622 623
	}

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

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

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

R
rebornix 已提交
636
	setCellSelection(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
637
		this.list?.setCellSelection(cell, range);
R
rebornix 已提交
638 639
	}

R
rebornix 已提交
640 641 642 643
	changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {
		return this.notebookViewModel?.changeDecorations(callback);
	}

R
rebornix 已提交
644
	setHiddenAreas(_ranges: ICellRange[]): boolean {
R
rebornix 已提交
645
		return this.list!.setHiddenAreas(_ranges, true);
R
rebornix 已提交
646 647
	}

R
rebornix 已提交
648 649
	//#endregion

R
rebornix 已提交
650 651 652 653 654 655 656 657
	//#region Find Delegate

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

	public hideFind() {
		this.findWidget.hide();
R
rebornix 已提交
658
		this.focus();
R
rebornix 已提交
659 660 661 662
	}

	//#endregion

R
rebornix 已提交
663 664 665 666 667 668 669 670 671
	//#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 已提交
672
	//#region Cell operations
673
	async layoutNotebookCell(cell: ICellViewModel, height: number): Promise<void> {
674 675 676 677 678 679
		const viewIndex = this.list!.getViewIndex(cell);
		if (viewIndex === undefined) {
			// the cell is hidden
			return;
		}

R
rebornix 已提交
680
		let relayout = (cell: ICellViewModel, height: number) => {
R
rebornix 已提交
681
			this.list?.updateElementHeight2(cell, height);
R
rebornix 已提交
682 683
		};

684
		let r: () => void;
R
rebornix 已提交
685
		DOM.scheduleAtNextAnimationFrame(() => {
R
rebornix 已提交
686
			relayout(cell, height);
687
			r();
R
rebornix 已提交
688
		});
689 690

		return new Promise(resolve => { r = resolve; });
691 692
	}

R
rebornix 已提交
693
	async insertNotebookCell(cell: ICellViewModel, type: CellKind, direction: 'above' | 'below', initialText: string = ''): Promise<CellViewModel> {
R
rebornix 已提交
694 695
		const newLanguages = this.notebookViewModel!.languages;
		const language = newLanguages && newLanguages.length ? newLanguages[0] : 'markdown';
R
rebornix 已提交
696
		const index = this.notebookViewModel!.getCellIndex(cell);
P
Peng Lyu 已提交
697
		const insertIndex = direction === 'above' ? index : index + 1;
R
rebornix 已提交
698
		const newCell = this.notebookViewModel!.createCell(insertIndex, initialText.split(/\r?\n/g), language, type, true);
R
rebornix 已提交
699
		this.list?.focusElement(newCell);
P
Peng Lyu 已提交
700

R
rebornix 已提交
701
		if (type === CellKind.Markdown) {
702
			newCell.editState = CellEditState.Editing;
P
Peng Lyu 已提交
703
		}
R
rebornix 已提交
704

R
rebornix 已提交
705
		let r: (cell: CellViewModel) => void;
R
rebornix 已提交
706
		DOM.scheduleAtNextAnimationFrame(() => {
R
rebornix 已提交
707
			this.list?.revealElementInCenterIfOutsideViewport(cell);
R
rebornix 已提交
708
			r(newCell);
R
rebornix 已提交
709
		});
710 711

		return new Promise(resolve => { r = resolve; });
P
Peng Lyu 已提交
712 713
	}

714
	async deleteNotebookCell(cell: ICellViewModel): Promise<boolean> {
715
		(cell as CellViewModel).save();
R
rebornix 已提交
716
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
717
		this.notebookViewModel!.deleteCell(index, true);
718
		return true;
R
rebornix 已提交
719 720
	}

721
	async moveCellDown(cell: ICellViewModel): Promise<boolean> {
R
rebornix 已提交
722
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
723
		if (index === this.notebookViewModel!.length - 1) {
724
			return false;
R
rebornix 已提交
725 726
		}

727
		const newIdx = index + 1;
728
		return this.moveCellToIndex(index, newIdx);
729 730
	}

731
	async moveCellUp(cell: ICellViewModel): Promise<boolean> {
R
rebornix 已提交
732
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
733
		if (index === 0) {
734
			return false;
R
rebornix 已提交
735 736
		}

737
		const newIdx = index - 1;
738
		return this.moveCellToIndex(index, newIdx);
739 740
	}

741
	async moveCell(cell: ICellViewModel, relativeToCell: ICellViewModel, direction: 'above' | 'below'): Promise<boolean> {
R
Rob Lourens 已提交
742
		if (cell === relativeToCell) {
743
			return false;
R
Rob Lourens 已提交
744 745 746 747 748 749 750 751 752
		}

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

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

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

758
		let r: (val: boolean) => void;
759
		DOM.scheduleAtNextAnimationFrame(() => {
760
			this.list?.revealElementInView(this.notebookViewModel!.viewCells[newIdx]);
761
			r(true);
762
		});
763 764

		return new Promise(resolve => { r = resolve; });
765 766
	}

R
rebornix 已提交
767
	editNotebookCell(cell: CellViewModel): void {
768
		cell.editState = CellEditState.Editing;
R
rebornix 已提交
769 770

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

R
rebornix 已提交
773
	saveNotebookCell(cell: ICellViewModel): void {
774
		cell.editState = CellEditState.Preview;
P
Peng Lyu 已提交
775 776
	}

R
rebornix 已提交
777 778 779 780 781 782 783 784 785 786
	getActiveCell() {
		let elements = this.list?.getFocusedElements();

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

		return undefined;
	}

787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
	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;
	}

833
	async executeNotebookCell(cell: ICellViewModel): Promise<void> {
834
		const tokenSource = new CancellationTokenSource();
835 836 837 838 839 840 841
		try {
			this._executeNotebookCell(cell, tokenSource);
		} finally {
			tokenSource.dispose();
		}
	}

R
Rob Lourens 已提交
842
	private async _executeNotebookCell(cell: ICellViewModel, tokenSource: CancellationTokenSource): Promise<void> {
843
		try {
844
			cell.currentTokenSource = tokenSource;
R
rebornix 已提交
845
			const provider = this.notebookService.getContributedNotebookProviders(this.viewModel!.uri)[0];
846 847 848 849
			if (provider) {
				const viewType = provider.id;
				const notebookUri = CellUri.parse(cell.uri)?.notebook;
				if (notebookUri) {
850
					return await this.notebookService.executeNotebookCell(viewType, notebookUri, cell.handle, tokenSource.token);
851 852 853
				}
			}
		} finally {
854
			cell.currentTokenSource = undefined;
855 856 857
		}
	}

R
rebornix 已提交
858
	focusNotebookCell(cell: ICellViewModel, focusEditor: boolean) {
R
rebornix 已提交
859
		if (focusEditor) {
R
rebornix 已提交
860
			this.selectElement(cell);
R
rebornix 已提交
861
			this.list?.focusView();
R
rebornix 已提交
862

863
			cell.editState = CellEditState.Editing;
R
rebornix 已提交
864
			cell.focusMode = CellFocusMode.Editor;
865
			this.revealInCenterIfOutsideViewport(cell);
R
rebornix 已提交
866
		} else {
R
rebornix 已提交
867
			let itemDOM = this.list?.domElementOfElement(cell);
R
rebornix 已提交
868 869 870
			if (document.activeElement && itemDOM && itemDOM.contains(document.activeElement)) {
				(document.activeElement as HTMLElement).blur();
			}
871

872
			cell.editState = CellEditState.Preview;
873
			cell.focusMode = CellFocusMode.Container;
R
rebornix 已提交
874

R
rebornix 已提交
875
			this.selectElement(cell);
876
			this.revealInCenterIfOutsideViewport(cell);
R
rebornix 已提交
877
			this.list?.focusView();
R
rebornix 已提交
878 879 880
		}
	}

R
rebornix 已提交
881 882 883 884
	//#endregion

	//#region MISC

R
rebornix 已提交
885 886 887 888 889 890 891 892 893 894 895
	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 已提交
896

R
rebornix 已提交
897 898
	triggerScroll(event: IMouseWheelEvent) {
		this.list?.triggerScrollFromMouseWheelEvent(event);
R
rebornix 已提交
899 900
	}

R
rebornix 已提交
901
	createInset(cell: CodeCellViewModel, output: IOutput, shadowContent: string, offset: number) {
R
rebornix 已提交
902 903
		if (!this.webview) {
			return;
R
rebornix 已提交
904 905
		}

R
rebornix 已提交
906
		let preloads = this.notebookViewModel!.renderers;
R
rebornix 已提交
907

908
		if (!this.webview!.insetMapping.has(output)) {
R
rebornix 已提交
909
			let cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
910
			this.webview!.createInset(cell, output, cellTop, offset, shadowContent, preloads);
R
rebornix 已提交
911
		} else {
R
rebornix 已提交
912
			let cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
R
rebornix 已提交
913 914
			let scrollTop = this.list?.scrollTop || 0;

915
			this.webview!.updateViewScrollTop(-scrollTop, [{ cell: cell, output: output, cellTop: cellTop }]);
R
rebornix 已提交
916
		}
R
rebornix 已提交
917
	}
R
rebornix 已提交
918

R
rebornix 已提交
919 920 921 922 923 924 925 926
	removeInset(output: IOutput) {
		if (!this.webview) {
			return;
		}

		this.webview!.removeInset(output);
	}

927 928 929 930 931 932 933 934
	hideInset(output: IOutput) {
		if (!this.webview) {
			return;
		}

		this.webview!.hideInset(output);
	}

R
rebornix 已提交
935 936
	getOutputRenderer(): OutputRenderer {
		return this.outputRenderer;
R
rebornix 已提交
937
	}
938

939 940 941 942
	postMessage(message: any) {
		this.webview?.webview.sendMessage(message);
	}

R
rebornix 已提交
943
	//#endregion
944

R
rebornix 已提交
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
	//#region Editor Contributions
	public getContribution<T extends INotebookEditorContribution>(id: string): T {
		return <T>(this._contributions[id] || null);
	}

	//#endregion
	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();
	}

961 962 963 964 965
	toJSON(): any {
		return {
			notebookHandle: this.viewModel?.handle
		};
	}
P
Peng Lyu 已提交
966 967 968 969
}

const embeddedEditorBackground = 'walkThrough.embeddedEditorBackground';

970 971 972 973 974 975
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."));

976 977 978 979 980 981 982
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 已提交
983
// TODO currently also used for toolbar border, if we keep all of this, pick a generic name
R
rebornix 已提交
984 985 986 987 988 989
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"));

990

P
Peng Lyu 已提交
991 992 993
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 已提交
994
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .monaco-editor-background,
R
Rob Lourens 已提交
995 996
			.monaco-workbench .part.editor > .content .notebook-editor .cell .margin-view-overlays,
			.monaco-workbench .part.editor > .content .notebook-editor .cell .cell-statusbar-container { background: ${color}; }`);
997
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-drag-image .cell-editor-container > div { background: ${color} !important; }`);
P
Peng Lyu 已提交
998 999 1000
	}
	const link = theme.getColor(textLinkForeground);
	if (link) {
R
Rob Lourens 已提交
1001
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .output a { color: ${link}; }`);
P
Peng Lyu 已提交
1002 1003 1004
	}
	const activeLink = theme.getColor(textLinkActiveForeground);
	if (activeLink) {
R
Rob Lourens 已提交
1005 1006
		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 已提交
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
	}
	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}; }`);
	}
1025

1026 1027 1028
	const containerBackground = theme.getColor(notebookOutputContainerColor);
	if (containerBackground) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { background-color: ${containerBackground}; }`);
1029
	}
1030

R
Rob Lourens 已提交
1031 1032 1033
	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 已提交
1034
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar { background-color: ${editorBackgroundColor}; }`);
R
Rob Lourens 已提交
1035
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.cell-drag-image { background-color: ${editorBackgroundColor}; }`);
1036 1037
	}

R
rebornix 已提交
1038 1039 1040 1041
	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 已提交
1042
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar { border: solid 1px ${cellToolbarSeperator}; }`);
R
Rob Lourens 已提交
1043 1044 1045 1046 1047 1048
		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}; }`);
1049
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .notebook-cell-focus-indicator { border-color: ${focusedCellIndicatorColor}; }`);
R
Rob Lourens 已提交
1050
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .notebook-cell-insertion-indicator-top { background-color: ${focusedCellIndicatorColor}; }`);
1051
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.cell-editor-focus .cell-editor-part { outline: solid 1px ${focusedCellIndicatorColor}; }`);
R
rebornix 已提交
1052 1053
	}

1054
	// Cell Margin
R
rebornix 已提交
1055 1056
	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; }`);
1057
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 0px ${CELL_MARGIN}px 0px ${CELL_MARGIN + CELL_RUN_GUTTER}px }`);
R
rebornix 已提交
1058
	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 已提交
1059

1060
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .markdown-cell-row .cell .cell-editor-part { margin-left: ${CELL_RUN_GUTTER}px; }`);
R
rebornix 已提交
1061
	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 已提交
1062
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .run-button-container { width: ${CELL_RUN_GUTTER}px; }`);
R
Rob Lourens 已提交
1063
	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; }`);
1064
	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 已提交
1065
});