@effect-tui/react 0.15.2 → 0.16.0
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 +2 -2
- package/dist/src/components/ListView.d.ts +4 -4
- package/dist/src/components/ListView.d.ts.map +1 -1
- package/dist/src/components/ListView.js +16 -17
- package/dist/src/components/ListView.js.map +1 -1
- package/dist/src/console/ConsolePopover.d.ts +7 -1
- package/dist/src/console/ConsolePopover.d.ts.map +1 -1
- package/dist/src/console/ConsolePopover.js +55 -74
- package/dist/src/console/ConsolePopover.js.map +1 -1
- package/dist/src/debug/DebugOverlay.d.ts.map +1 -1
- package/dist/src/debug/DebugOverlay.js +3 -57
- package/dist/src/debug/DebugOverlay.js.map +1 -1
- package/dist/src/debug/DiagnosticsPanel.js +1 -1
- package/dist/src/debug/DiagnosticsPanel.js.map +1 -1
- package/dist/src/dev.d.ts +5 -117
- package/dist/src/dev.d.ts.map +1 -1
- package/dist/src/dev.js +3 -333
- package/dist/src/dev.js.map +1 -1
- package/dist/src/hooks/use-scroll.d.ts +31 -35
- package/dist/src/hooks/use-scroll.d.ts.map +1 -1
- package/dist/src/hooks/use-scroll.js +51 -90
- package/dist/src/hooks/use-scroll.js.map +1 -1
- package/dist/src/hosts/canvas.d.ts +2 -2
- package/dist/src/hosts/canvas.d.ts.map +1 -1
- package/dist/src/hosts/canvas.js +8 -10
- package/dist/src/hosts/canvas.js.map +1 -1
- package/dist/src/hosts/codeblock.d.ts +2 -2
- package/dist/src/hosts/codeblock.js +2 -2
- package/dist/src/hosts/flex-container.d.ts +1 -1
- package/dist/src/hosts/flex-container.d.ts.map +1 -1
- package/dist/src/hosts/flex-container.js +3 -3
- package/dist/src/hosts/flex-container.js.map +1 -1
- package/dist/src/hosts/index.d.ts +2 -1
- package/dist/src/hosts/index.d.ts.map +1 -1
- package/dist/src/hosts/index.js +2 -1
- package/dist/src/hosts/index.js.map +1 -1
- package/dist/src/hosts/layout-helpers.d.ts +10 -0
- package/dist/src/hosts/layout-helpers.d.ts.map +1 -0
- package/dist/src/hosts/layout-helpers.js +10 -0
- package/dist/src/hosts/layout-helpers.js.map +1 -0
- package/dist/src/hosts/leaf.d.ts +14 -0
- package/dist/src/hosts/leaf.d.ts.map +1 -0
- package/dist/src/hosts/leaf.js +31 -0
- package/dist/src/hosts/leaf.js.map +1 -0
- package/dist/src/hosts/overlay.d.ts.map +1 -1
- package/dist/src/hosts/overlay.js +4 -7
- package/dist/src/hosts/overlay.js.map +1 -1
- package/dist/src/hosts/scroll.d.ts +47 -24
- package/dist/src/hosts/scroll.d.ts.map +1 -1
- package/dist/src/hosts/scroll.js +68 -51
- package/dist/src/hosts/scroll.js.map +1 -1
- package/dist/src/hosts/spacer.d.ts +2 -2
- package/dist/src/hosts/spacer.js +2 -2
- package/dist/src/hosts/text.d.ts +2 -3
- package/dist/src/hosts/text.d.ts.map +1 -1
- package/dist/src/hosts/text.js +5 -61
- package/dist/src/hosts/text.js.map +1 -1
- package/dist/src/hosts/vstack.js +1 -1
- package/dist/src/hosts/vstack.js.map +1 -1
- package/dist/src/hosts/zstack.d.ts +1 -1
- package/dist/src/hosts/zstack.d.ts.map +1 -1
- package/dist/src/hosts/zstack.js +6 -6
- package/dist/src/hosts/zstack.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/internal/dev/hmr.d.ts +20 -0
- package/dist/src/internal/dev/hmr.d.ts.map +1 -0
- package/dist/src/internal/dev/hmr.js +93 -0
- package/dist/src/internal/dev/hmr.js.map +1 -0
- package/dist/src/internal/dev/runtime.d.ts +24 -0
- package/dist/src/internal/dev/runtime.d.ts.map +1 -0
- package/dist/src/internal/dev/runtime.js +135 -0
- package/dist/src/internal/dev/runtime.js.map +1 -0
- package/dist/src/internal/dev/ui.d.ts +13 -0
- package/dist/src/internal/dev/ui.d.ts.map +1 -0
- package/dist/src/internal/dev/ui.js +51 -0
- package/dist/src/internal/dev/ui.js.map +1 -0
- package/dist/src/internal/renderer/context.d.ts +9 -0
- package/dist/src/internal/renderer/context.d.ts.map +1 -0
- package/dist/src/internal/renderer/context.js +22 -0
- package/dist/src/internal/renderer/context.js.map +1 -0
- package/dist/src/internal/renderer/core/FrameBuilder.d.ts +18 -0
- package/dist/src/internal/renderer/core/FrameBuilder.d.ts.map +1 -0
- package/dist/src/internal/renderer/core/FrameBuilder.js +40 -0
- package/dist/src/internal/renderer/core/FrameBuilder.js.map +1 -0
- package/dist/src/internal/renderer/core/RendererState.d.ts +41 -0
- package/dist/src/internal/renderer/core/RendererState.d.ts.map +1 -0
- package/dist/src/internal/renderer/core/RendererState.js +70 -0
- package/dist/src/internal/renderer/core/RendererState.js.map +1 -0
- package/dist/src/internal/renderer/core/index.d.ts +3 -0
- package/dist/src/internal/renderer/core/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/core/index.js +3 -0
- package/dist/src/internal/renderer/core/index.js.map +1 -0
- package/dist/src/internal/renderer/index.d.ts +40 -0
- package/dist/src/internal/renderer/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/index.js +518 -0
- package/dist/src/internal/renderer/index.js.map +1 -0
- package/dist/src/internal/renderer/input/InputProcessor.d.ts +30 -0
- package/dist/src/internal/renderer/input/InputProcessor.d.ts.map +1 -0
- package/dist/src/internal/renderer/input/InputProcessor.js +122 -0
- package/dist/src/internal/renderer/input/InputProcessor.js.map +1 -0
- package/dist/src/internal/renderer/input/index.d.ts +2 -0
- package/dist/src/internal/renderer/input/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/input/index.js +2 -0
- package/dist/src/internal/renderer/input/index.js.map +1 -0
- package/dist/src/internal/renderer/lifecycle/EventBus.d.ts +42 -0
- package/dist/src/internal/renderer/lifecycle/EventBus.d.ts.map +1 -0
- package/dist/src/internal/renderer/lifecycle/EventBus.js +97 -0
- package/dist/src/internal/renderer/lifecycle/EventBus.js.map +1 -0
- package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.d.ts +13 -0
- package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.d.ts.map +1 -0
- package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.js +111 -0
- package/dist/src/internal/renderer/lifecycle/ProcessLifecycle.js.map +1 -0
- package/dist/src/internal/renderer/lifecycle/RenderCache.d.ts +3 -0
- package/dist/src/internal/renderer/lifecycle/RenderCache.d.ts.map +1 -0
- package/dist/src/internal/renderer/lifecycle/RenderCache.js +9 -0
- package/dist/src/internal/renderer/lifecycle/RenderCache.js.map +1 -0
- package/dist/src/internal/renderer/lifecycle/index.d.ts +4 -0
- package/dist/src/internal/renderer/lifecycle/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/lifecycle/index.js +4 -0
- package/dist/src/internal/renderer/lifecycle/index.js.map +1 -0
- package/dist/src/internal/renderer/modes/FullscreenRenderer.d.ts +12 -0
- package/dist/src/internal/renderer/modes/FullscreenRenderer.d.ts.map +1 -0
- package/dist/src/internal/renderer/modes/FullscreenRenderer.js +54 -0
- package/dist/src/internal/renderer/modes/FullscreenRenderer.js.map +1 -0
- package/dist/src/internal/renderer/modes/InlineRenderer.d.ts +25 -0
- package/dist/src/internal/renderer/modes/InlineRenderer.d.ts.map +1 -0
- package/dist/src/internal/renderer/modes/InlineRenderer.js +166 -0
- package/dist/src/internal/renderer/modes/InlineRenderer.js.map +1 -0
- package/dist/src/internal/renderer/modes/RendererMode.d.ts +42 -0
- package/dist/src/internal/renderer/modes/RendererMode.d.ts.map +1 -0
- package/dist/src/internal/renderer/modes/RendererMode.js +2 -0
- package/dist/src/internal/renderer/modes/RendererMode.js.map +1 -0
- package/dist/src/internal/renderer/modes/StaticContentRenderer.d.ts +25 -0
- package/dist/src/internal/renderer/modes/StaticContentRenderer.d.ts.map +1 -0
- package/dist/src/internal/renderer/modes/StaticContentRenderer.js +49 -0
- package/dist/src/internal/renderer/modes/StaticContentRenderer.js.map +1 -0
- package/dist/src/internal/renderer/modes/index.d.ts +5 -0
- package/dist/src/internal/renderer/modes/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/modes/index.js +4 -0
- package/dist/src/internal/renderer/modes/index.js.map +1 -0
- package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.d.ts +13 -0
- package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.d.ts.map +1 -0
- package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.js +75 -0
- package/dist/src/internal/renderer/terminal/KeyboardCapabilityProbe.js.map +1 -0
- package/dist/src/internal/renderer/terminal/TerminalSetup.d.ts +29 -0
- package/dist/src/internal/renderer/terminal/TerminalSetup.d.ts.map +1 -0
- package/dist/src/internal/renderer/terminal/TerminalSetup.js +82 -0
- package/dist/src/internal/renderer/terminal/TerminalSetup.js.map +1 -0
- package/dist/src/internal/renderer/terminal/index.d.ts +3 -0
- package/dist/src/internal/renderer/terminal/index.d.ts.map +1 -0
- package/dist/src/internal/renderer/terminal/index.js +3 -0
- package/dist/src/internal/renderer/terminal/index.js.map +1 -0
- package/dist/src/internal/renderer/types.d.ts +118 -0
- package/dist/src/internal/renderer/types.d.ts.map +1 -0
- package/dist/src/internal/renderer/types.js +2 -0
- package/dist/src/internal/renderer/types.js.map +1 -0
- package/dist/src/renderer-context.d.ts +1 -8
- package/dist/src/renderer-context.d.ts.map +1 -1
- package/dist/src/renderer-context.js +1 -21
- package/dist/src/renderer-context.js.map +1 -1
- package/dist/src/renderer-types.d.ts +1 -115
- package/dist/src/renderer-types.d.ts.map +1 -1
- package/dist/src/renderer.d.ts +1 -31
- package/dist/src/renderer.d.ts.map +1 -1
- package/dist/src/renderer.js +1 -495
- package/dist/src/renderer.js.map +1 -1
- package/dist/src/test/render-tui.d.ts +3 -3
- package/dist/src/test/render-tui.d.ts.map +1 -1
- package/dist/src/test/render-tui.js +16 -9
- package/dist/src/test/render-tui.js.map +1 -1
- package/dist/src/utils/alignment.d.ts +1 -1
- package/dist/src/utils/alignment.d.ts.map +1 -1
- package/dist/src/utils/alignment.js +0 -2
- package/dist/src/utils/alignment.js.map +1 -1
- package/dist/src/utils/console-helpers.d.ts +19 -0
- package/dist/src/utils/console-helpers.d.ts.map +1 -0
- package/dist/src/utils/console-helpers.js +61 -0
- package/dist/src/utils/console-helpers.js.map +1 -0
- package/dist/src/utils/index.d.ts +1 -1
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +1 -1
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/utils/styles.d.ts +8 -1
- package/dist/src/utils/styles.d.ts.map +1 -1
- package/dist/src/utils/styles.js +10 -8
- package/dist/src/utils/styles.js.map +1 -1
- package/dist/src/utils/text-wrap.d.ts +5 -0
- package/dist/src/utils/text-wrap.d.ts.map +1 -1
- package/dist/src/utils/text-wrap.js +110 -48
- package/dist/src/utils/text-wrap.js.map +1 -1
- package/dist/src/visualize/index.js +1 -1
- package/dist/src/visualize/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/components/ListView.tsx +21 -23
- package/src/console/ConsolePopover.tsx +124 -107
- package/src/debug/DebugOverlay.ts +15 -74
- package/src/debug/DiagnosticsPanel.tsx +1 -1
- package/src/dev.tsx +5 -458
- package/src/hooks/use-scroll.ts +85 -145
- package/src/hosts/canvas.ts +8 -11
- package/src/hosts/codeblock.ts +2 -2
- package/src/hosts/flex-container.ts +4 -4
- package/src/hosts/index.ts +10 -1
- package/src/hosts/layout-helpers.ts +20 -0
- package/src/hosts/leaf.ts +36 -0
- package/src/hosts/overlay.ts +11 -9
- package/src/hosts/scroll.ts +94 -69
- package/src/hosts/spacer.ts +2 -2
- package/src/hosts/text.ts +5 -58
- package/src/hosts/vstack.ts +1 -1
- package/src/hosts/zstack.ts +7 -7
- package/src/index.ts +1 -1
- package/src/internal/dev/hmr.ts +101 -0
- package/src/internal/dev/runtime.ts +170 -0
- package/src/internal/dev/ui.tsx +87 -0
- package/src/internal/renderer/context.ts +27 -0
- package/src/{renderer → internal/renderer}/core/FrameBuilder.ts +2 -2
- package/src/internal/renderer/index.ts +656 -0
- package/src/{renderer → internal/renderer}/input/InputProcessor.ts +10 -1
- package/src/{renderer → internal/renderer}/lifecycle/EventBus.ts +9 -1
- package/src/internal/renderer/lifecycle/ProcessLifecycle.ts +125 -0
- package/src/internal/renderer/lifecycle/index.ts +3 -0
- package/src/{renderer → internal/renderer}/modes/InlineRenderer.ts +5 -2
- package/src/{renderer → internal/renderer}/modes/RendererMode.ts +1 -1
- package/src/{renderer → internal/renderer}/modes/StaticContentRenderer.ts +5 -2
- package/src/internal/renderer/terminal/KeyboardCapabilityProbe.ts +91 -0
- package/src/{renderer/lifecycle → internal/renderer/terminal}/TerminalSetup.ts +4 -22
- package/src/internal/renderer/terminal/index.ts +2 -0
- package/src/internal/renderer/types.ts +125 -0
- package/src/renderer-context.ts +1 -27
- package/src/renderer-types.ts +10 -123
- package/src/renderer.ts +1 -619
- package/src/test/render-tui.ts +16 -10
- package/src/utils/alignment.ts +1 -3
- package/src/utils/console-helpers.ts +86 -0
- package/src/utils/index.ts +1 -1
- package/src/utils/styles.ts +16 -4
- package/src/utils/text-wrap.ts +139 -48
- package/src/visualize/index.tsx +1 -1
- package/src/renderer/lifecycle/ResizeManager.ts +0 -65
- package/src/renderer/lifecycle/index.ts +0 -4
- /package/src/{renderer → internal/renderer}/core/RendererState.ts +0 -0
- /package/src/{renderer → internal/renderer}/core/index.ts +0 -0
- /package/src/{renderer → internal/renderer}/input/index.ts +0 -0
- /package/src/{renderer → internal/renderer}/lifecycle/RenderCache.ts +0 -0
- /package/src/{renderer → internal/renderer}/modes/FullscreenRenderer.ts +0 -0
- /package/src/{renderer → internal/renderer}/modes/index.ts +0 -0
package/src/utils/alignment.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { Rect, Size } from "../reconciler/types.js"
|
|
6
6
|
|
|
7
|
-
export type HAlign = "left" | "center" | "right"
|
|
7
|
+
export type HAlign = "left" | "center" | "right"
|
|
8
8
|
export type VAlign = "top" | "center" | "bottom"
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -22,14 +22,12 @@ export function alignInRect(
|
|
|
22
22
|
|
|
23
23
|
switch (hAlign) {
|
|
24
24
|
case "left":
|
|
25
|
-
case "leading":
|
|
26
25
|
x = rect.x
|
|
27
26
|
break
|
|
28
27
|
case "center":
|
|
29
28
|
x = rect.x + Math.floor((rect.w - size.w) / 2)
|
|
30
29
|
break
|
|
31
30
|
case "right":
|
|
32
|
-
case "trailing":
|
|
33
31
|
x = rect.x + Math.max(0, rect.w - size.w)
|
|
34
32
|
break
|
|
35
33
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export interface SelectionPoint {
|
|
2
|
+
line: number
|
|
3
|
+
col: number
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function formatTimestamp(date: Date): string {
|
|
7
|
+
const h = date.getHours().toString().padStart(2, "0")
|
|
8
|
+
const m = date.getMinutes().toString().padStart(2, "0")
|
|
9
|
+
const s = date.getSeconds().toString().padStart(2, "0")
|
|
10
|
+
return `${h}:${m}:${s}`
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function formatLocation(loc?: { file: string; line: number }): string {
|
|
14
|
+
if (!loc) return ""
|
|
15
|
+
const parts = loc.file.split("/")
|
|
16
|
+
const filename = parts[parts.length - 1]
|
|
17
|
+
return `${filename}:${loc.line}`
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function wrapLine(text: string, maxWidth: number): string[] {
|
|
21
|
+
if (text.length <= maxWidth) return [text]
|
|
22
|
+
|
|
23
|
+
const lines: string[] = []
|
|
24
|
+
let remaining = text
|
|
25
|
+
|
|
26
|
+
while (remaining.length > 0) {
|
|
27
|
+
if (remaining.length <= maxWidth) {
|
|
28
|
+
lines.push(remaining)
|
|
29
|
+
break
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let breakAt = maxWidth
|
|
33
|
+
const lastSpace = remaining.lastIndexOf(" ", maxWidth)
|
|
34
|
+
if (lastSpace > maxWidth * 0.5) {
|
|
35
|
+
breakAt = lastSpace
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
lines.push(remaining.slice(0, breakAt))
|
|
39
|
+
remaining = remaining.slice(breakAt).trimStart()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return lines
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Normalize selection so start is before end */
|
|
46
|
+
export function normalizeSelection(
|
|
47
|
+
anchor: SelectionPoint,
|
|
48
|
+
head: SelectionPoint,
|
|
49
|
+
): [SelectionPoint, SelectionPoint] {
|
|
50
|
+
if (anchor.line < head.line || (anchor.line === head.line && anchor.col <= head.col)) {
|
|
51
|
+
return [anchor, head]
|
|
52
|
+
}
|
|
53
|
+
return [head, anchor]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Get selection bounds for a specific line */
|
|
57
|
+
export function getLineSelection(
|
|
58
|
+
lineIndex: number,
|
|
59
|
+
lineLength: number,
|
|
60
|
+
start: SelectionPoint,
|
|
61
|
+
end: SelectionPoint,
|
|
62
|
+
): { startCol: number; endCol: number } | null {
|
|
63
|
+
if (lineIndex < start.line || lineIndex > end.line) return null
|
|
64
|
+
|
|
65
|
+
const startCol = lineIndex === start.line ? Math.min(start.col, lineLength) : 0
|
|
66
|
+
const endCol = lineIndex === end.line ? Math.min(end.col, lineLength) : lineLength
|
|
67
|
+
|
|
68
|
+
if (startCol >= endCol && lineIndex === start.line && lineIndex === end.line) return null
|
|
69
|
+
|
|
70
|
+
return { startCol, endCol }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function getSelectionText(
|
|
74
|
+
lines: string[],
|
|
75
|
+
start: SelectionPoint,
|
|
76
|
+
end: SelectionPoint,
|
|
77
|
+
): string {
|
|
78
|
+
const selected: string[] = []
|
|
79
|
+
for (let i = start.line; i <= end.line && i < lines.length; i++) {
|
|
80
|
+
const lineText = lines[i] ?? ""
|
|
81
|
+
const startCol = i === start.line ? Math.min(start.col, lineText.length) : 0
|
|
82
|
+
const endCol = i === end.line ? Math.min(end.col, lineText.length) : lineText.length
|
|
83
|
+
selected.push(lineText.slice(startCol, endCol))
|
|
84
|
+
}
|
|
85
|
+
return selected.join("\n")
|
|
86
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -20,5 +20,5 @@ export {
|
|
|
20
20
|
styleSpecFromProps,
|
|
21
21
|
toColorValue,
|
|
22
22
|
} from "./styles.js"
|
|
23
|
-
export { wrapSpans } from "./text-wrap.js"
|
|
23
|
+
export { wrapSpans, wrapText } from "./text-wrap.js"
|
|
24
24
|
export { isWhitespace, matchNextWord, matchPrevWord, splitWords } from "./word-boundaries.js"
|
package/src/utils/styles.ts
CHANGED
|
@@ -83,14 +83,26 @@ export function resolveInheritedBgStyle(
|
|
|
83
83
|
/**
|
|
84
84
|
* Fill a rect with background color, inheriting from parent if needed.
|
|
85
85
|
*/
|
|
86
|
+
export interface FillRectWithInheritedBgOptions {
|
|
87
|
+
/** Skip filling when there is no inherited background value. */
|
|
88
|
+
skipWhenUndefined?: boolean
|
|
89
|
+
}
|
|
90
|
+
|
|
86
91
|
export function fillRectWithInheritedBg(
|
|
87
92
|
buffer: CellBuffer,
|
|
88
93
|
palette: Palette,
|
|
89
94
|
rect: Rect,
|
|
90
95
|
explicitBg: Color | undefined,
|
|
91
96
|
parent: HostInstance | null,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
options?: FillRectWithInheritedBgOptions,
|
|
98
|
+
): { value?: ColorValue; styleId: number } {
|
|
99
|
+
if (rect.w <= 0 || rect.h <= 0) {
|
|
100
|
+
return { value: undefined, styleId: 0 }
|
|
101
|
+
}
|
|
102
|
+
const resolved = resolveInheritedBgStyle(palette, explicitBg, parent)
|
|
103
|
+
if (options?.skipWhenUndefined && resolved.value === undefined) {
|
|
104
|
+
return resolved
|
|
105
|
+
}
|
|
106
|
+
buffer.fillRect(rect.x, rect.y, rect.w, rect.h, " ".codePointAt(0)!, resolved.styleId)
|
|
107
|
+
return resolved
|
|
96
108
|
}
|
package/src/utils/text-wrap.ts
CHANGED
|
@@ -3,59 +3,99 @@ import { isWhitespace, splitWords } from "./word-boundaries.js"
|
|
|
3
3
|
|
|
4
4
|
type SpanLike = { text: string }
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
type TokenSpec<T> = {
|
|
7
|
+
text: string
|
|
8
|
+
width: number
|
|
9
|
+
isWhitespace: boolean
|
|
10
|
+
make: (text: string) => T
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type LineToken<T> = {
|
|
14
|
+
value: T
|
|
15
|
+
width: number
|
|
16
|
+
isWhitespace: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type WrapOptions = {
|
|
20
|
+
trimTrailingWhitespace?: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function wrapTokens<T>(tokens: TokenSpec<T>[], maxWidth: number, options?: WrapOptions): T[][] {
|
|
24
|
+
const lines: LineToken<T>[][] = [[]]
|
|
12
25
|
let lineWidth = 0
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
27
|
+
const trimLine = () => {
|
|
28
|
+
if (!options?.trimTrailingWhitespace) return
|
|
29
|
+
const line = lines[lines.length - 1]
|
|
30
|
+
while (line.length > 0 && line[line.length - 1].isWhitespace) {
|
|
31
|
+
const removed = line.pop()
|
|
32
|
+
if (removed) {
|
|
33
|
+
lineWidth -= removed.width
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
17
37
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
38
|
+
const startNewLine = () => {
|
|
39
|
+
lines.push([])
|
|
40
|
+
lineWidth = 0
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const addToken = (token: TokenSpec<T>, text: string, width: number, isWhitespace: boolean) => {
|
|
44
|
+
lines[lines.length - 1].push({ value: token.make(text), width, isWhitespace })
|
|
45
|
+
lineWidth += width
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (const token of tokens) {
|
|
49
|
+
if (!token.text) continue
|
|
50
|
+
const tokenWidth = token.width
|
|
51
|
+
const isWs = token.isWhitespace
|
|
52
|
+
|
|
53
|
+
if (lineWidth + tokenWidth <= maxWidth) {
|
|
54
|
+
addToken(token, token.text, tokenWidth, isWs)
|
|
55
|
+
continue
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (isWs) {
|
|
59
|
+
// Skip whitespace at line break
|
|
60
|
+
continue
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (tokenWidth <= maxWidth) {
|
|
64
|
+
trimLine()
|
|
65
|
+
if (lines[lines.length - 1].length > 0) {
|
|
66
|
+
startNewLine()
|
|
67
|
+
}
|
|
68
|
+
addToken(token, token.text, tokenWidth, isWs)
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Token is longer than maxWidth - break by character
|
|
73
|
+
trimLine()
|
|
74
|
+
if (lines[lines.length - 1].length > 0) {
|
|
75
|
+
startNewLine()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let segment = ""
|
|
79
|
+
let segmentWidth = 0
|
|
80
|
+
|
|
81
|
+
for (const ch of token.text) {
|
|
82
|
+
const chWidth = displayWidth(ch)
|
|
83
|
+
if (lineWidth + segmentWidth + chWidth > maxWidth && (segment || lineWidth > 0)) {
|
|
84
|
+
if (segment) {
|
|
85
|
+
addToken(token, segment, segmentWidth, false)
|
|
56
86
|
}
|
|
87
|
+
startNewLine()
|
|
88
|
+
segment = ch
|
|
89
|
+
segmentWidth = chWidth
|
|
90
|
+
} else {
|
|
91
|
+
segment += ch
|
|
92
|
+
segmentWidth += chWidth
|
|
57
93
|
}
|
|
58
94
|
}
|
|
95
|
+
|
|
96
|
+
if (segment) {
|
|
97
|
+
addToken(token, segment, segmentWidth, false)
|
|
98
|
+
}
|
|
59
99
|
}
|
|
60
100
|
|
|
61
101
|
// Remove empty lines at the end
|
|
@@ -63,5 +103,56 @@ export function wrapSpans<T extends SpanLike>(spans: T[], maxWidth: number): T[]
|
|
|
63
103
|
lines.pop()
|
|
64
104
|
}
|
|
65
105
|
|
|
66
|
-
return lines.length > 0 ? lines : [[]]
|
|
106
|
+
return lines.length > 0 ? lines.map((line) => line.map((token) => token.value)) : [[]]
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Wrap spans into lines, breaking at word boundaries.
|
|
111
|
+
* Preserves span styling by cloning span objects with updated text.
|
|
112
|
+
*/
|
|
113
|
+
export function wrapSpans<T extends SpanLike>(spans: T[], maxWidth: number): T[][] {
|
|
114
|
+
const tokens: Array<TokenSpec<T>> = []
|
|
115
|
+
for (const span of spans) {
|
|
116
|
+
for (const token of splitWords(span.text)) {
|
|
117
|
+
if (!token) continue
|
|
118
|
+
tokens.push({
|
|
119
|
+
text: token,
|
|
120
|
+
width: displayWidth(token),
|
|
121
|
+
isWhitespace: isWhitespace(token),
|
|
122
|
+
make: (text) => ({ ...span, text }),
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return wrapTokens(tokens, maxWidth)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Wrap plain text into lines, breaking at word boundaries.
|
|
132
|
+
* Trims trailing whitespace when a line breaks.
|
|
133
|
+
*/
|
|
134
|
+
export function wrapText(text: string, maxWidth: number): string[] {
|
|
135
|
+
const lines: string[] = []
|
|
136
|
+
for (const rawLine of text.split("\n")) {
|
|
137
|
+
if (rawLine === "") {
|
|
138
|
+
lines.push("")
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
const tokens: Array<TokenSpec<string>> = []
|
|
142
|
+
for (const token of splitWords(rawLine)) {
|
|
143
|
+
if (!token) continue
|
|
144
|
+
tokens.push({
|
|
145
|
+
text: token,
|
|
146
|
+
width: displayWidth(token),
|
|
147
|
+
isWhitespace: isWhitespace(token),
|
|
148
|
+
make: (segment) => segment,
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
const wrapped = wrapTokens(tokens, maxWidth, { trimTrailingWhitespace: true })
|
|
152
|
+
for (const line of wrapped) {
|
|
153
|
+
lines.push(line.join(""))
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return lines.length > 0 ? lines : [""]
|
|
67
158
|
}
|
package/src/visualize/index.tsx
CHANGED
|
@@ -273,7 +273,7 @@ export const visualize = <A, E, R>(
|
|
|
273
273
|
: { status: "failure", elapsedMs: Date.now() - startTime, errorSummary: summarizeCause(exit.cause) },
|
|
274
274
|
)
|
|
275
275
|
renderer.requestRender()
|
|
276
|
-
renderer.
|
|
276
|
+
renderer.renderNow() // Ensure final state is rendered
|
|
277
277
|
|
|
278
278
|
// Wait for completion animation
|
|
279
279
|
yield* Effect.sleep(COMPLETION_DELAY_MS)
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import type { TuiWriteStream } from "../../renderer-types.js"
|
|
2
|
-
|
|
3
|
-
export interface ResizeState {
|
|
4
|
-
width: number
|
|
5
|
-
height: number
|
|
6
|
-
lastWidth: number
|
|
7
|
-
previousHeight: number // For inline mode
|
|
8
|
-
inlineClearHeight: number
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface ResizeResult {
|
|
12
|
-
newWidth: number
|
|
13
|
-
newHeight: number
|
|
14
|
-
needsFullClear: boolean // Fullscreen mode
|
|
15
|
-
inlineClearHeight: number // Inline mode
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Handles terminal resize events and calculates necessary clear/redraw actions.
|
|
20
|
-
*/
|
|
21
|
-
export class ResizeManager {
|
|
22
|
-
constructor(
|
|
23
|
-
private stdout: TuiWriteStream,
|
|
24
|
-
private mode: "fullscreen" | "inline",
|
|
25
|
-
) {}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Process a resize event and determine what actions are needed.
|
|
29
|
-
*/
|
|
30
|
-
handleResize(currentState: ResizeState): ResizeResult {
|
|
31
|
-
const newWidth = this.stdout.columns || 80
|
|
32
|
-
const newHeight = this.stdout.rows || 24
|
|
33
|
-
|
|
34
|
-
let needsFullClear = false
|
|
35
|
-
let inlineClearHeight = currentState.inlineClearHeight
|
|
36
|
-
|
|
37
|
-
if (this.mode === "fullscreen") {
|
|
38
|
-
// Fullscreen: defer clear to renderFrame so it's written atomically with content
|
|
39
|
-
needsFullClear = true
|
|
40
|
-
} else if (newWidth !== currentState.lastWidth || newHeight !== currentState.height) {
|
|
41
|
-
// Inline: on dimension change, request clear on next render
|
|
42
|
-
const clearHeight = Math.max(currentState.previousHeight, currentState.height, newHeight)
|
|
43
|
-
if (clearHeight > inlineClearHeight) {
|
|
44
|
-
inlineClearHeight = clearHeight
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
newWidth,
|
|
50
|
-
newHeight,
|
|
51
|
-
needsFullClear,
|
|
52
|
-
inlineClearHeight,
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Get current terminal dimensions.
|
|
58
|
-
*/
|
|
59
|
-
getDimensions(): { width: number; height: number } {
|
|
60
|
-
return {
|
|
61
|
-
width: this.stdout.columns || 80,
|
|
62
|
-
height: this.stdout.rows || 24,
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { EventBus } from "./EventBus.js"
|
|
2
|
-
export { getRenderCache, type RenderCache } from "./RenderCache.js"
|
|
3
|
-
export { ResizeManager, type ResizeResult, type ResizeState } from "./ResizeManager.js"
|
|
4
|
-
export { TerminalSetup, type TerminalSetupConfig } from "./TerminalSetup.js"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|