From f1b360520a79a1548cde31fcd650df403c657747 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 14 Jul 2021 13:30:40 +0200 Subject: [PATCH] Extends CodeEditorService so that rich decorations can be registered for injected text. Adopts injected text for inlay text. --- .../browser/services/codeEditorServiceImpl.ts | 25 ++++++++++++++++--- src/vs/editor/common/editorCommon.ts | 2 ++ .../inlayHints/inlayHintsController.ts | 8 +++++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/vs/editor/browser/services/codeEditorServiceImpl.ts b/src/vs/editor/browser/services/codeEditorServiceImpl.ts index 7e7ddddee8475..ffcb5fb6dc90a 100644 --- a/src/vs/editor/browser/services/codeEditorServiceImpl.ts +++ b/src/vs/editor/browser/services/codeEditorServiceImpl.ts @@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { AbstractCodeEditorService } from 'vs/editor/browser/services/abstractCodeEditorService'; import { IContentDecorationRenderOptions, IDecorationRenderOptions, IThemeDecorationRenderOptions, isThemeColor } from 'vs/editor/common/editorCommon'; -import { IModelDecorationOptions, IModelDecorationOverviewRulerOptions, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model'; +import { IModelDecorationOptions, IModelDecorationOverviewRulerOptions, InjectedTextOptions, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model'; import { IColorTheme, IThemeService, ThemeColor } from 'vs/platform/theme/common/themeService'; export class RefCountedStyleSheet { @@ -250,6 +250,7 @@ export class DecorationTypeOptionsProvider implements IModelDecorationOptionsPro public isWholeLine: boolean; public overviewRuler: IModelDecorationOverviewRulerOptions | undefined; public stickiness: TrackedRangeStickiness | undefined; + public beforeInjectedText: InjectedTextOptions | undefined; constructor(description: string, themeService: IThemeService, styleSheet: GlobalStyleSheet | RefCountedStyleSheet, providerArgs: ProviderArguments) { this.description = description; @@ -283,6 +284,16 @@ export class DecorationTypeOptionsProvider implements IModelDecorationOptionsPro } this.beforeContentClassName = createCSSRules(ModelDecorationCSSRuleType.BeforeContentClassName); this.afterContentClassName = createCSSRules(ModelDecorationCSSRuleType.AfterContentClassName); + + if (providerArgs.options.beforeInjectedText && providerArgs.options.beforeInjectedText.contentText) { + const beforeInlineData = createInlineCSSRules(ModelDecorationCSSRuleType.BeforeInjectedTextClassName); + this.beforeInjectedText = { + content: providerArgs.options.beforeInjectedText.contentText, + inlineClassName: beforeInlineData?.className, + inlineClassNameAffectsLetterSpacing: beforeInlineData?.hasLetterSpacing || providerArgs.options.beforeInjectedText.affectsLetterSpacing + }; + } + this.glyphMarginClassName = createCSSRules(ModelDecorationCSSRuleType.GlyphMarginClassName); const options = providerArgs.options; @@ -307,6 +318,7 @@ export class DecorationTypeOptionsProvider implements IModelDecorationOptionsPro if (!writable) { return this; } + return { description: this.description, inlineClassName: this.inlineClassName, @@ -316,7 +328,8 @@ export class DecorationTypeOptionsProvider implements IModelDecorationOptionsPro glyphMarginClassName: this.glyphMarginClassName, isWholeLine: this.isWholeLine, overviewRuler: this.overviewRuler, - stickiness: this.stickiness + stickiness: this.stickiness, + before: this.beforeInjectedText }; } @@ -461,6 +474,11 @@ class DecorationCSSRules { lightCSS = this.getCSSTextForModelDecorationContentClassName(options.light && options.light.after); darkCSS = this.getCSSTextForModelDecorationContentClassName(options.dark && options.dark.after); break; + case ModelDecorationCSSRuleType.BeforeInjectedTextClassName: + unthemedCSS = this.getCSSTextForModelDecorationContentClassName(options.beforeInjectedText); + lightCSS = this.getCSSTextForModelDecorationContentClassName(options.light && options.light.beforeInjectedText); + darkCSS = this.getCSSTextForModelDecorationContentClassName(options.dark && options.dark.beforeInjectedText); + break; default: throw new Error('Unknown rule type: ' + this._ruleType); } @@ -600,7 +618,8 @@ const enum ModelDecorationCSSRuleType { InlineClassName = 1, GlyphMarginClassName = 2, BeforeContentClassName = 3, - AfterContentClassName = 4 + AfterContentClassName = 4, + BeforeInjectedTextClassName = 5, } class CSSNameHelper { diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index fd38dafbd887c..d653bca78fe65 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -620,6 +620,8 @@ export interface IThemeDecorationRenderOptions { before?: IContentDecorationRenderOptions; after?: IContentDecorationRenderOptions; + + beforeInjectedText?: IContentDecorationRenderOptions & { affectsLetterSpacing?: boolean }; } /** diff --git a/src/vs/editor/contrib/inlayHints/inlayHintsController.ts b/src/vs/editor/contrib/inlayHints/inlayHintsController.ts index e82dc8afd627d..469d681b12b1d 100644 --- a/src/vs/editor/contrib/inlayHints/inlayHintsController.ts +++ b/src/vs/editor/contrib/inlayHints/inlayHintsController.ts @@ -26,6 +26,7 @@ import { IRange } from 'vs/base/common/range'; import { assertType } from 'vs/base/common/types'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { Position } from 'vs/editor/common/core/position'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; const MAX_DECORATORS = 500; @@ -65,6 +66,7 @@ export class InlayHintsController implements IEditorContribution { private readonly _editor: ICodeEditor, @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, @IThemeService private readonly _themeService: IThemeService, + @IContextKeyService private readonly _contextKeyService: IContextKeyService ) { this._disposables.add(InlayHintsProviderRegistry.onDidChange(() => this._update())); this._disposables.add(_themeService.onDidColorThemeChange(() => this._update())); @@ -145,6 +147,9 @@ export class InlayHintsController implements IEditorContribution { const fontFamilyVar = '--inlayHintsFontFamily'; this._editor.getContainerDomNode().style.setProperty(fontFamilyVar, fontFamily); + const key = this._contextKeyService.getContextKeyValue('config.editor.useInjectedText'); + const shouldUseInjectedText = key === undefined ? true : !!key; + for (const { list: hints } of hintsData) { for (let j = 0; j < hints.length && newDecorationsData.length < MAX_DECORATORS; j++) { @@ -163,7 +168,8 @@ export class InlayHintsController implements IEditorContribution { borderRadius: `${(fontSize / 4) | 0}px`, }; const key = 'inlayHints-' + hash(before).toString(16); - this._codeEditorService.registerDecorationType('inlay-hints-controller', key, { before }, undefined, this._editor); + this._codeEditorService.registerDecorationType('inlay-hints-controller', key, + shouldUseInjectedText ? { beforeInjectedText: { ...before, affectsLetterSpacing: true } } : { before }, undefined, this._editor); // decoration types are ref-counted which means we only need to // call register und remove equally often