@luan.sh/pi-libtui 0.3.8

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.
Files changed (157) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +208 -0
  3. package/native-revision +1 -0
  4. package/package.json +58 -0
  5. package/src/activity-presentation.ts +75 -0
  6. package/src/appearance.ts +632 -0
  7. package/src/background-surface.ts +125 -0
  8. package/src/color/palette.ts +186 -0
  9. package/src/color/preview.ts +157 -0
  10. package/src/color/resolver.ts +75 -0
  11. package/src/color/theme.ts +531 -0
  12. package/src/component-stack.ts +247 -0
  13. package/src/content/markdown-code.ts +60 -0
  14. package/src/content/terminal-text.ts +135 -0
  15. package/src/content/text.ts +105 -0
  16. package/src/controls/action-panel.ts +420 -0
  17. package/src/controls/dialog-button-bar.ts +287 -0
  18. package/src/controls/multi-select.ts +467 -0
  19. package/src/controls/picker-panel.ts +447 -0
  20. package/src/controls/screen-icon-actions.ts +134 -0
  21. package/src/controls/searchable-select.ts +394 -0
  22. package/src/controls/select-box.ts +224 -0
  23. package/src/controls/selectable-list.ts +433 -0
  24. package/src/controls/selection-action-bar.ts +382 -0
  25. package/src/controls/semantic-input.ts +23 -0
  26. package/src/controls/tab.ts +189 -0
  27. package/src/cursor.ts +288 -0
  28. package/src/decoration/editor-pills.ts +156 -0
  29. package/src/decoration/glyphs.ts +326 -0
  30. package/src/decoration/pointer-interaction.ts +123 -0
  31. package/src/decoration/powerline-pill.ts +104 -0
  32. package/src/decoration/status.ts +185 -0
  33. package/src/decoration/transient-pill.ts +176 -0
  34. package/src/diff/index.ts +21 -0
  35. package/src/diff/model.ts +76 -0
  36. package/src/diff/parse.ts +310 -0
  37. package/src/diff/pierre-syntax.ts +86 -0
  38. package/src/diff/render.ts +504 -0
  39. package/src/diff/structured.ts +264 -0
  40. package/src/diff/view.ts +75 -0
  41. package/src/editor/chrome.ts +341 -0
  42. package/src/editor/composition.ts +53 -0
  43. package/src/editor/layout.ts +81 -0
  44. package/src/editor/presentation.ts +35 -0
  45. package/src/editor/protocol.ts +188 -0
  46. package/src/editor.ts +41 -0
  47. package/src/extension.ts +30 -0
  48. package/src/folding.ts +192 -0
  49. package/src/host/cursor-bridge.ts +210 -0
  50. package/src/host/editor-bridge.ts +148 -0
  51. package/src/host/extension-host.ts +231 -0
  52. package/src/host/mouse-bridge.ts +212 -0
  53. package/src/host/mouse-dispatch.ts +400 -0
  54. package/src/host/mouse-input.ts +85 -0
  55. package/src/host/mouse-targets.ts +238 -0
  56. package/src/host/pi-layout-adapter.ts +298 -0
  57. package/src/host/pi-native-selection.ts +227 -0
  58. package/src/host/split-pane-bridge.ts +720 -0
  59. package/src/host/transcript-bridge.ts +236 -0
  60. package/src/index.ts +334 -0
  61. package/src/line-layout.ts +6 -0
  62. package/src/motion.ts +1409 -0
  63. package/src/mouse/events.ts +55 -0
  64. package/src/mouse/fullscreen-layout.ts +260 -0
  65. package/src/mouse/registry.ts +348 -0
  66. package/src/mouse.ts +37 -0
  67. package/src/native-binary.ts +189 -0
  68. package/src/overlay/anchored.ts +91 -0
  69. package/src/overlay/detail-card.ts +158 -0
  70. package/src/overlay/dialog.ts +266 -0
  71. package/src/overlay/floating.ts +106 -0
  72. package/src/overlay/framed-editor.ts +236 -0
  73. package/src/overlay/fullscreen.ts +170 -0
  74. package/src/overlay/hover-tooltip.ts +109 -0
  75. package/src/overlay/modal-mount.ts +118 -0
  76. package/src/panels.ts +207 -0
  77. package/src/render-cache.ts +80 -0
  78. package/src/render-epoch.ts +48 -0
  79. package/src/request-animation.ts +160 -0
  80. package/src/scrollbar.ts +27 -0
  81. package/src/selection.ts +148 -0
  82. package/src/split-pane.ts +232 -0
  83. package/src/status-presentation.ts +411 -0
  84. package/src/stream.ts +543 -0
  85. package/src/syntax.ts +316 -0
  86. package/src/terminal/bridge-client.ts +243 -0
  87. package/src/terminal/embedding.ts +6 -0
  88. package/src/terminal/output.ts +151 -0
  89. package/src/terminal/projection.ts +362 -0
  90. package/src/terminal/pty-host.ts +263 -0
  91. package/src/terminal/pty-pane.ts +308 -0
  92. package/src/terminal-colors.ts +334 -0
  93. package/src/tool/action.ts +170 -0
  94. package/src/tool/activity.ts +500 -0
  95. package/src/tool/call-preview.ts +44 -0
  96. package/src/tool/disclosure-action.ts +89 -0
  97. package/src/tool/expanded-region-viewport.ts +103 -0
  98. package/src/tool/index.ts +26 -0
  99. package/src/tool/output.ts +271 -0
  100. package/src/tool/transcript.ts +150 -0
  101. package/src/tool/view-region.ts +581 -0
  102. package/test/appearance.test.ts +183 -0
  103. package/test/bounded-stream.test.ts +150 -0
  104. package/test/bridge-client.test.ts +42 -0
  105. package/test/color-preview.test.ts +23 -0
  106. package/test/component-stack.test.ts +206 -0
  107. package/test/components.test.ts +1165 -0
  108. package/test/content-text.test.ts +21 -0
  109. package/test/cursor-bridge.test.ts +151 -0
  110. package/test/cursor.test.ts +147 -0
  111. package/test/editor-chrome.test.ts +119 -0
  112. package/test/editor-layout.test.ts +30 -0
  113. package/test/editor-registry.test.ts +203 -0
  114. package/test/editor-theme.test.ts +33 -0
  115. package/test/editor-token-pill.test.ts +72 -0
  116. package/test/floating-overlay.test.ts +57 -0
  117. package/test/folding.test.ts +147 -0
  118. package/test/harmonious-theme.test.ts +23 -0
  119. package/test/interaction.test.ts +104 -0
  120. package/test/key-icons.test.ts +62 -0
  121. package/test/markdown-code.test.ts +24 -0
  122. package/test/modal-overlay-mount.test.ts +94 -0
  123. package/test/motion.test.ts +649 -0
  124. package/test/mouse/bridge.test.ts +1302 -0
  125. package/test/mouse/extension.test.ts +205 -0
  126. package/test/mouse/registry.test.ts +140 -0
  127. package/test/mouse/screen-decoration.test.ts +167 -0
  128. package/test/native-binary.test.ts +52 -0
  129. package/test/palette.test.ts +32 -0
  130. package/test/panels.test.ts +74 -0
  131. package/test/pointer-components.test.ts +151 -0
  132. package/test/progress.test.ts +54 -0
  133. package/test/pty-host.test.ts +126 -0
  134. package/test/pty-pane.test.ts +62 -0
  135. package/test/public-surface.test.ts +75 -0
  136. package/test/render-cache.test.ts +25 -0
  137. package/test/render-epoch.test.ts +119 -0
  138. package/test/request-animation.test.ts +193 -0
  139. package/test/screen-icon-actions.test.ts +69 -0
  140. package/test/select-box.test.ts +86 -0
  141. package/test/select-pointer.test.ts +369 -0
  142. package/test/selectable-list.test.ts +258 -0
  143. package/test/selection/registry.test.ts +44 -0
  144. package/test/selection-action-bar.test.ts +204 -0
  145. package/test/split-pane-bridge.test.ts +944 -0
  146. package/test/split-pane.test.ts +134 -0
  147. package/test/status-presentation.test.ts +39 -0
  148. package/test/syntax.test.ts +59 -0
  149. package/test/terminal-colors.test.ts +115 -0
  150. package/test/terminal-embedding.test.ts +12 -0
  151. package/test/terminal-projection.test.ts +312 -0
  152. package/test/theme-colors.test.ts +175 -0
  153. package/test/tool-output.test.ts +160 -0
  154. package/test/tool-transcript.test.ts +1190 -0
  155. package/test/unified-diff.test.ts +691 -0
  156. package/themes/harmonious.json +61 -0
  157. package/tsconfig.json +16 -0
