mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-20 08:04:44 +00:00
refactor(coding-agent): simplify tree indentation
- At indent 0: stay flat unless parent branches - At indent 1: children go to indent 2 (visual grouping) - At indent 2+: stay flat for single-child chains - Remove gutter/connector complexity for now
This commit is contained in:
parent
6fbc3a01ef
commit
7c103ddc55
1 changed files with 27 additions and 39 deletions
|
|
@ -21,10 +21,8 @@ import { DynamicBorder } from "./dynamic-border.js";
|
||||||
/** Flattened tree node for navigation */
|
/** Flattened tree node for navigation */
|
||||||
interface FlatNode {
|
interface FlatNode {
|
||||||
node: SessionTreeNode;
|
node: SessionTreeNode;
|
||||||
/** For each indent level, true = show │ gutter, false = show spaces */
|
/** Indentation level (each level = 2 spaces) */
|
||||||
gutterLevels: boolean[];
|
indent: number;
|
||||||
/** none = no connector, branch = ├─, last = └─ */
|
|
||||||
connector: "none" | "branch" | "last";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Filter mode for tree display */
|
/** Filter mode for tree display */
|
||||||
|
|
@ -72,26 +70,23 @@ class TreeList implements Component {
|
||||||
const result: FlatNode[] = [];
|
const result: FlatNode[] = [];
|
||||||
this.toolCallMap.clear();
|
this.toolCallMap.clear();
|
||||||
|
|
||||||
// Iterative traversal to avoid stack overflow
|
// Indentation rules:
|
||||||
// Stack items: [node, gutterLevels, connector]
|
// - At indent 0: stay at 0 unless parent has >1 children (then +1)
|
||||||
// gutterLevels: for each indent level, true = show │, false = show spaces
|
// - At indent 1: children always go to indent 2 (visual grouping of subtree)
|
||||||
// connector: none/branch/last
|
// - At indent 2+: stay flat for single-child chains, +1 only if parent branches
|
||||||
type StackItem = [SessionTreeNode, boolean[], "none" | "branch" | "last"];
|
|
||||||
|
// Stack items: [node, indent, justBranched]
|
||||||
|
// justBranched: true if parent had multiple children (used for indent 1 -> 2 transition)
|
||||||
|
type StackItem = [SessionTreeNode, number, boolean];
|
||||||
const stack: StackItem[] = [];
|
const stack: StackItem[] = [];
|
||||||
|
|
||||||
// Add roots in reverse order
|
// Add roots in reverse order
|
||||||
const multipleRoots = roots.length > 1;
|
|
||||||
for (let i = roots.length - 1; i >= 0; i--) {
|
for (let i = roots.length - 1; i >= 0; i--) {
|
||||||
const connector: "none" | "branch" | "last" = multipleRoots
|
stack.push([roots[i], 0, roots.length > 1]);
|
||||||
? i === roots.length - 1
|
|
||||||
? "last"
|
|
||||||
: "branch"
|
|
||||||
: "none";
|
|
||||||
stack.push([roots[i], [], connector]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (stack.length > 0) {
|
while (stack.length > 0) {
|
||||||
const [node, gutterLevels, connector] = stack.pop()!;
|
const [node, indent, justBranched] = stack.pop()!;
|
||||||
|
|
||||||
// Extract tool calls from assistant messages for later lookup
|
// Extract tool calls from assistant messages for later lookup
|
||||||
const entry = node.entry;
|
const entry = node.entry;
|
||||||
|
|
@ -107,32 +102,27 @@ class TreeList implements Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push({ node, gutterLevels, connector });
|
result.push({ node, indent });
|
||||||
|
|
||||||
const children = node.children;
|
const children = node.children;
|
||||||
const multipleChildren = children.length > 1;
|
const multipleChildren = children.length > 1;
|
||||||
|
|
||||||
// Build gutterLevels for children
|
// Calculate child indent
|
||||||
// Only add a gutter level if THIS node had a connector (was in a branch)
|
let childIndent: number;
|
||||||
let childGutterLevels: boolean[];
|
if (multipleChildren) {
|
||||||
if (connector !== "none") {
|
// Parent branches: children get +1
|
||||||
// We showed a connector, so children get a gutter level
|
childIndent = indent + 1;
|
||||||
// If we're not last, show │; if we are last, show spaces
|
} else if (justBranched && indent > 0) {
|
||||||
childGutterLevels = [...gutterLevels, connector !== "last"];
|
// First generation after a branch: +1 for visual grouping
|
||||||
|
childIndent = indent + 1;
|
||||||
} else {
|
} else {
|
||||||
// No connector, children inherit same gutter levels
|
// Single-child chain: stay flat
|
||||||
childGutterLevels = gutterLevels;
|
childIndent = indent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add children in reverse order
|
// Add children in reverse order
|
||||||
for (let i = children.length - 1; i >= 0; i--) {
|
for (let i = children.length - 1; i >= 0; i--) {
|
||||||
const child = children[i];
|
stack.push([children[i], childIndent, multipleChildren]);
|
||||||
const childConnector: "none" | "branch" | "last" = multipleChildren
|
|
||||||
? i === children.length - 1
|
|
||||||
? "last"
|
|
||||||
: "branch"
|
|
||||||
: "none";
|
|
||||||
stack.push([child, childGutterLevels, childConnector]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,16 +300,14 @@ class TreeList implements Component {
|
||||||
const isSelected = i === this.selectedIndex;
|
const isSelected = i === this.selectedIndex;
|
||||||
const isCurrentLeaf = entry.id === this.currentLeafId;
|
const isCurrentLeaf = entry.id === this.currentLeafId;
|
||||||
|
|
||||||
// Build line: cursor + gutter + connector + label + content + suffix
|
// Build line: cursor + indent + label + content + suffix
|
||||||
const cursor = isSelected ? theme.fg("accent", "› ") : " ";
|
const cursor = isSelected ? theme.fg("accent", "› ") : " ";
|
||||||
const gutter = flatNode.gutterLevels.map((show) => (show ? "│ " : " ")).join("");
|
const indentStr = " ".repeat(flatNode.indent);
|
||||||
const connector = flatNode.connector === "branch" ? "├─ " : flatNode.connector === "last" ? "└─ " : "";
|
|
||||||
const prefix = gutter || connector ? theme.fg("dim", gutter + connector) : "";
|
|
||||||
const label = flatNode.node.label ? theme.fg("warning", `[${flatNode.node.label}] `) : "";
|
const label = flatNode.node.label ? theme.fg("warning", `[${flatNode.node.label}] `) : "";
|
||||||
const content = this.getEntryDisplayText(flatNode.node, isSelected);
|
const content = this.getEntryDisplayText(flatNode.node, isSelected);
|
||||||
const suffix = isCurrentLeaf ? theme.fg("accent", " *") : "";
|
const suffix = isCurrentLeaf ? theme.fg("accent", " *") : "";
|
||||||
|
|
||||||
const line = cursor + prefix + label + content + suffix;
|
const line = cursor + indentStr + label + content + suffix;
|
||||||
lines.push(truncateToWidth(line, width));
|
lines.push(truncateToWidth(line, width));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue