mirror of
https://github.com/ckaczor/vscode-gitlens.git
synced 2026-02-16 10:58:34 -05:00
Attempts to fix #80 - on line with link, annotation gets underlined
This commit is contained in:
@@ -12,7 +12,8 @@ import { WhitespaceController } from './whitespaceController';
|
|||||||
|
|
||||||
export const Decorations = {
|
export const Decorations = {
|
||||||
annotation: window.createTextEditorDecorationType({
|
annotation: window.createTextEditorDecorationType({
|
||||||
isWholeLine: true
|
isWholeLine: true,
|
||||||
|
textDecoration: 'none'
|
||||||
} as DecorationRenderOptions),
|
} as DecorationRenderOptions),
|
||||||
highlight: undefined as TextEditorDecorationType | undefined
|
highlight: undefined as TextEditorDecorationType | undefined
|
||||||
};
|
};
|
||||||
@@ -233,7 +234,7 @@ export class AnnotationController extends Disposable {
|
|||||||
for (const [key, p] of this._annotationProviders) {
|
for (const [key, p] of this._annotationProviders) {
|
||||||
if (!TextDocumentComparer.equals(p.document, e.document)) continue;
|
if (!TextDocumentComparer.equals(p.document, e.document)) continue;
|
||||||
|
|
||||||
// TODO: Rework this once https://github.com/Microsoft/vscode/issues/27231 is released in v1.13
|
// TODO: Rework this once https://github.com/Microsoft/vscode/issues/27231 is released in v1.13
|
||||||
// We have to defer because isDirty is not reliable inside this event
|
// We have to defer because isDirty is not reliable inside this event
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// If the document is dirty all is fine, just kick out since the GitContextTracker will handle it
|
// If the document is dirty all is fine, just kick out since the GitContextTracker will handle it
|
||||||
|
|||||||
@@ -77,8 +77,7 @@ export class Annotations {
|
|||||||
before: {
|
before: {
|
||||||
...renderOptions.before,
|
...renderOptions.before,
|
||||||
...{
|
...{
|
||||||
contentText: content,
|
contentText: content
|
||||||
margin: '0 26px 0 0'
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dark: {
|
dark: {
|
||||||
@@ -113,7 +112,9 @@ export class Annotations {
|
|||||||
before: {
|
before: {
|
||||||
borderStyle: borderStyle,
|
borderStyle: borderStyle,
|
||||||
borderWidth: borderWidth,
|
borderWidth: borderWidth,
|
||||||
height: cfgFileTheme.separateLines ? 'calc(100% - 1px)' : '100%'
|
height: cfgFileTheme.separateLines ? 'calc(100% - 1px)' : '100%',
|
||||||
|
margin: '0 26px 0 0',
|
||||||
|
textDecoration: 'none'
|
||||||
},
|
},
|
||||||
dark: {
|
dark: {
|
||||||
backgroundColor: cfgFileTheme.dark.backgroundColor || undefined,
|
backgroundColor: cfgFileTheme.dark.backgroundColor || undefined,
|
||||||
@@ -123,7 +124,7 @@ export class Annotations {
|
|||||||
backgroundColor: cfgFileTheme.light.backgroundColor || undefined,
|
backgroundColor: cfgFileTheme.light.backgroundColor || undefined,
|
||||||
color: cfgFileTheme.light.foregroundColor || themeDefaults.annotations.file.gutter.light.foregroundColor
|
color: cfgFileTheme.light.foregroundColor || themeDefaults.annotations.file.gutter.light.foregroundColor
|
||||||
} as DecorationInstanceRenderOptions
|
} as DecorationInstanceRenderOptions
|
||||||
};
|
} as IRenderOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
static hover(commit: GitCommit, renderOptions: IRenderOptions, heatmap: boolean): DecorationOptions {
|
static hover(commit: GitCommit, renderOptions: IRenderOptions, heatmap: boolean): DecorationOptions {
|
||||||
@@ -142,7 +143,8 @@ export class Annotations {
|
|||||||
borderWidth: '0 0 0 2px',
|
borderWidth: '0 0 0 2px',
|
||||||
contentText: '\u200B',
|
contentText: '\u200B',
|
||||||
height: cfgTheme.annotations.file.hover.separateLines ? 'calc(100% - 1px)' : '100%',
|
height: cfgTheme.annotations.file.hover.separateLines ? 'calc(100% - 1px)' : '100%',
|
||||||
margin: '0 26px 0 0'
|
margin: '0 26px 0 0',
|
||||||
|
textDecoration: 'none'
|
||||||
}
|
}
|
||||||
} as IRenderOptions;
|
} as IRenderOptions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,205 +1,206 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { Functions, Objects } from './system';
|
import { Functions, Objects } from './system';
|
||||||
import { DecorationOptions, DecorationRenderOptions, Disposable, ExtensionContext, Range, StatusBarAlignment, StatusBarItem, TextEditor, TextEditorDecorationType, TextEditorSelectionChangeEvent, window, workspace } from 'vscode';
|
import { DecorationOptions, DecorationRenderOptions, Disposable, ExtensionContext, Range, StatusBarAlignment, StatusBarItem, TextEditor, TextEditorDecorationType, TextEditorSelectionChangeEvent, window, workspace } from 'vscode';
|
||||||
import { AnnotationController } from './annotations/annotationController';
|
import { AnnotationController } from './annotations/annotationController';
|
||||||
import { Annotations, endOfLineIndex } from './annotations/annotations';
|
import { Annotations, endOfLineIndex } from './annotations/annotations';
|
||||||
import { Commands } from './commands';
|
import { Commands } from './commands';
|
||||||
import { TextEditorComparer } from './comparers';
|
import { TextEditorComparer } from './comparers';
|
||||||
import { FileAnnotationType, IConfig, LineAnnotationType, StatusBarCommand } from './configuration';
|
import { FileAnnotationType, IConfig, LineAnnotationType, StatusBarCommand } from './configuration';
|
||||||
import { DocumentSchemes, ExtensionKey } from './constants';
|
import { DocumentSchemes, ExtensionKey } from './constants';
|
||||||
import { BlameabilityChangeEvent, CommitFormatter, GitCommit, GitContextTracker, GitService, GitUri, IGitCommitLine } from './gitService';
|
import { BlameabilityChangeEvent, CommitFormatter, GitCommit, GitContextTracker, GitService, GitUri, IGitCommitLine } from './gitService';
|
||||||
|
|
||||||
const annotationDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({
|
const annotationDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({
|
||||||
after: {
|
after: {
|
||||||
margin: '0 0 0 4em'
|
margin: '0 0 0 3em',
|
||||||
}
|
textDecoration: 'none'
|
||||||
} as DecorationRenderOptions);
|
}
|
||||||
|
} as DecorationRenderOptions);
|
||||||
export class CurrentLineController extends Disposable {
|
|
||||||
|
export class CurrentLineController extends Disposable {
|
||||||
private _activeEditorLineDisposable: Disposable | undefined;
|
|
||||||
private _blameable: boolean;
|
private _activeEditorLineDisposable: Disposable | undefined;
|
||||||
private _config: IConfig;
|
private _blameable: boolean;
|
||||||
private _currentLine: number = -1;
|
private _config: IConfig;
|
||||||
private _disposable: Disposable;
|
private _currentLine: number = -1;
|
||||||
private _editor: TextEditor | undefined;
|
private _disposable: Disposable;
|
||||||
private _isAnnotating: boolean = false;
|
private _editor: TextEditor | undefined;
|
||||||
private _statusBarItem: StatusBarItem | undefined;
|
private _isAnnotating: boolean = false;
|
||||||
private _updateBlameDebounced: (line: number, editor: TextEditor) => Promise<void>;
|
private _statusBarItem: StatusBarItem | undefined;
|
||||||
private _uri: GitUri;
|
private _updateBlameDebounced: (line: number, editor: TextEditor) => Promise<void>;
|
||||||
|
private _uri: GitUri;
|
||||||
constructor(context: ExtensionContext, private git: GitService, private gitContextTracker: GitContextTracker, private annotationController: AnnotationController) {
|
|
||||||
super(() => this.dispose());
|
constructor(context: ExtensionContext, private git: GitService, private gitContextTracker: GitContextTracker, private annotationController: AnnotationController) {
|
||||||
|
super(() => this.dispose());
|
||||||
this._updateBlameDebounced = Functions.debounce(this._updateBlame, 250);
|
|
||||||
|
this._updateBlameDebounced = Functions.debounce(this._updateBlame, 250);
|
||||||
this._onConfigurationChanged();
|
|
||||||
|
this._onConfigurationChanged();
|
||||||
const subscriptions: Disposable[] = [];
|
|
||||||
|
const subscriptions: Disposable[] = [];
|
||||||
subscriptions.push(workspace.onDidChangeConfiguration(this._onConfigurationChanged, this));
|
|
||||||
subscriptions.push(git.onDidChangeGitCache(this._onGitCacheChanged, this));
|
subscriptions.push(workspace.onDidChangeConfiguration(this._onConfigurationChanged, this));
|
||||||
subscriptions.push(annotationController.onDidToggleAnnotations(this._onAnnotationsToggled, this));
|
subscriptions.push(git.onDidChangeGitCache(this._onGitCacheChanged, this));
|
||||||
|
subscriptions.push(annotationController.onDidToggleAnnotations(this._onAnnotationsToggled, this));
|
||||||
this._disposable = Disposable.from(...subscriptions);
|
|
||||||
}
|
this._disposable = Disposable.from(...subscriptions);
|
||||||
|
}
|
||||||
dispose() {
|
|
||||||
this._clearAnnotations(this._editor, true);
|
dispose() {
|
||||||
|
this._clearAnnotations(this._editor, true);
|
||||||
this._activeEditorLineDisposable && this._activeEditorLineDisposable.dispose();
|
|
||||||
this._statusBarItem && this._statusBarItem.dispose();
|
this._activeEditorLineDisposable && this._activeEditorLineDisposable.dispose();
|
||||||
this._disposable && this._disposable.dispose();
|
this._statusBarItem && this._statusBarItem.dispose();
|
||||||
}
|
this._disposable && this._disposable.dispose();
|
||||||
|
}
|
||||||
private _onConfigurationChanged() {
|
|
||||||
const cfg = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
|
private _onConfigurationChanged() {
|
||||||
|
const cfg = workspace.getConfiguration().get<IConfig>(ExtensionKey)!;
|
||||||
let changed = false;
|
|
||||||
|
let changed = false;
|
||||||
if (!Objects.areEquivalent(cfg.blame.line, this._config && this._config.blame.line) ||
|
|
||||||
!Objects.areEquivalent(cfg.annotations.line.trailing, this._config && this._config.annotations.line.trailing) ||
|
if (!Objects.areEquivalent(cfg.blame.line, this._config && this._config.blame.line) ||
|
||||||
!Objects.areEquivalent(cfg.annotations.line.hover, this._config && this._config.annotations.line.hover) ||
|
!Objects.areEquivalent(cfg.annotations.line.trailing, this._config && this._config.annotations.line.trailing) ||
|
||||||
!Objects.areEquivalent(cfg.theme.annotations.line.trailing, this._config && this._config.theme.annotations.line.trailing)) {
|
!Objects.areEquivalent(cfg.annotations.line.hover, this._config && this._config.annotations.line.hover) ||
|
||||||
changed = true;
|
!Objects.areEquivalent(cfg.theme.annotations.line.trailing, this._config && this._config.theme.annotations.line.trailing)) {
|
||||||
this._clearAnnotations(this._editor);
|
changed = true;
|
||||||
}
|
this._clearAnnotations(this._editor);
|
||||||
|
}
|
||||||
if (!Objects.areEquivalent(cfg.statusBar, this._config && this._config.statusBar)) {
|
|
||||||
changed = true;
|
if (!Objects.areEquivalent(cfg.statusBar, this._config && this._config.statusBar)) {
|
||||||
if (cfg.statusBar.enabled) {
|
changed = true;
|
||||||
const alignment = cfg.statusBar.alignment !== 'left' ? StatusBarAlignment.Right : StatusBarAlignment.Left;
|
if (cfg.statusBar.enabled) {
|
||||||
if (this._statusBarItem !== undefined && this._statusBarItem.alignment !== alignment) {
|
const alignment = cfg.statusBar.alignment !== 'left' ? StatusBarAlignment.Right : StatusBarAlignment.Left;
|
||||||
this._statusBarItem.dispose();
|
if (this._statusBarItem !== undefined && this._statusBarItem.alignment !== alignment) {
|
||||||
this._statusBarItem = undefined;
|
this._statusBarItem.dispose();
|
||||||
}
|
this._statusBarItem = undefined;
|
||||||
|
}
|
||||||
this._statusBarItem = this._statusBarItem || window.createStatusBarItem(alignment, alignment === StatusBarAlignment.Right ? 1000 : 0);
|
|
||||||
this._statusBarItem.command = cfg.statusBar.command;
|
this._statusBarItem = this._statusBarItem || window.createStatusBarItem(alignment, alignment === StatusBarAlignment.Right ? 1000 : 0);
|
||||||
}
|
this._statusBarItem.command = cfg.statusBar.command;
|
||||||
else if (!cfg.statusBar.enabled && this._statusBarItem) {
|
}
|
||||||
this._statusBarItem.dispose();
|
else if (!cfg.statusBar.enabled && this._statusBarItem) {
|
||||||
this._statusBarItem = undefined;
|
this._statusBarItem.dispose();
|
||||||
}
|
this._statusBarItem = undefined;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this._config = cfg;
|
|
||||||
|
this._config = cfg;
|
||||||
if (!changed) return;
|
|
||||||
|
if (!changed) return;
|
||||||
const trackCurrentLine = cfg.statusBar.enabled || cfg.blame.line.enabled;
|
|
||||||
if (trackCurrentLine && !this._activeEditorLineDisposable) {
|
const trackCurrentLine = cfg.statusBar.enabled || cfg.blame.line.enabled;
|
||||||
const subscriptions: Disposable[] = [];
|
if (trackCurrentLine && !this._activeEditorLineDisposable) {
|
||||||
|
const subscriptions: Disposable[] = [];
|
||||||
subscriptions.push(window.onDidChangeActiveTextEditor(this._onActiveTextEditorChanged, this));
|
|
||||||
subscriptions.push(window.onDidChangeTextEditorSelection(this._onTextEditorSelectionChanged, this));
|
subscriptions.push(window.onDidChangeActiveTextEditor(this._onActiveTextEditorChanged, this));
|
||||||
subscriptions.push(this.gitContextTracker.onDidBlameabilityChange(this._onBlameabilityChanged, this));
|
subscriptions.push(window.onDidChangeTextEditorSelection(this._onTextEditorSelectionChanged, this));
|
||||||
|
subscriptions.push(this.gitContextTracker.onDidBlameabilityChange(this._onBlameabilityChanged, this));
|
||||||
this._activeEditorLineDisposable = Disposable.from(...subscriptions);
|
|
||||||
}
|
this._activeEditorLineDisposable = Disposable.from(...subscriptions);
|
||||||
else if (!trackCurrentLine && this._activeEditorLineDisposable) {
|
}
|
||||||
this._activeEditorLineDisposable.dispose();
|
else if (!trackCurrentLine && this._activeEditorLineDisposable) {
|
||||||
this._activeEditorLineDisposable = undefined;
|
this._activeEditorLineDisposable.dispose();
|
||||||
}
|
this._activeEditorLineDisposable = undefined;
|
||||||
|
}
|
||||||
this._onActiveTextEditorChanged(window.activeTextEditor);
|
|
||||||
}
|
this._onActiveTextEditorChanged(window.activeTextEditor);
|
||||||
|
}
|
||||||
private isEditorBlameable(editor: TextEditor | undefined): boolean {
|
|
||||||
if (editor === undefined || editor.document === undefined) return false;
|
private isEditorBlameable(editor: TextEditor | undefined): boolean {
|
||||||
|
if (editor === undefined || editor.document === undefined) return false;
|
||||||
if (!this.git.isTrackable(editor.document.uri)) return false;
|
|
||||||
if (editor.document.isUntitled && editor.document.uri.scheme === DocumentSchemes.File) return false;
|
if (!this.git.isTrackable(editor.document.uri)) return false;
|
||||||
|
if (editor.document.isUntitled && editor.document.uri.scheme === DocumentSchemes.File) return false;
|
||||||
return this.git.isEditorBlameable(editor);
|
|
||||||
}
|
return this.git.isEditorBlameable(editor);
|
||||||
|
}
|
||||||
private async _onActiveTextEditorChanged(editor: TextEditor | undefined) {
|
|
||||||
this._currentLine = -1;
|
private async _onActiveTextEditorChanged(editor: TextEditor | undefined) {
|
||||||
this._clearAnnotations(this._editor);
|
this._currentLine = -1;
|
||||||
|
this._clearAnnotations(this._editor);
|
||||||
if (editor === undefined || !this.isEditorBlameable(editor)) {
|
|
||||||
this.clear(editor);
|
if (editor === undefined || !this.isEditorBlameable(editor)) {
|
||||||
this._editor = undefined;
|
this.clear(editor);
|
||||||
|
this._editor = undefined;
|
||||||
return;
|
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
this._blameable = editor !== undefined && editor.document !== undefined && !editor.document.isDirty;
|
|
||||||
this._editor = editor;
|
this._blameable = editor !== undefined && editor.document !== undefined && !editor.document.isDirty;
|
||||||
this._uri = await GitUri.fromUri(editor.document.uri, this.git);
|
this._editor = editor;
|
||||||
|
this._uri = await GitUri.fromUri(editor.document.uri, this.git);
|
||||||
const maxLines = this._config.advanced.caching.maxLines;
|
|
||||||
// If caching is on and the file is small enough -- kick off a blame for the whole file
|
const maxLines = this._config.advanced.caching.maxLines;
|
||||||
if (this._config.advanced.caching.enabled && (maxLines <= 0 || editor.document.lineCount <= maxLines)) {
|
// If caching is on and the file is small enough -- kick off a blame for the whole file
|
||||||
this.git.getBlameForFile(this._uri);
|
if (this._config.advanced.caching.enabled && (maxLines <= 0 || editor.document.lineCount <= maxLines)) {
|
||||||
}
|
this.git.getBlameForFile(this._uri);
|
||||||
|
}
|
||||||
this._updateBlameDebounced(editor.selection.active.line, editor);
|
|
||||||
}
|
this._updateBlameDebounced(editor.selection.active.line, editor);
|
||||||
|
}
|
||||||
private _onBlameabilityChanged(e: BlameabilityChangeEvent) {
|
|
||||||
this._blameable = e.blameable;
|
private _onBlameabilityChanged(e: BlameabilityChangeEvent) {
|
||||||
if (!e.blameable || !this._editor) {
|
this._blameable = e.blameable;
|
||||||
this.clear(e.editor);
|
if (!e.blameable || !this._editor) {
|
||||||
return;
|
this.clear(e.editor);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
// Make sure this is for the editor we are tracking
|
|
||||||
if (!TextEditorComparer.equals(this._editor, e.editor)) return;
|
// Make sure this is for the editor we are tracking
|
||||||
|
if (!TextEditorComparer.equals(this._editor, e.editor)) return;
|
||||||
this._updateBlameDebounced(this._editor.selection.active.line, this._editor);
|
|
||||||
}
|
this._updateBlameDebounced(this._editor.selection.active.line, this._editor);
|
||||||
|
}
|
||||||
private _onAnnotationsToggled() {
|
|
||||||
this._onActiveTextEditorChanged(window.activeTextEditor);
|
private _onAnnotationsToggled() {
|
||||||
}
|
this._onActiveTextEditorChanged(window.activeTextEditor);
|
||||||
|
}
|
||||||
private _onGitCacheChanged() {
|
|
||||||
this._onActiveTextEditorChanged(window.activeTextEditor);
|
private _onGitCacheChanged() {
|
||||||
}
|
this._onActiveTextEditorChanged(window.activeTextEditor);
|
||||||
|
}
|
||||||
private async _onTextEditorSelectionChanged(e: TextEditorSelectionChangeEvent): Promise<void> {
|
|
||||||
// Make sure this is for the editor we are tracking
|
private async _onTextEditorSelectionChanged(e: TextEditorSelectionChangeEvent): Promise<void> {
|
||||||
if (!this._blameable || !TextEditorComparer.equals(this._editor, e.textEditor)) return;
|
// Make sure this is for the editor we are tracking
|
||||||
|
if (!this._blameable || !TextEditorComparer.equals(this._editor, e.textEditor)) return;
|
||||||
const line = e.selections[0].active.line;
|
|
||||||
if (line === this._currentLine) return;
|
const line = e.selections[0].active.line;
|
||||||
|
if (line === this._currentLine) return;
|
||||||
|
|
||||||
|
this._currentLine = line;
|
||||||
|
|
||||||
this._currentLine = line;
|
|
||||||
|
|
||||||
if (!this._uri && e.textEditor !== undefined) {
|
if (!this._uri && e.textEditor !== undefined) {
|
||||||
this._uri = await GitUri.fromUri(e.textEditor.document.uri, this.git);
|
this._uri = await GitUri.fromUri(e.textEditor.document.uri, this.git);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._clearAnnotations(e.textEditor);
|
this._clearAnnotations(e.textEditor);
|
||||||
this._updateBlameDebounced(line, e.textEditor);
|
this._updateBlameDebounced(line, e.textEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _updateBlame(line: number, editor: TextEditor) {
|
private async _updateBlame(line: number, editor: TextEditor) {
|
||||||
line = line - this._uri.offset;
|
line = line - this._uri.offset;
|
||||||
|
|
||||||
let commit: GitCommit | undefined = undefined;
|
let commit: GitCommit | undefined = undefined;
|
||||||
let commitLine: IGitCommitLine | undefined = undefined;
|
let commitLine: IGitCommitLine | undefined = undefined;
|
||||||
// Since blame information isn't valid when there are unsaved changes -- don't show any status
|
// Since blame information isn't valid when there are unsaved changes -- don't show any status
|
||||||
if (this._blameable && line >= 0) {
|
if (this._blameable && line >= 0) {
|
||||||
const blameLine = await this.git.getBlameForLine(this._uri, line);
|
const blameLine = await this.git.getBlameForLine(this._uri, line);
|
||||||
commitLine = blameLine === undefined ? undefined : blameLine.line;
|
commitLine = blameLine === undefined ? undefined : blameLine.line;
|
||||||
commit = blameLine === undefined ? undefined : blameLine.commit;
|
commit = blameLine === undefined ? undefined : blameLine.commit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commit !== undefined && commitLine !== undefined) {
|
if (commit !== undefined && commitLine !== undefined) {
|
||||||
this.show(commit, commitLine, editor);
|
this.show(commit, commitLine, editor);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.clear(editor);
|
this.clear(editor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async clear(editor: TextEditor | undefined) {
|
async clear(editor: TextEditor | undefined) {
|
||||||
this._clearAnnotations(editor, true);
|
this._clearAnnotations(editor, true);
|
||||||
this._statusBarItem && this._statusBarItem.hide();
|
this._statusBarItem && this._statusBarItem.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _clearAnnotations(editor: TextEditor | undefined, force: boolean = false) {
|
private async _clearAnnotations(editor: TextEditor | undefined, force: boolean = false) {
|
||||||
if (editor === undefined || (!this._isAnnotating && !force)) return;
|
if (editor === undefined || (!this._isAnnotating && !force)) return;
|
||||||
@@ -208,233 +209,233 @@ export class CurrentLineController extends Disposable {
|
|||||||
this._isAnnotating = false;
|
this._isAnnotating = false;
|
||||||
|
|
||||||
if (!force) return;
|
if (!force) return;
|
||||||
|
|
||||||
// I have no idea why the decorators sometimes don't get removed, but if they don't try again with a tiny delay
|
// I have no idea why the decorators sometimes don't get removed, but if they don't try again with a tiny delay
|
||||||
await Functions.wait(1);
|
await Functions.wait(1);
|
||||||
editor.setDecorations(annotationDecoration, []);
|
editor.setDecorations(annotationDecoration, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
async show(commit: GitCommit, blameLine: IGitCommitLine, editor: TextEditor) {
|
async show(commit: GitCommit, blameLine: IGitCommitLine, editor: TextEditor) {
|
||||||
// I have no idea why I need this protection -- but it happens
|
// I have no idea why I need this protection -- but it happens
|
||||||
if (editor.document === undefined) return;
|
if (editor.document === undefined) return;
|
||||||
|
|
||||||
this._updateStatusBar(commit);
|
this._updateStatusBar(commit);
|
||||||
await this._updateAnnotations(commit, blameLine, editor);
|
await this._updateAnnotations(commit, blameLine, editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
async showAnnotations(editor: TextEditor, type: LineAnnotationType) {
|
async showAnnotations(editor: TextEditor, type: LineAnnotationType) {
|
||||||
if (editor === undefined) return;
|
if (editor === undefined) return;
|
||||||
|
|
||||||
const cfg = this._config.blame.line;
|
const cfg = this._config.blame.line;
|
||||||
if (!cfg.enabled || cfg.annotationType !== type) {
|
if (!cfg.enabled || cfg.annotationType !== type) {
|
||||||
cfg.enabled = true;
|
cfg.enabled = true;
|
||||||
cfg.annotationType = type;
|
cfg.annotationType = type;
|
||||||
|
|
||||||
await this._clearAnnotations(editor);
|
await this._clearAnnotations(editor);
|
||||||
await this._updateBlame(editor.selection.active.line, editor);
|
await this._updateBlame(editor.selection.active.line, editor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggleAnnotations(editor: TextEditor, type: LineAnnotationType) {
|
async toggleAnnotations(editor: TextEditor, type: LineAnnotationType) {
|
||||||
if (editor === undefined) return;
|
if (editor === undefined) return;
|
||||||
|
|
||||||
const cfg = this._config.blame.line;
|
const cfg = this._config.blame.line;
|
||||||
cfg.enabled = !cfg.enabled;
|
cfg.enabled = !cfg.enabled;
|
||||||
cfg.annotationType = type;
|
cfg.annotationType = type;
|
||||||
|
|
||||||
await this._clearAnnotations(editor);
|
await this._clearAnnotations(editor);
|
||||||
await this._updateBlame(editor.selection.active.line, editor);
|
await this._updateBlame(editor.selection.active.line, editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _updateAnnotations(commit: GitCommit, blameLine: IGitCommitLine, editor: TextEditor) {
|
private async _updateAnnotations(commit: GitCommit, blameLine: IGitCommitLine, editor: TextEditor) {
|
||||||
const cfg = this._config.blame.line;
|
const cfg = this._config.blame.line;
|
||||||
if (!cfg.enabled) return;
|
if (!cfg.enabled) return;
|
||||||
|
|
||||||
const line = blameLine.line + this._uri.offset;
|
const line = blameLine.line + this._uri.offset;
|
||||||
|
|
||||||
const decorationOptions: DecorationOptions[] = [];
|
const decorationOptions: DecorationOptions[] = [];
|
||||||
|
|
||||||
let showChanges = false;
|
let showChanges = false;
|
||||||
let showChangesStartIndex = 0;
|
let showChangesStartIndex = 0;
|
||||||
let showChangesInStartingWhitespace = false;
|
let showChangesInStartingWhitespace = false;
|
||||||
|
|
||||||
let showDetails = false;
|
let showDetails = false;
|
||||||
let showDetailsStartIndex = 0;
|
let showDetailsStartIndex = 0;
|
||||||
let showDetailsInStartingWhitespace = false;
|
let showDetailsInStartingWhitespace = false;
|
||||||
|
|
||||||
switch (cfg.annotationType) {
|
switch (cfg.annotationType) {
|
||||||
case LineAnnotationType.Trailing: {
|
case LineAnnotationType.Trailing: {
|
||||||
const cfgAnnotations = this._config.annotations.line.trailing;
|
const cfgAnnotations = this._config.annotations.line.trailing;
|
||||||
|
|
||||||
showChanges = cfgAnnotations.hover.changes;
|
showChanges = cfgAnnotations.hover.changes;
|
||||||
showDetails = cfgAnnotations.hover.details;
|
showDetails = cfgAnnotations.hover.details;
|
||||||
|
|
||||||
if (cfgAnnotations.hover.wholeLine) {
|
if (cfgAnnotations.hover.wholeLine) {
|
||||||
showChangesStartIndex = 0;
|
showChangesStartIndex = 0;
|
||||||
showChangesInStartingWhitespace = false;
|
showChangesInStartingWhitespace = false;
|
||||||
|
|
||||||
showDetailsStartIndex = 0;
|
showDetailsStartIndex = 0;
|
||||||
showDetailsInStartingWhitespace = false;
|
showDetailsInStartingWhitespace = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
showChangesStartIndex = endOfLineIndex;
|
showChangesStartIndex = endOfLineIndex;
|
||||||
showChangesInStartingWhitespace = true;
|
showChangesInStartingWhitespace = true;
|
||||||
|
|
||||||
showDetailsStartIndex = endOfLineIndex;
|
showDetailsStartIndex = endOfLineIndex;
|
||||||
showDetailsInStartingWhitespace = true;
|
showDetailsInStartingWhitespace = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const decoration = Annotations.trailing(commit, cfgAnnotations.format, cfgAnnotations.dateFormat, this._config.theme);
|
const decoration = Annotations.trailing(commit, cfgAnnotations.format, cfgAnnotations.dateFormat, this._config.theme);
|
||||||
decoration.range = editor.document.validateRange(new Range(line, endOfLineIndex, line, endOfLineIndex));
|
decoration.range = editor.document.validateRange(new Range(line, endOfLineIndex, line, endOfLineIndex));
|
||||||
decorationOptions.push(decoration);
|
decorationOptions.push(decoration);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LineAnnotationType.Hover: {
|
case LineAnnotationType.Hover: {
|
||||||
const cfgAnnotations = this._config.annotations.line.hover;
|
const cfgAnnotations = this._config.annotations.line.hover;
|
||||||
|
|
||||||
showChanges = cfgAnnotations.changes;
|
showChanges = cfgAnnotations.changes;
|
||||||
showChangesStartIndex = 0;
|
showChangesStartIndex = 0;
|
||||||
showChangesInStartingWhitespace = false;
|
showChangesInStartingWhitespace = false;
|
||||||
|
|
||||||
showDetails = cfgAnnotations.details;
|
showDetails = cfgAnnotations.details;
|
||||||
showDetailsStartIndex = 0;
|
showDetailsStartIndex = 0;
|
||||||
showDetailsInStartingWhitespace = false;
|
showDetailsInStartingWhitespace = false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showDetails || showChanges) {
|
if (showDetails || showChanges) {
|
||||||
const annotationType = this.annotationController.getAnnotationType(editor);
|
const annotationType = this.annotationController.getAnnotationType(editor);
|
||||||
|
|
||||||
const firstNonWhitespace = editor.document.lineAt(line).firstNonWhitespaceCharacterIndex;
|
const firstNonWhitespace = editor.document.lineAt(line).firstNonWhitespaceCharacterIndex;
|
||||||
|
|
||||||
switch (annotationType) {
|
switch (annotationType) {
|
||||||
case FileAnnotationType.Gutter: {
|
case FileAnnotationType.Gutter: {
|
||||||
const cfgHover = this._config.annotations.file.gutter.hover;
|
const cfgHover = this._config.annotations.file.gutter.hover;
|
||||||
if (cfgHover.details) {
|
if (cfgHover.details) {
|
||||||
showDetailsInStartingWhitespace = false;
|
showDetailsInStartingWhitespace = false;
|
||||||
if (cfgHover.wholeLine) {
|
if (cfgHover.wholeLine) {
|
||||||
// Avoid double annotations if we are showing the whole-file hover blame annotations
|
// Avoid double annotations if we are showing the whole-file hover blame annotations
|
||||||
showDetails = false;
|
showDetails = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (showDetailsStartIndex === 0) {
|
if (showDetailsStartIndex === 0) {
|
||||||
showDetailsStartIndex = firstNonWhitespace === 0 ? 1 : firstNonWhitespace;
|
showDetailsStartIndex = firstNonWhitespace === 0 ? 1 : firstNonWhitespace;
|
||||||
}
|
}
|
||||||
if (showChangesStartIndex === 0) {
|
if (showChangesStartIndex === 0) {
|
||||||
showChangesInStartingWhitespace = true;
|
showChangesInStartingWhitespace = true;
|
||||||
showChangesStartIndex = firstNonWhitespace === 0 ? 1 : firstNonWhitespace;
|
showChangesStartIndex = firstNonWhitespace === 0 ? 1 : firstNonWhitespace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FileAnnotationType.Hover: {
|
case FileAnnotationType.Hover: {
|
||||||
const cfgHover = this._config.annotations.file.hover;
|
const cfgHover = this._config.annotations.file.hover;
|
||||||
showDetailsInStartingWhitespace = false;
|
showDetailsInStartingWhitespace = false;
|
||||||
if (cfgHover.wholeLine) {
|
if (cfgHover.wholeLine) {
|
||||||
// Avoid double annotations if we are showing the whole-file hover blame annotations
|
// Avoid double annotations if we are showing the whole-file hover blame annotations
|
||||||
showDetails = false;
|
showDetails = false;
|
||||||
showChangesStartIndex = 0;
|
showChangesStartIndex = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (showDetailsStartIndex === 0) {
|
if (showDetailsStartIndex === 0) {
|
||||||
showDetailsStartIndex = firstNonWhitespace === 0 ? 1 : firstNonWhitespace;
|
showDetailsStartIndex = firstNonWhitespace === 0 ? 1 : firstNonWhitespace;
|
||||||
}
|
}
|
||||||
if (showChangesStartIndex === 0) {
|
if (showChangesStartIndex === 0) {
|
||||||
showChangesInStartingWhitespace = true;
|
showChangesInStartingWhitespace = true;
|
||||||
showChangesStartIndex = firstNonWhitespace === 0 ? 1 : firstNonWhitespace;
|
showChangesStartIndex = firstNonWhitespace === 0 ? 1 : firstNonWhitespace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showDetails) {
|
if (showDetails) {
|
||||||
// Get the full commit message -- since blame only returns the summary
|
// Get the full commit message -- since blame only returns the summary
|
||||||
let logCommit: GitCommit | undefined = undefined;
|
let logCommit: GitCommit | undefined = undefined;
|
||||||
if (!commit.isUncommitted) {
|
if (!commit.isUncommitted) {
|
||||||
logCommit = await this.git.getLogCommit(this._uri.repoPath, this._uri.fsPath, commit.sha);
|
logCommit = await this.git.getLogCommit(this._uri.repoPath, this._uri.fsPath, commit.sha);
|
||||||
}
|
}
|
||||||
|
|
||||||
// I have no idea why I need this protection -- but it happens
|
// I have no idea why I need this protection -- but it happens
|
||||||
if (editor.document === undefined) return;
|
if (editor.document === undefined) return;
|
||||||
|
|
||||||
const decoration = Annotations.detailsHover(logCommit || commit);
|
const decoration = Annotations.detailsHover(logCommit || commit);
|
||||||
decoration.range = editor.document.validateRange(new Range(line, showDetailsStartIndex, line, endOfLineIndex));
|
decoration.range = editor.document.validateRange(new Range(line, showDetailsStartIndex, line, endOfLineIndex));
|
||||||
decorationOptions.push(decoration);
|
decorationOptions.push(decoration);
|
||||||
|
|
||||||
if (showDetailsInStartingWhitespace && showDetailsStartIndex !== 0) {
|
if (showDetailsInStartingWhitespace && showDetailsStartIndex !== 0) {
|
||||||
decorationOptions.push(Annotations.withRange(decoration, 0, firstNonWhitespace));
|
decorationOptions.push(Annotations.withRange(decoration, 0, firstNonWhitespace));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showChanges) {
|
if (showChanges) {
|
||||||
const decoration = await Annotations.changesHover(commit, line, this._uri, this.git);
|
const decoration = await Annotations.changesHover(commit, line, this._uri, this.git);
|
||||||
|
|
||||||
// I have no idea why I need this protection -- but it happens
|
// I have no idea why I need this protection -- but it happens
|
||||||
if (editor.document === undefined) return;
|
if (editor.document === undefined) return;
|
||||||
|
|
||||||
decoration.range = editor.document.validateRange(new Range(line, showChangesStartIndex, line, endOfLineIndex));
|
decoration.range = editor.document.validateRange(new Range(line, showChangesStartIndex, line, endOfLineIndex));
|
||||||
decorationOptions.push(decoration);
|
decorationOptions.push(decoration);
|
||||||
|
|
||||||
if (showChangesInStartingWhitespace && showChangesStartIndex !== 0) {
|
if (showChangesInStartingWhitespace && showChangesStartIndex !== 0) {
|
||||||
decorationOptions.push(Annotations.withRange(decoration, 0, firstNonWhitespace));
|
decorationOptions.push(Annotations.withRange(decoration, 0, firstNonWhitespace));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decorationOptions.length) {
|
if (decorationOptions.length) {
|
||||||
editor.setDecorations(annotationDecoration, decorationOptions);
|
editor.setDecorations(annotationDecoration, decorationOptions);
|
||||||
this._isAnnotating = true;
|
this._isAnnotating = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateStatusBar(commit: GitCommit) {
|
private _updateStatusBar(commit: GitCommit) {
|
||||||
const cfg = this._config.statusBar;
|
const cfg = this._config.statusBar;
|
||||||
if (!cfg.enabled || this._statusBarItem === undefined) return;
|
if (!cfg.enabled || this._statusBarItem === undefined) return;
|
||||||
|
|
||||||
this._statusBarItem.text = `$(git-commit) ${CommitFormatter.fromTemplate(cfg.format, commit, cfg.dateFormat)}`;
|
this._statusBarItem.text = `$(git-commit) ${CommitFormatter.fromTemplate(cfg.format, commit, cfg.dateFormat)}`;
|
||||||
|
|
||||||
switch (cfg.command) {
|
switch (cfg.command) {
|
||||||
case StatusBarCommand.BlameAnnotate:
|
case StatusBarCommand.BlameAnnotate:
|
||||||
this._statusBarItem.tooltip = 'Toggle Blame Annotations';
|
this._statusBarItem.tooltip = 'Toggle Blame Annotations';
|
||||||
break;
|
break;
|
||||||
case StatusBarCommand.ShowBlameHistory:
|
case StatusBarCommand.ShowBlameHistory:
|
||||||
this._statusBarItem.tooltip = 'Open Blame History Explorer';
|
this._statusBarItem.tooltip = 'Open Blame History Explorer';
|
||||||
break;
|
break;
|
||||||
case StatusBarCommand.ShowFileHistory:
|
case StatusBarCommand.ShowFileHistory:
|
||||||
this._statusBarItem.tooltip = 'Open File History Explorer';
|
this._statusBarItem.tooltip = 'Open File History Explorer';
|
||||||
break;
|
break;
|
||||||
case StatusBarCommand.DiffWithPrevious:
|
case StatusBarCommand.DiffWithPrevious:
|
||||||
this._statusBarItem.command = Commands.DiffLineWithPrevious;
|
this._statusBarItem.command = Commands.DiffLineWithPrevious;
|
||||||
this._statusBarItem.tooltip = 'Compare Line Commit with Previous';
|
this._statusBarItem.tooltip = 'Compare Line Commit with Previous';
|
||||||
break;
|
break;
|
||||||
case StatusBarCommand.DiffWithWorking:
|
case StatusBarCommand.DiffWithWorking:
|
||||||
this._statusBarItem.command = Commands.DiffLineWithWorking;
|
this._statusBarItem.command = Commands.DiffLineWithWorking;
|
||||||
this._statusBarItem.tooltip = 'Compare Line Commit with Working Tree';
|
this._statusBarItem.tooltip = 'Compare Line Commit with Working Tree';
|
||||||
break;
|
break;
|
||||||
case StatusBarCommand.ToggleCodeLens:
|
case StatusBarCommand.ToggleCodeLens:
|
||||||
this._statusBarItem.tooltip = 'Toggle Git CodeLens';
|
this._statusBarItem.tooltip = 'Toggle Git CodeLens';
|
||||||
break;
|
break;
|
||||||
case StatusBarCommand.ShowQuickCommitDetails:
|
case StatusBarCommand.ShowQuickCommitDetails:
|
||||||
this._statusBarItem.tooltip = 'Show Commit Details';
|
this._statusBarItem.tooltip = 'Show Commit Details';
|
||||||
break;
|
break;
|
||||||
case StatusBarCommand.ShowQuickCommitFileDetails:
|
case StatusBarCommand.ShowQuickCommitFileDetails:
|
||||||
this._statusBarItem.tooltip = 'Show Line Commit Details';
|
this._statusBarItem.tooltip = 'Show Line Commit Details';
|
||||||
break;
|
break;
|
||||||
case StatusBarCommand.ShowQuickFileHistory:
|
case StatusBarCommand.ShowQuickFileHistory:
|
||||||
this._statusBarItem.tooltip = 'Show File History';
|
this._statusBarItem.tooltip = 'Show File History';
|
||||||
break;
|
break;
|
||||||
case StatusBarCommand.ShowQuickCurrentBranchHistory:
|
case StatusBarCommand.ShowQuickCurrentBranchHistory:
|
||||||
this._statusBarItem.tooltip = 'Show Branch History';
|
this._statusBarItem.tooltip = 'Show Branch History';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._statusBarItem.show();
|
this._statusBarItem.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user