novac 2.0.1 → 2.2.0
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 +1 -1
- package/README.md +1574 -597
- package/bin/novac +468 -171
- package/bin/nvc +522 -0
- package/bin/nvml +78 -17
- package/demo.nv +0 -0
- package/demo_builtins.nv +0 -0
- package/demo_http.nv +0 -0
- package/examples/bf.nv +69 -0
- package/examples/math.nv +21 -0
- package/kits/birdAPI/kitdef.js +954 -0
- package/kits/kitRNG/kitdef.js +740 -0
- package/kits/kitSSH/kitdef.js +1272 -0
- package/kits/kitadb/kitdef.js +606 -0
- package/kits/kitai/kitdef.js +2185 -0
- package/kits/kitansi/kitdef.js +1402 -0
- package/kits/kitcanvas/kitdef.js +914 -0
- package/kits/kitclippy/kitdef.js +925 -0
- package/kits/kitformat/kitdef.js +1485 -0
- package/kits/kitgps/kitdef.js +1862 -0
- package/kits/kitlibproc/kitdef.js +3 -2
- package/kits/kitmatrix/ex.js +19 -0
- package/kits/kitmatrix/kitdef.js +960 -0
- package/kits/kitmorse/kitdef.js +229 -0
- package/kits/kitmpatch/kitdef.js +906 -0
- package/kits/kitnet/kitdef.js +1401 -0
- package/kits/kitnovacweb/README.md +1416 -143
- package/kits/kitnovacweb/kitdef.js +92 -2
- package/kits/kitnovacweb/nvml/executor.js +578 -176
- package/kits/kitnovacweb/nvml/index.js +2 -2
- package/kits/kitnovacweb/nvml/lexer.js +72 -69
- package/kits/kitnovacweb/nvml/parser.js +328 -159
- package/kits/kitnovacweb/nvml/renderer.js +770 -270
- package/kits/kitparse/kitdef.js +1688 -0
- package/kits/kitproto/kitdef.js +613 -0
- package/kits/kitqr/kitdef.js +637 -0
- package/kits/kitregex++/kitdef.js +1353 -0
- package/kits/kitrequire/kitdef.js +1599 -0
- package/kits/kitx11/kitdef.js +1 -0
- package/kits/kitx11/kitx11.js +2472 -0
- package/kits/kitx11/kitx11_conn.js +948 -0
- package/kits/kitx11/kitx11_worker.js +121 -0
- package/kits/libtea/kitdef.js +2691 -0
- package/kits/libterm/ex.js +285 -0
- package/kits/libterm/kitdef.js +1927 -0
- package/novac/LICENSE +21 -0
- package/novac/README.md +1823 -0
- package/novac/bin/novac +950 -0
- package/novac/bin/nvc +522 -0
- package/novac/bin/nvml +542 -0
- package/novac/demo.nv +245 -0
- package/novac/demo_builtins.nv +209 -0
- package/novac/demo_http.nv +62 -0
- package/novac/examples/bf.nv +69 -0
- package/novac/examples/math.nv +21 -0
- package/novac/kits/kitai/kitdef.js +2185 -0
- package/novac/kits/kitansi/kitdef.js +1402 -0
- package/novac/kits/kitformat/kitdef.js +1485 -0
- package/novac/kits/kitgps/kitdef.js +1862 -0
- package/novac/kits/kitlibfs/kitdef.js +231 -0
- package/{examples/example-project/nova_modules → novac/kits}/kitlibproc/kitdef.js +3 -2
- package/novac/kits/kitmatrix/ex.js +19 -0
- package/novac/kits/kitmatrix/kitdef.js +960 -0
- package/novac/kits/kitmpatch/kitdef.js +906 -0
- package/novac/kits/kitnovacweb/README.md +1572 -0
- package/novac/kits/kitnovacweb/demo.nv +12 -0
- package/novac/kits/kitnovacweb/demo.nvml +71 -0
- package/novac/kits/kitnovacweb/index.nova +12 -0
- package/novac/kits/kitnovacweb/kitdef.js +692 -0
- package/novac/kits/kitnovacweb/nova.kit.json +8 -0
- package/novac/kits/kitnovacweb/nvml/executor.js +739 -0
- package/novac/kits/kitnovacweb/nvml/index.js +67 -0
- package/novac/kits/kitnovacweb/nvml/lexer.js +263 -0
- package/novac/kits/kitnovacweb/nvml/parser.js +508 -0
- package/novac/kits/kitnovacweb/nvml/renderer.js +924 -0
- package/novac/kits/kitparse/kitdef.js +1688 -0
- package/novac/kits/kitregex++/kitdef.js +1353 -0
- package/novac/kits/kitrequire/kitdef.js +1599 -0
- package/novac/kits/kitx11/kitdef.js +1 -0
- package/novac/kits/kitx11/kitx11.js +2472 -0
- package/novac/kits/kitx11/kitx11_conn.js +948 -0
- package/novac/kits/kitx11/kitx11_worker.js +121 -0
- package/novac/kits/libtea/tf.js +2691 -0
- package/novac/kits/libterm/ex.js +285 -0
- package/novac/kits/libterm/kitdef.js +1927 -0
- package/novac/node_modules/chalk/license +9 -0
- package/novac/node_modules/chalk/package.json +83 -0
- package/novac/node_modules/chalk/readme.md +297 -0
- package/novac/node_modules/chalk/source/index.d.ts +325 -0
- package/novac/node_modules/chalk/source/index.js +225 -0
- package/novac/node_modules/chalk/source/utilities.js +33 -0
- package/novac/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
- package/novac/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
- package/novac/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
- package/novac/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
- package/novac/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
- package/novac/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
- package/novac/node_modules/commander/LICENSE +22 -0
- package/novac/node_modules/commander/Readme.md +1176 -0
- package/novac/node_modules/commander/esm.mjs +16 -0
- package/novac/node_modules/commander/index.js +24 -0
- package/novac/node_modules/commander/lib/argument.js +150 -0
- package/novac/node_modules/commander/lib/command.js +2777 -0
- package/novac/node_modules/commander/lib/error.js +39 -0
- package/novac/node_modules/commander/lib/help.js +747 -0
- package/novac/node_modules/commander/lib/option.js +380 -0
- package/novac/node_modules/commander/lib/suggestSimilar.js +101 -0
- package/novac/node_modules/commander/package-support.json +19 -0
- package/novac/node_modules/commander/package.json +82 -0
- package/novac/node_modules/commander/typings/esm.d.mts +3 -0
- package/novac/node_modules/commander/typings/index.d.ts +1113 -0
- package/novac/node_modules/node-addon-api/LICENSE.md +9 -0
- package/novac/node_modules/node-addon-api/README.md +95 -0
- package/novac/node_modules/node-addon-api/common.gypi +21 -0
- package/novac/node_modules/node-addon-api/except.gypi +25 -0
- package/novac/node_modules/node-addon-api/index.js +14 -0
- package/novac/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
- package/novac/node_modules/node-addon-api/napi-inl.h +7165 -0
- package/novac/node_modules/node-addon-api/napi.h +3364 -0
- package/novac/node_modules/node-addon-api/node_addon_api.gyp +42 -0
- package/novac/node_modules/node-addon-api/node_api.gyp +9 -0
- package/novac/node_modules/node-addon-api/noexcept.gypi +26 -0
- package/novac/node_modules/node-addon-api/package-support.json +21 -0
- package/novac/node_modules/node-addon-api/package.json +480 -0
- package/novac/node_modules/node-addon-api/tools/README.md +73 -0
- package/novac/node_modules/node-addon-api/tools/check-napi.js +99 -0
- package/novac/node_modules/node-addon-api/tools/clang-format.js +71 -0
- package/novac/node_modules/node-addon-api/tools/conversion.js +301 -0
- package/novac/node_modules/serialize-javascript/LICENSE +27 -0
- package/novac/node_modules/serialize-javascript/README.md +149 -0
- package/novac/node_modules/serialize-javascript/index.js +297 -0
- package/novac/node_modules/serialize-javascript/package.json +33 -0
- package/novac/package.json +27 -0
- package/novac/scripts/update-bin.js +24 -0
- package/novac/src/core/bstd.js +1035 -0
- package/novac/src/core/config.js +155 -0
- package/novac/src/core/describe.js +187 -0
- package/novac/src/core/emitter.js +499 -0
- package/novac/src/core/error.js +86 -0
- package/novac/src/core/executor.js +5606 -0
- package/novac/src/core/formatter.js +686 -0
- package/novac/src/core/lexer.js +1026 -0
- package/novac/src/core/nova_builtins.js +717 -0
- package/novac/src/core/nova_thread_worker.js +166 -0
- package/novac/src/core/parser.js +2181 -0
- package/novac/src/core/types.js +112 -0
- package/novac/src/index.js +28 -0
- package/novac/src/runtime/stdlib.js +244 -0
- package/package.json +6 -3
- package/scripts/update-bin.js +0 -0
- package/src/core/bstd.js +838 -362
- package/src/core/executor.js +2578 -170
- package/src/core/lexer.js +502 -54
- package/src/core/nova_builtins.js +21 -3
- package/src/core/parser.js +413 -72
- package/src/core/types.js +30 -2
- package/src/index.js +0 -0
- package/examples/example-project/README.md +0 -3
- package/examples/example-project/src/main.nova +0 -3
- package/src/core/environment.js +0 -0
- /package/{examples/example-project/bin/example-project.nv → novac/node_modules/node-addon-api/nothing.c} +0 -0
|
@@ -0,0 +1,1402 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ============================================================
|
|
4
|
+
// kitansi.js — Full ANSI escape sequence kit
|
|
5
|
+
// Every sequence. Every control. Every color system.
|
|
6
|
+
// module.exports = { kitdef: { ...all exports } }
|
|
7
|
+
// ============================================================
|
|
8
|
+
|
|
9
|
+
// ────────────────────────────────────────────────────────────
|
|
10
|
+
// SECTION 1: CORE ESCAPE PRIMITIVES
|
|
11
|
+
// ────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
const ESC = '\x1b'; // Escape character
|
|
14
|
+
const CSI = '\x1b['; // Control Sequence Introducer
|
|
15
|
+
const OSC = '\x1b]'; // Operating System Command
|
|
16
|
+
const DCS = '\x1bP'; // Device Control String
|
|
17
|
+
const ST = '\x1b\\'; // String Terminator
|
|
18
|
+
const BEL = '\x07'; // Bell character (alt ST for OSC)
|
|
19
|
+
const SS3 = '\x1bO'; // Single Shift Three
|
|
20
|
+
const PM = '\x1b^'; // Privacy Message
|
|
21
|
+
const APC = '\x1b_'; // Application Program Command
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Raw CSI sequence builder.
|
|
25
|
+
* @param {string} code
|
|
26
|
+
* @returns {string}
|
|
27
|
+
*/
|
|
28
|
+
function csi(code) { return CSI + code; }
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Raw OSC sequence builder.
|
|
32
|
+
* @param {string} code
|
|
33
|
+
* @returns {string}
|
|
34
|
+
*/
|
|
35
|
+
function osc(code) { return OSC + code + BEL; }
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Raw OSC sequence with ST terminator instead of BEL.
|
|
39
|
+
*/
|
|
40
|
+
function oscST(code) { return OSC + code + ST; }
|
|
41
|
+
|
|
42
|
+
// ────────────────────────────────────────────────────────────
|
|
43
|
+
// SECTION 2: SGR — SELECT GRAPHIC RENDITION (styles/colors)
|
|
44
|
+
// ────────────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Build a CSI SGR sequence from numeric codes.
|
|
48
|
+
* @param {...number} codes
|
|
49
|
+
* @returns {string}
|
|
50
|
+
*/
|
|
51
|
+
function sgr(...codes) { return CSI + codes.join(';') + 'm'; }
|
|
52
|
+
|
|
53
|
+
// ── Reset ────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
const RESET = sgr(0); // Reset all attributes
|
|
56
|
+
const RESET_FG = sgr(39); // Default foreground color
|
|
57
|
+
const RESET_BG = sgr(49); // Default background color
|
|
58
|
+
const RESET_UNDER = sgr(59); // Default underline color
|
|
59
|
+
|
|
60
|
+
// ── Text style codes ─────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
const Style = {
|
|
63
|
+
RESET: sgr(0),
|
|
64
|
+
BOLD: sgr(1),
|
|
65
|
+
DIM: sgr(2),
|
|
66
|
+
ITALIC: sgr(3),
|
|
67
|
+
UNDERLINE: sgr(4),
|
|
68
|
+
BLINK: sgr(5), // Slow blink (<150/min)
|
|
69
|
+
BLINK_FAST: sgr(6), // Rapid blink (≥150/min, limited support)
|
|
70
|
+
INVERSE: sgr(7), // Swap fg/bg
|
|
71
|
+
HIDDEN: sgr(8), // Invisible (conceal)
|
|
72
|
+
STRIKE: sgr(9), // Strikethrough
|
|
73
|
+
FONT_DEFAULT: sgr(10), // Primary font
|
|
74
|
+
FONT_ALT_1: sgr(11),
|
|
75
|
+
FONT_ALT_2: sgr(12),
|
|
76
|
+
FONT_ALT_3: sgr(13),
|
|
77
|
+
FONT_ALT_4: sgr(14),
|
|
78
|
+
FONT_ALT_5: sgr(15),
|
|
79
|
+
FONT_ALT_6: sgr(16),
|
|
80
|
+
FONT_ALT_7: sgr(17),
|
|
81
|
+
FONT_ALT_8: sgr(18),
|
|
82
|
+
FONT_ALT_9: sgr(19),
|
|
83
|
+
FRAKTUR: sgr(20), // Gothic / Fraktur (rare)
|
|
84
|
+
BOLD_OFF: sgr(21), // Bold off (or double underline)
|
|
85
|
+
NORMAL: sgr(22), // Normal intensity (bold+dim off)
|
|
86
|
+
ITALIC_OFF: sgr(23),
|
|
87
|
+
UNDERLINE_OFF: sgr(24),
|
|
88
|
+
BLINK_OFF: sgr(25),
|
|
89
|
+
PROPORTIONAL: sgr(26), // Proportional spacing (rare)
|
|
90
|
+
INVERSE_OFF: sgr(27),
|
|
91
|
+
REVEAL: sgr(28), // Conceal off
|
|
92
|
+
STRIKE_OFF: sgr(29),
|
|
93
|
+
// 30-37: standard fg (see Color)
|
|
94
|
+
// 38: extended fg
|
|
95
|
+
// 39: default fg
|
|
96
|
+
// 40-47: standard bg (see Color)
|
|
97
|
+
// 48: extended bg
|
|
98
|
+
// 49: default bg
|
|
99
|
+
PROPORTIONAL_OFF: sgr(50),
|
|
100
|
+
FRAMED: sgr(51),
|
|
101
|
+
ENCIRCLED: sgr(52),
|
|
102
|
+
OVERLINE: sgr(53),
|
|
103
|
+
FRAMED_OFF: sgr(54), // Framed + encircled off
|
|
104
|
+
OVERLINE_OFF: sgr(55),
|
|
105
|
+
// 58: underline color (extended)
|
|
106
|
+
// 59: default underline color
|
|
107
|
+
SUPERSCRIPT: sgr(73), // Rare; mintty etc.
|
|
108
|
+
SUBSCRIPT: sgr(74),
|
|
109
|
+
SUPERSCRIPT_OFF:sgr(75),
|
|
110
|
+
DOUBLE_UNDERLINE: sgr(21), // In some terminals = double underline
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// ── Standard 16 colors ───────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
const Color = {
|
|
116
|
+
// Foreground
|
|
117
|
+
FG_BLACK: sgr(30),
|
|
118
|
+
FG_RED: sgr(31),
|
|
119
|
+
FG_GREEN: sgr(32),
|
|
120
|
+
FG_YELLOW: sgr(33),
|
|
121
|
+
FG_BLUE: sgr(34),
|
|
122
|
+
FG_MAGENTA: sgr(35),
|
|
123
|
+
FG_CYAN: sgr(36),
|
|
124
|
+
FG_WHITE: sgr(37),
|
|
125
|
+
FG_DEFAULT: sgr(39),
|
|
126
|
+
FG_BRIGHT_BLACK: sgr(90), // "Gray" / dark gray
|
|
127
|
+
FG_BRIGHT_RED: sgr(91),
|
|
128
|
+
FG_BRIGHT_GREEN: sgr(92),
|
|
129
|
+
FG_BRIGHT_YELLOW: sgr(93),
|
|
130
|
+
FG_BRIGHT_BLUE: sgr(94),
|
|
131
|
+
FG_BRIGHT_MAGENTA: sgr(95),
|
|
132
|
+
FG_BRIGHT_CYAN: sgr(96),
|
|
133
|
+
FG_BRIGHT_WHITE: sgr(97),
|
|
134
|
+
|
|
135
|
+
// Background
|
|
136
|
+
BG_BLACK: sgr(40),
|
|
137
|
+
BG_RED: sgr(41),
|
|
138
|
+
BG_GREEN: sgr(42),
|
|
139
|
+
BG_YELLOW: sgr(43),
|
|
140
|
+
BG_BLUE: sgr(44),
|
|
141
|
+
BG_MAGENTA: sgr(45),
|
|
142
|
+
BG_CYAN: sgr(46),
|
|
143
|
+
BG_WHITE: sgr(47),
|
|
144
|
+
BG_DEFAULT: sgr(49),
|
|
145
|
+
BG_BRIGHT_BLACK: sgr(100),
|
|
146
|
+
BG_BRIGHT_RED: sgr(101),
|
|
147
|
+
BG_BRIGHT_GREEN: sgr(102),
|
|
148
|
+
BG_BRIGHT_YELLOW: sgr(103),
|
|
149
|
+
BG_BRIGHT_BLUE: sgr(104),
|
|
150
|
+
BG_BRIGHT_MAGENTA: sgr(105),
|
|
151
|
+
BG_BRIGHT_CYAN: sgr(106),
|
|
152
|
+
BG_BRIGHT_WHITE: sgr(107),
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// ── 256-color ─────────────────────────────────────────────────
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Set foreground to a 256-color palette entry (0–255).
|
|
159
|
+
* @param {number} n
|
|
160
|
+
* @returns {string}
|
|
161
|
+
*/
|
|
162
|
+
function fg256(n) { return sgr(38, 5, n); }
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Set background to a 256-color palette entry (0–255).
|
|
166
|
+
* @param {number} n
|
|
167
|
+
* @returns {string}
|
|
168
|
+
*/
|
|
169
|
+
function bg256(n) { return sgr(48, 5, n); }
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Set underline color to a 256-color palette entry.
|
|
173
|
+
* @param {number} n
|
|
174
|
+
* @returns {string}
|
|
175
|
+
*/
|
|
176
|
+
function ul256(n) { return sgr(58, 5, n); }
|
|
177
|
+
|
|
178
|
+
// ── True color (24-bit RGB) ───────────────────────────────────
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Set foreground to an RGB true color.
|
|
182
|
+
* @param {number} r 0–255
|
|
183
|
+
* @param {number} g 0–255
|
|
184
|
+
* @param {number} b 0–255
|
|
185
|
+
* @returns {string}
|
|
186
|
+
*/
|
|
187
|
+
function fgRGB(r, g, b) { return sgr(38, 2, r, g, b); }
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Set background to an RGB true color.
|
|
191
|
+
*/
|
|
192
|
+
function bgRGB(r, g, b) { return sgr(48, 2, r, g, b); }
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Set underline color to an RGB true color.
|
|
196
|
+
*/
|
|
197
|
+
function ulRGB(r, g, b) { return sgr(58, 2, r, g, b); }
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Parse a hex color string (#RGB or #RRGGBB) to [r, g, b].
|
|
201
|
+
* @param {string} hex
|
|
202
|
+
* @returns {[number, number, number]}
|
|
203
|
+
*/
|
|
204
|
+
function _hexToRGB(hex) {
|
|
205
|
+
hex = hex.replace('#', '');
|
|
206
|
+
if (hex.length === 3) hex = hex.split('').map(c => c + c).join('');
|
|
207
|
+
return [
|
|
208
|
+
parseInt(hex.slice(0, 2), 16),
|
|
209
|
+
parseInt(hex.slice(2, 4), 16),
|
|
210
|
+
parseInt(hex.slice(4, 6), 16),
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Set foreground to a hex color.
|
|
216
|
+
* @param {string} hex '#RRGGBB' or '#RGB'
|
|
217
|
+
* @returns {string}
|
|
218
|
+
*/
|
|
219
|
+
function fgHex(hex) { return fgRGB(..._hexToRGB(hex)); }
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Set background to a hex color.
|
|
223
|
+
*/
|
|
224
|
+
function bgHex(hex) { return bgRGB(..._hexToRGB(hex)); }
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Set underline color to a hex color.
|
|
228
|
+
*/
|
|
229
|
+
function ulHex(hex) { return ulRGB(..._hexToRGB(hex)); }
|
|
230
|
+
|
|
231
|
+
// ── Underline style (kitty / VTE extension) ──────────────────
|
|
232
|
+
|
|
233
|
+
const UnderlineStyle = {
|
|
234
|
+
OFF: sgr(4, 0), // No underline
|
|
235
|
+
SINGLE: sgr(4, 1), // Single underline (or just sgr(4))
|
|
236
|
+
DOUBLE: sgr(4, 2), // Double underline
|
|
237
|
+
CURLY: sgr(4, 3), // Curly / wavy underline
|
|
238
|
+
DOTTED: sgr(4, 4), // Dotted underline
|
|
239
|
+
DASHED: sgr(4, 5), // Dashed underline
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// ── Composite: wrap a string with open/close SGR codes ────────
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Wrap a string with one or more SGR open codes, closing with RESET.
|
|
246
|
+
* @param {string} str
|
|
247
|
+
* @param {...number} codes SGR numeric codes
|
|
248
|
+
* @returns {string}
|
|
249
|
+
*/
|
|
250
|
+
function wrap(str, ...codes) {
|
|
251
|
+
return sgr(...codes) + str + RESET;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Wrap a string with explicit open and close SGR sequences.
|
|
256
|
+
* @param {string} str
|
|
257
|
+
* @param {string} open - full escape sequence to prepend
|
|
258
|
+
* @param {string} close - full escape sequence to append
|
|
259
|
+
* @returns {string}
|
|
260
|
+
*/
|
|
261
|
+
function wrapRaw(str, open, close) {
|
|
262
|
+
return open + str + close;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ────────────────────────────────────────────────────────────
|
|
266
|
+
// SECTION 3: CURSOR CONTROL
|
|
267
|
+
// ────────────────────────────────────────────────────────────
|
|
268
|
+
|
|
269
|
+
const Cursor = {
|
|
270
|
+
// ── Absolute positioning ─────────────────────────────────
|
|
271
|
+
|
|
272
|
+
/** Move cursor to row, col (1-based). */
|
|
273
|
+
to: (row, col) => csi(`${row};${col}H`),
|
|
274
|
+
/** Alias: CUP — Cursor Position. */
|
|
275
|
+
pos: (row, col) => csi(`${row};${col}H`),
|
|
276
|
+
/** Move to column (1-based). */
|
|
277
|
+
toCol: (col) => csi(`${col}G`),
|
|
278
|
+
/** Move to row (1-based). */
|
|
279
|
+
toRow: (row) => csi(`${row}d`),
|
|
280
|
+
|
|
281
|
+
// ── Relative movement ────────────────────────────────────
|
|
282
|
+
|
|
283
|
+
/** Move up N lines. */
|
|
284
|
+
up: (n = 1) => csi(`${n}A`),
|
|
285
|
+
/** Move down N lines. */
|
|
286
|
+
down: (n = 1) => csi(`${n}B`),
|
|
287
|
+
/** Move right N columns. */
|
|
288
|
+
right: (n = 1) => csi(`${n}C`),
|
|
289
|
+
/** Move left N columns. */
|
|
290
|
+
left: (n = 1) => csi(`${n}D`),
|
|
291
|
+
/** Move down N lines, to column 1 (CNL). */
|
|
292
|
+
nextLine: (n = 1) => csi(`${n}E`),
|
|
293
|
+
/** Move up N lines, to column 1 (CPL). */
|
|
294
|
+
prevLine: (n = 1) => csi(`${n}F`),
|
|
295
|
+
|
|
296
|
+
// ── Save / Restore ───────────────────────────────────────
|
|
297
|
+
|
|
298
|
+
/** Save cursor position (ANSI/VT100). */
|
|
299
|
+
save: ESC + '7',
|
|
300
|
+
/** Restore cursor position (ANSI/VT100). */
|
|
301
|
+
restore: ESC + '8',
|
|
302
|
+
/** Save cursor position (CSI variant). */
|
|
303
|
+
saveCSI: csi('s'),
|
|
304
|
+
/** Restore cursor position (CSI variant). */
|
|
305
|
+
restoreCSI: csi('u'),
|
|
306
|
+
/** Save cursor + attrs (DECSC). */
|
|
307
|
+
saveDEC: ESC + '7',
|
|
308
|
+
/** Restore cursor + attrs (DECRC). */
|
|
309
|
+
restoreDEC: ESC + '8',
|
|
310
|
+
|
|
311
|
+
// ── Visibility ───────────────────────────────────────────
|
|
312
|
+
|
|
313
|
+
/** Hide cursor. */
|
|
314
|
+
hide: csi('?25l'),
|
|
315
|
+
/** Show cursor. */
|
|
316
|
+
show: csi('?25h'),
|
|
317
|
+
|
|
318
|
+
// ── Style (DECSCUSR) ─────────────────────────────────────
|
|
319
|
+
|
|
320
|
+
/** Cursor styles via DECSCUSR. */
|
|
321
|
+
style: {
|
|
322
|
+
DEFAULT: csi('0 q'),
|
|
323
|
+
BLOCK_BLINK: csi('1 q'),
|
|
324
|
+
BLOCK_STEADY: csi('2 q'),
|
|
325
|
+
UNDERLINE_BLINK: csi('3 q'),
|
|
326
|
+
UNDERLINE_STEADY: csi('4 q'),
|
|
327
|
+
BAR_BLINK: csi('5 q'),
|
|
328
|
+
BAR_STEADY: csi('6 q'),
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
// ── Blinking ─────────────────────────────────────────────
|
|
332
|
+
|
|
333
|
+
/** Enable cursor blinking. */
|
|
334
|
+
blinkOn: csi('?12h'),
|
|
335
|
+
/** Disable cursor blinking. */
|
|
336
|
+
blinkOff: csi('?12l'),
|
|
337
|
+
|
|
338
|
+
// ── Report ───────────────────────────────────────────────
|
|
339
|
+
|
|
340
|
+
/** Request cursor position report (CPR). Terminal replies with ESC[row;colR. */
|
|
341
|
+
report: csi('6n'),
|
|
342
|
+
/** Request extended cursor position (DECXCPR). */
|
|
343
|
+
reportExt: csi('?6n'),
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// ────────────────────────────────────────────────────────────
|
|
347
|
+
// SECTION 4: SCREEN / LINE ERASING
|
|
348
|
+
// ────────────────────────────────────────────────────────────
|
|
349
|
+
|
|
350
|
+
const Erase = {
|
|
351
|
+
// ── Display ──────────────────────────────────────────────
|
|
352
|
+
|
|
353
|
+
/** Erase from cursor to end of screen (ED 0). */
|
|
354
|
+
toEndOfScreen: csi('0J'),
|
|
355
|
+
/** Erase from start of screen to cursor (ED 1). */
|
|
356
|
+
toStartOfScreen: csi('1J'),
|
|
357
|
+
/** Erase entire screen (ED 2). */
|
|
358
|
+
screen: csi('2J'),
|
|
359
|
+
/** Erase entire screen + scrollback buffer (ED 3, xterm). */
|
|
360
|
+
screenAndScrollback:csi('3J'),
|
|
361
|
+
|
|
362
|
+
// ── Line ─────────────────────────────────────────────────
|
|
363
|
+
|
|
364
|
+
/** Erase from cursor to end of line (EL 0). */
|
|
365
|
+
toEndOfLine: csi('0K'),
|
|
366
|
+
/** Erase from start of line to cursor (EL 1). */
|
|
367
|
+
toStartOfLine: csi('1K'),
|
|
368
|
+
/** Erase entire current line (EL 2). */
|
|
369
|
+
line: csi('2K'),
|
|
370
|
+
|
|
371
|
+
// ── Characters ───────────────────────────────────────────
|
|
372
|
+
|
|
373
|
+
/** Erase N characters at cursor position (ECH). */
|
|
374
|
+
chars: (n = 1) => csi(`${n}X`),
|
|
375
|
+
/** Delete N characters from cursor (DCH, shifts left). */
|
|
376
|
+
deleteChars: (n = 1) => csi(`${n}P`),
|
|
377
|
+
/** Delete N lines from cursor (DL, shifts up). */
|
|
378
|
+
deleteLines: (n = 1) => csi(`${n}M`),
|
|
379
|
+
|
|
380
|
+
// ── Insert ───────────────────────────────────────────────
|
|
381
|
+
|
|
382
|
+
/** Insert N blank characters at cursor (ICH, shifts right). */
|
|
383
|
+
insertChars: (n = 1) => csi(`${n}@`),
|
|
384
|
+
/** Insert N blank lines at cursor (IL, shifts down). */
|
|
385
|
+
insertLines: (n = 1) => csi(`${n}L`),
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
// ────────────────────────────────────────────────────────────
|
|
389
|
+
// SECTION 5: SCROLLING
|
|
390
|
+
// ────────────────────────────────────────────────────────────
|
|
391
|
+
|
|
392
|
+
const Scroll = {
|
|
393
|
+
/** Scroll up N lines (SU — new lines at bottom). */
|
|
394
|
+
up: (n = 1) => csi(`${n}S`),
|
|
395
|
+
/** Scroll down N lines (SD — new lines at top). */
|
|
396
|
+
down: (n = 1) => csi(`${n}T`),
|
|
397
|
+
/** Set scrolling region top/bottom rows (DECSTBM, 1-based). */
|
|
398
|
+
region: (top, bottom) => csi(`${top};${bottom}r`),
|
|
399
|
+
/** Reset scrolling region to full screen. */
|
|
400
|
+
resetRegion: csi('r'),
|
|
401
|
+
/** Enable smooth (slow) scroll. */
|
|
402
|
+
smoothOn: csi('?4h'),
|
|
403
|
+
/** Disable smooth scroll (jump scroll). */
|
|
404
|
+
smoothOff: csi('?4l'),
|
|
405
|
+
/** Save scrolling region. */
|
|
406
|
+
save: ESC + '7',
|
|
407
|
+
/** Restore scrolling region. */
|
|
408
|
+
restore: ESC + '8',
|
|
409
|
+
/** Pan down (DECBI — Back Index). */
|
|
410
|
+
panDown: ESC + '6',
|
|
411
|
+
/** Pan up (DECFI — Forward Index). */
|
|
412
|
+
panUp: ESC + '9',
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
// ────────────────────────────────────────────────────────────
|
|
416
|
+
// SECTION 6: SCREEN MODES & ALTERNATE BUFFER
|
|
417
|
+
// ────────────────────────────────────────────────────────────
|
|
418
|
+
|
|
419
|
+
const Screen = {
|
|
420
|
+
// ── Alternate screen buffer ──────────────────────────────
|
|
421
|
+
|
|
422
|
+
/** Enter alternate screen buffer (xterm). */
|
|
423
|
+
altOn: csi('?1049h'),
|
|
424
|
+
/** Leave alternate screen buffer. */
|
|
425
|
+
altOff: csi('?1049l'),
|
|
426
|
+
/** Enter alternate screen (simple, no save/restore). */
|
|
427
|
+
altSimpleOn: csi('?47h'),
|
|
428
|
+
/** Leave alternate screen (simple). */
|
|
429
|
+
altSimpleOff: csi('?47l'),
|
|
430
|
+
|
|
431
|
+
// ── Screen modes ─────────────────────────────────────────
|
|
432
|
+
|
|
433
|
+
/** 40×25 monochrome (text). */
|
|
434
|
+
mode40x25Mono: csi('=0h'),
|
|
435
|
+
/** 40×25 color. */
|
|
436
|
+
mode40x25Color: csi('=1h'),
|
|
437
|
+
/** 80×25 monochrome. */
|
|
438
|
+
mode80x25Mono: csi('=2h'),
|
|
439
|
+
/** 80×25 color. */
|
|
440
|
+
mode80x25Color: csi('=3h'),
|
|
441
|
+
/** 320×200 4-color. */
|
|
442
|
+
mode320x200_4: csi('=4h'),
|
|
443
|
+
/** 320×200 monochrome. */
|
|
444
|
+
mode320x200Mono:csi('=5h'),
|
|
445
|
+
/** 320×200 color (mode 13h). */
|
|
446
|
+
mode320x200_256:csi('=13h'),
|
|
447
|
+
/** 640×200 monochrome. */
|
|
448
|
+
mode640x200Mono:csi('=6h'),
|
|
449
|
+
/** 640×200 color. */
|
|
450
|
+
mode640x200Color:csi('=14h'),
|
|
451
|
+
/** Line wrap on. */
|
|
452
|
+
wrapOn: csi('?7h'),
|
|
453
|
+
/** Line wrap off. */
|
|
454
|
+
wrapOff: csi('?7l'),
|
|
455
|
+
/** Reverse video (light background). */
|
|
456
|
+
reverseOn: csi('?5h'),
|
|
457
|
+
/** Normal video. */
|
|
458
|
+
reverseOff: csi('?5l'),
|
|
459
|
+
/** Enable bracketed paste mode. */
|
|
460
|
+
bracketedPasteOn: csi('?2004h'),
|
|
461
|
+
/** Disable bracketed paste mode. */
|
|
462
|
+
bracketedPasteOff: csi('?2004l'),
|
|
463
|
+
/** Enable focus reporting. */
|
|
464
|
+
focusReportOn: csi('?1004h'),
|
|
465
|
+
/** Disable focus reporting. */
|
|
466
|
+
focusReportOff: csi('?1004l'),
|
|
467
|
+
|
|
468
|
+
// ── Resize ────────────────────────────────────────────────
|
|
469
|
+
|
|
470
|
+
/** Resize terminal to cols×rows (xterm CSI 8 ; rows ; cols t). */
|
|
471
|
+
resize: (rows, cols) => csi(`8;${rows};${cols}t`),
|
|
472
|
+
/** Maximize window. */
|
|
473
|
+
maximize: csi('9;1t'),
|
|
474
|
+
/** Restore window size. */
|
|
475
|
+
restoreSize: csi('9;0t'),
|
|
476
|
+
/** Raise window to front. */
|
|
477
|
+
raise: csi('5t'),
|
|
478
|
+
/** Lower window. */
|
|
479
|
+
lower: csi('6t'),
|
|
480
|
+
/** Refresh / repaint window. */
|
|
481
|
+
repaint: csi('7t'),
|
|
482
|
+
/** Report terminal size in chars (CSI 18 t). */
|
|
483
|
+
reportSize: csi('18t'),
|
|
484
|
+
/** Report screen size in chars (CSI 19 t). */
|
|
485
|
+
reportScreenSize: csi('19t'),
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
// ────────────────────────────────────────────────────────────
|
|
489
|
+
// SECTION 7: MOUSE REPORTING
|
|
490
|
+
// ────────────────────────────────────────────────────────────
|
|
491
|
+
|
|
492
|
+
const Mouse = {
|
|
493
|
+
// ── Basic mouse ──────────────────────────────────────────
|
|
494
|
+
|
|
495
|
+
/** Enable X10 mouse (button press only). */
|
|
496
|
+
x10On: csi('?9h'),
|
|
497
|
+
x10Off: csi('?9l'),
|
|
498
|
+
|
|
499
|
+
/** Enable normal (VT200) mouse reporting (press+release). */
|
|
500
|
+
normalOn: csi('?1000h'),
|
|
501
|
+
normalOff: csi('?1000l'),
|
|
502
|
+
|
|
503
|
+
/** Enable mouse highlight tracking. */
|
|
504
|
+
highlightOn: csi('?1001h'),
|
|
505
|
+
highlightOff: csi('?1001l'),
|
|
506
|
+
|
|
507
|
+
/** Enable button-event mouse reporting. */
|
|
508
|
+
buttonOn: csi('?1002h'),
|
|
509
|
+
buttonOff: csi('?1002l'),
|
|
510
|
+
|
|
511
|
+
/** Enable any-event mouse reporting (motion too). */
|
|
512
|
+
anyOn: csi('?1003h'),
|
|
513
|
+
anyOff: csi('?1003l'),
|
|
514
|
+
|
|
515
|
+
// ── Extended encoding ────────────────────────────────────
|
|
516
|
+
|
|
517
|
+
/** UTF-8 extended mouse mode (xterm). */
|
|
518
|
+
utf8On: csi('?1005h'),
|
|
519
|
+
utf8Off: csi('?1005l'),
|
|
520
|
+
|
|
521
|
+
/** SGR extended mouse mode (recommended; supports >223 cols). */
|
|
522
|
+
sgrOn: csi('?1006h'),
|
|
523
|
+
sgrOff: csi('?1006l'),
|
|
524
|
+
|
|
525
|
+
/** URXVT extended mouse mode. */
|
|
526
|
+
urxvtOn: csi('?1015h'),
|
|
527
|
+
urxvtOff: csi('?1015l'),
|
|
528
|
+
|
|
529
|
+
/** SGR pixel-based mouse reporting (xterm 379+). */
|
|
530
|
+
sgrPixelOn: csi('?1016h'),
|
|
531
|
+
sgrPixelOff: csi('?1016l'),
|
|
532
|
+
|
|
533
|
+
// ── Convenience combos ───────────────────────────────────
|
|
534
|
+
|
|
535
|
+
/** Enable full mouse (any-event + SGR encoding). */
|
|
536
|
+
enableFull: csi('?1003h') + csi('?1006h'),
|
|
537
|
+
/** Disable full mouse. */
|
|
538
|
+
disableFull: csi('?1003l') + csi('?1006l'),
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
// ────────────────────────────────────────────────────────────
|
|
542
|
+
// SECTION 8: WINDOW / TITLE (OSC)
|
|
543
|
+
// ────────────────────────────────────────────────────────────
|
|
544
|
+
|
|
545
|
+
const Window = {
|
|
546
|
+
/**
|
|
547
|
+
* Set window title.
|
|
548
|
+
* @param {string} title
|
|
549
|
+
* @returns {string}
|
|
550
|
+
*/
|
|
551
|
+
title: (title) => osc(`0;${title}`),
|
|
552
|
+
/**
|
|
553
|
+
* Set icon name only.
|
|
554
|
+
*/
|
|
555
|
+
iconName: (name) => osc(`1;${name}`),
|
|
556
|
+
/**
|
|
557
|
+
* Set both icon name and window title.
|
|
558
|
+
*/
|
|
559
|
+
titleAndIcon: (title) => osc(`0;${title}`),
|
|
560
|
+
/**
|
|
561
|
+
* Set terminal tab color (iTerm2 / some terminals). Hex e.g. 'ff0000'.
|
|
562
|
+
*/
|
|
563
|
+
tabColor: (hex) => osc(`6;1;bg;red;brightness;${parseInt(hex.slice(0,2),16)}`),
|
|
564
|
+
/**
|
|
565
|
+
* iTerm2: set current directory.
|
|
566
|
+
*/
|
|
567
|
+
currentDir:(path) => osc(`7;file://localhost${path}`),
|
|
568
|
+
/**
|
|
569
|
+
* iTerm2: set mark (shell integration).
|
|
570
|
+
*/
|
|
571
|
+
mark: osc('133;A'),
|
|
572
|
+
/**
|
|
573
|
+
* iTerm2: start of command output.
|
|
574
|
+
*/
|
|
575
|
+
cmdStart: osc('133;C'),
|
|
576
|
+
/**
|
|
577
|
+
* iTerm2: end of command output.
|
|
578
|
+
*/
|
|
579
|
+
cmdEnd: (code=0) => osc(`133;D;${code}`),
|
|
580
|
+
/**
|
|
581
|
+
* Hyperlink (OSC 8). Opens url, closes with empty url.
|
|
582
|
+
* @param {string} url
|
|
583
|
+
* @param {string} text
|
|
584
|
+
* @returns {string}
|
|
585
|
+
*/
|
|
586
|
+
hyperlink: (url, text) => osc(`8;;${url}`) + ST + text + osc('8;;') + ST,
|
|
587
|
+
/**
|
|
588
|
+
* Notify (libnotify via OSC 777, supported by some terminals).
|
|
589
|
+
*/
|
|
590
|
+
notify: (title, body) => osc(`777;notify;${title};${body}`),
|
|
591
|
+
/**
|
|
592
|
+
* Set clipboard contents (OSC 52).
|
|
593
|
+
* @param {string} data - base64-encoded string
|
|
594
|
+
* @param {'c'|'p'|'s'} [buf='c'] - c=clipboard, p=primary, s=secondary
|
|
595
|
+
*/
|
|
596
|
+
clipboard: (data, buf = 'c') => osc(`52;${buf};${data}`),
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
// ────────────────────────────────────────────────────────────
|
|
600
|
+
// SECTION 9: DEVICE CONTROL / TERMINAL QUERIES
|
|
601
|
+
// ────────────────────────────────────────────────────────────
|
|
602
|
+
|
|
603
|
+
const Device = {
|
|
604
|
+
/** Device Attributes (DA1) — request terminal ID. */
|
|
605
|
+
queryDA1: csi('c'),
|
|
606
|
+
/** Secondary Device Attributes (DA2). */
|
|
607
|
+
queryDA2: csi('>c'),
|
|
608
|
+
/** Tertiary Device Attributes (DA3). */
|
|
609
|
+
queryDA3: csi('=c'),
|
|
610
|
+
/** Status report (DSR) — reports cursor position. */
|
|
611
|
+
statusReport: csi('5n'),
|
|
612
|
+
/** DECID — identify terminal. */
|
|
613
|
+
identify: ESC + 'Z',
|
|
614
|
+
/** Request DEC private mode (DECRQM). */
|
|
615
|
+
queryMode: (mode) => csi(`?${mode}$p`),
|
|
616
|
+
/** Soft terminal reset (DECSTR). */
|
|
617
|
+
softReset: csi('!p'),
|
|
618
|
+
/** Hard terminal reset (RIS). */
|
|
619
|
+
hardReset: ESC + 'c',
|
|
620
|
+
/** Invoke character set G0 (SI). */
|
|
621
|
+
charSetG0: '\x0F',
|
|
622
|
+
/** Invoke character set G1 (SO). */
|
|
623
|
+
charSetG1: '\x0E',
|
|
624
|
+
/** Designate G0 as US ASCII. */
|
|
625
|
+
g0ASCII: ESC + '(B',
|
|
626
|
+
/** Designate G0 as DEC special graphics. */
|
|
627
|
+
g0DEC: ESC + '(0',
|
|
628
|
+
/** Conformance Level. */
|
|
629
|
+
conformLevel1: csi('61"p'),
|
|
630
|
+
conformLevel2: csi('62"p'),
|
|
631
|
+
conformLevel3: csi('63"p'),
|
|
632
|
+
conformLevel4: csi('64"p'),
|
|
633
|
+
/** XTVERSION — request terminal version string. */
|
|
634
|
+
queryVersion: csi('>0q'),
|
|
635
|
+
/** XTSMGRAPHICS — sixel / ReGIS graphics queries. */
|
|
636
|
+
querySixel: csi('?1;1;0S'),
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
// ────────────────────────────────────────────────────────────
|
|
640
|
+
// SECTION 10: SPECIAL / MISC SEQUENCES
|
|
641
|
+
// ────────────────────────────────────────────────────────────
|
|
642
|
+
|
|
643
|
+
const Special = {
|
|
644
|
+
/** Bell (BEL). */
|
|
645
|
+
bell: BEL,
|
|
646
|
+
/** Backspace. */
|
|
647
|
+
backspace: '\x08',
|
|
648
|
+
/** Horizontal tab. */
|
|
649
|
+
tab: '\x09',
|
|
650
|
+
/** Line feed. */
|
|
651
|
+
lf: '\x0A',
|
|
652
|
+
/** Vertical tab. */
|
|
653
|
+
vt: '\x0B',
|
|
654
|
+
/** Form feed / new page. */
|
|
655
|
+
ff: '\x0C',
|
|
656
|
+
/** Carriage return. */
|
|
657
|
+
cr: '\x0D',
|
|
658
|
+
/** Return to home position (no erase). */
|
|
659
|
+
home: csi('H'),
|
|
660
|
+
/** Next line (NEL). */
|
|
661
|
+
nextLine: ESC + 'E',
|
|
662
|
+
/** Index (IND) — move down one line. */
|
|
663
|
+
index: ESC + 'D',
|
|
664
|
+
/** Reverse index (RI) — move up one line. */
|
|
665
|
+
reverseIndex: ESC + 'M',
|
|
666
|
+
/** Tab set at current column (HTS). */
|
|
667
|
+
tabSet: ESC + 'H',
|
|
668
|
+
/** Tab clear at current column (TBC 0). */
|
|
669
|
+
tabClear: csi('0g'),
|
|
670
|
+
/** Tab clear all (TBC 3). */
|
|
671
|
+
tabClearAll: csi('3g'),
|
|
672
|
+
/** Tab forward N (CHT). */
|
|
673
|
+
tabForward: (n=1) => csi(`${n}I`),
|
|
674
|
+
/** Tab backward N (CBT). */
|
|
675
|
+
tabBackward: (n=1) => csi(`${n}Z`),
|
|
676
|
+
/** Lock keyboard (DECLL). */
|
|
677
|
+
lockKbd: csi('0q'),
|
|
678
|
+
/** Unlock keyboard. */
|
|
679
|
+
unlockKbd: csi('2q'),
|
|
680
|
+
/** Application Keypad Mode. */
|
|
681
|
+
keypadApp: ESC + '=',
|
|
682
|
+
/** Numeric Keypad Mode. */
|
|
683
|
+
keypadNum: ESC + '>',
|
|
684
|
+
/** Application Cursor Keys (DECCKM). */
|
|
685
|
+
cursorKeysApp: csi('?1h'),
|
|
686
|
+
/** Normal Cursor Keys. */
|
|
687
|
+
cursorKeysNormal: csi('?1l'),
|
|
688
|
+
/** Enable auto-repeat. */
|
|
689
|
+
autoRepeatOn: csi('?8h'),
|
|
690
|
+
/** Disable auto-repeat. */
|
|
691
|
+
autoRepeatOff: csi('?8l'),
|
|
692
|
+
/** Set insert mode (IRM). */
|
|
693
|
+
insertModeOn: csi('4h'),
|
|
694
|
+
/** Set replace mode. */
|
|
695
|
+
insertModeOff: csi('4l'),
|
|
696
|
+
/** Enable local echo. */
|
|
697
|
+
echoOn: csi('12l'),
|
|
698
|
+
/** Disable local echo. */
|
|
699
|
+
echoOff: csi('12h'),
|
|
700
|
+
/** DEC Origin Mode on (DECOM). */
|
|
701
|
+
originModeOn: csi('?6h'),
|
|
702
|
+
/** DEC Origin Mode off. */
|
|
703
|
+
originModeOff: csi('?6l'),
|
|
704
|
+
/** Column 132 mode on (DECCOLM). */
|
|
705
|
+
col132On: csi('?3h'),
|
|
706
|
+
/** Column 80 mode. */
|
|
707
|
+
col80On: csi('?3l'),
|
|
708
|
+
/** Enable 80/132 column switching (DECCOLM allowed). */
|
|
709
|
+
colSwitchOn: csi('?40h'),
|
|
710
|
+
colSwitchOff: csi('?40l'),
|
|
711
|
+
/** Left/right margin mode (DECLRMM). */
|
|
712
|
+
lrMarginOn: csi('?69h'),
|
|
713
|
+
lrMarginOff: csi('?69l'),
|
|
714
|
+
/** Set left and right margins (DECSLRM). */
|
|
715
|
+
setLRMargins: (l, r) => csi(`${l};${r}s`),
|
|
716
|
+
/** Print screen. */
|
|
717
|
+
printScreen: csi('i'),
|
|
718
|
+
/** Print line. */
|
|
719
|
+
printLine: csi('1i'),
|
|
720
|
+
/** Enter print controller mode. */
|
|
721
|
+
printCtrlOn: csi('5i'),
|
|
722
|
+
/** Exit print controller mode. */
|
|
723
|
+
printCtrlOff: csi('4i'),
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
// ────────────────────────────────────────────────────────────
|
|
727
|
+
// SECTION 11: SIXEL GRAPHICS (DCS)
|
|
728
|
+
// ────────────────────────────────────────────────────────────
|
|
729
|
+
|
|
730
|
+
const Sixel = {
|
|
731
|
+
/**
|
|
732
|
+
* Begin a sixel data stream.
|
|
733
|
+
* @param {number} [aspectRatio=0] - 0=1:1 pixels, 2=2:1 etc.
|
|
734
|
+
* @param {number} [background=0] - 0=bg stays, 1=bg clears to first color
|
|
735
|
+
* @param {number} [gridSize=0] - 0=use terminal default
|
|
736
|
+
* @returns {string}
|
|
737
|
+
*/
|
|
738
|
+
begin: (aspectRatio = 0, background = 0, gridSize = 0) =>
|
|
739
|
+
`${DCS}${aspectRatio};${background};${gridSize}q`,
|
|
740
|
+
|
|
741
|
+
/** End sixel data stream. */
|
|
742
|
+
end: ST,
|
|
743
|
+
|
|
744
|
+
/** Wrap raw sixel data in a DCS container. */
|
|
745
|
+
wrap: (data, aspectRatio = 0, background = 0) =>
|
|
746
|
+
`${DCS}${aspectRatio};${background};0q${data}${ST}`,
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Set sixel color register (# n ; 2 ; r ; g ; b for RGB, # n ; 1 ; h ; l ; s for HLS).
|
|
750
|
+
* @param {number} reg - register index 0–255
|
|
751
|
+
* @param {number} r - red 0–100
|
|
752
|
+
* @param {number} g - green 0–100
|
|
753
|
+
* @param {number} b - blue 0–100
|
|
754
|
+
*/
|
|
755
|
+
colorRGB: (reg, r, g, b) => `#${reg};2;${r};${g};${b}`,
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* Set sixel color register (HLS).
|
|
759
|
+
* @param {number} reg
|
|
760
|
+
* @param {number} h hue 0–360
|
|
761
|
+
* @param {number} l lightness 0–100
|
|
762
|
+
* @param {number} s saturation 0–100
|
|
763
|
+
*/
|
|
764
|
+
colorHLS: (reg, h, l, s) => `#${reg};1;${h};${l};${s}`,
|
|
765
|
+
|
|
766
|
+
/** Use a defined color register for following sixel data. */
|
|
767
|
+
useColor: (reg) => `#${reg}`,
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
// ────────────────────────────────────────────────────────────
|
|
771
|
+
// SECTION 12: KITTY GRAPHICS PROTOCOL (APC)
|
|
772
|
+
// ────────────────────────────────────────────────────────────
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Build a kitty graphics protocol APC payload.
|
|
776
|
+
* @param {object} keys - key=value control pairs
|
|
777
|
+
* @param {string} [payload='']
|
|
778
|
+
* @returns {string}
|
|
779
|
+
*/
|
|
780
|
+
function kittyGfx(keys, payload = '') {
|
|
781
|
+
const ctrl = Object.entries(keys).map(([k, v]) => `${k}=${v}`).join(',');
|
|
782
|
+
return `${APC}G${ctrl};${payload}${ST}`;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
const KittyGfx = {
|
|
786
|
+
/**
|
|
787
|
+
* Transmit image data (chunked base64).
|
|
788
|
+
* @param {string} b64data - base64 payload chunk
|
|
789
|
+
* @param {object} [opts]
|
|
790
|
+
* @param {'png'|'rgb'|'rgba'|'jpg'} [opts.format='png']
|
|
791
|
+
* @param {number} [opts.width]
|
|
792
|
+
* @param {number} [opts.height]
|
|
793
|
+
* @param {number} [opts.id] - image id
|
|
794
|
+
* @param {0|1} [opts.more=0] - 1 if more chunks follow
|
|
795
|
+
*/
|
|
796
|
+
transmit: (b64data, opts = {}) => {
|
|
797
|
+
const keys = { a: 't', f: opts.format === 'rgb' ? 24 : opts.format === 'rgba' ? 32 : opts.format === 'jpg' ? 100 : 100, t: 'd' };
|
|
798
|
+
if (opts.width) keys.s = opts.width;
|
|
799
|
+
if (opts.height) keys.v = opts.height;
|
|
800
|
+
if (opts.id) keys.i = opts.id;
|
|
801
|
+
if (opts.more) keys.m = opts.more;
|
|
802
|
+
return kittyGfx(keys, b64data);
|
|
803
|
+
},
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Display a previously transmitted image.
|
|
807
|
+
* @param {number} id
|
|
808
|
+
* @param {object} [opts]
|
|
809
|
+
* @param {number} [opts.x] - display column
|
|
810
|
+
* @param {number} [opts.y] - display row
|
|
811
|
+
* @param {number} [opts.cols] - display columns
|
|
812
|
+
* @param {number} [opts.rows] - display rows
|
|
813
|
+
*/
|
|
814
|
+
display: (id, opts = {}) => {
|
|
815
|
+
const keys = { a: 'p', i: id };
|
|
816
|
+
if (opts.x !== undefined) keys.X = opts.x;
|
|
817
|
+
if (opts.y !== undefined) keys.Y = opts.y;
|
|
818
|
+
if (opts.cols !== undefined) keys.c = opts.cols;
|
|
819
|
+
if (opts.rows !== undefined) keys.r = opts.rows;
|
|
820
|
+
return kittyGfx(keys);
|
|
821
|
+
},
|
|
822
|
+
|
|
823
|
+
/** Delete image by id. */
|
|
824
|
+
delete: (id) => kittyGfx({ a: 'd', d: 'i', i: id }),
|
|
825
|
+
|
|
826
|
+
/** Delete all images. */
|
|
827
|
+
deleteAll: kittyGfx({ a: 'd', d: 'a' }),
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
// ────────────────────────────────────────────────────────────
|
|
831
|
+
// SECTION 13: ITERM2 / WEZTERM INLINE IMAGES (OSC 1337)
|
|
832
|
+
// ────────────────────────────────────────────────────────────
|
|
833
|
+
|
|
834
|
+
const InlineImage = {
|
|
835
|
+
/**
|
|
836
|
+
* Display an inline image (iTerm2 / WezTerm protocol, OSC 1337).
|
|
837
|
+
* @param {string} b64data - base64-encoded image data
|
|
838
|
+
* @param {object} [opts]
|
|
839
|
+
* @param {string} [opts.name]
|
|
840
|
+
* @param {number} [opts.width] - in chars or pixels (e.g. '100px' or 10)
|
|
841
|
+
* @param {number} [opts.height]
|
|
842
|
+
* @param {boolean} [opts.preserveAspect=true]
|
|
843
|
+
* @param {boolean} [opts.inline=true]
|
|
844
|
+
*/
|
|
845
|
+
display: (b64data, opts = {}) => {
|
|
846
|
+
const args = [`size=${b64data.length}`];
|
|
847
|
+
if (opts.name) args.push(`name=${Buffer.from ? Buffer.from(opts.name).toString('base64') : btoa(opts.name)}`);
|
|
848
|
+
if (opts.width) args.push(`width=${opts.width}`);
|
|
849
|
+
if (opts.height) args.push(`height=${opts.height}`);
|
|
850
|
+
args.push(`preserveAspectRatio=${opts.preserveAspect === false ? 0 : 1}`);
|
|
851
|
+
args.push(`inline=${opts.inline === false ? 0 : 1}`);
|
|
852
|
+
return `${OSC}1337;File=${args.join(';')}:${b64data}${BEL}`;
|
|
853
|
+
},
|
|
854
|
+
};
|
|
855
|
+
|
|
856
|
+
// ────────────────────────────────────────────────────────────
|
|
857
|
+
// SECTION 14: STRIP / MEASURE / DETECT
|
|
858
|
+
// ────────────────────────────────────────────────────────────
|
|
859
|
+
|
|
860
|
+
/** Regex matching all ANSI escape sequences. */
|
|
861
|
+
const ANSI_RE = /\x1b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]|][^\x07\x1b]*(?:\x07|\x1b\\)|[()][AB012]|[NOPX^_][\s\S]*?\x1b\\)/g;
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* Strip all ANSI escape sequences from a string.
|
|
865
|
+
* @param {string} str
|
|
866
|
+
* @returns {string}
|
|
867
|
+
*/
|
|
868
|
+
function strip(str) {
|
|
869
|
+
return str.replace(ANSI_RE, '');
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
/**
|
|
873
|
+
* Measure the visible (printable) length of a string after stripping ANSI.
|
|
874
|
+
* Accounts for fullwidth Unicode characters (CJK, emoji) as width 2.
|
|
875
|
+
* @param {string} str
|
|
876
|
+
* @returns {number}
|
|
877
|
+
*/
|
|
878
|
+
function visibleLength(str) {
|
|
879
|
+
const s = strip(str);
|
|
880
|
+
let len = 0;
|
|
881
|
+
for (const cp of s) {
|
|
882
|
+
const code = cp.codePointAt(0);
|
|
883
|
+
// Fullwidth / wide chars: CJK unified, CJK compat, fullwidth forms, emoji blocks
|
|
884
|
+
if (
|
|
885
|
+
(code >= 0x1100 && code <= 0x115F) || // Hangul Jamo
|
|
886
|
+
(code >= 0x2E80 && code <= 0x303E) || // CJK Radicals
|
|
887
|
+
(code >= 0x3041 && code <= 0x33FF) || // Hiragana, Katakana, CJK compat
|
|
888
|
+
(code >= 0x3400 && code <= 0x4DBF) || // CJK Extension A
|
|
889
|
+
(code >= 0x4E00 && code <= 0xA4CF) || // CJK Unified
|
|
890
|
+
(code >= 0xA960 && code <= 0xA97F) || // Hangul Jamo Extended
|
|
891
|
+
(code >= 0xAC00 && code <= 0xD7FF) || // Hangul Syllables
|
|
892
|
+
(code >= 0xF900 && code <= 0xFAFF) || // CJK Compat Ideographs
|
|
893
|
+
(code >= 0xFE10 && code <= 0xFE19) || // Vertical Forms
|
|
894
|
+
(code >= 0xFE30 && code <= 0xFE4F) || // CJK Compat Forms
|
|
895
|
+
(code >= 0xFF01 && code <= 0xFF60) || // Fullwidth ASCII + Halfwidth Katakana
|
|
896
|
+
(code >= 0xFFE0 && code <= 0xFFE6) || // Fullwidth Signs
|
|
897
|
+
(code >= 0x1B000 && code <= 0x1B0FF) || // Kana Supplement
|
|
898
|
+
(code >= 0x1F004 && code <= 0x1F0CF) || // Mahjong / Playing cards
|
|
899
|
+
(code >= 0x1F300 && code <= 0x1F9FF) || // Misc symbols, Emoji
|
|
900
|
+
(code >= 0x20000 && code <= 0x2FFFD) || // CJK Extension B-F
|
|
901
|
+
(code >= 0x30000 && code <= 0x3FFFD) // CJK Extension G
|
|
902
|
+
) {
|
|
903
|
+
len += 2;
|
|
904
|
+
} else if (code >= 0x0300 && code <= 0x036F) {
|
|
905
|
+
// Combining diacriticals: zero width
|
|
906
|
+
} else {
|
|
907
|
+
len += 1;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
return len;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* Detect whether the current environment likely supports ANSI color.
|
|
915
|
+
* @returns {'truecolor'|'256'|'16'|'none'}
|
|
916
|
+
*/
|
|
917
|
+
function detectColorSupport() {
|
|
918
|
+
// Browser / non-Node environment
|
|
919
|
+
if (typeof process === 'undefined') return 'none';
|
|
920
|
+
|
|
921
|
+
const env = process.env || {};
|
|
922
|
+
const argv = process.argv || [];
|
|
923
|
+
const term = (env.TERM || '').toLowerCase();
|
|
924
|
+
const cterm = (env.COLORTERM || '').toLowerCase();
|
|
925
|
+
|
|
926
|
+
// Explicitly disabled
|
|
927
|
+
if (env.NO_COLOR !== undefined || env.NODE_DISABLE_COLORS !== undefined) return 'none';
|
|
928
|
+
if (argv.includes('--no-color') || argv.includes('--color=false')) return 'none';
|
|
929
|
+
|
|
930
|
+
// Force flags
|
|
931
|
+
if (argv.includes('--color=16m') || argv.includes('--color=full')) return 'truecolor';
|
|
932
|
+
if (argv.includes('--color=256')) return '256';
|
|
933
|
+
if (argv.includes('--color')) return '16';
|
|
934
|
+
|
|
935
|
+
// Truecolor env vars
|
|
936
|
+
if (cterm === 'truecolor' || cterm === '24bit') return 'truecolor';
|
|
937
|
+
if (env.TERM_PROGRAM === 'iTerm.app') return 'truecolor';
|
|
938
|
+
if (env.TERM_PROGRAM === 'hyper') return 'truecolor';
|
|
939
|
+
if (env.TERM_PROGRAM === 'vscode') return 'truecolor';
|
|
940
|
+
if (env.WT_SESSION) return 'truecolor'; // Windows Terminal
|
|
941
|
+
if (env.COLORTERM) return '256';
|
|
942
|
+
|
|
943
|
+
// 256 color
|
|
944
|
+
if (term.includes('256color')) return '256';
|
|
945
|
+
if (term.includes('256')) return '256';
|
|
946
|
+
|
|
947
|
+
// 16 color
|
|
948
|
+
if (term.includes('color') || term === 'xterm' || term === 'screen' || term === 'linux') return '16';
|
|
949
|
+
|
|
950
|
+
// Check if stdout is a TTY
|
|
951
|
+
if (process.stdout && process.stdout.isTTY) return '16';
|
|
952
|
+
|
|
953
|
+
return 'none';
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Returns true if the environment supports at least basic color.
|
|
958
|
+
*/
|
|
959
|
+
function hasColor() {
|
|
960
|
+
return detectColorSupport() !== 'none';
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// ────────────────────────────────────────────────────────────
|
|
964
|
+
// SECTION 15: ANSI PARSER
|
|
965
|
+
// ────────────────────────────────────────────────────────────
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* @typedef {object} AnsiToken
|
|
969
|
+
* @property {'text'|'sgr'|'cursor'|'erase'|'osc'|'dcs'|'escape'|'unknown'} type
|
|
970
|
+
* @property {string} raw - the raw escape sequence or text chunk
|
|
971
|
+
* @property {string} [text] - for type='text', the plain text
|
|
972
|
+
* @property {number[]} [codes] - for type='sgr', the SGR code list
|
|
973
|
+
* @property {string} [cmd] - final byte / command identifier
|
|
974
|
+
* @property {string} [params] - raw parameter string
|
|
975
|
+
* @property {string} [payload] - for OSC/DCS, the payload string
|
|
976
|
+
* @property {object} [style] - decoded style object for SGR tokens
|
|
977
|
+
*/
|
|
978
|
+
|
|
979
|
+
const SGR_NAMES = {
|
|
980
|
+
0: 'reset',
|
|
981
|
+
1: 'bold', 2: 'dim', 3: 'italic',
|
|
982
|
+
4: 'underline', 5: 'blink', 6: 'blink_fast',
|
|
983
|
+
7: 'inverse', 8: 'hidden', 9: 'strike',
|
|
984
|
+
21: 'double_underline',
|
|
985
|
+
22: 'normal', 23: 'italic_off', 24: 'underline_off',
|
|
986
|
+
25: 'blink_off', 27: 'inverse_off', 28: 'reveal',
|
|
987
|
+
29: 'strike_off',
|
|
988
|
+
30: 'fg_black', 31: 'fg_red', 32: 'fg_green', 33: 'fg_yellow',
|
|
989
|
+
34: 'fg_blue', 35: 'fg_magenta',36: 'fg_cyan', 37: 'fg_white',
|
|
990
|
+
39: 'fg_default',
|
|
991
|
+
40: 'bg_black', 41: 'bg_red', 42: 'bg_green', 43: 'bg_yellow',
|
|
992
|
+
44: 'bg_blue', 45: 'bg_magenta',46: 'bg_cyan', 47: 'bg_white',
|
|
993
|
+
49: 'bg_default',
|
|
994
|
+
51: 'framed', 52: 'encircled', 53: 'overline',
|
|
995
|
+
54: 'framed_off', 55: 'overline_off',
|
|
996
|
+
90: 'fg_bright_black', 91: 'fg_bright_red', 92: 'fg_bright_green',
|
|
997
|
+
93: 'fg_bright_yellow', 94: 'fg_bright_blue', 95: 'fg_bright_magenta',
|
|
998
|
+
96: 'fg_bright_cyan', 97: 'fg_bright_white',
|
|
999
|
+
100:'bg_bright_black', 101:'bg_bright_red', 102:'bg_bright_green',
|
|
1000
|
+
103:'bg_bright_yellow', 104:'bg_bright_blue', 105:'bg_bright_magenta',
|
|
1001
|
+
106:'bg_bright_cyan', 107:'bg_bright_white',
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* Decode a list of SGR codes into a human-readable style object.
|
|
1006
|
+
* @param {number[]} codes
|
|
1007
|
+
* @returns {object}
|
|
1008
|
+
*/
|
|
1009
|
+
function decodeSGR(codes) {
|
|
1010
|
+
const style = {};
|
|
1011
|
+
let i = 0;
|
|
1012
|
+
while (i < codes.length) {
|
|
1013
|
+
const c = codes[i];
|
|
1014
|
+
if ((c === 38 || c === 48 || c === 58) && codes[i+1] === 2) {
|
|
1015
|
+
// RGB color
|
|
1016
|
+
const [r, g, b] = [codes[i+2], codes[i+3], codes[i+4]];
|
|
1017
|
+
const key = c === 38 ? 'fg' : c === 48 ? 'bg' : 'ul';
|
|
1018
|
+
style[key] = { type: 'rgb', r, g, b, hex: `#${[r,g,b].map(v=>v.toString(16).padStart(2,'0')).join('')}` };
|
|
1019
|
+
i += 5;
|
|
1020
|
+
} else if ((c === 38 || c === 48 || c === 58) && codes[i+1] === 5) {
|
|
1021
|
+
const key = c === 38 ? 'fg' : c === 48 ? 'bg' : 'ul';
|
|
1022
|
+
style[key] = { type: '256', index: codes[i+2] };
|
|
1023
|
+
i += 3;
|
|
1024
|
+
} else {
|
|
1025
|
+
if (SGR_NAMES[c]) style[SGR_NAMES[c]] = true;
|
|
1026
|
+
i++;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
return style;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
/**
|
|
1033
|
+
* Parse a string containing ANSI escape sequences into an array of tokens.
|
|
1034
|
+
* @param {string} str
|
|
1035
|
+
* @returns {AnsiToken[]}
|
|
1036
|
+
*/
|
|
1037
|
+
function parse(str) {
|
|
1038
|
+
const tokens = [];
|
|
1039
|
+
// Tokeniser: match escape sequences or text runs
|
|
1040
|
+
const re = /\x1b(?:(\[)([\x30-\x3F]*)([\x20-\x2F]*)([\x40-\x7E])|(])((?:[^\x07\x1b]|\x1b(?!\\))*?)(?:\x07|\x1b\\)|(P)([\s\S]*?)\x1b\\|([@-Z\\-_]))/g;
|
|
1041
|
+
let last = 0;
|
|
1042
|
+
|
|
1043
|
+
for (let m = re.exec(str); m; m = re.exec(str)) {
|
|
1044
|
+
// Text before this match
|
|
1045
|
+
if (m.index > last) tokens.push({ type: 'text', raw: str.slice(last, m.index), text: str.slice(last, m.index) });
|
|
1046
|
+
last = re.lastIndex;
|
|
1047
|
+
|
|
1048
|
+
if (m[1] === '[') {
|
|
1049
|
+
// CSI sequence
|
|
1050
|
+
const params = m[2] || '';
|
|
1051
|
+
const inter = m[3] || '';
|
|
1052
|
+
const cmd = m[4];
|
|
1053
|
+
const raw = m[0];
|
|
1054
|
+
if (cmd === 'm') {
|
|
1055
|
+
// SGR
|
|
1056
|
+
const codes = params === '' ? [0] : params.split(';').map(Number);
|
|
1057
|
+
tokens.push({ type: 'sgr', raw, params, cmd, codes, style: decodeSGR(codes) });
|
|
1058
|
+
} else if ('ABCDEFGH'.includes(cmd)) {
|
|
1059
|
+
tokens.push({ type: 'cursor', raw, params, cmd });
|
|
1060
|
+
} else if ('JK'.includes(cmd)) {
|
|
1061
|
+
tokens.push({ type: 'erase', raw, params, cmd });
|
|
1062
|
+
} else {
|
|
1063
|
+
tokens.push({ type: 'csi', raw, params, inter, cmd });
|
|
1064
|
+
}
|
|
1065
|
+
} else if (m[5] === ']') {
|
|
1066
|
+
// OSC sequence
|
|
1067
|
+
tokens.push({ type: 'osc', raw: m[0], payload: m[6] });
|
|
1068
|
+
} else if (m[7] === 'P') {
|
|
1069
|
+
// DCS sequence
|
|
1070
|
+
tokens.push({ type: 'dcs', raw: m[0], payload: m[8] });
|
|
1071
|
+
} else {
|
|
1072
|
+
// Single ESC + char
|
|
1073
|
+
tokens.push({ type: 'escape', raw: m[0], cmd: m[9] });
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// Trailing text
|
|
1078
|
+
if (last < str.length) tokens.push({ type: 'text', raw: str.slice(last), text: str.slice(last) });
|
|
1079
|
+
return tokens;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// ────────────────────────────────────────────────────────────
|
|
1083
|
+
// SECTION 16: CHAINABLE ANSI STRING BUILDER
|
|
1084
|
+
// ────────────────────────────────────────────────────────────
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* AnsiString — chainable ANSI-aware string builder.
|
|
1088
|
+
*
|
|
1089
|
+
* Every method returns a new AnsiString (immutable chain).
|
|
1090
|
+
* Call .toString() to get the final escape-code-embedded string.
|
|
1091
|
+
* Call .plain() to get the stripped visible text.
|
|
1092
|
+
*
|
|
1093
|
+
* @example
|
|
1094
|
+
* const s = AnsiString.of('Hello')
|
|
1095
|
+
* .bold()
|
|
1096
|
+
* .fgRGB(255, 100, 0)
|
|
1097
|
+
* .append(' World')
|
|
1098
|
+
* .underline()
|
|
1099
|
+
* .toString();
|
|
1100
|
+
*/
|
|
1101
|
+
class AnsiString {
|
|
1102
|
+
/**
|
|
1103
|
+
* @param {string} [str='']
|
|
1104
|
+
*/
|
|
1105
|
+
constructor(str = '') {
|
|
1106
|
+
this._buf = String(str);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/** Create a new AnsiString from a value. */
|
|
1110
|
+
static of(str = '') { return new AnsiString(str); }
|
|
1111
|
+
|
|
1112
|
+
/** Get the raw (escape-code-embedded) string. */
|
|
1113
|
+
toString() { return this._buf; }
|
|
1114
|
+
valueOf() { return this._buf; }
|
|
1115
|
+
|
|
1116
|
+
/** Get the visible plain text (no escape codes). */
|
|
1117
|
+
plain() { return strip(this._buf); }
|
|
1118
|
+
|
|
1119
|
+
/** Visible character width. */
|
|
1120
|
+
width() { return visibleLength(this._buf); }
|
|
1121
|
+
|
|
1122
|
+
_clone(str) { return new AnsiString(str); }
|
|
1123
|
+
|
|
1124
|
+
// ── Append / prepend ────────────────────────────────────
|
|
1125
|
+
|
|
1126
|
+
/** Append raw text or another AnsiString. */
|
|
1127
|
+
append(str) { return this._clone(this._buf + String(str)); }
|
|
1128
|
+
/** Prepend raw text or another AnsiString. */
|
|
1129
|
+
prepend(str) { return this._clone(String(str) + this._buf); }
|
|
1130
|
+
/** Append a newline. */
|
|
1131
|
+
nl() { return this._clone(this._buf + '\n'); }
|
|
1132
|
+
/** Append a reset code. */
|
|
1133
|
+
reset() { return this._clone(this._buf + RESET); }
|
|
1134
|
+
|
|
1135
|
+
// ── SGR style methods ────────────────────────────────────
|
|
1136
|
+
|
|
1137
|
+
/** Apply one or more raw SGR codes to the current content. */
|
|
1138
|
+
_sgr(openCodes, closeCodes) {
|
|
1139
|
+
return this._clone(sgr(...openCodes) + this._buf + sgr(...closeCodes));
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
bold() { return this._sgr([1], [22]); }
|
|
1143
|
+
dim() { return this._sgr([2], [22]); }
|
|
1144
|
+
italic() { return this._sgr([3], [23]); }
|
|
1145
|
+
underline() { return this._sgr([4], [24]); }
|
|
1146
|
+
blink() { return this._sgr([5], [25]); }
|
|
1147
|
+
blinkFast() { return this._sgr([6], [25]); }
|
|
1148
|
+
inverse() { return this._sgr([7], [27]); }
|
|
1149
|
+
hidden() { return this._sgr([8], [28]); }
|
|
1150
|
+
strike() { return this._sgr([9], [29]); }
|
|
1151
|
+
overline() { return this._sgr([53], [55]); }
|
|
1152
|
+
framed() { return this._sgr([51], [54]); }
|
|
1153
|
+
encircled() { return this._sgr([52], [54]); }
|
|
1154
|
+
doubleUnderline() { return this._sgr([21], [24]); }
|
|
1155
|
+
superscript() { return this._sgr([73], [75]); }
|
|
1156
|
+
subscript() { return this._sgr([74], [75]); }
|
|
1157
|
+
|
|
1158
|
+
// ── Standard 16 colors ───────────────────────────────────
|
|
1159
|
+
|
|
1160
|
+
black() { return this._sgr([30], [39]); }
|
|
1161
|
+
red() { return this._sgr([31], [39]); }
|
|
1162
|
+
green() { return this._sgr([32], [39]); }
|
|
1163
|
+
yellow() { return this._sgr([33], [39]); }
|
|
1164
|
+
blue() { return this._sgr([34], [39]); }
|
|
1165
|
+
magenta() { return this._sgr([35], [39]); }
|
|
1166
|
+
cyan() { return this._sgr([36], [39]); }
|
|
1167
|
+
white() { return this._sgr([37], [39]); }
|
|
1168
|
+
gray() { return this._sgr([90], [39]); }
|
|
1169
|
+
brightRed() { return this._sgr([91], [39]); }
|
|
1170
|
+
brightGreen() { return this._sgr([92], [39]); }
|
|
1171
|
+
brightYellow() { return this._sgr([93], [39]); }
|
|
1172
|
+
brightBlue() { return this._sgr([94], [39]); }
|
|
1173
|
+
brightMagenta() { return this._sgr([95], [39]); }
|
|
1174
|
+
brightCyan() { return this._sgr([96], [39]); }
|
|
1175
|
+
brightWhite() { return this._sgr([97], [39]); }
|
|
1176
|
+
|
|
1177
|
+
bgBlack() { return this._sgr([40], [49]); }
|
|
1178
|
+
bgRed() { return this._sgr([41], [49]); }
|
|
1179
|
+
bgGreen() { return this._sgr([42], [49]); }
|
|
1180
|
+
bgYellow() { return this._sgr([43], [49]); }
|
|
1181
|
+
bgBlue() { return this._sgr([44], [49]); }
|
|
1182
|
+
bgMagenta() { return this._sgr([45], [49]); }
|
|
1183
|
+
bgCyan() { return this._sgr([46], [49]); }
|
|
1184
|
+
bgWhite() { return this._sgr([47], [49]); }
|
|
1185
|
+
bgGray() { return this._sgr([100], [49]); }
|
|
1186
|
+
bgBrightRed() { return this._sgr([101], [49]); }
|
|
1187
|
+
bgBrightGreen() { return this._sgr([102], [49]); }
|
|
1188
|
+
bgBrightYellow() { return this._sgr([103], [49]); }
|
|
1189
|
+
bgBrightBlue() { return this._sgr([104], [49]); }
|
|
1190
|
+
bgBrightMagenta() { return this._sgr([105], [49]); }
|
|
1191
|
+
bgBrightCyan() { return this._sgr([106], [49]); }
|
|
1192
|
+
bgBrightWhite() { return this._sgr([107], [49]); }
|
|
1193
|
+
|
|
1194
|
+
// ── 256 color ────────────────────────────────────────────
|
|
1195
|
+
|
|
1196
|
+
/** Foreground 256-color (0–255). */
|
|
1197
|
+
fg256(n) { return this._clone(fg256(n) + this._buf + sgr(39)); }
|
|
1198
|
+
/** Background 256-color (0–255). */
|
|
1199
|
+
bg256(n) { return this._clone(bg256(n) + this._buf + sgr(49)); }
|
|
1200
|
+
/** Underline 256-color. */
|
|
1201
|
+
ul256(n) { return this._clone(ul256(n) + this._buf + sgr(59)); }
|
|
1202
|
+
|
|
1203
|
+
// ── True color ───────────────────────────────────────────
|
|
1204
|
+
|
|
1205
|
+
/** Foreground RGB. */
|
|
1206
|
+
fgRGB(r, g, b) { return this._clone(fgRGB(r,g,b) + this._buf + sgr(39)); }
|
|
1207
|
+
/** Background RGB. */
|
|
1208
|
+
bgRGB(r, g, b) { return this._clone(bgRGB(r,g,b) + this._buf + sgr(49)); }
|
|
1209
|
+
/** Underline RGB. */
|
|
1210
|
+
ulRGB(r, g, b) { return this._clone(ulRGB(r,g,b) + this._buf + sgr(59)); }
|
|
1211
|
+
/** Foreground hex. */
|
|
1212
|
+
fgHex(hex) { return this._clone(fgHex(hex) + this._buf + sgr(39)); }
|
|
1213
|
+
/** Background hex. */
|
|
1214
|
+
bgHex(hex) { return this._clone(bgHex(hex) + this._buf + sgr(49)); }
|
|
1215
|
+
/** Underline hex. */
|
|
1216
|
+
ulHex(hex) { return this._clone(ulHex(hex) + this._buf + sgr(59)); }
|
|
1217
|
+
|
|
1218
|
+
// ── Gradient (horizontal true-color) ─────────────────────
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Apply a horizontal RGB gradient across the visible characters.
|
|
1222
|
+
* @param {[number,number,number]} from - start [r,g,b]
|
|
1223
|
+
* @param {[number,number,number]} to - end [r,g,b]
|
|
1224
|
+
* @param {'fg'|'bg'} [target='fg']
|
|
1225
|
+
*/
|
|
1226
|
+
gradient(from, to, target = 'fg') {
|
|
1227
|
+
const plain = this.plain();
|
|
1228
|
+
const len = plain.length || 1;
|
|
1229
|
+
let out = '';
|
|
1230
|
+
for (let i = 0; i < plain.length; i++) {
|
|
1231
|
+
const t = i / (len - 1 || 1);
|
|
1232
|
+
const r = Math.round(from[0] + (to[0] - from[0]) * t);
|
|
1233
|
+
const g = Math.round(from[1] + (to[1] - from[1]) * t);
|
|
1234
|
+
const b = Math.round(from[2] + (to[2] - from[2]) * t);
|
|
1235
|
+
out += (target === 'bg' ? bgRGB(r,g,b) : fgRGB(r,g,b)) + plain[i];
|
|
1236
|
+
}
|
|
1237
|
+
out += RESET;
|
|
1238
|
+
return this._clone(out);
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
// ── Underline style ──────────────────────────────────────
|
|
1242
|
+
|
|
1243
|
+
curlyUnderline() { return this._clone(UnderlineStyle.CURLY + this._buf + sgr(24)); }
|
|
1244
|
+
dottedUnderline() { return this._clone(UnderlineStyle.DOTTED + this._buf + sgr(24)); }
|
|
1245
|
+
dashedUnderline() { return this._clone(UnderlineStyle.DASHED + this._buf + sgr(24)); }
|
|
1246
|
+
|
|
1247
|
+
// ── Wrapping helpers ─────────────────────────────────────
|
|
1248
|
+
|
|
1249
|
+
/** Wrap entire current buffer with open/close sequences. */
|
|
1250
|
+
wrap(open, close) { return this._clone(open + this._buf + close); }
|
|
1251
|
+
|
|
1252
|
+
/** Apply an arbitrary transform function to the raw string. */
|
|
1253
|
+
pipe(fn) { return this._clone(fn(this._buf)); }
|
|
1254
|
+
|
|
1255
|
+
/** Strip all ANSI codes. */
|
|
1256
|
+
strip() { return this._clone(strip(this._buf)); }
|
|
1257
|
+
|
|
1258
|
+
/** Pad right to a visible width (ANSI-aware). */
|
|
1259
|
+
padEnd(width, char = ' ') {
|
|
1260
|
+
const vlen = visibleLength(this._buf);
|
|
1261
|
+
if (vlen >= width) return this;
|
|
1262
|
+
return this._clone(this._buf + char.repeat(width - vlen));
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
/** Pad left to a visible width (ANSI-aware). */
|
|
1266
|
+
padStart(width, char = ' ') {
|
|
1267
|
+
const vlen = visibleLength(this._buf);
|
|
1268
|
+
if (vlen >= width) return this;
|
|
1269
|
+
return this._clone(char.repeat(width - vlen) + this._buf);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
/** Center to a visible width (ANSI-aware). */
|
|
1273
|
+
padCenter(width, char = ' ') {
|
|
1274
|
+
const vlen = visibleLength(this._buf);
|
|
1275
|
+
if (vlen >= width) return this;
|
|
1276
|
+
const total = width - vlen;
|
|
1277
|
+
const left = Math.floor(total / 2);
|
|
1278
|
+
const right = total - left;
|
|
1279
|
+
return this._clone(char.repeat(left) + this._buf + char.repeat(right));
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
/** Parse the current string into AnsiTokens. */
|
|
1283
|
+
parse() { return parse(this._buf); }
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// ────────────────────────────────────────────────────────────
|
|
1287
|
+
// SECTION 17: CONVENIENCE WRAP FUNCTIONS
|
|
1288
|
+
// ────────────────────────────────────────────────────────────
|
|
1289
|
+
|
|
1290
|
+
// These are standalone functions that mirror the AnsiString methods
|
|
1291
|
+
// for use without the class.
|
|
1292
|
+
|
|
1293
|
+
const bold = (s) => sgr(1) + s + sgr(22);
|
|
1294
|
+
const dim = (s) => sgr(2) + s + sgr(22);
|
|
1295
|
+
const italic = (s) => sgr(3) + s + sgr(23);
|
|
1296
|
+
const underline = (s) => sgr(4) + s + sgr(24);
|
|
1297
|
+
const blink = (s) => sgr(5) + s + sgr(25);
|
|
1298
|
+
const blinkFast = (s) => sgr(6) + s + sgr(25);
|
|
1299
|
+
const inverse = (s) => sgr(7) + s + sgr(27);
|
|
1300
|
+
const hidden = (s) => sgr(8) + s + sgr(28);
|
|
1301
|
+
const strike = (s) => sgr(9) + s + sgr(29);
|
|
1302
|
+
const overline = (s) => sgr(53) + s + sgr(55);
|
|
1303
|
+
const framed = (s) => sgr(51) + s + sgr(54);
|
|
1304
|
+
|
|
1305
|
+
// FG
|
|
1306
|
+
const black = (s) => sgr(30) + s + sgr(39);
|
|
1307
|
+
const red = (s) => sgr(31) + s + sgr(39);
|
|
1308
|
+
const green = (s) => sgr(32) + s + sgr(39);
|
|
1309
|
+
const yellow = (s) => sgr(33) + s + sgr(39);
|
|
1310
|
+
const blue = (s) => sgr(34) + s + sgr(39);
|
|
1311
|
+
const magenta = (s) => sgr(35) + s + sgr(39);
|
|
1312
|
+
const cyan = (s) => sgr(36) + s + sgr(39);
|
|
1313
|
+
const white = (s) => sgr(37) + s + sgr(39);
|
|
1314
|
+
const gray = (s) => sgr(90) + s + sgr(39);
|
|
1315
|
+
const brightRed = (s) => sgr(91) + s + sgr(39);
|
|
1316
|
+
const brightGreen = (s) => sgr(92) + s + sgr(39);
|
|
1317
|
+
const brightYellow = (s) => sgr(93) + s + sgr(39);
|
|
1318
|
+
const brightBlue = (s) => sgr(94) + s + sgr(39);
|
|
1319
|
+
const brightMagenta = (s) => sgr(95) + s + sgr(39);
|
|
1320
|
+
const brightCyan = (s) => sgr(96) + s + sgr(39);
|
|
1321
|
+
const brightWhite = (s) => sgr(97) + s + sgr(39);
|
|
1322
|
+
|
|
1323
|
+
// BG
|
|
1324
|
+
const bgBlack = (s) => sgr(40) + s + sgr(49);
|
|
1325
|
+
const bgRed = (s) => sgr(41) + s + sgr(49);
|
|
1326
|
+
const bgGreen = (s) => sgr(42) + s + sgr(49);
|
|
1327
|
+
const bgYellow = (s) => sgr(43) + s + sgr(49);
|
|
1328
|
+
const bgBlue = (s) => sgr(44) + s + sgr(49);
|
|
1329
|
+
const bgMagenta = (s) => sgr(45) + s + sgr(49);
|
|
1330
|
+
const bgCyan = (s) => sgr(46) + s + sgr(49);
|
|
1331
|
+
const bgWhite = (s) => sgr(47) + s + sgr(49);
|
|
1332
|
+
const bgGray = (s) => sgr(100) + s + sgr(49);
|
|
1333
|
+
const bgBrightRed = (s) => sgr(101) + s + sgr(49);
|
|
1334
|
+
const bgBrightGreen = (s) => sgr(102) + s + sgr(49);
|
|
1335
|
+
const bgBrightYellow = (s) => sgr(103) + s + sgr(49);
|
|
1336
|
+
const bgBrightBlue = (s) => sgr(104) + s + sgr(49);
|
|
1337
|
+
const bgBrightMagenta = (s) => sgr(105) + s + sgr(49);
|
|
1338
|
+
const bgBrightCyan = (s) => sgr(106) + s + sgr(49);
|
|
1339
|
+
const bgBrightWhite = (s) => sgr(107) + s + sgr(49);
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* Apply a horizontal RGB gradient to a plain string.
|
|
1343
|
+
* @param {string} str
|
|
1344
|
+
* @param {[number,number,number]} from
|
|
1345
|
+
* @param {[number,number,number]} to
|
|
1346
|
+
* @param {'fg'|'bg'} [target='fg']
|
|
1347
|
+
*/
|
|
1348
|
+
function gradient(str, from, to, target = 'fg') {
|
|
1349
|
+
return AnsiString.of(str).gradient(from, to, target).toString();
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// ────────────────────────────────────────────────────────────
|
|
1353
|
+
// EXPORTS
|
|
1354
|
+
// ────────────────────────────────────────────────────────────
|
|
1355
|
+
|
|
1356
|
+
module.exports = {
|
|
1357
|
+
kitdef: {
|
|
1358
|
+
// ── Primitives ──────────────────────────────────
|
|
1359
|
+
ESC, CSI, OSC, DCS, ST, BEL, SS3, PM, APC,
|
|
1360
|
+
csi, osc, oscST, sgr,
|
|
1361
|
+
|
|
1362
|
+
// ── SGR constants ────────────────────────────────
|
|
1363
|
+
RESET, RESET_FG, RESET_BG, RESET_UNDER,
|
|
1364
|
+
Style, Color, UnderlineStyle,
|
|
1365
|
+
|
|
1366
|
+
// ── Color functions ──────────────────────────────
|
|
1367
|
+
fg256, bg256, ul256,
|
|
1368
|
+
fgRGB, bgRGB, ulRGB,
|
|
1369
|
+
fgHex, bgHex, ulHex,
|
|
1370
|
+
|
|
1371
|
+
// ── Wrap helpers ─────────────────────────────────
|
|
1372
|
+
wrap, wrapRaw,
|
|
1373
|
+
|
|
1374
|
+
// ── Standalone style functions ───────────────────
|
|
1375
|
+
bold, dim, italic, underline, blink, blinkFast,
|
|
1376
|
+
inverse, hidden, strike, overline, framed,
|
|
1377
|
+
black, red, green, yellow, blue, magenta, cyan, white, gray,
|
|
1378
|
+
brightRed, brightGreen, brightYellow, brightBlue,
|
|
1379
|
+
brightMagenta, brightCyan, brightWhite,
|
|
1380
|
+
bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta,
|
|
1381
|
+
bgCyan, bgWhite, bgGray, bgBrightRed, bgBrightGreen,
|
|
1382
|
+
bgBrightYellow, bgBrightBlue, bgBrightMagenta,
|
|
1383
|
+
bgBrightCyan, bgBrightWhite,
|
|
1384
|
+
gradient,
|
|
1385
|
+
|
|
1386
|
+
// ── Terminal control ─────────────────────────────
|
|
1387
|
+
Cursor, Erase, Scroll, Screen, Mouse, Window,
|
|
1388
|
+
Device, Special,
|
|
1389
|
+
|
|
1390
|
+
// ── Graphics protocols ───────────────────────────
|
|
1391
|
+
Sixel, KittyGfx, kittyGfx, InlineImage,
|
|
1392
|
+
|
|
1393
|
+
// ── Utilities ────────────────────────────────────
|
|
1394
|
+
strip, visibleLength,
|
|
1395
|
+
detectColorSupport, hasColor,
|
|
1396
|
+
parse, decodeSGR,
|
|
1397
|
+
ANSI_RE,
|
|
1398
|
+
|
|
1399
|
+
// ── Chainable builder ────────────────────────────
|
|
1400
|
+
AnsiString,
|
|
1401
|
+
}
|
|
1402
|
+
};
|