Skip to content

Commit 091fe3e

Browse files
committed
Expands command support for uncommitted files
- Adds missing commands (e.g., external diff, open changes) for uncommitted files - Fixes missing command handlers for uncommitted files - Refactors `UncommittedFileNode` and `StatusFileNode` to extend `ViewRefFileNode`
1 parent bc6a37f commit 091fe3e

File tree

12 files changed

+207
-205
lines changed

12 files changed

+207
-205
lines changed

contributions.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,7 +1675,7 @@
16751675
"menus": {
16761676
"gitlens/commit/file/changes": [
16771677
{
1678-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails",
1678+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.commitDetails",
16791679
"group": "1_gitlens",
16801680
"order": 3
16811681
}
@@ -1688,7 +1688,7 @@
16881688
"menus": {
16891689
"gitlens/commit/file/changes": [
16901690
{
1691-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails",
1691+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.graphDetails",
16921692
"group": "1_gitlens",
16931693
"order": 3
16941694
}
@@ -1739,7 +1739,7 @@
17391739
"menus": {
17401740
"gitlens/commit/file/changes": [
17411741
{
1742-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails",
1742+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.commitDetails",
17431743
"group": "1_gitlens",
17441744
"order": 4
17451745
}
@@ -1751,7 +1751,7 @@
17511751
"menus": {
17521752
"gitlens/commit/file/changes": [
17531753
{
1754-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails",
1754+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.graphDetails",
17551755
"group": "1_gitlens",
17561756
"order": 4
17571757
}
@@ -1871,7 +1871,7 @@
18711871
"menus": {
18721872
"gitlens/commit/file/changes": [
18731873
{
1874-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails",
1874+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails",
18751875
"group": "1_gitlens_",
18761876
"order": 5
18771877
}
@@ -1883,7 +1883,7 @@
18831883
"menus": {
18841884
"gitlens/commit/file/changes": [
18851885
{
1886-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails",
1886+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails",
18871887
"group": "1_gitlens_",
18881888
"order": 5
18891889
}
@@ -10646,7 +10646,7 @@
1064610646
"menus": {
1064710647
"gitlens/commit/file/changes": [
1064810648
{
10649-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails",
10649+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.commitDetails",
1065010650
"group": "1_gitlens",
1065110651
"order": 1
1065210652
}
@@ -10659,7 +10659,7 @@
1065910659
"menus": {
1066010660
"gitlens/commit/file/changes": [
1066110661
{
10662-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails",
10662+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.graphDetails",
1066310663
"group": "1_gitlens",
1066410664
"order": 1
1066510665
}
@@ -10925,7 +10925,7 @@
1092510925
"menus": {
1092610926
"gitlens/commit/file/changes": [
1092710927
{
10928-
"when": "viewItem =~ /gitlens:file\\b(?!.*?\\b\\+(conflicted|stashed|staged|unstaged)\\b)/",
10928+
"when": "viewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/",
1092910929
"group": "1_gitlens",
1093010930
"order": 2
1093110931
}

package.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15399,7 +15399,7 @@
1539915399
},
1540015400
{
1540115401
"command": "gitlens.views.openPreviousChangesWithWorking",
15402-
"when": "viewItem =~ /gitlens:file\\b(?!.*?\\b\\+(conflicted|stashed|staged|unstaged)\\b)/",
15402+
"when": "viewItem =~ /gitlens:file\\b(?=.*?\\b\\+committed\\b)/",
1540315403
"group": "1_gitlens@2"
1540415404
},
1540515405
{
@@ -15434,12 +15434,12 @@
1543415434
},
1543515435
{
1543615436
"command": "gitlens.views.openChangesWithWorking:commitDetails",
15437-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails",
15437+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.commitDetails",
1543815438
"group": "1_gitlens@1"
1543915439
},
1544015440
{
1544115441
"command": "gitlens.views.openChangesWithWorking:graphDetails",
15442-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails",
15442+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.graphDetails",
1544315443
"group": "1_gitlens@1"
1544415444
},
1544515445
{
@@ -15454,32 +15454,32 @@
1545415454
},
1545515455
{
1545615456
"command": "gitlens.diffWithRevision:commitDetails",
15457-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails",
15457+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.commitDetails",
1545815458
"group": "1_gitlens@3"
1545915459
},
1546015460
{
1546115461
"command": "gitlens.diffWithRevision:graphDetails",
15462-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails",
15462+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.graphDetails",
1546315463
"group": "1_gitlens@3"
1546415464
},
1546515465
{
1546615466
"command": "gitlens.diffWithRevisionFrom:commitDetails",
15467-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.commitDetails",
15467+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.commitDetails",
1546815468
"group": "1_gitlens@4"
1546915469
},
1547015470
{
1547115471
"command": "gitlens.diffWithRevisionFrom:graphDetails",
15472-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)/ && webview == gitlens.views.graphDetails",
15472+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)/ && webview == gitlens.views.graphDetails",
1547315473
"group": "1_gitlens@4"
1547415474
},
1547515475
{
1547615476
"command": "gitlens.externalDiff:commitDetails",
15477-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails",
15477+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.commitDetails",
1547815478
"group": "1_gitlens_@5"
1547915479
},
1548015480
{
1548115481
"command": "gitlens.externalDiff:graphDetails",
15482-
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails",
15482+
"when": "webviewItem =~ /gitlens:file\\b(?=.*?\\b\\+(committed|stashed|staged|unstaged)\\b)(?!.*?\\b\\+conflicted\\b)/ && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webview == gitlens.views.graphDetails",
1548315483
"group": "1_gitlens_@5"
1548415484
},
1548515485
{

src/commands/commandContext.utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ export function isCommandContextViewNodeHasRef(
114114
);
115115
}
116116

117+
export function isCommandContextViewNodeHasRefFile(
118+
context: CommandContext,
119+
): context is CommandViewNodeContext & { node: ViewRefFileNode } {
120+
return context.type === 'viewItem' && context.node instanceof ViewRefFileNode;
121+
}
122+
117123
export function isCommandContextViewNodeHasRemote(
118124
context: CommandContext,
119125
): context is CommandViewNodeContext & { node: ViewNode & { remote: GitRemote } } {

src/commands/externalDiff.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { ScmResource } from '../@types/vscode.git.resources';
44
import { ScmResourceGroupType, ScmStatus } from '../@types/vscode.git.resources.enums';
55
import type { Container } from '../container';
66
import { GitUri } from '../git/gitUri';
7-
import { isUncommitted } from '../git/utils/revision.utils';
7+
import { isUncommitted, isUncommittedStaged } from '../git/utils/revision.utils';
88
import { showGenericErrorMessage } from '../messages';
99
import { getRepositoryOrShowPicker } from '../quickpicks/repositoryPicker';
1010
import { command } from '../system/-webview/command';
@@ -13,7 +13,11 @@ import { filterMap } from '../system/array';
1313
import { Logger } from '../system/logger';
1414
import { GlCommandBase } from './commandBase';
1515
import type { CommandContext } from './commandContext';
16-
import { isCommandContextViewNodeHasFileCommit, isCommandContextViewNodeHasFileRefs } from './commandContext.utils';
16+
import {
17+
isCommandContextViewNodeHasFileCommit,
18+
isCommandContextViewNodeHasFileRefs,
19+
isCommandContextViewNodeHasRefFile,
20+
} from './commandContext.utils';
1721

1822
interface ExternalDiffFile {
1923
uri: Uri;
@@ -65,6 +69,20 @@ export class ExternalDiffCommand extends GlCommandBase {
6569
return this.execute(args);
6670
}
6771

72+
if (isCommandContextViewNodeHasRefFile(context)) {
73+
const rev = context.node.ref.ref;
74+
args.files = [
75+
{
76+
uri: GitUri.fromFile(context.node.file, context.node.file.repoPath ?? context.node.repoPath),
77+
staged: isUncommittedStaged(rev) || context.node.file.indexStatus != null,
78+
ref1: isUncommitted(rev) ? '' : `${rev}^`,
79+
ref2: isUncommitted(rev) ? '' : rev,
80+
},
81+
];
82+
83+
return this.execute(args);
84+
}
85+
6886
if (args.files == null) {
6987
if (context.type === 'scm-states') {
7088
args.files = context.scmResourceStates.map(r => ({

src/constants.views.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,26 +104,23 @@ export const viewIdsByDefaultContainerId = new Map<ViewContainerIds | CoreViewCo
104104

105105
export type TreeViewRefNodeTypes = 'branch' | 'commit' | 'stash' | 'tag';
106106
export const treeViewRefNodeTypes: TreeViewRefNodeTypes[] = ['branch', 'commit', 'stash', 'tag'];
107-
export type TreeViewRefFileNodeTypes = 'commit-file' | 'file-commit' | 'results-file' | 'stash-file';
107+
export type TreeViewRefFileNodeTypes =
108+
| 'commit-file'
109+
| 'file-commit'
110+
| 'results-file'
111+
| 'stash-file'
112+
| 'status-file'
113+
| 'uncommitted-file';
108114
export const treeViewRefFileNodeTypes: TreeViewRefFileNodeTypes[] = [
109115
'commit-file',
110116
'file-commit',
111117
'results-file',
112118
'stash-file',
113-
];
114-
export type TreeViewFileNodeTypes =
115-
| TreeViewRefFileNodeTypes
116-
| 'conflict-file'
117-
// | 'folder'
118-
| 'status-file'
119-
| 'uncommitted-file';
120-
export const treeViewFileNodeTypes: TreeViewFileNodeTypes[] = [
121-
...treeViewRefFileNodeTypes,
122-
'conflict-file',
123-
// 'folder',
124119
'status-file',
125120
'uncommitted-file',
126121
];
122+
export type TreeViewFileNodeTypes = TreeViewRefFileNodeTypes | 'conflict-file';
123+
export const treeViewFileNodeTypes: TreeViewFileNodeTypes[] = [...treeViewRefFileNodeTypes, 'conflict-file'];
127124
export type TreeViewSubscribableNodeTypes =
128125
| 'autolinks'
129126
| 'commits-current-branch'

src/env/node/git/sub-providers/diff.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,6 @@ export class DiffGitSubProvider implements GitDiffSubProvider {
111111
from = prepareToFromDiffArgs(to, from, args, options?.notation);
112112

113113
let paths: Set<string> | undefined;
114-
let untrackedPaths: string[] | undefined;
115-
116114
if (options?.uris) {
117115
paths = new Set<string>(options.uris.map(u => this.provider.getRelativePath(u, repoPath)));
118116
args.push('--', ...paths);
@@ -130,10 +128,6 @@ export class DiffGitSubProvider implements GitDiffSubProvider {
130128
debugger;
131129
Logger.error(ex, scope);
132130
return undefined;
133-
} finally {
134-
if (untrackedPaths?.length) {
135-
await this.provider.staging?.unstageFiles(repoPath, untrackedPaths);
136-
}
137131
}
138132

139133
const diff: GitDiff = { contents: result.stdout, from: from, to: to, notation: options?.notation };

src/views/nodes/UncommittedFileNode.ts

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,22 @@ import type { DiffWithPreviousCommandArgs } from '../../commands/diffWithPreviou
44
import { StatusFileFormatter } from '../../git/formatters/statusFormatter';
55
import { GitUri } from '../../git/gitUri';
66
import type { GitFile } from '../../git/models/file';
7+
import type { GitRevisionReference } from '../../git/models/reference';
8+
import { uncommitted } from '../../git/models/revision';
79
import { getGitFileStatusIcon } from '../../git/utils/fileStatus.utils';
10+
import { createReference } from '../../git/utils/reference.utils';
811
import { createCommand } from '../../system/-webview/command';
912
import { editorLineToDiffRange } from '../../system/-webview/vscode/editors';
13+
import { memoize } from '../../system/decorators/memoize';
1014
import { dirname, joinPaths } from '../../system/path';
1115
import type { ViewsWithCommits } from '../viewBase';
12-
import { getFileTooltipMarkdown, ViewFileNode } from './abstract/viewFileNode';
16+
import { getFileTooltipMarkdown } from './abstract/viewFileNode';
1317
import type { ViewNode } from './abstract/viewNode';
1418
import { ContextValues } from './abstract/viewNode';
19+
import { ViewRefFileNode } from './abstract/viewRefNode';
1520
import type { FileNode } from './folderNode';
1621

17-
export class UncommittedFileNode extends ViewFileNode<'uncommitted-file', ViewsWithCommits> implements FileNode {
22+
export class UncommittedFileNode extends ViewRefFileNode<'uncommitted-file', ViewsWithCommits> implements FileNode {
1823
constructor(view: ViewsWithCommits, parent: ViewNode, repoPath: string, file: GitFile) {
1924
super('uncommitted-file', GitUri.fromFile(file, repoPath), view, parent, file);
2025
}
@@ -23,10 +28,55 @@ export class UncommittedFileNode extends ViewFileNode<'uncommitted-file', ViewsW
2328
return this.path;
2429
}
2530

31+
private _description: string | undefined;
32+
get description(): string {
33+
this._description ??= StatusFileFormatter.fromTemplate(
34+
this.view.config.formats.files.description,
35+
{ ...this.file },
36+
{ relativePath: this.relativePath },
37+
);
38+
return this._description;
39+
}
40+
41+
private _folderName: string | undefined;
42+
get folderName(): string {
43+
this._folderName ??= dirname(this.uri.relativePath);
44+
return this._folderName;
45+
}
46+
47+
private _label: string | undefined;
48+
get label(): string {
49+
this._label ??= StatusFileFormatter.fromTemplate(
50+
`\${file}`,
51+
{ ...this.file },
52+
{ relativePath: this.relativePath },
53+
);
54+
return this._label;
55+
}
56+
2657
get path(): string {
2758
return this.file.path;
2859
}
2960

61+
get priority(): number {
62+
return 0;
63+
}
64+
65+
@memoize()
66+
get ref(): GitRevisionReference {
67+
return createReference(uncommitted, this.uri.repoPath!, { refType: 'revision' });
68+
}
69+
70+
private _relativePath: string | undefined;
71+
get relativePath(): string | undefined {
72+
return this._relativePath;
73+
}
74+
set relativePath(value: string | undefined) {
75+
this._relativePath = value;
76+
this._label = undefined;
77+
this._description = undefined;
78+
}
79+
3080
getChildren(): ViewNode[] {
3181
return [];
3282
}
@@ -54,52 +104,6 @@ export class UncommittedFileNode extends ViewFileNode<'uncommitted-file', ViewsW
54104
return item;
55105
}
56106

57-
private _description: string | undefined;
58-
get description(): string {
59-
if (this._description == null) {
60-
this._description = StatusFileFormatter.fromTemplate(
61-
this.view.config.formats.files.description,
62-
{ ...this.file },
63-
{ relativePath: this.relativePath },
64-
);
65-
}
66-
return this._description;
67-
}
68-
69-
private _folderName: string | undefined;
70-
get folderName(): string {
71-
if (this._folderName == null) {
72-
this._folderName = dirname(this.uri.relativePath);
73-
}
74-
return this._folderName;
75-
}
76-
77-
private _label: string | undefined;
78-
get label(): string {
79-
if (this._label == null) {
80-
this._label = StatusFileFormatter.fromTemplate(
81-
`\${file}`,
82-
{ ...this.file },
83-
{ relativePath: this.relativePath },
84-
);
85-
}
86-
return this._label;
87-
}
88-
89-
get priority(): number {
90-
return 0;
91-
}
92-
93-
private _relativePath: string | undefined;
94-
get relativePath(): string | undefined {
95-
return this._relativePath;
96-
}
97-
set relativePath(value: string | undefined) {
98-
this._relativePath = value;
99-
this._label = undefined;
100-
this._description = undefined;
101-
}
102-
103107
override getCommand(): Command | undefined {
104108
return createCommand<[undefined, DiffWithPreviousCommandArgs]>(
105109
'gitlens.diffWithPrevious:views',

0 commit comments

Comments
 (0)