@code-yeongyu/senpi-tui 2026.7.31 → 2026.8.3

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 (74) hide show
  1. package/README.md +77 -14
  2. package/dist/TuiAltScreen.d.ts +83 -0
  3. package/dist/TuiAltScreen.d.ts.map +1 -0
  4. package/dist/TuiAltScreen.js +687 -0
  5. package/dist/TuiAltScreen.js.map +1 -0
  6. package/dist/TuiMainScreen.d.ts +5 -0
  7. package/dist/TuiMainScreen.d.ts.map +1 -0
  8. package/dist/TuiMainScreen.js +5 -0
  9. package/dist/TuiMainScreen.js.map +1 -0
  10. package/dist/components/alt-screen-flash.d.ts +13 -0
  11. package/dist/components/alt-screen-flash.d.ts.map +1 -0
  12. package/dist/components/alt-screen-flash.js +36 -0
  13. package/dist/components/alt-screen-flash.js.map +1 -0
  14. package/dist/components/h-stack.d.ts +7 -0
  15. package/dist/components/h-stack.d.ts.map +1 -0
  16. package/dist/components/h-stack.js +43 -0
  17. package/dist/components/h-stack.js.map +1 -0
  18. package/dist/components/image.d.ts.map +1 -1
  19. package/dist/components/image.js +4 -4
  20. package/dist/components/image.js.map +1 -1
  21. package/dist/components/markdown.d.ts +2 -0
  22. package/dist/components/markdown.d.ts.map +1 -1
  23. package/dist/components/markdown.js +3 -2
  24. package/dist/components/markdown.js.map +1 -1
  25. package/dist/components/scroll-view.d.ts +51 -0
  26. package/dist/components/scroll-view.d.ts.map +1 -0
  27. package/dist/components/scroll-view.js +163 -0
  28. package/dist/components/scroll-view.js.map +1 -0
  29. package/dist/components/settings-list.d.ts.map +1 -1
  30. package/dist/components/settings-list.js +3 -6
  31. package/dist/components/settings-list.js.map +1 -1
  32. package/dist/components/stack.d.ts +32 -0
  33. package/dist/components/stack.d.ts.map +1 -0
  34. package/dist/components/stack.js +109 -0
  35. package/dist/components/stack.js.map +1 -0
  36. package/dist/components/v-stack.d.ts +8 -0
  37. package/dist/components/v-stack.d.ts.map +1 -0
  38. package/dist/components/v-stack.js +21 -0
  39. package/dist/components/v-stack.js.map +1 -0
  40. package/dist/index.d.ts +10 -4
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +10 -4
  43. package/dist/index.js.map +1 -1
  44. package/dist/keybindings.d.ts +30 -0
  45. package/dist/keybindings.d.ts.map +1 -1
  46. package/dist/keybindings.js +18 -0
  47. package/dist/keybindings.js.map +1 -1
  48. package/dist/layout-node.d.ts +40 -0
  49. package/dist/layout-node.d.ts.map +1 -0
  50. package/dist/layout-node.js +6 -0
  51. package/dist/layout-node.js.map +1 -0
  52. package/dist/layout.d.ts +40 -0
  53. package/dist/layout.d.ts.map +1 -0
  54. package/dist/layout.js +315 -0
  55. package/dist/layout.js.map +1 -0
  56. package/dist/mux.js +1 -1
  57. package/dist/mux.js.map +1 -1
  58. package/dist/terminal-image.d.ts +10 -0
  59. package/dist/terminal-image.d.ts.map +1 -1
  60. package/dist/terminal-image.js +61 -3
  61. package/dist/terminal-image.js.map +1 -1
  62. package/dist/terminal-text.d.ts +1 -0
  63. package/dist/terminal-text.d.ts.map +1 -1
  64. package/dist/terminal-text.js +12 -2
  65. package/dist/terminal-text.js.map +1 -1
  66. package/dist/tui.d.ts +37 -16
  67. package/dist/tui.d.ts.map +1 -1
  68. package/dist/tui.js +89 -21
  69. package/dist/tui.js.map +1 -1
  70. package/dist/utils.d.ts +10 -0
  71. package/dist/utils.d.ts.map +1 -1
  72. package/dist/utils.js +95 -4
  73. package/dist/utils.js.map +1 -1
  74. package/package.json +2 -2
