Skip to content

Commit 4409000

Browse files
committed
Improves explain commands
- shows toast for no results - reduces redundant commit lookups - simplifies source tracking - updates error messaging
1 parent 13746b6 commit 4409000

File tree

6 files changed

+81
-64
lines changed

6 files changed

+81
-64
lines changed

src/commands/explainBranch.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { CancellationToken, TextEditor, Uri } from 'vscode';
22
import { ProgressLocation } from 'vscode';
3+
import type { Source } from '../constants.telemetry';
34
import type { Container } from '../container';
45
import { GitUri } from '../git/gitUri';
56
import type { GitBranch } from '../git/models/branch';
67
import { showGenericErrorMessage } from '../messages';
7-
import type { AIExplainSource } from '../plus/ai/aiProviderService';
88
import { prepareCompareDataForAIRequest } from '../plus/ai/aiProviderService';
99
import { ReferencesQuickPickIncludes, showReferencePicker } from '../quickpicks/referencePicker';
1010
import { getBestRepositoryOrShowPicker } from '../quickpicks/repositoryPicker';
@@ -20,7 +20,7 @@ import { isCommandContextViewNodeHasBranch } from './commandContext.utils';
2020
export interface ExplainBranchCommandArgs {
2121
repoPath?: string | Uri;
2222
ref?: string;
23-
source?: AIExplainSource;
23+
source?: Source;
2424
}
2525

2626
@command()
@@ -34,7 +34,7 @@ export class ExplainBranchCommand extends GlCommandBase {
3434
args = { ...args };
3535
args.repoPath = args.repoPath ?? getNodeRepoPath(context.node);
3636
args.ref = args.ref ?? context.node.branch.ref;
37-
args.source = args.source ?? { source: 'view', type: 'branch' };
37+
args.source = args.source ?? { source: 'view' };
3838
}
3939

