1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
import { CustomEditor, type ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { matchesKey, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
const NORMAL_KEYS: Record<string, string | null> = {
h: "\x1b[D",
j: "\x1b[B",
k: "\x1b[A",
l: "\x1b[C",
"0": "\x01",
$: "\x05",
x: "\x1b[3~",
i: null,
a: null,
};
class ModalEditor extends CustomEditor {
private mode: "normal" | "insert" = "insert";
handleInput(data: string): void {
if (matchesKey(data, "escape")) {
if (this.mode === "insert") {
this.mode = "normal";
} else {
super.handleInput(data);
}
return;
}
if (this.mode === "insert") {
super.handleInput(data);
return;
}
if (data in NORMAL_KEYS) {
const seq = NORMAL_KEYS[data];
if (data === "i") {
this.mode = "insert";
} else if (data === "a") {
this.mode = "insert";
super.handleInput("\x1b[C");
} else if (seq) {
super.handleInput(seq);
}
return;
}
if (data.length === 1 && data.charCodeAt(0) >= 32) return;
super.handleInput(data);
}
render(width: number): string[] {
const lines = super.render(width);
if (lines.length === 0) return lines;
const label = this.mode === "normal" ? " NORMAL " : " INSERT ";
const last = lines.length - 1;
if (visibleWidth(lines[last]!) >= label.length) {
lines[last] = truncateToWidth(lines[last]!, width - label.length, "") + label;
}
return lines;
}
}
export default function (pi: ExtensionAPI) {
pi.on("session_start", (_event, ctx) => {
ctx.ui.setEditorComponent((tui, theme, kb) => new ModalEditor(tui, theme, kb));
});
}
|