@caupulican/pi-tui 0.81.41 → 0.81.43
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/autocomplete.d.ts +1 -1
- package/dist/autocomplete.d.ts.map +1 -1
- package/dist/autocomplete.js +15 -23
- package/dist/autocomplete.js.map +1 -1
- package/dist/bracketed-paste.d.ts +33 -0
- package/dist/bracketed-paste.d.ts.map +1 -0
- package/dist/bracketed-paste.js +96 -0
- package/dist/bracketed-paste.js.map +1 -0
- package/dist/components/box.d.ts.map +1 -1
- package/dist/components/box.js +2 -7
- package/dist/components/box.js.map +1 -1
- package/dist/components/cancellable-loader.d.ts.map +1 -1
- package/dist/components/cancellable-loader.js +4 -3
- package/dist/components/cancellable-loader.js.map +1 -1
- package/dist/components/editor.d.ts +20 -8
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +172 -310
- package/dist/components/editor.js.map +1 -1
- package/dist/components/image.d.ts.map +1 -1
- package/dist/components/image.js +12 -35
- package/dist/components/image.js.map +1 -1
- package/dist/components/input.d.ts +8 -8
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +29 -75
- package/dist/components/input.js.map +1 -1
- package/dist/components/loader.d.ts.map +1 -1
- package/dist/components/loader.js +7 -9
- package/dist/components/loader.js.map +1 -1
- package/dist/components/markdown.d.ts +3 -11
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +48 -124
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/select-list.d.ts.map +1 -1
- package/dist/components/select-list.js +4 -9
- package/dist/components/select-list.js.map +1 -1
- package/dist/components/settings-list.d.ts.map +1 -1
- package/dist/components/settings-list.js +4 -12
- package/dist/components/settings-list.js.map +1 -1
- package/dist/components/spacer.d.ts.map +1 -1
- package/dist/components/spacer.js +0 -1
- package/dist/components/spacer.js.map +1 -1
- package/dist/components/text-layout.d.ts +49 -0
- package/dist/components/text-layout.d.ts.map +1 -0
- package/dist/components/text-layout.js +103 -0
- package/dist/components/text-layout.js.map +1 -0
- package/dist/components/text.d.ts +2 -11
- package/dist/components/text.d.ts.map +1 -1
- package/dist/components/text.js +16 -83
- package/dist/components/text.js.map +1 -1
- package/dist/components/truncated-text.d.ts.map +1 -1
- package/dist/components/truncated-text.js +0 -3
- package/dist/components/truncated-text.js.map +1 -1
- package/dist/editing-actions.d.ts +17 -0
- package/dist/editing-actions.d.ts.map +1 -0
- package/dist/editing-actions.js +34 -0
- package/dist/editing-actions.js.map +1 -0
- package/dist/editor-component.d.ts +9 -0
- package/dist/editor-component.d.ts.map +1 -1
- package/dist/editor-component.js +4 -1
- package/dist/editor-component.js.map +1 -1
- package/dist/fuzzy.d.ts.map +1 -1
- package/dist/fuzzy.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/keybindings.d.ts +2 -2
- package/dist/keybindings.d.ts.map +1 -1
- package/dist/keybindings.js +4 -6
- package/dist/keybindings.js.map +1 -1
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js.map +1 -1
- package/dist/kill-ring.d.ts.map +1 -1
- package/dist/kill-ring.js +2 -4
- package/dist/kill-ring.js.map +1 -1
- package/dist/native-loader.d.ts +3 -0
- package/dist/native-loader.d.ts.map +1 -0
- package/dist/native-loader.js +25 -0
- package/dist/native-loader.js.map +1 -0
- package/dist/native-modifiers.d.ts.map +1 -1
- package/dist/native-modifiers.js +5 -20
- package/dist/native-modifiers.js.map +1 -1
- package/dist/stdin-buffer.d.ts +8 -2
- package/dist/stdin-buffer.d.ts.map +1 -1
- package/dist/stdin-buffer.js +38 -32
- package/dist/stdin-buffer.js.map +1 -1
- package/dist/terminal-image.d.ts.map +1 -1
- package/dist/terminal-image.js.map +1 -1
- package/dist/terminal.d.ts +1 -0
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +47 -72
- package/dist/terminal.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +26 -31
- package/dist/tui.js.map +1 -1
- package/dist/undo-stack.d.ts.map +1 -1
- package/dist/undo-stack.js +2 -4
- package/dist/undo-stack.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +197 -275
- package/dist/utils.js.map +1 -1
- package/dist/word-navigation.d.ts.map +1 -1
- package/dist/word-navigation.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface PreparedTextBlock {
|
|
2
|
+
normalizedText: string;
|
|
3
|
+
contentWidth: number;
|
|
4
|
+
}
|
|
5
|
+
export interface TextFrameOptions {
|
|
6
|
+
width: number;
|
|
7
|
+
paddingX: number;
|
|
8
|
+
paddingY: number;
|
|
9
|
+
background?: (text: string) => string;
|
|
10
|
+
isPassthrough?: (line: string) => boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class TextRenderCache {
|
|
13
|
+
private text?;
|
|
14
|
+
private width?;
|
|
15
|
+
private lines?;
|
|
16
|
+
read(text: string, width: number): string[] | undefined;
|
|
17
|
+
write(text: string, width: number, lines: string[]): void;
|
|
18
|
+
clear(): void;
|
|
19
|
+
}
|
|
20
|
+
export type TextRenderStart = {
|
|
21
|
+
kind: "complete";
|
|
22
|
+
lines: string[];
|
|
23
|
+
} | {
|
|
24
|
+
kind: "render";
|
|
25
|
+
prepared: PreparedTextBlock;
|
|
26
|
+
};
|
|
27
|
+
/** Owns the cache/revision lifecycle shared by terminal text components. */
|
|
28
|
+
export declare class TextRenderState {
|
|
29
|
+
private cache;
|
|
30
|
+
private _revision;
|
|
31
|
+
get revision(): number;
|
|
32
|
+
invalidate(): void;
|
|
33
|
+
begin(text: string, width: number, paddingX: number): TextRenderStart;
|
|
34
|
+
finish(text: string, width: number, lines: string[]): string[];
|
|
35
|
+
}
|
|
36
|
+
/** Shared mutable lifecycle for cache-backed text components. */
|
|
37
|
+
export declare class CachedTextComponent {
|
|
38
|
+
protected text: string;
|
|
39
|
+
protected paddingX: number;
|
|
40
|
+
protected paddingY: number;
|
|
41
|
+
protected renderState: TextRenderState;
|
|
42
|
+
constructor(text: string, paddingX: number, paddingY: number);
|
|
43
|
+
get renderRevision(): number;
|
|
44
|
+
setText(text: string): void;
|
|
45
|
+
invalidate(): void;
|
|
46
|
+
}
|
|
47
|
+
export declare function prepareTextBlock(text: string, width: number, paddingX: number): PreparedTextBlock | undefined;
|
|
48
|
+
export declare function frameTextLines(lines: readonly string[], options: TextFrameOptions): string[];
|
|
49
|
+
//# sourceMappingURL=text-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-layout.d.ts","sourceRoot":"","sources":["../../src/components/text-layout.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC1C;AAED,qBAAa,eAAe;IAC3B,OAAO,CAAC,IAAI,CAAC,CAAS;IACtB,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,KAAK,CAAC,CAAW;IAEzB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAEtD;IAED,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAIxD;IAED,KAAK,IAAI,IAAI,CAIZ;CACD;AAED,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAEtH,4EAA4E;AAC5E,qBAAa,eAAe;IAC3B,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,SAAS,CAAK;IAEtB,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,UAAU,IAAI,IAAI,CAGjB;IAED,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CAWpE;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAG7D;CACD;AAED,iEAAiE;AACjE,qBAAa,mBAAmB;IAC/B,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,WAAW,EAAE,eAAe,CAAC;IAEvC,YAAY,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAK3D;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAG1B;IAED,UAAU,IAAI,IAAI,CAEjB;CACD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAM7G;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAkC5F"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { applyBackgroundToLine, visibleWidth } from "../utils.js";
|
|
2
|
+
export class TextRenderCache {
|
|
3
|
+
read(text, width) {
|
|
4
|
+
return this.lines && this.text === text && this.width === width ? this.lines.slice() : undefined;
|
|
5
|
+
}
|
|
6
|
+
write(text, width, lines) {
|
|
7
|
+
this.text = text;
|
|
8
|
+
this.width = width;
|
|
9
|
+
this.lines = lines;
|
|
10
|
+
}
|
|
11
|
+
clear() {
|
|
12
|
+
this.text = undefined;
|
|
13
|
+
this.width = undefined;
|
|
14
|
+
this.lines = undefined;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/** Owns the cache/revision lifecycle shared by terminal text components. */
|
|
18
|
+
export class TextRenderState {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.cache = new TextRenderCache();
|
|
21
|
+
this._revision = 0;
|
|
22
|
+
}
|
|
23
|
+
get revision() {
|
|
24
|
+
return this._revision;
|
|
25
|
+
}
|
|
26
|
+
invalidate() {
|
|
27
|
+
this.cache.clear();
|
|
28
|
+
this._revision++;
|
|
29
|
+
}
|
|
30
|
+
begin(text, width, paddingX) {
|
|
31
|
+
const cached = this.cache.read(text, width);
|
|
32
|
+
if (cached)
|
|
33
|
+
return { kind: "complete", lines: cached };
|
|
34
|
+
this._revision++;
|
|
35
|
+
const prepared = prepareTextBlock(text, width, paddingX);
|
|
36
|
+
if (prepared)
|
|
37
|
+
return { kind: "render", prepared };
|
|
38
|
+
const lines = [];
|
|
39
|
+
this.cache.write(text, width, lines);
|
|
40
|
+
return { kind: "complete", lines: [] };
|
|
41
|
+
}
|
|
42
|
+
finish(text, width, lines) {
|
|
43
|
+
this.cache.write(text, width, lines);
|
|
44
|
+
return lines.length > 0 ? lines.slice() : [""];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Shared mutable lifecycle for cache-backed text components. */
|
|
48
|
+
export class CachedTextComponent {
|
|
49
|
+
constructor(text, paddingX, paddingY) {
|
|
50
|
+
this.text = text;
|
|
51
|
+
this.paddingX = paddingX;
|
|
52
|
+
this.paddingY = paddingY;
|
|
53
|
+
this.renderState = new TextRenderState();
|
|
54
|
+
}
|
|
55
|
+
get renderRevision() {
|
|
56
|
+
return this.renderState.revision;
|
|
57
|
+
}
|
|
58
|
+
setText(text) {
|
|
59
|
+
this.text = text;
|
|
60
|
+
this.invalidate();
|
|
61
|
+
}
|
|
62
|
+
invalidate() {
|
|
63
|
+
this.renderState.invalidate();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function prepareTextBlock(text, width, paddingX) {
|
|
67
|
+
if (!text || text.trim() === "")
|
|
68
|
+
return undefined;
|
|
69
|
+
return {
|
|
70
|
+
normalizedText: text.replace(/\t/g, " "),
|
|
71
|
+
contentWidth: Math.max(1, width - paddingX * 2),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function frameTextLines(lines, options) {
|
|
75
|
+
const leftMargin = " ".repeat(options.paddingX);
|
|
76
|
+
const rightMargin = leftMargin;
|
|
77
|
+
const result = [];
|
|
78
|
+
const emptyLine = " ".repeat(options.width);
|
|
79
|
+
const framedEmptyLine = options.background
|
|
80
|
+
? applyBackgroundToLine(emptyLine, options.width, options.background)
|
|
81
|
+
: emptyLine;
|
|
82
|
+
for (let index = 0; index < options.paddingY; index++) {
|
|
83
|
+
result.push(framedEmptyLine);
|
|
84
|
+
}
|
|
85
|
+
for (const line of lines) {
|
|
86
|
+
if (options.isPassthrough?.(line)) {
|
|
87
|
+
result.push(line);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const lineWithMargins = leftMargin + line + rightMargin;
|
|
91
|
+
if (options.background) {
|
|
92
|
+
result.push(applyBackgroundToLine(lineWithMargins, options.width, options.background));
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const paddingNeeded = Math.max(0, options.width - visibleWidth(lineWithMargins));
|
|
96
|
+
result.push(lineWithMargins + " ".repeat(paddingNeeded));
|
|
97
|
+
}
|
|
98
|
+
for (let index = 0; index < options.paddingY; index++) {
|
|
99
|
+
result.push(framedEmptyLine);
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=text-layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-layout.js","sourceRoot":"","sources":["../../src/components/text-layout.ts"],"names":[],"mappings":"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","sourcesContent":["import { applyBackgroundToLine, visibleWidth } from \"../utils.ts\";\n\nexport interface PreparedTextBlock {\n\tnormalizedText: string;\n\tcontentWidth: number;\n}\n\nexport interface TextFrameOptions {\n\twidth: number;\n\tpaddingX: number;\n\tpaddingY: number;\n\tbackground?: (text: string) => string;\n\tisPassthrough?: (line: string) => boolean;\n}\n\nexport class TextRenderCache {\n\tprivate text?: string;\n\tprivate width?: number;\n\tprivate lines?: string[];\n\n\tread(text: string, width: number): string[] | undefined {\n\t\treturn this.lines && this.text === text && this.width === width ? this.lines.slice() : undefined;\n\t}\n\n\twrite(text: string, width: number, lines: string[]): void {\n\t\tthis.text = text;\n\t\tthis.width = width;\n\t\tthis.lines = lines;\n\t}\n\n\tclear(): void {\n\t\tthis.text = undefined;\n\t\tthis.width = undefined;\n\t\tthis.lines = undefined;\n\t}\n}\n\nexport type TextRenderStart = { kind: \"complete\"; lines: string[] } | { kind: \"render\"; prepared: PreparedTextBlock };\n\n/** Owns the cache/revision lifecycle shared by terminal text components. */\nexport class TextRenderState {\n\tprivate cache = new TextRenderCache();\n\tprivate _revision = 0;\n\n\tget revision(): number {\n\t\treturn this._revision;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cache.clear();\n\t\tthis._revision++;\n\t}\n\n\tbegin(text: string, width: number, paddingX: number): TextRenderStart {\n\t\tconst cached = this.cache.read(text, width);\n\t\tif (cached) return { kind: \"complete\", lines: cached };\n\t\tthis._revision++;\n\n\t\tconst prepared = prepareTextBlock(text, width, paddingX);\n\t\tif (prepared) return { kind: \"render\", prepared };\n\n\t\tconst lines: string[] = [];\n\t\tthis.cache.write(text, width, lines);\n\t\treturn { kind: \"complete\", lines: [] };\n\t}\n\n\tfinish(text: string, width: number, lines: string[]): string[] {\n\t\tthis.cache.write(text, width, lines);\n\t\treturn lines.length > 0 ? lines.slice() : [\"\"];\n\t}\n}\n\n/** Shared mutable lifecycle for cache-backed text components. */\nexport class CachedTextComponent {\n\tprotected text: string;\n\tprotected paddingX: number;\n\tprotected paddingY: number;\n\tprotected renderState: TextRenderState;\n\n\tconstructor(text: string, paddingX: number, paddingY: number) {\n\t\tthis.text = text;\n\t\tthis.paddingX = paddingX;\n\t\tthis.paddingY = paddingY;\n\t\tthis.renderState = new TextRenderState();\n\t}\n\n\tget renderRevision(): number {\n\t\treturn this.renderState.revision;\n\t}\n\n\tsetText(text: string): void {\n\t\tthis.text = text;\n\t\tthis.invalidate();\n\t}\n\n\tinvalidate(): void {\n\t\tthis.renderState.invalidate();\n\t}\n}\n\nexport function prepareTextBlock(text: string, width: number, paddingX: number): PreparedTextBlock | undefined {\n\tif (!text || text.trim() === \"\") return undefined;\n\treturn {\n\t\tnormalizedText: text.replace(/\\t/g, \" \"),\n\t\tcontentWidth: Math.max(1, width - paddingX * 2),\n\t};\n}\n\nexport function frameTextLines(lines: readonly string[], options: TextFrameOptions): string[] {\n\tconst leftMargin = \" \".repeat(options.paddingX);\n\tconst rightMargin = leftMargin;\n\tconst result: string[] = [];\n\tconst emptyLine = \" \".repeat(options.width);\n\tconst framedEmptyLine = options.background\n\t\t? applyBackgroundToLine(emptyLine, options.width, options.background)\n\t\t: emptyLine;\n\n\tfor (let index = 0; index < options.paddingY; index++) {\n\t\tresult.push(framedEmptyLine);\n\t}\n\n\tfor (const line of lines) {\n\t\tif (options.isPassthrough?.(line)) {\n\t\t\tresult.push(line);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst lineWithMargins = leftMargin + line + rightMargin;\n\t\tif (options.background) {\n\t\t\tresult.push(applyBackgroundToLine(lineWithMargins, options.width, options.background));\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst paddingNeeded = Math.max(0, options.width - visibleWidth(lineWithMargins));\n\t\tresult.push(lineWithMargins + \" \".repeat(paddingNeeded));\n\t}\n\n\tfor (let index = 0; index < options.paddingY; index++) {\n\t\tresult.push(framedEmptyLine);\n\t}\n\n\treturn result;\n}\n"]}
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
import type { Component } from "../tui.ts";
|
|
2
|
+
import { CachedTextComponent } from "./text-layout.ts";
|
|
2
3
|
/**
|
|
3
4
|
* Text component - displays multi-line text with word wrapping
|
|
4
5
|
*/
|
|
5
|
-
export declare class Text implements Component {
|
|
6
|
-
private text;
|
|
7
|
-
private _renderRevision;
|
|
8
|
-
get renderRevision(): number;
|
|
9
|
-
private paddingX;
|
|
10
|
-
private paddingY;
|
|
6
|
+
export declare class Text extends CachedTextComponent implements Component {
|
|
11
7
|
private customBgFn?;
|
|
12
|
-
private cachedText?;
|
|
13
|
-
private cachedWidth?;
|
|
14
|
-
private cachedLines?;
|
|
15
8
|
constructor(text?: string, paddingX?: number, paddingY?: number, customBgFn?: (text: string) => string);
|
|
16
|
-
setText(text: string): void;
|
|
17
9
|
setCustomBgFn(customBgFn?: (text: string) => string): void;
|
|
18
|
-
invalidate(): void;
|
|
19
10
|
render(width: number): string[];
|
|
20
11
|
}
|
|
21
12
|
//# sourceMappingURL=text.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/components/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/components/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,mBAAmB,EAAkB,MAAM,kBAAkB,CAAC;AAEvE;;GAEG;AACH,qBAAa,IAAK,SAAQ,mBAAoB,YAAW,SAAS;IACjE,OAAO,CAAC,UAAU,CAAC,CAA2B;IAE9C,YAAY,IAAI,GAAE,MAAW,EAAE,QAAQ,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAU,EAAE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAG/G;IAED,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAGzD;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAa9B;CACD"}
|
package/dist/components/text.js
CHANGED
|
@@ -1,97 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { wrapTextWithAnsi } from "../utils.js";
|
|
2
|
+
import { CachedTextComponent, frameTextLines } from "./text-layout.js";
|
|
2
3
|
/**
|
|
3
4
|
* Text component - displays multi-line text with word wrapping
|
|
4
5
|
*/
|
|
5
|
-
export class Text {
|
|
6
|
-
text;
|
|
7
|
-
_renderRevision = 0;
|
|
8
|
-
get renderRevision() {
|
|
9
|
-
return this._renderRevision;
|
|
10
|
-
}
|
|
11
|
-
paddingX; // Left/right padding
|
|
12
|
-
paddingY; // Top/bottom padding
|
|
13
|
-
customBgFn;
|
|
14
|
-
// Cache for rendered output
|
|
15
|
-
cachedText;
|
|
16
|
-
cachedWidth;
|
|
17
|
-
cachedLines;
|
|
6
|
+
export class Text extends CachedTextComponent {
|
|
18
7
|
constructor(text = "", paddingX = 1, paddingY = 1, customBgFn) {
|
|
19
|
-
|
|
20
|
-
this.paddingX = paddingX;
|
|
21
|
-
this.paddingY = paddingY;
|
|
8
|
+
super(text, paddingX, paddingY);
|
|
22
9
|
this.customBgFn = customBgFn;
|
|
23
10
|
}
|
|
24
|
-
setText(text) {
|
|
25
|
-
this.text = text;
|
|
26
|
-
this.cachedText = undefined;
|
|
27
|
-
this.cachedWidth = undefined;
|
|
28
|
-
this.cachedLines = undefined;
|
|
29
|
-
this._renderRevision++;
|
|
30
|
-
}
|
|
31
11
|
setCustomBgFn(customBgFn) {
|
|
32
12
|
this.customBgFn = customBgFn;
|
|
33
|
-
this.
|
|
34
|
-
this.cachedWidth = undefined;
|
|
35
|
-
this.cachedLines = undefined;
|
|
36
|
-
this._renderRevision++;
|
|
37
|
-
}
|
|
38
|
-
invalidate() {
|
|
39
|
-
this.cachedText = undefined;
|
|
40
|
-
this.cachedWidth = undefined;
|
|
41
|
-
this.cachedLines = undefined;
|
|
42
|
-
this._renderRevision++;
|
|
13
|
+
this.renderState.invalidate();
|
|
43
14
|
}
|
|
44
15
|
render(width) {
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
this._renderRevision++;
|
|
50
|
-
// Don't render anything if there's no actual text
|
|
51
|
-
if (!this.text || this.text.trim() === "") {
|
|
52
|
-
const result = [];
|
|
53
|
-
this.cachedText = this.text;
|
|
54
|
-
this.cachedWidth = width;
|
|
55
|
-
this.cachedLines = result;
|
|
56
|
-
return result.slice();
|
|
57
|
-
}
|
|
58
|
-
// Replace tabs with 3 spaces
|
|
59
|
-
const normalizedText = this.text.replace(/\t/g, " ");
|
|
60
|
-
// Calculate content width (subtract left/right margins)
|
|
61
|
-
const contentWidth = Math.max(1, width - this.paddingX * 2);
|
|
16
|
+
const start = this.renderState.begin(this.text, width, this.paddingX);
|
|
17
|
+
if (start.kind === "complete")
|
|
18
|
+
return start.lines;
|
|
62
19
|
// Wrap text (this preserves ANSI codes but does NOT pad)
|
|
63
|
-
const wrappedLines = wrapTextWithAnsi(normalizedText, contentWidth);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// Apply background if specified (this also pads to full width)
|
|
72
|
-
if (this.customBgFn) {
|
|
73
|
-
contentLines.push(applyBackgroundToLine(lineWithMargins, width, this.customBgFn));
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
// No background - just pad to width with spaces
|
|
77
|
-
const visibleLen = visibleWidth(lineWithMargins);
|
|
78
|
-
const paddingNeeded = Math.max(0, width - visibleLen);
|
|
79
|
-
contentLines.push(lineWithMargins + " ".repeat(paddingNeeded));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
// Add top/bottom padding (empty lines)
|
|
83
|
-
const emptyLine = " ".repeat(width);
|
|
84
|
-
const emptyLines = [];
|
|
85
|
-
for (let i = 0; i < this.paddingY; i++) {
|
|
86
|
-
const line = this.customBgFn ? applyBackgroundToLine(emptyLine, width, this.customBgFn) : emptyLine;
|
|
87
|
-
emptyLines.push(line);
|
|
88
|
-
}
|
|
89
|
-
const result = [...emptyLines, ...contentLines, ...emptyLines];
|
|
90
|
-
// Update cache
|
|
91
|
-
this.cachedText = this.text;
|
|
92
|
-
this.cachedWidth = width;
|
|
93
|
-
this.cachedLines = result;
|
|
94
|
-
return result.length > 0 ? result.slice() : [""];
|
|
20
|
+
const wrappedLines = wrapTextWithAnsi(start.prepared.normalizedText, start.prepared.contentWidth);
|
|
21
|
+
const result = frameTextLines(wrappedLines, {
|
|
22
|
+
width,
|
|
23
|
+
paddingX: this.paddingX,
|
|
24
|
+
paddingY: this.paddingY,
|
|
25
|
+
background: this.customBgFn,
|
|
26
|
+
});
|
|
27
|
+
return this.renderState.finish(this.text, width, result);
|
|
95
28
|
}
|
|
96
29
|
}
|
|
97
30
|
//# sourceMappingURL=text.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/components/text.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/components/text.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvE;;GAEG;AACH,MAAM,OAAO,IAAK,SAAQ,mBAAmB;IAG5C,YAAY,IAAI,GAAW,EAAE,EAAE,QAAQ,GAAW,CAAC,EAAE,QAAQ,GAAW,CAAC,EAAE,UAAqC;QAC/G,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAChC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC9B,CAAC;IAED,aAAa,CAAC,UAAqC;QAClD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,CAAC;IAC/B,CAAC;IAED,MAAM,CAAC,KAAa;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtE,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC;QAElD,yDAAyD;QACzD,MAAM,YAAY,GAAG,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAClG,MAAM,MAAM,GAAG,cAAc,CAAC,YAAY,EAAE;YAC3C,KAAK;YACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,UAAU,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC;CACD","sourcesContent":["import type { Component } from \"../tui.ts\";\nimport { wrapTextWithAnsi } from \"../utils.ts\";\nimport { CachedTextComponent, frameTextLines } from \"./text-layout.ts\";\n\n/**\n * Text component - displays multi-line text with word wrapping\n */\nexport class Text extends CachedTextComponent implements Component {\n\tprivate customBgFn?: (text: string) => string;\n\n\tconstructor(text: string = \"\", paddingX: number = 1, paddingY: number = 1, customBgFn?: (text: string) => string) {\n\t\tsuper(text, paddingX, paddingY);\n\t\tthis.customBgFn = customBgFn;\n\t}\n\n\tsetCustomBgFn(customBgFn?: (text: string) => string): void {\n\t\tthis.customBgFn = customBgFn;\n\t\tthis.renderState.invalidate();\n\t}\n\n\trender(width: number): string[] {\n\t\tconst start = this.renderState.begin(this.text, width, this.paddingX);\n\t\tif (start.kind === \"complete\") return start.lines;\n\n\t\t// Wrap text (this preserves ANSI codes but does NOT pad)\n\t\tconst wrappedLines = wrapTextWithAnsi(start.prepared.normalizedText, start.prepared.contentWidth);\n\t\tconst result = frameTextLines(wrappedLines, {\n\t\t\twidth,\n\t\t\tpaddingX: this.paddingX,\n\t\t\tpaddingY: this.paddingY,\n\t\t\tbackground: this.customBgFn,\n\t\t});\n\t\treturn this.renderState.finish(this.text, width, result);\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"truncated-text.d.ts","sourceRoot":"","sources":["../../src/components/truncated-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,qBAAa,aAAc,YAAW,SAAS;IAC9C,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IAEzB,YAAY,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAU,EAInE;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA0C9B;CACD"
|
|
1
|
+
{"version":3,"file":"truncated-text.d.ts","sourceRoot":"","sources":["../../src/components/truncated-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,qBAAa,aAAc,YAAW,SAAS;IAC9C,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IAEzB,YAAY,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAU,EAInE;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA0C9B;CACD"}
|
|
@@ -3,9 +3,6 @@ import { truncateToWidth, visibleWidth } from "../utils.js";
|
|
|
3
3
|
* Text component that truncates to fit viewport width
|
|
4
4
|
*/
|
|
5
5
|
export class TruncatedText {
|
|
6
|
-
text;
|
|
7
|
-
paddingX;
|
|
8
|
-
paddingY;
|
|
9
6
|
constructor(text, paddingX = 0, paddingY = 0) {
|
|
10
7
|
this.text = text;
|
|
11
8
|
this.paddingX = paddingX;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"truncated-text.js","sourceRoot":"","sources":["../../src/components/truncated-text.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE5D;;GAEG;AACH,MAAM,OAAO,aAAa;
|
|
1
|
+
{"version":3,"file":"truncated-text.js","sourceRoot":"","sources":["../../src/components/truncated-text.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE5D;;GAEG;AACH,MAAM,OAAO,aAAa;IAKzB,YAAY,IAAY,EAAE,QAAQ,GAAW,CAAC,EAAE,QAAQ,GAAW,CAAC;QACnE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC1B,CAAC;IAED,UAAU;QACT,0CAA0C;IAC3C,CAAC;IAED,MAAM,CAAC,KAAa;QACnB,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,6BAA6B;QAC7B,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEpC,6BAA6B;QAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC;QAED,qDAAqD;QACrD,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;QAE9D,6CAA6C;QAC7C,IAAI,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC;QAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;YACzB,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;QACvD,CAAC;QAED,sDAAsD;QACtD,MAAM,WAAW,GAAG,eAAe,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;QAEpE,yBAAyB;QACzB,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9C,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,eAAe,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;QAEjE,uCAAuC;QACvC,MAAM,gBAAgB,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;QACvD,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,gBAAgB,CAAC,CAAC;QAC5D,MAAM,SAAS,GAAG,eAAe,GAAG,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAE9D,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAEvB,6BAA6B;QAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,MAAM,CAAC;IACf,CAAC;CACD","sourcesContent":["import type { Component } from \"../tui.ts\";\nimport { truncateToWidth, visibleWidth } from \"../utils.ts\";\n\n/**\n * Text component that truncates to fit viewport width\n */\nexport class TruncatedText implements Component {\n\tprivate text: string;\n\tprivate paddingX: number;\n\tprivate paddingY: number;\n\n\tconstructor(text: string, paddingX: number = 0, paddingY: number = 0) {\n\t\tthis.text = text;\n\t\tthis.paddingX = paddingX;\n\t\tthis.paddingY = paddingY;\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached state to invalidate currently\n\t}\n\n\trender(width: number): string[] {\n\t\tconst result: string[] = [];\n\n\t\t// Empty line padded to width\n\t\tconst emptyLine = \" \".repeat(width);\n\n\t\t// Add vertical padding above\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tresult.push(emptyLine);\n\t\t}\n\n\t\t// Calculate available width after horizontal padding\n\t\tconst availableWidth = Math.max(1, width - this.paddingX * 2);\n\n\t\t// Take only the first line (stop at newline)\n\t\tlet singleLineText = this.text;\n\t\tconst newlineIndex = this.text.indexOf(\"\\n\");\n\t\tif (newlineIndex !== -1) {\n\t\t\tsingleLineText = this.text.substring(0, newlineIndex);\n\t\t}\n\n\t\t// Truncate text if needed (accounting for ANSI codes)\n\t\tconst displayText = truncateToWidth(singleLineText, availableWidth);\n\n\t\t// Add horizontal padding\n\t\tconst leftPadding = \" \".repeat(this.paddingX);\n\t\tconst rightPadding = \" \".repeat(this.paddingX);\n\t\tconst lineWithPadding = leftPadding + displayText + rightPadding;\n\n\t\t// Pad line to exactly width characters\n\t\tconst lineVisibleWidth = visibleWidth(lineWithPadding);\n\t\tconst paddingNeeded = Math.max(0, width - lineVisibleWidth);\n\t\tconst finalLine = lineWithPadding + \" \".repeat(paddingNeeded);\n\n\t\tresult.push(finalLine);\n\n\t\t// Add vertical padding below\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tresult.push(emptyLine);\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const DELETE_CHARACTER_BACKWARD: unique symbol;
|
|
2
|
+
export declare const DELETE_CHARACTER_FORWARD: unique symbol;
|
|
3
|
+
export declare const DELETE_WORD_BACKWARD: unique symbol;
|
|
4
|
+
export declare const DELETE_WORD_FORWARD: unique symbol;
|
|
5
|
+
export declare const DELETE_TO_LINE_START: unique symbol;
|
|
6
|
+
export declare const DELETE_TO_LINE_END: unique symbol;
|
|
7
|
+
export interface DeletionActionTarget {
|
|
8
|
+
[DELETE_CHARACTER_BACKWARD](): void;
|
|
9
|
+
[DELETE_CHARACTER_FORWARD](): void;
|
|
10
|
+
[DELETE_WORD_BACKWARD](): void;
|
|
11
|
+
[DELETE_WORD_FORWARD](): void;
|
|
12
|
+
[DELETE_TO_LINE_START](): void;
|
|
13
|
+
[DELETE_TO_LINE_END](): void;
|
|
14
|
+
}
|
|
15
|
+
/** Resolve and execute the shared configurable editor deletion intents. */
|
|
16
|
+
export declare function dispatchDeletionInput(data: string, target: DeletionActionTarget): boolean;
|
|
17
|
+
//# sourceMappingURL=editing-actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editing-actions.d.ts","sourceRoot":"","sources":["../src/editing-actions.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,yBAAyB,eAAoC,CAAC;AAC3E,eAAO,MAAM,wBAAwB,eAAmC,CAAC;AACzE,eAAO,MAAM,oBAAoB,eAA+B,CAAC;AACjE,eAAO,MAAM,mBAAmB,eAA8B,CAAC;AAC/D,eAAO,MAAM,oBAAoB,eAA8B,CAAC;AAChE,eAAO,MAAM,kBAAkB,eAA4B,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACpC,CAAC,yBAAyB,CAAC,IAAI,IAAI,CAAC;IACpC,CAAC,wBAAwB,CAAC,IAAI,IAAI,CAAC;IACnC,CAAC,oBAAoB,CAAC,IAAI,IAAI,CAAC;IAC/B,CAAC,mBAAmB,CAAC,IAAI,IAAI,CAAC;IAC9B,CAAC,oBAAoB,CAAC,IAAI,IAAI,CAAC;IAC/B,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC;CAC7B;AAED,2EAA2E;AAC3E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAkBzF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { getKeybindings } from "./keybindings.js";
|
|
2
|
+
export const DELETE_CHARACTER_BACKWARD = Symbol("deleteCharacterBackward");
|
|
3
|
+
export const DELETE_CHARACTER_FORWARD = Symbol("deleteCharacterForward");
|
|
4
|
+
export const DELETE_WORD_BACKWARD = Symbol("deleteWordBackward");
|
|
5
|
+
export const DELETE_WORD_FORWARD = Symbol("deleteWordForward");
|
|
6
|
+
export const DELETE_TO_LINE_START = Symbol("deleteToLineStart");
|
|
7
|
+
export const DELETE_TO_LINE_END = Symbol("deleteToLineEnd");
|
|
8
|
+
/** Resolve and execute the shared configurable editor deletion intents. */
|
|
9
|
+
export function dispatchDeletionInput(data, target) {
|
|
10
|
+
const keybindings = getKeybindings();
|
|
11
|
+
if (keybindings.matches(data, "tui.editor.deleteToLineEnd")) {
|
|
12
|
+
target[DELETE_TO_LINE_END]();
|
|
13
|
+
}
|
|
14
|
+
else if (keybindings.matches(data, "tui.editor.deleteToLineStart")) {
|
|
15
|
+
target[DELETE_TO_LINE_START]();
|
|
16
|
+
}
|
|
17
|
+
else if (keybindings.matches(data, "tui.editor.deleteWordBackward")) {
|
|
18
|
+
target[DELETE_WORD_BACKWARD]();
|
|
19
|
+
}
|
|
20
|
+
else if (keybindings.matches(data, "tui.editor.deleteWordForward")) {
|
|
21
|
+
target[DELETE_WORD_FORWARD]();
|
|
22
|
+
}
|
|
23
|
+
else if (keybindings.matches(data, "tui.editor.deleteCharBackward")) {
|
|
24
|
+
target[DELETE_CHARACTER_BACKWARD]();
|
|
25
|
+
}
|
|
26
|
+
else if (keybindings.matches(data, "tui.editor.deleteCharForward")) {
|
|
27
|
+
target[DELETE_CHARACTER_FORWARD]();
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=editing-actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editing-actions.js","sourceRoot":"","sources":["../src/editing-actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAC3E,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;AACzE,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;AACjE,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;AAC/D,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;AAChE,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAW5D,2EAA2E;AAC3E,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,MAA4B;IAC/E,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,4BAA4B,CAAC,EAAE,CAAC;QAC7D,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC;IAC9B,CAAC;SAAM,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,8BAA8B,CAAC,EAAE,CAAC;QACtE,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC;IAChC,CAAC;SAAM,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,+BAA+B,CAAC,EAAE,CAAC;QACvE,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC;IAChC,CAAC;SAAM,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,8BAA8B,CAAC,EAAE,CAAC;QACtE,MAAM,CAAC,mBAAmB,CAAC,EAAE,CAAC;IAC/B,CAAC;SAAM,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,+BAA+B,CAAC,EAAE,CAAC;QACvE,MAAM,CAAC,yBAAyB,CAAC,EAAE,CAAC;IACrC,CAAC;SAAM,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,8BAA8B,CAAC,EAAE,CAAC;QACtE,MAAM,CAAC,wBAAwB,CAAC,EAAE,CAAC;IACpC,CAAC;SAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC","sourcesContent":["import { getKeybindings } from \"./keybindings.ts\";\n\nexport const DELETE_CHARACTER_BACKWARD = Symbol(\"deleteCharacterBackward\");\nexport const DELETE_CHARACTER_FORWARD = Symbol(\"deleteCharacterForward\");\nexport const DELETE_WORD_BACKWARD = Symbol(\"deleteWordBackward\");\nexport const DELETE_WORD_FORWARD = Symbol(\"deleteWordForward\");\nexport const DELETE_TO_LINE_START = Symbol(\"deleteToLineStart\");\nexport const DELETE_TO_LINE_END = Symbol(\"deleteToLineEnd\");\n\nexport interface DeletionActionTarget {\n\t[DELETE_CHARACTER_BACKWARD](): void;\n\t[DELETE_CHARACTER_FORWARD](): void;\n\t[DELETE_WORD_BACKWARD](): void;\n\t[DELETE_WORD_FORWARD](): void;\n\t[DELETE_TO_LINE_START](): void;\n\t[DELETE_TO_LINE_END](): void;\n}\n\n/** Resolve and execute the shared configurable editor deletion intents. */\nexport function dispatchDeletionInput(data: string, target: DeletionActionTarget): boolean {\n\tconst keybindings = getKeybindings();\n\tif (keybindings.matches(data, \"tui.editor.deleteToLineEnd\")) {\n\t\ttarget[DELETE_TO_LINE_END]();\n\t} else if (keybindings.matches(data, \"tui.editor.deleteToLineStart\")) {\n\t\ttarget[DELETE_TO_LINE_START]();\n\t} else if (keybindings.matches(data, \"tui.editor.deleteWordBackward\")) {\n\t\ttarget[DELETE_WORD_BACKWARD]();\n\t} else if (keybindings.matches(data, \"tui.editor.deleteWordForward\")) {\n\t\ttarget[DELETE_WORD_FORWARD]();\n\t} else if (keybindings.matches(data, \"tui.editor.deleteCharBackward\")) {\n\t\ttarget[DELETE_CHARACTER_BACKWARD]();\n\t} else if (keybindings.matches(data, \"tui.editor.deleteCharForward\")) {\n\t\ttarget[DELETE_CHARACTER_FORWARD]();\n\t} else {\n\t\treturn false;\n\t}\n\treturn true;\n}\n"]}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { AutocompleteProvider } from "./autocomplete.ts";
|
|
2
2
|
import type { Component } from "./tui.ts";
|
|
3
|
+
/** Allocation-bounded structural projection for observers that do not need the full document. */
|
|
4
|
+
export interface EditorChangeSummary {
|
|
5
|
+
firstNonWhitespace: string | undefined;
|
|
6
|
+
}
|
|
7
|
+
export declare function firstNonWhitespaceCharacter(text: string): string | undefined;
|
|
3
8
|
/**
|
|
4
9
|
* Interface for custom editor components.
|
|
5
10
|
*
|
|
@@ -18,6 +23,10 @@ export interface EditorComponent extends Component {
|
|
|
18
23
|
onSubmit?: (text: string) => void;
|
|
19
24
|
/** Called when text changes */
|
|
20
25
|
onChange?: (text: string) => void;
|
|
26
|
+
/** Explicit capability flag for structural change notifications. */
|
|
27
|
+
readonly supportsChangeSummary?: true;
|
|
28
|
+
/** Called without materializing the full document when supported. */
|
|
29
|
+
onChangeSummary?: (summary: EditorChangeSummary) => void;
|
|
21
30
|
/** Add text to history for up/down navigation */
|
|
22
31
|
addToHistory?(text: string): void;
|
|
23
32
|
/** Replace the full input-history recall buffer, oldest entry first. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-component.d.ts","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAKjD,mCAAmC;IACnC,OAAO,IAAI,MAAM,CAAC;IAElB,2BAA2B;IAC3B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,qEAAqE;IACrE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAMhC,iDAAiD;IACjD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"editor-component.d.ts","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,iGAAiG;AACjG,MAAM,WAAW,mBAAmB;IACnC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG5E;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAKjD,mCAAmC;IACnC,OAAO,IAAI,MAAM,CAAC;IAElB,2BAA2B;IAC3B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAE5B,qEAAqE;IACrE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAMhC,iDAAiD;IACjD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAElC,oEAAoE;IACpE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,IAAI,CAAC;IAEtC,qEAAqE;IACrE,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAMzD,iDAAiD;IACjD,YAAY,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,wEAAwE;IACxE,UAAU,CAAC,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IAM5C,6CAA6C;IAC7C,kBAAkB,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAExC;;;OAGG;IACH,eAAe,CAAC,IAAI,MAAM,CAAC;IAM3B,oCAAoC;IACpC,uBAAuB,CAAC,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAM/D,4BAA4B;IAC5B,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IAEtC,6BAA6B;IAC7B,WAAW,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEpC,qDAAqD;IACrD,yBAAyB,CAAC,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACrD"}
|
package/dist/editor-component.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor-component.js","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"","sourcesContent":["import type { AutocompleteProvider } from \"./autocomplete.ts\";\nimport type { Component } from \"./tui.ts\";\n\n/**\n * Interface for custom editor components.\n *\n * This allows extensions to provide their own editor implementation\n * (e.g., vim mode, emacs mode, custom keybindings) while maintaining\n * compatibility with the core application.\n */\nexport interface EditorComponent extends Component {\n\t// =========================================================================\n\t// Core text access (required)\n\t// =========================================================================\n\n\t/** Get the current text content */\n\tgetText(): string;\n\n\t/** Set the text content */\n\tsetText(text: string): void;\n\n\t/** Handle raw terminal input (key presses, paste sequences, etc.) */\n\thandleInput(data: string): void;\n\n\t// =========================================================================\n\t// Callbacks (required)\n\t// =========================================================================\n\n\t/** Called when user submits (e.g., Enter key) */\n\tonSubmit?: (text: string) => void;\n\n\t/** Called when text changes */\n\tonChange?: (text: string) => void;\n\n\t// =========================================================================\n\t// History support (optional)\n\t// =========================================================================\n\n\t/** Add text to history for up/down navigation */\n\taddToHistory?(text: string): void;\n\n\t/** Replace the full input-history recall buffer, oldest entry first. */\n\tsetHistory?(texts: readonly string[]): void;\n\n\t// =========================================================================\n\t// Advanced text manipulation (optional)\n\t// =========================================================================\n\n\t/** Insert text at current cursor position */\n\tinsertTextAtCursor?(text: string): void;\n\n\t/**\n\t * Get text with any markers expanded (e.g., paste markers).\n\t * Falls back to getText() if not implemented.\n\t */\n\tgetExpandedText?(): string;\n\n\t// =========================================================================\n\t// Autocomplete support (optional)\n\t// =========================================================================\n\n\t/** Set the autocomplete provider */\n\tsetAutocompleteProvider?(provider: AutocompleteProvider): void;\n\n\t// =========================================================================\n\t// Appearance (optional)\n\t// =========================================================================\n\n\t/** Border color function */\n\tborderColor?: (str: string) => string;\n\n\t/** Set horizontal padding */\n\tsetPaddingX?(padding: number): void;\n\n\t/** Set max visible items in autocomplete dropdown */\n\tsetAutocompleteMaxVisible?(maxVisible: number): void;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"editor-component.js","sourceRoot":"","sources":["../src/editor-component.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,2BAA2B,CAAC,IAAY;IACvD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC","sourcesContent":["import type { AutocompleteProvider } from \"./autocomplete.ts\";\nimport type { Component } from \"./tui.ts\";\n\n/** Allocation-bounded structural projection for observers that do not need the full document. */\nexport interface EditorChangeSummary {\n\tfirstNonWhitespace: string | undefined;\n}\n\nexport function firstNonWhitespaceCharacter(text: string): string | undefined {\n\tconst index = text.search(/\\S/u);\n\treturn index === -1 ? undefined : text[index];\n}\n\n/**\n * Interface for custom editor components.\n *\n * This allows extensions to provide their own editor implementation\n * (e.g., vim mode, emacs mode, custom keybindings) while maintaining\n * compatibility with the core application.\n */\nexport interface EditorComponent extends Component {\n\t// =========================================================================\n\t// Core text access (required)\n\t// =========================================================================\n\n\t/** Get the current text content */\n\tgetText(): string;\n\n\t/** Set the text content */\n\tsetText(text: string): void;\n\n\t/** Handle raw terminal input (key presses, paste sequences, etc.) */\n\thandleInput(data: string): void;\n\n\t// =========================================================================\n\t// Callbacks (required)\n\t// =========================================================================\n\n\t/** Called when user submits (e.g., Enter key) */\n\tonSubmit?: (text: string) => void;\n\n\t/** Called when text changes */\n\tonChange?: (text: string) => void;\n\n\t/** Explicit capability flag for structural change notifications. */\n\treadonly supportsChangeSummary?: true;\n\n\t/** Called without materializing the full document when supported. */\n\tonChangeSummary?: (summary: EditorChangeSummary) => void;\n\n\t// =========================================================================\n\t// History support (optional)\n\t// =========================================================================\n\n\t/** Add text to history for up/down navigation */\n\taddToHistory?(text: string): void;\n\n\t/** Replace the full input-history recall buffer, oldest entry first. */\n\tsetHistory?(texts: readonly string[]): void;\n\n\t// =========================================================================\n\t// Advanced text manipulation (optional)\n\t// =========================================================================\n\n\t/** Insert text at current cursor position */\n\tinsertTextAtCursor?(text: string): void;\n\n\t/**\n\t * Get text with any markers expanded (e.g., paste markers).\n\t * Falls back to getText() if not implemented.\n\t */\n\tgetExpandedText?(): string;\n\n\t// =========================================================================\n\t// Autocomplete support (optional)\n\t// =========================================================================\n\n\t/** Set the autocomplete provider */\n\tsetAutocompleteProvider?(provider: AutocompleteProvider): void;\n\n\t// =========================================================================\n\t// Appearance (optional)\n\t// =========================================================================\n\n\t/** Border color function */\n\tborderColor?: (str: string) => string;\n\n\t/** Set horizontal padding */\n\tsetPaddingX?(padding: number): void;\n\n\t/** Set max visible items in autocomplete dropdown */\n\tsetAutocompleteMaxVisible?(maxVisible: number): void;\n}\n"]}
|
package/dist/fuzzy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fuzzy.d.ts","sourceRoot":"","sources":["../src/fuzzy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,UAAU;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CAiFlE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,CAAC,EAAE,CAsC3F"
|
|
1
|
+
{"version":3,"file":"fuzzy.d.ts","sourceRoot":"","sources":["../src/fuzzy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,UAAU;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CAiFlE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,CAAC,EAAE,CAsC3F"}
|
package/dist/fuzzy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fuzzy.js","sourceRoot":"","sources":["../src/fuzzy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,IAAY
|
|
1
|
+
{"version":3,"file":"fuzzy.js","sourceRoot":"","sources":["../src/fuzzy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,IAAY;IACrD,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAErC,MAAM,UAAU,GAAG,CAAC,eAAuB,EAAc,EAAE;QAC1D,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACpC,CAAC;QAED,IAAI,eAAe,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;YAC/C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACrC,CAAC;QAED,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,cAAc,GAAG,CAAC,CAAC,CAAC;QACxB,IAAI,kBAAkB,GAAG,CAAC,CAAC;QAE3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,IAAI,UAAU,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClF,IAAI,SAAS,CAAC,CAAC,CAAC,KAAK,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClD,MAAM,cAAc,GAAG,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,CAAC;gBAEvE,6BAA6B;gBAC7B,IAAI,cAAc,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC9B,kBAAkB,EAAE,CAAC;oBACrB,KAAK,IAAI,kBAAkB,GAAG,CAAC,CAAC;gBACjC,CAAC;qBAAM,CAAC;oBACP,kBAAkB,GAAG,CAAC,CAAC;oBACvB,gBAAgB;oBAChB,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;wBACzB,KAAK,IAAI,CAAC,CAAC,GAAG,cAAc,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;oBACvC,CAAC;gBACF,CAAC;gBAED,+BAA+B;gBAC/B,IAAI,cAAc,EAAE,CAAC;oBACpB,KAAK,IAAI,EAAE,CAAC;gBACb,CAAC;gBAED,mCAAmC;gBACnC,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC;gBAEjB,cAAc,GAAG,CAAC,CAAC;gBACnB,UAAU,EAAE,CAAC;YACd,CAAC;QACF,CAAC;QAED,IAAI,UAAU,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC;YACzC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACrC,CAAC;QAED,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;YACnC,KAAK,IAAI,GAAG,CAAC;QACd,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACjC,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;QAC1B,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,MAAM,iBAAiB,GAAG,UAAU,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACpF,MAAM,iBAAiB,GAAG,UAAU,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACpF,MAAM,YAAY,GAAG,iBAAiB;QACrC,CAAC,CAAC,GAAG,iBAAiB,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,GAAG,iBAAiB,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,EAAE;QACvF,CAAC,CAAC,iBAAiB;YAClB,CAAC,CAAC,GAAG,iBAAiB,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,GAAG,iBAAiB,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE;YACvF,CAAC,CAAC,EAAE,CAAC;IAEP,IAAI,CAAC,YAAY,EAAE,CAAC;QACnB,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,MAAM,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;QAC3B,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAI,KAAU,EAAE,KAAa,EAAE,OAA4B;IACrF,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QACnB,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,KAAK;SAClB,IAAI,EAAE;SACN,KAAK,CAAC,KAAK,CAAC;SACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE9B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAsC,EAAE,CAAC;IAEtD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,QAAQ,GAAG,IAAI,CAAC;QAEpB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACtC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBACnB,UAAU,IAAI,KAAK,CAAC,KAAK,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACP,QAAQ,GAAG,KAAK,CAAC;gBACjB,MAAM;YACP,CAAC;QACF,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QACpC,CAAC;IACF,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;IACpD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC","sourcesContent":["/**\n * Fuzzy matching utilities.\n * Matches if all query characters appear in order (not necessarily consecutive).\n * Lower score = better match.\n */\n\nexport interface FuzzyMatch {\n\tmatches: boolean;\n\tscore: number;\n}\n\nexport function fuzzyMatch(query: string, text: string): FuzzyMatch {\n\tconst queryLower = query.toLowerCase();\n\tconst textLower = text.toLowerCase();\n\n\tconst matchQuery = (normalizedQuery: string): FuzzyMatch => {\n\t\tif (normalizedQuery.length === 0) {\n\t\t\treturn { matches: true, score: 0 };\n\t\t}\n\n\t\tif (normalizedQuery.length > textLower.length) {\n\t\t\treturn { matches: false, score: 0 };\n\t\t}\n\n\t\tlet queryIndex = 0;\n\t\tlet score = 0;\n\t\tlet lastMatchIndex = -1;\n\t\tlet consecutiveMatches = 0;\n\n\t\tfor (let i = 0; i < textLower.length && queryIndex < normalizedQuery.length; i++) {\n\t\t\tif (textLower[i] === normalizedQuery[queryIndex]) {\n\t\t\t\tconst isWordBoundary = i === 0 || /[\\s\\-_./:]/.test(textLower[i - 1]!);\n\n\t\t\t\t// Reward consecutive matches\n\t\t\t\tif (lastMatchIndex === i - 1) {\n\t\t\t\t\tconsecutiveMatches++;\n\t\t\t\t\tscore -= consecutiveMatches * 5;\n\t\t\t\t} else {\n\t\t\t\t\tconsecutiveMatches = 0;\n\t\t\t\t\t// Penalize gaps\n\t\t\t\t\tif (lastMatchIndex >= 0) {\n\t\t\t\t\t\tscore += (i - lastMatchIndex - 1) * 2;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Reward word boundary matches\n\t\t\t\tif (isWordBoundary) {\n\t\t\t\t\tscore -= 10;\n\t\t\t\t}\n\n\t\t\t\t// Slight penalty for later matches\n\t\t\t\tscore += i * 0.1;\n\n\t\t\t\tlastMatchIndex = i;\n\t\t\t\tqueryIndex++;\n\t\t\t}\n\t\t}\n\n\t\tif (queryIndex < normalizedQuery.length) {\n\t\t\treturn { matches: false, score: 0 };\n\t\t}\n\n\t\tif (normalizedQuery === textLower) {\n\t\t\tscore -= 100;\n\t\t}\n\n\t\treturn { matches: true, score };\n\t};\n\n\tconst primaryMatch = matchQuery(queryLower);\n\tif (primaryMatch.matches) {\n\t\treturn primaryMatch;\n\t}\n\n\tconst alphaNumericMatch = queryLower.match(/^(?<letters>[a-z]+)(?<digits>[0-9]+)$/);\n\tconst numericAlphaMatch = queryLower.match(/^(?<digits>[0-9]+)(?<letters>[a-z]+)$/);\n\tconst swappedQuery = alphaNumericMatch\n\t\t? `${alphaNumericMatch.groups?.digits ?? \"\"}${alphaNumericMatch.groups?.letters ?? \"\"}`\n\t\t: numericAlphaMatch\n\t\t\t? `${numericAlphaMatch.groups?.letters ?? \"\"}${numericAlphaMatch.groups?.digits ?? \"\"}`\n\t\t\t: \"\";\n\n\tif (!swappedQuery) {\n\t\treturn primaryMatch;\n\t}\n\n\tconst swappedMatch = matchQuery(swappedQuery);\n\tif (!swappedMatch.matches) {\n\t\treturn primaryMatch;\n\t}\n\n\treturn { matches: true, score: swappedMatch.score + 5 };\n}\n\n/**\n * Filter and sort items by fuzzy match quality (best matches first).\n * Supports space-separated tokens: all tokens must match.\n */\nexport function fuzzyFilter<T>(items: T[], query: string, getText: (item: T) => string): T[] {\n\tif (!query.trim()) {\n\t\treturn items;\n\t}\n\n\tconst tokens = query\n\t\t.trim()\n\t\t.split(/\\s+/)\n\t\t.filter((t) => t.length > 0);\n\n\tif (tokens.length === 0) {\n\t\treturn items;\n\t}\n\n\tconst results: { item: T; totalScore: number }[] = [];\n\n\tfor (const item of items) {\n\t\tconst text = getText(item);\n\t\tlet totalScore = 0;\n\t\tlet allMatch = true;\n\n\t\tfor (const token of tokens) {\n\t\t\tconst match = fuzzyMatch(token, text);\n\t\t\tif (match.matches) {\n\t\t\t\ttotalScore += match.score;\n\t\t\t} else {\n\t\t\t\tallMatch = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (allMatch) {\n\t\t\tresults.push({ item, totalScore });\n\t\t}\n\t}\n\n\tresults.sort((a, b) => a.totalScore - b.totalScore);\n\treturn results.map((r) => r.item);\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export { type SettingItem, SettingsList, type SettingsListTheme } from "./compon
|
|
|
11
11
|
export { Spacer } from "./components/spacer.ts";
|
|
12
12
|
export { Text } from "./components/text.ts";
|
|
13
13
|
export { TruncatedText } from "./components/truncated-text.ts";
|
|
14
|
-
export type
|
|
14
|
+
export { type EditorChangeSummary, type EditorComponent, firstNonWhitespaceCharacter, } from "./editor-component.ts";
|
|
15
15
|
export { type FuzzyMatch, fuzzyFilter, fuzzyMatch } from "./fuzzy.ts";
|
|
16
16
|
export { getKeybindings, type Keybinding, type KeybindingConflict, type KeybindingDefinition, type KeybindingDefinitions, type Keybindings, type KeybindingsConfig, KeybindingsManager, setKeybindings, TUI_KEYBINDINGS, } from "./keybindings.ts";
|
|
17
17
|
export { decodeKittyPrintable, isKeyRelease, isKeyRepeat, isKittyProtocolActive, Key, type KeyEventType, type KeyId, matchesKey, parseKey, setKittyProtocolActive, } from "./keys.ts";
|