notebookEditor.ts 41.1 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';
13
import { DisposableStore, MutableDisposable, combinedDisposable } 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 { CellEditState, CellFocusMode, ICellRange, ICellViewModel, INotebookCellList, INotebookEditor, INotebookEditorMouseEvent, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, INotebookEditorContribution, NOTEBOOK_EDITOR_RUNNABLE } 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 editorRunnable: IContextKey<boolean> | null = null;
110
	private editorExecutingNotebook: IContextKey<boolean> | null = null;
R
rebornix 已提交
111
	private outputRenderer: OutputRenderer;
R
rebornix 已提交
112
	protected readonly _contributions: { [key: string]: INotebookEditorContribution; };
R
rebornix 已提交
113
	private scrollBeyondLastLine: boolean;
P
Peng Lyu 已提交
114 115 116 117 118

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

		this.editorMemento = this.getEditorMemento<INotebookEditorViewState>(editorGroupService, NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY);
R
rebornix 已提交
128
		this.outputRenderer = new OutputRenderer(this, this.instantiationService);
R
rebornix 已提交
129
		this._contributions = {};
R
rebornix 已提交
130 131 132 133 134 135 136 137 138 139
		this.scrollBeyondLastLine = this.configurationService.getValue<boolean>('editor.scrollBeyondLastLine');

		this.configurationService.onDidChangeConfiguration(e => {
			if (e.affectsConfiguration('editor.scrollBeyondLastLine')) {
				this.scrollBeyondLastLine = this.configurationService.getValue<boolean>('editor.scrollBeyondLastLine');
				if (this.dimension) {
					this.layout(this.dimension);
				}
			}
		});
R
rebornix 已提交
140 141 142 143 144 145 146 147 148
	}

	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 已提交
149 150
	}

R
rebornix 已提交
151 152 153 154
	get viewModel() {
		return this.notebookViewModel;
	}

P
Peng Lyu 已提交
155 156 157 158 159 160 161 162
	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 已提交
163
	//#region Editor Core
R
rebornix 已提交
164

R
rebornix 已提交
165 166 167 168 169

	public get isNotebookEditor() {
		return true;
	}

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

		this._register(this.onDidBlur(() => {
			this.editorFocus?.set(false);
		}));
R
rebornix 已提交
183 184 185

		this.editorEditable = NOTEBOOK_EDITOR_EDITABLE.bindTo(this.contextKeyService);
		this.editorEditable.set(true);
186 187
		this.editorRunnable = NOTEBOOK_EDITOR_RUNNABLE.bindTo(this.contextKeyService);
		this.editorRunnable.set(true);
188
		this.editorExecutingNotebook = NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK.bindTo(this.contextKeyService);
R
rebornix 已提交
189 190 191 192 193 194 195 196 197 198 199

		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);
			}
		}
200 201 202 203 204
	}

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

	private createBody(parent: HTMLElement): void {
P
Peng Lyu 已提交
208
		this.body = document.createElement('div');
P
Peng Lyu 已提交
209 210 211
		DOM.addClass(this.body, 'cell-list-container');
		this.createCellList();
		DOM.append(parent, this.body);
P
Peng Lyu 已提交
212 213
	}

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

R
Rob Lourens 已提交
217
		const dndController = new CellDragAndDropController(this);
P
Peng Lyu 已提交
218
		const renders = [
R
Rob Lourens 已提交
219 220
			this.instantiationService.createInstance(CodeCellRenderer, this, this.contextKeyService, this.renderedEditors, dndController),
			this.instantiationService.createInstance(MarkdownCellRenderer, this.contextKeyService, this, dndController),
P
Peng Lyu 已提交
221 222
		];

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

267
		this.control = new NotebookCodeEditors(this.list, this.renderedEditors);
268
		this.webview = this.instantiationService.createInstance(BackLayerWebView, this);
269 270 271 272 273
		this._register(this.webview.onMessage(message => {
			if (this.viewModel) {
				this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.viewModel.uri, message);
			}
		}));
R
rebornix 已提交
274
		this.list.rowsContainer.appendChild(this.webview.element);
R
rebornix 已提交
275

P
Peng Lyu 已提交
276
		this._register(this.list);
277
		this._register(combinedDisposable(...renders));
R
rebornix 已提交
278 279 280

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

