notebookEditor.ts 41.6 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
			DOM.scheduleAtNextAnimationFrame(() => {
				const scrollTop = this.list?.scrollTop || 0;
				const scrollHeight = this.list?.scrollHeight || 0;
				this.webview!.element.style.height = `${scrollHeight}px`;

				if (this.webview?.insetMapping) {
R
rebornix 已提交
471 472
					let updateItems: { cell: CodeCellViewModel, output: IOutput, cellTop: number }[] = [];
					let removedItems: IOutput[] = [];
473 474 475 476 477 478 479 480
					this.webview?.insetMapping.forEach((value, key) => {
						const cell = value.cell;
						const viewIndex = this.list?.getViewIndex(cell);

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

R
rebornix 已提交
481 482 483 484 485
						if (cell.outputs.indexOf(key) < 0) {
							// output is already gone
							removedItems.push(key);
						}

486 487 488 489 490 491 492 493 494 495
						const cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
						if (this.webview!.shouldUpdateInset(cell, key, cellTop)) {
							updateItems.push({
								cell: cell,
								output: key,
								cellTop: cellTop
							});
						}
					});

R
rebornix 已提交
496 497
					removedItems.forEach(output => this.webview?.removeInset(output));

498 499
					if (updateItems.length) {
						this.webview?.updateViewScrollTop(-scrollTop, updateItems);
R
rebornix 已提交
500
					}
R
rebornix 已提交
501
				}
502
			});
R
rebornix 已提交
503 504
		}));

R
rebornix 已提交
505
		this.list!.attachViewModel(this.viewModel);
R
rebornix 已提交
506 507 508
		this.localStore.add(this.list!.onDidRemoveOutput(output => {
			this.removeInset(output);
		}));
509 510 511
		this.localStore.add(this.list!.onDidHideOutput(output => {
			this.hideInset(output);
		}));
R
rebornix 已提交
512 513

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

R
rebornix 已提交
515
		// restore list state at last, it must be after list layout
R
rebornix 已提交
516
		this.restoreListViewState(viewState);
517 518
	}

R
rebornix 已提交
519
	private restoreListViewState(viewState: INotebookEditorViewState | undefined): void {
R
rebornix 已提交
520 521 522 523 524 525 526
		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;
		}
527

528
		const focusIdx = typeof viewState?.focus === 'number' ? viewState.focus : 0;
R
rebornix 已提交
529 530 531 532 533 534
		if (focusIdx < this.list!.length) {
			this.list!.setFocus([focusIdx]);
			this.list!.setSelection([focusIdx]);
		} else if (this.list!.length > 0) {
			this.list!.setFocus([0]);
		}
535 536 537 538 539 540 541

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

R
rebornix 已提交
545
	private saveEditorViewState(input: NotebookEditorInput): void {
R
npe  
rebornix 已提交
546
		if (this.group && this.notebookViewModel) {
R
rebornix 已提交
547
			const state = this.notebookViewModel.geteEditorViewState();
R
rebornix 已提交
548 549
			if (this.list) {
				state.scrollPosition = { left: this.list.scrollLeft, top: this.list.scrollTop };
550
				let cellHeights: { [key: number]: number } = {};
R
rebornix 已提交
551
				for (let i = 0; i < this.viewModel!.length; i++) {
R
rebornix 已提交
552
					const elm = this.viewModel!.viewCells[i] as CellViewModel;
553 554 555 556 557 558 559 560
					if (elm.cellKind === CellKind.Code) {
						cellHeights[i] = elm.layoutInfo.totalHeight;
					} else {
						cellHeights[i] = 0;
					}
				}

				state.cellTotalHeights = cellHeights;
561 562 563

				const focus = this.list.getFocus()[0];
				if (focus) {
564 565 566 567 568 569 570 571
					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;
572 573
					state.focus = focus;
				}
R
rebornix 已提交
574 575
			}

R
rebornix 已提交
576
			// Save contribution view states
R
rebornix 已提交
577 578 579 580 581 582 583 584
			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 已提交
585 586
			}

R
rebornix 已提交
587
			state.contributionsState = contributionsState;
R
rebornix 已提交
588
			this.editorMemento.saveEditorState(this.group, input.resource, state);
R
rebornix 已提交
589 590 591 592 593
		}
	}

	private loadTextEditorViewState(input: NotebookEditorInput): INotebookEditorViewState | undefined {
		if (this.group) {
R
rebornix 已提交
594
			return this.editorMemento.loadEditorState(this.group, input.resource);
R
rebornix 已提交
595 596 597 598 599 600 601
		}

		return;
	}

	layout(dimension: DOM.Dimension): void {
		this.dimension = new DOM.Dimension(dimension.width, dimension.height);
R
rebornix 已提交
602 603
		DOM.toggleClass(this._rootElement, 'mid-width', dimension.width < 1000 && dimension.width >= 600);
		DOM.toggleClass(this._rootElement, 'narrow-width', dimension.width < 600);
R
rebornix 已提交
604
		DOM.size(this.body, dimension.width, dimension.height);
R
rebornix 已提交
605
		this.list?.updateOptions({ additionalScrollHeight: this.scrollBeyondLastLine ? dimension.height : 0 });
R
rebornix 已提交
606
		this.list?.layout(dimension.height, dimension.width);
R
rebornix 已提交
607 608 609 610 611 612

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

R
rebornix 已提交
613
		this.eventDispatcher?.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]);