@@ -0,0 +1,236 @@
1
+ import { AssistantMessageComponent } from "@earendil-works/pi-coding-agent";
2
+ import { type Component, type TUI, stripTerminalSequences } from "@earendil-works/pi-tui";
3
+ import { sanitizeTuiFieldPreview } from "../content/terminal-text.ts";
4
+
5
+ export type TranscriptEntry =
6
+ | { kind: "content"; key: object; component: Component }
7
+ | { kind: "thinking"; key: object; component: Component; summary: string; running: boolean; failed: boolean }
8
+ | { kind: "tool"; key: object; component: Component; summary: string; running: boolean; failed: boolean };
9
+
10
+ export interface TranscriptProjection extends Component {
11
+ dispose(): void;
12
+ }
13
+
14
+ type AssistantMessage = Parameters<AssistantMessageComponent["updateContent"]>[0];
15
+ type AssistantOptions = ConstructorParameters<typeof AssistantMessageComponent>;
16
+ interface NativeAssistant extends Component {
17
+ contentContainer: NativeContainer;
18
+ lastMessage: AssistantMessage;
19
+ isStreaming: boolean;
20
+ markdownTheme: AssistantOptions[2];
21
+ outputPad: number;
22
+ markdownTransformers: NonNullable<AssistantOptions[5]>;
23
+ updateContent: AssistantMessageComponent["updateContent"];
24
+ }
25
+ interface NativeTool extends Component {
26
+ toolCallId: string;
27
+ toolName: string;
28
+ args: object;
29
+ isPartial: boolean;
30
+ executionStarted: boolean;
31
+ result?: { isError: boolean };
32
+ resultRendererComponent?: Component;
33
+ }
34
+ interface NativeContainer extends Component {
35
+ children: Component[];
36
+ }
37
+
38
+ // type-boundary: Pi 0.84–0.85 private transcript fields; the shape guards below narrow each native node before projection.
39
+ type NativeValue = unknown;
40
+ const INSTALLATION = Symbol.for("pi-libtui/transcript-projection/v1");
41
+
42
+ function record(value: NativeValue): value is Record<string, NativeValue> {
43
+ return value !== null && typeof value === "object";
44
+ }
45
+ function component(value: NativeValue): value is Component {
46
+ return record(value) && typeof value.render === "function" && typeof value.invalidate === "function";
47
+ }
48
+ function container(value: NativeValue): value is NativeContainer {
49
+ return component(value) && "children" in value && Array.isArray(value.children) && value.children.every(component);
50
+ }
51
+ function assistant(value: Component): value is NativeAssistant {
52
+ const node: NativeValue = value;
53
+ if (!record(node) || typeof node.updateContent !== "function" || !record(node.lastMessage)) return false;
54
+ const message = node.lastMessage;
55
+ return (
56
+ message.role === "assistant" &&
57
+ Array.isArray(message.content) &&
58
+ message.content.every(
59
+ (part: NativeValue) =>
60
+ record(part) &&
61
+ ((part.type === "text" && typeof part.text === "string") ||
62
+ (part.type === "thinking" && typeof part.thinking === "string") ||
63
+ (part.type === "toolCall" && typeof part.name === "string")),
64
+ ) &&
65
+ container(node.contentContainer) &&
66
+ typeof node.isStreaming === "boolean" &&
67
+ typeof node.outputPad === "number" &&
68
+ record(node.markdownTheme) &&
69
+ Array.isArray(node.markdownTransformers)
70
+ );
71
+ }
72
+ function tool(value: Component): value is NativeTool {
73
+ const node: NativeValue = value;
74
+ return (
75
+ record(node) &&
76
+ typeof node.toolCallId === "string" &&
77
+ typeof node.toolName === "string" &&
78
+ record(node.args) &&
79
+ typeof node.isPartial === "boolean" &&
80
+ typeof node.executionStarted === "boolean" &&
81
+ (node.result === undefined || (record(node.result) && typeof node.result.isError === "boolean")) &&
82
+ (node.resultRendererComponent === undefined || component(node.resultRendererComponent))
83
+ );
84
+ }
85
+
86
+ /** Read the latest nested semantic action without rendering its output. */
87
+ function activityLabel(node: Component, visited = new Set<Component>()): string | undefined {
88
+ if (visited.has(node)) return undefined;
89
+ visited.add(node);
90
+ const getter: NativeValue = Reflect.get(node, "getActivityLabel");
91
+ if (typeof getter === "function") {
92
+ try {
93
+ const label: NativeValue = Reflect.apply(getter, node, []);
94
+ if (typeof label === "string" && label.trim()) return label;
95
+ } catch {
96
+ // A feature's optional summary must not break the enclosing transcript.
97
+ }
98
+ }
99
+ if (container(node)) {
100
+ for (let index = node.children.length - 1; index >= 0; index--) {
101
+ const label = activityLabel(node.children[index]!, visited);
102
+ if (label) return label;
103
+ }
104
+ }
105
+ return undefined;
106
+ }
107
+
108
+ function toolLabel(node: NativeTool): string {
109
+ const rendered = node.resultRendererComponent && activityLabel(node.resultRendererComponent);
110
+ if (rendered) return sanitizeTuiFieldPreview(stripTerminalSequences(rendered), 240);
111
+ for (const key of ["cmd", "command", "path", "query", "pattern"]) {
112
+ const value: NativeValue = Reflect.get(node.args, key);
113
+ if (typeof value === "string" && value.trim()) return sanitizeTuiFieldPreview(`${node.toolName}: ${value}`, 240);
114
+ }
115
+ return node.toolName;
116
+ }
117
+
118
+ class NativeEntries {
119
+ private readonly assistants = new WeakMap<
120
+ Component,
121
+ {
122
+ children: Component[];
123
+ streaming: boolean;
124
+ entries: TranscriptEntry[];
125
+ }
126
+ >();
127
+ private readonly tools = new WeakMap<
128
+ Component,
129
+ {
130
+ result: NativeTool["result"];
131
+ args: object;
132
+ partial: boolean;
133
+ entry: TranscriptEntry;
134
+ }
135
+ >();
136
+
137
+ read(node: Component): readonly TranscriptEntry[] {
138
+ if (assistant(node)) return this.readAssistant(node);
139
+ if (!tool(node)) return [{ kind: "content", key: node, component: node }];
140
+ const previous = this.tools.get(node);
141
+ if (
142
+ previous &&
143
+ previous.result === node.result &&
144
+ previous.args === node.args &&
145
+ previous.partial === node.isPartial
146
+ )
147
+ return [previous.entry];
148
+ const entry: TranscriptEntry = {
149
+ kind: "tool",
150
+ key: node,
151
+ component: node,
152
+ summary: toolLabel(node),
153
+ running: !node.result || node.isPartial,
154
+ failed: node.result?.isError ?? false,
155
+ };
156
+ this.tools.set(node, { result: node.result, args: node.args, partial: node.isPartial, entry });
157
+ return [entry];
158
+ }
159
+
160
+ private readAssistant(node: NativeAssistant): readonly TranscriptEntry[] {
161
+ const message = node.lastMessage;
162
+ // Keep native error/truncation notices visible, rather than hiding them in a thought fold.
163
+ if (["error", "aborted", "length"].includes(message.stopReason))
164
+ return [{ kind: "content", key: node, component: node }];
165
+ const previous = this.assistants.get(node);
166
+ if (previous?.children === node.contentContainer.children && previous.streaming === node.isStreaming)
167
+ return previous.entries;
168
+ const entries: TranscriptEntry[] = [];
169
+ for (const [index, part] of message.content.entries()) {
170
+ if (part.type === "toolCall") continue;
171
+ const text = part.type === "thinking" ? part.thinking : part.text;
172
+ if (!text.trim()) continue;
173
+ const old = previous?.entries[entries.length];
174
+ const view =
175
+ old?.component instanceof AssistantMessageComponent
176
+ ? old.component
177
+ : new AssistantMessageComponent(
178
+ undefined,
179
+ false,
180
+ node.markdownTheme,
181
+ undefined,
182
+ node.outputPad,
183
+ node.markdownTransformers,
184
+ );
185
+ view.updateContent({ ...message, content: [part], stopReason: "toolUse" }, node.isStreaming);
186
+ entries.push(
187
+ part.type === "thinking"
188
+ ? {
189
+ kind: "thinking",
190
+ key: view,
191
+ component: view,
192
+ summary: text,
193
+ running: node.isStreaming && index === message.content.length - 1,
194
+ failed: false,
195
+ }
196
+ : { kind: "content", key: view, component: view },
197
+ );
198
+ }
199
+ this.assistants.set(node, { children: node.contentContainer.children, streaming: node.isStreaming, entries });
200
+ return entries;
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Project Pi's chat container without changing messages or its mutation targets.
206
+ * Pi 0.84–0.85 mounts [header, resources, chat] as the first document child in
207
+ * both modes. Fail open on another shape; replace this bridge when Pi exposes a transcript API.
208
+ */
209
+ export function mountTranscriptProjection(
210
+ tui: TUI,
211
+ create: (entries: () => readonly TranscriptEntry[]) => TranscriptProjection,
212
+ ): (() => void) | undefined {
213
+ const roots: NativeValue = Reflect.get(tui, "children");
214
+ if (!Array.isArray(roots)) return undefined;
215
+ const document: NativeValue = roots[0];
216
+ if (!container(document) || document.children.length !== 3 || !document.children.every(container)) return undefined;
217
+ if (Reflect.get(document, INSTALLATION)) return undefined;
218
+ const source = document.children[2]!;
219
+ if (!container(source)) return undefined;
220
+ const reader = new NativeEntries();
221
+ const projection = create(() =>
222
+ source.children.flatMap((child): readonly TranscriptEntry[] =>
223
+ tui.mode === "fullscreen" ? reader.read(child) : [{ kind: "content", key: child, component: child }],
224
+ ),
225
+ );
226
+ const children: Component[] = document.children;
227
+ children[2] = projection;
228
+ Reflect.set(document, INSTALLATION, projection);
229
+ tui.requestRender();
230
+ return () => {
231
+ if (document.children[2] === projection) document.children[2] = source;
232
+ if (Reflect.get(document, INSTALLATION) === projection) Reflect.deleteProperty(document, INSTALLATION);
233
+ projection.dispose();
234
+ tui.requestRender();
235
+ };
236
+ }
package/src/index.ts ADDED
@@ -0,0 +1,334 @@
1
+ export {
2
+ type ActivityPresentationOptions,
3
+ activityPresentationCadenceMs,
4
+ activityPresentationFrame,
5
+ } from "./activity-presentation.ts";
6
+ export {
7
+ configureTuiAppearance,
8
+ DEFAULT_TUI_APPEARANCE,
9
+ getTuiAppearance,
10
+ isTuiActivityIndicatorStyle,
11
+ isTuiActivityMessageStyle,
12
+ isTuiAnimationSmoothness,
13
+ isTuiAnimationSpeed,
14
+ isTuiPulseEffectStyle,
15
+ isTuiStatusPresentationStyle,
16
+ isTuiTextEffectScope,
17
+ isTuiTextEffectStyle,
18
+ requestPhaseAnimation,
19
+ resolveActivityPresentation,
20
+ subscribeTuiAppearance,
21
+ TUI_ACTIVITY_INDICATOR_OPTIONS,
22
+ TUI_STATUS_PRESENTATION_OPTIONS,
23
+ type TuiActivityIndicatorStyle,
24
+ type TuiActivityMessageStyle,
25
+ type TuiActivityPresentation,
26
+ type TuiAnimationOverride,
27
+ type TuiAnimationSmoothness,
28
+ type TuiAnimationSpeed,
29
+ type TuiAppearanceSettings,
30
+ type TuiCursorStyle,
31
+ type TuiIconPack,
32
+ type TuiPulseEffectStyle,
33
+ type TuiRequestPhase,
34
+ type TuiStatusPresentationStyle,
35
+ type TuiTextEffectScope,
36
+ type TuiTextEffectStyle,
37
+ } from "./appearance.ts";
38
+ export {
39
+ BackgroundSurface,
40
+ type BackgroundSurfaceOptions,
41
+ type HalfBlockSurfaceEdge,
42
+ halfBlockSurfaceEdge,
43
+ TOOL_SURFACE_BACKGROUND,
44
+ } from "./background-surface.ts";
45
+ export {
46
+ createTuiThemeVariation,
47
+ type TuiBackgroundPaint,
48
+ type TuiBackgroundToken,
49
+ type TuiColor,
50
+ type TuiForegroundColor,
51
+ type TuiForegroundPaint,
52
+ type TuiForegroundToken,
53
+ type TuiHue,
54
+ type TuiShade,
55
+ type TuiSwatch,
56
+ type TuiTheme,
57
+ type TuiThemeAppearance,
58
+ type TuiThemeVariation,
59
+ tuiTheme,
60
+ tuiThemeAppearance,
61
+ } from "./color/theme.ts";
62
+ export {
63
+ ComponentStack,
64
+ type ComponentStackInputMode,
65
+ type ComponentStackOptions,
66
+ type ComponentStackSpan,
67
+ } from "./component-stack.ts";
68
+ export {
69
+ sanitizeTuiField,
70
+ sanitizeTuiFieldPreview,
71
+ sanitizeTuiText,
72
+ sanitizeTuiTextPreview,
73
+ } from "./content/terminal-text.ts";
74
+ export { markdownCodeRanges, type TextRange } from "./content/markdown-code.ts";
75
+ export {
76
+ MarkdownText,
77
+ type MarkdownTextOptions,
78
+ semanticMarkdownTheme,
79
+ } from "./content/text.ts";
80
+ export {
81
+ ActionPanel,
82
+ type ActionPanelFooter,
83
+ type ActionPanelGeometry,
84
+ type ActionPanelMouseEvent,
85
+ type ActionPanelOption,
86
+ type ActionPanelOptions,
87
+ type ActionPanelRect,
88
+ type ActionPanelRowContext,
89
+ type ActionPanelRowGeometry,
90
+ } from "./controls/action-panel.ts";
91
+ export {
92
+ DialogButtonBar,
93
+ type DialogButtonBarGeometry,
94
+ type DialogButtonBarOptions,
95
+ type DialogButtonGeometry,
96
+ type DialogButtonSpec,
97
+ } from "./controls/dialog-button-bar.ts";
98
+ export { MultiSelect, type MultiSelectOptions } from "./controls/multi-select.ts";
99
+ export {
100
+ type PickerOption,
101
+ PickerPanel,
102
+ type PickerPanelHost,
103
+ type PickerPanelOptions,
104
+ type PickerRowContext,
105
+ } from "./controls/picker-panel.ts";
106
+ export {
107
+ mountScreenIconActions,
108
+ type ScreenIconAction,
109
+ type ScreenIconActionsMount,
110
+ type ScreenIconActionsOptions,
111
+ screenIconActionsWidth,
112
+ } from "./controls/screen-icon-actions.ts";
113
+ export {
114
+ SearchableSelect,
115
+ type SearchableSelectOptions,
116
+ type SearchableSelectRowContext,
117
+ type SelectOption,
118
+ } from "./controls/searchable-select.ts";
119
+ export {
120
+ SelectBox,
121
+ type SelectBoxOptions,
122
+ type SelectBoxRowContext,
123
+ } from "./controls/select-box.ts";
124
+ export {
125
+ SelectableList,
126
+ type SelectableListGeometry,
127
+ type SelectableListItemGeometry,
128
+ type SelectableListOptions,
129
+ type SelectableListRenderContext,
130
+ type SelectableListRow,
131
+ } from "./controls/selectable-list.ts";
132
+ export {
133
+ mountSelectionActionBar,
134
+ placeSelectionActionBar,
135
+ SelectionActionBar,
136
+ type SelectionActionBarAction,
137
+ type SelectionActionBarGeometry,
138
+ type SelectionActionBarItemGeometry,
139
+ type SelectionActionBarMount,
140
+ type SelectionActionBarMountOptions,
141
+ type SelectionActionBarOptions,
142
+ type SelectionActionBarPlacementRequest,
143
+ type SelectionActionBarTarget,
144
+ } from "./controls/selection-action-bar.ts";
145
+ export { SemanticInput } from "./controls/semantic-input.ts";
146
+ export { type Tab, TabBar } from "./controls/tab.ts";
147
+ export {
148
+ type CursorRole,
149
+ cursorStyle,
150
+ isNativeCursorStyle,
151
+ type MarkEditorCursorOptions,
152
+ markEditorCursor,
153
+ markSemanticCursorPosition,
154
+ removeUnmarkedEditorCursor,
155
+ renderSemanticCursor,
156
+ renderVirtualCursor,
157
+ type SemanticCursorOptions,
158
+ stripCursorRoleMarkers,
159
+ type VirtualCursorOptions,
160
+ } from "./cursor.ts";
161
+ export {
162
+ type EditorTokenPillGeometry,
163
+ type EditorTokenPillRenderContext,
164
+ type EditorTokenPillResult,
165
+ type EditorTokenPresentation,
166
+ renderEditorPasteMarkerPills,
167
+ renderEditorTokenPills,
168
+ } from "./decoration/editor-pills.ts";
169
+ export {
170
+ icon,
171
+ keyHintGlyph,
172
+ type PillContent,
173
+ renderKeyHint,
174
+ renderPillText,
175
+ type TuiIconName,
176
+ type TuiKeyIconPack,
177
+ } from "./decoration/glyphs.ts";
178
+ export {
179
+ PointerInteractionController,
180
+ type PointerInteractionHandlers,
181
+ type PointerInteractionOptions,
182
+ } from "./decoration/pointer-interaction.ts";
183
+ export {
184
+ backgroundAnsiAtColumn,
185
+ contrastingPillBackground,
186
+ renderPill,
187
+ } from "./decoration/powerline-pill.ts";
188
+ export type {
189
+ ActivityIndicatorOptions,
190
+ ProgressBarOptions,
191
+ ProgressFrameOptions,
192
+ TuiTitle,
193
+ TuiTitleSource,
194
+ TuiTitleValue,
195
+ } from "./decoration/status.ts";
196
+ export {
197
+ ActivityIndicator,
198
+ ProgressBar,
199
+ progressFrame,
200
+ } from "./decoration/status.ts";
201
+ export {
202
+ placeTransientPill,
203
+ TransientPill,
204
+ type TransientPillMessage,
205
+ type TransientPillOptions,
206
+ type TransientPillPlacementRequest,
207
+ } from "./decoration/transient-pill.ts";
208
+ export type {
209
+ ActivityAnimationOverrides,
210
+ ActivityFrame,
211
+ MotionClock,
212
+ MotionMount,
213
+ MotionMountOptions,
214
+ MotionRenderTarget,
215
+ MotionTimerHandle,
216
+ } from "./motion.ts";
217
+ export {
218
+ activityAnimatesText,
219
+ activityFrame,
220
+ animationSmoothnessCadenceMs,
221
+ animationSpeedMultiplier,
222
+ configuredAnimationCadenceMs,
223
+ glyphFrame,
224
+ lightningShimmerFrame,
225
+ MotionScheduler,
226
+ mountConfiguredAnimation,
227
+ pulseFrame,
228
+ pulseGlyphFrame,
229
+ rainbowGlowShimmerFrame,
230
+ rainbowShimmerFrame,
231
+ sharedMotionScheduler,
232
+ shimmerFrame,
233
+ spinnerFrame,
234
+ } from "./motion.ts";
235
+ export {
236
+ type AnchoredOverlayPlacement,
237
+ type AnchoredOverlayRect,
238
+ type AnchoredOverlayRequest,
239
+ placeAnchoredOverlay,
240
+ } from "./overlay/anchored.ts";
241
+ export {
242
+ type DetailCardContent,
243
+ decorateDetailCard,
244
+ type HoverDetailCardMount,
245
+ type HoverDetailCardOptions,
246
+ type HoverDetailCardTarget,
247
+ mountHoverDetailCard,
248
+ overlayTotalWidth,
249
+ renderDetailCard,
250
+ } from "./overlay/detail-card.ts";
251
+ export {
252
+ type DialogHost,
253
+ DialogOverlay,
254
+ type DialogOverlayAnchor,
255
+ DialogOverlayHost,
256
+ type DialogOverlayOptions,
257
+ offsetDialogHost,
258
+ } from "./overlay/dialog.ts";
259
+ export { FloatingOverlay, type FloatingOverlayOptions } from "./overlay/floating.ts";
260
+ export {
261
+ FramedEditorOverlay,
262
+ type FramedEditorOverlayGeometry,
263
+ type FramedEditorOverlayOptions,
264
+ } from "./overlay/framed-editor.ts";
265
+ export { FullscreenOverlay, fullscreenOverlayOptions } from "./overlay/fullscreen.ts";
266
+ export {
267
+ compositeHoverTooltip,
268
+ findScreenTextRect,
269
+ type HoverTooltipMount,
270
+ type HoverTooltipMountOptions,
271
+ type HoverTooltipTarget,
272
+ mountHoverTooltip,
273
+ } from "./overlay/hover-tooltip.ts";
274
+ export {
275
+ type ModalOverlayComponent,
276
+ type ModalOverlayMountOptions,
277
+ type ModalOverlayMouseEvent,
278
+ type MountedModalOverlayComponent,
279
+ mountModalOverlay,
280
+ } from "./overlay/modal-mount.ts";
281
+ export { RenderedLinesCache } from "./render-cache.ts";
282
+ export { applyScrollbar } from "./scrollbar.ts";
283
+ export {
284
+ ensureSidePanelRegistry,
285
+ registerSidePanelProvider,
286
+ SIDE_PANEL_PROTOCOL,
287
+ SIDE_PANEL_REGISTRY_KEY,
288
+ type SidePanelContent,
289
+ type SidePanelEmptyAction,
290
+ type SidePanelHeaderAction,
291
+ type SidePanelProvider,
292
+ type SidePanelRegistry,
293
+ type SidePanelSession,
294
+ type SidePanelTab,
295
+ } from "./panels.ts";
296
+ export {
297
+ ensureSplitPaneRegistry,
298
+ type MountedSplitPane,
299
+ mountSplitPane,
300
+ SPLIT_PANE_PROTOCOL,
301
+ SPLIT_PANE_REGISTRY_KEY,
302
+ type SplitPaneComponent,
303
+ type SplitPaneComponentFactory,
304
+ type SplitPaneDefinition,
305
+ type SplitPaneHost,
306
+ type SplitPanePosition,
307
+ type SplitPaneRegistry,
308
+ } from "./split-pane.ts";
309
+ export { statusPresentationFrame } from "./status-presentation.ts";
310
+ export {
311
+ highlightSyntaxBlock,
312
+ SyntaxText,
313
+ type SyntaxTextOptions,
314
+ whenSyntaxReady,
315
+ } from "./syntax.ts";
316
+ export {
317
+ type EnsureNativeBinaryHooks,
318
+ ensureNativeBinary,
319
+ locateNativeBinary,
320
+ type NativeBinary,
321
+ type NativeBinaryLocation,
322
+ type NativeBinaryOptions,
323
+ TERMINAL_BRIDGE,
324
+ terminalBridgeBinaryPath,
325
+ } from "./native-binary.ts";
326
+ export {
327
+ createTerminalBridgeClient,
328
+ parseTerminalBridgeReadResponse,
329
+ type TerminalBridgeClient,
330
+ type TerminalBridgeClientDependencies,
331
+ type TerminalBridgeReadResponse,
332
+ } from "./terminal/bridge-client.ts";
333
+ export { stripTopLevelZoneMarkers } from "./terminal/embedding.ts";
334
+ export { PtyPane, type PtyPaneOptions, PtyProcess, type PtyProcessOptions } from "./terminal/pty-pane.ts";
@@ -0,0 +1,6 @@
1
+ import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
2
+
3
+ export function fitLine(line: string, width: number): string {
4
+ const clipped = truncateToWidth(line, width, "");
5
+ return clipped + " ".repeat(Math.max(0, width - visibleWidth(clipped)));
6
+ }