Skip to content

Commit

Permalink
Adds context menus to the Graph (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
eamodio committed Sep 27, 2022
1 parent 379d83e commit 9bb1012
Show file tree
Hide file tree
Showing 6 changed files with 411 additions and 18 deletions.
133 changes: 133 additions & 0 deletions package.json
Expand Up @@ -6249,6 +6249,56 @@
"command": "gitlens.disableDebugLogging",
"title": "Disable Debug Logging",
"category": "GitLens"
},
{
"command": "gitlens.graph.switchToAnotherBranch",
"title": "Switch to Another Branch...",
"category": "GitLens",
"icon": "$(gitlens-switch)"
},
{
"command": "gitlens.graph.switchToBranch",
"title": "Switch to Branch...",
"category": "GitLens",
"icon": "$(gitlens-switch)"
},
{
"command": "gitlens.graph.switchToCommit",
"title": "Switch to Commit...",
"category": "GitLens",
"icon": "$(gitlens-switch)"
},
{
"command": "gitlens.graph.switchToTag",
"title": "Switch to Tag...",
"category": "GitLens",
"icon": "$(gitlens-switch)"
},
{
"command": "gitlens.graph.rebaseOntoCommit",
"title": "Rebase Current Branch onto Commit...",
"category": "GitLens"
},
{
"command": "gitlens.graph.resetCommit",
"title": "Reset Current Branch to Previous Commit...",
"category": "GitLens"
},
{
"command": "gitlens.graph.resetToCommit",
"title": "Reset Current Branch to Commit...",
"category": "GitLens"
},
{
"command": "gitlens.graph.revert",
"title": "Revert Commit...",
"category": "GitLens"
},
{
"command": "gitlens.graph.undoCommit",
"title": "Undo Commit",
"category": "GitLens",
"icon": "$(discard)"
}
],
"icons": {
Expand Down Expand Up @@ -8036,6 +8086,42 @@
"command": "gitlens.views.worktrees.setShowBranchPullRequestOff",
"when": "false"
},
{
"command": "gitlens.graph.switchToAnotherBranch",
"when": "false"
},
{
"command": "gitlens.graph.switchToBranch",
"when": "false"
},
{
"command": "gitlens.graph.switchToCommit",
"when": "false"
},
{
"command": "gitlens.graph.switchToTag",
"when": "false"
},
{
"command": "gitlens.graph.rebaseOntoCommit",
"when": "false"
},
{
"command": "gitlens.graph.resetCommit",
"when": "false"
},
{
"command": "gitlens.graph.resetToCommit",
"when": "false"
},
{
"command": "gitlens.graph.revert",
"when": "false"
},
{
"command": "gitlens.graph.undoCommit",
"when": "false"
},
{
"command": "gitlens.enableDebugLogging",
"when": "config.gitlens.outputLevel != debug"
Expand Down Expand Up @@ -10467,6 +10553,53 @@
"group": "1_gitlens@0"
}
],
"webview/context": [
{
"command": "gitlens.graph.switchToAnotherBranch",
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?=.*?\\b\\+current\\b)/",
"group": "1_gitlens_actions@1"
},
{
"command": "gitlens.graph.switchToBranch",
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:branch\\b(?!.*?\\b\\+current\\b)/",
"group": "1_gitlens_actions@1"
},
{
"command": "gitlens.graph.undoCommit",
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:commit\\b(?=.*?\\b\\+HEAD\\b)/",
"group": "1_gitlens_actions@1"
},
{
"command": "gitlens.graph.revert",
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:commit\\b(?=.*?\\b\\+current\\b)/",
"group": "1_gitlens_actions@3"
},
{
"command": "gitlens.graph.resetToCommit",
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:commit\\b(?=.*?\\b\\+current\\b)/",
"group": "1_gitlens_actions@4"
},
{
"command": "gitlens.graph.resetCommit",
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:commit\\b(?=.*?\\b\\+current\\b)/",
"group": "1_gitlens_actions@5"
},
{
"command": "gitlens.graph.rebaseOntoCommit",
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:commit\\b/",
"group": "1_gitlens_actions@6"
},
{
"command": "gitlens.graph.switchToCommit",
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:commit\\b/",
"group": "1_gitlens_actions@7"
},
{
"command": "gitlens.graph.switchToTag",
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:tag\\b/",
"group": "1_gitlens_actions@1"
}
],
"gitlens/commit/browse": [
{
"command": "gitlens.views.browseRepoAtRevision",
Expand Down
108 changes: 95 additions & 13 deletions src/env/node/git/localGitProvider.ts
Expand Up @@ -60,6 +60,7 @@ import { GitFileChange } from '../../../git/models/file';
import type {
GitGraph,
GitGraphRow,
GitGraphRowContexts,
GitGraphRowHead,
GitGraphRowRemoteHead,
GitGraphRowTag,
Expand Down Expand Up @@ -118,6 +119,7 @@ import {
showGitMissingErrorMessage,
showGitVersionUnsupportedErrorMessage,
} from '../../../messages';
import type { GraphItemContext, GraphItemRefContext } from '../../../plus/webviews/graph/graphWebview';
import { countStringLength, filterMap } from '../../../system/array';
import { TimedCancellationSource } from '../../../system/cancellation';
import { gate } from '../../../system/decorators/gate';
Expand All @@ -140,6 +142,7 @@ import { any, fastestSettled, getSettledValue } from '../../../system/promise';
import { equalsIgnoreCase, getDurationMilliseconds, interpolate, md5, splitSingle } from '../../../system/string';
import { PathTrie } from '../../../system/trie';
import { compare, fromString } from '../../../system/version';
import { serializeWebviewItemContext } from '../../../system/webview';
import type { CachedBlame, CachedDiff, CachedLog, TrackedDocument } from '../../../trackers/gitDocumentTracker';
import { GitDocumentState } from '../../../trackers/gitDocumentTracker';
import type { Git } from './git';
Expand Down Expand Up @@ -1731,12 +1734,15 @@ export class LocalGitProvider implements GitProvider, Disposable {
const rows: GitGraphRow[] = [];

let current = false;
let headCommit = false;
let refHeads: GitGraphRowHead[];
let refRemoteHeads: GitGraphRowRemoteHead[];
let refTags: GitGraphRowTag[];
let parents: string[];
let remoteName: string;
let isStashCommit: boolean;
let stashCommit: GitStashCommit | undefined;
let tag: GitGraphRowTag;
let contexts: GitGraphRowContexts | undefined;

let count = 0;

Expand All @@ -1753,24 +1759,40 @@ export class LocalGitProvider implements GitProvider, Disposable {
refHeads = [];
refRemoteHeads = [];
refTags = [];
contexts = undefined;
headCommit = false;

if (commit.tips) {
for (let tip of commit.tips.split(', ')) {
if (tip === 'refs/stash') continue;

if (tip.startsWith('tag: ')) {
refTags.push({
tag = {
name: tip.substring(5),
// Not currently used, so don't bother looking it up
annotated: true,
};
tag.context = serializeWebviewItemContext<GraphItemRefContext>({
webviewItem: 'gitlens:tag',
webviewItemValue: {
type: 'tag',
ref: GitReference.create(tag.name, repoPath, {
refType: 'tag',
name: tag.name,
}),
},
});
refTags.push(tag);

continue;
}

current = tip.startsWith('HEAD');
if (current && tip !== 'HEAD') {
tip = tip.substring(8);
if (current) {
headCommit = true;
if (tip !== 'HEAD') {
tip = tip.substring(8);
}
}

remoteName = getRemoteNameFromBranchName(tip);
Expand All @@ -1788,6 +1810,18 @@ export class LocalGitProvider implements GitProvider, Disposable {
remote.provider?.avatarUri ??
getRemoteIconUri(this.container, remote, asWebviewUri)
)?.toString(true),
context: serializeWebviewItemContext<GraphItemRefContext>({
webviewItem: 'gitlens:branch+remote',
webviewItemValue: {
type: 'branch',
ref: GitReference.create(branchName, repoPath, {
refType: 'branch',
name: branchName,
remote: true,
upstream: remote.name,
}),
},
}),
});

continue;
Expand All @@ -1797,23 +1831,69 @@ export class LocalGitProvider implements GitProvider, Disposable {
refHeads.push({
name: tip,
isCurrentHead: current,
// TODO@eamodio Add +tracking
context: serializeWebviewItemContext<GraphItemRefContext>({
webviewItem: `gitlens:branch${current ? '+current' : ''}`,
webviewItemValue: {
type: 'branch',
ref: GitReference.create(tip, repoPath, {
refType: 'branch',
name: tip,
remote: false,
// upstream: undefined,
}),
},
}),
});
}
}

isStashCommit = stash?.commits.has(commit.sha) ?? false;
stashCommit = stash?.commits.get(commit.sha);

contexts = {};
if (stashCommit != null) {
contexts.row = serializeWebviewItemContext<GraphItemRefContext>({
webviewItem: 'gitlens:stash',
webviewItemValue: {
type: 'stash',
ref: GitReference.create(commit.sha, repoPath, {
refType: 'stash',
name: stashCommit.name,
number: stashCommit.number,
}),
},
});
} else {
contexts.row = serializeWebviewItemContext<GraphItemRefContext>({
webviewItem: `gitlens:commit${headCommit ? '+HEAD' : ''}${true ? '+current' : ''}`,
webviewItemValue: {
type: 'commit',
ref: GitReference.create(commit.sha, repoPath, {
refType: 'revision',
message: commit.message,
}),
},
});
contexts.avatar = serializeWebviewItemContext<GraphItemContext>({
webviewItem: 'gitlens:avatar',
webviewItemValue: {
type: 'avatar',
email: commit.authorEmail,
},
});
}

parents = commit.parents ? commit.parents.split(' ') : [];
// Remove the second & third parent, if exists, from each stash commit as it is a Git implementation for the index and untracked files
if (isStashCommit && parents.length > 1) {
if (stashCommit != null && parents.length > 1) {
// Skip the "index commit" (e.g. contains staged files) of the stash
skipStashParents.add(parents[1]);
// Skip the "untracked commit" (e.g. contains untracked files) of the stash
skipStashParents.add(parents[2]);
parents.splice(1, 2);
}

if (!isStashCommit && !avatars.has(commit.authorEmail)) {
if (stashCommit == null && !avatars.has(commit.authorEmail)) {
const uri = getCachedAvatarUri(commit.authorEmail);
if (uri != null) {
avatars.set(commit.authorEmail, uri.toString(true));
Expand All @@ -1824,18 +1904,20 @@ export class LocalGitProvider implements GitProvider, Disposable {
sha: commit.sha,
parents: parents,
author: commit.author,
email: commit.authorEmail ?? '',
email: commit.authorEmail,
date: Number(ordering === 'author-date' ? commit.authorDate : commit.committerDate) * 1000,
message: emojify(commit.message.trim()),
// TODO: review logic for stash, wip, etc
type: isStashCommit
? GitGraphRowType.Stash
: parents.length > 1
? GitGraphRowType.MergeCommit
: GitGraphRowType.Commit,
type:
stashCommit != null
? GitGraphRowType.Stash
: parents.length > 1
? GitGraphRowType.MergeCommit
: GitGraphRowType.Commit,
heads: refHeads,
remotes: refRemoteHeads,
tags: refTags,
contexts: contexts,
});
}

Expand Down
4 changes: 3 additions & 1 deletion src/git/models/graph.ts
@@ -1,8 +1,9 @@
import type { GraphRow, Head, Remote, Tag } from '@gitkraken/gitkraken-components';
import type { GraphRow, Head, Remote, RowContexts, Tag } from '@gitkraken/gitkraken-components';

export type GitGraphRowHead = Head;
export type GitGraphRowRemoteHead = Remote;
export type GitGraphRowTag = Tag;
export type GitGraphRowContexts = RowContexts;
export const enum GitGraphRowType {
Commit = 'commit-node',
MergeCommit = 'merge-node',
Expand All @@ -17,6 +18,7 @@ export interface GitGraphRow extends GraphRow {
heads?: GitGraphRowHead[];
remotes?: GitGraphRowRemoteHead[];
tags?: GitGraphRowTag[];
contexts?: GitGraphRowContexts;
}

export interface GitGraph {
Expand Down

0 comments on commit 9bb1012

Please sign in to comment.