package/dist/layout.js ADDED
@@ -0,0 +1,315 @@
1
+ import { allocateStackSizes, visibleStackEntries } from "./components/stack.js";
2
+ import { getLayoutNode } from "./layout-node.js";
3
+ import { cropKittyImageLine, getKittyImageMetadata, isImageLine } from "./terminal-image.js";
4
+ import { CURSOR_MARKER, compositeTuiLine } from "./tui.js";
5
+ import { extractAnsiCode, getGraphemeCellRange, sliceByColumn, visibleWidth } from "./utils.js";
6
+ const OSC133_ZONE_PREFIX = /^(?:\x1b\]133;[ABC](?:\x07|\x1b\\))+/;
7
+ function intersect(a, b) {
8
+ const x = Math.max(a.x, b.x);
9
+ const y = Math.max(a.y, b.y);
10
+ const right = Math.min(a.x + a.width, b.x + b.width);
11
+ const bottom = Math.min(a.y + a.height, b.y + b.height);
12
+ return { x, y, width: Math.max(0, right - x), height: Math.max(0, bottom - y) };
13
+ }
14
+ function renderCached(context, component, width) {
15
+ const safeWidth = Math.max(1, Math.floor(width));
16
+ let widths = context.renderCache.get(component);
17
+ if (!widths) {
18
+ widths = new Map();
19
+ context.renderCache.set(component, widths);
20
+ }
21
+ let lines = widths.get(safeWidth);
22
+ if (!lines) {
23
+ lines = component.render(safeWidth);
24
+ widths.set(safeWidth, lines);
25
+ }
26
+ return lines;
27
+ }
28
+ function measureHeight(context, component, width) {
29
+ return renderCached(context, component, width).length;
30
+ }
31
+ function measureWidth(context, component, width) {
32
+ return renderCached(context, component, width).reduce((max, line) => Math.max(max, visibleWidth(line)), 0);
33
+ }
34
+ function withParent(box, parent) {
35
+ box.parent = parent;
36
+ return box;
37
+ }
38
+ function translateBox(box, deltaY) {
39
+ box.rect.y += deltaY;
40
+ for (const child of box.children)
41
+ translateBox(child, deltaY);
42
+ }
43
+ function updateClips(box, parentClip) {
44
+ box.clip = intersect(parentClip, box.rect);
45
+ for (const child of box.children)
46
+ updateClips(child, box.clip);
47
+ }
48
+ function layoutComponent(context, component, x, y, width, height, clip) {
49
+ const safeWidth = Math.max(1, Math.floor(width));
50
+ const node = getLayoutNode(component);
51
+ if (!node) {
52
+ const lines = renderCached(context, component, safeWidth);
53
+ const allocatedHeight = height === undefined ? lines.length : Math.max(0, Math.floor(height));
54
+ let lineOffset = 0;
55
+ if (lines.length > allocatedHeight && allocatedHeight > 0) {
56
+ const cursorLine = lines.findIndex((line) => line.includes(CURSOR_MARKER));
57
+ if (cursorLine >= allocatedHeight)
58
+ lineOffset = cursorLine - allocatedHeight + 1;
59
+ }
60
+ return {
61
+ component,
62
+ rect: { x, y, width: safeWidth, height: allocatedHeight },
63
+ clip: intersect(clip, { x, y, width: safeWidth, height: allocatedHeight }),
64
+ children: [],
65
+ lines,
66
+ lineOffset,
67
+ layer: 0,
68
+ };
69
+ }
70
+ if (node.type === "scroll") {
71
+ const previousScrollTop = node.state.scrollTop;
72
+ const contentWidth = node.state.getContentWidth(safeWidth);
73
+ const childBox = layoutComponent(context, node.component, x, y - previousScrollTop, contentWidth, undefined, clip);
74
+ const contentHeight = childBox.rect.height;
75
+ const viewportHeight = height === undefined ? contentHeight : Math.max(0, Math.floor(height));
76
+ node.state.updateLayout(contentHeight, viewportHeight, context.requestRender);
77
+ translateBox(childBox, previousScrollTop - node.state.scrollTop);
78
+ const scrollView = node.state;
79
+ if (node.state.primary || !context.primaryScrollView)
80
+ context.primaryScrollView = scrollView;
81
+ const rect = { x, y, width: safeWidth, height: viewportHeight };
82
+ const childClip = intersect(clip, rect);
83
+ const box = {
84
+ component,
85
+ rect,
86
+ clip: childClip,
87
+ children: [childBox],
88
+ scrollView,
89
+ scrollContentLines: renderCached(context, node.component, contentWidth),
90
+ layer: 0,
91
+ };
92
+ childBox.parent = box;
93
+ updateClips(childBox, childClip);
94
+ return box;
95
+ }
96
+ const entries = visibleStackEntries(node.entries, context.viewport);
97
+ const gapTotal = Math.max(0, entries.length - 1) * node.gap;
98
+ if (node.type === "vstack") {
99
+ const intrinsicHeights = entries.map((entry) => measureHeight(context, entry.component, safeWidth));
100
+ const sizes = allocateStackSizes(entries, intrinsicHeights, height, node.gap);
101
+ const naturalHeight = sizes.reduce((sum, size) => sum + size, 0) + gapTotal;
102
+ const allocatedHeight = height === undefined ? naturalHeight : Math.max(0, Math.floor(height));
103
+ const rect = { x, y, width: safeWidth, height: allocatedHeight };
104
+ const box = {
105
+ component,
106
+ rect,
107
+ clip: intersect(clip, rect),
108
+ children: [],
109
+ layer: 0,
110
+ };
111
+ let childY = y;
112
+ for (let index = 0; index < entries.length; index++) {
113
+ box.children.push(withParent(layoutComponent(context, entries[index].component, x, childY, safeWidth, sizes[index], box.clip), box));
114
+ childY += sizes[index] + node.gap;
115
+ }
116
+ return box;
117
+ }
118
+ const intrinsicWidths = entries.map((entry) => measureWidth(context, entry.component, safeWidth));
119
+ const widths = allocateStackSizes(entries, intrinsicWidths, safeWidth, node.gap);
120
+ const intrinsicHeights = entries.map((entry, index) => measureHeight(context, entry.component, Math.max(1, widths[index])));
121
+ const allocatedHeight = height === undefined
122
+ ? intrinsicHeights.reduce((max, childHeight) => Math.max(max, childHeight), 0)
123
+ : Math.max(0, height);
124
+ const rect = { x, y, width: safeWidth, height: allocatedHeight };
125
+ const box = {
126
+ component,
127
+ rect,
128
+ clip: intersect(clip, rect),
129
+ children: [],
130
+ layer: 0,
131
+ };
132
+ let childX = x;
133
+ for (let index = 0; index < entries.length; index++) {
134
+ const naturalChildHeight = intrinsicHeights[index];
135
+ const childHeight = node.align === "stretch" ? allocatedHeight : Math.min(allocatedHeight, naturalChildHeight);
136
+ let childY = y;
137
+ if (node.align === "center")
138
+ childY += Math.floor((allocatedHeight - childHeight) / 2);
139
+ else if (node.align === "end")
140
+ childY += allocatedHeight - childHeight;
141
+ const childWidth = widths[index];
142
+ if (childWidth === 0) {
143
+ box.children.push({
144
+ component: entries[index].component,
145
+ rect: { x: childX, y: childY, width: 0, height: childHeight },
146
+ clip: { x: childX, y: childY, width: 0, height: 0 },
147
+ children: [],
148
+ parent: box,
149
+ layer: 0,
150
+ });
151
+ }
152
+ else {
153
+ box.children.push(withParent(layoutComponent(context, entries[index].component, childX, childY, childWidth, childHeight, box.clip), box));
154
+ }
155
+ childX += childWidth + node.gap;
156
+ }
157
+ return box;
158
+ }
159
+ function styleScrollbarCell(line, column, totalWidth, style) {
160
+ if (isImageLine(line))
161
+ return line;
162
+ const graphemeRange = getGraphemeCellRange(line, column);
163
+ const start = graphemeRange?.start ?? column;
164
+ const end = graphemeRange?.end ?? column + 1;
165
+ const before = sliceByColumn(line, 0, start, true);
166
+ const target = sliceByColumn(line, start, end - start, true);
167
+ const after = sliceByColumn(line, end, Math.max(0, totalWidth - end), true);
168
+ let targetPrefix = "";
169
+ let targetIndex = 0;
170
+ while (targetIndex < target.length) {
171
+ const ansi = extractAnsiCode(target, targetIndex);
172
+ if (!ansi)
173
+ break;
174
+ targetPrefix += ansi.code;
175
+ targetIndex += ansi.length;
176
+ }
177
+ const targetText = target.slice(targetIndex) || " ".repeat(end - start);
178
+ const beforePadding = " ".repeat(Math.max(0, start - visibleWidth(before)));
179
+ return `${before}${beforePadding}${targetPrefix}${style(targetText)}${after}`;
180
+ }
181
+ export function getScrollbarGeometry(box) {
182
+ if (!box.scrollView?.isScrollbarVisible || box.rect.width <= 0 || box.rect.height <= 0)
183
+ return undefined;
184
+ const contentHeight = box.children[0]?.rect.height ?? box.scrollContentLines?.length ?? 0;
185
+ const trackHeight = box.rect.height;
186
+ const minThumbHeight = Math.min(2, trackHeight);
187
+ const thumbHeight = Math.max(minThumbHeight, Math.min(trackHeight, Math.round((trackHeight * trackHeight) / contentHeight)));
188
+ const maxScrollTop = Math.max(0, contentHeight - trackHeight);
189
+ const maxThumbTop = trackHeight - thumbHeight;
190
+ const thumbOffset = maxScrollTop === 0 ? 0 : Math.round((box.scrollView.scrollTop / maxScrollTop) * maxThumbTop);
191
+ const column = box.rect.x + box.rect.width - 1;
192
+ if (column < box.clip.x || column >= box.clip.x + box.clip.width)
193
+ return undefined;
194
+ return {
195
+ column,
196
+ trackTop: box.rect.y,
197
+ trackHeight,
198
+ thumbTop: box.rect.y + thumbOffset,
199
+ thumbHeight,
200
+ maxScrollTop,
201
+ };
202
+ }
203
+ function paintScrollbar(box, screen, totalWidth) {
204
+ const geometry = getScrollbarGeometry(box);
205
+ if (!geometry || !box.scrollView)
206
+ return;
207
+ for (let offset = 0; offset < geometry.thumbHeight; offset++) {
208
+ const row = geometry.thumbTop + offset;
209
+ if (row < box.clip.y || row >= box.clip.y + box.clip.height || row < 0 || row >= screen.length)
210
+ continue;
211
+ screen[row] = styleScrollbarCell(screen[row] ?? "", geometry.column, totalWidth, box.scrollView.scrollbarStyle);
212
+ }
213
+ }
214
+ function paintBox(box, screen, totalWidth) {
215
+ if (box.lines) {
216
+ const offset = box.lineOffset ?? 0;
217
+ for (let localRow = 0; localRow < box.rect.height; localRow++) {
218
+ const row = box.rect.y + localRow;
219
+ if (row < box.clip.y || row >= box.clip.y + box.clip.height || row < 0 || row >= screen.length)
220
+ continue;
221
+ const sourceLine = box.lines[offset + localRow];
222
+ if (sourceLine === undefined)
223
+ continue;
224
+ let line = sourceLine.replace(OSC133_ZONE_PREFIX, "");
225
+ const imageMetadata = getKittyImageMetadata(line);
226
+ if (imageMetadata) {
227
+ const clipBottom = Math.min(screen.length, box.clip.y + box.clip.height);
228
+ const visibleRows = Math.min(imageMetadata.rows, clipBottom - row);
229
+ if (visibleRows < imageMetadata.rows)
230
+ line = cropKittyImageLine(line, 0, visibleRows);
231
+ }
232
+ if (isImageLine(line) && box.rect.x === 0 && box.rect.width >= totalWidth)
233
+ screen[row] = line;
234
+ else
235
+ screen[row] = compositeTuiLine(screen[row] ?? "", line, box.rect.x, box.rect.width, totalWidth);
236
+ }
237
+ }
238
+ for (const child of box.children)
239
+ paintBox(child, screen, totalWidth);
240
+ if (box.scrollView && box.scrollContentLines && box.scrollView.scrollTop > 0 && box.rect.height > 0) {
241
+ for (let imageRow = box.scrollView.scrollTop - 1; imageRow >= 0; imageRow--) {
242
+ const imageLine = box.scrollContentLines[imageRow] ?? "";
243
+ const metadata = getKittyImageMetadata(imageLine);
244
+ if (metadata) {
245
+ const hiddenRows = box.scrollView.scrollTop - imageRow;
246
+ if (hiddenRows < metadata.rows) {
247
+ const visibleRows = Math.min(box.rect.height, metadata.rows - hiddenRows);
248
+ const cropped = cropKittyImageLine(imageLine, hiddenRows, visibleRows);
249
+ if (box.rect.x === 0 && box.rect.width >= totalWidth)
250
+ screen[box.rect.y] = cropped;
251
+ }
252
+ break;
253
+ }
254
+ if (imageLine !== "")
255
+ break;
256
+ }
257
+ }
258
+ paintScrollbar(box, screen, totalWidth);
259
+ }
260
+ export function renderLayoutFrame(root, width, height, requestRender) {
261
+ const safeWidth = Math.max(1, Math.floor(width));
262
+ const safeHeight = Math.max(1, Math.floor(height));
263
+ const context = {
264
+ viewport: { width: safeWidth, height: safeHeight },
265
+ renderCache: new Map(),
266
+ requestRender,
267
+ primaryScrollView: undefined,
268
+ };
269
+ const rootBox = layoutComponent(context, root, 0, 0, safeWidth, safeHeight, {
270
+ x: 0,
271
+ y: 0,
272
+ width: safeWidth,
273
+ height: safeHeight,
274
+ });
275
+ const lines = Array.from({ length: safeHeight }, () => "");
276
+ paintBox(rootBox, lines, safeWidth);
277
+ return {
278
+ root: rootBox,
279
+ width: safeWidth,
280
+ height: safeHeight,
281
+ lines,
282
+ ...(context.primaryScrollView === undefined ? {} : { primaryScrollView: context.primaryScrollView }),
283
+ };
284
+ }
285
+ function containsPoint(rect, x, y) {
286
+ return x >= rect.x && x < rect.x + rect.width && y >= rect.y && y < rect.y + rect.height;
287
+ }
288
+ export function getScrollViewBox(frame, scrollView) {
289
+ const visit = (box) => {
290
+ if (box.scrollView === scrollView)
291
+ return box;
292
+ for (const child of box.children) {
293
+ const match = visit(child);
294
+ if (match)
295
+ return match;
296
+ }
297
+ return undefined;
298
+ };
299
+ return visit(frame.root);
300
+ }
301
+ export function getScrollViewsAt(frame, x, y) {
302
+ const result = [];
303
+ const visit = (box, depth) => {
304
+ if (!containsPoint(box.clip, x, y))
305
+ return;
306
+ if (box.scrollView && containsPoint(box.rect, x, y))
307
+ result.push({ scrollView: box.scrollView, depth });
308
+ for (const child of box.children)
309
+ visit(child, depth + 1);
310
+ };
311
+ visit(frame.root, 0);
312
+ result.sort((a, b) => b.depth - a.depth);
313
+ return result.map((entry) => entry.scrollView);
314
+ }
315
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ScrollView } from \"./components/scroll-view.ts\";\nimport { allocateStackSizes, visibleStackEntries } from \"./components/stack.ts\";\nimport { getLayoutNode } from \"./layout-node.ts\";\nimport { cropKittyImageLine, getKittyImageMetadata, isImageLine } from \"./terminal-image.ts\";\nimport { type Component, CURSOR_MARKER, compositeTuiLine } from \"./tui.ts\";\nimport { extractAnsiCode, getGraphemeCellRange, sliceByColumn, visibleWidth } from \"./utils.ts\";\n\nconst OSC133_ZONE_PREFIX = /^(?:\\x1b\\]133;[ABC](?:\\x07|\\x1b\\\\))+/;\n\nexport interface LayoutRect {\n\tx: number;\n\ty: number;\n\twidth: number;\n\theight: number;\n}\n\nexport interface LayoutBox {\n\tcomponent: Component;\n\trect: LayoutRect;\n\tclip: LayoutRect;\n\tchildren: LayoutBox[];\n\tparent?: LayoutBox;\n\tlines?: readonly string[];\n\tlineOffset?: number;\n\tscrollView?: ScrollView;\n\tscrollContentLines?: readonly string[];\n\tlayer: number;\n}\n\nexport interface LayoutFrame {\n\troot: LayoutBox;\n\twidth: number;\n\theight: number;\n\tlines: string[];\n\tprimaryScrollView?: ScrollView;\n}\n\nexport interface ScrollbarGeometry {\n\tcolumn: number;\n\ttrackTop: number;\n\ttrackHeight: number;\n\tthumbTop: number;\n\tthumbHeight: number;\n\tmaxScrollTop: number;\n}\n\ninterface LayoutContext {\n\tviewport: { width: number; height: number };\n\trenderCache: Map<Component, Map<number, string[]>>;\n\trequestRender: () => void;\n\tprimaryScrollView: ScrollView | undefined;\n}\n\nfunction intersect(a: LayoutRect, b: LayoutRect): LayoutRect {\n\tconst x = Math.max(a.x, b.x);\n\tconst y = Math.max(a.y, b.y);\n\tconst right = Math.min(a.x + a.width, b.x + b.width);\n\tconst bottom = Math.min(a.y + a.height, b.y + b.height);\n\treturn { x, y, width: Math.max(0, right - x), height: Math.max(0, bottom - y) };\n}\n\nfunction renderCached(context: LayoutContext, component: Component, width: number): string[] {\n\tconst safeWidth = Math.max(1, Math.floor(width));\n\tlet widths = context.renderCache.get(component);\n\tif (!widths) {\n\t\twidths = new Map<number, string[]>();\n\t\tcontext.renderCache.set(component, widths);\n\t}\n\tlet lines = widths.get(safeWidth);\n\tif (!lines) {\n\t\tlines = component.render(safeWidth);\n\t\twidths.set(safeWidth, lines);\n\t}\n\treturn lines;\n}\n\nfunction measureHeight(context: LayoutContext, component: Component, width: number): number {\n\treturn renderCached(context, component, width).length;\n}\n\nfunction measureWidth(context: LayoutContext, component: Component, width: number): number {\n\treturn renderCached(context, component, width).reduce((max, line) => Math.max(max, visibleWidth(line)), 0);\n}\n\nfunction withParent(box: LayoutBox, parent: LayoutBox): LayoutBox {\n\tbox.parent = parent;\n\treturn box;\n}\n\nfunction translateBox(box: LayoutBox, deltaY: number): void {\n\tbox.rect.y += deltaY;\n\tfor (const child of box.children) translateBox(child, deltaY);\n}\n\nfunction updateClips(box: LayoutBox, parentClip: LayoutRect): void {\n\tbox.clip = intersect(parentClip, box.rect);\n\tfor (const child of box.children) updateClips(child, box.clip);\n}\n\nfunction layoutComponent(\n\tcontext: LayoutContext,\n\tcomponent: Component,\n\tx: number,\n\ty: number,\n\twidth: number,\n\theight: number | undefined,\n\tclip: LayoutRect,\n): LayoutBox {\n\tconst safeWidth = Math.max(1, Math.floor(width));\n\tconst node = getLayoutNode(component);\n\tif (!node) {\n\t\tconst lines = renderCached(context, component, safeWidth);\n\t\tconst allocatedHeight = height === undefined ? lines.length : Math.max(0, Math.floor(height));\n\t\tlet lineOffset = 0;\n\t\tif (lines.length > allocatedHeight && allocatedHeight > 0) {\n\t\t\tconst cursorLine = lines.findIndex((line) => line.includes(CURSOR_MARKER));\n\t\t\tif (cursorLine >= allocatedHeight) lineOffset = cursorLine - allocatedHeight + 1;\n\t\t}\n\t\treturn {\n\t\t\tcomponent,\n\t\t\trect: { x, y, width: safeWidth, height: allocatedHeight },\n\t\t\tclip: intersect(clip, { x, y, width: safeWidth, height: allocatedHeight }),\n\t\t\tchildren: [],\n\t\t\tlines,\n\t\t\tlineOffset,\n\t\t\tlayer: 0,\n\t\t};\n\t}\n\n\tif (node.type === \"scroll\") {\n\t\tconst previousScrollTop = node.state.scrollTop;\n\t\tconst contentWidth = node.state.getContentWidth(safeWidth);\n\t\tconst childBox = layoutComponent(\n\t\t\tcontext,\n\t\t\tnode.component,\n\t\t\tx,\n\t\t\ty - previousScrollTop,\n\t\t\tcontentWidth,\n\t\t\tundefined,\n\t\t\tclip,\n\t\t);\n\t\tconst contentHeight = childBox.rect.height;\n\t\tconst viewportHeight = height === undefined ? contentHeight : Math.max(0, Math.floor(height));\n\t\tnode.state.updateLayout(contentHeight, viewportHeight, context.requestRender);\n\t\ttranslateBox(childBox, previousScrollTop - node.state.scrollTop);\n\t\tconst scrollView = node.state as ScrollView;\n\t\tif (node.state.primary || !context.primaryScrollView) context.primaryScrollView = scrollView;\n\t\tconst rect = { x, y, width: safeWidth, height: viewportHeight };\n\t\tconst childClip = intersect(clip, rect);\n\t\tconst box: LayoutBox = {\n\t\t\tcomponent,\n\t\t\trect,\n\t\t\tclip: childClip,\n\t\t\tchildren: [childBox],\n\t\t\tscrollView,\n\t\t\tscrollContentLines: renderCached(context, node.component, contentWidth),\n\t\t\tlayer: 0,\n\t\t};\n\t\tchildBox.parent = box;\n\t\tupdateClips(childBox, childClip);\n\t\treturn box;\n\t}\n\n\tconst entries = visibleStackEntries(node.entries, context.viewport);\n\tconst gapTotal = Math.max(0, entries.length - 1) * node.gap;\n\tif (node.type === \"vstack\") {\n\t\tconst intrinsicHeights = entries.map((entry) => measureHeight(context, entry.component, safeWidth));\n\t\tconst sizes = allocateStackSizes(entries, intrinsicHeights, height, node.gap);\n\t\tconst naturalHeight = sizes.reduce((sum, size) => sum + size, 0) + gapTotal;\n\t\tconst allocatedHeight = height === undefined ? naturalHeight : Math.max(0, Math.floor(height));\n\t\tconst rect = { x, y, width: safeWidth, height: allocatedHeight };\n\t\tconst box: LayoutBox = {\n\t\t\tcomponent,\n\t\t\trect,\n\t\t\tclip: intersect(clip, rect),\n\t\t\tchildren: [],\n\t\t\tlayer: 0,\n\t\t};\n\t\tlet childY = y;\n\t\tfor (let index = 0; index < entries.length; index++) {\n\t\t\tbox.children.push(\n\t\t\t\twithParent(\n\t\t\t\t\tlayoutComponent(context, entries[index]!.component, x, childY, safeWidth, sizes[index]!, box.clip),\n\t\t\t\t\tbox,\n\t\t\t\t),\n\t\t\t);\n\t\t\tchildY += sizes[index]! + node.gap;\n\t\t}\n\t\treturn box;\n\t}\n\n\tconst intrinsicWidths = entries.map((entry) => measureWidth(context, entry.component, safeWidth));\n\tconst widths = allocateStackSizes(entries, intrinsicWidths, safeWidth, node.gap);\n\tconst intrinsicHeights = entries.map((entry, index) =>\n\t\tmeasureHeight(context, entry.component, Math.max(1, widths[index]!)),\n\t);\n\tconst allocatedHeight =\n\t\theight === undefined\n\t\t\t? intrinsicHeights.reduce((max, childHeight) => Math.max(max, childHeight), 0)\n\t\t\t: Math.max(0, height);\n\tconst rect = { x, y, width: safeWidth, height: allocatedHeight };\n\tconst box: LayoutBox = {\n\t\tcomponent,\n\t\trect,\n\t\tclip: intersect(clip, rect),\n\t\tchildren: [],\n\t\tlayer: 0,\n\t};\n\tlet childX = x;\n\tfor (let index = 0; index < entries.length; index++) {\n\t\tconst naturalChildHeight = intrinsicHeights[index]!;\n\t\tconst childHeight = node.align === \"stretch\" ? allocatedHeight : Math.min(allocatedHeight, naturalChildHeight);\n\t\tlet childY = y;\n\t\tif (node.align === \"center\") childY += Math.floor((allocatedHeight - childHeight) / 2);\n\t\telse if (node.align === \"end\") childY += allocatedHeight - childHeight;\n\t\tconst childWidth = widths[index]!;\n\t\tif (childWidth === 0) {\n\t\t\tbox.children.push({\n\t\t\t\tcomponent: entries[index]!.component,\n\t\t\t\trect: { x: childX, y: childY, width: 0, height: childHeight },\n\t\t\t\tclip: { x: childX, y: childY, width: 0, height: 0 },\n\t\t\t\tchildren: [],\n\t\t\t\tparent: box,\n\t\t\t\tlayer: 0,\n\t\t\t});\n\t\t} else {\n\t\t\tbox.children.push(\n\t\t\t\twithParent(\n\t\t\t\t\tlayoutComponent(context, entries[index]!.component, childX, childY, childWidth, childHeight, box.clip),\n\t\t\t\t\tbox,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tchildX += childWidth + node.gap;\n\t}\n\treturn box;\n}\n\nfunction styleScrollbarCell(line: string, column: number, totalWidth: number, style: (text: string) => string): string {\n\tif (isImageLine(line)) return line;\n\n\tconst graphemeRange = getGraphemeCellRange(line, column);\n\tconst start = graphemeRange?.start ?? column;\n\tconst end = graphemeRange?.end ?? column + 1;\n\tconst before = sliceByColumn(line, 0, start, true);\n\tconst target = sliceByColumn(line, start, end - start, true);\n\tconst after = sliceByColumn(line, end, Math.max(0, totalWidth - end), true);\n\n\tlet targetPrefix = \"\";\n\tlet targetIndex = 0;\n\twhile (targetIndex < target.length) {\n\t\tconst ansi = extractAnsiCode(target, targetIndex);\n\t\tif (!ansi) break;\n\t\ttargetPrefix += ansi.code;\n\t\ttargetIndex += ansi.length;\n\t}\n\tconst targetText = target.slice(targetIndex) || \" \".repeat(end - start);\n\tconst beforePadding = \" \".repeat(Math.max(0, start - visibleWidth(before)));\n\treturn `${before}${beforePadding}${targetPrefix}${style(targetText)}${after}`;\n}\n\nexport function getScrollbarGeometry(box: LayoutBox): ScrollbarGeometry | undefined {\n\tif (!box.scrollView?.isScrollbarVisible || box.rect.width <= 0 || box.rect.height <= 0) return undefined;\n\n\tconst contentHeight = box.children[0]?.rect.height ?? box.scrollContentLines?.length ?? 0;\n\tconst trackHeight = box.rect.height;\n\n\tconst minThumbHeight = Math.min(2, trackHeight);\n\tconst thumbHeight = Math.max(\n\t\tminThumbHeight,\n\t\tMath.min(trackHeight, Math.round((trackHeight * trackHeight) / contentHeight)),\n\t);\n\tconst maxScrollTop = Math.max(0, contentHeight - trackHeight);\n\tconst maxThumbTop = trackHeight - thumbHeight;\n\tconst thumbOffset = maxScrollTop === 0 ? 0 : Math.round((box.scrollView.scrollTop / maxScrollTop) * maxThumbTop);\n\tconst column = box.rect.x + box.rect.width - 1;\n\tif (column < box.clip.x || column >= box.clip.x + box.clip.width) return undefined;\n\n\treturn {\n\t\tcolumn,\n\t\ttrackTop: box.rect.y,\n\t\ttrackHeight,\n\t\tthumbTop: box.rect.y + thumbOffset,\n\t\tthumbHeight,\n\t\tmaxScrollTop,\n\t};\n}\n\nfunction paintScrollbar(box: LayoutBox, screen: string[], totalWidth: number): void {\n\tconst geometry = getScrollbarGeometry(box);\n\tif (!geometry || !box.scrollView) return;\n\n\tfor (let offset = 0; offset < geometry.thumbHeight; offset++) {\n\t\tconst row = geometry.thumbTop + offset;\n\t\tif (row < box.clip.y || row >= box.clip.y + box.clip.height || row < 0 || row >= screen.length) continue;\n\t\tscreen[row] = styleScrollbarCell(screen[row] ?? \"\", geometry.column, totalWidth, box.scrollView.scrollbarStyle);\n\t}\n}\n\nfunction paintBox(box: LayoutBox, screen: string[], totalWidth: number): void {\n\tif (box.lines) {\n\t\tconst offset = box.lineOffset ?? 0;\n\t\tfor (let localRow = 0; localRow < box.rect.height; localRow++) {\n\t\t\tconst row = box.rect.y + localRow;\n\t\t\tif (row < box.clip.y || row >= box.clip.y + box.clip.height || row < 0 || row >= screen.length) continue;\n\t\t\tconst sourceLine = box.lines[offset + localRow];\n\t\t\tif (sourceLine === undefined) continue;\n\t\t\tlet line = sourceLine.replace(OSC133_ZONE_PREFIX, \"\");\n\t\t\tconst imageMetadata = getKittyImageMetadata(line);\n\t\t\tif (imageMetadata) {\n\t\t\t\tconst clipBottom = Math.min(screen.length, box.clip.y + box.clip.height);\n\t\t\t\tconst visibleRows = Math.min(imageMetadata.rows, clipBottom - row);\n\t\t\t\tif (visibleRows < imageMetadata.rows) line = cropKittyImageLine(line, 0, visibleRows);\n\t\t\t}\n\t\t\tif (isImageLine(line) && box.rect.x === 0 && box.rect.width >= totalWidth) screen[row] = line;\n\t\t\telse screen[row] = compositeTuiLine(screen[row] ?? \"\", line, box.rect.x, box.rect.width, totalWidth);\n\t\t}\n\t}\n\tfor (const child of box.children) paintBox(child, screen, totalWidth);\n\n\tif (box.scrollView && box.scrollContentLines && box.scrollView.scrollTop > 0 && box.rect.height > 0) {\n\t\tfor (let imageRow = box.scrollView.scrollTop - 1; imageRow >= 0; imageRow--) {\n\t\t\tconst imageLine = box.scrollContentLines[imageRow] ?? \"\";\n\t\t\tconst metadata = getKittyImageMetadata(imageLine);\n\t\t\tif (metadata) {\n\t\t\t\tconst hiddenRows = box.scrollView.scrollTop - imageRow;\n\t\t\t\tif (hiddenRows < metadata.rows) {\n\t\t\t\t\tconst visibleRows = Math.min(box.rect.height, metadata.rows - hiddenRows);\n\t\t\t\t\tconst cropped = cropKittyImageLine(imageLine, hiddenRows, visibleRows);\n\t\t\t\t\tif (box.rect.x === 0 && box.rect.width >= totalWidth) screen[box.rect.y] = cropped;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (imageLine !== \"\") break;\n\t\t}\n\t}\n\n\tpaintScrollbar(box, screen, totalWidth);\n}\n\nexport function renderLayoutFrame(\n\troot: Component,\n\twidth: number,\n\theight: number,\n\trequestRender: () => void,\n): LayoutFrame {\n\tconst safeWidth = Math.max(1, Math.floor(width));\n\tconst safeHeight = Math.max(1, Math.floor(height));\n\tconst context: LayoutContext = {\n\t\tviewport: { width: safeWidth, height: safeHeight },\n\t\trenderCache: new Map(),\n\t\trequestRender,\n\t\tprimaryScrollView: undefined,\n\t};\n\tconst rootBox = layoutComponent(context, root, 0, 0, safeWidth, safeHeight, {\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: safeWidth,\n\t\theight: safeHeight,\n\t});\n\tconst lines = Array.from({ length: safeHeight }, () => \"\");\n\tpaintBox(rootBox, lines, safeWidth);\n\treturn {\n\t\troot: rootBox,\n\t\twidth: safeWidth,\n\t\theight: safeHeight,\n\t\tlines,\n\t\t...(context.primaryScrollView === undefined ? {} : { primaryScrollView: context.primaryScrollView }),\n\t};\n}\n\nfunction containsPoint(rect: LayoutRect, x: number, y: number): boolean {\n\treturn x >= rect.x && x < rect.x + rect.width && y >= rect.y && y < rect.y + rect.height;\n}\n\nexport function getScrollViewBox(frame: LayoutFrame, scrollView: ScrollView): LayoutBox | undefined {\n\tconst visit = (box: LayoutBox): LayoutBox | undefined => {\n\t\tif (box.scrollView === scrollView) return box;\n\t\tfor (const child of box.children) {\n\t\t\tconst match = visit(child);\n\t\t\tif (match) return match;\n\t\t}\n\t\treturn undefined;\n\t};\n\treturn visit(frame.root);\n}\n\nexport function getScrollViewsAt(frame: LayoutFrame, x: number, y: number): ScrollView[] {\n\tconst result: Array<{ scrollView: ScrollView; depth: number }> = [];\n\tconst visit = (box: LayoutBox, depth: number): void => {\n\t\tif (!containsPoint(box.clip, x, y)) return;\n\t\tif (box.scrollView && containsPoint(box.rect, x, y)) result.push({ scrollView: box.scrollView, depth });\n\t\tfor (const child of box.children) visit(child, depth + 1);\n\t};\n\tvisit(frame.root, 0);\n\tresult.sort((a, b) => b.depth - a.depth);\n\treturn result.map((entry) => entry.scrollView);\n}\n"]}
package/dist/mux.js CHANGED
@@ -5,6 +5,6 @@ export function useLegacyMuxRender() {
5
5
  return process.env.PI_TUI_LEGACY_MUX_RENDER === "1";
6
6
  }