R
rebornix 已提交
283
		this._register(DOM.addStandardDisposableGenericMouseDownListner(this._rootElement, (e: StandardMouseEvent) => {
R
rebornix 已提交
284 285 286 287 288
			if (DOM.hasClass(e.target, 'slider') && this.webviewTransparentCover) {
				this.webviewTransparentCover.style.display = 'block';
			}
		}));

R
rebornix 已提交
289
		this._register(DOM.addStandardDisposableGenericMouseUpListner(this._rootElement, (e: StandardMouseEvent) => {
R
rebornix 已提交
290 291
			if (this.webviewTransparentCover) {
				// no matter when
292
				this.webviewTransparentCover.style.display = 'none';
R
rebornix 已提交
293 294 295
			}
		}));

R
rebornix 已提交
296 297 298 299 300 301 302 303 304 305 306 307
		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 已提交
308 309
	}

R
rebornix 已提交
310 311 312 313
	getDomNode() {
		return this._rootElement;
	}

314 315 316 317
	getControl() {
		return this.control;
	}

R
rebornix 已提交
318 319 320 321
	getInnerWebview(): Webview | undefined {
		return this.webview?.webview;
	}

322 323
	onWillHide() {
		if (this.input && this.input instanceof NotebookEditorInput && !this.input.isDisposed()) {
R
rebornix 已提交
324
			this.saveEditorViewState(this.input);
325 326
		}

R
rebornix 已提交
327
		this.editorFocus?.set(false);
328 329
		if (this.webview) {
			this.localStore.clear();
R
rebornix 已提交
330
			this.list?.rowsContainer.removeChild(this.webview?.element);
331 332 333 334
			this.webview?.dispose();
			this.webview = null;
		}

R
rebornix 已提交
335
		this.list?.clear();
336
		super.onHide();
P
Peng Lyu 已提交
337 338
	}

R
rebornix 已提交
339 340 341 342 343 344 345 346 347 348 349 350
	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 已提交
351
			this.saveEditorViewState(editor);
352 353 354
		}
	}

R
rebornix 已提交
355 356 357
	focus() {
		super.focus();
		this.editorFocus?.set(true);
358
		this.list?.domFocus();
R
rebornix 已提交
359 360
	}

R
rebornix 已提交
361
	async setInput(input: NotebookEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
R
rebornix 已提交
362
		if (this.input instanceof NotebookEditorInput) {
R
rebornix 已提交
363
			this.saveEditorViewState(this.input);
R
rebornix 已提交
364 365
		}

R
rebornix 已提交
366 367
		await super.setInput(input, options, token);
		const model = await input.resolve();
P
Peng Lyu 已提交
368

369 370 371
		if (this.notebookViewModel === undefined || !this.notebookViewModel.equal(model) || this.webview === null) {
			this.detachModel();
			await this.attachModel(input, model);
R
rebornix 已提交
372
		}
P
Peng Lyu 已提交
373

374 375 376
		// reveal cell if editor options tell to do so
		if (options instanceof NotebookEditorOptions && options.cellOptions) {
			const cellOptions = options.cellOptions;
R
rebornix 已提交
377
			const cell = this.notebookViewModel!.viewCells.find(cell => cell.uri.toString() === cellOptions.resource.toString());
378
			if (cell) {
379
				this.selectElement(cell);
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
				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();
					}
				}
395 396
			}
		}
R
rebornix 已提交
397
	}
398

R
rebornix 已提交
399 400 401 402
	clearInput(): void {
		super.clearInput();
	}

R
rebornix 已提交
403 404
	private detachModel() {
		this.localStore.clear();
R
rebornix 已提交
405
		this.list?.detachViewModel();
R
rebornix 已提交
406 407
		this.viewModel?.dispose();
		// avoid event
R
rebornix 已提交
408 409 410
		this.notebookViewModel = undefined;
		this.webview?.clearInsets();
		this.webview?.clearPreloadsCache();
R
rebornix 已提交
411
		this.list?.clear();
R
rebornix 已提交
412
	}
R
rebornix 已提交
413

414 415 416 417 418 419
	private updateForMetadata(): void {
		this.editorEditable?.set(!!this.viewModel!.metadata?.editable);
		this.editorRunnable?.set(!!this.viewModel!.metadata?.runnable);
		DOM.toggleClass(this.getDomNode(), 'notebook-editor-editable', !!this.viewModel!.metadata?.editable);
	}