R
rebornix 已提交
614 615 616 617
	}

	protected saveState(): void {
		if (this.input instanceof NotebookEditorInput) {
R
rebornix 已提交
618
			this.saveEditorViewState(this.input);
R
rebornix 已提交
619 620 621 622 623 624 625
		}

		super.saveState();
	}

	//#endregion

R
rebornix 已提交
626 627
	//#region Editor Features

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

R
rebornix 已提交
632
	revealInView(cell: ICellViewModel) {
R
rebornix 已提交
633
		this.list?.revealElementInView(cell);
R
rebornix 已提交
634 635
	}

R
rebornix 已提交
636
	revealInCenterIfOutsideViewport(cell: ICellViewModel) {
R
rebornix 已提交
637
		this.list?.revealElementInCenterIfOutsideViewport(cell);
R
rebornix 已提交
638 639
	}

R
rebornix 已提交
640
	revealInCenter(cell: ICellViewModel) {
R
rebornix 已提交
641
		this.list?.revealElementInCenter(cell);
R
rebornix 已提交
642 643
	}

R
rebornix 已提交
644
	revealLineInView(cell: ICellViewModel, line: number): void {
R
rebornix 已提交
645
		this.list?.revealElementLineInView(cell, line);
R
rebornix 已提交
646
	}
R
rebornix 已提交
647

R
rebornix 已提交
648
	revealLineInCenter(cell: ICellViewModel, line: number) {
R
rebornix 已提交
649
		this.list?.revealElementLineInCenter(cell, line);
R
rebornix 已提交
650 651
	}

R
rebornix 已提交
652
	revealLineInCenterIfOutsideViewport(cell: ICellViewModel, line: number) {
R
rebornix 已提交
653
		this.list?.revealElementLineInCenterIfOutsideViewport(cell, line);
R
rebornix 已提交
654 655
	}

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

R
rebornix 已提交
660
	revealRangeInCenter(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
661
		this.list?.revealElementRangeInCenter(cell, range);
R
rebornix 已提交
662 663
	}

R
rebornix 已提交
664
	revealRangeInCenterIfOutsideViewport(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
665
		this.list?.revealElementRangeInCenterIfOutsideViewport(cell, range);
R
rebornix 已提交
666 667
	}

R
rebornix 已提交
668
	setCellSelection(cell: ICellViewModel, range: Range): void {
R
rebornix 已提交
669
		this.list?.setCellSelection(cell, range);
R
rebornix 已提交
670 671
	}

R
rebornix 已提交
672 673 674 675
	changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {
		return this.notebookViewModel?.changeDecorations(callback);
	}

R
rebornix 已提交
676
	setHiddenAreas(_ranges: ICellRange[]): boolean {
R
rebornix 已提交
677
		return this.list!.setHiddenAreas(_ranges, true);
R
rebornix 已提交
678 679
	}

R
rebornix 已提交
680 681
	//#endregion

R
rebornix 已提交
682 683 684 685 686 687 688 689 690
	//#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 已提交
691
	//#region Cell operations
