@hatchway/cli 0.51.1 → 0.51.4
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/dist/chunks/{Banner-_pJB7dCO.js → Banner-Dslid-AI.js} +2 -3
- package/dist/chunks/{Banner-_pJB7dCO.js.map → Banner-Dslid-AI.js.map} +1 -1
- package/dist/chunks/devtools-CPruVlOo.js.map +1 -1
- package/dist/chunks/{index-CovlIWnu.js → index-y6cN9k8l.js} +2 -3
- package/dist/chunks/{index-CovlIWnu.js.map → index-y6cN9k8l.js.map} +1 -1
- package/dist/chunks/{init-Eo7XainT.js → init-Cw1DkJP-.js} +6 -5
- package/dist/chunks/{init-Eo7XainT.js.map → init-Cw1DkJP-.js.map} +1 -1
- package/dist/chunks/{init-tui-Cgxsmmn-.js → init-tui-WELhLH16.js} +7 -6
- package/dist/chunks/{init-tui-Cgxsmmn-.js.map → init-tui-WELhLH16.js.map} +1 -1
- package/dist/chunks/{main-tui-D580QurF.js → main-tui-BI9X6TRI.js} +8 -7
- package/dist/chunks/{main-tui-D580QurF.js.map → main-tui-BI9X6TRI.js.map} +1 -1
- package/dist/chunks/{manager-0U0BIO9r.js → manager-LKbmrJIf.js} +6 -97
- package/dist/chunks/manager-LKbmrJIf.js.map +1 -0
- package/dist/chunks/{run-DbXViD2C.js → run-Bvfox4jS.js} +10 -9
- package/dist/chunks/{run-DbXViD2C.js.map → run-Bvfox4jS.js.map} +1 -1
- package/dist/chunks/{start-BEIpWjyK.js → start-Drql12dh.js} +8 -7
- package/dist/chunks/{start-BEIpWjyK.js.map → start-Drql12dh.js.map} +1 -1
- package/dist/chunks/{theme-CzLXk_6s.js → theme-BmodcXss.js} +3430 -631
- package/dist/chunks/theme-BmodcXss.js.map +1 -0
- package/dist/chunks/{use-app-Dw8M2HNg.js → use-app-0PVAweWQ.js} +2 -2
- package/dist/chunks/{use-app-Dw8M2HNg.js.map → use-app-0PVAweWQ.js.map} +1 -1
- package/dist/chunks/{useBuildState-DjvkDA6v.js → useBuildState-CGyaE4Ou.js} +3 -3
- package/dist/chunks/{useBuildState-DjvkDA6v.js.map → useBuildState-CGyaE4Ou.js.map} +1 -1
- package/dist/cli/index.js +5 -5
- package/dist/index.js +1 -53
- package/dist/index.js.map +1 -1
- package/dist/lib/skills/platform-plugin/skills/todo-workflow/SKILL.md +43 -21
- package/package.json +1 -1
- package/dist/chunks/manager-0U0BIO9r.js.map +0 -1
- package/dist/chunks/theme-CzLXk_6s.js.map +0 -1
|
@@ -3,10 +3,13 @@ import { PassThrough, Stream } from 'node:stream';
|
|
|
3
3
|
import process$1, { env, cwd } from 'node:process';
|
|
4
4
|
import require$$0$1 from 'assert';
|
|
5
5
|
import require$$2 from 'events';
|
|
6
|
+
import { execFileSync } from 'node:child_process';
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import fs__default from 'node:fs';
|
|
9
|
+
import tty from 'node:tty';
|
|
6
10
|
import chalk from 'chalk';
|
|
7
11
|
import os from 'node:os';
|
|
8
12
|
import { EventEmitter } from 'node:events';
|
|
9
|
-
import * as fs from 'node:fs';
|
|
10
13
|
import require$$1 from 'module';
|
|
11
14
|
import { Buffer as Buffer$1 } from 'node:buffer';
|
|
12
15
|
|
|
@@ -1882,117 +1885,170 @@ function requireReact () {
|
|
|
1882
1885
|
var reactExports = requireReact();
|
|
1883
1886
|
var React = /*@__PURE__*/getDefaultExportFromCjs(reactExports);
|
|
1884
1887
|
|
|
1888
|
+
//#region src/function/debounce.ts
|
|
1889
|
+
/**
|
|
1890
|
+
* Creates a debounced function that delays invoking the provided function until after `debounceMs` milliseconds
|
|
1891
|
+
* have elapsed since the last time the debounced function was invoked. The debounced function also has a `cancel`
|
|
1892
|
+
* method to cancel any pending execution.
|
|
1893
|
+
*
|
|
1894
|
+
* @template F - The type of function.
|
|
1895
|
+
* @param func - The function to debounce.
|
|
1896
|
+
* @param debounceMs - The number of milliseconds to delay.
|
|
1897
|
+
* @param options - The options object
|
|
1898
|
+
* @param options.signal - An optional AbortSignal to cancel the debounced function.
|
|
1899
|
+
* @param options.edges - An optional array specifying whether the function should be invoked on the leading edge, trailing edge, or both.
|
|
1900
|
+
* @returns A new debounced function with a `cancel` method.
|
|
1901
|
+
*
|
|
1902
|
+
* @example
|
|
1903
|
+
* const debouncedFunction = debounce(() => {
|
|
1904
|
+
* console.log('Function executed');
|
|
1905
|
+
* }, 1000);
|
|
1906
|
+
*
|
|
1907
|
+
* // Will log 'Function executed' after 1 second if not called again in that time
|
|
1908
|
+
* debouncedFunction();
|
|
1909
|
+
*
|
|
1910
|
+
* // Will not log anything as the previous call is canceled
|
|
1911
|
+
* debouncedFunction.cancel();
|
|
1912
|
+
*
|
|
1913
|
+
* // With AbortSignal
|
|
1914
|
+
* const controller = new AbortController();
|
|
1915
|
+
* const signal = controller.signal;
|
|
1916
|
+
* const debouncedWithSignal = debounce(() => {
|
|
1917
|
+
* console.log('Function executed');
|
|
1918
|
+
* }, 1000, { signal });
|
|
1919
|
+
*
|
|
1920
|
+
* debouncedWithSignal();
|
|
1921
|
+
*
|
|
1922
|
+
* // Will cancel the debounced function call
|
|
1923
|
+
* controller.abort();
|
|
1924
|
+
*/
|
|
1885
1925
|
function debounce$1(func, debounceMs, { signal, edges } = {}) {
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
invoke();
|
|
1937
|
-
}
|
|
1938
|
-
};
|
|
1939
|
-
debounced.schedule = schedule;
|
|
1940
|
-
debounced.cancel = cancel;
|
|
1941
|
-
debounced.flush = flush;
|
|
1942
|
-
signal?.addEventListener('abort', cancel, { once: true });
|
|
1943
|
-
return debounced;
|
|
1926
|
+
let pendingThis = void 0;
|
|
1927
|
+
let pendingArgs = null;
|
|
1928
|
+
const leading = edges != null && edges.includes("leading");
|
|
1929
|
+
const trailing = edges == null || edges.includes("trailing");
|
|
1930
|
+
const invoke = () => {
|
|
1931
|
+
if (pendingArgs !== null) {
|
|
1932
|
+
func.apply(pendingThis, pendingArgs);
|
|
1933
|
+
pendingThis = void 0;
|
|
1934
|
+
pendingArgs = null;
|
|
1935
|
+
}
|
|
1936
|
+
};
|
|
1937
|
+
const onTimerEnd = () => {
|
|
1938
|
+
if (trailing) invoke();
|
|
1939
|
+
cancel();
|
|
1940
|
+
};
|
|
1941
|
+
let timeoutId = null;
|
|
1942
|
+
const schedule = () => {
|
|
1943
|
+
if (timeoutId != null) clearTimeout(timeoutId);
|
|
1944
|
+
timeoutId = setTimeout(() => {
|
|
1945
|
+
timeoutId = null;
|
|
1946
|
+
onTimerEnd();
|
|
1947
|
+
}, debounceMs);
|
|
1948
|
+
};
|
|
1949
|
+
const cancelTimer = () => {
|
|
1950
|
+
if (timeoutId !== null) {
|
|
1951
|
+
clearTimeout(timeoutId);
|
|
1952
|
+
timeoutId = null;
|
|
1953
|
+
}
|
|
1954
|
+
};
|
|
1955
|
+
const cancel = () => {
|
|
1956
|
+
cancelTimer();
|
|
1957
|
+
pendingThis = void 0;
|
|
1958
|
+
pendingArgs = null;
|
|
1959
|
+
};
|
|
1960
|
+
const flush = () => {
|
|
1961
|
+
invoke();
|
|
1962
|
+
};
|
|
1963
|
+
const debounced = function(...args) {
|
|
1964
|
+
if (signal?.aborted) return;
|
|
1965
|
+
pendingThis = this;
|
|
1966
|
+
pendingArgs = args;
|
|
1967
|
+
const isFirstCall = timeoutId == null;
|
|
1968
|
+
schedule();
|
|
1969
|
+
if (leading && isFirstCall) invoke();
|
|
1970
|
+
};
|
|
1971
|
+
debounced.schedule = schedule;
|
|
1972
|
+
debounced.cancel = cancel;
|
|
1973
|
+
debounced.flush = flush;
|
|
1974
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
1975
|
+
return debounced;
|
|
1944
1976
|
}
|
|
1945
1977
|
|
|
1978
|
+
//#region src/compat/function/debounce.ts
|
|
1946
1979
|
function debounce(func, debounceMs = 0, options = {}) {
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
};
|
|
1980
|
-
const flush = () => {
|
|
1981
|
-
_debounced.flush();
|
|
1982
|
-
return result;
|
|
1983
|
-
};
|
|
1984
|
-
debounced.cancel = _debounced.cancel;
|
|
1985
|
-
debounced.flush = flush;
|
|
1986
|
-
return debounced;
|
|
1980
|
+
if (typeof options !== "object") options = {};
|
|
1981
|
+
const { leading = false, trailing = true, maxWait } = options;
|
|
1982
|
+
const edges = Array(2);
|
|
1983
|
+
if (leading) edges[0] = "leading";
|
|
1984
|
+
if (trailing) edges[1] = "trailing";
|
|
1985
|
+
let result = void 0;
|
|
1986
|
+
let pendingAt = null;
|
|
1987
|
+
const _debounced = debounce$1(function(...args) {
|
|
1988
|
+
result = func.apply(this, args);
|
|
1989
|
+
pendingAt = null;
|
|
1990
|
+
}, debounceMs, { edges });
|
|
1991
|
+
const debounced = function(...args) {
|
|
1992
|
+
if (maxWait != null) {
|
|
1993
|
+
if (pendingAt === null) pendingAt = Date.now();
|
|
1994
|
+
if (Date.now() - pendingAt >= maxWait) {
|
|
1995
|
+
result = func.apply(this, args);
|
|
1996
|
+
pendingAt = Date.now();
|
|
1997
|
+
_debounced.cancel();
|
|
1998
|
+
_debounced.schedule();
|
|
1999
|
+
return result;
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
_debounced.apply(this, args);
|
|
2003
|
+
return result;
|
|
2004
|
+
};
|
|
2005
|
+
const flush = () => {
|
|
2006
|
+
_debounced.flush();
|
|
2007
|
+
return result;
|
|
2008
|
+
};
|
|
2009
|
+
debounced.cancel = _debounced.cancel;
|
|
2010
|
+
debounced.flush = flush;
|
|
2011
|
+
return debounced;
|
|
1987
2012
|
}
|
|
1988
2013
|
|
|
2014
|
+
//#region src/compat/function/throttle.ts
|
|
2015
|
+
/**
|
|
2016
|
+
* Creates a throttled function that only invokes the provided function at most once
|
|
2017
|
+
* per every `throttleMs` milliseconds. Subsequent calls to the throttled function
|
|
2018
|
+
* within the wait time will not trigger the execution of the original function.
|
|
2019
|
+
*
|
|
2020
|
+
* @template F - The type of function.
|
|
2021
|
+
* @param func - The function to throttle.
|
|
2022
|
+
* @param throttleMs - The number of milliseconds to throttle executions to.
|
|
2023
|
+
* @param options - The options object
|
|
2024
|
+
* @param options.signal - An optional AbortSignal to cancel the throttled function.
|
|
2025
|
+
* @param options.leading - If `true`, the function will be invoked on the leading edge of the timeout.
|
|
2026
|
+
* @param options.trailing - If `true`, the function will be invoked on the trailing edge of the timeout.
|
|
2027
|
+
* @returns A new throttled function that accepts the same parameters as the original function.
|
|
2028
|
+
*
|
|
2029
|
+
* @example
|
|
2030
|
+
* const throttledFunction = throttle(() => {
|
|
2031
|
+
* console.log('Function executed');
|
|
2032
|
+
* }, 1000);
|
|
2033
|
+
*
|
|
2034
|
+
* // Will log 'Function executed' immediately
|
|
2035
|
+
* throttledFunction();
|
|
2036
|
+
*
|
|
2037
|
+
* // Will not log anything as it is within the throttle time
|
|
2038
|
+
* throttledFunction();
|
|
2039
|
+
*
|
|
2040
|
+
* // After 1 second
|
|
2041
|
+
* setTimeout(() => {
|
|
2042
|
+
* throttledFunction(); // Will log 'Function executed'
|
|
2043
|
+
* }, 1000);
|
|
2044
|
+
*/
|
|
1989
2045
|
function throttle(func, throttleMs = 0, options = {}) {
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
2046
|
+
const { leading = true, trailing = true } = options;
|
|
2047
|
+
return debounce(func, throttleMs, {
|
|
2048
|
+
leading,
|
|
2049
|
+
maxWait: throttleMs,
|
|
2050
|
+
trailing
|
|
2051
|
+
});
|
|
1996
2052
|
}
|
|
1997
2053
|
|
|
1998
2054
|
/* globals WorkerGlobalScope, DedicatedWorkerGlobalScope, SharedWorkerGlobalScope, ServiceWorkerGlobalScope */
|
|
@@ -2049,7 +2105,18 @@ isBrowser ? () => {
|
|
|
2049
2105
|
throw new Error('`process.cwd()` only works in Node.js, not the browser.');
|
|
2050
2106
|
} : process$1.cwd;
|
|
2051
2107
|
|
|
2108
|
+
const cursorTo = (x, y) => {
|
|
2109
|
+
if (typeof x !== 'number') {
|
|
2110
|
+
throw new TypeError('The `x` argument is required');
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
{
|
|
2114
|
+
return ESC + (x + 1) + 'G';
|
|
2115
|
+
}
|
|
2116
|
+
};
|
|
2117
|
+
|
|
2052
2118
|
const cursorUp = (count = 1) => ESC + count + 'A';
|
|
2119
|
+
const cursorDown = (count = 1) => ESC + count + 'B';
|
|
2053
2120
|
|
|
2054
2121
|
const cursorLeft = ESC + 'G';
|
|
2055
2122
|
const cursorNextLine = ESC + 'E';
|
|
@@ -2067,6 +2134,8 @@ const eraseLines = count => {
|
|
|
2067
2134
|
|
|
2068
2135
|
return clear;
|
|
2069
2136
|
};
|
|
2137
|
+
|
|
2138
|
+
const eraseEndLine = ESC + 'K';
|
|
2070
2139
|
const eraseLine = ESC + '2K';
|
|
2071
2140
|
const eraseScreen = ESC + '2J';
|
|
2072
2141
|
|
|
@@ -2987,7 +3056,7 @@ function stripAnsi(string) {
|
|
|
2987
3056
|
|
|
2988
3057
|
// Generated code.
|
|
2989
3058
|
|
|
2990
|
-
function isAmbiguous(x) {
|
|
3059
|
+
function isAmbiguous$1(x) {
|
|
2991
3060
|
return x === 0xA1
|
|
2992
3061
|
|| x === 0xA4
|
|
2993
3062
|
|| x === 0xA7
|
|
@@ -3205,13 +3274,13 @@ function isAmbiguous(x) {
|
|
|
3205
3274
|
|| x >= 0x100000 && x <= 0x10FFFD;
|
|
3206
3275
|
}
|
|
3207
3276
|
|
|
3208
|
-
function isFullWidth(x) {
|
|
3277
|
+
function isFullWidth$1(x) {
|
|
3209
3278
|
return x === 0x3000
|
|
3210
3279
|
|| x >= 0xFF01 && x <= 0xFF60
|
|
3211
3280
|
|| x >= 0xFFE0 && x <= 0xFFE6;
|
|
3212
3281
|
}
|
|
3213
3282
|
|
|
3214
|
-
function isWide(x) {
|
|
3283
|
+
function isWide$1(x) {
|
|
3215
3284
|
return x >= 0x1100 && x <= 0x115F
|
|
3216
3285
|
|| x === 0x231A
|
|
3217
3286
|
|| x === 0x231B
|
|
@@ -3350,19 +3419,19 @@ function isWide(x) {
|
|
|
3350
3419
|
|| x >= 0x30000 && x <= 0x3FFFD;
|
|
3351
3420
|
}
|
|
3352
3421
|
|
|
3353
|
-
function validate(codePoint) {
|
|
3422
|
+
function validate$1(codePoint) {
|
|
3354
3423
|
if (!Number.isSafeInteger(codePoint)) {
|
|
3355
3424
|
throw new TypeError(`Expected a code point, got \`${typeof codePoint}\`.`);
|
|
3356
3425
|
}
|
|
3357
3426
|
}
|
|
3358
3427
|
|
|
3359
|
-
function eastAsianWidth(codePoint, {ambiguousAsWide = false} = {}) {
|
|
3360
|
-
validate(codePoint);
|
|
3428
|
+
function eastAsianWidth$1(codePoint, {ambiguousAsWide = false} = {}) {
|
|
3429
|
+
validate$1(codePoint);
|
|
3361
3430
|
|
|
3362
3431
|
if (
|
|
3363
|
-
isFullWidth(codePoint)
|
|
3364
|
-
|| isWide(codePoint)
|
|
3365
|
-
|| (ambiguousAsWide && isAmbiguous(codePoint))
|
|
3432
|
+
isFullWidth$1(codePoint)
|
|
3433
|
+
|| isWide$1(codePoint)
|
|
3434
|
+
|| (ambiguousAsWide && isAmbiguous$1(codePoint))
|
|
3366
3435
|
) {
|
|
3367
3436
|
return 2;
|
|
3368
3437
|
}
|
|
@@ -3375,7 +3444,7 @@ var emojiRegex = () => {
|
|
|
3375
3444
|
return /[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26D3\uFE0F?(?:\u200D\uD83D\uDCA5)?|\u26F9(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF43\uDF45-\uDF4A\uDF4C-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDF44(?:\u200D\uD83D\uDFEB)?|\uDF4B(?:\u200D\uD83D\uDFE9)?|\uDFC3(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E-\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4\uDEB5](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE41\uDE43\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED8\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC26(?:\u200D(?:\u2B1B|\uD83D\uDD25))?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFE])))?))?|\uDD75(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?|\uDE42(?:\u200D[\u2194\u2195]\uFE0F?)?|\uDEB6(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3C-\uDD3E\uDDB8\uDDB9\uDDCD\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE8A\uDE8E-\uDEC2\uDEC6\uDEC8\uDECD-\uDEDC\uDEDF-\uDEEA\uDEEF]|\uDDCE(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1|\uDDD1\u200D\uD83E\uDDD2(?:\u200D\uD83E\uDDD2)?|\uDDD2(?:\u200D\uD83E\uDDD2)?))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)/g;
|
|
3376
3445
|
};
|
|
3377
3446
|
|
|
3378
|
-
const segmenter$
|
|
3447
|
+
const segmenter$2 = new Intl.Segmenter();
|
|
3379
3448
|
|
|
3380
3449
|
const defaultIgnorableCodePointRegex = /^\p{Default_Ignorable_Code_Point}$/u;
|
|
3381
3450
|
|
|
@@ -3400,7 +3469,7 @@ function stringWidth$1(string, options = {}) {
|
|
|
3400
3469
|
let width = 0;
|
|
3401
3470
|
const eastAsianWidthOptions = {ambiguousAsWide: !ambiguousIsNarrow};
|
|
3402
3471
|
|
|
3403
|
-
for (const {segment: character} of segmenter$
|
|
3472
|
+
for (const {segment: character} of segmenter$2.segment(string)) {
|
|
3404
3473
|
const codePoint = character.codePointAt(0);
|
|
3405
3474
|
|
|
3406
3475
|
// Ignore control characters
|
|
@@ -3448,7 +3517,7 @@ function stringWidth$1(string, options = {}) {
|
|
|
3448
3517
|
continue;
|
|
3449
3518
|
}
|
|
3450
3519
|
|
|
3451
|
-
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
3520
|
+
width += eastAsianWidth$1(codePoint, eastAsianWidthOptions);
|
|
3452
3521
|
}
|
|
3453
3522
|
|
|
3454
3523
|
return width;
|
|
@@ -3683,12 +3752,12 @@ const ESCAPES$2 = new Set([
|
|
|
3683
3752
|
|
|
3684
3753
|
const END_CODE = 39;
|
|
3685
3754
|
const ANSI_ESCAPE_BELL = '\u0007';
|
|
3686
|
-
const ANSI_CSI = '[';
|
|
3687
|
-
const ANSI_OSC = ']';
|
|
3688
|
-
const ANSI_SGR_TERMINATOR = 'm';
|
|
3689
|
-
const ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
|
|
3755
|
+
const ANSI_CSI$1 = '[';
|
|
3756
|
+
const ANSI_OSC$1 = ']';
|
|
3757
|
+
const ANSI_SGR_TERMINATOR$1 = 'm';
|
|
3758
|
+
const ANSI_ESCAPE_LINK = `${ANSI_OSC$1}8;;`;
|
|
3690
3759
|
|
|
3691
|
-
const wrapAnsiCode = code => `${ESCAPES$2.values().next().value}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
|
|
3760
|
+
const wrapAnsiCode = code => `${ESCAPES$2.values().next().value}${ANSI_CSI$1}${code}${ANSI_SGR_TERMINATOR$1}`;
|
|
3692
3761
|
const wrapAnsiHyperlink = url => `${ESCAPES$2.values().next().value}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
|
|
3693
3762
|
|
|
3694
3763
|
// Calculate the length of words split on ' ', ignoring
|
|
@@ -3727,7 +3796,7 @@ const wrapWord = (rows, word, columns) => {
|
|
|
3727
3796
|
isInsideEscape = false;
|
|
3728
3797
|
isInsideLinkEscape = false;
|
|
3729
3798
|
}
|
|
3730
|
-
} else if (character === ANSI_SGR_TERMINATOR) {
|
|
3799
|
+
} else if (character === ANSI_SGR_TERMINATOR$1) {
|
|
3731
3800
|
isInsideEscape = false;
|
|
3732
3801
|
}
|
|
3733
3802
|
|
|
@@ -3774,7 +3843,7 @@ const stringVisibleTrimSpacesRight = string => {
|
|
|
3774
3843
|
// 'hard' will never allow a string to take up more than columns characters.
|
|
3775
3844
|
//
|
|
3776
3845
|
// 'soft' allows long words to expand past the column length.
|
|
3777
|
-
const exec = (string, columns, options = {}) => {
|
|
3846
|
+
const exec$1 = (string, columns, options = {}) => {
|
|
3778
3847
|
if (options.trim !== false && string.trim() === '') {
|
|
3779
3848
|
return '';
|
|
3780
3849
|
}
|
|
@@ -3850,7 +3919,7 @@ const exec = (string, columns, options = {}) => {
|
|
|
3850
3919
|
returnValue += character;
|
|
3851
3920
|
|
|
3852
3921
|
if (ESCAPES$2.has(character)) {
|
|
3853
|
-
const {groups} = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`).exec(preString.slice(preStringIndex)) || {groups: {}};
|
|
3922
|
+
const {groups} = new RegExp(`(?:\\${ANSI_CSI$1}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`).exec(preString.slice(preStringIndex)) || {groups: {}};
|
|
3854
3923
|
if (groups.code !== undefined) {
|
|
3855
3924
|
const code = Number.parseFloat(groups.code);
|
|
3856
3925
|
escapeCode = code === END_CODE ? undefined : code;
|
|
@@ -3891,10 +3960,147 @@ function wrapAnsi(string, columns, options) {
|
|
|
3891
3960
|
.normalize()
|
|
3892
3961
|
.replaceAll('\r\n', '\n')
|
|
3893
3962
|
.split('\n')
|
|
3894
|
-
.map(line => exec(line, columns, options))
|
|
3963
|
+
.map(line => exec$1(line, columns, options))
|
|
3895
3964
|
.join('\n');
|
|
3896
3965
|
}
|
|
3897
3966
|
|
|
3967
|
+
const defaultColumns = 80;
|
|
3968
|
+
const defaultRows = 24;
|
|
3969
|
+
|
|
3970
|
+
const exec = (command, arguments_, {shell, env} = {}) =>
|
|
3971
|
+
execFileSync(command, arguments_, {
|
|
3972
|
+
encoding: 'utf8',
|
|
3973
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
3974
|
+
timeout: 500,
|
|
3975
|
+
shell,
|
|
3976
|
+
env,
|
|
3977
|
+
}).trim();
|
|
3978
|
+
|
|
3979
|
+
const create$1 = (columns, rows) => ({
|
|
3980
|
+
columns: Number.parseInt(columns, 10),
|
|
3981
|
+
rows: Number.parseInt(rows, 10),
|
|
3982
|
+
});
|
|
3983
|
+
|
|
3984
|
+
const createIfNotDefault = (maybeColumns, maybeRows) => {
|
|
3985
|
+
const {columns, rows} = create$1(maybeColumns, maybeRows);
|
|
3986
|
+
|
|
3987
|
+
if (Number.isNaN(columns) || Number.isNaN(rows)) {
|
|
3988
|
+
return;
|
|
3989
|
+
}
|
|
3990
|
+
|
|
3991
|
+
if (columns === defaultColumns && rows === defaultRows) {
|
|
3992
|
+
return;
|
|
3993
|
+
}
|
|
3994
|
+
|
|
3995
|
+
return {columns, rows};
|
|
3996
|
+
};
|
|
3997
|
+
|
|
3998
|
+
const isForegroundProcess = () => {
|
|
3999
|
+
if (process$1.platform !== 'linux') {
|
|
4000
|
+
return true;
|
|
4001
|
+
}
|
|
4002
|
+
|
|
4003
|
+
try {
|
|
4004
|
+
const statContents = fs__default.readFileSync('/proc/self/stat', 'utf8');
|
|
4005
|
+
const closingParenthesisIndex = statContents.lastIndexOf(') ');
|
|
4006
|
+
|
|
4007
|
+
if (closingParenthesisIndex === -1) {
|
|
4008
|
+
return false;
|
|
4009
|
+
}
|
|
4010
|
+
|
|
4011
|
+
const statFields = statContents.slice(closingParenthesisIndex + 2).trim().split(/\s+/);
|
|
4012
|
+
const processGroupId = Number.parseInt(statFields[2], 10);
|
|
4013
|
+
const foregroundProcessGroupId = Number.parseInt(statFields[5], 10);
|
|
4014
|
+
|
|
4015
|
+
if (Number.isNaN(processGroupId) || Number.isNaN(foregroundProcessGroupId)) {
|
|
4016
|
+
return false;
|
|
4017
|
+
}
|
|
4018
|
+
|
|
4019
|
+
if (foregroundProcessGroupId <= 0) {
|
|
4020
|
+
return false;
|
|
4021
|
+
}
|
|
4022
|
+
|
|
4023
|
+
return processGroupId === foregroundProcessGroupId;
|
|
4024
|
+
} catch {
|
|
4025
|
+
return false;
|
|
4026
|
+
}
|
|
4027
|
+
};
|
|
4028
|
+
|
|
4029
|
+
function terminalSize() {
|
|
4030
|
+
const {env, stdout, stderr} = process$1;
|
|
4031
|
+
|
|
4032
|
+
if (stdout?.columns && stdout?.rows) {
|
|
4033
|
+
return create$1(stdout.columns, stdout.rows);
|
|
4034
|
+
}
|
|
4035
|
+
|
|
4036
|
+
if (stderr?.columns && stderr?.rows) {
|
|
4037
|
+
return create$1(stderr.columns, stderr.rows);
|
|
4038
|
+
}
|
|
4039
|
+
|
|
4040
|
+
// These values are static, so not the first choice.
|
|
4041
|
+
if (env.COLUMNS && env.LINES) {
|
|
4042
|
+
return create$1(env.COLUMNS, env.LINES);
|
|
4043
|
+
}
|
|
4044
|
+
|
|
4045
|
+
const fallback = {
|
|
4046
|
+
columns: defaultColumns,
|
|
4047
|
+
rows: defaultRows,
|
|
4048
|
+
};
|
|
4049
|
+
|
|
4050
|
+
if (process$1.platform === 'win32') {
|
|
4051
|
+
// We include `tput` for Windows users using Git Bash.
|
|
4052
|
+
return tput() ?? fallback;
|
|
4053
|
+
}
|
|
4054
|
+
|
|
4055
|
+
if (process$1.platform === 'darwin') {
|
|
4056
|
+
return devTty() ?? tput() ?? fallback;
|
|
4057
|
+
}
|
|
4058
|
+
|
|
4059
|
+
return devTty() ?? tput() ?? resize() ?? fallback;
|
|
4060
|
+
}
|
|
4061
|
+
|
|
4062
|
+
const devTty = () => {
|
|
4063
|
+
try {
|
|
4064
|
+
// eslint-disable-next-line no-bitwise
|
|
4065
|
+
const flags = process$1.platform === 'darwin' ? fs__default.constants.O_EVTONLY | fs__default.constants.O_NONBLOCK : fs__default.constants.O_NONBLOCK;
|
|
4066
|
+
// eslint-disable-next-line new-cap
|
|
4067
|
+
const {columns, rows} = tty.WriteStream(fs__default.openSync('/dev/tty', flags));
|
|
4068
|
+
return {columns, rows};
|
|
4069
|
+
} catch {}
|
|
4070
|
+
};
|
|
4071
|
+
|
|
4072
|
+
// On macOS, this only returns correct values when stdout is not redirected.
|
|
4073
|
+
const tput = () => {
|
|
4074
|
+
try {
|
|
4075
|
+
// `tput` requires the `TERM` environment variable to be set.
|
|
4076
|
+
const columns = exec('tput', ['cols'], {env: {TERM: 'dumb', ...process$1.env}});
|
|
4077
|
+
const rows = exec('tput', ['lines'], {env: {TERM: 'dumb', ...process$1.env}});
|
|
4078
|
+
|
|
4079
|
+
if (columns && rows) {
|
|
4080
|
+
return createIfNotDefault(columns, rows);
|
|
4081
|
+
}
|
|
4082
|
+
} catch {}
|
|
4083
|
+
};
|
|
4084
|
+
|
|
4085
|
+
// Only exists on Linux.
|
|
4086
|
+
const resize = () => {
|
|
4087
|
+
// `resize` is preferred as it works even when all file descriptors are redirected
|
|
4088
|
+
// https://linux.die.net/man/1/resize
|
|
4089
|
+
try {
|
|
4090
|
+
if (!isForegroundProcess()) {
|
|
4091
|
+
return;
|
|
4092
|
+
}
|
|
4093
|
+
|
|
4094
|
+
const size = exec('resize', ['-u']).match(/\d+/g);
|
|
4095
|
+
|
|
4096
|
+
if (size.length === 2) {
|
|
4097
|
+
return createIfNotDefault(size[0], size[1]);
|
|
4098
|
+
}
|
|
4099
|
+
} catch {}
|
|
4100
|
+
};
|
|
4101
|
+
|
|
4102
|
+
const isDev = () => process$1.env['DEV'] === 'true';
|
|
4103
|
+
|
|
3898
4104
|
var reactReconciler = {exports: {}};
|
|
3899
4105
|
|
|
3900
4106
|
var reactReconciler_production = {exports: {}};
|
|
@@ -35970,11 +36176,343 @@ function requireReactReconciler () {
|
|
|
35970
36176
|
var reactReconcilerExports = requireReactReconciler();
|
|
35971
36177
|
var createReconciler = /*@__PURE__*/getDefaultExportFromCjs(reactReconcilerExports);
|
|
35972
36178
|
|
|
36179
|
+
var schedulerExports = requireScheduler();
|
|
36180
|
+
|
|
36181
|
+
// Generated by scripts/build.js
|
|
36182
|
+
|
|
36183
|
+
const ambiguousMinimalCodePoint = 161;
|
|
36184
|
+
const ambiguousMaximumCodePoint = 1114109;
|
|
36185
|
+
const ambiguousRanges = [161, 161, 164, 164, 167, 168, 170, 170, 173, 174, 176, 180, 182, 186, 188, 191, 198, 198, 208, 208, 215, 216, 222, 225, 230, 230, 232, 234, 236, 237, 240, 240, 242, 243, 247, 250, 252, 252, 254, 254, 257, 257, 273, 273, 275, 275, 283, 283, 294, 295, 299, 299, 305, 307, 312, 312, 319, 322, 324, 324, 328, 331, 333, 333, 338, 339, 358, 359, 363, 363, 462, 462, 464, 464, 466, 466, 468, 468, 470, 470, 472, 472, 474, 474, 476, 476, 593, 593, 609, 609, 708, 708, 711, 711, 713, 715, 717, 717, 720, 720, 728, 731, 733, 733, 735, 735, 768, 879, 913, 929, 931, 937, 945, 961, 963, 969, 1025, 1025, 1040, 1103, 1105, 1105, 8208, 8208, 8211, 8214, 8216, 8217, 8220, 8221, 8224, 8226, 8228, 8231, 8240, 8240, 8242, 8243, 8245, 8245, 8251, 8251, 8254, 8254, 8308, 8308, 8319, 8319, 8321, 8324, 8364, 8364, 8451, 8451, 8453, 8453, 8457, 8457, 8467, 8467, 8470, 8470, 8481, 8482, 8486, 8486, 8491, 8491, 8531, 8532, 8539, 8542, 8544, 8555, 8560, 8569, 8585, 8585, 8592, 8601, 8632, 8633, 8658, 8658, 8660, 8660, 8679, 8679, 8704, 8704, 8706, 8707, 8711, 8712, 8715, 8715, 8719, 8719, 8721, 8721, 8725, 8725, 8730, 8730, 8733, 8736, 8739, 8739, 8741, 8741, 8743, 8748, 8750, 8750, 8756, 8759, 8764, 8765, 8776, 8776, 8780, 8780, 8786, 8786, 8800, 8801, 8804, 8807, 8810, 8811, 8814, 8815, 8834, 8835, 8838, 8839, 8853, 8853, 8857, 8857, 8869, 8869, 8895, 8895, 8978, 8978, 9312, 9449, 9451, 9547, 9552, 9587, 9600, 9615, 9618, 9621, 9632, 9633, 9635, 9641, 9650, 9651, 9654, 9655, 9660, 9661, 9664, 9665, 9670, 9672, 9675, 9675, 9678, 9681, 9698, 9701, 9711, 9711, 9733, 9734, 9737, 9737, 9742, 9743, 9756, 9756, 9758, 9758, 9792, 9792, 9794, 9794, 9824, 9825, 9827, 9829, 9831, 9834, 9836, 9837, 9839, 9839, 9886, 9887, 9919, 9919, 9926, 9933, 9935, 9939, 9941, 9953, 9955, 9955, 9960, 9961, 9963, 9969, 9972, 9972, 9974, 9977, 9979, 9980, 9982, 9983, 10045, 10045, 10102, 10111, 11094, 11097, 12872, 12879, 57344, 63743, 65024, 65039, 65533, 65533, 127232, 127242, 127248, 127277, 127280, 127337, 127344, 127373, 127375, 127376, 127387, 127404, 917760, 917999, 983040, 1048573, 1048576, 1114109];
|
|
36186
|
+
|
|
36187
|
+
const fullwidthMinimalCodePoint = 12288;
|
|
36188
|
+
const fullwidthMaximumCodePoint = 65510;
|
|
36189
|
+
const fullwidthRanges = [12288, 12288, 65281, 65376, 65504, 65510];
|
|
36190
|
+
|
|
36191
|
+
const wideMinimalCodePoint = 4352;
|
|
36192
|
+
const wideMaximumCodePoint = 262141;
|
|
36193
|
+
const wideRanges = [4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749, 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918, 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981, 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071, 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929, 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591, 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388, 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180, 94192, 94198, 94208, 101589, 101631, 101662, 101760, 101874, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110882, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110951, 110960, 111355, 119552, 119638, 119648, 119670, 126980, 126980, 127183, 127183, 127374, 127374, 127377, 127386, 127488, 127490, 127504, 127547, 127552, 127560, 127568, 127569, 127584, 127589, 127744, 127776, 127789, 127797, 127799, 127868, 127870, 127891, 127904, 127946, 127951, 127955, 127968, 127984, 127988, 127988, 127992, 128062, 128064, 128064, 128066, 128252, 128255, 128317, 128331, 128334, 128336, 128359, 128378, 128378, 128405, 128406, 128420, 128420, 128507, 128591, 128640, 128709, 128716, 128716, 128720, 128722, 128725, 128728, 128732, 128735, 128747, 128748, 128756, 128764, 128992, 129003, 129008, 129008, 129292, 129338, 129340, 129349, 129351, 129535, 129648, 129660, 129664, 129674, 129678, 129734, 129736, 129736, 129741, 129756, 129759, 129770, 129775, 129784, 131072, 196605, 196608, 262141];
|
|
36194
|
+
|
|
36195
|
+
/**
|
|
36196
|
+
Binary search on a sorted flat array of [start, end] pairs.
|
|
36197
|
+
|
|
36198
|
+
@param {number[]} ranges - Flat array of inclusive [start, end] range pairs, e.g. [0, 5, 10, 20].
|
|
36199
|
+
@param {number} codePoint - The value to search for.
|
|
36200
|
+
@returns {boolean} Whether the value falls within any of the ranges.
|
|
36201
|
+
*/
|
|
36202
|
+
const isInRange = (ranges, codePoint) => {
|
|
36203
|
+
let low = 0;
|
|
36204
|
+
let high = Math.floor(ranges.length / 2) - 1;
|
|
36205
|
+
while (low <= high) {
|
|
36206
|
+
const mid = Math.floor((low + high) / 2);
|
|
36207
|
+
const i = mid * 2;
|
|
36208
|
+
if (codePoint < ranges[i]) {
|
|
36209
|
+
high = mid - 1;
|
|
36210
|
+
} else if (codePoint > ranges[i + 1]) {
|
|
36211
|
+
low = mid + 1;
|
|
36212
|
+
} else {
|
|
36213
|
+
return true;
|
|
36214
|
+
}
|
|
36215
|
+
}
|
|
36216
|
+
|
|
36217
|
+
return false;
|
|
36218
|
+
};
|
|
36219
|
+
|
|
36220
|
+
const commonCjkCodePoint = 0x4E_00;
|
|
36221
|
+
const [wideFastPathStart, wideFastPathEnd] = /* #__PURE__ */ findWideFastPathRange(wideRanges);
|
|
36222
|
+
|
|
36223
|
+
// Use a hot-path range so common `isWide` calls can skip binary search.
|
|
36224
|
+
// The range containing U+4E00 covers common CJK ideographs;
|
|
36225
|
+
// fallback to the largest range for resilience to Unicode table changes.
|
|
36226
|
+
function findWideFastPathRange(ranges) {
|
|
36227
|
+
let fastPathStart = ranges[0];
|
|
36228
|
+
let fastPathEnd = ranges[1];
|
|
36229
|
+
|
|
36230
|
+
for (let index = 0; index < ranges.length; index += 2) {
|
|
36231
|
+
const start = ranges[index];
|
|
36232
|
+
const end = ranges[index + 1];
|
|
36233
|
+
|
|
36234
|
+
if (
|
|
36235
|
+
commonCjkCodePoint >= start
|
|
36236
|
+
&& commonCjkCodePoint <= end
|
|
36237
|
+
) {
|
|
36238
|
+
return [start, end];
|
|
36239
|
+
}
|
|
36240
|
+
|
|
36241
|
+
if ((end - start) > (fastPathEnd - fastPathStart)) {
|
|
36242
|
+
fastPathStart = start;
|
|
36243
|
+
fastPathEnd = end;
|
|
36244
|
+
}
|
|
36245
|
+
}
|
|
36246
|
+
|
|
36247
|
+
return [fastPathStart, fastPathEnd];
|
|
36248
|
+
}
|
|
36249
|
+
|
|
36250
|
+
const isAmbiguous = codePoint => {
|
|
36251
|
+
if (
|
|
36252
|
+
codePoint < ambiguousMinimalCodePoint
|
|
36253
|
+
|| codePoint > ambiguousMaximumCodePoint
|
|
36254
|
+
) {
|
|
36255
|
+
return false;
|
|
36256
|
+
}
|
|
36257
|
+
|
|
36258
|
+
return isInRange(ambiguousRanges, codePoint);
|
|
36259
|
+
};
|
|
36260
|
+
|
|
36261
|
+
const isFullWidth = codePoint => {
|
|
36262
|
+
if (
|
|
36263
|
+
codePoint < fullwidthMinimalCodePoint
|
|
36264
|
+
|| codePoint > fullwidthMaximumCodePoint
|
|
36265
|
+
) {
|
|
36266
|
+
return false;
|
|
36267
|
+
}
|
|
36268
|
+
|
|
36269
|
+
return isInRange(fullwidthRanges, codePoint);
|
|
36270
|
+
};
|
|
36271
|
+
|
|
36272
|
+
const isWide = codePoint => {
|
|
36273
|
+
if (
|
|
36274
|
+
codePoint >= wideFastPathStart
|
|
36275
|
+
&& codePoint <= wideFastPathEnd
|
|
36276
|
+
) {
|
|
36277
|
+
return true;
|
|
36278
|
+
}
|
|
36279
|
+
|
|
36280
|
+
if (
|
|
36281
|
+
codePoint < wideMinimalCodePoint
|
|
36282
|
+
|| codePoint > wideMaximumCodePoint
|
|
36283
|
+
) {
|
|
36284
|
+
return false;
|
|
36285
|
+
}
|
|
36286
|
+
|
|
36287
|
+
return isInRange(wideRanges, codePoint);
|
|
36288
|
+
};
|
|
36289
|
+
|
|
36290
|
+
function validate(codePoint) {
|
|
36291
|
+
if (!Number.isSafeInteger(codePoint)) {
|
|
36292
|
+
throw new TypeError(`Expected a code point, got \`${typeof codePoint}\`.`);
|
|
36293
|
+
}
|
|
36294
|
+
}
|
|
36295
|
+
|
|
36296
|
+
function eastAsianWidth(codePoint, {ambiguousAsWide = false} = {}) {
|
|
36297
|
+
validate(codePoint);
|
|
36298
|
+
|
|
36299
|
+
if (
|
|
36300
|
+
isFullWidth(codePoint)
|
|
36301
|
+
|| isWide(codePoint)
|
|
36302
|
+
|| (ambiguousAsWide && isAmbiguous(codePoint))
|
|
36303
|
+
) {
|
|
36304
|
+
return 2;
|
|
36305
|
+
}
|
|
36306
|
+
|
|
36307
|
+
return 1;
|
|
36308
|
+
}
|
|
36309
|
+
|
|
36310
|
+
/**
|
|
36311
|
+
Logic:
|
|
36312
|
+
- Segment graphemes to match how terminals render clusters.
|
|
36313
|
+
- Width rules:
|
|
36314
|
+
1. Skip non-printing clusters (Default_Ignorable, Control, pure Mark, lone Surrogates). Tabs are ignored by design.
|
|
36315
|
+
2. RGI emoji clusters (\p{RGI_Emoji}) are double-width.
|
|
36316
|
+
3. Minimally-qualified/unqualified emoji clusters (ZWJ sequences with 2+ Extended_Pictographic, or keycap sequences) are double-width.
|
|
36317
|
+
4. Hangul jamo collapse each standard modern Hangul L+V or L+V+T syllable piece to width 2.
|
|
36318
|
+
Unmatched repeated leading/vowel/trailing jamo stay additive because that matches how the terminals we target render them.
|
|
36319
|
+
5. Otherwise use East Asian Width of the cluster's first visible code point, and add widths for trailing Halfwidth/Fullwidth Forms within the same cluster (e.g., dakuten/handakuten/prolonged sound mark).
|
|
36320
|
+
*/
|
|
36321
|
+
|
|
36322
|
+
const segmenter$1 = new Intl.Segmenter();
|
|
36323
|
+
|
|
36324
|
+
// Whole-cluster zero-width
|
|
36325
|
+
const zeroWidthClusterRegex = /^(?:\p{Default_Ignorable_Code_Point}|\p{Control}|\p{Format}|\p{Mark}|\p{Surrogate})+$/v;
|
|
36326
|
+
|
|
36327
|
+
// Pick the base scalar if the cluster starts with Prepend/Format/Marks
|
|
36328
|
+
const leadingNonPrintingRegex = /^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Mark}\p{Surrogate}]+/v;
|
|
36329
|
+
|
|
36330
|
+
// RGI emoji sequences
|
|
36331
|
+
const rgiEmojiRegex = /^\p{RGI_Emoji}$/v;
|
|
36332
|
+
|
|
36333
|
+
// Detect minimally-qualified/unqualified emoji sequences (missing VS16 but still render as double-width)
|
|
36334
|
+
const unqualifiedKeycapRegex = /^[\d#*]\u20E3$/;
|
|
36335
|
+
const extendedPictographicRegex = /\p{Extended_Pictographic}/gu;
|
|
36336
|
+
|
|
36337
|
+
function isDoubleWidthNonRgiEmojiSequence(segment) {
|
|
36338
|
+
// Real emoji clusters are < 30 chars; guard against pathological input
|
|
36339
|
+
if (segment.length > 50) {
|
|
36340
|
+
return false;
|
|
36341
|
+
}
|
|
36342
|
+
|
|
36343
|
+
if (unqualifiedKeycapRegex.test(segment)) {
|
|
36344
|
+
return true;
|
|
36345
|
+
}
|
|
36346
|
+
|
|
36347
|
+
// ZWJ sequences with 2+ Extended_Pictographic
|
|
36348
|
+
if (segment.includes('\u200D')) {
|
|
36349
|
+
const pictographics = segment.match(extendedPictographicRegex);
|
|
36350
|
+
return pictographics !== null && pictographics.length >= 2;
|
|
36351
|
+
}
|
|
36352
|
+
|
|
36353
|
+
return false;
|
|
36354
|
+
}
|
|
36355
|
+
|
|
36356
|
+
function baseVisible(segment) {
|
|
36357
|
+
return segment.replace(leadingNonPrintingRegex, '');
|
|
36358
|
+
}
|
|
36359
|
+
|
|
36360
|
+
function isZeroWidthCluster(segment) {
|
|
36361
|
+
return zeroWidthClusterRegex.test(segment);
|
|
36362
|
+
}
|
|
36363
|
+
|
|
36364
|
+
function isHangulLeadingJamo(codePoint) {
|
|
36365
|
+
return (codePoint >= 0x11_00 && codePoint <= 0x11_5F)
|
|
36366
|
+
|| (codePoint >= 0xA9_60 && codePoint <= 0xA9_7C);
|
|
36367
|
+
}
|
|
36368
|
+
|
|
36369
|
+
function isHangulVowelJamo(codePoint) {
|
|
36370
|
+
return (codePoint >= 0x11_60 && codePoint <= 0x11_A7)
|
|
36371
|
+
|| (codePoint >= 0xD7_B0 && codePoint <= 0xD7_C6);
|
|
36372
|
+
}
|
|
36373
|
+
|
|
36374
|
+
function isHangulTrailingJamo(codePoint) {
|
|
36375
|
+
return (codePoint >= 0x11_A8 && codePoint <= 0x11_FF)
|
|
36376
|
+
|| (codePoint >= 0xD7_CB && codePoint <= 0xD7_FB);
|
|
36377
|
+
}
|
|
36378
|
+
|
|
36379
|
+
function isHangulJamo(codePoint) {
|
|
36380
|
+
return isHangulLeadingJamo(codePoint)
|
|
36381
|
+
|| isHangulVowelJamo(codePoint)
|
|
36382
|
+
|| isHangulTrailingJamo(codePoint);
|
|
36383
|
+
}
|
|
36384
|
+
|
|
36385
|
+
function hangulClusterWidth(visibleSegment, eastAsianWidthOptions) {
|
|
36386
|
+
const codePoints = [];
|
|
36387
|
+
|
|
36388
|
+
for (const character of visibleSegment) {
|
|
36389
|
+
if (zeroWidthClusterRegex.test(character)) {
|
|
36390
|
+
continue;
|
|
36391
|
+
}
|
|
36392
|
+
|
|
36393
|
+
codePoints.push(character.codePointAt(0));
|
|
36394
|
+
}
|
|
36395
|
+
|
|
36396
|
+
if (codePoints.length === 0) {
|
|
36397
|
+
return undefined;
|
|
36398
|
+
}
|
|
36399
|
+
|
|
36400
|
+
let width = 0;
|
|
36401
|
+
|
|
36402
|
+
for (let index = 0; index < codePoints.length; index++) {
|
|
36403
|
+
const codePoint = codePoints[index];
|
|
36404
|
+
if (!isHangulJamo(codePoint)) {
|
|
36405
|
+
if (width === 0) {
|
|
36406
|
+
return undefined;
|
|
36407
|
+
}
|
|
36408
|
+
|
|
36409
|
+
// Mixed cluster (e.g., L + precomposed syllable): use EAW for non-jamo remainder
|
|
36410
|
+
for (let remaining = index; remaining < codePoints.length; remaining++) {
|
|
36411
|
+
width += eastAsianWidth(codePoints[remaining], eastAsianWidthOptions);
|
|
36412
|
+
}
|
|
36413
|
+
|
|
36414
|
+
return width;
|
|
36415
|
+
}
|
|
36416
|
+
|
|
36417
|
+
// Modern Hangul L+V(+T) shapes as one syllable block. Unmatched jamo stay additive:
|
|
36418
|
+
// U+1100 U+1100 U+1161 => U+1100 + (U+1100 U+1161) => 2 + 2.
|
|
36419
|
+
if (
|
|
36420
|
+
isHangulLeadingJamo(codePoint)
|
|
36421
|
+
&& isHangulVowelJamo(codePoints[index + 1])
|
|
36422
|
+
) {
|
|
36423
|
+
width += 2;
|
|
36424
|
+
index += isHangulTrailingJamo(codePoints[index + 2]) ? 2 : 1;
|
|
36425
|
+
continue;
|
|
36426
|
+
}
|
|
36427
|
+
|
|
36428
|
+
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
36429
|
+
}
|
|
36430
|
+
|
|
36431
|
+
return width;
|
|
36432
|
+
}
|
|
36433
|
+
|
|
36434
|
+
function trailingHalfwidthWidth(visibleSegment, eastAsianWidthOptions) {
|
|
36435
|
+
let extra = 0;
|
|
36436
|
+
let first = true;
|
|
36437
|
+
|
|
36438
|
+
for (const character of visibleSegment) {
|
|
36439
|
+
if (first) {
|
|
36440
|
+
first = false;
|
|
36441
|
+
continue;
|
|
36442
|
+
}
|
|
36443
|
+
|
|
36444
|
+
if (character >= '\uFF00' && character <= '\uFFEF') {
|
|
36445
|
+
extra += eastAsianWidth(character.codePointAt(0), eastAsianWidthOptions);
|
|
36446
|
+
}
|
|
36447
|
+
}
|
|
36448
|
+
|
|
36449
|
+
return extra;
|
|
36450
|
+
}
|
|
36451
|
+
|
|
36452
|
+
function stringWidth(input, options = {}) {
|
|
36453
|
+
if (typeof input !== 'string' || input.length === 0) {
|
|
36454
|
+
return 0;
|
|
36455
|
+
}
|
|
36456
|
+
|
|
36457
|
+
const {
|
|
36458
|
+
ambiguousIsNarrow = true,
|
|
36459
|
+
countAnsiEscapeCodes = false,
|
|
36460
|
+
} = options;
|
|
36461
|
+
|
|
36462
|
+
let string = input;
|
|
36463
|
+
|
|
36464
|
+
// Avoid calling stripAnsi when there are no ANSI escape sequences (ESC = 0x1B, CSI = 0x9B)
|
|
36465
|
+
if (!countAnsiEscapeCodes && (string.includes('\u001B') || string.includes('\u009B'))) {
|
|
36466
|
+
string = stripAnsi(string);
|
|
36467
|
+
}
|
|
36468
|
+
|
|
36469
|
+
if (string.length === 0) {
|
|
36470
|
+
return 0;
|
|
36471
|
+
}
|
|
36472
|
+
|
|
36473
|
+
// Fast path: printable ASCII (0x20–0x7E) needs no segmenter, regex, or EAW lookup — width equals length.
|
|
36474
|
+
if (/^[\u0020-\u007E]*$/.test(string)) {
|
|
36475
|
+
return string.length;
|
|
36476
|
+
}
|
|
36477
|
+
|
|
36478
|
+
let width = 0;
|
|
36479
|
+
const eastAsianWidthOptions = {ambiguousAsWide: !ambiguousIsNarrow};
|
|
36480
|
+
|
|
36481
|
+
for (const {segment} of segmenter$1.segment(string)) {
|
|
36482
|
+
// Zero-width / non-printing clusters
|
|
36483
|
+
if (isZeroWidthCluster(segment)) {
|
|
36484
|
+
continue;
|
|
36485
|
+
}
|
|
36486
|
+
|
|
36487
|
+
// Emoji width logic
|
|
36488
|
+
if (rgiEmojiRegex.test(segment) || isDoubleWidthNonRgiEmojiSequence(segment)) {
|
|
36489
|
+
width += 2;
|
|
36490
|
+
continue;
|
|
36491
|
+
}
|
|
36492
|
+
|
|
36493
|
+
const visibleSegment = baseVisible(segment);
|
|
36494
|
+
const hangulWidth = hangulClusterWidth(visibleSegment, eastAsianWidthOptions);
|
|
36495
|
+
if (hangulWidth !== undefined) {
|
|
36496
|
+
width += hangulWidth;
|
|
36497
|
+
continue;
|
|
36498
|
+
}
|
|
36499
|
+
|
|
36500
|
+
// Everything else: EAW of the cluster’s first visible scalar
|
|
36501
|
+
const codePoint = visibleSegment.codePointAt(0);
|
|
36502
|
+
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
36503
|
+
|
|
36504
|
+
// Add width for trailing Halfwidth and Fullwidth Forms (e.g., ゙, ゚, ー)
|
|
36505
|
+
width += trailingHalfwidthWidth(visibleSegment, eastAsianWidthOptions);
|
|
36506
|
+
}
|
|
36507
|
+
|
|
36508
|
+
return width;
|
|
36509
|
+
}
|
|
36510
|
+
|
|
35973
36511
|
function widestLine(string) {
|
|
35974
36512
|
let lineWidth = 0;
|
|
35975
36513
|
|
|
35976
36514
|
for (const line of string.split('\n')) {
|
|
35977
|
-
lineWidth = Math.max(lineWidth, stringWidth
|
|
36515
|
+
lineWidth = Math.max(lineWidth, stringWidth(line));
|
|
35978
36516
|
}
|
|
35979
36517
|
|
|
35980
36518
|
return lineWidth;
|
|
@@ -36004,74 +36542,609 @@ function isFullwidthCodePoint(codePoint) {
|
|
|
36004
36542
|
return false;
|
|
36005
36543
|
}
|
|
36006
36544
|
|
|
36007
|
-
return isFullWidth(codePoint) || isWide(codePoint);
|
|
36545
|
+
return isFullWidth$1(codePoint) || isWide$1(codePoint);
|
|
36008
36546
|
}
|
|
36009
36547
|
|
|
36010
|
-
|
|
36011
|
-
const
|
|
36548
|
+
const ESCAPE_CODE_POINT = 27;
|
|
36549
|
+
const C1_DCS_CODE_POINT = 144;
|
|
36550
|
+
const C1_SOS_CODE_POINT = 152;
|
|
36551
|
+
const C1_CSI_CODE_POINT = 155;
|
|
36552
|
+
const C1_ST_CODE_POINT = 156;
|
|
36553
|
+
const C1_OSC_CODE_POINT = 157;
|
|
36554
|
+
const C1_PM_CODE_POINT = 158;
|
|
36555
|
+
const C1_APC_CODE_POINT = 159;
|
|
36556
|
+
const ESCAPES$1 = new Set([
|
|
36557
|
+
ESCAPE_CODE_POINT,
|
|
36558
|
+
C1_DCS_CODE_POINT,
|
|
36559
|
+
C1_SOS_CODE_POINT,
|
|
36560
|
+
C1_CSI_CODE_POINT,
|
|
36561
|
+
C1_ST_CODE_POINT,
|
|
36562
|
+
C1_OSC_CODE_POINT,
|
|
36563
|
+
C1_PM_CODE_POINT,
|
|
36564
|
+
C1_APC_CODE_POINT,
|
|
36565
|
+
]);
|
|
36566
|
+
|
|
36567
|
+
const ESCAPE = '\u001B';
|
|
36568
|
+
const ANSI_BELL = '\u0007';
|
|
36569
|
+
const ANSI_CSI = '[';
|
|
36570
|
+
const ANSI_OSC = ']';
|
|
36571
|
+
const ANSI_DCS = 'P';
|
|
36572
|
+
const ANSI_SOS = 'X';
|
|
36573
|
+
const ANSI_PM = '^';
|
|
36574
|
+
const ANSI_APC = '_';
|
|
36575
|
+
const ANSI_SGR_TERMINATOR = 'm';
|
|
36576
|
+
const ANSI_OSC_TERMINATOR = '\\';
|
|
36577
|
+
const ANSI_STRING_TERMINATOR = `${ESCAPE}${ANSI_OSC_TERMINATOR}`;
|
|
36578
|
+
const C1_OSC = '\u009D';
|
|
36579
|
+
const C1_STRING_TERMINATOR = '\u009C';
|
|
36580
|
+
const ANSI_HYPERLINK_ESC_PREFIX = `${ESCAPE}${ANSI_OSC}8;`;
|
|
36581
|
+
const ANSI_HYPERLINK_C1_PREFIX = `${C1_OSC}8;`;
|
|
36582
|
+
const ANSI_HYPERLINK_ESC_CLOSE = `${ANSI_HYPERLINK_ESC_PREFIX};`;
|
|
36583
|
+
const ANSI_HYPERLINK_C1_CLOSE = `${ANSI_HYPERLINK_C1_PREFIX};`;
|
|
36012
36584
|
|
|
36013
36585
|
const CODE_POINT_0 = '0'.codePointAt(0);
|
|
36014
36586
|
const CODE_POINT_9 = '9'.codePointAt(0);
|
|
36587
|
+
const CODE_POINT_SEMICOLON = ';'.codePointAt(0);
|
|
36588
|
+
const CODE_POINT_COLON = ':'.codePointAt(0);
|
|
36589
|
+
// ECMA-48 CSI format: parameter bytes 0x30-0x3F, intermediates 0x20-0x2F, final 0x40-0x7E.
|
|
36590
|
+
const CODE_POINT_CSI_PARAMETER_START = '0'.codePointAt(0);
|
|
36591
|
+
const CODE_POINT_CSI_PARAMETER_END = '?'.codePointAt(0);
|
|
36592
|
+
const CODE_POINT_CSI_INTERMEDIATE_START = ' '.codePointAt(0);
|
|
36593
|
+
const CODE_POINT_CSI_INTERMEDIATE_END = '/'.codePointAt(0);
|
|
36594
|
+
const CODE_POINT_CSI_FINAL_START = '@'.codePointAt(0);
|
|
36595
|
+
const CODE_POINT_CSI_FINAL_END = '~'.codePointAt(0);
|
|
36596
|
+
const REGIONAL_INDICATOR_SYMBOL_LETTER_A = 127_462;
|
|
36597
|
+
const REGIONAL_INDICATOR_SYMBOL_LETTER_Z = 127_487;
|
|
36598
|
+
const SGR_RESET_CODE = 0;
|
|
36599
|
+
const SGR_EXTENDED_FOREGROUND_CODE = 38;
|
|
36600
|
+
const SGR_DEFAULT_FOREGROUND_CODE = 39;
|
|
36601
|
+
const SGR_EXTENDED_BACKGROUND_CODE = 48;
|
|
36602
|
+
const SGR_DEFAULT_BACKGROUND_CODE = 49;
|
|
36603
|
+
const SGR_COLOR_TYPE_ANSI_256 = 5;
|
|
36604
|
+
const SGR_COLOR_TYPE_TRUECOLOR = 2;
|
|
36605
|
+
const SGR_ANSI_256_FRAGMENT_LENGTH = 3;
|
|
36606
|
+
const SGR_TRUECOLOR_FRAGMENT_LENGTH = 5;
|
|
36607
|
+
const SGR_ANSI_256_LAST_PARAMETER_OFFSET = 2;
|
|
36608
|
+
const SGR_TRUECOLOR_LAST_PARAMETER_OFFSET = 4;
|
|
36609
|
+
const VARIATION_SELECTOR_16_CODE_POINT = 65_039;
|
|
36610
|
+
const COMBINING_ENCLOSING_KEYCAP_CODE_POINT = 8419;
|
|
36611
|
+
const EMOJI_PRESENTATION_GRAPHEME_REGEX = /\p{Emoji_Presentation}/u;
|
|
36612
|
+
const GRAPHEME_SEGMENTER = new Intl.Segmenter(undefined, {granularity: 'grapheme'});
|
|
36613
|
+
|
|
36614
|
+
const endCodeNumbers = new Set();
|
|
36615
|
+
for (const [, end] of ansiStyles.codes) {
|
|
36616
|
+
endCodeNumbers.add(end);
|
|
36617
|
+
}
|
|
36015
36618
|
|
|
36016
|
-
|
|
36619
|
+
function isSgrParameterCharacter(codePoint) {
|
|
36620
|
+
return (
|
|
36621
|
+
(codePoint >= CODE_POINT_0 && codePoint <= CODE_POINT_9)
|
|
36622
|
+
|| codePoint === CODE_POINT_SEMICOLON
|
|
36623
|
+
|| codePoint === CODE_POINT_COLON
|
|
36624
|
+
);
|
|
36625
|
+
}
|
|
36017
36626
|
|
|
36018
|
-
|
|
36019
|
-
|
|
36020
|
-
|
|
36021
|
-
|
|
36022
|
-
|
|
36627
|
+
function isCsiParameterCharacter$1(codePoint) {
|
|
36628
|
+
return codePoint >= CODE_POINT_CSI_PARAMETER_START && codePoint <= CODE_POINT_CSI_PARAMETER_END;
|
|
36629
|
+
}
|
|
36630
|
+
|
|
36631
|
+
function isCsiIntermediateCharacter$1(codePoint) {
|
|
36632
|
+
return codePoint >= CODE_POINT_CSI_INTERMEDIATE_START && codePoint <= CODE_POINT_CSI_INTERMEDIATE_END;
|
|
36633
|
+
}
|
|
36634
|
+
|
|
36635
|
+
function isCsiFinalCharacter$1(codePoint) {
|
|
36636
|
+
return codePoint >= CODE_POINT_CSI_FINAL_START && codePoint <= CODE_POINT_CSI_FINAL_END;
|
|
36637
|
+
}
|
|
36638
|
+
|
|
36639
|
+
function isRegionalIndicatorCodePoint(codePoint) {
|
|
36640
|
+
return codePoint >= REGIONAL_INDICATOR_SYMBOL_LETTER_A && codePoint <= REGIONAL_INDICATOR_SYMBOL_LETTER_Z;
|
|
36641
|
+
}
|
|
36642
|
+
|
|
36643
|
+
function createControlParseResult(code, endIndex) {
|
|
36644
|
+
return {
|
|
36645
|
+
token: {
|
|
36646
|
+
type: 'control',
|
|
36647
|
+
code,
|
|
36648
|
+
},
|
|
36649
|
+
endIndex,
|
|
36650
|
+
};
|
|
36651
|
+
}
|
|
36652
|
+
|
|
36653
|
+
function isEmojiStyleGrapheme(grapheme) {
|
|
36654
|
+
if (EMOJI_PRESENTATION_GRAPHEME_REGEX.test(grapheme)) {
|
|
36655
|
+
return true;
|
|
36656
|
+
}
|
|
36657
|
+
|
|
36658
|
+
for (const character of grapheme) {
|
|
36659
|
+
const codePoint = character.codePointAt(0);
|
|
36660
|
+
if (
|
|
36661
|
+
codePoint === VARIATION_SELECTOR_16_CODE_POINT
|
|
36662
|
+
|| codePoint === COMBINING_ENCLOSING_KEYCAP_CODE_POINT
|
|
36663
|
+
) {
|
|
36664
|
+
return true;
|
|
36665
|
+
}
|
|
36666
|
+
}
|
|
36667
|
+
|
|
36668
|
+
return false;
|
|
36669
|
+
}
|
|
36670
|
+
|
|
36671
|
+
function getGraphemeWidth(grapheme) {
|
|
36672
|
+
let regionalIndicatorCount = 0;
|
|
36673
|
+
for (const character of grapheme) {
|
|
36674
|
+
const codePoint = character.codePointAt(0);
|
|
36675
|
+
if (isFullwidthCodePoint(codePoint)) {
|
|
36676
|
+
return 2;
|
|
36677
|
+
}
|
|
36678
|
+
|
|
36679
|
+
if (isRegionalIndicatorCodePoint(codePoint)) {
|
|
36680
|
+
regionalIndicatorCount++;
|
|
36681
|
+
}
|
|
36682
|
+
}
|
|
36683
|
+
|
|
36684
|
+
if (regionalIndicatorCount >= 1) {
|
|
36685
|
+
return 2;
|
|
36686
|
+
}
|
|
36687
|
+
|
|
36688
|
+
if (isEmojiStyleGrapheme(grapheme)) {
|
|
36689
|
+
return 2;
|
|
36690
|
+
}
|
|
36691
|
+
|
|
36692
|
+
return 1;
|
|
36693
|
+
}
|
|
36694
|
+
|
|
36695
|
+
function getSgrPrefix(code) {
|
|
36696
|
+
if (code.startsWith('\u009B')) {
|
|
36697
|
+
return '\u009B';
|
|
36698
|
+
}
|
|
36699
|
+
|
|
36700
|
+
return `${ESCAPE}${ANSI_CSI}`;
|
|
36701
|
+
}
|
|
36702
|
+
|
|
36703
|
+
function createSgrCode(prefix, values) {
|
|
36704
|
+
return `${prefix}${values.join(';')}${ANSI_SGR_TERMINATOR}`;
|
|
36705
|
+
}
|
|
36706
|
+
|
|
36707
|
+
function getSgrFragments(code) {
|
|
36708
|
+
const fragments = [];
|
|
36709
|
+
const sgrPrefix = getSgrPrefix(code);
|
|
36710
|
+
let parameterString;
|
|
36711
|
+
|
|
36712
|
+
if (code.startsWith(`${ESCAPE}${ANSI_CSI}`)) {
|
|
36713
|
+
parameterString = code.slice(2, -1);
|
|
36714
|
+
} else if (code.startsWith('\u009B')) {
|
|
36715
|
+
parameterString = code.slice(1, -1);
|
|
36716
|
+
} else {
|
|
36717
|
+
return fragments;
|
|
36718
|
+
}
|
|
36719
|
+
|
|
36720
|
+
const rawCodes = parameterString.length === 0 ? [String(SGR_RESET_CODE)] : parameterString.split(';');
|
|
36721
|
+
let index = 0;
|
|
36722
|
+
while (index < rawCodes.length) {
|
|
36723
|
+
const codeNumber = Number.parseInt(rawCodes[index], 10);
|
|
36724
|
+
if (Number.isNaN(codeNumber)) {
|
|
36725
|
+
index++;
|
|
36726
|
+
continue;
|
|
36727
|
+
}
|
|
36728
|
+
|
|
36729
|
+
if (codeNumber === SGR_RESET_CODE) {
|
|
36730
|
+
fragments.push({type: 'reset'});
|
|
36731
|
+
index++;
|
|
36732
|
+
continue;
|
|
36733
|
+
}
|
|
36734
|
+
|
|
36735
|
+
if (codeNumber === SGR_EXTENDED_FOREGROUND_CODE || codeNumber === SGR_EXTENDED_BACKGROUND_CODE) {
|
|
36736
|
+
const colorType = Number.parseInt(rawCodes[index + 1], 10);
|
|
36737
|
+
if (colorType === SGR_COLOR_TYPE_ANSI_256 && index + SGR_ANSI_256_LAST_PARAMETER_OFFSET < rawCodes.length) {
|
|
36738
|
+
const openCode = createSgrCode(sgrPrefix, rawCodes.slice(index, index + SGR_ANSI_256_FRAGMENT_LENGTH));
|
|
36739
|
+
fragments.push({
|
|
36740
|
+
type: 'start',
|
|
36741
|
+
code: openCode,
|
|
36742
|
+
endCode: ansiStyles.color.ansi(codeNumber === SGR_EXTENDED_FOREGROUND_CODE ? SGR_DEFAULT_FOREGROUND_CODE : SGR_DEFAULT_BACKGROUND_CODE),
|
|
36743
|
+
});
|
|
36744
|
+
index += SGR_ANSI_256_FRAGMENT_LENGTH;
|
|
36745
|
+
continue;
|
|
36746
|
+
}
|
|
36747
|
+
|
|
36748
|
+
if (colorType === SGR_COLOR_TYPE_TRUECOLOR && index + SGR_TRUECOLOR_LAST_PARAMETER_OFFSET < rawCodes.length) {
|
|
36749
|
+
const openCode = createSgrCode(sgrPrefix, rawCodes.slice(index, index + SGR_TRUECOLOR_FRAGMENT_LENGTH));
|
|
36750
|
+
fragments.push({
|
|
36751
|
+
type: 'start',
|
|
36752
|
+
code: openCode,
|
|
36753
|
+
endCode: ansiStyles.color.ansi(codeNumber === SGR_EXTENDED_FOREGROUND_CODE ? SGR_DEFAULT_FOREGROUND_CODE : SGR_DEFAULT_BACKGROUND_CODE),
|
|
36754
|
+
});
|
|
36755
|
+
index += SGR_TRUECOLOR_FRAGMENT_LENGTH;
|
|
36756
|
+
continue;
|
|
36757
|
+
}
|
|
36758
|
+
|
|
36759
|
+
const openCode = createSgrCode(sgrPrefix, [rawCodes[index]]);
|
|
36760
|
+
fragments.push({
|
|
36761
|
+
type: 'start',
|
|
36762
|
+
code: openCode,
|
|
36763
|
+
endCode: ansiStyles.color.ansi(codeNumber === SGR_EXTENDED_FOREGROUND_CODE ? SGR_DEFAULT_FOREGROUND_CODE : SGR_DEFAULT_BACKGROUND_CODE),
|
|
36764
|
+
});
|
|
36765
|
+
index++;
|
|
36766
|
+
continue;
|
|
36767
|
+
}
|
|
36768
|
+
|
|
36769
|
+
if (endCodeNumbers.has(codeNumber)) {
|
|
36770
|
+
fragments.push({
|
|
36771
|
+
type: 'end',
|
|
36772
|
+
endCode: ansiStyles.color.ansi(codeNumber),
|
|
36773
|
+
});
|
|
36774
|
+
index++;
|
|
36775
|
+
continue;
|
|
36776
|
+
}
|
|
36777
|
+
|
|
36778
|
+
const mappedEndCode = ansiStyles.codes.get(codeNumber);
|
|
36779
|
+
if (mappedEndCode !== undefined) {
|
|
36780
|
+
const openCode = createSgrCode(sgrPrefix, [rawCodes[index]]);
|
|
36781
|
+
fragments.push({
|
|
36782
|
+
type: 'start',
|
|
36783
|
+
code: openCode,
|
|
36784
|
+
endCode: ansiStyles.color.ansi(mappedEndCode),
|
|
36785
|
+
});
|
|
36786
|
+
index++;
|
|
36787
|
+
continue;
|
|
36788
|
+
}
|
|
36789
|
+
|
|
36790
|
+
const openCode = createSgrCode(sgrPrefix, [rawCodes[index]]);
|
|
36791
|
+
fragments.push({
|
|
36792
|
+
type: 'start',
|
|
36793
|
+
code: openCode,
|
|
36794
|
+
endCode: ansiStyles.reset.open,
|
|
36795
|
+
});
|
|
36796
|
+
index++;
|
|
36797
|
+
}
|
|
36798
|
+
|
|
36799
|
+
if (fragments.length === 0) {
|
|
36800
|
+
fragments.push({type: 'reset'});
|
|
36801
|
+
}
|
|
36802
|
+
|
|
36803
|
+
return fragments;
|
|
36804
|
+
}
|
|
36805
|
+
|
|
36806
|
+
function parseCsiCode(string, index) {
|
|
36807
|
+
const escapeCodePoint = string.codePointAt(index);
|
|
36808
|
+
let sequenceStartIndex;
|
|
36809
|
+
|
|
36810
|
+
if (escapeCodePoint === ESCAPE_CODE_POINT) {
|
|
36811
|
+
if (string[index + 1] !== ANSI_CSI) {
|
|
36812
|
+
return;
|
|
36813
|
+
}
|
|
36814
|
+
|
|
36815
|
+
sequenceStartIndex = index + 2;
|
|
36816
|
+
} else if (escapeCodePoint === C1_CSI_CODE_POINT) {
|
|
36817
|
+
sequenceStartIndex = index + 1;
|
|
36818
|
+
} else {
|
|
36819
|
+
return;
|
|
36820
|
+
}
|
|
36821
|
+
|
|
36822
|
+
let hasCanonicalSgrParameters = true;
|
|
36823
|
+
for (let sequenceIndex = sequenceStartIndex; sequenceIndex < string.length; sequenceIndex++) {
|
|
36824
|
+
const codePoint = string.codePointAt(sequenceIndex);
|
|
36825
|
+
|
|
36826
|
+
if (isCsiFinalCharacter$1(codePoint)) {
|
|
36827
|
+
const code = string.slice(index, sequenceIndex + 1);
|
|
36828
|
+
if (string[sequenceIndex] !== ANSI_SGR_TERMINATOR || !hasCanonicalSgrParameters) {
|
|
36829
|
+
return createControlParseResult(code, sequenceIndex + 1);
|
|
36830
|
+
}
|
|
36831
|
+
|
|
36832
|
+
return {
|
|
36833
|
+
token: {
|
|
36834
|
+
type: 'sgr',
|
|
36835
|
+
code,
|
|
36836
|
+
fragments: getSgrFragments(code),
|
|
36837
|
+
},
|
|
36838
|
+
endIndex: sequenceIndex + 1,
|
|
36839
|
+
};
|
|
36840
|
+
}
|
|
36841
|
+
|
|
36842
|
+
if (isCsiParameterCharacter$1(codePoint)) {
|
|
36843
|
+
if (!isSgrParameterCharacter(codePoint)) {
|
|
36844
|
+
hasCanonicalSgrParameters = false;
|
|
36845
|
+
}
|
|
36846
|
+
|
|
36847
|
+
continue;
|
|
36848
|
+
}
|
|
36849
|
+
|
|
36850
|
+
if (isCsiIntermediateCharacter$1(codePoint)) {
|
|
36851
|
+
hasCanonicalSgrParameters = false;
|
|
36852
|
+
continue;
|
|
36853
|
+
}
|
|
36854
|
+
|
|
36855
|
+
const endIndex = sequenceIndex;
|
|
36856
|
+
return createControlParseResult(string.slice(index, endIndex), endIndex);
|
|
36857
|
+
}
|
|
36858
|
+
|
|
36859
|
+
return createControlParseResult(string.slice(index), string.length);
|
|
36860
|
+
}
|
|
36861
|
+
|
|
36862
|
+
function parseHyperlinkCode(string, index) {
|
|
36863
|
+
let hyperlinkPrefix;
|
|
36864
|
+
let hyperlinkClose;
|
|
36865
|
+
const codePoint = string.codePointAt(index);
|
|
36866
|
+
|
|
36867
|
+
if (
|
|
36868
|
+
codePoint === ESCAPE_CODE_POINT
|
|
36869
|
+
&& string.startsWith(ANSI_HYPERLINK_ESC_PREFIX, index)
|
|
36870
|
+
) {
|
|
36871
|
+
hyperlinkPrefix = ANSI_HYPERLINK_ESC_PREFIX;
|
|
36872
|
+
hyperlinkClose = ANSI_HYPERLINK_ESC_CLOSE;
|
|
36873
|
+
} else if (
|
|
36874
|
+
codePoint === C1_OSC_CODE_POINT
|
|
36875
|
+
&& string.startsWith(ANSI_HYPERLINK_C1_PREFIX, index)
|
|
36876
|
+
) {
|
|
36877
|
+
hyperlinkPrefix = ANSI_HYPERLINK_C1_PREFIX;
|
|
36878
|
+
hyperlinkClose = ANSI_HYPERLINK_C1_CLOSE;
|
|
36879
|
+
} else {
|
|
36880
|
+
return;
|
|
36881
|
+
}
|
|
36882
|
+
|
|
36883
|
+
const uriStart = string.indexOf(';', index + hyperlinkPrefix.length);
|
|
36884
|
+
if (uriStart === -1) {
|
|
36885
|
+
return createControlParseResult(string.slice(index), string.length);
|
|
36886
|
+
}
|
|
36887
|
+
|
|
36888
|
+
for (let sequenceIndex = uriStart + 1; sequenceIndex < string.length; sequenceIndex++) {
|
|
36889
|
+
const character = string[sequenceIndex];
|
|
36890
|
+
|
|
36891
|
+
if (character === ANSI_BELL) {
|
|
36892
|
+
const code = string.slice(index, sequenceIndex + 1);
|
|
36893
|
+
const action = sequenceIndex === uriStart + 1 ? 'close' : 'open';
|
|
36894
|
+
return {
|
|
36895
|
+
token: {
|
|
36896
|
+
type: 'hyperlink',
|
|
36897
|
+
code,
|
|
36898
|
+
action,
|
|
36899
|
+
closePrefix: hyperlinkClose,
|
|
36900
|
+
terminator: ANSI_BELL,
|
|
36901
|
+
},
|
|
36902
|
+
endIndex: sequenceIndex + 1,
|
|
36903
|
+
};
|
|
36904
|
+
}
|
|
36905
|
+
|
|
36906
|
+
if (
|
|
36907
|
+
character === ESCAPE
|
|
36908
|
+
&& string[sequenceIndex + 1] === ANSI_OSC_TERMINATOR
|
|
36909
|
+
) {
|
|
36910
|
+
const code = string.slice(index, sequenceIndex + 2);
|
|
36911
|
+
const action = sequenceIndex === uriStart + 1 ? 'close' : 'open';
|
|
36912
|
+
return {
|
|
36913
|
+
token: {
|
|
36914
|
+
type: 'hyperlink',
|
|
36915
|
+
code,
|
|
36916
|
+
action,
|
|
36917
|
+
closePrefix: hyperlinkClose,
|
|
36918
|
+
terminator: ANSI_STRING_TERMINATOR,
|
|
36919
|
+
},
|
|
36920
|
+
endIndex: sequenceIndex + 2,
|
|
36921
|
+
};
|
|
36922
|
+
}
|
|
36923
|
+
|
|
36924
|
+
if (character === C1_STRING_TERMINATOR) {
|
|
36925
|
+
const code = string.slice(index, sequenceIndex + 1);
|
|
36926
|
+
const action = sequenceIndex === uriStart + 1 ? 'close' : 'open';
|
|
36927
|
+
return {
|
|
36928
|
+
token: {
|
|
36929
|
+
type: 'hyperlink',
|
|
36930
|
+
code,
|
|
36931
|
+
action,
|
|
36932
|
+
closePrefix: hyperlinkClose,
|
|
36933
|
+
terminator: C1_STRING_TERMINATOR,
|
|
36934
|
+
},
|
|
36935
|
+
endIndex: sequenceIndex + 1,
|
|
36936
|
+
};
|
|
36937
|
+
}
|
|
36938
|
+
}
|
|
36939
|
+
|
|
36940
|
+
return createControlParseResult(string.slice(index), string.length);
|
|
36941
|
+
}
|
|
36942
|
+
|
|
36943
|
+
function parseControlStringCode(string, index) {
|
|
36944
|
+
const codePoint = string.codePointAt(index);
|
|
36945
|
+
let sequenceStartIndex;
|
|
36946
|
+
let supportsBellTerminator = false;
|
|
36947
|
+
|
|
36948
|
+
switch (codePoint) {
|
|
36949
|
+
case ESCAPE_CODE_POINT: {
|
|
36950
|
+
const command = string[index + 1];
|
|
36951
|
+
switch (command) {
|
|
36952
|
+
case ANSI_OSC: {
|
|
36953
|
+
// OSC accepts ST (ECMA-48) and BEL (xterm compatibility extension).
|
|
36954
|
+
sequenceStartIndex = index + 2;
|
|
36955
|
+
supportsBellTerminator = true;
|
|
36956
|
+
break;
|
|
36957
|
+
}
|
|
36958
|
+
|
|
36959
|
+
case ANSI_DCS:
|
|
36960
|
+
case ANSI_SOS:
|
|
36961
|
+
case ANSI_PM:
|
|
36962
|
+
case ANSI_APC: {
|
|
36963
|
+
sequenceStartIndex = index + 2;
|
|
36964
|
+
break;
|
|
36965
|
+
}
|
|
36966
|
+
|
|
36967
|
+
case ANSI_OSC_TERMINATOR: {
|
|
36968
|
+
return createControlParseResult(ANSI_STRING_TERMINATOR, index + 2);
|
|
36969
|
+
}
|
|
36970
|
+
|
|
36971
|
+
default: {
|
|
36972
|
+
return;
|
|
36973
|
+
}
|
|
36974
|
+
}
|
|
36975
|
+
|
|
36976
|
+
break;
|
|
36977
|
+
}
|
|
36978
|
+
|
|
36979
|
+
case C1_OSC_CODE_POINT: {
|
|
36980
|
+
sequenceStartIndex = index + 1;
|
|
36981
|
+
supportsBellTerminator = true;
|
|
36982
|
+
break;
|
|
36983
|
+
}
|
|
36984
|
+
|
|
36985
|
+
case C1_DCS_CODE_POINT:
|
|
36986
|
+
case C1_SOS_CODE_POINT:
|
|
36987
|
+
case C1_PM_CODE_POINT:
|
|
36988
|
+
case C1_APC_CODE_POINT: {
|
|
36989
|
+
sequenceStartIndex = index + 1;
|
|
36990
|
+
break;
|
|
36991
|
+
}
|
|
36992
|
+
|
|
36993
|
+
case C1_ST_CODE_POINT: {
|
|
36994
|
+
return createControlParseResult(C1_STRING_TERMINATOR, index + 1);
|
|
36995
|
+
}
|
|
36996
|
+
|
|
36997
|
+
default: {
|
|
36998
|
+
return;
|
|
36999
|
+
}
|
|
37000
|
+
}
|
|
37001
|
+
|
|
37002
|
+
for (let sequenceIndex = sequenceStartIndex; sequenceIndex < string.length; sequenceIndex++) {
|
|
37003
|
+
if (supportsBellTerminator && string[sequenceIndex] === ANSI_BELL) {
|
|
37004
|
+
return createControlParseResult(string.slice(index, sequenceIndex + 1), sequenceIndex + 1);
|
|
37005
|
+
}
|
|
37006
|
+
|
|
37007
|
+
if (
|
|
37008
|
+
string[sequenceIndex] === ESCAPE
|
|
37009
|
+
&& string[sequenceIndex + 1] === ANSI_OSC_TERMINATOR
|
|
37010
|
+
) {
|
|
37011
|
+
return createControlParseResult(string.slice(index, sequenceIndex + 2), sequenceIndex + 2);
|
|
37012
|
+
}
|
|
37013
|
+
|
|
37014
|
+
if (string[sequenceIndex] === C1_STRING_TERMINATOR) {
|
|
37015
|
+
return createControlParseResult(string.slice(index, sequenceIndex + 1), sequenceIndex + 1);
|
|
37016
|
+
}
|
|
37017
|
+
}
|
|
37018
|
+
|
|
37019
|
+
return createControlParseResult(string.slice(index), string.length);
|
|
36023
37020
|
}
|
|
36024
37021
|
|
|
36025
|
-
function
|
|
36026
|
-
|
|
36027
|
-
|
|
37022
|
+
function parseAnsiCode(string, index) {
|
|
37023
|
+
const codePoint = string.codePointAt(index);
|
|
37024
|
+
if (codePoint === ESCAPE_CODE_POINT || codePoint === C1_OSC_CODE_POINT) {
|
|
37025
|
+
const hyperlinkCode = parseHyperlinkCode(string, index);
|
|
37026
|
+
if (hyperlinkCode) {
|
|
37027
|
+
return hyperlinkCode;
|
|
37028
|
+
}
|
|
36028
37029
|
}
|
|
36029
37030
|
|
|
36030
|
-
|
|
36031
|
-
|
|
37031
|
+
const controlStringCode = parseControlStringCode(string, index);
|
|
37032
|
+
if (controlStringCode) {
|
|
37033
|
+
return controlStringCode;
|
|
36032
37034
|
}
|
|
36033
37035
|
|
|
36034
|
-
|
|
36035
|
-
|
|
36036
|
-
|
|
37036
|
+
return parseCsiCode(string, index);
|
|
37037
|
+
}
|
|
37038
|
+
|
|
37039
|
+
function appendTrailingAnsiTokens(string, index, tokens) {
|
|
37040
|
+
while (index < string.length) {
|
|
37041
|
+
const nextCodePoint = string.codePointAt(index);
|
|
37042
|
+
if (!ESCAPES$1.has(nextCodePoint)) {
|
|
37043
|
+
break;
|
|
37044
|
+
}
|
|
37045
|
+
|
|
37046
|
+
const escapeCode = parseAnsiCode(string, index);
|
|
37047
|
+
if (!escapeCode) {
|
|
37048
|
+
break;
|
|
37049
|
+
}
|
|
37050
|
+
|
|
37051
|
+
tokens.push(escapeCode.token);
|
|
37052
|
+
index = escapeCode.endIndex;
|
|
36037
37053
|
}
|
|
36038
37054
|
|
|
36039
|
-
|
|
36040
|
-
|
|
36041
|
-
|
|
37055
|
+
return index;
|
|
37056
|
+
}
|
|
37057
|
+
|
|
37058
|
+
function parseCharacterTokenWithRawSegmentation(string, index, graphemeSegments) {
|
|
37059
|
+
const segment = graphemeSegments.containing(index);
|
|
37060
|
+
if (!segment || segment.index !== index) {
|
|
37061
|
+
return;
|
|
36042
37062
|
}
|
|
36043
37063
|
|
|
36044
|
-
return
|
|
37064
|
+
return {
|
|
37065
|
+
token: {
|
|
37066
|
+
type: 'character',
|
|
37067
|
+
// Intentionally preserve UAX29 behavior (GB3): CRLF is one grapheme cluster.
|
|
37068
|
+
value: segment.segment,
|
|
37069
|
+
visibleWidth: getGraphemeWidth(segment.segment),
|
|
37070
|
+
isGraphemeContinuation: false,
|
|
37071
|
+
},
|
|
37072
|
+
endIndex: index + segment.segment.length,
|
|
37073
|
+
};
|
|
36045
37074
|
}
|
|
36046
37075
|
|
|
36047
|
-
function
|
|
36048
|
-
|
|
37076
|
+
function collectVisibleCharacters(string) {
|
|
37077
|
+
const visibleCharacters = [];
|
|
37078
|
+
let index = 0;
|
|
37079
|
+
|
|
37080
|
+
while (index < string.length) {
|
|
36049
37081
|
const codePoint = string.codePointAt(index);
|
|
36050
|
-
if (codePoint
|
|
36051
|
-
|
|
37082
|
+
if (ESCAPES$1.has(codePoint)) {
|
|
37083
|
+
const code = parseAnsiCode(string, index);
|
|
37084
|
+
if (code) {
|
|
37085
|
+
index = code.endIndex;
|
|
37086
|
+
continue;
|
|
37087
|
+
}
|
|
36052
37088
|
}
|
|
37089
|
+
|
|
37090
|
+
const value = String.fromCodePoint(codePoint);
|
|
37091
|
+
visibleCharacters.push({
|
|
37092
|
+
value,
|
|
37093
|
+
visibleWidth: 1,
|
|
37094
|
+
isGraphemeContinuation: false,
|
|
37095
|
+
});
|
|
37096
|
+
index += value.length;
|
|
36053
37097
|
}
|
|
36054
37098
|
|
|
36055
|
-
return
|
|
37099
|
+
return visibleCharacters;
|
|
36056
37100
|
}
|
|
36057
37101
|
|
|
36058
|
-
function
|
|
36059
|
-
|
|
36060
|
-
|
|
36061
|
-
|
|
36062
|
-
|
|
36063
|
-
|
|
36064
|
-
|
|
37102
|
+
function applyGraphemeMetadata(visibleCharacters) {
|
|
37103
|
+
if (visibleCharacters.length === 0) {
|
|
37104
|
+
return;
|
|
37105
|
+
}
|
|
37106
|
+
|
|
37107
|
+
const visibleString = visibleCharacters.map(({value}) => value).join('');
|
|
37108
|
+
const scalarOffsets = [];
|
|
37109
|
+
let scalarOffset = 0;
|
|
37110
|
+
|
|
37111
|
+
for (const visibleCharacter of visibleCharacters) {
|
|
37112
|
+
scalarOffsets.push(scalarOffset);
|
|
37113
|
+
scalarOffset += visibleCharacter.value.length;
|
|
37114
|
+
}
|
|
37115
|
+
|
|
37116
|
+
let scalarIndex = 0;
|
|
37117
|
+
for (const segment of GRAPHEME_SEGMENTER.segment(visibleString)) {
|
|
37118
|
+
while (
|
|
37119
|
+
scalarIndex < visibleCharacters.length
|
|
37120
|
+
&& scalarOffsets[scalarIndex] < segment.index
|
|
37121
|
+
) {
|
|
37122
|
+
scalarIndex++;
|
|
37123
|
+
}
|
|
37124
|
+
|
|
37125
|
+
let graphemeIndex = scalarIndex;
|
|
37126
|
+
let isFirstInGrapheme = true;
|
|
37127
|
+
while (
|
|
37128
|
+
graphemeIndex < visibleCharacters.length
|
|
37129
|
+
&& scalarOffsets[graphemeIndex] < segment.index + segment.segment.length
|
|
37130
|
+
) {
|
|
37131
|
+
visibleCharacters[graphemeIndex].visibleWidth = isFirstInGrapheme ? getGraphemeWidth(segment.segment) : 0;
|
|
37132
|
+
visibleCharacters[graphemeIndex].isGraphemeContinuation = !isFirstInGrapheme;
|
|
37133
|
+
isFirstInGrapheme = false;
|
|
37134
|
+
graphemeIndex++;
|
|
36065
37135
|
}
|
|
36066
37136
|
|
|
36067
|
-
|
|
37137
|
+
scalarIndex = graphemeIndex;
|
|
36068
37138
|
}
|
|
36069
37139
|
}
|
|
36070
37140
|
|
|
36071
|
-
function
|
|
36072
|
-
const
|
|
37141
|
+
function tokenizeAnsiWithVisibleSegmentation(string, {endCharacter = Number.POSITIVE_INFINITY} = {}) {
|
|
37142
|
+
const tokens = [];
|
|
37143
|
+
const visibleCharacters = collectVisibleCharacters(string);
|
|
37144
|
+
applyGraphemeMetadata(visibleCharacters);
|
|
36073
37145
|
|
|
36074
37146
|
let index = 0;
|
|
37147
|
+
let visibleCharacterIndex = 0;
|
|
36075
37148
|
let visibleCount = 0;
|
|
36076
37149
|
while (index < string.length) {
|
|
36077
37150
|
const codePoint = string.codePointAt(index);
|
|
@@ -36079,186 +37152,402 @@ function tokenize$1(string, endCharacter = Number.POSITIVE_INFINITY) {
|
|
|
36079
37152
|
if (ESCAPES$1.has(codePoint)) {
|
|
36080
37153
|
const code = parseAnsiCode(string, index);
|
|
36081
37154
|
if (code) {
|
|
36082
|
-
|
|
36083
|
-
|
|
36084
|
-
code,
|
|
36085
|
-
endCode: getEndCode$1(code),
|
|
36086
|
-
});
|
|
36087
|
-
index += code.length;
|
|
37155
|
+
tokens.push(code.token);
|
|
37156
|
+
index = code.endIndex;
|
|
36088
37157
|
continue;
|
|
36089
37158
|
}
|
|
36090
37159
|
}
|
|
36091
37160
|
|
|
36092
|
-
const
|
|
36093
|
-
const
|
|
37161
|
+
const value = String.fromCodePoint(codePoint);
|
|
37162
|
+
const visibleCharacter = visibleCharacters[visibleCharacterIndex];
|
|
37163
|
+
let visibleWidth = isFullwidthCodePoint(codePoint) ? 2 : value.length;
|
|
37164
|
+
if (visibleCharacter) {
|
|
37165
|
+
visibleWidth = visibleCharacter.visibleWidth;
|
|
37166
|
+
}
|
|
36094
37167
|
|
|
36095
|
-
|
|
37168
|
+
const token = {
|
|
36096
37169
|
type: 'character',
|
|
36097
|
-
value
|
|
36098
|
-
|
|
36099
|
-
|
|
37170
|
+
value,
|
|
37171
|
+
visibleWidth,
|
|
37172
|
+
isGraphemeContinuation: visibleCharacter ? visibleCharacter.isGraphemeContinuation : false,
|
|
37173
|
+
};
|
|
36100
37174
|
|
|
36101
|
-
|
|
36102
|
-
|
|
37175
|
+
tokens.push(token);
|
|
37176
|
+
index += value.length;
|
|
37177
|
+
visibleCharacterIndex++;
|
|
37178
|
+
visibleCount += token.visibleWidth;
|
|
36103
37179
|
|
|
36104
37180
|
if (visibleCount >= endCharacter) {
|
|
36105
|
-
|
|
37181
|
+
const nextVisibleCharacter = visibleCharacters[visibleCharacterIndex];
|
|
37182
|
+
if (
|
|
37183
|
+
!nextVisibleCharacter
|
|
37184
|
+
|| !nextVisibleCharacter.isGraphemeContinuation
|
|
37185
|
+
) {
|
|
37186
|
+
index = appendTrailingAnsiTokens(string, index, tokens);
|
|
37187
|
+
break;
|
|
37188
|
+
}
|
|
36106
37189
|
}
|
|
36107
37190
|
}
|
|
36108
37191
|
|
|
36109
|
-
return
|
|
37192
|
+
return tokens;
|
|
36110
37193
|
}
|
|
36111
37194
|
|
|
36112
|
-
function
|
|
36113
|
-
|
|
37195
|
+
function areValuesInSameGrapheme(leftValue, rightValue) {
|
|
37196
|
+
const pair = `${leftValue}${rightValue}`;
|
|
37197
|
+
const splitIndex = leftValue.length;
|
|
36114
37198
|
|
|
36115
|
-
for (const
|
|
36116
|
-
if (
|
|
36117
|
-
|
|
36118
|
-
|
|
36119
|
-
|
|
36120
|
-
|
|
36121
|
-
|
|
36122
|
-
} else {
|
|
36123
|
-
// This is a start code. Disable all styles this "overrides", then enable it
|
|
36124
|
-
returnValue = returnValue.filter(returnValueCode => returnValueCode.endCode !== code.endCode);
|
|
36125
|
-
returnValue.push(code);
|
|
37199
|
+
for (const segment of GRAPHEME_SEGMENTER.segment(pair)) {
|
|
37200
|
+
if (segment.index === splitIndex) {
|
|
37201
|
+
return false;
|
|
37202
|
+
}
|
|
37203
|
+
|
|
37204
|
+
if (segment.index > splitIndex) {
|
|
37205
|
+
return true;
|
|
36126
37206
|
}
|
|
36127
37207
|
}
|
|
36128
37208
|
|
|
36129
|
-
return
|
|
37209
|
+
return true;
|
|
36130
37210
|
}
|
|
36131
37211
|
|
|
36132
|
-
function
|
|
36133
|
-
|
|
36134
|
-
|
|
36135
|
-
|
|
37212
|
+
function hasAnsiSplitContinuationAhead(string, startIndex, previousVisibleValue, graphemeSegments) {
|
|
37213
|
+
if (!previousVisibleValue) {
|
|
37214
|
+
return false;
|
|
37215
|
+
}
|
|
37216
|
+
|
|
37217
|
+
let index = startIndex;
|
|
37218
|
+
let hasAnsiCode = false;
|
|
37219
|
+
while (index < string.length) {
|
|
37220
|
+
const codePoint = string.codePointAt(index);
|
|
37221
|
+
if (ESCAPES$1.has(codePoint)) {
|
|
37222
|
+
const code = parseAnsiCode(string, index);
|
|
37223
|
+
if (code) {
|
|
37224
|
+
hasAnsiCode = true;
|
|
37225
|
+
index = code.endIndex;
|
|
37226
|
+
continue;
|
|
37227
|
+
}
|
|
37228
|
+
}
|
|
37229
|
+
|
|
37230
|
+
if (!hasAnsiCode) {
|
|
37231
|
+
return false;
|
|
37232
|
+
}
|
|
37233
|
+
|
|
37234
|
+
const characterToken = parseCharacterTokenWithRawSegmentation(string, index, graphemeSegments);
|
|
37235
|
+
if (!characterToken) {
|
|
37236
|
+
return true;
|
|
37237
|
+
}
|
|
37238
|
+
|
|
37239
|
+
return areValuesInSameGrapheme(previousVisibleValue, characterToken.token.value);
|
|
37240
|
+
}
|
|
37241
|
+
|
|
37242
|
+
return false;
|
|
36136
37243
|
}
|
|
36137
37244
|
|
|
36138
|
-
function
|
|
36139
|
-
const tokens =
|
|
36140
|
-
|
|
36141
|
-
|
|
36142
|
-
let
|
|
36143
|
-
let
|
|
37245
|
+
function tokenizeAnsi$1(string, {endCharacter = Number.POSITIVE_INFINITY} = {}) {
|
|
37246
|
+
const tokens = [];
|
|
37247
|
+
const graphemeSegments = GRAPHEME_SEGMENTER.segment(string);
|
|
37248
|
+
|
|
37249
|
+
let index = 0;
|
|
37250
|
+
let visibleCount = 0;
|
|
37251
|
+
let previousVisibleValue;
|
|
37252
|
+
let hasAnsiSinceLastVisible = false;
|
|
37253
|
+
while (index < string.length) {
|
|
37254
|
+
const codePoint = string.codePointAt(index);
|
|
37255
|
+
|
|
37256
|
+
if (ESCAPES$1.has(codePoint)) {
|
|
37257
|
+
const code = parseAnsiCode(string, index);
|
|
37258
|
+
if (code) {
|
|
37259
|
+
tokens.push(code.token);
|
|
37260
|
+
index = code.endIndex;
|
|
37261
|
+
hasAnsiSinceLastVisible = true;
|
|
37262
|
+
continue;
|
|
37263
|
+
}
|
|
37264
|
+
}
|
|
37265
|
+
|
|
37266
|
+
const characterToken = parseCharacterTokenWithRawSegmentation(string, index, graphemeSegments);
|
|
37267
|
+
if (!characterToken) {
|
|
37268
|
+
return tokenizeAnsiWithVisibleSegmentation(string, {endCharacter});
|
|
37269
|
+
}
|
|
37270
|
+
|
|
37271
|
+
if (
|
|
37272
|
+
hasAnsiSinceLastVisible
|
|
37273
|
+
&& previousVisibleValue
|
|
37274
|
+
&& areValuesInSameGrapheme(previousVisibleValue, characterToken.token.value)
|
|
37275
|
+
) {
|
|
37276
|
+
return tokenizeAnsiWithVisibleSegmentation(string, {endCharacter});
|
|
37277
|
+
}
|
|
37278
|
+
|
|
37279
|
+
tokens.push(characterToken.token);
|
|
37280
|
+
index = characterToken.endIndex;
|
|
37281
|
+
visibleCount += characterToken.token.visibleWidth;
|
|
37282
|
+
hasAnsiSinceLastVisible = false;
|
|
37283
|
+
previousVisibleValue = characterToken.token.value;
|
|
37284
|
+
|
|
37285
|
+
if (visibleCount >= endCharacter) {
|
|
37286
|
+
if (hasAnsiSplitContinuationAhead(string, index, previousVisibleValue, graphemeSegments)) {
|
|
37287
|
+
return tokenizeAnsiWithVisibleSegmentation(string, {endCharacter});
|
|
37288
|
+
}
|
|
36144
37289
|
|
|
36145
|
-
|
|
36146
|
-
if (end !== undefined && position >= end) {
|
|
37290
|
+
index = appendTrailingAnsiTokens(string, index, tokens);
|
|
36147
37291
|
break;
|
|
36148
37292
|
}
|
|
37293
|
+
}
|
|
37294
|
+
|
|
37295
|
+
return tokens;
|
|
37296
|
+
}
|
|
36149
37297
|
|
|
36150
|
-
|
|
36151
|
-
|
|
36152
|
-
|
|
36153
|
-
|
|
37298
|
+
function applySgrFragments(activeStyles, fragments) {
|
|
37299
|
+
for (const fragment of fragments) {
|
|
37300
|
+
switch (fragment.type) {
|
|
37301
|
+
case 'reset': {
|
|
37302
|
+
activeStyles.clear();
|
|
37303
|
+
break;
|
|
36154
37304
|
}
|
|
36155
|
-
|
|
36156
|
-
|
|
36157
|
-
|
|
36158
|
-
|
|
36159
|
-
// Simplify active codes
|
|
36160
|
-
activeCodes = reduceAnsiCodes$1(activeCodes);
|
|
36161
|
-
returnValue = activeCodes.map(({code}) => code).join('');
|
|
37305
|
+
|
|
37306
|
+
case 'end': {
|
|
37307
|
+
activeStyles.delete(fragment.endCode);
|
|
37308
|
+
break;
|
|
36162
37309
|
}
|
|
36163
37310
|
|
|
36164
|
-
|
|
36165
|
-
|
|
37311
|
+
case 'start': {
|
|
37312
|
+
activeStyles.delete(fragment.endCode);
|
|
37313
|
+
activeStyles.set(fragment.endCode, fragment.code);
|
|
37314
|
+
break;
|
|
36166
37315
|
}
|
|
37316
|
+
}
|
|
37317
|
+
}
|
|
37318
|
+
|
|
37319
|
+
return activeStyles;
|
|
37320
|
+
}
|
|
37321
|
+
|
|
37322
|
+
function undoAnsiCodes$1(activeStyles) {
|
|
37323
|
+
return [...activeStyles.keys()].reverse().join('');
|
|
37324
|
+
}
|
|
37325
|
+
|
|
37326
|
+
function closeHyperlink(hyperlinkToken) {
|
|
37327
|
+
return `${hyperlinkToken.closePrefix}${hyperlinkToken.terminator}`;
|
|
37328
|
+
}
|
|
37329
|
+
|
|
37330
|
+
function shouldIncludeSgrAfterEnd(token, activeStyles) {
|
|
37331
|
+
let hasStartFragment = false;
|
|
37332
|
+
let hasClosingEffect = false;
|
|
37333
|
+
|
|
37334
|
+
for (const fragment of token.fragments) {
|
|
37335
|
+
if (fragment.type === 'start') {
|
|
37336
|
+
hasStartFragment = true;
|
|
37337
|
+
continue;
|
|
37338
|
+
}
|
|
37339
|
+
|
|
37340
|
+
if (fragment.type === 'reset' && activeStyles.size > 0) {
|
|
37341
|
+
hasClosingEffect = true;
|
|
37342
|
+
continue;
|
|
37343
|
+
}
|
|
36167
37344
|
|
|
36168
|
-
|
|
37345
|
+
if (fragment.type === 'end' && activeStyles.has(fragment.endCode)) {
|
|
37346
|
+
hasClosingEffect = true;
|
|
36169
37347
|
}
|
|
36170
37348
|
}
|
|
36171
37349
|
|
|
36172
|
-
|
|
36173
|
-
returnValue += undoAnsiCodes$1(activeCodes);
|
|
36174
|
-
return returnValue;
|
|
37350
|
+
return hasClosingEffect && !hasStartFragment;
|
|
36175
37351
|
}
|
|
36176
37352
|
|
|
36177
|
-
|
|
36178
|
-
|
|
36179
|
-
|
|
36180
|
-
|
|
36181
|
-
|
|
36182
|
-
|
|
36183
|
-
|
|
36184
|
-
|
|
37353
|
+
function applySgrToken({token, isPastEnd, activeStyles, returnValue, include, activeHyperlink, position}) {
|
|
37354
|
+
if (isPastEnd && !shouldIncludeSgrAfterEnd(token, activeStyles)) {
|
|
37355
|
+
return {
|
|
37356
|
+
activeStyles,
|
|
37357
|
+
activeHyperlink,
|
|
37358
|
+
position,
|
|
37359
|
+
returnValue,
|
|
37360
|
+
include,
|
|
37361
|
+
};
|
|
37362
|
+
}
|
|
36185
37363
|
|
|
36186
|
-
|
|
37364
|
+
activeStyles = applySgrFragments(activeStyles, token.fragments);
|
|
37365
|
+
if (include) {
|
|
37366
|
+
returnValue += token.code;
|
|
37367
|
+
}
|
|
36187
37368
|
|
|
36188
|
-
|
|
36189
|
-
|
|
37369
|
+
return {
|
|
37370
|
+
activeStyles,
|
|
37371
|
+
activeHyperlink,
|
|
37372
|
+
position,
|
|
37373
|
+
returnValue,
|
|
37374
|
+
include,
|
|
37375
|
+
};
|
|
37376
|
+
}
|
|
36190
37377
|
|
|
36191
|
-
|
|
36192
|
-
|
|
37378
|
+
function applyHyperlinkToken({token, isPastEnd, activeStyles, activeHyperlink, position, returnValue, include}) {
|
|
37379
|
+
if (
|
|
37380
|
+
isPastEnd
|
|
37381
|
+
&& (
|
|
37382
|
+
token.action !== 'close'
|
|
37383
|
+
|| !activeHyperlink
|
|
37384
|
+
)
|
|
37385
|
+
) {
|
|
37386
|
+
return {
|
|
37387
|
+
activeStyles,
|
|
37388
|
+
activeHyperlink,
|
|
37389
|
+
position,
|
|
37390
|
+
returnValue,
|
|
37391
|
+
include,
|
|
37392
|
+
};
|
|
37393
|
+
}
|
|
36193
37394
|
|
|
36194
|
-
|
|
36195
|
-
|
|
37395
|
+
if (token.action === 'open') {
|
|
37396
|
+
activeHyperlink = token;
|
|
37397
|
+
} else if (token.action === 'close') {
|
|
37398
|
+
activeHyperlink = undefined;
|
|
37399
|
+
}
|
|
36196
37400
|
|
|
36197
|
-
|
|
36198
|
-
|
|
37401
|
+
if (include) {
|
|
37402
|
+
returnValue += token.code;
|
|
37403
|
+
}
|
|
37404
|
+
|
|
37405
|
+
return {
|
|
37406
|
+
activeStyles,
|
|
37407
|
+
activeHyperlink,
|
|
37408
|
+
position,
|
|
37409
|
+
returnValue,
|
|
37410
|
+
include,
|
|
37411
|
+
};
|
|
36199
37412
|
}
|
|
36200
37413
|
|
|
36201
|
-
function
|
|
36202
|
-
|
|
37414
|
+
function applyControlToken({token, isPastEnd, activeStyles, activeHyperlink, position, returnValue, include}) {
|
|
37415
|
+
if (!isPastEnd && include) {
|
|
37416
|
+
returnValue += token.code;
|
|
37417
|
+
}
|
|
37418
|
+
|
|
37419
|
+
return {
|
|
37420
|
+
activeStyles,
|
|
37421
|
+
activeHyperlink,
|
|
37422
|
+
position,
|
|
37423
|
+
returnValue,
|
|
37424
|
+
include,
|
|
37425
|
+
};
|
|
36203
37426
|
}
|
|
36204
37427
|
|
|
36205
|
-
function
|
|
36206
|
-
|
|
36207
|
-
|
|
36208
|
-
|
|
36209
|
-
|
|
36210
|
-
|
|
36211
|
-
|
|
37428
|
+
function applyCharacterToken({token, start, activeStyles, activeHyperlink, position, returnValue, include}) {
|
|
37429
|
+
if (
|
|
37430
|
+
!include
|
|
37431
|
+
&& position >= start
|
|
37432
|
+
&& !token.isGraphemeContinuation
|
|
37433
|
+
) {
|
|
37434
|
+
include = true;
|
|
37435
|
+
returnValue = [...activeStyles.values()].join('');
|
|
37436
|
+
if (activeHyperlink) {
|
|
37437
|
+
returnValue += activeHyperlink.code;
|
|
36212
37438
|
}
|
|
36213
37439
|
}
|
|
36214
37440
|
|
|
36215
|
-
|
|
37441
|
+
if (include) {
|
|
37442
|
+
returnValue += token.value;
|
|
37443
|
+
}
|
|
37444
|
+
|
|
37445
|
+
position += token.visibleWidth;
|
|
37446
|
+
return {
|
|
37447
|
+
activeStyles,
|
|
37448
|
+
activeHyperlink,
|
|
37449
|
+
position,
|
|
37450
|
+
returnValue,
|
|
37451
|
+
include,
|
|
37452
|
+
};
|
|
36216
37453
|
}
|
|
36217
37454
|
|
|
36218
|
-
|
|
36219
|
-
|
|
36220
|
-
|
|
37455
|
+
const tokenHandlers = {
|
|
37456
|
+
sgr: applySgrToken,
|
|
37457
|
+
hyperlink: applyHyperlinkToken,
|
|
37458
|
+
control: applyControlToken,
|
|
37459
|
+
character: applyCharacterToken,
|
|
37460
|
+
};
|
|
37461
|
+
|
|
37462
|
+
function applyToken(parameters) {
|
|
37463
|
+
const tokenHandler = tokenHandlers[parameters.token.type];
|
|
37464
|
+
if (!tokenHandler) {
|
|
37465
|
+
const {
|
|
37466
|
+
activeStyles,
|
|
37467
|
+
activeHyperlink,
|
|
37468
|
+
position,
|
|
37469
|
+
returnValue,
|
|
37470
|
+
include,
|
|
37471
|
+
} = parameters;
|
|
37472
|
+
|
|
37473
|
+
return {
|
|
37474
|
+
activeStyles,
|
|
37475
|
+
activeHyperlink,
|
|
37476
|
+
position,
|
|
37477
|
+
returnValue,
|
|
37478
|
+
include,
|
|
37479
|
+
};
|
|
36221
37480
|
}
|
|
36222
37481
|
|
|
36223
|
-
|
|
36224
|
-
|
|
36225
|
-
countAnsiEscapeCodes = false,
|
|
36226
|
-
} = options;
|
|
37482
|
+
return tokenHandler(parameters);
|
|
37483
|
+
}
|
|
36227
37484
|
|
|
36228
|
-
|
|
37485
|
+
function createHasContinuationAheadMap(tokens) {
|
|
37486
|
+
const hasContinuationAhead = Array.from({length: tokens.length}, () => false);
|
|
37487
|
+
let nextCharacterIsContinuation = false;
|
|
36229
37488
|
|
|
36230
|
-
|
|
36231
|
-
|
|
37489
|
+
for (let tokenIndex = tokens.length - 1; tokenIndex >= 0; tokenIndex--) {
|
|
37490
|
+
const token = tokens[tokenIndex];
|
|
37491
|
+
hasContinuationAhead[tokenIndex] = nextCharacterIsContinuation;
|
|
37492
|
+
if (token.type === 'character') {
|
|
37493
|
+
nextCharacterIsContinuation = Boolean(token.isGraphemeContinuation);
|
|
37494
|
+
}
|
|
36232
37495
|
}
|
|
36233
37496
|
|
|
36234
|
-
|
|
36235
|
-
|
|
36236
|
-
}
|
|
37497
|
+
return hasContinuationAhead;
|
|
37498
|
+
}
|
|
36237
37499
|
|
|
36238
|
-
|
|
36239
|
-
const
|
|
37500
|
+
function sliceAnsi(string, start, end) {
|
|
37501
|
+
const tokens = tokenizeAnsi$1(string, {endCharacter: end});
|
|
37502
|
+
const hasContinuationAhead = createHasContinuationAheadMap(tokens);
|
|
37503
|
+
let activeStyles = new Map();
|
|
37504
|
+
let activeHyperlink;
|
|
37505
|
+
let position = 0;
|
|
37506
|
+
let returnValue = '';
|
|
37507
|
+
let include = false;
|
|
36240
37508
|
|
|
36241
|
-
for (const
|
|
36242
|
-
|
|
36243
|
-
if (
|
|
36244
|
-
|
|
37509
|
+
for (const [tokenIndex, token] of tokens.entries()) {
|
|
37510
|
+
let isPastEnd = end !== undefined && position >= end;
|
|
37511
|
+
if (
|
|
37512
|
+
isPastEnd
|
|
37513
|
+
&& token.type !== 'character'
|
|
37514
|
+
&& hasContinuationAhead[tokenIndex]
|
|
37515
|
+
) {
|
|
37516
|
+
isPastEnd = false;
|
|
36245
37517
|
}
|
|
36246
37518
|
|
|
36247
|
-
|
|
36248
|
-
|
|
36249
|
-
|
|
36250
|
-
|
|
37519
|
+
if (
|
|
37520
|
+
isPastEnd
|
|
37521
|
+
&& token.type === 'character'
|
|
37522
|
+
&& !token.isGraphemeContinuation
|
|
37523
|
+
) {
|
|
37524
|
+
break;
|
|
36251
37525
|
}
|
|
36252
37526
|
|
|
36253
|
-
|
|
36254
|
-
|
|
36255
|
-
|
|
37527
|
+
({activeStyles, activeHyperlink, position, returnValue, include} = applyToken({
|
|
37528
|
+
token,
|
|
37529
|
+
isPastEnd,
|
|
37530
|
+
start,
|
|
37531
|
+
activeStyles,
|
|
37532
|
+
activeHyperlink,
|
|
37533
|
+
position,
|
|
37534
|
+
returnValue,
|
|
37535
|
+
include,
|
|
37536
|
+
}));
|
|
37537
|
+
}
|
|
36256
37538
|
|
|
36257
|
-
|
|
36258
|
-
|
|
37539
|
+
if (!include) {
|
|
37540
|
+
return '';
|
|
36259
37541
|
}
|
|
36260
37542
|
|
|
36261
|
-
|
|
37543
|
+
if (activeHyperlink) {
|
|
37544
|
+
returnValue += closeHyperlink(activeHyperlink);
|
|
37545
|
+
}
|
|
37546
|
+
|
|
37547
|
+
// Disable active codes at the end
|
|
37548
|
+
returnValue += undoAnsiCodes$1(activeStyles);
|
|
37549
|
+
|
|
37550
|
+
return returnValue;
|
|
36262
37551
|
}
|
|
36263
37552
|
|
|
36264
37553
|
function getIndexOfNearestSpace(string, wantedIndex, shouldSearchRight) {
|
|
@@ -36455,6 +37744,347 @@ const wrapText = (text, maxWidth, wrapType) => {
|
|
|
36455
37744
|
return wrappedText;
|
|
36456
37745
|
};
|
|
36457
37746
|
|
|
37747
|
+
const bellCharacter = '\u0007';
|
|
37748
|
+
const escapeCharacter = '\u001B';
|
|
37749
|
+
const stringTerminatorCharacter = '\u009C';
|
|
37750
|
+
const csiCharacter = '\u009B';
|
|
37751
|
+
const oscCharacter = '\u009D';
|
|
37752
|
+
const dcsCharacter = '\u0090';
|
|
37753
|
+
const pmCharacter = '\u009E';
|
|
37754
|
+
const apcCharacter = '\u009F';
|
|
37755
|
+
const sosCharacter = '\u0098';
|
|
37756
|
+
const isCsiParameterCharacter = (character) => {
|
|
37757
|
+
const codePoint = character.codePointAt(0);
|
|
37758
|
+
return codePoint !== undefined && codePoint >= 0x30 && codePoint <= 0x3f;
|
|
37759
|
+
};
|
|
37760
|
+
const isCsiIntermediateCharacter = (character) => {
|
|
37761
|
+
const codePoint = character.codePointAt(0);
|
|
37762
|
+
return codePoint !== undefined && codePoint >= 0x20 && codePoint <= 0x2f;
|
|
37763
|
+
};
|
|
37764
|
+
const isCsiFinalCharacter = (character) => {
|
|
37765
|
+
const codePoint = character.codePointAt(0);
|
|
37766
|
+
return codePoint !== undefined && codePoint >= 0x40 && codePoint <= 0x7e;
|
|
37767
|
+
};
|
|
37768
|
+
const isEscapeIntermediateCharacter = (character) => {
|
|
37769
|
+
const codePoint = character.codePointAt(0);
|
|
37770
|
+
return codePoint !== undefined && codePoint >= 0x20 && codePoint <= 0x2f;
|
|
37771
|
+
};
|
|
37772
|
+
const isEscapeFinalCharacter = (character) => {
|
|
37773
|
+
const codePoint = character.codePointAt(0);
|
|
37774
|
+
return codePoint !== undefined && codePoint >= 0x30 && codePoint <= 0x7e;
|
|
37775
|
+
};
|
|
37776
|
+
const isC1ControlCharacter = (character) => {
|
|
37777
|
+
const codePoint = character.codePointAt(0);
|
|
37778
|
+
return codePoint !== undefined && codePoint >= 0x80 && codePoint <= 0x9f;
|
|
37779
|
+
};
|
|
37780
|
+
// Standards references:
|
|
37781
|
+
// ECMA-48 control functions and CSI byte classes: https://ecma-international.org/publications-and-standards/standards/ecma-48/
|
|
37782
|
+
// xterm CSI parameter/intermediate/final format notes: https://invisible-island.net/xterm/ecma-48-parameter-format.html
|
|
37783
|
+
// xterm/OSC BEL termination behavior: https://davidrg.github.io/ckwin/dev/ctlseqs.html
|
|
37784
|
+
const readCsiSequence = (text, fromIndex) => {
|
|
37785
|
+
let index = fromIndex;
|
|
37786
|
+
while (index < text.length) {
|
|
37787
|
+
const character = text[index];
|
|
37788
|
+
if (!isCsiParameterCharacter(character)) {
|
|
37789
|
+
break;
|
|
37790
|
+
}
|
|
37791
|
+
index++;
|
|
37792
|
+
}
|
|
37793
|
+
const parameterString = text.slice(fromIndex, index);
|
|
37794
|
+
const intermediateStartIndex = index;
|
|
37795
|
+
while (index < text.length) {
|
|
37796
|
+
const character = text[index];
|
|
37797
|
+
if (!isCsiIntermediateCharacter(character)) {
|
|
37798
|
+
break;
|
|
37799
|
+
}
|
|
37800
|
+
index++;
|
|
37801
|
+
}
|
|
37802
|
+
const intermediateString = text.slice(intermediateStartIndex, index);
|
|
37803
|
+
const finalCharacter = text[index];
|
|
37804
|
+
if (finalCharacter === undefined || !isCsiFinalCharacter(finalCharacter)) {
|
|
37805
|
+
return undefined;
|
|
37806
|
+
}
|
|
37807
|
+
return {
|
|
37808
|
+
endIndex: index + 1,
|
|
37809
|
+
parameterString,
|
|
37810
|
+
intermediateString,
|
|
37811
|
+
finalCharacter,
|
|
37812
|
+
};
|
|
37813
|
+
};
|
|
37814
|
+
const findControlStringTerminatorIndex = (text, fromIndex, allowBellTerminator) => {
|
|
37815
|
+
for (let index = fromIndex; index < text.length; index++) {
|
|
37816
|
+
const character = text[index];
|
|
37817
|
+
if (allowBellTerminator && character === bellCharacter) {
|
|
37818
|
+
return index + 1;
|
|
37819
|
+
}
|
|
37820
|
+
if (character === stringTerminatorCharacter) {
|
|
37821
|
+
return index + 1;
|
|
37822
|
+
}
|
|
37823
|
+
if (character === escapeCharacter) {
|
|
37824
|
+
const followingCharacter = text[index + 1];
|
|
37825
|
+
// Tmux escapes ESC bytes in payload as ESC ESC.
|
|
37826
|
+
if (followingCharacter === escapeCharacter) {
|
|
37827
|
+
index++;
|
|
37828
|
+
continue;
|
|
37829
|
+
}
|
|
37830
|
+
if (followingCharacter === '\\') {
|
|
37831
|
+
return index + 2;
|
|
37832
|
+
}
|
|
37833
|
+
}
|
|
37834
|
+
}
|
|
37835
|
+
return undefined;
|
|
37836
|
+
};
|
|
37837
|
+
const readEscapeSequence = (text, fromIndex) => {
|
|
37838
|
+
let index = fromIndex;
|
|
37839
|
+
while (index < text.length) {
|
|
37840
|
+
const character = text[index];
|
|
37841
|
+
if (!isEscapeIntermediateCharacter(character)) {
|
|
37842
|
+
break;
|
|
37843
|
+
}
|
|
37844
|
+
index++;
|
|
37845
|
+
}
|
|
37846
|
+
const intermediateString = text.slice(fromIndex, index);
|
|
37847
|
+
const finalCharacter = text[index];
|
|
37848
|
+
if (finalCharacter === undefined || !isEscapeFinalCharacter(finalCharacter)) {
|
|
37849
|
+
return undefined;
|
|
37850
|
+
}
|
|
37851
|
+
return {
|
|
37852
|
+
endIndex: index + 1,
|
|
37853
|
+
intermediateString,
|
|
37854
|
+
finalCharacter,
|
|
37855
|
+
};
|
|
37856
|
+
};
|
|
37857
|
+
// Centralize control-string rules so ESC and C1 paths do not diverge.
|
|
37858
|
+
const getControlStringFromEscapeIntroducer = (character) => {
|
|
37859
|
+
switch (character) {
|
|
37860
|
+
case ']': {
|
|
37861
|
+
return { type: 'osc', allowBellTerminator: true };
|
|
37862
|
+
}
|
|
37863
|
+
case 'P': {
|
|
37864
|
+
return { type: 'dcs', allowBellTerminator: false };
|
|
37865
|
+
}
|
|
37866
|
+
case '^': {
|
|
37867
|
+
return { type: 'pm', allowBellTerminator: false };
|
|
37868
|
+
}
|
|
37869
|
+
case '_': {
|
|
37870
|
+
return { type: 'apc', allowBellTerminator: false };
|
|
37871
|
+
}
|
|
37872
|
+
case 'X': {
|
|
37873
|
+
return { type: 'sos', allowBellTerminator: false };
|
|
37874
|
+
}
|
|
37875
|
+
default: {
|
|
37876
|
+
return undefined;
|
|
37877
|
+
}
|
|
37878
|
+
}
|
|
37879
|
+
};
|
|
37880
|
+
const getControlStringFromC1Introducer = (character) => {
|
|
37881
|
+
switch (character) {
|
|
37882
|
+
case oscCharacter: {
|
|
37883
|
+
return { type: 'osc', allowBellTerminator: true };
|
|
37884
|
+
}
|
|
37885
|
+
case dcsCharacter: {
|
|
37886
|
+
return { type: 'dcs', allowBellTerminator: false };
|
|
37887
|
+
}
|
|
37888
|
+
case pmCharacter: {
|
|
37889
|
+
return { type: 'pm', allowBellTerminator: false };
|
|
37890
|
+
}
|
|
37891
|
+
case apcCharacter: {
|
|
37892
|
+
return { type: 'apc', allowBellTerminator: false };
|
|
37893
|
+
}
|
|
37894
|
+
case sosCharacter: {
|
|
37895
|
+
return { type: 'sos', allowBellTerminator: false };
|
|
37896
|
+
}
|
|
37897
|
+
default: {
|
|
37898
|
+
return undefined;
|
|
37899
|
+
}
|
|
37900
|
+
}
|
|
37901
|
+
};
|
|
37902
|
+
const hasAnsiControlCharacters = (text) => {
|
|
37903
|
+
if (text.includes(escapeCharacter)) {
|
|
37904
|
+
return true;
|
|
37905
|
+
}
|
|
37906
|
+
for (const character of text) {
|
|
37907
|
+
if (isC1ControlCharacter(character)) {
|
|
37908
|
+
return true;
|
|
37909
|
+
}
|
|
37910
|
+
}
|
|
37911
|
+
return false;
|
|
37912
|
+
};
|
|
37913
|
+
const malformedFromIndex = (tokens, text, textStartIndex, fromIndex) => {
|
|
37914
|
+
if (fromIndex > textStartIndex) {
|
|
37915
|
+
tokens.push({ type: 'text', value: text.slice(textStartIndex, fromIndex) });
|
|
37916
|
+
}
|
|
37917
|
+
// Treat the remainder as invalid so callers can drop it as one unsafe unit.
|
|
37918
|
+
tokens.push({ type: 'invalid', value: text.slice(fromIndex) });
|
|
37919
|
+
return tokens;
|
|
37920
|
+
};
|
|
37921
|
+
const tokenizeAnsi = (text) => {
|
|
37922
|
+
if (!hasAnsiControlCharacters(text)) {
|
|
37923
|
+
return [{ type: 'text', value: text }];
|
|
37924
|
+
}
|
|
37925
|
+
const tokens = [];
|
|
37926
|
+
let textStartIndex = 0;
|
|
37927
|
+
for (let index = 0; index < text.length;) {
|
|
37928
|
+
const character = text[index];
|
|
37929
|
+
if (character === undefined) {
|
|
37930
|
+
break;
|
|
37931
|
+
}
|
|
37932
|
+
if (character === escapeCharacter) {
|
|
37933
|
+
const followingCharacter = text[index + 1];
|
|
37934
|
+
if (followingCharacter === undefined) {
|
|
37935
|
+
return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
37936
|
+
}
|
|
37937
|
+
if (followingCharacter === '[') {
|
|
37938
|
+
const csiSequence = readCsiSequence(text, index + 2);
|
|
37939
|
+
if (csiSequence === undefined) {
|
|
37940
|
+
return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
37941
|
+
}
|
|
37942
|
+
if (index > textStartIndex) {
|
|
37943
|
+
tokens.push({ type: 'text', value: text.slice(textStartIndex, index) });
|
|
37944
|
+
}
|
|
37945
|
+
tokens.push({
|
|
37946
|
+
type: 'csi',
|
|
37947
|
+
value: text.slice(index, csiSequence.endIndex),
|
|
37948
|
+
parameterString: csiSequence.parameterString,
|
|
37949
|
+
intermediateString: csiSequence.intermediateString,
|
|
37950
|
+
finalCharacter: csiSequence.finalCharacter,
|
|
37951
|
+
});
|
|
37952
|
+
index = csiSequence.endIndex;
|
|
37953
|
+
textStartIndex = index;
|
|
37954
|
+
continue;
|
|
37955
|
+
}
|
|
37956
|
+
const escapeControlString = getControlStringFromEscapeIntroducer(followingCharacter);
|
|
37957
|
+
if (escapeControlString !== undefined) {
|
|
37958
|
+
const controlStringTerminatorIndex = findControlStringTerminatorIndex(text, index + 2, escapeControlString.allowBellTerminator);
|
|
37959
|
+
if (controlStringTerminatorIndex === undefined) {
|
|
37960
|
+
return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
37961
|
+
}
|
|
37962
|
+
if (index > textStartIndex) {
|
|
37963
|
+
tokens.push({ type: 'text', value: text.slice(textStartIndex, index) });
|
|
37964
|
+
}
|
|
37965
|
+
tokens.push({
|
|
37966
|
+
type: escapeControlString.type,
|
|
37967
|
+
value: text.slice(index, controlStringTerminatorIndex),
|
|
37968
|
+
});
|
|
37969
|
+
index = controlStringTerminatorIndex;
|
|
37970
|
+
textStartIndex = index;
|
|
37971
|
+
continue;
|
|
37972
|
+
}
|
|
37973
|
+
const escapeSequence = readEscapeSequence(text, index + 1);
|
|
37974
|
+
if (escapeSequence === undefined) {
|
|
37975
|
+
// Incomplete escape sequences with intermediates are malformed control strings.
|
|
37976
|
+
if (isEscapeIntermediateCharacter(followingCharacter)) {
|
|
37977
|
+
return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
37978
|
+
}
|
|
37979
|
+
if (index > textStartIndex) {
|
|
37980
|
+
tokens.push({ type: 'text', value: text.slice(textStartIndex, index) });
|
|
37981
|
+
}
|
|
37982
|
+
// Ignore lone ESC and continue tokenizing the rest.
|
|
37983
|
+
index++;
|
|
37984
|
+
textStartIndex = index;
|
|
37985
|
+
continue;
|
|
37986
|
+
}
|
|
37987
|
+
if (index > textStartIndex) {
|
|
37988
|
+
tokens.push({ type: 'text', value: text.slice(textStartIndex, index) });
|
|
37989
|
+
}
|
|
37990
|
+
tokens.push({
|
|
37991
|
+
type: 'esc',
|
|
37992
|
+
value: text.slice(index, escapeSequence.endIndex),
|
|
37993
|
+
intermediateString: escapeSequence.intermediateString,
|
|
37994
|
+
finalCharacter: escapeSequence.finalCharacter,
|
|
37995
|
+
});
|
|
37996
|
+
index = escapeSequence.endIndex;
|
|
37997
|
+
textStartIndex = index;
|
|
37998
|
+
continue;
|
|
37999
|
+
}
|
|
38000
|
+
if (character === csiCharacter) {
|
|
38001
|
+
const csiSequence = readCsiSequence(text, index + 1);
|
|
38002
|
+
if (csiSequence === undefined) {
|
|
38003
|
+
return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
38004
|
+
}
|
|
38005
|
+
if (index > textStartIndex) {
|
|
38006
|
+
tokens.push({ type: 'text', value: text.slice(textStartIndex, index) });
|
|
38007
|
+
}
|
|
38008
|
+
tokens.push({
|
|
38009
|
+
type: 'csi',
|
|
38010
|
+
value: text.slice(index, csiSequence.endIndex),
|
|
38011
|
+
parameterString: csiSequence.parameterString,
|
|
38012
|
+
intermediateString: csiSequence.intermediateString,
|
|
38013
|
+
finalCharacter: csiSequence.finalCharacter,
|
|
38014
|
+
});
|
|
38015
|
+
index = csiSequence.endIndex;
|
|
38016
|
+
textStartIndex = index;
|
|
38017
|
+
continue;
|
|
38018
|
+
}
|
|
38019
|
+
const c1ControlString = getControlStringFromC1Introducer(character);
|
|
38020
|
+
if (c1ControlString !== undefined) {
|
|
38021
|
+
const controlStringTerminatorIndex = findControlStringTerminatorIndex(text, index + 1, c1ControlString.allowBellTerminator);
|
|
38022
|
+
if (controlStringTerminatorIndex === undefined) {
|
|
38023
|
+
return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
38024
|
+
}
|
|
38025
|
+
if (index > textStartIndex) {
|
|
38026
|
+
tokens.push({ type: 'text', value: text.slice(textStartIndex, index) });
|
|
38027
|
+
}
|
|
38028
|
+
tokens.push({
|
|
38029
|
+
type: c1ControlString.type,
|
|
38030
|
+
value: text.slice(index, controlStringTerminatorIndex),
|
|
38031
|
+
});
|
|
38032
|
+
index = controlStringTerminatorIndex;
|
|
38033
|
+
textStartIndex = index;
|
|
38034
|
+
continue;
|
|
38035
|
+
}
|
|
38036
|
+
if (character === stringTerminatorCharacter) {
|
|
38037
|
+
if (index > textStartIndex) {
|
|
38038
|
+
tokens.push({ type: 'text', value: text.slice(textStartIndex, index) });
|
|
38039
|
+
}
|
|
38040
|
+
tokens.push({ type: 'st', value: character });
|
|
38041
|
+
index++;
|
|
38042
|
+
textStartIndex = index;
|
|
38043
|
+
continue;
|
|
38044
|
+
}
|
|
38045
|
+
// Strip remaining C1 controls as standalone functions.
|
|
38046
|
+
if (isC1ControlCharacter(character)) {
|
|
38047
|
+
if (index > textStartIndex) {
|
|
38048
|
+
tokens.push({ type: 'text', value: text.slice(textStartIndex, index) });
|
|
38049
|
+
}
|
|
38050
|
+
tokens.push({ type: 'c1', value: character });
|
|
38051
|
+
index++;
|
|
38052
|
+
textStartIndex = index;
|
|
38053
|
+
continue;
|
|
38054
|
+
}
|
|
38055
|
+
index++;
|
|
38056
|
+
}
|
|
38057
|
+
if (textStartIndex < text.length) {
|
|
38058
|
+
tokens.push({ type: 'text', value: text.slice(textStartIndex) });
|
|
38059
|
+
}
|
|
38060
|
+
return tokens;
|
|
38061
|
+
};
|
|
38062
|
+
|
|
38063
|
+
const sgrParametersRegex = /^[\d:;]*$/;
|
|
38064
|
+
// Strip ANSI escape sequences that would conflict with Ink's layout.
|
|
38065
|
+
// Preserved: SGR sequences (colors, bold, etc. - end with 'm') and
|
|
38066
|
+
// OSC sequences (hyperlinks, etc. - ESC ] or C1 OSC).
|
|
38067
|
+
// Stripped: cursor movement, screen clearing, and other control sequences.
|
|
38068
|
+
const sanitizeAnsi = (text) => {
|
|
38069
|
+
if (!hasAnsiControlCharacters(text)) {
|
|
38070
|
+
return text;
|
|
38071
|
+
}
|
|
38072
|
+
let output = '';
|
|
38073
|
+
for (const token of tokenizeAnsi(text)) {
|
|
38074
|
+
if (token.type === 'text' || token.type === 'osc') {
|
|
38075
|
+
output += token.value;
|
|
38076
|
+
continue;
|
|
38077
|
+
}
|
|
38078
|
+
if (token.type === 'csi' &&
|
|
38079
|
+
token.finalCharacter === 'm' &&
|
|
38080
|
+
token.intermediateString === '' &&
|
|
38081
|
+
sgrParametersRegex.test(token.parameterString)) {
|
|
38082
|
+
output += token.value;
|
|
38083
|
+
}
|
|
38084
|
+
}
|
|
38085
|
+
return output;
|
|
38086
|
+
};
|
|
38087
|
+
|
|
36458
38088
|
// Squashing text nodes allows to combine multiple text nodes into one and write
|
|
36459
38089
|
// to `Output` instance only once. For example, <Text>hello{' '}world</Text>
|
|
36460
38090
|
// is actually 3 text nodes, which would result 3 writes to `Output`.
|
|
@@ -36486,7 +38116,7 @@ const squashTextNodes = (node) => {
|
|
|
36486
38116
|
}
|
|
36487
38117
|
text += nodeText;
|
|
36488
38118
|
}
|
|
36489
|
-
return text;
|
|
38119
|
+
return sanitizeAnsi(text);
|
|
36490
38120
|
};
|
|
36491
38121
|
|
|
36492
38122
|
const createNode = (nodeName) => {
|
|
@@ -36529,11 +38159,12 @@ const insertBeforeNode = (node, newChildNode, beforeChildNode) => {
|
|
|
36529
38159
|
if (newChildNode.yogaNode) {
|
|
36530
38160
|
node.yogaNode?.insertChild(newChildNode.yogaNode, index);
|
|
36531
38161
|
}
|
|
36532
|
-
return;
|
|
36533
38162
|
}
|
|
36534
|
-
|
|
36535
|
-
|
|
36536
|
-
|
|
38163
|
+
else {
|
|
38164
|
+
node.childNodes.push(newChildNode);
|
|
38165
|
+
if (newChildNode.yogaNode) {
|
|
38166
|
+
node.yogaNode?.insertChild(newChildNode.yogaNode, node.yogaNode.getChildCount());
|
|
38167
|
+
}
|
|
36537
38168
|
}
|
|
36538
38169
|
if (node.nodeName === 'ink-text' || node.nodeName === 'ink-virtual-text') {
|
|
36539
38170
|
markNodeAsDirty(node);
|
|
@@ -36841,7 +38472,7 @@ const styles = (node, style = {}) => {
|
|
|
36841
38472
|
// We need to conditionally perform devtools connection to avoid
|
|
36842
38473
|
// accidentally breaking other third-party code.
|
|
36843
38474
|
// See https://github.com/vadimdemedes/ink/issues/384
|
|
36844
|
-
if (
|
|
38475
|
+
if (isDev()) {
|
|
36845
38476
|
try {
|
|
36846
38477
|
await import('./devtools-CPruVlOo.js');
|
|
36847
38478
|
}
|
|
@@ -36894,6 +38525,14 @@ const cleanupYogaNode = (node) => {
|
|
|
36894
38525
|
};
|
|
36895
38526
|
let currentUpdatePriority = constantsExports.NoEventPriority;
|
|
36896
38527
|
let currentRootNode;
|
|
38528
|
+
async function loadPackageJson() {
|
|
38529
|
+
const fs = await import('node:fs');
|
|
38530
|
+
const content = fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8');
|
|
38531
|
+
return JSON.parse(content);
|
|
38532
|
+
}
|
|
38533
|
+
const packageJson = isDev()
|
|
38534
|
+
? await loadPackageJson()
|
|
38535
|
+
: { name: undefined, version: undefined };
|
|
36897
38536
|
var reconciler = createReconciler({
|
|
36898
38537
|
getRootHostContext: () => ({
|
|
36899
38538
|
isInsideText: false,
|
|
@@ -36994,6 +38633,14 @@ var reconciler = createReconciler({
|
|
|
36994
38633
|
supportsMutation: true,
|
|
36995
38634
|
supportsPersistence: false,
|
|
36996
38635
|
supportsHydration: false,
|
|
38636
|
+
// Scheduler integration for concurrent mode
|
|
38637
|
+
supportsMicrotasks: true,
|
|
38638
|
+
scheduleMicrotask: queueMicrotask,
|
|
38639
|
+
// @ts-expect-error @types/react-reconciler is outdated and doesn't include scheduleCallback
|
|
38640
|
+
scheduleCallback: schedulerExports.unstable_scheduleCallback,
|
|
38641
|
+
cancelCallback: schedulerExports.unstable_cancelCallback,
|
|
38642
|
+
shouldYield: schedulerExports.unstable_shouldYield,
|
|
38643
|
+
now: schedulerExports.unstable_now,
|
|
36997
38644
|
scheduleTimeout: setTimeout,
|
|
36998
38645
|
cancelTimeout: clearTimeout,
|
|
36999
38646
|
noTimeout: -1,
|
|
@@ -37057,7 +38704,8 @@ var reconciler = createReconciler({
|
|
|
37057
38704
|
return constantsExports.DefaultEventPriority;
|
|
37058
38705
|
},
|
|
37059
38706
|
maySuspendCommit() {
|
|
37060
|
-
|
|
38707
|
+
// Return true to enable Suspense resource preloading
|
|
38708
|
+
return true;
|
|
37061
38709
|
},
|
|
37062
38710
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
37063
38711
|
NotPendingTransition: undefined,
|
|
@@ -37083,6 +38731,8 @@ var reconciler = createReconciler({
|
|
|
37083
38731
|
waitForCommitToBeReady() {
|
|
37084
38732
|
return null;
|
|
37085
38733
|
},
|
|
38734
|
+
rendererPackageName: packageJson.name,
|
|
38735
|
+
rendererVersion: packageJson.version,
|
|
37086
38736
|
});
|
|
37087
38737
|
|
|
37088
38738
|
function indentString(string, count = 1, options = {}) {
|
|
@@ -37526,10 +39176,8 @@ for (const [start, end] of ansiStyles.codes) {
|
|
|
37526
39176
|
endCodesSet.add(ansiStyles.color.ansi(end));
|
|
37527
39177
|
endCodesMap.set(ansiStyles.color.ansi(start), ansiStyles.color.ansi(end));
|
|
37528
39178
|
}
|
|
37529
|
-
const
|
|
37530
|
-
const
|
|
37531
|
-
.split("")
|
|
37532
|
-
.map((char) => char.charCodeAt(0));
|
|
39179
|
+
const linkCodePrefix = "\x1B]8;"; // OSC 8 link prefix (params and URL follow)
|
|
39180
|
+
const linkCodePrefixCharCodes = linkCodePrefix.split("").map((char) => char.charCodeAt(0));
|
|
37533
39181
|
const linkCodeSuffix = "\x07";
|
|
37534
39182
|
const linkEndCode = `\x1B]8;;${linkCodeSuffix}`;
|
|
37535
39183
|
function getEndCode(code) {
|
|
@@ -37539,7 +39187,7 @@ function getEndCode(code) {
|
|
|
37539
39187
|
return endCodesMap.get(code);
|
|
37540
39188
|
// We have a few special cases to handle here:
|
|
37541
39189
|
// Links:
|
|
37542
|
-
if (code.startsWith(
|
|
39190
|
+
if (code.startsWith(linkCodePrefix))
|
|
37543
39191
|
return linkEndCode;
|
|
37544
39192
|
code = code.slice(2);
|
|
37545
39193
|
// 8-bit/24-bit colors:
|
|
@@ -37559,7 +39207,13 @@ function getEndCode(code) {
|
|
|
37559
39207
|
}
|
|
37560
39208
|
}
|
|
37561
39209
|
function ansiCodesToString(codes) {
|
|
37562
|
-
|
|
39210
|
+
// Deduplicate ANSI code strings before joining
|
|
39211
|
+
const deduplicated = new Set(codes.map((code) => code.code));
|
|
39212
|
+
return [...deduplicated].join("");
|
|
39213
|
+
}
|
|
39214
|
+
/** Check if a code is an intensity code (bold or dim) - these share endCode 22m but can coexist */
|
|
39215
|
+
function isIntensityCode(code) {
|
|
39216
|
+
return code.code === ansiStyles.bold.open || code.code === ansiStyles.dim.open;
|
|
37563
39217
|
}
|
|
37564
39218
|
|
|
37565
39219
|
/** Reduces the given array of ANSI codes to the minimum necessary to render with the same style */
|
|
@@ -37582,9 +39236,8 @@ function reduceAnsiCodesIncremental(codes, newCodes) {
|
|
|
37582
39236
|
// This is a start code. Remove codes it "overrides", then add it.
|
|
37583
39237
|
// If a new code has the same endCode, it "overrides" existing ones.
|
|
37584
39238
|
// Special case: Intensity codes (1m, 2m) can coexist (both end with 22m).
|
|
37585
|
-
|
|
37586
|
-
|
|
37587
|
-
if (isIntensityCode) {
|
|
39239
|
+
// We only add those if the exact same code is not already present.
|
|
39240
|
+
if (isIntensityCode(code)) {
|
|
37588
39241
|
if (!ret.find((retCode) => retCode.code === code.code && retCode.endCode === code.endCode)) {
|
|
37589
39242
|
ret.push(code);
|
|
37590
39243
|
}
|
|
@@ -37614,11 +39267,19 @@ function undoAnsiCodes(codes) {
|
|
|
37614
39267
|
*/
|
|
37615
39268
|
function diffAnsiCodes(from, to) {
|
|
37616
39269
|
const endCodesInTo = new Set(to.map((code) => code.endCode));
|
|
39270
|
+
const startCodesInTo = new Set(to.map((code) => code.code));
|
|
37617
39271
|
const startCodesInFrom = new Set(from.map((code) => code.code));
|
|
37618
39272
|
return [
|
|
37619
39273
|
// Ignore all styles in `from` that are not overwritten or removed by `to`
|
|
37620
39274
|
// Disable all styles in `from` that are removed in `to`
|
|
37621
|
-
...undoAnsiCodes(from.filter((code) =>
|
|
39275
|
+
...undoAnsiCodes(from.filter((code) => {
|
|
39276
|
+
// Special case: Intensity codes (1m, 2m) can coexist (both end with 22m).
|
|
39277
|
+
// We have to check the start codes for those, otherwise we might miss a reset.
|
|
39278
|
+
if (isIntensityCode(code)) {
|
|
39279
|
+
return !startCodesInTo.has(code.code);
|
|
39280
|
+
}
|
|
39281
|
+
return !endCodesInTo.has(code.endCode);
|
|
39282
|
+
})),
|
|
37622
39283
|
// Add all styles in `to` that don't exist in `from`
|
|
37623
39284
|
...to.filter((code) => !startCodesInFrom.has(code.code)),
|
|
37624
39285
|
];
|
|
@@ -37659,16 +39320,32 @@ function styledCharsToString(chars) {
|
|
|
37659
39320
|
return ret;
|
|
37660
39321
|
}
|
|
37661
39322
|
|
|
39323
|
+
const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
39324
|
+
function isFullwidthGrapheme(grapheme, baseCodePoint) {
|
|
39325
|
+
if (isFullwidthCodePoint(baseCodePoint))
|
|
39326
|
+
return true;
|
|
39327
|
+
// Variation Selector 16 forces emoji presentation (2 columns wide)
|
|
39328
|
+
if (grapheme.includes("\uFE0F"))
|
|
39329
|
+
return true;
|
|
39330
|
+
// Regional indicator pairs form flag emoji (2 columns wide)
|
|
39331
|
+
if (baseCodePoint >= 0x1f1e6 && baseCodePoint <= 0x1f1ff)
|
|
39332
|
+
return true;
|
|
39333
|
+
return false;
|
|
39334
|
+
}
|
|
37662
39335
|
// HOT PATH: Use only basic string/char code operations for maximum performance
|
|
37663
39336
|
function parseLinkCode(string, offset) {
|
|
37664
39337
|
string = string.slice(offset);
|
|
37665
|
-
for (let index = 1; index <
|
|
37666
|
-
if (string.charCodeAt(index) !==
|
|
39338
|
+
for (let index = 1; index < linkCodePrefixCharCodes.length; index++) {
|
|
39339
|
+
if (string.charCodeAt(index) !== linkCodePrefixCharCodes[index]) {
|
|
37667
39340
|
return undefined;
|
|
37668
39341
|
}
|
|
37669
39342
|
}
|
|
39343
|
+
// Find the semicolon that ends params
|
|
39344
|
+
const paramsEndIndex = string.indexOf(";", linkCodePrefix.length);
|
|
39345
|
+
if (paramsEndIndex === -1)
|
|
39346
|
+
return undefined;
|
|
37670
39347
|
// This is a link code (with or without the URL part). Find the end of it.
|
|
37671
|
-
const endIndex = string.indexOf("\x07",
|
|
39348
|
+
const endIndex = string.indexOf("\x07", paramsEndIndex + 1);
|
|
37672
39349
|
if (endIndex === -1)
|
|
37673
39350
|
return undefined;
|
|
37674
39351
|
return string.slice(0, endIndex + 1);
|
|
@@ -37743,10 +39420,13 @@ function splitCompoundSGRSequences(code) {
|
|
|
37743
39420
|
}
|
|
37744
39421
|
function tokenize(str, endChar = Number.POSITIVE_INFINITY) {
|
|
37745
39422
|
const ret = [];
|
|
37746
|
-
let index = 0;
|
|
37747
39423
|
let visible = 0;
|
|
37748
|
-
|
|
37749
|
-
|
|
39424
|
+
let codeEndIndex = 0;
|
|
39425
|
+
for (const { segment, index } of segmenter.segment(str)) {
|
|
39426
|
+
// Skip segments consumed as part of an ANSI sequence
|
|
39427
|
+
if (index < codeEndIndex)
|
|
39428
|
+
continue;
|
|
39429
|
+
const codePoint = segment.codePointAt(0);
|
|
37750
39430
|
if (ESCAPES.has(codePoint)) {
|
|
37751
39431
|
let code;
|
|
37752
39432
|
// Peek the next code point to determine the type of ANSI sequence
|
|
@@ -37778,19 +39458,17 @@ function tokenize(str, endChar = Number.POSITIVE_INFINITY) {
|
|
|
37778
39458
|
}
|
|
37779
39459
|
}
|
|
37780
39460
|
if (code) {
|
|
37781
|
-
index
|
|
39461
|
+
codeEndIndex = index + code.length;
|
|
37782
39462
|
continue;
|
|
37783
39463
|
}
|
|
37784
39464
|
}
|
|
37785
|
-
const fullWidth =
|
|
37786
|
-
const character = String.fromCodePoint(codePoint);
|
|
39465
|
+
const fullWidth = isFullwidthGrapheme(segment, codePoint);
|
|
37787
39466
|
ret.push({
|
|
37788
39467
|
type: "char",
|
|
37789
|
-
value:
|
|
39468
|
+
value: segment,
|
|
37790
39469
|
fullWidth,
|
|
37791
39470
|
});
|
|
37792
|
-
|
|
37793
|
-
visible += fullWidth ? 2 : character.length;
|
|
39471
|
+
visible += fullWidth ? 2 : 1;
|
|
37794
39472
|
if (visible >= endChar) {
|
|
37795
39473
|
break;
|
|
37796
39474
|
}
|
|
@@ -37798,10 +39476,44 @@ function tokenize(str, endChar = Number.POSITIVE_INFINITY) {
|
|
|
37798
39476
|
return ret;
|
|
37799
39477
|
}
|
|
37800
39478
|
|
|
39479
|
+
class OutputCaches {
|
|
39480
|
+
widths = new Map();
|
|
39481
|
+
blockWidths = new Map();
|
|
39482
|
+
styledChars = new Map();
|
|
39483
|
+
getStyledChars(line) {
|
|
39484
|
+
let cached = this.styledChars.get(line);
|
|
39485
|
+
if (cached === undefined) {
|
|
39486
|
+
cached = styledCharsFromTokens(tokenize(line));
|
|
39487
|
+
this.styledChars.set(line, cached);
|
|
39488
|
+
}
|
|
39489
|
+
return cached;
|
|
39490
|
+
}
|
|
39491
|
+
getStringWidth(text) {
|
|
39492
|
+
let cached = this.widths.get(text);
|
|
39493
|
+
if (cached === undefined) {
|
|
39494
|
+
cached = stringWidth(text);
|
|
39495
|
+
this.widths.set(text, cached);
|
|
39496
|
+
}
|
|
39497
|
+
return cached;
|
|
39498
|
+
}
|
|
39499
|
+
getWidestLine(text) {
|
|
39500
|
+
let cached = this.blockWidths.get(text);
|
|
39501
|
+
if (cached === undefined) {
|
|
39502
|
+
let lineWidth = 0;
|
|
39503
|
+
for (const line of text.split('\n')) {
|
|
39504
|
+
lineWidth = Math.max(lineWidth, this.getStringWidth(line));
|
|
39505
|
+
}
|
|
39506
|
+
cached = lineWidth;
|
|
39507
|
+
this.blockWidths.set(text, cached);
|
|
39508
|
+
}
|
|
39509
|
+
return cached;
|
|
39510
|
+
}
|
|
39511
|
+
}
|
|
37801
39512
|
class Output {
|
|
37802
39513
|
width;
|
|
37803
39514
|
height;
|
|
37804
39515
|
operations = [];
|
|
39516
|
+
caches = new OutputCaches();
|
|
37805
39517
|
constructor(options) {
|
|
37806
39518
|
const { width, height } = options;
|
|
37807
39519
|
this.width = width;
|
|
@@ -37865,7 +39577,7 @@ class Output {
|
|
|
37865
39577
|
// If text is positioned outside of clipping area altogether,
|
|
37866
39578
|
// skip to the next operation to avoid unnecessary calculations
|
|
37867
39579
|
if (clipHorizontally) {
|
|
37868
|
-
const width =
|
|
39580
|
+
const width = this.caches.getWidestLine(text);
|
|
37869
39581
|
if (x + width < clip.x1 || x > clip.x2) {
|
|
37870
39582
|
continue;
|
|
37871
39583
|
}
|
|
@@ -37879,7 +39591,7 @@ class Output {
|
|
|
37879
39591
|
if (clipHorizontally) {
|
|
37880
39592
|
lines = lines.map(line => {
|
|
37881
39593
|
const from = x < clip.x1 ? clip.x1 - x : 0;
|
|
37882
|
-
const width =
|
|
39594
|
+
const width = this.caches.getStringWidth(line);
|
|
37883
39595
|
const to = x + width > clip.x2 ? clip.x2 - x : width;
|
|
37884
39596
|
return sliceAnsi(line, from, to);
|
|
37885
39597
|
});
|
|
@@ -37907,12 +39619,12 @@ class Output {
|
|
|
37907
39619
|
for (const transformer of transformers) {
|
|
37908
39620
|
line = transformer(line, index);
|
|
37909
39621
|
}
|
|
37910
|
-
const characters =
|
|
39622
|
+
const characters = this.caches.getStyledChars(line);
|
|
37911
39623
|
let offsetX = x;
|
|
37912
39624
|
for (const character of characters) {
|
|
37913
39625
|
currentLine[offsetX] = character;
|
|
37914
39626
|
// Determine printed width using string-width to align with measurement
|
|
37915
|
-
const characterWidth = Math.max(1,
|
|
39627
|
+
const characterWidth = Math.max(1, this.caches.getStringWidth(character.value));
|
|
37916
39628
|
// For multi-column characters, clear following cells to avoid stray spaces/artifacts
|
|
37917
39629
|
if (characterWidth > 1) {
|
|
37918
39630
|
for (let index = 1; index < characterWidth; index++) {
|
|
@@ -38115,109 +39827,288 @@ cliCursor.toggle = (force, writableStream) => {
|
|
|
38115
39827
|
}
|
|
38116
39828
|
};
|
|
38117
39829
|
|
|
39830
|
+
const showCursorEscape = '\u001B[?25h';
|
|
39831
|
+
const hideCursorEscape = '\u001B[?25l';
|
|
39832
|
+
/**
|
|
39833
|
+
Compare two cursor positions. Returns true if they differ.
|
|
39834
|
+
*/
|
|
39835
|
+
const cursorPositionChanged = (a, b) => a?.x !== b?.x || a?.y !== b?.y;
|
|
39836
|
+
/**
|
|
39837
|
+
Build escape sequence to move cursor from bottom of output to the target position and show it.
|
|
39838
|
+
Assumes cursor is at (col 0, line visibleLineCount) — i.e. just after the last output line.
|
|
39839
|
+
*/
|
|
39840
|
+
const buildCursorSuffix = (visibleLineCount, cursorPosition) => {
|
|
39841
|
+
if (!cursorPosition) {
|
|
39842
|
+
return '';
|
|
39843
|
+
}
|
|
39844
|
+
const moveUp = visibleLineCount - cursorPosition.y;
|
|
39845
|
+
return ((moveUp > 0 ? cursorUp(moveUp) : '') +
|
|
39846
|
+
cursorTo(cursorPosition.x) +
|
|
39847
|
+
showCursorEscape);
|
|
39848
|
+
};
|
|
39849
|
+
/**
|
|
39850
|
+
Build escape sequence to move cursor from previousCursorPosition back to the bottom of output.
|
|
39851
|
+
This must be done before eraseLines or any operation that assumes cursor is at the bottom.
|
|
39852
|
+
*/
|
|
39853
|
+
const buildReturnToBottom = (previousLineCount, previousCursorPosition) => {
|
|
39854
|
+
if (!previousCursorPosition) {
|
|
39855
|
+
return '';
|
|
39856
|
+
}
|
|
39857
|
+
// PreviousLineCount includes trailing newline, so visible lines = previousLineCount - 1
|
|
39858
|
+
// cursor is at previousCursorPosition.y, need to go to line (previousLineCount - 1)
|
|
39859
|
+
const down = previousLineCount - 1 - previousCursorPosition.y;
|
|
39860
|
+
return ((down > 0 ? cursorDown(down) : '') + cursorTo(0));
|
|
39861
|
+
};
|
|
39862
|
+
/**
|
|
39863
|
+
Build the escape sequence for cursor-only updates (output unchanged, cursor moved).
|
|
39864
|
+
Hides cursor if it was previously shown, returns to bottom, then repositions.
|
|
39865
|
+
*/
|
|
39866
|
+
const buildCursorOnlySequence = (input) => {
|
|
39867
|
+
const hidePrefix = input.cursorWasShown ? hideCursorEscape : '';
|
|
39868
|
+
const returnToBottom = buildReturnToBottom(input.previousLineCount, input.previousCursorPosition);
|
|
39869
|
+
const cursorSuffix = buildCursorSuffix(input.visibleLineCount, input.cursorPosition);
|
|
39870
|
+
return hidePrefix + returnToBottom + cursorSuffix;
|
|
39871
|
+
};
|
|
39872
|
+
/**
|
|
39873
|
+
Build the prefix that hides cursor and returns to bottom before erasing or rewriting.
|
|
39874
|
+
Returns empty string if cursor was not shown.
|
|
39875
|
+
*/
|
|
39876
|
+
const buildReturnToBottomPrefix = (cursorWasShown, previousLineCount, previousCursorPosition) => {
|
|
39877
|
+
if (!cursorWasShown) {
|
|
39878
|
+
return '';
|
|
39879
|
+
}
|
|
39880
|
+
return (hideCursorEscape +
|
|
39881
|
+
buildReturnToBottom(previousLineCount, previousCursorPosition));
|
|
39882
|
+
};
|
|
39883
|
+
|
|
39884
|
+
// Count visible lines in a string, ignoring the trailing empty element
|
|
39885
|
+
// that `split('\n')` produces when the string ends with '\n'.
|
|
39886
|
+
const visibleLineCount = (lines, str) => str.endsWith('\n') ? lines.length - 1 : lines.length;
|
|
38118
39887
|
const createStandard = (stream, { showCursor = false } = {}) => {
|
|
38119
39888
|
let previousLineCount = 0;
|
|
38120
39889
|
let previousOutput = '';
|
|
38121
39890
|
let hasHiddenCursor = false;
|
|
39891
|
+
let cursorPosition;
|
|
39892
|
+
let cursorDirty = false;
|
|
39893
|
+
let previousCursorPosition;
|
|
39894
|
+
let cursorWasShown = false;
|
|
39895
|
+
const getActiveCursor = () => (cursorDirty ? cursorPosition : undefined);
|
|
39896
|
+
const hasChanges = (str, activeCursor) => {
|
|
39897
|
+
const cursorChanged = cursorPositionChanged(activeCursor, previousCursorPosition);
|
|
39898
|
+
return str !== previousOutput || cursorChanged;
|
|
39899
|
+
};
|
|
38122
39900
|
const render = (str) => {
|
|
38123
39901
|
if (!showCursor && !hasHiddenCursor) {
|
|
38124
|
-
cliCursor.hide();
|
|
39902
|
+
cliCursor.hide(stream);
|
|
38125
39903
|
hasHiddenCursor = true;
|
|
38126
39904
|
}
|
|
38127
|
-
|
|
38128
|
-
|
|
38129
|
-
|
|
39905
|
+
// Only use cursor if setCursorPosition was called since last render.
|
|
39906
|
+
// This ensures stale positions don't persist after component unmount.
|
|
39907
|
+
const activeCursor = getActiveCursor();
|
|
39908
|
+
cursorDirty = false;
|
|
39909
|
+
const cursorChanged = cursorPositionChanged(activeCursor, previousCursorPosition);
|
|
39910
|
+
if (!hasChanges(str, activeCursor)) {
|
|
39911
|
+
return false;
|
|
39912
|
+
}
|
|
39913
|
+
const lines = str.split('\n');
|
|
39914
|
+
const visibleCount = visibleLineCount(lines, str);
|
|
39915
|
+
const cursorSuffix = buildCursorSuffix(visibleCount, activeCursor);
|
|
39916
|
+
if (str === previousOutput && cursorChanged) {
|
|
39917
|
+
stream.write(buildCursorOnlySequence({
|
|
39918
|
+
cursorWasShown,
|
|
39919
|
+
previousLineCount,
|
|
39920
|
+
previousCursorPosition,
|
|
39921
|
+
visibleLineCount: visibleCount,
|
|
39922
|
+
cursorPosition: activeCursor,
|
|
39923
|
+
}));
|
|
38130
39924
|
}
|
|
38131
|
-
|
|
38132
|
-
|
|
38133
|
-
|
|
39925
|
+
else {
|
|
39926
|
+
previousOutput = str;
|
|
39927
|
+
const returnPrefix = buildReturnToBottomPrefix(cursorWasShown, previousLineCount, previousCursorPosition);
|
|
39928
|
+
stream.write(returnPrefix +
|
|
39929
|
+
eraseLines(previousLineCount) +
|
|
39930
|
+
str +
|
|
39931
|
+
cursorSuffix);
|
|
39932
|
+
previousLineCount = lines.length;
|
|
39933
|
+
}
|
|
39934
|
+
previousCursorPosition = activeCursor ? { ...activeCursor } : undefined;
|
|
39935
|
+
cursorWasShown = activeCursor !== undefined;
|
|
39936
|
+
return true;
|
|
38134
39937
|
};
|
|
38135
39938
|
render.clear = () => {
|
|
38136
|
-
|
|
39939
|
+
const prefix = buildReturnToBottomPrefix(cursorWasShown, previousLineCount, previousCursorPosition);
|
|
39940
|
+
stream.write(prefix + eraseLines(previousLineCount));
|
|
38137
39941
|
previousOutput = '';
|
|
38138
39942
|
previousLineCount = 0;
|
|
39943
|
+
previousCursorPosition = undefined;
|
|
39944
|
+
cursorWasShown = false;
|
|
38139
39945
|
};
|
|
38140
39946
|
render.done = () => {
|
|
38141
39947
|
previousOutput = '';
|
|
38142
39948
|
previousLineCount = 0;
|
|
39949
|
+
previousCursorPosition = undefined;
|
|
39950
|
+
cursorWasShown = false;
|
|
38143
39951
|
if (!showCursor) {
|
|
38144
|
-
cliCursor.show();
|
|
39952
|
+
cliCursor.show(stream);
|
|
38145
39953
|
hasHiddenCursor = false;
|
|
38146
39954
|
}
|
|
38147
39955
|
};
|
|
38148
39956
|
render.sync = (str) => {
|
|
38149
|
-
const
|
|
38150
|
-
|
|
38151
|
-
|
|
39957
|
+
const activeCursor = cursorDirty ? cursorPosition : undefined;
|
|
39958
|
+
cursorDirty = false;
|
|
39959
|
+
const lines = str.split('\n');
|
|
39960
|
+
previousOutput = str;
|
|
39961
|
+
previousLineCount = lines.length;
|
|
39962
|
+
if (!activeCursor && cursorWasShown) {
|
|
39963
|
+
stream.write(hideCursorEscape);
|
|
39964
|
+
}
|
|
39965
|
+
if (activeCursor) {
|
|
39966
|
+
stream.write(buildCursorSuffix(visibleLineCount(lines, str), activeCursor));
|
|
39967
|
+
}
|
|
39968
|
+
previousCursorPosition = activeCursor ? { ...activeCursor } : undefined;
|
|
39969
|
+
cursorWasShown = activeCursor !== undefined;
|
|
38152
39970
|
};
|
|
39971
|
+
render.setCursorPosition = (position) => {
|
|
39972
|
+
cursorPosition = position;
|
|
39973
|
+
cursorDirty = true;
|
|
39974
|
+
};
|
|
39975
|
+
render.isCursorDirty = () => cursorDirty;
|
|
39976
|
+
render.willRender = (str) => hasChanges(str, getActiveCursor());
|
|
38153
39977
|
return render;
|
|
38154
39978
|
};
|
|
38155
39979
|
const createIncremental = (stream, { showCursor = false } = {}) => {
|
|
38156
39980
|
let previousLines = [];
|
|
38157
39981
|
let previousOutput = '';
|
|
38158
39982
|
let hasHiddenCursor = false;
|
|
39983
|
+
let cursorPosition;
|
|
39984
|
+
let cursorDirty = false;
|
|
39985
|
+
let previousCursorPosition;
|
|
39986
|
+
let cursorWasShown = false;
|
|
39987
|
+
const getActiveCursor = () => (cursorDirty ? cursorPosition : undefined);
|
|
39988
|
+
const hasChanges = (str, activeCursor) => {
|
|
39989
|
+
const cursorChanged = cursorPositionChanged(activeCursor, previousCursorPosition);
|
|
39990
|
+
return str !== previousOutput || cursorChanged;
|
|
39991
|
+
};
|
|
38159
39992
|
const render = (str) => {
|
|
38160
39993
|
if (!showCursor && !hasHiddenCursor) {
|
|
38161
|
-
cliCursor.hide();
|
|
39994
|
+
cliCursor.hide(stream);
|
|
38162
39995
|
hasHiddenCursor = true;
|
|
38163
39996
|
}
|
|
38164
|
-
|
|
38165
|
-
|
|
38166
|
-
|
|
39997
|
+
// Only use cursor if setCursorPosition was called since last render.
|
|
39998
|
+
// This ensures stale positions don't persist after component unmount.
|
|
39999
|
+
const activeCursor = getActiveCursor();
|
|
40000
|
+
cursorDirty = false;
|
|
40001
|
+
const cursorChanged = cursorPositionChanged(activeCursor, previousCursorPosition);
|
|
40002
|
+
if (!hasChanges(str, activeCursor)) {
|
|
40003
|
+
return false;
|
|
38167
40004
|
}
|
|
38168
|
-
const
|
|
38169
|
-
const
|
|
38170
|
-
const
|
|
38171
|
-
|
|
38172
|
-
|
|
38173
|
-
|
|
38174
|
-
|
|
40005
|
+
const nextLines = str.split('\n');
|
|
40006
|
+
const visibleCount = visibleLineCount(nextLines, str);
|
|
40007
|
+
const previousVisible = visibleLineCount(previousLines, previousOutput);
|
|
40008
|
+
if (str === previousOutput && cursorChanged) {
|
|
40009
|
+
stream.write(buildCursorOnlySequence({
|
|
40010
|
+
cursorWasShown,
|
|
40011
|
+
previousLineCount: previousLines.length,
|
|
40012
|
+
previousCursorPosition,
|
|
40013
|
+
visibleLineCount: visibleCount,
|
|
40014
|
+
cursorPosition: activeCursor,
|
|
40015
|
+
}));
|
|
40016
|
+
previousCursorPosition = activeCursor ? { ...activeCursor } : undefined;
|
|
40017
|
+
cursorWasShown = activeCursor !== undefined;
|
|
40018
|
+
return true;
|
|
40019
|
+
}
|
|
40020
|
+
const returnPrefix = buildReturnToBottomPrefix(cursorWasShown, previousLines.length, previousCursorPosition);
|
|
40021
|
+
if (str === '\n' || previousOutput.length === 0) {
|
|
40022
|
+
const cursorSuffix = buildCursorSuffix(visibleCount, activeCursor);
|
|
40023
|
+
stream.write(returnPrefix +
|
|
40024
|
+
eraseLines(previousLines.length) +
|
|
40025
|
+
str +
|
|
40026
|
+
cursorSuffix);
|
|
40027
|
+
cursorWasShown = activeCursor !== undefined;
|
|
40028
|
+
previousCursorPosition = activeCursor ? { ...activeCursor } : undefined;
|
|
40029
|
+
previousOutput = str;
|
|
38175
40030
|
previousLines = nextLines;
|
|
38176
|
-
return;
|
|
40031
|
+
return true;
|
|
38177
40032
|
}
|
|
40033
|
+
const hasTrailingNewline = str.endsWith('\n');
|
|
38178
40034
|
// We aggregate all chunks for incremental rendering into a buffer, and then write them to stdout at the end.
|
|
38179
40035
|
const buffer = [];
|
|
40036
|
+
buffer.push(returnPrefix);
|
|
38180
40037
|
// Clear extra lines if the current content's line count is lower than the previous.
|
|
38181
|
-
if (
|
|
38182
|
-
|
|
38183
|
-
|
|
38184
|
-
eraseLines(
|
|
38185
|
-
// Positions cursor to the top of the rendered output.
|
|
38186
|
-
cursorUp(visibleCount));
|
|
40038
|
+
if (visibleCount < previousVisible) {
|
|
40039
|
+
const previousHadTrailingNewline = previousOutput.endsWith('\n');
|
|
40040
|
+
const extraSlot = previousHadTrailingNewline ? 1 : 0;
|
|
40041
|
+
buffer.push(eraseLines(previousVisible - visibleCount + extraSlot), cursorUp(visibleCount));
|
|
38187
40042
|
}
|
|
38188
40043
|
else {
|
|
38189
|
-
buffer.push(cursorUp(
|
|
40044
|
+
buffer.push(cursorUp(previousVisible - 1));
|
|
38190
40045
|
}
|
|
38191
40046
|
for (let i = 0; i < visibleCount; i++) {
|
|
40047
|
+
const isLastLine = i === visibleCount - 1;
|
|
38192
40048
|
// We do not write lines if the contents are the same. This prevents flickering during renders.
|
|
38193
40049
|
if (nextLines[i] === previousLines[i]) {
|
|
38194
|
-
|
|
40050
|
+
// Don't move past the last line when there's no trailing newline,
|
|
40051
|
+
// otherwise the cursor overshoots the rendered block.
|
|
40052
|
+
if (!isLastLine || hasTrailingNewline) {
|
|
40053
|
+
buffer.push(cursorNextLine);
|
|
40054
|
+
}
|
|
38195
40055
|
continue;
|
|
38196
40056
|
}
|
|
38197
|
-
buffer.push(
|
|
40057
|
+
buffer.push(cursorTo(0) +
|
|
40058
|
+
nextLines[i] +
|
|
40059
|
+
eraseEndLine +
|
|
40060
|
+
// Don't append newline after the last line when the input
|
|
40061
|
+
// has no trailing newline (fullscreen mode).
|
|
40062
|
+
(isLastLine && !hasTrailingNewline ? '' : '\n'));
|
|
38198
40063
|
}
|
|
40064
|
+
const cursorSuffix = buildCursorSuffix(visibleCount, activeCursor);
|
|
40065
|
+
buffer.push(cursorSuffix);
|
|
38199
40066
|
stream.write(buffer.join(''));
|
|
38200
|
-
|
|
40067
|
+
cursorWasShown = activeCursor !== undefined;
|
|
40068
|
+
previousCursorPosition = activeCursor ? { ...activeCursor } : undefined;
|
|
40069
|
+
previousOutput = str;
|
|
38201
40070
|
previousLines = nextLines;
|
|
40071
|
+
return true;
|
|
38202
40072
|
};
|
|
38203
40073
|
render.clear = () => {
|
|
38204
|
-
|
|
40074
|
+
const prefix = buildReturnToBottomPrefix(cursorWasShown, previousLines.length, previousCursorPosition);
|
|
40075
|
+
stream.write(prefix + eraseLines(previousLines.length));
|
|
38205
40076
|
previousOutput = '';
|
|
38206
40077
|
previousLines = [];
|
|
40078
|
+
previousCursorPosition = undefined;
|
|
40079
|
+
cursorWasShown = false;
|
|
38207
40080
|
};
|
|
38208
40081
|
render.done = () => {
|
|
38209
40082
|
previousOutput = '';
|
|
38210
40083
|
previousLines = [];
|
|
40084
|
+
previousCursorPosition = undefined;
|
|
40085
|
+
cursorWasShown = false;
|
|
38211
40086
|
if (!showCursor) {
|
|
38212
|
-
cliCursor.show();
|
|
40087
|
+
cliCursor.show(stream);
|
|
38213
40088
|
hasHiddenCursor = false;
|
|
38214
40089
|
}
|
|
38215
40090
|
};
|
|
38216
40091
|
render.sync = (str) => {
|
|
38217
|
-
const
|
|
38218
|
-
|
|
38219
|
-
|
|
40092
|
+
const activeCursor = cursorDirty ? cursorPosition : undefined;
|
|
40093
|
+
cursorDirty = false;
|
|
40094
|
+
const lines = str.split('\n');
|
|
40095
|
+
previousOutput = str;
|
|
40096
|
+
previousLines = lines;
|
|
40097
|
+
if (!activeCursor && cursorWasShown) {
|
|
40098
|
+
stream.write(hideCursorEscape);
|
|
40099
|
+
}
|
|
40100
|
+
if (activeCursor) {
|
|
40101
|
+
stream.write(buildCursorSuffix(visibleLineCount(lines, str), activeCursor));
|
|
40102
|
+
}
|
|
40103
|
+
previousCursorPosition = activeCursor ? { ...activeCursor } : undefined;
|
|
40104
|
+
cursorWasShown = activeCursor !== undefined;
|
|
40105
|
+
};
|
|
40106
|
+
render.setCursorPosition = (position) => {
|
|
40107
|
+
cursorPosition = position;
|
|
40108
|
+
cursorDirty = true;
|
|
38220
40109
|
};
|
|
40110
|
+
render.isCursorDirty = () => cursorDirty;
|
|
40111
|
+
render.willRender = (str) => hasChanges(str, getActiveCursor());
|
|
38221
40112
|
return render;
|
|
38222
40113
|
};
|
|
38223
40114
|
const create = (stream, { showCursor = false, incremental = false } = {}) => {
|
|
@@ -38228,6 +40119,12 @@ const create = (stream, { showCursor = false, incremental = false } = {}) => {
|
|
|
38228
40119
|
};
|
|
38229
40120
|
const logUpdate = { create };
|
|
38230
40121
|
|
|
40122
|
+
const bsu = '\u001B[?2026h';
|
|
40123
|
+
const esu = '\u001B[?2026l';
|
|
40124
|
+
function shouldSynchronize(stream) {
|
|
40125
|
+
return 'isTTY' in stream && stream.isTTY === true && !isInCi;
|
|
40126
|
+
}
|
|
40127
|
+
|
|
38231
40128
|
// Store all instances of Ink (instance.js) to ensure that consecutive render() calls
|
|
38232
40129
|
// use the same instance of Ink and don't create a new one
|
|
38233
40130
|
//
|
|
@@ -38235,6 +40132,160 @@ const logUpdate = { create };
|
|
|
38235
40132
|
// but instance.js should delete itself from the map on unmount
|
|
38236
40133
|
const instances = new WeakMap();
|
|
38237
40134
|
|
|
40135
|
+
const escape$1 = '\u001B';
|
|
40136
|
+
const isCsiParameterByte = (byte) => {
|
|
40137
|
+
return byte >= 0x30 && byte <= 0x3f;
|
|
40138
|
+
};
|
|
40139
|
+
const isCsiIntermediateByte = (byte) => {
|
|
40140
|
+
return byte >= 0x20 && byte <= 0x2f;
|
|
40141
|
+
};
|
|
40142
|
+
const isCsiFinalByte = (byte) => {
|
|
40143
|
+
return byte >= 0x40 && byte <= 0x7e;
|
|
40144
|
+
};
|
|
40145
|
+
const parseCsiSequence = (input, startIndex, prefixLength) => {
|
|
40146
|
+
const csiPayloadStart = startIndex + prefixLength + 1;
|
|
40147
|
+
let index = csiPayloadStart;
|
|
40148
|
+
for (; index < input.length; index++) {
|
|
40149
|
+
const byte = input.codePointAt(index);
|
|
40150
|
+
if (byte === undefined) {
|
|
40151
|
+
return 'pending';
|
|
40152
|
+
}
|
|
40153
|
+
if (isCsiParameterByte(byte) || isCsiIntermediateByte(byte)) {
|
|
40154
|
+
continue;
|
|
40155
|
+
}
|
|
40156
|
+
// Preserve legacy terminal function-key sequences like ESC[[A and ESC[[5~.
|
|
40157
|
+
if (byte === 0x5b && index === csiPayloadStart) {
|
|
40158
|
+
continue;
|
|
40159
|
+
}
|
|
40160
|
+
if (isCsiFinalByte(byte)) {
|
|
40161
|
+
return {
|
|
40162
|
+
sequence: input.slice(startIndex, index + 1),
|
|
40163
|
+
nextIndex: index + 1,
|
|
40164
|
+
};
|
|
40165
|
+
}
|
|
40166
|
+
return undefined;
|
|
40167
|
+
}
|
|
40168
|
+
return 'pending';
|
|
40169
|
+
};
|
|
40170
|
+
const parseSs3Sequence = (input, startIndex, prefixLength) => {
|
|
40171
|
+
const nextIndex = startIndex + prefixLength + 2;
|
|
40172
|
+
if (nextIndex > input.length) {
|
|
40173
|
+
return 'pending';
|
|
40174
|
+
}
|
|
40175
|
+
const finalByte = input.codePointAt(nextIndex - 1);
|
|
40176
|
+
if (finalByte === undefined || !isCsiFinalByte(finalByte)) {
|
|
40177
|
+
return undefined;
|
|
40178
|
+
}
|
|
40179
|
+
return {
|
|
40180
|
+
sequence: input.slice(startIndex, nextIndex),
|
|
40181
|
+
nextIndex,
|
|
40182
|
+
};
|
|
40183
|
+
};
|
|
40184
|
+
const parseControlSequence = (input, startIndex, prefixLength) => {
|
|
40185
|
+
const sequenceType = input[startIndex + prefixLength];
|
|
40186
|
+
if (sequenceType === undefined) {
|
|
40187
|
+
return 'pending';
|
|
40188
|
+
}
|
|
40189
|
+
if (sequenceType === '[') {
|
|
40190
|
+
return parseCsiSequence(input, startIndex, prefixLength);
|
|
40191
|
+
}
|
|
40192
|
+
if (sequenceType === 'O') {
|
|
40193
|
+
return parseSs3Sequence(input, startIndex, prefixLength);
|
|
40194
|
+
}
|
|
40195
|
+
return undefined;
|
|
40196
|
+
};
|
|
40197
|
+
const parseEscapedCodePoint = (input, escapeIndex) => {
|
|
40198
|
+
const nextCodePoint = input.codePointAt(escapeIndex + 1);
|
|
40199
|
+
const nextCodePointLength = nextCodePoint !== undefined && nextCodePoint > 0xff_ff ? 2 : 1;
|
|
40200
|
+
const nextIndex = escapeIndex + 1 + nextCodePointLength;
|
|
40201
|
+
return {
|
|
40202
|
+
sequence: input.slice(escapeIndex, nextIndex),
|
|
40203
|
+
nextIndex,
|
|
40204
|
+
};
|
|
40205
|
+
};
|
|
40206
|
+
const parseKeypresses = (input) => {
|
|
40207
|
+
const events = [];
|
|
40208
|
+
let index = 0;
|
|
40209
|
+
const pendingFrom = (pendingStartIndex) => ({
|
|
40210
|
+
events,
|
|
40211
|
+
pending: input.slice(pendingStartIndex),
|
|
40212
|
+
});
|
|
40213
|
+
while (index < input.length) {
|
|
40214
|
+
const escapeIndex = input.indexOf(escape$1, index);
|
|
40215
|
+
if (escapeIndex === -1) {
|
|
40216
|
+
events.push(input.slice(index));
|
|
40217
|
+
return {
|
|
40218
|
+
events,
|
|
40219
|
+
pending: '',
|
|
40220
|
+
};
|
|
40221
|
+
}
|
|
40222
|
+
if (escapeIndex > index) {
|
|
40223
|
+
events.push(input.slice(index, escapeIndex));
|
|
40224
|
+
}
|
|
40225
|
+
if (escapeIndex === input.length - 1) {
|
|
40226
|
+
return pendingFrom(escapeIndex);
|
|
40227
|
+
}
|
|
40228
|
+
const parsedSequence = parseControlSequence(input, escapeIndex, 1);
|
|
40229
|
+
if (parsedSequence === 'pending') {
|
|
40230
|
+
return pendingFrom(escapeIndex);
|
|
40231
|
+
}
|
|
40232
|
+
if (parsedSequence) {
|
|
40233
|
+
events.push(parsedSequence.sequence);
|
|
40234
|
+
index = parsedSequence.nextIndex;
|
|
40235
|
+
continue;
|
|
40236
|
+
}
|
|
40237
|
+
const next = input[escapeIndex + 1];
|
|
40238
|
+
if (next === escape$1) {
|
|
40239
|
+
if (escapeIndex + 2 >= input.length) {
|
|
40240
|
+
return pendingFrom(escapeIndex);
|
|
40241
|
+
}
|
|
40242
|
+
const doubleEscapeSequence = parseControlSequence(input, escapeIndex, 2);
|
|
40243
|
+
if (doubleEscapeSequence === 'pending') {
|
|
40244
|
+
return pendingFrom(escapeIndex);
|
|
40245
|
+
}
|
|
40246
|
+
if (doubleEscapeSequence) {
|
|
40247
|
+
events.push(doubleEscapeSequence.sequence);
|
|
40248
|
+
index = doubleEscapeSequence.nextIndex;
|
|
40249
|
+
continue;
|
|
40250
|
+
}
|
|
40251
|
+
events.push(input.slice(escapeIndex, escapeIndex + 2));
|
|
40252
|
+
index = escapeIndex + 2;
|
|
40253
|
+
continue;
|
|
40254
|
+
}
|
|
40255
|
+
const escapedCodePoint = parseEscapedCodePoint(input, escapeIndex);
|
|
40256
|
+
events.push(escapedCodePoint.sequence);
|
|
40257
|
+
index = escapedCodePoint.nextIndex;
|
|
40258
|
+
}
|
|
40259
|
+
return {
|
|
40260
|
+
events,
|
|
40261
|
+
pending: '',
|
|
40262
|
+
};
|
|
40263
|
+
};
|
|
40264
|
+
const createInputParser = () => {
|
|
40265
|
+
let pending = '';
|
|
40266
|
+
return {
|
|
40267
|
+
push(chunk) {
|
|
40268
|
+
const parsedInput = parseKeypresses(pending + chunk);
|
|
40269
|
+
pending = parsedInput.pending;
|
|
40270
|
+
return parsedInput.events;
|
|
40271
|
+
},
|
|
40272
|
+
hasPendingEscape() {
|
|
40273
|
+
return pending.startsWith(escape$1);
|
|
40274
|
+
},
|
|
40275
|
+
flushPendingEscape() {
|
|
40276
|
+
if (!pending.startsWith(escape$1)) {
|
|
40277
|
+
return undefined;
|
|
40278
|
+
}
|
|
40279
|
+
const pendingEscape = pending;
|
|
40280
|
+
pending = '';
|
|
40281
|
+
return pendingEscape;
|
|
40282
|
+
},
|
|
40283
|
+
reset() {
|
|
40284
|
+
pending = '';
|
|
40285
|
+
},
|
|
40286
|
+
};
|
|
40287
|
+
};
|
|
40288
|
+
|
|
38238
40289
|
/**
|
|
38239
40290
|
`AppContext` is a React context that exposes a method to manually exit the app (unmount).
|
|
38240
40291
|
*/
|
|
@@ -38294,6 +40345,12 @@ const FocusContext = reactExports.createContext({
|
|
|
38294
40345
|
});
|
|
38295
40346
|
FocusContext.displayName = 'InternalFocusContext';
|
|
38296
40347
|
|
|
40348
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
40349
|
+
const CursorContext = reactExports.createContext({
|
|
40350
|
+
setCursorPosition() { },
|
|
40351
|
+
});
|
|
40352
|
+
CursorContext.displayName = 'InternalCursorContext';
|
|
40353
|
+
|
|
38297
40354
|
var escapeStringRegexp;
|
|
38298
40355
|
var hasRequiredEscapeStringRegexp;
|
|
38299
40356
|
|
|
@@ -38856,102 +40913,130 @@ function ErrorOverview({ error }) {
|
|
|
38856
40913
|
})))));
|
|
38857
40914
|
}
|
|
38858
40915
|
|
|
38859
|
-
|
|
38860
|
-
|
|
38861
|
-
|
|
38862
|
-
|
|
38863
|
-
// It renders stdin and stdout contexts, so that children can access them if needed
|
|
38864
|
-
// It also handles Ctrl+C exiting and cursor visibility
|
|
38865
|
-
class App extends reactExports.PureComponent {
|
|
38866
|
-
static displayName = 'InternalApp';
|
|
40916
|
+
// Error boundary must be a class component since getDerivedStateFromError
|
|
40917
|
+
// and componentDidCatch are not available as hooks
|
|
40918
|
+
class ErrorBoundary extends reactExports.PureComponent {
|
|
40919
|
+
static displayName = 'InternalErrorBoundary';
|
|
38867
40920
|
static getDerivedStateFromError(error) {
|
|
38868
40921
|
return { error };
|
|
38869
40922
|
}
|
|
38870
40923
|
state = {
|
|
38871
|
-
isFocusEnabled: true,
|
|
38872
|
-
activeFocusId: undefined,
|
|
38873
|
-
focusables: [],
|
|
38874
40924
|
error: undefined,
|
|
38875
40925
|
};
|
|
40926
|
+
componentDidCatch(error) {
|
|
40927
|
+
this.props.onError(error);
|
|
40928
|
+
}
|
|
40929
|
+
render() {
|
|
40930
|
+
if (this.state.error) {
|
|
40931
|
+
return React.createElement(ErrorOverview, { error: this.state.error });
|
|
40932
|
+
}
|
|
40933
|
+
return this.props.children;
|
|
40934
|
+
}
|
|
40935
|
+
}
|
|
40936
|
+
|
|
40937
|
+
const tab = '\t';
|
|
40938
|
+
const shiftTab = '\u001B[Z';
|
|
40939
|
+
const escape = '\u001B';
|
|
40940
|
+
// Root component for all Ink apps
|
|
40941
|
+
// It renders stdin and stdout contexts, so that children can access them if needed
|
|
40942
|
+
// It also handles Ctrl+C exiting and cursor visibility
|
|
40943
|
+
function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, exitOnCtrlC, onExit, setCursorPosition, }) {
|
|
40944
|
+
const [isFocusEnabled, setIsFocusEnabled] = reactExports.useState(true);
|
|
40945
|
+
const [activeFocusId, setActiveFocusId] = reactExports.useState(undefined);
|
|
40946
|
+
// Focusables array is managed internally via setFocusables callback pattern
|
|
40947
|
+
// eslint-disable-next-line react/hook-use-state
|
|
40948
|
+
const [, setFocusables] = reactExports.useState([]);
|
|
40949
|
+
// Track focusables count for tab navigation check (avoids stale closure)
|
|
40950
|
+
const focusablesCountRef = reactExports.useRef(0);
|
|
38876
40951
|
// Count how many components enabled raw mode to avoid disabling
|
|
38877
40952
|
// raw mode until all components don't need it anymore
|
|
38878
|
-
rawModeEnabledCount = 0;
|
|
40953
|
+
const rawModeEnabledCount = reactExports.useRef(0);
|
|
38879
40954
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
38880
|
-
internal_eventEmitter = new EventEmitter();
|
|
40955
|
+
const internal_eventEmitter = reactExports.useRef(new EventEmitter());
|
|
40956
|
+
// Each useInput hook adds a listener, so the count can legitimately exceed the default limit of 10.
|
|
40957
|
+
internal_eventEmitter.current.setMaxListeners(Infinity);
|
|
40958
|
+
// Store the currently attached readable listener to avoid stale closure issues
|
|
40959
|
+
const readableListenerRef = reactExports.useRef(undefined);
|
|
40960
|
+
const inputParserRef = reactExports.useRef(createInputParser());
|
|
40961
|
+
const pendingInputFlushRef = reactExports.useRef(undefined);
|
|
40962
|
+
const clearPendingInputFlush = reactExports.useCallback(() => {
|
|
40963
|
+
if (!pendingInputFlushRef.current) {
|
|
40964
|
+
return;
|
|
40965
|
+
}
|
|
40966
|
+
clearImmediate(pendingInputFlushRef.current);
|
|
40967
|
+
pendingInputFlushRef.current = undefined;
|
|
40968
|
+
}, []);
|
|
38881
40969
|
// Determines if TTY is supported on the provided stdin
|
|
38882
|
-
isRawModeSupported
|
|
38883
|
-
|
|
38884
|
-
|
|
38885
|
-
|
|
38886
|
-
return (React.createElement(AppContext.Provider
|
|
38887
|
-
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
38888
|
-
, {
|
|
38889
|
-
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
38890
|
-
value: {
|
|
38891
|
-
exit: this.handleExit,
|
|
38892
|
-
} },
|
|
38893
|
-
React.createElement(StdinContext.Provider
|
|
38894
|
-
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
38895
|
-
, {
|
|
38896
|
-
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
38897
|
-
value: {
|
|
38898
|
-
stdin: this.props.stdin,
|
|
38899
|
-
setRawMode: this.handleSetRawMode,
|
|
38900
|
-
isRawModeSupported: this.isRawModeSupported(),
|
|
38901
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
38902
|
-
internal_exitOnCtrlC: this.props.exitOnCtrlC,
|
|
38903
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
38904
|
-
internal_eventEmitter: this.internal_eventEmitter,
|
|
38905
|
-
} },
|
|
38906
|
-
React.createElement(StdoutContext.Provider
|
|
38907
|
-
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
38908
|
-
, {
|
|
38909
|
-
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
38910
|
-
value: {
|
|
38911
|
-
stdout: this.props.stdout,
|
|
38912
|
-
write: this.props.writeToStdout,
|
|
38913
|
-
} },
|
|
38914
|
-
React.createElement(StderrContext.Provider
|
|
38915
|
-
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
38916
|
-
, {
|
|
38917
|
-
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
38918
|
-
value: {
|
|
38919
|
-
stderr: this.props.stderr,
|
|
38920
|
-
write: this.props.writeToStderr,
|
|
38921
|
-
} },
|
|
38922
|
-
React.createElement(FocusContext.Provider
|
|
38923
|
-
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
38924
|
-
, {
|
|
38925
|
-
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
38926
|
-
value: {
|
|
38927
|
-
activeId: this.state.activeFocusId,
|
|
38928
|
-
add: this.addFocusable,
|
|
38929
|
-
remove: this.removeFocusable,
|
|
38930
|
-
activate: this.activateFocusable,
|
|
38931
|
-
deactivate: this.deactivateFocusable,
|
|
38932
|
-
enableFocus: this.enableFocus,
|
|
38933
|
-
disableFocus: this.disableFocus,
|
|
38934
|
-
focusNext: this.focusNext,
|
|
38935
|
-
focusPrevious: this.focusPrevious,
|
|
38936
|
-
focus: this.focus,
|
|
38937
|
-
} }, this.state.error ? (React.createElement(ErrorOverview, { error: this.state.error })) : (this.props.children)))))));
|
|
38938
|
-
}
|
|
38939
|
-
componentDidMount() {
|
|
38940
|
-
cliCursor.hide(this.props.stdout);
|
|
38941
|
-
}
|
|
38942
|
-
componentWillUnmount() {
|
|
38943
|
-
cliCursor.show(this.props.stdout);
|
|
38944
|
-
// ignore calling setRawMode on an handle stdin it cannot be called
|
|
38945
|
-
if (this.isRawModeSupported()) {
|
|
38946
|
-
this.handleSetRawMode(false);
|
|
40970
|
+
const isRawModeSupported = stdin.isTTY;
|
|
40971
|
+
const detachReadableListener = reactExports.useCallback(() => {
|
|
40972
|
+
if (!readableListenerRef.current) {
|
|
40973
|
+
return;
|
|
38947
40974
|
}
|
|
38948
|
-
|
|
38949
|
-
|
|
38950
|
-
|
|
38951
|
-
|
|
38952
|
-
|
|
38953
|
-
|
|
38954
|
-
|
|
40975
|
+
stdin.removeListener('readable', readableListenerRef.current);
|
|
40976
|
+
readableListenerRef.current = undefined;
|
|
40977
|
+
}, [stdin]);
|
|
40978
|
+
const disableRawMode = reactExports.useCallback(() => {
|
|
40979
|
+
stdin.setRawMode(false);
|
|
40980
|
+
detachReadableListener();
|
|
40981
|
+
stdin.unref();
|
|
40982
|
+
rawModeEnabledCount.current = 0;
|
|
40983
|
+
inputParserRef.current.reset();
|
|
40984
|
+
clearPendingInputFlush();
|
|
40985
|
+
}, [stdin, detachReadableListener, clearPendingInputFlush]);
|
|
40986
|
+
const handleExit = reactExports.useCallback((errorOrResult) => {
|
|
40987
|
+
if (isRawModeSupported && rawModeEnabledCount.current > 0) {
|
|
40988
|
+
disableRawMode();
|
|
40989
|
+
}
|
|
40990
|
+
onExit(errorOrResult);
|
|
40991
|
+
}, [isRawModeSupported, disableRawMode, onExit]);
|
|
40992
|
+
const handleInput = reactExports.useCallback((input) => {
|
|
40993
|
+
// Exit on Ctrl+C
|
|
40994
|
+
// eslint-disable-next-line unicorn/no-hex-escape
|
|
40995
|
+
if (input === '\x03' && exitOnCtrlC) {
|
|
40996
|
+
handleExit();
|
|
40997
|
+
return;
|
|
40998
|
+
}
|
|
40999
|
+
// Reset focus when there's an active focused component on Esc
|
|
41000
|
+
if (input === escape) {
|
|
41001
|
+
setActiveFocusId(currentActiveFocusId => {
|
|
41002
|
+
if (currentActiveFocusId) {
|
|
41003
|
+
return undefined;
|
|
41004
|
+
}
|
|
41005
|
+
return currentActiveFocusId;
|
|
41006
|
+
});
|
|
41007
|
+
}
|
|
41008
|
+
}, [exitOnCtrlC, handleExit]);
|
|
41009
|
+
const emitInput = reactExports.useCallback((input) => {
|
|
41010
|
+
handleInput(input);
|
|
41011
|
+
internal_eventEmitter.current.emit('input', input);
|
|
41012
|
+
}, [handleInput]);
|
|
41013
|
+
const schedulePendingInputFlush = reactExports.useCallback(() => {
|
|
41014
|
+
clearPendingInputFlush();
|
|
41015
|
+
pendingInputFlushRef.current = setImmediate(() => {
|
|
41016
|
+
pendingInputFlushRef.current = undefined;
|
|
41017
|
+
const pendingEscape = inputParserRef.current.flushPendingEscape();
|
|
41018
|
+
if (!pendingEscape) {
|
|
41019
|
+
return;
|
|
41020
|
+
}
|
|
41021
|
+
emitInput(pendingEscape);
|
|
41022
|
+
});
|
|
41023
|
+
}, [clearPendingInputFlush, emitInput]);
|
|
41024
|
+
const handleReadable = reactExports.useCallback(() => {
|
|
41025
|
+
clearPendingInputFlush();
|
|
41026
|
+
let chunk;
|
|
41027
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
41028
|
+
while ((chunk = stdin.read()) !== null) {
|
|
41029
|
+
const inputEvents = inputParserRef.current.push(chunk);
|
|
41030
|
+
for (const input of inputEvents) {
|
|
41031
|
+
emitInput(input);
|
|
41032
|
+
}
|
|
41033
|
+
}
|
|
41034
|
+
if (inputParserRef.current.hasPendingEscape()) {
|
|
41035
|
+
schedulePendingInputFlush();
|
|
41036
|
+
}
|
|
41037
|
+
}, [stdin, emitInput, clearPendingInputFlush, schedulePendingInputFlush]);
|
|
41038
|
+
const handleSetRawMode = reactExports.useCallback((isEnabled) => {
|
|
41039
|
+
if (!isRawModeSupported) {
|
|
38955
41040
|
if (stdin === process$1.stdin) {
|
|
38956
41041
|
throw new Error('Raw mode is not supported on the current process.stdin, which Ink uses as input stream by default.\nRead about how to prevent this error on https://github.com/vadimdemedes/ink/#israwmodesupported');
|
|
38957
41042
|
}
|
|
@@ -38962,185 +41047,338 @@ class App extends reactExports.PureComponent {
|
|
|
38962
41047
|
stdin.setEncoding('utf8');
|
|
38963
41048
|
if (isEnabled) {
|
|
38964
41049
|
// Ensure raw mode is enabled only once
|
|
38965
|
-
if (
|
|
41050
|
+
if (rawModeEnabledCount.current === 0) {
|
|
38966
41051
|
stdin.ref();
|
|
38967
41052
|
stdin.setRawMode(true);
|
|
38968
|
-
|
|
41053
|
+
// Store the listener reference to avoid stale closure when removing
|
|
41054
|
+
readableListenerRef.current = handleReadable;
|
|
41055
|
+
stdin.addListener('readable', handleReadable);
|
|
38969
41056
|
}
|
|
38970
|
-
|
|
41057
|
+
rawModeEnabledCount.current++;
|
|
38971
41058
|
return;
|
|
38972
41059
|
}
|
|
38973
41060
|
// Disable raw mode only when no components left that are using it
|
|
38974
|
-
if (
|
|
38975
|
-
|
|
38976
|
-
stdin.removeListener('readable', this.handleReadable);
|
|
38977
|
-
stdin.unref();
|
|
41061
|
+
if (rawModeEnabledCount.current === 0) {
|
|
41062
|
+
return;
|
|
38978
41063
|
}
|
|
38979
|
-
|
|
38980
|
-
|
|
38981
|
-
let chunk;
|
|
38982
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
38983
|
-
while ((chunk = this.props.stdin.read()) !== null) {
|
|
38984
|
-
this.handleInput(chunk);
|
|
38985
|
-
this.internal_eventEmitter.emit('input', chunk);
|
|
41064
|
+
if (--rawModeEnabledCount.current === 0) {
|
|
41065
|
+
disableRawMode();
|
|
38986
41066
|
}
|
|
38987
|
-
};
|
|
38988
|
-
|
|
38989
|
-
|
|
38990
|
-
|
|
38991
|
-
|
|
38992
|
-
|
|
41067
|
+
}, [isRawModeSupported, stdin, handleReadable, disableRawMode]);
|
|
41068
|
+
// Focus navigation helpers
|
|
41069
|
+
const findNextFocusable = reactExports.useCallback((currentFocusables, currentActiveFocusId) => {
|
|
41070
|
+
const activeIndex = currentFocusables.findIndex(focusable => {
|
|
41071
|
+
return focusable.id === currentActiveFocusId;
|
|
41072
|
+
});
|
|
41073
|
+
for (let index = activeIndex + 1; index < currentFocusables.length; index++) {
|
|
41074
|
+
const focusable = currentFocusables[index];
|
|
41075
|
+
if (focusable?.isActive) {
|
|
41076
|
+
return focusable.id;
|
|
41077
|
+
}
|
|
38993
41078
|
}
|
|
38994
|
-
|
|
38995
|
-
|
|
38996
|
-
|
|
38997
|
-
|
|
38998
|
-
|
|
41079
|
+
return undefined;
|
|
41080
|
+
}, []);
|
|
41081
|
+
const findPreviousFocusable = reactExports.useCallback((currentFocusables, currentActiveFocusId) => {
|
|
41082
|
+
const activeIndex = currentFocusables.findIndex(focusable => {
|
|
41083
|
+
return focusable.id === currentActiveFocusId;
|
|
41084
|
+
});
|
|
41085
|
+
for (let index = activeIndex - 1; index >= 0; index--) {
|
|
41086
|
+
const focusable = currentFocusables[index];
|
|
41087
|
+
if (focusable?.isActive) {
|
|
41088
|
+
return focusable.id;
|
|
41089
|
+
}
|
|
38999
41090
|
}
|
|
39000
|
-
|
|
41091
|
+
return undefined;
|
|
41092
|
+
}, []);
|
|
41093
|
+
const focusNext = reactExports.useCallback(() => {
|
|
41094
|
+
setFocusables(currentFocusables => {
|
|
41095
|
+
setActiveFocusId(currentActiveFocusId => {
|
|
41096
|
+
const firstFocusableId = currentFocusables.find(focusable => focusable.isActive)?.id;
|
|
41097
|
+
const nextFocusableId = findNextFocusable(currentFocusables, currentActiveFocusId);
|
|
41098
|
+
return nextFocusableId ?? firstFocusableId;
|
|
41099
|
+
});
|
|
41100
|
+
return currentFocusables;
|
|
41101
|
+
});
|
|
41102
|
+
}, [findNextFocusable]);
|
|
41103
|
+
const focusPrevious = reactExports.useCallback(() => {
|
|
41104
|
+
setFocusables(currentFocusables => {
|
|
41105
|
+
setActiveFocusId(currentActiveFocusId => {
|
|
41106
|
+
const lastFocusableId = currentFocusables.findLast(focusable => focusable.isActive)?.id;
|
|
41107
|
+
const previousFocusableId = findPreviousFocusable(currentFocusables, currentActiveFocusId);
|
|
41108
|
+
return previousFocusableId ?? lastFocusableId;
|
|
41109
|
+
});
|
|
41110
|
+
return currentFocusables;
|
|
41111
|
+
});
|
|
41112
|
+
}, [findPreviousFocusable]);
|
|
41113
|
+
// Handle tab navigation via effect that subscribes to input events
|
|
41114
|
+
reactExports.useEffect(() => {
|
|
41115
|
+
const handleTabNavigation = (input) => {
|
|
41116
|
+
if (!isFocusEnabled || focusablesCountRef.current === 0)
|
|
41117
|
+
return;
|
|
39001
41118
|
if (input === tab) {
|
|
39002
|
-
|
|
41119
|
+
focusNext();
|
|
39003
41120
|
}
|
|
39004
41121
|
if (input === shiftTab) {
|
|
39005
|
-
|
|
41122
|
+
focusPrevious();
|
|
39006
41123
|
}
|
|
39007
|
-
}
|
|
39008
|
-
|
|
39009
|
-
|
|
39010
|
-
|
|
39011
|
-
|
|
39012
|
-
}
|
|
39013
|
-
|
|
39014
|
-
|
|
39015
|
-
|
|
39016
|
-
|
|
39017
|
-
|
|
41124
|
+
};
|
|
41125
|
+
internal_eventEmitter.current.on('input', handleTabNavigation);
|
|
41126
|
+
const emitter = internal_eventEmitter.current;
|
|
41127
|
+
return () => {
|
|
41128
|
+
emitter.off('input', handleTabNavigation);
|
|
41129
|
+
};
|
|
41130
|
+
}, [isFocusEnabled, focusNext, focusPrevious]);
|
|
41131
|
+
const enableFocus = reactExports.useCallback(() => {
|
|
41132
|
+
setIsFocusEnabled(true);
|
|
41133
|
+
}, []);
|
|
41134
|
+
const disableFocus = reactExports.useCallback(() => {
|
|
41135
|
+
setIsFocusEnabled(false);
|
|
41136
|
+
}, []);
|
|
41137
|
+
const focus = reactExports.useCallback((id) => {
|
|
41138
|
+
setFocusables(currentFocusables => {
|
|
41139
|
+
const hasFocusableId = currentFocusables.some(focusable => focusable?.id === id);
|
|
41140
|
+
if (hasFocusableId) {
|
|
41141
|
+
setActiveFocusId(id);
|
|
41142
|
+
}
|
|
41143
|
+
return currentFocusables;
|
|
39018
41144
|
});
|
|
39019
|
-
};
|
|
39020
|
-
|
|
39021
|
-
|
|
39022
|
-
|
|
41145
|
+
}, []);
|
|
41146
|
+
const addFocusable = reactExports.useCallback((id, { autoFocus }) => {
|
|
41147
|
+
setFocusables(currentFocusables => {
|
|
41148
|
+
focusablesCountRef.current = currentFocusables.length + 1;
|
|
41149
|
+
return [
|
|
41150
|
+
...currentFocusables,
|
|
41151
|
+
{
|
|
41152
|
+
id,
|
|
41153
|
+
isActive: true,
|
|
41154
|
+
},
|
|
41155
|
+
];
|
|
39023
41156
|
});
|
|
39024
|
-
|
|
39025
|
-
|
|
39026
|
-
|
|
39027
|
-
|
|
39028
|
-
|
|
39029
|
-
return
|
|
41157
|
+
if (autoFocus) {
|
|
41158
|
+
setActiveFocusId(currentActiveFocusId => {
|
|
41159
|
+
if (!currentActiveFocusId) {
|
|
41160
|
+
return id;
|
|
41161
|
+
}
|
|
41162
|
+
return currentActiveFocusId;
|
|
41163
|
+
});
|
|
41164
|
+
}
|
|
41165
|
+
}, []);
|
|
41166
|
+
const removeFocusable = reactExports.useCallback((id) => {
|
|
41167
|
+
setActiveFocusId(currentActiveFocusId => {
|
|
41168
|
+
if (currentActiveFocusId === id) {
|
|
41169
|
+
return undefined;
|
|
39030
41170
|
}
|
|
39031
|
-
return
|
|
41171
|
+
return currentActiveFocusId;
|
|
39032
41172
|
});
|
|
39033
|
-
|
|
39034
|
-
|
|
39035
|
-
|
|
39036
|
-
|
|
39037
|
-
|
|
39038
|
-
return
|
|
39039
|
-
activeFocusId: nextFocusableId ?? firstFocusableId,
|
|
39040
|
-
};
|
|
41173
|
+
setFocusables(currentFocusables => {
|
|
41174
|
+
const filtered = currentFocusables.filter(focusable => {
|
|
41175
|
+
return focusable.id !== id;
|
|
41176
|
+
});
|
|
41177
|
+
focusablesCountRef.current = filtered.length;
|
|
41178
|
+
return filtered;
|
|
39041
41179
|
});
|
|
39042
|
-
};
|
|
39043
|
-
|
|
39044
|
-
|
|
39045
|
-
|
|
39046
|
-
|
|
41180
|
+
}, []);
|
|
41181
|
+
const activateFocusable = reactExports.useCallback((id) => {
|
|
41182
|
+
setFocusables(currentFocusables => currentFocusables.map(focusable => {
|
|
41183
|
+
if (focusable.id !== id) {
|
|
41184
|
+
return focusable;
|
|
41185
|
+
}
|
|
39047
41186
|
return {
|
|
39048
|
-
|
|
41187
|
+
id,
|
|
41188
|
+
isActive: true,
|
|
39049
41189
|
};
|
|
41190
|
+
}));
|
|
41191
|
+
}, []);
|
|
41192
|
+
const deactivateFocusable = reactExports.useCallback((id) => {
|
|
41193
|
+
setActiveFocusId(currentActiveFocusId => {
|
|
41194
|
+
if (currentActiveFocusId === id) {
|
|
41195
|
+
return undefined;
|
|
41196
|
+
}
|
|
41197
|
+
return currentActiveFocusId;
|
|
39050
41198
|
});
|
|
39051
|
-
|
|
39052
|
-
|
|
39053
|
-
|
|
39054
|
-
let nextFocusId = previousState.activeFocusId;
|
|
39055
|
-
if (!nextFocusId && autoFocus) {
|
|
39056
|
-
nextFocusId = id;
|
|
41199
|
+
setFocusables(currentFocusables => currentFocusables.map(focusable => {
|
|
41200
|
+
if (focusable.id !== id) {
|
|
41201
|
+
return focusable;
|
|
39057
41202
|
}
|
|
39058
41203
|
return {
|
|
39059
|
-
|
|
39060
|
-
|
|
39061
|
-
...previousState.focusables,
|
|
39062
|
-
{
|
|
39063
|
-
id,
|
|
39064
|
-
isActive: true,
|
|
39065
|
-
},
|
|
39066
|
-
],
|
|
41204
|
+
id,
|
|
41205
|
+
isActive: false,
|
|
39067
41206
|
};
|
|
39068
|
-
});
|
|
39069
|
-
};
|
|
39070
|
-
removeFocusable = (id) => {
|
|
39071
|
-
this.setState(previousState => ({
|
|
39072
|
-
activeFocusId: previousState.activeFocusId === id
|
|
39073
|
-
? undefined
|
|
39074
|
-
: previousState.activeFocusId,
|
|
39075
|
-
focusables: previousState.focusables.filter(focusable => {
|
|
39076
|
-
return focusable.id !== id;
|
|
39077
|
-
}),
|
|
39078
41207
|
}));
|
|
39079
|
-
};
|
|
39080
|
-
|
|
39081
|
-
|
|
39082
|
-
|
|
39083
|
-
|
|
39084
|
-
|
|
39085
|
-
|
|
39086
|
-
return {
|
|
39087
|
-
id,
|
|
39088
|
-
isActive: true,
|
|
39089
|
-
};
|
|
39090
|
-
}),
|
|
39091
|
-
}));
|
|
39092
|
-
};
|
|
39093
|
-
deactivateFocusable = (id) => {
|
|
39094
|
-
this.setState(previousState => ({
|
|
39095
|
-
activeFocusId: previousState.activeFocusId === id
|
|
39096
|
-
? undefined
|
|
39097
|
-
: previousState.activeFocusId,
|
|
39098
|
-
focusables: previousState.focusables.map(focusable => {
|
|
39099
|
-
if (focusable.id !== id) {
|
|
39100
|
-
return focusable;
|
|
39101
|
-
}
|
|
39102
|
-
return {
|
|
39103
|
-
id,
|
|
39104
|
-
isActive: false,
|
|
39105
|
-
};
|
|
39106
|
-
}),
|
|
39107
|
-
}));
|
|
39108
|
-
};
|
|
39109
|
-
findNextFocusable = (state) => {
|
|
39110
|
-
const activeIndex = state.focusables.findIndex(focusable => {
|
|
39111
|
-
return focusable.id === state.activeFocusId;
|
|
39112
|
-
});
|
|
39113
|
-
for (let index = activeIndex + 1; index < state.focusables.length; index++) {
|
|
39114
|
-
const focusable = state.focusables[index];
|
|
39115
|
-
if (focusable?.isActive) {
|
|
39116
|
-
return focusable.id;
|
|
39117
|
-
}
|
|
39118
|
-
}
|
|
39119
|
-
return undefined;
|
|
39120
|
-
};
|
|
39121
|
-
findPreviousFocusable = (state) => {
|
|
39122
|
-
const activeIndex = state.focusables.findIndex(focusable => {
|
|
39123
|
-
return focusable.id === state.activeFocusId;
|
|
39124
|
-
});
|
|
39125
|
-
for (let index = activeIndex - 1; index >= 0; index--) {
|
|
39126
|
-
const focusable = state.focusables[index];
|
|
39127
|
-
if (focusable?.isActive) {
|
|
39128
|
-
return focusable.id;
|
|
41208
|
+
}, []);
|
|
41209
|
+
// Handle cursor visibility and raw mode cleanup on unmount
|
|
41210
|
+
reactExports.useEffect(() => {
|
|
41211
|
+
return () => {
|
|
41212
|
+
cliCursor.show(stdout);
|
|
41213
|
+
if (isRawModeSupported && rawModeEnabledCount.current > 0) {
|
|
41214
|
+
disableRawMode();
|
|
39129
41215
|
}
|
|
39130
|
-
}
|
|
39131
|
-
|
|
39132
|
-
|
|
41216
|
+
};
|
|
41217
|
+
}, [stdout, isRawModeSupported, disableRawMode]);
|
|
41218
|
+
// Memoize context values to prevent unnecessary re-renders
|
|
41219
|
+
const appContextValue = reactExports.useMemo(() => ({
|
|
41220
|
+
exit: handleExit,
|
|
41221
|
+
}), [handleExit]);
|
|
41222
|
+
const stdinContextValue = reactExports.useMemo(() => ({
|
|
41223
|
+
stdin,
|
|
41224
|
+
setRawMode: handleSetRawMode,
|
|
41225
|
+
isRawModeSupported,
|
|
41226
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
41227
|
+
internal_exitOnCtrlC: exitOnCtrlC,
|
|
41228
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
41229
|
+
internal_eventEmitter: internal_eventEmitter.current,
|
|
41230
|
+
}), [stdin, handleSetRawMode, isRawModeSupported, exitOnCtrlC]);
|
|
41231
|
+
const stdoutContextValue = reactExports.useMemo(() => ({
|
|
41232
|
+
stdout,
|
|
41233
|
+
write: writeToStdout,
|
|
41234
|
+
}), [stdout, writeToStdout]);
|
|
41235
|
+
const stderrContextValue = reactExports.useMemo(() => ({
|
|
41236
|
+
stderr,
|
|
41237
|
+
write: writeToStderr,
|
|
41238
|
+
}), [stderr, writeToStderr]);
|
|
41239
|
+
const cursorContextValue = reactExports.useMemo(() => ({
|
|
41240
|
+
setCursorPosition,
|
|
41241
|
+
}), [setCursorPosition]);
|
|
41242
|
+
const focusContextValue = reactExports.useMemo(() => ({
|
|
41243
|
+
activeId: activeFocusId,
|
|
41244
|
+
add: addFocusable,
|
|
41245
|
+
remove: removeFocusable,
|
|
41246
|
+
activate: activateFocusable,
|
|
41247
|
+
deactivate: deactivateFocusable,
|
|
41248
|
+
enableFocus,
|
|
41249
|
+
disableFocus,
|
|
41250
|
+
focusNext,
|
|
41251
|
+
focusPrevious,
|
|
41252
|
+
focus,
|
|
41253
|
+
}), [
|
|
41254
|
+
activeFocusId,
|
|
41255
|
+
addFocusable,
|
|
41256
|
+
removeFocusable,
|
|
41257
|
+
activateFocusable,
|
|
41258
|
+
deactivateFocusable,
|
|
41259
|
+
enableFocus,
|
|
41260
|
+
disableFocus,
|
|
41261
|
+
focusNext,
|
|
41262
|
+
focusPrevious,
|
|
41263
|
+
focus,
|
|
41264
|
+
]);
|
|
41265
|
+
return (React.createElement(AppContext.Provider, { value: appContextValue },
|
|
41266
|
+
React.createElement(StdinContext.Provider, { value: stdinContextValue },
|
|
41267
|
+
React.createElement(StdoutContext.Provider, { value: stdoutContextValue },
|
|
41268
|
+
React.createElement(StderrContext.Provider, { value: stderrContextValue },
|
|
41269
|
+
React.createElement(FocusContext.Provider, { value: focusContextValue },
|
|
41270
|
+
React.createElement(CursorContext.Provider, { value: cursorContextValue },
|
|
41271
|
+
React.createElement(ErrorBoundary, { onError: handleExit }, children))))))));
|
|
41272
|
+
}
|
|
41273
|
+
App.displayName = 'InternalApp';
|
|
41274
|
+
|
|
41275
|
+
// Kitty keyboard protocol flags.
|
|
41276
|
+
// @see https://sw.kovidgoyal.net/kitty/keyboard-protocol/
|
|
41277
|
+
const kittyFlags = {
|
|
41278
|
+
disambiguateEscapeCodes: 1,
|
|
41279
|
+
reportEventTypes: 2,
|
|
41280
|
+
reportAlternateKeys: 4,
|
|
41281
|
+
reportAllKeysAsEscapeCodes: 8,
|
|
41282
|
+
reportAssociatedText: 16,
|
|
41283
|
+
};
|
|
41284
|
+
// Converts an array of flag names to the corresponding bitmask value.
|
|
41285
|
+
function resolveFlags(flags) {
|
|
41286
|
+
let result = 0;
|
|
41287
|
+
for (const flag of flags) {
|
|
41288
|
+
// eslint-disable-next-line no-bitwise
|
|
41289
|
+
result |= kittyFlags[flag];
|
|
41290
|
+
}
|
|
41291
|
+
return result;
|
|
39133
41292
|
}
|
|
41293
|
+
// Kitty keyboard modifier bits.
|
|
41294
|
+
// These are used in the modifier parameter of CSI u sequences.
|
|
41295
|
+
// Note: The actual modifier value is (modifiers - 1) as per the protocol.
|
|
41296
|
+
const kittyModifiers = {
|
|
41297
|
+
shift: 1,
|
|
41298
|
+
alt: 2,
|
|
41299
|
+
ctrl: 4,
|
|
41300
|
+
super: 8,
|
|
41301
|
+
hyper: 16,
|
|
41302
|
+
meta: 32,
|
|
41303
|
+
capsLock: 64,
|
|
41304
|
+
numLock: 128,
|
|
41305
|
+
};
|
|
39134
41306
|
|
|
39135
41307
|
const noop = () => { };
|
|
41308
|
+
const kittyQueryEscapeByte = 0x1b;
|
|
41309
|
+
const kittyQueryOpenBracketByte = 0x5b;
|
|
41310
|
+
const kittyQueryQuestionMarkByte = 0x3f;
|
|
41311
|
+
const kittyQueryLetterByte = 0x75;
|
|
41312
|
+
const zeroByte = 0x30;
|
|
41313
|
+
const nineByte = 0x39;
|
|
41314
|
+
const isDigitByte = (byte) => byte >= zeroByte && byte <= nineByte;
|
|
41315
|
+
const matchKittyQueryResponse = (buffer, startIndex) => {
|
|
41316
|
+
if (buffer[startIndex] !== kittyQueryEscapeByte ||
|
|
41317
|
+
buffer[startIndex + 1] !== kittyQueryOpenBracketByte ||
|
|
41318
|
+
buffer[startIndex + 2] !== kittyQueryQuestionMarkByte) {
|
|
41319
|
+
return undefined;
|
|
41320
|
+
}
|
|
41321
|
+
let index = startIndex + 3;
|
|
41322
|
+
const digitsStartIndex = index;
|
|
41323
|
+
while (index < buffer.length && isDigitByte(buffer[index])) {
|
|
41324
|
+
index++;
|
|
41325
|
+
}
|
|
41326
|
+
if (index === digitsStartIndex) {
|
|
41327
|
+
return undefined;
|
|
41328
|
+
}
|
|
41329
|
+
if (index === buffer.length) {
|
|
41330
|
+
return { state: 'partial' };
|
|
41331
|
+
}
|
|
41332
|
+
if (buffer[index] === kittyQueryLetterByte) {
|
|
41333
|
+
return { state: 'complete', endIndex: index };
|
|
41334
|
+
}
|
|
41335
|
+
return undefined;
|
|
41336
|
+
};
|
|
41337
|
+
const hasCompleteKittyQueryResponse = (buffer) => {
|
|
41338
|
+
for (let index = 0; index < buffer.length; index++) {
|
|
41339
|
+
const match = matchKittyQueryResponse(buffer, index);
|
|
41340
|
+
if (match?.state === 'complete') {
|
|
41341
|
+
return true;
|
|
41342
|
+
}
|
|
41343
|
+
}
|
|
41344
|
+
return false;
|
|
41345
|
+
};
|
|
41346
|
+
const stripKittyQueryResponsesAndTrailingPartial = (buffer) => {
|
|
41347
|
+
const keptBytes = [];
|
|
41348
|
+
let index = 0;
|
|
41349
|
+
while (index < buffer.length) {
|
|
41350
|
+
const match = matchKittyQueryResponse(buffer, index);
|
|
41351
|
+
if (match?.state === 'complete') {
|
|
41352
|
+
index = match.endIndex + 1;
|
|
41353
|
+
continue;
|
|
41354
|
+
}
|
|
41355
|
+
if (match?.state === 'partial') {
|
|
41356
|
+
break;
|
|
41357
|
+
}
|
|
41358
|
+
keptBytes.push(buffer[index]);
|
|
41359
|
+
index++;
|
|
41360
|
+
}
|
|
41361
|
+
return keptBytes;
|
|
41362
|
+
};
|
|
41363
|
+
const isErrorInput = (value) => {
|
|
41364
|
+
return (value instanceof Error ||
|
|
41365
|
+
Object.prototype.toString.call(value) === '[object Error]');
|
|
41366
|
+
};
|
|
39136
41367
|
class Ink {
|
|
41368
|
+
/**
|
|
41369
|
+
Whether this instance is using concurrent rendering mode.
|
|
41370
|
+
*/
|
|
41371
|
+
isConcurrent;
|
|
39137
41372
|
options;
|
|
39138
41373
|
log;
|
|
41374
|
+
cursorPosition;
|
|
39139
41375
|
throttledLog;
|
|
39140
41376
|
isScreenReaderEnabled;
|
|
39141
41377
|
// Ignore last render after unmounting a tree to prevent empty output before exit
|
|
39142
41378
|
isUnmounted;
|
|
41379
|
+
isUnmounting;
|
|
39143
41380
|
lastOutput;
|
|
41381
|
+
lastOutputToRender;
|
|
39144
41382
|
lastOutputHeight;
|
|
39145
41383
|
lastTerminalWidth;
|
|
39146
41384
|
container;
|
|
@@ -39149,8 +41387,14 @@ class Ink {
|
|
|
39149
41387
|
// so that it's rerendered every time, not just new static parts, like in non-debug mode
|
|
39150
41388
|
fullStaticOutput;
|
|
39151
41389
|
exitPromise;
|
|
41390
|
+
exitResult;
|
|
41391
|
+
beforeExitHandler;
|
|
39152
41392
|
restoreConsole;
|
|
39153
41393
|
unsubscribeResize;
|
|
41394
|
+
throttledOnRender;
|
|
41395
|
+
hasPendingThrottledRender = false;
|
|
41396
|
+
kittyProtocolEnabled = false;
|
|
41397
|
+
cancelKittyDetection;
|
|
39154
41398
|
constructor(options) {
|
|
39155
41399
|
autoBind(this);
|
|
39156
41400
|
this.options = options;
|
|
@@ -39162,43 +41406,64 @@ class Ink {
|
|
|
39162
41406
|
const unthrottled = options.debug || this.isScreenReaderEnabled;
|
|
39163
41407
|
const maxFps = options.maxFps ?? 30;
|
|
39164
41408
|
const renderThrottleMs = maxFps > 0 ? Math.max(1, Math.ceil(1000 / maxFps)) : 0;
|
|
39165
|
-
|
|
39166
|
-
|
|
39167
|
-
|
|
41409
|
+
if (unthrottled) {
|
|
41410
|
+
this.rootNode.onRender = this.onRender;
|
|
41411
|
+
this.throttledOnRender = undefined;
|
|
41412
|
+
}
|
|
41413
|
+
else {
|
|
41414
|
+
const throttled = throttle(this.onRender, renderThrottleMs, {
|
|
39168
41415
|
leading: true,
|
|
39169
41416
|
trailing: true,
|
|
39170
41417
|
});
|
|
41418
|
+
this.rootNode.onRender = () => {
|
|
41419
|
+
this.hasPendingThrottledRender = true;
|
|
41420
|
+
throttled();
|
|
41421
|
+
};
|
|
41422
|
+
this.throttledOnRender = throttled;
|
|
41423
|
+
}
|
|
39171
41424
|
this.rootNode.onImmediateRender = this.onRender;
|
|
39172
41425
|
this.log = logUpdate.create(options.stdout, {
|
|
39173
41426
|
incremental: options.incrementalRendering,
|
|
39174
41427
|
});
|
|
41428
|
+
this.cursorPosition = undefined;
|
|
39175
41429
|
this.throttledLog = unthrottled
|
|
39176
41430
|
? this.log
|
|
39177
|
-
: throttle(
|
|
41431
|
+
: throttle((output) => {
|
|
41432
|
+
const shouldWrite = this.log.willRender(output);
|
|
41433
|
+
const sync = shouldSynchronize(this.options.stdout);
|
|
41434
|
+
if (sync && shouldWrite) {
|
|
41435
|
+
this.options.stdout.write(bsu);
|
|
41436
|
+
}
|
|
41437
|
+
this.log(output);
|
|
41438
|
+
if (sync && shouldWrite) {
|
|
41439
|
+
this.options.stdout.write(esu);
|
|
41440
|
+
}
|
|
41441
|
+
}, undefined, {
|
|
39178
41442
|
leading: true,
|
|
39179
41443
|
trailing: true,
|
|
39180
41444
|
});
|
|
39181
41445
|
// Ignore last render after unmounting a tree to prevent empty output before exit
|
|
39182
41446
|
this.isUnmounted = false;
|
|
41447
|
+
this.isUnmounting = false;
|
|
41448
|
+
// Store concurrent mode setting
|
|
41449
|
+
this.isConcurrent = options.concurrent ?? false;
|
|
39183
41450
|
// Store last output to only rerender when needed
|
|
39184
41451
|
this.lastOutput = '';
|
|
41452
|
+
this.lastOutputToRender = '';
|
|
39185
41453
|
this.lastOutputHeight = 0;
|
|
39186
41454
|
this.lastTerminalWidth = this.getTerminalWidth();
|
|
39187
41455
|
// This variable is used only in debug mode to store full static output
|
|
39188
41456
|
// so that it's rerendered every time, not just new static parts, like in non-debug mode
|
|
39189
41457
|
this.fullStaticOutput = '';
|
|
41458
|
+
// Use ConcurrentRoot for concurrent mode, LegacyRoot for legacy mode
|
|
41459
|
+
const rootTag = options.concurrent ? constantsExports.ConcurrentRoot : constantsExports.LegacyRoot;
|
|
39190
41460
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
39191
|
-
this.container = reconciler.createContainer(this.rootNode,
|
|
41461
|
+
this.container = reconciler.createContainer(this.rootNode, rootTag, null, false, null, 'id', () => { }, () => { }, () => { }, () => { });
|
|
39192
41462
|
// Unmount when process exits
|
|
39193
41463
|
this.unsubscribeExit = signalExit(this.unmount, { alwaysLast: false });
|
|
39194
|
-
if (
|
|
39195
|
-
|
|
39196
|
-
|
|
39197
|
-
// Reporting React DOM's version, not Ink's
|
|
39198
|
-
// See https://github.com/facebook/react/issues/16666#issuecomment-532639905
|
|
39199
|
-
version: '16.13.1',
|
|
39200
|
-
rendererPackageName: 'ink',
|
|
39201
|
-
});
|
|
41464
|
+
if (isDev()) {
|
|
41465
|
+
// @ts-expect-error outdated types
|
|
41466
|
+
reconciler.injectIntoDevTools();
|
|
39202
41467
|
}
|
|
39203
41468
|
if (options.patchConsole) {
|
|
39204
41469
|
this.patchConsole();
|
|
@@ -39209,11 +41474,16 @@ class Ink {
|
|
|
39209
41474
|
options.stdout.off('resize', this.resized);
|
|
39210
41475
|
};
|
|
39211
41476
|
}
|
|
41477
|
+
this.initKittyKeyboard();
|
|
39212
41478
|
}
|
|
39213
41479
|
getTerminalWidth = () => {
|
|
39214
41480
|
// The 'columns' property can be undefined or 0 when not using a TTY.
|
|
39215
|
-
//
|
|
39216
|
-
|
|
41481
|
+
// Use terminal-size as a fallback for piped processes, then default to 80.
|
|
41482
|
+
if (this.options.stdout.columns) {
|
|
41483
|
+
return this.options.stdout.columns;
|
|
41484
|
+
}
|
|
41485
|
+
const size = terminalSize();
|
|
41486
|
+
return size?.columns ?? 80;
|
|
39217
41487
|
};
|
|
39218
41488
|
resized = () => {
|
|
39219
41489
|
const currentWidth = this.getTerminalWidth();
|
|
@@ -39221,6 +41491,7 @@ class Ink {
|
|
|
39221
41491
|
// We clear the screen when decreasing terminal width to prevent duplicate overlapping re-renders.
|
|
39222
41492
|
this.log.clear();
|
|
39223
41493
|
this.lastOutput = '';
|
|
41494
|
+
this.lastOutputToRender = '';
|
|
39224
41495
|
}
|
|
39225
41496
|
this.calculateLayout();
|
|
39226
41497
|
this.onRender();
|
|
@@ -39229,12 +41500,34 @@ class Ink {
|
|
|
39229
41500
|
resolveExitPromise = () => { };
|
|
39230
41501
|
rejectExitPromise = () => { };
|
|
39231
41502
|
unsubscribeExit = () => { };
|
|
41503
|
+
handleAppExit = (errorOrResult) => {
|
|
41504
|
+
if (this.isUnmounted || this.isUnmounting) {
|
|
41505
|
+
return;
|
|
41506
|
+
}
|
|
41507
|
+
if (isErrorInput(errorOrResult)) {
|
|
41508
|
+
this.unmount(errorOrResult);
|
|
41509
|
+
return;
|
|
41510
|
+
}
|
|
41511
|
+
this.exitResult = errorOrResult;
|
|
41512
|
+
this.unmount();
|
|
41513
|
+
};
|
|
41514
|
+
setCursorPosition = (position) => {
|
|
41515
|
+
this.cursorPosition = position;
|
|
41516
|
+
this.log.setCursorPosition(position);
|
|
41517
|
+
};
|
|
41518
|
+
restoreLastOutput = () => {
|
|
41519
|
+
// Clear() resets log-update's cursor state, so replay the latest cursor intent
|
|
41520
|
+
// before restoring output after external stdout/stderr writes.
|
|
41521
|
+
this.log.setCursorPosition(this.cursorPosition);
|
|
41522
|
+
this.log(this.lastOutputToRender || this.lastOutput + '\n');
|
|
41523
|
+
};
|
|
39232
41524
|
calculateLayout = () => {
|
|
39233
41525
|
const terminalWidth = this.getTerminalWidth();
|
|
39234
41526
|
this.rootNode.yogaNode.setWidth(terminalWidth);
|
|
39235
41527
|
this.rootNode.yogaNode.calculateLayout(undefined, undefined, Yoga.DIRECTION_LTR);
|
|
39236
41528
|
};
|
|
39237
41529
|
onRender = () => {
|
|
41530
|
+
this.hasPendingThrottledRender = false;
|
|
39238
41531
|
if (this.isUnmounted) {
|
|
39239
41532
|
return;
|
|
39240
41533
|
}
|
|
@@ -39255,10 +41548,15 @@ class Ink {
|
|
|
39255
41548
|
this.options.stdout.write(staticOutput);
|
|
39256
41549
|
}
|
|
39257
41550
|
this.lastOutput = output;
|
|
41551
|
+
this.lastOutputToRender = output + '\n';
|
|
39258
41552
|
this.lastOutputHeight = outputHeight;
|
|
39259
41553
|
return;
|
|
39260
41554
|
}
|
|
39261
41555
|
if (this.isScreenReaderEnabled) {
|
|
41556
|
+
const sync = shouldSynchronize(this.options.stdout);
|
|
41557
|
+
if (sync) {
|
|
41558
|
+
this.options.stdout.write(bsu);
|
|
41559
|
+
}
|
|
39262
41560
|
if (hasStaticOutput) {
|
|
39263
41561
|
// We need to erase the main output before writing new static output
|
|
39264
41562
|
const erase = this.lastOutputHeight > 0
|
|
@@ -39269,9 +41567,12 @@ class Ink {
|
|
|
39269
41567
|
this.lastOutputHeight = 0;
|
|
39270
41568
|
}
|
|
39271
41569
|
if (output === this.lastOutput && !hasStaticOutput) {
|
|
41570
|
+
if (sync) {
|
|
41571
|
+
this.options.stdout.write(esu);
|
|
41572
|
+
}
|
|
39272
41573
|
return;
|
|
39273
41574
|
}
|
|
39274
|
-
const terminalWidth = this.
|
|
41575
|
+
const terminalWidth = this.getTerminalWidth();
|
|
39275
41576
|
const wrappedOutput = wrapAnsi(output, terminalWidth, {
|
|
39276
41577
|
trim: false,
|
|
39277
41578
|
hard: true,
|
|
@@ -39287,41 +41588,69 @@ class Ink {
|
|
|
39287
41588
|
this.options.stdout.write(erase + wrappedOutput);
|
|
39288
41589
|
}
|
|
39289
41590
|
this.lastOutput = output;
|
|
41591
|
+
this.lastOutputToRender = wrappedOutput;
|
|
39290
41592
|
this.lastOutputHeight =
|
|
39291
41593
|
wrappedOutput === '' ? 0 : wrappedOutput.split('\n').length;
|
|
41594
|
+
if (sync) {
|
|
41595
|
+
this.options.stdout.write(esu);
|
|
41596
|
+
}
|
|
39292
41597
|
return;
|
|
39293
41598
|
}
|
|
39294
41599
|
if (hasStaticOutput) {
|
|
39295
41600
|
this.fullStaticOutput += staticOutput;
|
|
39296
41601
|
}
|
|
41602
|
+
// Detect fullscreen: output fills or exceeds terminal height.
|
|
41603
|
+
// Only apply when writing to a real TTY — piped output always gets trailing newlines.
|
|
41604
|
+
const isFullscreen = this.options.stdout.isTTY && outputHeight >= this.options.stdout.rows;
|
|
41605
|
+
const outputToRender = isFullscreen ? output : output + '\n';
|
|
39297
41606
|
if (this.lastOutputHeight >= this.options.stdout.rows) {
|
|
41607
|
+
const sync = shouldSynchronize(this.options.stdout);
|
|
41608
|
+
if (sync) {
|
|
41609
|
+
this.options.stdout.write(bsu);
|
|
41610
|
+
}
|
|
39298
41611
|
this.options.stdout.write(clearTerminal + this.fullStaticOutput + output);
|
|
39299
41612
|
this.lastOutput = output;
|
|
41613
|
+
this.lastOutputToRender = outputToRender;
|
|
39300
41614
|
this.lastOutputHeight = outputHeight;
|
|
39301
|
-
this.log.sync(
|
|
41615
|
+
this.log.sync(outputToRender);
|
|
41616
|
+
if (sync) {
|
|
41617
|
+
this.options.stdout.write(esu);
|
|
41618
|
+
}
|
|
39302
41619
|
return;
|
|
39303
41620
|
}
|
|
39304
41621
|
// To ensure static output is cleanly rendered before main output, clear main output first
|
|
39305
41622
|
if (hasStaticOutput) {
|
|
41623
|
+
const sync = shouldSynchronize(this.options.stdout);
|
|
41624
|
+
if (sync) {
|
|
41625
|
+
this.options.stdout.write(bsu);
|
|
41626
|
+
}
|
|
39306
41627
|
this.log.clear();
|
|
39307
41628
|
this.options.stdout.write(staticOutput);
|
|
39308
|
-
this.log(
|
|
41629
|
+
this.log(outputToRender);
|
|
41630
|
+
if (sync) {
|
|
41631
|
+
this.options.stdout.write(esu);
|
|
41632
|
+
}
|
|
39309
41633
|
}
|
|
39310
|
-
if (
|
|
39311
|
-
|
|
41634
|
+
else if (output !== this.lastOutput || this.log.isCursorDirty()) {
|
|
41635
|
+
// ThrottledLog manages its own bsu/esu at actual write time
|
|
41636
|
+
this.throttledLog(outputToRender);
|
|
39312
41637
|
}
|
|
39313
41638
|
this.lastOutput = output;
|
|
41639
|
+
this.lastOutputToRender = outputToRender;
|
|
39314
41640
|
this.lastOutputHeight = outputHeight;
|
|
39315
41641
|
};
|
|
39316
41642
|
render(node) {
|
|
39317
41643
|
const tree = (React.createElement(accessibilityContext.Provider, { value: { isScreenReaderEnabled: this.isScreenReaderEnabled } },
|
|
39318
|
-
React.createElement(App, { stdin: this.options.stdin, stdout: this.options.stdout, stderr: this.options.stderr, writeToStdout: this.writeToStdout, writeToStderr: this.writeToStderr,
|
|
39319
|
-
|
|
39320
|
-
|
|
39321
|
-
|
|
39322
|
-
|
|
39323
|
-
|
|
39324
|
-
|
|
41644
|
+
React.createElement(App, { stdin: this.options.stdin, stdout: this.options.stdout, stderr: this.options.stderr, exitOnCtrlC: this.options.exitOnCtrlC, writeToStdout: this.writeToStdout, writeToStderr: this.writeToStderr, setCursorPosition: this.setCursorPosition, onExit: this.handleAppExit }, node)));
|
|
41645
|
+
if (this.options.concurrent) {
|
|
41646
|
+
// Concurrent mode: use updateContainer (async scheduling)
|
|
41647
|
+
reconciler.updateContainer(tree, this.container, null, noop);
|
|
41648
|
+
}
|
|
41649
|
+
else {
|
|
41650
|
+
// Legacy mode: use updateContainerSync + flushSyncWork (sync)
|
|
41651
|
+
reconciler.updateContainerSync(tree, this.container, null, noop);
|
|
41652
|
+
reconciler.flushSyncWork();
|
|
41653
|
+
}
|
|
39325
41654
|
}
|
|
39326
41655
|
writeToStdout(data) {
|
|
39327
41656
|
if (this.isUnmounted) {
|
|
@@ -39335,9 +41664,16 @@ class Ink {
|
|
|
39335
41664
|
this.options.stdout.write(data);
|
|
39336
41665
|
return;
|
|
39337
41666
|
}
|
|
41667
|
+
const sync = shouldSynchronize(this.options.stdout);
|
|
41668
|
+
if (sync) {
|
|
41669
|
+
this.options.stdout.write(bsu);
|
|
41670
|
+
}
|
|
39338
41671
|
this.log.clear();
|
|
39339
41672
|
this.options.stdout.write(data);
|
|
39340
|
-
this.
|
|
41673
|
+
this.restoreLastOutput();
|
|
41674
|
+
if (sync) {
|
|
41675
|
+
this.options.stdout.write(esu);
|
|
41676
|
+
}
|
|
39341
41677
|
}
|
|
39342
41678
|
writeToStderr(data) {
|
|
39343
41679
|
if (this.isUnmounted) {
|
|
@@ -39352,17 +41688,57 @@ class Ink {
|
|
|
39352
41688
|
this.options.stderr.write(data);
|
|
39353
41689
|
return;
|
|
39354
41690
|
}
|
|
41691
|
+
const sync = shouldSynchronize(this.options.stdout);
|
|
41692
|
+
if (sync) {
|
|
41693
|
+
this.options.stdout.write(bsu);
|
|
41694
|
+
}
|
|
39355
41695
|
this.log.clear();
|
|
39356
41696
|
this.options.stderr.write(data);
|
|
39357
|
-
this.
|
|
41697
|
+
this.restoreLastOutput();
|
|
41698
|
+
if (sync) {
|
|
41699
|
+
this.options.stdout.write(esu);
|
|
41700
|
+
}
|
|
39358
41701
|
}
|
|
39359
41702
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
39360
41703
|
unmount(error) {
|
|
39361
|
-
if (this.isUnmounted) {
|
|
41704
|
+
if (this.isUnmounted || this.isUnmounting) {
|
|
39362
41705
|
return;
|
|
39363
41706
|
}
|
|
39364
|
-
this.
|
|
39365
|
-
this.
|
|
41707
|
+
this.isUnmounting = true;
|
|
41708
|
+
if (this.beforeExitHandler) {
|
|
41709
|
+
process$1.off('beforeExit', this.beforeExitHandler);
|
|
41710
|
+
this.beforeExitHandler = undefined;
|
|
41711
|
+
}
|
|
41712
|
+
const stdout = this.options.stdout;
|
|
41713
|
+
const canWriteToStdout = !stdout.destroyed && !stdout.writableEnded && (stdout.writable ?? true);
|
|
41714
|
+
const settleThrottle = (throttled) => {
|
|
41715
|
+
if (typeof throttled.flush !== 'function') {
|
|
41716
|
+
return;
|
|
41717
|
+
}
|
|
41718
|
+
if (canWriteToStdout) {
|
|
41719
|
+
throttled.flush();
|
|
41720
|
+
}
|
|
41721
|
+
else if (typeof throttled.cancel === 'function') {
|
|
41722
|
+
throttled.cancel();
|
|
41723
|
+
}
|
|
41724
|
+
};
|
|
41725
|
+
// Clear any pending throttled render timer on unmount. When stdout is writable,
|
|
41726
|
+
// flush so the final frame is emitted; otherwise cancel to avoid delayed callbacks.
|
|
41727
|
+
settleThrottle(this.throttledOnRender ?? {});
|
|
41728
|
+
if (canWriteToStdout) {
|
|
41729
|
+
// If throttling is enabled and there is already a pending render, flushing above
|
|
41730
|
+
// is sufficient. Also avoid calling onRender() again when static output already
|
|
41731
|
+
// exists, as that can duplicate <Static> children output on exit (see issue #397).
|
|
41732
|
+
const shouldRenderFinalFrame = !this.throttledOnRender ||
|
|
41733
|
+
(!this.hasPendingThrottledRender && this.fullStaticOutput === '');
|
|
41734
|
+
if (shouldRenderFinalFrame) {
|
|
41735
|
+
this.calculateLayout();
|
|
41736
|
+
this.onRender();
|
|
41737
|
+
}
|
|
41738
|
+
}
|
|
41739
|
+
// Mark as unmounted after the final render but before stdout writes
|
|
41740
|
+
// that could re-enter exit() via synchronous write callbacks.
|
|
41741
|
+
this.isUnmounted = true;
|
|
39366
41742
|
this.unsubscribeExit();
|
|
39367
41743
|
if (typeof this.restoreConsole === 'function') {
|
|
39368
41744
|
this.restoreConsole();
|
|
@@ -39370,27 +41746,71 @@ class Ink {
|
|
|
39370
41746
|
if (typeof this.unsubscribeResize === 'function') {
|
|
39371
41747
|
this.unsubscribeResize();
|
|
39372
41748
|
}
|
|
39373
|
-
//
|
|
39374
|
-
|
|
39375
|
-
|
|
39376
|
-
|
|
41749
|
+
// Cancel any in-progress auto-detection before checking protocol state
|
|
41750
|
+
if (this.cancelKittyDetection) {
|
|
41751
|
+
this.cancelKittyDetection();
|
|
41752
|
+
}
|
|
41753
|
+
// Flush any pending throttled log writes if possible, otherwise cancel to
|
|
41754
|
+
// prevent delayed callbacks from writing to a closed stream.
|
|
41755
|
+
const throttledLog = this.throttledLog;
|
|
41756
|
+
settleThrottle(throttledLog);
|
|
41757
|
+
if (canWriteToStdout) {
|
|
41758
|
+
if (this.kittyProtocolEnabled) {
|
|
41759
|
+
try {
|
|
41760
|
+
this.options.stdout.write('\u001B[<u');
|
|
41761
|
+
}
|
|
41762
|
+
catch {
|
|
41763
|
+
// Best-effort: stdout may already be destroyed during shutdown
|
|
41764
|
+
}
|
|
41765
|
+
}
|
|
41766
|
+
// CIs don't handle erasing ansi escapes well, so it's better to
|
|
41767
|
+
// only render last frame of non-static output
|
|
41768
|
+
if (isInCi) {
|
|
41769
|
+
this.options.stdout.write(this.lastOutput + '\n');
|
|
41770
|
+
}
|
|
41771
|
+
else if (!this.options.debug) {
|
|
41772
|
+
this.log.done();
|
|
41773
|
+
}
|
|
39377
41774
|
}
|
|
39378
|
-
|
|
39379
|
-
|
|
41775
|
+
this.kittyProtocolEnabled = false;
|
|
41776
|
+
if (this.options.concurrent) {
|
|
41777
|
+
// Concurrent mode: use updateContainer (async scheduling)
|
|
41778
|
+
reconciler.updateContainer(null, this.container, null, noop);
|
|
41779
|
+
}
|
|
41780
|
+
else {
|
|
41781
|
+
// Legacy mode: use updateContainerSync + flushSyncWork (sync)
|
|
41782
|
+
reconciler.updateContainerSync(null, this.container, null, noop);
|
|
41783
|
+
reconciler.flushSyncWork();
|
|
39380
41784
|
}
|
|
39381
|
-
this.isUnmounted = true;
|
|
39382
|
-
// @ts-expect-error the types for `react-reconciler` are not up to date with the library.
|
|
39383
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
39384
|
-
reconciler.updateContainerSync(null, this.container, null, noop);
|
|
39385
|
-
// @ts-expect-error the types for `react-reconciler` are not up to date with the library.
|
|
39386
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
39387
|
-
reconciler.flushSyncWork();
|
|
39388
41785
|
instances.delete(this.options.stdout);
|
|
39389
|
-
|
|
39390
|
-
|
|
41786
|
+
// Ensure all queued writes have been processed before resolving the
|
|
41787
|
+
// exit promise. For real writable streams, queue an empty write as a
|
|
41788
|
+
// barrier — its callback fires only after all prior writes complete.
|
|
41789
|
+
// For non-stream objects (e.g. test spies), resolve on next tick.
|
|
41790
|
+
//
|
|
41791
|
+
// When called from signal-exit during process shutdown (error is a
|
|
41792
|
+
// number or null rather than undefined/Error), resolve synchronously
|
|
41793
|
+
// because the event loop is draining and async callbacks won't fire.
|
|
41794
|
+
const { exitResult } = this;
|
|
41795
|
+
const resolveOrReject = () => {
|
|
41796
|
+
if (isErrorInput(error)) {
|
|
41797
|
+
this.rejectExitPromise(error);
|
|
41798
|
+
}
|
|
41799
|
+
else {
|
|
41800
|
+
this.resolveExitPromise(exitResult);
|
|
41801
|
+
}
|
|
41802
|
+
};
|
|
41803
|
+
const isProcessExiting = error !== undefined && !isErrorInput(error);
|
|
41804
|
+
const hasWritableState = stdout._writableState !== undefined ||
|
|
41805
|
+
stdout.writableLength !== undefined;
|
|
41806
|
+
if (isProcessExiting) {
|
|
41807
|
+
resolveOrReject();
|
|
41808
|
+
}
|
|
41809
|
+
else if (canWriteToStdout && hasWritableState) {
|
|
41810
|
+
this.options.stdout.write('', resolveOrReject);
|
|
39391
41811
|
}
|
|
39392
41812
|
else {
|
|
39393
|
-
|
|
41813
|
+
setImmediate(resolveOrReject);
|
|
39394
41814
|
}
|
|
39395
41815
|
}
|
|
39396
41816
|
async waitUntilExit() {
|
|
@@ -39398,11 +41818,20 @@ class Ink {
|
|
|
39398
41818
|
this.resolveExitPromise = resolve;
|
|
39399
41819
|
this.rejectExitPromise = reject;
|
|
39400
41820
|
});
|
|
41821
|
+
if (!this.beforeExitHandler) {
|
|
41822
|
+
this.beforeExitHandler = () => {
|
|
41823
|
+
this.unmount();
|
|
41824
|
+
};
|
|
41825
|
+
process$1.once('beforeExit', this.beforeExitHandler);
|
|
41826
|
+
}
|
|
39401
41827
|
return this.exitPromise;
|
|
39402
41828
|
}
|
|
39403
41829
|
clear() {
|
|
39404
41830
|
if (!isInCi && !this.options.debug) {
|
|
39405
41831
|
this.log.clear();
|
|
41832
|
+
// Sync lastOutput so that unmount's final onRender
|
|
41833
|
+
// sees it as unchanged and log-update skips it
|
|
41834
|
+
this.log.sync(this.lastOutputToRender || this.lastOutput + '\n');
|
|
39406
41835
|
}
|
|
39407
41836
|
}
|
|
39408
41837
|
patchConsole() {
|
|
@@ -39421,6 +41850,73 @@ class Ink {
|
|
|
39421
41850
|
}
|
|
39422
41851
|
});
|
|
39423
41852
|
}
|
|
41853
|
+
initKittyKeyboard() {
|
|
41854
|
+
// Protocol is opt-in: if kittyKeyboard is not specified, do nothing
|
|
41855
|
+
if (!this.options.kittyKeyboard) {
|
|
41856
|
+
return;
|
|
41857
|
+
}
|
|
41858
|
+
const opts = this.options.kittyKeyboard;
|
|
41859
|
+
const mode = opts.mode ?? 'auto';
|
|
41860
|
+
if (mode === 'disabled' ||
|
|
41861
|
+
!this.options.stdin.isTTY ||
|
|
41862
|
+
!this.options.stdout.isTTY) {
|
|
41863
|
+
return;
|
|
41864
|
+
}
|
|
41865
|
+
const flags = opts.flags ?? ['disambiguateEscapeCodes'];
|
|
41866
|
+
if (mode === 'enabled') {
|
|
41867
|
+
this.enableKittyProtocol(flags);
|
|
41868
|
+
return;
|
|
41869
|
+
}
|
|
41870
|
+
// Auto mode: use heuristic precheck, then confirm with protocol query
|
|
41871
|
+
const term = process$1.env['TERM'] ?? '';
|
|
41872
|
+
const termProgram = process$1.env['TERM_PROGRAM'] ?? '';
|
|
41873
|
+
const isKnownSupportingTerminal = 'KITTY_WINDOW_ID' in process$1.env ||
|
|
41874
|
+
term === 'xterm-kitty' ||
|
|
41875
|
+
termProgram === 'WezTerm' ||
|
|
41876
|
+
termProgram === 'ghostty';
|
|
41877
|
+
if (!isInCi && isKnownSupportingTerminal) {
|
|
41878
|
+
this.confirmKittySupport(flags);
|
|
41879
|
+
}
|
|
41880
|
+
}
|
|
41881
|
+
confirmKittySupport(flags) {
|
|
41882
|
+
const { stdin, stdout } = this.options;
|
|
41883
|
+
let responseBuffer = [];
|
|
41884
|
+
const cleanup = () => {
|
|
41885
|
+
this.cancelKittyDetection = undefined;
|
|
41886
|
+
clearTimeout(timer);
|
|
41887
|
+
stdin.removeListener('data', onData);
|
|
41888
|
+
// Re-emit any buffered data that wasn't the protocol response,
|
|
41889
|
+
// so it isn't lost from Ink's normal input pipeline.
|
|
41890
|
+
// Clear responseBuffer afterwards to make cleanup idempotent.
|
|
41891
|
+
const remaining = stripKittyQueryResponsesAndTrailingPartial(responseBuffer);
|
|
41892
|
+
responseBuffer = [];
|
|
41893
|
+
if (remaining.length > 0) {
|
|
41894
|
+
stdin.unshift(Buffer.from(remaining));
|
|
41895
|
+
}
|
|
41896
|
+
};
|
|
41897
|
+
const onData = (data) => {
|
|
41898
|
+
const chunk = typeof data === 'string' ? Buffer.from(data) : data;
|
|
41899
|
+
for (const byte of chunk) {
|
|
41900
|
+
responseBuffer.push(byte);
|
|
41901
|
+
}
|
|
41902
|
+
if (hasCompleteKittyQueryResponse(responseBuffer)) {
|
|
41903
|
+
cleanup();
|
|
41904
|
+
if (!this.isUnmounted) {
|
|
41905
|
+
this.enableKittyProtocol(flags);
|
|
41906
|
+
}
|
|
41907
|
+
}
|
|
41908
|
+
};
|
|
41909
|
+
// Attach listener before writing the query so that synchronous
|
|
41910
|
+
// or immediate responses are not missed.
|
|
41911
|
+
stdin.on('data', onData);
|
|
41912
|
+
const timer = setTimeout(cleanup, 200);
|
|
41913
|
+
this.cancelKittyDetection = cleanup;
|
|
41914
|
+
stdout.write('\u001B[?u');
|
|
41915
|
+
}
|
|
41916
|
+
enableKittyProtocol(flags) {
|
|
41917
|
+
this.options.stdout.write(`\u001B[>${resolveFlags(flags)}u`);
|
|
41918
|
+
this.kittyProtocolEnabled = true;
|
|
41919
|
+
}
|
|
39424
41920
|
}
|
|
39425
41921
|
|
|
39426
41922
|
/**
|
|
@@ -39436,9 +41932,10 @@ const render = (node, options) => {
|
|
|
39436
41932
|
patchConsole: true,
|
|
39437
41933
|
maxFps: 30,
|
|
39438
41934
|
incrementalRendering: false,
|
|
41935
|
+
concurrent: false,
|
|
39439
41936
|
...getOptions(options),
|
|
39440
41937
|
};
|
|
39441
|
-
const instance = getInstance(inkOptions.stdout, () => new Ink(inkOptions));
|
|
41938
|
+
const instance = getInstance(inkOptions.stdout, () => new Ink(inkOptions), inkOptions.concurrent ?? false);
|
|
39442
41939
|
instance.render(node);
|
|
39443
41940
|
return {
|
|
39444
41941
|
rerender: instance.render,
|
|
@@ -39459,12 +41956,16 @@ const getOptions = (stdout = {}) => {
|
|
|
39459
41956
|
}
|
|
39460
41957
|
return stdout;
|
|
39461
41958
|
};
|
|
39462
|
-
const getInstance = (stdout, createInstance) => {
|
|
41959
|
+
const getInstance = (stdout, createInstance, concurrent) => {
|
|
39463
41960
|
let instance = instances.get(stdout);
|
|
39464
41961
|
if (!instance) {
|
|
39465
41962
|
instance = createInstance();
|
|
39466
41963
|
instances.set(stdout, instance);
|
|
39467
41964
|
}
|
|
41965
|
+
else if (instance.isConcurrent !== concurrent) {
|
|
41966
|
+
console.warn(`Warning: render() was called with concurrent: ${concurrent}, but the existing instance for this stdout uses concurrent: ${instance.isConcurrent}. ` +
|
|
41967
|
+
`The concurrent option only takes effect on the first render. Call unmount() first if you need to change the rendering mode.`);
|
|
41968
|
+
}
|
|
39468
41969
|
return instance;
|
|
39469
41970
|
};
|
|
39470
41971
|
|
|
@@ -39584,6 +42085,249 @@ const isCtrlKey = (code) => {
|
|
|
39584
42085
|
'[8^',
|
|
39585
42086
|
].includes(code);
|
|
39586
42087
|
};
|
|
42088
|
+
// Kitty keyboard protocol: CSI codepoint ; modifiers [: eventType] [; text-as-codepoints] u
|
|
42089
|
+
const kittyKeyRe = /^\x1b\[(\d+)(?:;(\d+)(?::(\d+))?(?:;([\d:]+))?)?u$/;
|
|
42090
|
+
// Kitty-enhanced special keys: CSI number ; modifiers : eventType {letter|~}
|
|
42091
|
+
// These are legacy CSI sequences enhanced with the :eventType field.
|
|
42092
|
+
// Examples: \x1b[1;1:1A (up arrow press), \x1b[3;1:3~ (delete release)
|
|
42093
|
+
const kittySpecialKeyRe = /^\x1b\[(\d+);(\d+):(\d+)([A-Za-z~])$/;
|
|
42094
|
+
// Letter-terminated special key names (CSI 1 ; mods letter)
|
|
42095
|
+
const kittySpecialLetterKeys = {
|
|
42096
|
+
A: 'up',
|
|
42097
|
+
B: 'down',
|
|
42098
|
+
C: 'right',
|
|
42099
|
+
D: 'left',
|
|
42100
|
+
E: 'clear',
|
|
42101
|
+
F: 'end',
|
|
42102
|
+
H: 'home',
|
|
42103
|
+
P: 'f1',
|
|
42104
|
+
Q: 'f2',
|
|
42105
|
+
R: 'f3',
|
|
42106
|
+
S: 'f4',
|
|
42107
|
+
};
|
|
42108
|
+
// Number-terminated special key names (CSI number ; mods ~)
|
|
42109
|
+
const kittySpecialNumberKeys = {
|
|
42110
|
+
2: 'insert',
|
|
42111
|
+
3: 'delete',
|
|
42112
|
+
5: 'pageup',
|
|
42113
|
+
6: 'pagedown',
|
|
42114
|
+
7: 'home',
|
|
42115
|
+
8: 'end',
|
|
42116
|
+
11: 'f1',
|
|
42117
|
+
12: 'f2',
|
|
42118
|
+
13: 'f3',
|
|
42119
|
+
14: 'f4',
|
|
42120
|
+
15: 'f5',
|
|
42121
|
+
17: 'f6',
|
|
42122
|
+
18: 'f7',
|
|
42123
|
+
19: 'f8',
|
|
42124
|
+
20: 'f9',
|
|
42125
|
+
21: 'f10',
|
|
42126
|
+
23: 'f11',
|
|
42127
|
+
24: 'f12',
|
|
42128
|
+
};
|
|
42129
|
+
// Map of special codepoints to key names in kitty protocol
|
|
42130
|
+
const kittyCodepointNames = {
|
|
42131
|
+
27: 'escape',
|
|
42132
|
+
// 13 (return) and 32 (space) are handled before this lookup
|
|
42133
|
+
// in parseKittyKeypress so they can be marked as printable.
|
|
42134
|
+
9: 'tab',
|
|
42135
|
+
127: 'delete',
|
|
42136
|
+
8: 'backspace',
|
|
42137
|
+
57358: 'capslock',
|
|
42138
|
+
57359: 'scrolllock',
|
|
42139
|
+
57360: 'numlock',
|
|
42140
|
+
57361: 'printscreen',
|
|
42141
|
+
57362: 'pause',
|
|
42142
|
+
57363: 'menu',
|
|
42143
|
+
57376: 'f13',
|
|
42144
|
+
57377: 'f14',
|
|
42145
|
+
57378: 'f15',
|
|
42146
|
+
57379: 'f16',
|
|
42147
|
+
57380: 'f17',
|
|
42148
|
+
57381: 'f18',
|
|
42149
|
+
57382: 'f19',
|
|
42150
|
+
57383: 'f20',
|
|
42151
|
+
57384: 'f21',
|
|
42152
|
+
57385: 'f22',
|
|
42153
|
+
57386: 'f23',
|
|
42154
|
+
57387: 'f24',
|
|
42155
|
+
57388: 'f25',
|
|
42156
|
+
57389: 'f26',
|
|
42157
|
+
57390: 'f27',
|
|
42158
|
+
57391: 'f28',
|
|
42159
|
+
57392: 'f29',
|
|
42160
|
+
57393: 'f30',
|
|
42161
|
+
57394: 'f31',
|
|
42162
|
+
57395: 'f32',
|
|
42163
|
+
57396: 'f33',
|
|
42164
|
+
57397: 'f34',
|
|
42165
|
+
57398: 'f35',
|
|
42166
|
+
57399: 'kp0',
|
|
42167
|
+
57400: 'kp1',
|
|
42168
|
+
57401: 'kp2',
|
|
42169
|
+
57402: 'kp3',
|
|
42170
|
+
57403: 'kp4',
|
|
42171
|
+
57404: 'kp5',
|
|
42172
|
+
57405: 'kp6',
|
|
42173
|
+
57406: 'kp7',
|
|
42174
|
+
57407: 'kp8',
|
|
42175
|
+
57408: 'kp9',
|
|
42176
|
+
57409: 'kpdecimal',
|
|
42177
|
+
57410: 'kpdivide',
|
|
42178
|
+
57411: 'kpmultiply',
|
|
42179
|
+
57412: 'kpsubtract',
|
|
42180
|
+
57413: 'kpadd',
|
|
42181
|
+
57414: 'kpenter',
|
|
42182
|
+
57415: 'kpequal',
|
|
42183
|
+
57416: 'kpseparator',
|
|
42184
|
+
57417: 'kpleft',
|
|
42185
|
+
57418: 'kpright',
|
|
42186
|
+
57419: 'kpup',
|
|
42187
|
+
57420: 'kpdown',
|
|
42188
|
+
57421: 'kppageup',
|
|
42189
|
+
57422: 'kppagedown',
|
|
42190
|
+
57423: 'kphome',
|
|
42191
|
+
57424: 'kpend',
|
|
42192
|
+
57425: 'kpinsert',
|
|
42193
|
+
57426: 'kpdelete',
|
|
42194
|
+
57427: 'kpbegin',
|
|
42195
|
+
57428: 'mediaplay',
|
|
42196
|
+
57429: 'mediapause',
|
|
42197
|
+
57430: 'mediaplaypause',
|
|
42198
|
+
57431: 'mediareverse',
|
|
42199
|
+
57432: 'mediastop',
|
|
42200
|
+
57433: 'mediafastforward',
|
|
42201
|
+
57434: 'mediarewind',
|
|
42202
|
+
57435: 'mediatracknext',
|
|
42203
|
+
57436: 'mediatrackprevious',
|
|
42204
|
+
57437: 'mediarecord',
|
|
42205
|
+
57438: 'lowervolume',
|
|
42206
|
+
57439: 'raisevolume',
|
|
42207
|
+
57440: 'mutevolume',
|
|
42208
|
+
57441: 'leftshift',
|
|
42209
|
+
57442: 'leftcontrol',
|
|
42210
|
+
57443: 'leftalt',
|
|
42211
|
+
57444: 'leftsuper',
|
|
42212
|
+
57445: 'lefthyper',
|
|
42213
|
+
57446: 'leftmeta',
|
|
42214
|
+
57447: 'rightshift',
|
|
42215
|
+
57448: 'rightcontrol',
|
|
42216
|
+
57449: 'rightalt',
|
|
42217
|
+
57450: 'rightsuper',
|
|
42218
|
+
57451: 'righthyper',
|
|
42219
|
+
57452: 'rightmeta',
|
|
42220
|
+
57453: 'isoLevel3Shift',
|
|
42221
|
+
57454: 'isoLevel5Shift',
|
|
42222
|
+
};
|
|
42223
|
+
// Valid Unicode codepoint range, excluding surrogates
|
|
42224
|
+
const isValidCodepoint = (cp) => cp >= 0 && cp <= 0x10_ffff && !(cp >= 0xd8_00 && cp <= 0xdf_ff);
|
|
42225
|
+
const safeFromCodePoint = (cp) => isValidCodepoint(cp) ? String.fromCodePoint(cp) : '?';
|
|
42226
|
+
function resolveEventType(value) {
|
|
42227
|
+
if (value === 3)
|
|
42228
|
+
return 'release';
|
|
42229
|
+
if (value === 2)
|
|
42230
|
+
return 'repeat';
|
|
42231
|
+
return 'press';
|
|
42232
|
+
}
|
|
42233
|
+
function parseKittyModifiers(modifiers) {
|
|
42234
|
+
return {
|
|
42235
|
+
ctrl: !!(modifiers & kittyModifiers.ctrl),
|
|
42236
|
+
shift: !!(modifiers & kittyModifiers.shift),
|
|
42237
|
+
meta: !!(modifiers & kittyModifiers.meta),
|
|
42238
|
+
option: !!(modifiers & kittyModifiers.alt),
|
|
42239
|
+
super: !!(modifiers & kittyModifiers.super),
|
|
42240
|
+
hyper: !!(modifiers & kittyModifiers.hyper),
|
|
42241
|
+
capsLock: !!(modifiers & kittyModifiers.capsLock),
|
|
42242
|
+
numLock: !!(modifiers & kittyModifiers.numLock),
|
|
42243
|
+
};
|
|
42244
|
+
}
|
|
42245
|
+
const parseKittyKeypress = (s) => {
|
|
42246
|
+
const match = kittyKeyRe.exec(s);
|
|
42247
|
+
if (!match)
|
|
42248
|
+
return null;
|
|
42249
|
+
const codepoint = parseInt(match[1], 10);
|
|
42250
|
+
const modifiers = match[2] ? Math.max(0, parseInt(match[2], 10) - 1) : 0;
|
|
42251
|
+
const eventType = match[3] ? parseInt(match[3], 10) : 1;
|
|
42252
|
+
const textField = match[4];
|
|
42253
|
+
// Bail on invalid primary codepoint
|
|
42254
|
+
if (!isValidCodepoint(codepoint)) {
|
|
42255
|
+
return null;
|
|
42256
|
+
}
|
|
42257
|
+
// Parse text-as-codepoints field (colon-separated Unicode codepoints)
|
|
42258
|
+
let text;
|
|
42259
|
+
if (textField) {
|
|
42260
|
+
text = textField
|
|
42261
|
+
.split(':')
|
|
42262
|
+
.map(cp => safeFromCodePoint(parseInt(cp, 10)))
|
|
42263
|
+
.join('');
|
|
42264
|
+
}
|
|
42265
|
+
// Determine key name from codepoint
|
|
42266
|
+
let name;
|
|
42267
|
+
let isPrintable;
|
|
42268
|
+
if (codepoint === 32) {
|
|
42269
|
+
name = 'space';
|
|
42270
|
+
isPrintable = true;
|
|
42271
|
+
}
|
|
42272
|
+
else if (codepoint === 13) {
|
|
42273
|
+
name = 'return';
|
|
42274
|
+
isPrintable = true;
|
|
42275
|
+
}
|
|
42276
|
+
else if (kittyCodepointNames[codepoint]) {
|
|
42277
|
+
name = kittyCodepointNames[codepoint];
|
|
42278
|
+
isPrintable = false;
|
|
42279
|
+
}
|
|
42280
|
+
else if (codepoint >= 1 && codepoint <= 26) {
|
|
42281
|
+
// Ctrl+letter comes as codepoint 1-26
|
|
42282
|
+
name = String.fromCodePoint(codepoint + 96); // 'a' is 97
|
|
42283
|
+
isPrintable = false;
|
|
42284
|
+
}
|
|
42285
|
+
else {
|
|
42286
|
+
name = safeFromCodePoint(codepoint).toLowerCase();
|
|
42287
|
+
isPrintable = true;
|
|
42288
|
+
}
|
|
42289
|
+
// Default text to the character from the codepoint when not explicitly
|
|
42290
|
+
// provided by the protocol, so keys like space and return produce their
|
|
42291
|
+
// expected text input (' ' and '\r' respectively).
|
|
42292
|
+
if (isPrintable && !text) {
|
|
42293
|
+
text = safeFromCodePoint(codepoint);
|
|
42294
|
+
}
|
|
42295
|
+
return {
|
|
42296
|
+
name,
|
|
42297
|
+
...parseKittyModifiers(modifiers),
|
|
42298
|
+
eventType: resolveEventType(eventType),
|
|
42299
|
+
sequence: s,
|
|
42300
|
+
raw: s,
|
|
42301
|
+
isKittyProtocol: true,
|
|
42302
|
+
isPrintable,
|
|
42303
|
+
text,
|
|
42304
|
+
};
|
|
42305
|
+
};
|
|
42306
|
+
// Parse kitty-enhanced special key sequences (arrow keys, function keys, etc.)
|
|
42307
|
+
// These use the legacy CSI format but with an added :eventType field.
|
|
42308
|
+
const parseKittySpecialKey = (s) => {
|
|
42309
|
+
const match = kittySpecialKeyRe.exec(s);
|
|
42310
|
+
if (!match)
|
|
42311
|
+
return null;
|
|
42312
|
+
const number = parseInt(match[1], 10);
|
|
42313
|
+
const modifiers = Math.max(0, parseInt(match[2], 10) - 1);
|
|
42314
|
+
const eventType = parseInt(match[3], 10);
|
|
42315
|
+
const terminator = match[4];
|
|
42316
|
+
const name = terminator === '~'
|
|
42317
|
+
? kittySpecialNumberKeys[number]
|
|
42318
|
+
: kittySpecialLetterKeys[terminator];
|
|
42319
|
+
if (!name)
|
|
42320
|
+
return null;
|
|
42321
|
+
return {
|
|
42322
|
+
name,
|
|
42323
|
+
...parseKittyModifiers(modifiers),
|
|
42324
|
+
eventType: resolveEventType(eventType),
|
|
42325
|
+
sequence: s,
|
|
42326
|
+
raw: s,
|
|
42327
|
+
isKittyProtocol: true,
|
|
42328
|
+
isPrintable: false,
|
|
42329
|
+
};
|
|
42330
|
+
};
|
|
39587
42331
|
const parseKeypress = (s = '') => {
|
|
39588
42332
|
let parts;
|
|
39589
42333
|
if (Buffer$1.isBuffer(s)) {
|
|
@@ -39601,6 +42345,29 @@ const parseKeypress = (s = '') => {
|
|
|
39601
42345
|
else if (!s) {
|
|
39602
42346
|
s = '';
|
|
39603
42347
|
}
|
|
42348
|
+
// Try kitty keyboard protocol parsers first
|
|
42349
|
+
const kittyResult = parseKittyKeypress(s);
|
|
42350
|
+
if (kittyResult)
|
|
42351
|
+
return kittyResult;
|
|
42352
|
+
const kittySpecialResult = parseKittySpecialKey(s);
|
|
42353
|
+
if (kittySpecialResult)
|
|
42354
|
+
return kittySpecialResult;
|
|
42355
|
+
// If the input matched the kitty CSI-u pattern but was rejected (e.g.,
|
|
42356
|
+
// invalid codepoint), return a safe empty keypress instead of falling
|
|
42357
|
+
// through to legacy parsing which can produce unsafe states (undefined name)
|
|
42358
|
+
if (kittyKeyRe.test(s)) {
|
|
42359
|
+
return {
|
|
42360
|
+
name: '',
|
|
42361
|
+
ctrl: false,
|
|
42362
|
+
meta: false,
|
|
42363
|
+
shift: false,
|
|
42364
|
+
option: false,
|
|
42365
|
+
sequence: s,
|
|
42366
|
+
raw: s,
|
|
42367
|
+
isKittyProtocol: true,
|
|
42368
|
+
isPrintable: false,
|
|
42369
|
+
};
|
|
42370
|
+
}
|
|
39604
42371
|
const key = {
|
|
39605
42372
|
name: '',
|
|
39606
42373
|
ctrl: false,
|
|
@@ -39611,10 +42378,11 @@ const parseKeypress = (s = '') => {
|
|
|
39611
42378
|
raw: s,
|
|
39612
42379
|
};
|
|
39613
42380
|
key.sequence = key.sequence || s || key.name;
|
|
39614
|
-
if (s === '\r') {
|
|
39615
|
-
// carriage return
|
|
42381
|
+
if (s === '\r' || s === '\x1b\r') {
|
|
42382
|
+
// carriage return (or option+return on macOS)
|
|
39616
42383
|
key.raw = undefined;
|
|
39617
42384
|
key.name = 'return';
|
|
42385
|
+
key.option = s.length === 2;
|
|
39618
42386
|
}
|
|
39619
42387
|
else if (s === '\n') {
|
|
39620
42388
|
// enter, should have been called linefeed
|
|
@@ -39742,6 +42510,8 @@ const useInput = (inputHandler, options = {}) => {
|
|
|
39742
42510
|
rightArrow: keypress.name === 'right',
|
|
39743
42511
|
pageDown: keypress.name === 'pagedown',
|
|
39744
42512
|
pageUp: keypress.name === 'pageup',
|
|
42513
|
+
home: keypress.name === 'home',
|
|
42514
|
+
end: keypress.name === 'end',
|
|
39745
42515
|
return: keypress.name === 'return',
|
|
39746
42516
|
escape: keypress.name === 'escape',
|
|
39747
42517
|
ctrl: keypress.ctrl,
|
|
@@ -39754,9 +42524,38 @@ const useInput = (inputHandler, options = {}) => {
|
|
|
39754
42524
|
// to avoid breaking changes in Ink.
|
|
39755
42525
|
// TODO(vadimdemedes): consider removing this in the next major version.
|
|
39756
42526
|
meta: keypress.meta || keypress.name === 'escape' || keypress.option,
|
|
42527
|
+
// Kitty keyboard protocol modifiers
|
|
42528
|
+
super: keypress.super ?? false,
|
|
42529
|
+
hyper: keypress.hyper ?? false,
|
|
42530
|
+
capsLock: keypress.capsLock ?? false,
|
|
42531
|
+
numLock: keypress.numLock ?? false,
|
|
42532
|
+
eventType: keypress.eventType,
|
|
39757
42533
|
};
|
|
39758
|
-
let input
|
|
39759
|
-
if (
|
|
42534
|
+
let input;
|
|
42535
|
+
if (keypress.isKittyProtocol) {
|
|
42536
|
+
// Use text-as-codepoints field for printable keys (needed when
|
|
42537
|
+
// reportAllKeysAsEscapeCodes flag is enabled), suppress non-printable
|
|
42538
|
+
if (keypress.isPrintable) {
|
|
42539
|
+
input = keypress.text ?? keypress.name;
|
|
42540
|
+
}
|
|
42541
|
+
else if (keypress.ctrl && keypress.name.length === 1) {
|
|
42542
|
+
// Ctrl+letter via codepoint 1-26 form: not printable text, but
|
|
42543
|
+
// the letter name must flow through so handlers (e.g. exitOnCtrlC
|
|
42544
|
+
// checking `input === 'c' && key.ctrl`) still work.
|
|
42545
|
+
input = keypress.name;
|
|
42546
|
+
}
|
|
42547
|
+
else {
|
|
42548
|
+
input = '';
|
|
42549
|
+
}
|
|
42550
|
+
}
|
|
42551
|
+
else if (keypress.ctrl) {
|
|
42552
|
+
input = keypress.name;
|
|
42553
|
+
}
|
|
42554
|
+
else {
|
|
42555
|
+
input = keypress.sequence;
|
|
42556
|
+
}
|
|
42557
|
+
if (!keypress.isKittyProtocol &&
|
|
42558
|
+
nonAlphanumericKeys.includes(keypress.name)) {
|
|
39760
42559
|
input = '';
|
|
39761
42560
|
}
|
|
39762
42561
|
// Strip meta if it's still remaining after `parseKeypress`
|
|
@@ -40253,4 +43052,4 @@ const layout = {
|
|
|
40253
43052
|
};
|
|
40254
43053
|
|
|
40255
43054
|
export { AppContext as A, Box as B, React as R, Text as T, useStdout as a, render as b, colors as c, jsxRuntimeExports as j, layout as l, reactExports as r, symbols as s, useInput as u };
|
|
40256
|
-
//# sourceMappingURL=theme-
|
|
43055
|
+
//# sourceMappingURL=theme-BmodcXss.js.map
|