@kolisachint/hoocode-tui 0.5.67 → 0.5.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/editor.d.ts +16 -0
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +35 -4
- package/dist/components/editor.js.map +1 -1
- package/dist/components/spacer.d.ts +31 -0
- package/dist/components/spacer.d.ts.map +1 -1
- package/dist/components/spacer.js +44 -0
- package/dist/components/spacer.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/keybindings.d.ts +9 -4
- package/dist/keybindings.d.ts.map +1 -1
- package/dist/keybindings.js +14 -2
- package/dist/keybindings.js.map +1 -1
- package/dist/mouse.d.ts +75 -0
- package/dist/mouse.d.ts.map +1 -0
- package/dist/mouse.js +115 -0
- package/dist/mouse.js.map +1 -0
- package/dist/terminal.d.ts +30 -0
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +49 -0
- package/dist/terminal.js.map +1 -1
- package/dist/tui.d.ts +335 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +712 -1
- package/dist/tui.js.map +1 -1
- package/dist/undo-stack.d.ts +39 -6
- package/dist/undo-stack.d.ts.map +1 -1
- package/dist/undo-stack.js +59 -6
- package/dist/undo-stack.js.map +1 -1
- package/package.json +1 -1
|
@@ -10,4 +10,35 @@ export declare class Spacer implements Component {
|
|
|
10
10
|
invalidate(): void;
|
|
11
11
|
render(_width: number): string[];
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* A spacer whose height the renderer decides, so the layout can fill the screen.
|
|
15
|
+
*
|
|
16
|
+
* ## Why the renderer and not the layout
|
|
17
|
+
*
|
|
18
|
+
* The app is a full-screen one: whatever is at the top of the tree belongs at
|
|
19
|
+
* the top of the terminal and the prompt belongs on the bottom row, with the
|
|
20
|
+
* conversation between them. Nothing in the component tree can work that out on
|
|
21
|
+
* its own — the height it has to make up is the terminal's height minus the
|
|
22
|
+
* height of *every other child*, which is only known once they have all
|
|
23
|
+
* rendered. So the root measures the frame it just built and tells this spacer
|
|
24
|
+
* what is left over (`TUI.setFlexSpacer`).
|
|
25
|
+
*
|
|
26
|
+
* Put one child of the root between the part that flows from the top and the
|
|
27
|
+
* chrome that hangs off the bottom. Once the content is taller than the screen
|
|
28
|
+
* the height settles at 0 and this costs nothing.
|
|
29
|
+
*
|
|
30
|
+
* `setHeight` reports whether it moved, because the root's flat cache compares
|
|
31
|
+
* child output by array identity: handing back a fresh array for an unchanged
|
|
32
|
+
* height would mark the whole tail of the buffer dirty on every single frame.
|
|
33
|
+
*/
|
|
34
|
+
export declare class FlexSpacer implements Component {
|
|
35
|
+
private height;
|
|
36
|
+
private lines;
|
|
37
|
+
/** Rows it is currently contributing. */
|
|
38
|
+
get currentHeight(): number;
|
|
39
|
+
/** Set the fill; true when it changed and a re-flatten is owed. */
|
|
40
|
+
setHeight(height: number): boolean;
|
|
41
|
+
invalidate(): void;
|
|
42
|
+
render(_width: number): string[];
|
|
43
|
+
}
|
|
13
44
|
//# sourceMappingURL=spacer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spacer.d.ts","sourceRoot":"","sources":["../../src/components/spacer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C;;GAEG;AACH,qBAAa,MAAO,YAAW,SAAS;IACvC,OAAO,CAAC,KAAK,CAAS;IAEtB,YAAY,KAAK,GAAE,MAAU,EAE5B;IAGD,OAAO,CAAC,MAAM,CAAC,CAAW;IAE1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG5B;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAS/B;CACD","sourcesContent":["import type { Component } from \"../tui.js\";\n\n/**\n * Spacer component that renders empty lines\n */\nexport class Spacer implements Component {\n\tprivate lines: number;\n\n\tconstructor(lines: number = 1) {\n\t\tthis.lines = lines;\n\t}\n\n\t// Cached so repeated renders stay reference-stable (parents memoize by ref).\n\tprivate cached?: string[];\n\n\tsetLines(lines: number): void {\n\t\tthis.lines = lines;\n\t\tthis.cached = undefined;\n\t}\n\n\tinvalidate(): void {\n\t\t// Output depends only on `lines`; keep the cache.\n\t}\n\n\trender(_width: number): string[] {\n\t\tif (!this.cached || this.cached.length !== this.lines) {\n\t\t\tconst result: string[] = [];\n\t\t\tfor (let i = 0; i < this.lines; i++) {\n\t\t\t\tresult.push(\"\");\n\t\t\t}\n\t\t\tthis.cached = result;\n\t\t}\n\t\treturn this.cached;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"spacer.d.ts","sourceRoot":"","sources":["../../src/components/spacer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C;;GAEG;AACH,qBAAa,MAAO,YAAW,SAAS;IACvC,OAAO,CAAC,KAAK,CAAS;IAEtB,YAAY,KAAK,GAAE,MAAU,EAE5B;IAGD,OAAO,CAAC,MAAM,CAAC,CAAW;IAE1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG5B;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAS/B;CACD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,UAAW,YAAW,SAAS;IAC3C,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAAgB;IAE7B,yCAAyC;IACzC,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,mEAAmE;IACnE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAMjC;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAE/B;CACD","sourcesContent":["import type { Component } from \"../tui.js\";\n\n/**\n * Spacer component that renders empty lines\n */\nexport class Spacer implements Component {\n\tprivate lines: number;\n\n\tconstructor(lines: number = 1) {\n\t\tthis.lines = lines;\n\t}\n\n\t// Cached so repeated renders stay reference-stable (parents memoize by ref).\n\tprivate cached?: string[];\n\n\tsetLines(lines: number): void {\n\t\tthis.lines = lines;\n\t\tthis.cached = undefined;\n\t}\n\n\tinvalidate(): void {\n\t\t// Output depends only on `lines`; keep the cache.\n\t}\n\n\trender(_width: number): string[] {\n\t\tif (!this.cached || this.cached.length !== this.lines) {\n\t\t\tconst result: string[] = [];\n\t\t\tfor (let i = 0; i < this.lines; i++) {\n\t\t\t\tresult.push(\"\");\n\t\t\t}\n\t\t\tthis.cached = result;\n\t\t}\n\t\treturn this.cached;\n\t}\n}\n\n/**\n * A spacer whose height the renderer decides, so the layout can fill the screen.\n *\n * ## Why the renderer and not the layout\n *\n * The app is a full-screen one: whatever is at the top of the tree belongs at\n * the top of the terminal and the prompt belongs on the bottom row, with the\n * conversation between them. Nothing in the component tree can work that out on\n * its own — the height it has to make up is the terminal's height minus the\n * height of *every other child*, which is only known once they have all\n * rendered. So the root measures the frame it just built and tells this spacer\n * what is left over (`TUI.setFlexSpacer`).\n *\n * Put one child of the root between the part that flows from the top and the\n * chrome that hangs off the bottom. Once the content is taller than the screen\n * the height settles at 0 and this costs nothing.\n *\n * `setHeight` reports whether it moved, because the root's flat cache compares\n * child output by array identity: handing back a fresh array for an unchanged\n * height would mark the whole tail of the buffer dirty on every single frame.\n */\nexport class FlexSpacer implements Component {\n\tprivate height = 0;\n\tprivate lines: string[] = [];\n\n\t/** Rows it is currently contributing. */\n\tget currentHeight(): number {\n\t\treturn this.height;\n\t}\n\n\t/** Set the fill; true when it changed and a re-flatten is owed. */\n\tsetHeight(height: number): boolean {\n\t\tconst next = Math.max(0, Math.floor(height));\n\t\tif (next === this.height) return false;\n\t\tthis.height = next;\n\t\tthis.lines = new Array<string>(next).fill(\"\");\n\t\treturn true;\n\t}\n\n\tinvalidate(): void {\n\t\t// Output depends only on `height`; the blank rows never restyle.\n\t}\n\n\trender(_width: number): string[] {\n\t\treturn this.lines;\n\t}\n}\n"]}
|
|
@@ -26,4 +26,48 @@ export class Spacer {
|
|
|
26
26
|
return this.cached;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* A spacer whose height the renderer decides, so the layout can fill the screen.
|
|
31
|
+
*
|
|
32
|
+
* ## Why the renderer and not the layout
|
|
33
|
+
*
|
|
34
|
+
* The app is a full-screen one: whatever is at the top of the tree belongs at
|
|
35
|
+
* the top of the terminal and the prompt belongs on the bottom row, with the
|
|
36
|
+
* conversation between them. Nothing in the component tree can work that out on
|
|
37
|
+
* its own — the height it has to make up is the terminal's height minus the
|
|
38
|
+
* height of *every other child*, which is only known once they have all
|
|
39
|
+
* rendered. So the root measures the frame it just built and tells this spacer
|
|
40
|
+
* what is left over (`TUI.setFlexSpacer`).
|
|
41
|
+
*
|
|
42
|
+
* Put one child of the root between the part that flows from the top and the
|
|
43
|
+
* chrome that hangs off the bottom. Once the content is taller than the screen
|
|
44
|
+
* the height settles at 0 and this costs nothing.
|
|
45
|
+
*
|
|
46
|
+
* `setHeight` reports whether it moved, because the root's flat cache compares
|
|
47
|
+
* child output by array identity: handing back a fresh array for an unchanged
|
|
48
|
+
* height would mark the whole tail of the buffer dirty on every single frame.
|
|
49
|
+
*/
|
|
50
|
+
export class FlexSpacer {
|
|
51
|
+
height = 0;
|
|
52
|
+
lines = [];
|
|
53
|
+
/** Rows it is currently contributing. */
|
|
54
|
+
get currentHeight() {
|
|
55
|
+
return this.height;
|
|
56
|
+
}
|
|
57
|
+
/** Set the fill; true when it changed and a re-flatten is owed. */
|
|
58
|
+
setHeight(height) {
|
|
59
|
+
const next = Math.max(0, Math.floor(height));
|
|
60
|
+
if (next === this.height)
|
|
61
|
+
return false;
|
|
62
|
+
this.height = next;
|
|
63
|
+
this.lines = new Array(next).fill("");
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
invalidate() {
|
|
67
|
+
// Output depends only on `height`; the blank rows never restyle.
|
|
68
|
+
}
|
|
69
|
+
render(_width) {
|
|
70
|
+
return this.lines;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
29
73
|
//# sourceMappingURL=spacer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spacer.js","sourceRoot":"","sources":["../../src/components/spacer.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,OAAO,MAAM;IACV,KAAK,CAAS;IAEtB,YAAY,KAAK,GAAW,CAAC,EAAE;QAC9B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAAA,CACnB;IAED,6EAA6E;IACrE,MAAM,CAAY;IAE1B,QAAQ,CAAC,KAAa,EAAQ;QAC7B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IAAA,CACxB;IAED,UAAU,GAAS;QAClB,kDAAkD;IAD/B,CAEnB;IAED,MAAM,CAAC,MAAc,EAAY;QAChC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;YACvD,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACjB,CAAC;YACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACtB,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC;IAAA,CACnB;CACD","sourcesContent":["import type { Component } from \"../tui.js\";\n\n/**\n * Spacer component that renders empty lines\n */\nexport class Spacer implements Component {\n\tprivate lines: number;\n\n\tconstructor(lines: number = 1) {\n\t\tthis.lines = lines;\n\t}\n\n\t// Cached so repeated renders stay reference-stable (parents memoize by ref).\n\tprivate cached?: string[];\n\n\tsetLines(lines: number): void {\n\t\tthis.lines = lines;\n\t\tthis.cached = undefined;\n\t}\n\n\tinvalidate(): void {\n\t\t// Output depends only on `lines`; keep the cache.\n\t}\n\n\trender(_width: number): string[] {\n\t\tif (!this.cached || this.cached.length !== this.lines) {\n\t\t\tconst result: string[] = [];\n\t\t\tfor (let i = 0; i < this.lines; i++) {\n\t\t\t\tresult.push(\"\");\n\t\t\t}\n\t\t\tthis.cached = result;\n\t\t}\n\t\treturn this.cached;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"spacer.js","sourceRoot":"","sources":["../../src/components/spacer.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,OAAO,MAAM;IACV,KAAK,CAAS;IAEtB,YAAY,KAAK,GAAW,CAAC,EAAE;QAC9B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAAA,CACnB;IAED,6EAA6E;IACrE,MAAM,CAAY;IAE1B,QAAQ,CAAC,KAAa,EAAQ;QAC7B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IAAA,CACxB;IAED,UAAU,GAAS;QAClB,kDAAkD;IAD/B,CAEnB;IAED,MAAM,CAAC,MAAc,EAAY;QAChC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;YACvD,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACjB,CAAC;YACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACtB,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC;IAAA,CACnB;CACD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,UAAU;IACd,MAAM,GAAG,CAAC,CAAC;IACX,KAAK,GAAa,EAAE,CAAC;IAE7B,yCAAyC;IACzC,IAAI,aAAa,GAAW;QAC3B,OAAO,IAAI,CAAC,MAAM,CAAC;IAAA,CACnB;IAED,mEAAmE;IACnE,SAAS,CAAC,MAAc,EAAW;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7C,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAS,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC;IAAA,CACZ;IAED,UAAU,GAAS;QAClB,iEAAiE;IAD9C,CAEnB;IAED,MAAM,CAAC,MAAc,EAAY;QAChC,OAAO,IAAI,CAAC,KAAK,CAAC;IAAA,CAClB;CACD","sourcesContent":["import type { Component } from \"../tui.js\";\n\n/**\n * Spacer component that renders empty lines\n */\nexport class Spacer implements Component {\n\tprivate lines: number;\n\n\tconstructor(lines: number = 1) {\n\t\tthis.lines = lines;\n\t}\n\n\t// Cached so repeated renders stay reference-stable (parents memoize by ref).\n\tprivate cached?: string[];\n\n\tsetLines(lines: number): void {\n\t\tthis.lines = lines;\n\t\tthis.cached = undefined;\n\t}\n\n\tinvalidate(): void {\n\t\t// Output depends only on `lines`; keep the cache.\n\t}\n\n\trender(_width: number): string[] {\n\t\tif (!this.cached || this.cached.length !== this.lines) {\n\t\t\tconst result: string[] = [];\n\t\t\tfor (let i = 0; i < this.lines; i++) {\n\t\t\t\tresult.push(\"\");\n\t\t\t}\n\t\t\tthis.cached = result;\n\t\t}\n\t\treturn this.cached;\n\t}\n}\n\n/**\n * A spacer whose height the renderer decides, so the layout can fill the screen.\n *\n * ## Why the renderer and not the layout\n *\n * The app is a full-screen one: whatever is at the top of the tree belongs at\n * the top of the terminal and the prompt belongs on the bottom row, with the\n * conversation between them. Nothing in the component tree can work that out on\n * its own — the height it has to make up is the terminal's height minus the\n * height of *every other child*, which is only known once they have all\n * rendered. So the root measures the frame it just built and tells this spacer\n * what is left over (`TUI.setFlexSpacer`).\n *\n * Put one child of the root between the part that flows from the top and the\n * chrome that hangs off the bottom. Once the content is taller than the screen\n * the height settles at 0 and this costs nothing.\n *\n * `setHeight` reports whether it moved, because the root's flat cache compares\n * child output by array identity: handing back a fresh array for an unchanged\n * height would mark the whole tail of the buffer dirty on every single frame.\n */\nexport class FlexSpacer implements Component {\n\tprivate height = 0;\n\tprivate lines: string[] = [];\n\n\t/** Rows it is currently contributing. */\n\tget currentHeight(): number {\n\t\treturn this.height;\n\t}\n\n\t/** Set the fill; true when it changed and a re-flatten is owed. */\n\tsetHeight(height: number): boolean {\n\t\tconst next = Math.max(0, Math.floor(height));\n\t\tif (next === this.height) return false;\n\t\tthis.height = next;\n\t\tthis.lines = new Array<string>(next).fill(\"\");\n\t\treturn true;\n\t}\n\n\tinvalidate(): void {\n\t\t// Output depends only on `height`; the blank rows never restyle.\n\t}\n\n\trender(_width: number): string[] {\n\t\treturn this.lines;\n\t}\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,16 +9,17 @@ export { Loader, type LoaderIndicatorOptions } from "./components/loader.js";
|
|
|
9
9
|
export { type DefaultTextStyle, Markdown, type MarkdownTheme } from "./components/markdown.js";
|
|
10
10
|
export { type SelectItem, SelectList, type SelectListLayoutOptions, type SelectListTheme, type SelectListTruncatePrimaryContext, } from "./components/select-list.js";
|
|
11
11
|
export { type SettingItem, SettingsList, type SettingsListTheme } from "./components/settings-list.js";
|
|
12
|
-
export { Spacer } from "./components/spacer.js";
|
|
12
|
+
export { FlexSpacer, Spacer } from "./components/spacer.js";
|
|
13
13
|
export { Text } from "./components/text.js";
|
|
14
14
|
export { TruncatedText } from "./components/truncated-text.js";
|
|
15
15
|
export type { EditorComponent } from "./editor-component.js";
|
|
16
16
|
export { type FuzzyMatch, fuzzyFilter, fuzzyMatch } from "./fuzzy.js";
|
|
17
17
|
export { getKeybindings, type Keybinding, type KeybindingConflict, type KeybindingDefinition, type KeybindingDefinitions, type Keybindings, type KeybindingsConfig, KeybindingsManager, setKeybindings, TUI_KEYBINDINGS, } from "./keybindings.js";
|
|
18
18
|
export { decodeKittyPrintable, isKeyRelease, isKeyRepeat, isKittyProtocolActive, Key, type KeyEventType, type KeyId, matchesKey, parseKey, setKittyProtocolActive, } from "./keys.js";
|
|
19
|
+
export { isMouseSequence, MOUSE_DISABLE, MOUSE_ENABLE, type MouseEvent, type MouseEventKind, mouseSequenceLength, parseMouseEvent, } from "./mouse.js";
|
|
19
20
|
export { StdinBuffer, type StdinBufferEventMap, type StdinBufferOptions } from "./stdin-buffer.js";
|
|
20
21
|
export { ProcessTerminal, type Terminal } from "./terminal.js";
|
|
21
22
|
export { allocateImageId, type CellDimensions, calculateImageRows, deleteAllKittyImages, deleteKittyImage, detectCapabilities, encodeITerm2, encodeKitty, getCapabilities, getCellDimensions, getGifDimensions, getImageDimensions, getJpegDimensions, getPngDimensions, getWebpDimensions, hyperlink, type ImageDimensions, type ImageProtocol, type ImageRenderOptions, imageFallback, isImageLine, renderImage, resetCapabilitiesCache, setCapabilities, setCellDimensions, type TerminalCapabilities, } from "./terminal-image.js";
|
|
22
|
-
export { type Component, Container, CURSOR_MARKER, type Focusable, isFocusable, type OverlayAnchor, type OverlayHandle, type OverlayMargin, type OverlayOptions, type SizeValue, TUI, } from "./tui.js";
|
|
23
|
+
export { type Component, Container, CURSOR_MARKER, type Focusable, isFocusable, type OverlayAnchor, type OverlayHandle, type OverlayMargin, type OverlayOptions, type ScrollSearchStatus, type ScrollStatus, type ScrollStatusFormatter, type SizeValue, Slot, TUI, } from "./tui.js";
|
|
23
24
|
export { applyBackgroundToLine, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "./utils.js";
|
|
24
25
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,4BAA4B,EAC5B,KAAK,YAAY,GACjB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,GAAG,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EACN,2BAA2B,EAC3B,MAAM,EACN,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,oBAAoB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,0BAA0B,EAC1B,KAAK,EACL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,eAAe,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,KAAK,gBAAgB,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC/F,OAAO,EACN,KAAK,UAAU,EACf,UAAU,EACV,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,gCAAgC,GACrC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,KAAK,WAAW,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvG,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core TUI interfaces and classes\n\n// Autocomplete support\nexport {\n\ttype AutocompleteItem,\n\ttype AutocompleteProvider,\n\ttype AutocompleteSuggestions,\n\tCombinedAutocompleteProvider,\n\ttype SlashCommand,\n} from \"./autocomplete.js\";\n// Components\nexport { Box, type PaperSheet } from \"./components/box.js\";\nexport { CancellableLoader } from \"./components/cancellable-loader.js\";\nexport {\n\tDEFAULT_EDITOR_BORDER_CHARS,\n\tEditor,\n\ttype EditorBorderChars,\n\ttype EditorBorderStyle,\n\ttype EditorOptions,\n\ttype EditorTheme,\n\ttype EditorTopBorderLabel,\n} from \"./components/editor.js\";\nexport {\n\tDEFAULT_FRAME_BORDER_CHARS,\n\tFrame,\n\ttype FrameBorderChars,\n\ttype FrameBorderStyle,\n\ttype FrameEdgeOptions,\n\ttype FrameLabel,\n\ttype FrameOptions,\n\trenderFrameEdge,\n} from \"./components/frame.js\";\nexport { Image, type ImageOptions, type ImageTheme } from \"./components/image.js\";\nexport { Input } from \"./components/input.js\";\nexport { Loader, type LoaderIndicatorOptions } from \"./components/loader.js\";\nexport { type DefaultTextStyle, Markdown, type MarkdownTheme } from \"./components/markdown.js\";\nexport {\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\ttype SelectListTheme,\n\ttype SelectListTruncatePrimaryContext,\n} from \"./components/select-list.js\";\nexport { type SettingItem, SettingsList, type SettingsListTheme } from \"./components/settings-list.js\";\nexport { FlexSpacer, Spacer } from \"./components/spacer.js\";\nexport { Text } from \"./components/text.js\";\nexport { TruncatedText } from \"./components/truncated-text.js\";\n// Editor component interface (for custom editors)\nexport type { EditorComponent } from \"./editor-component.js\";\n// Fuzzy matching\nexport { type FuzzyMatch, fuzzyFilter, fuzzyMatch } from \"./fuzzy.js\";\n// Keybindings\nexport {\n\tgetKeybindings,\n\ttype Keybinding,\n\ttype KeybindingConflict,\n\ttype KeybindingDefinition,\n\ttype KeybindingDefinitions,\n\ttype Keybindings,\n\ttype KeybindingsConfig,\n\tKeybindingsManager,\n\tsetKeybindings,\n\tTUI_KEYBINDINGS,\n} from \"./keybindings.js\";\n// Keyboard input handling\nexport {\n\tdecodeKittyPrintable,\n\tisKeyRelease,\n\tisKeyRepeat,\n\tisKittyProtocolActive,\n\tKey,\n\ttype KeyEventType,\n\ttype KeyId,\n\tmatchesKey,\n\tparseKey,\n\tsetKittyProtocolActive,\n} from \"./keys.js\";\n// Input buffering for batch splitting\n// Mouse reporting\nexport {\n\tisMouseSequence,\n\tMOUSE_DISABLE,\n\tMOUSE_ENABLE,\n\ttype MouseEvent,\n\ttype MouseEventKind,\n\tmouseSequenceLength,\n\tparseMouseEvent,\n} from \"./mouse.js\";\nexport { StdinBuffer, type StdinBufferEventMap, type StdinBufferOptions } from \"./stdin-buffer.js\";\n// Terminal interface and implementations\nexport { ProcessTerminal, type Terminal } from \"./terminal.js\";\n// Terminal image support\nexport {\n\tallocateImageId,\n\ttype CellDimensions,\n\tcalculateImageRows,\n\tdeleteAllKittyImages,\n\tdeleteKittyImage,\n\tdetectCapabilities,\n\tencodeITerm2,\n\tencodeKitty,\n\tgetCapabilities,\n\tgetCellDimensions,\n\tgetGifDimensions,\n\tgetImageDimensions,\n\tgetJpegDimensions,\n\tgetPngDimensions,\n\tgetWebpDimensions,\n\thyperlink,\n\ttype ImageDimensions,\n\ttype ImageProtocol,\n\ttype ImageRenderOptions,\n\timageFallback,\n\tisImageLine,\n\trenderImage,\n\tresetCapabilitiesCache,\n\tsetCapabilities,\n\tsetCellDimensions,\n\ttype TerminalCapabilities,\n} from \"./terminal-image.js\";\nexport {\n\ttype Component,\n\tContainer,\n\tCURSOR_MARKER,\n\ttype Focusable,\n\tisFocusable,\n\ttype OverlayAnchor,\n\ttype OverlayHandle,\n\ttype OverlayMargin,\n\ttype OverlayOptions,\n\ttype ScrollSearchStatus,\n\ttype ScrollStatus,\n\ttype ScrollStatusFormatter,\n\ttype SizeValue,\n\tSlot,\n\tTUI,\n} from \"./tui.js\";\n// Utilities\nexport { applyBackgroundToLine, truncateToWidth, visibleWidth, wrapTextWithAnsi } from \"./utils.js\";\n"]}
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ export { Loader } from "./components/loader.js";
|
|
|
12
12
|
export { Markdown } from "./components/markdown.js";
|
|
13
13
|
export { SelectList, } from "./components/select-list.js";
|
|
14
14
|
export { SettingsList } from "./components/settings-list.js";
|
|
15
|
-
export { Spacer } from "./components/spacer.js";
|
|
15
|
+
export { FlexSpacer, Spacer } from "./components/spacer.js";
|
|
16
16
|
export { Text } from "./components/text.js";
|
|
17
17
|
export { TruncatedText } from "./components/truncated-text.js";
|
|
18
18
|
// Fuzzy matching
|
|
@@ -22,12 +22,14 @@ export { getKeybindings, KeybindingsManager, setKeybindings, TUI_KEYBINDINGS, }
|
|
|
22
22
|
// Keyboard input handling
|
|
23
23
|
export { decodeKittyPrintable, isKeyRelease, isKeyRepeat, isKittyProtocolActive, Key, matchesKey, parseKey, setKittyProtocolActive, } from "./keys.js";
|
|
24
24
|
// Input buffering for batch splitting
|
|
25
|
+
// Mouse reporting
|
|
26
|
+
export { isMouseSequence, MOUSE_DISABLE, MOUSE_ENABLE, mouseSequenceLength, parseMouseEvent, } from "./mouse.js";
|
|
25
27
|
export { StdinBuffer } from "./stdin-buffer.js";
|
|
26
28
|
// Terminal interface and implementations
|
|
27
29
|
export { ProcessTerminal } from "./terminal.js";
|
|
28
30
|
// Terminal image support
|
|
29
31
|
export { allocateImageId, calculateImageRows, deleteAllKittyImages, deleteKittyImage, detectCapabilities, encodeITerm2, encodeKitty, getCapabilities, getCellDimensions, getGifDimensions, getImageDimensions, getJpegDimensions, getPngDimensions, getWebpDimensions, hyperlink, imageFallback, isImageLine, renderImage, resetCapabilitiesCache, setCapabilities, setCellDimensions, } from "./terminal-image.js";
|
|
30
|
-
export { Container, CURSOR_MARKER, isFocusable, TUI, } from "./tui.js";
|
|
32
|
+
export { Container, CURSOR_MARKER, isFocusable, Slot, TUI, } from "./tui.js";
|
|
31
33
|
// Utilities
|
|
32
34
|
export { applyBackgroundToLine, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "./utils.js";
|
|
33
35
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAElC,uBAAuB;AACvB,OAAO,EAIN,4BAA4B,GAE5B,MAAM,mBAAmB,CAAC;AAC3B,aAAa;AACb,OAAO,EAAE,GAAG,EAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EACN,2BAA2B,EAC3B,MAAM,GAMN,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,0BAA0B,EAC1B,KAAK,EAML,eAAe,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAsC,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAA+B,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAyB,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AAC/F,OAAO,EAEN,UAAU,GAIV,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAoB,YAAY,EAA0B,MAAM,+BAA+B,CAAC;AACvG,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAElC,uBAAuB;AACvB,OAAO,EAIN,4BAA4B,GAE5B,MAAM,mBAAmB,CAAC;AAC3B,aAAa;AACb,OAAO,EAAE,GAAG,EAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EACN,2BAA2B,EAC3B,MAAM,GAMN,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACN,0BAA0B,EAC1B,KAAK,EAML,eAAe,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAsC,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAA+B,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAyB,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AAC/F,OAAO,EAEN,UAAU,GAIV,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAoB,YAAY,EAA0B,MAAM,+BAA+B,CAAC;AACvG,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAG/D,iBAAiB;AACjB,OAAO,EAAmB,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACtE,cAAc;AACd,OAAO,EACN,cAAc,EAOd,kBAAkB,EAClB,cAAc,EACd,eAAe,GACf,MAAM,kBAAkB,CAAC;AAC1B,0BAA0B;AAC1B,OAAO,EACN,oBAAoB,EACpB,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,GAAG,EAGH,UAAU,EACV,QAAQ,EACR,sBAAsB,GACtB,MAAM,WAAW,CAAC;AACnB,sCAAsC;AACtC,kBAAkB;AAClB,OAAO,EACN,eAAe,EACf,aAAa,EACb,YAAY,EAGZ,mBAAmB,EACnB,eAAe,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAqD,MAAM,mBAAmB,CAAC;AACnG,yCAAyC;AACzC,OAAO,EAAE,eAAe,EAAiB,MAAM,eAAe,CAAC;AAC/D,yBAAyB;AACzB,OAAO,EACN,eAAe,EAEf,kBAAkB,EAClB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,EAIT,aAAa,EACb,WAAW,EACX,WAAW,EACX,sBAAsB,EACtB,eAAe,EACf,iBAAiB,GAEjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEN,SAAS,EACT,aAAa,EAEb,WAAW,EASX,IAAI,EACJ,GAAG,GACH,MAAM,UAAU,CAAC;AAClB,YAAY;AACZ,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC","sourcesContent":["// Core TUI interfaces and classes\n\n// Autocomplete support\nexport {\n\ttype AutocompleteItem,\n\ttype AutocompleteProvider,\n\ttype AutocompleteSuggestions,\n\tCombinedAutocompleteProvider,\n\ttype SlashCommand,\n} from \"./autocomplete.js\";\n// Components\nexport { Box, type PaperSheet } from \"./components/box.js\";\nexport { CancellableLoader } from \"./components/cancellable-loader.js\";\nexport {\n\tDEFAULT_EDITOR_BORDER_CHARS,\n\tEditor,\n\ttype EditorBorderChars,\n\ttype EditorBorderStyle,\n\ttype EditorOptions,\n\ttype EditorTheme,\n\ttype EditorTopBorderLabel,\n} from \"./components/editor.js\";\nexport {\n\tDEFAULT_FRAME_BORDER_CHARS,\n\tFrame,\n\ttype FrameBorderChars,\n\ttype FrameBorderStyle,\n\ttype FrameEdgeOptions,\n\ttype FrameLabel,\n\ttype FrameOptions,\n\trenderFrameEdge,\n} from \"./components/frame.js\";\nexport { Image, type ImageOptions, type ImageTheme } from \"./components/image.js\";\nexport { Input } from \"./components/input.js\";\nexport { Loader, type LoaderIndicatorOptions } from \"./components/loader.js\";\nexport { type DefaultTextStyle, Markdown, type MarkdownTheme } from \"./components/markdown.js\";\nexport {\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\ttype SelectListTheme,\n\ttype SelectListTruncatePrimaryContext,\n} from \"./components/select-list.js\";\nexport { type SettingItem, SettingsList, type SettingsListTheme } from \"./components/settings-list.js\";\nexport { FlexSpacer, Spacer } from \"./components/spacer.js\";\nexport { Text } from \"./components/text.js\";\nexport { TruncatedText } from \"./components/truncated-text.js\";\n// Editor component interface (for custom editors)\nexport type { EditorComponent } from \"./editor-component.js\";\n// Fuzzy matching\nexport { type FuzzyMatch, fuzzyFilter, fuzzyMatch } from \"./fuzzy.js\";\n// Keybindings\nexport {\n\tgetKeybindings,\n\ttype Keybinding,\n\ttype KeybindingConflict,\n\ttype KeybindingDefinition,\n\ttype KeybindingDefinitions,\n\ttype Keybindings,\n\ttype KeybindingsConfig,\n\tKeybindingsManager,\n\tsetKeybindings,\n\tTUI_KEYBINDINGS,\n} from \"./keybindings.js\";\n// Keyboard input handling\nexport {\n\tdecodeKittyPrintable,\n\tisKeyRelease,\n\tisKeyRepeat,\n\tisKittyProtocolActive,\n\tKey,\n\ttype KeyEventType,\n\ttype KeyId,\n\tmatchesKey,\n\tparseKey,\n\tsetKittyProtocolActive,\n} from \"./keys.js\";\n// Input buffering for batch splitting\n// Mouse reporting\nexport {\n\tisMouseSequence,\n\tMOUSE_DISABLE,\n\tMOUSE_ENABLE,\n\ttype MouseEvent,\n\ttype MouseEventKind,\n\tmouseSequenceLength,\n\tparseMouseEvent,\n} from \"./mouse.js\";\nexport { StdinBuffer, type StdinBufferEventMap, type StdinBufferOptions } from \"./stdin-buffer.js\";\n// Terminal interface and implementations\nexport { ProcessTerminal, type Terminal } from \"./terminal.js\";\n// Terminal image support\nexport {\n\tallocateImageId,\n\ttype CellDimensions,\n\tcalculateImageRows,\n\tdeleteAllKittyImages,\n\tdeleteKittyImage,\n\tdetectCapabilities,\n\tencodeITerm2,\n\tencodeKitty,\n\tgetCapabilities,\n\tgetCellDimensions,\n\tgetGifDimensions,\n\tgetImageDimensions,\n\tgetJpegDimensions,\n\tgetPngDimensions,\n\tgetWebpDimensions,\n\thyperlink,\n\ttype ImageDimensions,\n\ttype ImageProtocol,\n\ttype ImageRenderOptions,\n\timageFallback,\n\tisImageLine,\n\trenderImage,\n\tresetCapabilitiesCache,\n\tsetCapabilities,\n\tsetCellDimensions,\n\ttype TerminalCapabilities,\n} from \"./terminal-image.js\";\nexport {\n\ttype Component,\n\tContainer,\n\tCURSOR_MARKER,\n\ttype Focusable,\n\tisFocusable,\n\ttype OverlayAnchor,\n\ttype OverlayHandle,\n\ttype OverlayMargin,\n\ttype OverlayOptions,\n\ttype ScrollSearchStatus,\n\ttype ScrollStatus,\n\ttype ScrollStatusFormatter,\n\ttype SizeValue,\n\tSlot,\n\tTUI,\n} from \"./tui.js\";\n// Utilities\nexport { applyBackgroundToLine, truncateToWidth, visibleWidth, wrapTextWithAnsi } from \"./utils.js\";\n"]}
|
package/dist/keybindings.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export interface Keybindings {
|
|
|
25
25
|
"tui.editor.yank": true;
|
|
26
26
|
"tui.editor.yankPop": true;
|
|
27
27
|
"tui.editor.undo": true;
|
|
28
|
+
"tui.editor.redo": true;
|
|
28
29
|
"tui.input.newLine": true;
|
|
29
30
|
"tui.input.submit": true;
|
|
30
31
|
"tui.input.tab": true;
|
|
@@ -85,12 +86,12 @@ export declare const TUI_KEYBINDINGS: {
|
|
|
85
86
|
readonly description: "Jump backward to character";
|
|
86
87
|
};
|
|
87
88
|
readonly "tui.editor.pageUp": {
|
|
88
|
-
readonly defaultKeys:
|
|
89
|
-
readonly description: "Page up";
|
|
89
|
+
readonly defaultKeys: [];
|
|
90
|
+
readonly description: "Page up within the prompt";
|
|
90
91
|
};
|
|
91
92
|
readonly "tui.editor.pageDown": {
|
|
92
|
-
readonly defaultKeys:
|
|
93
|
-
readonly description: "Page down";
|
|
93
|
+
readonly defaultKeys: [];
|
|
94
|
+
readonly description: "Page down within the prompt";
|
|
94
95
|
};
|
|
95
96
|
readonly "tui.editor.deleteCharBackward": {
|
|
96
97
|
readonly defaultKeys: "backspace";
|
|
@@ -128,6 +129,10 @@ export declare const TUI_KEYBINDINGS: {
|
|
|
128
129
|
readonly defaultKeys: "ctrl+-";
|
|
129
130
|
readonly description: "Undo";
|
|
130
131
|
};
|
|
132
|
+
readonly "tui.editor.redo": {
|
|
133
|
+
readonly defaultKeys: "alt+u";
|
|
134
|
+
readonly description: "Redo";
|
|
135
|
+
};
|
|
131
136
|
readonly "tui.input.newLine": {
|
|
132
137
|
readonly defaultKeys: "shift+enter";
|
|
133
138
|
readonly description: "Insert newline";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"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","sourcesContent":["import { type KeyId, matchesKey } from \"./keys.js\";\n\n/**\n * Global keybinding registry.\n * Downstream packages can add keybindings via declaration merging.\n */\nexport interface Keybindings {\n\t// Editor navigation and editing\n\t\"tui.editor.cursorUp\": true;\n\t\"tui.editor.cursorDown\": true;\n\t\"tui.editor.cursorLeft\": true;\n\t\"tui.editor.cursorRight\": true;\n\t\"tui.editor.cursorWordLeft\": true;\n\t\"tui.editor.cursorWordRight\": true;\n\t\"tui.editor.cursorLineStart\": true;\n\t\"tui.editor.cursorLineEnd\": true;\n\t\"tui.editor.jumpForward\": true;\n\t\"tui.editor.jumpBackward\": true;\n\t\"tui.editor.pageUp\": true;\n\t\"tui.editor.pageDown\": true;\n\t\"tui.editor.deleteCharBackward\": true;\n\t\"tui.editor.deleteCharForward\": true;\n\t\"tui.editor.deleteWordBackward\": true;\n\t\"tui.editor.deleteWordForward\": true;\n\t\"tui.editor.deleteToLineStart\": true;\n\t\"tui.editor.deleteToLineEnd\": true;\n\t\"tui.editor.yank\": true;\n\t\"tui.editor.yankPop\": true;\n\t\"tui.editor.undo\": true;\n\t// Generic input actions\n\t\"tui.input.newLine\": true;\n\t\"tui.input.submit\": true;\n\t\"tui.input.tab\": true;\n\t\"tui.input.copy\": true;\n\t// Generic selection actions\n\t\"tui.select.up\": true;\n\t\"tui.select.down\": true;\n\t\"tui.select.pageUp\": true;\n\t\"tui.select.pageDown\": true;\n\t\"tui.select.confirm\": true;\n\t\"tui.select.cancel\": true;\n}\n\nexport type Keybinding = keyof Keybindings;\n\nexport interface KeybindingDefinition {\n\tdefaultKeys: KeyId | KeyId[];\n\tdescription?: string;\n}\n\nexport type KeybindingDefinitions = Record<string, KeybindingDefinition>;\nexport type KeybindingsConfig = Record<string, KeyId | KeyId[] | undefined>;\n\nexport const TUI_KEYBINDINGS = {\n\t\"tui.editor.cursorUp\": { defaultKeys: \"up\", description: \"Move cursor up\" },\n\t\"tui.editor.cursorDown\": { defaultKeys: \"down\", description: \"Move cursor down\" },\n\t\"tui.editor.cursorLeft\": {\n\t\tdefaultKeys: [\"left\", \"ctrl+b\"],\n\t\tdescription: \"Move cursor left\",\n\t},\n\t\"tui.editor.cursorRight\": {\n\t\tdefaultKeys: [\"right\", \"ctrl+f\"],\n\t\tdescription: \"Move cursor right\",\n\t},\n\t\"tui.editor.cursorWordLeft\": {\n\t\tdefaultKeys: [\"alt+left\", \"ctrl+left\", \"alt+b\"],\n\t\tdescription: \"Move cursor word left\",\n\t},\n\t\"tui.editor.cursorWordRight\": {\n\t\tdefaultKeys: [\"alt+right\", \"ctrl+right\", \"alt+f\"],\n\t\tdescription: \"Move cursor word right\",\n\t},\n\t\"tui.editor.cursorLineStart\": {\n\t\tdefaultKeys: [\"home\", \"ctrl+a\"],\n\t\tdescription: \"Move to line start\",\n\t},\n\t\"tui.editor.cursorLineEnd\": {\n\t\tdefaultKeys: [\"end\", \"ctrl+e\"],\n\t\tdescription: \"Move to line end\",\n\t},\n\t\"tui.editor.jumpForward\": {\n\t\tdefaultKeys: \"ctrl+]\",\n\t\tdescription: \"Jump forward to character\",\n\t},\n\t\"tui.editor.jumpBackward\": {\n\t\tdefaultKeys: \"ctrl+alt+]\",\n\t\tdescription: \"Jump backward to character\",\n\t},\n\t\"tui.editor.pageUp\": { defaultKeys: \"pageUp\", description: \"Page up\" },\n\t\"tui.editor.pageDown\": { defaultKeys: \"pageDown\", description: \"Page down\" },\n\t\"tui.editor.deleteCharBackward\": {\n\t\tdefaultKeys: \"backspace\",\n\t\tdescription: \"Delete character backward\",\n\t},\n\t\"tui.editor.deleteCharForward\": {\n\t\tdefaultKeys: [\"delete\", \"ctrl+d\"],\n\t\tdescription: \"Delete character forward\",\n\t},\n\t\"tui.editor.deleteWordBackward\": {\n\t\tdefaultKeys: [\"ctrl+w\", \"alt+backspace\"],\n\t\tdescription: \"Delete word backward\",\n\t},\n\t\"tui.editor.deleteWordForward\": {\n\t\tdefaultKeys: [\"alt+d\", \"alt+delete\"],\n\t\tdescription: \"Delete word forward\",\n\t},\n\t\"tui.editor.deleteToLineStart\": {\n\t\tdefaultKeys: \"ctrl+u\",\n\t\tdescription: \"Delete to line start\",\n\t},\n\t\"tui.editor.deleteToLineEnd\": {\n\t\tdefaultKeys: \"ctrl+k\",\n\t\tdescription: \"Delete to line end\",\n\t},\n\t\"tui.editor.yank\": { defaultKeys: \"ctrl+y\", description: \"Yank\" },\n\t\"tui.editor.yankPop\": { defaultKeys: \"alt+y\", description: \"Yank pop\" },\n\t\"tui.editor.undo\": { defaultKeys: \"ctrl+-\", description: \"Undo\" },\n\t\"tui.input.newLine\": { defaultKeys: \"shift+enter\", description: \"Insert newline\" },\n\t\"tui.input.submit\": { defaultKeys: \"enter\", description: \"Submit input\" },\n\t\"tui.input.tab\": { defaultKeys: \"tab\", description: \"Tab / autocomplete\" },\n\t\"tui.input.copy\": { defaultKeys: \"ctrl+c\", description: \"Copy selection\" },\n\t\"tui.select.up\": { defaultKeys: \"up\", description: \"Move selection up\" },\n\t\"tui.select.down\": { defaultKeys: \"down\", description: \"Move selection down\" },\n\t\"tui.select.pageUp\": { defaultKeys: \"pageUp\", description: \"Selection page up\" },\n\t\"tui.select.pageDown\": {\n\t\tdefaultKeys: \"pageDown\",\n\t\tdescription: \"Selection page down\",\n\t},\n\t\"tui.select.confirm\": { defaultKeys: \"enter\", description: \"Confirm selection\" },\n\t\"tui.select.cancel\": {\n\t\tdefaultKeys: [\"escape\", \"ctrl+c\"],\n\t\tdescription: \"Cancel selection\",\n\t},\n} as const satisfies KeybindingDefinitions;\n\nexport interface KeybindingConflict {\n\tkey: KeyId;\n\tkeybindings: string[];\n}\n\nfunction normalizeKeys(keys: KeyId | KeyId[] | undefined): KeyId[] {\n\tif (keys === undefined) return [];\n\tconst keyList = Array.isArray(keys) ? keys : [keys];\n\tconst seen = new Set<KeyId>();\n\tconst result: KeyId[] = [];\n\tfor (const key of keyList) {\n\t\tif (!seen.has(key)) {\n\t\t\tseen.add(key);\n\t\t\tresult.push(key);\n\t\t}\n\t}\n\treturn result;\n}\n\nexport class KeybindingsManager {\n\tprivate definitions: KeybindingDefinitions;\n\tprivate userBindings: KeybindingsConfig;\n\tprivate keysById = new Map<Keybinding, KeyId[]>();\n\tprivate conflicts: KeybindingConflict[] = [];\n\n\tconstructor(definitions: KeybindingDefinitions, userBindings: KeybindingsConfig = {}) {\n\t\tthis.definitions = definitions;\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\tthis.keysById.clear();\n\t\tthis.conflicts = [];\n\n\t\tconst userClaims = new Map<KeyId, Set<Keybinding>>();\n\t\tfor (const [keybinding, keys] of Object.entries(this.userBindings)) {\n\t\t\tif (!(keybinding in this.definitions)) continue;\n\t\t\tfor (const key of normalizeKeys(keys)) {\n\t\t\t\tconst claimants = userClaims.get(key) ?? new Set<Keybinding>();\n\t\t\t\tclaimants.add(keybinding as Keybinding);\n\t\t\t\tuserClaims.set(key, claimants);\n\t\t\t}\n\t\t}\n\n\t\tfor (const [key, keybindings] of userClaims) {\n\t\t\tif (keybindings.size > 1) {\n\t\t\t\tthis.conflicts.push({ key, keybindings: [...keybindings] });\n\t\t\t}\n\t\t}\n\n\t\tfor (const [id, definition] of Object.entries(this.definitions)) {\n\t\t\tconst userKeys = this.userBindings[id];\n\t\t\tconst keys = userKeys === undefined ? normalizeKeys(definition.defaultKeys) : normalizeKeys(userKeys);\n\t\t\tthis.keysById.set(id as Keybinding, keys);\n\t\t}\n\t}\n\n\tmatches(data: string, keybinding: Keybinding): boolean {\n\t\tconst keys = this.keysById.get(keybinding) ?? [];\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tgetKeys(keybinding: Keybinding): KeyId[] {\n\t\treturn [...(this.keysById.get(keybinding) ?? [])];\n\t}\n\n\tgetDefinition(keybinding: Keybinding): KeybindingDefinition {\n\t\treturn this.definitions[keybinding];\n\t}\n\n\tgetConflicts(): KeybindingConflict[] {\n\t\treturn this.conflicts.map((conflict) => ({ ...conflict, keybindings: [...conflict.keybindings] }));\n\t}\n\n\tsetUserBindings(userBindings: KeybindingsConfig): void {\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tgetUserBindings(): KeybindingsConfig {\n\t\treturn { ...this.userBindings };\n\t}\n\n\tgetResolvedBindings(): KeybindingsConfig {\n\t\tconst resolved: KeybindingsConfig = {};\n\t\tfor (const id of Object.keys(this.definitions)) {\n\t\t\tconst keys = this.keysById.get(id as Keybinding) ?? [];\n\t\t\tresolved[id] = keys.length === 1 ? keys[0]! : [...keys];\n\t\t}\n\t\treturn resolved;\n\t}\n}\n\nlet globalKeybindings: KeybindingsManager | null = null;\n\nexport function setKeybindings(keybindings: KeybindingsManager): void {\n\tglobalKeybindings = keybindings;\n}\n\nexport function getKeybindings(): KeybindingsManager {\n\tif (!globalKeybindings) {\n\t\tglobalKeybindings = new KeybindingsManager(TUI_KEYBINDINGS);\n\t}\n\treturn globalKeybindings;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"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","sourcesContent":["import { type KeyId, matchesKey } from \"./keys.js\";\n\n/**\n * Global keybinding registry.\n * Downstream packages can add keybindings via declaration merging.\n */\nexport interface Keybindings {\n\t// Editor navigation and editing\n\t\"tui.editor.cursorUp\": true;\n\t\"tui.editor.cursorDown\": true;\n\t\"tui.editor.cursorLeft\": true;\n\t\"tui.editor.cursorRight\": true;\n\t\"tui.editor.cursorWordLeft\": true;\n\t\"tui.editor.cursorWordRight\": true;\n\t\"tui.editor.cursorLineStart\": true;\n\t\"tui.editor.cursorLineEnd\": true;\n\t\"tui.editor.jumpForward\": true;\n\t\"tui.editor.jumpBackward\": true;\n\t\"tui.editor.pageUp\": true;\n\t\"tui.editor.pageDown\": true;\n\t\"tui.editor.deleteCharBackward\": true;\n\t\"tui.editor.deleteCharForward\": true;\n\t\"tui.editor.deleteWordBackward\": true;\n\t\"tui.editor.deleteWordForward\": true;\n\t\"tui.editor.deleteToLineStart\": true;\n\t\"tui.editor.deleteToLineEnd\": true;\n\t\"tui.editor.yank\": true;\n\t\"tui.editor.yankPop\": true;\n\t\"tui.editor.undo\": true;\n\t\"tui.editor.redo\": true;\n\t// Generic input actions\n\t\"tui.input.newLine\": true;\n\t\"tui.input.submit\": true;\n\t\"tui.input.tab\": true;\n\t\"tui.input.copy\": true;\n\t// Generic selection actions\n\t\"tui.select.up\": true;\n\t\"tui.select.down\": true;\n\t\"tui.select.pageUp\": true;\n\t\"tui.select.pageDown\": true;\n\t\"tui.select.confirm\": true;\n\t\"tui.select.cancel\": true;\n}\n\nexport type Keybinding = keyof Keybindings;\n\nexport interface KeybindingDefinition {\n\tdefaultKeys: KeyId | KeyId[];\n\tdescription?: string;\n}\n\nexport type KeybindingDefinitions = Record<string, KeybindingDefinition>;\nexport type KeybindingsConfig = Record<string, KeyId | KeyId[] | undefined>;\n\nexport const TUI_KEYBINDINGS = {\n\t\"tui.editor.cursorUp\": { defaultKeys: \"up\", description: \"Move cursor up\" },\n\t\"tui.editor.cursorDown\": { defaultKeys: \"down\", description: \"Move cursor down\" },\n\t\"tui.editor.cursorLeft\": {\n\t\tdefaultKeys: [\"left\", \"ctrl+b\"],\n\t\tdescription: \"Move cursor left\",\n\t},\n\t\"tui.editor.cursorRight\": {\n\t\tdefaultKeys: [\"right\", \"ctrl+f\"],\n\t\tdescription: \"Move cursor right\",\n\t},\n\t\"tui.editor.cursorWordLeft\": {\n\t\tdefaultKeys: [\"alt+left\", \"ctrl+left\", \"alt+b\"],\n\t\tdescription: \"Move cursor word left\",\n\t},\n\t\"tui.editor.cursorWordRight\": {\n\t\tdefaultKeys: [\"alt+right\", \"ctrl+right\", \"alt+f\"],\n\t\tdescription: \"Move cursor word right\",\n\t},\n\t\"tui.editor.cursorLineStart\": {\n\t\tdefaultKeys: [\"home\", \"ctrl+a\"],\n\t\tdescription: \"Move to line start\",\n\t},\n\t\"tui.editor.cursorLineEnd\": {\n\t\tdefaultKeys: [\"end\", \"ctrl+e\"],\n\t\tdescription: \"Move to line end\",\n\t},\n\t\"tui.editor.jumpForward\": {\n\t\tdefaultKeys: \"ctrl+]\",\n\t\tdescription: \"Jump forward to character\",\n\t},\n\t\"tui.editor.jumpBackward\": {\n\t\tdefaultKeys: \"ctrl+alt+]\",\n\t\tdescription: \"Jump backward to character\",\n\t},\n\t// Unbound by default. These page the cursor through the *prompt*, which is\n\t// one to three lines in almost every session, so the keys did nothing on\n\t// nearly every press — while pageUp/pageDown are the gesture everyone\n\t// already knows for \"show me what scrolled past\". The app gives them to the\n\t// transcript; bind these by hand if you write prompts tall enough to page.\n\t\"tui.editor.pageUp\": { defaultKeys: [], description: \"Page up within the prompt\" },\n\t\"tui.editor.pageDown\": { defaultKeys: [], description: \"Page down within the prompt\" },\n\t\"tui.editor.deleteCharBackward\": {\n\t\tdefaultKeys: \"backspace\",\n\t\tdescription: \"Delete character backward\",\n\t},\n\t\"tui.editor.deleteCharForward\": {\n\t\tdefaultKeys: [\"delete\", \"ctrl+d\"],\n\t\tdescription: \"Delete character forward\",\n\t},\n\t\"tui.editor.deleteWordBackward\": {\n\t\tdefaultKeys: [\"ctrl+w\", \"alt+backspace\"],\n\t\tdescription: \"Delete word backward\",\n\t},\n\t\"tui.editor.deleteWordForward\": {\n\t\tdefaultKeys: [\"alt+d\", \"alt+delete\"],\n\t\tdescription: \"Delete word forward\",\n\t},\n\t\"tui.editor.deleteToLineStart\": {\n\t\tdefaultKeys: \"ctrl+u\",\n\t\tdescription: \"Delete to line start\",\n\t},\n\t\"tui.editor.deleteToLineEnd\": {\n\t\tdefaultKeys: \"ctrl+k\",\n\t\tdescription: \"Delete to line end\",\n\t},\n\t\"tui.editor.yank\": { defaultKeys: \"ctrl+y\", description: \"Yank\" },\n\t\"tui.editor.yankPop\": { defaultKeys: \"alt+y\", description: \"Yank pop\" },\n\t\"tui.editor.undo\": { defaultKeys: \"ctrl+-\", description: \"Undo\" },\n\t// alt+u, not the shape-matching alt+- : `\\x1b-` is not a key this parser\n\t// reads, so alt+- would work only where the Kitty protocol does, and redo has\n\t// no other key to fall back on. The letters differ from undo's because\n\t// ctrl+- predates the pair and is in everyone's fingers already — the\n\t// asymmetry costs less than moving it would. ctrl+r, which vim users would\n\t// reach for, belongs to transcript search.\n\t\"tui.editor.redo\": { defaultKeys: \"alt+u\", description: \"Redo\" },\n\t\"tui.input.newLine\": { defaultKeys: \"shift+enter\", description: \"Insert newline\" },\n\t\"tui.input.submit\": { defaultKeys: \"enter\", description: \"Submit input\" },\n\t\"tui.input.tab\": { defaultKeys: \"tab\", description: \"Tab / autocomplete\" },\n\t\"tui.input.copy\": { defaultKeys: \"ctrl+c\", description: \"Copy selection\" },\n\t\"tui.select.up\": { defaultKeys: \"up\", description: \"Move selection up\" },\n\t\"tui.select.down\": { defaultKeys: \"down\", description: \"Move selection down\" },\n\t\"tui.select.pageUp\": { defaultKeys: \"pageUp\", description: \"Selection page up\" },\n\t\"tui.select.pageDown\": {\n\t\tdefaultKeys: \"pageDown\",\n\t\tdescription: \"Selection page down\",\n\t},\n\t\"tui.select.confirm\": { defaultKeys: \"enter\", description: \"Confirm selection\" },\n\t\"tui.select.cancel\": {\n\t\tdefaultKeys: [\"escape\", \"ctrl+c\"],\n\t\tdescription: \"Cancel selection\",\n\t},\n} as const satisfies KeybindingDefinitions;\n\nexport interface KeybindingConflict {\n\tkey: KeyId;\n\tkeybindings: string[];\n}\n\nfunction normalizeKeys(keys: KeyId | KeyId[] | undefined): KeyId[] {\n\tif (keys === undefined) return [];\n\tconst keyList = Array.isArray(keys) ? keys : [keys];\n\tconst seen = new Set<KeyId>();\n\tconst result: KeyId[] = [];\n\tfor (const key of keyList) {\n\t\tif (!seen.has(key)) {\n\t\t\tseen.add(key);\n\t\t\tresult.push(key);\n\t\t}\n\t}\n\treturn result;\n}\n\nexport class KeybindingsManager {\n\tprivate definitions: KeybindingDefinitions;\n\tprivate userBindings: KeybindingsConfig;\n\tprivate keysById = new Map<Keybinding, KeyId[]>();\n\tprivate conflicts: KeybindingConflict[] = [];\n\n\tconstructor(definitions: KeybindingDefinitions, userBindings: KeybindingsConfig = {}) {\n\t\tthis.definitions = definitions;\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\tthis.keysById.clear();\n\t\tthis.conflicts = [];\n\n\t\tconst userClaims = new Map<KeyId, Set<Keybinding>>();\n\t\tfor (const [keybinding, keys] of Object.entries(this.userBindings)) {\n\t\t\tif (!(keybinding in this.definitions)) continue;\n\t\t\tfor (const key of normalizeKeys(keys)) {\n\t\t\t\tconst claimants = userClaims.get(key) ?? new Set<Keybinding>();\n\t\t\t\tclaimants.add(keybinding as Keybinding);\n\t\t\t\tuserClaims.set(key, claimants);\n\t\t\t}\n\t\t}\n\n\t\tfor (const [key, keybindings] of userClaims) {\n\t\t\tif (keybindings.size > 1) {\n\t\t\t\tthis.conflicts.push({ key, keybindings: [...keybindings] });\n\t\t\t}\n\t\t}\n\n\t\tfor (const [id, definition] of Object.entries(this.definitions)) {\n\t\t\tconst userKeys = this.userBindings[id];\n\t\t\tconst keys = userKeys === undefined ? normalizeKeys(definition.defaultKeys) : normalizeKeys(userKeys);\n\t\t\tthis.keysById.set(id as Keybinding, keys);\n\t\t}\n\t}\n\n\tmatches(data: string, keybinding: Keybinding): boolean {\n\t\tconst keys = this.keysById.get(keybinding) ?? [];\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tgetKeys(keybinding: Keybinding): KeyId[] {\n\t\treturn [...(this.keysById.get(keybinding) ?? [])];\n\t}\n\n\tgetDefinition(keybinding: Keybinding): KeybindingDefinition {\n\t\treturn this.definitions[keybinding];\n\t}\n\n\tgetConflicts(): KeybindingConflict[] {\n\t\treturn this.conflicts.map((conflict) => ({ ...conflict, keybindings: [...conflict.keybindings] }));\n\t}\n\n\tsetUserBindings(userBindings: KeybindingsConfig): void {\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tgetUserBindings(): KeybindingsConfig {\n\t\treturn { ...this.userBindings };\n\t}\n\n\tgetResolvedBindings(): KeybindingsConfig {\n\t\tconst resolved: KeybindingsConfig = {};\n\t\tfor (const id of Object.keys(this.definitions)) {\n\t\t\tconst keys = this.keysById.get(id as Keybinding) ?? [];\n\t\t\tresolved[id] = keys.length === 1 ? keys[0]! : [...keys];\n\t\t}\n\t\treturn resolved;\n\t}\n}\n\nlet globalKeybindings: KeybindingsManager | null = null;\n\nexport function setKeybindings(keybindings: KeybindingsManager): void {\n\tglobalKeybindings = keybindings;\n}\n\nexport function getKeybindings(): KeybindingsManager {\n\tif (!globalKeybindings) {\n\t\tglobalKeybindings = new KeybindingsManager(TUI_KEYBINDINGS);\n\t}\n\treturn globalKeybindings;\n}\n"]}
|
package/dist/keybindings.js
CHANGED
|
@@ -34,8 +34,13 @@ export const TUI_KEYBINDINGS = {
|
|
|
34
34
|
defaultKeys: "ctrl+alt+]",
|
|
35
35
|
description: "Jump backward to character",
|
|
36
36
|
},
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
// Unbound by default. These page the cursor through the *prompt*, which is
|
|
38
|
+
// one to three lines in almost every session, so the keys did nothing on
|
|
39
|
+
// nearly every press — while pageUp/pageDown are the gesture everyone
|
|
40
|
+
// already knows for "show me what scrolled past". The app gives them to the
|
|
41
|
+
// transcript; bind these by hand if you write prompts tall enough to page.
|
|
42
|
+
"tui.editor.pageUp": { defaultKeys: [], description: "Page up within the prompt" },
|
|
43
|
+
"tui.editor.pageDown": { defaultKeys: [], description: "Page down within the prompt" },
|
|
39
44
|
"tui.editor.deleteCharBackward": {
|
|
40
45
|
defaultKeys: "backspace",
|
|
41
46
|
description: "Delete character backward",
|
|
@@ -63,6 +68,13 @@ export const TUI_KEYBINDINGS = {
|
|
|
63
68
|
"tui.editor.yank": { defaultKeys: "ctrl+y", description: "Yank" },
|
|
64
69
|
"tui.editor.yankPop": { defaultKeys: "alt+y", description: "Yank pop" },
|
|
65
70
|
"tui.editor.undo": { defaultKeys: "ctrl+-", description: "Undo" },
|
|
71
|
+
// alt+u, not the shape-matching alt+- : `\x1b-` is not a key this parser
|
|
72
|
+
// reads, so alt+- would work only where the Kitty protocol does, and redo has
|
|
73
|
+
// no other key to fall back on. The letters differ from undo's because
|
|
74
|
+
// ctrl+- predates the pair and is in everyone's fingers already — the
|
|
75
|
+
// asymmetry costs less than moving it would. ctrl+r, which vim users would
|
|
76
|
+
// reach for, belongs to transcript search.
|
|
77
|
+
"tui.editor.redo": { defaultKeys: "alt+u", description: "Redo" },
|
|
66
78
|
"tui.input.newLine": { defaultKeys: "shift+enter", description: "Insert newline" },
|
|
67
79
|
"tui.input.submit": { defaultKeys: "enter", description: "Submit input" },
|
|
68
80
|
"tui.input.tab": { defaultKeys: "tab", description: "Tab / autocomplete" },
|
package/dist/keybindings.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"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","sourcesContent":["import { type KeyId, matchesKey } from \"./keys.js\";\n\n/**\n * Global keybinding registry.\n * Downstream packages can add keybindings via declaration merging.\n */\nexport interface Keybindings {\n\t// Editor navigation and editing\n\t\"tui.editor.cursorUp\": true;\n\t\"tui.editor.cursorDown\": true;\n\t\"tui.editor.cursorLeft\": true;\n\t\"tui.editor.cursorRight\": true;\n\t\"tui.editor.cursorWordLeft\": true;\n\t\"tui.editor.cursorWordRight\": true;\n\t\"tui.editor.cursorLineStart\": true;\n\t\"tui.editor.cursorLineEnd\": true;\n\t\"tui.editor.jumpForward\": true;\n\t\"tui.editor.jumpBackward\": true;\n\t\"tui.editor.pageUp\": true;\n\t\"tui.editor.pageDown\": true;\n\t\"tui.editor.deleteCharBackward\": true;\n\t\"tui.editor.deleteCharForward\": true;\n\t\"tui.editor.deleteWordBackward\": true;\n\t\"tui.editor.deleteWordForward\": true;\n\t\"tui.editor.deleteToLineStart\": true;\n\t\"tui.editor.deleteToLineEnd\": true;\n\t\"tui.editor.yank\": true;\n\t\"tui.editor.yankPop\": true;\n\t\"tui.editor.undo\": true;\n\t// Generic input actions\n\t\"tui.input.newLine\": true;\n\t\"tui.input.submit\": true;\n\t\"tui.input.tab\": true;\n\t\"tui.input.copy\": true;\n\t// Generic selection actions\n\t\"tui.select.up\": true;\n\t\"tui.select.down\": true;\n\t\"tui.select.pageUp\": true;\n\t\"tui.select.pageDown\": true;\n\t\"tui.select.confirm\": true;\n\t\"tui.select.cancel\": true;\n}\n\nexport type Keybinding = keyof Keybindings;\n\nexport interface KeybindingDefinition {\n\tdefaultKeys: KeyId | KeyId[];\n\tdescription?: string;\n}\n\nexport type KeybindingDefinitions = Record<string, KeybindingDefinition>;\nexport type KeybindingsConfig = Record<string, KeyId | KeyId[] | undefined>;\n\nexport const TUI_KEYBINDINGS = {\n\t\"tui.editor.cursorUp\": { defaultKeys: \"up\", description: \"Move cursor up\" },\n\t\"tui.editor.cursorDown\": { defaultKeys: \"down\", description: \"Move cursor down\" },\n\t\"tui.editor.cursorLeft\": {\n\t\tdefaultKeys: [\"left\", \"ctrl+b\"],\n\t\tdescription: \"Move cursor left\",\n\t},\n\t\"tui.editor.cursorRight\": {\n\t\tdefaultKeys: [\"right\", \"ctrl+f\"],\n\t\tdescription: \"Move cursor right\",\n\t},\n\t\"tui.editor.cursorWordLeft\": {\n\t\tdefaultKeys: [\"alt+left\", \"ctrl+left\", \"alt+b\"],\n\t\tdescription: \"Move cursor word left\",\n\t},\n\t\"tui.editor.cursorWordRight\": {\n\t\tdefaultKeys: [\"alt+right\", \"ctrl+right\", \"alt+f\"],\n\t\tdescription: \"Move cursor word right\",\n\t},\n\t\"tui.editor.cursorLineStart\": {\n\t\tdefaultKeys: [\"home\", \"ctrl+a\"],\n\t\tdescription: \"Move to line start\",\n\t},\n\t\"tui.editor.cursorLineEnd\": {\n\t\tdefaultKeys: [\"end\", \"ctrl+e\"],\n\t\tdescription: \"Move to line end\",\n\t},\n\t\"tui.editor.jumpForward\": {\n\t\tdefaultKeys: \"ctrl+]\",\n\t\tdescription: \"Jump forward to character\",\n\t},\n\t\"tui.editor.jumpBackward\": {\n\t\tdefaultKeys: \"ctrl+alt+]\",\n\t\tdescription: \"Jump backward to character\",\n\t},\n\t\"tui.editor.pageUp\": { defaultKeys: \"pageUp\", description: \"Page up\" },\n\t\"tui.editor.pageDown\": { defaultKeys: \"pageDown\", description: \"Page down\" },\n\t\"tui.editor.deleteCharBackward\": {\n\t\tdefaultKeys: \"backspace\",\n\t\tdescription: \"Delete character backward\",\n\t},\n\t\"tui.editor.deleteCharForward\": {\n\t\tdefaultKeys: [\"delete\", \"ctrl+d\"],\n\t\tdescription: \"Delete character forward\",\n\t},\n\t\"tui.editor.deleteWordBackward\": {\n\t\tdefaultKeys: [\"ctrl+w\", \"alt+backspace\"],\n\t\tdescription: \"Delete word backward\",\n\t},\n\t\"tui.editor.deleteWordForward\": {\n\t\tdefaultKeys: [\"alt+d\", \"alt+delete\"],\n\t\tdescription: \"Delete word forward\",\n\t},\n\t\"tui.editor.deleteToLineStart\": {\n\t\tdefaultKeys: \"ctrl+u\",\n\t\tdescription: \"Delete to line start\",\n\t},\n\t\"tui.editor.deleteToLineEnd\": {\n\t\tdefaultKeys: \"ctrl+k\",\n\t\tdescription: \"Delete to line end\",\n\t},\n\t\"tui.editor.yank\": { defaultKeys: \"ctrl+y\", description: \"Yank\" },\n\t\"tui.editor.yankPop\": { defaultKeys: \"alt+y\", description: \"Yank pop\" },\n\t\"tui.editor.undo\": { defaultKeys: \"ctrl+-\", description: \"Undo\" },\n\t\"tui.input.newLine\": { defaultKeys: \"shift+enter\", description: \"Insert newline\" },\n\t\"tui.input.submit\": { defaultKeys: \"enter\", description: \"Submit input\" },\n\t\"tui.input.tab\": { defaultKeys: \"tab\", description: \"Tab / autocomplete\" },\n\t\"tui.input.copy\": { defaultKeys: \"ctrl+c\", description: \"Copy selection\" },\n\t\"tui.select.up\": { defaultKeys: \"up\", description: \"Move selection up\" },\n\t\"tui.select.down\": { defaultKeys: \"down\", description: \"Move selection down\" },\n\t\"tui.select.pageUp\": { defaultKeys: \"pageUp\", description: \"Selection page up\" },\n\t\"tui.select.pageDown\": {\n\t\tdefaultKeys: \"pageDown\",\n\t\tdescription: \"Selection page down\",\n\t},\n\t\"tui.select.confirm\": { defaultKeys: \"enter\", description: \"Confirm selection\" },\n\t\"tui.select.cancel\": {\n\t\tdefaultKeys: [\"escape\", \"ctrl+c\"],\n\t\tdescription: \"Cancel selection\",\n\t},\n} as const satisfies KeybindingDefinitions;\n\nexport interface KeybindingConflict {\n\tkey: KeyId;\n\tkeybindings: string[];\n}\n\nfunction normalizeKeys(keys: KeyId | KeyId[] | undefined): KeyId[] {\n\tif (keys === undefined) return [];\n\tconst keyList = Array.isArray(keys) ? keys : [keys];\n\tconst seen = new Set<KeyId>();\n\tconst result: KeyId[] = [];\n\tfor (const key of keyList) {\n\t\tif (!seen.has(key)) {\n\t\t\tseen.add(key);\n\t\t\tresult.push(key);\n\t\t}\n\t}\n\treturn result;\n}\n\nexport class KeybindingsManager {\n\tprivate definitions: KeybindingDefinitions;\n\tprivate userBindings: KeybindingsConfig;\n\tprivate keysById = new Map<Keybinding, KeyId[]>();\n\tprivate conflicts: KeybindingConflict[] = [];\n\n\tconstructor(definitions: KeybindingDefinitions, userBindings: KeybindingsConfig = {}) {\n\t\tthis.definitions = definitions;\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\tthis.keysById.clear();\n\t\tthis.conflicts = [];\n\n\t\tconst userClaims = new Map<KeyId, Set<Keybinding>>();\n\t\tfor (const [keybinding, keys] of Object.entries(this.userBindings)) {\n\t\t\tif (!(keybinding in this.definitions)) continue;\n\t\t\tfor (const key of normalizeKeys(keys)) {\n\t\t\t\tconst claimants = userClaims.get(key) ?? new Set<Keybinding>();\n\t\t\t\tclaimants.add(keybinding as Keybinding);\n\t\t\t\tuserClaims.set(key, claimants);\n\t\t\t}\n\t\t}\n\n\t\tfor (const [key, keybindings] of userClaims) {\n\t\t\tif (keybindings.size > 1) {\n\t\t\t\tthis.conflicts.push({ key, keybindings: [...keybindings] });\n\t\t\t}\n\t\t}\n\n\t\tfor (const [id, definition] of Object.entries(this.definitions)) {\n\t\t\tconst userKeys = this.userBindings[id];\n\t\t\tconst keys = userKeys === undefined ? normalizeKeys(definition.defaultKeys) : normalizeKeys(userKeys);\n\t\t\tthis.keysById.set(id as Keybinding, keys);\n\t\t}\n\t}\n\n\tmatches(data: string, keybinding: Keybinding): boolean {\n\t\tconst keys = this.keysById.get(keybinding) ?? [];\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tgetKeys(keybinding: Keybinding): KeyId[] {\n\t\treturn [...(this.keysById.get(keybinding) ?? [])];\n\t}\n\n\tgetDefinition(keybinding: Keybinding): KeybindingDefinition {\n\t\treturn this.definitions[keybinding];\n\t}\n\n\tgetConflicts(): KeybindingConflict[] {\n\t\treturn this.conflicts.map((conflict) => ({ ...conflict, keybindings: [...conflict.keybindings] }));\n\t}\n\n\tsetUserBindings(userBindings: KeybindingsConfig): void {\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tgetUserBindings(): KeybindingsConfig {\n\t\treturn { ...this.userBindings };\n\t}\n\n\tgetResolvedBindings(): KeybindingsConfig {\n\t\tconst resolved: KeybindingsConfig = {};\n\t\tfor (const id of Object.keys(this.definitions)) {\n\t\t\tconst keys = this.keysById.get(id as Keybinding) ?? [];\n\t\t\tresolved[id] = keys.length === 1 ? keys[0]! : [...keys];\n\t\t}\n\t\treturn resolved;\n\t}\n}\n\nlet globalKeybindings: KeybindingsManager | null = null;\n\nexport function setKeybindings(keybindings: KeybindingsManager): void {\n\tglobalKeybindings = keybindings;\n}\n\nexport function getKeybindings(): KeybindingsManager {\n\tif (!globalKeybindings) {\n\t\tglobalKeybindings = new KeybindingsManager(TUI_KEYBINDINGS);\n\t}\n\treturn globalKeybindings;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"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","sourcesContent":["import { type KeyId, matchesKey } from \"./keys.js\";\n\n/**\n * Global keybinding registry.\n * Downstream packages can add keybindings via declaration merging.\n */\nexport interface Keybindings {\n\t// Editor navigation and editing\n\t\"tui.editor.cursorUp\": true;\n\t\"tui.editor.cursorDown\": true;\n\t\"tui.editor.cursorLeft\": true;\n\t\"tui.editor.cursorRight\": true;\n\t\"tui.editor.cursorWordLeft\": true;\n\t\"tui.editor.cursorWordRight\": true;\n\t\"tui.editor.cursorLineStart\": true;\n\t\"tui.editor.cursorLineEnd\": true;\n\t\"tui.editor.jumpForward\": true;\n\t\"tui.editor.jumpBackward\": true;\n\t\"tui.editor.pageUp\": true;\n\t\"tui.editor.pageDown\": true;\n\t\"tui.editor.deleteCharBackward\": true;\n\t\"tui.editor.deleteCharForward\": true;\n\t\"tui.editor.deleteWordBackward\": true;\n\t\"tui.editor.deleteWordForward\": true;\n\t\"tui.editor.deleteToLineStart\": true;\n\t\"tui.editor.deleteToLineEnd\": true;\n\t\"tui.editor.yank\": true;\n\t\"tui.editor.yankPop\": true;\n\t\"tui.editor.undo\": true;\n\t\"tui.editor.redo\": true;\n\t// Generic input actions\n\t\"tui.input.newLine\": true;\n\t\"tui.input.submit\": true;\n\t\"tui.input.tab\": true;\n\t\"tui.input.copy\": true;\n\t// Generic selection actions\n\t\"tui.select.up\": true;\n\t\"tui.select.down\": true;\n\t\"tui.select.pageUp\": true;\n\t\"tui.select.pageDown\": true;\n\t\"tui.select.confirm\": true;\n\t\"tui.select.cancel\": true;\n}\n\nexport type Keybinding = keyof Keybindings;\n\nexport interface KeybindingDefinition {\n\tdefaultKeys: KeyId | KeyId[];\n\tdescription?: string;\n}\n\nexport type KeybindingDefinitions = Record<string, KeybindingDefinition>;\nexport type KeybindingsConfig = Record<string, KeyId | KeyId[] | undefined>;\n\nexport const TUI_KEYBINDINGS = {\n\t\"tui.editor.cursorUp\": { defaultKeys: \"up\", description: \"Move cursor up\" },\n\t\"tui.editor.cursorDown\": { defaultKeys: \"down\", description: \"Move cursor down\" },\n\t\"tui.editor.cursorLeft\": {\n\t\tdefaultKeys: [\"left\", \"ctrl+b\"],\n\t\tdescription: \"Move cursor left\",\n\t},\n\t\"tui.editor.cursorRight\": {\n\t\tdefaultKeys: [\"right\", \"ctrl+f\"],\n\t\tdescription: \"Move cursor right\",\n\t},\n\t\"tui.editor.cursorWordLeft\": {\n\t\tdefaultKeys: [\"alt+left\", \"ctrl+left\", \"alt+b\"],\n\t\tdescription: \"Move cursor word left\",\n\t},\n\t\"tui.editor.cursorWordRight\": {\n\t\tdefaultKeys: [\"alt+right\", \"ctrl+right\", \"alt+f\"],\n\t\tdescription: \"Move cursor word right\",\n\t},\n\t\"tui.editor.cursorLineStart\": {\n\t\tdefaultKeys: [\"home\", \"ctrl+a\"],\n\t\tdescription: \"Move to line start\",\n\t},\n\t\"tui.editor.cursorLineEnd\": {\n\t\tdefaultKeys: [\"end\", \"ctrl+e\"],\n\t\tdescription: \"Move to line end\",\n\t},\n\t\"tui.editor.jumpForward\": {\n\t\tdefaultKeys: \"ctrl+]\",\n\t\tdescription: \"Jump forward to character\",\n\t},\n\t\"tui.editor.jumpBackward\": {\n\t\tdefaultKeys: \"ctrl+alt+]\",\n\t\tdescription: \"Jump backward to character\",\n\t},\n\t// Unbound by default. These page the cursor through the *prompt*, which is\n\t// one to three lines in almost every session, so the keys did nothing on\n\t// nearly every press — while pageUp/pageDown are the gesture everyone\n\t// already knows for \"show me what scrolled past\". The app gives them to the\n\t// transcript; bind these by hand if you write prompts tall enough to page.\n\t\"tui.editor.pageUp\": { defaultKeys: [], description: \"Page up within the prompt\" },\n\t\"tui.editor.pageDown\": { defaultKeys: [], description: \"Page down within the prompt\" },\n\t\"tui.editor.deleteCharBackward\": {\n\t\tdefaultKeys: \"backspace\",\n\t\tdescription: \"Delete character backward\",\n\t},\n\t\"tui.editor.deleteCharForward\": {\n\t\tdefaultKeys: [\"delete\", \"ctrl+d\"],\n\t\tdescription: \"Delete character forward\",\n\t},\n\t\"tui.editor.deleteWordBackward\": {\n\t\tdefaultKeys: [\"ctrl+w\", \"alt+backspace\"],\n\t\tdescription: \"Delete word backward\",\n\t},\n\t\"tui.editor.deleteWordForward\": {\n\t\tdefaultKeys: [\"alt+d\", \"alt+delete\"],\n\t\tdescription: \"Delete word forward\",\n\t},\n\t\"tui.editor.deleteToLineStart\": {\n\t\tdefaultKeys: \"ctrl+u\",\n\t\tdescription: \"Delete to line start\",\n\t},\n\t\"tui.editor.deleteToLineEnd\": {\n\t\tdefaultKeys: \"ctrl+k\",\n\t\tdescription: \"Delete to line end\",\n\t},\n\t\"tui.editor.yank\": { defaultKeys: \"ctrl+y\", description: \"Yank\" },\n\t\"tui.editor.yankPop\": { defaultKeys: \"alt+y\", description: \"Yank pop\" },\n\t\"tui.editor.undo\": { defaultKeys: \"ctrl+-\", description: \"Undo\" },\n\t// alt+u, not the shape-matching alt+- : `\\x1b-` is not a key this parser\n\t// reads, so alt+- would work only where the Kitty protocol does, and redo has\n\t// no other key to fall back on. The letters differ from undo's because\n\t// ctrl+- predates the pair and is in everyone's fingers already — the\n\t// asymmetry costs less than moving it would. ctrl+r, which vim users would\n\t// reach for, belongs to transcript search.\n\t\"tui.editor.redo\": { defaultKeys: \"alt+u\", description: \"Redo\" },\n\t\"tui.input.newLine\": { defaultKeys: \"shift+enter\", description: \"Insert newline\" },\n\t\"tui.input.submit\": { defaultKeys: \"enter\", description: \"Submit input\" },\n\t\"tui.input.tab\": { defaultKeys: \"tab\", description: \"Tab / autocomplete\" },\n\t\"tui.input.copy\": { defaultKeys: \"ctrl+c\", description: \"Copy selection\" },\n\t\"tui.select.up\": { defaultKeys: \"up\", description: \"Move selection up\" },\n\t\"tui.select.down\": { defaultKeys: \"down\", description: \"Move selection down\" },\n\t\"tui.select.pageUp\": { defaultKeys: \"pageUp\", description: \"Selection page up\" },\n\t\"tui.select.pageDown\": {\n\t\tdefaultKeys: \"pageDown\",\n\t\tdescription: \"Selection page down\",\n\t},\n\t\"tui.select.confirm\": { defaultKeys: \"enter\", description: \"Confirm selection\" },\n\t\"tui.select.cancel\": {\n\t\tdefaultKeys: [\"escape\", \"ctrl+c\"],\n\t\tdescription: \"Cancel selection\",\n\t},\n} as const satisfies KeybindingDefinitions;\n\nexport interface KeybindingConflict {\n\tkey: KeyId;\n\tkeybindings: string[];\n}\n\nfunction normalizeKeys(keys: KeyId | KeyId[] | undefined): KeyId[] {\n\tif (keys === undefined) return [];\n\tconst keyList = Array.isArray(keys) ? keys : [keys];\n\tconst seen = new Set<KeyId>();\n\tconst result: KeyId[] = [];\n\tfor (const key of keyList) {\n\t\tif (!seen.has(key)) {\n\t\t\tseen.add(key);\n\t\t\tresult.push(key);\n\t\t}\n\t}\n\treturn result;\n}\n\nexport class KeybindingsManager {\n\tprivate definitions: KeybindingDefinitions;\n\tprivate userBindings: KeybindingsConfig;\n\tprivate keysById = new Map<Keybinding, KeyId[]>();\n\tprivate conflicts: KeybindingConflict[] = [];\n\n\tconstructor(definitions: KeybindingDefinitions, userBindings: KeybindingsConfig = {}) {\n\t\tthis.definitions = definitions;\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tprivate rebuild(): void {\n\t\tthis.keysById.clear();\n\t\tthis.conflicts = [];\n\n\t\tconst userClaims = new Map<KeyId, Set<Keybinding>>();\n\t\tfor (const [keybinding, keys] of Object.entries(this.userBindings)) {\n\t\t\tif (!(keybinding in this.definitions)) continue;\n\t\t\tfor (const key of normalizeKeys(keys)) {\n\t\t\t\tconst claimants = userClaims.get(key) ?? new Set<Keybinding>();\n\t\t\t\tclaimants.add(keybinding as Keybinding);\n\t\t\t\tuserClaims.set(key, claimants);\n\t\t\t}\n\t\t}\n\n\t\tfor (const [key, keybindings] of userClaims) {\n\t\t\tif (keybindings.size > 1) {\n\t\t\t\tthis.conflicts.push({ key, keybindings: [...keybindings] });\n\t\t\t}\n\t\t}\n\n\t\tfor (const [id, definition] of Object.entries(this.definitions)) {\n\t\t\tconst userKeys = this.userBindings[id];\n\t\t\tconst keys = userKeys === undefined ? normalizeKeys(definition.defaultKeys) : normalizeKeys(userKeys);\n\t\t\tthis.keysById.set(id as Keybinding, keys);\n\t\t}\n\t}\n\n\tmatches(data: string, keybinding: Keybinding): boolean {\n\t\tconst keys = this.keysById.get(keybinding) ?? [];\n\t\tfor (const key of keys) {\n\t\t\tif (matchesKey(data, key)) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tgetKeys(keybinding: Keybinding): KeyId[] {\n\t\treturn [...(this.keysById.get(keybinding) ?? [])];\n\t}\n\n\tgetDefinition(keybinding: Keybinding): KeybindingDefinition {\n\t\treturn this.definitions[keybinding];\n\t}\n\n\tgetConflicts(): KeybindingConflict[] {\n\t\treturn this.conflicts.map((conflict) => ({ ...conflict, keybindings: [...conflict.keybindings] }));\n\t}\n\n\tsetUserBindings(userBindings: KeybindingsConfig): void {\n\t\tthis.userBindings = userBindings;\n\t\tthis.rebuild();\n\t}\n\n\tgetUserBindings(): KeybindingsConfig {\n\t\treturn { ...this.userBindings };\n\t}\n\n\tgetResolvedBindings(): KeybindingsConfig {\n\t\tconst resolved: KeybindingsConfig = {};\n\t\tfor (const id of Object.keys(this.definitions)) {\n\t\t\tconst keys = this.keysById.get(id as Keybinding) ?? [];\n\t\t\tresolved[id] = keys.length === 1 ? keys[0]! : [...keys];\n\t\t}\n\t\treturn resolved;\n\t}\n}\n\nlet globalKeybindings: KeybindingsManager | null = null;\n\nexport function setKeybindings(keybindings: KeybindingsManager): void {\n\tglobalKeybindings = keybindings;\n}\n\nexport function getKeybindings(): KeybindingsManager {\n\tif (!globalKeybindings) {\n\t\tglobalKeybindings = new KeybindingsManager(TUI_KEYBINDINGS);\n\t}\n\treturn globalKeybindings;\n}\n"]}
|
package/dist/mouse.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mouse reporting: turning it on, and reading what comes back.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the app captures the mouse at all
|
|
5
|
+
*
|
|
6
|
+
* Without mouse reporting the wheel belongs to the terminal, which scrolls its
|
|
7
|
+
* own scrollback under the app's feet. That is fine right up until the app
|
|
8
|
+
* repaints — and this renderer repaints the whole transcript whenever a line
|
|
9
|
+
* above the viewport changes — at which point the terminal snaps back to the
|
|
10
|
+
* bottom and the scroll position the reader was holding is gone. The wheel is
|
|
11
|
+
* captured so that scrolling is one thing the app decides, not a race between
|
|
12
|
+
* the app's writes and the terminal's idea of where the view should sit.
|
|
13
|
+
*
|
|
14
|
+
* The cost is real and worth naming: while reporting is on, a plain click-drag
|
|
15
|
+
* is delivered here instead of selecting text. Every terminal worth using keeps
|
|
16
|
+
* a bypass on **shift** (option on iTerm2), so selection is one modifier away
|
|
17
|
+
* rather than gone. `HOOCODE_MOUSE=0` turns the whole thing off for anyone who
|
|
18
|
+
* would rather have the drag back.
|
|
19
|
+
*
|
|
20
|
+
* ## What is enabled, and what deliberately is not
|
|
21
|
+
*
|
|
22
|
+
* - `?1000h` — button press and release, which is what carries wheel events.
|
|
23
|
+
* - `?1006h` — SGR encoding, so coordinates past column 223 survive. Terminals
|
|
24
|
+
* that ignore it keep sending the X10 form, which `parseMouseEvent` also
|
|
25
|
+
* reads, so a terminal without SGR degrades to "works up to column 223"
|
|
26
|
+
* rather than to garbage on screen.
|
|
27
|
+
*
|
|
28
|
+
* `?1002h` (drag tracking) and `?1003h` (any-motion) are **not** enabled. They
|
|
29
|
+
* would deliver a motion event per cell of travel — thousands of wakeups for a
|
|
30
|
+
* gesture this app has no use for — and `?1003h` in particular fires on plain
|
|
31
|
+
* pointer movement over the window, so an idle terminal with the mouse resting
|
|
32
|
+
* over it would never stop waking the render loop.
|
|
33
|
+
*/
|
|
34
|
+
/** Enable button + wheel reporting, preferring SGR coordinates. */
|
|
35
|
+
export declare const MOUSE_ENABLE = "\u001B[?1000h\u001B[?1006h";
|
|
36
|
+
/** Disable in the reverse order it was enabled. */
|
|
37
|
+
export declare const MOUSE_DISABLE = "\u001B[?1006l\u001B[?1000l";
|
|
38
|
+
export type MouseEventKind = "wheelUp" | "wheelDown" | "wheelLeft" | "wheelRight" | "press" | "release";
|
|
39
|
+
export interface MouseEvent {
|
|
40
|
+
kind: MouseEventKind;
|
|
41
|
+
/** 0 left, 1 middle, 2 right. -1 for wheel events, which name no button. */
|
|
42
|
+
button: number;
|
|
43
|
+
/** 1-based, as the terminal reports it. */
|
|
44
|
+
column: number;
|
|
45
|
+
/** 1-based, as the terminal reports it. */
|
|
46
|
+
row: number;
|
|
47
|
+
shift: boolean;
|
|
48
|
+
alt: boolean;
|
|
49
|
+
ctrl: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Whether `data` starts with a mouse report.
|
|
53
|
+
*
|
|
54
|
+
* Used to swallow reports the app does not act on. A mouse sequence that
|
|
55
|
+
* reaches a text field is typed into it — `<35;10;4M` appearing in the prompt
|
|
56
|
+
* is this check having been skipped.
|
|
57
|
+
*/
|
|
58
|
+
export declare function isMouseSequence(data: string): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* How many bytes the leading mouse report occupies, or 0 if there is none.
|
|
61
|
+
*
|
|
62
|
+
* Reports arrive coalesced — a fast wheel spin delivers several in one read,
|
|
63
|
+
* and a keystroke can ride along behind them — so the caller peels them off one
|
|
64
|
+
* at a time rather than treating the whole chunk as a single event.
|
|
65
|
+
*/
|
|
66
|
+
export declare function mouseSequenceLength(data: string): number;
|
|
67
|
+
/**
|
|
68
|
+
* Read the mouse report at the start of `data`, or null if there is not one.
|
|
69
|
+
*
|
|
70
|
+
* Coordinates come back 1-based, exactly as the terminal sends them; callers
|
|
71
|
+
* that index into a line subtract the one themselves rather than having it
|
|
72
|
+
* subtracted here, where it would be invisible.
|
|
73
|
+
*/
|
|
74
|
+
export declare function parseMouseEvent(data: string): MouseEvent | null;
|
|
75
|
+
//# sourceMappingURL=mouse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mouse.d.ts","sourceRoot":"","sources":["../src/mouse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,mEAAmE;AACnE,eAAO,MAAM,YAAY,+BAA2B,CAAC;AAErD,mDAAmD;AACnD,eAAO,MAAM,aAAa,+BAA2B,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,GAAG,SAAS,CAAC;AAExG,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,cAAc,CAAC;IACrB,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;CACd;AAMD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOxD;AAyBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAmB/D","sourcesContent":["/**\n * Mouse reporting: turning it on, and reading what comes back.\n *\n * ## Why the app captures the mouse at all\n *\n * Without mouse reporting the wheel belongs to the terminal, which scrolls its\n * own scrollback under the app's feet. That is fine right up until the app\n * repaints — and this renderer repaints the whole transcript whenever a line\n * above the viewport changes — at which point the terminal snaps back to the\n * bottom and the scroll position the reader was holding is gone. The wheel is\n * captured so that scrolling is one thing the app decides, not a race between\n * the app's writes and the terminal's idea of where the view should sit.\n *\n * The cost is real and worth naming: while reporting is on, a plain click-drag\n * is delivered here instead of selecting text. Every terminal worth using keeps\n * a bypass on **shift** (option on iTerm2), so selection is one modifier away\n * rather than gone. `HOOCODE_MOUSE=0` turns the whole thing off for anyone who\n * would rather have the drag back.\n *\n * ## What is enabled, and what deliberately is not\n *\n * - `?1000h` — button press and release, which is what carries wheel events.\n * - `?1006h` — SGR encoding, so coordinates past column 223 survive. Terminals\n * that ignore it keep sending the X10 form, which `parseMouseEvent` also\n * reads, so a terminal without SGR degrades to \"works up to column 223\"\n * rather than to garbage on screen.\n *\n * `?1002h` (drag tracking) and `?1003h` (any-motion) are **not** enabled. They\n * would deliver a motion event per cell of travel — thousands of wakeups for a\n * gesture this app has no use for — and `?1003h` in particular fires on plain\n * pointer movement over the window, so an idle terminal with the mouse resting\n * over it would never stop waking the render loop.\n */\n\n/** Enable button + wheel reporting, preferring SGR coordinates. */\nexport const MOUSE_ENABLE = \"\\x1b[?1000h\\x1b[?1006h\";\n\n/** Disable in the reverse order it was enabled. */\nexport const MOUSE_DISABLE = \"\\x1b[?1006l\\x1b[?1000l\";\n\nexport type MouseEventKind = \"wheelUp\" | \"wheelDown\" | \"wheelLeft\" | \"wheelRight\" | \"press\" | \"release\";\n\nexport interface MouseEvent {\n\tkind: MouseEventKind;\n\t/** 0 left, 1 middle, 2 right. -1 for wheel events, which name no button. */\n\tbutton: number;\n\t/** 1-based, as the terminal reports it. */\n\tcolumn: number;\n\t/** 1-based, as the terminal reports it. */\n\trow: number;\n\tshift: boolean;\n\talt: boolean;\n\tctrl: boolean;\n}\n\nconst SGR_PATTERN = /^\\x1b\\[<(\\d+);(\\d+);(\\d+)([Mm])/;\n// X10: ESC [ M then three bytes, each its value plus 32.\nconst X10_PREFIX = \"\\x1b[M\";\n\n/**\n * Whether `data` starts with a mouse report.\n *\n * Used to swallow reports the app does not act on. A mouse sequence that\n * reaches a text field is typed into it — `<35;10;4M` appearing in the prompt\n * is this check having been skipped.\n */\nexport function isMouseSequence(data: string): boolean {\n\tif (SGR_PATTERN.test(data)) return true;\n\treturn data.startsWith(X10_PREFIX) && data.length >= X10_PREFIX.length + 3;\n}\n\n/**\n * How many bytes the leading mouse report occupies, or 0 if there is none.\n *\n * Reports arrive coalesced — a fast wheel spin delivers several in one read,\n * and a keystroke can ride along behind them — so the caller peels them off one\n * at a time rather than treating the whole chunk as a single event.\n */\nexport function mouseSequenceLength(data: string): number {\n\tconst sgr = data.match(SGR_PATTERN);\n\tif (sgr) return sgr[0].length;\n\tif (data.startsWith(X10_PREFIX) && data.length >= X10_PREFIX.length + 3) {\n\t\treturn X10_PREFIX.length + 3;\n\t}\n\treturn 0;\n}\n\nfunction decode(flags: number, column: number, row: number, pressed: boolean): MouseEvent {\n\tconst shift = (flags & 4) !== 0;\n\tconst alt = (flags & 8) !== 0;\n\tconst ctrl = (flags & 16) !== 0;\n\n\t// Bit 6 marks the wheel, and the low two bits then say which way it turned\n\t// rather than which button was hit.\n\tif ((flags & 64) !== 0) {\n\t\tconst direction = flags & 3;\n\t\tconst kind: MouseEventKind =\n\t\t\tdirection === 0 ? \"wheelUp\" : direction === 1 ? \"wheelDown\" : direction === 2 ? \"wheelLeft\" : \"wheelRight\";\n\t\treturn { kind, button: -1, column, row, shift, alt, ctrl };\n\t}\n\n\tconst button = flags & 3;\n\t// X10 has no separate release code per button: button 3 *is* the release,\n\t// which is why SGR's trailing `m` exists and why this has to check both.\n\tif (!pressed || button === 3) {\n\t\treturn { kind: \"release\", button: button === 3 ? -1 : button, column, row, shift, alt, ctrl };\n\t}\n\treturn { kind: \"press\", button, column, row, shift, alt, ctrl };\n}\n\n/**\n * Read the mouse report at the start of `data`, or null if there is not one.\n *\n * Coordinates come back 1-based, exactly as the terminal sends them; callers\n * that index into a line subtract the one themselves rather than having it\n * subtracted here, where it would be invisible.\n */\nexport function parseMouseEvent(data: string): MouseEvent | null {\n\tconst sgr = data.match(SGR_PATTERN);\n\tif (sgr) {\n\t\tconst flags = Number(sgr[1]);\n\t\tconst column = Number(sgr[2]);\n\t\tconst row = Number(sgr[3]);\n\t\tif (!Number.isFinite(flags) || !Number.isFinite(column) || !Number.isFinite(row)) return null;\n\t\treturn decode(flags, column, row, sgr[4] === \"M\");\n\t}\n\n\tif (data.startsWith(X10_PREFIX) && data.length >= X10_PREFIX.length + 3) {\n\t\tconst flags = data.charCodeAt(X10_PREFIX.length) - 32;\n\t\tconst column = data.charCodeAt(X10_PREFIX.length + 1) - 32;\n\t\tconst row = data.charCodeAt(X10_PREFIX.length + 2) - 32;\n\t\tif (flags < 0 || column < 0 || row < 0) return null;\n\t\treturn decode(flags, column, row, true);\n\t}\n\n\treturn null;\n}\n"]}
|