692
	async layoutNotebookCell(cell: ICellViewModel, height: number): Promise<void> {
693 694 695 696 697 698
		const viewIndex = this.list!.getViewIndex(cell);
		if (viewIndex === undefined) {
			// the cell is hidden
			return;
		}

R
rebornix 已提交
699
		let relayout = (cell: ICellViewModel, height: number) => {
R
rebornix 已提交
700
			this.list?.updateElementHeight2(cell, height);
R
rebornix 已提交
701 702
		};

703
		let r: () => void;
R
rebornix 已提交
704
		DOM.scheduleAtNextAnimationFrame(() => {
R
rebornix 已提交
705
			relayout(cell, height);
706
			r();
R
rebornix 已提交
707
		});
708 709

		return new Promise(resolve => { r = resolve; });
710 711
	}

712 713 714 715 716
	insertNotebookCell(cell: ICellViewModel | undefined, type: CellKind, direction: 'above' | 'below' = 'above', initialText: string = ''): CellViewModel | null {
		if (!this.notebookViewModel!.metadata.editable) {
			return null;
		}

R
rebornix 已提交
717 718
		const newLanguages = this.notebookViewModel!.languages;
		const language = newLanguages && newLanguages.length ? newLanguages[0] : 'markdown';
719 720 721 722
		const index = cell ? this.notebookViewModel!.getCellIndex(cell) : 0;
		const insertIndex = cell ?
			(direction === 'above' ? index : index + 1) :
			index;
R
rebornix 已提交
723
		const newCell = this.notebookViewModel!.createCell(insertIndex, initialText.split(/\r?\n/g), language, type, true);
P
Peng Lyu 已提交
724

R
rebornix 已提交
725
		if (type === CellKind.Markdown) {
726
			newCell.editState = CellEditState.Editing;
P
Peng Lyu 已提交
727
		}
R
rebornix 已提交
728

729
		return newCell;
P
Peng Lyu 已提交
730 731
	}

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

737
		(cell as CellViewModel).save();
R
rebornix 已提交
738
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
739
		this.notebookViewModel!.deleteCell(index, true);
740
		return true;
R
rebornix 已提交
741 742
	}

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

R
rebornix 已提交
748
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
749
		if (index === this.notebookViewModel!.length - 1) {
750
			return false;
R
rebornix 已提交
751 752
		}

753
		const newIdx = index + 1;
754
		return this.moveCellToIndex(index, newIdx);
755 756
	}

757
	async moveCellUp(cell: ICellViewModel): Promise<boolean> {
758 759 760 761
		if (!this.notebookViewModel!.metadata.editable) {
			return false;
		}

R
rebornix 已提交
762
		const index = this.notebookViewModel!.getCellIndex(cell);
R
rebornix 已提交
763
		if (index === 0) {
764
			return false;
R
rebornix 已提交
765 766
		}

767
		const newIdx = index - 1;
768
		return this.moveCellToIndex(index, newIdx);
769 770
	}

771
	async moveCell(cell: ICellViewModel, relativeToCell: ICellViewModel, direction: 'above' | 'below'): Promise<boolean> {
772 773 774 775
		if (!this.notebookViewModel!.metadata.editable) {
			return false;
		}

R
Rob Lourens 已提交
776
		if (cell === relativeToCell) {
777
			return false;
R
Rob Lourens 已提交
778 779 780 781 782 783 784 785 786
		}

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

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

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

792
		let r: (val: boolean) => void;
793
		DOM.scheduleAtNextAnimationFrame(() => {
794
			this.list?.revealElementInView(this.notebookViewModel!.viewCells[newIdx]);
795
			r(true);
796
		});
797 798

		return new Promise(resolve => { r = resolve; });
799 800
	}

