diff --git a/CHANGELOG.md b/CHANGELOG.md
index c78bd4f..d683329 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
+## [Unreleased]
+
+### Added
+
+- Adds the ability to turn on file annotations (blame, heatmap, and recent changes) via user-defined modes — closes [#542](https://github.com/eamodio/vscode-gitlens/issues/542)
+
## [9.2.4] - 2018-12-26
### Added
diff --git a/README.md b/README.md
index 20661d1..6b82722 100644
--- a/README.md
+++ b/README.md
@@ -831,12 +831,12 @@ See also [View Settings](#view-settings- 'Jump to the View settings')
### Modes Settings [#](#modes-settings- 'Modes Settings')
-| Name | Description |
-| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
-| `gitlens.mode.active` | Specifies the active GitLens mode, if any |
-| `gitlens.mode.statusBar.enabled` | Specifies whether to provide the active GitLens mode in the status bar |
-| `gitlens.mode.statusBar.alignment` | Specifies the active GitLens mode alignment in the status bar
`left` - aligns to the left
`right` - aligns to the right |
-| `gitlens.modes` | Specifies the user-defined GitLens modes |
+| Name | Description |
+| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `gitlens.mode.active` | Specifies the active GitLens mode, if any |
+| `gitlens.mode.statusBar.enabled` | Specifies whether to provide the active GitLens mode in the status bar |
+| `gitlens.mode.statusBar.alignment` | Specifies the active GitLens mode alignment in the status bar
`left` - aligns to the left
`right` - aligns to the right |
+| `gitlens.modes` | Specifies the user-defined GitLens modes
Example — adds heatmap annotations to the built-in _Reviewing_ mode
`"gitlens.modes": { "review": { "annotations": "heatmap" } }`
Example — adds a new _Annotating_ mode with blame annotations
`"gitlens.modes": {`
`"annotate": {`
`"name": "Annotating",`
`"statusBarItemName": "Annotating",`
`"description": "for root cause analysis",`
`"annotations": "blame",`
`"codeLens": false,`
`"currentLine": false,`
`"hovers": true`
`}`
`}` |
### Advanced Settings [#](#advanced-settings- 'Advanced Settings')
diff --git a/package.json b/package.json
index 9e5ba6c..f9b665a 100644
--- a/package.json
+++ b/package.json
@@ -841,65 +841,75 @@
"properties": {
"zen": {
"type": "object",
- "required": [
- "name"
- ],
"properties": {
"name": {
- "type": "string"
+ "type": "string",
+ "description": "Specifies the friendly name of this user-defined mode"
},
"statusBarItemName": {
- "type": "string"
+ "type": "string",
+ "description": "Specifies the name shown in the status bar when this user-defined mode is active"
},
"description": {
- "type": "string"
+ "type": "string",
+ "description": "Specifies the description of this user-defined mode"
},
"codeLens": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show any Git code lens when this user-defined mode is active"
},
"currentLine": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show a blame annotation for the current line when this user-defined mode is active"
},
"hovers": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show any hovers when this user-defined mode is active"
},
"statusBar": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show blame information in the status bar when this user-defined mode is active"
},
"views": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show any GitLens views when this user-defined mode is active"
}
}
},
"review": {
"type": "object",
- "required": [
- "name"
- ],
"properties": {
"name": {
- "type": "string"
+ "type": "string",
+ "description": "Specifies the friendly name of this user-defined mode"
},
"statusBarItemName": {
- "type": "string"
+ "type": "string",
+ "description": "Specifies the name shown in the status bar when this user-defined mode is active"
},
"description": {
- "type": "string"
+ "type": "string",
+ "description": "Specifies the description of this user-defined mode"
},
"codeLens": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show any Git code lens when this user-defined mode is active"
},
"currentLine": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show a blame annotation for the current line when this user-defined mode is active"
},
"hovers": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show any hovers when this user-defined mode is active"
},
"statusBar": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show blame information in the status bar when this user-defined mode is active"
},
"views": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show any GitLens views when this user-defined mode is active"
}
}
}
@@ -911,28 +921,50 @@
],
"properties": {
"name": {
- "type": "string"
+ "type": "string",
+ "description": "Specifies the friendly name of this user-defined mode"
},
"statusBarItemName": {
- "type": "string"
+ "type": "string",
+ "description": "Specifies the name shown in the status bar when this user-defined mode is active"
},
"description": {
- "type": "string"
+ "type": "string",
+ "description": "Specifies the description of this user-defined mode"
+ },
+ "annotations": {
+ "type": "string",
+ "enum": [
+ "blame",
+ "heatmap",
+ "recentChanges"
+ ],
+ "enumDescriptions": [
+ "Shows the gutter blame annotations",
+ "Shows the gutter heatmap annotations",
+ "Shows the recently changed lines annotations"
+ ],
+ "description": "Specifies which (if any) file annotations will be shown when this user-defined mode is active"
},
"codeLens": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show any Git code lens when this user-defined mode is active"
},
"currentLine": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show a blame annotation for the current line when this user-defined mode is active"
},
"hovers": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show any hovers when this user-defined mode is active"
},
"statusBar": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show blame information in the status bar when this user-defined mode is active"
},
"views": {
- "type": "boolean"
+ "type": "boolean",
+ "description": "Specifies whether to show any GitLens views when this user-defined mode is active"
}
}
},
@@ -967,6 +999,12 @@
"verbose",
"debug"
],
+ "enumDescriptions": [
+ "Logs nothing",
+ "Logs only errors",
+ "Logs all errors, warnings, and messages",
+ "Logs all errors, warnings, and messages with extra context useful for debugging"
+ ],
"markdownDescription": "Specifies how much (if any) output will be sent to the GitLens output channel",
"scope": "window"
},
diff --git a/src/annotations/annotations.ts b/src/annotations/annotations.ts
index 12a8e89..8223605 100644
--- a/src/annotations/annotations.ts
+++ b/src/annotations/annotations.ts
@@ -344,10 +344,7 @@ export class Annotations {
static heatmapRenderOptions(): IRenderOptions {
return {
borderStyle: 'solid',
- borderWidth: '0 0 0 2px',
- contentText: GlyphChars.ZeroWidthSpace,
- height: '100%',
- margin: '0 26px -1px 0'
+ borderWidth: '0 0 0 2px'
} as IRenderOptions;
}
diff --git a/src/annotations/fileAnnotationController.ts b/src/annotations/fileAnnotationController.ts
index 1f0d906..01d92e3 100644
--- a/src/annotations/fileAnnotationController.ts
+++ b/src/annotations/fileAnnotationController.ts
@@ -19,7 +19,7 @@ import {
workspace
} from 'vscode';
import { AnnotationsToggleMode, configuration, FileAnnotationType, HighlightLocations } from '../configuration';
-import { CommandContext, isTextEditor, setCommandContext } from '../constants';
+import { CommandContext, GlyphChars, isTextEditor, setCommandContext } from '../constants';
import { Container } from '../container';
import { KeyboardScope, KeyCommand, Keys } from '../keyboard';
import { Logger } from '../logger';
@@ -49,7 +49,13 @@ export const Decorations = {
textDecoration: 'none'
} as DecorationRenderOptions),
blameHighlight: undefined as TextEditorDecorationType | undefined,
- heatmapAnnotation: window.createTextEditorDecorationType({} as DecorationRenderOptions),
+ heatmapAnnotation: window.createTextEditorDecorationType({
+ before: {
+ contentText: GlyphChars.ZeroWidthSpace,
+ height: '100%',
+ margin: '0 26px -1px 0'
+ }
+ } as DecorationRenderOptions),
heatmapHighlight: undefined as TextEditorDecorationType | undefined,
recentChangesAnnotation: undefined as TextEditorDecorationType | undefined,
recentChangesHighlight: undefined as TextEditorDecorationType | undefined
@@ -389,7 +395,8 @@ export class FileAnnotationController implements Disposable {
async toggle(
editor: TextEditor | undefined,
type: FileAnnotationType,
- shaOrLine?: string | number
+ shaOrLine?: string | number,
+ on?: boolean
): Promise {
if (editor !== undefined) {
const trackedDocument = await Container.tracker.getOrAdd(editor.document);
@@ -405,6 +412,7 @@ export class FileAnnotationController implements Disposable {
if (provider === undefined) return this.show(editor!, type, shaOrLine);
const reopen = provider.annotationType !== type;
+ if (on === true && !reopen) return true;
if (this.isInWindowToggle()) {
await this.clearAll();
diff --git a/src/commands/annotations.ts b/src/commands/annotations.ts
index d653d19..70dd15b 100644
--- a/src/commands/annotations.ts
+++ b/src/commands/annotations.ts
@@ -36,6 +36,7 @@ export class ClearFileAnnotationsCommand extends EditorCommand {
}
export interface ToggleFileBlameCommandArgs {
+ on?: boolean;
sha?: string;
type?: FileAnnotationType;
}
@@ -65,7 +66,8 @@ export class ToggleFileBlameCommand extends ActiveEditorCommand {
return Container.fileAnnotations.toggle(
editor,
args.type!,
- args.sha !== undefined ? args.sha : editor && editor.selection.active.line
+ args.sha !== undefined ? args.sha : editor && editor.selection.active.line,
+ args.on
);
}
catch (ex) {
@@ -83,8 +85,9 @@ export class ToggleFileHeatmapCommand extends ActiveEditorCommand {
super(Commands.ToggleFileHeatmap);
}
- async execute(editor: TextEditor, uri?: Uri): Promise {
+ async execute(editor: TextEditor, uri?: Uri, args: ToggleFileBlameCommandArgs = {}): Promise {
commands.executeCommand(Commands.ToggleFileBlame, uri, {
+ ...args,
type: FileAnnotationType.Heatmap
} as ToggleFileBlameCommandArgs);
}
@@ -96,8 +99,9 @@ export class ToggleFileRecentChangesCommand extends ActiveEditorCommand {
super(Commands.ToggleFileRecentChanges);
}
- async execute(editor: TextEditor, uri?: Uri): Promise {
+ async execute(editor: TextEditor, uri?: Uri, args: ToggleFileBlameCommandArgs = {}): Promise {
commands.executeCommand(Commands.ToggleFileBlame, uri, {
+ ...args,
type: FileAnnotationType.RecentChanges
} as ToggleFileBlameCommandArgs);
}
diff --git a/src/commands/switchMode.ts b/src/commands/switchMode.ts
index e8f346f..b6e03be 100644
--- a/src/commands/switchMode.ts
+++ b/src/commands/switchMode.ts
@@ -15,6 +15,20 @@ export class SwitchModeCommand extends Command {
const pick = await ModesQuickPick.show();
if (pick === undefined) return;
+ const active = Container.config.mode.active;
+ if (active === pick.key) return;
+
+ // Check if we have applied any annotations and clear them if we won't be applying them again
+ if (active != null && active.length !== 0) {
+ const activeAnnotations = Container.config.modes[active].annotations;
+ if (activeAnnotations != null) {
+ const newAnnotations = pick.key != null ? Container.config.modes[pick.key].annotations : undefined;
+ if (activeAnnotations !== newAnnotations) {
+ await Container.fileAnnotations.clearAll();
+ }
+ }
+ }
+
await configuration.update(configuration.name('mode')('active').value, pick.key, ConfigurationTarget.Global);
}
}
diff --git a/src/configuration.ts b/src/configuration.ts
index 2ac3223..edc1344 100644
--- a/src/configuration.ts
+++ b/src/configuration.ts
@@ -40,9 +40,12 @@ export class Configuration {
this._configAffectedByMode = [
`gitlens.${this.name('mode').value}`,
`gitlens.${this.name('modes').value}`,
+ `gitlens.${this.name('blame')('toggleMode').value}`,
`gitlens.${this.name('codeLens').value}`,
`gitlens.${this.name('currentLine').value}`,
+ `gitlens.${this.name('heatmap')('toggleMode').value}`,
`gitlens.${this.name('hovers').value}`,
+ `gitlens.${this.name('recentChanges')('toggleMode').value}`,
`gitlens.${this.name('statusBar').value}`,
`gitlens.${this.name('views')('compare').value}`,
`gitlens.${this.name('views')('fileHistory').value}`,
diff --git a/src/container.ts b/src/container.ts
index 9c3017a..c2d561b 100644
--- a/src/container.ts
+++ b/src/container.ts
@@ -1,9 +1,10 @@
'use strict';
-import { Disposable, ExtensionContext } from 'vscode';
+import { commands, Disposable, ExtensionContext } from 'vscode';
import { FileAnnotationController } from './annotations/fileAnnotationController';
import { LineAnnotationController } from './annotations/lineAnnotationController';
import { GitCodeLensController } from './codelens/codeLensController';
-import { Config, configuration } from './configuration';
+import { Commands, ToggleFileBlameCommandArgs } from './commands';
+import { AnnotationsToggleMode, Config, configuration } from './configuration';
import { GitFileSystemProvider } from './git/fsProvider';
import { GitService } from './git/gitService';
import { LineHoverController } from './hovers/lineHoverController';
@@ -244,6 +245,35 @@ export class Container {
const mode = config.modes[config.mode.active];
if (mode == null) return config;
+ if (mode.annotations != null) {
+ let command: string | undefined;
+ switch (mode.annotations) {
+ case 'blame':
+ config.blame.toggleMode = AnnotationsToggleMode.Window;
+ command = Commands.ToggleFileBlame;
+ break;
+ case 'heatmap':
+ config.heatmap.toggleMode = AnnotationsToggleMode.Window;
+ command = Commands.ToggleFileHeatmap;
+ break;
+ case 'recentChanges':
+ config.recentChanges.toggleMode = AnnotationsToggleMode.Window;
+ command = Commands.ToggleFileRecentChanges;
+ break;
+ }
+
+ if (command !== undefined) {
+ // Make sure to delay the execution by a bit so that the configuration changes get propegated first
+ setTimeout(
+ () =>
+ commands.executeCommand(command!, {
+ on: true
+ } as ToggleFileBlameCommandArgs),
+ 50
+ );
+ }
+ }
+
if (mode.codeLens != null) {
config.codeLens.enabled = mode.codeLens;
}
diff --git a/src/ui/config.ts b/src/ui/config.ts
index d35dd1f..af521f8 100644
--- a/src/ui/config.ts
+++ b/src/ui/config.ts
@@ -312,6 +312,7 @@ export interface ModeConfig {
name: string;
statusBarItemName?: string;
description?: string;
+ annotations?: 'blame' | 'heatmap' | 'recentChanges';
codeLens?: boolean;
currentLine?: boolean;
hovers?: boolean;