nb decoration api first cut.

This commit is contained in:
rebornix
2020-09-16 14:00:07 -07:00
parent 50cc1d0e97
commit 289bce5e1a
16 changed files with 343 additions and 25 deletions
+18
View File
@@ -1414,6 +1414,9 @@ declare module 'vscode' {
export interface NotebookCellRange {
readonly start: number;
/**
* exclusive
*/
readonly end: number;
}
@@ -1505,6 +1508,8 @@ declare module 'vscode' {
*/
edit(callback: (editBuilder: NotebookEditorEdit) => void): Thenable<boolean>;
setDecorations(decorationType: NotebookEditorDecorationType, range: NotebookCellRange): void;
revealRange(range: NotebookCellRange, revealType?: NotebookEditorRevealType): void;
}
@@ -1760,6 +1765,18 @@ declare module 'vscode' {
dispose(): void;
}
export interface NotebookDecorationRenderOptions {
backgroundColor?: string | ThemeColor;
borderColor?: string | ThemeColor;
top: ThemableDecorationAttachmentRenderOptions;
}
export interface NotebookEditorDecorationType {
readonly key: string;
dispose(): void;
}
export namespace notebook {
export function registerNotebookContentProvider(
notebookType: string,
@@ -1783,6 +1800,7 @@ declare module 'vscode' {
provider: NotebookKernelProvider
): Disposable;
export function createNotebookEditorDecorationType(options: NotebookDecorationRenderOptions): NotebookEditorDecorationType;
export const onDidOpenNotebookDocument: Event<NotebookDocument>;
export const onDidCloseNotebookDocument: Event<NotebookDocument>;
export const onDidSaveNotebookDocument: Event<NotebookDocument>;
@@ -18,7 +18,7 @@ import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookB
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDocumentFilter, NotebookCellOutputsSplice, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, NotebookCellOutputsSplice, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
@@ -648,6 +648,22 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
}
}
$registerNotebookEditorDecorationType(key: string, options: INotebookDecorationRenderOptions) {
this._notebookService.registerEditorDecorationType(key, options);
}
$removeNotebookEditorDecorationType(key: string) {
this._notebookService.removeEditorDecorationType(key);
}
$trySetDecorations(id: string, range: ICellRange, key: string) {
const editor = this._notebookService.listNotebookEditors().find(editor => editor.getId() === id);
if (editor && editor.isNotebookEditor) {
const notebookEditor = editor as INotebookEditor;
notebookEditor.setEditorDecorations(key, range);
}
}
async $setStatusBarEntry(id: number, rawStatusBarEntry: INotebookCellStatusBarEntryDto): Promise<void> {
const statusBarEntry = {
...rawStatusBarEntry,
@@ -966,6 +966,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookKernelProvider(extension, selector, provider);
},
createNotebookEditorDecorationType(options: vscode.NotebookDecorationRenderOptions): vscode.NotebookEditorDecorationType {
return extHostNotebook.createNotebookEditorDecorationType(options);
},
get activeNotebookEditor(): vscode.NotebookEditor | undefined {
checkProposedApiEnabled(extension);
return extHostNotebook.activeNotebookEditor;
@@ -51,7 +51,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
import { revive } from 'vs/base/common/marshalling';
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange, INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { Dto } from 'vs/base/common/types';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
@@ -746,6 +746,9 @@ export interface MainThreadNotebookShape extends IDisposable {
$postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean>;
$setStatusBarEntry(id: number, statusBarEntry: INotebookCellStatusBarEntryDto): Promise<void>;
$tryRevealRange(id: string, range: ICellRange, revealType: NotebookEditorRevealType): Promise<void>;
$registerNotebookEditorDecorationType(key: string, options: INotebookDecorationRenderOptions): void;
$removeNotebookEditorDecorationType(key: string): void;
$trySetDecorations(id: string, range: ICellRange, decorationKey: string): void;
$onUndoableContentChange(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
$onContentChange(resource: UriComponents, viewType: string): void;
}
@@ -22,6 +22,7 @@ import * as vscode from 'vscode';
import { ResourceMap } from 'vs/base/common/map';
import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument';
import { ExtHostNotebookEditor } from './extHostNotebookEditor';
import { IdGenerator } from 'vs/base/common/idGenerator';
class ExtHostWebviewCommWrapper extends Disposable {
private readonly _onDidReceiveDocumentMessage = new Emitter<any>();
@@ -187,6 +188,24 @@ async function withToken(cb: (token: CancellationToken) => any) {
}
}
export class NotebookEditorDecorationType implements vscode.NotebookEditorDecorationType {
private static readonly _Keys = new IdGenerator('NotebookEditorDecorationType');
private _proxy: MainThreadNotebookShape;
public key: string;
constructor(proxy: MainThreadNotebookShape, options: vscode.NotebookDecorationRenderOptions) {
this.key = NotebookEditorDecorationType._Keys.nextId();
this._proxy = proxy;
this._proxy.$registerNotebookEditorDecorationType(this.key, typeConverters.NotebookDecorationRenderOptions.from(options));
}
public dispose(): void {
this._proxy.$removeNotebookEditorDecorationType(this.key);
}
}
export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostNotebookOutputRenderingHandler {
private static _notebookKernelProviderHandlePool: number = 0;
@@ -338,6 +357,10 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
});
}
createNotebookEditorDecorationType(options: vscode.NotebookDecorationRenderOptions): vscode.NotebookEditorDecorationType {
return new NotebookEditorDecorationType(this._proxy, options);
}
private _withAdapter<T>(handle: number, uri: UriComponents, callback: (adapter: ExtHostNotebookKernelProviderAdapter, document: ExtHostNotebookDocument) => Promise<T>) {
const document = this._documents.get(URI.revive(uri));
@@ -99,6 +99,8 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
readonly onDidDispose: Event<void> = this._onDidDispose.event;
readonly onDidReceiveMessage: vscode.Event<any> = this._onDidReceiveMessage.event;
private _hasDecorationsForKey: { [key: string]: boolean; } = Object.create(null);
constructor(
readonly id: string,
private readonly _viewType: string,
@@ -214,6 +216,25 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
return this._proxy.$tryApplyEdits(this._viewType, this.document.uri, editData.documentVersionId, compressedEdits);
}
setDecorations(decorationType: vscode.NotebookEditorDecorationType, range: vscode.NotebookCellRange): void {
const willBeEmpty = (range.start === range.end);
if (willBeEmpty && !this._hasDecorationsForKey[decorationType.key]) {
// avoid no-op call to the renderer
return;
}
if (willBeEmpty) {
delete this._hasDecorationsForKey[decorationType.key];
} else {
this._hasDecorationsForKey[decorationType.key] = true;
}
return this._proxy.$trySetDecorations(
this.id,
range,
decorationType.key
);
}
revealRange(range: vscode.NotebookCellRange, revealType?: extHostTypes.NotebookEditorRevealType) {
this._proxy.$tryRevealRange(this.id, range, revealType || extHostTypes.NotebookEditorRevealType.Default);
}
@@ -32,6 +32,7 @@ import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays';
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
export interface PositionLike {
line: number;
@@ -1348,3 +1349,13 @@ export namespace NotebookExclusiveDocumentPattern {
return rp && typeof rp.base === 'string' && typeof rp.pattern === 'string';
}
}
export namespace NotebookDecorationRenderOptions {
export function from(options: vscode.NotebookDecorationRenderOptions): INotebookDecorationRenderOptions {
return {
backgroundColor: <string | types.ThemeColor>options.backgroundColor,
borderColor: <string | types.ThemeColor>options.borderColor,
top: options.top ? ThemableDecorationAttachmentRenderOptions.from(options.top) : undefined
};
}
}
@@ -438,6 +438,9 @@ export interface INotebookEditor extends IEditor {
*/
changeModelDecorations<T>(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): T | null;
setEditorDecorations(key: string, range: ICellRange): void;
removeEditorDecorations(key: string): void;
/**
* An event emitted on a "mouseup".
* @event
@@ -515,6 +518,7 @@ export interface INotebookCellList {
}
export interface BaseCellRenderTemplate {
rootContainer: HTMLElement;
editorPart: HTMLElement;
collapsedPart: HTMLElement;
expandButton: HTMLElement;
@@ -22,7 +22,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { Range } from 'vs/editor/common/core/range';
import { IEditor } from 'vs/editor/common/editorCommon';
import { IEditor, isThemeColor } from 'vs/editor/common/editorCommon';
import * as nls from 'vs/nls';
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -34,7 +34,7 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { contrastBorder, diffInserted, diffRemoved, editorBackground, errorForeground, focusBorder, foreground, listFocusBackground, listInactiveSelectionBackground, registerColor, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, textBlockQuoteBackground, textBlockQuoteBorder, textLinkActiveForeground, textLinkForeground, textPreformatForeground, transparent } from 'vs/platform/theme/common/colorRegistry';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { IColorTheme, IThemeService, registerThemingParticipant, ThemeColor } from 'vs/platform/theme/common/themeService';
import { EditorMemento } from 'vs/workbench/browser/parts/editor/editorPane';
import { IEditorMemento } from 'vs/workbench/common/editor';
import { Memento, MementoObject } from 'vs/workbench/common/memento';
@@ -54,7 +54,7 @@ import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewMod
import { NotebookEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
import { CellViewModel, IModelDecorationsChangeAccessor, INotebookEditorViewState, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { CellKind, CellToolbarLocKey, ICellRange, IInsetRenderOutput, INotebookKernelInfo2, IProcessedOutput, isTransformedDisplayOutput, NotebookCellRunState, NotebookRunState, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CellKind, CellToolbarLocKey, ICellRange, IInsetRenderOutput, INotebookDecorationRenderOptions, INotebookKernelInfo2, IProcessedOutput, isTransformedDisplayOutput, NotebookCellRunState, NotebookRunState, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator';
@@ -241,7 +241,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
@ILayoutService private readonly layoutService: ILayoutService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IMenuService private readonly menuService: IMenuService,
@IQuickInputService private readonly quickInputService: IQuickInputService
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IThemeService private readonly themeService: IThemeService
) {
super();
this.isEmbedded = creationOptions.isEmbedded || false;
@@ -1224,6 +1225,63 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
return this._list!.setHiddenAreas(_ranges, true);
}
private _editorStyleSheets = new Map<string, RefCountedStyleSheet>();
private _decorationRules = new Map<string, DecorationCSSRules>();
private _decortionKeyToIds = new Map<string, string[]>();
_removeEditorStyleSheets(key: string): void {
this._editorStyleSheets.delete(key);
}
private _registerDecorationType(key: string) {
const options = this.notebookService.resolveEditorDecorationOptions(key);
if (options) {
const styleElement = DOM.createStyleSheet(this._body);
const styleSheet = new RefCountedStyleSheet(this, key, styleElement);
this._editorStyleSheets.set(key, styleSheet);
this._decorationRules.set(key, new DecorationCSSRules(this.themeService, styleSheet, {
key,
options,
styleSheet
}));
}
}
setEditorDecorations(key: string, range: ICellRange): void {
if (!this.viewModel) {
return;
}
// create css style for the decoration
if (!this._editorStyleSheets.has(key)) {
this._registerDecorationType(key);
}
const decorationRule = this._decorationRules.get(key);
if (!decorationRule) {
return;
}
const existingDecorations = this._decortionKeyToIds.get(key) || [];
const newDecorations = this.viewModel.viewCells.slice(range.start, range.end).map(cell => ({
handle: cell.handle,
options: { className: decorationRule.className, outputClassName: decorationRule.className }
}));
this._decortionKeyToIds.set(key, this.deltaCellDecorations(existingDecorations, newDecorations));
}
removeEditorDecorations(key: string): void {
if (this._decorationRules.has(key)) {
this._decorationRules.get(key)?.dispose();
}
const cellDecorations = this._decortionKeyToIds.get(key);
this.deltaCellDecorations(cellDecorations || [], []);
}
//#endregion
//#region Mouse Events
@@ -1952,8 +2010,8 @@ registerThemingParticipant((theme, collector) => {
const cellSymbolHighlightColor = theme.getColor(cellSymbolHighlight);
if (cellSymbolHighlightColor) {
collector.addRule(`.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row .nb-symbolHighlight .cell-focus-indicator,
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row .nb-symbolHighlight {
collector.addRule(`.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.nb-symbolHighlight .cell-focus-indicator,
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row.nb-symbolHighlight {
background-color: ${cellSymbolHighlightColor} !important;
}`);
}
@@ -2021,11 +2079,11 @@ registerThemingParticipant((theme, collector) => {
const modifiedBackground = theme.getColor(editorGutterModifiedBackground);
if (modifiedBackground) {
collector.addRule(`
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row .nb-cell-modified .cell-focus-indicator {
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.nb-cell-modified .cell-focus-indicator {
background-color: ${modifiedBackground} !important;
}
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row .nb-cell-modified {
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row.nb-cell-modified {
background-color: ${modifiedBackground} !important;
}`);
}
@@ -2033,22 +2091,22 @@ registerThemingParticipant((theme, collector) => {
const addedBackground = theme.getColor(diffInserted);
if (addedBackground) {
collector.addRule(`
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row .nb-cell-added .cell-focus-indicator {
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.nb-cell-added .cell-focus-indicator {
background-color: ${addedBackground} !important;
}
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row .nb-cell-added {
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row.nb-cell-added {
background-color: ${addedBackground} !important;
}`);
}
const deletedBackground = theme.getColor(diffRemoved);
if (deletedBackground) {
collector.addRule(`
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row .nb-cell-deleted .cell-focus-indicator {
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.nb-cell-deleted .cell-focus-indicator {
background-color: ${deletedBackground} !important;
}
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row .nb-cell-deleted {
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row.nb-cell-deleted {
background-color: ${deletedBackground} !important;
}`);
}
@@ -2077,3 +2135,117 @@ registerThemingParticipant((theme, collector) => {
collector.addRule(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell-bottom-toolbar-container { height: ${BOTTOM_CELL_TOOLBAR_HEIGHT}px }`);
});
export class RefCountedStyleSheet {
private readonly _widget: NotebookEditorWidget;
private readonly _key: string;
private readonly _styleSheet: HTMLStyleElement;
private _refCount: number;
constructor(widget: NotebookEditorWidget, key: string, styleSheet: HTMLStyleElement) {
this._widget = widget;
this._key = key;
this._styleSheet = styleSheet;
this._refCount = 0;
}
public ref(): void {
this._refCount++;
}
public unref(): void {
this._refCount--;
if (this._refCount === 0) {
this._styleSheet.parentNode?.removeChild(this._styleSheet);
this._widget._removeEditorStyleSheets(this._key);
}
}
public insertRule(rule: string, index?: number): void {
const sheet = <CSSStyleSheet>this._styleSheet.sheet;
sheet.insertRule(rule, index);
}
}
interface ProviderArguments {
styleSheet: RefCountedStyleSheet;
key: string;
options: INotebookDecorationRenderOptions;
}
class DecorationCSSRules {
private _theme: IColorTheme;
private _className: string;
get className() {
return this._className;
}
constructor(
private readonly _themeService: IThemeService,
private readonly _styleSheet: RefCountedStyleSheet,
private readonly _providerArgs: ProviderArguments
) {
this._styleSheet.ref();
this._theme = this._themeService.getColorTheme();
this._className = CSSNameHelper.getClassName(this._providerArgs.key, CellDecorationCSSRuleType.ClassName);
this._buildCSS();
}
private _buildCSS() {
this._styleSheet.insertRule('.foo { color: red; }', 0);
if (this._providerArgs.options.backgroundColor) {
const backgroundColor = this._resolveValue(this._providerArgs.options.backgroundColor);
this._styleSheet.insertRule(`.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.code-cell-row.${this.className} .cell-focus-indicator,
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.markdown-cell-row.${this.className} {
background-color: ${backgroundColor} !important;
}`);
}
if (this._providerArgs.options.borderColor) {
const borderColor = this._resolveValue(this._providerArgs.options.borderColor);
this._styleSheet.insertRule(`.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.${this.className} .cell-focus-indicator-top:before,
.monaco-workbench .notebookOverlay .monaco-list .monaco-list-row.${this.className} .cell-focus-indicator-bottom:before,
.monaco-workbench .notebookOverlay .monaco-list .${this.className}.markdown-cell-row.focused:before,
.monaco-workbench .notebookOverlay .monaco-list .${this.className}.markdown-cell-row.focused:after {
border-color: ${borderColor} !important;
}`);
// more specific rule for `.focused` can override existing rules
this._styleSheet.insertRule(`.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused.${this.className} .cell-focus-indicator-top:before,
.monaco-workbench .notebookOverlay .monaco-list:focus-within .monaco-list-row.focused.${this.className} .cell-focus-indicator-bottom:before,
.monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused.${this.className}:before,
.monaco-workbench .notebookOverlay .monaco-list:focus-within .markdown-cell-row.focused.${this.className}:after {
border-color: ${borderColor} !important;
}`);
}
}
private _resolveValue(value: string | ThemeColor): string {
if (isThemeColor(value)) {
const color = this._theme.getColor(value.id);
if (color) {
return color.toString();
}
return 'transparent';
}
return value;
}
dispose() {
this._styleSheet.unref();
}
}
const enum CellDecorationCSSRuleType {
ClassName = 0,
}
class CSSNameHelper {
public static getClassName(key: string, type: CellDecorationCSSRuleType): string {
return 'nb-' + key + '-' + type;
}
}
@@ -27,7 +27,7 @@ import { NotebookKernelProviderAssociationRegistry, NotebookViewTypesExtensionRe
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellEditType, CellKind, CellOutputKind, DisplayOrderKey, ICellEditOperation, IDisplayOutput, INotebookKernelInfo2, INotebookKernelProvider, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, ITransformedDisplayOutputDto, mimeTypeSupportedByCore, NotebookCellOutputsSplice, notebookDocumentFilterMatch, NotebookEditorPriority, NOTEBOOK_DISPLAY_ORDER, sortMimeTypes } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, BUILTIN_RENDERER_ID, CellEditType, CellKind, CellOutputKind, DisplayOrderKey, ICellEditOperation, IDisplayOutput, INotebookDecorationRenderOptions, INotebookKernelInfo2, INotebookKernelProvider, INotebookRendererInfo, INotebookTextModel, IOrderedMimeType, ITransformedDisplayOutputDto, mimeTypeSupportedByCore, NotebookCellOutputsSplice, notebookDocumentFilterMatch, NotebookEditorPriority, NOTEBOOK_DISPLAY_ORDER, sortMimeTypes } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer';
import { NotebookEditorDescriptor, NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
@@ -261,6 +261,7 @@ export class NotebookService extends Disposable implements INotebookService, ICu
private _lastClipboardIsCopy: boolean = true;
private _displayOrder: { userOrder: string[], defaultOrder: string[] } = Object.create(null);
private readonly _decorationOptionProviders = new Map<string, INotebookDecorationRenderOptions>();
constructor(
@IExtensionService private readonly _extensionService: IExtensionService,
@@ -519,6 +520,24 @@ export class NotebookService extends Disposable implements INotebookService, ICu
}
registerEditorDecorationType(key: string, options: INotebookDecorationRenderOptions): void {
if (this._decorationOptionProviders.has(key)) {
return;
}
this._decorationOptionProviders.set(key, options);
}
removeEditorDecorationType(key: string): void {
this._decorationOptionProviders.delete(key);
this.listNotebookEditors().forEach(editor => editor.removeEditorDecorations(key));
}
resolveEditorDecorationOptions(key: string): INotebookDecorationRenderOptions | undefined {
return this._decorationOptionProviders.get(key);
}
getViewTypes(): ICustomEditorInfo[] {
return [...this.notebookProviderInfoStore].map(info => ({
id: info.id,
@@ -418,6 +418,7 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
const titleMenu = disposables.add(this.cellMenus.getCellTitleMenu(contextKeyService));
const templateData: MarkdownCellRenderTemplate = {
rootContainer,
collapsedPart,
expandButton,
contextKeyService,
@@ -471,6 +472,17 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR
}
renderElement(element: MarkdownCellViewModel, index: number, templateData: MarkdownCellRenderTemplate, height: number | undefined): void {
const removedClassNames: string[] = [];
templateData.rootContainer.classList.forEach(className => {
if (/^nb\-.*$/.test(className)) {
removedClassNames.push(className);
}
});
removedClassNames.forEach(className => {
templateData.rootContainer.classList.remove(className);
});
this.commonRenderElement(element, templateData);
templateData.currentRenderedCell = element;
@@ -700,6 +712,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
const titleMenu = disposables.add(this.cellMenus.getCellTitleMenu(contextKeyService));
const templateData: CodeCellRenderTemplate = {
rootContainer,
editorPart,
collapsedPart,
expandButton,
@@ -808,14 +821,14 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende
renderElement(element: CodeCellViewModel, index: number, templateData: CodeCellRenderTemplate, height: number | undefined): void {
const removedClassNames: string[] = [];
templateData.container.classList.forEach(className => {
templateData.rootContainer.classList.forEach(className => {
if (/^nb\-.*$/.test(className)) {
removedClassNames.push(className);
}
});
removedClassNames.forEach(className => {
templateData.container.classList.remove(className);
templateData.rootContainer.classList.remove(className);
});
this.commonRenderElement(element, templateData);
@@ -223,7 +223,7 @@ export class CodeCell extends Disposable {
this._register(viewCell.onCellDecorationsChanged((e) => {
e.added.forEach(options => {
if (options.className) {
DOM.addClass(templateData.container, options.className);
DOM.addClass(templateData.rootContainer, options.className);
}
if (options.outputClassName) {
@@ -233,7 +233,7 @@ export class CodeCell extends Disposable {
e.removed.forEach(options => {
if (options.className) {
DOM.removeClass(templateData.container, options.className);
DOM.removeClass(templateData.rootContainer, options.className);
}
if (options.outputClassName) {
@@ -245,7 +245,7 @@ export class CodeCell extends Disposable {
viewCell.getCellDecorations().forEach(options => {
if (options.className) {
DOM.addClass(templateData.container, options.className);
DOM.addClass(templateData.rootContainer, options.className);
}
if (options.outputClassName) {
@@ -109,13 +109,13 @@ export class StatefulMarkdownCell extends Disposable {
this._register(viewCell.onCellDecorationsChanged((e) => {
e.added.forEach(options => {
if (options.className) {
DOM.addClass(templateData.container, options.className);
DOM.addClass(templateData.rootContainer, options.className);
}
});
e.removed.forEach(options => {
if (options.className) {
DOM.removeClass(templateData.container, options.className);
DOM.removeClass(templateData.rootContainer, options.className);
}
});
}));
@@ -124,7 +124,7 @@ export class StatefulMarkdownCell extends Disposable {
viewCell.getCellDecorations().forEach(options => {
if (options.className) {
DOM.addClass(templateData.container, options.className);
DOM.addClass(templateData.rootContainer, options.className);
}
});
@@ -24,6 +24,7 @@ import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/no
import { IDisposable } from 'vs/base/common/lifecycle';
import { IFileStatWithMetadata } from 'vs/platform/files/common/files';
import { IRange } from 'vs/editor/common/core/range';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
export enum CellKind {
Markdown = 1,
@@ -883,3 +884,9 @@ export const enum CellStatusbarAlignment {
LEFT,
RIGHT
}
export interface INotebookDecorationRenderOptions {
backgroundColor?: string | ThemeColor;
borderColor?: string | ThemeColor;
top?: editorCommon.IContentDecorationRenderOptions;
}
@@ -10,7 +10,7 @@ import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.pr
import { Event } from 'vs/base/common/event';
import {
INotebookTextModel, INotebookRendererInfo,
IEditor, ICellEditOperation, NotebookCellOutputsSplice, INotebookKernelProvider, INotebookKernelInfo2, TransientMetadata, NotebookDataDto, TransientOptions
IEditor, ICellEditOperation, NotebookCellOutputsSplice, INotebookKernelProvider, INotebookKernelInfo2, TransientMetadata, NotebookDataDto, TransientOptions, INotebookDecorationRenderOptions
} from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -78,5 +78,7 @@ export interface INotebookService {
listNotebookEditors(): readonly IEditor[];
listVisibleNotebookEditors(): readonly IEditor[];
listNotebookDocuments(): readonly NotebookTextModel[];
registerEditorDecorationType(key: string, options: INotebookDecorationRenderOptions): void;
removeEditorDecorationType(key: string): void;
resolveEditorDecorationOptions(key: string): INotebookDecorationRenderOptions | undefined;
}
@@ -66,6 +66,12 @@ export class TestNotebookEditor implements INotebookEditor {
constructor(
) { }
setEditorDecorations(key: string, range: ICellRange): void {
// throw new Error('Method not implemented.');
}
removeEditorDecorations(key: string): void {
// throw new Error('Method not implemented.');
}
getSelectionHandles(): number[] {
return [];
}