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
15 changed files with 195 additions and 170 deletions
@@ -7,18 +7,22 @@ import { spawnSync } from "node:child_process";
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import { Container, Editor, getEditorKeybindings, matchesKey, Spacer, Text, type TUI } from "@mariozechner/pi-tui";
import { Container, Editor, getEditorKeybindings, Spacer, Text, type TUI } from "@mariozechner/pi-tui";
import type { KeybindingsManager } from "../../../core/keybindings.js";
import { getEditorTheme, theme } from "../theme/theme.js";
import { DynamicBorder } from "./dynamic-border.js";
import { appKeyHint, keyHint } from "./keybinding-hints.js";
export class ExtensionEditorComponent extends Container {
private editor: Editor;
private onSubmitCallback: (value: string) => void;
private onCancelCallback: () => void;
private tui: TUI;
private keybindings: KeybindingsManager;
constructor(
tui: TUI,
keybindings: KeybindingsManager,
title: string,
prefill: string | undefined,
onSubmit: (value: string) => void,
@@ -27,6 +31,7 @@ export class ExtensionEditorComponent extends Container {
super();
this.tui = tui;
this.keybindings = keybindings;
this.onSubmitCallback = onSubmit;
this.onCancelCallback = onCancel;
@@ -53,10 +58,14 @@ export class ExtensionEditorComponent extends Container {
// Add hint
const hasExternalEditor = !!(process.env.VISUAL || process.env.EDITOR);
const hint = hasExternalEditor
? "enter submit shift+enter newline esc cancel ctrl+g external editor"
: "enter submit shift+enter newline esc cancel";
this.addChild(new Text(theme.fg("dim", hint), 1, 0));
const hint =
keyHint("selectConfirm", "submit") +
" " +
keyHint("newLine", "newline") +
" " +
keyHint("selectCancel", "cancel") +
(hasExternalEditor ? ` ${appKeyHint(this.keybindings, "externalEditor", "external editor")}` : "");
this.addChild(new Text(hint, 1, 0));
this.addChild(new Spacer(1));
@@ -72,8 +81,8 @@ export class ExtensionEditorComponent extends Container {
return;
}
// Ctrl+G for external editor (keep matchesKey for this app-specific action)
if (matchesKey(keyData, "ctrl+g")) {
// External editor (app keybinding)
if (this.keybindings.matches(keyData, "externalEditor")) {
this.openExternalEditor();
return;
}