@node-core/utils 7.1.0 → 7.2.1
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/components/metadata.js +2 -1
- package/lib/ci/build-types/test_build.js +3 -3
- package/lib/ci/failure_aggregator.js +2 -2
- package/lib/ci/run_ci.js +3 -2
- package/lib/cli.js +6 -6
- package/lib/figures.js +6 -6
- package/lib/prepare_security.js +20 -21
- package/lib/request.js +1 -1
- package/lib/update-v8/backport.js +3 -4
- package/lib/utils.js +4 -2
- package/lib/verbosity.js +2 -4
- package/node_modules/@listr2/{prompt-adapter-enquirer → prompt-adapter-inquirer}/README.md +4 -4
- package/node_modules/@listr2/prompt-adapter-inquirer/dist/index.d.mts +21 -0
- package/node_modules/@listr2/prompt-adapter-inquirer/dist/index.mjs +46 -0
- package/node_modules/@listr2/prompt-adapter-inquirer/node_modules/@inquirer/type/LICENSE +22 -0
- package/node_modules/@listr2/prompt-adapter-inquirer/node_modules/@inquirer/type/dist/index.d.ts +2 -0
- package/node_modules/@listr2/prompt-adapter-inquirer/node_modules/@inquirer/type/dist/index.js +2 -0
- package/node_modules/@listr2/prompt-adapter-inquirer/node_modules/@inquirer/type/dist/inquirer.d.ts +35 -0
- package/node_modules/@listr2/prompt-adapter-inquirer/node_modules/@inquirer/type/dist/inquirer.js +1 -0
- package/node_modules/@listr2/prompt-adapter-inquirer/node_modules/@inquirer/type/dist/utils.d.ts +34 -0
- package/node_modules/@listr2/prompt-adapter-inquirer/node_modules/@inquirer/type/dist/utils.js +2 -0
- package/node_modules/@listr2/prompt-adapter-inquirer/node_modules/@inquirer/type/package.json +88 -0
- package/node_modules/@listr2/{prompt-adapter-enquirer → prompt-adapter-inquirer}/package.json +25 -20
- package/node_modules/{log-update/node_modules/ansi-escapes → ansi-escapes}/base.d.ts +48 -3
- package/node_modules/{log-update/node_modules/ansi-escapes → ansi-escapes}/base.js +58 -19
- package/node_modules/{log-update/node_modules/ansi-escapes → ansi-escapes}/package.json +1 -1
- package/node_modules/{log-update/node_modules/ansi-escapes → ansi-escapes}/readme.md +36 -1
- package/node_modules/ansi-regex/index.js +9 -4
- package/node_modules/ansi-regex/package.json +1 -1
- package/node_modules/ansi-regex/readme.md +6 -0
- package/node_modules/ansi-styles/index.d.ts +12 -12
- package/node_modules/ansi-styles/index.js +3 -3
- package/node_modules/ansi-styles/package.json +4 -4
- package/node_modules/cli-truncate/index.d.ts +3 -3
- package/node_modules/cli-truncate/index.js +40 -14
- package/node_modules/cli-truncate/node_modules/string-width/index.js +133 -15
- package/node_modules/cli-truncate/node_modules/string-width/package.json +4 -4
- package/node_modules/cli-truncate/node_modules/string-width/readme.md +1 -1
- package/node_modules/cli-truncate/package.json +7 -7
- package/node_modules/cli-truncate/readme.md +2 -3
- package/node_modules/ghauth/.github/dependabot.yml +11 -3
- package/node_modules/ghauth/.github/workflows/depsound.yml +33 -0
- package/node_modules/ghauth/.github/workflows/test-and-release.yml +4 -4
- package/node_modules/ghauth/CHANGELOG.md +60 -0
- package/node_modules/ghauth/package.json +30 -6
- package/node_modules/js-yaml/README.md +20 -187
- package/node_modules/js-yaml/dist/browser/js-yaml.esm.min.mjs +1008 -946
- package/node_modules/js-yaml/dist/browser/js-yaml.esm.min.mjs.map +1 -1
- package/node_modules/js-yaml/dist/browser/js-yaml.umd.min.js +29 -23
- package/node_modules/js-yaml/dist/browser/js-yaml.umd.min.js.map +1 -1
- package/node_modules/js-yaml/dist/js-yaml.cjs.js +1043 -583
- package/node_modules/js-yaml/dist/js-yaml.cjs.js.map +1 -1
- package/node_modules/js-yaml/dist/js-yaml.d.ts +877 -133
- package/node_modules/js-yaml/dist/js-yaml.mjs +995 -556
- package/node_modules/js-yaml/dist/js-yaml.mjs.map +1 -1
- package/node_modules/js-yaml/package.json +8 -7
- package/node_modules/listr2/dist/{index.d.cts → index.d.mts} +90 -60
- package/node_modules/listr2/dist/{index.js → index.mjs} +496 -373
- package/node_modules/listr2/node_modules/string-width/index.d.ts +39 -0
- package/node_modules/listr2/node_modules/string-width/index.js +207 -0
- package/node_modules/listr2/node_modules/string-width/package.json +65 -0
- package/node_modules/listr2/node_modules/string-width/readme.md +66 -0
- package/node_modules/listr2/node_modules/wrap-ansi/index.d.ts +1 -1
- package/node_modules/listr2/node_modules/wrap-ansi/index.js +544 -116
- package/node_modules/listr2/node_modules/wrap-ansi/package.json +10 -13
- package/node_modules/listr2/node_modules/wrap-ansi/readme.md +2 -0
- package/node_modules/listr2/package.json +16 -19
- package/node_modules/log-update/index.d.ts +64 -1
- package/node_modules/log-update/index.js +268 -18
- package/node_modules/log-update/node_modules/string-width/index.d.ts +39 -0
- package/node_modules/log-update/node_modules/string-width/index.js +207 -0
- package/node_modules/log-update/node_modules/string-width/package.json +65 -0
- package/node_modules/log-update/node_modules/string-width/readme.md +66 -0
- package/node_modules/log-update/node_modules/wrap-ansi/index.d.ts +1 -1
- package/node_modules/log-update/node_modules/wrap-ansi/index.js +544 -116
- package/node_modules/log-update/node_modules/wrap-ansi/package.json +10 -13
- package/node_modules/log-update/node_modules/wrap-ansi/readme.md +2 -0
- package/node_modules/log-update/package.json +14 -12
- package/node_modules/log-update/readme.md +61 -0
- package/node_modules/slice-ansi/index.d.ts +2 -2
- package/node_modules/slice-ansi/index.js +260 -112
- package/node_modules/slice-ansi/package.json +10 -9
- package/node_modules/slice-ansi/readme.md +3 -2
- package/node_modules/slice-ansi/tokenize-ansi.js +752 -0
- package/node_modules/smol-toml/README.md +205 -191
- package/node_modules/smol-toml/dist/date.d.ts +0 -1
- package/node_modules/smol-toml/dist/date.js +0 -1
- package/node_modules/smol-toml/dist/error.d.ts +0 -1
- package/node_modules/smol-toml/dist/error.js +0 -1
- package/node_modules/smol-toml/dist/extract.js +32 -65
- package/node_modules/smol-toml/dist/index.cjs +302 -288
- package/node_modules/smol-toml/dist/index.d.ts +0 -1
- package/node_modules/smol-toml/dist/index.js +0 -1
- package/node_modules/smol-toml/dist/parse.d.ts +1 -3
- package/node_modules/smol-toml/dist/parse.js +22 -21
- package/node_modules/smol-toml/dist/primitive.js +75 -76
- package/node_modules/smol-toml/dist/stringify.d.ts +0 -1
- package/node_modules/smol-toml/dist/stringify.js +43 -30
- package/node_modules/smol-toml/dist/struct.js +90 -93
- package/node_modules/smol-toml/dist/util.d.ts +1 -1
- package/node_modules/smol-toml/dist/util.js +36 -39
- package/node_modules/smol-toml/package.json +6 -6
- package/node_modules/strip-ansi/index.js +5 -0
- package/node_modules/strip-ansi/package.json +5 -5
- package/package.json +3 -9
- package/node_modules/@listr2/prompt-adapter-enquirer/dist/index.cjs +0 -127
- package/node_modules/@listr2/prompt-adapter-enquirer/dist/index.d.cts +0 -152
- package/node_modules/@listr2/prompt-adapter-enquirer/dist/index.d.ts +0 -152
- package/node_modules/@listr2/prompt-adapter-enquirer/dist/index.js +0 -92
- package/node_modules/chalk/package.json +0 -92
- package/node_modules/chalk/readme.md +0 -331
- package/node_modules/chalk/source/index.d.ts +0 -437
- package/node_modules/chalk/source/index.js +0 -261
- package/node_modules/chalk/source/utilities.js +0 -33
- package/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +0 -299
- package/node_modules/chalk/source/vendor/ansi-styles/index.js +0 -261
- package/node_modules/chalk/source/vendor/supports-color/browser.d.ts +0 -1
- package/node_modules/chalk/source/vendor/supports-color/browser.js +0 -32
- package/node_modules/chalk/source/vendor/supports-color/index.d.ts +0 -55
- package/node_modules/chalk/source/vendor/supports-color/index.js +0 -206
- package/node_modules/colorette/LICENSE.md +0 -7
- package/node_modules/colorette/README.md +0 -134
- package/node_modules/colorette/index.cjs +0 -218
- package/node_modules/colorette/index.d.ts +0 -93
- package/node_modules/colorette/index.js +0 -150
- package/node_modules/colorette/package.json +0 -40
- package/node_modules/eventemitter3/LICENSE +0 -21
- package/node_modules/eventemitter3/README.md +0 -94
- package/node_modules/eventemitter3/dist/eventemitter3.esm.js +0 -347
- package/node_modules/eventemitter3/dist/eventemitter3.esm.min.js +0 -1
- package/node_modules/eventemitter3/dist/eventemitter3.esm.min.js.map +0 -1
- package/node_modules/eventemitter3/dist/eventemitter3.umd.js +0 -355
- package/node_modules/eventemitter3/dist/eventemitter3.umd.min.js +0 -1
- package/node_modules/eventemitter3/dist/eventemitter3.umd.min.js.map +0 -1
- package/node_modules/eventemitter3/index.d.ts +0 -135
- package/node_modules/eventemitter3/index.js +0 -336
- package/node_modules/eventemitter3/index.mjs +0 -4
- package/node_modules/eventemitter3/package.json +0 -67
- package/node_modules/figures/index.d.ts +0 -279
- package/node_modules/figures/index.js +0 -292
- package/node_modules/figures/package.json +0 -49
- package/node_modules/figures/readme.md +0 -337
- package/node_modules/isexe/LICENSE.md +0 -55
- package/node_modules/isexe/README.md +0 -80
- package/node_modules/isexe/dist/commonjs/index.d.ts +0 -14
- package/node_modules/isexe/dist/commonjs/index.d.ts.map +0 -1
- package/node_modules/isexe/dist/commonjs/index.js +0 -56
- package/node_modules/isexe/dist/commonjs/index.js.map +0 -1
- package/node_modules/isexe/dist/commonjs/index.min.js +0 -2
- package/node_modules/isexe/dist/commonjs/index.min.js.map +0 -7
- package/node_modules/isexe/dist/commonjs/options.d.ts +0 -32
- package/node_modules/isexe/dist/commonjs/options.d.ts.map +0 -1
- package/node_modules/isexe/dist/commonjs/options.js +0 -3
- package/node_modules/isexe/dist/commonjs/options.js.map +0 -1
- package/node_modules/isexe/dist/commonjs/package.json +0 -3
- package/node_modules/isexe/dist/commonjs/posix.d.ts +0 -18
- package/node_modules/isexe/dist/commonjs/posix.d.ts.map +0 -1
- package/node_modules/isexe/dist/commonjs/posix.js +0 -67
- package/node_modules/isexe/dist/commonjs/posix.js.map +0 -1
- package/node_modules/isexe/dist/commonjs/win32.d.ts +0 -18
- package/node_modules/isexe/dist/commonjs/win32.d.ts.map +0 -1
- package/node_modules/isexe/dist/commonjs/win32.js +0 -63
- package/node_modules/isexe/dist/commonjs/win32.js.map +0 -1
- package/node_modules/isexe/dist/esm/index.d.ts +0 -14
- package/node_modules/isexe/dist/esm/index.d.ts.map +0 -1
- package/node_modules/isexe/dist/esm/index.js +0 -16
- package/node_modules/isexe/dist/esm/index.js.map +0 -1
- package/node_modules/isexe/dist/esm/index.min.js +0 -2
- package/node_modules/isexe/dist/esm/index.min.js.map +0 -7
- package/node_modules/isexe/dist/esm/options.d.ts +0 -32
- package/node_modules/isexe/dist/esm/options.d.ts.map +0 -1
- package/node_modules/isexe/dist/esm/options.js +0 -2
- package/node_modules/isexe/dist/esm/options.js.map +0 -1
- package/node_modules/isexe/dist/esm/package.json +0 -3
- package/node_modules/isexe/dist/esm/posix.d.ts +0 -18
- package/node_modules/isexe/dist/esm/posix.d.ts.map +0 -1
- package/node_modules/isexe/dist/esm/posix.js +0 -62
- package/node_modules/isexe/dist/esm/posix.js.map +0 -1
- package/node_modules/isexe/dist/esm/win32.d.ts +0 -18
- package/node_modules/isexe/dist/esm/win32.d.ts.map +0 -1
- package/node_modules/isexe/dist/esm/win32.js +0 -58
- package/node_modules/isexe/dist/esm/win32.js.map +0 -1
- package/node_modules/isexe/package.json +0 -78
- package/node_modules/listr2/dist/index.cjs +0 -2189
- package/node_modules/listr2/dist/index.d.ts +0 -1528
- package/node_modules/rfdc/.github/workflows/ci.yml +0 -21
- package/node_modules/rfdc/LICENSE +0 -15
- package/node_modules/rfdc/default.js +0 -3
- package/node_modules/rfdc/index.d.ts +0 -13
- package/node_modules/rfdc/index.js +0 -198
- package/node_modules/rfdc/index.test-d.ts +0 -13
- package/node_modules/rfdc/package.json +0 -73
- package/node_modules/rfdc/readme.md +0 -181
- package/node_modules/rfdc/test/index.js +0 -306
- package/node_modules/smol-toml/dist/date.d.ts.map +0 -1
- package/node_modules/smol-toml/dist/date.js.map +0 -1
- package/node_modules/smol-toml/dist/error.d.ts.map +0 -1
- package/node_modules/smol-toml/dist/error.js.map +0 -1
- package/node_modules/smol-toml/dist/extract.js.map +0 -1
- package/node_modules/smol-toml/dist/index.cjs.map +0 -1
- package/node_modules/smol-toml/dist/index.d.ts.map +0 -1
- package/node_modules/smol-toml/dist/index.js.map +0 -1
- package/node_modules/smol-toml/dist/parse.d.ts.map +0 -1
- package/node_modules/smol-toml/dist/parse.js.map +0 -1
- package/node_modules/smol-toml/dist/primitive.d.ts +0 -29
- package/node_modules/smol-toml/dist/primitive.d.ts.map +0 -1
- package/node_modules/smol-toml/dist/primitive.js.map +0 -1
- package/node_modules/smol-toml/dist/stringify.d.ts.map +0 -1
- package/node_modules/smol-toml/dist/stringify.js.map +0 -1
- package/node_modules/smol-toml/dist/struct.js.map +0 -1
- package/node_modules/smol-toml/dist/util.d.ts.map +0 -1
- package/node_modules/smol-toml/dist/util.js.map +0 -1
- package/node_modules/smol-toml/src/date.ts +0 -152
- package/node_modules/smol-toml/src/error.ts +0 -77
- package/node_modules/smol-toml/src/extract.ts +0 -113
- package/node_modules/smol-toml/src/index.ts +0 -42
- package/node_modules/smol-toml/src/parse.ts +0 -184
- package/node_modules/smol-toml/src/primitive.ts +0 -249
- package/node_modules/smol-toml/src/stringify.ts +0 -191
- package/node_modules/smol-toml/src/struct.ts +0 -202
- package/node_modules/smol-toml/src/util.ts +0 -106
- package/node_modules/which/LICENSE +0 -15
- package/node_modules/which/README.md +0 -51
- package/node_modules/which/bin/which.js +0 -52
- package/node_modules/which/lib/index.js +0 -111
- package/node_modules/which/package.json +0 -52
- /package/node_modules/@listr2/{prompt-adapter-enquirer → prompt-adapter-inquirer}/LICENSE +0 -0
- /package/node_modules/{log-update/node_modules/ansi-escapes → ansi-escapes}/index.d.ts +0 -0
- /package/node_modules/{log-update/node_modules/ansi-escapes → ansi-escapes}/index.js +0 -0
- /package/node_modules/{chalk → ansi-escapes}/license +0 -0
- /package/node_modules/{figures → listr2/node_modules/string-width}/license +0 -0
- /package/node_modules/log-update/node_modules/{ansi-escapes → string-width}/license +0 -0
|
@@ -1,98 +1,551 @@
|
|
|
1
1
|
import stringWidth from 'string-width';
|
|
2
|
-
import stripAnsi from 'strip-ansi';
|
|
3
2
|
import ansiStyles from 'ansi-styles';
|
|
4
3
|
|
|
5
|
-
const
|
|
6
|
-
'\u001B',
|
|
7
|
-
'\u009B',
|
|
8
|
-
]);
|
|
9
|
-
|
|
10
|
-
const END_CODE = 39;
|
|
4
|
+
const ANSI_ESCAPE = '\u001B';
|
|
11
5
|
const ANSI_ESCAPE_BELL = '\u0007';
|
|
6
|
+
const C1_CSI = '\u009B';
|
|
12
7
|
const ANSI_CSI = '[';
|
|
13
8
|
const ANSI_OSC = ']';
|
|
14
9
|
const ANSI_SGR_TERMINATOR = 'm';
|
|
15
|
-
const
|
|
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
|
+
// The first character of every sequence we recognize.
|
|
21
|
+
const ESCAPES = new Set([
|
|
22
|
+
ANSI_ESCAPE,
|
|
23
|
+
C1_CSI,
|
|
24
|
+
]);
|
|
25
|
+
const ESCAPE_CHARACTERS = [...ESCAPES].join('');
|
|
26
|
+
|
|
27
|
+
const CSI_INTRODUCER = `(?:${ANSI_ESCAPE}\\${ANSI_CSI}|${C1_CSI})`;
|
|
28
|
+
const CSI_PARAMETERS = '[0-?]*[ -/]*[@-~]';
|
|
29
|
+
const SGR_PARAMETERS = `(?<sgr>[0-9;:]*)${ANSI_SGR_TERMINATOR}`;
|
|
30
|
+
const OSC_STRING_TERMINATOR = `(?:${ANSI_ESCAPE_BELL}|${ANSI_ESCAPE}\\\\)`;
|
|
31
|
+
const OSC_STRING_PAYLOAD = String.raw`[^\u0000-\u001F\u007F-\u009F]*`;
|
|
32
|
+
// A hyperlink is `OSC 8 ; parameters ; URI ST`, where `parameters` is a possibly empty list of `key=value` pairs joined by `:`.
|
|
33
|
+
const LINK_PARAMETERS = String.raw`8;(?<parameters>[^;\u0000-\u001F\u007F-\u009F]*);(?<uri>${OSC_STRING_PAYLOAD})${OSC_STRING_TERMINATOR}`;
|
|
34
|
+
const OSC_STRING = `${OSC_STRING_PAYLOAD}${OSC_STRING_TERMINATOR}`;
|
|
35
|
+
|
|
36
|
+
// Supported boundary: semicolon-delimited SGR styling, colon-delimited RGB/indexed colors, and OSC 8 hyperlinks are tracked, while ordinary CSI sequences and other complete 7-bit OSC commands are preserved as opaque zero-width units. This is intentionally not a terminal emulator, so other colon-delimited SGR semantics, C0 bytes inside sequences, DCS/SOS/PM/APC control strings, cancellations, generic ESC sequences, and 8-bit control-string forms are unsupported. Newlines always delimit input lines before ANSI parsing.
|
|
37
|
+
const ANSI_ESCAPE_REGEX = new RegExp(
|
|
38
|
+
`${CSI_INTRODUCER}(?:${SGR_PARAMETERS}|${CSI_PARAMETERS})`
|
|
39
|
+
+ `|${ANSI_ESCAPE}\\${ANSI_OSC}(?:${LINK_PARAMETERS}|${OSC_STRING})`,
|
|
40
|
+
'y',
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const ANSI_SGR_MODIFIER_CLOSE_CODES = new Set(ansiStyles.codes.values());
|
|
44
|
+
ANSI_SGR_MODIFIER_CLOSE_CODES.delete(ANSI_SGR_RESET);
|
|
45
|
+
|
|
46
|
+
const segmenter = new Intl.Segmenter();
|
|
47
|
+
// Complete ANSI sequences have already been removed before measuring these strings. Avoid string-width's ANSI scan so malformed sequences are not rescanned.
|
|
48
|
+
const getStringWidth = string => stringWidth(string, {countAnsiEscapeCodes: true});
|
|
49
|
+
const TAB_SIZE = 8;
|
|
50
|
+
|
|
51
|
+
// Finds the next character that could introduce a sequence, so plain text is skipped in one native step.
|
|
52
|
+
const ESCAPE_INTRODUCER_REGEX = new RegExp(`[${ESCAPE_CHARACTERS}]`, 'g');
|
|
53
|
+
// The final pass only cares about sequences and row boundaries, so it skips everything else in one native step.
|
|
54
|
+
const ROW_BOUNDARY_REGEX = new RegExp(`[\\n${ESCAPE_CHARACTERS}]`, 'g');
|
|
55
|
+
// Every printable ASCII character is its own grapheme cluster of width one, which lets the segmenter be skipped.
|
|
56
|
+
const ASCII_PRINTABLE_REGEX = /^[ -~]*$/;
|
|
57
|
+
|
|
58
|
+
const wrapAnsiCode = code => `${ANSI_ESCAPE}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
|
|
59
|
+
const wrapAnsiHyperlink = (url, parameters = '') => `${ANSI_ESCAPE}${ANSI_ESCAPE_LINK}${parameters};${url}${ANSI_ESCAPE_BELL}`;
|
|
60
|
+
|
|
61
|
+
// Match a complete escape sequence starting at `index`, or return `undefined` when none starts there.
|
|
62
|
+
const matchAnsiEscape = (string, index) => {
|
|
63
|
+
if (!ESCAPES.has(string[index])) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
16
66
|
|
|
17
|
-
|
|
18
|
-
|
|
67
|
+
ANSI_ESCAPE_REGEX.lastIndex = index;
|
|
68
|
+
return ANSI_ESCAPE_REGEX.exec(string) ?? undefined;
|
|
69
|
+
};
|
|
19
70
|
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
const
|
|
71
|
+
// Walk a string as alternating plain text runs and complete escape sequences.
|
|
72
|
+
// A character that looks like an introducer but does not start a valid sequence stays plain text.
|
|
73
|
+
const forEachSegment = (string, onPlainText, onEscape = () => {}) => {
|
|
74
|
+
let plainStart = 0;
|
|
75
|
+
let index = 0;
|
|
23
76
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
const characters = [...word];
|
|
77
|
+
while (index < string.length) {
|
|
78
|
+
ESCAPE_INTRODUCER_REGEX.lastIndex = index;
|
|
79
|
+
const introducer = ESCAPE_INTRODUCER_REGEX.exec(string);
|
|
28
80
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
81
|
+
if (!introducer) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
32
84
|
|
|
33
|
-
|
|
34
|
-
const characterLength = stringWidth(character);
|
|
85
|
+
const escape = matchAnsiEscape(string, introducer.index);
|
|
35
86
|
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
rows.push(character);
|
|
40
|
-
visible = 0;
|
|
87
|
+
if (!escape) {
|
|
88
|
+
index = introducer.index + 1;
|
|
89
|
+
continue;
|
|
41
90
|
}
|
|
42
91
|
|
|
43
|
-
if (
|
|
44
|
-
|
|
92
|
+
if (introducer.index > plainStart) {
|
|
93
|
+
onPlainText(string.slice(plainStart, introducer.index));
|
|
94
|
+
}
|
|
45
95
|
|
|
46
|
-
|
|
47
|
-
|
|
96
|
+
onEscape(escape[0]);
|
|
97
|
+
index = introducer.index + escape[0].length;
|
|
98
|
+
plainStart = index;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (plainStart < string.length) {
|
|
102
|
+
onPlainText(string.slice(plainStart));
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// The visible width of a string, ignoring escape sequences.
|
|
107
|
+
const getWidth = string => {
|
|
108
|
+
let plainText = '';
|
|
109
|
+
|
|
110
|
+
forEachSegment(string, part => {
|
|
111
|
+
plainText += part;
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return getStringWidth(plainText);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Split a string into escape sequences, which are zero width and must never be split, and grapheme clusters.
|
|
118
|
+
// The supported boundary is between grapheme clusters and ANSI sequences; ANSI inserted inside a cluster is treated as separate segments.
|
|
119
|
+
const getTokens = string => {
|
|
120
|
+
const tokens = [];
|
|
121
|
+
|
|
122
|
+
forEachSegment(string, plainText => {
|
|
123
|
+
if (ASCII_PRINTABLE_REGEX.test(plainText)) {
|
|
124
|
+
for (const character of plainText) {
|
|
125
|
+
tokens.push({value: character, width: 1});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return;
|
|
48
129
|
}
|
|
49
130
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
131
|
+
for (const {segment} of segmenter.segment(plainText)) {
|
|
132
|
+
tokens.push({value: segment, width: getStringWidth(segment)});
|
|
133
|
+
}
|
|
134
|
+
}, escape => {
|
|
135
|
+
tokens.push({value: escape, width: 0});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
return tokens;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Split on spaces, ignoring spaces that appear inside a recognized sequence.
|
|
142
|
+
const splitWords = string => {
|
|
143
|
+
let currentWord = {value: '', plainText: ''};
|
|
144
|
+
const words = [currentWord];
|
|
145
|
+
|
|
146
|
+
forEachSegment(string, plainText => {
|
|
147
|
+
const parts = plainText.split(' ');
|
|
148
|
+
currentWord.value += parts[0];
|
|
149
|
+
currentWord.plainText += parts[0];
|
|
150
|
+
|
|
151
|
+
for (let index = 1; index < parts.length; index++) {
|
|
152
|
+
currentWord = {value: parts[index], plainText: parts[index]};
|
|
153
|
+
words.push(currentWord);
|
|
154
|
+
}
|
|
155
|
+
}, escape => {
|
|
156
|
+
currentWord.value += escape;
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Measured once per word rather than per run, so a grapheme cluster split by an escape still counts once.
|
|
160
|
+
for (const word of words) {
|
|
161
|
+
word.width = getStringWidth(word.plainText);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return words;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const getColonColorToken = parameter => {
|
|
168
|
+
const parts = parameter.split(':');
|
|
169
|
+
const code = Number.parseInt(parts[0], 10);
|
|
170
|
+
const mode = Number.parseInt(parts[1], 10);
|
|
171
|
+
|
|
172
|
+
if (![ANSI_SGR_FOREGROUND_EXTENDED, ANSI_SGR_BACKGROUND_EXTENDED, ANSI_SGR_UNDERLINE_COLOR_EXTENDED].includes(code)) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (mode === ANSI_SGR_COLOR_MODE_256 && parts.length === 3 && /^\d+$/.test(parts[2])) {
|
|
177
|
+
return {code, open: parameter, hasArguments: true};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (mode !== ANSI_SGR_COLOR_MODE_RGB) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const components = parts.length === 6 ? parts.slice(3) : parts.slice(2);
|
|
185
|
+
const colorSpace = parts.length === 6 ? parts[2] : undefined;
|
|
186
|
+
if (components.length === 3 && components.every(component => /^\d+$/.test(component)) && (colorSpace === undefined || /^\d*$/.test(colorSpace))) {
|
|
187
|
+
return {code, open: parameter, hasArguments: true};
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const getSgrTokens = sgrParameters => {
|
|
192
|
+
const parameters = sgrParameters.split(';');
|
|
193
|
+
const sgrTokens = [];
|
|
194
|
+
|
|
195
|
+
for (let index = 0; index < parameters.length; index++) {
|
|
196
|
+
const parameter = parameters[index];
|
|
197
|
+
if (parameter.includes(':')) {
|
|
198
|
+
const colonColorToken = getColonColorToken(parameter);
|
|
199
|
+
if (colonColorToken) {
|
|
200
|
+
sgrTokens.push(colonColorToken);
|
|
58
201
|
}
|
|
59
202
|
|
|
60
203
|
continue;
|
|
61
204
|
}
|
|
62
205
|
|
|
63
|
-
|
|
206
|
+
const code = parameter === '' ? ANSI_SGR_RESET : Number.parseInt(parameter, 10);
|
|
207
|
+
|
|
208
|
+
if (!Number.isFinite(code)) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (code === ANSI_SGR_FOREGROUND_EXTENDED || code === ANSI_SGR_BACKGROUND_EXTENDED || code === ANSI_SGR_UNDERLINE_COLOR_EXTENDED) {
|
|
213
|
+
if (index + 1 >= parameters.length) {
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const mode = Number.parseInt(parameters[index + 1], 10);
|
|
218
|
+
const colorIndex = Number.parseInt(parameters[index + 2], 10);
|
|
219
|
+
if (mode === ANSI_SGR_COLOR_MODE_256 && Number.isFinite(colorIndex)) {
|
|
220
|
+
sgrTokens.push({code, open: [code, mode, colorIndex].join(';'), hasArguments: true});
|
|
221
|
+
index += 2;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const red = Number.parseInt(parameters[index + 2], 10);
|
|
226
|
+
const green = Number.parseInt(parameters[index + 3], 10);
|
|
227
|
+
const blue = Number.parseInt(parameters[index + 4], 10);
|
|
228
|
+
if (mode === ANSI_SGR_COLOR_MODE_RGB && Number.isFinite(red) && Number.isFinite(green) && Number.isFinite(blue)) {
|
|
229
|
+
sgrTokens.push({code, open: [code, mode, red, green, blue].join(';'), hasArguments: true});
|
|
230
|
+
index += 4;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
sgrTokens.push({code, open: String(code), hasArguments: false});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return sgrTokens;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const removeActiveStyle = (activeStyles, family) => {
|
|
244
|
+
const activeStyleIndex = activeStyles.findIndex(activeStyle => activeStyle.family === family);
|
|
245
|
+
|
|
246
|
+
if (activeStyleIndex !== -1) {
|
|
247
|
+
activeStyles.splice(activeStyleIndex, 1);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const upsertActiveStyle = (activeStyles, nextActiveStyle) => {
|
|
252
|
+
removeActiveStyle(activeStyles, nextActiveStyle.family);
|
|
253
|
+
activeStyles.push(nextActiveStyle);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const removeModifierStylesByClose = (activeStyles, closeCode) => {
|
|
257
|
+
for (let index = activeStyles.length - 1; index >= 0; index--) {
|
|
258
|
+
const activeStyle = activeStyles[index];
|
|
259
|
+
if (activeStyle.family.startsWith('modifier-') && activeStyle.close === closeCode) {
|
|
260
|
+
activeStyles.splice(index, 1);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const getColorStyle = sgrToken => {
|
|
266
|
+
const {code, open, hasArguments} = sgrToken;
|
|
267
|
+
if ((code >= 30 && code <= 37) || (code >= 90 && code <= 97) || (code === ANSI_SGR_FOREGROUND_EXTENDED && hasArguments)) {
|
|
268
|
+
return {
|
|
269
|
+
family: 'foreground',
|
|
270
|
+
open,
|
|
271
|
+
close: ANSI_SGR_RESET_FOREGROUND,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if ((code >= 40 && code <= 47) || (code >= 100 && code <= 107) || (code === ANSI_SGR_BACKGROUND_EXTENDED && hasArguments)) {
|
|
276
|
+
return {
|
|
277
|
+
family: 'background',
|
|
278
|
+
open,
|
|
279
|
+
close: ANSI_SGR_RESET_BACKGROUND,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (code === ANSI_SGR_UNDERLINE_COLOR_EXTENDED && hasArguments) {
|
|
284
|
+
return {
|
|
285
|
+
family: 'underlineColor',
|
|
286
|
+
open,
|
|
287
|
+
close: ANSI_SGR_RESET_UNDERLINE_COLOR,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const applySgrResetCode = (code, activeStyles) => {
|
|
293
|
+
if (code === ANSI_SGR_RESET) {
|
|
294
|
+
activeStyles.length = 0;
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (code === ANSI_SGR_RESET_FOREGROUND) {
|
|
299
|
+
removeActiveStyle(activeStyles, 'foreground');
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (code === ANSI_SGR_RESET_BACKGROUND) {
|
|
304
|
+
removeActiveStyle(activeStyles, 'background');
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (code === ANSI_SGR_RESET_UNDERLINE_COLOR) {
|
|
309
|
+
removeActiveStyle(activeStyles, 'underlineColor');
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (ANSI_SGR_MODIFIER_CLOSE_CODES.has(code)) {
|
|
314
|
+
removeModifierStylesByClose(activeStyles, code);
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return false;
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const applySgrToken = (sgrToken, activeStyles) => {
|
|
322
|
+
const {code} = sgrToken;
|
|
323
|
+
|
|
324
|
+
if (applySgrResetCode(code, activeStyles)) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const colorStyle = getColorStyle(sgrToken);
|
|
329
|
+
if (colorStyle) {
|
|
330
|
+
upsertActiveStyle(activeStyles, colorStyle);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const close = ansiStyles.codes.get(code);
|
|
335
|
+
if (close !== undefined && close !== ANSI_SGR_RESET) {
|
|
336
|
+
upsertActiveStyle(activeStyles, {
|
|
337
|
+
family: `modifier-${code}`,
|
|
338
|
+
open: sgrToken.open,
|
|
339
|
+
close,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const applySgrParameters = (sgrParameters, activeStyles) => {
|
|
345
|
+
for (const sgrToken of getSgrTokens(sgrParameters)) {
|
|
346
|
+
applySgrToken(sgrToken, activeStyles);
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const applySgrResets = (sgrParameters, activeStyles) => {
|
|
351
|
+
for (const {code} of getSgrTokens(sgrParameters)) {
|
|
352
|
+
applySgrResetCode(code, activeStyles);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
const applyLeadingSgrResets = (string, startIndex, activeStyles) => {
|
|
357
|
+
let index = startIndex;
|
|
358
|
+
|
|
359
|
+
while (index < string.length) {
|
|
360
|
+
const match = matchAnsiEscape(string, index);
|
|
361
|
+
if (!match) {
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (match.groups.sgr !== undefined) {
|
|
366
|
+
applySgrResets(match.groups.sgr, activeStyles);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
index += match[0].length;
|
|
370
|
+
}
|
|
371
|
+
};
|
|
64
372
|
|
|
65
|
-
|
|
373
|
+
const getClosingSgrSequence = activeStyles => [...activeStyles].reverse().map(activeStyle => wrapAnsiCode(activeStyle.close)).join('');
|
|
374
|
+
const getOpeningSgrSequence = activeStyles => activeStyles.map(activeStyle => wrapAnsiCode(activeStyle.open)).join('');
|
|
375
|
+
|
|
376
|
+
// Wrap a long word across multiple rows
|
|
377
|
+
// ANSI escape codes do not count towards length
|
|
378
|
+
// Takes the visible width of the last row and returns the width of the row the word ends on, so callers never have to measure the rows themselves.
|
|
379
|
+
const wrapWord = (rows, word, columns, rowWidth) => {
|
|
380
|
+
const tokens = getTokens(word);
|
|
381
|
+
|
|
382
|
+
let visible = rowWidth;
|
|
383
|
+
|
|
384
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
385
|
+
const token = tokens[index];
|
|
386
|
+
|
|
387
|
+
// Escape sequences and combining marks are zero width, so they always stay on the current row.
|
|
388
|
+
if (token.width > 0 && visible > 0 && visible + token.width > columns) {
|
|
389
|
+
rows.push('');
|
|
390
|
+
visible = 0;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
rows[rows.length - 1] += token.value;
|
|
394
|
+
visible += token.width;
|
|
395
|
+
|
|
396
|
+
if (visible === columns && index < tokens.length - 1) {
|
|
66
397
|
rows.push('');
|
|
67
398
|
visible = 0;
|
|
68
399
|
}
|
|
69
400
|
}
|
|
70
401
|
|
|
71
402
|
// It's possible that the last row we copy over is only
|
|
72
|
-
//
|
|
403
|
+
// ANSI escape characters, handle this edge-case
|
|
73
404
|
if (!visible && rows.at(-1).length > 0 && rows.length > 1) {
|
|
74
405
|
rows[rows.length - 2] += rows.pop();
|
|
75
406
|
}
|
|
407
|
+
|
|
408
|
+
// The tokens are measured one by one, so a grapheme cluster that an escape sequence splits is counted once per part rather than once as a whole. Only the finished row tells the true width, and it is at most one row long to measure.
|
|
409
|
+
return getWidth(rows.at(-1));
|
|
76
410
|
};
|
|
77
411
|
|
|
78
412
|
// Trims spaces from a string ignoring invisible sequences
|
|
79
413
|
const stringVisibleTrimSpacesRight = string => {
|
|
80
|
-
|
|
81
|
-
|
|
414
|
+
if (!string.includes(' ')) {
|
|
415
|
+
return string;
|
|
416
|
+
}
|
|
82
417
|
|
|
83
|
-
|
|
84
|
-
|
|
418
|
+
const segments = [];
|
|
419
|
+
forEachSegment(string, plainText => {
|
|
420
|
+
segments.push({value: plainText, isEscape: false});
|
|
421
|
+
}, escape => {
|
|
422
|
+
segments.push({value: escape, isEscape: true});
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// Drop the spaces that trail the last visible character, but keep the invisible sequences among them.
|
|
426
|
+
for (let index = segments.length - 1; index >= 0; index--) {
|
|
427
|
+
const segment = segments[index];
|
|
428
|
+
|
|
429
|
+
if (segment.isEscape) {
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Scanned rather than matched with a regex, as a trailing-space pattern backtracks quadratically.
|
|
434
|
+
let end = segment.value.length;
|
|
435
|
+
while (end > 0 && segment.value[end - 1] === ' ') {
|
|
436
|
+
end--;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
segment.value = segment.value.slice(0, end);
|
|
440
|
+
|
|
441
|
+
if (getStringWidth(segment.value) > 0) {
|
|
85
442
|
break;
|
|
86
443
|
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return segments.map(segment => segment.value).join('');
|
|
447
|
+
};
|
|
87
448
|
|
|
88
|
-
|
|
449
|
+
const expandTabs = line => {
|
|
450
|
+
if (!line.includes('\t')) {
|
|
451
|
+
return line;
|
|
89
452
|
}
|
|
90
453
|
|
|
91
|
-
|
|
92
|
-
|
|
454
|
+
let visible = 0;
|
|
455
|
+
let expandedLine = '';
|
|
456
|
+
let plainTextSinceTab = '';
|
|
457
|
+
|
|
458
|
+
const expandPlainText = plainText => {
|
|
459
|
+
const segments = plainText.split('\t');
|
|
460
|
+
|
|
461
|
+
for (const [index, segment] of segments.entries()) {
|
|
462
|
+
expandedLine += segment;
|
|
463
|
+
plainTextSinceTab += segment;
|
|
464
|
+
|
|
465
|
+
if (index < segments.length - 1) {
|
|
466
|
+
visible += getStringWidth(plainTextSinceTab);
|
|
467
|
+
plainTextSinceTab = '';
|
|
468
|
+
const spaces = TAB_SIZE - (visible % TAB_SIZE);
|
|
469
|
+
expandedLine += ' '.repeat(spaces);
|
|
470
|
+
visible += spaces;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
forEachSegment(line, expandPlainText, escape => {
|
|
476
|
+
expandedLine += escape;
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
return expandedLine;
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// Close the active styles and hyperlink before every row break and reopen them after, so each row stands on its own.
|
|
483
|
+
// Only sequences and newlines matter here, so the string is scanned directly rather than split into grapheme clusters.
|
|
484
|
+
const restoreStylesAcrossRows = preString => {
|
|
485
|
+
let returnValue = '';
|
|
486
|
+
let activeHyperlink;
|
|
487
|
+
const activeStyles = [];
|
|
488
|
+
let index = 0;
|
|
489
|
+
let copiedIndex = 0;
|
|
490
|
+
|
|
491
|
+
while (index < preString.length) {
|
|
492
|
+
ROW_BOUNDARY_REGEX.lastIndex = index;
|
|
493
|
+
const boundary = ROW_BOUNDARY_REGEX.exec(preString);
|
|
494
|
+
|
|
495
|
+
if (!boundary) {
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
index = boundary.index;
|
|
500
|
+
|
|
501
|
+
if (boundary[0] !== '\n') {
|
|
502
|
+
const escape = matchAnsiEscape(preString, index);
|
|
503
|
+
|
|
504
|
+
if (!escape) {
|
|
505
|
+
index++;
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const {groups} = escape;
|
|
510
|
+
if (groups.sgr !== undefined) {
|
|
511
|
+
applySgrParameters(groups.sgr, activeStyles);
|
|
512
|
+
} else if (groups.uri !== undefined) {
|
|
513
|
+
activeHyperlink = groups.uri.length === 0 ? undefined : {parameters: groups.parameters, uri: groups.uri};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
index += escape[0].length;
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Everything up to the row break is copied verbatim, sequences included.
|
|
521
|
+
returnValue += preString.slice(copiedIndex, index);
|
|
522
|
+
|
|
523
|
+
// An empty row never reopened anything, so there is nothing to close.
|
|
524
|
+
if (index > copiedIndex) {
|
|
525
|
+
if (activeHyperlink) {
|
|
526
|
+
returnValue += wrapAnsiHyperlink('');
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
returnValue += getClosingSgrSequence(activeStyles);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
returnValue += '\n';
|
|
533
|
+
index++;
|
|
534
|
+
copiedIndex = index;
|
|
535
|
+
|
|
536
|
+
// An empty row has nothing to style, so the styles stay closed until the next row with content. A trailing row break leaves no row at all.
|
|
537
|
+
if (index < preString.length && preString[index] !== '\n') {
|
|
538
|
+
const openingStyles = [...activeStyles];
|
|
539
|
+
applyLeadingSgrResets(preString, index, openingStyles);
|
|
540
|
+
returnValue += getOpeningSgrSequence(openingStyles);
|
|
541
|
+
|
|
542
|
+
if (activeHyperlink) {
|
|
543
|
+
returnValue += wrapAnsiHyperlink(activeHyperlink.uri, activeHyperlink.parameters);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
93
546
|
}
|
|
94
547
|
|
|
95
|
-
return
|
|
548
|
+
return returnValue + preString.slice(copiedIndex);
|
|
96
549
|
};
|
|
97
550
|
|
|
98
551
|
// The wrap-ansi module can be invoked in either 'hard' or 'soft' wrap mode.
|
|
@@ -105,21 +558,35 @@ const exec = (string, columns, options = {}) => {
|
|
|
105
558
|
return '';
|
|
106
559
|
}
|
|
107
560
|
|
|
108
|
-
|
|
109
|
-
let escapeCode;
|
|
110
|
-
let escapeUrl;
|
|
111
|
-
|
|
112
|
-
const lengths = wordLengths(string);
|
|
561
|
+
const words = splitWords(string);
|
|
113
562
|
let rows = [''];
|
|
563
|
+
// Tracked as rows are built. Remeasuring the row for every word makes wrapping quadratic in the line length.
|
|
564
|
+
let rowLength = 0;
|
|
565
|
+
// Words are only ever appended, so a row that already starts with content can never become trimmable again. Retrimming it for every word makes wrapping quadratic in the line length.
|
|
566
|
+
let trimmedRowIndex = -1;
|
|
114
567
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
568
|
+
let isFirstWord = true;
|
|
569
|
+
|
|
570
|
+
for (const word of words) {
|
|
571
|
+
const rowIndex = rows.length - 1;
|
|
119
572
|
|
|
120
|
-
|
|
573
|
+
if (options.trim !== false && trimmedRowIndex !== rowIndex) {
|
|
574
|
+
const row = rows[rowIndex];
|
|
575
|
+
const trimmedRow = row.trimStart();
|
|
121
576
|
|
|
122
|
-
|
|
577
|
+
if (trimmedRow.length !== row.length) {
|
|
578
|
+
rows[rowIndex] = trimmedRow;
|
|
579
|
+
rowLength = getWidth(trimmedRow);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (trimmedRow.length > 0) {
|
|
583
|
+
trimmedRowIndex = rowIndex;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (isFirstWord) {
|
|
588
|
+
isFirstWord = false;
|
|
589
|
+
} else {
|
|
123
590
|
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
|
|
124
591
|
// If we start with a new word but the current row length equals the length of the columns, add a new row
|
|
125
592
|
rows.push('');
|
|
@@ -133,90 +600,51 @@ const exec = (string, columns, options = {}) => {
|
|
|
133
600
|
}
|
|
134
601
|
|
|
135
602
|
// In 'hard' wrap mode, the length of a line is never allowed to extend past 'columns'
|
|
136
|
-
if (options.hard &&
|
|
137
|
-
const remainingColumns =
|
|
138
|
-
const breaksStartingThisLine = 1 + Math.floor((
|
|
139
|
-
const breaksStartingNextLine = Math.floor((
|
|
603
|
+
if (options.hard && options.wordWrap !== false && word.width > columns) {
|
|
604
|
+
const remainingColumns = columns - rowLength;
|
|
605
|
+
const breaksStartingThisLine = 1 + Math.floor((word.width - remainingColumns - 1) / columns);
|
|
606
|
+
const breaksStartingNextLine = Math.floor((word.width - 1) / columns);
|
|
140
607
|
if (breaksStartingNextLine < breaksStartingThisLine) {
|
|
141
608
|
rows.push('');
|
|
609
|
+
rowLength = 0;
|
|
142
610
|
}
|
|
143
611
|
|
|
144
|
-
wrapWord(rows, word, columns);
|
|
612
|
+
rowLength = wrapWord(rows, word.value, columns, rowLength);
|
|
145
613
|
continue;
|
|
146
614
|
}
|
|
147
615
|
|
|
148
|
-
if (rowLength +
|
|
616
|
+
if (rowLength + word.width > columns && rowLength > 0 && word.width > 0) {
|
|
149
617
|
if (options.wordWrap === false && rowLength < columns) {
|
|
150
|
-
wrapWord(rows, word, columns);
|
|
618
|
+
rowLength = wrapWord(rows, word.value, columns, rowLength);
|
|
151
619
|
continue;
|
|
152
620
|
}
|
|
153
621
|
|
|
154
622
|
rows.push('');
|
|
623
|
+
rowLength = 0;
|
|
155
624
|
}
|
|
156
625
|
|
|
157
|
-
if (rowLength +
|
|
158
|
-
wrapWord(rows, word, columns);
|
|
626
|
+
if (rowLength + word.width > columns && options.wordWrap === false) {
|
|
627
|
+
rowLength = wrapWord(rows, word.value, columns, rowLength);
|
|
159
628
|
continue;
|
|
160
629
|
}
|
|
161
630
|
|
|
162
|
-
rows[rows.length - 1] += word;
|
|
631
|
+
rows[rows.length - 1] += word.value;
|
|
632
|
+
rowLength += word.width;
|
|
163
633
|
}
|
|
164
634
|
|
|
165
635
|
if (options.trim !== false) {
|
|
166
636
|
rows = rows.map(row => stringVisibleTrimSpacesRight(row));
|
|
167
637
|
}
|
|
168
638
|
|
|
169
|
-
|
|
170
|
-
const pre = [...preString];
|
|
171
|
-
|
|
172
|
-
// We need to keep a separate index as `String#slice()` works on Unicode code units, while `pre` is an array of codepoints.
|
|
173
|
-
let preStringIndex = 0;
|
|
174
|
-
|
|
175
|
-
for (const [index, character] of pre.entries()) {
|
|
176
|
-
returnValue += character;
|
|
177
|
-
|
|
178
|
-
if (ESCAPES.has(character)) {
|
|
179
|
-
const {groups} = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`).exec(preString.slice(preStringIndex)) || {groups: {}};
|
|
180
|
-
if (groups.code !== undefined) {
|
|
181
|
-
const code = Number.parseFloat(groups.code);
|
|
182
|
-
escapeCode = code === END_CODE ? undefined : code;
|
|
183
|
-
} else if (groups.uri !== undefined) {
|
|
184
|
-
escapeUrl = groups.uri.length === 0 ? undefined : groups.uri;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const code = ansiStyles.codes.get(Number(escapeCode));
|
|
189
|
-
|
|
190
|
-
if (pre[index + 1] === '\n') {
|
|
191
|
-
if (escapeUrl) {
|
|
192
|
-
returnValue += wrapAnsiHyperlink('');
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (escapeCode && code) {
|
|
196
|
-
returnValue += wrapAnsiCode(code);
|
|
197
|
-
}
|
|
198
|
-
} else if (character === '\n') {
|
|
199
|
-
if (escapeCode && code) {
|
|
200
|
-
returnValue += wrapAnsiCode(escapeCode);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (escapeUrl) {
|
|
204
|
-
returnValue += wrapAnsiHyperlink(escapeUrl);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
preStringIndex += character.length;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return returnValue;
|
|
639
|
+
return restoreStylesAcrossRows(rows.join('\n'));
|
|
212
640
|
};
|
|
213
641
|
|
|
214
|
-
// For each newline, invoke the method separately
|
|
642
|
+
// For each newline, invoke the method separately.
|
|
215
643
|
export default function wrapAnsi(string, columns, options) {
|
|
216
644
|
return String(string)
|
|
217
645
|
.normalize()
|
|
218
646
|
.replaceAll('\r\n', '\n')
|
|
219
647
|
.split('\n')
|
|
220
|
-
.map(line => exec(line, columns, options))
|
|
648
|
+
.map(line => exec(expandTabs(line), columns, options))
|
|
221
649
|
.join('\n');
|
|
222
650
|
}
|