Skip to content

Commit 677b9eb

Browse files
committed
Improves commit & stash tooltips
Improves tips in labels & tooltips - Adds remote icons to tips rendering
1 parent 5923e8f commit 677b9eb

File tree

13 files changed

+189
-62
lines changed

13 files changed

+189
-62
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
1111
- Adds a new `counts` option to the `gitlens.launchpad.indicator.label` setting to show the status counts of items which need your attention in the _Launchpad_ status bar indicator
1212
- Adds _Search for Commits within Selection_ command to the editor context menu when there is a selection
1313
- Adds a `gitlens.launchpad.ignoredOrganizations` setting to specify an array of organizations (or users) to ignore in the _Launchpad_
14+
- Improves the tooltips of stashes in GitLens views
15+
- Adds a `gitlens.views.formats.stashes.tooltip` setting to specify the tooltip format of the stashes in GitLens views
16+
- Improves the display of branch and tag tips in the _File History_ and _Line History_ and in commit tooltips in GitLens views
17+
- Adds provider-specific icons to tips of remote branches
1418

1519
### Changed
1620

package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@
650650
},
651651
"gitlens.views.formats.commits.tooltip": {
652652
"type": "string",
653-
"default": "${link}${' via 'pullRequest}${'  •  'changesDetail}${'    'tips}\n\n${avatar}  __${author}__, ${ago}   _(${date})_ \n\n${message}${\n\n---\n\nfootnotes}",
653+
"default": "${link}${'  •  'changesDetail}${'    'tips} \\\n${avatar}  __${author}__, ${ago}${' via 'pullRequest}   _(${date})_ \n\n${message}${\n\n---\n\nfootnotes}",
654654
"markdownDescription": "Specifies the tooltip format (in markdown) of commits in the views. See [_Commit Tokens_](https://github.com/eamodio/vscode-gitlens/wiki/Custom-Formatting#commit-tokens) in the GitLens docs",
655655
"scope": "window",
656656
"order": 32
@@ -690,6 +690,13 @@
690690
"scope": "window",
691691
"order": 51
692692
},
693+
"gitlens.views.formats.stashes.tooltip": {
694+
"type": "string",
695+
"default": "${link}${' on `'stashOnRef`}${'  •  'changesDetail} \\\n  ${ago}   _(${date})_ \n\n${message}${\n\n---\n\nfootnotes}",
696+
"markdownDescription": "Specifies the tooltip format (in markdown) of stashes in the views. See [_Commit Tokens_](https://github.com/eamodio/vscode-gitlens/wiki/Custom-Formatting#commit-tokens) in the GitLens docs",
697+
"scope": "window",
698+
"order": 52
699+
},
693700
"gitlens.views.openChangesInMultiDiffEditor": {
694701
"type": "boolean",
695702
"default": true,

src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,7 @@ export interface ViewsCommonConfig {
596596
readonly stashes: {
597597
readonly label: string;
598598
readonly description: string;
599+
readonly tooltip: string;
599600
};
600601
};
601602
readonly openChangesInMultiDiffEditor: boolean;

src/env/node/git/localGitProvider.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ import type { GitFile, GitFileStatus } from '../../../git/models/file';
8181
import { GitFileChange } from '../../../git/models/file';
8282
import type {
8383
GitGraph,
84-
GitGraphHostingServiceType,
8584
GitGraphRow,
8685
GitGraphRowContexts,
8786
GitGraphRowHead,
@@ -2569,7 +2568,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
25692568
avatarUrl: avatarUrl,
25702569
context: serializeWebviewItemContext<GraphItemRefContext>(context),
25712570
current: tip === headRefUpstreamName,
2572-
hostingServiceType: remote.provider?.id as GitGraphHostingServiceType,
2571+
hostingServiceType: remote.provider?.gkProviderId,
25732572
};
25742573
refRemoteHeads.push(refRemoteHead);
25752574

src/git/formatters/commitFormatter.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { encodeHtmlWeak, escapeMarkdown, getSuperscript } from '../../system/str
2929
import type { ContactPresence } from '../../vsls/vsls';
3030
import type { PreviousLineComparisonUrisResult } from '../gitProvider';
3131
import type { GitCommit } from '../models/commit';
32-
import { isCommit } from '../models/commit';
32+
import { isCommit, isStash } from '../models/commit';
3333
import { uncommitted, uncommittedStaged } from '../models/constants';
3434
import { getIssueOrPullRequestMarkdownIcon } from '../models/issue';
3535
import type { PullRequest } from '../models/pullRequest';
@@ -585,28 +585,41 @@ export class CommitFormatter extends Formatter<GitCommit, CommitFormatOptions> {
585585
}
586586

587587
get link(): string {
588+
let icon;
589+
let label;
590+
if (isStash(this._item)) {
591+
icon = 'archive';
592+
label = this._padOrTruncate(
593+
`Stash${this._item.number ? ` #${this._item.number}` : ''}`,
594+
this._options.tokenOptions.link,
595+
);
596+
} else {
597+
icon = this._item.sha != null && !this._item.isUncommitted ? 'git-commit' : '';
598+
label = this._padOrTruncate(
599+
shortenRevision(this._item.sha ?? '', { strings: { working: 'Working Tree' } }),
600+
this._options.tokenOptions.id,
601+
);
602+
}
603+
588604
let link;
589605
switch (this._options.outputFormat) {
590-
case 'markdown': {
591-
const sha = this._padOrTruncate(this._item.shortSha ?? '', this._options.tokenOptions.id);
592-
link = `[\`$(git-commit) ${sha}\`](${InspectCommand.getMarkdownCommandArgs(
593-
this._item.sha,
594-
this._item.repoPath,
595-
)} "Inspect Commit Details")`;
606+
case 'markdown':
607+
icon = icon ? `$(${icon}) ` : '';
608+
link = `[\`${icon}${label}\`](${InspectCommand.getMarkdownCommandArgs({
609+
ref: getReferenceFromRevision(this._item),
610+
})} "Inspect Commit Details")`;
596611
break;
597-
}
598-
case 'html': {
599-
const sha = this._padOrTruncate(this._item.shortSha ?? '', this._options.tokenOptions.id);
600-
link = /*html*/ `<a href="${InspectCommand.getMarkdownCommandArgs(
601-
this._item.sha,
602-
this._item.repoPath,
603-
)}" title="Inspect Commit Details"${
612+
case 'html':
613+
icon = icon ? `<span class="codicon codicon-${icon}"></span>` : '';
614+
link = /*html*/ `<a href="${InspectCommand.getMarkdownCommandArgs({
615+
ref: getReferenceFromRevision(this._item),
616+
})}" title="Inspect Commit Details"${
604617
this._options.htmlFormat?.classes?.link ? ` class="${this._options.htmlFormat.classes.link}"` : ''
605-
}><span class="codicon codicon-git-commit"></span>${sha}</a>`;
618+
}>${icon}${label}</a>`;
606619
break;
607-
}
608620
default:
609-
return this.id;
621+
link = this.id;
622+
break;
610623
}
611624