R
rebornix 已提交
420 421
	private async attachModel(input: NotebookEditorInput, model: NotebookEditorModel) {
		if (!this.webview) {
422
			this.webview = this.instantiationService.createInstance(BackLayerWebView, this);
R
rebornix 已提交
423 424
			this.list?.rowsContainer.insertAdjacentElement('afterbegin', this.webview!.element);
		}
425

426 427
		await this.webview.waitForInitialization();

R
rebornix 已提交
428
		this.eventDispatcher = new NotebookEventDispatcher();
R
rebornix 已提交
429
		this.viewModel = this.instantiationService.createInstance(NotebookViewModel, input.viewType!, model, this.eventDispatcher, this.getLayoutInfo());
R
rebornix 已提交
430
		this.eventDispatcher.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]);
431

432
		this.updateForMetadata();
R
rebornix 已提交
433
		this.localStore.add(this.eventDispatcher.onDidChangeMetadata((e) => {
434
			this.updateForMetadata();
R
rebornix 已提交
435 436
		}));

R
rebornix 已提交
437
		// restore view states, including contributions
R
rebornix 已提交
438
		const viewState = this.loadTextEditorViewState(input);
R
rebornix 已提交
439 440 441

		{
			// restore view state
R
rebornix 已提交
442
			this.viewModel.restoreEditorViewState(viewState);
R
rebornix 已提交
443 444

			// contribution state restore
R
rebornix 已提交
445 446 447 448 449 450 451 452 453 454

			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 已提交
455
		}
456

R
rebornix 已提交
457
		this.webview?.updateRendererPreloads(this.viewModel.renderers);
R
rebornix 已提交
458 459 460

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

		this.localStore.add(this.list!.onDidChangeContentHeight(() => {
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
			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 已提交
492
					}
R
rebornix 已提交
493
				}
494
			});
R
rebornix 已提交
495 496
		}));

R
rebornix 已提交
497
		this.list!.attachViewModel(this.viewModel);
R
rebornix 已提交
498 499 500
		this.localStore.add(this.list!.onDidRemoveOutput(output => {
			this.removeInset(output);
		}));
501 502 503
		this.localStore.add(this.list!.onDidHideOutput(output => {
			this.hideInset(output);
		}));
R
rebornix 已提交
504 505

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

R
rebornix 已提交
507
		// restore list state at last, it must be after list layout
508 509 510 511
		this.restoreTextEditorViewState(viewState);
	}

	private restoreTextEditorViewState(viewState: INotebookEditorViewState | undefined): void {
R
rebornix 已提交
512 513 514 515 516 517 518
		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;
		}
519

520 521 522 523 524 525 526 527 528 529
		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;
			}
530
		}
P
Peng Lyu 已提交
531 532
	}

R
rebornix 已提交
533
	private saveEditorViewState(input: NotebookEditorInput): void {
R
npe  
rebornix 已提交
534
		if (this.group && this.notebookViewModel) {
R
rebornix 已提交
535
			const state = this.notebookViewModel.geteEditorViewState();
R
rebornix 已提交
536 537
			if (this.list) {
				state.scrollPosition = { left: this.list.scrollLeft, top: this.list.scrollTop };
538
				let cellHeights: { [key: number]: number } = {};
R
rebornix 已提交
539
				for (let i = 0; i < this.viewModel!.length; i++) {
R
rebornix 已提交
540
					const elm = this.viewModel!.viewCells[i] as CellViewModel;
541 542 543 544 545 546 547 548
					if (elm.cellKind === CellKind.Code) {
						cellHeights[i] = elm.layoutInfo.totalHeight;
					} else {
						cellHeights[i] = 0;
					}
				}

				state.cellTotalHeights = cellHeights;
549 550 551

				const focus = this.list.getFocus()[0];
				if (focus) {
552 553 554 555 556 557 558 559
					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;
560 561
					state.focus = focus;
				}
R
rebornix 已提交
562 563
			}

R
rebornix 已提交
564
			// Save contribution view states
R
rebornix 已提交
565 566 567 568 569 570 571 572
			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 已提交
573 574
			}

R
rebornix 已提交
575
			state.contributionsState = contributionsState;
R
rebornix 已提交
576
			this.editorMemento.saveEditorState(this.group, input.resource, state);
R
rebornix 已提交
577 578 579 580 581
		}
	}

	private loadTextEditorViewState(input: NotebookEditorInput): INotebookEditorViewState | undefined {
		if (this.group) {
R
rebornix 已提交
582
			return this.editorMemento.loadEditorState(this.group, input.resource);
R
rebornix 已提交
583 584 585 586 587 588 589
		}

		return;
	}

	layout(dimension: DOM.Dimension): void {
		this.dimension = new DOM.Dimension(dimension.width, dimension.height);
R
rebornix 已提交
590 591
		DOM.toggleClass(this._rootElement, 'mid-width', dimension.width < 1000 && dimension.width >= 600);
		DOM.toggleClass(this._rootElement, 'narrow-width', dimension.width < 600);
R
rebornix 已提交
592
		DOM.size(this.body, dimension.width, dimension.height);
R
rebornix 已提交
593
		this.list?.updateOptions({ additionalScrollHeight: this.scrollBeyondLastLine ? dimension.height : 0 });
R
rebornix 已提交
594
		this.list?.layout(dimension.height, dimension.width);
R
rebornix 已提交
595 596 597 598 599 600

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

R
rebornix 已提交
601
		this.eventDispatcher?.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]);
