From e77dbbd68f06135ee5de76c4322984910b856934 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 17 Mar 2022 00:52:44 -0400 Subject: [PATCH] Adds theme awareness to Changes annotations --- CHANGELOG.md | 1 + src/annotations/annotationProvider.ts | 19 +++ src/annotations/fileAnnotationController.ts | 240 +++++++++++++++++----------- 3 files changed, 169 insertions(+), 91 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 557c949..682bad4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Changes the current line blame hover to show at the cursor, rather than the start of the line, when showing the hover over the whole line (e.g. line & annotation) - Changes the default of showing PR information in the current line blame annotation to reduce overhead (e.g. GitHub queries) +- Changes [**_Gutter Changes_**](https://github.com/gitkraken/vscode-gitlens#gutter-changes-) file annotations to be theme-aware ### Fixed diff --git a/src/annotations/annotationProvider.ts b/src/annotations/annotationProvider.ts index 305d46a..f176c7c 100644 --- a/src/annotations/annotationProvider.ts +++ b/src/annotations/annotationProvider.ts @@ -92,6 +92,25 @@ export abstract class AnnotationProviderBase) { + if (this.editor == null || !this.decorations?.length) return; + + const decorations = []; + + for (const d of this.decorations) { + const type = replaceDecorationTypes.get(d.decorationType); + // If the type is null then we've removed that type, so remove the decorations that reference it + if (type === null) continue; + + if (type != null) { + d.decorationType = type; + } + decorations.push(d); + } + + this.setDecorations(this.decorations); + } + async restore(editor: TextEditor) { // If the editor isn't disposed then we don't need to do anything // Explicitly check for `false` diff --git a/src/annotations/fileAnnotationController.ts b/src/annotations/fileAnnotationController.ts index e9f442f..48ff83b 100644 --- a/src/annotations/fileAnnotationController.ts +++ b/src/annotations/fileAnnotationController.ts @@ -1,4 +1,6 @@ import { + ColorTheme, + ColorThemeKind, ConfigurationChangeEvent, DecorationRangeBehavior, Disposable, @@ -86,6 +88,7 @@ export class FileAnnotationController implements Disposable { this._disposable = Disposable.from( once(container.onReady)(this.onReady, this), configuration.onDidChange(this.onConfigurationChanged, this), + window.onDidChangeActiveColorTheme(this.onThemeChanged, this), ); this._toggleModes = new Map(); @@ -111,95 +114,12 @@ export class FileAnnotationController implements Disposable { private onConfigurationChanged(e?: ConfigurationChangeEvent) { const cfg = this.container.config; - if (configuration.changed(e, 'blame.highlight')) { - Decorations.gutterBlameHighlight?.dispose(); - Decorations.gutterBlameHighlight = undefined; - - const highlight = cfg.blame.highlight; - - if (highlight.enabled) { - const { locations } = highlight; - - // TODO@eamodio: Read from the theme color when the API exists - const gutterHighlightColor = '#00bcf2'; // new ThemeColor(Colors.LineHighlightOverviewRulerColor) - const gutterHighlightUri = locations.includes(BlameHighlightLocations.Gutter) - ? Uri.parse( - `data:image/svg+xml,${encodeURIComponent( - ``, - )}`, - ) - : undefined; - - Decorations.gutterBlameHighlight = window.createTextEditorDecorationType({ - gutterIconPath: gutterHighlightUri, - gutterIconSize: 'contain', - isWholeLine: true, - overviewRulerLane: OverviewRulerLane.Right, - backgroundColor: locations.includes(BlameHighlightLocations.Line) - ? new ThemeColor(Colors.LineHighlightBackgroundColor) - : undefined, - overviewRulerColor: locations.includes(BlameHighlightLocations.Overview) - ? new ThemeColor(Colors.LineHighlightOverviewRulerColor) - : undefined, - }); - } - } - - if (configuration.changed(e, 'changes.locations')) { - Decorations.changesLineAddedAnnotation?.dispose(); - Decorations.changesLineChangedAnnotation?.dispose(); - Decorations.changesLineDeletedAnnotation?.dispose(); - - const { locations } = cfg.changes; - - Decorations.changesLineAddedAnnotation = window.createTextEditorDecorationType({ - gutterIconPath: locations.includes(ChangesLocations.Gutter) - ? Uri.parse( - `data:image/svg+xml,${encodeURIComponent( - "", - )}`, - ) - : undefined, - gutterIconSize: 'contain', - overviewRulerLane: OverviewRulerLane.Left, - overviewRulerColor: locations.includes(ChangesLocations.Overview) - ? new ThemeColor('editorOverviewRuler.addedForeground') - : undefined, - }); - - Decorations.changesLineChangedAnnotation = window.createTextEditorDecorationType({ - gutterIconPath: locations.includes(ChangesLocations.Gutter) - ? Uri.parse( - `data:image/svg+xml,${encodeURIComponent( - "", - )}`, - ) - : undefined, - gutterIconSize: 'contain', - overviewRulerLane: OverviewRulerLane.Left, - overviewRulerColor: locations.includes(ChangesLocations.Overview) - ? new ThemeColor('editorOverviewRuler.modifiedForeground') - : undefined, - }); + const initializing = e == null; - Decorations.changesLineDeletedAnnotation = window.createTextEditorDecorationType({ - gutterIconPath: locations.includes(ChangesLocations.Gutter) - ? Uri.parse( - `data:image/svg+xml,${encodeURIComponent( - "", - )}`, - ) - : undefined, - gutterIconSize: 'contain', - overviewRulerLane: OverviewRulerLane.Left, - overviewRulerColor: locations.includes(ChangesLocations.Overview) - ? new ThemeColor('editorOverviewRuler.deletedForeground') - : undefined, - }); + if (configuration.changed(e, 'blame.highlight') || configuration.changed(e, 'changes.locations')) { + this.updateDecorations(false); } - const initializing = e == null; - if (configuration.changed(e, 'blame.toggleMode')) { this._toggleModes.set(FileAnnotationType.Blame, cfg.blame.toggleMode); if (!initializing && cfg.blame.toggleMode === AnnotationsToggleMode.File) { @@ -242,6 +162,10 @@ export class FileAnnotationController implements Disposable { } } + private onThemeChanged(_e: ColorTheme) { + this.updateDecorations(true); + } + private async onActiveTextEditorChanged(editor: TextEditor | undefined) { if (editor != null && !isTextEditor(editor)) return; @@ -312,14 +236,11 @@ export class FileAnnotationController implements Disposable { } private onVisibleTextEditorsChanged(editors: readonly TextEditor[]) { - let provider: AnnotationProviderBase | undefined; for (const e of editors) { - provider = this.getProvider(e); - if (provider == null) continue; - - void provider.restore(e); + void this.getProvider(e)?.restore(e); } } + isInWindowToggle(): boolean { return this.getToggleMode(this._windowAnnotationType) === AnnotationsToggleMode.Window; } @@ -589,4 +510,141 @@ export class FileAnnotationController implements Disposable { return undefined; } + + private updateDecorations(refresh: boolean) { + const previous = refresh ? Object.entries(Decorations) : (undefined! as []); + + this.updateHighlightDecoration(); + this.updateChangedDecorations(); + + if (!refresh) return; + + const replaceDecorationTypes = new Map(); + for (const [key, value] of previous) { + if (value == null) continue; + + const newValue = (Decorations as Record)[key] ?? null; + if (value === newValue) continue; + + replaceDecorationTypes.set( + value, + (Decorations as Record)[key] ?? null, + ); + } + + if (replaceDecorationTypes.size === 0) return; + + for (const e of window.visibleTextEditors) { + void this.getProvider(e)?.refresh(replaceDecorationTypes); + } + } + + private updateChangedDecorations() { + Decorations.changesLineAddedAnnotation?.dispose(); + Decorations.changesLineChangedAnnotation?.dispose(); + Decorations.changesLineDeletedAnnotation?.dispose(); + + const { locations } = this.container.config.changes; + + let addedColor; + let changedColor; + let deletedColor; + + switch (window.activeColorTheme.kind) { + case ColorThemeKind.Light: + addedColor = '#48985D'; + changedColor = '#2090D3'; + deletedColor = '#E51400'; + break; + case ColorThemeKind.HighContrast: + addedColor = '#487E02'; + changedColor = '#1B81A8'; + deletedColor = '#F14C4C'; + break; + default: + addedColor = '#487E02'; + changedColor = '#1B81A8'; + deletedColor = '#F14C4C'; + break; + } + + Decorations.changesLineAddedAnnotation = window.createTextEditorDecorationType({ + gutterIconPath: locations.includes(ChangesLocations.Gutter) + ? Uri.parse( + `data:image/svg+xml,${encodeURIComponent( + ``, + )}`, + ) + : undefined, + gutterIconSize: 'contain', + overviewRulerLane: OverviewRulerLane.Left, + overviewRulerColor: locations.includes(ChangesLocations.Overview) + ? new ThemeColor('editorOverviewRuler.addedForeground') + : undefined, + }); + + Decorations.changesLineChangedAnnotation = window.createTextEditorDecorationType({ + gutterIconPath: locations.includes(ChangesLocations.Gutter) + ? Uri.parse( + `data:image/svg+xml,${encodeURIComponent( + ``, + )}`, + ) + : undefined, + gutterIconSize: 'contain', + overviewRulerLane: OverviewRulerLane.Left, + overviewRulerColor: locations.includes(ChangesLocations.Overview) + ? new ThemeColor('editorOverviewRuler.modifiedForeground') + : undefined, + }); + + Decorations.changesLineDeletedAnnotation = window.createTextEditorDecorationType({ + gutterIconPath: locations.includes(ChangesLocations.Gutter) + ? Uri.parse( + `data:image/svg+xml,${encodeURIComponent( + ``, + )}`, + ) + : undefined, + gutterIconSize: 'contain', + overviewRulerLane: OverviewRulerLane.Left, + overviewRulerColor: locations.includes(ChangesLocations.Overview) + ? new ThemeColor('editorOverviewRuler.deletedForeground') + : undefined, + }); + } + + private updateHighlightDecoration() { + Decorations.gutterBlameHighlight?.dispose(); + Decorations.gutterBlameHighlight = undefined; + + const { highlight } = this.container.config.blame; + + if (highlight.enabled) { + const { locations } = highlight; + + // TODO@eamodio: Read from the theme color when the API exists + const gutterHighlightColor = '#00bcf2'; // new ThemeColor(Colors.LineHighlightOverviewRulerColor) + const gutterHighlightUri = locations.includes(BlameHighlightLocations.Gutter) + ? Uri.parse( + `data:image/svg+xml,${encodeURIComponent( + ``, + )}`, + ) + : undefined; + + Decorations.gutterBlameHighlight = window.createTextEditorDecorationType({ + gutterIconPath: gutterHighlightUri, + gutterIconSize: 'contain', + isWholeLine: true, + overviewRulerLane: OverviewRulerLane.Right, + backgroundColor: locations.includes(BlameHighlightLocations.Line) + ? new ThemeColor(Colors.LineHighlightBackgroundColor) + : undefined, + overviewRulerColor: locations.includes(BlameHighlightLocations.Overview) + ? new ThemeColor(Colors.LineHighlightOverviewRulerColor) + : undefined, + }); + } + } }