Fix tree selector gutter alignment, add page navigation, improve styling

- Fix gutter/connector alignment by tracking gutter positions with GutterInfo
- Convert recursive markContains to iterative to avoid stack overflow
- Add left/right arrow keys for page up/down navigation
- Consistent assistant message styling (green prefix, appropriate status colors)
- Remove leaf marker (*), active path bullets are sufficient
- Add Expandable interface for toggle expansion
- Fix BranchSummaryMessageComponent expansion toggle
This commit is contained in:
Mario Zechner 2025-12-29 18:57:15 +01:00
parent 975e90ea8c
commit 159e19a010
5 changed files with 186 additions and 104 deletions

View file

@ -23,8 +23,13 @@ function restoreLineEndings(text: string, ending: "\r\n" | "\n"): string {
/**
* Generate a unified diff string with line numbers and context
* Returns both the diff string and the first changed line number (in the new file)
*/
function generateDiffString(oldContent: string, newContent: string, contextLines = 4): string {
function generateDiffString(
oldContent: string,
newContent: string,
contextLines = 4,
): { diff: string; firstChangedLine: number | undefined } {
const parts = Diff.diffLines(oldContent, newContent);
const output: string[] = [];
@ -36,6 +41,7 @@ function generateDiffString(oldContent: string, newContent: string, contextLines
let oldLineNum = 1;
let newLineNum = 1;
let lastWasChange = false;
let firstChangedLine: number | undefined;
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
@ -45,6 +51,11 @@ function generateDiffString(oldContent: string, newContent: string, contextLines
}
if (part.added || part.removed) {
// Capture the first changed line (in the new file)
if (firstChangedLine === undefined) {
firstChangedLine = newLineNum;
}
// Show the change
for (const line of raw) {
if (part.added) {
@ -113,7 +124,7 @@ function generateDiffString(oldContent: string, newContent: string, contextLines
}
}
return output.join("\n");
return { diff: output.join("\n"), firstChangedLine };
}
const editSchema = Type.Object({
@ -125,6 +136,8 @@ const editSchema = Type.Object({
export interface EditToolDetails {
/** Unified diff of the changes made */
diff: string;
/** Line number of the first change in the new file (for editor navigation) */
firstChangedLine?: number;
}
export function createEditTool(cwd: string): AgentTool<typeof editSchema> {
@ -143,7 +156,7 @@ export function createEditTool(cwd: string): AgentTool<typeof editSchema> {
return new Promise<{
content: Array<{ type: "text"; text: string }>;
details: { diff: string } | undefined;
details: EditToolDetails | undefined;
}>((resolve, reject) => {
// Check if already aborted
if (signal?.aborted) {
@ -262,6 +275,7 @@ export function createEditTool(cwd: string): AgentTool<typeof editSchema> {
signal.removeEventListener("abort", onAbort);
}
const diffResult = generateDiffString(normalizedContent, normalizedNewContent);
resolve({
content: [
{
@ -269,7 +283,7 @@ export function createEditTool(cwd: string): AgentTool<typeof editSchema> {
text: `Successfully replaced text in ${path}.`,
},
],
details: { diff: generateDiffString(normalizedContent, normalizedNewContent) },
details: { diff: diffResult.diff, firstChangedLine: diffResult.firstChangedLine },
});
} catch (error: any) {
// Clean up abort handler