@code-yeongyu/senpi-tui 2026.9.12 → 2026.9.13
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/README.md +53 -4
- package/dist/alt-screen-search.d.ts +21 -1
- package/dist/alt-screen-search.d.ts.map +1 -1
- package/dist/alt-screen-search.js +199 -42
- package/dist/alt-screen-search.js.map +1 -1
- package/dist/components/box.d.ts +3 -1
- package/dist/components/box.d.ts.map +1 -1
- package/dist/components/box.js +28 -0
- package/dist/components/box.js.map +1 -1
- package/dist/components/editor.d.ts +6 -1
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +98 -18
- package/dist/components/editor.js.map +1 -1
- package/dist/components/input.d.ts +12 -1
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +40 -6
- package/dist/components/input.js.map +1 -1
- package/dist/components/latex.d.ts.map +1 -1
- package/dist/components/latex.js +7 -0
- package/dist/components/latex.js.map +1 -1
- package/dist/components/loader.d.ts +3 -0
- package/dist/components/loader.d.ts.map +1 -1
- package/dist/components/loader.js +20 -8
- package/dist/components/loader.js.map +1 -1
- package/dist/components/mouse-region.d.ts +12 -0
- package/dist/components/mouse-region.d.ts.map +1 -0
- package/dist/components/mouse-region.js +19 -0
- package/dist/components/mouse-region.js.map +1 -0
- package/dist/components/scroll-view.d.ts +6 -3
- package/dist/components/scroll-view.d.ts.map +1 -1
- package/dist/components/scroll-view.js +6 -1
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/components/select-list.d.ts +4 -1
- package/dist/components/select-list.d.ts.map +1 -1
- package/dist/components/select-list.js +48 -2
- package/dist/components/select-list.js.map +1 -1
- package/dist/components/settings-list.d.ts +5 -1
- package/dist/components/settings-list.d.ts.map +1 -1
- package/dist/components/settings-list.js +54 -5
- package/dist/components/settings-list.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts +3 -1
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +32 -9
- package/dist/layout.js.map +1 -1
- package/dist/native-modifiers.d.ts +2 -1
- package/dist/native-modifiers.d.ts.map +1 -1
- package/dist/native-modifiers.js +3 -44
- package/dist/native-modifiers.js.map +1 -1
- package/dist/native-platform.d.ts +18 -0
- package/dist/native-platform.d.ts.map +1 -0
- package/dist/native-platform.js +42 -0
- package/dist/native-platform.js.map +1 -0
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +2 -20
- package/dist/terminal.js.map +1 -1
- package/dist/tui-alt-screen.d.ts +31 -1
- package/dist/tui-alt-screen.d.ts.map +1 -1
- package/dist/tui-alt-screen.js +335 -41
- package/dist/tui-alt-screen.js.map +1 -1
- package/dist/tui.d.ts +83 -5
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +118 -4
- package/dist/tui.js.map +1 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +9 -0
- package/dist/utils.js.map +1 -1
- package/native/clipboard.h +170 -0
- package/native/darwin/README.md +8 -6
- package/native/darwin/build.sh +12 -5
- package/native/darwin/prebuilds/darwin-arm64/{darwin-modifiers.node → darwin-platform.node} +0 -0
- package/native/darwin/prebuilds/darwin-x64/{darwin-modifiers.node → darwin-platform.node} +0 -0
- package/native/darwin/src/darwin-platform.m +93 -0
- package/native/linux/README.md +23 -0
- package/native/linux/build.sh +65 -0
- package/native/linux/prebuilds/linux-arm64/linux-platform-x11.node +0 -0
- package/native/linux/prebuilds/linux-x64/linux-platform-x11.node +0 -0
- package/native/linux/src/clipboard-worker.h +70 -0
- package/native/linux/src/linux-platform-x11.c +274 -0
- package/native/napi.h +89 -0
- package/native/win32/README.md +18 -7
- package/native/win32/build.mjs +7 -4
- package/native/win32/prebuilds/win32-arm64/win32-platform.node +0 -0
- package/native/win32/prebuilds/win32-x64/win32-platform.node +0 -0
- package/native/win32/src/win32-platform.c +241 -0
- package/package.json +10 -3
- package/native/darwin/src/darwin-modifiers.c +0 -70
- package/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/native/win32/src/win32-console-mode.c +0 -119
package/dist/components/box.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dispatchMouseEvent } from "../tui.js";
|
|
1
2
|
import { applyBackgroundToLine, visibleWidth } from "../utils.js";
|
|
2
3
|
/**
|
|
3
4
|
* Box component - a container that applies padding and background to all children
|
|
@@ -63,6 +64,30 @@ export class Box {
|
|
|
63
64
|
child.invalidate?.();
|
|
64
65
|
}
|
|
65
66
|
}
|
|
67
|
+
handleMouse(event) {
|
|
68
|
+
const contentWidth = Math.max(1, event.width - this.paddingX * 2);
|
|
69
|
+
const contentY = event.y - this.paddingY;
|
|
70
|
+
const contentX = event.x - this.paddingX;
|
|
71
|
+
if (contentY < 0 || contentX < 0 || contentX >= contentWidth)
|
|
72
|
+
return undefined;
|
|
73
|
+
const mouseChildren = this.mouseLayout?.width === contentWidth
|
|
74
|
+
? this.mouseLayout.children
|
|
75
|
+
: this.children.map((component) => ({ component, height: component.render(contentWidth).length }));
|
|
76
|
+
let childY = 0;
|
|
77
|
+
for (const { component: child, height: childHeight } of mouseChildren) {
|
|
78
|
+
if (contentY >= childY && contentY < childY + childHeight) {
|
|
79
|
+
return dispatchMouseEvent(child, {
|
|
80
|
+
...event,
|
|
81
|
+
x: contentX,
|
|
82
|
+
y: contentY - childY,
|
|
83
|
+
width: contentWidth,
|
|
84
|
+
height: childHeight,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
childY += childHeight;
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
66
91
|
render(width) {
|
|
67
92
|
if (this.children.length === 0) {
|
|
68
93
|
return [];
|
|
@@ -71,12 +96,15 @@ export class Box {
|
|
|
71
96
|
const leftPad = " ".repeat(this.paddingX);
|
|
72
97
|
// Render all children
|
|
73
98
|
const childLines = [];
|
|
99
|
+
const mouseChildren = [];
|
|
74
100
|
for (const child of this.children) {
|
|
75
101
|
const lines = child.render(contentWidth);
|
|
102
|
+
mouseChildren.push({ component: child, height: lines.length });
|
|
76
103
|
for (const line of lines) {
|
|
77
104
|
childLines.push(leftPad + line);
|
|
78
105
|
}
|
|
79
106
|
}
|
|
107
|
+
this.mouseLayout = { width: contentWidth, children: mouseChildren };
|
|
80
108
|
if (childLines.length === 0) {
|
|
81
109
|
return [];
|
|
82
110
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"box.js","sourceRoot":"","sources":["../../src/components/box.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component } from \"../tui.ts\";\nimport { applyBackgroundToLine, visibleWidth } from \"../utils.ts\";\n\ntype RenderCache = {\n\tchildLines: string[];\n\twidth: number;\n\tbgSample: string | undefined;\n\tlines: string[];\n};\n\n/**\n * Box component - a container that applies padding and background to all children\n */\nexport class Box implements Component {\n\tchildren: Component[] = [];\n\tprivate paddingX: number;\n\tprivate paddingY: number;\n\tprivate bgFn?: (text: string) => string;\n\tprivate disposed = false;\n\n\t// Cache for rendered output\n\tprivate cache?: RenderCache;\n\n\tconstructor(paddingX = 1, paddingY = 1, bgFn?: (text: string) => string) {\n\t\tthis.paddingX = paddingX;\n\t\tthis.paddingY = paddingY;\n\t\tthis.bgFn = bgFn;\n\t}\n\n\taddChild(component: Component): void {\n\t\tthis.children.push(component);\n\t\tthis.invalidateCache();\n\t}\n\n\tremoveChild(component: Component): void {\n\t\tconst index = this.children.indexOf(component);\n\t\tif (index !== -1) {\n\t\t\tthis.children.splice(index, 1);\n\t\t\tthis.invalidateCache();\n\t\t\tcomponent.dispose?.();\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tfor (const child of this.children) {\n\t\t\tchild.dispose?.();\n\t\t}\n\t\tthis.children = [];\n\t\tthis.invalidateCache();\n\t}\n\n\tdetachAll(): void {\n\t\tthis.children = [];\n\t\tthis.invalidateCache();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tfor (const child of this.children) {\n\t\t\tchild.dispose?.();\n\t\t}\n\t\tthis.invalidateCache();\n\t}\n\n\tsetBgFn(bgFn?: (text: string) => string): void {\n\t\tthis.bgFn = bgFn;\n\t\t// Don't invalidate here - we'll detect bgFn changes by sampling output\n\t}\n\n\tprivate invalidateCache(): void {\n\t\tthis.cache = undefined;\n\t}\n\n\tprivate matchCache(width: number, childLines: string[], bgSample: string | undefined): boolean {\n\t\tconst cache = this.cache;\n\t\treturn (\n\t\t\t!!cache &&\n\t\t\tcache.width === width &&\n\t\t\tcache.bgSample === bgSample &&\n\t\t\tcache.childLines.length === childLines.length &&\n\t\t\tcache.childLines.every((line, i) => line === childLines[i])\n\t\t);\n\t}\n\n\tinvalidate(): void {\n\t\tthis.invalidateCache();\n\t\tfor (const child of this.children) {\n\t\t\tchild.invalidate?.();\n\t\t}\n\t}\n\n\trender(width: number): string[] {\n\t\tif (this.children.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst contentWidth = Math.max(1, width - this.paddingX * 2);\n\t\tconst leftPad = \" \".repeat(this.paddingX);\n\n\t\t// Render all children\n\t\tconst childLines: string[] = [];\n\t\tfor (const child of this.children) {\n\t\t\tconst lines = child.render(contentWidth);\n\t\t\tfor (const line of lines) {\n\t\t\t\tchildLines.push(leftPad + line);\n\t\t\t}\n\t\t}\n\n\t\tif (childLines.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Check if bgFn output changed by sampling\n\t\tconst bgSample = this.bgFn ? this.bgFn(\"test\") : undefined;\n\n\t\t// Check cache validity\n\t\tif (this.matchCache(width, childLines, bgSample)) {\n\t\t\treturn this.cache!.lines;\n\t\t}\n\n\t\t// Apply background and padding\n\t\tconst result: string[] = [];\n\n\t\t// Top padding\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tresult.push(this.applyBg(\"\", width));\n\t\t}\n\n\t\t// Content\n\t\tfor (const line of childLines) {\n\t\t\tresult.push(this.applyBg(line, width));\n\t\t}\n\n\t\t// Bottom padding\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tresult.push(this.applyBg(\"\", width));\n\t\t}\n\n\t\t// Update cache\n\t\tthis.cache = { childLines, width, bgSample, lines: result };\n\n\t\treturn result;\n\t}\n\n\tprivate applyBg(line: string, width: number): string {\n\t\tconst visLen = visibleWidth(line);\n\t\tconst padNeeded = Math.max(0, width - visLen);\n\t\tconst padded = line + \" \".repeat(padNeeded);\n\n\t\tif (this.bgFn) {\n\t\t\treturn applyBackgroundToLine(padded, width, this.bgFn);\n\t\t}\n\t\treturn padded;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"box.js","sourceRoot":"","sources":["../../src/components/box.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, dispatchMouseEvent, type TuiMouseDispatchResult, type TuiMouseEvent } from \"../tui.ts\";\nimport { applyBackgroundToLine, visibleWidth } from \"../utils.ts\";\n\ntype RenderCache = {\n\tchildLines: string[];\n\twidth: number;\n\tbgSample: string | undefined;\n\tlines: string[];\n};\n\n/**\n * Box component - a container that applies padding and background to all children\n */\nexport class Box implements Component {\n\tchildren: Component[] = [];\n\tprivate paddingX: number;\n\tprivate paddingY: number;\n\tprivate bgFn?: (text: string) => string;\n\tprivate disposed = false;\n\n\t// Cache for rendered output\n\tprivate cache?: RenderCache;\n\tprivate mouseLayout?: { width: number; children: Array<{ component: Component; height: number }> };\n\n\tconstructor(paddingX = 1, paddingY = 1, bgFn?: (text: string) => string) {\n\t\tthis.paddingX = paddingX;\n\t\tthis.paddingY = paddingY;\n\t\tthis.bgFn = bgFn;\n\t}\n\n\taddChild(component: Component): void {\n\t\tthis.children.push(component);\n\t\tthis.invalidateCache();\n\t}\n\n\tremoveChild(component: Component): void {\n\t\tconst index = this.children.indexOf(component);\n\t\tif (index !== -1) {\n\t\t\tthis.children.splice(index, 1);\n\t\t\tthis.invalidateCache();\n\t\t\tcomponent.dispose?.();\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tfor (const child of this.children) {\n\t\t\tchild.dispose?.();\n\t\t}\n\t\tthis.children = [];\n\t\tthis.invalidateCache();\n\t}\n\n\tdetachAll(): void {\n\t\tthis.children = [];\n\t\tthis.invalidateCache();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tfor (const child of this.children) {\n\t\t\tchild.dispose?.();\n\t\t}\n\t\tthis.invalidateCache();\n\t}\n\n\tsetBgFn(bgFn?: (text: string) => string): void {\n\t\tthis.bgFn = bgFn;\n\t\t// Don't invalidate here - we'll detect bgFn changes by sampling output\n\t}\n\n\tprivate invalidateCache(): void {\n\t\tthis.cache = undefined;\n\t}\n\n\tprivate matchCache(width: number, childLines: string[], bgSample: string | undefined): boolean {\n\t\tconst cache = this.cache;\n\t\treturn (\n\t\t\t!!cache &&\n\t\t\tcache.width === width &&\n\t\t\tcache.bgSample === bgSample &&\n\t\t\tcache.childLines.length === childLines.length &&\n\t\t\tcache.childLines.every((line, i) => line === childLines[i])\n\t\t);\n\t}\n\n\tinvalidate(): void {\n\t\tthis.invalidateCache();\n\t\tfor (const child of this.children) {\n\t\t\tchild.invalidate?.();\n\t\t}\n\t}\n\n\thandleMouse(event: TuiMouseEvent): TuiMouseDispatchResult | undefined {\n\t\tconst contentWidth = Math.max(1, event.width - this.paddingX * 2);\n\t\tconst contentY = event.y - this.paddingY;\n\t\tconst contentX = event.x - this.paddingX;\n\t\tif (contentY < 0 || contentX < 0 || contentX >= contentWidth) return undefined;\n\n\t\tconst mouseChildren =\n\t\t\tthis.mouseLayout?.width === contentWidth\n\t\t\t\t? this.mouseLayout.children\n\t\t\t\t: this.children.map((component) => ({ component, height: component.render(contentWidth).length }));\n\t\tlet childY = 0;\n\t\tfor (const { component: child, height: childHeight } of mouseChildren) {\n\t\t\tif (contentY >= childY && contentY < childY + childHeight) {\n\t\t\t\treturn dispatchMouseEvent(child, {\n\t\t\t\t\t...event,\n\t\t\t\t\tx: contentX,\n\t\t\t\t\ty: contentY - childY,\n\t\t\t\t\twidth: contentWidth,\n\t\t\t\t\theight: childHeight,\n\t\t\t\t});\n\t\t\t}\n\t\t\tchildY += childHeight;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\trender(width: number): string[] {\n\t\tif (this.children.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst contentWidth = Math.max(1, width - this.paddingX * 2);\n\t\tconst leftPad = \" \".repeat(this.paddingX);\n\n\t\t// Render all children\n\t\tconst childLines: string[] = [];\n\t\tconst mouseChildren: Array<{ component: Component; height: number }> = [];\n\t\tfor (const child of this.children) {\n\t\t\tconst lines = child.render(contentWidth);\n\t\t\tmouseChildren.push({ component: child, height: lines.length });\n\t\t\tfor (const line of lines) {\n\t\t\t\tchildLines.push(leftPad + line);\n\t\t\t}\n\t\t}\n\t\tthis.mouseLayout = { width: contentWidth, children: mouseChildren };\n\n\t\tif (childLines.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Check if bgFn output changed by sampling\n\t\tconst bgSample = this.bgFn ? this.bgFn(\"test\") : undefined;\n\n\t\t// Check cache validity\n\t\tif (this.matchCache(width, childLines, bgSample)) {\n\t\t\treturn this.cache!.lines;\n\t\t}\n\n\t\t// Apply background and padding\n\t\tconst result: string[] = [];\n\n\t\t// Top padding\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tresult.push(this.applyBg(\"\", width));\n\t\t}\n\n\t\t// Content\n\t\tfor (const line of childLines) {\n\t\t\tresult.push(this.applyBg(line, width));\n\t\t}\n\n\t\t// Bottom padding\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tresult.push(this.applyBg(\"\", width));\n\t\t}\n\n\t\t// Update cache\n\t\tthis.cache = { childLines, width, bgSample, lines: result };\n\n\t\treturn result;\n\t}\n\n\tprivate applyBg(line: string, width: number): string {\n\t\tconst visLen = visibleWidth(line);\n\t\tconst padNeeded = Math.max(0, width - visLen);\n\t\tconst padded = line + \" \".repeat(padNeeded);\n\n\t\tif (this.bgFn) {\n\t\t\treturn applyBackgroundToLine(padded, width, this.bgFn);\n\t\t}\n\t\treturn padded;\n\t}\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AutocompleteProvider } from "../autocomplete.ts";
|
|
2
2
|
import { type EditorImageState } from "../image-markers.ts";
|
|
3
3
|
import { type EditorPasteState } from "../paste-markers.ts";
|
|
4
|
-
import { type Component, type Focusable, type TUI } from "../tui.ts";
|
|
4
|
+
import { type Component, type Focusable, type TUI, type TuiMouseEvent, type TuiMouseEventResult } from "../tui.ts";
|
|
5
5
|
import { type SelectListTheme } from "./select-list.ts";
|
|
6
6
|
/** Which atomic marker family a segment belongs to, if any. */
|
|
7
7
|
export type MarkerKind = "paste" | "image";
|
|
@@ -55,6 +55,8 @@ export declare class Editor implements Component, Focusable {
|
|
|
55
55
|
private terminalPlatform?;
|
|
56
56
|
private terminalSocketExists?;
|
|
57
57
|
private lastWidth;
|
|
58
|
+
private renderedVisibleLineCount;
|
|
59
|
+
private renderedAutocompleteHeight;
|
|
58
60
|
private scrollOffset;
|
|
59
61
|
borderColor: (str: string) => string;
|
|
60
62
|
private autocompleteProvider?;
|
|
@@ -143,7 +145,10 @@ export declare class Editor implements Component, Focusable {
|
|
|
143
145
|
private setTextInternal;
|
|
144
146
|
invalidate(): void;
|
|
145
147
|
private getWrappedLine;
|
|
148
|
+
protected renderTopBorder(width: number, hiddenLineCount: number): string;
|
|
149
|
+
protected renderBottomBorder(width: number, hiddenLineCount: number): string;
|
|
146
150
|
render(width: number): string[];
|
|
151
|
+
handleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined;
|
|
147
152
|
handleInput(data: string): void;
|
|
148
153
|
private layoutText;
|
|
149
154
|
getText(): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/components/editor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAA2B,MAAM,oBAAoB,CAAC;AACxF,OAAO,EACN,KAAK,gBAAgB,EAOrB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EACN,KAAK,gBAAgB,EAKrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/components/editor.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { decodePrintableKey, matchesKey } from "../keys.js";
|
|
|
4
4
|
import { KillRing } from "../kill-ring.js";
|
|
5
5
|
import { isPasteMarker, PasteMarkerRegistry, pasteMarkerId, segmentWithMarkers, } from "../paste-markers.js";
|
|
6
6
|
import { normalizeWarpWslShiftEnterInput } from "../terminal.js";
|
|
7
|
-
import { CURSOR_MARKER } from "../tui.js";
|
|
7
|
+
import { CURSOR_MARKER, } from "../tui.js";
|
|
8
8
|
import { UndoStack } from "../undo-stack.js";
|
|
9
9
|
import { cjkBreakRegex, getGraphemeSegmenter, getWordSegmenter, isWhitespaceChar, sliceByColumn, visibleWidth, } from "../utils.js";
|
|
10
10
|
import { findWordBackward, findWordForward } from "../word-navigation.js";
|
|
@@ -183,6 +183,12 @@ function buildDebouncePattern(triggerCharacters) {
|
|
|
183
183
|
}
|
|
184
184
|
function createScrollBorder(direction, hiddenLineCount, width) {
|
|
185
185
|
const availableWidth = Math.max(0, width);
|
|
186
|
+
const label = ` ${direction} ${hiddenLineCount} more `;
|
|
187
|
+
const labelWidth = visibleWidth(label);
|
|
188
|
+
if (labelWidth + 2 <= availableWidth) {
|
|
189
|
+
const leftWidth = Math.floor((availableWidth - labelWidth) / 2);
|
|
190
|
+
return "─".repeat(leftWidth) + label + "─".repeat(availableWidth - leftWidth - labelWidth);
|
|
191
|
+
}
|
|
186
192
|
const indicator = `─── ${direction} ${hiddenLineCount} more `;
|
|
187
193
|
const remaining = availableWidth - visibleWidth(indicator);
|
|
188
194
|
if (remaining >= 0)
|
|
@@ -201,8 +207,10 @@ export class Editor {
|
|
|
201
207
|
/** Focusable interface - set by TUI when focus changes */
|
|
202
208
|
this.focused = false;
|
|
203
209
|
this.paddingX = 0;
|
|
204
|
-
// Store last render
|
|
210
|
+
// Store last render geometry for cursor navigation and mouse hit-testing.
|
|
205
211
|
this.lastWidth = 80;
|
|
212
|
+
this.renderedVisibleLineCount = 1;
|
|
213
|
+
this.renderedAutocompleteHeight = 0;
|
|
206
214
|
// Vertical scrolling support
|
|
207
215
|
this.scrollOffset = 0;
|
|
208
216
|
this.autocompleteTriggerCharacters = [...DEFAULT_AUTOCOMPLETE_TRIGGER_CHARACTERS];
|
|
@@ -437,6 +445,14 @@ export class Editor {
|
|
|
437
445
|
this.wrappedLineCache[lineIndex] = wrapped;
|
|
438
446
|
return wrapped;
|
|
439
447
|
}
|
|
448
|
+
renderTopBorder(width, hiddenLineCount) {
|
|
449
|
+
const border = hiddenLineCount > 0 ? createScrollBorder("↑", hiddenLineCount, width) : "─".repeat(width);
|
|
450
|
+
return this.borderColor(border);
|
|
451
|
+
}
|
|
452
|
+
renderBottomBorder(width, hiddenLineCount) {
|
|
453
|
+
const border = hiddenLineCount > 0 ? createScrollBorder("↓", hiddenLineCount, width) : "─".repeat(width);
|
|
454
|
+
return this.borderColor(border);
|
|
455
|
+
}
|
|
440
456
|
render(width) {
|
|
441
457
|
const maxPadding = Math.max(0, Math.floor((width - 1) / 2));
|
|
442
458
|
const paddingX = Math.min(this.paddingX, maxPadding);
|
|
@@ -446,7 +462,6 @@ export class Editor {
|
|
|
446
462
|
const layoutWidth = Math.max(1, contentWidth - (paddingX ? 0 : 1));
|
|
447
463
|
// Store for cursor navigation (must match wrapping width)
|
|
448
464
|
this.lastWidth = layoutWidth;
|
|
449
|
-
const horizontal = this.borderColor("─");
|
|
450
465
|
// Layout the text
|
|
451
466
|
const layoutLines = this.layoutText(layoutWidth);
|
|
452
467
|
// Calculate max visible lines: 30% of terminal height, minimum 5 lines
|
|
@@ -468,17 +483,12 @@ export class Editor {
|
|
|
468
483
|
this.scrollOffset = Math.max(0, Math.min(this.scrollOffset, maxScrollOffset));
|
|
469
484
|
// Get visible lines slice
|
|
470
485
|
const visibleLines = layoutLines.slice(this.scrollOffset, this.scrollOffset + maxVisibleLines);
|
|
486
|
+
this.renderedVisibleLineCount = visibleLines.length;
|
|
471
487
|
const result = [];
|
|
472
488
|
const leftPadding = " ".repeat(paddingX);
|
|
473
489
|
const rightPadding = leftPadding;
|
|
474
490
|
// Render top border (with scroll indicator if scrolled down)
|
|
475
|
-
|
|
476
|
-
const border = createScrollBorder("↑", this.scrollOffset, width);
|
|
477
|
-
result.push(this.borderColor(border));
|
|
478
|
-
}
|
|
479
|
-
else {
|
|
480
|
-
result.push(horizontal.repeat(width));
|
|
481
|
-
}
|
|
491
|
+
result.push(this.renderTopBorder(width, this.scrollOffset));
|
|
482
492
|
// Render each visible layout line
|
|
483
493
|
// Emit hardware cursor marker when focused so TUI can position the
|
|
484
494
|
// hardware cursor for IME candidate-window placement even while
|
|
@@ -527,16 +537,12 @@ export class Editor {
|
|
|
527
537
|
}
|
|
528
538
|
// Render bottom border (with scroll indicator if more content below)
|
|
529
539
|
const linesBelow = layoutLines.length - (this.scrollOffset + visibleLines.length);
|
|
530
|
-
|
|
531
|
-
const border = createScrollBorder("↓", linesBelow, width);
|
|
532
|
-
result.push(this.borderColor(border));
|
|
533
|
-
}
|
|
534
|
-
else {
|
|
535
|
-
result.push(horizontal.repeat(width));
|
|
536
|
-
}
|
|
540
|
+
result.push(this.renderBottomBorder(width, linesBelow));
|
|
537
541
|
// Add autocomplete list if active
|
|
542
|
+
this.renderedAutocompleteHeight = 0;
|
|
538
543
|
if (this.autocompleteState && this.autocompleteList) {
|
|
539
544
|
const autocompleteResult = this.autocompleteList.render(contentWidth);
|
|
545
|
+
this.renderedAutocompleteHeight = autocompleteResult.length;
|
|
540
546
|
for (const line of autocompleteResult) {
|
|
541
547
|
const lineWidth = visibleWidth(line);
|
|
542
548
|
const linePadding = " ".repeat(Math.max(0, contentWidth - lineWidth));
|
|
@@ -545,6 +551,67 @@ export class Editor {
|
|
|
545
551
|
}
|
|
546
552
|
return result;
|
|
547
553
|
}
|
|
554
|
+
handleMouse(event) {
|
|
555
|
+
const autocompleteStartRow = this.renderedVisibleLineCount + 2;
|
|
556
|
+
if (this.autocompleteState &&
|
|
557
|
+
this.autocompleteList &&
|
|
558
|
+
event.y >= autocompleteStartRow &&
|
|
559
|
+
event.y < autocompleteStartRow + this.renderedAutocompleteHeight) {
|
|
560
|
+
const maxPadding = Math.max(0, Math.floor((event.width - 1) / 2));
|
|
561
|
+
const paddingX = Math.min(this.paddingX, maxPadding);
|
|
562
|
+
const contentWidth = Math.max(1, event.width - paddingX * 2);
|
|
563
|
+
const result = this.autocompleteList.handleMouse?.({
|
|
564
|
+
...event,
|
|
565
|
+
x: event.x - paddingX,
|
|
566
|
+
y: event.y - autocompleteStartRow,
|
|
567
|
+
width: contentWidth,
|
|
568
|
+
height: this.renderedAutocompleteHeight,
|
|
569
|
+
});
|
|
570
|
+
return result ? { ...result, focus: true } : undefined;
|
|
571
|
+
}
|
|
572
|
+
// Leave press/drag/release unhandled so the renderer's screen-level text
|
|
573
|
+
// selection can run over the editor rows (drag to select, release to copy).
|
|
574
|
+
// The renderer synthesizes a click when press and release land on the same
|
|
575
|
+
// cell without movement, which is the gesture that positions the cursor.
|
|
576
|
+
if (event.type !== "click" || event.button !== "left")
|
|
577
|
+
return undefined;
|
|
578
|
+
if (event.y <= 0 || event.y > this.renderedVisibleLineCount)
|
|
579
|
+
return { handled: true, focus: true };
|
|
580
|
+
const visualLines = this.buildVisualLineMap(this.lastWidth);
|
|
581
|
+
const visualLineIndex = this.scrollOffset + event.y - 1;
|
|
582
|
+
const visualLine = visualLines[visualLineIndex];
|
|
583
|
+
if (!visualLine)
|
|
584
|
+
return { handled: true, focus: true };
|
|
585
|
+
const logicalLine = this.state.lines[visualLine.logicalLine] ?? "";
|
|
586
|
+
const chunkEnd = visualLine.startCol + visualLine.length;
|
|
587
|
+
const chunk = logicalLine.slice(visualLine.startCol, chunkEnd);
|
|
588
|
+
const maxPadding = Math.max(0, Math.floor((event.width - 1) / 2));
|
|
589
|
+
const paddingX = Math.min(this.paddingX, maxPadding);
|
|
590
|
+
const targetColumn = Math.max(0, event.x - paddingX);
|
|
591
|
+
let visibleColumn = 0;
|
|
592
|
+
let targetIndex = chunk.length;
|
|
593
|
+
let lastGraphemeIndex = 0;
|
|
594
|
+
for (const grapheme of this.segment(chunk, "grapheme")) {
|
|
595
|
+
const nextColumn = visibleColumn + visibleWidth(grapheme.segment);
|
|
596
|
+
lastGraphemeIndex = grapheme.index;
|
|
597
|
+
if (targetColumn < nextColumn) {
|
|
598
|
+
targetIndex = grapheme.index;
|
|
599
|
+
break;
|
|
600
|
+
}
|
|
601
|
+
visibleColumn = nextColumn;
|
|
602
|
+
}
|
|
603
|
+
const isLastSegment = visualLineIndex === visualLines.length - 1 ||
|
|
604
|
+
visualLines[visualLineIndex + 1]?.logicalLine !== visualLine.logicalLine;
|
|
605
|
+
if (!isLastSegment && targetIndex === chunk.length && chunk.length > 0)
|
|
606
|
+
targetIndex = lastGraphemeIndex;
|
|
607
|
+
this.state.cursorLine = visualLine.logicalLine;
|
|
608
|
+
this.setCursorCol(visualLine.startCol + targetIndex);
|
|
609
|
+
this.lastAction = null;
|
|
610
|
+
this.exitHistoryBrowsing();
|
|
611
|
+
if (this.autocompleteState)
|
|
612
|
+
this.updateAutocomplete();
|
|
613
|
+
return { handled: true, focus: true };
|
|
614
|
+
}
|
|
548
615
|
handleInput(data) {
|
|
549
616
|
data = normalizeWarpWslShiftEnterInput(data, this.terminalEnvironment, this.terminalPlatform, this.terminalSocketExists);
|
|
550
617
|
const kb = getKeybindings();
|
|
@@ -1969,7 +2036,20 @@ export class Editor {
|
|
|
1969
2036
|
}
|
|
1970
2037
|
createAutocompleteList(prefix, items) {
|
|
1971
2038
|
const layout = prefix.startsWith("/") ? SLASH_COMMAND_SELECT_LIST_LAYOUT : undefined;
|
|
1972
|
-
|
|
2039
|
+
const list = new SelectList(items, this.autocompleteMaxVisible, this.theme.selectList, layout);
|
|
2040
|
+
list.onSelect = (selected) => {
|
|
2041
|
+
if (!this.autocompleteProvider)
|
|
2042
|
+
return;
|
|
2043
|
+
this.pushUndoSnapshot();
|
|
2044
|
+
this.lastAction = null;
|
|
2045
|
+
const result = this.autocompleteProvider.applyCompletion(this.state.lines, this.state.cursorLine, this.state.cursorCol, selected, this.autocompletePrefix);
|
|
2046
|
+
this.state.lines = result.lines;
|
|
2047
|
+
this.state.cursorLine = result.cursorLine;
|
|
2048
|
+
this.setCursorCol(result.cursorCol);
|
|
2049
|
+
this.cancelAutocomplete();
|
|
2050
|
+
this.onChange?.(this.getText());
|
|
2051
|
+
};
|
|
2052
|
+
return list;
|
|
1973
2053
|
}
|
|
1974
2054
|
tryTriggerAutocomplete(explicitTab = false) {
|
|
1975
2055
|
this.requestAutocomplete({ force: false, explicitTab });
|