mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 07:04:45 +00:00
feat(coding-agent): add treeFilterMode setting for /tree default filter (#1852)
Add configurable initial filter mode for the session tree navigator. Users who always switch to a specific filter (e.g. no-tools via Ctrl+T) can now set it as default in settings. Same pattern as doubleEscapeAction (#404). Filter infra from #747.
This commit is contained in:
parent
a0d839ce84
commit
1f39cc776a
5 changed files with 39 additions and 2 deletions
|
|
@ -42,6 +42,7 @@ Edit directly or use `/settings` for common options.
|
|||
| `quietStartup` | boolean | `false` | Hide startup header |
|
||||
| `collapseChangelog` | boolean | `false` | Show condensed changelog after updates |
|
||||
| `doubleEscapeAction` | string | `"tree"` | Action for double-escape: `"tree"`, `"fork"`, or `"none"` |
|
||||
| `treeFilterMode` | string | `"default"` | Default filter for `/tree`: `"default"`, `"no-tools"`, `"user-only"`, `"labeled-only"`, `"all"` |
|
||||
| `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
|
||||
| `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
|
||||
| `showHardwareCursor` | boolean | `false` | Show terminal cursor |
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ export interface Settings {
|
|||
images?: ImageSettings;
|
||||
enabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)
|
||||
doubleEscapeAction?: "fork" | "tree" | "none"; // Action for double-escape with empty editor (default: "tree")
|
||||
treeFilterMode?: "default" | "no-tools" | "user-only" | "labeled-only" | "all"; // Default filter when opening /tree
|
||||
thinkingBudgets?: ThinkingBudgetsSettings; // Custom token budgets for thinking levels
|
||||
editorPaddingX?: number; // Horizontal padding for input editor (default: 0)
|
||||
autocompleteMaxVisible?: number; // Max visible items in autocomplete dropdown (default: 5)
|
||||
|
|
@ -866,6 +867,18 @@ export class SettingsManager {
|
|||
this.save();
|
||||
}
|
||||
|
||||
getTreeFilterMode(): "default" | "no-tools" | "user-only" | "labeled-only" | "all" {
|
||||
const mode = this.settings.treeFilterMode;
|
||||
const valid = ["default", "no-tools", "user-only", "labeled-only", "all"];
|
||||
return mode && valid.includes(mode) ? mode : "default";
|
||||
}
|
||||
|
||||
setTreeFilterMode(mode: "default" | "no-tools" | "user-only" | "labeled-only" | "all"): void {
|
||||
this.globalSettings.treeFilterMode = mode;
|
||||
this.markModified("treeFilterMode");
|
||||
this.save();
|
||||
}
|
||||
|
||||
getShowHardwareCursor(): boolean {
|
||||
return this.settings.showHardwareCursor ?? process.env.PI_HARDWARE_CURSOR === "1";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ export interface SettingsConfig {
|
|||
hideThinkingBlock: boolean;
|
||||
collapseChangelog: boolean;
|
||||
doubleEscapeAction: "fork" | "tree" | "none";
|
||||
treeFilterMode: "default" | "no-tools" | "user-only" | "labeled-only" | "all";
|
||||
showHardwareCursor: boolean;
|
||||
editorPaddingX: number;
|
||||
autocompleteMaxVisible: number;
|
||||
|
|
@ -60,6 +61,7 @@ export interface SettingsCallbacks {
|
|||
onHideThinkingBlockChange: (hidden: boolean) => void;
|
||||
onCollapseChangelogChange: (collapsed: boolean) => void;
|
||||
onDoubleEscapeActionChange: (action: "fork" | "tree" | "none") => void;
|
||||
onTreeFilterModeChange: (mode: "default" | "no-tools" | "user-only" | "labeled-only" | "all") => void;
|
||||
onShowHardwareCursorChange: (enabled: boolean) => void;
|
||||
onEditorPaddingXChange: (padding: number) => void;
|
||||
onAutocompleteMaxVisibleChange: (maxVisible: number) => void;
|
||||
|
|
@ -200,6 +202,13 @@ export class SettingsSelectorComponent extends Container {
|
|||
currentValue: config.doubleEscapeAction,
|
||||
values: ["tree", "fork", "none"],
|
||||
},
|
||||
{
|
||||
id: "tree-filter-mode",
|
||||
label: "Tree filter mode",
|
||||
description: "Default filter when opening /tree",
|
||||
currentValue: config.treeFilterMode,
|
||||
values: ["default", "no-tools", "user-only", "labeled-only", "all"],
|
||||
},
|
||||
{
|
||||
id: "thinking",
|
||||
label: "Thinking level",
|
||||
|
|
@ -379,6 +388,11 @@ export class SettingsSelectorComponent extends Container {
|
|||
case "double-escape-action":
|
||||
callbacks.onDoubleEscapeActionChange(newValue as "fork" | "tree");
|
||||
break;
|
||||
case "tree-filter-mode":
|
||||
callbacks.onTreeFilterModeChange(
|
||||
newValue as "default" | "no-tools" | "user-only" | "labeled-only" | "all",
|
||||
);
|
||||
break;
|
||||
case "show-hardware-cursor":
|
||||
callbacks.onShowHardwareCursorChange(newValue === "true");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ interface FlatNode {
|
|||
}
|
||||
|
||||
/** Filter mode for tree display */
|
||||
type FilterMode = "default" | "no-tools" | "user-only" | "labeled-only" | "all";
|
||||
export type FilterMode = "default" | "no-tools" | "user-only" | "labeled-only" | "all";
|
||||
|
||||
/**
|
||||
* Tree list component with selection and ASCII art visualization
|
||||
|
|
@ -70,9 +70,11 @@ class TreeList implements Component {
|
|||
currentLeafId: string | null,
|
||||
maxVisibleLines: number,
|
||||
initialSelectedId?: string,
|
||||
initialFilterMode?: FilterMode,
|
||||
) {
|
||||
this.currentLeafId = currentLeafId;
|
||||
this.maxVisibleLines = maxVisibleLines;
|
||||
this.filterMode = initialFilterMode ?? "default";
|
||||
this.multipleRoots = tree.length > 1;
|
||||
this.flatNodes = this.flattenTree(tree);
|
||||
this.buildActivePath();
|
||||
|
|
@ -1001,13 +1003,14 @@ export class TreeSelectorComponent extends Container implements Focusable {
|
|||
onCancel: () => void,
|
||||
onLabelChange?: (entryId: string, label: string | undefined) => void,
|
||||
initialSelectedId?: string,
|
||||
initialFilterMode?: FilterMode,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.onLabelChangeCallback = onLabelChange;
|
||||
const maxVisibleLines = Math.max(5, Math.floor(terminalHeight / 2));
|
||||
|
||||
this.treeList = new TreeList(tree, currentLeafId, maxVisibleLines, initialSelectedId);
|
||||
this.treeList = new TreeList(tree, currentLeafId, maxVisibleLines, initialSelectedId, initialFilterMode);
|
||||
this.treeList.onSelect = onSelect;
|
||||
this.treeList.onCancel = onCancel;
|
||||
this.treeList.onLabelEdit = (entryId, currentLabel) => this.showLabelInput(entryId, currentLabel);
|
||||
|
|
|
|||
|
|
@ -3045,6 +3045,7 @@ export class InteractiveMode {
|
|||
hideThinkingBlock: this.hideThinkingBlock,
|
||||
collapseChangelog: this.settingsManager.getCollapseChangelog(),
|
||||
doubleEscapeAction: this.settingsManager.getDoubleEscapeAction(),
|
||||
treeFilterMode: this.settingsManager.getTreeFilterMode(),
|
||||
showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
|
||||
editorPaddingX: this.settingsManager.getEditorPaddingX(),
|
||||
autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
|
||||
|
|
@ -3124,6 +3125,9 @@ export class InteractiveMode {
|
|||
onDoubleEscapeActionChange: (action) => {
|
||||
this.settingsManager.setDoubleEscapeAction(action);
|
||||
},
|
||||
onTreeFilterModeChange: (mode) => {
|
||||
this.settingsManager.setTreeFilterMode(mode);
|
||||
},
|
||||
onShowHardwareCursorChange: (enabled) => {
|
||||
this.settingsManager.setShowHardwareCursor(enabled);
|
||||
this.ui.setShowHardwareCursor(enabled);
|
||||
|
|
@ -3413,6 +3417,7 @@ export class InteractiveMode {
|
|||
private showTreeSelector(initialSelectedId?: string): void {
|
||||
const tree = this.sessionManager.getTree();
|
||||
const realLeafId = this.sessionManager.getLeafId();
|
||||
const initialFilterMode = this.settingsManager.getTreeFilterMode();
|
||||
|
||||
if (tree.length === 0) {
|
||||
this.showStatus("No entries in session");
|
||||
|
|
@ -3531,6 +3536,7 @@ export class InteractiveMode {
|
|||
this.ui.requestRender();
|
||||
},
|
||||
initialSelectedId,
|
||||
initialFilterMode,
|
||||
);
|
||||
return { component: selector, focus: selector };
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue