Procházet zdrojové kódy

Fixes issues with annotation character settings

Fixes #29 - Commit info tooltip duplicated for current line when blame is enabled
Improves performance of navigating line when active line annotations & statusbar blame are enabled
main
Eric Amodio před 7 roky
rodič
revize
80aa43a84b
6 změnil soubory, kde provedl 62 přidání a 40 odebrání
  1. +0
    -1
      README.md
  2. +7
    -0
      src/blameAnnotationController.ts
  3. +21
    -15
      src/blameAnnotationFormatter.ts
  4. +31
    -21
      src/blameStatusBarController.ts
  5. +1
    -1
      src/extension.ts
  6. +2
    -2
      src/system/function.ts

+ 0
- 1
README.md Zobrazit soubor

@ -2,7 +2,6 @@
Provides Git CodeLens information (most recent commit, # of authors), on-demand inline blame annotations, status bar blame information, file and blame history explorers, and commands to compare changes with the working tree or previous versions.
---
## Features
- Provides (optional) **CodeLens** on code blocks:

+ 7
- 0
src/blameAnnotationController.ts Zobrazit soubor

@ -99,6 +99,13 @@ export default class BlameAnnotationController extends Disposable {
return provider.provideBlameAnnotation(shaOrLine);
}
isAnnotating(editor: TextEditor): boolean {
if (!editor || !editor.document) return false;
if (editor.viewColumn === undefined && !this.git.hasGitUriForFile(editor)) return false;
return !!this._annotationProviders.get(editor.viewColumn || -1);
}
async toggleBlameAnnotation(editor: TextEditor, shaOrLine?: string | number): Promise<boolean> {
if (!editor || !editor.document) return false;
if (editor.viewColumn === undefined && !this.git.hasGitUriForFile(editor)) return false;

+ 21
- 15
src/blameAnnotationFormatter.ts Zobrazit soubor

@ -9,16 +9,22 @@ export const defaultRelativeDateLength = 13;
export const defaultAuthorLength = 16;
export const defaultMessageLength = 32;
export let cssEllipse = '\\2026';
export let cssIndent = '\\2759';
export let cssSeparator = '\\2022';
export let cssPadding = '\\00a0';
export let cssEllipse = '\\002026';
export let cssIndent = '\\002759';
export let cssSeparator = '\\002022';
export let cssPadding = '\\0000a0';
let cssEllipseLength: number = 1;
const cssUnicodeMatcher = /\\[0-9a-fA-F]{1,6}/;
export function configureCssCharacters(config: IBlameConfig) {
cssEllipse = config.annotation.characters.ellipse || cssEllipse;
cssIndent = config.annotation.characters.indent || cssIndent;
cssPadding = config.annotation.characters.padding || cssPadding;
cssSeparator = config.annotation.characters.separator || cssSeparator;
cssEllipseLength = cssUnicodeMatcher.test(cssEllipse) ? 1 : cssEllipse.length;
}
export enum BlameAnnotationFormat {
@ -35,10 +41,10 @@ export default class BlameAnnotationFormatter {
if (format === BlameAnnotationFormat.Unconstrained) {
const authorAndDate = this.getAuthorAndDate(config, commit, 'MMMM Do, YYYY h:MMa');
if (config.annotation.sha) {
message = `${sha}${(authorAndDate ? ` ${cssSeparator} ${authorAndDate}` : '')}${(message ? ` ${cssSeparator} ${message}` : '')}`;
message = `${sha}${(authorAndDate ? `${cssPadding}${cssSeparator}${cssPadding} ${authorAndDate}` : '')}${(message ? `${cssPadding}${cssSeparator}${cssPadding} ${message}` : '')}`;
}
else if (config.annotation.author || config.annotation.date) {
message = `${authorAndDate}${(message ? ` ${cssSeparator} ${message}` : '')}`;
message = `${authorAndDate}${(message ? `${cssPadding}${cssSeparator}${cssPadding} ${message}` : '')}`;
}
return message;
@ -47,13 +53,13 @@ export default class BlameAnnotationFormatter {
const author = this.getAuthor(config, commit, defaultAuthorLength);
const date = this.getDate(config, commit, 'MM/DD/YYYY', true);
if (config.annotation.sha) {
message = `${sha}${(author ? ` ${cssSeparator} ${author}` : '')}${(date ? ` ${cssSeparator} ${date}` : '')}${(message ? ` ${cssSeparator} ${message}` : '')}`;
message = `${sha}${(author ? `${cssPadding}${cssSeparator}${cssPadding} ${author}` : '')}${(date ? `${cssPadding}${cssSeparator}${cssPadding} ${date}` : '')}${(message ? `${cssPadding}${cssSeparator}${cssPadding} ${message}` : '')}`;
}
else if (config.annotation.author) {
message = `${author}${(date ? ` ${cssSeparator} ${date}` : '')}${(message ? ` ${cssSeparator} ${message}` : '')}`;
message = `${author}${(date ? `${cssPadding}${cssSeparator}${cssPadding} ${date}` : '')}${(message ? `${cssPadding}${cssSeparator}${cssPadding} ${message}` : '')}`;
}
else if (config.annotation.date) {
message = `${date}${(message ? ` ${cssSeparator} ${message}` : '')}`;
message = `${date}${(message ? `${cssPadding}${cssSeparator}${cssPadding} ${message}` : '')}`;
}
return message;
@ -62,7 +68,7 @@ export default class BlameAnnotationFormatter {
static getAnnotationHover(config: IBlameConfig, line: IGitCommitLine, commit: GitCommit): string | Array<string> {
const message = commit.message.replace(/\n/g, '\n\n');
if (commit.isUncommitted) {
return `\`${'0'.repeat(8)}\` &nbsp; __Uncommitted changes__ \n\n > ${message}`;
return `\`${'0'.repeat(8)}\` &nbsp; __Uncommitted changes__`;
}
return `\`${commit.sha}\` &nbsp; __${commit.author}__, ${moment(commit.date).fromNow()} _(${moment(commit.date).format('MMMM Do, YYYY h:MMa')})_ \n\n > ${message}`;
@ -85,11 +91,11 @@ export default class BlameAnnotationFormatter {
static getAuthor(config: IBlameConfig, commit: GitCommit, truncateTo: number = 0, force: boolean = false) {
if (!force && !config.annotation.author) return '';
const author = commit.isUncommitted ? 'Uncommitted' : commit.author;
const author = commit.isUncommitted ? 'Uncommited' : commit.author;
if (!truncateTo) return author;
if (author.length > truncateTo) {
return `${author.substring(0, truncateTo - cssEllipse.length)}${cssEllipse}`;
return `${author.substring(0, truncateTo - cssEllipseLength)}${cssEllipse}`;
}
if (force) return author; // Don't pad when just asking for the value
@ -106,7 +112,7 @@ export default class BlameAnnotationFormatter {
const truncateTo = config.annotation.date === 'relative' ? defaultRelativeDateLength : defaultAbsoluteDateLength;
if (date.length > truncateTo) {
return `${date.substring(0, truncateTo - cssEllipse.length)}${cssEllipse}`;
return `${date.substring(0, truncateTo - cssEllipseLength)}${cssEllipse}`;
}
if (force) return date; // Don't pad when just asking for the value
@ -116,9 +122,9 @@ export default class BlameAnnotationFormatter {
static getMessage(config: IBlameConfig, commit: GitCommit, truncateTo: number = 0, force: boolean = false) {
if (!force && !config.annotation.message) return '';
let message = commit.message;
let message = commit.isUncommitted ? 'Uncommited change' : commit.message;
if (truncateTo && message.length > truncateTo) {
return `${message.substring(0, truncateTo - cssEllipse.length)}${cssEllipse}`;
return `${message.substring(0, truncateTo - cssEllipseLength)}${cssEllipse}`;
}
return message;

+ 31
- 21
src/blameStatusBarController.ts Zobrazit soubor

@ -1,6 +1,7 @@
'use strict';
import { Objects } from './system';
import { Functions, Objects } from './system';
import { DecorationOptions, DecorationInstanceRenderOptions, DecorationRenderOptions, Disposable, ExtensionContext, Range, StatusBarAlignment, StatusBarItem, TextDocumentChangeEvent, TextEditor, TextEditorDecorationType, TextEditorSelectionChangeEvent, window, workspace } from 'vscode';
import BlameAnnotationController from './blameAnnotationController';
import BlameAnnotationFormatter, { BlameAnnotationFormat } from './blameAnnotationFormatter';
import { TextDocumentComparer, TextEditorComparer } from './comparers';
import { IBlameConfig, IConfig, StatusBarCommand } from './configuration';
@ -19,15 +20,19 @@ export default class BlameStatusBarController extends Disposable {
private _activeEditorLineDisposable: Disposable | undefined;
private _blame: Promise<IGitBlame> | undefined;
private _config: IConfig;
private _currentLine: number = -1;
private _disposable: Disposable;
private _editor: TextEditor | undefined;
private _showBlameDebounced: (line: number, editor: TextEditor) => Promise<void>;
private _statusBarItem: StatusBarItem | undefined;
private _uri: GitUri;
private _useCaching: boolean;
constructor(context: ExtensionContext, private git: GitProvider) {
constructor(context: ExtensionContext, private git: GitProvider, private annotationController: BlameAnnotationController) {
super(() => this.dispose());
this._showBlameDebounced = Functions.debounce(this._showBlame, 50);
this._onConfigure();
const subscriptions: Disposable[] = [];
@ -104,7 +109,9 @@ export default class BlameStatusBarController extends Disposable {
this._onActiveTextEditorChanged(window.activeTextEditor);
}
private async _onActiveTextEditorChanged(e: TextEditor): Promise<void> {
private _onActiveTextEditorChanged(e: TextEditor) {
this._currentLine = -1;
const previousEditor = this._editor;
previousEditor && previousEditor.setDecorations(activeLineDecoration, []);
@ -129,21 +136,26 @@ export default class BlameStatusBarController extends Disposable {
this._blame = undefined;
}
return await this._showBlame(e.selection.active.line, e);
this._showBlame(e.selection.active.line, e);
}
private async _onEditorSelectionChanged(e: TextEditorSelectionChangeEvent): Promise<void> {
private _onEditorSelectionChanged(e: TextEditorSelectionChangeEvent): void {
// Make sure this is for the editor we are tracking
if (!TextEditorComparer.equals(e.textEditor, this._editor)) return;
return await this._showBlame(e.selections[0].active.line, e.textEditor);
const line = e.selections[0].active.line;
if (line === this._currentLine) return;
this._currentLine = line;
this._showBlameDebounced(line, e.textEditor);
}
private async _onDocumentChanged(e: TextDocumentChangeEvent): Promise<void> {
private _onDocumentChanged(e: TextDocumentChangeEvent) {
// Make sure this is for the editor we are tracking
if (!this._editor || !TextDocumentComparer.equals(e.document, this._editor.document)) return;
this._currentLine = -1;
return await this._showBlame(this._editor.selections[0].active.line, this._editor);
this._showBlame(this._editor.selections[0].active.line, this._editor);
}
private async _showBlame(line: number, editor: TextEditor) {
@ -248,11 +260,21 @@ export default class BlameStatusBarController extends Disposable {
const log = await this.git.getLogForFile(this._uri.fsPath, commit.sha, this._uri.repoPath, undefined, 1);
logCommit = log && log.commits.get(commit.sha);
}
const hoverMessage = BlameAnnotationFormatter.getAnnotationHover(config, blameLine, logCommit || commit);
let hoverMessage: string | string[];
if (activeLine !== 'inline') {
// If the messages match (or we couldn't find the log), then this is a possible duplicate annotation
const possibleDuplicate = !logCommit || logCommit.message === commit.message;
// If we don't have a possible dupe or we aren't showing annotations get the hover message
if (!possibleDuplicate || !this.annotationController.isAnnotating(editor)) {
hoverMessage = BlameAnnotationFormatter.getAnnotationHover(config, blameLine, logCommit || commit);
}
}
let decorationOptions: DecorationOptions;
switch (activeLine) {
case 'both':
case 'inline':
decorationOptions = {
range: editor.document.validateRange(new Range(blameLine.line + offset, 0, blameLine.line + offset, 1000000)),
hoverMessage: hoverMessage,
@ -265,18 +287,6 @@ export default class BlameStatusBarController extends Disposable {
} as DecorationOptions;
break;
case 'inline':
decorationOptions = {
range: editor.document.validateRange(new Range(blameLine.line + offset, 1000000, blameLine.line + offset, 1000000)),
renderOptions: {
after: {
color: 'rgba(153, 153, 153, 0.3)',
contentText: annotation
}
} as DecorationInstanceRenderOptions
} as DecorationOptions;
break;
case 'hover':
decorationOptions = {
range: editor.document.validateRange(new Range(blameLine.line + offset, 0, blameLine.line + offset, 1000000)),

+ 1
- 1
src/extension.ts Zobrazit soubor

@ -62,7 +62,7 @@ export async function activate(context: ExtensionContext) {
const annotationController = new BlameAnnotationController(context, git);
context.subscriptions.push(annotationController);
const statusBarController = new BlameStatusBarController(context, git);
const statusBarController = new BlameStatusBarController(context, git, annotationController);
context.subscriptions.push(statusBarController);
context.subscriptions.push(new DiffWithWorkingCommand(git));

+ 2
- 2
src/system/function.ts Zobrazit soubor

@ -4,11 +4,11 @@ const _once = require('lodash.once');
export interface IDeferred {
cancel(): void;
flush(): void;
flush(...args: any[]): void;
}
export namespace Functions {
export function debounce<T extends Function>(fn: T, wait?: number, options?: any): T & IDeferred {
export function debounce<T extends Function>(fn: T, wait?: number, options?: { leading?: boolean, maxWait?: number, trailing?: boolean }): T & IDeferred {
return _debounce(fn, wait, options);
}

Načítá se…
Zrušit
Uložit