linecraft 0.2.1 → 0.2.2
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/LICENSE +0 -1
- package/README.md +3 -1
- package/lib/component.d.ts +34 -0
- package/lib/component.d.ts.map +1 -0
- package/lib/component.js +42 -0
- package/lib/component.js.map +1 -0
- package/lib/components/code-debug.d.ts +35 -0
- package/lib/components/code-debug.d.ts.map +1 -0
- package/lib/components/code-debug.js +294 -0
- package/lib/components/code-debug.js.map +1 -0
- package/lib/components/fill.d.ts +15 -0
- package/lib/components/fill.d.ts.map +1 -0
- package/lib/components/fill.js +37 -0
- package/lib/components/fill.js.map +1 -0
- package/lib/components/index.d.ts +2 -2
- package/lib/components/index.d.ts.map +1 -1
- package/lib/components/index.js +2 -2
- package/lib/components/index.js.map +1 -1
- package/lib/components/progress-bar-grid.d.ts +1 -1
- package/lib/components/progress-bar-grid.d.ts.map +1 -1
- package/lib/components/progress-bar-grid.js +6 -6
- package/lib/components/progress-bar-grid.js.map +1 -1
- package/lib/components/prompt.d.ts +4 -5
- package/lib/components/prompt.d.ts.map +1 -1
- package/lib/components/prompt.js +17 -69
- package/lib/components/prompt.js.map +1 -1
- package/lib/components/section.d.ts +33 -0
- package/lib/components/section.d.ts.map +1 -0
- package/lib/components/section.js +178 -0
- package/lib/components/section.js.map +1 -0
- package/lib/components/segments.d.ts +26 -0
- package/lib/components/segments.d.ts.map +1 -0
- package/lib/components/segments.js +105 -0
- package/lib/components/segments.js.map +1 -0
- package/lib/components/spinner.d.ts +18 -16
- package/lib/components/spinner.d.ts.map +1 -1
- package/lib/components/spinner.js +63 -47
- package/lib/components/spinner.js.map +1 -1
- package/lib/components/style.test.js +11 -11
- package/lib/components/style.test.js.map +1 -1
- package/lib/components/styled.d.ts +17 -0
- package/lib/components/styled.d.ts.map +1 -0
- package/lib/components/styled.js +107 -0
- package/lib/components/styled.js.map +1 -0
- package/lib/components/styled.test.d.ts +2 -0
- package/lib/components/styled.test.d.ts.map +1 -0
- package/lib/components/styled.test.js +135 -0
- package/lib/components/styled.test.js.map +1 -0
- package/lib/index.d.ts +17 -13
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +13 -13
- package/lib/index.js.map +1 -1
- package/lib/index.test.js +17 -11
- package/lib/index.test.js.map +1 -1
- package/lib/layout/grid.d.ts +31 -35
- package/lib/layout/grid.d.ts.map +1 -1
- package/lib/layout/grid.js +437 -216
- package/lib/layout/grid.js.map +1 -1
- package/lib/layout/grid.test.js +332 -36
- package/lib/layout/grid.test.js.map +1 -1
- package/lib/native/ansi.d.ts +9 -0
- package/lib/native/ansi.d.ts.map +1 -1
- package/lib/native/ansi.js +9 -0
- package/lib/native/ansi.js.map +1 -1
- package/lib/native/diff.d.ts +5 -1
- package/lib/native/diff.d.ts.map +1 -1
- package/lib/native/diff.js +25 -7
- package/lib/native/diff.js.map +1 -1
- package/lib/native/region-renderer-debug.test.d.ts +2 -0
- package/lib/native/region-renderer-debug.test.d.ts.map +1 -0
- package/lib/native/region-renderer-debug.test.js +45 -0
- package/lib/native/region-renderer-debug.test.js.map +1 -0
- package/lib/native/region-renderer.d.ts +57 -148
- package/lib/native/region-renderer.d.ts.map +1 -1
- package/lib/native/region-renderer.js +455 -1124
- package/lib/native/region-renderer.js.map +1 -1
- package/lib/native/region.test.js +2 -20
- package/lib/native/region.test.js.map +1 -1
- package/lib/region-resize.test.d.ts +2 -0
- package/lib/region-resize.test.d.ts.map +1 -0
- package/lib/region-resize.test.js +124 -0
- package/lib/region-resize.test.js.map +1 -0
- package/lib/region.d.ts +97 -9
- package/lib/region.d.ts.map +1 -1
- package/lib/region.js +591 -185
- package/lib/region.js.map +1 -1
- package/lib/region.test.js +3 -3
- package/lib/region.test.js.map +1 -1
- package/lib/types.d.ts +9 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/utils/file-link.d.ts +16 -0
- package/lib/utils/file-link.d.ts.map +1 -0
- package/lib/utils/file-link.js +23 -0
- package/lib/utils/file-link.js.map +1 -0
- package/lib/utils/prompt.d.ts +15 -0
- package/lib/utils/prompt.d.ts.map +1 -0
- package/lib/utils/prompt.js +128 -0
- package/lib/utils/prompt.js.map +1 -0
- package/lib/utils/terminal-theme.d.ts +36 -0
- package/lib/utils/terminal-theme.d.ts.map +1 -0
- package/lib/utils/terminal-theme.js +61 -0
- package/lib/utils/terminal-theme.js.map +1 -0
- package/lib/utils/text.d.ts +53 -3
- package/lib/utils/text.d.ts.map +1 -1
- package/lib/utils/text.js +194 -36
- package/lib/utils/text.js.map +1 -1
- package/lib/utils/wait-for-spacebar.d.ts.map +1 -1
- package/lib/utils/wait-for-spacebar.js +9 -6
- package/lib/utils/wait-for-spacebar.js.map +1 -1
- package/package.json +13 -13
package/lib/native/ansi.js
CHANGED
|
@@ -104,6 +104,15 @@ export const DISABLE_AUTO_WRAP = '\x1b[?7l';
|
|
|
104
104
|
* This is the default terminal state. Use this to restore after DISABLE_AUTO_WRAP.
|
|
105
105
|
*/
|
|
106
106
|
export const ENABLE_AUTO_WRAP = '\x1b[?7h';
|
|
107
|
+
/**
|
|
108
|
+
* Switch to the terminal's alternate screen buffer.
|
|
109
|
+
* Commonly used by fullscreen TUIs so the main screen is restored on exit.
|
|
110
|
+
*/
|
|
111
|
+
export const ENTER_ALTERNATE_SCREEN = '\x1b[?1049h';
|
|
112
|
+
/**
|
|
113
|
+
* Return to the main screen buffer from the alternate buffer.
|
|
114
|
+
*/
|
|
115
|
+
export const EXIT_ALTERNATE_SCREEN = '\x1b[?1049l';
|
|
107
116
|
/**
|
|
108
117
|
* Query cursor position (DSR - Device Status Report)
|
|
109
118
|
* Format: \x1b[6n
|
package/lib/native/ansi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ansi.js","sourceRoot":"","sources":["../../src/native/ansi.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,0CAA0C;AAE1C;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,CAAS,EAAE,CAAS;IAC/C,kDAAkD;IAClD,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,QAAQ,CAAC,GAAG,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,CAAS;IACtC,OAAO,QAAQ,CAAC,GAAG,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,CAAS;IACvC,OAAO,QAAQ,CAAC,GAAG,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,CAAS;IACtC,OAAO,QAAQ,CAAC,GAAG,CAAC;AACtB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAAC;AAElD,gDAAgD;AAChD,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC;AACpC,MAAM,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC;AACtC,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AACxC,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC;AACvC,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC;AACvC,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC;AACpC,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC;AACvC,MAAM,CAAC,MAAM,KAAK,GAAG,SAAS,CAAC;AAE/B;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,OAAO,QAAQ,CAAC,GAAG,CAAC;AACtB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAAC;AAErC;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AAExC;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC;AAEtC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAE3C;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"ansi.js","sourceRoot":"","sources":["../../src/native/ansi.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,0CAA0C;AAE1C;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,CAAS,EAAE,CAAS;IAC/C,kDAAkD;IAClD,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,OAAO,QAAQ,CAAC,GAAG,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,CAAS;IACtC,OAAO,QAAQ,CAAC,GAAG,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,CAAS;IACvC,OAAO,QAAQ,CAAC,GAAG,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,CAAS;IACtC,OAAO,QAAQ,CAAC,GAAG,CAAC;AACtB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAAC;AAElD,gDAAgD;AAChD,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC;AACpC,MAAM,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC;AACtC,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AACxC,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC;AACvC,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC;AACvC,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC;AACpC,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC;AACvC,MAAM,CAAC,MAAM,KAAK,GAAG,SAAS,CAAC;AAE/B;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,OAAO,QAAQ,CAAC,GAAG,CAAC;AACtB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAAC;AAErC;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AAExC;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC;AAEtC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,aAAa,CAAC;AAEpD;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,aAAa,CAAC;AAEnD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,SAAS,CAAC"}
|
package/lib/native/diff.d.ts
CHANGED
|
@@ -14,7 +14,11 @@ export type DiffOp = {
|
|
|
14
14
|
};
|
|
15
15
|
/**
|
|
16
16
|
* Diff two frames to generate minimal update operations.
|
|
17
|
-
*
|
|
17
|
+
*
|
|
18
|
+
* Strategy:
|
|
19
|
+
* - If only a small continuous region of a line changes, use partial update
|
|
20
|
+
* - If multiple regions change or changes are scattered, redraw the whole line
|
|
21
|
+
* - When lines are deleted, all lines below need to be redrawn (reflow)
|
|
18
22
|
*/
|
|
19
23
|
export declare function diffFrames(prev: string[], curr: string[]): DiffOp[];
|
|
20
24
|
//# sourceMappingURL=diff.d.ts.map
|
package/lib/native/diff.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/native/diff.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,MAAM,GACd;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/native/diff.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,MAAM,GACd;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAG3D;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAsCnE"}
|
package/lib/native/diff.js
CHANGED
|
@@ -2,29 +2,47 @@
|
|
|
2
2
|
// Optimized for Node.js performance
|
|
3
3
|
/**
|
|
4
4
|
* Diff two frames to generate minimal update operations.
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
|
+
* Strategy:
|
|
7
|
+
* - If only a small continuous region of a line changes, use partial update
|
|
8
|
+
* - If multiple regions change or changes are scattered, redraw the whole line
|
|
9
|
+
* - When lines are deleted, all lines below need to be redrawn (reflow)
|
|
6
10
|
*/
|
|
7
11
|
export function diffFrames(prev, curr) {
|
|
8
12
|
const ops = [];
|
|
9
13
|
const maxLen = Math.max(prev.length, curr.length);
|
|
14
|
+
let needsReflow = false; // Track if we need to redraw lines below
|
|
10
15
|
for (let i = 0; i < maxLen; i++) {
|
|
11
16
|
const prevLine = i < prev.length ? prev[i] : null;
|
|
12
17
|
const currLine = i < curr.length ? curr[i] : null;
|
|
13
18
|
if (prevLine === null && currLine !== null) {
|
|
14
|
-
// Line inserted
|
|
19
|
+
// Line inserted - causes reflow
|
|
20
|
+
needsReflow = true;
|
|
15
21
|
ops.push({ type: 'insert_line', line: i, content: currLine });
|
|
16
22
|
}
|
|
17
23
|
else if (prevLine !== null && currLine === null) {
|
|
18
|
-
// Line deleted
|
|
24
|
+
// Line deleted - causes reflow of everything below
|
|
25
|
+
needsReflow = true;
|
|
19
26
|
ops.push({ type: 'delete_line', line: i });
|
|
20
27
|
}
|
|
21
28
|
else if (prevLine !== null && currLine !== null) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
if (prevLine === currLine) {
|
|
30
|
+
// No change, but if we had reflow above, we need to redraw
|
|
31
|
+
if (needsReflow) {
|
|
32
|
+
ops.push({ type: 'update_line', line: i, content: currLine });
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
ops.push({ type: 'no_change' });
|
|
36
|
+
}
|
|
25
37
|
}
|
|
26
38
|
else {
|
|
27
|
-
|
|
39
|
+
// Line changed
|
|
40
|
+
// For now, we always redraw the whole line for simplicity
|
|
41
|
+
// Partial updates with ANSI codes are complex and error-prone
|
|
42
|
+
// The optimization would be: if change is small and continuous, update just that region
|
|
43
|
+
// But preserving ANSI codes at boundaries is tricky, so we redraw for correctness
|
|
44
|
+
needsReflow = true; // Any line change causes reflow below
|
|
45
|
+
ops.push({ type: 'update_line', line: i, content: currLine });
|
|
28
46
|
}
|
|
29
47
|
}
|
|
30
48
|
}
|
package/lib/native/diff.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/native/diff.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,oCAAoC;
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/native/diff.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,oCAAoC;AASpC;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,IAAc,EAAE,IAAc;IACvD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAClD,IAAI,WAAW,GAAG,KAAK,CAAC,CAAC,yCAAyC;IAElE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAClD,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAElD,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC3C,gCAAgC;YAChC,WAAW,GAAG,IAAI,CAAC;YACnB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChE,CAAC;aAAM,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YAClD,mDAAmD;YACnD,WAAW,GAAG,IAAI,CAAC;YACnB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7C,CAAC;aAAM,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YAClD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC1B,2DAA2D;gBAC3D,IAAI,WAAW,EAAE,CAAC;oBAClB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;gBAChE,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,eAAe;gBACf,0DAA0D;gBAC1D,8DAA8D;gBAC9D,wFAAwF;gBACxF,kFAAkF;gBAClF,WAAW,GAAG,IAAI,CAAC,CAAC,sCAAsC;gBAC1D,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"region-renderer-debug.test.d.ts","sourceRoot":"","sources":["../../src/native/region-renderer-debug.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Debug test to understand viewport frame calculation during resize
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import { RegionRenderer } from './region-renderer';
|
|
4
|
+
describe('Viewport frame calculation during resize', () => {
|
|
5
|
+
it('should show correct lines when content height changes', () => {
|
|
6
|
+
const mockStdout = {
|
|
7
|
+
isTTY: true,
|
|
8
|
+
columns: 80,
|
|
9
|
+
rows: 24,
|
|
10
|
+
write: () => true,
|
|
11
|
+
on: () => { },
|
|
12
|
+
off: () => { },
|
|
13
|
+
removeListener: () => { },
|
|
14
|
+
};
|
|
15
|
+
const renderer = new RegionRenderer({
|
|
16
|
+
stdout: mockStdout,
|
|
17
|
+
disableRendering: true,
|
|
18
|
+
});
|
|
19
|
+
// Set initial content (10 lines)
|
|
20
|
+
const initialContent = Array.from({ length: 10 }, (_, i) => `Line ${i + 1}`);
|
|
21
|
+
renderer.pendingFrame = [...initialContent];
|
|
22
|
+
renderer.height = 10;
|
|
23
|
+
renderer.previousFrame = [...initialContent];
|
|
24
|
+
// Simulate viewport showing bottom 5 lines (lines 6-10)
|
|
25
|
+
renderer.viewportHeight = 5;
|
|
26
|
+
const frame1 = renderer.buildViewportFrame();
|
|
27
|
+
expect(frame1.length).toBe(5);
|
|
28
|
+
expect(frame1[0]).toBe('Line 6');
|
|
29
|
+
expect(frame1[4]).toBe('Line 10');
|
|
30
|
+
// Now content wraps to 15 lines (more lines)
|
|
31
|
+
const newContent = Array.from({ length: 15 }, (_, i) => `Line ${i + 1} (wrapped)`);
|
|
32
|
+
renderer.pendingFrame = [...newContent];
|
|
33
|
+
renderer.height = 15;
|
|
34
|
+
// Viewport frame should show bottom 5 lines (lines 11-15)
|
|
35
|
+
const frame2 = renderer.buildViewportFrame();
|
|
36
|
+
expect(frame2.length).toBe(5);
|
|
37
|
+
expect(frame2[0]).toBe('Line 11 (wrapped)');
|
|
38
|
+
expect(frame2[4]).toBe('Line 15 (wrapped)');
|
|
39
|
+
// The issue: previousViewportFrame has old content at old positions
|
|
40
|
+
// But new frame has new content at new positions
|
|
41
|
+
// Diff will compare frame1[0] ('Line 6') with frame2[0] ('Line 11 (wrapped)')
|
|
42
|
+
// This looks like a transposition, but it's actually just the viewport shifting
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=region-renderer-debug.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"region-renderer-debug.test.js","sourceRoot":"","sources":["../../src/native/region-renderer-debug.test.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAEpE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;IACxD,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,UAAU,GAAG;YACjB,KAAK,EAAE,IAAI;YACX,OAAO,EAAE,EAAE;YACX,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI;YACjB,EAAE,EAAE,GAAG,EAAE,GAAE,CAAC;YACZ,GAAG,EAAE,GAAG,EAAE,GAAE,CAAC;YACb,cAAc,EAAE,GAAG,EAAE,GAAE,CAAC;SAClB,CAAC;QAET,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC;YAClC,MAAM,EAAE,UAAU;YAClB,gBAAgB,EAAE,IAAI;SACvB,CAAC,CAAC;QAEH,iCAAiC;QACjC,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7E,QAAQ,CAAC,YAAY,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC;QAC5C,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC;QACpB,QAAgB,CAAC,aAAa,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC;QAEtD,wDAAwD;QACvD,QAAgB,CAAC,cAAc,GAAG,CAAC,CAAC;QACrC,MAAM,MAAM,GAAI,QAAgB,CAAC,kBAAkB,EAAE,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAElC,6CAA6C;QAC7C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QACnF,QAAQ,CAAC,YAAY,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;QACxC,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC;QAErB,0DAA0D;QAC1D,MAAM,MAAM,GAAI,QAAgB,CAAC,kBAAkB,EAAE,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAE5C,oEAAoE;QACpE,iDAAiD;QACjD,8EAA8E;QAC9E,gFAAgF;IAClF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1,167 +1,76 @@
|
|
|
1
1
|
export interface RegionRendererOptions {
|
|
2
|
-
width?: number;
|
|
3
|
-
height?: number;
|
|
4
2
|
stdout?: NodeJS.WriteStream;
|
|
5
3
|
disableRendering?: boolean;
|
|
6
4
|
onKeepAlive?: () => void;
|
|
5
|
+
debugLog?: string;
|
|
7
6
|
}
|
|
8
|
-
/**
|
|
9
|
-
* TerminalRegion manages a rectangular region of the terminal.
|
|
10
|
-
*
|
|
11
|
-
* The region reserves new lines at the bottom of the terminal and only
|
|
12
|
-
* updates within those reserved lines. This prevents overwriting existing
|
|
13
|
-
* terminal content.
|
|
14
|
-
*
|
|
15
|
-
* Performance optimizations:
|
|
16
|
-
* - Frame diffing to minimize writes
|
|
17
|
-
* - Throttling to limit render frequency
|
|
18
|
-
* - Batched writes to stdout
|
|
19
|
-
* - Efficient string operations
|
|
20
|
-
* - Relative cursor movements (no absolute positioning)
|
|
21
|
-
*/
|
|
22
7
|
export declare class RegionRenderer {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
private
|
|
30
|
-
private
|
|
31
|
-
private
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
pendingFrame: string[];
|
|
11
|
+
previousFrame: string[];
|
|
12
|
+
disableRendering: boolean;
|
|
13
|
+
lastRenderedHeight: number;
|
|
14
|
+
private readonly stdout;
|
|
15
|
+
private readonly throttle;
|
|
16
|
+
private readonly renderBuffer;
|
|
32
17
|
private readonly permanentlyDisabled;
|
|
33
|
-
private
|
|
34
|
-
private
|
|
35
|
-
private
|
|
36
|
-
private
|
|
37
|
-
private
|
|
18
|
+
private readonly onKeepAlive?;
|
|
19
|
+
private viewportWidth;
|
|
20
|
+
private viewportHeight;
|
|
21
|
+
private previousViewportFrame;
|
|
22
|
+
private effectiveWidth;
|
|
38
23
|
private autoWrapDisabled;
|
|
39
|
-
private
|
|
40
|
-
private visibleRegionTopRow;
|
|
41
|
-
private lastRenderedHeight;
|
|
42
|
-
private hasRendered;
|
|
24
|
+
private inAlternateScreen;
|
|
43
25
|
private isRendering;
|
|
44
|
-
private
|
|
45
|
-
private
|
|
46
|
-
private
|
|
47
|
-
private
|
|
26
|
+
private renderTimer;
|
|
27
|
+
private resizeCleanup?;
|
|
28
|
+
private destroyed;
|
|
29
|
+
private debugLogPath?;
|
|
30
|
+
private debugLogCleared;
|
|
31
|
+
private cursorVisible;
|
|
48
32
|
private static exitHandlerSetup;
|
|
49
33
|
private static activeRegions;
|
|
50
34
|
constructor(options?: RegionRendererOptions);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
private static setupExitHandler;
|
|
56
|
-
/**
|
|
57
|
-
* Set up resize event handler to react to terminal size changes
|
|
58
|
-
*/
|
|
59
|
-
private setupResizeHandler;
|
|
60
|
-
/**
|
|
61
|
-
* Initialize the region by reserving new lines at the bottom of the terminal.
|
|
62
|
-
* This appends new lines so the region doesn't overwrite existing content.
|
|
63
|
-
*
|
|
64
|
-
* Also disables terminal auto-wrap so we can manage all wrapping ourselves.
|
|
65
|
-
*/
|
|
66
|
-
private initializeRegion;
|
|
67
|
-
/**
|
|
68
|
-
* Query cursor position after resize and store it for use in rendering
|
|
69
|
-
* This helps us position correctly when the saved cursor position is invalid
|
|
70
|
-
*/
|
|
71
|
-
private queryCursorPositionAfterResize;
|
|
72
|
-
/**
|
|
73
|
-
* Poll cursor position multiple times after resize to understand if it's moving
|
|
74
|
-
* This helps debug cursor position inconsistencies on resize
|
|
75
|
-
*/
|
|
76
|
-
private pollCursorPositionAfterResize;
|
|
77
|
-
private logToFile;
|
|
78
|
-
/**
|
|
79
|
-
* Strip ANSI escape codes from a string
|
|
80
|
-
*/
|
|
81
|
-
private stripAnsi;
|
|
82
|
-
/**
|
|
83
|
-
* Get terminal height, with fallback
|
|
84
|
-
*/
|
|
85
|
-
private getTerminalHeight;
|
|
86
|
-
/**
|
|
87
|
-
* Truncate content to maxWidth while preserving ANSI codes
|
|
88
|
-
* Only truncates if content is significantly longer (more than 2 chars) as a safety measure
|
|
89
|
-
*/
|
|
90
|
-
private truncateContent;
|
|
91
|
-
/**
|
|
92
|
-
* Clear the current line and move to start
|
|
93
|
-
*/
|
|
94
|
-
private clearCurrentLine;
|
|
95
|
-
/**
|
|
96
|
-
* Move to top-left of region and save cursor position
|
|
97
|
-
*/
|
|
98
|
-
private moveToTopLeftAndSave;
|
|
99
|
-
/**
|
|
100
|
-
* Check if content has changed between previous and pending frames
|
|
101
|
-
*/
|
|
102
|
-
private hasContentChanged;
|
|
103
|
-
/**
|
|
104
|
-
* Expand region to accommodate more lines
|
|
105
|
-
*/
|
|
106
|
-
private expandTo;
|
|
107
|
-
/**
|
|
108
|
-
* Get a single line (1-based line numbers)
|
|
109
|
-
* Returns empty string if line doesn't exist
|
|
110
|
-
*/
|
|
111
|
-
getLine(lineNumber: number): string;
|
|
112
|
-
/**
|
|
113
|
-
* Set a single line (1-based line numbers)
|
|
114
|
-
*
|
|
115
|
-
* Note: With auto-wrap disabled, we manage all wrapping ourselves.
|
|
116
|
-
* This method sets a single line - if content needs to wrap, it should
|
|
117
|
-
* be handled by the component layer (col, flex, etc.) before calling this.
|
|
118
|
-
*/
|
|
35
|
+
getWidth(): number;
|
|
36
|
+
getHeight(): number;
|
|
37
|
+
getStartRow(): Promise<number | null>;
|
|
38
|
+
setThrottleFps(fps: number): void;
|
|
119
39
|
setLine(lineNumber: number, content: string): void;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
40
|
+
updateLines(updates: Array<{
|
|
41
|
+
lineNumber: number;
|
|
42
|
+
content: string;
|
|
43
|
+
}>): void;
|
|
123
44
|
set(content: string): void;
|
|
124
|
-
|
|
125
|
-
* Schedule a render (respects throttle)
|
|
126
|
-
*/
|
|
127
|
-
private scheduleRender;
|
|
128
|
-
/**
|
|
129
|
-
* Copy pending frame to previous frame
|
|
130
|
-
*/
|
|
131
|
-
private copyPendingToPrevious;
|
|
132
|
-
/**
|
|
133
|
-
* Render immediately (bypasses throttle)
|
|
134
|
-
* Uses relative cursor movements to update only within reserved lines
|
|
135
|
-
*/
|
|
136
|
-
private renderNow;
|
|
137
|
-
/**
|
|
138
|
-
* Force immediate render of pending updates (bypasses throttle)
|
|
139
|
-
* Returns a promise that resolves when rendering is complete
|
|
140
|
-
*/
|
|
141
|
-
flush(): Promise<void>;
|
|
142
|
-
/**
|
|
143
|
-
* Set throttle FPS
|
|
144
|
-
*/
|
|
145
|
-
setThrottleFps(fps: number): void;
|
|
146
|
-
/**
|
|
147
|
-
* Clear a single line (1-based)
|
|
148
|
-
*/
|
|
45
|
+
getLine(lineNumber: number): string;
|
|
149
46
|
clearLine(lineNumber: number): void;
|
|
150
|
-
/**
|
|
151
|
-
* Clear entire region
|
|
152
|
-
*/
|
|
153
47
|
clear(): void;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
* @param clearFirst - If true, clears the region before destroying (default: false)
|
|
159
|
-
*
|
|
160
|
-
* Note: This is automatically called on process exit, but you can also call it explicitly
|
|
161
|
-
* to clean up resources earlier (e.g., before continuing with other terminal output)
|
|
162
|
-
*/
|
|
48
|
+
flush(): Promise<void>;
|
|
49
|
+
expandTo(newHeight: number): void;
|
|
50
|
+
setHeight(height: number): void;
|
|
51
|
+
shrinkFrame(startIndex: number, count: number): void;
|
|
163
52
|
destroy(clearFirst?: boolean): Promise<void>;
|
|
164
|
-
|
|
165
|
-
|
|
53
|
+
logToFile(message: string): void;
|
|
54
|
+
private static registerRegion;
|
|
55
|
+
private static setupExitHandler;
|
|
56
|
+
ensureFrameSize(size: number): void;
|
|
57
|
+
private scheduleRender;
|
|
58
|
+
private renderNow;
|
|
59
|
+
private copyPendingToPrevious;
|
|
60
|
+
private buildViewportFrame;
|
|
61
|
+
private mapLineToViewportRow;
|
|
62
|
+
hideCursor(): void;
|
|
63
|
+
showCursorAt(lineNumber: number, column: number): void;
|
|
64
|
+
private getEffectiveFrame;
|
|
65
|
+
private applyDiff;
|
|
66
|
+
private truncateContent;
|
|
67
|
+
private initializeTerminalState;
|
|
68
|
+
private ensureTerminalState;
|
|
69
|
+
private leaveAlternateScreen;
|
|
70
|
+
private setupResizeHandler;
|
|
71
|
+
private updateViewportMetrics;
|
|
72
|
+
private readViewportWidth;
|
|
73
|
+
private readViewportHeight;
|
|
74
|
+
private resolveDebugLogPath;
|
|
166
75
|
}
|
|
167
76
|
//# sourceMappingURL=region-renderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"region-renderer.d.ts","sourceRoot":"","sources":["../../src/native/region-renderer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"region-renderer.d.ts","sourceRoot":"","sources":["../../src/native/region-renderer.ts"],"names":[],"mappings":"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"}
|