4040
return this.execute(context.editor, context.uri, args);
@@ -87,7 +87,7 @@ export class ExplainBranchCommand extends GlCommandBase {
8787
const baseBranchName = await getMergeTarget(this.container, branch);
8888
const baseBranch = await repository.git.branches().getBranch(baseBranchName);
8989
if (!baseBranch) {
90-
void showGenericErrorMessage(`Unable to find the base branch for ${branch.name}.`);
90+
void showGenericErrorMessage(`Unable to find the base branch for branch ${branch.name}.`);
9191
return;
9292
}
9393

@@ -117,7 +117,11 @@ export class ExplainBranchCommand extends GlCommandBase {
117117
// Call the AI service to explain the changes
118118
const result = await this.container.ai.explainChanges(
119119
changes,
120-
args.source ?? { source: 'commandPalette', type: 'commit' },
120+
{
121+
...args.source,
122+
source: args.source?.source ?? 'commandPalette',
123+
type: 'branch',
124+
},
121125
{
122126
progress: { location: ProgressLocation.Notification, title: 'Explaining branch changes...' },
123127
},
@@ -128,7 +132,7 @@ export class ExplainBranchCommand extends GlCommandBase {
128132
return;
129133
}
130134

131-
const content = `# Branch Summary\n\n> Generated by ${result.model.name}\n\n## ${branch.name}\n\n${result?.parsed.summary}\n\n${result?.parsed.body}`;
135+
const content = `# Branch Summary\n\n> Generated by ${result.model.name}\n\n## ${branch.name}\n\n${result.parsed.summary}\n\n${result.parsed.body}`;
132136

133137
void showMarkdownPreview(content);
134138
} catch (ex) {

src/commands/explainCommit.ts

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import type { TextEditor, Uri } from 'vscode';
22
import { ProgressLocation } from 'vscode';
3+
import type { Source } from '../constants.telemetry';
34
import type { Container } from '../container';
45
import { GitUri } from '../git/gitUri';
6+
import type { GitCommit } from '../git/models/commit';
57
import { showGenericErrorMessage } from '../messages';
6-
import type { AIExplainSource } from '../plus/ai/aiProviderService';
78
import { showCommitPicker } from '../quickpicks/commitPicker';
89
import { getBestRepositoryOrShowPicker } from '../quickpicks/repositoryPicker';
910
import { command } from '../system/-webview/command';
@@ -18,7 +19,7 @@ import { isCommandContextViewNodeHasCommit } from './commandContext.utils';
1819
export interface ExplainCommitCommandArgs {
1920
repoPath?: string | Uri;
2021
ref?: string;
21-
source?: AIExplainSource;
22+
source?: Source;
2223
}
2324

2425
@command()
@@ -33,7 +34,7 @@ export class ExplainCommitCommand extends GlCommandBase {
3334
args = { ...args };
3435
args.repoPath = args.repoPath ?? getNodeRepoPath(context.node);
3536
args.ref = args.ref ?? context.node.commit.sha;
36-
args.source = args.source ?? { source: 'view', type: 'commit' };
37+
args.source = args.source ?? { source: 'view' };
3738
}
3839

3940
return this.execute(context.editor, context.uri, args);
@@ -61,38 +62,44 @@ export class ExplainCommitCommand extends GlCommandBase {
6162
if (repository == null) return;
6263

6364
try {
64-
// If no ref is provided, show a picker to select a commit
65+
let commit: GitCommit | undefined;
6566
if (args.ref == null) {
6667
const commitsProvider = repository.git.commits();
6768
const log = await commitsProvider.getLog();
6869
const pick = await showCommitPicker(log, 'Explain Commit', 'Choose a commit to explain');
6970
if (pick?.sha == null) return;
7071
args.ref = pick.sha;
71-
}
72-
73-
// Get the commit
74-
const commit = await repository.git.commits().getCommit(args.ref);
75-
if (commit == null) {
76-
void showGenericErrorMessage('Unable to find the specified commit');
77-
return;
72+
commit = pick;
73+
} else {
74+
// Get the commit
75+
commit = await repository.git.commits().getCommit(args.ref);
76+
if (commit == null) {
77+
void showGenericErrorMessage('Unable to find the specified commit');
78+
return;
79+
}
7880
}
7981

8082
// Call the AI service to explain the commit
8183
const result = await this.container.ai.explainCommit(
8284
commit,
83-
args.source ?? { source: 'commandPalette', type: 'commit' },
85+
{
86+
...args.source,
87+
source: args.source?.source ?? 'commandPalette',
88+
type: 'commit',
89+
},
8490
{
8591
progress: { location: ProgressLocation.Notification, title: 'Explaining commit...' },
8692
},
8793
);
8894

89-
// Display the result
90-
let content = `# Commit Summary\n\n`;
91-
if (result != null) {
92-
content += `> Generated by ${result.model.name}\n\n## ${commit.summary} (${commit.shortSha})\n\n${result?.parsed.summary}\n\n${result?.parsed.body}`;
93-
} else {
94-
content += `> No changes found to explain.`;
95+
if (result == null) {
96+
void showGenericErrorMessage('No changes found to explain for commit');
97+
return;
9598
}
99+
100+
// Display the result
101+
const content = `# Commit Summary\n\n> Generated by ${result.model.name}\n\n## ${commit.summary} (${commit.shortSha})\n\n${result.parsed.summary}\n\n${result.parsed.body}`;
102+
96103
void showMarkdownPreview(content);
97104
} catch (ex) {
98105
Logger.error(ex, 'ExplainCommitCommand', 'execute');

src/commands/explainStash.ts

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { TextEditor, Uri } from 'vscode';
22
import { ProgressLocation } from 'vscode';
3+
import type { Source } from '../constants.telemetry';
34
import type { Container } from '../container';
45
import { GitUri } from '../git/gitUri';
5-
import type { GitStashCommit } from '../git/models/commit';
6+
import type { GitCommit, GitStashCommit } from '../git/models/commit';
67
import { showGenericErrorMessage } from '../messages';
7-
import type { AIExplainSource } from '../plus/ai/aiProviderService';
88
import { getBestRepositoryOrShowPicker } from '../quickpicks/repositoryPicker';
99
import { showStashPicker } from '../quickpicks/stashPicker';
1010
import { command } from '../system/-webview/command';
@@ -18,7 +18,7 @@ import { isCommandContextViewNodeHasCommit } from './commandContext.utils';
1818
export interface ExplainStashCommandArgs {
1919
repoPath?: string | Uri;
2020
ref?: string;
21-
source?: AIExplainSource;
21+
source?: Source;
2222
}
2323

2424
@command()
@@ -33,7 +33,7 @@ export class ExplainStashCommand extends GlCommandBase {
3333
args = { ...args };
3434
args.repoPath = args.repoPath ?? context.node.commit.repoPath;
3535
args.ref = args.ref ?? context.node.commit.sha;
36-
args.source = args.source ?? { source: 'view', type: 'stash' };
36+
args.source = args.source ?? { source: 'view' };
3737
}
3838

3939
return this.execute(context.editor, context.uri, args);
@@ -61,37 +61,42 @@ export class ExplainStashCommand extends GlCommandBase {
6161
if (repository == null) return;
6262

6363
try {
64-
// If no ref is provided, show a picker to select a stash
64+
let commit: GitCommit | undefined;
6565
if (args.ref == null) {
6666
const pick = await showStashPicker('Explain Stash', 'Choose a stash to explain', repository);
6767
if (pick?.ref == null) return;
6868
args.ref = pick.ref;
69+
commit = pick;
70+
} else {
71+
commit = await repository.git.commits().getCommit(args.ref);
72+
if (commit == null) {
73+
void showGenericErrorMessage('Unable to find the specified stash commit');
74+
return;
75+
}
6976
}
7077

71-
// Get the stash commit
72-
const commit = await repository.git.commits().getCommit(args.ref);
73-
if (commit == null) {
74-
void showGenericErrorMessage('Unable to find the specified stash commit');
75-
return;
76-
}
77-
78-
// Call the AI service to explain the stash
7978
const result = await this.container.ai.explainCommit(
8079
commit,
81-
args.source ?? { source: 'commandPalette', type: 'stash' },
80+
{
81+
...args.source,
82+
source: args.source?.source ?? 'commandPalette',
83+
type: 'stash',
84+
},
8285
{
8386
progress: { location: ProgressLocation.Notification, title: 'Explaining stash...' },
8487
},
8588
);
8689

87-
// Display the result
88-
let content = `# Stash Summary\n\n`;
89-
if (result != null) {
90-
content += `> Generated by ${result.model.name}\n\n## ${commit.message || commit.ref}}\n\n${result
91-
?.parsed.summary}\n\n${result?.parsed.body}`;
92-
} else {
93-
content += `> No changes found to explain.`;
90+
if (result == null) {
91+
void showGenericErrorMessage('No changes found to explain for stash');
92+
return;
9493
}
94+
95+
// Display the result
96+
const content = `# Stash Summary\n\n> Generated by ${result.model.name}\n\n## ${
97+
commit.message || commit.ref
98+
}\n\n${result.parsed.summary}\n\n${result.parsed.body}`;
99+
95100
void showMarkdownPreview(content);
96101
} catch (ex) {
97102
Logger.error(ex, 'ExplainStashCommand', 'execute');

src/commands/explainWip.ts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { TextEditor, Uri } from 'vscode';
22
import { ProgressLocation } from 'vscode';
3+
import type { Source } from '../constants.telemetry';
34
import type { Container } from '../container';
45
import { GitUri } from '../git/gitUri';
56
import { uncommitted, uncommittedStaged } from '../git/models/revision';
67
import { showGenericErrorMessage } from '../messages';
7-
import type { AIExplainSource } from '../plus/ai/aiProviderService';
88
import { getBestRepositoryOrShowPicker } from '../quickpicks/repositoryPicker';
99
import { command } from '../system/-webview/command';
1010
import { showMarkdownPreview } from '../system/-webview/markdown';
@@ -21,7 +21,7 @@ import {
2121
export interface ExplainWipCommandArgs {
2222
repoPath?: string | Uri;
2323
staged?: boolean;
24-
source?: AIExplainSource;
24+
source?: Source;
2525
worktreePath?: string;
2626
}
2727

@@ -36,15 +36,15 @@ export class ExplainWipCommand extends GlCommandBase {
3636
args = { ...args };
3737
args.repoPath = context.node.worktree.repoPath;
3838
args.worktreePath = context.node.worktree.path;
39-
args.source = args.source ?? { source: 'view', type: 'wip' };
39+
args.source = args.source ?? { source: 'view' };
4040
} else if (isCommandContextViewNodeHasRepository(context)) {
4141
args = { ...args };
4242
args.repoPath = context.node.repo.path;
43-
args.source = args.source ?? { source: 'view', type: 'wip' };
43+
args.source = args.source ?? { source: 'view' };
4444
} else if (isCommandContextViewNodeHasRepoPath(context)) {
4545
args = { ...args };
4646
args.repoPath = context.node.repoPath;
47-
args.source = args.source ?? { source: 'view', type: 'wip' };
47+
args.source = args.source ?? { source: 'view' };
4848
}
4949

5050
return this.execute(context.editor, context.uri, args);
@@ -93,10 +93,7 @@ export class ExplainWipCommand extends GlCommandBase {
9393
to = uncommitted;
9494
}
9595

96-
// If a worktree path is specified, use it for the diff
97-
// const options = args?.worktreePath ? { uris: [Uri.file(args.worktreePath)] } : undefined;
98-
const options = undefined;
99-
const diff = await diffService.getDiff(to, undefined, options);
96+
const diff = await diffService.getDiff(to, undefined);
10097
if (!diff?.contents) {
10198
void showGenericErrorMessage('No working changes found to explain');
10299
return;
@@ -126,7 +123,11 @@ export class ExplainWipCommand extends GlCommandBase {
126123
diff: diff.contents,
127124
message: `${stagedLabel} working changes${worktreeInfo}`,
128125
},
129-
args.source ?? { source: 'commandPalette', type: 'wip' },
126+
{
127+
...args.source,
128+
source: args.source?.source ?? 'commandPalette',
129+
type: 'wip',
130+
},
130131
{
131132
progress: {
132133
location: ProgressLocation.Notification,
@@ -135,13 +136,14 @@ export class ExplainWipCommand extends GlCommandBase {
135136
},
136137
);
137138

138-
const title = `Working Changes Summary${worktreeDisplayName}`;
139-
let content = `# ${title}\n\n`;
140-
if (result != null) {
141-
content += `> Generated by ${result.model.name}\n\n## ${stagedLabel} Changes\n\n${result?.parsed.summary}\n\n${result?.parsed.body}`;
142-
} else {
143-
content += `> No changes found to explain.`;
139+
if (result == null) {
140+
void showGenericErrorMessage('Unable to explain working changes');
141+
return;
144142
}
143+
144+
const title = `Working Changes Summary${worktreeDisplayName}`;
145+
const content = `# ${title}\n\n> Generated by ${result.model.name}\n\n## ${stagedLabel} Changes\n\n${result.parsed.summary}\n\n${result.parsed.body}`;
146+
145147
void showMarkdownPreview(content);
146148
} catch (ex) {
147149
Logger.error(ex, 'ExplainWipCommand', 'execute');

src/git/actions/commit.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import type { ShowQuickCommitCommandArgs } from '../../commands/showQuickCommit'
1111
import type { ShowQuickCommitFileCommandArgs } from '../../commands/showQuickCommitFile';
1212
import type { FileAnnotationType } from '../../config';
1313
import { GlyphChars } from '../../constants';
14+
import type { Source } from '../../constants.telemetry';
1415
import { Container } from '../../container';
15-
import type { AIExplainSource } from '../../plus/ai/aiProviderService';
1616
import { showRevisionFilesPicker } from '../../quickpicks/revisionFilesPicker';
1717
import { executeCommand, executeCoreGitCommand, executeEditorCommand } from '../../system/-webview/command';
1818
import { configuration } from '../../system/-webview/configuration';
@@ -755,7 +755,7 @@ export async function showInCommitGraph(
755755

756756
export async function explainCommit(
757757
commit: GitRevisionReference | GitCommit,
758-
options?: { source?: AIExplainSource },
758+
options?: { source?: Source },
759759
): Promise<void> {
760760
void (await executeCommand<ExplainCommitCommandArgs>('gitlens.ai.explainCommit', {
761761
repoPath: commit.repoPath,

src/quickpicks/items/commits.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,6 @@ export class CommitExplainCommandQuickPickItem extends CommandQuickPickItem {
299299
return CommitActions.explainCommit(this.commit, {
300300
source: {
301301
source: 'commandPalette',
302-
type: 'commit',
303302
},
304303
});
305304
}

0 commit comments

Comments
 (0)