612625
return this._padOrTruncate(link, this._options.tokenOptions.link);

src/git/gitProviderService.ts

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ import type { GitBranchReference, GitReference } from './models/reference';
6969
import { createRevisionRange, isSha, isUncommitted, isUncommittedParent } from './models/reference';
7070
import type { GitReflog } from './models/reflog';
7171
import type { GitRemote } from './models/remote';
72-
import { getVisibilityCacheKey } from './models/remote';
72+
import { getRemoteThemeIconString, getVisibilityCacheKey } from './models/remote';
7373
import type { RepositoryChangeEvent } from './models/repository';
7474
import { Repository, RepositoryChange, RepositoryChangeComparisonMode } from './models/repository';
7575
import type { GitStash } from './models/stash';
@@ -1605,60 +1605,69 @@ export class GitProviderService implements Disposable {
16051605
@log()
16061606
async getBranchesAndTagsTipsFn(
16071607
repoPath: string | Uri | undefined,
1608-
currentName?: string,
1608+
suppressName?: string,
16091609
): Promise<
16101610
(sha: string, options?: { compact?: boolean | undefined; icons?: boolean | undefined }) => string | undefined
16111611
> {
1612-
const [branchesResult, tagsResult] = await Promise.allSettled([
1612+
if (repoPath == null) return () => undefined;
1613+
1614+
const [branchesResult, tagsResult, remotesResult] = await Promise.allSettled([
16131615
this.getBranches(repoPath),
16141616
this.getTags(repoPath),
1617+
this.getRemotes(repoPath),
16151618
]);
16161619

16171620
const branches = getSettledValue(branchesResult)?.values ?? [];
16181621
const tags = getSettledValue(tagsResult)?.values ?? [];
1622+
const remotes = getSettledValue(remotesResult) ?? [];
16191623

16201624
const branchesAndTagsBySha = groupByFilterMap(
16211625
(branches as (GitBranch | GitTag)[]).concat(tags as (GitBranch | GitTag)[]),
16221626
bt => bt.sha,
16231627
bt => {
1624-
if (currentName) {
1625-
if (bt.name === currentName) return undefined;
1626-
if (bt.refType === 'branch' && bt.getNameWithoutRemote() === currentName) {
1627-
return { name: bt.name, compactName: bt.getRemoteName(), type: bt.refType };
1628+
let icon;
1629+
if (bt.refType === 'branch') {
1630+
if (bt.remote) {
1631+
const remote = remotes.find(r => r.name === bt.getRemoteName());
1632+
icon = `$(${getRemoteThemeIconString(remote)}) `;
1633+
} else {
1634+
icon = '$(git-branch) ';
16281635
}
1636+
} else {
1637+
icon = '$(tag) ';
16291638
}
16301639

1631-
return { name: bt.name, compactName: undefined, type: bt.refType };
1640+
return {
1641+
name: bt.name,
1642+
icon: icon,
1643+
compactName:
1644+
suppressName && bt.refType === 'branch' && bt.getNameWithoutRemote() === suppressName
1645+
? bt.getRemoteName()
1646+
: undefined,
1647+
type: bt.refType,
1648+
};
16321649
},
16331650
);
16341651

16351652
return (sha: string, options?: { compact?: boolean; icons?: boolean }): string | undefined => {
16361653
const branchesAndTags = branchesAndTagsBySha.get(sha);
1637-
if (branchesAndTags == null || branchesAndTags.length === 0) return undefined;
1654+
if (!branchesAndTags?.length) return undefined;
1655+
1656+
const tips =
1657+
suppressName && options?.compact
1658+
? branchesAndTags.filter(bt => bt.name !== suppressName)
1659+
: branchesAndTags;
16381660

16391661
if (!options?.compact) {
1640-
return branchesAndTags
1641-
.map(
1642-
bt => `${options?.icons ? `${bt.type === 'tag' ? '$(tag)' : '$(git-branch)'} ` : ''}${bt.name}`,
1643-
)
1644-
.join(', ');
1662+
return tips.map(bt => `${options?.icons ? bt.icon : ''}${bt.name}`).join(', ');
16451663
}
16461664

1647-
if (branchesAndTags.length > 1) {
1648-
const [bt] = branchesAndTags;
1649-
return `${options?.icons ? `${bt.type === 'tag' ? '$(tag)' : '$(git-branch)'} ` : ''}${
1650-
bt.compactName ?? bt.name
1651-
}, ${GlyphChars.Ellipsis}`;
1665+
if (tips.length > 1) {
1666+
const [bt] = tips;
1667+
return `${options?.icons ? bt.icon : ''}${bt.compactName ?? bt.name}, ${GlyphChars.Ellipsis}`;
16521668
}
16531669

1654-
return branchesAndTags
1655-
.map(
1656-
bt =>
1657-
`${options?.icons ? `${bt.type === 'tag' ? '$(tag)' : '$(git-branch)'} ` : ''}${
1658-
bt.compactName ?? bt.name
1659-
}`,
1660-
)
1661-
.join(', ');
1670+
return tips.map(bt => `${options?.icons ? bt.icon : ''}${bt.compactName ?? bt.name}`).join(', ');
16621671
};
16631672
}
16641673

src/git/models/graph.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import type {
77
RowStats,
88
Tag,
99
} from '@gitkraken/gitkraken-components';
10+
import type { GkProviderId } from '../../gk/models/repositoryIdentities';
11+
import type { Brand, Unbrand } from '../../system/brand';
1012
import type { GitBranch } from './branch';
1113
import type { GitRemote } from './remote';
1214

@@ -64,3 +66,44 @@ export interface GitGraph {
6466
}
6567

6668
export type GitGraphRowsStats = Map<string, GitGraphRowStats>;
69+
70+
export function convertHostingServiceTypeToGkProviderId(type: GitGraphHostingServiceType): GkProviderId | undefined {
71+
switch (type) {
72+
case 'github':
73+
return 'github' satisfies Unbrand<GkProviderId> as Brand<GkProviderId>;
74+
case 'githubEnterprise':
75+
return 'githubEnterprise' satisfies Unbrand<GkProviderId> as Brand<GkProviderId>;
76+
case 'gitlab':
77+
return 'gitlab' satisfies Unbrand<GkProviderId> as Brand<GkProviderId>;
78+
case 'gitlabSelfHosted':
79+
return 'gitlabSelfHosted' satisfies Unbrand<GkProviderId> as Brand<GkProviderId>;
80+
case 'bitbucket':
81+
return 'bitbucket' satisfies Unbrand<GkProviderId> as Brand<GkProviderId>;
82+
case 'bitbucketServer':
83+
return 'bitbucketServer' satisfies Unbrand<GkProviderId> as Brand<GkProviderId>;
84+
case 'azureDevops':
85+
return 'azureDevops' satisfies Unbrand<GkProviderId> as Brand<GkProviderId>;
86+
default:
87+
return undefined;
88+
}
89+
}
90+
91+
export function getGkProviderThemeIconString(
92+
providerIdOrHostingType: GkProviderId | GitGraphHostingServiceType | undefined,
93+
): string {
94+
switch (providerIdOrHostingType) {
95+
case 'azureDevops':
96+
return 'gitlens-provider-azdo';
97+
case 'bitbucket':
98+
case 'bitbucketServer':
99+
return 'gitlens-provider-bitbucket';
100+
case 'github':
101+
case 'githubEnterprise':
102+
return 'gitlens-provider-github';
103+
case 'gitlab':
104+
case 'gitlabSelfHosted':
105+
return 'gitlens-provider-gitlab';
106+
default:
107+
return 'cloud';
108+
}
109+
}

src/git/models/remote.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { equalsIgnoreCase, sortCompare } from '../../system/string';
88
import { isLightTheme } from '../../system/utils';
99
import { parseGitRemoteUrl } from '../parsers/remoteParser';
1010
import type { RemoteProvider } from '../remotes/remoteProvider';
11+
import { getRemoteProviderThemeIconString } from '../remotes/remoteProvider';
1112

1213
export type GitRemoteType = 'fetch' | 'push';
1314

@@ -163,6 +164,10 @@ export function getRemoteIconUri(
163164
return asWebviewUri != null ? asWebviewUri(uri) : uri;
164165
}
165166

167+
export function getRemoteThemeIconString(remote: GitRemote | undefined): string {
168+
return getRemoteProviderThemeIconString(remote?.provider);
169+
}
170+
166171
export function getRemoteUpstreamDescription(remote: GitRemote): string {
167172
const arrows = getRemoteArrowsGlyph(remote);
168173

src/git/remotes/remoteProvider.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,7 @@ export abstract class RemoteProvider<T extends ResourceDescriptor = ResourceDesc
193193
return urls;
194194
}
195195
}
196+
197+
export function getRemoteProviderThemeIconString(provider: RemoteProvider | undefined): string {
198+
return provider != null ? `gitlens-provider-${provider.icon}` : 'cloud';
199+
}

src/plus/integrations/providers/github/githubGitProvider.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ import type { GitFile } from '../../../../git/models/file';
4949
import { GitFileChange, GitFileIndexStatus } from '../../../../git/models/file';
5050
import type {
5151
GitGraph,
52-
GitGraphHostingServiceType,
5352
GitGraphRow,
5453
GitGraphRowContexts,
5554
GitGraphRowHead,
@@ -1424,7 +1423,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
14241423
avatarUrl: avatarUrl,
14251424
context: serializeWebviewItemContext<GraphItemRefContext>(context),
14261425
current: true,
1427-
hostingServiceType: remote.provider?.id as GitGraphHostingServiceType,
1426+
hostingServiceType: remote.provider?.gkProviderId,
14281427
},
14291428
];
14301429

@@ -1476,7 +1475,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
14761475
url: remote.url,
14771476
avatarUrl: avatarUrl,
14781477
context: serializeWebviewItemContext<GraphItemRefContext>(context),
1479-
hostingServiceType: remote.provider?.id as GitGraphHostingServiceType,
1478+
hostingServiceType: remote.provider?.gkProviderId,
14801479
});
14811480
}
14821481
}

0 commit comments

Comments
 (0)