@f5-sales-demo/pi-tui 20.2.4 → 20.2.7
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/CHANGELOG.md +47 -0
- package/README.md +244 -244
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
- Autocomplete fuzzy discovery now accepts optional SearchDb instance for faster searches
|
|
42
42
|
|
|
43
43
|
## [13.16.0] - 2026-03-27
|
|
44
|
+
|
|
44
45
|
### Changed
|
|
45
46
|
|
|
46
47
|
- Updated tab replacement in editor text sanitization to respect configured tab width setting
|
|
@@ -56,6 +57,7 @@
|
|
|
56
57
|
- Fixed editor consuming user-rebound copy keys, preventing custom keybindings from working in the editor
|
|
57
58
|
|
|
58
59
|
## [13.14.1] - 2026-03-21
|
|
60
|
+
|
|
59
61
|
### Added
|
|
60
62
|
|
|
61
63
|
- Added Ctrl+_ as an additional default shortcut for undo
|
|
@@ -76,17 +78,20 @@
|
|
|
76
78
|
- Fixed paste marker expansion to handle special regex replacement tokens ($1, $2, $&, $$, $`, $') literally in pasted content
|
|
77
79
|
|
|
78
80
|
## [13.11.0] - 2026-03-12
|
|
81
|
+
|
|
79
82
|
### Fixed
|
|
80
83
|
|
|
81
84
|
- Fixed OSC 11 background color detection to correctly handle partial escape sequences that arrive mid-buffer, preventing user input from being swallowed
|
|
82
85
|
- Fixed race condition where overlapping OSC 11 queries would be incorrectly cancelled by DA1 sentinels from previous queries
|
|
83
86
|
|
|
84
87
|
## [13.7.5] - 2026-03-04
|
|
88
|
+
|
|
85
89
|
### Changed
|
|
86
90
|
|
|
87
91
|
- Extracted word navigation logic into reusable `moveWordLeft` and `moveWordRight` utility functions for consistent cursor movement across components
|
|
88
92
|
|
|
89
93
|
## [13.6.2] - 2026-03-03
|
|
94
|
+
|
|
90
95
|
### Fixed
|
|
91
96
|
|
|
92
97
|
- Fixed cursor positioning when content shrinks to empty without clearOnShrink enabled
|
|
@@ -96,6 +101,7 @@
|
|
|
96
101
|
### Fixed
|
|
97
102
|
|
|
98
103
|
- Fixed viewport repaint scrollback accounting during resize oscillation to avoid double-scrolling on height shrink and added exact-row scrollback assertions in overlay regression coverage ([#228](https://github.com/can1357/oh-my-pi/issues/228), [#234](https://github.com/can1357/oh-my-pi/issues/234))
|
|
104
|
+
|
|
99
105
|
## [13.5.3] - 2026-03-01
|
|
100
106
|
|
|
101
107
|
### Fixed
|
|
@@ -105,6 +111,7 @@
|
|
|
105
111
|
- Fixed cursor positioning instability when appending content under external cursor relocation by using absolute screen addressing instead of relative cursor movement
|
|
106
112
|
|
|
107
113
|
## [13.5.2] - 2026-03-01
|
|
114
|
+
|
|
108
115
|
### Breaking Changes
|
|
109
116
|
|
|
110
117
|
- Removed `getMermaidImage` callback from MarkdownTheme; replaced with `getMermaidAscii` that accepts ASCII string instead of image data
|
|
@@ -115,6 +122,7 @@
|
|
|
115
122
|
- Mermaid diagrams now render as ASCII text instead of terminal graphics protocol images
|
|
116
123
|
|
|
117
124
|
## [13.5.1] - 2026-03-01
|
|
125
|
+
|
|
118
126
|
### Fixed
|
|
119
127
|
|
|
120
128
|
- Fixed viewport shift handling to prevent stale content when mixed updates remap screen rows
|
|
@@ -142,6 +150,7 @@
|
|
|
142
150
|
|
|
143
151
|
- Fixed stale/duplicated terminal cursor dedup state by synchronizing `#lastCursorSequence` in all render write paths (hard reset, viewport repaint, deleted-lines clear path, append fast path, and differential path).
|
|
144
152
|
- Fixed scroll overshoot on `stop()` when content fills the viewport by clamping target row movement to valid screen rows.
|
|
153
|
+
|
|
145
154
|
## [13.4.0] - 2026-03-01
|
|
146
155
|
|
|
147
156
|
### Added
|
|
@@ -163,6 +172,7 @@
|
|
|
163
172
|
- Restored terminal image protocol override and fallback detection for image rendering, including `PI_FORCE_IMAGE_PROTOCOL` support and Kitty fallback for screen/tmux/ghostty-style TERM environments.
|
|
164
173
|
|
|
165
174
|
## [13.3.8] - 2026-02-28
|
|
175
|
+
|
|
166
176
|
### Breaking Changes
|
|
167
177
|
|
|
168
178
|
- Changed mermaid hash type from string to bigint in `getMermaidImage` callback and `extractMermaidBlocks` return type
|
|
@@ -184,6 +194,7 @@
|
|
|
184
194
|
- Fixed stale viewport rows appearing when terminal height increases by triggering full re-render on height changes
|
|
185
195
|
|
|
186
196
|
## [12.18.0] - 2026-02-21
|
|
197
|
+
|
|
187
198
|
### Fixed
|
|
188
199
|
|
|
189
200
|
- Fixed viewport synchronization issue by clearing scrollback when terminal state becomes desynced during full re-renders
|
|
@@ -212,18 +223,21 @@
|
|
|
212
223
|
- Fixed incremental stale-row clearing to use erase-below semantics in synchronized output, reducing leftover-line artifacts after shrink operations.
|
|
213
224
|
|
|
214
225
|
## [12.9.0] - 2026-02-17
|
|
226
|
+
|
|
215
227
|
### Added
|
|
216
228
|
|
|
217
229
|
- Exported `getTerminalId()` function to get a stable identifier for the current terminal, with support for TTY device paths and terminal multiplexers
|
|
218
230
|
- Exported `getTtyPath()` function to resolve the TTY device path for stdin via POSIX `ttyname(3)`
|
|
219
231
|
|
|
220
232
|
## [12.5.0] - 2026-02-15
|
|
233
|
+
|
|
221
234
|
### Added
|
|
222
235
|
|
|
223
236
|
- Added `cursorOverride` and `cursorOverrideWidth` properties to customize the end-of-text cursor glyph with ANSI-styled strings
|
|
224
237
|
- Added `getUseTerminalCursor()` method to query the terminal cursor mode setting
|
|
225
238
|
|
|
226
239
|
## [11.10.0] - 2026-02-10
|
|
240
|
+
|
|
227
241
|
### Added
|
|
228
242
|
|
|
229
243
|
- Added `hint` property to autocomplete items to display dim ghost text after cursor when item is selected
|
|
@@ -236,6 +250,7 @@
|
|
|
236
250
|
- Updated editor to render inline hint text as dim ghost text after cursor when autocomplete suggestions are active or provider supplies hints
|
|
237
251
|
|
|
238
252
|
## [11.8.0] - 2026-02-10
|
|
253
|
+
|
|
239
254
|
### Added
|
|
240
255
|
|
|
241
256
|
- Added Alt+Y keybinding to cycle through kill ring entries (yank-pop)
|
|
@@ -252,6 +267,7 @@
|
|
|
252
267
|
- Changed undo coalescing in Input component to group consecutive word typing into single undo units
|
|
253
268
|
|
|
254
269
|
## [11.4.1] - 2026-02-06
|
|
270
|
+
|
|
255
271
|
### Fixed
|
|
256
272
|
|
|
257
273
|
- Fixed terminal scrolling when displaying overlays after rendering large content, preventing hundreds of blank lines from being output
|
|
@@ -344,6 +360,7 @@
|
|
|
344
360
|
- Fixed handling of private use Unicode codepoints (U+E000 to U+F8FF) in Kitty key decoding to prevent invalid character interpretation
|
|
345
361
|
|
|
346
362
|
## [9.7.0] - 2026-02-01
|
|
363
|
+
|
|
347
364
|
### Breaking Changes
|
|
348
365
|
|
|
349
366
|
- Removed `Key` helper object from public API; use string literals like `"ctrl+c"` instead of `Key.ctrl("c")`
|
|
@@ -355,6 +372,7 @@
|
|
|
355
372
|
- Simplified `isKeyRelease()` and `isKeyRepeat()` to use regex pattern matching instead of string inclusion checks
|
|
356
373
|
|
|
357
374
|
## [9.6.2] - 2026-02-01
|
|
375
|
+
|
|
358
376
|
### Changed
|
|
359
377
|
|
|
360
378
|
- Renamed `EllipsisKind` enum to `Ellipsis` for clearer API naming
|
|
@@ -368,6 +386,7 @@
|
|
|
368
386
|
- Removed `extractAnsiCode` function from public API
|
|
369
387
|
|
|
370
388
|
## [9.6.1] - 2026-02-01
|
|
389
|
+
|
|
371
390
|
### Changed
|
|
372
391
|
|
|
373
392
|
- Improved performance of key ID parsing with optimized cache lookup strategy
|
|
@@ -378,12 +397,14 @@
|
|
|
378
397
|
- Removed `visibleWidth` benchmark file in favor of Kitty sequence benchmarking
|
|
379
398
|
|
|
380
399
|
## [9.5.0] - 2026-02-01
|
|
400
|
+
|
|
381
401
|
### Changed
|
|
382
402
|
|
|
383
403
|
- Improved fuzzy file search performance by using native implementation instead of spawning external process
|
|
384
404
|
- Replaced external `fd` binary with native fuzzy path search for `@`-prefixed autocomplete
|
|
385
405
|
|
|
386
406
|
## [9.4.0] - 2026-01-31
|
|
407
|
+
|
|
387
408
|
### Added
|
|
388
409
|
|
|
389
410
|
- Exported `padding` utility function for creating space-padded strings efficiently
|
|
@@ -395,59 +416,74 @@
|
|
|
395
416
|
## [9.2.2] - 2026-01-31
|
|
396
417
|
|
|
397
418
|
### Added
|
|
419
|
+
|
|
398
420
|
- Added setAutocompleteMaxVisible() configuration (3-20 items)
|
|
399
421
|
- Added image detection to terminal capabilities (containsImage method)
|
|
400
422
|
- Added stdin monitoring to detect stalled input events and log warnings
|
|
401
423
|
|
|
402
424
|
### Changed
|
|
425
|
+
|
|
403
426
|
- Improved blockquote rendering with text wrapping in Markdown component
|
|
404
427
|
- Restructured terminal capabilities from interface-based to class-based model
|
|
405
428
|
- Improved table column width calculation with word-aware wrapping
|
|
406
429
|
- Refactored text utilities to use native WASM implementations for strings >256 chars with JS fast path
|
|
407
430
|
|
|
408
431
|
### Fixed
|
|
432
|
+
|
|
409
433
|
- Simplified terminal write error handling to mark terminal as dead on any write failure
|
|
410
434
|
- Fixed multi-line strings in renderOutputBlock causing width overflow
|
|
411
435
|
- Fixed slash command autocomplete applying stale completion when typing quickly
|
|
412
436
|
|
|
413
437
|
### Removed
|
|
438
|
+
|
|
414
439
|
- Removed TUI layout engine exports from public API (BoxNode, ColumnNode, LayoutNode, etc.)
|
|
415
440
|
|
|
416
441
|
## [8.12.7] - 2026-01-29
|
|
417
442
|
|
|
418
443
|
### Fixed
|
|
444
|
+
|
|
419
445
|
- Fixed slash command autocomplete applying stale completion when typing quickly
|
|
420
446
|
|
|
421
447
|
## [8.4.1] - 2026-01-25
|
|
422
448
|
|
|
423
449
|
### Added
|
|
450
|
+
|
|
424
451
|
- Added fuzzy match function for autocomplete suggestions
|
|
452
|
+
|
|
425
453
|
## [8.4.0] - 2026-01-25
|
|
426
454
|
|
|
427
455
|
### Changed
|
|
456
|
+
|
|
428
457
|
- Added Ctrl+Backspace as a delete-word-backward keybinding and improved modified backspace matching
|
|
429
458
|
|
|
430
459
|
### Fixed
|
|
460
|
+
|
|
431
461
|
- Terminal gracefully handles write failures by marking dead instead of exiting the process
|
|
432
462
|
- Reserved cursor space for zero padding and corrected end-of-line cursor rendering to prevent wrap glitches
|
|
433
463
|
- Corrected editor end-of-line cursor rendering assertion to use includes() instead of endsWith()
|
|
464
|
+
|
|
434
465
|
## [8.2.0] - 2026-01-24
|
|
435
466
|
|
|
436
467
|
### Added
|
|
468
|
+
|
|
437
469
|
- Added mermaid diagram rendering engine (renderMermaidToPng) with mmdc CLI integration
|
|
438
470
|
- Added terminal graphics encoding (iTerm2/Kitty) for mermaid diagrams with automatic width scaling
|
|
439
471
|
- Added mermaid block extraction and deduplication utilities (extractMermaidBlocks)
|
|
440
472
|
|
|
441
473
|
### Changed
|
|
474
|
+
|
|
442
475
|
- Updated TypeScript configuration for better publish-time configuration handling with tsconfig.publish.json
|
|
443
476
|
- Migrated file system operations from synchronous to asynchronous APIs in autocomplete provider for non-blocking I/O
|
|
444
477
|
- Migrated node module imports from named to namespace imports across all packages for consistency with project guidelines
|
|
445
478
|
|
|
446
479
|
### Fixed
|
|
480
|
+
|
|
447
481
|
- Fixed crash when terminal becomes unavailable (EIO errors) by exiting gracefully instead of throwing
|
|
448
482
|
- Fixed potential errors during emergency terminal restore when terminal is already dead
|
|
449
483
|
- Fixed autocomplete race condition by tracking request ID to prevent stale suggestion results
|
|
484
|
+
|
|
450
485
|
## [6.8.3] - 2026-01-21
|
|
486
|
+
|
|
451
487
|
### Added
|
|
452
488
|
|
|
453
489
|
- Added undo support in the editor via `Ctrl+-`
|
|
@@ -503,6 +539,7 @@
|
|
|
503
539
|
- Fixed Alt+letter key combinations for better recognition
|
|
504
540
|
|
|
505
541
|
## [5.3.1] - 2026-01-15
|
|
542
|
+
|
|
506
543
|
### Fixed
|
|
507
544
|
|
|
508
545
|
- Fixed rendering issues on Windows by preventing re-entrant renders
|
|
@@ -532,27 +569,32 @@
|
|
|
532
569
|
## [4.7.0] - 2026-01-12
|
|
533
570
|
|
|
534
571
|
### Fixed
|
|
572
|
+
|
|
535
573
|
- Remove trailing space padding from Text, Markdown, and TruncatedText components when no background color is set (fixes copied text including unwanted whitespace)
|
|
536
574
|
|
|
537
575
|
## [4.6.0] - 2026-01-12
|
|
538
576
|
|
|
539
577
|
### Added
|
|
578
|
+
|
|
540
579
|
- Add fuzzy matching module (`fuzzyMatch`, `fuzzyFilter`) for command autocomplete
|
|
541
580
|
- Add `getExpandedText()` to editor for expanding paste markers
|
|
542
581
|
- Add backslash+enter newline fallback for terminals without Kitty protocol
|
|
543
582
|
|
|
544
583
|
### Fixed
|
|
584
|
+
|
|
545
585
|
- Remove Kitty protocol query timeout that caused shift+enter delays
|
|
546
586
|
- Add bracketed paste check to prevent false key release/repeat detection
|
|
547
587
|
- Rendering optimizations: only re-render changed lines
|
|
548
588
|
- Refactor input component to use keybindings manager
|
|
549
589
|
|
|
550
590
|
## [4.4.4] - 2026-01-11
|
|
591
|
+
|
|
551
592
|
### Fixed
|
|
552
593
|
|
|
553
594
|
- Fixed Ctrl+Enter sequences to insert new lines in the editor
|
|
554
595
|
|
|
555
596
|
## [4.2.1] - 2026-01-11
|
|
597
|
+
|
|
556
598
|
### Changed
|
|
557
599
|
|
|
558
600
|
- Improved file autocomplete to show directory listing when typing `@` with no query, and fall back to prefix matching when fuzzy search returns no results
|
|
@@ -563,11 +605,13 @@
|
|
|
563
605
|
- Fixed `fd` tool detection to automatically find `fd` or `fdfind` in PATH when not explicitly configured
|
|
564
606
|
|
|
565
607
|
## [4.1.0] - 2026-01-10
|
|
608
|
+
|
|
566
609
|
### Added
|
|
567
610
|
|
|
568
611
|
- Added persistent prompt history storage support via `setHistoryStorage()` method, allowing history to be saved and restored across sessions
|
|
569
612
|
|
|
570
613
|
## [4.0.0] - 2026-01-10
|
|
614
|
+
|
|
571
615
|
### Added
|
|
572
616
|
|
|
573
617
|
- `EditorComponent` interface for custom editor implementations
|
|
@@ -598,6 +642,7 @@
|
|
|
598
642
|
- Fixed text wrapping allowing long whitespace tokens to exceed line width
|
|
599
643
|
|
|
600
644
|
## [3.20.0] - 2026-01-06
|
|
645
|
+
|
|
601
646
|
### Added
|
|
602
647
|
|
|
603
648
|
- Added `isCapsLock` helper function for detecting Caps Lock key press via Kitty protocol
|
|
@@ -629,6 +674,7 @@
|
|
|
629
674
|
- Added support for custom spinner frames in the Loader component
|
|
630
675
|
|
|
631
676
|
## [3.9.1337] - 2026-01-04
|
|
677
|
+
|
|
632
678
|
### Added
|
|
633
679
|
|
|
634
680
|
- Added `setTopBorder()` method to Editor component for displaying custom status content in the top border
|
|
@@ -641,6 +687,7 @@
|
|
|
641
687
|
- Changed cursor style from block to thin blinking bar (▏) at end of line
|
|
642
688
|
|
|
643
689
|
## [1.500.0] - 2026-01-03
|
|
690
|
+
|
|
644
691
|
### Added
|
|
645
692
|
|
|
646
693
|
- Added `getText()` method to Text component for retrieving current text content
|
package/README.md
CHANGED
|
@@ -29,8 +29,8 @@ tui.addChild(new Text("Welcome to my app!"));
|
|
|
29
29
|
|
|
30
30
|
const editor = new Editor(editorTheme);
|
|
31
31
|
editor.onSubmit = (text) => {
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
console.log("Submitted:", text);
|
|
33
|
+
tui.addChild(new Text(`You said: ${text}`));
|
|
34
34
|
};
|
|
35
35
|
tui.addChild(editor);
|
|
36
36
|
|
|
@@ -62,9 +62,9 @@ All components implement:
|
|
|
62
62
|
|
|
63
63
|
```typescript
|
|
64
64
|
interface Component {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
render(width: number): string[];
|
|
66
|
+
handleInput?(data: string): void;
|
|
67
|
+
invalidate?(): void;
|
|
68
68
|
}
|
|
69
69
|
```
|
|
70
70
|
|
|
@@ -92,9 +92,9 @@ Container that applies padding and background color to all children.
|
|
|
92
92
|
|
|
93
93
|
```typescript
|
|
94
94
|
const box = new Box(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
1, // paddingX (default: 1)
|
|
96
|
+
1, // paddingY (default: 1)
|
|
97
|
+
(text) => chalk.bgGray(text), // optional background function
|
|
98
98
|
);
|
|
99
99
|
box.addChild(new Text("Content"));
|
|
100
100
|
box.setBgFn((text) => chalk.bgBlue(text)); // Change background dynamically
|
|
@@ -106,10 +106,10 @@ Displays multi-line text with word wrapping and padding.
|
|
|
106
106
|
|
|
107
107
|
```typescript
|
|
108
108
|
const text = new Text(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
"Hello World", // text content
|
|
110
|
+
1, // paddingX (default: 1)
|
|
111
|
+
1, // paddingY (default: 1)
|
|
112
|
+
(text) => chalk.bgGray(text), // optional background function
|
|
113
113
|
);
|
|
114
114
|
text.setText("Updated text");
|
|
115
115
|
text.setCustomBgFn((text) => chalk.bgBlue(text));
|
|
@@ -121,9 +121,9 @@ Single-line text that truncates to fit viewport width. Useful for status lines a
|
|
|
121
121
|
|
|
122
122
|
```typescript
|
|
123
123
|
const truncated = new TruncatedText(
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
"This is a very long line that will be truncated...",
|
|
125
|
+
0, // paddingX (default: 0)
|
|
126
|
+
0, // paddingY (default: 0)
|
|
127
127
|
);
|
|
128
128
|
```
|
|
129
129
|
|
|
@@ -155,51 +155,51 @@ Multi-line text editor with autocomplete, file completion, and paste handling.
|
|
|
155
155
|
|
|
156
156
|
```typescript
|
|
157
157
|
interface SymbolTheme {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
158
|
+
cursor: string;
|
|
159
|
+
ellipsis: string;
|
|
160
|
+
boxRound: {
|
|
161
|
+
topLeft: string;
|
|
162
|
+
topRight: string;
|
|
163
|
+
bottomLeft: string;
|
|
164
|
+
bottomRight: string;
|
|
165
|
+
horizontal: string;
|
|
166
|
+
vertical: string;
|
|
167
|
+
};
|
|
168
|
+
boxSharp: {
|
|
169
|
+
topLeft: string;
|
|
170
|
+
topRight: string;
|
|
171
|
+
bottomLeft: string;
|
|
172
|
+
bottomRight: string;
|
|
173
|
+
horizontal: string;
|
|
174
|
+
vertical: string;
|
|
175
|
+
teeDown: string;
|
|
176
|
+
teeUp: string;
|
|
177
|
+
teeLeft: string;
|
|
178
|
+
teeRight: string;
|
|
179
|
+
cross: string;
|
|
180
|
+
};
|
|
181
|
+
table: {
|
|
182
|
+
topLeft: string;
|
|
183
|
+
topRight: string;
|
|
184
|
+
bottomLeft: string;
|
|
185
|
+
bottomRight: string;
|
|
186
|
+
horizontal: string;
|
|
187
|
+
vertical: string;
|
|
188
|
+
teeDown: string;
|
|
189
|
+
teeUp: string;
|
|
190
|
+
teeLeft: string;
|
|
191
|
+
teeRight: string;
|
|
192
|
+
cross: string;
|
|
193
|
+
};
|
|
194
|
+
quoteBorder: string;
|
|
195
|
+
hrChar: string;
|
|
196
|
+
spinnerFrames: string[];
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
interface EditorTheme {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
200
|
+
borderColor: (str: string) => string;
|
|
201
|
+
selectList: SelectListTheme;
|
|
202
|
+
symbols: SymbolTheme;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
const editor = new Editor(theme);
|
|
@@ -236,40 +236,40 @@ Renders markdown with syntax highlighting and theming support.
|
|
|
236
236
|
|
|
237
237
|
```typescript
|
|
238
238
|
interface MarkdownTheme {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
239
|
+
heading: (text: string) => string;
|
|
240
|
+
link: (text: string) => string;
|
|
241
|
+
linkUrl: (text: string) => string;
|
|
242
|
+
code: (text: string) => string;
|
|
243
|
+
codeBlock: (text: string) => string;
|
|
244
|
+
codeBlockBorder: (text: string) => string;
|
|
245
|
+
quote: (text: string) => string;
|
|
246
|
+
quoteBorder: (text: string) => string;
|
|
247
|
+
hr: (text: string) => string;
|
|
248
|
+
listBullet: (text: string) => string;
|
|
249
|
+
bold: (text: string) => string;
|
|
250
|
+
italic: (text: string) => string;
|
|
251
|
+
strikethrough: (text: string) => string;
|
|
252
|
+
underline: (text: string) => string;
|
|
253
|
+
highlightCode?: (code: string, lang?: string) => string[];
|
|
254
|
+
symbols: SymbolTheme;
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
interface DefaultTextStyle {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
258
|
+
color?: (text: string) => string;
|
|
259
|
+
bgColor?: (text: string) => string;
|
|
260
|
+
bold?: boolean;
|
|
261
|
+
italic?: boolean;
|
|
262
|
+
strikethrough?: boolean;
|
|
263
|
+
underline?: boolean;
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
const md = new Markdown(
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
267
|
+
"# Hello\n\nSome **bold** text",
|
|
268
|
+
1, // paddingX
|
|
269
|
+
1, // paddingY
|
|
270
|
+
theme, // MarkdownTheme
|
|
271
|
+
defaultStyle, // optional DefaultTextStyle
|
|
272
|
+
2, // optional code block indent (spaces)
|
|
273
273
|
);
|
|
274
274
|
md.setText("Updated markdown");
|
|
275
275
|
```
|
|
@@ -288,10 +288,10 @@ Animated loading spinner.
|
|
|
288
288
|
|
|
289
289
|
```typescript
|
|
290
290
|
const loader = new Loader(
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
291
|
+
tui, // TUI instance for render updates
|
|
292
|
+
(s) => chalk.cyan(s), // spinner color function
|
|
293
|
+
(s) => chalk.gray(s), // message color function
|
|
294
|
+
"Loading...", // message (default: "Loading...")
|
|
295
295
|
);
|
|
296
296
|
loader.start();
|
|
297
297
|
loader.setMessage("Still loading...");
|
|
@@ -304,10 +304,10 @@ Extends Loader with Escape key handling and an AbortSignal for cancelling async
|
|
|
304
304
|
|
|
305
305
|
```typescript
|
|
306
306
|
const loader = new CancellableLoader(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
307
|
+
tui, // TUI instance for render updates
|
|
308
|
+
(s) => chalk.cyan(s), // spinner color function
|
|
309
|
+
(s) => chalk.gray(s), // message color function
|
|
310
|
+
"Working...", // message
|
|
311
311
|
);
|
|
312
312
|
loader.onAbort = () => done(null); // Called when user presses Escape
|
|
313
313
|
doAsyncWork(loader.signal).then(done);
|
|
@@ -325,27 +325,27 @@ Interactive selection list with keyboard navigation.
|
|
|
325
325
|
|
|
326
326
|
```typescript
|
|
327
327
|
interface SelectItem {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
328
|
+
value: string;
|
|
329
|
+
label: string;
|
|
330
|
+
description?: string;
|
|
331
331
|
}
|
|
332
332
|
|
|
333
333
|
interface SelectListTheme {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
334
|
+
selectedPrefix: (text: string) => string;
|
|
335
|
+
selectedText: (text: string) => string;
|
|
336
|
+
description: (text: string) => string;
|
|
337
|
+
scrollInfo: (text: string) => string;
|
|
338
|
+
noMatch: (text: string) => string;
|
|
339
|
+
symbols: SymbolTheme;
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
const list = new SelectList(
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
343
|
+
[
|
|
344
|
+
{ value: "opt1", label: "Option 1", description: "First option" },
|
|
345
|
+
{ value: "opt2", label: "Option 2", description: "Second option" },
|
|
346
|
+
],
|
|
347
|
+
5, // maxVisible
|
|
348
|
+
theme, // SelectListTheme
|
|
349
349
|
);
|
|
350
350
|
|
|
351
351
|
list.onSelect = (item) => console.log("Selected:", item);
|
|
@@ -366,31 +366,31 @@ Settings panel with value cycling and submenus.
|
|
|
366
366
|
|
|
367
367
|
```typescript
|
|
368
368
|
interface SettingItem {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
369
|
+
id: string;
|
|
370
|
+
label: string;
|
|
371
|
+
description?: string;
|
|
372
|
+
currentValue: string;
|
|
373
|
+
values?: string[]; // If provided, Enter/Space cycles through these
|
|
374
|
+
submenu?: (currentValue: string, done: (selectedValue?: string) => void) => Component;
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
interface SettingsListTheme {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
378
|
+
label: (text: string, selected: boolean) => string;
|
|
379
|
+
value: (text: string, selected: boolean) => string;
|
|
380
|
+
description: (text: string) => string;
|
|
381
|
+
cursor: string;
|
|
382
|
+
hint: (text: string) => string;
|
|
383
383
|
}
|
|
384
384
|
|
|
385
385
|
const settings = new SettingsList(
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
386
|
+
[
|
|
387
|
+
{ id: "theme", label: "Theme", currentValue: "dark", values: ["dark", "light"] },
|
|
388
|
+
{ id: "model", label: "Model", currentValue: "gpt-4", submenu: (val, done) => modelSelector },
|
|
389
|
+
],
|
|
390
|
+
10, // maxVisible
|
|
391
|
+
theme, // SettingsListTheme
|
|
392
|
+
(id, newValue) => console.log(`${id} changed to ${newValue}`),
|
|
393
|
+
() => console.log("Cancelled"),
|
|
394
394
|
);
|
|
395
395
|
settings.updateValue("theme", "light");
|
|
396
396
|
```
|
|
@@ -415,20 +415,20 @@ Renders images inline for terminals that support the Kitty graphics protocol (Ki
|
|
|
415
415
|
|
|
416
416
|
```typescript
|
|
417
417
|
interface ImageTheme {
|
|
418
|
-
|
|
418
|
+
fallbackColor: (str: string) => string;
|
|
419
419
|
}
|
|
420
420
|
|
|
421
421
|
interface ImageOptions {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
422
|
+
maxWidthCells?: number;
|
|
423
|
+
maxHeightCells?: number;
|
|
424
|
+
filename?: string;
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
const image = new Image(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
428
|
+
base64Data, // base64-encoded image data
|
|
429
|
+
"image/png", // MIME type
|
|
430
|
+
theme, // ImageTheme
|
|
431
|
+
options, // optional ImageOptions
|
|
432
432
|
);
|
|
433
433
|
tui.addChild(image);
|
|
434
434
|
```
|
|
@@ -446,12 +446,12 @@ import { CombinedAutocompleteProvider } from "@f5-sales-demo/pi-tui";
|
|
|
446
446
|
import { getProjectDir } from "@f5-sales-demo/pi-utils";
|
|
447
447
|
|
|
448
448
|
const provider = new CombinedAutocompleteProvider(
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
449
|
+
[
|
|
450
|
+
{ name: "help", description: "Show help" },
|
|
451
|
+
{ name: "clear", description: "Clear screen" },
|
|
452
|
+
{ name: "delete", description: "Delete last message" },
|
|
453
|
+
],
|
|
454
|
+
getProjectDir(), // base path for file completion
|
|
455
455
|
);
|
|
456
456
|
|
|
457
457
|
editor.setAutocompleteProvider(provider);
|
|
@@ -470,38 +470,38 @@ Helper functions for detecting keyboard input (supports Kitty keyboard protocol)
|
|
|
470
470
|
|
|
471
471
|
```typescript
|
|
472
472
|
import {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
473
|
+
isEnter,
|
|
474
|
+
isEscape,
|
|
475
|
+
isTab,
|
|
476
|
+
isShiftTab,
|
|
477
|
+
isArrowUp,
|
|
478
|
+
isArrowDown,
|
|
479
|
+
isArrowLeft,
|
|
480
|
+
isArrowRight,
|
|
481
|
+
isCtrlA,
|
|
482
|
+
isCtrlC,
|
|
483
|
+
isCtrlE,
|
|
484
|
+
isCtrlK,
|
|
485
|
+
isCtrlO,
|
|
486
|
+
isCtrlP,
|
|
487
|
+
isCtrlLeft,
|
|
488
|
+
isCtrlRight,
|
|
489
|
+
isAltLeft,
|
|
490
|
+
isAltRight,
|
|
491
|
+
isShiftEnter,
|
|
492
|
+
isAltEnter,
|
|
493
|
+
isShiftCtrlO,
|
|
494
|
+
isShiftCtrlD,
|
|
495
|
+
isShiftCtrlP,
|
|
496
|
+
isBackspace,
|
|
497
|
+
isDelete,
|
|
498
|
+
isHome,
|
|
499
|
+
isEnd,
|
|
500
|
+
// ... and more
|
|
501
501
|
} from "@f5-sales-demo/pi-tui";
|
|
502
502
|
|
|
503
503
|
if (isCtrlC(data)) {
|
|
504
|
-
|
|
504
|
+
process.exit(0);
|
|
505
505
|
}
|
|
506
506
|
```
|
|
507
507
|
|
|
@@ -521,17 +521,17 @@ The TUI works with any object implementing the `Terminal` interface:
|
|
|
521
521
|
|
|
522
522
|
```typescript
|
|
523
523
|
interface Terminal {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
524
|
+
start(onInput: (data: string) => void, onResize: () => void): void;
|
|
525
|
+
stop(): void;
|
|
526
|
+
write(data: string): void;
|
|
527
|
+
get columns(): number;
|
|
528
|
+
get rows(): number;
|
|
529
|
+
moveBy(lines: number): void;
|
|
530
|
+
hideCursor(): void;
|
|
531
|
+
showCursor(): void;
|
|
532
|
+
clearLine(): void;
|
|
533
|
+
clearFromCursor(): void;
|
|
534
|
+
clearScreen(): void;
|
|
535
535
|
}
|
|
536
536
|
```
|
|
537
537
|
|
|
@@ -572,30 +572,30 @@ import { isEnter, isEscape, isArrowUp, isArrowDown, isCtrlC, isTab, isBackspace
|
|
|
572
572
|
import type { Component } from "@f5-sales-demo/pi-tui";
|
|
573
573
|
|
|
574
574
|
class MyInteractiveComponent implements Component {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
575
|
+
private selectedIndex = 0;
|
|
576
|
+
private items = ["Option 1", "Option 2", "Option 3"];
|
|
577
|
+
|
|
578
|
+
onSelect?: (index: number) => void;
|
|
579
|
+
onCancel?: () => void;
|
|
580
|
+
|
|
581
|
+
handleInput(data: string): void {
|
|
582
|
+
if (isArrowUp(data)) {
|
|
583
|
+
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
584
|
+
} else if (isArrowDown(data)) {
|
|
585
|
+
this.selectedIndex = Math.min(this.items.length - 1, this.selectedIndex + 1);
|
|
586
|
+
} else if (isEnter(data)) {
|
|
587
|
+
this.onSelect?.(this.selectedIndex);
|
|
588
|
+
} else if (isEscape(data) || isCtrlC(data)) {
|
|
589
|
+
this.onCancel?.();
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
render(width: number): string[] {
|
|
594
|
+
return this.items.map((item, i) => {
|
|
595
|
+
const prefix = i === this.selectedIndex ? "> " : " ";
|
|
596
|
+
return truncateToWidth(prefix + item, width);
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
599
|
}
|
|
600
600
|
```
|
|
601
601
|
|
|
@@ -608,25 +608,25 @@ import { visibleWidth, truncateToWidth } from "@f5-sales-demo/pi-tui";
|
|
|
608
608
|
import type { Component } from "@f5-sales-demo/pi-tui";
|
|
609
609
|
|
|
610
610
|
class MyComponent implements Component {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
611
|
+
private text: string;
|
|
612
|
+
|
|
613
|
+
constructor(text: string) {
|
|
614
|
+
this.text = text;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
render(width: number): string[] {
|
|
618
|
+
// Option 1: Truncate long lines
|
|
619
|
+
return [truncateToWidth(this.text, width)];
|
|
620
|
+
|
|
621
|
+
// Option 2: Check and pad to exact width
|
|
622
|
+
const line = this.text;
|
|
623
|
+
const visible = visibleWidth(line);
|
|
624
|
+
if (visible > width) {
|
|
625
|
+
return [truncateToWidth(line, width)];
|
|
626
|
+
}
|
|
627
|
+
// Pad to exact width (optional, for backgrounds)
|
|
628
|
+
return [line + " ".repeat(width - visible)];
|
|
629
|
+
}
|
|
630
630
|
}
|
|
631
631
|
```
|
|
632
632
|
|
|
@@ -652,26 +652,26 @@ For performance, components should cache their rendered output and only re-rende
|
|
|
652
652
|
|
|
653
653
|
```typescript
|
|
654
654
|
class CachedComponent implements Component {
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
655
|
+
private text: string;
|
|
656
|
+
private cachedWidth?: number;
|
|
657
|
+
private cachedLines?: string[];
|
|
658
|
+
|
|
659
|
+
render(width: number): string[] {
|
|
660
|
+
if (this.cachedLines && this.cachedWidth === width) {
|
|
661
|
+
return this.cachedLines;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
const lines = [truncateToWidth(this.text, width)];
|
|
665
|
+
|
|
666
|
+
this.cachedWidth = width;
|
|
667
|
+
this.cachedLines = lines;
|
|
668
|
+
return lines;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
invalidate(): void {
|
|
672
|
+
this.cachedWidth = undefined;
|
|
673
|
+
this.cachedLines = undefined;
|
|
674
|
+
}
|
|
675
675
|
}
|
|
676
676
|
```
|
|
677
677
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/pi-tui",
|
|
4
|
-
"version": "20.2.
|
|
4
|
+
"version": "20.2.7",
|
|
5
5
|
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"fmt": "biome format --write ."
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@f5-sales-demo/pi-natives": "20.2.
|
|
41
|
-
"@f5-sales-demo/pi-utils": "20.2.
|
|
40
|
+
"@f5-sales-demo/pi-natives": "20.2.7",
|
|
41
|
+
"@f5-sales-demo/pi-utils": "20.2.7",
|
|
42
42
|
"marked": "^18.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|