@ashx-j/lunr-tui 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tui.d.ts +4 -9
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +44 -104
- package/dist/tui.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 {
|
|
12
|
+
import { extractSegments, normalizeTerminalOutput, 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);
|
|
@@ -118,7 +118,7 @@ export class TUI extends Container {
|
|
|
118
118
|
inputListeners = new Set();
|
|
119
119
|
/** Global callback for debug key (Shift+Ctrl+D). Called before input is forwarded to focused component. */
|
|
120
120
|
onDebug;
|
|
121
|
-
/**
|
|
121
|
+
/** Kept for callers; left-drag no longer selects. Shift+drag stays native terminal selection. */
|
|
122
122
|
onTextSelected;
|
|
123
123
|
renderRequested = false;
|
|
124
124
|
renderTimer;
|
|
@@ -155,9 +155,8 @@ export class TUI extends Container {
|
|
|
155
155
|
alternateScreenActive = false;
|
|
156
156
|
mouseTrackingActive = false;
|
|
157
157
|
static WHEEL_LINES = 3;
|
|
158
|
-
chatHitRegions = [];
|
|
159
158
|
chatScrollbar;
|
|
160
|
-
|
|
159
|
+
scrollbarDrag;
|
|
161
160
|
constructor(terminal, showHardwareCursor) {
|
|
162
161
|
super();
|
|
163
162
|
this.terminal = terminal;
|
|
@@ -405,13 +404,9 @@ export class TUI extends Container {
|
|
|
405
404
|
}
|
|
406
405
|
return;
|
|
407
406
|
}
|
|
408
|
-
const start = lines.length;
|
|
409
407
|
for (const line of child.render(width)) {
|
|
410
408
|
lines.push(line);
|
|
411
409
|
}
|
|
412
|
-
if (child.selectable && lines.length > start) {
|
|
413
|
-
this.chatHitRegions.push({ y0: start, y1: lines.length - 1, lines: lines.slice(start) });
|
|
414
|
-
}
|
|
415
410
|
}
|
|
416
411
|
snapStartToKittyImageHeader(lines, start) {
|
|
417
412
|
if (start <= 0 || start >= lines.length)
|
|
@@ -434,8 +429,8 @@ export class TUI extends Container {
|
|
|
434
429
|
render(width) {
|
|
435
430
|
const pinIndex = this.getPinIndex();
|
|
436
431
|
if (pinIndex < 0) {
|
|
437
|
-
this.chatHitRegions = [];
|
|
438
432
|
this.chatScrollbar = undefined;
|
|
433
|
+
this.scrollbarDrag = undefined;
|
|
439
434
|
this.chatLayoutCache = undefined;
|
|
440
435
|
this.chatUsesGutter = false;
|
|
441
436
|
this.chatLaidOut = false;
|
|
@@ -457,18 +452,15 @@ export class TUI extends Container {
|
|
|
457
452
|
const cache = this.chatLayoutCache;
|
|
458
453
|
if (cache && cache.epoch === this.contentEpoch && cache.chatWidth === chatWidth) {
|
|
459
454
|
scrollLines = cache.scrollLines;
|
|
460
|
-
this.chatHitRegions = this.copyHitRegions(cache.hitRegionsUnshifted);
|
|
461
455
|
fromCache = true;
|
|
462
456
|
}
|
|
463
457
|
else {
|
|
464
|
-
this.chatHitRegions = [];
|
|
465
458
|
scrollLines = this.collectChildLines(0, pinIndex, chatWidth);
|
|
466
459
|
}
|
|
467
460
|
if (this.chatUsesGutter) {
|
|
468
461
|
if (scrollLines.length <= viewH) {
|
|
469
462
|
this.chatUsesGutter = false;
|
|
470
463
|
chatWidth = width;
|
|
471
|
-
this.chatHitRegions = [];
|
|
472
464
|
scrollLines = this.collectChildLines(0, pinIndex, chatWidth);
|
|
473
465
|
fromCache = false;
|
|
474
466
|
}
|
|
@@ -476,7 +468,6 @@ export class TUI extends Container {
|
|
|
476
468
|
else if (scrollLines.length > viewH) {
|
|
477
469
|
this.chatUsesGutter = true;
|
|
478
470
|
chatWidth = Math.max(1, width - 1);
|
|
479
|
-
this.chatHitRegions = [];
|
|
480
471
|
scrollLines = this.collectChildLines(0, pinIndex, chatWidth);
|
|
481
472
|
fromCache = false;
|
|
482
473
|
}
|
|
@@ -485,7 +476,6 @@ export class TUI extends Container {
|
|
|
485
476
|
epoch: this.contentEpoch,
|
|
486
477
|
chatWidth,
|
|
487
478
|
scrollLines,
|
|
488
|
-
hitRegionsUnshifted: this.copyHitRegions(this.chatHitRegions),
|
|
489
479
|
};
|
|
490
480
|
}
|
|
491
481
|
let chatSlice;
|
|
@@ -495,6 +485,7 @@ export class TUI extends Container {
|
|
|
495
485
|
this.chatScrollOffset = 0;
|
|
496
486
|
this.lastChatScrollMax = 0;
|
|
497
487
|
this.chatScrollbar = undefined;
|
|
488
|
+
this.scrollbarDrag = undefined;
|
|
498
489
|
chatSlice = scrollLines.slice();
|
|
499
490
|
}
|
|
500
491
|
else {
|
|
@@ -507,42 +498,31 @@ export class TUI extends Container {
|
|
|
507
498
|
while (chatSlice.length < viewH) {
|
|
508
499
|
chatSlice.push("");
|
|
509
500
|
}
|
|
510
|
-
this.chatScrollbar = { x: width, y0: 1, y1: viewH, viewH, scrollMax: this.lastChatScrollMax };
|
|
511
501
|
const thumbH = Math.max(1, Math.round((viewH * viewH) / scrollLines.length));
|
|
512
502
|
const travel = Math.max(0, viewH - thumbH);
|
|
513
503
|
const thumbTop = this.lastChatScrollMax === 0
|
|
514
504
|
? viewH - thumbH
|
|
515
505
|
: Math.round(travel * (1 - this.chatScrollOffset / this.lastChatScrollMax));
|
|
516
|
-
|
|
517
|
-
|
|
506
|
+
this.chatScrollbar = {
|
|
507
|
+
x: width,
|
|
508
|
+
y0: 1,
|
|
509
|
+
y1: viewH,
|
|
510
|
+
viewH,
|
|
511
|
+
scrollMax: this.lastChatScrollMax,
|
|
512
|
+
thumbTop,
|
|
513
|
+
thumbH,
|
|
514
|
+
};
|
|
515
|
+
// Reset SGR so error/thinking colors cannot bleed into the gutter.
|
|
516
|
+
const RESET = "\x1b[0m";
|
|
517
|
+
const track = `${RESET}\x1b[2m│\x1b[0m`;
|
|
518
|
+
const thumb = `${RESET}\x1b[1m█\x1b[0m`;
|
|
518
519
|
for (let i = 0; i < chatSlice.length; i++) {
|
|
519
520
|
const glyph = i >= thumbTop && i < thumbTop + thumbH ? thumb : track;
|
|
520
521
|
chatSlice[i] = `${padToWidth(chatSlice[i] ?? "", chatWidth)}${glyph}`;
|
|
521
522
|
}
|
|
522
523
|
}
|
|
523
|
-
this.shiftHitRegions(-start);
|
|
524
|
-
if (this.selection) {
|
|
525
|
-
const lo = Math.min(this.selection.anchorY, this.selection.focusY);
|
|
526
|
-
const hi = Math.max(this.selection.anchorY, this.selection.focusY);
|
|
527
|
-
const highlightWidth = this.chatUsesGutter ? chatWidth : width;
|
|
528
|
-
for (let y = lo; y <= hi; y++) {
|
|
529
|
-
const idx = y - 1;
|
|
530
|
-
if (idx < 0 || idx >= chatSlice.length)
|
|
531
|
-
continue;
|
|
532
|
-
chatSlice[idx] = applySelectionHighlight(chatSlice[idx] ?? "", highlightWidth);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
524
|
return [...chatSlice, ...dockLines];
|
|
536
525
|
}
|
|
537
|
-
copyHitRegions(regions) {
|
|
538
|
-
return regions.map((region) => ({ y0: region.y0, y1: region.y1, lines: region.lines }));
|
|
539
|
-
}
|
|
540
|
-
shiftHitRegions(delta) {
|
|
541
|
-
for (const region of this.chatHitRegions) {
|
|
542
|
-
region.y0 += delta;
|
|
543
|
-
region.y1 += delta;
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
526
|
/**
|
|
547
527
|
* Show an overlay component with configurable positioning and sizing.
|
|
548
528
|
* Returns a handle to control the overlay's visibility.
|
|
@@ -860,61 +840,39 @@ export class TUI extends Container {
|
|
|
860
840
|
// Shift+drag stays with the terminal's native selection.
|
|
861
841
|
if (mouse.shift)
|
|
862
842
|
return;
|
|
863
|
-
if (
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
const rel = (y - this.chatScrollbar.y0) / Math.max(1, viewH - 1);
|
|
867
|
-
this.setChatScroll(Math.round((1 - rel) * this.chatScrollbar.scrollMax));
|
|
868
|
-
this.selection = undefined;
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
if (mouse.kind === "button" && !mouse.release) {
|
|
872
|
-
const region = this.hitSelectable(mouse.y);
|
|
873
|
-
if (!region) {
|
|
874
|
-
this.selection = undefined;
|
|
843
|
+
if (this.scrollbarDrag) {
|
|
844
|
+
if (mouse.kind === "move") {
|
|
845
|
+
this.dragScrollbarTo(mouse.y);
|
|
875
846
|
return;
|
|
876
847
|
}
|
|
877
|
-
|
|
878
|
-
|
|
848
|
+
if (mouse.kind === "button" && mouse.release) {
|
|
849
|
+
this.scrollbarDrag = undefined;
|
|
850
|
+
}
|
|
879
851
|
return;
|
|
880
852
|
}
|
|
881
|
-
if (!this.
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
853
|
+
if (mouse.kind === "button" && !mouse.release && this.chatScrollbar && mouse.x >= this.chatScrollbar.x) {
|
|
854
|
+
const sb = this.chatScrollbar;
|
|
855
|
+
const y = Math.max(sb.y0, Math.min(mouse.y, sb.y1));
|
|
856
|
+
const row = y - sb.y0;
|
|
857
|
+
const onThumb = row >= sb.thumbTop && row < sb.thumbTop + sb.thumbH;
|
|
858
|
+
if (!onThumb) {
|
|
859
|
+
const rel = (y - sb.y0) / Math.max(1, sb.viewH - 1);
|
|
860
|
+
this.setChatScroll(Math.round((1 - rel) * sb.scrollMax));
|
|
861
|
+
}
|
|
862
|
+
this.scrollbarDrag = { grabY: y, startOffset: this.chatScrollOffset };
|
|
886
863
|
return;
|
|
887
864
|
}
|
|
888
|
-
if (mouse.kind === "button" && mouse.release) {
|
|
889
|
-
this.selection.focusY = mouse.y;
|
|
890
|
-
const text = this.selectedText();
|
|
891
|
-
this.selection = undefined;
|
|
892
|
-
this.requestRender();
|
|
893
|
-
if (text)
|
|
894
|
-
this.onTextSelected?.(text);
|
|
895
|
-
}
|
|
896
865
|
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
const
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
const lines = [];
|
|
908
|
-
for (const region of this.chatHitRegions) {
|
|
909
|
-
for (let i = 0; i < region.lines.length; i++) {
|
|
910
|
-
const y = region.y0 + i + 1;
|
|
911
|
-
if (y < lo || y > hi)
|
|
912
|
-
continue;
|
|
913
|
-
lines.push(stripAnsiForCopy(region.lines[i] ?? ""));
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
const text = lines.join("\n").trim();
|
|
917
|
-
return text.length > 0 ? text : undefined;
|
|
866
|
+
dragScrollbarTo(mouseY) {
|
|
867
|
+
if (!this.scrollbarDrag || !this.chatScrollbar)
|
|
868
|
+
return;
|
|
869
|
+
const { viewH, thumbH, scrollMax, y0, y1 } = this.chatScrollbar;
|
|
870
|
+
const travel = viewH - thumbH;
|
|
871
|
+
if (travel <= 0 || scrollMax <= 0)
|
|
872
|
+
return;
|
|
873
|
+
const y = Math.max(y0, Math.min(mouseY, y1));
|
|
874
|
+
const deltaY = y - this.scrollbarDrag.grabY;
|
|
875
|
+
this.setChatScroll(this.scrollbarDrag.startOffset - Math.round((deltaY * scrollMax) / travel));
|
|
918
876
|
}
|
|
919
877
|
handleInput(data) {
|
|
920
878
|
if (this.consumeOsc11BackgroundResponse(data)) {
|
|
@@ -1791,22 +1749,4 @@ function padToWidth(line, width) {
|
|
|
1791
1749
|
return line;
|
|
1792
1750
|
return line + " ".repeat(width - vis);
|
|
1793
1751
|
}
|
|
1794
|
-
function applySelectionHighlight(line, width) {
|
|
1795
|
-
const padded = padToWidth(line, width);
|
|
1796
|
-
return `\x1b[7m${padded}\x1b[27m`;
|
|
1797
|
-
}
|
|
1798
|
-
function stripAnsiForCopy(line) {
|
|
1799
|
-
let out = "";
|
|
1800
|
-
let i = 0;
|
|
1801
|
-
while (i < line.length) {
|
|
1802
|
-
const ansi = extractAnsiCode(line, i);
|
|
1803
|
-
if (ansi) {
|
|
1804
|
-
i += ansi.length;
|
|
1805
|
-
continue;
|
|
1806
|
-
}
|
|
1807
|
-
out += line[i];
|
|
1808
|
-
i++;
|
|
1809
|
-
}
|
|
1810
|
-
return out.replace(/\s+$/, "");
|
|
1811
|
-
}
|
|
1812
1752
|
//# sourceMappingURL=tui.js.map
|