R
rebornix 已提交
801
	editNotebookCell(cell: CellViewModel): void {
802 803 804 805
		if (!cell.getEvaluatedMetadata(this.notebookViewModel!.metadata).editable) {
			return;
		}

806
		cell.editState = CellEditState.Editing;
R
rebornix 已提交
807 808

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

R
rebornix 已提交
811
	saveNotebookCell(cell: ICellViewModel): void {
812
		cell.editState = CellEditState.Preview;
P
Peng Lyu 已提交
813 814
	}

R
rebornix 已提交
815 816 817 818 819 820 821 822 823 824
	getActiveCell() {
		let elements = this.list?.getFocusedElements();

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

		return undefined;
	}

825 826 827 828 829 830 831 832 833 834 835
	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> {
836 837 838 839
		if (!this.notebookViewModel!.metadata.runnable) {
			return;
		}

840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
		// 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;
	}

875
	async executeNotebookCell(cell: ICellViewModel): Promise<void> {
876 877 878 879
		if (!cell.getEvaluatedMetadata(this.notebookViewModel!.metadata).runnable) {
			return;
		}

880
		const tokenSource = new CancellationTokenSource();
881 882 883 884 885 886 887
		try {
			this._executeNotebookCell(cell, tokenSource);
		} finally {
			tokenSource.dispose();
		}
	}

R
Rob Lourens 已提交
888
	private async _executeNotebookCell(cell: ICellViewModel, tokenSource: CancellationTokenSource): Promise<void> {
889
		try {
890
			cell.currentTokenSource = tokenSource;
R
rebornix 已提交
891
			const provider = this.notebookService.getContributedNotebookProviders(this.viewModel!.uri)[0];
892 893 894 895
			if (provider) {
				const viewType = provider.id;
				const notebookUri = CellUri.parse(cell.uri)?.notebook;
				if (notebookUri) {
896
					return await this.notebookService.executeNotebookCell(viewType, notebookUri, cell.handle, tokenSource.token);
897 898 899
				}
			}
		} finally {
900
			cell.currentTokenSource = undefined;
901 902 903
		}
	}

R
rebornix 已提交
904
	focusNotebookCell(cell: ICellViewModel, focusEditor: boolean) {
R
rebornix 已提交
905
		if (focusEditor) {
R
rebornix 已提交
906
			this.selectElement(cell);
R
rebornix 已提交
907
			this.list?.focusView();
R
rebornix 已提交
908

909
			cell.editState = CellEditState.Editing;
R
rebornix 已提交
910
			cell.focusMode = CellFocusMode.Editor;
911
			this.revealInCenterIfOutsideViewport(cell);
R
rebornix 已提交
912
		} else {
R
rebornix 已提交
913
			let itemDOM = this.list?.domElementOfElement(cell);
R
rebornix 已提交
914 915 916
			if (document.activeElement && itemDOM && itemDOM.contains(document.activeElement)) {
				(document.activeElement as HTMLElement).blur();
			}
917

918
			cell.editState = CellEditState.Preview;
919
			cell.focusMode = CellFocusMode.Container;
R
rebornix 已提交
920

R
rebornix 已提交
921
			this.selectElement(cell);
922
			this.revealInCenterIfOutsideViewport(cell);
R
rebornix 已提交
923
			this.list?.focusView();
R
rebornix 已提交
924 925 926
		}
	}

R
rebornix 已提交
927 928 929 930
	//#endregion

	//#region MISC

R
rebornix 已提交
931 932 933 934 935 936 937 938 939 940 941
	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 已提交
942

R
rebornix 已提交
943 944
	triggerScroll(event: IMouseWheelEvent) {
		this.list?.triggerScrollFromMouseWheelEvent(event);
R
rebornix 已提交
945 946
	}

R
rebornix 已提交
947
	createInset(cell: CodeCellViewModel, output: IOutput, shadowContent: string, offset: number) {
R
rebornix 已提交
948 949
		if (!this.webview) {
			return;
R
rebornix 已提交
950 951
		}

R
rebornix 已提交
952
		let preloads = this.notebookViewModel!.renderers;
R
rebornix 已提交
953

954
		if (!this.webview!.insetMapping.has(output)) {
R
rebornix 已提交
955
			let cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
956
			this.webview!.createInset(cell, output, cellTop, offset, shadowContent, preloads);
R
rebornix 已提交
957
		} else {
R
rebornix 已提交
958
			let cellTop = this.list?.getAbsoluteTopOfElement(cell) || 0;
R
rebornix 已提交
959 960
			let scrollTop = this.list?.scrollTop || 0;

961
			this.webview!.updateViewScrollTop(-scrollTop, [{ cell: cell, output: output, cellTop: cellTop }]);
R
rebornix 已提交
962
		}
R
rebornix 已提交
963
	}
R
rebornix 已提交
964

R
rebornix 已提交
965 966 967 968 969 970 971 972
	removeInset(output: IOutput) {
		if (!this.webview) {
			return;
		}

		this.webview!.removeInset(output);
	}

973 974 975 976 977 978 979 980
	hideInset(output: IOutput) {
		if (!this.webview) {
			return;
		}

		this.webview!.hideInset(output);
	}

R
rebornix 已提交
981 982
	getOutputRenderer(): OutputRenderer {
		return this.outputRenderer;
R
rebornix 已提交
983
	}
984

985 986 987 988
	postMessage(message: any) {
		this.webview?.webview.sendMessage(message);
	}

R
rebornix 已提交
989
	//#endregion
990

R
rebornix 已提交
991 992 993 994 995 996
	//#region Editor Contributions
	public getContribution<T extends INotebookEditorContribution>(id: string): T {
		return <T>(this._contributions[id] || null);
	}

	//#endregion
R
rebornix 已提交
997

R
rebornix 已提交
998 999 1000 1001 1002 1003 1004 1005 1006 1007
	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();
	}