R
rebornix 已提交
602 603 604 605
	}

	protected saveState(): void {
		if (this.input instanceof NotebookEditorInput) {
R
rebornix 已提交
606
			this.saveEditorViewState(this.input);
R
rebornix 已提交
607 608 609 610 611 612 613
		}

		super.saveState();
	}

	//#endregion

R
rebornix 已提交
614 615
	//#region Editor Features

R
rebornix 已提交
616
	selectElement(cell: ICellViewModel) {
R
rebornix 已提交
617
		this.list?.selectElement(cell);
R
rebornix 已提交
618 619
	}

R
rebornix 已提交
620
	revealInView(cell: ICellViewModel) {
R
rebornix 已提交
621
		this.list?.revealElementInView(cell);
R
rebornix 已提交
622 623
	}

R
rebornix 已提交
624
	revealInCenterIfOutsideViewport(cell: ICellViewModel) {
R
rebornix 已提交
625
		this.list?.revealElementInCenterIfOutsideViewport(cell);
R
rebornix 已提交
626 627
	}

R
rebornix 已提交
628
	revealInCenter(cell: ICellViewModel) {
R
rebornix 已提交
629
		this.list?.revealElementInCenter(cell);
R
rebornix 已提交
630 631
	}

R
rebornix 已提交
632
	revealLineInView(cell: ICellViewModel, line: number): void {
R
rebornix 已提交
633
		this.list?.revealElementLineInView(cell, line);
R
rebornix 已提交
634
	}
R
rebornix 已提交
635

R
rebornix 已提交
636
	revealLineInCenter(cell: ICellViewModel, line: number) {
R
rebornix 已提交
637
		this.list?.revealElementLineInCenter(cell, line);
R
rebornix 已提交
638 639
	}

R
rebornix 已提交
640
	revealLineInCenterIfOutsideViewport(cell: ICellViewModel, line: number) {
R
rebornix 已提交
641
		this.list?.revealElementLineInCenterIfOutsideViewport(cell, line);
R
rebornix 已提交
642 643
	}

R
rebornix 已提交
644
	revealRangeInView(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
645
		this.list?.revealElementRangeInView(cell, range);
R
rebornix 已提交
646 647
	}

R
rebornix 已提交
648
	revealRangeInCenter(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
649
		this.list?.revealElementRangeInCenter(cell, range);
R
rebornix 已提交
650 651
	}

R
rebornix 已提交
652
	revealRangeInCenterIfOutsideViewport(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
653
		this.list?.revealElementRangeInCenterIfOutsideViewport(cell, range);
R
rebornix 已提交
654 655
	}

R
rebornix 已提交
656
	setCellSelection(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
657
		this.list?.setCellSelection(cell, range);
R
rebornix 已提交
658 659
	}

R
rebornix 已提交
660 661 662 663
	changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {
		return this.notebookViewModel?.changeDecorations(callback);
	}

R
rebornix 已提交
664
	setHiddenAreas(_ranges: ICellRange[]): boolean {
R
rebornix 已提交
665
		return this.list!.setHiddenAreas(_ranges, true);
R
rebornix 已提交
666 667
	}

R
rebornix 已提交
668 669
	//#endregion

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

R
rebornix 已提交
687
		let relayout = (cell: ICellViewModel, height: number) => {
R
rebornix 已提交
688
			this.list?.updateElementHeight2(cell, height);
R
rebornix 已提交
689 690
		};

