@code-yeongyu/senpi-tui 2026.8.14 → 2026.8.16
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/README.md +1 -1
- package/dist/alt-screen-search.d.ts +26 -0
- package/dist/alt-screen-search.d.ts.map +1 -0
- package/dist/alt-screen-search.js +121 -0
- package/dist/alt-screen-search.js.map +1 -0
- package/dist/components/scroll-view.d.ts +6 -1
- package/dist/components/scroll-view.d.ts.map +1 -1
- package/dist/components/scroll-view.js +23 -7
- package/dist/components/scroll-view.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/keybindings.d.ts +30 -0
- package/dist/keybindings.d.ts.map +1 -1
- package/dist/keybindings.js +24 -0
- package/dist/keybindings.js.map +1 -1
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +9 -2
- package/dist/layout.js.map +1 -1
- package/dist/stdin-buffer.d.ts +8 -2
- package/dist/stdin-buffer.d.ts.map +1 -1
- package/dist/stdin-buffer.js +6 -2
- package/dist/stdin-buffer.js.map +1 -1
- package/dist/terminal.d.ts +6 -0
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +18 -1
- package/dist/terminal.js.map +1 -1
- package/dist/tui-alt-screen.d.ts +21 -0
- package/dist/tui-alt-screen.d.ts.map +1 -1
- package/dist/tui-alt-screen.js +243 -5
- package/dist/tui-alt-screen.js.map +1 -1
- package/dist/tui.d.ts +2 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +33 -8
- package/dist/tui.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ if (isViewportTUI(tui)) {
|
|
|
121
121
|
}
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
-
Stack entries support `basis`, `grow`, `shrink`, `minSize`, `maxSize`, and responsive `visible` callbacks. Mouse-wheel input targets the scroll view under the pointer and unused delta chains to outer scroll views by default. The primary scroll view receives the alternate-screen keyboard navigation actions and wheel input over non-scrollable regions. It can also jump between OSC 133 semantic prompt markers, matching common terminal prompt-navigation shortcuts.
|
|
124
|
+
Stack entries support `basis`, `grow`, `shrink`, `minSize`, `maxSize`, and responsive `visible` callbacks. Mouse-wheel input targets the scroll view under the pointer and unused delta chains to outer scroll views by default. The primary scroll view receives the alternate-screen keyboard navigation actions and wheel input over non-scrollable regions. It can also jump between OSC 133 semantic prompt markers, matching common terminal prompt-navigation shortcuts. Press `Ctrl+Shift+F` to search its rendered content, `Enter`/`Ctrl+G` and `Shift+Enter`/`Ctrl+Shift+G` to move between matches, and `Escape` to close search. `TuiAltScreenOptions.searchMatchStyle` and `searchCurrentMatchStyle` customize match highlighting.
|
|
125
125
|
|
|
126
126
|
Layout geometry is rebuilt for each requested frame. Stateful components are retained, and their existing rendered-line caches remain effective. Calling `render(width)` directly on these layout components produces an unbounded document, which is also used when alt mode restores the main screen.
|
|
127
127
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Component, Focusable } from "./tui.ts";
|
|
2
|
+
export interface AltScreenSearchSegment {
|
|
3
|
+
row: number;
|
|
4
|
+
startCol: number;
|
|
5
|
+
endCol: number;
|
|
6
|
+
}
|
|
7
|
+
export interface AltScreenSearchMatch {
|
|
8
|
+
segments: AltScreenSearchSegment[];
|
|
9
|
+
}
|
|
10
|
+
export declare function findAltScreenSearchMatches(lines: readonly string[], query: string): AltScreenSearchMatch[];
|
|
11
|
+
export declare function getAltScreenSearchMatchKey(match: AltScreenSearchMatch): string;
|
|
12
|
+
export declare class AltScreenSearchComponent implements Component, Focusable {
|
|
13
|
+
private readonly input;
|
|
14
|
+
private readonly onQueryChange;
|
|
15
|
+
private resultCount;
|
|
16
|
+
private resultIndex;
|
|
17
|
+
private _focused;
|
|
18
|
+
constructor(onQueryChange: (query: string) => void);
|
|
19
|
+
get focused(): boolean;
|
|
20
|
+
set focused(value: boolean);
|
|
21
|
+
setResult(index: number, count: number): void;
|
|
22
|
+
handleInput(data: string): void;
|
|
23
|
+
invalidate(): void;
|
|
24
|
+
render(width: number): string[];
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=alt-screen-search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alt-screen-search.d.ts","sourceRoot":"","sources":["../src/alt-screen-search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAWrD,MAAM,WAAW,sBAAsB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,sBAAsB,EAAE,CAAC;CACnC;AAkDD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,oBAAoB,EAAE,CA0B1G;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,oBAAoB,GAAG,MAAM,CAI9E;AAED,qBAAa,wBAAyB,YAAW,SAAS,EAAE,SAAS;IACpE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0B;IACxD,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,QAAQ,CAAS;gBAEb,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;IAIlD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,OAAO,EAGzB;IAED,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7C,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAO/B,UAAU,IAAI,IAAI;IAIlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAgB/B"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Input } from "./components/input.js";
|
|
2
|
+
import { getGraphemeSegmenter, stripTerminalSequences, truncateToWidth, visibleWidth } from "./utils.js";
|
|
3
|
+
const segmenter = getGraphemeSegmenter();
|
|
4
|
+
function appendMappedText(text, span, corpus) {
|
|
5
|
+
corpus.text += text;
|
|
6
|
+
for (let index = 0; index < text.length; index++)
|
|
7
|
+
corpus.source.push(span);
|
|
8
|
+
}
|
|
9
|
+
function buildSearchCorpus(lines) {
|
|
10
|
+
const corpus = { text: "", source: [] };
|
|
11
|
+
let pendingSeparator = false;
|
|
12
|
+
for (let row = 0; row < lines.length; row++) {
|
|
13
|
+
const line = stripTerminalSequences(lines[row] ?? "");
|
|
14
|
+
let column = 0;
|
|
15
|
+
for (const grapheme of segmenter.segment(line)) {
|
|
16
|
+
const text = grapheme.segment;
|
|
17
|
+
const width = visibleWidth(text);
|
|
18
|
+
if (/^\s+$/u.test(text)) {
|
|
19
|
+
if (corpus.text.length > 0)
|
|
20
|
+
pendingSeparator = true;
|
|
21
|
+
column += width;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (pendingSeparator) {
|
|
25
|
+
appendMappedText(" ", undefined, corpus);
|
|
26
|
+
pendingSeparator = false;
|
|
27
|
+
}
|
|
28
|
+
appendMappedText(text, { row, startCol: column, endCol: column + width }, corpus);
|
|
29
|
+
column += width;
|
|
30
|
+
}
|
|
31
|
+
if (corpus.text.length > 0)
|
|
32
|
+
pendingSeparator = true;
|
|
33
|
+
}
|
|
34
|
+
return corpus;
|
|
35
|
+
}
|
|
36
|
+
function normalizeQuery(query) {
|
|
37
|
+
return query.replace(/\s+/gu, " ").trim();
|
|
38
|
+
}
|
|
39
|
+
function escapeRegExp(text) {
|
|
40
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
41
|
+
}
|
|
42
|
+
export function findAltScreenSearchMatches(lines, query) {
|
|
43
|
+
const normalizedQuery = normalizeQuery(query);
|
|
44
|
+
if (!normalizedQuery)
|
|
45
|
+
return [];
|
|
46
|
+
const corpus = buildSearchCorpus(lines);
|
|
47
|
+
const expression = new RegExp(escapeRegExp(normalizedQuery), "giu");
|
|
48
|
+
const matches = [];
|
|
49
|
+
for (const match of corpus.text.matchAll(expression)) {
|
|
50
|
+
const start = match.index;
|
|
51
|
+
const end = start + match[0].length;
|
|
52
|
+
const segments = [];
|
|
53
|
+
for (let index = start; index < end; index++) {
|
|
54
|
+
const span = corpus.source[index];
|
|
55
|
+
if (!span)
|
|
56
|
+
continue;
|
|
57
|
+
const previous = segments[segments.length - 1];
|
|
58
|
+
if (previous && previous.row === span.row && span.startCol <= previous.endCol) {
|
|
59
|
+
previous.endCol = Math.max(previous.endCol, span.endCol);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
segments.push({ ...span });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (segments.length > 0)
|
|
66
|
+
matches.push({ segments });
|
|
67
|
+
}
|
|
68
|
+
return matches;
|
|
69
|
+
}
|
|
70
|
+
export function getAltScreenSearchMatchKey(match) {
|
|
71
|
+
const first = match.segments[0];
|
|
72
|
+
const last = match.segments[match.segments.length - 1];
|
|
73
|
+
return first && last ? `${first.row}:${first.startCol}:${last.row}:${last.endCol}` : "";
|
|
74
|
+
}
|
|
75
|
+
export class AltScreenSearchComponent {
|
|
76
|
+
constructor(onQueryChange) {
|
|
77
|
+
this.input = new Input();
|
|
78
|
+
this.resultCount = 0;
|
|
79
|
+
this.resultIndex = -1;
|
|
80
|
+
this._focused = false;
|
|
81
|
+
this.onQueryChange = onQueryChange;
|
|
82
|
+
}
|
|
83
|
+
get focused() {
|
|
84
|
+
return this._focused;
|
|
85
|
+
}
|
|
86
|
+
set focused(value) {
|
|
87
|
+
this._focused = value;
|
|
88
|
+
this.input.focused = value;
|
|
89
|
+
}
|
|
90
|
+
setResult(index, count) {
|
|
91
|
+
this.resultIndex = index;
|
|
92
|
+
this.resultCount = count;
|
|
93
|
+
}
|
|
94
|
+
handleInput(data) {
|
|
95
|
+
const previous = this.input.getValue();
|
|
96
|
+
this.input.handleInput(data);
|
|
97
|
+
const query = this.input.getValue();
|
|
98
|
+
if (query !== previous)
|
|
99
|
+
this.onQueryChange(query);
|
|
100
|
+
}
|
|
101
|
+
invalidate() {
|
|
102
|
+
this.input.invalidate();
|
|
103
|
+
}
|
|
104
|
+
render(width) {
|
|
105
|
+
const safeWidth = Math.max(1, width);
|
|
106
|
+
const label = " Find transcript";
|
|
107
|
+
const query = this.input.getValue();
|
|
108
|
+
const status = !query
|
|
109
|
+
? ""
|
|
110
|
+
: this.resultCount === 0
|
|
111
|
+
? "No matches "
|
|
112
|
+
: `${this.resultIndex + 1}/${this.resultCount} `;
|
|
113
|
+
const labelWidth = visibleWidth(label);
|
|
114
|
+
const statusWidth = visibleWidth(status);
|
|
115
|
+
const gap = " ".repeat(Math.max(1, safeWidth - labelWidth - statusWidth));
|
|
116
|
+
const title = truncateToWidth(`${label}${gap}${status}`, safeWidth, "");
|
|
117
|
+
const padding = " ".repeat(Math.max(0, safeWidth - visibleWidth(title)));
|
|
118
|
+
return [`\x1b[7m${title}${padding}\x1b[27m`, ...this.input.render(safeWidth)];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=alt-screen-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alt-screen-search.js","sourceRoot":"","sources":["../src/alt-screen-search.ts"],"names":[],"mappings":"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","sourcesContent":["import { Input } from \"./components/input.ts\";\nimport type { Component, Focusable } from \"./tui.ts\";\nimport { getGraphemeSegmenter, stripTerminalSequences, truncateToWidth, visibleWidth } from \"./utils.ts\";\n\nconst segmenter = getGraphemeSegmenter();\n\ninterface SearchSourceSpan {\n\trow: number;\n\tstartCol: number;\n\tendCol: number;\n}\n\nexport interface AltScreenSearchSegment {\n\trow: number;\n\tstartCol: number;\n\tendCol: number;\n}\n\nexport interface AltScreenSearchMatch {\n\tsegments: AltScreenSearchSegment[];\n}\n\nfunction appendMappedText(\n\ttext: string,\n\tspan: SearchSourceSpan | undefined,\n\tcorpus: { text: string; source: Array<SearchSourceSpan | undefined> },\n): void {\n\tcorpus.text += text;\n\tfor (let index = 0; index < text.length; index++) corpus.source.push(span);\n}\n\nfunction buildSearchCorpus(lines: readonly string[]): {\n\ttext: string;\n\tsource: Array<SearchSourceSpan | undefined>;\n} {\n\tconst corpus: { text: string; source: Array<SearchSourceSpan | undefined> } = { text: \"\", source: [] };\n\tlet pendingSeparator = false;\n\n\tfor (let row = 0; row < lines.length; row++) {\n\t\tconst line = stripTerminalSequences(lines[row] ?? \"\");\n\t\tlet column = 0;\n\t\tfor (const grapheme of segmenter.segment(line)) {\n\t\t\tconst text = grapheme.segment;\n\t\t\tconst width = visibleWidth(text);\n\t\t\tif (/^\\s+$/u.test(text)) {\n\t\t\t\tif (corpus.text.length > 0) pendingSeparator = true;\n\t\t\t\tcolumn += width;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (pendingSeparator) {\n\t\t\t\tappendMappedText(\" \", undefined, corpus);\n\t\t\t\tpendingSeparator = false;\n\t\t\t}\n\t\t\tappendMappedText(text, { row, startCol: column, endCol: column + width }, corpus);\n\t\t\tcolumn += width;\n\t\t}\n\t\tif (corpus.text.length > 0) pendingSeparator = true;\n\t}\n\n\treturn corpus;\n}\n\nfunction normalizeQuery(query: string): string {\n\treturn query.replace(/\\s+/gu, \" \").trim();\n}\n\nfunction escapeRegExp(text: string): string {\n\treturn text.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nexport function findAltScreenSearchMatches(lines: readonly string[], query: string): AltScreenSearchMatch[] {\n\tconst normalizedQuery = normalizeQuery(query);\n\tif (!normalizedQuery) return [];\n\n\tconst corpus = buildSearchCorpus(lines);\n\tconst expression = new RegExp(escapeRegExp(normalizedQuery), \"giu\");\n\tconst matches: AltScreenSearchMatch[] = [];\n\n\tfor (const match of corpus.text.matchAll(expression)) {\n\t\tconst start = match.index;\n\t\tconst end = start + match[0].length;\n\t\tconst segments: AltScreenSearchSegment[] = [];\n\t\tfor (let index = start; index < end; index++) {\n\t\t\tconst span = corpus.source[index];\n\t\t\tif (!span) continue;\n\t\t\tconst previous = segments[segments.length - 1];\n\t\t\tif (previous && previous.row === span.row && span.startCol <= previous.endCol) {\n\t\t\t\tprevious.endCol = Math.max(previous.endCol, span.endCol);\n\t\t\t} else {\n\t\t\t\tsegments.push({ ...span });\n\t\t\t}\n\t\t}\n\t\tif (segments.length > 0) matches.push({ segments });\n\t}\n\n\treturn matches;\n}\n\nexport function getAltScreenSearchMatchKey(match: AltScreenSearchMatch): string {\n\tconst first = match.segments[0];\n\tconst last = match.segments[match.segments.length - 1];\n\treturn first && last ? `${first.row}:${first.startCol}:${last.row}:${last.endCol}` : \"\";\n}\n\nexport class AltScreenSearchComponent implements Component, Focusable {\n\tprivate readonly input = new Input();\n\tprivate readonly onQueryChange: (query: string) => void;\n\tprivate resultCount = 0;\n\tprivate resultIndex = -1;\n\tprivate _focused = false;\n\n\tconstructor(onQueryChange: (query: string) => void) {\n\t\tthis.onQueryChange = onQueryChange;\n\t}\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.input.focused = value;\n\t}\n\n\tsetResult(index: number, count: number): void {\n\t\tthis.resultIndex = index;\n\t\tthis.resultCount = count;\n\t}\n\n\thandleInput(data: string): void {\n\t\tconst previous = this.input.getValue();\n\t\tthis.input.handleInput(data);\n\t\tconst query = this.input.getValue();\n\t\tif (query !== previous) this.onQueryChange(query);\n\t}\n\n\tinvalidate(): void {\n\t\tthis.input.invalidate();\n\t}\n\n\trender(width: number): string[] {\n\t\tconst safeWidth = Math.max(1, width);\n\t\tconst label = \" Find transcript\";\n\t\tconst query = this.input.getValue();\n\t\tconst status = !query\n\t\t\t? \"\"\n\t\t\t: this.resultCount === 0\n\t\t\t\t? \"No matches \"\n\t\t\t\t: `${this.resultIndex + 1}/${this.resultCount} `;\n\t\tconst labelWidth = visibleWidth(label);\n\t\tconst statusWidth = visibleWidth(status);\n\t\tconst gap = \" \".repeat(Math.max(1, safeWidth - labelWidth - statusWidth));\n\t\tconst title = truncateToWidth(`${label}${gap}${status}`, safeWidth, \"\");\n\t\tconst padding = \" \".repeat(Math.max(0, safeWidth - visibleWidth(title)));\n\t\treturn [`\\x1b[7m${title}${padding}\\x1b[27m`, ...this.input.render(safeWidth)];\n\t}\n}\n"]}
|
|
@@ -10,6 +10,10 @@ export interface ScrollViewOptions {
|
|
|
10
10
|
scrollbarStyle?: (text: string) => string;
|
|
11
11
|
scrollbarHideDelayMs?: number;
|
|
12
12
|
}
|
|
13
|
+
export interface ScrollViewScrollToOptions {
|
|
14
|
+
/** Keep follow-end disabled even when the target is the current content end. */
|
|
15
|
+
disableFollow?: boolean;
|
|
16
|
+
}
|
|
13
17
|
export declare class ScrollView extends Container {
|
|
14
18
|
private readonly child;
|
|
15
19
|
private readonly followEnd;
|
|
@@ -22,6 +26,7 @@ export declare class ScrollView extends Container {
|
|
|
22
26
|
private contentHeight;
|
|
23
27
|
private currentViewportHeight;
|
|
24
28
|
private followingEnd;
|
|
29
|
+
private followSuppressedAtEnd;
|
|
25
30
|
private requestRenderCallback;
|
|
26
31
|
private transientScrollbarVisible;
|
|
27
32
|
private scrollbarActive;
|
|
@@ -37,7 +42,7 @@ export declare class ScrollView extends Container {
|
|
|
37
42
|
private markScrollbarActivity;
|
|
38
43
|
private hideTransientScrollbar;
|
|
39
44
|
setScrollbarActive(active: boolean): void;
|
|
40
|
-
scrollTo(scrollTop: number): void;
|
|
45
|
+
scrollTo(scrollTop: number, options?: ScrollViewScrollToOptions): void;
|
|
41
46
|
scrollBy(lines: number): number;
|
|
42
47
|
scrollToStart(): void;
|
|
43
48
|
scrollToEnd(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-view.d.ts","sourceRoot":"","sources":["../../src/components/scroll-view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE/D,MAAM,WAAW,iBAAiB;IACjC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,qBAAa,UAAW,SAAQ,SAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,OAAO,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAC9C,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,qBAAqB,CAA2B;IACxD,OAAO,CAAC,yBAAyB,CAAS;IAC1C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,kBAAkB,CAA6B;gBAE3C,SAAS,EAAE,SAAS,EAAE,OAAO,GAAE,iBAAsB;IAgBjE,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,SAAS,IAAI,mBAAmB,CAEnC;IAED,IAAI,kBAAkB,IAAI,OAAO,CAKhC;IAED,YAAY,CAAC,SAAS,EAAE,mBAAmB,GAAG,IAAI;IAQlD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAItC,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,sBAAsB;IAO9B,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAMzC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"scroll-view.d.ts","sourceRoot":"","sources":["../../src/components/scroll-view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE/D,MAAM,WAAW,iBAAiB;IACjC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC1C,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,yBAAyB;IACzC,gFAAgF;IAChF,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,qBAAa,UAAW,SAAQ,SAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,OAAO,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAC9C,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,qBAAqB,CAAS;IACtC,OAAO,CAAC,qBAAqB,CAA2B;IACxD,OAAO,CAAC,yBAAyB,CAAS;IAC1C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,kBAAkB,CAA6B;gBAE3C,SAAS,EAAE,SAAS,EAAE,OAAO,GAAE,iBAAsB;IAgBjE,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,SAAS,IAAI,mBAAmB,CAEnC;IAED,IAAI,kBAAkB,IAAI,OAAO,CAKhC;IAED,YAAY,CAAC,SAAS,EAAE,mBAAmB,GAAG,IAAI;IAQlD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAItC,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,sBAAsB;IAO9B,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAMzC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,yBAA8B,GAAG,IAAI;IAqB1E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAgB/B,aAAa,IAAI,IAAI;IAarB,WAAW,IAAI,IAAI;IAYnB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,IAAI,GAAG,IAAI;IAcnF,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,IAAI;IAIrC,WAAW,CAAC,UAAU,EAAE,SAAS,GAAG,IAAI;IAIxC,KAAK,IAAI,IAAI;IAIb,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAMxC,CAAC,WAAW,CAAC,IAAI,gBAAgB;CAGjC"}
|
|
@@ -6,6 +6,7 @@ export class ScrollView extends Container {
|
|
|
6
6
|
this.currentScrollTop = 0;
|
|
7
7
|
this.contentHeight = 0;
|
|
8
8
|
this.currentViewportHeight = 0;
|
|
9
|
+
this.followSuppressedAtEnd = false;
|
|
9
10
|
this.transientScrollbarVisible = false;
|
|
10
11
|
this.scrollbarActive = false;
|
|
11
12
|
if (options.axis !== undefined && options.axis !== "vertical") {
|
|
@@ -81,15 +82,23 @@ export class ScrollView extends Container {
|
|
|
81
82
|
this.scrollbarActive = active;
|
|
82
83
|
this.markScrollbarActivity();
|
|
83
84
|
}
|
|
84
|
-
scrollTo(scrollTop) {
|
|
85
|
+
scrollTo(scrollTop, options = {}) {
|
|
85
86
|
const requested = Number.isFinite(scrollTop) ? Math.trunc(scrollTop) : this.currentScrollTop;
|
|
86
87
|
const maxScrollTop = Math.max(0, this.contentHeight - this.currentViewportHeight);
|
|
87
88
|
const next = Math.max(0, Math.min(maxScrollTop, requested));
|
|
88
|
-
|
|
89
|
+
const nextFollowSuppressedAtEnd = options.disableFollow === true && next === maxScrollTop;
|
|
90
|
+
const nextFollowingEnd = !nextFollowSuppressedAtEnd && this.followEnd && next === maxScrollTop;
|
|
91
|
+
if (next === this.currentScrollTop &&
|
|
92
|
+
nextFollowingEnd === this.followingEnd &&
|
|
93
|
+
nextFollowSuppressedAtEnd === this.followSuppressedAtEnd) {
|
|
89
94
|
return;
|
|
95
|
+
}
|
|
96
|
+
const moved = next !== this.currentScrollTop;
|
|
90
97
|
this.currentScrollTop = next;
|
|
91
|
-
this.followingEnd =
|
|
92
|
-
this.
|
|
98
|
+
this.followingEnd = nextFollowingEnd;
|
|
99
|
+
this.followSuppressedAtEnd = nextFollowSuppressedAtEnd;
|
|
100
|
+
if (moved)
|
|
101
|
+
this.markScrollbarActivity();
|
|
93
102
|
this.requestRenderCallback?.();
|
|
94
103
|
}
|
|
95
104
|
scrollBy(lines) {
|
|
@@ -100,12 +109,14 @@ export class ScrollView extends Container {
|
|
|
100
109
|
const start = this.followingEnd ? maxScrollTop : this.currentScrollTop;
|
|
101
110
|
const next = Math.max(0, Math.min(maxScrollTop, start + requested));
|
|
102
111
|
const moved = next - start;
|
|
112
|
+
const wasFollowingEnd = this.followingEnd;
|
|
103
113
|
this.currentScrollTop = next;
|
|
104
114
|
this.followingEnd = this.followEnd && next === maxScrollTop;
|
|
105
|
-
|
|
115
|
+
this.followSuppressedAtEnd = false;
|
|
116
|
+
if (moved !== 0)
|
|
106
117
|
this.markScrollbarActivity();
|
|
118
|
+
if (moved !== 0 || this.followingEnd !== wasFollowingEnd)
|
|
107
119
|
this.requestRenderCallback?.();
|
|
108
|
-
}
|
|
109
120
|
return requested - moved;
|
|
110
121
|
}
|
|
111
122
|
scrollToStart() {
|
|
@@ -113,6 +124,7 @@ export class ScrollView extends Container {
|
|
|
113
124
|
this.followingEnd !== (this.followEnd && this.contentHeight <= this.currentViewportHeight);
|
|
114
125
|
this.currentScrollTop = 0;
|
|
115
126
|
this.followingEnd = this.followEnd && this.contentHeight <= this.currentViewportHeight;
|
|
127
|
+
this.followSuppressedAtEnd = false;
|
|
116
128
|
if (changed) {
|
|
117
129
|
this.markScrollbarActivity();
|
|
118
130
|
this.requestRenderCallback?.();
|
|
@@ -123,6 +135,7 @@ export class ScrollView extends Container {
|
|
|
123
135
|
const changed = this.currentScrollTop !== next || this.followingEnd !== this.followEnd;
|
|
124
136
|
this.currentScrollTop = next;
|
|
125
137
|
this.followingEnd = this.followEnd;
|
|
138
|
+
this.followSuppressedAtEnd = false;
|
|
126
139
|
if (changed) {
|
|
127
140
|
this.markScrollbarActivity();
|
|
128
141
|
this.requestRenderCallback?.();
|
|
@@ -137,8 +150,11 @@ export class ScrollView extends Container {
|
|
|
137
150
|
this.currentScrollTop = maxScrollTop;
|
|
138
151
|
else
|
|
139
152
|
this.currentScrollTop = Math.max(0, Math.min(this.currentScrollTop, maxScrollTop));
|
|
140
|
-
if (this.
|
|
153
|
+
if (this.currentScrollTop < maxScrollTop)
|
|
154
|
+
this.followSuppressedAtEnd = false;
|
|
155
|
+
if (this.followEnd && this.currentScrollTop === maxScrollTop && !this.followSuppressedAtEnd) {
|
|
141
156
|
this.followingEnd = true;
|
|
157
|
+
}
|
|
142
158
|
if (this.contentHeight <= this.currentViewportHeight)
|
|
143
159
|
this.hideTransientScrollbar();
|
|
144
160
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-view.js","sourceRoot":"","sources":["../../src/components/scroll-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { LAYOUT_NODE, type ScrollLayoutNode } from \"../layout-node.ts\";\nimport { type Component, Container } from \"../tui.ts\";\n\nexport type ScrollViewScrollbar = \"hidden\" | \"auto\" | \"always\";\n\nexport interface ScrollViewOptions {\n\taxis?: \"vertical\";\n\tfollow?: \"none\" | \"end\";\n\tprimary?: boolean;\n\toverscroll?: \"chain\" | \"contain\";\n\tscrollbar?: ScrollViewScrollbar;\n\tscrollbarStyle?: (text: string) => string;\n\tscrollbarHideDelayMs?: number;\n}\n\nexport class ScrollView extends Container {\n\tprivate readonly child: Component;\n\tprivate readonly followEnd: boolean;\n\treadonly primary: boolean;\n\treadonly overscroll: \"chain\" | \"contain\";\n\treadonly scrollbarStyle: (text: string) => string;\n\tprivate currentScrollbar: ScrollViewScrollbar;\n\tprivate readonly scrollbarHideDelayMs: number;\n\tprivate currentScrollTop = 0;\n\tprivate contentHeight = 0;\n\tprivate currentViewportHeight = 0;\n\tprivate followingEnd: boolean;\n\tprivate requestRenderCallback: (() => void) | undefined;\n\tprivate transientScrollbarVisible = false;\n\tprivate scrollbarActive = false;\n\tprivate scrollbarHideTimer: NodeJS.Timeout | undefined;\n\n\tconstructor(component: Component, options: ScrollViewOptions = {}) {\n\t\tsuper();\n\t\tif (options.axis !== undefined && options.axis !== \"vertical\") {\n\t\t\tthrow new Error(`Unsupported ScrollView axis: ${options.axis}`);\n\t\t}\n\t\tthis.child = component;\n\t\tthis.children.push(component);\n\t\tthis.followEnd = (options.follow ?? \"none\") === \"end\";\n\t\tthis.followingEnd = this.followEnd;\n\t\tthis.primary = options.primary ?? false;\n\t\tthis.overscroll = options.overscroll ?? \"chain\";\n\t\tthis.currentScrollbar = options.scrollbar ?? \"hidden\";\n\t\tthis.scrollbarStyle = options.scrollbarStyle ?? ((text) => `\\x1b[100m${text}\\x1b[49m`);\n\t\tthis.scrollbarHideDelayMs = Math.max(0, Math.floor(options.scrollbarHideDelayMs ?? 1000));\n\t}\n\n\tget scrollTop(): number {\n\t\treturn this.currentScrollTop;\n\t}\n\n\tget isFollowingEnd(): boolean {\n\t\treturn this.followingEnd;\n\t}\n\n\tget viewportHeight(): number {\n\t\treturn this.currentViewportHeight;\n\t}\n\n\tget scrollbar(): ScrollViewScrollbar {\n\t\treturn this.currentScrollbar;\n\t}\n\n\tget isScrollbarVisible(): boolean {\n\t\tif (this.scrollbar === \"always\") return this.currentViewportHeight > 0;\n\t\treturn (\n\t\t\tthis.scrollbar === \"auto\" && this.contentHeight > this.currentViewportHeight && this.transientScrollbarVisible\n\t\t);\n\t}\n\n\tsetScrollbar(scrollbar: ScrollViewScrollbar): void {\n\t\tif (scrollbar === this.currentScrollbar) return;\n\t\tthis.currentScrollbar = scrollbar;\n\t\tif (scrollbar !== \"auto\") this.hideTransientScrollbar();\n\t\telse if (this.scrollbarActive) this.markScrollbarActivity();\n\t\tthis.requestRenderCallback?.();\n\t}\n\n\tgetContentWidth(width: number): number {\n\t\treturn this.scrollbar === \"always\" && width > 1 ? width - 1 : width;\n\t}\n\n\tprivate markScrollbarActivity(): void {\n\t\tif (this.scrollbar !== \"auto\" || this.contentHeight <= this.currentViewportHeight) return;\n\t\tthis.transientScrollbarVisible = true;\n\t\tif (this.scrollbarHideTimer) {\n\t\t\tclearTimeout(this.scrollbarHideTimer);\n\t\t\tthis.scrollbarHideTimer = undefined;\n\t\t}\n\t\tif (this.scrollbarActive) return;\n\t\tthis.scrollbarHideTimer = setTimeout(() => {\n\t\t\tthis.scrollbarHideTimer = undefined;\n\t\t\tthis.transientScrollbarVisible = false;\n\t\t\tthis.requestRenderCallback?.();\n\t\t}, this.scrollbarHideDelayMs);\n\t\tthis.scrollbarHideTimer.unref();\n\t}\n\n\tprivate hideTransientScrollbar(): void {\n\t\tthis.transientScrollbarVisible = false;\n\t\tif (!this.scrollbarHideTimer) return;\n\t\tclearTimeout(this.scrollbarHideTimer);\n\t\tthis.scrollbarHideTimer = undefined;\n\t}\n\n\tsetScrollbarActive(active: boolean): void {\n\t\tif (active === this.scrollbarActive) return;\n\t\tthis.scrollbarActive = active;\n\t\tthis.markScrollbarActivity();\n\t}\n\n\tscrollTo(scrollTop: number): void {\n\t\tconst requested = Number.isFinite(scrollTop) ? Math.trunc(scrollTop) : this.currentScrollTop;\n\t\tconst maxScrollTop = Math.max(0, this.contentHeight - this.currentViewportHeight);\n\t\tconst next = Math.max(0, Math.min(maxScrollTop, requested));\n\t\tif (next === this.currentScrollTop) return;\n\t\tthis.currentScrollTop = next;\n\t\tthis.followingEnd = this.followEnd && next === maxScrollTop;\n\t\tthis.markScrollbarActivity();\n\t\tthis.requestRenderCallback?.();\n\t}\n\n\tscrollBy(lines: number): number {\n\t\tconst requested = Number.isFinite(lines) ? Math.trunc(lines) : 0;\n\t\tif (requested === 0) return 0;\n\t\tconst maxScrollTop = Math.max(0, this.contentHeight - this.currentViewportHeight);\n\t\tconst start = this.followingEnd ? maxScrollTop : this.currentScrollTop;\n\t\tconst next = Math.max(0, Math.min(maxScrollTop, start + requested));\n\t\tconst moved = next - start;\n\t\tthis.currentScrollTop = next;\n\t\tthis.followingEnd = this.followEnd && next === maxScrollTop;\n\t\tif (moved !== 0) {\n\t\t\tthis.markScrollbarActivity();\n\t\t\tthis.requestRenderCallback?.();\n\t\t}\n\t\treturn requested - moved;\n\t}\n\n\tscrollToStart(): void {\n\t\tconst changed =\n\t\t\tthis.currentScrollTop !== 0 ||\n\t\t\tthis.followingEnd !== (this.followEnd && this.contentHeight <= this.currentViewportHeight);\n\t\tthis.currentScrollTop = 0;\n\t\tthis.followingEnd = this.followEnd && this.contentHeight <= this.currentViewportHeight;\n\t\tif (changed) {\n\t\t\tthis.markScrollbarActivity();\n\t\t\tthis.requestRenderCallback?.();\n\t\t}\n\t}\n\n\tscrollToEnd(): void {\n\t\tconst next = Math.max(0, this.contentHeight - this.currentViewportHeight);\n\t\tconst changed = this.currentScrollTop !== next || this.followingEnd !== this.followEnd;\n\t\tthis.currentScrollTop = next;\n\t\tthis.followingEnd = this.followEnd;\n\t\tif (changed) {\n\t\t\tthis.markScrollbarActivity();\n\t\t\tthis.requestRenderCallback?.();\n\t\t}\n\t}\n\n\tupdateLayout(contentHeight: number, viewportHeight: number, requestRender: () => void): void {\n\t\tthis.contentHeight = Math.max(0, Math.floor(contentHeight));\n\t\tthis.currentViewportHeight = Math.max(0, Math.floor(viewportHeight));\n\t\tthis.requestRenderCallback = requestRender;\n\t\tconst maxScrollTop = Math.max(0, this.contentHeight - this.currentViewportHeight);\n\t\tif (this.followingEnd) this.currentScrollTop = maxScrollTop;\n\t\telse this.currentScrollTop = Math.max(0, Math.min(this.currentScrollTop, maxScrollTop));\n\t\tif (this.followEnd && this.currentScrollTop === maxScrollTop) this.followingEnd = true;\n\t\tif (this.contentHeight <= this.currentViewportHeight) this.hideTransientScrollbar();\n\t}\n\n\toverride addChild(_component: Component): void {\n\t\tthrow new Error(\"ScrollView has exactly one child\");\n\t}\n\n\toverride removeChild(_component: Component): void {\n\t\tthrow new Error(\"ScrollView child cannot be removed\");\n\t}\n\n\toverride clear(): void {\n\t\tthrow new Error(\"ScrollView child cannot be cleared\");\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst contentWidth = this.getContentWidth(width);\n\t\tconst lines = this.child.render(contentWidth);\n\t\treturn contentWidth === width ? lines : lines.map((line) => `${line} `);\n\t}\n\n\t[LAYOUT_NODE](): ScrollLayoutNode {\n\t\treturn { type: \"scroll\", component: this.child, state: this };\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"scroll-view.js","sourceRoot":"","sources":["../../src/components/scroll-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { LAYOUT_NODE, type ScrollLayoutNode } from \"../layout-node.ts\";\nimport { type Component, Container } from \"../tui.ts\";\n\nexport type ScrollViewScrollbar = \"hidden\" | \"auto\" | \"always\";\n\nexport interface ScrollViewOptions {\n\taxis?: \"vertical\";\n\tfollow?: \"none\" | \"end\";\n\tprimary?: boolean;\n\toverscroll?: \"chain\" | \"contain\";\n\tscrollbar?: ScrollViewScrollbar;\n\tscrollbarStyle?: (text: string) => string;\n\tscrollbarHideDelayMs?: number;\n}\n\nexport interface ScrollViewScrollToOptions {\n\t/** Keep follow-end disabled even when the target is the current content end. */\n\tdisableFollow?: boolean;\n}\n\nexport class ScrollView extends Container {\n\tprivate readonly child: Component;\n\tprivate readonly followEnd: boolean;\n\treadonly primary: boolean;\n\treadonly overscroll: \"chain\" | \"contain\";\n\treadonly scrollbarStyle: (text: string) => string;\n\tprivate currentScrollbar: ScrollViewScrollbar;\n\tprivate readonly scrollbarHideDelayMs: number;\n\tprivate currentScrollTop = 0;\n\tprivate contentHeight = 0;\n\tprivate currentViewportHeight = 0;\n\tprivate followingEnd: boolean;\n\tprivate followSuppressedAtEnd = false;\n\tprivate requestRenderCallback: (() => void) | undefined;\n\tprivate transientScrollbarVisible = false;\n\tprivate scrollbarActive = false;\n\tprivate scrollbarHideTimer: NodeJS.Timeout | undefined;\n\n\tconstructor(component: Component, options: ScrollViewOptions = {}) {\n\t\tsuper();\n\t\tif (options.axis !== undefined && options.axis !== \"vertical\") {\n\t\t\tthrow new Error(`Unsupported ScrollView axis: ${options.axis}`);\n\t\t}\n\t\tthis.child = component;\n\t\tthis.children.push(component);\n\t\tthis.followEnd = (options.follow ?? \"none\") === \"end\";\n\t\tthis.followingEnd = this.followEnd;\n\t\tthis.primary = options.primary ?? false;\n\t\tthis.overscroll = options.overscroll ?? \"chain\";\n\t\tthis.currentScrollbar = options.scrollbar ?? \"hidden\";\n\t\tthis.scrollbarStyle = options.scrollbarStyle ?? ((text) => `\\x1b[100m${text}\\x1b[49m`);\n\t\tthis.scrollbarHideDelayMs = Math.max(0, Math.floor(options.scrollbarHideDelayMs ?? 1000));\n\t}\n\n\tget scrollTop(): number {\n\t\treturn this.currentScrollTop;\n\t}\n\n\tget isFollowingEnd(): boolean {\n\t\treturn this.followingEnd;\n\t}\n\n\tget viewportHeight(): number {\n\t\treturn this.currentViewportHeight;\n\t}\n\n\tget scrollbar(): ScrollViewScrollbar {\n\t\treturn this.currentScrollbar;\n\t}\n\n\tget isScrollbarVisible(): boolean {\n\t\tif (this.scrollbar === \"always\") return this.currentViewportHeight > 0;\n\t\treturn (\n\t\t\tthis.scrollbar === \"auto\" && this.contentHeight > this.currentViewportHeight && this.transientScrollbarVisible\n\t\t);\n\t}\n\n\tsetScrollbar(scrollbar: ScrollViewScrollbar): void {\n\t\tif (scrollbar === this.currentScrollbar) return;\n\t\tthis.currentScrollbar = scrollbar;\n\t\tif (scrollbar !== \"auto\") this.hideTransientScrollbar();\n\t\telse if (this.scrollbarActive) this.markScrollbarActivity();\n\t\tthis.requestRenderCallback?.();\n\t}\n\n\tgetContentWidth(width: number): number {\n\t\treturn this.scrollbar === \"always\" && width > 1 ? width - 1 : width;\n\t}\n\n\tprivate markScrollbarActivity(): void {\n\t\tif (this.scrollbar !== \"auto\" || this.contentHeight <= this.currentViewportHeight) return;\n\t\tthis.transientScrollbarVisible = true;\n\t\tif (this.scrollbarHideTimer) {\n\t\t\tclearTimeout(this.scrollbarHideTimer);\n\t\t\tthis.scrollbarHideTimer = undefined;\n\t\t}\n\t\tif (this.scrollbarActive) return;\n\t\tthis.scrollbarHideTimer = setTimeout(() => {\n\t\t\tthis.scrollbarHideTimer = undefined;\n\t\t\tthis.transientScrollbarVisible = false;\n\t\t\tthis.requestRenderCallback?.();\n\t\t}, this.scrollbarHideDelayMs);\n\t\tthis.scrollbarHideTimer.unref();\n\t}\n\n\tprivate hideTransientScrollbar(): void {\n\t\tthis.transientScrollbarVisible = false;\n\t\tif (!this.scrollbarHideTimer) return;\n\t\tclearTimeout(this.scrollbarHideTimer);\n\t\tthis.scrollbarHideTimer = undefined;\n\t}\n\n\tsetScrollbarActive(active: boolean): void {\n\t\tif (active === this.scrollbarActive) return;\n\t\tthis.scrollbarActive = active;\n\t\tthis.markScrollbarActivity();\n\t}\n\n\tscrollTo(scrollTop: number, options: ScrollViewScrollToOptions = {}): void {\n\t\tconst requested = Number.isFinite(scrollTop) ? Math.trunc(scrollTop) : this.currentScrollTop;\n\t\tconst maxScrollTop = Math.max(0, this.contentHeight - this.currentViewportHeight);\n\t\tconst next = Math.max(0, Math.min(maxScrollTop, requested));\n\t\tconst nextFollowSuppressedAtEnd = options.disableFollow === true && next === maxScrollTop;\n\t\tconst nextFollowingEnd = !nextFollowSuppressedAtEnd && this.followEnd && next === maxScrollTop;\n\t\tif (\n\t\t\tnext === this.currentScrollTop &&\n\t\t\tnextFollowingEnd === this.followingEnd &&\n\t\t\tnextFollowSuppressedAtEnd === this.followSuppressedAtEnd\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tconst moved = next !== this.currentScrollTop;\n\t\tthis.currentScrollTop = next;\n\t\tthis.followingEnd = nextFollowingEnd;\n\t\tthis.followSuppressedAtEnd = nextFollowSuppressedAtEnd;\n\t\tif (moved) this.markScrollbarActivity();\n\t\tthis.requestRenderCallback?.();\n\t}\n\n\tscrollBy(lines: number): number {\n\t\tconst requested = Number.isFinite(lines) ? Math.trunc(lines) : 0;\n\t\tif (requested === 0) return 0;\n\t\tconst maxScrollTop = Math.max(0, this.contentHeight - this.currentViewportHeight);\n\t\tconst start = this.followingEnd ? maxScrollTop : this.currentScrollTop;\n\t\tconst next = Math.max(0, Math.min(maxScrollTop, start + requested));\n\t\tconst moved = next - start;\n\t\tconst wasFollowingEnd = this.followingEnd;\n\t\tthis.currentScrollTop = next;\n\t\tthis.followingEnd = this.followEnd && next === maxScrollTop;\n\t\tthis.followSuppressedAtEnd = false;\n\t\tif (moved !== 0) this.markScrollbarActivity();\n\t\tif (moved !== 0 || this.followingEnd !== wasFollowingEnd) this.requestRenderCallback?.();\n\t\treturn requested - moved;\n\t}\n\n\tscrollToStart(): void {\n\t\tconst changed =\n\t\t\tthis.currentScrollTop !== 0 ||\n\t\t\tthis.followingEnd !== (this.followEnd && this.contentHeight <= this.currentViewportHeight);\n\t\tthis.currentScrollTop = 0;\n\t\tthis.followingEnd = this.followEnd && this.contentHeight <= this.currentViewportHeight;\n\t\tthis.followSuppressedAtEnd = false;\n\t\tif (changed) {\n\t\t\tthis.markScrollbarActivity();\n\t\t\tthis.requestRenderCallback?.();\n\t\t}\n\t}\n\n\tscrollToEnd(): void {\n\t\tconst next = Math.max(0, this.contentHeight - this.currentViewportHeight);\n\t\tconst changed = this.currentScrollTop !== next || this.followingEnd !== this.followEnd;\n\t\tthis.currentScrollTop = next;\n\t\tthis.followingEnd = this.followEnd;\n\t\tthis.followSuppressedAtEnd = false;\n\t\tif (changed) {\n\t\t\tthis.markScrollbarActivity();\n\t\t\tthis.requestRenderCallback?.();\n\t\t}\n\t}\n\n\tupdateLayout(contentHeight: number, viewportHeight: number, requestRender: () => void): void {\n\t\tthis.contentHeight = Math.max(0, Math.floor(contentHeight));\n\t\tthis.currentViewportHeight = Math.max(0, Math.floor(viewportHeight));\n\t\tthis.requestRenderCallback = requestRender;\n\t\tconst maxScrollTop = Math.max(0, this.contentHeight - this.currentViewportHeight);\n\t\tif (this.followingEnd) this.currentScrollTop = maxScrollTop;\n\t\telse this.currentScrollTop = Math.max(0, Math.min(this.currentScrollTop, maxScrollTop));\n\t\tif (this.currentScrollTop < maxScrollTop) this.followSuppressedAtEnd = false;\n\t\tif (this.followEnd && this.currentScrollTop === maxScrollTop && !this.followSuppressedAtEnd) {\n\t\t\tthis.followingEnd = true;\n\t\t}\n\t\tif (this.contentHeight <= this.currentViewportHeight) this.hideTransientScrollbar();\n\t}\n\n\toverride addChild(_component: Component): void {\n\t\tthrow new Error(\"ScrollView has exactly one child\");\n\t}\n\n\toverride removeChild(_component: Component): void {\n\t\tthrow new Error(\"ScrollView child cannot be removed\");\n\t}\n\n\toverride clear(): void {\n\t\tthrow new Error(\"ScrollView child cannot be cleared\");\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst contentWidth = this.getContentWidth(width);\n\t\tconst lines = this.child.render(contentWidth);\n\t\treturn contentWidth === width ? lines : lines.map((line) => `${line} `);\n\t}\n\n\t[LAYOUT_NODE](): ScrollLayoutNode {\n\t\treturn { type: \"scroll\", component: this.child, state: this };\n\t}\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { CellDimensions, ImageDimensions } from "./terminal-image.ts";
|
|
1
2
|
export { Marked, type Token, type Tokens } from "marked";
|
|
3
|
+
export { AltScreenSearchComponent, type AltScreenSearchMatch, type AltScreenSearchSegment, findAltScreenSearchMatches, getAltScreenSearchMatchKey, } from "./alt-screen-search.ts";
|
|
2
4
|
export { type AutocompleteItem, type AutocompleteProvider, type AutocompleteSuggestions, CombinedAutocompleteProvider, type SlashCommand, } from "./autocomplete.ts";
|
|
3
5
|
export { Box } from "./components/box.ts";
|
|
4
6
|
export { CancellableLoader } from "./components/cancellable-loader.ts";
|
|
@@ -8,7 +10,7 @@ export { Image, type ImageOptions, type ImageTheme } from "./components/image.ts
|
|
|
8
10
|
export { Input } from "./components/input.ts";
|
|
9
11
|
export { Loader, type LoaderIndicatorOptions } from "./components/loader.ts";
|
|
10
12
|
export { clearRenderCache, type DefaultTextStyle, getMarkdownHighlightCallCount, Markdown, type MarkdownOptions, type MarkdownTheme, resetMarkdownHighlightCallCount, } from "./components/markdown.ts";
|
|
11
|
-
export { ScrollView, type ScrollViewOptions, type ScrollViewScrollbar } from "./components/scroll-view.ts";
|
|
13
|
+
export { ScrollView, type ScrollViewOptions, type ScrollViewScrollbar, type ScrollViewScrollToOptions, } from "./components/scroll-view.ts";
|
|
12
14
|
export { type SelectItem, SelectList, type SelectListLayoutOptions, type SelectListRenderRow, type SelectListRowParts, type SelectListTheme, type SelectListTruncatePrimaryContext, } from "./components/select-list.ts";
|
|
13
15
|
export { type SettingItem, SettingsList, type SettingsListTheme } from "./components/settings-list.ts";
|
|
14
16
|
export { Spacer } from "./components/spacer.ts";
|
|
@@ -23,6 +25,7 @@ export { type EditorPasteState, expandPasteMarkers } from "./paste-markers.ts";
|
|
|
23
25
|
export { StdinBuffer, type StdinBufferEventMap, type StdinBufferOptions } from "./stdin-buffer.ts";
|
|
24
26
|
export { ProcessTerminal, type ProcessTerminalOptions, type Terminal } from "./terminal.ts";
|
|
25
27
|
export { parseOsc11BackgroundColor, parseTerminalColorSchemeReport, type RgbColor, type TerminalColorScheme, } from "./terminal-colors.ts";
|
|
28
|
+
export declare function calculateImageRows(imageDimensions: ImageDimensions, targetWidthCells: number, cellDimensions?: CellDimensions): number;
|
|
26
29
|
export { allocateImageId, buildKittyPlaceholderRow, type CellDimensions, deleteAllKittyImages, deleteKittyImage, detectCapabilities, encodeITerm2, encodeKitty, getCapabilities, getCellDimensions, getGifDimensions, getImageDimensions, getJpegDimensions, getPngDimensions, getWebpDimensions, hyperlink, type ImageDimensions, type ImageProtocol, type ImageRenderOptions, imageFallback, KITTY_PLACEHOLDER_MAX, outerKittyGraphicsMode, renderImage, resetCapabilitiesCache, setCapabilities, setCellDimensions, type TerminalCapabilities, type TmuxPassthroughState, wrapTmuxPassthrough, } from "./terminal-image.ts";
|
|
27
30
|
export { sanitizeTerminalLabel, shortenImagePath } from "./terminal-text.ts";
|
|
28
31
|
export { type Component, Container, CURSOR_MARKER, compositeTuiLine, type Focusable, isFocusable, isViewportTUI, type OverlayAnchor, type OverlayHandle, type OverlayMargin, type OverlayOptions, type OverlayUnfocusOptions, type SizeValue, TUI, type TuiInputListener, type TuiInputListenerResult, type TuiMode, type TuiStopOptions, type ViewportTUI, } from "./tui.ts";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,KAAK,KAAK,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEzD,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,4BAA4B,EAC5B,KAAK,YAAY,GACjB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EACN,MAAM,EACN,KAAK,aAAa,EAClB,KAAK,WAAW,GAChB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EACN,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,6BAA6B,EAC7B,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,+BAA+B,GAC/B,MAAM,0BAA0B,CAAC;AAClC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// Core TUI interfaces and classes
|
|
2
|
+
import { calculateImageCellSize } from "./terminal-image.js";
|
|
2
3
|
export { Marked } from "marked";
|
|
4
|
+
// Fullscreen transcript search
|
|
5
|
+
export { AltScreenSearchComponent, findAltScreenSearchMatches, getAltScreenSearchMatchKey, } from "./alt-screen-search.js";
|
|
3
6
|
// Autocomplete support
|
|
4
7
|
export { CombinedAutocompleteProvider, } from "./autocomplete.js";
|
|
5
8
|
// Components
|
|
@@ -11,7 +14,7 @@ export { Image } from "./components/image.js";
|
|
|
11
14
|
export { Input } from "./components/input.js";
|
|
12
15
|
export { Loader } from "./components/loader.js";
|
|
13
16
|
export { clearRenderCache, getMarkdownHighlightCallCount, Markdown, resetMarkdownHighlightCallCount, } from "./components/markdown.js";
|
|
14
|
-
export { ScrollView } from "./components/scroll-view.js";
|
|
17
|
+
export { ScrollView, } from "./components/scroll-view.js";
|
|
15
18
|
export { SelectList, } from "./components/select-list.js";
|
|
16
19
|
export { SettingsList } from "./components/settings-list.js";
|
|
17
20
|
export { Spacer } from "./components/spacer.js";
|
|
@@ -32,6 +35,9 @@ export { ProcessTerminal } from "./terminal.js";
|
|
|
32
35
|
// Terminal colors
|
|
33
36
|
export { parseOsc11BackgroundColor, parseTerminalColorSchemeReport, } from "./terminal-colors.js";
|
|
34
37
|
// Terminal image support
|
|
38
|
+
export function calculateImageRows(imageDimensions, targetWidthCells, cellDimensions = { widthPx: 9, heightPx: 18 }) {
|
|
39
|
+
return calculateImageCellSize(imageDimensions, targetWidthCells, undefined, cellDimensions).rows;
|
|
40
|
+
}
|
|
35
41
|
export { allocateImageId, buildKittyPlaceholderRow, deleteAllKittyImages, deleteKittyImage, detectCapabilities, encodeITerm2, encodeKitty, getCapabilities, getCellDimensions, getGifDimensions, getImageDimensions, getJpegDimensions, getPngDimensions, getWebpDimensions, hyperlink, imageFallback, KITTY_PLACEHOLDER_MAX, outerKittyGraphicsMode, renderImage, resetCapabilitiesCache, setCapabilities, setCellDimensions, wrapTmuxPassthrough, } from "./terminal-image.js";
|
|
36
42
|
export { sanitizeTerminalLabel, shortenImagePath } from "./terminal-text.js";
|
|
37
43
|
export { Container, CURSOR_MARKER, compositeTuiLine, isFocusable, isViewportTUI, TUI, } from "./tui.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["// Core TUI interfaces and classes\n\nimport type { CellDimensions, ImageDimensions } from \"./terminal-image.ts\";\nimport { calculateImageCellSize } from \"./terminal-image.ts\";\n\nexport { Marked, type Token, type Tokens } from \"marked\";\n// Fullscreen transcript search\nexport {\n\tAltScreenSearchComponent,\n\ttype AltScreenSearchMatch,\n\ttype AltScreenSearchSegment,\n\tfindAltScreenSearchMatches,\n\tgetAltScreenSearchMatchKey,\n} from \"./alt-screen-search.ts\";\n// Autocomplete support\nexport {\n\ttype AutocompleteItem,\n\ttype AutocompleteProvider,\n\ttype AutocompleteSuggestions,\n\tCombinedAutocompleteProvider,\n\ttype SlashCommand,\n} from \"./autocomplete.ts\";\n// Components\nexport { Box } from \"./components/box.ts\";\nexport { CancellableLoader } from \"./components/cancellable-loader.ts\";\nexport {\n\tEditor,\n\ttype EditorOptions,\n\ttype EditorTheme,\n} from \"./components/editor.ts\";\nexport { HStack } from \"./components/h-stack.ts\";\nexport { Image, type ImageOptions, type ImageTheme } from \"./components/image.ts\";\nexport { Input } from \"./components/input.ts\";\nexport { Loader, type LoaderIndicatorOptions } from \"./components/loader.ts\";\nexport {\n\tclearRenderCache,\n\ttype DefaultTextStyle,\n\tgetMarkdownHighlightCallCount,\n\tMarkdown,\n\ttype MarkdownOptions,\n\ttype MarkdownTheme,\n\tresetMarkdownHighlightCallCount,\n} from \"./components/markdown.ts\";\nexport {\n\tScrollView,\n\ttype ScrollViewOptions,\n\ttype ScrollViewScrollbar,\n\ttype ScrollViewScrollToOptions,\n} from \"./components/scroll-view.ts\";\nexport {\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\ttype SelectListRenderRow,\n\ttype SelectListRowParts,\n\ttype SelectListTheme,\n\ttype SelectListTruncatePrimaryContext,\n} from \"./components/select-list.ts\";\nexport { type SettingItem, SettingsList, type SettingsListTheme } from \"./components/settings-list.ts\";\nexport { Spacer } from \"./components/spacer.ts\";\nexport { Text } from \"./components/text.ts\";\nexport { TruncatedText } from \"./components/truncated-text.ts\";\nexport {\n\ttype StackChild,\n\ttype StackEntry,\n\ttype StackEntryOptions,\n\ttype StackOptions,\n\tVStack,\n} from \"./components/v-stack.ts\";\n// Editor component interface (for custom editors)\nexport type { EditorComponent } from \"./editor-component.ts\";\n// Fuzzy matching\nexport { type FuzzyMatch, fuzzyFilter, fuzzyMatch } from \"./fuzzy.ts\";\n// Keybindings\nexport {\n\tgetKeybindings,\n\ttype Keybinding,\n\ttype KeybindingConflict,\n\ttype KeybindingDefinition,\n\ttype KeybindingDefinitions,\n\ttype Keybindings,\n\ttype KeybindingsConfig,\n\tKeybindingsManager,\n\tsetKeybindings,\n\tTUI_KEYBINDINGS,\n} from \"./keybindings.ts\";\n// Keyboard input handling\nexport {\n\tdecodeKittyPrintable,\n\tisKeyRelease,\n\tisKeyRepeat,\n\tisKittyProtocolActive,\n\tKey,\n\ttype KeyEventType,\n\ttype KeyId,\n\tmatchesKey,\n\tparseKey,\n\tsetKittyProtocolActive,\n} from \"./keys.ts\";\nexport { type EditorPasteState, expandPasteMarkers } from \"./paste-markers.ts\";\n// Input buffering for batch splitting\nexport { StdinBuffer, type StdinBufferEventMap, type StdinBufferOptions } from \"./stdin-buffer.ts\";\n// Terminal interface and implementations\nexport { ProcessTerminal, type ProcessTerminalOptions, type Terminal } from \"./terminal.ts\";\n// Terminal colors\nexport {\n\tparseOsc11BackgroundColor,\n\tparseTerminalColorSchemeReport,\n\ttype RgbColor,\n\ttype TerminalColorScheme,\n} from \"./terminal-colors.ts\";\n// Terminal image support\nexport function calculateImageRows(\n\timageDimensions: ImageDimensions,\n\ttargetWidthCells: number,\n\tcellDimensions: CellDimensions = { widthPx: 9, heightPx: 18 },\n): number {\n\treturn calculateImageCellSize(imageDimensions, targetWidthCells, undefined, cellDimensions).rows;\n}\nexport {\n\tallocateImageId,\n\tbuildKittyPlaceholderRow,\n\ttype CellDimensions,\n\tdeleteAllKittyImages,\n\tdeleteKittyImage,\n\tdetectCapabilities,\n\tencodeITerm2,\n\tencodeKitty,\n\tgetCapabilities,\n\tgetCellDimensions,\n\tgetGifDimensions,\n\tgetImageDimensions,\n\tgetJpegDimensions,\n\tgetPngDimensions,\n\tgetWebpDimensions,\n\thyperlink,\n\ttype ImageDimensions,\n\ttype ImageProtocol,\n\ttype ImageRenderOptions,\n\timageFallback,\n\tKITTY_PLACEHOLDER_MAX,\n\touterKittyGraphicsMode,\n\trenderImage,\n\tresetCapabilitiesCache,\n\tsetCapabilities,\n\tsetCellDimensions,\n\ttype TerminalCapabilities,\n\ttype TmuxPassthroughState,\n\twrapTmuxPassthrough,\n} from \"./terminal-image.ts\";\nexport { sanitizeTerminalLabel, shortenImagePath } from \"./terminal-text.ts\";\nexport {\n\ttype Component,\n\tContainer,\n\tCURSOR_MARKER,\n\tcompositeTuiLine,\n\ttype Focusable,\n\tisFocusable,\n\tisViewportTUI,\n\ttype OverlayAnchor,\n\ttype OverlayHandle,\n\ttype OverlayMargin,\n\ttype OverlayOptions,\n\ttype OverlayUnfocusOptions,\n\ttype SizeValue,\n\tTUI,\n\ttype TuiInputListener,\n\ttype TuiInputListenerResult,\n\ttype TuiMode,\n\ttype TuiStopOptions,\n\ttype ViewportTUI,\n} from \"./tui.ts\";\nexport { TuiAltScreen, type TuiAltScreenOptions } from \"./tui-alt-screen.ts\";\nexport { TuiMainScreen, type TuiMainScreenRenderState } from \"./tui-main-screen.ts\";\n// Utilities\nexport {\n\tgetGraphemeSegmenter,\n\tgetOsc8LinkAtColumn,\n\tgetWordSegmenter,\n\tsliceByColumn,\n\tstripTerminalSequences,\n\ttruncateToWidth,\n\tvisibleWidth,\n\twrapTextWithAnsi,\n} from \"./utils.ts\";\n"]}
|
package/dist/keybindings.d.ts
CHANGED
|
@@ -41,8 +41,14 @@ export interface Keybindings {
|
|
|
41
41
|
"tui.altScreen.pageDown": true;
|
|
42
42
|
"tui.altScreen.halfPageUp": true;
|
|
43
43
|
"tui.altScreen.halfPageDown": true;
|
|
44
|
+
"tui.altScreen.lineUp": true;
|
|
45
|
+
"tui.altScreen.lineDown": true;
|
|
44
46
|
"tui.altScreen.previousPrompt": true;
|
|
45
47
|
"tui.altScreen.nextPrompt": true;
|
|
48
|
+
"tui.altScreen.search": true;
|
|
49
|
+
"tui.altScreen.searchNext": true;
|
|
50
|
+
"tui.altScreen.searchPrevious": true;
|
|
51
|
+
"tui.altScreen.searchClose": true;
|
|
46
52
|
"tui.altScreen.top": true;
|
|
47
53
|
"tui.altScreen.bottom": true;
|
|
48
54
|
}
|
|
@@ -202,6 +208,14 @@ export declare const TUI_KEYBINDINGS: {
|
|
|
202
208
|
readonly defaultKeys: [];
|
|
203
209
|
readonly description: "Scroll viewport down half a page";
|
|
204
210
|
};
|
|
211
|
+
readonly "tui.altScreen.lineUp": {
|
|
212
|
+
readonly defaultKeys: [];
|
|
213
|
+
readonly description: "Scroll viewport up one line";
|
|
214
|
+
};
|
|
215
|
+
readonly "tui.altScreen.lineDown": {
|
|
216
|
+
readonly defaultKeys: [];
|
|
217
|
+
readonly description: "Scroll viewport down one line";
|
|
218
|
+
};
|
|
205
219
|
readonly "tui.altScreen.previousPrompt": {
|
|
206
220
|
readonly defaultKeys: "ctrl+shift+up";
|
|
207
221
|
readonly description: "Jump to previous semantic prompt";
|
|
@@ -210,6 +224,22 @@ export declare const TUI_KEYBINDINGS: {
|
|
|
210
224
|
readonly defaultKeys: "ctrl+shift+down";
|
|
211
225
|
readonly description: "Jump to next semantic prompt";
|
|
212
226
|
};
|
|
227
|
+
readonly "tui.altScreen.search": {
|
|
228
|
+
readonly defaultKeys: "ctrl+shift+f";
|
|
229
|
+
readonly description: "Search the primary scroll view";
|
|
230
|
+
};
|
|
231
|
+
readonly "tui.altScreen.searchNext": {
|
|
232
|
+
readonly defaultKeys: ["enter", "ctrl+g"];
|
|
233
|
+
readonly description: "Select the next search match";
|
|
234
|
+
};
|
|
235
|
+
readonly "tui.altScreen.searchPrevious": {
|
|
236
|
+
readonly defaultKeys: ["shift+enter", "ctrl+shift+g"];
|
|
237
|
+
readonly description: "Select the previous search match";
|
|
238
|
+
};
|
|
239
|
+
readonly "tui.altScreen.searchClose": {
|
|
240
|
+
readonly defaultKeys: "escape";
|
|
241
|
+
readonly description: "Close transcript search";
|
|
242
|
+
};
|
|
213
243
|
readonly "tui.altScreen.top": {
|
|
214
244
|
readonly defaultKeys: "home";
|
|
215
245
|
readonly description: "Scroll viewport to top";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAc,MAAM,WAAW,CAAC;AAEnD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAE3B,qBAAqB,EAAE,IAAI,CAAC;IAC5B,uBAAuB,EAAE,IAAI,CAAC;IAC9B,4BAA4B,EAAE,IAAI,CAAC;IACnC,wBAAwB,EAAE,IAAI,CAAC;IAC/B,uBAAuB,EAAE,IAAI,CAAC;IAC9B,wBAAwB,EAAE,IAAI,CAAC;IAC/B,2BAA2B,EAAE,IAAI,CAAC;IAClC,4BAA4B,EAAE,IAAI,CAAC;IACnC,4BAA4B,EAAE,IAAI,CAAC;IACnC,0BAA0B,EAAE,IAAI,CAAC;IACjC,wBAAwB,EAAE,IAAI,CAAC;IAC/B,yBAAyB,EAAE,IAAI,CAAC;IAChC,mBAAmB,EAAE,IAAI,CAAC;IAC1B,qBAAqB,EAAE,IAAI,CAAC;IAC5B,+BAA+B,EAAE,IAAI,CAAC;IACtC,8BAA8B,EAAE,IAAI,CAAC;IACrC,+BAA+B,EAAE,IAAI,CAAC;IACtC,8BAA8B,EAAE,IAAI,CAAC;IACrC,8BAA8B,EAAE,IAAI,CAAC;IACrC,4BAA4B,EAAE,IAAI,CAAC;IACnC,iBAAiB,EAAE,IAAI,CAAC;IACxB,oBAAoB,EAAE,IAAI,CAAC;IAC3B,iBAAiB,EAAE,IAAI,CAAC;IAExB,mBAAmB,EAAE,IAAI,CAAC;IAC1B,kBAAkB,EAAE,IAAI,CAAC;IACzB,eAAe,EAAE,IAAI,CAAC;IACtB,gBAAgB,EAAE,IAAI,CAAC;IAEvB,eAAe,EAAE,IAAI,CAAC;IACtB,iBAAiB,EAAE,IAAI,CAAC;IACxB,mBAAmB,EAAE,IAAI,CAAC;IAC1B,qBAAqB,EAAE,IAAI,CAAC;IAC5B,oBAAoB,EAAE,IAAI,CAAC;IAC3B,mBAAmB,EAAE,IAAI,CAAC;IAE1B,sBAAsB,EAAE,IAAI,CAAC;IAC7B,wBAAwB,EAAE,IAAI,CAAC;IAC/B,0BAA0B,EAAE,IAAI,CAAC;IACjC,4BAA4B,EAAE,IAAI,CAAC;IACnC,8BAA8B,EAAE,IAAI,CAAC;IACrC,0BAA0B,EAAE,IAAI,CAAC;IACjC,mBAAmB,EAAE,IAAI,CAAC;IAC1B,sBAAsB,EAAE,IAAI,CAAC;CAC7B;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC;AAE3C,MAAM,WAAW,oBAAoB;IACpC,WAAW,EAAE,KAAK,GAAG,KAAK,EAAE,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;AACzE,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,SAAS,CAAC,CAAC;AAE5E,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../src/keybindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAc,MAAM,WAAW,CAAC;AAEnD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAE3B,qBAAqB,EAAE,IAAI,CAAC;IAC5B,uBAAuB,EAAE,IAAI,CAAC;IAC9B,4BAA4B,EAAE,IAAI,CAAC;IACnC,wBAAwB,EAAE,IAAI,CAAC;IAC/B,uBAAuB,EAAE,IAAI,CAAC;IAC9B,wBAAwB,EAAE,IAAI,CAAC;IAC/B,2BAA2B,EAAE,IAAI,CAAC;IAClC,4BAA4B,EAAE,IAAI,CAAC;IACnC,4BAA4B,EAAE,IAAI,CAAC;IACnC,0BAA0B,EAAE,IAAI,CAAC;IACjC,wBAAwB,EAAE,IAAI,CAAC;IAC/B,yBAAyB,EAAE,IAAI,CAAC;IAChC,mBAAmB,EAAE,IAAI,CAAC;IAC1B,qBAAqB,EAAE,IAAI,CAAC;IAC5B,+BAA+B,EAAE,IAAI,CAAC;IACtC,8BAA8B,EAAE,IAAI,CAAC;IACrC,+BAA+B,EAAE,IAAI,CAAC;IACtC,8BAA8B,EAAE,IAAI,CAAC;IACrC,8BAA8B,EAAE,IAAI,CAAC;IACrC,4BAA4B,EAAE,IAAI,CAAC;IACnC,iBAAiB,EAAE,IAAI,CAAC;IACxB,oBAAoB,EAAE,IAAI,CAAC;IAC3B,iBAAiB,EAAE,IAAI,CAAC;IAExB,mBAAmB,EAAE,IAAI,CAAC;IAC1B,kBAAkB,EAAE,IAAI,CAAC;IACzB,eAAe,EAAE,IAAI,CAAC;IACtB,gBAAgB,EAAE,IAAI,CAAC;IAEvB,eAAe,EAAE,IAAI,CAAC;IACtB,iBAAiB,EAAE,IAAI,CAAC;IACxB,mBAAmB,EAAE,IAAI,CAAC;IAC1B,qBAAqB,EAAE,IAAI,CAAC;IAC5B,oBAAoB,EAAE,IAAI,CAAC;IAC3B,mBAAmB,EAAE,IAAI,CAAC;IAE1B,sBAAsB,EAAE,IAAI,CAAC;IAC7B,wBAAwB,EAAE,IAAI,CAAC;IAC/B,0BAA0B,EAAE,IAAI,CAAC;IACjC,4BAA4B,EAAE,IAAI,CAAC;IACnC,sBAAsB,EAAE,IAAI,CAAC;IAC7B,wBAAwB,EAAE,IAAI,CAAC;IAC/B,8BAA8B,EAAE,IAAI,CAAC;IACrC,0BAA0B,EAAE,IAAI,CAAC;IACjC,sBAAsB,EAAE,IAAI,CAAC;IAC7B,0BAA0B,EAAE,IAAI,CAAC;IACjC,8BAA8B,EAAE,IAAI,CAAC;IACrC,2BAA2B,EAAE,IAAI,CAAC;IAClC,mBAAmB,EAAE,IAAI,CAAC;IAC1B,sBAAsB,EAAE,IAAI,CAAC;CAC7B;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC;AAE3C,MAAM,WAAW,oBAAoB;IACpC,WAAW,EAAE,KAAK,GAAG,KAAK,EAAE,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;AACzE,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,SAAS,CAAC,CAAC;AAE5E,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Ic,CAAC;AAE3C,MAAM,WAAW,kBAAkB;IAClC,GAAG,EAAE,KAAK,CAAC;IACX,WAAW,EAAE,MAAM,EAAE,CAAC;CACtB;AAgBD,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,SAAS,CAA4B;gBAEjC,WAAW,EAAE,qBAAqB,EAAE,YAAY,GAAE,iBAAsB;IAMpF,OAAO,CAAC,OAAO;IA2Bf,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO;IAQtD,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,KAAK,EAAE;IAIxC,aAAa,CAAC,UAAU,EAAE,UAAU,GAAG,oBAAoB;IAI3D,YAAY,IAAI,kBAAkB,EAAE;IAIpC,eAAe,CAAC,YAAY,EAAE,iBAAiB,GAAG,IAAI;IAKtD,eAAe,IAAI,iBAAiB;IAIpC,mBAAmB,IAAI,iBAAiB;CAQxC;AAID,wBAAgB,cAAc,CAAC,WAAW,EAAE,kBAAkB,GAAG,IAAI,CAEpE;AAED,wBAAgB,cAAc,IAAI,kBAAkB,CAKnD"}
|
package/dist/keybindings.js
CHANGED
|
@@ -104,6 +104,14 @@ export const TUI_KEYBINDINGS = {
|
|
|
104
104
|
defaultKeys: [],
|
|
105
105
|
description: "Scroll viewport down half a page",
|
|
106
106
|
},
|
|
107
|
+
"tui.altScreen.lineUp": {
|
|
108
|
+
defaultKeys: [],
|
|
109
|
+
description: "Scroll viewport up one line",
|
|
110
|
+
},
|
|
111
|
+
"tui.altScreen.lineDown": {
|
|
112
|
+
defaultKeys: [],
|
|
113
|
+
description: "Scroll viewport down one line",
|
|
114
|
+
},
|
|
107
115
|
"tui.altScreen.previousPrompt": {
|
|
108
116
|
defaultKeys: "ctrl+shift+up",
|
|
109
117
|
description: "Jump to previous semantic prompt",
|
|
@@ -112,6 +120,22 @@ export const TUI_KEYBINDINGS = {
|
|
|
112
120
|
defaultKeys: "ctrl+shift+down",
|
|
113
121
|
description: "Jump to next semantic prompt",
|
|
114
122
|
},
|
|
123
|
+
"tui.altScreen.search": {
|
|
124
|
+
defaultKeys: "ctrl+shift+f",
|
|
125
|
+
description: "Search the primary scroll view",
|
|
126
|
+
},
|
|
127
|
+
"tui.altScreen.searchNext": {
|
|
128
|
+
defaultKeys: ["enter", "ctrl+g"],
|
|
129
|
+
description: "Select the next search match",
|
|
130
|
+
},
|
|
131
|
+
"tui.altScreen.searchPrevious": {
|
|
132
|
+
defaultKeys: ["shift+enter", "ctrl+shift+g"],
|
|
133
|
+
description: "Select the previous search match",
|
|
134
|
+
},
|
|
135
|
+
"tui.altScreen.searchClose": {
|
|
136
|
+
defaultKeys: "escape",
|
|
137
|
+
description: "Close transcript search",
|
|
138
|
+
},
|
|
115
139
|
"tui.altScreen.top": { defaultKeys: "home", description: "Scroll viewport to top" },
|
|
116
140
|
"tui.altScreen.bottom": { defaultKeys: "end", description: "Scroll viewport to bottom" },
|
|
117
141
|
};
|