mirror of
https://github.com/microsoft/vscode.git
synced 2026-02-15 07:28:05 +00:00
Show latest commit message for branch in terminal suggest widget details view (#272296)
This commit is contained in:
@@ -74,46 +74,67 @@ const postProcessBranches =
|
||||
const seen = new Set<string>();
|
||||
return output
|
||||
.split("\n")
|
||||
.filter((line) => !line.trim().startsWith("HEAD"))
|
||||
.filter((line) => line.trim() && !line.trim().startsWith("HEAD"))
|
||||
.map((branch) => {
|
||||
let name = branch.trim();
|
||||
const parts = branch.match(/\S+/g);
|
||||
if (parts && parts.length > 1) {
|
||||
if (parts[0] === "*") {
|
||||
// We are in a detached HEAD state
|
||||
if (branch.includes("HEAD detached")) {
|
||||
return null;
|
||||
// Parse the format: branchName|author|hash|subject|timeAgo
|
||||
const parts = branch.split("|");
|
||||
if (parts.length < 5) {
|
||||
// Fallback to old parsing if format doesn't match
|
||||
let name = branch.trim();
|
||||
const oldParts = branch.match(/\S+/g);
|
||||
if (oldParts && oldParts.length > 1) {
|
||||
if (oldParts[0] === "*") {
|
||||
if (branch.includes("HEAD detached")) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
name: branch.replaceAll("*", "").trim(),
|
||||
description: "Current branch",
|
||||
priority: 100,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmBranch}`
|
||||
};
|
||||
} else if (oldParts[0] === "+") {
|
||||
name = branch.replaceAll("+", "").trim();
|
||||
}
|
||||
// Current branch
|
||||
return {
|
||||
name: branch.replace("*", "").trim(),
|
||||
description: "Current branch",
|
||||
priority: 100,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmBranch}`
|
||||
};
|
||||
} else if (parts[0] === "+") {
|
||||
// Branch checked out in another worktree.
|
||||
name = branch.replace("+", "").trim();
|
||||
}
|
||||
|
||||
let description = "Branch";
|
||||
if (insertWithoutRemotes && name.startsWith("remotes/")) {
|
||||
name = name.slice(name.indexOf("/", 8) + 1);
|
||||
description = "Remote branch";
|
||||
}
|
||||
|
||||
const space = name.indexOf(" ");
|
||||
if (space !== -1) {
|
||||
name = name.slice(0, space);
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
description,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmBranch}`,
|
||||
priority: 75,
|
||||
};
|
||||
}
|
||||
|
||||
let description = "Branch";
|
||||
let name = parts[0].trim();
|
||||
const author = parts[1].trim();
|
||||
const hash = parts[2].trim();
|
||||
const subject = parts[3].trim();
|
||||
const timeAgo = parts[4].trim();
|
||||
|
||||
const description = `${timeAgo} • ${author} • ${hash} • ${subject}`;
|
||||
const priority = 75;
|
||||
|
||||
if (insertWithoutRemotes && name.startsWith("remotes/")) {
|
||||
name = name.slice(name.indexOf("/", 8) + 1);
|
||||
description = "Remote branch";
|
||||
}
|
||||
|
||||
const space = name.indexOf(" ");
|
||||
if (space !== -1) {
|
||||
name = name.slice(0, space);
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
description,
|
||||
icon: `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmBranch}`,
|
||||
priority: 75,
|
||||
priority,
|
||||
};
|
||||
})
|
||||
.filter((suggestion) => {
|
||||
@@ -128,6 +149,15 @@ const postProcessBranches =
|
||||
});
|
||||
};
|
||||
|
||||
// Common git for-each-ref arguments for branch queries with commit details
|
||||
const gitBranchForEachRefArgs = [
|
||||
"git",
|
||||
"--no-optional-locks",
|
||||
"for-each-ref",
|
||||
"--sort=-committerdate",
|
||||
"--format=%(refname:short)|%(authorname)|%(objectname:short)|%(subject)|%(committerdate:relative)",
|
||||
] as const;
|
||||
|
||||
export const gitGenerators = {
|
||||
// Commit history
|
||||
commits: {
|
||||
@@ -252,23 +282,17 @@ export const gitGenerators = {
|
||||
// All branches
|
||||
remoteLocalBranches: {
|
||||
script: [
|
||||
"git",
|
||||
"--no-optional-locks",
|
||||
"branch",
|
||||
"-a",
|
||||
"--no-color",
|
||||
"--sort=-committerdate",
|
||||
...gitBranchForEachRefArgs,
|
||||
"refs/heads/",
|
||||
"refs/remotes/",
|
||||
],
|
||||
postProcess: postProcessBranches({ insertWithoutRemotes: true }),
|
||||
} satisfies Fig.Generator,
|
||||
|
||||
localBranches: {
|
||||
script: [
|
||||
"git",
|
||||
"--no-optional-locks",
|
||||
"branch",
|
||||
"--no-color",
|
||||
"--sort=-committerdate",
|
||||
...gitBranchForEachRefArgs,
|
||||
"refs/heads/",
|
||||
],
|
||||
postProcess: postProcessBranches({ insertWithoutRemotes: true }),
|
||||
} satisfies Fig.Generator,
|
||||
@@ -278,37 +302,19 @@ export const gitGenerators = {
|
||||
localOrRemoteBranches: {
|
||||
custom: async (tokens, executeShellCommand) => {
|
||||
const pp = postProcessBranches({ insertWithoutRemotes: true });
|
||||
if (tokens.includes("-r")) {
|
||||
return pp?.(
|
||||
(
|
||||
await executeShellCommand({
|
||||
command: "git",
|
||||
args: [
|
||||
"--no-optional-locks",
|
||||
"-r",
|
||||
"--no-color",
|
||||
"--sort=-committerdate",
|
||||
],
|
||||
})
|
||||
).stdout,
|
||||
tokens
|
||||
);
|
||||
} else {
|
||||
return pp?.(
|
||||
(
|
||||
await executeShellCommand({
|
||||
command: "git",
|
||||
args: [
|
||||
"--no-optional-locks",
|
||||
"branch",
|
||||
"--no-color",
|
||||
"--sort=-committerdate",
|
||||
],
|
||||
})
|
||||
).stdout,
|
||||
tokens
|
||||
);
|
||||
}
|
||||
const refs = tokens.includes("-r") ? "refs/remotes/" : "refs/heads/";
|
||||
return pp?.(
|
||||
(
|
||||
await executeShellCommand({
|
||||
command: gitBranchForEachRefArgs[0],
|
||||
args: [
|
||||
...gitBranchForEachRefArgs.slice(1),
|
||||
refs,
|
||||
],
|
||||
})
|
||||
).stdout,
|
||||
tokens
|
||||
);
|
||||
},
|
||||
} satisfies Fig.Generator,
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { gitGenerators } from '../../completions/git';
|
||||
|
||||
suite('Git Branch Completions', () => {
|
||||
test('postProcessBranches should parse git for-each-ref output with commit details', () => {
|
||||
const input = `main|John Doe|abc1234|Fix response codeblock in debug view|2 days ago
|
||||
feature/test|Jane Smith|def5678|Add new feature|1 week ago`;
|
||||
|
||||
const result = gitGenerators.localBranches.postProcess!(input, []);
|
||||
|
||||
assert.ok(result);
|
||||
assert.strictEqual(result.length, 2);
|
||||
assert.ok(result[0]);
|
||||
assert.strictEqual(result[0].name, 'main');
|
||||
assert.strictEqual(result[0].description, '2 days ago • John Doe • abc1234 • Fix response codeblock in debug view');
|
||||
assert.strictEqual(result[0].icon, `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmBranch}`);
|
||||
|
||||
assert.ok(result[1]);
|
||||
assert.strictEqual(result[1].name, 'feature/test');
|
||||
assert.strictEqual(result[1].description, '1 week ago • Jane Smith • def5678 • Add new feature');
|
||||
assert.strictEqual(result[1].icon, `vscode://icon?type=${vscode.TerminalCompletionItemKind.ScmBranch}`);
|
||||
});
|
||||
|
||||
test('postProcessBranches should handle remote branches', () => {
|
||||
const input = `remotes/origin/main|John Doe|abc1234|Fix bug|2 days ago
|
||||
remotes/origin/feature|Jane Smith|def5678|Add feature|1 week ago`;
|
||||
|
||||
const result = gitGenerators.remoteLocalBranches.postProcess!(input, []);
|
||||
|
||||
assert.ok(result);
|
||||
assert.strictEqual(result.length, 2);
|
||||
assert.ok(result[0]);
|
||||
assert.strictEqual(result[0].name, 'main');
|
||||
assert.strictEqual(result[0].description, '2 days ago • John Doe • abc1234 • Fix bug');
|
||||
|
||||
assert.ok(result[1]);
|
||||
assert.strictEqual(result[1].name, 'feature');
|
||||
assert.strictEqual(result[1].description, '1 week ago • Jane Smith • def5678 • Add feature');
|
||||
});
|
||||
|
||||
test('postProcessBranches should filter out HEAD branches', () => {
|
||||
const input = `main|John Doe|abc1234|Fix bug|2 days ago
|
||||
HEAD -> main|John Doe|abc1234|Fix bug|2 days ago`;
|
||||
|
||||
const result = gitGenerators.localBranches.postProcess!(input, []);
|
||||
|
||||
assert.ok(result);
|
||||
assert.strictEqual(result.length, 1);
|
||||
assert.ok(result[0]);
|
||||
assert.strictEqual(result[0].name, 'main');
|
||||
});
|
||||
|
||||
test('postProcessBranches should handle empty input', () => {
|
||||
const input = '';
|
||||
|
||||
const result = gitGenerators.localBranches.postProcess!(input, []);
|
||||
|
||||
assert.ok(result);
|
||||
assert.strictEqual(result.length, 0);
|
||||
});
|
||||
|
||||
test('postProcessBranches should handle git error output', () => {
|
||||
const input = 'fatal: not a git repository';
|
||||
|
||||
const result = gitGenerators.localBranches.postProcess!(input, []);
|
||||
|
||||
assert.ok(result);
|
||||
assert.strictEqual(result.length, 0);
|
||||
});
|
||||
|
||||
test('postProcessBranches should deduplicate branches', () => {
|
||||
const input = `main|John Doe|abc1234|Fix bug|2 days ago
|
||||
main|John Doe|abc1234|Fix bug|2 days ago`;
|
||||
|
||||
const result = gitGenerators.localBranches.postProcess!(input, []);
|
||||
|
||||
assert.ok(result);
|
||||
assert.strictEqual(result.length, 1);
|
||||
assert.ok(result[0]);
|
||||
assert.strictEqual(result[0].name, 'main');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user