From b10f7391ed19219d95555ff4b3d088342c7339ed Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 25 Feb 2018 15:59:57 -0500 Subject: [PATCH] Adds control over annotation toggling Supports toggling annotations for each file individually or all files at once Closes #289 --- CHANGELOG.md | 6 ++ README.md | 8 ++ package.json | 36 +++++++- src/annotations/annotationController.ts | 92 +++++++++++++++++++-- src/annotations/annotations.ts | 12 ++- src/annotations/blameAnnotationProvider.ts | 2 +- src/annotations/recentChangesAnnotationProvider.ts | 2 +- src/commands/toggleFileBlame.ts | 24 +++--- src/commands/toggleFileHeatmap.ts | 8 +- src/commands/toggleFileRecentChanges.ts | 8 +- src/currentLineController.ts | 2 +- src/ui/config.ts | 11 +++ src/ui/images/settings/heatmap.png | Bin 0 -> 10473 bytes src/ui/settings/index.html | 66 ++++++++++++++- 14 files changed, 235 insertions(+), 42 deletions(-) create mode 100644 src/ui/images/settings/heatmap.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 022b0a9..25e8ea2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] ### Added - Adds multi-cursor support to current line annotations — closes [#291](https://github.com/eamodio/vscode-gitlens/issues/291) +- Adds support to toggle annotations for each file individually or for all files at once — closes [#289](https://github.com/eamodio/vscode-gitlens/issues/289) + - Adds new controls the interactive settings editor (*Open Settings* from the Command Palette) to configure this new behavior + - Adds `gitlens.blame.toggleMode` setting to specify how the gutter blame annotations will be toggled, per file or window + - Adds `gitlens.heatmap.toggleMode` setting to specify how the gutter heatmap annotations will be toggled, per file or window + - Adds `gitlens.recentChanges.toggleMode` setting to specify how the recently changed lines annotations will be toggled, per file or window + ### Changed - Renames *Compare Selected Ancestor with Working Tree* command to *Compare Ancestry with Working Tree* and removes the need to select a branch first, since all compares are done to the working tree — closes [#279](https://github.com/eamodio/vscode-gitlens/issues/279) diff --git a/README.md b/README.md index 9ab5d99..cb73bbf 100644 --- a/README.md +++ b/README.md @@ -583,6 +583,13 @@ See also [Explorer Settings](#explorer-settings "Jump to the Explorer settings") |`gitlens.blame.highlight.locations`|Specifies where the associated line highlights will be shown
`gutter` - adds a gutter glyph
`line` - adds a full-line highlight background color
`overview` - adds a decoration to the overview ruler (scroll bar) |`gitlens.blame.ignoreWhitespace`|Specifies whether to ignore whitespace when comparing revisions during blame operations |`gitlens.blame.separateLines`|Specifies whether gutter blame annotations will have line separators +|`gitlens.blame.toggleMode`|Specifies how the gutter blame annotations will be toggled
`file` - toggle each file individually
`window` - toggle the window, i.e. all files at once + +### Gutter Heatmap Settings + +|Name | Description +|-----|------------ +|`gitlens.heatmap.toggleMode`|Specifies how the gutter heatmap annotations will be toggled
`file` - toggle each file individually
`window` - toggle the window, i.e. all files at once ### Hover Settings @@ -603,6 +610,7 @@ See also [Explorer Settings](#explorer-settings "Jump to the Explorer settings") |Name | Description |-----|------------ |`gitlens.recentChanges.highlight.locations`|Specifies where the highlights of the recently changed lines will be shown
`gutter` - adds a gutter glyph
`line` - adds a full-line highlight background color
`overview` - adds a decoration to the overview ruler (scroll bar) +|`gitlens.recentChanges.toggleMode`|Specifies how the recently changed lines annotations will be toggled
`file` - toggle each file individually
`window` - toggle the window, i.e. all files at once ### Status Bar Settings diff --git a/package.json b/package.json index ec36841..ec0853a 100644 --- a/package.json +++ b/package.json @@ -129,6 +129,16 @@ "description": "Specifies whether gutter blame annotations will be separated by a small gap", "scope": "window" }, + "gitlens.blame.toggleMode": { + "type": "string", + "default": "file", + "enum": [ + "file", + "window" + ], + "description": "Specifies how the gutter blame annotations will be toggled\n `file` - toggle each file individually\n `window` - toggle the window, i.e. all files at once", + "scope": "window" + }, "gitlens.codeLens.authors.command": { "type": "string", "default": "gitlens.toggleFileBlame", @@ -459,6 +469,16 @@ "description": "Specifies the starting view (mode) of the `GitLens` explorer\n `auto` - shows the last selected view, defaults to `repository`\n `history` - shows the commit history of the active file\n `repository` - shows a repository explorer", "scope": "window" }, + "gitlens.heatmap.toggleMode": { + "type": "string", + "default": "file", + "enum": [ + "file", + "window" + ], + "description": "Specifies how the gutter heatmap annotations will be toggled\n `file` - toggle each file individually\n `window` - toggle the window, i.e. all files at once", + "scope": "window" + }, "gitlens.hovers.annotations.changes": { "type": "boolean", "default": true, @@ -571,6 +591,16 @@ "description": "Specifies where the highlights of the recently changed lines will be shown\n `gutter` - adds a gutter glyph\n `line` - adds a full-line highlight background color\n `overview` - adds a decoration to the overview ruler (scroll bar)", "scope": "window" }, + "gitlens.recentChanges.toggleMode": { + "type": "string", + "default": "file", + "enum": [ + "file", + "window" + ], + "description": "Specifies how the recently changed lines annotations will be toggled\n `file` - toggle each file individually\n `window` - toggle the window, i.e. all files at once", + "scope": "window" + }, "gitlens.remotes": { "type": "array", "default": null, @@ -1733,7 +1763,7 @@ }, { "command": "gitlens.clearFileAnnotations", - "when": "gitlens:annotationStatus == computed" + "when": "gitlens:activeIsBlameable && gitlens:annotationStatus == computed" }, { "command": "gitlens.computingFileAnnotations", @@ -2134,12 +2164,12 @@ }, { "command": "gitlens.computingFileAnnotations", - "when": "gitlens:annotationStatus == computing && config.gitlens.advanced.menus.editorTitle.blame", + "when": "gitlens:activeIsBlameable && gitlens:annotationStatus == computing && config.gitlens.advanced.menus.editorTitle.blame", "group": "navigation@100" }, { "command": "gitlens.clearFileAnnotations", - "when": "gitlens:annotationStatus == computed && config.gitlens.advanced.menus.editorTitle.blame", + "when": "gitlens:activeIsBlameable && gitlens:annotationStatus == computed && config.gitlens.advanced.menus.editorTitle.blame", "group": "navigation@100" }, { diff --git a/src/annotations/annotationController.ts b/src/annotations/annotationController.ts index 2ba7655..5c17c8d 100644 --- a/src/annotations/annotationController.ts +++ b/src/annotations/annotationController.ts @@ -2,7 +2,7 @@ import { Functions, Iterables } from '../system'; import { ConfigurationChangeEvent, DecorationRangeBehavior, DecorationRenderOptions, Disposable, Event, EventEmitter, OverviewRulerLane, Progress, ProgressLocation, TextDocument, TextEditor, TextEditorDecorationType, TextEditorViewColumnChangeEvent, ThemeColor, window, workspace } from 'vscode'; import { AnnotationProviderBase, AnnotationStatus, TextEditorCorrelationKey } from './annotationProvider'; -import { configuration, FileAnnotationType, HighlightLocations } from '../configuration'; +import { AnnotationsToggleMode, configuration, FileAnnotationType, HighlightLocations } from '../configuration'; import { CommandContext, isTextEditor, setCommandContext } from '../constants'; import { Container } from '../container'; import { DocumentBlameStateChangeEvent, DocumentDirtyStateChangeEvent, GitDocumentState } from '../trackers/documentTracker'; @@ -46,6 +46,8 @@ export class AnnotationController extends Disposable { private _disposable: Disposable; private _editor: TextEditor | undefined; private _keyboardScope: KeyboardScope | undefined = undefined; + private readonly _toggleModes: Map; + private _annotationType: FileAnnotationType | undefined = undefined; constructor() { super(() => this.dispose()); @@ -53,11 +55,13 @@ export class AnnotationController extends Disposable { this._disposable = Disposable.from( configuration.onDidChange(this.onConfigurationChanged, this) ); + + this._toggleModes = new Map(); this.onConfigurationChanged(configuration.initializingChangeEvent); } dispose() { - this._annotationProviders.forEach(async (p, key) => await this.clearCore(key, AnnotationClearReason.Disposing)); + this.clearAll(); Decorations.blameAnnotation && Decorations.blameAnnotation.dispose(); Decorations.blameHighlight && Decorations.blameHighlight.dispose(); @@ -132,6 +136,27 @@ export class AnnotationController extends Disposable { }); } + if (initializing || configuration.changed(e, configuration.name('blame')('toggleMode').value)) { + this._toggleModes.set(FileAnnotationType.Blame, cfg.blame.toggleMode); + if (!initializing && cfg.blame.toggleMode === AnnotationsToggleMode.File) { + this.clearAll(); + } + } + + if (initializing || configuration.changed(e, configuration.name('heatmap')('toggleMode').value)) { + this._toggleModes.set(FileAnnotationType.Heatmap, cfg.heatmap.toggleMode); + if (!initializing && cfg.heatmap.toggleMode === AnnotationsToggleMode.File) { + this.clearAll(); + } + } + + if (initializing || configuration.changed(e, configuration.name('recentChanges')('toggleMode').value)) { + this._toggleModes.set(FileAnnotationType.RecentChanges, cfg.recentChanges.toggleMode); + if (!initializing && cfg.recentChanges.toggleMode === AnnotationsToggleMode.File) { + this.clearAll(); + } + } + if (initializing) return; if (configuration.changed(e, configuration.name('blame').value) || @@ -154,12 +179,18 @@ export class AnnotationController extends Disposable { } } - private onActiveTextEditorChanged(editor: TextEditor | undefined) { + private async onActiveTextEditorChanged(editor: TextEditor | undefined) { if (editor !== undefined && !isTextEditor(editor)) return; this._editor = editor; // Logger.log('AnnotationController.onActiveTextEditorChanged', editor && editor.document.uri.fsPath); + if (this.isInWindowToggle()) { + await this.showAnnotations(editor, this._annotationType!); + + return; + } + const provider = this.getProvider(editor); if (provider === undefined) { setCommandContext(CommandContext.AnnotationStatus, undefined); @@ -215,7 +246,7 @@ export class AnnotationController extends Disposable { provider.restore(e.textEditor); } - private async onVisibleTextEditorsChanged(editors: TextEditor[]) { + private onVisibleTextEditorsChanged(editors: TextEditor[]) { let provider: AnnotationProviderBase | undefined; for (const e of editors) { provider = this.getProvider(e); @@ -225,8 +256,29 @@ export class AnnotationController extends Disposable { } } - async clear(editor: TextEditor, reason: AnnotationClearReason = AnnotationClearReason.User) { - this.clearCore(AnnotationProviderBase.getCorrelationKey(editor), reason); + isInWindowToggle(): boolean { + return this.getToggleMode(this._annotationType) === AnnotationsToggleMode.Window; + } + + private getToggleMode(annotationType: FileAnnotationType | undefined): AnnotationsToggleMode { + if (annotationType === undefined) return AnnotationsToggleMode.File; + + return this._toggleModes.get(annotationType) || AnnotationsToggleMode.File; + } + + clear(editor: TextEditor, reason: AnnotationClearReason = AnnotationClearReason.User) { + if (this.isInWindowToggle()) { + return this.clearAll(); + } + + return this.clearCore(AnnotationProviderBase.getCorrelationKey(editor), reason); + } + + async clearAll() { + this._annotationType = undefined; + for (const [key] of this._annotationProviders) { + await this.clearCore(key, AnnotationClearReason.Disposing); + } } async getAnnotationType(editor: TextEditor | undefined): Promise { @@ -245,6 +297,26 @@ export class AnnotationController extends Disposable { } async showAnnotations(editor: TextEditor | undefined, type: FileAnnotationType, shaOrLine?: string | number): Promise { + if (this.getToggleMode(type) === AnnotationsToggleMode.Window) { + let first = this._annotationType === undefined; + const reset = !first && this._annotationType !== type; + + this._annotationType = type; + + if (reset) { + await this.clearAll(); + first = true; + } + + if (first) { + for (const e of window.visibleTextEditors) { + if (e === editor) continue; + + this.showAnnotations(e, type); + } + } + } + if (editor === undefined) return false; // || editor.viewColumn === undefined) return false; this._editor = editor; @@ -283,7 +355,13 @@ export class AnnotationController extends Disposable { if (provider === undefined) return this.showAnnotations(editor!, type, shaOrLine); const reopen = provider.annotationType !== type; - await this.clearCore(provider.correlationKey, AnnotationClearReason.User); + + if (this.isInWindowToggle()) { + await this.clearAll(); + } + else { + await this.clearCore(provider.correlationKey, AnnotationClearReason.User); + } if (!reopen) return false; diff --git a/src/annotations/annotations.ts b/src/annotations/annotations.ts index cda71d4..f8e0ca6 100644 --- a/src/annotations/annotations.ts +++ b/src/annotations/annotations.ts @@ -1,5 +1,5 @@ import { Dates, Objects, Strings } from '../system'; -import { DecorationInstanceRenderOptions, DecorationOptions, MarkdownString, ThemableDecorationRenderOptions, ThemeColor, window } from 'vscode'; +import { DecorationInstanceRenderOptions, DecorationOptions, MarkdownString, ThemableDecorationRenderOptions, ThemeColor } from 'vscode'; import { DiffWithCommand, OpenCommitInRemoteCommand, OpenFileRevisionCommand, ShowQuickCommitDetailsCommand, ShowQuickCommitFileDetailsCommand } from '../commands'; import { FileAnnotationType } from './../configuration'; import { GlyphChars } from '../constants'; @@ -41,7 +41,7 @@ export class Annotations { return '#793738'; } - private static getHoverCommandBar(commit: GitCommit, hasRemote: boolean, annotationType?: FileAnnotationType) { + private static getHoverCommandBar(commit: GitCommit, hasRemote: boolean, annotationType?: FileAnnotationType, line: number = 0) { let commandBar = `[\`${GlyphChars.DoubleArrowLeft}\`](${DiffWithCommand.getMarkdownCommandArgs(commit)} "Open Changes") `; if (commit.previousSha !== undefined) { @@ -50,8 +50,6 @@ export class Annotations { } const uri = GitUri.toRevisionUri(commit.previousSha, commit.previousUri.fsPath, commit.repoPath); - const line = window.activeTextEditor!.selection.active.line; - commandBar += `[\`${GlyphChars.SquareWithTopShadow}\`](${OpenFileRevisionCommand.getMarkdownCommandArgs(uri, annotationType || FileAnnotationType.Blame, line)} "Blame Previous Revision") `; } @@ -64,7 +62,7 @@ export class Annotations { return commandBar; } - static getHoverMessage(commit: GitCommit, dateFormat: string | null, hasRemote: boolean, annotationType?: FileAnnotationType): MarkdownString { + static getHoverMessage(commit: GitCommit, dateFormat: string | null, hasRemote: boolean, annotationType?: FileAnnotationType, line: number = 0): MarkdownString { if (dateFormat === null) { dateFormat = 'MMMM Do, YYYY h:mma'; } @@ -73,7 +71,7 @@ export class Annotations { let commandBar = ''; let showCommitDetailsCommand = ''; if (!commit.isUncommitted) { - commandBar = `\n\n${this.getHoverCommandBar(commit, hasRemote, annotationType)}`; + commandBar = `\n\n${this.getHoverCommandBar(commit, hasRemote, annotationType, line)}`; showCommitDetailsCommand = `[\`${commit.shortSha}\`](${ShowQuickCommitDetailsCommand.getMarkdownCommandArgs(commit.sha)} "Show Commit Details")`; message = commit.message @@ -137,7 +135,7 @@ export class Annotations { } as DecorationOptions; } - static detailsHover(commit: GitCommit, dateFormat: string | null, hasRemote: boolean, annotationType?: FileAnnotationType): DecorationOptions { + static detailsHover(commit: GitCommit, dateFormat: string | null, hasRemote: boolean, annotationType?: FileAnnotationType, line: number = 0): DecorationOptions { const message = this.getHoverMessage(commit, dateFormat, hasRemote, annotationType); return { hoverMessage: message diff --git a/src/annotations/blameAnnotationProvider.ts b/src/annotations/blameAnnotationProvider.ts index 79b4bf4..06d828b 100644 --- a/src/annotations/blameAnnotationProvider.ts +++ b/src/annotations/blameAnnotationProvider.ts @@ -121,7 +121,7 @@ export abstract class BlameAnnotationProviderBase extends AnnotationProviderBase } } - const message = Annotations.getHoverMessage(logCommit || commit, Container.config.defaultDateFormat, await Container.git.hasRemote(commit.repoPath), this.annotationType); + const message = Annotations.getHoverMessage(logCommit || commit, Container.config.defaultDateFormat, await Container.git.hasRemote(commit.repoPath), this.annotationType, this.editor.selection.active.line); return new Hover(message, document.validateRange(new Range(position.line, 0, position.line, RangeEndOfLineIndex))); } diff --git a/src/annotations/recentChangesAnnotationProvider.ts b/src/annotations/recentChangesAnnotationProvider.ts index 611d572..22aa342 100644 --- a/src/annotations/recentChangesAnnotationProvider.ts +++ b/src/annotations/recentChangesAnnotationProvider.ts @@ -56,7 +56,7 @@ export class RecentChangesAnnotationProvider extends AnnotationProviderBase { if (cfg.hovers.enabled && cfg.hovers.annotations.enabled) { if (cfg.hovers.annotations.details) { this.decorations.push({ - hoverMessage: Annotations.getHoverMessage(commit, dateFormat, await Container.git.hasRemote(commit.repoPath), this.annotationType), + hoverMessage: Annotations.getHoverMessage(commit, dateFormat, await Container.git.hasRemote(commit.repoPath), this.annotationType, this.editor.selection.active.line), range: range } as DecorationOptions); } diff --git a/src/commands/toggleFileBlame.ts b/src/commands/toggleFileBlame.ts index dff7485..e498d07 100644 --- a/src/commands/toggleFileBlame.ts +++ b/src/commands/toggleFileBlame.ts @@ -1,6 +1,6 @@ 'use strict'; -import { TextEditor, TextEditorEdit, Uri, window } from 'vscode'; -import { Commands, EditorCommand } from './common'; +import { TextEditor, Uri, window } from 'vscode'; +import { ActiveEditorCommand, Commands } from './common'; import { UriComparer } from '../comparers'; import { FileAnnotationType } from '../configuration'; import { Container } from '../container'; @@ -11,20 +11,22 @@ export interface ToggleFileBlameCommandArgs { type?: FileAnnotationType; } -export class ToggleFileBlameCommand extends EditorCommand { +export class ToggleFileBlameCommand extends ActiveEditorCommand { constructor() { super(Commands.ToggleFileBlame); } - async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri, args: ToggleFileBlameCommandArgs = {}): Promise { - if (editor === undefined) return undefined; + async execute(editor: TextEditor, uri?: Uri, args: ToggleFileBlameCommandArgs = {}): Promise { + // if (editor === undefined) return undefined; - // Handle the case where we are focused on a non-editor editor (output, debug console) - if (uri !== undefined && !UriComparer.equals(uri, editor.document.uri)) { - const e = window.visibleTextEditors.find(e => UriComparer.equals(uri, e.document.uri)); - if (e !== undefined) { - editor = e; + if (editor !== undefined) { + // Handle the case where we are focused on a non-editor editor (output, debug console) + if (uri !== undefined && !UriComparer.equals(uri, editor.document.uri)) { + const e = window.visibleTextEditors.find(e => UriComparer.equals(uri, e.document.uri)); + if (e !== undefined) { + editor = e; + } } } @@ -33,7 +35,7 @@ export class ToggleFileBlameCommand extends EditorCommand { args = { ...args, type: FileAnnotationType.Blame }; } - return Container.annotations.toggleAnnotations(editor, args.type!, args.sha !== undefined ? args.sha : editor.selection.active.line); + return Container.annotations.toggleAnnotations(editor, args.type!, args.sha !== undefined ? args.sha : editor && editor.selection.active.line); } catch (ex) { Logger.error(ex, 'ToggleFileBlameCommand'); diff --git a/src/commands/toggleFileHeatmap.ts b/src/commands/toggleFileHeatmap.ts index 8082db5..6467889 100644 --- a/src/commands/toggleFileHeatmap.ts +++ b/src/commands/toggleFileHeatmap.ts @@ -1,16 +1,16 @@ 'use strict'; -import { commands, TextEditor, TextEditorEdit, Uri } from 'vscode'; +import { commands, TextEditor, Uri } from 'vscode'; import { ToggleFileBlameCommandArgs } from '../commands'; -import { Commands, EditorCommand } from './common'; +import { ActiveEditorCommand, Commands } from './common'; import { FileAnnotationType } from '../configuration'; -export class ToggleFileHeatmapCommand extends EditorCommand { +export class ToggleFileHeatmapCommand extends ActiveEditorCommand { constructor() { super(Commands.ToggleFileHeatmap); } - async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri): Promise { + async execute(editor: TextEditor, uri?: Uri): Promise { commands.executeCommand(Commands.ToggleFileBlame, uri, { type: FileAnnotationType.Heatmap } as ToggleFileBlameCommandArgs); } } \ No newline at end of file diff --git a/src/commands/toggleFileRecentChanges.ts b/src/commands/toggleFileRecentChanges.ts index 415d00a..cc96f89 100644 --- a/src/commands/toggleFileRecentChanges.ts +++ b/src/commands/toggleFileRecentChanges.ts @@ -1,16 +1,16 @@ 'use strict'; -import { commands, TextEditor, TextEditorEdit, Uri } from 'vscode'; +import { commands, TextEditor, Uri } from 'vscode'; import { ToggleFileBlameCommandArgs } from '../commands'; -import { Commands, EditorCommand } from './common'; +import { ActiveEditorCommand, Commands } from './common'; import { FileAnnotationType } from '../configuration'; -export class ToggleFileRecentChangesCommand extends EditorCommand { +export class ToggleFileRecentChangesCommand extends ActiveEditorCommand { constructor() { super(Commands.ToggleFileRecentChanges); } - async execute(editor: TextEditor, edit: TextEditorEdit, uri?: Uri): Promise { + async execute(editor: TextEditor, uri?: Uri): Promise { commands.executeCommand(Commands.ToggleFileBlame, uri, { type: FileAnnotationType.RecentChanges } as ToggleFileBlameCommandArgs); } } \ No newline at end of file diff --git a/src/currentLineController.ts b/src/currentLineController.ts index 2b796ab..46d566c 100644 --- a/src/currentLineController.ts +++ b/src/currentLineController.ts @@ -263,7 +263,7 @@ export class CurrentLineController extends Disposable { const trackedDocument = await Container.tracker.get(document); if (trackedDocument === undefined) return undefined; - const message = Annotations.getHoverMessage(logCommit || commit, Container.config.defaultDateFormat, trackedDocument.hasRemotes, fileAnnotations); + const message = Annotations.getHoverMessage(logCommit || commit, Container.config.defaultDateFormat, trackedDocument.hasRemotes, fileAnnotations, position.line); return new Hover(message, range); } diff --git a/src/ui/config.ts b/src/ui/config.ts index c1df7a9..d57f512 100644 --- a/src/ui/config.ts +++ b/src/ui/config.ts @@ -1,5 +1,10 @@ 'use strict'; +export enum AnnotationsToggleMode { + File = 'file', + Window = 'window' +} + export enum CodeLensCommand { DiffWithPrevious = 'gitlens.diffWithPrevious', ShowQuickCommitDetails = 'gitlens.showQuickCommitDetails', @@ -256,6 +261,7 @@ export interface IConfig { }; ignoreWhitespace: boolean; separateLines: boolean; + toggleMode: AnnotationsToggleMode; }; currentLine: { @@ -275,6 +281,10 @@ export interface IConfig { gitExplorer: IGitExplorerConfig; + heatmap: { + toggleMode: AnnotationsToggleMode; + }; + hovers: { annotations: { changes: boolean; @@ -301,6 +311,7 @@ export interface IConfig { highlight: { locations: HighlightLocations[]; }; + toggleMode: AnnotationsToggleMode; }; remotes: IRemotesConfig[]; diff --git a/src/ui/images/settings/heatmap.png b/src/ui/images/settings/heatmap.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1cdb17b45d873bdd30a8562716c53ac3654976 GIT binary patch literal 10473 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 b7+xkQX_`Z#m7xV#_8=7n4f$%>XF>k~{YLT0 literal 0 HcmV?d00001 diff --git a/src/ui/settings/index.html b/src/ui/settings/index.html index 8023402..6a27e6b 100644 --- a/src/ui/settings/index.html +++ b/src/ui/settings/index.html @@ -281,7 +281,7 @@ For more advanced customizations open User Settings and search for gitlens.currentLine Use the - GitLens: Toggle Line Blame Annotations command to override this setting for the current window + GitLens: Toggle Line Blame Annotations command to override this setting for the current window

@@ -298,6 +298,14 @@
+
+ + +
+
@@ -356,6 +364,47 @@ For more advanced customizations open User Settings and search for gitlens.blame + Use the + + + command to turn the annotations on or off + + + Press Esc to turn off the annotations + +

+
+ + +
+
+

Gutter Heatmap + + + +

+

Adds on-demand heatmap to the edge of the gutter to show the relative age of a line

+
+
+
+
+ + +
+
+
+ +
+

+ + Use the + + + command to turn the annotations on or off + Press Esc to turn off the annotations

@@ -476,6 +525,14 @@
+
+ + +
+
@@ -498,7 +555,9 @@

Use the - GitLens: Toggle Recent File Changes Annotations command to turn the annotations on or off + + + command to turn the annotations on or off Press Esc to turn off the annotations @@ -552,7 +611,7 @@ For more advanced customizations open User Settings and search for gitlens.statusBar Use the - GitLens: Toggle Line Blame Annotations command to override this setting for the current window + GitLens: Toggle Line Blame Annotations command to override this setting for the current window

@@ -602,6 +661,7 @@
  • Code Lens
  • Current Line Blame
  • Gutter Blame
  • +
  • Gutter Heatmap
  • Hovers
  • Recent Changes
  • Status Bar Blame