691
		let r: () => void;
R
rebornix 已提交
692
		DOM.scheduleAtNextAnimationFrame(() => {
R
rebornix 已提交
693
			relayout(cell, height);
694
			r();
R
rebornix 已提交
695
		});
696 697

		return new Promise(resolve => { r = resolve; });
698 699
	}

700 701 702 703 704
	insertNotebookCell(cell: ICellViewModel | undefined, type: CellKind, direction: 'above' | 'below' = 'above', initialText: string = ''): CellViewModel | null {
		if (!this.notebookViewModel!.metadata.editable) {
			return null;
		}

R
rebornix 已提交
705 706
		const newLanguages = this.notebookViewModel!.languages;
		const language = newLanguages && newLanguages.length ? newLanguages[0] : 'markdown';
707 708 709 710
		const index = cell ? this.notebookViewModel!.getCellIndex(cell) : 0;
		const insertIndex = cell ?
			(direction === 'above' ? index : index + 1) :
			index;
R
rebornix 已提交
711
		const newCell = this.notebookViewModel!.createCell(insertIndex, initialText.split(/\r?\n/g), language, type, true);
P
Peng Lyu 已提交
712

R
rebornix 已提交
713
		if (type === CellKind.Markdown) {
714
			newCell.editState = CellEditState.Editing;
P
Peng Lyu 已提交
715
		}
R
rebornix 已提交
716

717
		return newCell;
P
Peng Lyu 已提交
718 719
	}

720
	async deleteNotebookCell(cell: ICellViewModel): Promise<boolean> {
721 722 723 724
		if (!this.notebookViewModel!.metadata.editable) {
			return false;
		}

725
		(cell as CellViewModel).save();
R
rebornix 已提交
726
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
727
		this.notebookViewModel!.deleteCell(index, true);
728
		return true;
R
rebornix 已提交
729 730
	}

731
	async moveCellDown(cell: ICellViewModel): Promise<boolean> {
732 733 734 735
		if (!this.notebookViewModel!.metadata.editable) {
			return false;
		}

R
rebornix 已提交
736
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
737
		if (index === this.notebookViewModel!.length - 1) {
738
			return false;
R
rebornix 已提交
739 740
		}

741
		const newIdx = index + 1;
742
		return this.moveCellToIndex(index, newIdx);
743 744
	}

745
	async moveCellUp(cell: ICellViewModel): Promise<boolean> {
746 747 748 749
		if (!this.notebookViewModel!.metadata.editable) {
			return false;
		}

R
rebornix 已提交
750
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
751
		if (index === 0) {
752
			return false;
R
rebornix 已提交
753 754
		}

755
		const newIdx = index - 1;
756
		return this.moveCellToIndex(index, newIdx);
757 758
	}

759
	async moveCell(cell: ICellViewModel, relativeToCell: ICellViewModel, direction: 'above' | 'below'): Promise<boolean> {
760 761 762 763
		if (!this.notebookViewModel!.metadata.editable) {
			return false;
		}

R
Rob Lourens 已提交
764
		if (cell === relativeToCell) {
765
			return false;
R
Rob Lourens 已提交
766 767 768 769 770 771 772 773 774
		}

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

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

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

780
		let r: (val: boolean) => void;
781
		DOM.scheduleAtNextAnimationFrame(() => {
782
			this.list?.revealElementInView(this.notebookViewModel!.viewCells[newIdx]);
783
			r(true);
784
		});
785 786

		return new Promise(resolve => { r = resolve; });
787 788
	}

