Git - add git blame hover (status bar item, editor decoration) (#234338)

This commit is contained in:
Ladislau Szomoru
2024-11-21 12:21:34 +01:00
committed by GitHub
parent 7bb46ece48
commit 157567fd8f
2 changed files with 56 additions and 5 deletions

View File

@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DecorationOptions, l10n, Position, Range, TextEditor, TextEditorChange, TextEditorDecorationType, TextEditorChangeKind, ThemeColor, Uri, window, workspace, EventEmitter, ConfigurationChangeEvent, StatusBarItem, StatusBarAlignment, Command } from 'vscode';
import { DecorationOptions, l10n, Position, Range, TextEditor, TextEditorChange, TextEditorDecorationType, TextEditorChangeKind, ThemeColor, Uri, window, workspace, EventEmitter, ConfigurationChangeEvent, StatusBarItem, StatusBarAlignment, Command, MarkdownString } from 'vscode';
import { Model } from './model';
import { dispose, fromNow, IDisposable, pathEquals } from './util';
import { Repository } from './repository';
@@ -86,6 +86,41 @@ function processTextEditorChangesWithBlameInformation(blameInformation: BlameInf
return changesWithBlameInformation;
}
function getBlameInformationHover(documentUri: Uri, blameInformation: BlameInformation | string): MarkdownString {
if (typeof blameInformation === 'string') {
return new MarkdownString(blameInformation, true);
}
const markdownString = new MarkdownString();
markdownString.supportThemeIcons = true;
markdownString.isTrusted = true;
if (blameInformation.authorName) {
markdownString.appendMarkdown(`$(account) **${blameInformation.authorName}**`);
if (blameInformation.date) {
const dateString = new Date(blameInformation.date).toLocaleString(undefined, { year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' });
markdownString.appendMarkdown(`, $(history) ${fromNow(blameInformation.date, true, true)} (${dateString})`);
}
markdownString.appendMarkdown('\n\n');
}
markdownString.appendMarkdown(`${blameInformation.message}\n\n`);
markdownString.appendMarkdown(`---\n\n`);
markdownString.appendMarkdown(`[$(eye) View Commit](command:git.blameStatusBarItem.viewCommit?${encodeURIComponent(JSON.stringify([documentUri, blameInformation.id]))})`);
markdownString.appendMarkdown('  |  ');
markdownString.appendMarkdown(`[$(copy) ${blameInformation.id.substring(0, 8)}](command:git.blameStatusBarItem.copyContent?${encodeURIComponent(JSON.stringify(blameInformation.id))})`);
if (blameInformation.message) {
markdownString.appendMarkdown('  ');
markdownString.appendMarkdown(`[$(copy) Message](command:git.blameStatusBarItem.copyContent?${encodeURIComponent(JSON.stringify(blameInformation.message))})`);
}
return markdownString;
}
interface RepositoryBlameInformation {
readonly commit: string; /* commit used for blame information */
readonly blameInformation: Map<Uri, ResourceBlameInformation>;
@@ -314,16 +349,19 @@ class GitBlameEditorDecoration {
const contentText = typeof blame.blameInformation === 'string'
? blame.blameInformation
: `${blame.blameInformation.message ?? ''}, ${blame.blameInformation.authorName ?? ''} (${fromNow(blame.blameInformation.date ?? Date.now(), true, true)})`;
return this._createDecoration(blame.lineNumber, contentText);
const hoverMessage = getBlameInformationHover(textEditor.document.uri, blame.blameInformation);
return this._createDecoration(blame.lineNumber, contentText, hoverMessage);
});
textEditor.setDecorations(this._decorationType, decorations);
}
private _createDecoration(lineNumber: number, contentText: string): DecorationOptions {
private _createDecoration(lineNumber: number, contentText: string, hoverMessage: MarkdownString): DecorationOptions {
const position = new Position(lineNumber, Number.MAX_SAFE_INTEGER);
return {
hoverMessage,
range: new Range(position, position),
renderOptions: {
after: {
@@ -389,6 +427,7 @@ class GitBlameStatusBarItem {
if (!this._statusBarItem) {
this._statusBarItem = window.createStatusBarItem('git.blame', StatusBarAlignment.Right, 200);
this._statusBarItem.name = l10n.t('Git Blame Information');
this._disposables.push(this._statusBarItem);
}
@@ -400,11 +439,14 @@ class GitBlameStatusBarItem {
if (typeof blameInformation[0].blameInformation === 'string') {
this._statusBarItem.text = `$(git-commit) ${blameInformation[0].blameInformation}`;
this._statusBarItem.tooltip = getBlameInformationHover(textEditor.document.uri, blameInformation[0].blameInformation);
this._statusBarItem.command = undefined;
} else {
this._statusBarItem.text = `$(git-commit) ${blameInformation[0].blameInformation.authorName ?? ''} (${fromNow(blameInformation[0].blameInformation.date ?? new Date(), true, true)})`;
this._statusBarItem.tooltip = getBlameInformationHover(textEditor.document.uri, blameInformation[0].blameInformation);
this._statusBarItem.command = {
title: l10n.t('View Commit'),
command: 'git.statusBar.viewCommit',
command: 'git.blameStatusBarItem.viewCommit',
arguments: [textEditor.document.uri, blameInformation[0].blameInformation.id]
} satisfies Command;
}

View File

@@ -4307,7 +4307,7 @@ export class CommandCenter {
env.clipboard.writeText(historyItem.message);
}
@command('git.statusBar.viewCommit', { repository: true })
@command('git.blameStatusBarItem.viewCommit', { repository: true })
async viewStatusBarCommit(repository: Repository, historyItemId: string): Promise<void> {
if (!repository || !historyItemId) {
return;
@@ -4325,6 +4325,15 @@ export class CommandCenter {
await commands.executeCommand('_workbench.openMultiDiffEditor', { multiDiffSourceUri, title, resources });
}
@command('git.blameStatusBarItem.copyContent')
async blameStatusBarCopyContent(content: string): Promise<void> {
if (typeof content !== 'string') {
return;
}
env.clipboard.writeText(content);
}
private createCommand(id: string, key: string, method: Function, options: ScmCommandOptions): (...args: any[]) => any {
const result = (...args: any[]) => {
let result: Promise<any>;