@alchemy.run/sigil 0.0.0-alpha.3 → 0.0.0-alpha.5
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 +23 -13
- package/THIRD_PARTY_NOTICES.md +70 -23
- package/dist/Text-D5HUf3Fj.d.ts +452 -0
- package/dist/ansi.d.ts +137 -143
- package/dist/ansi.js +87 -2
- 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/{devtools-BhYGjb7h.js → devtools-DbthxoD1.js} +22 -23
- 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-Bmc2tRPk.d.ts +21 -0
- package/dist/index.d.ts +235 -754
- package/dist/index.js +1362 -3001
- 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-BOh__-65.js +324 -0
- package/dist/screen-BReKIheE.d.ts +40 -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-BJmzX2NJ.js +664 -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-C2sciZOo.js +1335 -0
- package/package.json +43 -17
- package/src/ansi/chalk.ts +12 -53
- package/src/ansi/cursor.ts +2 -4
- package/src/ansi/east-asian-width.ts +44 -0
- package/src/ansi/escapes.ts +18 -26
- package/src/ansi/graphemes.ts +8 -0
- package/src/ansi/hyperlink.ts +44 -0
- package/src/ansi/index.ts +14 -14
- package/src/ansi/osc.ts +77 -0
- package/src/ansi/sgr.ts +2 -5
- package/src/ansi/slice.ts +1 -1
- package/src/ansi/string-width.ts +91 -206
- package/src/ansi/strip.ts +13 -33
- package/src/ansi/tokenize.ts +96 -169
- package/src/ansi/truncate.ts +5 -3
- package/src/ansi/wrap.ts +13 -14
- package/src/ansi-tokenizer.ts +1 -1
- 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 +109 -22
- package/src/components/BackgroundContext.ts +2 -3
- package/src/components/Box.tsx +43 -60
- package/src/components/CursorContext.ts +1 -1
- package/src/components/ErrorBoundary.tsx +1 -1
- package/src/components/ErrorOverview.tsx +8 -7
- package/src/components/Hyperlink.tsx +56 -0
- package/src/components/Spacer.tsx +1 -1
- package/src/components/Static.tsx +1 -1
- package/src/components/StderrContext.ts +0 -2
- package/src/components/StdinContext.ts +0 -1
- package/src/components/StdoutContext.ts +1 -3
- package/src/components/TerminalOscContext.ts +25 -0
- package/src/components/Text.tsx +23 -46
- package/src/components/Transform.tsx +2 -2
- package/src/cursor-position.ts +1 -1
- package/src/devtools.ts +84 -24
- package/src/dom.ts +11 -8
- package/src/env.ts +12 -0
- package/src/get-max-width.ts +1 -1
- package/src/global.d.ts +6 -4
- package/src/{boxes.ts → glyphs.ts} +17 -18
- package/src/hooks/use-animation.ts +1 -1
- package/src/hooks/use-app.ts +1 -1
- package/src/hooks/use-box-metrics.ts +1 -1
- package/src/hooks/use-capabilities.ts +73 -0
- package/src/hooks/use-cursor.ts +3 -3
- package/src/hooks/use-focus-manager.ts +1 -1
- package/src/hooks/use-focus.ts +5 -6
- package/src/hooks/use-input.ts +4 -4
- package/src/hooks/use-is-screen-reader-enabled.ts +1 -1
- package/src/hooks/use-paste.ts +2 -2
- package/src/hooks/use-stderr.ts +1 -1
- package/src/hooks/use-stdin.ts +1 -1
- package/src/hooks/use-stdout.ts +1 -1
- package/src/hooks/use-terminal-osc.ts +59 -0
- package/src/hooks/use-window-size.ts +2 -2
- package/src/index.ts +88 -44
- package/src/ink.tsx +620 -745
- package/src/input-parser.ts +1 -1
- package/src/instances.ts +1 -1
- package/src/kitty-keyboard.ts +128 -0
- package/src/measure-element.ts +1 -1
- package/src/measure-text.ts +2 -2
- package/src/{render-node-to-output.ts → paint-tree.ts} +78 -53
- package/src/parse-keypress.ts +4 -5
- package/src/parse-stack-line.ts +0 -1
- package/src/patch-console.ts +44 -0
- package/src/reconciler.ts +36 -62
- package/src/render-background.ts +37 -16
- package/src/render-border.ts +97 -64
- package/src/render-frame.ts +83 -0
- package/src/render-to-string.ts +24 -9
- package/src/render.ts +24 -16
- 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/sanitize-ansi.ts +1 -1
- package/src/screen/ansi.ts +184 -0
- package/src/screen/canvas.ts +137 -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 +272 -0
- package/src/screen/serialize.ts +129 -0
- package/src/screen.ts +1 -0
- package/src/semantic-text-style.ts +118 -0
- package/src/signal-exit.ts +4 -5
- package/src/squash-text-nodes.ts +4 -7
- package/src/stream.ts +2 -4
- package/src/structured-text.ts +321 -0
- package/src/styles.ts +16 -17
- 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-size.ts +9 -8
- 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/types.ts +1 -6
- package/src/utils.ts +2 -2
- package/src/wrap-text.ts +4 -4
- package/src/yoga/config.ts +2 -2
- package/src/yoga/core/absoluteLayout.ts +15 -15
- package/src/yoga/core/baseline.ts +3 -3
- package/src/yoga/core/cache.ts +4 -4
- package/src/yoga/core/calculateLayout.ts +33 -27
- package/src/yoga/core/config.ts +1 -1
- package/src/yoga/core/flexLine.ts +3 -3
- package/src/yoga/core/helpers.ts +3 -3
- package/src/yoga/core/layoutResults.ts +4 -4
- package/src/yoga/core/node.ts +16 -16
- package/src/yoga/core/pixelGrid.ts +4 -4
- package/src/yoga/core/style.ts +11 -11
- package/src/yoga/core/types.ts +2 -2
- package/src/yoga/index.ts +6 -6
- package/src/yoga/node.ts +8 -8
- package/dist/sgr-CMfEpjSk.d.ts +0 -91
- package/dist/truncate-CBiyyZzw.js +0 -2156
- package/src/ansi/supports-color.ts +0 -213
- package/src/ansi/widest-line.ts +0 -12
- package/src/auto-bind.ts +0 -41
- package/src/colorize.ts +0 -60
- package/src/devtools-window-polyfill.ts +0 -73
- package/src/indent-string.ts +0 -16
- package/src/is-in-ci.ts +0 -7
- package/src/log-update.ts +0 -370
- package/src/output.ts +0 -308
- package/src/renderer.ts +0 -73
- package/src/write-synchronized.ts +0 -9
package/src/ansi/string-width.ts
CHANGED
|
@@ -1,236 +1,121 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// Logic:
|
|
6
|
-
// - Segment graphemes to match how terminals render clusters.
|
|
7
|
-
// - Width rules:
|
|
8
|
-
// 1. Skip non-printing clusters (Default_Ignorable, Control, pure
|
|
9
|
-
// nonspacing/enclosing Mark, lone Surrogates). Tabs are ignored by design.
|
|
10
|
-
// 2. RGI emoji clusters (\p{RGI_Emoji}) are double-width.
|
|
11
|
-
// 3. Minimally-qualified/unqualified emoji clusters (ZWJ sequences with 2+
|
|
12
|
-
// Extended_Pictographic, or keycap sequences) are double-width.
|
|
13
|
-
// 4. Hangul jamo collapse each standard modern Hangul L+V or L+V+T syllable
|
|
14
|
-
// piece to width 2. Unmatched repeated leading/vowel/trailing jamo stay
|
|
15
|
-
// additive because that matches how the terminals we target render them.
|
|
16
|
-
// 5. Otherwise use East Asian Width of the cluster's first visible code
|
|
17
|
-
// point, and add widths for trailing spacing marks and Halfwidth/Fullwidth
|
|
18
|
-
// Forms within the same cluster (e.g., dakuten/handakuten).
|
|
19
|
-
import { C1_CSI, ESC } from "./escapes.ts";
|
|
20
|
-
import { stripAnsi } from "./strip.ts";
|
|
21
|
-
|
|
22
|
-
export type StringWidthOptions = {
|
|
23
|
-
readonly ambiguousIsNarrow?: boolean;
|
|
24
|
-
readonly countAnsiEscapeCodes?: boolean;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
type EastAsianWidthOptions = {
|
|
28
|
-
readonly ambiguousAsWide: boolean;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const segmenter = new Intl.Segmenter();
|
|
32
|
-
|
|
33
|
-
// Whole-cluster zero-width
|
|
34
|
-
const zeroWidthClusterRegex =
|
|
35
|
-
/^(?:\p{Default_Ignorable_Code_Point}|\p{Control}|\p{Format}|\p{Nonspacing_Mark}|\p{Enclosing_Mark}|\p{Surrogate})+$/v;
|
|
1
|
+
// Derived from `fast-string-truncated-width` (MIT, Fabio Spampinato),
|
|
2
|
+
// reduced to plain width measurement: Sigil truncates via `truncate.ts`, and
|
|
3
|
+
// no caller customizes per-class widths, so those are constants here.
|
|
4
|
+
// Width tables live in east-asian-width.ts, the single width-data module.
|
|
36
5
|
|
|
37
|
-
|
|
38
|
-
const leadingNonPrintingRegex =
|
|
39
|
-
/^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Nonspacing_Mark}\p{Enclosing_Mark}\p{Surrogate}]+/v;
|
|
40
|
-
const spacingMarkRegex = /\p{Spacing_Mark}/v;
|
|
6
|
+
import { isFullWidth, isWideNotCJKTNotEmoji } from "#/ansi/east-asian-width.ts";
|
|
41
7
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Detect minimally-qualified/unqualified emoji sequences (missing VS16 but
|
|
46
|
-
// still rendering as double-width)
|
|
47
|
-
const unqualifiedKeycapRegex = /^[\d#*]\u20E3$/;
|
|
48
|
-
const extendedPictographicRegex = /\p{Extended_Pictographic}/gu;
|
|
49
|
-
|
|
50
|
-
function isDoubleWidthNonRgiEmojiSequence(segment: string): boolean {
|
|
51
|
-
// Real emoji clusters are < 30 chars; guard against pathological input
|
|
52
|
-
if (segment.length > 50) {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (unqualifiedKeycapRegex.test(segment)) {
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
8
|
+
const getCodePointsLength = (input: string): number => {
|
|
9
|
+
let length = 0;
|
|
59
10
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const pictographics = segment.match(extendedPictographicRegex);
|
|
63
|
-
return pictographics !== null && pictographics.length >= 2;
|
|
11
|
+
for (const _ of input) {
|
|
12
|
+
length += 1;
|
|
64
13
|
}
|
|
65
14
|
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function baseVisible(segment: string): string {
|
|
70
|
-
return segment.replace(leadingNonPrintingRegex, "");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function isZeroWidthCluster(segment: string): boolean {
|
|
74
|
-
return zeroWidthClusterRegex.test(segment);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function isHangulLeadingJamo(codePoint: number | undefined): boolean {
|
|
78
|
-
return (
|
|
79
|
-
codePoint !== undefined &&
|
|
80
|
-
((codePoint >= 0x11_00 && codePoint <= 0x11_5f) ||
|
|
81
|
-
(codePoint >= 0xa9_60 && codePoint <= 0xa9_7c))
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function isHangulVowelJamo(codePoint: number | undefined): boolean {
|
|
86
|
-
return (
|
|
87
|
-
codePoint !== undefined &&
|
|
88
|
-
((codePoint >= 0x11_60 && codePoint <= 0x11_a7) ||
|
|
89
|
-
(codePoint >= 0xd7_b0 && codePoint <= 0xd7_c6))
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function isHangulTrailingJamo(codePoint: number | undefined): boolean {
|
|
94
|
-
return (
|
|
95
|
-
codePoint !== undefined &&
|
|
96
|
-
((codePoint >= 0x11_a8 && codePoint <= 0x11_ff) ||
|
|
97
|
-
(codePoint >= 0xd7_cb && codePoint <= 0xd7_fb))
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function isHangulJamo(codePoint: number): boolean {
|
|
102
|
-
return (
|
|
103
|
-
isHangulLeadingJamo(codePoint) ||
|
|
104
|
-
isHangulVowelJamo(codePoint) ||
|
|
105
|
-
isHangulTrailingJamo(codePoint)
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function hangulClusterWidth(
|
|
110
|
-
visibleSegment: string,
|
|
111
|
-
eastAsianWidthOptions: EastAsianWidthOptions,
|
|
112
|
-
): number | undefined {
|
|
113
|
-
const codePoints: number[] = [];
|
|
114
|
-
|
|
115
|
-
for (const character of visibleSegment) {
|
|
116
|
-
if (zeroWidthClusterRegex.test(character)) {
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
15
|
+
return length;
|
|
16
|
+
};
|
|
119
17
|
|
|
120
|
-
|
|
121
|
-
|
|
18
|
+
// Unlike the original port, CSI parameters also allow `:` so ITU T.416
|
|
19
|
+
// colon-parameter SGR sequences (which Sigil preserves) measure as width 0.
|
|
20
|
+
const ANSI_RE =
|
|
21
|
+
/[\u001b\u009b][[()#;?]*[0-9;:]*[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
|
|
22
|
+
const CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
|
|
23
|
+
const CJKT_WIDE_RE =
|
|
24
|
+
/(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/uy;
|
|
25
|
+
const TAB_RE = /\t{1,1000}/y;
|
|
26
|
+
const EMOJI_RE =
|
|
27
|
+
/[\u{1F1E6}-\u{1F1FF}]{2}|\u{1F3F4}[\u{E0061}-\u{E007A}]{2}[\u{E0030}-\u{E0039}\u{E0061}-\u{E007A}]{1,3}\u{E007F}|(?:\p{Emoji}\uFE0F\u20E3?|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation})(?:\u200D(?:\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F\u20E3?))*/uy;
|
|
28
|
+
const LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
|
|
29
|
+
const MODIFIER_RE = /\p{M}+/gu;
|
|
30
|
+
|
|
31
|
+
const ANSI_WIDTH = 0;
|
|
32
|
+
const CONTROL_WIDTH = 0;
|
|
33
|
+
const TAB_WIDTH = 8;
|
|
34
|
+
const EMOJI_WIDTH = 2;
|
|
35
|
+
const FULL_WIDTH_WIDTH = 2;
|
|
36
|
+
const REGULAR_WIDTH = 1;
|
|
37
|
+
const WIDE_WIDTH = 2;
|
|
38
|
+
|
|
39
|
+
const PARSE_BLOCKS: [RegExp, number][] = [
|
|
40
|
+
[LATIN_RE, REGULAR_WIDTH],
|
|
41
|
+
[ANSI_RE, ANSI_WIDTH],
|
|
42
|
+
[CONTROL_RE, CONTROL_WIDTH],
|
|
43
|
+
[TAB_RE, TAB_WIDTH],
|
|
44
|
+
[EMOJI_RE, EMOJI_WIDTH],
|
|
45
|
+
[CJKT_WIDE_RE, WIDE_WIDTH],
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
export const stringWidth = (input: string): number => {
|
|
49
|
+
let indexPrev = 0;
|
|
50
|
+
let index = 0;
|
|
51
|
+
const length = input.length;
|
|
52
|
+
let unmatchedStart = 0;
|
|
53
|
+
let unmatchedEnd = 0;
|
|
54
|
+
let width = 0;
|
|
122
55
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
56
|
+
outer: while (true) {
|
|
57
|
+
/* UNMATCHED */
|
|
126
58
|
|
|
127
|
-
|
|
59
|
+
if (unmatchedEnd > unmatchedStart || (index >= length && index > indexPrev)) {
|
|
60
|
+
const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
|
|
128
61
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (!isHangulJamo(codePoint)) {
|
|
132
|
-
if (width === 0) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
62
|
+
for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
|
|
63
|
+
const codePoint = char.codePointAt(0) || 0;
|
|
135
64
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
65
|
+
width += isFullWidth(codePoint)
|
|
66
|
+
? FULL_WIDTH_WIDTH
|
|
67
|
+
: isWideNotCJKTNotEmoji(codePoint)
|
|
68
|
+
? WIDE_WIDTH
|
|
69
|
+
: REGULAR_WIDTH;
|
|
140
70
|
}
|
|
141
71
|
|
|
142
|
-
|
|
72
|
+
unmatchedStart = unmatchedEnd = 0;
|
|
143
73
|
}
|
|
144
74
|
|
|
145
|
-
|
|
146
|
-
// additive: U+1100 U+1100 U+1161 => U+1100 + (U+1100 U+1161) => 2 + 2.
|
|
147
|
-
if (isHangulLeadingJamo(codePoint) && isHangulVowelJamo(codePoints[index + 1])) {
|
|
148
|
-
width += 2;
|
|
149
|
-
index += isHangulTrailingJamo(codePoints[index + 2]) ? 2 : 1;
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
154
|
-
}
|
|
75
|
+
/* EXITING */
|
|
155
76
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
function trailingWidth(
|
|
160
|
-
visibleSegment: string,
|
|
161
|
-
eastAsianWidthOptions: EastAsianWidthOptions,
|
|
162
|
-
): number {
|
|
163
|
-
let extra = 0;
|
|
164
|
-
let first = true;
|
|
165
|
-
|
|
166
|
-
for (const character of visibleSegment) {
|
|
167
|
-
if (first) {
|
|
168
|
-
first = false;
|
|
169
|
-
continue;
|
|
77
|
+
if (index >= length) {
|
|
78
|
+
break;
|
|
170
79
|
}
|
|
171
80
|
|
|
172
|
-
|
|
173
|
-
extra += eastAsianWidth(character.codePointAt(0)!, eastAsianWidthOptions);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
81
|
+
/* PARSE BLOCKS */
|
|
176
82
|
|
|
177
|
-
|
|
178
|
-
|
|
83
|
+
for (let i = 0, l = PARSE_BLOCKS.length; i < l; i++) {
|
|
84
|
+
const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i]!;
|
|
179
85
|
|
|
180
|
-
|
|
181
|
-
if (typeof input !== "string" || input.length === 0) {
|
|
182
|
-
return 0;
|
|
183
|
-
}
|
|
86
|
+
BLOCK_RE.lastIndex = index;
|
|
184
87
|
|
|
185
|
-
|
|
88
|
+
if (BLOCK_RE.test(input)) {
|
|
89
|
+
const lengthExtra =
|
|
90
|
+
BLOCK_RE === CJKT_WIDE_RE
|
|
91
|
+
? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex))
|
|
92
|
+
: BLOCK_RE === EMOJI_RE
|
|
93
|
+
? 1
|
|
94
|
+
: BLOCK_RE.lastIndex - index;
|
|
186
95
|
|
|
187
|
-
|
|
96
|
+
width += lengthExtra * BLOCK_WIDTH;
|
|
97
|
+
unmatchedStart = indexPrev;
|
|
98
|
+
unmatchedEnd = index;
|
|
99
|
+
index = indexPrev = BLOCK_RE.lastIndex;
|
|
188
100
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
string = stripAnsi(string);
|
|
193
|
-
}
|
|
101
|
+
continue outer;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
194
104
|
|
|
195
|
-
|
|
196
|
-
return 0;
|
|
197
|
-
}
|
|
105
|
+
/* UNMATCHED INDEX */
|
|
198
106
|
|
|
199
|
-
|
|
200
|
-
// lookup — width equals length.
|
|
201
|
-
if (/^[ -~]*$/.test(string)) {
|
|
202
|
-
return string.length;
|
|
107
|
+
index += 1;
|
|
203
108
|
}
|
|
204
109
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
for (const { segment } of segmenter.segment(string)) {
|
|
209
|
-
// Zero-width / non-printing clusters
|
|
210
|
-
if (isZeroWidthCluster(segment)) {
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Emoji width logic
|
|
215
|
-
if (rgiEmojiRegex.test(segment) || isDoubleWidthNonRgiEmojiSequence(segment)) {
|
|
216
|
-
width += 2;
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const visibleSegment = baseVisible(segment);
|
|
221
|
-
const hangulWidth = hangulClusterWidth(visibleSegment, eastAsianWidthOptions);
|
|
222
|
-
if (hangulWidth !== undefined) {
|
|
223
|
-
width += hangulWidth;
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
110
|
+
return width;
|
|
111
|
+
};
|
|
226
112
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
113
|
+
export const widestLine = (text: string): number => {
|
|
114
|
+
let lineWidth = 0;
|
|
230
115
|
|
|
231
|
-
|
|
232
|
-
|
|
116
|
+
for (const line of text.split("\n")) {
|
|
117
|
+
lineWidth = Math.max(lineWidth, stringWidth(line));
|
|
233
118
|
}
|
|
234
119
|
|
|
235
|
-
return
|
|
236
|
-
}
|
|
120
|
+
return lineWidth;
|
|
121
|
+
};
|
package/src/ansi/strip.ts
CHANGED
|
@@ -1,33 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// CSI and related: ESC/C1, optional intermediates, optional params
|
|
16
|
-
// (supports ; and :) then final byte
|
|
17
|
-
const csi = `[${ESC}${C1_CSI}][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]`;
|
|
18
|
-
|
|
19
|
-
return new RegExp(`${osc}|${csi}`, onlyFirst ? undefined : "g");
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const regex = ansiRegex();
|
|
23
|
-
|
|
24
|
-
export function stripAnsi(string: string): string {
|
|
25
|
-
// Fast path: ANSI codes require ESC (7-bit) or CSI (8-bit) introducer
|
|
26
|
-
if (!string.includes(ESC) && !string.includes(C1_CSI)) {
|
|
27
|
-
return string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Even though the regex is global, we don't need to reset `.lastIndex`
|
|
31
|
-
// because `.replace()` does it automatically.
|
|
32
|
-
return string.replace(regex, "");
|
|
33
|
-
}
|
|
1
|
+
import { stripVTControlCharacters } from "node:util";
|
|
2
|
+
|
|
3
|
+
// Node's stripVTControlCharacters only understands semicolon-separated CSI
|
|
4
|
+
// parameters, so an ITU T.416 colon-parameter SGR sequence like
|
|
5
|
+
// `\u001B[38:2::255:100:0m` — which Sigil deliberately preserves in output
|
|
6
|
+
// (see sanitize-ansi.ts) — would leave `:2::255:100:0m` behind. Remove those
|
|
7
|
+
// first, then let Node handle everything else.
|
|
8
|
+
// https://github.com/nodejs/node/pull/65379 fixes this upstream; this wrapper
|
|
9
|
+
// can go once the minimum supported Node version ships it.
|
|
10
|
+
const colonSgrRegex = /(?:\u001B\[|\u009B)[\d;]*:[\d;:]*m/g;
|
|
11
|
+
|
|
12
|
+
export const stripAnsi = (input: string): string =>
|
|
13
|
+
stripVTControlCharacters(input.replaceAll(colonSgrRegex, ""));
|