7
7
  export function viewportRenderEnabled() {
8
- return process.env.PI_TUI_VIEWPORT_RENDER === "1";
8
+ return process.env.PI_TUI_VIEWPORT_RENDER !== "0";
9
9
  }
10
10
  //# sourceMappingURL=mux.js.map
package/dist/mux.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mux.js","sourceRoot":"","sources":["../src/mux.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,oBAAoB;IACnC,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,kBAAkB;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,wBAAwB,KAAK,GAAG,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,qBAAqB;IACpC,OAAO,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,GAAG,CAAC;AACnD,CAAC","sourcesContent":["export function isMultiplexerSession(): boolean {\n\treturn Boolean(process.env.TMUX || process.env.TMUX_PANE || process.env.STY || process.env.ZELLIJ);\n}\n\nexport function useLegacyMuxRender(): boolean {\n\treturn process.env.PI_TUI_LEGACY_MUX_RENDER === \"1\";\n}\n\nexport function viewportRenderEnabled(): boolean {\n\treturn process.env.PI_TUI_VIEWPORT_RENDER === \"1\";\n}\n"]}
1
+ {"version":3,"file":"mux.js","sourceRoot":"","sources":["../src/mux.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,oBAAoB;IACnC,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACpG,CAAC;AAED,MAAM,UAAU,kBAAkB;IACjC,OAAO,OAAO,CAAC,GAAG,CAAC,wBAAwB,KAAK,GAAG,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,qBAAqB;IACpC,OAAO,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,GAAG,CAAC;AACnD,CAAC","sourcesContent":["export function isMultiplexerSession(): boolean {\n\treturn Boolean(process.env.TMUX || process.env.TMUX_PANE || process.env.STY || process.env.ZELLIJ);\n}\n\nexport function useLegacyMuxRender(): boolean {\n\treturn process.env.PI_TUI_LEGACY_MUX_RENDER === \"1\";\n}\n\nexport function viewportRenderEnabled(): boolean {\n\treturn process.env.PI_TUI_VIEWPORT_RENDER !== \"0\";\n}\n"]}
@@ -87,6 +87,14 @@ export interface ImageCellSize {
87
87
  columns: number;
88
88
  rows: number;
89
89
  }
90
+ export interface KittyImageMetadata extends ImageCellSize {
91
+ imageId: number;
92
+ widthPx: number;
93
+ heightPx: number;
94
+ }
95
+ export declare function registerKittyImageMetadata(metadata: KittyImageMetadata): void;
96
+ export declare function getKittyImageMetadata(line: string): KittyImageMetadata | undefined;
97
+ export declare function cropKittyImageLine(line: string, hiddenRows: number, visibleRows: number): string;
90
98
  export declare function calculateImageCellSize(imageDimensions: ImageDimensions, maxWidthCells: number, maxHeightCells?: number, cellDimensions?: CellDimensions): ImageCellSize;
91
99
  export declare function getPngDimensions(base64Data: string): ImageDimensions | null;
92
100
  export declare function getJpegDimensions(base64Data: string): ImageDimensions | null;
@@ -95,6 +103,7 @@ export declare function getWebpDimensions(base64Data: string): ImageDimensions |
95
103
  export declare function getImageDimensions(base64Data: string, mimeType: string): ImageDimensions | null;
96
104
  export declare function renderImage(base64Data: string, imageDimensions: ImageDimensions, options?: ImageRenderOptions): {
97
105
  sequence: string;
106
+ columns: number;
98
107
  rows: number;
99
108
  imageId?: number;
100
109
  lines?: string[];
@@ -110,4 +119,5 @@ export declare function renderImage(base64Data: string, imageDimensions: ImageDi
110
119
  * @param url - The URL to link to
111
120
  */
112
121
  export declare function hyperlink(text: string, url: string): string;
122
+ export declare function imageFallback(mimeType: string, dimensions?: ImageDimensions, filename?: string): string;
113
123
  //# sourceMappingURL=terminal-image.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-image.d.ts","sourceRoot":"","sources":["../src/terminal-image.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"terminal-image.d.ts","sourceRoot":"","sources":["../src/terminal-image.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,7 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { pathToFileURL } from "node:url";
1
3
  import { detectTerminalCapabilities, } from "./terminal-capabilities.js";
4
+ import { sanitizeTerminalLabel, shortenImagePath } from "./terminal-text.js";
2
5
  export { outerKittyGraphicsMode } from "./terminal-capabilities.js";
3
6
  let cachedCapabilities = null;
4
7
  // Default cell dimensions - updated by TUI when terminal responds to query
@@ -203,6 +206,38 @@ export function encodeITerm2(base64Data, options = {}) {
203
206
  }
204
207
  return `\x1b]1337;File=${params.join(";")}:${base64Data}\x07`;
205
208
  }
209
+ const kittyImageMetadata = new Map();
210
+ export function registerKittyImageMetadata(metadata) {
211
+ kittyImageMetadata.delete(metadata.imageId);
212
+ kittyImageMetadata.set(metadata.imageId, metadata);
213
+ if (kittyImageMetadata.size > 1000) {
214
+ const oldestImageId = kittyImageMetadata.keys().next().value;
215
+ if (oldestImageId !== undefined)
216
+ kittyImageMetadata.delete(oldestImageId);
217
+ }
218
+ }
219
+ export function getKittyImageMetadata(line) {
220
+ const controls = /\x1b_G([^;]*);/.exec(line)?.[1];
221
+ if (!controls)
222
+ return undefined;
223
+ const imageId = /(?:^|,)i=(\d+)(?:,|$)/.exec(controls)?.[1];
224
+ return imageId === undefined ? undefined : kittyImageMetadata.get(Number.parseInt(imageId, 10));
225
+ }
226
+ export function cropKittyImageLine(line, hiddenRows, visibleRows) {
227
+ const metadata = getKittyImageMetadata(line);
228
+ const match = /\x1b_G([^;]*);/.exec(line);
229
+ if (!metadata || !match || hiddenRows < 0 || hiddenRows >= metadata.rows || visibleRows <= 0)
230
+ return line;
231
+ const croppedRows = Math.min(visibleRows, metadata.rows - hiddenRows);
232
+ if (hiddenRows === 0 && croppedRows === metadata.rows)
233
+ return line;
234
+ const sourceY = Math.floor((metadata.heightPx * hiddenRows) / metadata.rows);
235
+ const sourceEnd = Math.ceil((metadata.heightPx * (hiddenRows + croppedRows)) / metadata.rows);
236
+ const sourceHeight = Math.max(1, Math.min(metadata.heightPx, sourceEnd) - sourceY);
237
+ const controls = match[1].split(",").filter((control) => !/^[yhr]=/.test(control));
238
+ controls.push(`y=${sourceY}`, `h=${sourceHeight}`, `r=${croppedRows}`);
239
+ return `${line.slice(0, match.index)}\x1b_G${controls.join(",")};${line.slice(match.index + match[0].length)}`;
240
+ }
206
241
  export function calculateImageCellSize(imageDimensions, maxWidthCells, maxHeightCells, cellDimensions = { widthPx: 9, heightPx: 18 }) {
207
242
  const maxWidth = Math.max(1, Math.floor(maxWidthCells));
208
243
  const maxHeight = maxHeightCells === undefined ? undefined : Math.max(1, Math.floor(maxHeightCells));
@@ -366,16 +401,25 @@ export function renderImage(base64Data, imageDimensions, options = {}) {
366
401
  const placeholderRow = buildKittyPlaceholderRow(imageId, row, columns);
367
402
  lines.push(row === 0 ? sequence + placeholderRow : placeholderRow);
368
403
  }
369
- return { sequence, rows, imageId, lines };
404
+ return { sequence, columns, rows, imageId, lines };
370
405
  }
371
406
  if (caps.images === "kitty") {
407
+ if (options.imageId !== undefined) {
408
+ registerKittyImageMetadata({
409
+ imageId: options.imageId,
410
+ columns: size.columns,
411
+ rows: size.rows,
412
+ widthPx: imageDimensions.widthPx,
413
+ heightPx: imageDimensions.heightPx,
414
+ });
415
+ }
372
416
  const sequence = encodeKitty(base64Data, {
373
417
  columns: size.columns,
374
418
  rows: size.rows,
375
419
  imageId: options.imageId,
376
420
  moveCursor: options.moveCursor,
377
421
  });
378
- return { sequence, rows: size.rows, imageId: options.imageId };
422
+ return { sequence, columns: size.columns, rows: size.rows, imageId: options.imageId };
379
423
  }
380
424
  if (caps.images === "iterm2") {
381
425
  const sequence = encodeITerm2(base64Data, {
@@ -383,7 +427,7 @@ export function renderImage(base64Data, imageDimensions, options = {}) {
383
427
  height: "auto",
384
428
  preserveAspectRatio: options.preserveAspectRatio ?? true,
385
429
  });
386
- return { sequence, rows: size.rows };
430
+ return { sequence, columns: size.columns, rows: size.rows };
387
431
  }
388
432
  return null;
389
433
  }
@@ -400,4 +444,18 @@ export function renderImage(base64Data, imageDimensions, options = {}) {
400
444
  export function hyperlink(text, url) {
401
445
  return `\x1b]8;;${url}\x1b\\${text}\x1b]8;;\x1b\\`;
402
446
  }
447
+ export function imageFallback(mimeType, dimensions, filename) {
448
+ const parts = [];
449
+ if (filename) {
450
+ const sanitized = sanitizeTerminalLabel(filename);
451
+ const display = shortenImagePath(sanitized);
452
+ parts.push(getCapabilities().hyperlinks && isAbsolute(sanitized)
453
+ ? hyperlink(display, pathToFileURL(sanitized).href)
454
+ : display);
455
+ }
456
+ parts.push(`[${sanitizeTerminalLabel(mimeType)}]`);
457
+ if (dimensions)
458
+ parts.push(`${dimensions.widthPx}x${dimensions.heightPx}`);
459
+ return `[Image: ${parts.join(" ")}]`;
460
+ }
403
461
  //# sourceMappingURL=terminal-image.js.map