refactor: use configurable keybindings for all UI hints (#724)

Follow-up to #717. Replaces all remaining hardcoded keybinding hints with configurable ones.

- Add pasteImage to AppAction so it can be configured in keybindings.json
- Create keybinding-hints.ts with reusable helper functions:
  - editorKey(action) / appKey(keybindings, action) - get key display string
  - keyHint(action, desc) / appKeyHint(kb, action, desc) / rawKeyHint(key, desc) - styled hints
- Export helpers from components/index.ts for extensions
- Update all components to use configured keybindings
- Remove now-unused getDisplayString() from KeybindingsManager and EditorKeybindingsManager
- Use keybindings.matches() instead of matchesKey() for pasteImage in custom-editor.ts
This commit is contained in:
Danila Poyarkov 2026-01-14 17:42:03 +03:00 committed by GitHub
parent 558a77b45f
commit a497fccd06
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 195 additions and 170 deletions

View file

@ -12,6 +12,7 @@ import {
import type { SessionTreeNode } from "../../../core/session-manager.js";
import { theme } from "../theme/theme.js";
import { DynamicBorder } from "./dynamic-border.js";
import { keyHint } from "./keybinding-hints.js";
/** Gutter info: position (displayIndent where connector was) and whether to show │ */
interface GutterInfo {
@ -760,7 +761,9 @@ class LabelInput implements Component {
const availableWidth = width - indent.length;
lines.push(truncateToWidth(`${indent}${theme.fg("muted", "Label (empty to remove):")}`, width));
lines.push(...this.input.render(availableWidth).map((line) => truncateToWidth(`${indent}${line}`, width)));
lines.push(truncateToWidth(`${indent}${theme.fg("dim", "enter: save esc: cancel")}`, width));
lines.push(
truncateToWidth(`${indent}${keyHint("selectConfirm", "save")} ${keyHint("selectCancel", "cancel")}`, width),
);
return lines;
}
@ -815,7 +818,13 @@ export class TreeSelectorComponent extends Container {
this.addChild(new DynamicBorder());
this.addChild(new Text(theme.bold(" Session Tree"), 1, 0));
this.addChild(
new TruncatedText(theme.fg("muted", " ↑/↓: move. ←/→: page. l: label. ^O/⇧^O: filter. Type to search"), 0, 0),
new TruncatedText(
theme.fg("muted", " ↑/↓: move. ←/→: page. l: label. ") +
theme.fg("dim", "^O/⇧^O") +
theme.fg("muted", ": filter. Type to search"),
0,
0,
),
);
this.addChild(new SearchLine(this.treeList));
this.addChild(new DynamicBorder());