R
rebornix 已提交
789
	editNotebookCell(cell: CellViewModel): void {
790 791 792 793
		if (!cell.getEvaluatedMetadata(this.notebookViewModel!.metadata).editable) {
			return;
		}

794
		cell.editState = CellEditState.Editing;
R
rebornix 已提交
795 796

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

R
rebornix 已提交
799
	saveNotebookCell(cell: ICellViewModel): void {
800
		cell.editState = CellEditState.Preview;
P
Peng Lyu 已提交
801 802
	}

R
rebornix 已提交
803 804 805 806 807 808 809 810 811 812
	getActiveCell() {
		let elements = this.list?.getFocusedElements();

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

		return undefined;
	}

813 814 815 816 817 818 819 820 821 822 823
	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> {
824 825 826 827
		if (!this.notebookViewModel!.metadata.runnable) {
			return;
		}

828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862
		// 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;
	}

863
	async executeNotebookCell(cell: ICellViewModel): Promise<void> {
864 865 866 867
		if (!cell.getEvaluatedMetadata(this.notebookViewModel!.metadata).runnable) {
			return;
		}

868
		const tokenSource = new CancellationTokenSource();
869 870 871 872 873 874 875
		try {
			this._executeNotebookCell(cell, tokenSource);
		} finally {
			tokenSource.dispose();
		}
	}

R
Rob Lourens 已提交
876
	private async _executeNotebookCell(cell: ICellViewModel, tokenSource: CancellationTokenSource): Promise<void> {
877
		try {
878
			cell.currentTokenSource = tokenSource;
R
rebornix 已提交
879
			const provider = this.notebookService.getContributedNotebookProviders(this.viewModel!.uri)[0];
880 881 882 883
			if (provider) {
				const viewType = provider.id;
				const notebookUri = CellUri.parse(cell.uri)?.notebook;
				if (notebookUri) {
884
					return await this.notebookService.executeNotebookCell(viewType, notebookUri, cell.handle, tokenSource.token);
885 886 887
				}
			}
		} finally {
888
			cell.currentTokenSource = undefined;
889 890 891
		}
	}

R
rebornix 已提交
892
	focusNotebookCell(cell: ICellViewModel, focusEditor: boolean) {
R
rebornix 已提交
893
		if (focusEditor) {
R
rebornix 已提交
894
			this.selectElement(cell);
R
rebornix 已提交
895
			this.list?.focusView();
R
rebornix 已提交
896

897
			cell.editState = CellEditState.Editing;
R
rebornix 已提交
898
			cell.focusMode = CellFocusMode.Editor;
899
			this.revealInCenterIfOutsideViewport(cell);
R
rebornix 已提交
900
		} else {
R
rebornix 已提交
901
			let itemDOM = this.list?.domElementOfElement(cell);
R
rebornix 已提交
902 903 904
			if (document.activeElement && itemDOM && itemDOM.contains(document.activeElement)) {
				(document.activeElement as HTMLElement).blur();
			}
905

906
			cell.editState = CellEditState.Preview;
907
			cell.focusMode = CellFocusMode.Container;
R
rebornix 已提交
908

R
rebornix 已提交
909
			this.selectElement(cell);
910
			this.revealInCenterIfOutsideViewport(cell);
R
rebornix 已提交
911
			this.list?.focusView();
R
rebornix 已提交
912 913 914
		}
	}

R
rebornix 已提交
915 916 917 918
	//#endregion

	//#region MISC

R
rebornix 已提交
919 920 921 922 923 924 925 926 927 928 929
	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 已提交
930

R
rebornix 已提交
931 932
	triggerScroll(event: IMouseWheelEvent) {
		this.list?.triggerScrollFromMouseWheelEvent(event);
R
rebornix 已提交
933 934
	}

R
rebornix 已提交
935
	createInset(cell: CodeCellViewModel, output: IOutput, shadowContent: string, offset: number) {
R
rebornix 已提交
936 937
		if (!this.webview) {
			return;
R
rebornix 已提交
938 939
		}

R
rebornix 已提交
940
		let preloads = this.notebookViewModel!.renderers;
R
rebornix 已提交
941

942
		if (!this.webview!.insetMapping.has(output)) {
R
rebornix 已提交
943
			let cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
944
			this.webview!.createInset(cell, output, cellTop, offset, shadowContent, preloads);
R
rebornix 已提交
945
		} else {
R
rebornix 已提交
946
			let cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
R
rebornix 已提交
947 948
			let scrollTop = this.list?.scrollTop || 0;

949
			this.webview!.updateViewScrollTop(-scrollTop, [{ cell: cell, output: output, cellTop: cellTop }]);
R
rebornix 已提交
950
		}
R
rebornix 已提交
951
	}
R
rebornix 已提交
952

R
rebornix 已提交
953 954 955 956 957 958 959 960
	removeInset(output: IOutput) {
		if (!this.webview) {
			return;
		}

		this.webview!.removeInset(output);
	}

961 962 963 964 965 966 967 968
	hideInset(output: IOutput) {
		if (!this.webview) {
			return;
		}

		this.webview!.hideInset(output);
	}

R
rebornix 已提交
969 970
	getOutputRenderer(): OutputRenderer {
		return this.outputRenderer;
R
rebornix 已提交
971
	}
972

973 974 975 976
	postMessage(message: any) {
		this.webview?.webview.sendMessage(message);
	}

R
rebornix 已提交
977
	//#endregion
978

R
rebornix 已提交
979 980 981 982 983 984
	//#region Editor Contributions
	public getContribution<T extends INotebookEditorContribution>(id: string): T {
		return <T>(this._contributions[id] || null);
	}

	//#endregion
R
rebornix 已提交
985

R
rebornix 已提交
986 987 988 989 990 991 992 993 994 995
	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();
	}

