diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fad5d0..4f8b83c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ## [Unreleased] +### Added + +- Adds a `Show in Commit Graph` action to the hovers + +### Changed + +- Changes the `Show Commit` action in the hovers to `Show Details` and opens the _Commit Details_ view + ### Fixed - Fixes Commit Details showing incorrect actions for uncommitted changes diff --git a/src/commands/showCommitsInView.ts b/src/commands/showCommitsInView.ts index 777965f..59f219a 100644 --- a/src/commands/showCommitsInView.ts +++ b/src/commands/showCommitsInView.ts @@ -18,6 +18,13 @@ export interface ShowCommitsInViewCommandArgs { @command() export class ShowCommitsInViewCommand extends ActiveEditorCommand { + static getMarkdownCommandArgs(sha: string, repoPath: string): string; + static getMarkdownCommandArgs(args: ShowCommitsInViewCommandArgs): string; + static getMarkdownCommandArgs(argsOrSha: ShowCommitsInViewCommandArgs | string, repoPath?: string): string { + const args = typeof argsOrSha === 'string' ? { refs: [argsOrSha], repoPath: repoPath } : argsOrSha; + return super.getMarkdownCommandArgsCore<ShowCommitsInViewCommandArgs>(Commands.ShowCommitInView, args); + } + constructor(private readonly container: Container) { super([Commands.ShowCommitInView, Commands.ShowCommitsInView]); } diff --git a/src/git/formatters/commitFormatter.ts b/src/git/formatters/commitFormatter.ts index 706c9ec..88b3b00 100644 --- a/src/git/formatters/commitFormatter.ts +++ b/src/git/formatters/commitFormatter.ts @@ -11,7 +11,7 @@ import { DiffWithCommand, OpenCommitOnRemoteCommand, OpenFileAtRevisionCommand, - ShowQuickCommitCommand, + ShowCommitsInViewCommand, ShowQuickCommitFileCommand, } from '../../commands'; import { Command } from '../../commands/base'; @@ -19,6 +19,7 @@ import { configuration, DateStyle, FileAnnotationType } from '../../configuratio import { Commands, GlyphChars } from '../../constants'; import { Container } from '../../container'; import { emojify } from '../../emojis'; +import type { ShowCommitInGraphCommandArgs } from '../../plus/webviews/graph/graphWebview'; import { join, map } from '../../system/iterable'; import { PromiseCancelledError } from '../../system/promise'; import type { TokenOptions } from '../../system/string'; @@ -283,14 +284,17 @@ export class CommitFormatter extends Formatter<GitCommit, CommitFormatOptions> { if (this._item.isUncommitted) { const { previousLineComparisonUris: diffUris } = this._options; if (diffUris?.previous != null) { - commands = `\`${this._padOrTruncate( + commands = `[\`${this._padOrTruncate( GitRevision.shorten( GitRevision.isUncommittedStaged(diffUris.current.sha) ? diffUris.current.sha : GitRevision.uncommitted, )!, this._options.tokenOptions.commands, - )}\``; + )}\`](${ShowCommitsInViewCommand.getMarkdownCommandArgs( + this._item.sha, + this._item.repoPath, + )} "Show Details")`; commands += ` [$(chevron-left)$(compare-changes)](${DiffWithCommand.getMarkdownCommandArgs({ lhs: { @@ -311,12 +315,15 @@ export class CommitFormatter extends Formatter<GitCommit, CommitFormatOptions> { this._options.editor?.line, )} "Open Blame Prior to this Change")`; } else { - commands = `\`${this._padOrTruncate( + commands = `[\`${this._padOrTruncate( GitRevision.shorten( this._item.isUncommittedStaged ? GitRevision.uncommittedStaged : GitRevision.uncommitted, )!, this._options.tokenOptions.commands, - )}\``; + )}\`](${ShowCommitsInViewCommand.getMarkdownCommandArgs( + this._item.sha, + this._item.repoPath, + )} "Show Details")`; } return commands; @@ -324,9 +331,10 @@ export class CommitFormatter extends Formatter<GitCommit, CommitFormatOptions> { const separator = ' | '; - commands = `---\n\n[\`$(git-commit) ${this.id}\`](${ShowQuickCommitCommand.getMarkdownCommandArgs( + commands = `---\n\n[\`$(git-commit) ${this.id}\`](${ShowCommitsInViewCommand.getMarkdownCommandArgs( this._item.sha, - )} "Show Commit")`; + this._item.repoPath, + )} "Show Details")`; commands += ` [$(chevron-left)$(compare-changes)](${DiffWithCommand.getMarkdownCommandArgs( this._item, @@ -346,6 +354,11 @@ export class CommitFormatter extends Formatter<GitCommit, CommitFormatOptions> { )} "Open Blame Prior to this Change")`; } + commands += ` [$(gitlens-graph)](${Command.getMarkdownCommandArgsCore<ShowCommitInGraphCommandArgs>( + Commands.ShowCommitInGraph, + { sha: this._item.sha, repoPath: this._item.repoPath }, + )} "Show in Commit Graph")`; + if (this._options.remotes != null && this._options.remotes.length !== 0) { const providers = GitRemote.getHighlanderProviders(this._options.remotes); @@ -478,9 +491,10 @@ export class CommitFormatter extends Formatter<GitCommit, CommitFormatOptions> { if (!this._options.markdown) return this.id; const sha = this._padOrTruncate(this._item.shortSha ?? '', this._options.tokenOptions.id); - const link = `[\`$(git-commit) ${sha}\`](${ShowQuickCommitCommand.getMarkdownCommandArgs( + const link = `[\`$(git-commit) ${sha}\`](${ShowCommitsInViewCommand.getMarkdownCommandArgs( this._item.sha, - )} "Show Commit")`; + this._item.repoPath, + )} "Show Details")`; return this._padOrTruncate(link, this._options.tokenOptions.link); } diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index 1cbeb71..cec56af 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -51,7 +51,7 @@ import { RepositoryVisibility } from './gitProvider'; import type { GitUri } from './gitUri'; import type { GitBlame, GitBlameLine, GitBlameLines } from './models/blame'; import type { BranchSortOptions, GitBranch } from './models/branch'; -import type { GitCommit } from './models/commit'; +import { GitCommit, GitCommitIdentity } from './models/commit'; import type { GitContributor } from './models/contributor'; import type { GitDiff, GitDiffFilter, GitDiffHunkLine, GitDiffShortStat } from './models/diff'; import type { GitFile } from './models/file'; @@ -1309,8 +1309,27 @@ export class GitProviderService implements Disposable { } @log() - getCommit(repoPath: string | Uri, ref: string): Promise<GitCommit | undefined> { + async getCommit(repoPath: string | Uri, ref: string): Promise<GitCommit | undefined> { const { provider, path } = this.getProvider(repoPath); + + if (ref === GitRevision.uncommitted || ref === GitRevision.uncommittedStaged) { + const now = new Date(); + const user = await this.getCurrentUser(repoPath); + return new GitCommit( + this.container, + path, + ref, + new GitCommitIdentity('You', user?.email ?? undefined, now), + new GitCommitIdentity('You', user?.email ?? undefined, now), + 'Uncommitted changes', + [], + 'Uncommitted changes', + undefined, + undefined, + [], + ); + } + return provider.getCommit(path, ref); } diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index 3614e0e..6e293bd 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -43,6 +43,7 @@ import { export interface ShowCommitInGraphCommandArgs { repoPath: string; sha: string; + preserveFocus?: boolean; } export interface GraphSelectionChangeEvent { @@ -116,7 +117,7 @@ export class GraphWebview extends WebviewBase<State> { this._selectedSha = args.sha; if (this._panel == null) { - void this.show(); + void this.show({ preserveFocus: args.preserveFocus }); } else { if (this._ids.has(args.sha)) { void this.notifyDidChangeSelection(); @@ -131,7 +132,7 @@ export class GraphWebview extends WebviewBase<State> { this.onConfigurationChanged(); } - override async show(column: ViewColumn = ViewColumn.Active, ...args: unknown[]): Promise<void> { + override async show(options?: { column?: ViewColumn; preserveFocus?: boolean }, ...args: unknown[]): Promise<void> { if (!(await ensurePlusFeaturesEnabled())) return; if (this.container.git.repositoryCount > 1) { @@ -152,7 +153,7 @@ export class GraphWebview extends WebviewBase<State> { } } - return super.show(column, ...args); + return super.show({ column: ViewColumn.Active, ...options }, ...args); } protected override refresh(force?: boolean): Promise<void> { diff --git a/src/plus/webviews/timeline/timelineWebview.ts b/src/plus/webviews/timeline/timelineWebview.ts index 8dfc3c0..a49912d 100644 --- a/src/plus/webviews/timeline/timelineWebview.ts +++ b/src/plus/webviews/timeline/timelineWebview.ts @@ -1,6 +1,6 @@ 'use strict'; -import type { Disposable, TextEditor } from 'vscode'; -import { Uri, ViewColumn, window } from 'vscode'; +import type { Disposable, TextEditor, ViewColumn } from 'vscode'; +import { Uri, window } from 'vscode'; import { GitActions } from '../../../commands/gitCommands.actions'; import { configuration } from '../../../configuration'; import { Commands, ContextKeys } from '../../../constants'; @@ -60,10 +60,10 @@ export class TimelineWebview extends WebviewBase<State> { }; } - override async show(column: ViewColumn = ViewColumn.Beside, ...args: unknown[]): Promise<void> { + override async show(options?: { column?: ViewColumn; preserveFocus?: boolean }, ...args: unknown[]): Promise<void> { if (!(await ensurePlusFeaturesEnabled())) return; - return super.show(column, ...args); + return super.show(options, ...args); } protected override onInitializing(): Disposable[] | undefined { diff --git a/src/webviews/webviewBase.ts b/src/webviews/webviewBase.ts index 4a3e012..61063a5 100644 --- a/src/webviews/webviewBase.ts +++ b/src/webviews/webviewBase.ts @@ -75,9 +75,10 @@ export abstract class WebviewBase<State> implements Disposable { } @log({ args: false }) - async show(column: ViewColumn = ViewColumn.Beside, ..._args: unknown[]): Promise<void> { + async show(options?: { column?: ViewColumn; preserveFocus?: boolean }, ..._args: unknown[]): Promise<void> { void this.container.usage.track(`${this.trackingFeature}:shown`); + let column = options?.column ?? ViewColumn.Beside; // Only try to open beside if there is an active tab if (column === ViewColumn.Beside && window.tabGroups.activeTabGroup.activeTab == null) { column = ViewColumn.Active; @@ -87,7 +88,7 @@ export abstract class WebviewBase<State> implements Disposable { this._panel = window.createWebviewPanel( this.id, this._title, - { viewColumn: column, preserveFocus: false }, + { viewColumn: column, preserveFocus: options?.preserveFocus ?? false }, { retainContextWhenHidden: true, enableFindWidget: true, @@ -109,7 +110,7 @@ export abstract class WebviewBase<State> implements Disposable { this._panel.webview.html = await this.getHtml(this._panel.webview); } else { await this.refresh(true); - this._panel.reveal(this._panel.viewColumn ?? ViewColumn.Active, false); + this._panel.reveal(this._panel.viewColumn ?? ViewColumn.Active, options?.preserveFocus ?? false); } }