@silvery/term 0.3.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/package.json +54 -0
- package/src/adapters/canvas-adapter.ts +356 -0
- package/src/adapters/dom-adapter.ts +452 -0
- package/src/adapters/flexily-zero-adapter.ts +368 -0
- package/src/adapters/terminal-adapter.ts +305 -0
- package/src/adapters/yoga-adapter.ts +370 -0
- package/src/ansi/ansi.ts +251 -0
- package/src/ansi/constants.ts +76 -0
- package/src/ansi/detection.ts +441 -0
- package/src/ansi/hyperlink.ts +38 -0
- package/src/ansi/index.ts +201 -0
- package/src/ansi/patch-console.ts +159 -0
- package/src/ansi/sgr-codes.ts +34 -0
- package/src/ansi/storybook.ts +209 -0
- package/src/ansi/term.ts +724 -0
- package/src/ansi/types.ts +202 -0
- package/src/ansi/underline.ts +156 -0
- package/src/ansi/utils.ts +65 -0
- package/src/ansi-sanitize.ts +509 -0
- package/src/app.ts +571 -0
- package/src/bound-term.ts +94 -0
- package/src/bracketed-paste.ts +75 -0
- package/src/browser-renderer.ts +174 -0
- package/src/buffer.ts +1984 -0
- package/src/clipboard.ts +74 -0
- package/src/cursor-query.ts +85 -0
- package/src/device-attrs.ts +228 -0
- package/src/devtools.ts +123 -0
- package/src/dom/index.ts +194 -0
- package/src/errors.ts +39 -0
- package/src/focus-reporting.ts +48 -0
- package/src/hit-registry-core.ts +228 -0
- package/src/hit-registry.ts +176 -0
- package/src/index.ts +458 -0
- package/src/input.ts +119 -0
- package/src/inspector.ts +155 -0
- package/src/kitty-detect.ts +95 -0
- package/src/kitty-manager.ts +160 -0
- package/src/layout-engine.ts +296 -0
- package/src/layout.ts +26 -0
- package/src/measurer.ts +74 -0
- package/src/mode-query.ts +106 -0
- package/src/mouse-events.ts +419 -0
- package/src/mouse.ts +83 -0
- package/src/non-tty.ts +223 -0
- package/src/osc-markers.ts +32 -0
- package/src/osc-palette.ts +169 -0
- package/src/output.ts +406 -0
- package/src/pane-manager.ts +248 -0
- package/src/pipeline/CLAUDE.md +587 -0
- package/src/pipeline/content-phase-adapter.ts +976 -0
- package/src/pipeline/content-phase.ts +1765 -0
- package/src/pipeline/helpers.ts +42 -0
- package/src/pipeline/index.ts +416 -0
- package/src/pipeline/layout-phase.ts +686 -0
- package/src/pipeline/measure-phase.ts +198 -0
- package/src/pipeline/measure-stats.ts +21 -0
- package/src/pipeline/output-phase.ts +2593 -0
- package/src/pipeline/render-box.ts +343 -0
- package/src/pipeline/render-helpers.ts +243 -0
- package/src/pipeline/render-text.ts +1255 -0
- package/src/pipeline/types.ts +161 -0
- package/src/pipeline.ts +29 -0
- package/src/pixel-size.ts +119 -0
- package/src/render-adapter.ts +179 -0
- package/src/renderer.ts +1330 -0
- package/src/runtime/create-app.tsx +1845 -0
- package/src/runtime/create-buffer.ts +18 -0
- package/src/runtime/create-runtime.ts +325 -0
- package/src/runtime/diff.ts +56 -0
- package/src/runtime/event-handlers.ts +254 -0
- package/src/runtime/index.ts +119 -0
- package/src/runtime/keys.ts +8 -0
- package/src/runtime/layout.ts +164 -0
- package/src/runtime/run.tsx +318 -0
- package/src/runtime/term-provider.ts +399 -0
- package/src/runtime/terminal-lifecycle.ts +246 -0
- package/src/runtime/tick.ts +219 -0
- package/src/runtime/types.ts +210 -0
- package/src/scheduler.ts +723 -0
- package/src/screenshot.ts +57 -0
- package/src/scroll-region.ts +69 -0
- package/src/scroll-utils.ts +97 -0
- package/src/term-def.ts +267 -0
- package/src/terminal-caps.ts +5 -0
- package/src/terminal-colors.ts +216 -0
- package/src/termtest.ts +224 -0
- package/src/text-sizing.ts +109 -0
- package/src/toolbelt/index.ts +72 -0
- package/src/unicode.ts +1763 -0
- package/src/xterm/index.ts +491 -0
- package/src/xterm/xterm-provider.ts +204 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yoga Layout Engine Adapter
|
|
3
|
+
*
|
|
4
|
+
* Wraps yoga-wasm-web to implement the LayoutEngine interface.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
Align,
|
|
9
|
+
Direction,
|
|
10
|
+
Display,
|
|
11
|
+
Edge,
|
|
12
|
+
FlexDirection,
|
|
13
|
+
Gutter,
|
|
14
|
+
Justify,
|
|
15
|
+
Overflow,
|
|
16
|
+
PositionType,
|
|
17
|
+
Wrap,
|
|
18
|
+
Yoga,
|
|
19
|
+
Node as YogaNode,
|
|
20
|
+
} from "yoga-wasm-web"
|
|
21
|
+
import type {
|
|
22
|
+
AlignValue,
|
|
23
|
+
DirectionValue,
|
|
24
|
+
DisplayValue,
|
|
25
|
+
EdgeValue,
|
|
26
|
+
FlexDirectionValue,
|
|
27
|
+
GutterValue,
|
|
28
|
+
JustifyValue,
|
|
29
|
+
LayoutConstants,
|
|
30
|
+
LayoutEngine,
|
|
31
|
+
LayoutNode,
|
|
32
|
+
MeasureFunc,
|
|
33
|
+
MeasureMode,
|
|
34
|
+
MeasureModeValue,
|
|
35
|
+
OverflowValue,
|
|
36
|
+
PositionTypeValue,
|
|
37
|
+
WrapValue,
|
|
38
|
+
} from "../layout-engine"
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Yoga Node Adapter
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Wraps a Yoga node to implement LayoutNode interface.
|
|
46
|
+
*/
|
|
47
|
+
class YogaNodeAdapter implements LayoutNode {
|
|
48
|
+
private node: YogaNode
|
|
49
|
+
private yoga: Yoga
|
|
50
|
+
private hasMeasureFunc = false
|
|
51
|
+
|
|
52
|
+
constructor(node: YogaNode, yoga: Yoga) {
|
|
53
|
+
this.node = node
|
|
54
|
+
this.yoga = yoga
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Get the underlying Yoga node (for tree operations) */
|
|
58
|
+
getYogaNode(): YogaNode {
|
|
59
|
+
return this.node
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Tree operations
|
|
63
|
+
insertChild(child: LayoutNode, index: number): void {
|
|
64
|
+
const yogaChild = (child as YogaNodeAdapter).getYogaNode()
|
|
65
|
+
this.node.insertChild(yogaChild, index)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
removeChild(child: LayoutNode): void {
|
|
69
|
+
const yogaChild = (child as YogaNodeAdapter).getYogaNode()
|
|
70
|
+
this.node.removeChild(yogaChild)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
free(): void {
|
|
74
|
+
this.node.free()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Measure function
|
|
78
|
+
setMeasureFunc(measureFunc: MeasureFunc): void {
|
|
79
|
+
this.hasMeasureFunc = true
|
|
80
|
+
this.node.setMeasureFunc((width, widthMode, height, heightMode) => {
|
|
81
|
+
const widthModeStr = this.measureModeToString(widthMode)
|
|
82
|
+
const heightModeStr = this.measureModeToString(heightMode)
|
|
83
|
+
return measureFunc(width, widthModeStr, height, heightModeStr)
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Dirty tracking - forces layout recalculation
|
|
88
|
+
// Yoga only allows markDirty() on leaf nodes with measure functions
|
|
89
|
+
markDirty(): void {
|
|
90
|
+
if (this.hasMeasureFunc) {
|
|
91
|
+
this.node.markDirty()
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private measureModeToString(mode: number): MeasureMode {
|
|
96
|
+
if (mode === this.yoga.MEASURE_MODE_EXACTLY) return "exactly"
|
|
97
|
+
if (mode === this.yoga.MEASURE_MODE_AT_MOST) return "at-most"
|
|
98
|
+
return "undefined"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Dimension setters
|
|
102
|
+
setWidth(value: number): void {
|
|
103
|
+
this.node.setWidth(value)
|
|
104
|
+
}
|
|
105
|
+
setWidthPercent(value: number): void {
|
|
106
|
+
this.node.setWidthPercent(value)
|
|
107
|
+
}
|
|
108
|
+
setWidthAuto(): void {
|
|
109
|
+
this.node.setWidthAuto()
|
|
110
|
+
}
|
|
111
|
+
setHeight(value: number): void {
|
|
112
|
+
this.node.setHeight(value)
|
|
113
|
+
}
|
|
114
|
+
setHeightPercent(value: number): void {
|
|
115
|
+
this.node.setHeightPercent(value)
|
|
116
|
+
}
|
|
117
|
+
setHeightAuto(): void {
|
|
118
|
+
this.node.setHeightAuto()
|
|
119
|
+
}
|
|
120
|
+
setMinWidth(value: number): void {
|
|
121
|
+
this.node.setMinWidth(value)
|
|
122
|
+
}
|
|
123
|
+
setMinWidthPercent(value: number): void {
|
|
124
|
+
this.node.setMinWidthPercent(value)
|
|
125
|
+
}
|
|
126
|
+
setMinHeight(value: number): void {
|
|
127
|
+
this.node.setMinHeight(value)
|
|
128
|
+
}
|
|
129
|
+
setMinHeightPercent(value: number): void {
|
|
130
|
+
this.node.setMinHeightPercent(value)
|
|
131
|
+
}
|
|
132
|
+
setMaxWidth(value: number): void {
|
|
133
|
+
this.node.setMaxWidth(value)
|
|
134
|
+
}
|
|
135
|
+
setMaxWidthPercent(value: number): void {
|
|
136
|
+
this.node.setMaxWidthPercent(value)
|
|
137
|
+
}
|
|
138
|
+
setMaxHeight(value: number): void {
|
|
139
|
+
this.node.setMaxHeight(value)
|
|
140
|
+
}
|
|
141
|
+
setMaxHeightPercent(value: number): void {
|
|
142
|
+
this.node.setMaxHeightPercent(value)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Flex properties
|
|
146
|
+
setFlexGrow(value: number): void {
|
|
147
|
+
this.node.setFlexGrow(value)
|
|
148
|
+
}
|
|
149
|
+
setFlexShrink(value: number): void {
|
|
150
|
+
this.node.setFlexShrink(value)
|
|
151
|
+
}
|
|
152
|
+
setFlexBasis(value: number): void {
|
|
153
|
+
this.node.setFlexBasis(value)
|
|
154
|
+
}
|
|
155
|
+
setFlexBasisPercent(value: number): void {
|
|
156
|
+
this.node.setFlexBasisPercent(value)
|
|
157
|
+
}
|
|
158
|
+
setFlexBasisAuto(): void {
|
|
159
|
+
this.node.setFlexBasisAuto()
|
|
160
|
+
}
|
|
161
|
+
setFlexDirection(direction: number): void {
|
|
162
|
+
// LayoutEngine uses plain numbers; Yoga uses branded FlexDirection type
|
|
163
|
+
this.node.setFlexDirection(direction as FlexDirection)
|
|
164
|
+
}
|
|
165
|
+
setFlexWrap(wrap: number): void {
|
|
166
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Wrap type
|
|
167
|
+
this.node.setFlexWrap(wrap as Wrap)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Alignment
|
|
171
|
+
setAlignItems(align: number): void {
|
|
172
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Align type
|
|
173
|
+
this.node.setAlignItems(align as Align)
|
|
174
|
+
}
|
|
175
|
+
setAlignSelf(align: number): void {
|
|
176
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Align type
|
|
177
|
+
this.node.setAlignSelf(align as Align)
|
|
178
|
+
}
|
|
179
|
+
setAlignContent(align: number): void {
|
|
180
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Align type
|
|
181
|
+
this.node.setAlignContent(align as Align)
|
|
182
|
+
}
|
|
183
|
+
setJustifyContent(justify: number): void {
|
|
184
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Justify type
|
|
185
|
+
this.node.setJustifyContent(justify as Justify)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Spacing
|
|
189
|
+
setPadding(edge: number, value: number): void {
|
|
190
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Edge type
|
|
191
|
+
this.node.setPadding(edge as Edge, value)
|
|
192
|
+
}
|
|
193
|
+
setMargin(edge: number, value: number): void {
|
|
194
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Edge type
|
|
195
|
+
this.node.setMargin(edge as Edge, value)
|
|
196
|
+
}
|
|
197
|
+
setBorder(edge: number, value: number): void {
|
|
198
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Edge type
|
|
199
|
+
this.node.setBorder(edge as Edge, value)
|
|
200
|
+
}
|
|
201
|
+
setGap(gutter: number, value: number): void {
|
|
202
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Gutter type
|
|
203
|
+
this.node.setGap(gutter as Gutter, value)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Display & Position
|
|
207
|
+
setDisplay(display: number): void {
|
|
208
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Display type
|
|
209
|
+
this.node.setDisplay(display as Display)
|
|
210
|
+
}
|
|
211
|
+
setPositionType(positionType: number): void {
|
|
212
|
+
// LayoutEngine uses plain numbers; Yoga uses branded PositionType type
|
|
213
|
+
this.node.setPositionType(positionType as PositionType)
|
|
214
|
+
}
|
|
215
|
+
setPosition(edge: number, value: number): void {
|
|
216
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Edge type
|
|
217
|
+
this.node.setPosition(edge as Edge, value)
|
|
218
|
+
}
|
|
219
|
+
setPositionPercent(edge: number, value: number): void {
|
|
220
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Edge type
|
|
221
|
+
this.node.setPositionPercent(edge as Edge, value)
|
|
222
|
+
}
|
|
223
|
+
setOverflow(overflow: number): void {
|
|
224
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Overflow type
|
|
225
|
+
this.node.setOverflow(overflow as Overflow)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Aspect Ratio
|
|
229
|
+
setAspectRatio(value: number): void {
|
|
230
|
+
this.node.setAspectRatio(value)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Layout calculation
|
|
234
|
+
calculateLayout(width: number, height: number, direction?: number): void {
|
|
235
|
+
// LayoutEngine uses plain numbers; Yoga uses branded Direction type
|
|
236
|
+
this.node.calculateLayout(width, height, (direction ?? this.yoga.DIRECTION_LTR) as Direction)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Layout results
|
|
240
|
+
getComputedLeft(): number {
|
|
241
|
+
return this.node.getComputedLeft()
|
|
242
|
+
}
|
|
243
|
+
getComputedTop(): number {
|
|
244
|
+
return this.node.getComputedTop()
|
|
245
|
+
}
|
|
246
|
+
getComputedWidth(): number {
|
|
247
|
+
return this.node.getComputedWidth()
|
|
248
|
+
}
|
|
249
|
+
getComputedHeight(): number {
|
|
250
|
+
return this.node.getComputedHeight()
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ============================================================================
|
|
255
|
+
// Yoga Layout Engine
|
|
256
|
+
// ============================================================================
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Layout engine implementation using Yoga (WASM).
|
|
260
|
+
*/
|
|
261
|
+
export class YogaLayoutEngine implements LayoutEngine {
|
|
262
|
+
private yoga: Yoga
|
|
263
|
+
private _constants: LayoutConstants
|
|
264
|
+
|
|
265
|
+
constructor(yoga: Yoga) {
|
|
266
|
+
this.yoga = yoga
|
|
267
|
+
// Cast Yoga's branded types to our LayoutEngine branded types at the adapter boundary
|
|
268
|
+
this._constants = {
|
|
269
|
+
// Flex Direction
|
|
270
|
+
FLEX_DIRECTION_COLUMN: yoga.FLEX_DIRECTION_COLUMN as unknown as FlexDirectionValue,
|
|
271
|
+
FLEX_DIRECTION_COLUMN_REVERSE: yoga.FLEX_DIRECTION_COLUMN_REVERSE as unknown as FlexDirectionValue,
|
|
272
|
+
FLEX_DIRECTION_ROW: yoga.FLEX_DIRECTION_ROW as unknown as FlexDirectionValue,
|
|
273
|
+
FLEX_DIRECTION_ROW_REVERSE: yoga.FLEX_DIRECTION_ROW_REVERSE as unknown as FlexDirectionValue,
|
|
274
|
+
|
|
275
|
+
// Wrap
|
|
276
|
+
WRAP_NO_WRAP: yoga.WRAP_NO_WRAP as unknown as WrapValue,
|
|
277
|
+
WRAP_WRAP: yoga.WRAP_WRAP as unknown as WrapValue,
|
|
278
|
+
WRAP_WRAP_REVERSE: yoga.WRAP_WRAP_REVERSE as unknown as WrapValue,
|
|
279
|
+
|
|
280
|
+
// Align
|
|
281
|
+
ALIGN_AUTO: yoga.ALIGN_AUTO as unknown as AlignValue,
|
|
282
|
+
ALIGN_FLEX_START: yoga.ALIGN_FLEX_START as unknown as AlignValue,
|
|
283
|
+
ALIGN_CENTER: yoga.ALIGN_CENTER as unknown as AlignValue,
|
|
284
|
+
ALIGN_FLEX_END: yoga.ALIGN_FLEX_END as unknown as AlignValue,
|
|
285
|
+
ALIGN_STRETCH: yoga.ALIGN_STRETCH as unknown as AlignValue,
|
|
286
|
+
ALIGN_BASELINE: yoga.ALIGN_BASELINE as unknown as AlignValue,
|
|
287
|
+
ALIGN_SPACE_BETWEEN: yoga.ALIGN_SPACE_BETWEEN as unknown as AlignValue,
|
|
288
|
+
ALIGN_SPACE_AROUND: yoga.ALIGN_SPACE_AROUND as unknown as AlignValue,
|
|
289
|
+
ALIGN_SPACE_EVENLY: yoga.ALIGN_SPACE_EVENLY as unknown as AlignValue,
|
|
290
|
+
|
|
291
|
+
// Justify
|
|
292
|
+
JUSTIFY_FLEX_START: yoga.JUSTIFY_FLEX_START as unknown as JustifyValue,
|
|
293
|
+
JUSTIFY_CENTER: yoga.JUSTIFY_CENTER as unknown as JustifyValue,
|
|
294
|
+
JUSTIFY_FLEX_END: yoga.JUSTIFY_FLEX_END as unknown as JustifyValue,
|
|
295
|
+
JUSTIFY_SPACE_BETWEEN: yoga.JUSTIFY_SPACE_BETWEEN as unknown as JustifyValue,
|
|
296
|
+
JUSTIFY_SPACE_AROUND: yoga.JUSTIFY_SPACE_AROUND as unknown as JustifyValue,
|
|
297
|
+
JUSTIFY_SPACE_EVENLY: yoga.JUSTIFY_SPACE_EVENLY as unknown as JustifyValue,
|
|
298
|
+
|
|
299
|
+
// Edge
|
|
300
|
+
EDGE_LEFT: yoga.EDGE_LEFT as unknown as EdgeValue,
|
|
301
|
+
EDGE_TOP: yoga.EDGE_TOP as unknown as EdgeValue,
|
|
302
|
+
EDGE_RIGHT: yoga.EDGE_RIGHT as unknown as EdgeValue,
|
|
303
|
+
EDGE_BOTTOM: yoga.EDGE_BOTTOM as unknown as EdgeValue,
|
|
304
|
+
EDGE_HORIZONTAL: yoga.EDGE_HORIZONTAL as unknown as EdgeValue,
|
|
305
|
+
EDGE_VERTICAL: yoga.EDGE_VERTICAL as unknown as EdgeValue,
|
|
306
|
+
EDGE_ALL: yoga.EDGE_ALL as unknown as EdgeValue,
|
|
307
|
+
|
|
308
|
+
// Gutter
|
|
309
|
+
GUTTER_COLUMN: yoga.GUTTER_COLUMN as unknown as GutterValue,
|
|
310
|
+
GUTTER_ROW: yoga.GUTTER_ROW as unknown as GutterValue,
|
|
311
|
+
GUTTER_ALL: yoga.GUTTER_ALL as unknown as GutterValue,
|
|
312
|
+
|
|
313
|
+
// Display
|
|
314
|
+
DISPLAY_FLEX: yoga.DISPLAY_FLEX as unknown as DisplayValue,
|
|
315
|
+
DISPLAY_NONE: yoga.DISPLAY_NONE as unknown as DisplayValue,
|
|
316
|
+
|
|
317
|
+
// Position Type
|
|
318
|
+
POSITION_TYPE_STATIC: yoga.POSITION_TYPE_STATIC as unknown as PositionTypeValue,
|
|
319
|
+
POSITION_TYPE_RELATIVE: yoga.POSITION_TYPE_RELATIVE as unknown as PositionTypeValue,
|
|
320
|
+
POSITION_TYPE_ABSOLUTE: yoga.POSITION_TYPE_ABSOLUTE as unknown as PositionTypeValue,
|
|
321
|
+
|
|
322
|
+
// Overflow
|
|
323
|
+
OVERFLOW_VISIBLE: yoga.OVERFLOW_VISIBLE as unknown as OverflowValue,
|
|
324
|
+
OVERFLOW_HIDDEN: yoga.OVERFLOW_HIDDEN as unknown as OverflowValue,
|
|
325
|
+
OVERFLOW_SCROLL: yoga.OVERFLOW_SCROLL as unknown as OverflowValue,
|
|
326
|
+
|
|
327
|
+
// Direction
|
|
328
|
+
DIRECTION_LTR: yoga.DIRECTION_LTR as unknown as DirectionValue,
|
|
329
|
+
|
|
330
|
+
// Measure Mode
|
|
331
|
+
MEASURE_MODE_UNDEFINED: yoga.MEASURE_MODE_UNDEFINED as unknown as MeasureModeValue,
|
|
332
|
+
MEASURE_MODE_EXACTLY: yoga.MEASURE_MODE_EXACTLY as unknown as MeasureModeValue,
|
|
333
|
+
MEASURE_MODE_AT_MOST: yoga.MEASURE_MODE_AT_MOST as unknown as MeasureModeValue,
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
createNode(): LayoutNode {
|
|
338
|
+
return new YogaNodeAdapter(this.yoga.Node.create(), this.yoga)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
get constants(): LayoutConstants {
|
|
342
|
+
return this._constants
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
get name(): string {
|
|
346
|
+
return "yoga"
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// ============================================================================
|
|
351
|
+
// Initialization Helper
|
|
352
|
+
// ============================================================================
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Create a Yoga layout engine from an initialized Yoga instance.
|
|
356
|
+
*/
|
|
357
|
+
export function createYogaEngine(yoga: Yoga): YogaLayoutEngine {
|
|
358
|
+
return new YogaLayoutEngine(yoga)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Initialize Yoga and create a layout engine.
|
|
363
|
+
* Uses yoga-wasm-web/auto which automatically selects the right implementation.
|
|
364
|
+
*/
|
|
365
|
+
export async function initYogaEngine(): Promise<YogaLayoutEngine> {
|
|
366
|
+
const { default: yoga } = (await import("yoga-wasm-web/auto")) as {
|
|
367
|
+
default: Yoga
|
|
368
|
+
}
|
|
369
|
+
return new YogaLayoutEngine(yoga)
|
|
370
|
+
}
|
package/src/ansi/ansi.ts
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ANSI terminal control helpers.
|
|
3
|
+
*
|
|
4
|
+
* Pure string-returning functions for terminal control sequences.
|
|
5
|
+
* No side effects, no stdout writes -- consumers compose and write.
|
|
6
|
+
*
|
|
7
|
+
* Covers: screen management, cursor control, scroll regions,
|
|
8
|
+
* mouse tracking, keyboard protocols, and bracketed paste.
|
|
9
|
+
*
|
|
10
|
+
* @see https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
|
11
|
+
* @see https://sw.kovidgoyal.net/kitty/keyboard-protocol/
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Base Constants
|
|
16
|
+
// =============================================================================
|
|
17
|
+
|
|
18
|
+
/** Escape character (0x1B) */
|
|
19
|
+
const ESC = "\x1b"
|
|
20
|
+
|
|
21
|
+
/** Control Sequence Introducer: ESC [ */
|
|
22
|
+
const CSI = `${ESC}[`
|
|
23
|
+
|
|
24
|
+
/** Operating System Command: ESC ] */
|
|
25
|
+
const OSC = `${ESC}]`
|
|
26
|
+
|
|
27
|
+
/** Bell character (0x07) -- used as string terminator in OSC sequences */
|
|
28
|
+
const BEL = "\x07"
|
|
29
|
+
|
|
30
|
+
// =============================================================================
|
|
31
|
+
// Screen
|
|
32
|
+
// =============================================================================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Enter the alternate screen buffer (DEC private mode 1049).
|
|
36
|
+
* The alternate screen preserves the main scrollback buffer.
|
|
37
|
+
*/
|
|
38
|
+
export function enterAltScreen(): string {
|
|
39
|
+
return `${CSI}?1049h`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Leave the alternate screen buffer and restore the main screen.
|
|
44
|
+
*/
|
|
45
|
+
export function leaveAltScreen(): string {
|
|
46
|
+
return `${CSI}?1049l`
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Clear the entire screen (ED 2 -- Erase in Display, all).
|
|
51
|
+
*/
|
|
52
|
+
export function clearScreen(): string {
|
|
53
|
+
return `${CSI}2J`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Clear the current line (EL 2 -- Erase in Line, entire line).
|
|
58
|
+
*/
|
|
59
|
+
export function clearLine(): string {
|
|
60
|
+
return `${CSI}2K`
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// =============================================================================
|
|
64
|
+
// Cursor
|
|
65
|
+
// =============================================================================
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Move cursor to an absolute position.
|
|
69
|
+
* Uses 0-indexed row/col; converts to 1-indexed CUP (Cursor Position).
|
|
70
|
+
*/
|
|
71
|
+
export function cursorTo(row: number, col: number): string {
|
|
72
|
+
return `${CSI}${row + 1};${col + 1}H`
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Move cursor to the home position (top-left, row 0, col 0).
|
|
77
|
+
*/
|
|
78
|
+
export function cursorHome(): string {
|
|
79
|
+
return `${CSI}H`
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Hide the cursor (DEC private mode 25, reset).
|
|
84
|
+
*/
|
|
85
|
+
export function cursorHide(): string {
|
|
86
|
+
return `${CSI}?25l`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Show the cursor (DEC private mode 25, set).
|
|
91
|
+
*/
|
|
92
|
+
export function cursorShow(): string {
|
|
93
|
+
return `${CSI}?25h`
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Set cursor style via DECSCUSR (DEC Set Cursor Style).
|
|
98
|
+
*
|
|
99
|
+
* | Style | Code | Description |
|
|
100
|
+
* | ----------- | ---- | ------------------------ |
|
|
101
|
+
* | block | 2 | Steady block |
|
|
102
|
+
* | underline | 4 | Steady underline |
|
|
103
|
+
* | beam | 6 | Steady bar (vertical) |
|
|
104
|
+
*
|
|
105
|
+
* Steady variants are used (even codes). Blinking would be odd codes.
|
|
106
|
+
* Supported by: xterm, Ghostty, Kitty, WezTerm, iTerm2, Alacritty, foot.
|
|
107
|
+
*/
|
|
108
|
+
export function cursorStyle(style: "block" | "underline" | "beam"): string {
|
|
109
|
+
const code = style === "block" ? 2 : style === "underline" ? 4 : 6
|
|
110
|
+
return `${CSI}${code} q`
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// =============================================================================
|
|
114
|
+
// Terminal
|
|
115
|
+
// =============================================================================
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Set the terminal window title using OSC 2 (window title only).
|
|
119
|
+
* Does not affect icon title. Widely supported.
|
|
120
|
+
*/
|
|
121
|
+
export function setTitle(title: string): string {
|
|
122
|
+
return `${OSC}2;${title}${BEL}`
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Enable mouse tracking.
|
|
127
|
+
*
|
|
128
|
+
* Enables three modes for full mouse support:
|
|
129
|
+
* - 1000: Basic button press/release reporting
|
|
130
|
+
* - 1002: Button-event tracking (drag events)
|
|
131
|
+
* - 1006: SGR extended coordinates (supports >223 columns)
|
|
132
|
+
*/
|
|
133
|
+
export function enableMouse(): string {
|
|
134
|
+
return `${CSI}?1000h${CSI}?1002h${CSI}?1006h`
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Disable mouse tracking.
|
|
139
|
+
*
|
|
140
|
+
* Disables in reverse order of enabling.
|
|
141
|
+
*/
|
|
142
|
+
export function disableMouse(): string {
|
|
143
|
+
return `${CSI}?1006l${CSI}?1002l${CSI}?1000l`
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Enable bracketed paste mode (DEC private mode 2004).
|
|
148
|
+
* Terminal wraps pasted text with markers so the app can distinguish
|
|
149
|
+
* paste from typed input.
|
|
150
|
+
*/
|
|
151
|
+
export function enableBracketedPaste(): string {
|
|
152
|
+
return `${CSI}?2004h`
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Disable bracketed paste mode.
|
|
157
|
+
*/
|
|
158
|
+
export function disableBracketedPaste(): string {
|
|
159
|
+
return `${CSI}?2004l`
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Enable synchronized update mode (DEC private mode 2026).
|
|
164
|
+
* Tells the terminal to batch output and paint atomically, preventing tearing.
|
|
165
|
+
* Supported by: Ghostty, Kitty, WezTerm, iTerm2, Foot, Alacritty 0.14+, tmux 3.2+.
|
|
166
|
+
* Terminals that don't support it safely ignore this sequence.
|
|
167
|
+
*/
|
|
168
|
+
export function enableSyncUpdate(): string {
|
|
169
|
+
return `${CSI}?2026h`
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Disable synchronized update mode.
|
|
174
|
+
* Sending this when not in sync mode is a harmless no-op.
|
|
175
|
+
*/
|
|
176
|
+
export function disableSyncUpdate(): string {
|
|
177
|
+
return `${CSI}?2026l`
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// =============================================================================
|
|
181
|
+
// Scroll
|
|
182
|
+
// =============================================================================
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Set the terminal scroll region (DECSTBM -- DEC Set Top and Bottom Margins).
|
|
186
|
+
* Uses 0-indexed top/bottom; converts to 1-indexed for the terminal.
|
|
187
|
+
*
|
|
188
|
+
* Supported by most modern terminals: xterm, iTerm2, Kitty, Ghostty, WezTerm, etc.
|
|
189
|
+
*/
|
|
190
|
+
export function setScrollRegion(top: number, bottom: number): string {
|
|
191
|
+
return `${CSI}${top + 1};${bottom + 1}r`
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Reset the scroll region to the full terminal height.
|
|
196
|
+
*/
|
|
197
|
+
export function resetScrollRegion(): string {
|
|
198
|
+
return `${CSI}r`
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Scroll content up by N lines within the current scroll region (SU).
|
|
203
|
+
* New blank lines appear at the bottom.
|
|
204
|
+
*/
|
|
205
|
+
export function scrollUp(n: number): string {
|
|
206
|
+
if (n <= 0) return ""
|
|
207
|
+
return `${CSI}${n}S`
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Scroll content down by N lines within the current scroll region (SD).
|
|
212
|
+
* New blank lines appear at the top.
|
|
213
|
+
*/
|
|
214
|
+
export function scrollDown(n: number): string {
|
|
215
|
+
if (n <= 0) return ""
|
|
216
|
+
return `${CSI}${n}T`
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// =============================================================================
|
|
220
|
+
// Keyboard
|
|
221
|
+
// =============================================================================
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Enable the Kitty keyboard protocol (push mode).
|
|
225
|
+
*
|
|
226
|
+
* Sends CSI > flags u to opt into the specified modes.
|
|
227
|
+
* Supported by: Ghostty, Kitty, WezTerm, foot. Ignored by unsupported terminals.
|
|
228
|
+
*
|
|
229
|
+
* Flags are a bitfield:
|
|
230
|
+
*
|
|
231
|
+
* | Flag | Bit | Description |
|
|
232
|
+
* | ---- | --- | ----------------------------------------- |
|
|
233
|
+
* | 1 | 0 | Disambiguate escape codes |
|
|
234
|
+
* | 2 | 1 | Report event types (press/repeat/release) |
|
|
235
|
+
* | 4 | 2 | Report alternate keys |
|
|
236
|
+
* | 8 | 3 | Report all keys as escape codes |
|
|
237
|
+
* | 16 | 4 | Report associated text |
|
|
238
|
+
*
|
|
239
|
+
* @param flags Bitfield of Kitty keyboard flags
|
|
240
|
+
*/
|
|
241
|
+
export function enableKittyKeyboard(flags: number): string {
|
|
242
|
+
return `${CSI}>${flags}u`
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Disable the Kitty keyboard protocol (pop mode stack).
|
|
247
|
+
* Sends CSI < u to restore the previous keyboard mode.
|
|
248
|
+
*/
|
|
249
|
+
export function disableKittyKeyboard(): string {
|
|
250
|
+
return `${CSI}<u`
|
|
251
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ANSI escape code constants for extended terminal features.
|
|
3
|
+
*
|
|
4
|
+
* @see https://sw.kovidgoyal.net/kitty/underlines/
|
|
5
|
+
* @see https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// Extended Underline Styles (ISO 8613-6 / ECMA-48)
|
|
10
|
+
// =============================================================================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Extended underline style codes.
|
|
14
|
+
* Uses colon-separated parameters (ISO 8613-6): \x1b[4:Nm
|
|
15
|
+
*/
|
|
16
|
+
export const UNDERLINE_CODES = {
|
|
17
|
+
/** No underline */
|
|
18
|
+
none: "\x1b[4:0m",
|
|
19
|
+
/** Standard single underline */
|
|
20
|
+
single: "\x1b[4:1m",
|
|
21
|
+
/** Double underline (two parallel lines) */
|
|
22
|
+
double: "\x1b[4:2m",
|
|
23
|
+
/** Curly/wavy underline (spell check style) */
|
|
24
|
+
curly: "\x1b[4:3m",
|
|
25
|
+
/** Dotted underline */
|
|
26
|
+
dotted: "\x1b[4:4m",
|
|
27
|
+
/** Dashed underline */
|
|
28
|
+
dashed: "\x1b[4:5m",
|
|
29
|
+
/** Reset extended underline (same as none) */
|
|
30
|
+
reset: "\x1b[4:0m",
|
|
31
|
+
} as const
|
|
32
|
+
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// Standard Underline (Fallback)
|
|
35
|
+
// =============================================================================
|
|
36
|
+
|
|
37
|
+
/** Standard underline on (SGR 4) - works on all terminals */
|
|
38
|
+
export const UNDERLINE_STANDARD = "\x1b[4m"
|
|
39
|
+
|
|
40
|
+
/** Standard underline off (SGR 24) */
|
|
41
|
+
export const UNDERLINE_RESET_STANDARD = "\x1b[24m"
|
|
42
|
+
|
|
43
|
+
// =============================================================================
|
|
44
|
+
// Underline Color (SGR 58/59)
|
|
45
|
+
// =============================================================================
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Reset underline color to default (SGR 59)
|
|
49
|
+
*/
|
|
50
|
+
export const UNDERLINE_COLOR_RESET = "\x1b[59m"
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Build underline color escape code for RGB values.
|
|
54
|
+
* Format: \x1b[58:2::r:g:bm (SGR 58 with RGB color space)
|
|
55
|
+
*/
|
|
56
|
+
export function buildUnderlineColorCode(r: number, g: number, b: number): string {
|
|
57
|
+
return `\x1b[58:2::${r}:${g}:${b}m`
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// =============================================================================
|
|
61
|
+
// Hyperlinks (OSC 8)
|
|
62
|
+
// =============================================================================
|
|
63
|
+
|
|
64
|
+
/** OSC 8 hyperlink start sequence */
|
|
65
|
+
export const HYPERLINK_START = "\x1b]8;;"
|
|
66
|
+
|
|
67
|
+
/** OSC 8 hyperlink end sequence (ST - String Terminator) */
|
|
68
|
+
export const HYPERLINK_END = "\x1b\\"
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Build a hyperlink escape sequence.
|
|
72
|
+
* Format: \x1b]8;;<url>\x1b\\ <text> \x1b]8;;\x1b\\
|
|
73
|
+
*/
|
|
74
|
+
export function buildHyperlink(text: string, url: string): string {
|
|
75
|
+
return `${HYPERLINK_START}${url}${HYPERLINK_END}${text}${HYPERLINK_START}${HYPERLINK_END}`
|
|
76
|
+
}
|