@ashx-j/lunr-tui 0.2.12 → 0.2.13-dev.2.1
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/dist/components/box.d.ts +3 -8
- package/dist/components/box.d.ts.map +1 -1
- package/dist/components/box.js +8 -27
- package/dist/components/box.js.map +1 -1
- package/dist/components/editor.d.ts +1 -0
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +3 -2
- package/dist/components/editor.js.map +1 -1
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +8 -4
- package/dist/components/input.js.map +1 -1
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +2 -2
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/text.d.ts.map +1 -1
- package/dist/components/text.js +2 -2
- package/dist/components/text.js.map +1 -1
- package/dist/components/truncated-text.d.ts.map +1 -1
- package/dist/components/truncated-text.js +5 -4
- package/dist/components/truncated-text.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/stdin-buffer.d.ts.map +1 -1
- package/dist/stdin-buffer.js +7 -4
- package/dist/stdin-buffer.js.map +1 -1
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +2 -1
- package/dist/terminal.js.map +1 -1
- package/dist/tui.d.ts +9 -2
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +98 -30
- package/dist/tui.js.map +1 -1
- package/dist/utils.d.ts +4 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +112 -0
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/dist/tui.js
CHANGED
|
@@ -9,7 +9,7 @@ import { isKeyRelease, matchesKey } from "./keys.js";
|
|
|
9
9
|
import { MOUSE_TRACKING_DISABLE, MOUSE_TRACKING_ENABLE, parseMouseEvent } from "./mouse.js";
|
|
10
10
|
import { isOsc11BackgroundColorResponse, parseOsc11BackgroundColor, parseTerminalColorSchemeReport, } from "./terminal-colors.js";
|
|
11
11
|
import { deleteKittyImage, getCapabilities, isImageLine, setCellDimensions } from "./terminal-image.js";
|
|
12
|
-
import { extractSegments, normalizeTerminalOutput, sliceByColumn, sliceWithWidth, visibleWidth } from "./utils.js";
|
|
12
|
+
import { extractSegments, normalizeTerminalOutput, sanitizeTerminalOutput, sliceByColumn, sliceWithWidth, visibleWidth, } from "./utils.js";
|
|
13
13
|
const KITTY_SEQUENCE_PREFIX = "\x1b_G";
|
|
14
14
|
function parseKittyImageHeader(line) {
|
|
15
15
|
const sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);
|
|
@@ -77,29 +77,57 @@ function isTermuxSession() {
|
|
|
77
77
|
*/
|
|
78
78
|
export class Container {
|
|
79
79
|
children = [];
|
|
80
|
+
revision = 0;
|
|
81
|
+
parents = new Set();
|
|
80
82
|
addChild(component) {
|
|
81
83
|
this.children.push(component);
|
|
84
|
+
if (component instanceof Container)
|
|
85
|
+
component.parents.add(this);
|
|
86
|
+
this.markDirty();
|
|
82
87
|
}
|
|
83
88
|
removeChild(component) {
|
|
84
89
|
const index = this.children.indexOf(component);
|
|
85
90
|
if (index !== -1) {
|
|
86
91
|
this.children.splice(index, 1);
|
|
92
|
+
if (component instanceof Container && !this.children.includes(component))
|
|
93
|
+
component.parents.delete(this);
|
|
94
|
+
this.markDirty();
|
|
87
95
|
}
|
|
88
96
|
}
|
|
89
97
|
clear() {
|
|
98
|
+
for (const child of this.children) {
|
|
99
|
+
if (child instanceof Container)
|
|
100
|
+
child.parents.delete(this);
|
|
101
|
+
}
|
|
90
102
|
this.children = [];
|
|
103
|
+
this.markDirty();
|
|
91
104
|
}
|
|
92
105
|
invalidate() {
|
|
106
|
+
this.markDirty();
|
|
93
107
|
for (const child of this.children) {
|
|
94
108
|
child.invalidate?.();
|
|
95
109
|
}
|
|
96
110
|
}
|
|
111
|
+
getRenderRevision() {
|
|
112
|
+
return this.revision;
|
|
113
|
+
}
|
|
114
|
+
syncChildParents() {
|
|
115
|
+
for (const child of this.children) {
|
|
116
|
+
if (child instanceof Container)
|
|
117
|
+
child.parents.add(this);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
markDirty() {
|
|
121
|
+
this.revision++;
|
|
122
|
+
for (const parent of this.parents)
|
|
123
|
+
parent.markDirty();
|
|
124
|
+
}
|
|
97
125
|
render(width) {
|
|
98
126
|
const lines = [];
|
|
99
127
|
for (const child of this.children) {
|
|
100
128
|
const childLines = child.render(width);
|
|
101
129
|
for (const line of childLines) {
|
|
102
|
-
lines.push(line);
|
|
130
|
+
lines.push(sanitizeTerminalOutput(line, isImageLine(line)));
|
|
103
131
|
}
|
|
104
132
|
}
|
|
105
133
|
return lines;
|
|
@@ -162,8 +190,6 @@ export class TUI extends Container {
|
|
|
162
190
|
lastChatScrollMax = 0;
|
|
163
191
|
chatLaidOut = false;
|
|
164
192
|
chatUsesGutter = false;
|
|
165
|
-
/** Bumped on non-scroll `requestRender` so offset-only paints can reuse chat layout. */
|
|
166
|
-
contentEpoch = 0;
|
|
167
193
|
chatLayoutCache;
|
|
168
194
|
alternateScreen = false;
|
|
169
195
|
alternateScreenActive = false;
|
|
@@ -181,6 +207,11 @@ export class TUI extends Container {
|
|
|
181
207
|
this.showHardwareCursor = showHardwareCursor;
|
|
182
208
|
}
|
|
183
209
|
}
|
|
210
|
+
markDirty() {
|
|
211
|
+
super.markDirty();
|
|
212
|
+
if (this.started)
|
|
213
|
+
this.queueRender(false);
|
|
214
|
+
}
|
|
184
215
|
get fullRedraws() {
|
|
185
216
|
return this.fullRedrawCount;
|
|
186
217
|
}
|
|
@@ -403,6 +434,23 @@ export class TUI extends Container {
|
|
|
403
434
|
return -1;
|
|
404
435
|
return this.children.indexOf(this.pinComponent);
|
|
405
436
|
}
|
|
437
|
+
captureChatComponentState(to) {
|
|
438
|
+
return this.children.slice(0, to).map((component) => ({
|
|
439
|
+
component,
|
|
440
|
+
revision: component instanceof Container ? component.getRenderRevision() : 0,
|
|
441
|
+
childCount: component instanceof Container ? component.children.length : undefined,
|
|
442
|
+
firstChild: component instanceof Container ? component.children[0] : undefined,
|
|
443
|
+
lastChild: component instanceof Container ? component.children[component.children.length - 1] : undefined,
|
|
444
|
+
}));
|
|
445
|
+
}
|
|
446
|
+
chatComponentStateMatches(cached, current) {
|
|
447
|
+
return (cached.length === current.length &&
|
|
448
|
+
cached.every((state, index) => state.component === current[index]?.component &&
|
|
449
|
+
state.revision === current[index]?.revision &&
|
|
450
|
+
state.childCount === current[index]?.childCount &&
|
|
451
|
+
state.firstChild === current[index]?.firstChild &&
|
|
452
|
+
state.lastChild === current[index]?.lastChild));
|
|
453
|
+
}
|
|
406
454
|
collectChildLines(from, to, width, ranges) {
|
|
407
455
|
const lines = [];
|
|
408
456
|
for (let i = from; i < to; i++) {
|
|
@@ -423,7 +471,7 @@ export class TUI extends Container {
|
|
|
423
471
|
}
|
|
424
472
|
const start = lines.length;
|
|
425
473
|
for (const line of child.render(width)) {
|
|
426
|
-
lines.push(line);
|
|
474
|
+
lines.push(sanitizeTerminalOutput(line, isImageLine(line)));
|
|
427
475
|
}
|
|
428
476
|
ranges?.push({ component: child, start, end: lines.length });
|
|
429
477
|
}
|
|
@@ -465,17 +513,25 @@ export class TUI extends Container {
|
|
|
465
513
|
const viewH = Math.max(minView, rows - dockLines.length);
|
|
466
514
|
this.lastChatViewportHeight = viewH;
|
|
467
515
|
this.chatLaidOut = true;
|
|
468
|
-
|
|
516
|
+
const canUseGutter = width >= 2;
|
|
517
|
+
if (!canUseGutter)
|
|
518
|
+
this.chatUsesGutter = false;
|
|
519
|
+
let chatWidth = this.chatUsesGutter ? width - 1 : width;
|
|
469
520
|
let scrollLines;
|
|
470
521
|
let ranges;
|
|
471
522
|
let fromCache = false;
|
|
472
523
|
const cache = this.chatLayoutCache;
|
|
473
|
-
|
|
524
|
+
const componentState = this.captureChatComponentState(pinIndex);
|
|
525
|
+
if (cache && cache.chatWidth === chatWidth && this.chatComponentStateMatches(cache.components, componentState)) {
|
|
474
526
|
scrollLines = cache.scrollLines;
|
|
475
527
|
ranges = cache.ranges;
|
|
476
528
|
fromCache = true;
|
|
477
529
|
}
|
|
478
530
|
else {
|
|
531
|
+
for (const state of componentState) {
|
|
532
|
+
if (state.component instanceof Container)
|
|
533
|
+
state.component.syncChildParents();
|
|
534
|
+
}
|
|
479
535
|
ranges = [];
|
|
480
536
|
scrollLines = this.collectChildLines(0, pinIndex, chatWidth, ranges);
|
|
481
537
|
}
|
|
@@ -488,17 +544,17 @@ export class TUI extends Container {
|
|
|
488
544
|
fromCache = false;
|
|
489
545
|
}
|
|
490
546
|
}
|
|
491
|
-
else if (scrollLines.length > viewH) {
|
|
547
|
+
else if (canUseGutter && scrollLines.length > viewH) {
|
|
492
548
|
this.chatUsesGutter = true;
|
|
493
|
-
chatWidth =
|
|
549
|
+
chatWidth = width - 1;
|
|
494
550
|
ranges = [];
|
|
495
551
|
scrollLines = this.collectChildLines(0, pinIndex, chatWidth, ranges);
|
|
496
552
|
fromCache = false;
|
|
497
553
|
}
|
|
498
554
|
if (!fromCache) {
|
|
499
555
|
this.chatLayoutCache = {
|
|
500
|
-
epoch: this.contentEpoch,
|
|
501
556
|
chatWidth,
|
|
557
|
+
components: this.captureChatComponentState(pinIndex),
|
|
502
558
|
scrollLines,
|
|
503
559
|
ranges,
|
|
504
560
|
};
|
|
@@ -518,7 +574,8 @@ export class TUI extends Container {
|
|
|
518
574
|
this.lastChatScrollMax = scrollLines.length - viewH;
|
|
519
575
|
this.chatScrollOffset = Math.max(0, Math.min(this.chatScrollOffset, this.lastChatScrollMax));
|
|
520
576
|
start = scrollLines.length - viewH - this.chatScrollOffset;
|
|
521
|
-
|
|
577
|
+
if (this.chatScrollOffset > 0)
|
|
578
|
+
start = this.snapStartToKittyImageHeader(scrollLines, start);
|
|
522
579
|
start = Math.max(0, start);
|
|
523
580
|
this.lastChatStart = start;
|
|
524
581
|
chatSlice = scrollLines.slice(start, start + viewH);
|
|
@@ -530,26 +587,34 @@ export class TUI extends Container {
|
|
|
530
587
|
const thumbTop = this.lastChatScrollMax === 0
|
|
531
588
|
? viewH - thumbH
|
|
532
589
|
: Math.round(travel * (1 - this.chatScrollOffset / this.lastChatScrollMax));
|
|
533
|
-
this.
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
590
|
+
if (this.chatUsesGutter) {
|
|
591
|
+
this.chatScrollbar = {
|
|
592
|
+
x: width,
|
|
593
|
+
y0: 1,
|
|
594
|
+
y1: viewH,
|
|
595
|
+
viewH,
|
|
596
|
+
scrollMax: this.lastChatScrollMax,
|
|
597
|
+
thumbTop,
|
|
598
|
+
thumbH,
|
|
599
|
+
};
|
|
600
|
+
const RESET = "\x1b[0m";
|
|
601
|
+
const track = `${RESET}\x1b[2m│\x1b[0m`;
|
|
602
|
+
const thumb = `${RESET}\x1b[1m█\x1b[0m`;
|
|
603
|
+
for (let i = 0; i < chatSlice.length; i++) {
|
|
604
|
+
const glyph = i >= thumbTop && i < thumbTop + thumbH ? thumb : track;
|
|
605
|
+
chatSlice[i] = `${padToWidth(chatSlice[i] ?? "", chatWidth)}${glyph}`;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
this.chatScrollbar = undefined;
|
|
610
|
+
this.scrollbarDrag = undefined;
|
|
549
611
|
}
|
|
550
612
|
}
|
|
551
613
|
this.lastChatSliceHeight = chatSlice.length;
|
|
552
|
-
|
|
614
|
+
const frame = [...chatSlice, ...dockLines];
|
|
615
|
+
if (width > 1)
|
|
616
|
+
return frame;
|
|
617
|
+
return frame.map((line) => (visibleWidth(line) > width ? sliceByColumn(line, 0, width, true) : line));
|
|
553
618
|
}
|
|
554
619
|
/**
|
|
555
620
|
* Show an overlay component with configurable positioning and sizing.
|
|
@@ -779,9 +844,12 @@ export class TUI extends Container {
|
|
|
779
844
|
this.terminal.stop();
|
|
780
845
|
}
|
|
781
846
|
requestRender(force = false) {
|
|
782
|
-
this.
|
|
847
|
+
this.chatLayoutCache = undefined;
|
|
783
848
|
this.queueRender(force);
|
|
784
849
|
}
|
|
850
|
+
requestPaint() {
|
|
851
|
+
this.queueRender(false);
|
|
852
|
+
}
|
|
785
853
|
requestRenderFromScroll() {
|
|
786
854
|
this.queueRender(false);
|
|
787
855
|
}
|
|
@@ -1267,7 +1335,7 @@ export class TUI extends Container {
|
|
|
1267
1335
|
for (let i = 0; i < lines.length; i++) {
|
|
1268
1336
|
const line = lines[i];
|
|
1269
1337
|
if (!isImageLine(line)) {
|
|
1270
|
-
lines[i] = normalizeTerminalOutput(line) + reset;
|
|
1338
|
+
lines[i] = normalizeTerminalOutput(sanitizeTerminalOutput(line)) + reset;
|
|
1271
1339
|
}
|
|
1272
1340
|
}
|
|
1273
1341
|
return lines;
|