1008 1009 1010 1011 1012
	toJSON(): any {
		return {
			notebookHandle: this.viewModel?.handle
		};
	}
P
Peng Lyu 已提交
1013 1014 1015 1016
}

const embeddedEditorBackground = 'walkThrough.embeddedEditorBackground';

1017 1018 1019 1020 1021 1022
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."));

1023 1024 1025 1026 1027 1028 1029
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 已提交
1030
// TODO currently also used for toolbar border, if we keep all of this, pick a generic name
R
rebornix 已提交
1031 1032 1033 1034 1035 1036
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"));

1037

P
Peng Lyu 已提交
1038 1039 1040
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 已提交
1041
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .monaco-editor-background,
R
Rob Lourens 已提交
1042 1043
			.monaco-workbench .part.editor > .content .notebook-editor .cell .margin-view-overlays,
			.monaco-workbench .part.editor > .content .notebook-editor .cell .cell-statusbar-container { background: ${color}; }`);
1044
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-drag-image .cell-editor-container > div { background: ${color} !important; }`);
P
Peng Lyu 已提交
1045 1046 1047
	}
	const link = theme.getColor(textLinkForeground);
	if (link) {
M
Miguel Solorio 已提交
1048 1049
		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 已提交
1050 1051 1052
	}
	const activeLink = theme.getColor(textLinkActiveForeground);
	if (activeLink) {
R
Rob Lourens 已提交
1053 1054
		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 已提交
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
	}
	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}; }`);
	}
1073

1074 1075 1076
	const containerBackground = theme.getColor(notebookOutputContainerColor);
	if (containerBackground) {
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { background-color: ${containerBackground}; }`);
1077
	}
1078

R
Rob Lourens 已提交
1079 1080 1081
	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 已提交
1082
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar { background-color: ${editorBackgroundColor}; }`);
R
Rob Lourens 已提交
1083
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.cell-drag-image { background-color: ${editorBackgroundColor}; }`);
1084 1085
	}

R
rebornix 已提交
1086 1087 1088 1089
	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 已提交
1090
		collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar { border: solid 1px ${cellToolbarSeperator}; }`);
1091 1092
		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 已提交
1093 1094 1095 1096 1097
	}

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

R
rebornix 已提交
1103 1104 1105 1106 1107 1108 1109
	// 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}
	// 	}`)
	// }

1110
	// Cell Margin
R
Rob Lourens 已提交
1111
	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 + CELL_RUN_GUTTER}px 0px ${CELL_MARGIN}px; }`);
R
rebornix 已提交
1112
	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; }`);
1113
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 0px ${CELL_MARGIN}px 0px ${CELL_MARGIN + CELL_RUN_GUTTER}px }`);
R
rebornix 已提交
1114
	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 已提交
1115

1116
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .markdown-cell-row .cell .cell-editor-part { margin-left: ${CELL_RUN_GUTTER}px; }`);
R
rebornix 已提交
1117
	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 已提交
1118
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .run-button-container { width: ${CELL_RUN_GUTTER}px; }`);
R
Rob Lourens 已提交
1119
	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; }`);
1120
	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; }`);
R
Rob Lourens 已提交
1121
	collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list .monaco-list-row .notebook-cell-focus-indicator { left: ${CELL_MARGIN}px; }`);
P
Peng Lyu 已提交
1122
});