@alchemy.run/sigil 0.0.0-alpha.4 → 0.0.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -9
- package/THIRD_PARTY_NOTICES.md +39 -1
- package/dist/Text-BobFKi74.d.ts +452 -0
- package/dist/ansi.d.ts +122 -131
- package/dist/ansi.js +86 -6
- package/dist/capabilities.d.ts +5 -0
- package/dist/capabilities.js +3 -0
- package/dist/cell-_ZVhbfl0.js +44 -0
- package/dist/color-CkbalRqK.js +2 -0
- package/dist/color-policy-BMzMwV7Q.d.ts +22 -0
- package/dist/color-policy-SVj1pYTA.js +560 -0
- package/dist/color-profile-DHhQHY55.js +36 -0
- package/dist/color-profile-u0Nhe9Nv.d.ts +97 -0
- package/dist/color.d.ts +21 -0
- package/dist/color.js +3 -0
- package/dist/cursor-position-D2LAkRG0.d.ts +7 -0
- package/dist/detect-Bh4yGP6w.d.ts +186 -0
- package/dist/detect-BuTXtY6e.js +373 -0
- package/dist/env-YVw64yZS.js +9 -0
- package/dist/escapes-CB_6CWOE.d.ts +72 -0
- package/dist/geometry-BxXOzJgo.d.ts +11 -0
- package/dist/index-DZ88EXJv.d.ts +21 -0
- package/dist/index.d.ts +143 -498
- package/dist/index.js +1026 -2244
- package/dist/osc-CCH7xDoS.js +71 -0
- package/dist/osc-Cn0fw77g.d.ts +23 -0
- package/dist/paint-C19minOS.d.ts +81 -0
- package/dist/query-vaIeGOkH.d.ts +152 -0
- package/dist/router.d.ts +392 -0
- package/dist/router.js +709 -0
- package/dist/sample-Cqw1bjUL.js +445 -0
- package/dist/screen-BOSLQ8fF.d.ts +49 -0
- package/dist/screen-CiPytswf.js +342 -0
- package/dist/screen.d.ts +5 -0
- package/dist/screen.js +5 -0
- package/dist/semantic-text-style-DIMzC7xt.js +91 -0
- package/dist/serialize-BTkAZgw1.js +79 -0
- package/dist/session-aZr9O8h3.js +665 -0
- package/dist/sgr-BhwaWAJB.js +246 -0
- package/dist/store-CgrG9K4y.d.ts +72 -0
- package/dist/string-width-CijQwpIk.js +69 -0
- package/dist/strip-BvU4toXG.js +6 -0
- package/dist/terminal.d.ts +118 -0
- package/dist/terminal.js +2 -0
- package/dist/tokenize-AjqbvtiT.js +1242 -0
- package/dist/tokenize-Dx1y_l5H.d.ts +57 -0
- package/dist/truncate-D31fhU6i.js +562 -0
- package/dist/use-focus-BzqAJi0n.js +1337 -0
- package/package.json +41 -9
- package/src/ansi/chalk.ts +5 -3
- package/src/ansi/escapes.ts +14 -0
- package/src/ansi/graphemes.ts +8 -0
- package/src/ansi/hyperlink.ts +44 -0
- package/src/ansi/index.ts +3 -1
- package/src/ansi/osc.ts +77 -0
- package/src/ansi/tokenize.ts +3 -4
- package/src/capabilities/color-policy.ts +34 -0
- package/src/capabilities/detect.ts +594 -0
- package/src/capabilities/index.ts +37 -0
- package/src/capabilities/query.ts +657 -0
- package/src/capabilities/store.ts +379 -0
- package/src/color/index.ts +3 -0
- package/src/color/paint.ts +169 -0
- package/src/color/palette.ts +48 -0
- package/src/color/sample.ts +323 -0
- package/src/color.ts +1 -0
- package/src/components/AnsiText.tsx +42 -0
- package/src/components/App.tsx +98 -10
- package/src/components/BackgroundContext.ts +2 -3
- package/src/components/Box.tsx +0 -8
- package/src/components/CursorContext.ts +1 -1
- package/src/components/Hyperlink.tsx +56 -0
- package/src/components/TerminalOscContext.ts +25 -0
- package/src/components/Text.tsx +22 -45
- package/src/components/Transform.tsx +1 -1
- package/src/dom.ts +11 -2
- package/src/global.d.ts +3 -0
- package/src/hooks/use-capabilities.ts +73 -0
- package/src/hooks/use-cursor.ts +2 -2
- package/src/hooks/use-terminal-osc.ts +59 -0
- package/src/index.ts +45 -1
- package/src/ink.tsx +213 -153
- package/src/{render-node-to-output.ts → paint-tree.ts} +75 -48
- package/src/reconciler.ts +24 -3
- package/src/render-background.ts +36 -15
- package/src/render-border.ts +94 -61
- package/src/render-frame.ts +83 -0
- package/src/render-to-string.ts +21 -6
- package/src/render.ts +15 -6
- package/src/router/components.tsx +343 -0
- package/src/router/context.ts +41 -0
- package/src/router/history.ts +194 -0
- package/src/router/hooks.tsx +391 -0
- package/src/router/index.ts +34 -0
- package/src/router/matcher.ts +571 -0
- package/src/screen/ansi.ts +184 -0
- package/src/screen/canvas.ts +160 -0
- package/src/screen/cell.ts +138 -0
- package/src/screen/color-profile.ts +47 -0
- package/src/screen/geometry.ts +9 -0
- package/src/screen/index.ts +6 -0
- package/src/screen/screen.ts +305 -0
- package/src/screen/serialize.ts +129 -0
- package/src/screen.ts +1 -0
- package/src/semantic-text-style.ts +118 -0
- package/src/squash-text-nodes.ts +2 -5
- package/src/structured-text.ts +325 -0
- package/src/styles.ts +19 -14
- package/src/terminal/index.ts +2 -0
- package/src/terminal/inline-presenter.ts +120 -0
- package/src/terminal/input.ts +86 -0
- package/src/terminal/render-scheduler.ts +37 -0
- package/src/terminal/screen-presenter.ts +188 -0
- package/src/terminal/session.ts +407 -0
- package/src/terminal.ts +1 -0
- package/src/testing/browser.ts +588 -0
- package/src/testing/emulators.ts +205 -0
- package/src/testing/explorer-app/index.html +12 -0
- package/src/testing/explorer-app/main.ts +381 -0
- package/src/testing/explorer-app/style.css +194 -0
- package/src/testing/explorer-app/tsconfig.json +15 -0
- package/src/testing/explorer-app/vite-env.d.ts +1 -0
- package/src/testing/index.ts +26 -0
- package/src/testing/keys.ts +56 -0
- package/src/testing/live.ts +85 -0
- package/src/testing/matchers.ts +70 -0
- package/src/testing/public.ts +94 -0
- package/src/testing/terminal.ts +349 -0
- package/src/testing/vitest.ts +157 -0
- package/src/transform-adapter.ts +14 -0
- package/src/wrap-text.ts +4 -0
- package/dist/sgr-CMfEpjSk.d.ts +0 -91
- package/dist/truncate-Cr6xVFMa.js +0 -2330
- package/src/ansi/supports-color.ts +0 -207
- package/src/colorize.ts +0 -60
- package/src/log-update.ts +0 -370
- package/src/output.ts +0 -308
- package/src/renderer.ts +0 -73
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
//#region src/ansi/tokenize.d.ts
|
|
2
|
+
/**
|
|
3
|
+
An ANSI code paired with the code that ends its effect.
|
|
4
|
+
*/
|
|
5
|
+
type AnsiCode = {
|
|
6
|
+
readonly code: string;
|
|
7
|
+
readonly endCode: string;
|
|
8
|
+
};
|
|
9
|
+
type AnsiToken = AnsiCode & {
|
|
10
|
+
readonly type: "ansi";
|
|
11
|
+
};
|
|
12
|
+
type ControlToken = {
|
|
13
|
+
readonly type: "control";
|
|
14
|
+
readonly code: string;
|
|
15
|
+
};
|
|
16
|
+
type CharToken = {
|
|
17
|
+
readonly type: "char";
|
|
18
|
+
readonly value: string;
|
|
19
|
+
readonly fullWidth: boolean;
|
|
20
|
+
};
|
|
21
|
+
type Token = AnsiToken | ControlToken | CharToken;
|
|
22
|
+
type StyledChar = CharToken & {
|
|
23
|
+
readonly styles: AnsiCode[];
|
|
24
|
+
};
|
|
25
|
+
declare const endCodesSet: Set<string>;
|
|
26
|
+
declare function getLinkStartCode(url: string, params?: Record<string, string>): string;
|
|
27
|
+
declare function getEndCode(code: string): string;
|
|
28
|
+
declare function ansiCodesToString(codes: readonly AnsiCode[]): string;
|
|
29
|
+
/**
|
|
30
|
+
Check if a code is an intensity code (bold or dim) — these share the end code
|
|
31
|
+
`22m` but can coexist.
|
|
32
|
+
*/
|
|
33
|
+
declare function isIntensityCode(code: AnsiCode): boolean;
|
|
34
|
+
declare function tokenize(string: string, endChar?: number): Token[];
|
|
35
|
+
/**
|
|
36
|
+
Reduces the given array of ANSI codes to the minimum necessary to render with
|
|
37
|
+
the same style.
|
|
38
|
+
*/
|
|
39
|
+
declare function reduceAnsiCodes(codes: readonly AnsiCode[]): AnsiCode[];
|
|
40
|
+
/**
|
|
41
|
+
Like {@link reduceAnsiCodes}, but assumes that `codes` is already reduced.
|
|
42
|
+
Further reductions are only done for the items in `newCodes`.
|
|
43
|
+
*/
|
|
44
|
+
declare function reduceAnsiCodesIncremental(codes: readonly AnsiCode[], newCodes: readonly AnsiCode[]): AnsiCode[];
|
|
45
|
+
/**
|
|
46
|
+
Returns the combination of ANSI codes needed to undo the given ANSI codes.
|
|
47
|
+
*/
|
|
48
|
+
declare function undoAnsiCodes(codes: readonly AnsiCode[]): AnsiCode[];
|
|
49
|
+
/**
|
|
50
|
+
Returns the minimum amount of ANSI codes necessary to get from the compound
|
|
51
|
+
style `from` to `to`. Both are expected to be reduced.
|
|
52
|
+
*/
|
|
53
|
+
declare function diffAnsiCodes(from: readonly AnsiCode[], to: readonly AnsiCode[]): AnsiCode[];
|
|
54
|
+
declare function styledCharsFromTokens(tokens: readonly Token[]): StyledChar[];
|
|
55
|
+
declare function styledCharsToString(chars: readonly StyledChar[]): string;
|
|
56
|
+
//#endregion
|
|
57
|
+
export { tokenize as _, StyledChar as a, diffAnsiCodes as c, getLinkStartCode as d, isIntensityCode as f, styledCharsToString as g, styledCharsFromTokens as h, ControlToken as i, endCodesSet as l, reduceAnsiCodesIncremental as m, AnsiToken as n, Token as o, reduceAnsiCodes as p, CharToken as r, ansiCodesToString as s, AnsiCode as t, getEndCode as u, undoAnsiCodes as v };
|
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
import { i as codes } from "./sgr-BhwaWAJB.js";
|
|
2
|
+
import { d as tokenize, l as styledCharsFromTokens, u as styledCharsToString } from "./tokenize-AjqbvtiT.js";
|
|
3
|
+
import { t as stringWidth } from "./string-width-CijQwpIk.js";
|
|
4
|
+
//#region src/ansi/wrap.ts
|
|
5
|
+
const ANSI_ESCAPE = "\x1B";
|
|
6
|
+
const ANSI_ESCAPE_BELL = "\x07";
|
|
7
|
+
const ANSI_CSI = "[";
|
|
8
|
+
const ANSI_OSC = "]";
|
|
9
|
+
const ANSI_SGR_TERMINATOR = "m";
|
|
10
|
+
const ANSI_SGR_RESET = 0;
|
|
11
|
+
const ANSI_SGR_RESET_FOREGROUND = 39;
|
|
12
|
+
const ANSI_SGR_RESET_BACKGROUND = 49;
|
|
13
|
+
const ANSI_SGR_RESET_UNDERLINE_COLOR = 59;
|
|
14
|
+
const ANSI_SGR_FOREGROUND_EXTENDED = 38;
|
|
15
|
+
const ANSI_SGR_BACKGROUND_EXTENDED = 48;
|
|
16
|
+
const ANSI_SGR_UNDERLINE_COLOR_EXTENDED = 58;
|
|
17
|
+
const ANSI_SGR_COLOR_MODE_RGB = 2;
|
|
18
|
+
const ANSI_SGR_COLOR_MODE_256 = 5;
|
|
19
|
+
const ANSI_ESCAPE_LINK = `${ANSI_OSC}8;`;
|
|
20
|
+
const ESCAPES = /* @__PURE__ */ new Set([ANSI_ESCAPE, ""]);
|
|
21
|
+
const ESCAPE_CHARACTERS = [...ESCAPES].join("");
|
|
22
|
+
const CSI_INTRODUCER = `(?:${ANSI_ESCAPE}\\${ANSI_CSI}|)`;
|
|
23
|
+
const CSI_PARAMETERS = "[0-?]*[ -/]*[@-~]";
|
|
24
|
+
const SGR_PARAMETERS = `(?<sgr>[0-9;:]*)${ANSI_SGR_TERMINATOR}`;
|
|
25
|
+
const OSC_STRING_TERMINATOR = `(?:${ANSI_ESCAPE_BELL}|${ANSI_ESCAPE}\\\\)`;
|
|
26
|
+
const OSC_STRING_PAYLOAD = String.raw`[^\u0000-\u001F\u007F-\u009F]*`;
|
|
27
|
+
const LINK_PARAMETERS = String.raw`8;(?<parameters>[^;\u0000-\u001F\u007F-\u009F]*);(?<uri>${OSC_STRING_PAYLOAD})${OSC_STRING_TERMINATOR}`;
|
|
28
|
+
const OSC_STRING = `${OSC_STRING_PAYLOAD}${OSC_STRING_TERMINATOR}`;
|
|
29
|
+
const ANSI_ESCAPE_REGEX = new RegExp(`${CSI_INTRODUCER}(?:${SGR_PARAMETERS}|${CSI_PARAMETERS})|${ANSI_ESCAPE}\\${ANSI_OSC}(?:${LINK_PARAMETERS}|${OSC_STRING})`, "y");
|
|
30
|
+
const ANSI_SGR_MODIFIER_CLOSE_CODES = new Set(codes.values());
|
|
31
|
+
ANSI_SGR_MODIFIER_CLOSE_CODES.delete(ANSI_SGR_RESET);
|
|
32
|
+
const segmenter = new Intl.Segmenter();
|
|
33
|
+
const getStringWidth = (string) => stringWidth(string);
|
|
34
|
+
const TAB_SIZE = 8;
|
|
35
|
+
const ESCAPE_INTRODUCER_REGEX = new RegExp(`[${ESCAPE_CHARACTERS}]`, "g");
|
|
36
|
+
const ROW_BOUNDARY_REGEX = new RegExp(`[\\n${ESCAPE_CHARACTERS}]`, "g");
|
|
37
|
+
const ASCII_PRINTABLE_REGEX = /^[ -~]*$/;
|
|
38
|
+
const wrapAnsiCode = (code) => `${ANSI_ESCAPE}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
|
|
39
|
+
const wrapAnsiHyperlink = (url, parameters = "") => `${ANSI_ESCAPE}${ANSI_ESCAPE_LINK}${parameters};${url}${ANSI_ESCAPE_BELL}`;
|
|
40
|
+
const matchAnsiEscape = (string, index) => {
|
|
41
|
+
if (!ESCAPES.has(string[index])) return;
|
|
42
|
+
ANSI_ESCAPE_REGEX.lastIndex = index;
|
|
43
|
+
return ANSI_ESCAPE_REGEX.exec(string) ?? void 0;
|
|
44
|
+
};
|
|
45
|
+
const forEachSegment = (string, onPlainText, onEscape = () => {}) => {
|
|
46
|
+
let plainStart = 0;
|
|
47
|
+
let index = 0;
|
|
48
|
+
while (index < string.length) {
|
|
49
|
+
ESCAPE_INTRODUCER_REGEX.lastIndex = index;
|
|
50
|
+
const introducer = ESCAPE_INTRODUCER_REGEX.exec(string);
|
|
51
|
+
if (!introducer) break;
|
|
52
|
+
const escape = matchAnsiEscape(string, introducer.index);
|
|
53
|
+
if (!escape) {
|
|
54
|
+
index = introducer.index + 1;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (introducer.index > plainStart) onPlainText(string.slice(plainStart, introducer.index));
|
|
58
|
+
onEscape(escape[0]);
|
|
59
|
+
index = introducer.index + escape[0].length;
|
|
60
|
+
plainStart = index;
|
|
61
|
+
}
|
|
62
|
+
if (plainStart < string.length) onPlainText(string.slice(plainStart));
|
|
63
|
+
};
|
|
64
|
+
const getWidth = (string) => {
|
|
65
|
+
let plainText = "";
|
|
66
|
+
forEachSegment(string, (part) => {
|
|
67
|
+
plainText += part;
|
|
68
|
+
});
|
|
69
|
+
return getStringWidth(plainText);
|
|
70
|
+
};
|
|
71
|
+
const getTokens = (string) => {
|
|
72
|
+
const tokens = [];
|
|
73
|
+
forEachSegment(string, (plainText) => {
|
|
74
|
+
if (ASCII_PRINTABLE_REGEX.test(plainText)) {
|
|
75
|
+
for (const character of plainText) tokens.push({
|
|
76
|
+
value: character,
|
|
77
|
+
width: 1
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
for (const { segment } of segmenter.segment(plainText)) tokens.push({
|
|
82
|
+
value: segment,
|
|
83
|
+
width: getStringWidth(segment)
|
|
84
|
+
});
|
|
85
|
+
}, (escape) => {
|
|
86
|
+
tokens.push({
|
|
87
|
+
value: escape,
|
|
88
|
+
width: 0
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
return tokens;
|
|
92
|
+
};
|
|
93
|
+
const splitWords = (string) => {
|
|
94
|
+
let currentWord = {
|
|
95
|
+
value: "",
|
|
96
|
+
plainText: "",
|
|
97
|
+
width: 0
|
|
98
|
+
};
|
|
99
|
+
const words = [currentWord];
|
|
100
|
+
forEachSegment(string, (plainText) => {
|
|
101
|
+
const parts = plainText.split(" ");
|
|
102
|
+
currentWord.value += parts[0];
|
|
103
|
+
currentWord.plainText += parts[0];
|
|
104
|
+
for (let index = 1; index < parts.length; index++) {
|
|
105
|
+
currentWord = {
|
|
106
|
+
value: parts[index],
|
|
107
|
+
plainText: parts[index],
|
|
108
|
+
width: 0
|
|
109
|
+
};
|
|
110
|
+
words.push(currentWord);
|
|
111
|
+
}
|
|
112
|
+
}, (escape) => {
|
|
113
|
+
currentWord.value += escape;
|
|
114
|
+
});
|
|
115
|
+
for (const word of words) word.width = getStringWidth(word.plainText);
|
|
116
|
+
return words;
|
|
117
|
+
};
|
|
118
|
+
const EXTENDED_COLOR_CODES = /* @__PURE__ */ new Set([
|
|
119
|
+
ANSI_SGR_FOREGROUND_EXTENDED,
|
|
120
|
+
ANSI_SGR_BACKGROUND_EXTENDED,
|
|
121
|
+
ANSI_SGR_UNDERLINE_COLOR_EXTENDED
|
|
122
|
+
]);
|
|
123
|
+
const getColonColorToken = (parameter) => {
|
|
124
|
+
const parts = parameter.split(":");
|
|
125
|
+
const code = Number.parseInt(parts[0], 10);
|
|
126
|
+
const mode = Number.parseInt(parts[1], 10);
|
|
127
|
+
if (!EXTENDED_COLOR_CODES.has(code)) return;
|
|
128
|
+
if (mode === ANSI_SGR_COLOR_MODE_256 && parts.length === 3 && /^\d+$/.test(parts[2])) return {
|
|
129
|
+
code,
|
|
130
|
+
open: parameter,
|
|
131
|
+
hasArguments: true
|
|
132
|
+
};
|
|
133
|
+
if (mode !== ANSI_SGR_COLOR_MODE_RGB) return;
|
|
134
|
+
const components = parts.length === 6 ? parts.slice(3) : parts.slice(2);
|
|
135
|
+
const colorSpace = parts.length === 6 ? parts[2] : void 0;
|
|
136
|
+
if (components.length === 3 && components.every((component) => /^\d+$/.test(component)) && (colorSpace === void 0 || /^\d*$/.test(colorSpace))) return {
|
|
137
|
+
code,
|
|
138
|
+
open: parameter,
|
|
139
|
+
hasArguments: true
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
const getSgrTokens = (sgrParameters) => {
|
|
143
|
+
const parameters = sgrParameters.split(";");
|
|
144
|
+
const sgrTokens = [];
|
|
145
|
+
for (let index = 0; index < parameters.length; index++) {
|
|
146
|
+
const parameter = parameters[index];
|
|
147
|
+
if (parameter.includes(":")) {
|
|
148
|
+
const colonColorToken = getColonColorToken(parameter);
|
|
149
|
+
if (colonColorToken) sgrTokens.push(colonColorToken);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const code = parameter === "" ? ANSI_SGR_RESET : Number.parseInt(parameter, 10);
|
|
153
|
+
if (!Number.isFinite(code)) continue;
|
|
154
|
+
if (code === ANSI_SGR_FOREGROUND_EXTENDED || code === ANSI_SGR_BACKGROUND_EXTENDED || code === ANSI_SGR_UNDERLINE_COLOR_EXTENDED) {
|
|
155
|
+
if (index + 1 >= parameters.length) break;
|
|
156
|
+
const mode = Number.parseInt(parameters[index + 1], 10);
|
|
157
|
+
const colorIndex = Number.parseInt(parameters[index + 2] ?? "", 10);
|
|
158
|
+
if (mode === ANSI_SGR_COLOR_MODE_256 && Number.isFinite(colorIndex)) {
|
|
159
|
+
sgrTokens.push({
|
|
160
|
+
code,
|
|
161
|
+
open: [
|
|
162
|
+
code,
|
|
163
|
+
mode,
|
|
164
|
+
colorIndex
|
|
165
|
+
].join(";"),
|
|
166
|
+
hasArguments: true
|
|
167
|
+
});
|
|
168
|
+
index += 2;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const red = Number.parseInt(parameters[index + 2] ?? "", 10);
|
|
172
|
+
const green = Number.parseInt(parameters[index + 3] ?? "", 10);
|
|
173
|
+
const blue = Number.parseInt(parameters[index + 4] ?? "", 10);
|
|
174
|
+
if (mode === ANSI_SGR_COLOR_MODE_RGB && Number.isFinite(red) && Number.isFinite(green) && Number.isFinite(blue)) {
|
|
175
|
+
sgrTokens.push({
|
|
176
|
+
code,
|
|
177
|
+
open: [
|
|
178
|
+
code,
|
|
179
|
+
mode,
|
|
180
|
+
red,
|
|
181
|
+
green,
|
|
182
|
+
blue
|
|
183
|
+
].join(";"),
|
|
184
|
+
hasArguments: true
|
|
185
|
+
});
|
|
186
|
+
index += 4;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
sgrTokens.push({
|
|
192
|
+
code,
|
|
193
|
+
open: String(code),
|
|
194
|
+
hasArguments: false
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return sgrTokens;
|
|
198
|
+
};
|
|
199
|
+
const removeActiveStyle = (activeStyles, family) => {
|
|
200
|
+
const activeStyleIndex = activeStyles.findIndex((activeStyle) => activeStyle.family === family);
|
|
201
|
+
if (activeStyleIndex !== -1) activeStyles.splice(activeStyleIndex, 1);
|
|
202
|
+
};
|
|
203
|
+
const upsertActiveStyle = (activeStyles, nextActiveStyle) => {
|
|
204
|
+
removeActiveStyle(activeStyles, nextActiveStyle.family);
|
|
205
|
+
activeStyles.push(nextActiveStyle);
|
|
206
|
+
};
|
|
207
|
+
const removeModifierStylesByClose = (activeStyles, closeCode) => {
|
|
208
|
+
for (let index = activeStyles.length - 1; index >= 0; index--) {
|
|
209
|
+
const activeStyle = activeStyles[index];
|
|
210
|
+
if (activeStyle.family.startsWith("modifier-") && activeStyle.close === closeCode) activeStyles.splice(index, 1);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
const getColorStyle = (sgrToken) => {
|
|
214
|
+
const { code, open, hasArguments } = sgrToken;
|
|
215
|
+
if (code >= 30 && code <= 37 || code >= 90 && code <= 97 || code === ANSI_SGR_FOREGROUND_EXTENDED && hasArguments) return {
|
|
216
|
+
family: "foreground",
|
|
217
|
+
open,
|
|
218
|
+
close: ANSI_SGR_RESET_FOREGROUND
|
|
219
|
+
};
|
|
220
|
+
if (code >= 40 && code <= 47 || code >= 100 && code <= 107 || code === ANSI_SGR_BACKGROUND_EXTENDED && hasArguments) return {
|
|
221
|
+
family: "background",
|
|
222
|
+
open,
|
|
223
|
+
close: ANSI_SGR_RESET_BACKGROUND
|
|
224
|
+
};
|
|
225
|
+
if (code === ANSI_SGR_UNDERLINE_COLOR_EXTENDED && hasArguments) return {
|
|
226
|
+
family: "underlineColor",
|
|
227
|
+
open,
|
|
228
|
+
close: ANSI_SGR_RESET_UNDERLINE_COLOR
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
const applySgrResetCode = (code, activeStyles) => {
|
|
232
|
+
if (code === ANSI_SGR_RESET) {
|
|
233
|
+
activeStyles.length = 0;
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
if (code === ANSI_SGR_RESET_FOREGROUND) {
|
|
237
|
+
removeActiveStyle(activeStyles, "foreground");
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
if (code === ANSI_SGR_RESET_BACKGROUND) {
|
|
241
|
+
removeActiveStyle(activeStyles, "background");
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
if (code === ANSI_SGR_RESET_UNDERLINE_COLOR) {
|
|
245
|
+
removeActiveStyle(activeStyles, "underlineColor");
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
if (ANSI_SGR_MODIFIER_CLOSE_CODES.has(code)) {
|
|
249
|
+
removeModifierStylesByClose(activeStyles, code);
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
};
|
|
254
|
+
const applySgrToken = (sgrToken, activeStyles) => {
|
|
255
|
+
const { code } = sgrToken;
|
|
256
|
+
if (applySgrResetCode(code, activeStyles)) return;
|
|
257
|
+
const colorStyle = getColorStyle(sgrToken);
|
|
258
|
+
if (colorStyle) {
|
|
259
|
+
upsertActiveStyle(activeStyles, colorStyle);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const close = codes.get(code);
|
|
263
|
+
if (close !== void 0 && close !== ANSI_SGR_RESET) upsertActiveStyle(activeStyles, {
|
|
264
|
+
family: `modifier-${code}`,
|
|
265
|
+
open: sgrToken.open,
|
|
266
|
+
close
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
const applySgrParameters = (sgrParameters, activeStyles) => {
|
|
270
|
+
for (const sgrToken of getSgrTokens(sgrParameters)) applySgrToken(sgrToken, activeStyles);
|
|
271
|
+
};
|
|
272
|
+
const applySgrResets = (sgrParameters, activeStyles) => {
|
|
273
|
+
for (const { code } of getSgrTokens(sgrParameters)) applySgrResetCode(code, activeStyles);
|
|
274
|
+
};
|
|
275
|
+
const applyLeadingSgrResets = (string, startIndex, activeStyles) => {
|
|
276
|
+
let index = startIndex;
|
|
277
|
+
while (index < string.length) {
|
|
278
|
+
const match = matchAnsiEscape(string, index);
|
|
279
|
+
if (!match) break;
|
|
280
|
+
if (match.groups?.["sgr"] !== void 0) applySgrResets(match.groups["sgr"], activeStyles);
|
|
281
|
+
index += match[0].length;
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
const getClosingSgrSequence = (activeStyles) => activeStyles.toReversed().map((activeStyle) => wrapAnsiCode(activeStyle.close)).join("");
|
|
285
|
+
const getOpeningSgrSequence = (activeStyles) => activeStyles.map((activeStyle) => wrapAnsiCode(activeStyle.open)).join("");
|
|
286
|
+
const wrapWord = (rows, word, columns, rowWidth) => {
|
|
287
|
+
const tokens = getTokens(word);
|
|
288
|
+
let visible = rowWidth;
|
|
289
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
290
|
+
const token = tokens[index];
|
|
291
|
+
if (token.width > 0 && visible > 0 && visible + token.width > columns) {
|
|
292
|
+
rows.push("");
|
|
293
|
+
visible = 0;
|
|
294
|
+
}
|
|
295
|
+
rows[rows.length - 1] += token.value;
|
|
296
|
+
visible += token.width;
|
|
297
|
+
if (visible === columns && index < tokens.length - 1) {
|
|
298
|
+
rows.push("");
|
|
299
|
+
visible = 0;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (!visible && rows.at(-1).length > 0 && rows.length > 1) {
|
|
303
|
+
const lastRow = rows.pop();
|
|
304
|
+
rows[rows.length - 1] = rows[rows.length - 1] + lastRow;
|
|
305
|
+
}
|
|
306
|
+
return getWidth(rows.at(-1));
|
|
307
|
+
};
|
|
308
|
+
const stringVisibleTrimSpacesRight = (string) => {
|
|
309
|
+
if (!string.includes(" ")) return string;
|
|
310
|
+
const segments = [];
|
|
311
|
+
forEachSegment(string, (plainText) => {
|
|
312
|
+
segments.push({
|
|
313
|
+
value: plainText,
|
|
314
|
+
isEscape: false
|
|
315
|
+
});
|
|
316
|
+
}, (escape) => {
|
|
317
|
+
segments.push({
|
|
318
|
+
value: escape,
|
|
319
|
+
isEscape: true
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
for (let index = segments.length - 1; index >= 0; index--) {
|
|
323
|
+
const segment = segments[index];
|
|
324
|
+
if (segment.isEscape) continue;
|
|
325
|
+
let end = segment.value.length;
|
|
326
|
+
while (end > 0 && segment.value[end - 1] === " ") end--;
|
|
327
|
+
segment.value = segment.value.slice(0, end);
|
|
328
|
+
if (getStringWidth(segment.value) > 0) break;
|
|
329
|
+
}
|
|
330
|
+
return segments.map((segment) => segment.value).join("");
|
|
331
|
+
};
|
|
332
|
+
const expandTabs = (line) => {
|
|
333
|
+
if (!line.includes(" ")) return line;
|
|
334
|
+
let visible = 0;
|
|
335
|
+
let expandedLine = "";
|
|
336
|
+
let plainTextSinceTab = "";
|
|
337
|
+
const expandPlainText = (plainText) => {
|
|
338
|
+
const segments = plainText.split(" ");
|
|
339
|
+
for (const [index, segment] of segments.entries()) {
|
|
340
|
+
expandedLine += segment;
|
|
341
|
+
plainTextSinceTab += segment;
|
|
342
|
+
if (index < segments.length - 1) {
|
|
343
|
+
visible += getStringWidth(plainTextSinceTab);
|
|
344
|
+
plainTextSinceTab = "";
|
|
345
|
+
const spaces = TAB_SIZE - visible % TAB_SIZE;
|
|
346
|
+
expandedLine += " ".repeat(spaces);
|
|
347
|
+
visible += spaces;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
forEachSegment(line, expandPlainText, (escape) => {
|
|
352
|
+
expandedLine += escape;
|
|
353
|
+
});
|
|
354
|
+
return expandedLine;
|
|
355
|
+
};
|
|
356
|
+
const restoreStylesAcrossRows = (preString) => {
|
|
357
|
+
let returnValue = "";
|
|
358
|
+
let activeHyperlink;
|
|
359
|
+
const activeStyles = [];
|
|
360
|
+
let index = 0;
|
|
361
|
+
let copiedIndex = 0;
|
|
362
|
+
while (index < preString.length) {
|
|
363
|
+
ROW_BOUNDARY_REGEX.lastIndex = index;
|
|
364
|
+
const boundary = ROW_BOUNDARY_REGEX.exec(preString);
|
|
365
|
+
if (!boundary) break;
|
|
366
|
+
index = boundary.index;
|
|
367
|
+
if (boundary[0] !== "\n") {
|
|
368
|
+
const escape = matchAnsiEscape(preString, index);
|
|
369
|
+
if (!escape) {
|
|
370
|
+
index++;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
const groups = escape.groups ?? {};
|
|
374
|
+
if (groups["sgr"] !== void 0) applySgrParameters(groups["sgr"], activeStyles);
|
|
375
|
+
else if (groups["uri"] !== void 0) activeHyperlink = groups["uri"].length === 0 ? void 0 : {
|
|
376
|
+
parameters: groups["parameters"] ?? "",
|
|
377
|
+
uri: groups["uri"]
|
|
378
|
+
};
|
|
379
|
+
index += escape[0].length;
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
returnValue += preString.slice(copiedIndex, index);
|
|
383
|
+
if (index > copiedIndex) {
|
|
384
|
+
if (activeHyperlink) returnValue += wrapAnsiHyperlink("");
|
|
385
|
+
returnValue += getClosingSgrSequence(activeStyles);
|
|
386
|
+
}
|
|
387
|
+
returnValue += "\n";
|
|
388
|
+
index++;
|
|
389
|
+
copiedIndex = index;
|
|
390
|
+
if (index < preString.length && preString[index] !== "\n") {
|
|
391
|
+
const openingStyles = [...activeStyles];
|
|
392
|
+
applyLeadingSgrResets(preString, index, openingStyles);
|
|
393
|
+
returnValue += getOpeningSgrSequence(openingStyles);
|
|
394
|
+
if (activeHyperlink) returnValue += wrapAnsiHyperlink(activeHyperlink.uri, activeHyperlink.parameters);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return returnValue + preString.slice(copiedIndex);
|
|
398
|
+
};
|
|
399
|
+
const exec = (string, columns, options = {}) => {
|
|
400
|
+
if (options.trim !== false && string.trim() === "") return "";
|
|
401
|
+
const words = splitWords(string);
|
|
402
|
+
let rows = [""];
|
|
403
|
+
let rowLength = 0;
|
|
404
|
+
let trimmedRowIndex = -1;
|
|
405
|
+
let isFirstWord = true;
|
|
406
|
+
for (const word of words) {
|
|
407
|
+
const rowIndex = rows.length - 1;
|
|
408
|
+
if (options.trim !== false && trimmedRowIndex !== rowIndex) {
|
|
409
|
+
const row = rows[rowIndex];
|
|
410
|
+
const trimmedRow = row.trimStart();
|
|
411
|
+
if (trimmedRow.length !== row.length) {
|
|
412
|
+
rows[rowIndex] = trimmedRow;
|
|
413
|
+
rowLength = getWidth(trimmedRow);
|
|
414
|
+
}
|
|
415
|
+
if (trimmedRow.length > 0) trimmedRowIndex = rowIndex;
|
|
416
|
+
}
|
|
417
|
+
if (isFirstWord) isFirstWord = false;
|
|
418
|
+
else {
|
|
419
|
+
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
|
|
420
|
+
rows.push("");
|
|
421
|
+
rowLength = 0;
|
|
422
|
+
}
|
|
423
|
+
if (rowLength > 0 || options.trim === false) {
|
|
424
|
+
rows[rows.length - 1] += " ";
|
|
425
|
+
rowLength++;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (options.hard && options.wordWrap !== false && word.width > columns) {
|
|
429
|
+
const remainingColumns = columns - rowLength;
|
|
430
|
+
const breaksStartingThisLine = 1 + Math.floor((word.width - remainingColumns - 1) / columns);
|
|
431
|
+
if (Math.floor((word.width - 1) / columns) < breaksStartingThisLine) {
|
|
432
|
+
rows.push("");
|
|
433
|
+
rowLength = 0;
|
|
434
|
+
}
|
|
435
|
+
rowLength = wrapWord(rows, word.value, columns, rowLength);
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
if (rowLength + word.width > columns && rowLength > 0 && word.width > 0) {
|
|
439
|
+
if (options.wordWrap === false && rowLength < columns) {
|
|
440
|
+
rowLength = wrapWord(rows, word.value, columns, rowLength);
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
rows.push("");
|
|
444
|
+
rowLength = 0;
|
|
445
|
+
}
|
|
446
|
+
if (rowLength + word.width > columns && options.wordWrap === false) {
|
|
447
|
+
rowLength = wrapWord(rows, word.value, columns, rowLength);
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
rows[rows.length - 1] += word.value;
|
|
451
|
+
rowLength += word.width;
|
|
452
|
+
}
|
|
453
|
+
if (options.trim !== false) rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
|
|
454
|
+
return restoreStylesAcrossRows(rows.join("\n"));
|
|
455
|
+
};
|
|
456
|
+
function wrapAnsi(string, columns, options) {
|
|
457
|
+
return string.normalize().replaceAll("\r\n", "\n").split("\n").map((line) => exec(expandTabs(line), columns, options)).join("\n");
|
|
458
|
+
}
|
|
459
|
+
//#endregion
|
|
460
|
+
//#region src/ansi/slice.ts
|
|
461
|
+
function sliceAnsi(string, start, end) {
|
|
462
|
+
const sliceEnd = end ?? Number.POSITIVE_INFINITY;
|
|
463
|
+
if (start >= sliceEnd || string === "") return "";
|
|
464
|
+
if (start === 0 && sliceEnd === Number.POSITIVE_INFINITY) return string;
|
|
465
|
+
const chars = styledCharsFromTokens(tokenize(string));
|
|
466
|
+
const included = [];
|
|
467
|
+
let column = 0;
|
|
468
|
+
for (const char of chars) {
|
|
469
|
+
const width = char.fullWidth ? 2 : 1;
|
|
470
|
+
if (column + width > sliceEnd) break;
|
|
471
|
+
if (column >= start) included.push(char);
|
|
472
|
+
column += width;
|
|
473
|
+
}
|
|
474
|
+
return styledCharsToString(included);
|
|
475
|
+
}
|
|
476
|
+
//#endregion
|
|
477
|
+
//#region src/ansi/truncate.ts
|
|
478
|
+
function getIndexOfNearestSpace(string, wantedIndex, shouldSearchRight = false) {
|
|
479
|
+
if (string.charAt(wantedIndex) === " ") return wantedIndex;
|
|
480
|
+
const direction = shouldSearchRight ? 1 : -1;
|
|
481
|
+
for (let index = 0; index <= 3; index++) {
|
|
482
|
+
const finalIndex = wantedIndex + index * direction;
|
|
483
|
+
if (string.charAt(finalIndex) === " ") return finalIndex;
|
|
484
|
+
}
|
|
485
|
+
return wantedIndex;
|
|
486
|
+
}
|
|
487
|
+
const ANSI_ESC = 27;
|
|
488
|
+
const ANSI_LEFT_BRACKET = 91;
|
|
489
|
+
const ANSI_LETTER_M = 109;
|
|
490
|
+
const isSgrParameter = (code) => code >= 48 && code <= 57 || code === 59 || code === 58;
|
|
491
|
+
function leadingSgrSpanEndIndex(string) {
|
|
492
|
+
let index = 0;
|
|
493
|
+
while (index + 2 < string.length && string.codePointAt(index) === ANSI_ESC && string.codePointAt(index + 1) === ANSI_LEFT_BRACKET) {
|
|
494
|
+
let scan = index + 2;
|
|
495
|
+
while (scan < string.length && isSgrParameter(string.codePointAt(scan))) scan++;
|
|
496
|
+
if (scan < string.length && string.codePointAt(scan) === ANSI_LETTER_M) {
|
|
497
|
+
index = scan + 1;
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
return index;
|
|
503
|
+
}
|
|
504
|
+
function trailingSgrSpanStartIndex(string) {
|
|
505
|
+
let start = string.length;
|
|
506
|
+
while (start > 1 && string.codePointAt(start - 1) === ANSI_LETTER_M) {
|
|
507
|
+
let scan = start - 2;
|
|
508
|
+
while (scan >= 0 && isSgrParameter(string.codePointAt(scan))) scan--;
|
|
509
|
+
if (scan >= 1 && string.codePointAt(scan - 1) === ANSI_ESC && string.codePointAt(scan) === ANSI_LEFT_BRACKET) {
|
|
510
|
+
start = scan - 1;
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
break;
|
|
514
|
+
}
|
|
515
|
+
return start;
|
|
516
|
+
}
|
|
517
|
+
function appendWithInheritedStyleFromEnd(visible, suffix) {
|
|
518
|
+
const start = trailingSgrSpanStartIndex(visible);
|
|
519
|
+
if (start === visible.length) return visible + suffix;
|
|
520
|
+
return visible.slice(0, start) + suffix + visible.slice(start);
|
|
521
|
+
}
|
|
522
|
+
function prependWithInheritedStyleFromStart(prefix, visible) {
|
|
523
|
+
const end = leadingSgrSpanEndIndex(visible);
|
|
524
|
+
if (end === 0) return prefix + visible;
|
|
525
|
+
return visible.slice(0, end) + prefix + visible.slice(end);
|
|
526
|
+
}
|
|
527
|
+
function cliTruncate(text, columns, options = {}) {
|
|
528
|
+
const { position = "end", space = false, preferTruncationOnSpace = false } = options;
|
|
529
|
+
let { truncationCharacter = "…" } = options;
|
|
530
|
+
if (columns < 1) return "";
|
|
531
|
+
const length = stringWidth(text);
|
|
532
|
+
if (length <= columns) return text;
|
|
533
|
+
if (columns === 1) return truncationCharacter;
|
|
534
|
+
if (position === "start") {
|
|
535
|
+
if (preferTruncationOnSpace) {
|
|
536
|
+
const right = sliceAnsi(text, getIndexOfNearestSpace(text, length - columns + stringWidth(truncationCharacter), true), length).trim();
|
|
537
|
+
return prependWithInheritedStyleFromStart(truncationCharacter, right);
|
|
538
|
+
}
|
|
539
|
+
if (space) truncationCharacter += " ";
|
|
540
|
+
const right = sliceAnsi(text, length - columns + stringWidth(truncationCharacter), length);
|
|
541
|
+
return prependWithInheritedStyleFromStart(truncationCharacter, right);
|
|
542
|
+
}
|
|
543
|
+
if (position === "middle") {
|
|
544
|
+
if (space) {
|
|
545
|
+
truncationCharacter = ` ${truncationCharacter} `;
|
|
546
|
+
if (stringWidth(truncationCharacter) >= columns) truncationCharacter = truncationCharacter.trim();
|
|
547
|
+
}
|
|
548
|
+
const truncationWidth = stringWidth(truncationCharacter);
|
|
549
|
+
const half = Math.min(Math.floor(columns / 2), Math.max(0, columns - truncationWidth));
|
|
550
|
+
if (preferTruncationOnSpace) {
|
|
551
|
+
const spaceNearFirstBreakPoint = getIndexOfNearestSpace(text, half);
|
|
552
|
+
const spaceNearSecondBreakPoint = getIndexOfNearestSpace(text, length - (columns - half) + truncationWidth, true);
|
|
553
|
+
return sliceAnsi(text, 0, spaceNearFirstBreakPoint) + truncationCharacter + sliceAnsi(text, spaceNearSecondBreakPoint, length).trim();
|
|
554
|
+
}
|
|
555
|
+
return sliceAnsi(text, 0, half) + truncationCharacter + sliceAnsi(text, length - (columns - half) + truncationWidth, length);
|
|
556
|
+
}
|
|
557
|
+
if (preferTruncationOnSpace) return appendWithInheritedStyleFromEnd(sliceAnsi(text, 0, getIndexOfNearestSpace(text, columns - stringWidth(truncationCharacter))), truncationCharacter);
|
|
558
|
+
if (space) truncationCharacter = ` ${truncationCharacter}`;
|
|
559
|
+
return appendWithInheritedStyleFromEnd(sliceAnsi(text, 0, columns - stringWidth(truncationCharacter)), truncationCharacter);
|
|
560
|
+
}
|
|
561
|
+
//#endregion
|
|
562
|
+
export { sliceAnsi as n, wrapAnsi as r, cliTruncate as t };
|