996 997 998 999 1000
	toJSON(): any {
		return {
			notebookHandle: this.viewModel?.handle
		};
	}
P
Peng Lyu 已提交
1001 1002 1003 1004
}

const embeddedEditorBackground = 'walkThrough.embeddedEditorBackground';

1005 1006 1007 1008 1009 1010
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."));

1011 1012 1013 1014 1015 1016 1017
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 已提交
1018
// TODO currently also used for toolbar border, if we keep all of this, pick a generic name
R
rebornix 已提交
1019 1020 1021 1022 1023 1024
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"));

1025

P
Peng Lyu 已提交
1026 1027 1028
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 已提交
1029
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .monaco-editor-background,
R
Rob Lourens 已提交
1030 1031
			.monaco-workbench .part.editor > .content .notebook-editor .cell .margin-view-overlays,
			.monaco-workbench .part.editor > .content .notebook-editor .cell .cell-statusbar-container { background: ${color}; }`);
1032
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-drag-image .cell-editor-container > div { background: ${color} !important; }`);
P
Peng Lyu 已提交
1033 1034 1035
	}
	const link = theme.getColor(textLinkForeground);
	if (link) {
M
Miguel Solorio 已提交
1036 1037
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .output a,
			.monaco-workbench .part.editor > .content .notebook-editor .cell.markdown a { color: ${link};} `);
P
Peng Lyu 已提交
1038 1039 1040
	}
	const activeLink = theme.getColor(textLinkActiveForeground);
	if (activeLink) {
R
Rob Lourens 已提交
1041 1042
		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 已提交
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
	}
	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}; }`);
	}
1061

1062 1063 1064
	const containerBackground = theme.getColor(notebookOutputContainerColor);
	if (containerBackground) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { background-color: ${containerBackground}; }`);
1065
	}
1066

R
Rob Lourens 已提交
1067 1068 1069
	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 已提交
1070
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar { background-color: ${editorBackgroundColor}; }`);
R
Rob Lourens 已提交
1071
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.cell-drag-image { background-color: ${editorBackgroundColor}; }`);
1072 1073
	}

R
rebornix 已提交
1074 1075 1076 1077
	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 已提交
1078
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar { border: solid 1px ${cellToolbarSeperator}; }`);
1079 1080
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .notebook-cell-focus-indicator,
			.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.cell-output-hover .notebook-cell-focus-indicator { border-color: ${cellToolbarSeperator}; }`);
R
Rob Lourens 已提交
1081 1082 1083 1084 1085
	}

	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}; }`);
1086
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .notebook-cell-focus-indicator { border-color: ${focusedCellIndicatorColor}; }`);
R
Rob Lourens 已提交
1087
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .notebook-cell-insertion-indicator-top { background-color: ${focusedCellIndicatorColor}; }`);
R
Rob Lourens 已提交
1088
		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 已提交
1089 1090
	}

R
rebornix 已提交
1091 1092 1093 1094 1095 1096 1097
	// const widgetShadowColor = theme.getColor(widgetShadow);
	// if (widgetShadowColor) {
	// 	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > .monaco-toolbar {
	// 		box-shadow:  0 0 8px 4px ${widgetShadowColor}
	// 	}`)
	// }

1098
	// Cell Margin
R
rebornix 已提交
1099 1100
	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; }`);
1101
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 0px ${CELL_MARGIN}px 0px ${CELL_MARGIN + CELL_RUN_GUTTER}px }`);
R
rebornix 已提交
1102
	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 已提交
1103

1104
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .markdown-cell-row .cell .cell-editor-part { margin-left: ${CELL_RUN_GUTTER}px; }`);
R
rebornix 已提交
1105
	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 已提交
1106
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .run-button-container { width: ${CELL_RUN_GUTTER}px; }`);
R
Rob Lourens 已提交
1107
	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; }`);
1108
	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 已提交
1109
});