From f1b360520a79a1548cde31fcd650df403c657747 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 14 Jul 2021 13:30:40 +0200 Subject: [PATCH 1/3] 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 7e7ddddee84..ffcb5fb6dc9 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 fd38dafbd88..d653bca78fe 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 e82dc8afd62..469d681b12b 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 From c8d80b5001e4e730038bcd8b5ad7099c354da6c2 Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 14 Jul 2021 13:37:35 +0200 Subject: [PATCH 2/3] Adds afterInjectedText to IThemeDecorationRenderOptions. --- .../browser/services/codeEditorServiceImpl.ts | 16 ++++++++++++++++ src/vs/editor/common/editorCommon.ts | 1 + 2 files changed, 17 insertions(+) diff --git a/src/vs/editor/browser/services/codeEditorServiceImpl.ts b/src/vs/editor/browser/services/codeEditorServiceImpl.ts index ffcb5fb6dc9..48e8b5a73cf 100644 --- a/src/vs/editor/browser/services/codeEditorServiceImpl.ts +++ b/src/vs/editor/browser/services/codeEditorServiceImpl.ts @@ -251,6 +251,7 @@ export class DecorationTypeOptionsProvider implements IModelDecorationOptionsPro public overviewRuler: IModelDecorationOverviewRulerOptions | undefined; public stickiness: TrackedRangeStickiness | undefined; public beforeInjectedText: InjectedTextOptions | undefined; + public afterInjectedText: InjectedTextOptions | undefined; constructor(description: string, themeService: IThemeService, styleSheet: GlobalStyleSheet | RefCountedStyleSheet, providerArgs: ProviderArguments) { this.description = description; @@ -294,6 +295,15 @@ export class DecorationTypeOptionsProvider implements IModelDecorationOptionsPro }; } + if (providerArgs.options.afterInjectedText && providerArgs.options.afterInjectedText.contentText) { + const afterInlineData = createInlineCSSRules(ModelDecorationCSSRuleType.AfterInjectedTextClassName); + this.afterInjectedText = { + content: providerArgs.options.afterInjectedText.contentText, + inlineClassName: afterInlineData?.className, + inlineClassNameAffectsLetterSpacing: afterInlineData?.hasLetterSpacing || providerArgs.options.afterInjectedText.affectsLetterSpacing + }; + } + this.glyphMarginClassName = createCSSRules(ModelDecorationCSSRuleType.GlyphMarginClassName); const options = providerArgs.options; @@ -479,6 +489,11 @@ class DecorationCSSRules { lightCSS = this.getCSSTextForModelDecorationContentClassName(options.light && options.light.beforeInjectedText); darkCSS = this.getCSSTextForModelDecorationContentClassName(options.dark && options.dark.beforeInjectedText); break; + case ModelDecorationCSSRuleType.AfterInjectedTextClassName: + unthemedCSS = this.getCSSTextForModelDecorationContentClassName(options.afterInjectedText); + lightCSS = this.getCSSTextForModelDecorationContentClassName(options.light && options.light.afterInjectedText); + darkCSS = this.getCSSTextForModelDecorationContentClassName(options.dark && options.dark.afterInjectedText); + break; default: throw new Error('Unknown rule type: ' + this._ruleType); } @@ -620,6 +635,7 @@ const enum ModelDecorationCSSRuleType { BeforeContentClassName = 3, AfterContentClassName = 4, BeforeInjectedTextClassName = 5, + AfterInjectedTextClassName = 6, } class CSSNameHelper { diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index d653bca78fe..55da3496fac 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -622,6 +622,7 @@ export interface IThemeDecorationRenderOptions { after?: IContentDecorationRenderOptions; beforeInjectedText?: IContentDecorationRenderOptions & { affectsLetterSpacing?: boolean }; + afterInjectedText?: IContentDecorationRenderOptions & { affectsLetterSpacing?: boolean }; } /** From 821fe26af98c9960661de97d435c4f7812e3d4ca Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Wed, 14 Jul 2021 15:22:19 +0200 Subject: [PATCH 3/3] IContextKeyService -> IConfigurationService --- src/vs/editor/contrib/inlayHints/inlayHintsController.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/inlayHints/inlayHintsController.ts b/src/vs/editor/contrib/inlayHints/inlayHintsController.ts index 469d681b12b..30c644c4d20 100644 --- a/src/vs/editor/contrib/inlayHints/inlayHintsController.ts +++ b/src/vs/editor/contrib/inlayHints/inlayHintsController.ts @@ -26,7 +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'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; const MAX_DECORATORS = 500; @@ -66,7 +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 + @IConfigurationService private readonly _configurationService: IConfigurationService, ) { this._disposables.add(InlayHintsProviderRegistry.onDidChange(() => this._update())); this._disposables.add(_themeService.onDidColorThemeChange(() => this._update())); @@ -147,7 +147,7 @@ export class InlayHintsController implements IEditorContribution { const fontFamilyVar = '--inlayHintsFontFamily'; this._editor.getContainerDomNode().style.setProperty(fontFamilyVar, fontFamily); - const key = this._contextKeyService.getContextKeyValue('config.editor.useInjectedText'); + const key = this._configurationService.getValue('editor.useInjectedText'); const shouldUseInjectedText = key === undefined ? true : !!key; for (const { list: hints } of hintsData) {