@alchemy.run/sigil 0.0.0-alpha.3 → 0.0.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -13
- package/THIRD_PARTY_NOTICES.md +70 -23
- package/dist/Text-D5HUf3Fj.d.ts +452 -0
- package/dist/ansi.d.ts +137 -143
- package/dist/ansi.js +87 -2
- package/dist/capabilities.d.ts +5 -0
- package/dist/capabilities.js +3 -0
- package/dist/cell-_ZVhbfl0.js +44 -0
- package/dist/color-CkbalRqK.js +2 -0
- package/dist/color-policy-BMzMwV7Q.d.ts +22 -0
- package/dist/color-policy-SVj1pYTA.js +560 -0
- package/dist/color-profile-DHhQHY55.js +36 -0
- package/dist/color-profile-u0Nhe9Nv.d.ts +97 -0
- package/dist/color.d.ts +21 -0
- package/dist/color.js +3 -0
- package/dist/cursor-position-D2LAkRG0.d.ts +7 -0
- package/dist/detect-Bh4yGP6w.d.ts +186 -0
- package/dist/detect-BuTXtY6e.js +373 -0
- package/dist/{devtools-BhYGjb7h.js → devtools-DbthxoD1.js} +22 -23
- package/dist/env-YVw64yZS.js +9 -0
- package/dist/escapes-CB_6CWOE.d.ts +72 -0
- package/dist/geometry-BxXOzJgo.d.ts +11 -0
- package/dist/index-Bmc2tRPk.d.ts +21 -0
- package/dist/index.d.ts +235 -754
- package/dist/index.js +1362 -3001
- package/dist/osc-CCH7xDoS.js +71 -0
- package/dist/osc-Cn0fw77g.d.ts +23 -0
- package/dist/paint-C19minOS.d.ts +81 -0
- package/dist/query-vaIeGOkH.d.ts +152 -0
- package/dist/router.d.ts +392 -0
- package/dist/router.js +709 -0
- package/dist/sample-Cqw1bjUL.js +445 -0
- package/dist/screen-BOh__-65.js +324 -0
- package/dist/screen-BReKIheE.d.ts +40 -0
- package/dist/screen.d.ts +5 -0
- package/dist/screen.js +5 -0
- package/dist/semantic-text-style-DIMzC7xt.js +91 -0
- package/dist/serialize-BTkAZgw1.js +79 -0
- package/dist/session-BJmzX2NJ.js +664 -0
- package/dist/sgr-BhwaWAJB.js +246 -0
- package/dist/store-CgrG9K4y.d.ts +72 -0
- package/dist/string-width-CijQwpIk.js +69 -0
- package/dist/strip-BvU4toXG.js +6 -0
- package/dist/terminal.d.ts +118 -0
- package/dist/terminal.js +2 -0
- package/dist/tokenize-AjqbvtiT.js +1242 -0
- package/dist/tokenize-Dx1y_l5H.d.ts +57 -0
- package/dist/truncate-D31fhU6i.js +562 -0
- package/dist/use-focus-C2sciZOo.js +1335 -0
- package/package.json +43 -17
- package/src/ansi/chalk.ts +12 -53
- package/src/ansi/cursor.ts +2 -4
- package/src/ansi/east-asian-width.ts +44 -0
- package/src/ansi/escapes.ts +18 -26
- package/src/ansi/graphemes.ts +8 -0
- package/src/ansi/hyperlink.ts +44 -0
- package/src/ansi/index.ts +14 -14
- package/src/ansi/osc.ts +77 -0
- package/src/ansi/sgr.ts +2 -5
- package/src/ansi/slice.ts +1 -1
- package/src/ansi/string-width.ts +91 -206
- package/src/ansi/strip.ts +13 -33
- package/src/ansi/tokenize.ts +96 -169
- package/src/ansi/truncate.ts +5 -3
- package/src/ansi/wrap.ts +13 -14
- package/src/ansi-tokenizer.ts +1 -1
- package/src/capabilities/color-policy.ts +34 -0
- package/src/capabilities/detect.ts +594 -0
- package/src/capabilities/index.ts +37 -0
- package/src/capabilities/query.ts +657 -0
- package/src/capabilities/store.ts +379 -0
- package/src/color/index.ts +3 -0
- package/src/color/paint.ts +169 -0
- package/src/color/palette.ts +48 -0
- package/src/color/sample.ts +323 -0
- package/src/color.ts +1 -0
- package/src/components/AnsiText.tsx +42 -0
- package/src/components/App.tsx +109 -22
- package/src/components/BackgroundContext.ts +2 -3
- package/src/components/Box.tsx +43 -60
- package/src/components/CursorContext.ts +1 -1
- package/src/components/ErrorBoundary.tsx +1 -1
- package/src/components/ErrorOverview.tsx +8 -7
- package/src/components/Hyperlink.tsx +56 -0
- package/src/components/Spacer.tsx +1 -1
- package/src/components/Static.tsx +1 -1
- package/src/components/StderrContext.ts +0 -2
- package/src/components/StdinContext.ts +0 -1
- package/src/components/StdoutContext.ts +1 -3
- package/src/components/TerminalOscContext.ts +25 -0
- package/src/components/Text.tsx +23 -46
- package/src/components/Transform.tsx +2 -2
- package/src/cursor-position.ts +1 -1
- package/src/devtools.ts +84 -24
- package/src/dom.ts +11 -8
- package/src/env.ts +12 -0
- package/src/get-max-width.ts +1 -1
- package/src/global.d.ts +6 -4
- package/src/{boxes.ts → glyphs.ts} +17 -18
- package/src/hooks/use-animation.ts +1 -1
- package/src/hooks/use-app.ts +1 -1
- package/src/hooks/use-box-metrics.ts +1 -1
- package/src/hooks/use-capabilities.ts +73 -0
- package/src/hooks/use-cursor.ts +3 -3
- package/src/hooks/use-focus-manager.ts +1 -1
- package/src/hooks/use-focus.ts +5 -6
- package/src/hooks/use-input.ts +4 -4
- package/src/hooks/use-is-screen-reader-enabled.ts +1 -1
- package/src/hooks/use-paste.ts +2 -2
- package/src/hooks/use-stderr.ts +1 -1
- package/src/hooks/use-stdin.ts +1 -1
- package/src/hooks/use-stdout.ts +1 -1
- package/src/hooks/use-terminal-osc.ts +59 -0
- package/src/hooks/use-window-size.ts +2 -2
- package/src/index.ts +88 -44
- package/src/ink.tsx +620 -745
- package/src/input-parser.ts +1 -1
- package/src/instances.ts +1 -1
- package/src/kitty-keyboard.ts +128 -0
- package/src/measure-element.ts +1 -1
- package/src/measure-text.ts +2 -2
- package/src/{render-node-to-output.ts → paint-tree.ts} +78 -53
- package/src/parse-keypress.ts +4 -5
- package/src/parse-stack-line.ts +0 -1
- package/src/patch-console.ts +44 -0
- package/src/reconciler.ts +36 -62
- package/src/render-background.ts +37 -16
- package/src/render-border.ts +97 -64
- package/src/render-frame.ts +83 -0
- package/src/render-to-string.ts +24 -9
- package/src/render.ts +24 -16
- package/src/router/components.tsx +343 -0
- package/src/router/context.ts +41 -0
- package/src/router/history.ts +194 -0
- package/src/router/hooks.tsx +391 -0
- package/src/router/index.ts +34 -0
- package/src/router/matcher.ts +571 -0
- package/src/sanitize-ansi.ts +1 -1
- package/src/screen/ansi.ts +184 -0
- package/src/screen/canvas.ts +137 -0
- package/src/screen/cell.ts +138 -0
- package/src/screen/color-profile.ts +47 -0
- package/src/screen/geometry.ts +9 -0
- package/src/screen/index.ts +6 -0
- package/src/screen/screen.ts +272 -0
- package/src/screen/serialize.ts +129 -0
- package/src/screen.ts +1 -0
- package/src/semantic-text-style.ts +118 -0
- package/src/signal-exit.ts +4 -5
- package/src/squash-text-nodes.ts +4 -7
- package/src/stream.ts +2 -4
- package/src/structured-text.ts +321 -0
- package/src/styles.ts +16 -17
- package/src/terminal/index.ts +2 -0
- package/src/terminal/inline-presenter.ts +120 -0
- package/src/terminal/input.ts +86 -0
- package/src/terminal/render-scheduler.ts +37 -0
- package/src/terminal/screen-presenter.ts +188 -0
- package/src/terminal/session.ts +407 -0
- package/src/terminal-size.ts +9 -8
- package/src/terminal.ts +1 -0
- package/src/testing/browser.ts +588 -0
- package/src/testing/emulators.ts +205 -0
- package/src/testing/explorer-app/index.html +12 -0
- package/src/testing/explorer-app/main.ts +381 -0
- package/src/testing/explorer-app/style.css +194 -0
- package/src/testing/explorer-app/tsconfig.json +15 -0
- package/src/testing/explorer-app/vite-env.d.ts +1 -0
- package/src/testing/index.ts +26 -0
- package/src/testing/keys.ts +56 -0
- package/src/testing/live.ts +85 -0
- package/src/testing/matchers.ts +70 -0
- package/src/testing/public.ts +94 -0
- package/src/testing/terminal.ts +349 -0
- package/src/testing/vitest.ts +157 -0
- package/src/transform-adapter.ts +14 -0
- package/src/types.ts +1 -6
- package/src/utils.ts +2 -2
- package/src/wrap-text.ts +4 -4
- package/src/yoga/config.ts +2 -2
- package/src/yoga/core/absoluteLayout.ts +15 -15
- package/src/yoga/core/baseline.ts +3 -3
- package/src/yoga/core/cache.ts +4 -4
- package/src/yoga/core/calculateLayout.ts +33 -27
- package/src/yoga/core/config.ts +1 -1
- package/src/yoga/core/flexLine.ts +3 -3
- package/src/yoga/core/helpers.ts +3 -3
- package/src/yoga/core/layoutResults.ts +4 -4
- package/src/yoga/core/node.ts +16 -16
- package/src/yoga/core/pixelGrid.ts +4 -4
- package/src/yoga/core/style.ts +11 -11
- package/src/yoga/core/types.ts +2 -2
- package/src/yoga/index.ts +6 -6
- package/src/yoga/node.ts +8 -8
- package/dist/sgr-CMfEpjSk.d.ts +0 -91
- package/dist/truncate-CBiyyZzw.js +0 -2156
- package/src/ansi/supports-color.ts +0 -213
- package/src/ansi/widest-line.ts +0 -12
- package/src/auto-bind.ts +0 -41
- package/src/colorize.ts +0 -60
- package/src/devtools-window-polyfill.ts +0 -73
- package/src/indent-string.ts +0 -16
- package/src/is-in-ci.ts +0 -7
- package/src/log-update.ts +0 -370
- package/src/output.ts +0 -308
- package/src/renderer.ts +0 -73
- package/src/write-synchronized.ts +0 -9
package/dist/index.js
CHANGED
|
@@ -1,198 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as bsu, S as ansiEscapes, V as esu, W as link, _ as CSI } from "./sgr-BhwaWAJB.js";
|
|
2
|
+
import { h as tokenizeAnsi, p as graphemes } from "./tokenize-AjqbvtiT.js";
|
|
3
|
+
import { t as stringWidth } from "./string-width-CijQwpIk.js";
|
|
4
|
+
import { n as sliceAnsi, r as wrapAnsi } from "./truncate-D31fhU6i.js";
|
|
5
|
+
import { _ as squashTextNodes, a as reconciler, c as kittyModifiers, d as FocusContext, f as Text, g as transformAnsiLine, h as emitLayoutListeners, i as useStdinContext, l as resolveFlags, m as createNode, n as useInput, o as detectKittySupport, p as addLayoutListener, r as useStdin, s as kittyFlags, t as useFocus, u as StdinContext, v as accessibilityContext } from "./use-focus-C2sciZOo.js";
|
|
6
|
+
import { a as isTty, i as isSigilDev, o as isWindows, r as isScreenReader, t as isInCi } from "./env-YVw64yZS.js";
|
|
7
|
+
import { a as detectTerminal, c as signalExit, i as detectHyperlinkSupport, n as detectCapabilities, o as detectUnicodeSupport, r as detectColorLevel, s as terminalSize, t as createSupportsColor } from "./detect-BuTXtY6e.js";
|
|
8
|
+
import { u as cliCursor } from "./osc-CCH7xDoS.js";
|
|
9
|
+
import { a as registerTerminalIntegration, c as ensureTerminalQuery, d as queryTerminal, f as refreshTerminalQuery, i as getCapabilities, l as getTerminalQuery, o as getRawModeStream, r as capabilities, s as applyTerminalQuery, u as getTerminalQueryPromise } from "./color-policy-SVj1pYTA.js";
|
|
10
|
+
import { a as buildCursorSuffix, c as hideCursorEscape, i as buildCursorOnlySequence, o as buildReturnToBottomPrefix, s as cursorPositionChanged, t as TerminalSession } from "./session-BJmzX2NJ.js";
|
|
2
11
|
import { t as Yoga } from "./yoga-5jKhYCJC.js";
|
|
3
|
-
import
|
|
12
|
+
import { r as createCell, t as cellAttributes } from "./cell-_ZVhbfl0.js";
|
|
13
|
+
import { i as semanticTextStyleToCellStyle, n as mergeSemanticTextStyles, t as emptySemanticTextStyle } from "./semantic-text-style-DIMzC7xt.js";
|
|
14
|
+
import { a as samplePaint } from "./sample-Cqw1bjUL.js";
|
|
15
|
+
import { n as cellFromStyledChar, r as cellsFromAnsi, t as Screen } from "./screen-BOh__-65.js";
|
|
16
|
+
import { t as colorProfileFromLevel } from "./color-profile-DHhQHY55.js";
|
|
17
|
+
import { n as serializeScreen, t as serializeLine } from "./serialize-BTkAZgw1.js";
|
|
18
|
+
import { t as stripAnsi } from "./strip-BvU4toXG.js";
|
|
19
|
+
import "./color-CkbalRqK.js";
|
|
4
20
|
import { PassThrough, Stream } from "node:stream";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
21
|
+
import { setImmediate as setImmediate$1 } from "node:timers/promises";
|
|
22
|
+
import { isNativeError } from "node:util/types";
|
|
23
|
+
import { PureComponent, createContext, useCallback, useContext, useEffect, useEffectEvent, useInsertionEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
24
|
+
import "react-reconciler";
|
|
25
|
+
import { ConcurrentRoot, LegacyRoot } from "react-reconciler/constants.js";
|
|
7
26
|
import { EventEmitter } from "node:events";
|
|
8
|
-
import
|
|
9
|
-
import
|
|
27
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
28
|
+
import { cwd } from "node:process";
|
|
10
29
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
-
import tty from "node:tty";
|
|
12
30
|
import { Console } from "node:console";
|
|
13
|
-
import createReconciler from "react-reconciler";
|
|
14
|
-
import * as Scheduler from "scheduler";
|
|
15
|
-
//#region src/auto-bind.ts
|
|
16
|
-
const getAllProperties = (object) => {
|
|
17
|
-
const properties = [];
|
|
18
|
-
let current = object;
|
|
19
|
-
do {
|
|
20
|
-
for (const key of Reflect.ownKeys(current)) properties.push([current, key]);
|
|
21
|
-
current = Reflect.getPrototypeOf(current);
|
|
22
|
-
} while (current && current !== Object.prototype);
|
|
23
|
-
return properties;
|
|
24
|
-
};
|
|
25
|
-
const autoBind = (self) => {
|
|
26
|
-
for (const [object, key] of getAllProperties(self.constructor.prototype)) {
|
|
27
|
-
if (key === "constructor") continue;
|
|
28
|
-
const descriptor = Reflect.getOwnPropertyDescriptor(object, key);
|
|
29
|
-
if (descriptor && typeof descriptor.value === "function") {
|
|
30
|
-
const value = self[key];
|
|
31
|
-
if (typeof value === "function") self[key] = value.bind(self);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return self;
|
|
35
|
-
};
|
|
36
|
-
//#endregion
|
|
37
|
-
//#region src/components/AccessibilityContext.ts
|
|
38
|
-
const accessibilityContext = createContext({ isScreenReaderEnabled: false });
|
|
39
|
-
//#endregion
|
|
40
|
-
//#region src/input-parser.ts
|
|
41
|
-
const escape$1 = "\x1B";
|
|
42
|
-
const isCsiParameterByte = (byte) => {
|
|
43
|
-
return byte >= 48 && byte <= 63;
|
|
44
|
-
};
|
|
45
|
-
const isCsiIntermediateByte = (byte) => {
|
|
46
|
-
return byte >= 32 && byte <= 47;
|
|
47
|
-
};
|
|
48
|
-
const isCsiFinalByte = (byte) => {
|
|
49
|
-
return byte >= 64 && byte <= 126;
|
|
50
|
-
};
|
|
51
|
-
const parseCsiSequence = (input, startIndex, prefixLength) => {
|
|
52
|
-
const csiPayloadStart = startIndex + prefixLength + 1;
|
|
53
|
-
let index = csiPayloadStart;
|
|
54
|
-
for (; index < input.length; index++) {
|
|
55
|
-
const byte = input.codePointAt(index);
|
|
56
|
-
if (byte === void 0) return "pending";
|
|
57
|
-
if (isCsiParameterByte(byte) || isCsiIntermediateByte(byte)) continue;
|
|
58
|
-
if (byte === 91 && index === csiPayloadStart) continue;
|
|
59
|
-
if (isCsiFinalByte(byte)) return {
|
|
60
|
-
sequence: input.slice(startIndex, index + 1),
|
|
61
|
-
nextIndex: index + 1
|
|
62
|
-
};
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
return "pending";
|
|
66
|
-
};
|
|
67
|
-
const parseSs3Sequence = (input, startIndex, prefixLength) => {
|
|
68
|
-
const nextIndex = startIndex + prefixLength + 2;
|
|
69
|
-
if (nextIndex > input.length) return "pending";
|
|
70
|
-
const finalByte = input.codePointAt(nextIndex - 1);
|
|
71
|
-
if (finalByte === void 0 || !isCsiFinalByte(finalByte)) return;
|
|
72
|
-
return {
|
|
73
|
-
sequence: input.slice(startIndex, nextIndex),
|
|
74
|
-
nextIndex
|
|
75
|
-
};
|
|
76
|
-
};
|
|
77
|
-
const parseControlSequence = (input, startIndex, prefixLength) => {
|
|
78
|
-
const sequenceType = input[startIndex + prefixLength];
|
|
79
|
-
if (sequenceType === void 0) return "pending";
|
|
80
|
-
if (sequenceType === "[") return parseCsiSequence(input, startIndex, prefixLength);
|
|
81
|
-
if (sequenceType === "O") return parseSs3Sequence(input, startIndex, prefixLength);
|
|
82
|
-
};
|
|
83
|
-
const parseEscapedCodePoint = (input, escapeIndex) => {
|
|
84
|
-
const nextCodePoint = input.codePointAt(escapeIndex + 1);
|
|
85
|
-
const nextCodePointLength = nextCodePoint !== void 0 && nextCodePoint > 65535 ? 2 : 1;
|
|
86
|
-
const nextIndex = escapeIndex + 1 + nextCodePointLength;
|
|
87
|
-
return {
|
|
88
|
-
sequence: input.slice(escapeIndex, nextIndex),
|
|
89
|
-
nextIndex
|
|
90
|
-
};
|
|
91
|
-
};
|
|
92
|
-
const parseEscapeSequence = (input, escapeIndex) => {
|
|
93
|
-
if (escapeIndex === input.length - 1) return "pending";
|
|
94
|
-
if (input[escapeIndex + 1] === escape$1) {
|
|
95
|
-
if (escapeIndex + 2 >= input.length) return "pending";
|
|
96
|
-
const doubleEscapeSequence = parseControlSequence(input, escapeIndex, 2);
|
|
97
|
-
if (doubleEscapeSequence === "pending") return "pending";
|
|
98
|
-
if (doubleEscapeSequence) return doubleEscapeSequence;
|
|
99
|
-
return {
|
|
100
|
-
sequence: input.slice(escapeIndex, escapeIndex + 2),
|
|
101
|
-
nextIndex: escapeIndex + 2
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
const controlSequence = parseControlSequence(input, escapeIndex, 1);
|
|
105
|
-
if (controlSequence === "pending") return "pending";
|
|
106
|
-
if (controlSequence) return controlSequence;
|
|
107
|
-
return parseEscapedCodePoint(input, escapeIndex);
|
|
108
|
-
};
|
|
109
|
-
/**
|
|
110
|
-
Split a chunk of non-escape text so that backspace bytes (`0x7F` and `0x08`) become individual events. When a user holds the backspace key, the terminal sends repeated bytes in a single stdin chunk. Without splitting, `parseKeypress` receives the multi-byte string and fails to recognize it as a key event, corrupting the input state.
|
|
111
|
-
|
|
112
|
-
Other control characters like `\r` and `\t` are NOT split because they can legitimately appear inside pasted text.
|
|
113
|
-
*/
|
|
114
|
-
const splitBackspaceBytes = (text, events) => {
|
|
115
|
-
let textSegmentStart = 0;
|
|
116
|
-
for (let index = 0; index < text.length; index++) {
|
|
117
|
-
const character = text[index];
|
|
118
|
-
if (character === "" || character === "\b") {
|
|
119
|
-
if (index > textSegmentStart) events.push(text.slice(textSegmentStart, index));
|
|
120
|
-
events.push(character);
|
|
121
|
-
textSegmentStart = index + 1;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
if (textSegmentStart < text.length) events.push(text.slice(textSegmentStart));
|
|
125
|
-
};
|
|
126
|
-
const parseKeypresses = (input) => {
|
|
127
|
-
const events = [];
|
|
128
|
-
let index = 0;
|
|
129
|
-
const pendingFrom = (pendingStartIndex) => ({
|
|
130
|
-
events,
|
|
131
|
-
pending: input.slice(pendingStartIndex)
|
|
132
|
-
});
|
|
133
|
-
while (index < input.length) {
|
|
134
|
-
const escapeIndex = input.indexOf(escape$1, index);
|
|
135
|
-
if (escapeIndex === -1) {
|
|
136
|
-
splitBackspaceBytes(input.slice(index), events);
|
|
137
|
-
return {
|
|
138
|
-
events,
|
|
139
|
-
pending: ""
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
if (escapeIndex > index) splitBackspaceBytes(input.slice(index, escapeIndex), events);
|
|
143
|
-
const parsedEscapeSequence = parseEscapeSequence(input, escapeIndex);
|
|
144
|
-
if (parsedEscapeSequence === "pending") return pendingFrom(escapeIndex);
|
|
145
|
-
if (parsedEscapeSequence.sequence === pasteStart) {
|
|
146
|
-
const afterStart = parsedEscapeSequence.nextIndex;
|
|
147
|
-
const endIndex = input.indexOf(pasteEnd, afterStart);
|
|
148
|
-
if (endIndex === -1) return pendingFrom(escapeIndex);
|
|
149
|
-
events.push({ paste: input.slice(afterStart, endIndex) });
|
|
150
|
-
index = endIndex + pasteEnd.length;
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
events.push(parsedEscapeSequence.sequence);
|
|
154
|
-
index = parsedEscapeSequence.nextIndex;
|
|
155
|
-
}
|
|
156
|
-
return {
|
|
157
|
-
events,
|
|
158
|
-
pending: ""
|
|
159
|
-
};
|
|
160
|
-
};
|
|
161
|
-
const createInputParser = () => {
|
|
162
|
-
let pending = "";
|
|
163
|
-
return {
|
|
164
|
-
push(chunk) {
|
|
165
|
-
const parsedInput = parseKeypresses(pending + chunk);
|
|
166
|
-
pending = parsedInput.pending;
|
|
167
|
-
return parsedInput.events;
|
|
168
|
-
},
|
|
169
|
-
hasPendingEscape() {
|
|
170
|
-
return pending.startsWith(escape$1) && !pending.startsWith(pasteStart) && pending !== pasteStart.slice(0, -1);
|
|
171
|
-
},
|
|
172
|
-
flushPendingEscape() {
|
|
173
|
-
if (!pending.startsWith(escape$1)) return;
|
|
174
|
-
const pendingEscape = pending;
|
|
175
|
-
pending = "";
|
|
176
|
-
return pendingEscape;
|
|
177
|
-
},
|
|
178
|
-
reset() {
|
|
179
|
-
pending = "";
|
|
180
|
-
}
|
|
181
|
-
};
|
|
182
|
-
};
|
|
183
|
-
//#endregion
|
|
184
|
-
//#region src/stream.ts
|
|
185
|
-
const isTty = (stream) => {
|
|
186
|
-
return "isTTY" in stream && stream.isTTY === true;
|
|
187
|
-
};
|
|
188
|
-
const isRawModeStream = (stdin) => {
|
|
189
|
-
return isTty(stdin) && "setRawMode" in stdin && typeof stdin.setRawMode === "function";
|
|
190
|
-
};
|
|
191
|
-
const getRawModeStream = (stdin) => {
|
|
192
|
-
if (!isRawModeStream(stdin)) return;
|
|
193
|
-
return stdin;
|
|
194
|
-
};
|
|
195
|
-
//#endregion
|
|
196
31
|
//#region src/components/AnimationContext.ts
|
|
197
32
|
const animationContext = createContext({
|
|
198
33
|
renderThrottleMs: 0,
|
|
@@ -247,6 +82,119 @@ const codeExcerpt = (source, line, options = {}) => {
|
|
|
247
82
|
}));
|
|
248
83
|
};
|
|
249
84
|
//#endregion
|
|
85
|
+
//#region src/glyphs.ts
|
|
86
|
+
const BOXES = {
|
|
87
|
+
single: {
|
|
88
|
+
topLeft: "┌",
|
|
89
|
+
top: "─",
|
|
90
|
+
topRight: "┐",
|
|
91
|
+
right: "│",
|
|
92
|
+
bottomRight: "┘",
|
|
93
|
+
bottom: "─",
|
|
94
|
+
bottomLeft: "└",
|
|
95
|
+
left: "│"
|
|
96
|
+
},
|
|
97
|
+
double: {
|
|
98
|
+
topLeft: "╔",
|
|
99
|
+
top: "═",
|
|
100
|
+
topRight: "╗",
|
|
101
|
+
right: "║",
|
|
102
|
+
bottomRight: "╝",
|
|
103
|
+
bottom: "═",
|
|
104
|
+
bottomLeft: "╚",
|
|
105
|
+
left: "║"
|
|
106
|
+
},
|
|
107
|
+
round: {
|
|
108
|
+
topLeft: "╭",
|
|
109
|
+
top: "─",
|
|
110
|
+
topRight: "╮",
|
|
111
|
+
right: "│",
|
|
112
|
+
bottomRight: "╯",
|
|
113
|
+
bottom: "─",
|
|
114
|
+
bottomLeft: "╰",
|
|
115
|
+
left: "│"
|
|
116
|
+
},
|
|
117
|
+
bold: {
|
|
118
|
+
topLeft: "┏",
|
|
119
|
+
top: "━",
|
|
120
|
+
topRight: "┓",
|
|
121
|
+
right: "┃",
|
|
122
|
+
bottomRight: "┛",
|
|
123
|
+
bottom: "━",
|
|
124
|
+
bottomLeft: "┗",
|
|
125
|
+
left: "┃"
|
|
126
|
+
},
|
|
127
|
+
singleDouble: {
|
|
128
|
+
topLeft: "╓",
|
|
129
|
+
top: "─",
|
|
130
|
+
topRight: "╖",
|
|
131
|
+
right: "║",
|
|
132
|
+
bottomRight: "╜",
|
|
133
|
+
bottom: "─",
|
|
134
|
+
bottomLeft: "╙",
|
|
135
|
+
left: "║"
|
|
136
|
+
},
|
|
137
|
+
doubleSingle: {
|
|
138
|
+
topLeft: "╒",
|
|
139
|
+
top: "═",
|
|
140
|
+
topRight: "╕",
|
|
141
|
+
right: "│",
|
|
142
|
+
bottomRight: "╛",
|
|
143
|
+
bottom: "═",
|
|
144
|
+
bottomLeft: "╘",
|
|
145
|
+
left: "│"
|
|
146
|
+
},
|
|
147
|
+
classic: {
|
|
148
|
+
topLeft: "+",
|
|
149
|
+
top: "-",
|
|
150
|
+
topRight: "+",
|
|
151
|
+
right: "|",
|
|
152
|
+
bottomRight: "+",
|
|
153
|
+
bottom: "-",
|
|
154
|
+
bottomLeft: "+",
|
|
155
|
+
left: "|"
|
|
156
|
+
},
|
|
157
|
+
arrow: {
|
|
158
|
+
topLeft: "↘",
|
|
159
|
+
top: "↓",
|
|
160
|
+
topRight: "↙",
|
|
161
|
+
right: "←",
|
|
162
|
+
bottomRight: "↖",
|
|
163
|
+
bottom: "↑",
|
|
164
|
+
bottomLeft: "↗",
|
|
165
|
+
left: "→"
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/components/Box.tsx
|
|
170
|
+
/** @jsxImportSource react */
|
|
171
|
+
/**
|
|
172
|
+
`<Box>` is an essential Ink component to build your layout. It's like `<div style="display: flex">` in the browser.
|
|
173
|
+
*/
|
|
174
|
+
function Box({ children, ref, backgroundColor, "aria-label": ariaLabel, "aria-hidden": ariaHidden, "aria-role": role, "aria-state": ariaState, ...style }) {
|
|
175
|
+
const { isScreenReaderEnabled } = useContext(accessibilityContext);
|
|
176
|
+
const label = ariaLabel ? /* @__PURE__ */ jsx("ink-text", { children: ariaLabel }) : void 0;
|
|
177
|
+
if (isScreenReaderEnabled && ariaHidden) return null;
|
|
178
|
+
return /* @__PURE__ */ jsx("ink-box", {
|
|
179
|
+
ref,
|
|
180
|
+
style: {
|
|
181
|
+
flexWrap: "nowrap",
|
|
182
|
+
flexDirection: "row",
|
|
183
|
+
flexGrow: 0,
|
|
184
|
+
flexShrink: 1,
|
|
185
|
+
...style,
|
|
186
|
+
backgroundColor,
|
|
187
|
+
overflowX: style.overflowX ?? style.overflow ?? "visible",
|
|
188
|
+
overflowY: style.overflowY ?? style.overflow ?? "visible"
|
|
189
|
+
},
|
|
190
|
+
internal_accessibility: {
|
|
191
|
+
role,
|
|
192
|
+
state: ariaState
|
|
193
|
+
},
|
|
194
|
+
children: isScreenReaderEnabled && label ? label : children
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
//#endregion
|
|
250
198
|
//#region src/parse-stack-line.ts
|
|
251
199
|
const lineRegExp = new RegExp("^" + String.raw`(?:\s*at )?` + "(?:(new) )?" + String.raw`(?:(.*?) \()?` + String.raw`(?:eval at ([^ ]+) \((.+?):(\d+):(\d+)\), )?` + String.raw`(?:(.+?):(\d+):(\d+)|(native))` + String.raw`(\)?)$`);
|
|
252
200
|
const methodRegExp = /^(.*?) \[as (.*?)]$/;
|
|
@@ -308,110 +256,6 @@ const parseStackLine = (line) => {
|
|
|
308
256
|
return result;
|
|
309
257
|
};
|
|
310
258
|
//#endregion
|
|
311
|
-
//#region src/components/BackgroundContext.ts
|
|
312
|
-
const backgroundContext = createContext(void 0);
|
|
313
|
-
//#endregion
|
|
314
|
-
//#region src/components/Box.tsx
|
|
315
|
-
/** @jsxImportSource react */
|
|
316
|
-
/**
|
|
317
|
-
`<Box>` is an essential Ink component to build your layout. It's like `<div style="display: flex">` in the browser.
|
|
318
|
-
*/
|
|
319
|
-
const Box = forwardRef(({ children, backgroundColor, "aria-label": ariaLabel, "aria-hidden": ariaHidden, "aria-role": role, "aria-state": ariaState, ...style }, ref) => {
|
|
320
|
-
const { isScreenReaderEnabled } = useContext(accessibilityContext);
|
|
321
|
-
const label = ariaLabel ? /* @__PURE__ */ jsx("ink-text", { children: ariaLabel }) : void 0;
|
|
322
|
-
if (isScreenReaderEnabled && ariaHidden) return null;
|
|
323
|
-
const boxElement = /* @__PURE__ */ jsx("ink-box", {
|
|
324
|
-
ref,
|
|
325
|
-
style: {
|
|
326
|
-
flexWrap: "nowrap",
|
|
327
|
-
flexDirection: "row",
|
|
328
|
-
flexGrow: 0,
|
|
329
|
-
flexShrink: 1,
|
|
330
|
-
...style,
|
|
331
|
-
backgroundColor,
|
|
332
|
-
overflowX: style.overflowX ?? style.overflow ?? "visible",
|
|
333
|
-
overflowY: style.overflowY ?? style.overflow ?? "visible"
|
|
334
|
-
},
|
|
335
|
-
internal_accessibility: {
|
|
336
|
-
role,
|
|
337
|
-
state: ariaState
|
|
338
|
-
},
|
|
339
|
-
children: isScreenReaderEnabled && label ? label : children
|
|
340
|
-
});
|
|
341
|
-
if (backgroundColor) return /* @__PURE__ */ jsx(backgroundContext.Provider, {
|
|
342
|
-
value: backgroundColor,
|
|
343
|
-
children: boxElement
|
|
344
|
-
});
|
|
345
|
-
return boxElement;
|
|
346
|
-
});
|
|
347
|
-
Box.displayName = "Box";
|
|
348
|
-
//#endregion
|
|
349
|
-
//#region src/colorize.ts
|
|
350
|
-
const rgbRegex = /^rgb\(\s?(\d+),\s?(\d+),\s?(\d+)\s?\)$/;
|
|
351
|
-
const ansiRegex = /^ansi256\(\s?(\d+)\s?\)$/;
|
|
352
|
-
const isNamedColor = (color) => {
|
|
353
|
-
return color in chalk;
|
|
354
|
-
};
|
|
355
|
-
const colorize = (str, color, type) => {
|
|
356
|
-
if (!color) return str;
|
|
357
|
-
if (isNamedColor(color)) {
|
|
358
|
-
if (type === "foreground") return chalk[color](str);
|
|
359
|
-
const methodName = `bg${color[0].toUpperCase() + color.slice(1)}`;
|
|
360
|
-
return chalk[methodName](str);
|
|
361
|
-
}
|
|
362
|
-
if (color.startsWith("#")) return type === "foreground" ? chalk.hex(color)(str) : chalk.bgHex(color)(str);
|
|
363
|
-
if (color.startsWith("ansi256")) {
|
|
364
|
-
const matches = ansiRegex.exec(color);
|
|
365
|
-
if (!matches) return str;
|
|
366
|
-
const value = Number(matches[1]);
|
|
367
|
-
return type === "foreground" ? chalk.ansi256(value)(str) : chalk.bgAnsi256(value)(str);
|
|
368
|
-
}
|
|
369
|
-
if (color.startsWith("rgb")) {
|
|
370
|
-
const matches = rgbRegex.exec(color);
|
|
371
|
-
if (!matches) return str;
|
|
372
|
-
const firstValue = Number(matches[1]);
|
|
373
|
-
const secondValue = Number(matches[2]);
|
|
374
|
-
const thirdValue = Number(matches[3]);
|
|
375
|
-
return type === "foreground" ? chalk.rgb(firstValue, secondValue, thirdValue)(str) : chalk.bgRgb(firstValue, secondValue, thirdValue)(str);
|
|
376
|
-
}
|
|
377
|
-
return str;
|
|
378
|
-
};
|
|
379
|
-
//#endregion
|
|
380
|
-
//#region src/components/Text.tsx
|
|
381
|
-
/** @jsxImportSource react */
|
|
382
|
-
/**
|
|
383
|
-
This component can display text and change its style to make it bold, underlined, italic, or strikethrough.
|
|
384
|
-
*/
|
|
385
|
-
function Text({ color, backgroundColor, dimColor = false, bold = false, italic = false, underline = false, strikethrough = false, inverse = false, wrap = "wrap", children, "aria-label": ariaLabel, "aria-hidden": ariaHidden = false }) {
|
|
386
|
-
const { isScreenReaderEnabled } = useContext(accessibilityContext);
|
|
387
|
-
const inheritedBackgroundColor = useContext(backgroundContext);
|
|
388
|
-
const childrenOrAriaLabel = isScreenReaderEnabled && ariaLabel ? ariaLabel : children;
|
|
389
|
-
if (childrenOrAriaLabel === void 0 || childrenOrAriaLabel === null) return null;
|
|
390
|
-
const transform = (text) => {
|
|
391
|
-
if (dimColor) text = chalk.dim(text);
|
|
392
|
-
if (color) text = colorize(text, color, "foreground");
|
|
393
|
-
const effectiveBackgroundColor = backgroundColor ?? inheritedBackgroundColor;
|
|
394
|
-
if (effectiveBackgroundColor) text = colorize(text, effectiveBackgroundColor, "background");
|
|
395
|
-
if (bold) text = chalk.bold(text);
|
|
396
|
-
if (italic) text = chalk.italic(text);
|
|
397
|
-
if (underline) text = chalk.underline(text);
|
|
398
|
-
if (strikethrough) text = chalk.strikethrough(text);
|
|
399
|
-
if (inverse) text = chalk.inverse(text);
|
|
400
|
-
return text;
|
|
401
|
-
};
|
|
402
|
-
if (isScreenReaderEnabled && ariaHidden) return null;
|
|
403
|
-
return /* @__PURE__ */ jsx("ink-text", {
|
|
404
|
-
style: {
|
|
405
|
-
flexGrow: 0,
|
|
406
|
-
flexShrink: 1,
|
|
407
|
-
flexDirection: "row",
|
|
408
|
-
textWrap: wrap
|
|
409
|
-
},
|
|
410
|
-
internal_transform: transform,
|
|
411
|
-
children: childrenOrAriaLabel
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
//#endregion
|
|
415
259
|
//#region src/components/ErrorOverview.tsx
|
|
416
260
|
/** @jsxImportSource react */
|
|
417
261
|
const cleanupPath = (path) => {
|
|
@@ -424,8 +268,8 @@ function ErrorOverview({ error }) {
|
|
|
424
268
|
let excerpt;
|
|
425
269
|
let lineWidth = 0;
|
|
426
270
|
const stackLineCounts = /* @__PURE__ */ new Map();
|
|
427
|
-
if (filePath && origin?.line &&
|
|
428
|
-
const sourceCode =
|
|
271
|
+
if (filePath && origin?.line && existsSync(filePath)) {
|
|
272
|
+
const sourceCode = readFileSync(filePath, "utf8");
|
|
429
273
|
excerpt = codeExcerpt(sourceCode, origin.line);
|
|
430
274
|
if (excerpt) for (const { line } of excerpt) lineWidth = Math.max(lineWidth, String(line).length);
|
|
431
275
|
}
|
|
@@ -542,21 +386,6 @@ var ErrorBoundary = class extends PureComponent {
|
|
|
542
386
|
}
|
|
543
387
|
};
|
|
544
388
|
//#endregion
|
|
545
|
-
//#region src/components/FocusContext.ts
|
|
546
|
-
const FocusContext = createContext({
|
|
547
|
-
activeId: void 0,
|
|
548
|
-
add() {},
|
|
549
|
-
remove() {},
|
|
550
|
-
activate() {},
|
|
551
|
-
deactivate() {},
|
|
552
|
-
enableFocus() {},
|
|
553
|
-
disableFocus() {},
|
|
554
|
-
focusNext() {},
|
|
555
|
-
focusPrevious() {},
|
|
556
|
-
focus() {}
|
|
557
|
-
});
|
|
558
|
-
FocusContext.displayName = "InternalFocusContext";
|
|
559
|
-
//#endregion
|
|
560
389
|
//#region src/components/StderrContext.ts
|
|
561
390
|
/**
|
|
562
391
|
`StderrContext` is a React context that exposes the stderr stream.
|
|
@@ -567,20 +396,6 @@ const StderrContext = createContext({
|
|
|
567
396
|
});
|
|
568
397
|
StderrContext.displayName = "InternalStderrContext";
|
|
569
398
|
//#endregion
|
|
570
|
-
//#region src/components/StdinContext.ts
|
|
571
|
-
/**
|
|
572
|
-
`StdinContext` is a React context that exposes the input stream.
|
|
573
|
-
*/
|
|
574
|
-
const StdinContext = createContext({
|
|
575
|
-
stdin: process.stdin,
|
|
576
|
-
internal_eventEmitter: new EventEmitter(),
|
|
577
|
-
setRawMode() {},
|
|
578
|
-
setBracketedPasteMode() {},
|
|
579
|
-
isRawModeSupported: false,
|
|
580
|
-
internal_exitOnCtrlC: true
|
|
581
|
-
});
|
|
582
|
-
StdinContext.displayName = "InternalStdinContext";
|
|
583
|
-
//#endregion
|
|
584
399
|
//#region src/components/StdoutContext.ts
|
|
585
400
|
/**
|
|
586
401
|
`StdoutContext` is a React context that exposes the stdout stream where Ink renders your app.
|
|
@@ -596,7 +411,7 @@ StdoutContext.displayName = "InternalStdoutContext";
|
|
|
596
411
|
const tab = " ";
|
|
597
412
|
const shiftTab = `${CSI}Z`;
|
|
598
413
|
const escape = "\x1B";
|
|
599
|
-
function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, exitOnCtrlC, onExit, onWaitUntilRenderFlush, onSuspendTerminal, onRegisterInputControl, setCursorPosition, interactive, renderThrottleMs }) {
|
|
414
|
+
function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, exitOnCtrlC, onExit, onWaitUntilRenderFlush, onSuspendTerminal, onRegisterInputControl, setCursorPosition, interactive, renderThrottleMs, terminalInput }) {
|
|
600
415
|
const [isFocusEnabled, setIsFocusEnabled] = useState(true);
|
|
601
416
|
const [activeFocusId, setActiveFocusId] = useState(void 0);
|
|
602
417
|
const [, setFocusables] = useState([]);
|
|
@@ -609,7 +424,6 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
|
|
|
609
424
|
const internal_eventEmitter = useRef(new EventEmitter());
|
|
610
425
|
internal_eventEmitter.current.setMaxListeners(Infinity);
|
|
611
426
|
const readableListenerRef = useRef(void 0);
|
|
612
|
-
const inputParserRef = useRef(createInputParser());
|
|
613
427
|
const pendingInputFlushRef = useRef(void 0);
|
|
614
428
|
const pendingInputFlushDelayMilliseconds = 20;
|
|
615
429
|
const clearPendingInputFlush = useCallback(() => {
|
|
@@ -675,10 +489,14 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
|
|
|
675
489
|
readableListenerRef.current = void 0;
|
|
676
490
|
}, [stdin]);
|
|
677
491
|
const clearInputState = useCallback(() => {
|
|
678
|
-
|
|
492
|
+
terminalInput.reset();
|
|
679
493
|
clearPendingInputFlush();
|
|
680
494
|
detachReadableListener();
|
|
681
|
-
}, [
|
|
495
|
+
}, [
|
|
496
|
+
clearPendingInputFlush,
|
|
497
|
+
detachReadableListener,
|
|
498
|
+
terminalInput
|
|
499
|
+
]);
|
|
682
500
|
const disableRawMode = useCallback(() => {
|
|
683
501
|
if (!rawModeStdin) return;
|
|
684
502
|
pendingDisableRawModeRef.current = false;
|
|
@@ -714,16 +532,20 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
|
|
|
714
532
|
clearPendingInputFlush();
|
|
715
533
|
pendingInputFlushRef.current = setTimeout(() => {
|
|
716
534
|
pendingInputFlushRef.current = void 0;
|
|
717
|
-
const pendingEscape =
|
|
535
|
+
const pendingEscape = terminalInput.flushPendingEscape();
|
|
718
536
|
if (!pendingEscape) return;
|
|
719
537
|
emitInput(pendingEscape);
|
|
720
538
|
}, pendingInputFlushDelayMilliseconds);
|
|
721
|
-
}, [
|
|
539
|
+
}, [
|
|
540
|
+
clearPendingInputFlush,
|
|
541
|
+
emitInput,
|
|
542
|
+
terminalInput
|
|
543
|
+
]);
|
|
722
544
|
const handleReadable = useCallback(() => {
|
|
723
545
|
clearPendingInputFlush();
|
|
724
546
|
let chunk;
|
|
725
547
|
while ((chunk = stdin.read()) !== null) {
|
|
726
|
-
const inputEvents =
|
|
548
|
+
const inputEvents = terminalInput.push(chunk);
|
|
727
549
|
for (const event of inputEvents) if (typeof event === "string") emitInput(event);
|
|
728
550
|
else {
|
|
729
551
|
if (internal_eventEmitter.current.listenerCount("paste") === 0) {
|
|
@@ -733,12 +555,13 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
|
|
|
733
555
|
internal_eventEmitter.current.emit("paste", event.paste);
|
|
734
556
|
}
|
|
735
557
|
}
|
|
736
|
-
if (
|
|
558
|
+
if (terminalInput.hasPendingEscape()) schedulePendingInputFlush();
|
|
737
559
|
}, [
|
|
738
560
|
stdin,
|
|
739
561
|
emitInput,
|
|
740
562
|
clearPendingInputFlush,
|
|
741
|
-
schedulePendingInputFlush
|
|
563
|
+
schedulePendingInputFlush,
|
|
564
|
+
terminalInput
|
|
742
565
|
]);
|
|
743
566
|
const attachReadableListener = useCallback(() => {
|
|
744
567
|
if (readableListenerRef.current) return;
|
|
@@ -780,6 +603,49 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
|
|
|
780
603
|
clearInputState,
|
|
781
604
|
disableRawMode
|
|
782
605
|
]);
|
|
606
|
+
const handleQueryTerminal = useCallback(async ({ refresh = false } = {}) => {
|
|
607
|
+
if (!interactive || !isRawModeSupported || !stdout.isTTY) return;
|
|
608
|
+
if (!refresh) {
|
|
609
|
+
const existing = getTerminalQueryPromise(stdout);
|
|
610
|
+
if (existing) return existing;
|
|
611
|
+
}
|
|
612
|
+
handleSetRawMode(true);
|
|
613
|
+
detachReadableListener();
|
|
614
|
+
try {
|
|
615
|
+
return await (refresh ? refreshTerminalQuery(stdin, stdout) : ensureTerminalQuery(stdin, stdout));
|
|
616
|
+
} finally {
|
|
617
|
+
attachReadableListener();
|
|
618
|
+
handleSetRawMode(false);
|
|
619
|
+
}
|
|
620
|
+
}, [
|
|
621
|
+
interactive,
|
|
622
|
+
isRawModeSupported,
|
|
623
|
+
stdin,
|
|
624
|
+
stdout,
|
|
625
|
+
handleSetRawMode,
|
|
626
|
+
detachReadableListener,
|
|
627
|
+
attachReadableListener
|
|
628
|
+
]);
|
|
629
|
+
const reportFeedActiveRef = useRef(false);
|
|
630
|
+
const handleSetReportFeed = useCallback((active) => {
|
|
631
|
+
if (active === reportFeedActiveRef.current || !isRawModeSupported) return;
|
|
632
|
+
reportFeedActiveRef.current = active;
|
|
633
|
+
handleSetRawMode(active);
|
|
634
|
+
}, [isRawModeSupported, handleSetRawMode]);
|
|
635
|
+
useInsertionEffect(() => {
|
|
636
|
+
const unregister = registerTerminalIntegration(stdout, {
|
|
637
|
+
runQuery: handleQueryTerminal,
|
|
638
|
+
setReportFeed: handleSetReportFeed
|
|
639
|
+
});
|
|
640
|
+
return () => {
|
|
641
|
+
unregister();
|
|
642
|
+
handleSetReportFeed(false);
|
|
643
|
+
};
|
|
644
|
+
}, [
|
|
645
|
+
stdout,
|
|
646
|
+
handleQueryTerminal,
|
|
647
|
+
handleSetReportFeed
|
|
648
|
+
]);
|
|
783
649
|
const handleSetBracketedPasteMode = useCallback((isEnabled) => {
|
|
784
650
|
if (!stdout.isTTY) return;
|
|
785
651
|
if (isEnabled) {
|
|
@@ -1053,844 +919,21 @@ function App({ children, stdin, stdout, stderr, writeToStdout, writeToStderr, ex
|
|
|
1053
919
|
}
|
|
1054
920
|
App.displayName = "InternalApp";
|
|
1055
921
|
//#endregion
|
|
1056
|
-
//#region src/
|
|
1057
|
-
const
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
That is always `lines.length - 1` for `lines = str.split('\n')`, whether or not the output ends
|
|
1068
|
-
with a newline:
|
|
1069
|
-
|
|
1070
|
-
- With a trailing newline, `split` yields one extra empty element and the renderer stops just
|
|
1071
|
-
past the last visible line — which is `lines.length - 1`.
|
|
1072
|
-
- Without one, there is no extra element and the renderer deliberately stops on the last visible
|
|
1073
|
-
line instead of moving past it — which is also `lines.length - 1`.
|
|
1074
|
-
|
|
1075
|
-
This is the same row basis `buildReturnToBottom` measures from, so the two stay in step.
|
|
1076
|
-
*/
|
|
1077
|
-
const buildCursorSuffix = (bottomLine, cursorPosition) => {
|
|
1078
|
-
if (!cursorPosition) return "";
|
|
1079
|
-
const moveUp = bottomLine - cursorPosition.y;
|
|
1080
|
-
return (moveUp > 0 ? ansiEscapes.cursorUp(moveUp) : "") + ansiEscapes.cursorTo(cursorPosition.x) + showCursorEscape;
|
|
1081
|
-
};
|
|
1082
|
-
/**
|
|
1083
|
-
Build escape sequence to move cursor from previousCursorPosition back to the bottom of output.
|
|
1084
|
-
This must be done before eraseLines or any operation that assumes cursor is at the bottom.
|
|
1085
|
-
*/
|
|
1086
|
-
const buildReturnToBottom = (previousLineCount, previousCursorPosition) => {
|
|
1087
|
-
if (!previousCursorPosition) return "";
|
|
1088
|
-
const down = previousLineCount - 1 - previousCursorPosition.y;
|
|
1089
|
-
return (down > 0 ? ansiEscapes.cursorDown(down) : "") + ansiEscapes.cursorTo(0);
|
|
1090
|
-
};
|
|
1091
|
-
/**
|
|
1092
|
-
Build the escape sequence for cursor-only updates (output unchanged, cursor moved).
|
|
1093
|
-
Hides cursor if it was previously shown, returns to bottom, then repositions.
|
|
1094
|
-
|
|
1095
|
-
`buildReturnToBottom` has just placed the cursor on row `previousLineCount - 1`, so the
|
|
1096
|
-
suffix measures from there rather than recomputing the row from the output.
|
|
1097
|
-
*/
|
|
1098
|
-
const buildCursorOnlySequence = (input) => {
|
|
1099
|
-
const hidePrefix = input.cursorWasShown ? hideCursorEscape : "";
|
|
1100
|
-
const returnToBottom = buildReturnToBottom(input.previousLineCount, input.previousCursorPosition);
|
|
1101
|
-
const cursorSuffix = buildCursorSuffix(input.previousLineCount - 1, input.cursorPosition);
|
|
1102
|
-
return hidePrefix + returnToBottom + cursorSuffix;
|
|
1103
|
-
};
|
|
1104
|
-
/**
|
|
1105
|
-
Build the prefix that hides cursor and returns to bottom before erasing or rewriting.
|
|
1106
|
-
Returns empty string if cursor was not shown.
|
|
1107
|
-
*/
|
|
1108
|
-
const buildReturnToBottomPrefix = (cursorWasShown, previousLineCount, previousCursorPosition) => {
|
|
1109
|
-
if (!cursorWasShown) return "";
|
|
1110
|
-
return hideCursorEscape + buildReturnToBottom(previousLineCount, previousCursorPosition);
|
|
1111
|
-
};
|
|
1112
|
-
//#endregion
|
|
1113
|
-
//#region src/quick-lru.ts
|
|
1114
|
-
var QuickLru = class {
|
|
1115
|
-
#size = 0;
|
|
1116
|
-
#cache = /* @__PURE__ */ new Map();
|
|
1117
|
-
#oldCache = /* @__PURE__ */ new Map();
|
|
1118
|
-
#maxSize;
|
|
1119
|
-
constructor({ maxSize }) {
|
|
1120
|
-
if (!(maxSize && maxSize > 0)) throw new TypeError("`maxSize` must be a number greater than 0");
|
|
1121
|
-
this.#maxSize = maxSize;
|
|
1122
|
-
}
|
|
1123
|
-
get size() {
|
|
1124
|
-
let oldCacheSize = 0;
|
|
1125
|
-
for (const key of this.#oldCache.keys()) if (!this.#cache.has(key)) oldCacheSize++;
|
|
1126
|
-
return Math.min(this.#size + oldCacheSize, this.#maxSize);
|
|
1127
|
-
}
|
|
1128
|
-
get(key) {
|
|
1129
|
-
if (this.#cache.has(key)) return this.#cache.get(key);
|
|
1130
|
-
if (this.#oldCache.has(key)) {
|
|
1131
|
-
const value = this.#oldCache.get(key);
|
|
1132
|
-
this.#oldCache.delete(key);
|
|
1133
|
-
this.#set(key, value);
|
|
1134
|
-
return value;
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
set(key, value) {
|
|
1138
|
-
if (this.#cache.has(key)) this.#cache.set(key, value);
|
|
1139
|
-
else this.#set(key, value);
|
|
1140
|
-
return this;
|
|
1141
|
-
}
|
|
1142
|
-
has(key) {
|
|
1143
|
-
return this.#cache.has(key) || this.#oldCache.has(key);
|
|
1144
|
-
}
|
|
1145
|
-
delete(key) {
|
|
1146
|
-
const deleted = this.#cache.delete(key);
|
|
1147
|
-
if (deleted) this.#size--;
|
|
1148
|
-
return this.#oldCache.delete(key) || deleted;
|
|
1149
|
-
}
|
|
1150
|
-
clear() {
|
|
1151
|
-
this.#cache.clear();
|
|
1152
|
-
this.#oldCache.clear();
|
|
1153
|
-
this.#size = 0;
|
|
1154
|
-
}
|
|
1155
|
-
#set(key, value) {
|
|
1156
|
-
this.#cache.set(key, value);
|
|
1157
|
-
this.#size++;
|
|
1158
|
-
if (this.#size >= this.#maxSize) {
|
|
1159
|
-
this.#size = 0;
|
|
1160
|
-
this.#oldCache = this.#cache;
|
|
1161
|
-
this.#cache = /* @__PURE__ */ new Map();
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
};
|
|
1165
|
-
//#endregion
|
|
1166
|
-
//#region src/measure-text.ts
|
|
1167
|
-
const cache = new QuickLru({ maxSize: 4096 });
|
|
1168
|
-
const measureText = (text) => {
|
|
1169
|
-
if (text.length === 0) return {
|
|
1170
|
-
width: 0,
|
|
1171
|
-
height: 0
|
|
1172
|
-
};
|
|
1173
|
-
const cachedDimensions = cache.get(text);
|
|
1174
|
-
if (cachedDimensions) return cachedDimensions;
|
|
1175
|
-
const dimensions = {
|
|
1176
|
-
width: widestLine(text),
|
|
1177
|
-
height: text.split("\n").length
|
|
1178
|
-
};
|
|
1179
|
-
cache.set(text, dimensions);
|
|
1180
|
-
return dimensions;
|
|
1181
|
-
};
|
|
1182
|
-
//#endregion
|
|
1183
|
-
//#region src/ansi-tokenizer.ts
|
|
1184
|
-
const bellCharacter = "\x07";
|
|
1185
|
-
const escapeCharacter = "\x1B";
|
|
1186
|
-
const stringTerminatorCharacter = "";
|
|
1187
|
-
const csiCharacter = "";
|
|
1188
|
-
const oscCharacter = "";
|
|
1189
|
-
const dcsCharacter = "";
|
|
1190
|
-
const pmCharacter = "";
|
|
1191
|
-
const apcCharacter = "";
|
|
1192
|
-
const sosCharacter = "";
|
|
1193
|
-
const isCsiParameterCharacter = (character) => {
|
|
1194
|
-
const codePoint = character.codePointAt(0);
|
|
1195
|
-
return codePoint !== void 0 && codePoint >= 48 && codePoint <= 63;
|
|
1196
|
-
};
|
|
1197
|
-
const isCsiIntermediateCharacter = (character) => {
|
|
1198
|
-
const codePoint = character.codePointAt(0);
|
|
1199
|
-
return codePoint !== void 0 && codePoint >= 32 && codePoint <= 47;
|
|
1200
|
-
};
|
|
1201
|
-
const isCsiFinalCharacter = (character) => {
|
|
1202
|
-
const codePoint = character.codePointAt(0);
|
|
1203
|
-
return codePoint !== void 0 && codePoint >= 64 && codePoint <= 126;
|
|
1204
|
-
};
|
|
1205
|
-
const isEscapeIntermediateCharacter = (character) => {
|
|
1206
|
-
const codePoint = character.codePointAt(0);
|
|
1207
|
-
return codePoint !== void 0 && codePoint >= 32 && codePoint <= 47;
|
|
1208
|
-
};
|
|
1209
|
-
const isEscapeFinalCharacter = (character) => {
|
|
1210
|
-
const codePoint = character.codePointAt(0);
|
|
1211
|
-
return codePoint !== void 0 && codePoint >= 48 && codePoint <= 126;
|
|
1212
|
-
};
|
|
1213
|
-
const isC1ControlCharacter = (character) => {
|
|
1214
|
-
const codePoint = character.codePointAt(0);
|
|
1215
|
-
return codePoint !== void 0 && codePoint >= 128 && codePoint <= 159;
|
|
1216
|
-
};
|
|
1217
|
-
const readCsiSequence = (text, fromIndex) => {
|
|
1218
|
-
let index = fromIndex;
|
|
1219
|
-
while (index < text.length) {
|
|
1220
|
-
const character = text[index];
|
|
1221
|
-
if (!isCsiParameterCharacter(character)) break;
|
|
1222
|
-
index++;
|
|
1223
|
-
}
|
|
1224
|
-
const parameterString = text.slice(fromIndex, index);
|
|
1225
|
-
const intermediateStartIndex = index;
|
|
1226
|
-
while (index < text.length) {
|
|
1227
|
-
const character = text[index];
|
|
1228
|
-
if (!isCsiIntermediateCharacter(character)) break;
|
|
1229
|
-
index++;
|
|
1230
|
-
}
|
|
1231
|
-
const intermediateString = text.slice(intermediateStartIndex, index);
|
|
1232
|
-
const finalCharacter = text[index];
|
|
1233
|
-
if (finalCharacter === void 0 || !isCsiFinalCharacter(finalCharacter)) return;
|
|
1234
|
-
return {
|
|
1235
|
-
endIndex: index + 1,
|
|
1236
|
-
parameterString,
|
|
1237
|
-
intermediateString,
|
|
1238
|
-
finalCharacter
|
|
1239
|
-
};
|
|
1240
|
-
};
|
|
1241
|
-
const findControlStringTerminatorIndex = (text, fromIndex, allowBellTerminator) => {
|
|
1242
|
-
for (let index = fromIndex; index < text.length; index++) {
|
|
1243
|
-
const character = text[index];
|
|
1244
|
-
if (allowBellTerminator && character === bellCharacter) return index + 1;
|
|
1245
|
-
if (character === stringTerminatorCharacter) return index + 1;
|
|
1246
|
-
if (character === escapeCharacter) {
|
|
1247
|
-
const followingCharacter = text[index + 1];
|
|
1248
|
-
if (followingCharacter === escapeCharacter) {
|
|
1249
|
-
index++;
|
|
1250
|
-
continue;
|
|
1251
|
-
}
|
|
1252
|
-
if (followingCharacter === "\\") return index + 2;
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
|
-
};
|
|
1256
|
-
const readEscapeSequence = (text, fromIndex) => {
|
|
1257
|
-
let index = fromIndex;
|
|
1258
|
-
while (index < text.length) {
|
|
1259
|
-
const character = text[index];
|
|
1260
|
-
if (!isEscapeIntermediateCharacter(character)) break;
|
|
1261
|
-
index++;
|
|
1262
|
-
}
|
|
1263
|
-
const intermediateString = text.slice(fromIndex, index);
|
|
1264
|
-
const finalCharacter = text[index];
|
|
1265
|
-
if (finalCharacter === void 0 || !isEscapeFinalCharacter(finalCharacter)) return;
|
|
1266
|
-
return {
|
|
1267
|
-
endIndex: index + 1,
|
|
1268
|
-
intermediateString,
|
|
1269
|
-
finalCharacter
|
|
1270
|
-
};
|
|
1271
|
-
};
|
|
1272
|
-
const getControlStringFromEscapeIntroducer = (character) => {
|
|
1273
|
-
switch (character) {
|
|
1274
|
-
case "]": return {
|
|
1275
|
-
type: "osc",
|
|
1276
|
-
allowBellTerminator: true
|
|
1277
|
-
};
|
|
1278
|
-
case "P": return {
|
|
1279
|
-
type: "dcs",
|
|
1280
|
-
allowBellTerminator: false
|
|
1281
|
-
};
|
|
1282
|
-
case "^": return {
|
|
1283
|
-
type: "pm",
|
|
1284
|
-
allowBellTerminator: false
|
|
1285
|
-
};
|
|
1286
|
-
case "_": return {
|
|
1287
|
-
type: "apc",
|
|
1288
|
-
allowBellTerminator: false
|
|
1289
|
-
};
|
|
1290
|
-
case "X": return {
|
|
1291
|
-
type: "sos",
|
|
1292
|
-
allowBellTerminator: false
|
|
1293
|
-
};
|
|
1294
|
-
default: return;
|
|
1295
|
-
}
|
|
1296
|
-
};
|
|
1297
|
-
const getControlStringFromC1Introducer = (character) => {
|
|
1298
|
-
switch (character) {
|
|
1299
|
-
case oscCharacter: return {
|
|
1300
|
-
type: "osc",
|
|
1301
|
-
allowBellTerminator: true
|
|
1302
|
-
};
|
|
1303
|
-
case dcsCharacter: return {
|
|
1304
|
-
type: "dcs",
|
|
1305
|
-
allowBellTerminator: false
|
|
1306
|
-
};
|
|
1307
|
-
case pmCharacter: return {
|
|
1308
|
-
type: "pm",
|
|
1309
|
-
allowBellTerminator: false
|
|
1310
|
-
};
|
|
1311
|
-
case apcCharacter: return {
|
|
1312
|
-
type: "apc",
|
|
1313
|
-
allowBellTerminator: false
|
|
1314
|
-
};
|
|
1315
|
-
case sosCharacter: return {
|
|
1316
|
-
type: "sos",
|
|
1317
|
-
allowBellTerminator: false
|
|
1318
|
-
};
|
|
1319
|
-
default: return;
|
|
1320
|
-
}
|
|
1321
|
-
};
|
|
1322
|
-
const hasAnsiControlCharacters = (text) => {
|
|
1323
|
-
if (text.includes(escapeCharacter)) return true;
|
|
1324
|
-
for (const character of text) if (isC1ControlCharacter(character)) return true;
|
|
1325
|
-
return false;
|
|
1326
|
-
};
|
|
1327
|
-
const malformedFromIndex = (tokens, text, textStartIndex, fromIndex) => {
|
|
1328
|
-
if (fromIndex > textStartIndex) tokens.push({
|
|
1329
|
-
type: "text",
|
|
1330
|
-
value: text.slice(textStartIndex, fromIndex)
|
|
1331
|
-
});
|
|
1332
|
-
tokens.push({
|
|
1333
|
-
type: "invalid",
|
|
1334
|
-
value: text.slice(fromIndex)
|
|
1335
|
-
});
|
|
1336
|
-
return tokens;
|
|
1337
|
-
};
|
|
1338
|
-
const tokenizeAnsi = (text) => {
|
|
1339
|
-
if (!hasAnsiControlCharacters(text)) return [{
|
|
1340
|
-
type: "text",
|
|
1341
|
-
value: text
|
|
1342
|
-
}];
|
|
1343
|
-
const tokens = [];
|
|
1344
|
-
let textStartIndex = 0;
|
|
1345
|
-
for (let index = 0; index < text.length;) {
|
|
1346
|
-
const character = text[index];
|
|
1347
|
-
if (character === void 0) break;
|
|
1348
|
-
if (character === escapeCharacter) {
|
|
1349
|
-
const followingCharacter = text[index + 1];
|
|
1350
|
-
if (followingCharacter === void 0) return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
1351
|
-
if (followingCharacter === "[") {
|
|
1352
|
-
const csiSequence = readCsiSequence(text, index + 2);
|
|
1353
|
-
if (csiSequence === void 0) return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
1354
|
-
if (index > textStartIndex) tokens.push({
|
|
1355
|
-
type: "text",
|
|
1356
|
-
value: text.slice(textStartIndex, index)
|
|
1357
|
-
});
|
|
1358
|
-
tokens.push({
|
|
1359
|
-
type: "csi",
|
|
1360
|
-
value: text.slice(index, csiSequence.endIndex),
|
|
1361
|
-
parameterString: csiSequence.parameterString,
|
|
1362
|
-
intermediateString: csiSequence.intermediateString,
|
|
1363
|
-
finalCharacter: csiSequence.finalCharacter
|
|
1364
|
-
});
|
|
1365
|
-
index = csiSequence.endIndex;
|
|
1366
|
-
textStartIndex = index;
|
|
1367
|
-
continue;
|
|
1368
|
-
}
|
|
1369
|
-
const escapeControlString = getControlStringFromEscapeIntroducer(followingCharacter);
|
|
1370
|
-
if (escapeControlString !== void 0) {
|
|
1371
|
-
const controlStringTerminatorIndex = findControlStringTerminatorIndex(text, index + 2, escapeControlString.allowBellTerminator);
|
|
1372
|
-
if (controlStringTerminatorIndex === void 0) return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
1373
|
-
if (index > textStartIndex) tokens.push({
|
|
1374
|
-
type: "text",
|
|
1375
|
-
value: text.slice(textStartIndex, index)
|
|
1376
|
-
});
|
|
1377
|
-
tokens.push({
|
|
1378
|
-
type: escapeControlString.type,
|
|
1379
|
-
value: text.slice(index, controlStringTerminatorIndex)
|
|
1380
|
-
});
|
|
1381
|
-
index = controlStringTerminatorIndex;
|
|
1382
|
-
textStartIndex = index;
|
|
1383
|
-
continue;
|
|
1384
|
-
}
|
|
1385
|
-
const escapeSequence = readEscapeSequence(text, index + 1);
|
|
1386
|
-
if (escapeSequence === void 0) {
|
|
1387
|
-
if (isEscapeIntermediateCharacter(followingCharacter)) return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
1388
|
-
if (index > textStartIndex) tokens.push({
|
|
1389
|
-
type: "text",
|
|
1390
|
-
value: text.slice(textStartIndex, index)
|
|
1391
|
-
});
|
|
1392
|
-
index++;
|
|
1393
|
-
textStartIndex = index;
|
|
1394
|
-
continue;
|
|
1395
|
-
}
|
|
1396
|
-
if (index > textStartIndex) tokens.push({
|
|
1397
|
-
type: "text",
|
|
1398
|
-
value: text.slice(textStartIndex, index)
|
|
1399
|
-
});
|
|
1400
|
-
tokens.push({
|
|
1401
|
-
type: "esc",
|
|
1402
|
-
value: text.slice(index, escapeSequence.endIndex),
|
|
1403
|
-
intermediateString: escapeSequence.intermediateString,
|
|
1404
|
-
finalCharacter: escapeSequence.finalCharacter
|
|
1405
|
-
});
|
|
1406
|
-
index = escapeSequence.endIndex;
|
|
1407
|
-
textStartIndex = index;
|
|
1408
|
-
continue;
|
|
1409
|
-
}
|
|
1410
|
-
if (character === csiCharacter) {
|
|
1411
|
-
const csiSequence = readCsiSequence(text, index + 1);
|
|
1412
|
-
if (csiSequence === void 0) return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
1413
|
-
if (index > textStartIndex) tokens.push({
|
|
1414
|
-
type: "text",
|
|
1415
|
-
value: text.slice(textStartIndex, index)
|
|
1416
|
-
});
|
|
1417
|
-
tokens.push({
|
|
1418
|
-
type: "csi",
|
|
1419
|
-
value: text.slice(index, csiSequence.endIndex),
|
|
1420
|
-
parameterString: csiSequence.parameterString,
|
|
1421
|
-
intermediateString: csiSequence.intermediateString,
|
|
1422
|
-
finalCharacter: csiSequence.finalCharacter
|
|
1423
|
-
});
|
|
1424
|
-
index = csiSequence.endIndex;
|
|
1425
|
-
textStartIndex = index;
|
|
1426
|
-
continue;
|
|
1427
|
-
}
|
|
1428
|
-
const c1ControlString = getControlStringFromC1Introducer(character);
|
|
1429
|
-
if (c1ControlString !== void 0) {
|
|
1430
|
-
const controlStringTerminatorIndex = findControlStringTerminatorIndex(text, index + 1, c1ControlString.allowBellTerminator);
|
|
1431
|
-
if (controlStringTerminatorIndex === void 0) return malformedFromIndex(tokens, text, textStartIndex, index);
|
|
1432
|
-
if (index > textStartIndex) tokens.push({
|
|
1433
|
-
type: "text",
|
|
1434
|
-
value: text.slice(textStartIndex, index)
|
|
1435
|
-
});
|
|
1436
|
-
tokens.push({
|
|
1437
|
-
type: c1ControlString.type,
|
|
1438
|
-
value: text.slice(index, controlStringTerminatorIndex)
|
|
1439
|
-
});
|
|
1440
|
-
index = controlStringTerminatorIndex;
|
|
1441
|
-
textStartIndex = index;
|
|
1442
|
-
continue;
|
|
1443
|
-
}
|
|
1444
|
-
if (character === stringTerminatorCharacter) {
|
|
1445
|
-
if (index > textStartIndex) tokens.push({
|
|
1446
|
-
type: "text",
|
|
1447
|
-
value: text.slice(textStartIndex, index)
|
|
1448
|
-
});
|
|
1449
|
-
tokens.push({
|
|
1450
|
-
type: "st",
|
|
1451
|
-
value: character
|
|
1452
|
-
});
|
|
1453
|
-
index++;
|
|
1454
|
-
textStartIndex = index;
|
|
1455
|
-
continue;
|
|
1456
|
-
}
|
|
1457
|
-
if (isC1ControlCharacter(character)) {
|
|
1458
|
-
if (index > textStartIndex) tokens.push({
|
|
1459
|
-
type: "text",
|
|
1460
|
-
value: text.slice(textStartIndex, index)
|
|
1461
|
-
});
|
|
1462
|
-
tokens.push({
|
|
1463
|
-
type: "c1",
|
|
1464
|
-
value: character
|
|
1465
|
-
});
|
|
1466
|
-
index++;
|
|
1467
|
-
textStartIndex = index;
|
|
1468
|
-
continue;
|
|
1469
|
-
}
|
|
1470
|
-
index++;
|
|
1471
|
-
}
|
|
1472
|
-
if (textStartIndex < text.length) tokens.push({
|
|
1473
|
-
type: "text",
|
|
1474
|
-
value: text.slice(textStartIndex)
|
|
1475
|
-
});
|
|
1476
|
-
return tokens;
|
|
1477
|
-
};
|
|
1478
|
-
//#endregion
|
|
1479
|
-
//#region src/sanitize-ansi.ts
|
|
1480
|
-
const sgrParametersRegex = /^[\d:;]*$/;
|
|
1481
|
-
const sanitizeAnsi = (text) => {
|
|
1482
|
-
if (!hasAnsiControlCharacters(text)) return text;
|
|
1483
|
-
let output = "";
|
|
1484
|
-
for (const token of tokenizeAnsi(text)) {
|
|
1485
|
-
if (token.type === "text" || token.type === "osc") {
|
|
1486
|
-
output += token.value;
|
|
1487
|
-
continue;
|
|
1488
|
-
}
|
|
1489
|
-
if (token.type === "csi" && token.finalCharacter === "m" && token.intermediateString === "" && sgrParametersRegex.test(token.parameterString)) output += token.value;
|
|
1490
|
-
}
|
|
1491
|
-
return output;
|
|
1492
|
-
};
|
|
1493
|
-
//#endregion
|
|
1494
|
-
//#region src/squash-text-nodes.ts
|
|
1495
|
-
const squashTextNodes = (node) => {
|
|
1496
|
-
let text = "";
|
|
1497
|
-
for (let index = 0; index < node.childNodes.length; index++) {
|
|
1498
|
-
const childNode = node.childNodes[index];
|
|
1499
|
-
if (childNode === void 0) continue;
|
|
1500
|
-
let nodeText = "";
|
|
1501
|
-
if (childNode.nodeName === "#text") nodeText = childNode.nodeValue;
|
|
1502
|
-
else {
|
|
1503
|
-
if (childNode.nodeName === "ink-text" || childNode.nodeName === "ink-virtual-text") nodeText = squashTextNodes(childNode);
|
|
1504
|
-
if (nodeText.length > 0 && typeof childNode.internal_transform === "function") nodeText = childNode.internal_transform(nodeText, index);
|
|
1505
|
-
}
|
|
1506
|
-
text += nodeText;
|
|
1507
|
-
}
|
|
1508
|
-
return sanitizeAnsi(text);
|
|
1509
|
-
};
|
|
1510
|
-
//#endregion
|
|
1511
|
-
//#region src/wrap-text.ts
|
|
1512
|
-
const wrapTextCache = new QuickLru({ maxSize: 4096 });
|
|
1513
|
-
const wrapText = (text, maxWidth, wrapType) => {
|
|
1514
|
-
const cacheKey = text + String(maxWidth) + String(wrapType);
|
|
1515
|
-
const cachedText = wrapTextCache.get(cacheKey);
|
|
1516
|
-
if (cachedText !== void 0) return cachedText;
|
|
1517
|
-
let wrappedText = text;
|
|
1518
|
-
if (wrapType === "wrap") wrappedText = wrapAnsi(text, maxWidth, {
|
|
1519
|
-
trim: false,
|
|
1520
|
-
hard: true
|
|
1521
|
-
});
|
|
1522
|
-
if (wrapType === "hard") wrappedText = wrapAnsi(text, maxWidth, {
|
|
1523
|
-
trim: false,
|
|
1524
|
-
hard: true,
|
|
1525
|
-
wordWrap: false
|
|
1526
|
-
});
|
|
1527
|
-
if (wrapType.startsWith("truncate")) {
|
|
1528
|
-
let position = "end";
|
|
1529
|
-
if (wrapType === "truncate-middle") position = "middle";
|
|
1530
|
-
if (wrapType === "truncate-start") position = "start";
|
|
1531
|
-
wrappedText = cliTruncate(text, maxWidth, { position });
|
|
1532
|
-
}
|
|
1533
|
-
wrapTextCache.set(cacheKey, wrappedText);
|
|
1534
|
-
return wrappedText;
|
|
1535
|
-
};
|
|
1536
|
-
//#endregion
|
|
1537
|
-
//#region src/dom.ts
|
|
1538
|
-
const createNode = (nodeName) => {
|
|
1539
|
-
const node = {
|
|
1540
|
-
nodeName,
|
|
1541
|
-
style: {},
|
|
1542
|
-
attributes: {},
|
|
1543
|
-
childNodes: [],
|
|
1544
|
-
parentNode: void 0,
|
|
1545
|
-
yogaNode: nodeName === "ink-virtual-text" ? void 0 : Yoga.Node.create(),
|
|
1546
|
-
internal_accessibility: {}
|
|
1547
|
-
};
|
|
1548
|
-
if (nodeName === "ink-text") node.yogaNode?.setMeasureFunc(measureTextNode.bind(null, node));
|
|
1549
|
-
return node;
|
|
1550
|
-
};
|
|
1551
|
-
const appendChildNode = (node, childNode) => {
|
|
1552
|
-
if (childNode.parentNode) removeChildNode(childNode.parentNode, childNode);
|
|
1553
|
-
childNode.parentNode = node;
|
|
1554
|
-
node.childNodes.push(childNode);
|
|
1555
|
-
if (childNode.yogaNode) node.yogaNode?.insertChild(childNode.yogaNode, node.yogaNode.getChildCount());
|
|
1556
|
-
if (node.nodeName === "ink-text" || node.nodeName === "ink-virtual-text") markNodeAsDirty(node);
|
|
1557
|
-
};
|
|
1558
|
-
const insertBeforeNode = (node, newChildNode, beforeChildNode) => {
|
|
1559
|
-
if (newChildNode.parentNode) removeChildNode(newChildNode.parentNode, newChildNode);
|
|
1560
|
-
newChildNode.parentNode = node;
|
|
1561
|
-
const index = node.childNodes.indexOf(beforeChildNode);
|
|
1562
|
-
if (index >= 0) {
|
|
1563
|
-
node.childNodes.splice(index, 0, newChildNode);
|
|
1564
|
-
if (newChildNode.yogaNode) node.yogaNode?.insertChild(newChildNode.yogaNode, index);
|
|
1565
|
-
} else {
|
|
1566
|
-
node.childNodes.push(newChildNode);
|
|
1567
|
-
if (newChildNode.yogaNode) node.yogaNode?.insertChild(newChildNode.yogaNode, node.yogaNode.getChildCount());
|
|
1568
|
-
}
|
|
1569
|
-
if (node.nodeName === "ink-text" || node.nodeName === "ink-virtual-text") markNodeAsDirty(node);
|
|
1570
|
-
};
|
|
1571
|
-
const removeChildNode = (node, removeNode) => {
|
|
1572
|
-
if (removeNode.yogaNode) removeNode.parentNode?.yogaNode?.removeChild(removeNode.yogaNode);
|
|
1573
|
-
removeNode.parentNode = void 0;
|
|
1574
|
-
const index = node.childNodes.indexOf(removeNode);
|
|
1575
|
-
if (index >= 0) node.childNodes.splice(index, 1);
|
|
1576
|
-
if (node.nodeName === "ink-text" || node.nodeName === "ink-virtual-text") markNodeAsDirty(node);
|
|
1577
|
-
};
|
|
1578
|
-
const nullifyYogaNodes = (node) => {
|
|
1579
|
-
node.yogaNode = void 0;
|
|
1580
|
-
if (node.nodeName !== "#text") for (const childNode of node.childNodes) nullifyYogaNodes(childNode);
|
|
1581
|
-
};
|
|
1582
|
-
/**
|
|
1583
|
-
Detach a removed subtree from the layout engine: drop the measure callback
|
|
1584
|
-
and null the `yogaNode` reference on every DOM node within it.
|
|
1585
|
-
|
|
1586
|
-
Nulling the references makes every `?.yogaNode` guard in the codebase
|
|
1587
|
-
effective for removed nodes, turns lingering access into a safe no-op (see
|
|
1588
|
-
QwenLM/qwen-code#6820), and lets the garbage collector reclaim the Yoga
|
|
1589
|
-
tree along with its closures.
|
|
1590
|
-
*/
|
|
1591
|
-
const detachYogaSubtree = (removeNode) => {
|
|
1592
|
-
removeNode.yogaNode?.unsetMeasureFunc();
|
|
1593
|
-
nullifyYogaNodes(removeNode);
|
|
1594
|
-
};
|
|
1595
|
-
const setAttribute = (node, key, value) => {
|
|
1596
|
-
if (key === "internal_accessibility") {
|
|
1597
|
-
node.internal_accessibility = value;
|
|
1598
|
-
return;
|
|
1599
|
-
}
|
|
1600
|
-
node.attributes[key] = value;
|
|
1601
|
-
};
|
|
1602
|
-
const setStyle = (node, style) => {
|
|
1603
|
-
node.style = style ?? {};
|
|
1604
|
-
};
|
|
1605
|
-
const createTextNode = (text) => {
|
|
1606
|
-
const node = {
|
|
1607
|
-
nodeName: "#text",
|
|
1608
|
-
nodeValue: text,
|
|
1609
|
-
yogaNode: void 0,
|
|
1610
|
-
parentNode: void 0,
|
|
1611
|
-
style: {}
|
|
1612
|
-
};
|
|
1613
|
-
setTextNodeValue(node, text);
|
|
1614
|
-
return node;
|
|
1615
|
-
};
|
|
1616
|
-
const measureTextNode = function(node, width) {
|
|
1617
|
-
const text = node.nodeName === "#text" ? node.nodeValue : squashTextNodes(node);
|
|
1618
|
-
const dimensions = measureText(text);
|
|
1619
|
-
if (dimensions.width <= width) return dimensions;
|
|
1620
|
-
if (dimensions.width >= 1 && width > 0 && width < 1) return dimensions;
|
|
1621
|
-
const textWrap = node.style?.textWrap ?? "wrap";
|
|
1622
|
-
const wrappedText = wrapText(text, width, textWrap);
|
|
1623
|
-
return measureText(wrappedText);
|
|
1624
|
-
};
|
|
1625
|
-
const findClosestYogaNode = (node) => {
|
|
1626
|
-
if (!node?.parentNode) return;
|
|
1627
|
-
return node.yogaNode ?? findClosestYogaNode(node.parentNode);
|
|
1628
|
-
};
|
|
1629
|
-
const markNodeAsDirty = (node) => {
|
|
1630
|
-
findClosestYogaNode(node)?.markDirty();
|
|
1631
|
-
};
|
|
1632
|
-
const setTextNodeValue = (node, text) => {
|
|
1633
|
-
if (typeof text !== "string") text = String(text);
|
|
1634
|
-
node.nodeValue = text;
|
|
1635
|
-
markNodeAsDirty(node);
|
|
1636
|
-
};
|
|
1637
|
-
const addLayoutListener = (rootNode, listener) => {
|
|
1638
|
-
if (rootNode.nodeName !== "ink-root") return () => {};
|
|
1639
|
-
rootNode.internal_layoutListeners ??= /* @__PURE__ */ new Set();
|
|
1640
|
-
rootNode.internal_layoutListeners.add(listener);
|
|
1641
|
-
return () => {
|
|
1642
|
-
rootNode.internal_layoutListeners?.delete(listener);
|
|
1643
|
-
};
|
|
1644
|
-
};
|
|
1645
|
-
const emitLayoutListeners = (rootNode) => {
|
|
1646
|
-
if (rootNode.nodeName !== "ink-root" || !rootNode.internal_layoutListeners) return;
|
|
1647
|
-
for (const listener of rootNode.internal_layoutListeners) listener();
|
|
1648
|
-
};
|
|
922
|
+
//#region src/components/TerminalOscContext.ts
|
|
923
|
+
const noop$1 = () => {};
|
|
924
|
+
const TerminalOscContext = createContext({
|
|
925
|
+
publishProgress: noop$1,
|
|
926
|
+
copyToClipboard: noop$1,
|
|
927
|
+
publishTitle: noop$1,
|
|
928
|
+
setWorkingDirectory: noop$1,
|
|
929
|
+
notify: noop$1,
|
|
930
|
+
setPointerShape: noop$1
|
|
931
|
+
});
|
|
932
|
+
TerminalOscContext.displayName = "InternalTerminalOscContext";
|
|
1649
933
|
//#endregion
|
|
1650
934
|
//#region src/instances.ts
|
|
1651
935
|
const instances = /* @__PURE__ */ new WeakMap();
|
|
1652
936
|
//#endregion
|
|
1653
|
-
//#region src/is-in-ci.ts
|
|
1654
|
-
const check = (key) => key in process.env && process.env[key] !== "0" && process.env[key] !== "false";
|
|
1655
|
-
const isInCi = check("CI") || check("CONTINUOUS_INTEGRATION");
|
|
1656
|
-
//#endregion
|
|
1657
|
-
//#region src/kitty-keyboard.ts
|
|
1658
|
-
const kittyFlags = {
|
|
1659
|
-
disambiguateEscapeCodes: 1,
|
|
1660
|
-
reportEventTypes: 2,
|
|
1661
|
-
reportAlternateKeys: 4,
|
|
1662
|
-
reportAllKeysAsEscapeCodes: 8,
|
|
1663
|
-
reportAssociatedText: 16
|
|
1664
|
-
};
|
|
1665
|
-
function resolveFlags(flags) {
|
|
1666
|
-
let result = 0;
|
|
1667
|
-
for (const flag of flags) result |= kittyFlags[flag];
|
|
1668
|
-
return result;
|
|
1669
|
-
}
|
|
1670
|
-
const kittyModifiers = {
|
|
1671
|
-
shift: 1,
|
|
1672
|
-
alt: 2,
|
|
1673
|
-
ctrl: 4,
|
|
1674
|
-
super: 8,
|
|
1675
|
-
hyper: 16,
|
|
1676
|
-
meta: 32,
|
|
1677
|
-
capsLock: 64,
|
|
1678
|
-
numLock: 128
|
|
1679
|
-
};
|
|
1680
|
-
//#endregion
|
|
1681
|
-
//#region src/log-update.ts
|
|
1682
|
-
const visibleLineCount = (lines, str) => str.endsWith("\n") ? lines.length - 1 : lines.length;
|
|
1683
|
-
const createStandard = (stream, { showCursor = false } = {}) => {
|
|
1684
|
-
let previousLineCount = 0;
|
|
1685
|
-
let previousOutput = "";
|
|
1686
|
-
let hasHiddenCursor = false;
|
|
1687
|
-
let cursorPosition;
|
|
1688
|
-
let cursorDirty = false;
|
|
1689
|
-
let previousCursorPosition;
|
|
1690
|
-
let cursorWasShown = false;
|
|
1691
|
-
const getActiveCursor = () => cursorDirty ? cursorPosition : void 0;
|
|
1692
|
-
const hasChanges = (str, activeCursor) => {
|
|
1693
|
-
const cursorChanged = cursorPositionChanged(activeCursor, previousCursorPosition);
|
|
1694
|
-
return str !== previousOutput || cursorChanged;
|
|
1695
|
-
};
|
|
1696
|
-
const render = (str) => {
|
|
1697
|
-
if (!showCursor && !hasHiddenCursor) {
|
|
1698
|
-
cliCursor.hide(stream);
|
|
1699
|
-
hasHiddenCursor = true;
|
|
1700
|
-
}
|
|
1701
|
-
const activeCursor = getActiveCursor();
|
|
1702
|
-
cursorDirty = false;
|
|
1703
|
-
const cursorChanged = cursorPositionChanged(activeCursor, previousCursorPosition);
|
|
1704
|
-
if (!hasChanges(str, activeCursor)) return false;
|
|
1705
|
-
const lines = str.split("\n");
|
|
1706
|
-
const cursorSuffix = buildCursorSuffix(lines.length - 1, activeCursor);
|
|
1707
|
-
if (str === previousOutput && cursorChanged) stream.write(buildCursorOnlySequence({
|
|
1708
|
-
cursorWasShown,
|
|
1709
|
-
previousLineCount,
|
|
1710
|
-
previousCursorPosition,
|
|
1711
|
-
cursorPosition: activeCursor
|
|
1712
|
-
}));
|
|
1713
|
-
else {
|
|
1714
|
-
previousOutput = str;
|
|
1715
|
-
const returnPrefix = buildReturnToBottomPrefix(cursorWasShown, previousLineCount, previousCursorPosition);
|
|
1716
|
-
stream.write(returnPrefix + ansiEscapes.eraseLines(previousLineCount) + str + cursorSuffix);
|
|
1717
|
-
previousLineCount = lines.length;
|
|
1718
|
-
}
|
|
1719
|
-
previousCursorPosition = activeCursor ? { ...activeCursor } : void 0;
|
|
1720
|
-
cursorWasShown = activeCursor !== void 0;
|
|
1721
|
-
return true;
|
|
1722
|
-
};
|
|
1723
|
-
render.clear = () => {
|
|
1724
|
-
const prefix = buildReturnToBottomPrefix(cursorWasShown, previousLineCount, previousCursorPosition);
|
|
1725
|
-
stream.write(prefix + ansiEscapes.eraseLines(previousLineCount));
|
|
1726
|
-
previousOutput = "";
|
|
1727
|
-
previousLineCount = 0;
|
|
1728
|
-
previousCursorPosition = void 0;
|
|
1729
|
-
cursorWasShown = false;
|
|
1730
|
-
};
|
|
1731
|
-
render.done = () => {
|
|
1732
|
-
previousOutput = "";
|
|
1733
|
-
previousLineCount = 0;
|
|
1734
|
-
previousCursorPosition = void 0;
|
|
1735
|
-
cursorWasShown = false;
|
|
1736
|
-
if (!showCursor) {
|
|
1737
|
-
cliCursor.show(stream);
|
|
1738
|
-
hasHiddenCursor = false;
|
|
1739
|
-
}
|
|
1740
|
-
};
|
|
1741
|
-
render.reset = () => {
|
|
1742
|
-
previousOutput = "";
|
|
1743
|
-
previousLineCount = 0;
|
|
1744
|
-
previousCursorPosition = void 0;
|
|
1745
|
-
cursorWasShown = false;
|
|
1746
|
-
};
|
|
1747
|
-
render.sync = (str) => {
|
|
1748
|
-
const activeCursor = cursorDirty ? cursorPosition : void 0;
|
|
1749
|
-
cursorDirty = false;
|
|
1750
|
-
const lines = str.split("\n");
|
|
1751
|
-
previousOutput = str;
|
|
1752
|
-
previousLineCount = lines.length;
|
|
1753
|
-
if (!activeCursor && cursorWasShown) stream.write(hideCursorEscape);
|
|
1754
|
-
if (activeCursor) stream.write(buildCursorSuffix(lines.length - 1, activeCursor));
|
|
1755
|
-
previousCursorPosition = activeCursor ? { ...activeCursor } : void 0;
|
|
1756
|
-
cursorWasShown = activeCursor !== void 0;
|
|
1757
|
-
};
|
|
1758
|
-
render.setCursorPosition = (position) => {
|
|
1759
|
-
cursorPosition = position;
|
|
1760
|
-
cursorDirty = true;
|
|
1761
|
-
};
|
|
1762
|
-
render.isCursorDirty = () => cursorDirty;
|
|
1763
|
-
render.willRender = (str) => hasChanges(str, getActiveCursor());
|
|
1764
|
-
return render;
|
|
1765
|
-
};
|
|
1766
|
-
const createIncremental = (stream, { showCursor = false } = {}) => {
|
|
1767
|
-
let previousLines = [];
|
|
1768
|
-
let previousOutput = "";
|
|
1769
|
-
let hasHiddenCursor = false;
|
|
1770
|
-
let cursorPosition;
|
|
1771
|
-
let cursorDirty = false;
|
|
1772
|
-
let previousCursorPosition;
|
|
1773
|
-
let cursorWasShown = false;
|
|
1774
|
-
const getActiveCursor = () => cursorDirty ? cursorPosition : void 0;
|
|
1775
|
-
const hasChanges = (str, activeCursor) => {
|
|
1776
|
-
const cursorChanged = cursorPositionChanged(activeCursor, previousCursorPosition);
|
|
1777
|
-
return str !== previousOutput || cursorChanged;
|
|
1778
|
-
};
|
|
1779
|
-
const render = (str) => {
|
|
1780
|
-
if (!showCursor && !hasHiddenCursor) {
|
|
1781
|
-
cliCursor.hide(stream);
|
|
1782
|
-
hasHiddenCursor = true;
|
|
1783
|
-
}
|
|
1784
|
-
const activeCursor = getActiveCursor();
|
|
1785
|
-
cursorDirty = false;
|
|
1786
|
-
const cursorChanged = cursorPositionChanged(activeCursor, previousCursorPosition);
|
|
1787
|
-
if (!hasChanges(str, activeCursor)) return false;
|
|
1788
|
-
const nextLines = str.split("\n");
|
|
1789
|
-
const visibleCount = visibleLineCount(nextLines, str);
|
|
1790
|
-
const previousVisible = visibleLineCount(previousLines, previousOutput);
|
|
1791
|
-
if (str === previousOutput && cursorChanged) {
|
|
1792
|
-
stream.write(buildCursorOnlySequence({
|
|
1793
|
-
cursorWasShown,
|
|
1794
|
-
previousLineCount: previousLines.length,
|
|
1795
|
-
previousCursorPosition,
|
|
1796
|
-
cursorPosition: activeCursor
|
|
1797
|
-
}));
|
|
1798
|
-
previousCursorPosition = activeCursor ? { ...activeCursor } : void 0;
|
|
1799
|
-
cursorWasShown = activeCursor !== void 0;
|
|
1800
|
-
return true;
|
|
1801
|
-
}
|
|
1802
|
-
const returnPrefix = buildReturnToBottomPrefix(cursorWasShown, previousLines.length, previousCursorPosition);
|
|
1803
|
-
if (str === "\n" || previousOutput.length === 0) {
|
|
1804
|
-
const cursorSuffix = buildCursorSuffix(nextLines.length - 1, activeCursor);
|
|
1805
|
-
stream.write(returnPrefix + ansiEscapes.eraseLines(previousLines.length) + str + cursorSuffix);
|
|
1806
|
-
cursorWasShown = activeCursor !== void 0;
|
|
1807
|
-
previousCursorPosition = activeCursor ? { ...activeCursor } : void 0;
|
|
1808
|
-
previousOutput = str;
|
|
1809
|
-
previousLines = nextLines;
|
|
1810
|
-
return true;
|
|
1811
|
-
}
|
|
1812
|
-
if (visibleCount > previousVisible) {
|
|
1813
|
-
const cursorSuffix = buildCursorSuffix(visibleCount, activeCursor);
|
|
1814
|
-
stream.write(returnPrefix + ansiEscapes.eraseLines(previousLines.length) + str + cursorSuffix);
|
|
1815
|
-
cursorWasShown = activeCursor !== void 0;
|
|
1816
|
-
previousCursorPosition = activeCursor ? { ...activeCursor } : void 0;
|
|
1817
|
-
previousOutput = str;
|
|
1818
|
-
previousLines = nextLines;
|
|
1819
|
-
return true;
|
|
1820
|
-
}
|
|
1821
|
-
const hasTrailingNewline = str.endsWith("\n");
|
|
1822
|
-
const buffer = [];
|
|
1823
|
-
buffer.push(returnPrefix);
|
|
1824
|
-
if (visibleCount < previousVisible) {
|
|
1825
|
-
const extraSlot = previousOutput.endsWith("\n") ? 1 : 0;
|
|
1826
|
-
buffer.push(ansiEscapes.eraseLines(previousVisible - visibleCount + extraSlot), ansiEscapes.cursorUp(visibleCount));
|
|
1827
|
-
} else buffer.push(ansiEscapes.cursorUp(previousLines.length - 1));
|
|
1828
|
-
for (let i = 0; i < visibleCount; i++) {
|
|
1829
|
-
const isLastLine = i === visibleCount - 1;
|
|
1830
|
-
if (nextLines[i] === previousLines[i]) {
|
|
1831
|
-
if (!isLastLine || hasTrailingNewline) buffer.push(ansiEscapes.cursorNextLine);
|
|
1832
|
-
continue;
|
|
1833
|
-
}
|
|
1834
|
-
buffer.push(ansiEscapes.cursorTo(0) + nextLines[i] + ansiEscapes.eraseEndLine + (isLastLine && !hasTrailingNewline ? "" : "\n"));
|
|
1835
|
-
}
|
|
1836
|
-
const cursorSuffix = buildCursorSuffix(nextLines.length - 1, activeCursor);
|
|
1837
|
-
buffer.push(cursorSuffix);
|
|
1838
|
-
stream.write(buffer.join(""));
|
|
1839
|
-
cursorWasShown = activeCursor !== void 0;
|
|
1840
|
-
previousCursorPosition = activeCursor ? { ...activeCursor } : void 0;
|
|
1841
|
-
previousOutput = str;
|
|
1842
|
-
previousLines = nextLines;
|
|
1843
|
-
return true;
|
|
1844
|
-
};
|
|
1845
|
-
render.clear = () => {
|
|
1846
|
-
const prefix = buildReturnToBottomPrefix(cursorWasShown, previousLines.length, previousCursorPosition);
|
|
1847
|
-
stream.write(prefix + ansiEscapes.eraseLines(previousLines.length));
|
|
1848
|
-
previousOutput = "";
|
|
1849
|
-
previousLines = [];
|
|
1850
|
-
previousCursorPosition = void 0;
|
|
1851
|
-
cursorWasShown = false;
|
|
1852
|
-
};
|
|
1853
|
-
render.done = () => {
|
|
1854
|
-
previousOutput = "";
|
|
1855
|
-
previousLines = [];
|
|
1856
|
-
previousCursorPosition = void 0;
|
|
1857
|
-
cursorWasShown = false;
|
|
1858
|
-
if (!showCursor) {
|
|
1859
|
-
cliCursor.show(stream);
|
|
1860
|
-
hasHiddenCursor = false;
|
|
1861
|
-
}
|
|
1862
|
-
};
|
|
1863
|
-
render.reset = () => {
|
|
1864
|
-
previousOutput = "";
|
|
1865
|
-
previousLines = [];
|
|
1866
|
-
previousCursorPosition = void 0;
|
|
1867
|
-
cursorWasShown = false;
|
|
1868
|
-
};
|
|
1869
|
-
render.sync = (str) => {
|
|
1870
|
-
const activeCursor = cursorDirty ? cursorPosition : void 0;
|
|
1871
|
-
cursorDirty = false;
|
|
1872
|
-
const lines = str.split("\n");
|
|
1873
|
-
previousOutput = str;
|
|
1874
|
-
previousLines = lines;
|
|
1875
|
-
if (!activeCursor && cursorWasShown) stream.write(hideCursorEscape);
|
|
1876
|
-
if (activeCursor) stream.write(buildCursorSuffix(lines.length - 1, activeCursor));
|
|
1877
|
-
previousCursorPosition = activeCursor ? { ...activeCursor } : void 0;
|
|
1878
|
-
cursorWasShown = activeCursor !== void 0;
|
|
1879
|
-
};
|
|
1880
|
-
render.setCursorPosition = (position) => {
|
|
1881
|
-
cursorPosition = position;
|
|
1882
|
-
cursorDirty = true;
|
|
1883
|
-
};
|
|
1884
|
-
render.isCursorDirty = () => cursorDirty;
|
|
1885
|
-
render.willRender = (str) => hasChanges(str, getActiveCursor());
|
|
1886
|
-
return render;
|
|
1887
|
-
};
|
|
1888
|
-
const create$1 = (stream, { showCursor = false, incremental = false } = {}) => {
|
|
1889
|
-
if (incremental) return createIncremental(stream, { showCursor });
|
|
1890
|
-
return createStandard(stream, { showCursor });
|
|
1891
|
-
};
|
|
1892
|
-
const logUpdate = { create: create$1 };
|
|
1893
|
-
//#endregion
|
|
1894
937
|
//#region src/patch-console.ts
|
|
1895
938
|
const consoleMethods = [
|
|
1896
939
|
"assert",
|
|
@@ -1905,590 +948,46 @@ const consoleMethods = [
|
|
|
1905
948
|
"groupEnd",
|
|
1906
949
|
"info",
|
|
1907
950
|
"log",
|
|
1908
|
-
"table",
|
|
1909
|
-
"time",
|
|
1910
|
-
"timeEnd",
|
|
1911
|
-
"timeLog",
|
|
1912
|
-
"trace",
|
|
1913
|
-
"warn"
|
|
1914
|
-
];
|
|
1915
|
-
const patchConsole = (callback) => {
|
|
1916
|
-
const stdout = new PassThrough();
|
|
1917
|
-
const stderr = new PassThrough();
|
|
1918
|
-
stdout.write = (data) => {
|
|
1919
|
-
callback("stdout", String(data));
|
|
1920
|
-
return true;
|
|
1921
|
-
};
|
|
1922
|
-
stderr.write = (data) => {
|
|
1923
|
-
callback("stderr", String(data));
|
|
1924
|
-
return true;
|
|
1925
|
-
};
|
|
1926
|
-
const internalConsole = new Console(stdout, stderr);
|
|
1927
|
-
const originalMethods = /* @__PURE__ */ new Map();
|
|
1928
|
-
for (const method of consoleMethods) {
|
|
1929
|
-
originalMethods.set(method, console[method]);
|
|
1930
|
-
console[method] = internalConsole[method];
|
|
1931
|
-
}
|
|
1932
|
-
return () => {
|
|
1933
|
-
for (const method of consoleMethods) console[method] = originalMethods.get(method);
|
|
1934
|
-
originalMethods.clear();
|
|
1935
|
-
};
|
|
1936
|
-
};
|
|
1937
|
-
//#endregion
|
|
1938
|
-
//#region src/styles.ts
|
|
1939
|
-
const positionEdges = [
|
|
1940
|
-
["top", Yoga.EDGE_TOP],
|
|
1941
|
-
["right", Yoga.EDGE_RIGHT],
|
|
1942
|
-
["bottom", Yoga.EDGE_BOTTOM],
|
|
1943
|
-
["left", Yoga.EDGE_LEFT]
|
|
1944
|
-
];
|
|
1945
|
-
const applyPositionStyles = (node, style) => {
|
|
1946
|
-
if ("position" in style) {
|
|
1947
|
-
let positionType = Yoga.POSITION_TYPE_RELATIVE;
|
|
1948
|
-
if (style.position === "absolute") positionType = Yoga.POSITION_TYPE_ABSOLUTE;
|
|
1949
|
-
else if (style.position === "static") positionType = Yoga.POSITION_TYPE_STATIC;
|
|
1950
|
-
node.setPositionType(positionType);
|
|
1951
|
-
}
|
|
1952
|
-
for (const [property, edge] of positionEdges) {
|
|
1953
|
-
if (!(property in style)) continue;
|
|
1954
|
-
const value = style[property];
|
|
1955
|
-
if (typeof value === "string") {
|
|
1956
|
-
node.setPositionPercent(edge, Number.parseFloat(value));
|
|
1957
|
-
continue;
|
|
1958
|
-
}
|
|
1959
|
-
node.setPosition(edge, value);
|
|
1960
|
-
}
|
|
1961
|
-
};
|
|
1962
|
-
const applyMarginStyles = (node, style) => {
|
|
1963
|
-
if ("margin" in style) node.setMargin(Yoga.EDGE_ALL, style.margin ?? 0);
|
|
1964
|
-
if ("marginX" in style) node.setMargin(Yoga.EDGE_HORIZONTAL, style.marginX ?? 0);
|
|
1965
|
-
if ("marginY" in style) node.setMargin(Yoga.EDGE_VERTICAL, style.marginY ?? 0);
|
|
1966
|
-
if ("marginLeft" in style) node.setMargin(Yoga.EDGE_START, style.marginLeft ?? 0);
|
|
1967
|
-
if ("marginRight" in style) node.setMargin(Yoga.EDGE_END, style.marginRight ?? 0);
|
|
1968
|
-
if ("marginTop" in style) node.setMargin(Yoga.EDGE_TOP, style.marginTop ?? 0);
|
|
1969
|
-
if ("marginBottom" in style) node.setMargin(Yoga.EDGE_BOTTOM, style.marginBottom ?? 0);
|
|
1970
|
-
};
|
|
1971
|
-
const applyPaddingStyles = (node, style) => {
|
|
1972
|
-
if ("padding" in style) node.setPadding(Yoga.EDGE_ALL, style.padding ?? 0);
|
|
1973
|
-
if ("paddingX" in style) node.setPadding(Yoga.EDGE_HORIZONTAL, style.paddingX ?? 0);
|
|
1974
|
-
if ("paddingY" in style) node.setPadding(Yoga.EDGE_VERTICAL, style.paddingY ?? 0);
|
|
1975
|
-
if ("paddingLeft" in style) node.setPadding(Yoga.EDGE_LEFT, style.paddingLeft ?? 0);
|
|
1976
|
-
if ("paddingRight" in style) node.setPadding(Yoga.EDGE_RIGHT, style.paddingRight ?? 0);
|
|
1977
|
-
if ("paddingTop" in style) node.setPadding(Yoga.EDGE_TOP, style.paddingTop ?? 0);
|
|
1978
|
-
if ("paddingBottom" in style) node.setPadding(Yoga.EDGE_BOTTOM, style.paddingBottom ?? 0);
|
|
1979
|
-
};
|
|
1980
|
-
const applyFlexStyles = (node, style) => {
|
|
1981
|
-
if ("flexGrow" in style) node.setFlexGrow(style.flexGrow ?? 0);
|
|
1982
|
-
if ("flexShrink" in style) node.setFlexShrink(typeof style.flexShrink === "number" ? style.flexShrink : 1);
|
|
1983
|
-
if ("flexWrap" in style) {
|
|
1984
|
-
if (style.flexWrap === "nowrap") node.setFlexWrap(Yoga.WRAP_NO_WRAP);
|
|
1985
|
-
if (style.flexWrap === "wrap") node.setFlexWrap(Yoga.WRAP_WRAP);
|
|
1986
|
-
if (style.flexWrap === "wrap-reverse") node.setFlexWrap(Yoga.WRAP_WRAP_REVERSE);
|
|
1987
|
-
}
|
|
1988
|
-
if ("flexDirection" in style) {
|
|
1989
|
-
if (style.flexDirection === "row") node.setFlexDirection(Yoga.FLEX_DIRECTION_ROW);
|
|
1990
|
-
if (style.flexDirection === "row-reverse") node.setFlexDirection(Yoga.FLEX_DIRECTION_ROW_REVERSE);
|
|
1991
|
-
if (style.flexDirection === "column") node.setFlexDirection(Yoga.FLEX_DIRECTION_COLUMN);
|
|
1992
|
-
if (style.flexDirection === "column-reverse") node.setFlexDirection(Yoga.FLEX_DIRECTION_COLUMN_REVERSE);
|
|
1993
|
-
}
|
|
1994
|
-
if ("flexBasis" in style) {
|
|
1995
|
-
if (typeof style.flexBasis === "number") node.setFlexBasis(style.flexBasis);
|
|
1996
|
-
else if (typeof style.flexBasis === "string") node.setFlexBasisPercent(Number.parseInt(style.flexBasis, 10));
|
|
1997
|
-
else node.setFlexBasisAuto();
|
|
1998
|
-
}
|
|
1999
|
-
if ("alignItems" in style) {
|
|
2000
|
-
if (style.alignItems === "stretch" || !style.alignItems) node.setAlignItems(Yoga.ALIGN_STRETCH);
|
|
2001
|
-
if (style.alignItems === "flex-start") node.setAlignItems(Yoga.ALIGN_FLEX_START);
|
|
2002
|
-
if (style.alignItems === "center") node.setAlignItems(Yoga.ALIGN_CENTER);
|
|
2003
|
-
if (style.alignItems === "flex-end") node.setAlignItems(Yoga.ALIGN_FLEX_END);
|
|
2004
|
-
if (style.alignItems === "baseline") node.setAlignItems(Yoga.ALIGN_BASELINE);
|
|
2005
|
-
}
|
|
2006
|
-
if ("alignSelf" in style) {
|
|
2007
|
-
if (style.alignSelf === "auto" || !style.alignSelf) node.setAlignSelf(Yoga.ALIGN_AUTO);
|
|
2008
|
-
if (style.alignSelf === "flex-start") node.setAlignSelf(Yoga.ALIGN_FLEX_START);
|
|
2009
|
-
if (style.alignSelf === "center") node.setAlignSelf(Yoga.ALIGN_CENTER);
|
|
2010
|
-
if (style.alignSelf === "flex-end") node.setAlignSelf(Yoga.ALIGN_FLEX_END);
|
|
2011
|
-
if (style.alignSelf === "stretch") node.setAlignSelf(Yoga.ALIGN_STRETCH);
|
|
2012
|
-
if (style.alignSelf === "baseline") node.setAlignSelf(Yoga.ALIGN_BASELINE);
|
|
2013
|
-
}
|
|
2014
|
-
if ("alignContent" in style) {
|
|
2015
|
-
if (style.alignContent === "flex-start" || !style.alignContent) node.setAlignContent(Yoga.ALIGN_FLEX_START);
|
|
2016
|
-
if (style.alignContent === "center") node.setAlignContent(Yoga.ALIGN_CENTER);
|
|
2017
|
-
if (style.alignContent === "flex-end") node.setAlignContent(Yoga.ALIGN_FLEX_END);
|
|
2018
|
-
if (style.alignContent === "space-between") node.setAlignContent(Yoga.ALIGN_SPACE_BETWEEN);
|
|
2019
|
-
if (style.alignContent === "space-around") node.setAlignContent(Yoga.ALIGN_SPACE_AROUND);
|
|
2020
|
-
if (style.alignContent === "space-evenly") node.setAlignContent(Yoga.ALIGN_SPACE_EVENLY);
|
|
2021
|
-
if (style.alignContent === "stretch") node.setAlignContent(Yoga.ALIGN_STRETCH);
|
|
2022
|
-
}
|
|
2023
|
-
if ("justifyContent" in style) {
|
|
2024
|
-
if (style.justifyContent === "flex-start" || !style.justifyContent) node.setJustifyContent(Yoga.JUSTIFY_FLEX_START);
|
|
2025
|
-
if (style.justifyContent === "center") node.setJustifyContent(Yoga.JUSTIFY_CENTER);
|
|
2026
|
-
if (style.justifyContent === "flex-end") node.setJustifyContent(Yoga.JUSTIFY_FLEX_END);
|
|
2027
|
-
if (style.justifyContent === "space-between") node.setJustifyContent(Yoga.JUSTIFY_SPACE_BETWEEN);
|
|
2028
|
-
if (style.justifyContent === "space-around") node.setJustifyContent(Yoga.JUSTIFY_SPACE_AROUND);
|
|
2029
|
-
if (style.justifyContent === "space-evenly") node.setJustifyContent(Yoga.JUSTIFY_SPACE_EVENLY);
|
|
2030
|
-
}
|
|
2031
|
-
};
|
|
2032
|
-
const applyDimensionStyles = (node, style) => {
|
|
2033
|
-
if ("width" in style) {
|
|
2034
|
-
if (typeof style.width === "number") node.setWidth(style.width);
|
|
2035
|
-
else if (typeof style.width === "string") node.setWidthPercent(Number.parseInt(style.width, 10));
|
|
2036
|
-
else node.setWidthAuto();
|
|
2037
|
-
}
|
|
2038
|
-
if ("height" in style) {
|
|
2039
|
-
if (typeof style.height === "number") node.setHeight(style.height);
|
|
2040
|
-
else if (typeof style.height === "string") node.setHeightPercent(Number.parseInt(style.height, 10));
|
|
2041
|
-
else node.setHeightAuto();
|
|
2042
|
-
}
|
|
2043
|
-
if ("minWidth" in style) {
|
|
2044
|
-
if (typeof style.minWidth === "string") node.setMinWidthPercent(Number.parseInt(style.minWidth, 10));
|
|
2045
|
-
else node.setMinWidth(style.minWidth ?? 0);
|
|
2046
|
-
}
|
|
2047
|
-
if ("minHeight" in style) {
|
|
2048
|
-
if (typeof style.minHeight === "string") node.setMinHeightPercent(Number.parseInt(style.minHeight, 10));
|
|
2049
|
-
else node.setMinHeight(style.minHeight ?? 0);
|
|
2050
|
-
}
|
|
2051
|
-
if ("maxWidth" in style) {
|
|
2052
|
-
if (typeof style.maxWidth === "string") node.setMaxWidthPercent(Number.parseInt(style.maxWidth, 10));
|
|
2053
|
-
else node.setMaxWidth(style.maxWidth);
|
|
2054
|
-
}
|
|
2055
|
-
if ("maxHeight" in style) {
|
|
2056
|
-
if (typeof style.maxHeight === "string") node.setMaxHeightPercent(Number.parseInt(style.maxHeight, 10));
|
|
2057
|
-
else node.setMaxHeight(style.maxHeight);
|
|
2058
|
-
}
|
|
2059
|
-
if ("aspectRatio" in style) node.setAspectRatio(style.aspectRatio);
|
|
2060
|
-
};
|
|
2061
|
-
const applyDisplayStyles = (node, style) => {
|
|
2062
|
-
if ("display" in style) node.setDisplay(style.display === "flex" ? Yoga.DISPLAY_FLEX : Yoga.DISPLAY_NONE);
|
|
2063
|
-
};
|
|
2064
|
-
const applyBorderStyles = (node, style, currentStyle) => {
|
|
2065
|
-
if (!("borderStyle" in style || "borderTop" in style || "borderBottom" in style || "borderLeft" in style || "borderRight" in style)) return;
|
|
2066
|
-
const borderWidth = currentStyle.borderStyle ? 1 : 0;
|
|
2067
|
-
node.setBorder(Yoga.EDGE_TOP, currentStyle.borderTop === false ? 0 : borderWidth);
|
|
2068
|
-
node.setBorder(Yoga.EDGE_BOTTOM, currentStyle.borderBottom === false ? 0 : borderWidth);
|
|
2069
|
-
node.setBorder(Yoga.EDGE_LEFT, currentStyle.borderLeft === false ? 0 : borderWidth);
|
|
2070
|
-
node.setBorder(Yoga.EDGE_RIGHT, currentStyle.borderRight === false ? 0 : borderWidth);
|
|
2071
|
-
};
|
|
2072
|
-
const applyGapStyles = (node, style) => {
|
|
2073
|
-
if ("gap" in style) node.setGap(Yoga.GUTTER_ALL, style.gap ?? 0);
|
|
2074
|
-
if ("columnGap" in style) node.setGap(Yoga.GUTTER_COLUMN, style.columnGap ?? 0);
|
|
2075
|
-
if ("rowGap" in style) node.setGap(Yoga.GUTTER_ROW, style.rowGap ?? 0);
|
|
2076
|
-
};
|
|
2077
|
-
const styles = (node, style = {}, currentStyle = style) => {
|
|
2078
|
-
applyPositionStyles(node, style);
|
|
2079
|
-
applyMarginStyles(node, style);
|
|
2080
|
-
applyPaddingStyles(node, style);
|
|
2081
|
-
applyFlexStyles(node, style);
|
|
2082
|
-
applyDimensionStyles(node, style);
|
|
2083
|
-
applyDisplayStyles(node, style);
|
|
2084
|
-
applyBorderStyles(node, style, currentStyle);
|
|
2085
|
-
applyGapStyles(node, style);
|
|
2086
|
-
};
|
|
2087
|
-
//#endregion
|
|
2088
|
-
//#region src/reconciler.ts
|
|
2089
|
-
if (process.env["SIGIL_DEV"] === "true") {
|
|
2090
|
-
let isDevtoolsInstalled = false;
|
|
2091
|
-
try {
|
|
2092
|
-
import.meta.resolve("react-devtools-core");
|
|
2093
|
-
isDevtoolsInstalled = true;
|
|
2094
|
-
} catch {}
|
|
2095
|
-
if (isDevtoolsInstalled) await import("./devtools-BhYGjb7h.js");
|
|
2096
|
-
}
|
|
2097
|
-
const diff = (before, after) => {
|
|
2098
|
-
if (before === after) return;
|
|
2099
|
-
if (!before) return after;
|
|
2100
|
-
const changed = {};
|
|
2101
|
-
let isChanged = false;
|
|
2102
|
-
for (const key of Object.keys(before)) if (after ? !Object.hasOwn(after, key) : true) {
|
|
2103
|
-
changed[key] = void 0;
|
|
2104
|
-
isChanged = true;
|
|
2105
|
-
}
|
|
2106
|
-
if (after) {
|
|
2107
|
-
for (const key of Object.keys(after)) if (after[key] !== before[key]) {
|
|
2108
|
-
changed[key] = after[key];
|
|
2109
|
-
isChanged = true;
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
return isChanged ? changed : void 0;
|
|
2113
|
-
};
|
|
2114
|
-
const findRootNode$1 = (node) => {
|
|
2115
|
-
let current = node;
|
|
2116
|
-
while (current) {
|
|
2117
|
-
if (current.nodeName === "ink-root") return current;
|
|
2118
|
-
current = current.parentNode;
|
|
2119
|
-
}
|
|
2120
|
-
};
|
|
2121
|
-
/**
|
|
2122
|
-
* Clear the root's cached `staticNode` when the node it points at is being
|
|
2123
|
-
* removed as part of a larger subtree.
|
|
2124
|
-
*
|
|
2125
|
-
* The previous identity check (`staticNode === removeNode`) only caught direct
|
|
2126
|
-
* removal of the `<Static>` element. When an *ancestor* of `<Static>` is
|
|
2127
|
-
* removed, the stale `staticNode` reference survives and the next render would
|
|
2128
|
-
* replay stale static output (and, before `detachYogaSubtree`, trap on detached
|
|
2129
|
-
* WASM memory — see QwenLM/qwen-code#6820).
|
|
2130
|
-
*
|
|
2131
|
-
* The owning root is derived from the host parent passed to the removal hook,
|
|
2132
|
-
* not a module-level global, so instances with separate stdout streams don't
|
|
2133
|
-
* clobber each other's pointers.
|
|
2134
|
-
*/
|
|
2135
|
-
const clearStaticNodeIfContained = (rootNode, removeNode) => {
|
|
2136
|
-
if (!rootNode?.staticNode) return;
|
|
2137
|
-
let current = rootNode.staticNode;
|
|
2138
|
-
while (current) {
|
|
2139
|
-
if (current === removeNode) {
|
|
2140
|
-
rootNode.staticNode = void 0;
|
|
2141
|
-
return;
|
|
2142
|
-
}
|
|
2143
|
-
current = current.parentNode;
|
|
2144
|
-
}
|
|
2145
|
-
};
|
|
2146
|
-
let currentUpdatePriority = NoEventPriority;
|
|
2147
|
-
async function loadPackageJson() {
|
|
2148
|
-
const content = (await import("node:fs")).readFileSync(new URL("../package.json", import.meta.url), "utf8");
|
|
2149
|
-
const parsedContent = JSON.parse(content);
|
|
2150
|
-
return {
|
|
2151
|
-
name: parsedContent?.name,
|
|
2152
|
-
version: parsedContent?.version
|
|
2153
|
-
};
|
|
2154
|
-
}
|
|
2155
|
-
let packageInfo = {
|
|
2156
|
-
name: "ink",
|
|
2157
|
-
version
|
|
2158
|
-
};
|
|
2159
|
-
if (process.env["DEV"] === "true") try {
|
|
2160
|
-
const loaded = await loadPackageJson();
|
|
2161
|
-
packageInfo = {
|
|
2162
|
-
name: loaded.name || packageInfo.name,
|
|
2163
|
-
version: loaded.version || packageInfo.version
|
|
2164
|
-
};
|
|
2165
|
-
} catch (error) {
|
|
2166
|
-
console.warn("Failed to load package.json in development mode. Falling back to default renderer metadata.", error);
|
|
2167
|
-
}
|
|
2168
|
-
const reconciler = createReconciler({
|
|
2169
|
-
getRootHostContext: () => ({ isInsideText: false }),
|
|
2170
|
-
prepareForCommit: () => null,
|
|
2171
|
-
preparePortalMount: () => null,
|
|
2172
|
-
clearContainer: () => false,
|
|
2173
|
-
resetAfterCommit(rootNode) {
|
|
2174
|
-
if (typeof rootNode.onComputeLayout === "function") rootNode.onComputeLayout();
|
|
2175
|
-
emitLayoutListeners(rootNode);
|
|
2176
|
-
if (rootNode.staticNode !== rootNode.previousStaticNode) {
|
|
2177
|
-
rootNode.previousStaticNode = rootNode.staticNode;
|
|
2178
|
-
if (typeof rootNode.onStaticChange === "function") rootNode.onStaticChange();
|
|
2179
|
-
}
|
|
2180
|
-
if (rootNode.isStaticDirty) {
|
|
2181
|
-
rootNode.isStaticDirty = false;
|
|
2182
|
-
if (typeof rootNode.onImmediateRender === "function") rootNode.onImmediateRender();
|
|
2183
|
-
return;
|
|
2184
|
-
}
|
|
2185
|
-
if (typeof rootNode.onRender === "function") rootNode.onRender();
|
|
2186
|
-
},
|
|
2187
|
-
getChildHostContext(parentHostContext, type) {
|
|
2188
|
-
const previousIsInsideText = parentHostContext.isInsideText;
|
|
2189
|
-
const isInsideText = type === "ink-text" || type === "ink-virtual-text";
|
|
2190
|
-
if (previousIsInsideText === isInsideText) return parentHostContext;
|
|
2191
|
-
return { isInsideText };
|
|
2192
|
-
},
|
|
2193
|
-
shouldSetTextContent: () => false,
|
|
2194
|
-
createInstance(originalType, newProps, rootNode, hostContext) {
|
|
2195
|
-
if (hostContext.isInsideText && originalType === "ink-box") throw new Error(`<Box> can’t be nested inside <Text> component`);
|
|
2196
|
-
const type = originalType === "ink-text" && hostContext.isInsideText ? "ink-virtual-text" : originalType;
|
|
2197
|
-
const node = createNode(type);
|
|
2198
|
-
for (const [key, value] of Object.entries(newProps)) {
|
|
2199
|
-
if (key === "children") continue;
|
|
2200
|
-
if (key === "style") {
|
|
2201
|
-
setStyle(node, value);
|
|
2202
|
-
if (node.yogaNode) styles(node.yogaNode, value);
|
|
2203
|
-
continue;
|
|
2204
|
-
}
|
|
2205
|
-
if (key === "internal_transform") {
|
|
2206
|
-
node.internal_transform = value;
|
|
2207
|
-
continue;
|
|
2208
|
-
}
|
|
2209
|
-
if (key === "internal_static") {
|
|
2210
|
-
node.internal_static = true;
|
|
2211
|
-
rootNode.isStaticDirty = true;
|
|
2212
|
-
rootNode.staticNode = node;
|
|
2213
|
-
continue;
|
|
2214
|
-
}
|
|
2215
|
-
setAttribute(node, key, value);
|
|
2216
|
-
}
|
|
2217
|
-
return node;
|
|
2218
|
-
},
|
|
2219
|
-
createTextInstance(text, _root, hostContext) {
|
|
2220
|
-
if (!hostContext.isInsideText) throw new Error(`Text string "${text}" must be rendered inside <Text> component`);
|
|
2221
|
-
return createTextNode(text);
|
|
2222
|
-
},
|
|
2223
|
-
resetTextContent() {},
|
|
2224
|
-
hideTextInstance(node) {
|
|
2225
|
-
setTextNodeValue(node, "");
|
|
2226
|
-
},
|
|
2227
|
-
unhideTextInstance(node, text) {
|
|
2228
|
-
setTextNodeValue(node, text);
|
|
2229
|
-
},
|
|
2230
|
-
getPublicInstance: (instance) => instance,
|
|
2231
|
-
hideInstance(node) {
|
|
2232
|
-
node.yogaNode?.setDisplay(Yoga.DISPLAY_NONE);
|
|
2233
|
-
},
|
|
2234
|
-
unhideInstance(node) {
|
|
2235
|
-
node.yogaNode?.setDisplay(Yoga.DISPLAY_FLEX);
|
|
2236
|
-
},
|
|
2237
|
-
appendInitialChild: appendChildNode,
|
|
2238
|
-
appendChild: appendChildNode,
|
|
2239
|
-
insertBefore: insertBeforeNode,
|
|
2240
|
-
finalizeInitialChildren() {
|
|
2241
|
-
return false;
|
|
2242
|
-
},
|
|
2243
|
-
isPrimaryRenderer: true,
|
|
2244
|
-
supportsMutation: true,
|
|
2245
|
-
supportsPersistence: false,
|
|
2246
|
-
supportsHydration: false,
|
|
2247
|
-
supportsMicrotasks: true,
|
|
2248
|
-
scheduleMicrotask: queueMicrotask,
|
|
2249
|
-
scheduleCallback: Scheduler.unstable_scheduleCallback,
|
|
2250
|
-
cancelCallback: Scheduler.unstable_cancelCallback,
|
|
2251
|
-
shouldYield: Scheduler.unstable_shouldYield,
|
|
2252
|
-
now: Scheduler.unstable_now,
|
|
2253
|
-
scheduleTimeout: setTimeout,
|
|
2254
|
-
cancelTimeout: clearTimeout,
|
|
2255
|
-
noTimeout: -1,
|
|
2256
|
-
beforeActiveInstanceBlur() {},
|
|
2257
|
-
afterActiveInstanceBlur() {},
|
|
2258
|
-
detachDeletedInstance() {},
|
|
2259
|
-
getInstanceFromNode: () => null,
|
|
2260
|
-
prepareScopeUpdate() {},
|
|
2261
|
-
getInstanceFromScope: () => null,
|
|
2262
|
-
appendChildToContainer: appendChildNode,
|
|
2263
|
-
insertInContainerBefore: insertBeforeNode,
|
|
2264
|
-
removeChildFromContainer(node, removeNode) {
|
|
2265
|
-
clearStaticNodeIfContained(findRootNode$1(node), removeNode);
|
|
2266
|
-
removeChildNode(node, removeNode);
|
|
2267
|
-
detachYogaSubtree(removeNode);
|
|
2268
|
-
},
|
|
2269
|
-
commitUpdate(node, _type, oldProps, newProps) {
|
|
2270
|
-
if (node.internal_static) {
|
|
2271
|
-
const rootNode = findRootNode$1(node);
|
|
2272
|
-
if (rootNode) rootNode.isStaticDirty = true;
|
|
2273
|
-
}
|
|
2274
|
-
const props = diff(oldProps, newProps);
|
|
2275
|
-
const style = diff(oldProps["style"], newProps["style"]);
|
|
2276
|
-
if (!props && !style) return;
|
|
2277
|
-
if (props) for (const [key, value] of Object.entries(props)) {
|
|
2278
|
-
if (key === "style") {
|
|
2279
|
-
setStyle(node, value);
|
|
2280
|
-
continue;
|
|
2281
|
-
}
|
|
2282
|
-
if (key === "internal_transform") {
|
|
2283
|
-
node.internal_transform = value;
|
|
2284
|
-
continue;
|
|
2285
|
-
}
|
|
2286
|
-
if (key === "internal_static") {
|
|
2287
|
-
node.internal_static = true;
|
|
2288
|
-
continue;
|
|
2289
|
-
}
|
|
2290
|
-
setAttribute(node, key, value);
|
|
2291
|
-
}
|
|
2292
|
-
if (style && node.yogaNode) styles(node.yogaNode, style, newProps["style"] ?? {});
|
|
2293
|
-
},
|
|
2294
|
-
commitTextUpdate(node, _oldText, newText) {
|
|
2295
|
-
setTextNodeValue(node, newText);
|
|
2296
|
-
},
|
|
2297
|
-
removeChild(node, removeNode) {
|
|
2298
|
-
clearStaticNodeIfContained(findRootNode$1(node), removeNode);
|
|
2299
|
-
removeChildNode(node, removeNode);
|
|
2300
|
-
detachYogaSubtree(removeNode);
|
|
2301
|
-
},
|
|
2302
|
-
setCurrentUpdatePriority(newPriority) {
|
|
2303
|
-
currentUpdatePriority = newPriority;
|
|
2304
|
-
},
|
|
2305
|
-
getCurrentUpdatePriority: () => currentUpdatePriority,
|
|
2306
|
-
resolveUpdatePriority() {
|
|
2307
|
-
if (currentUpdatePriority !== NoEventPriority) return currentUpdatePriority;
|
|
2308
|
-
return DefaultEventPriority;
|
|
2309
|
-
},
|
|
2310
|
-
maySuspendCommit() {
|
|
951
|
+
"table",
|
|
952
|
+
"time",
|
|
953
|
+
"timeEnd",
|
|
954
|
+
"timeLog",
|
|
955
|
+
"trace",
|
|
956
|
+
"warn"
|
|
957
|
+
];
|
|
958
|
+
const patchConsole = (callback) => {
|
|
959
|
+
const stdout = new PassThrough();
|
|
960
|
+
const stderr = new PassThrough();
|
|
961
|
+
stdout.write = (data) => {
|
|
962
|
+
callback("stdout", String(data));
|
|
2311
963
|
return true;
|
|
2312
|
-
}
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
resetFormInstance() {},
|
|
2316
|
-
requestPostPaintCallback() {},
|
|
2317
|
-
shouldAttemptEagerTransition() {
|
|
2318
|
-
return false;
|
|
2319
|
-
},
|
|
2320
|
-
trackSchedulerEvent() {},
|
|
2321
|
-
resolveEventType() {
|
|
2322
|
-
return null;
|
|
2323
|
-
},
|
|
2324
|
-
resolveEventTimeStamp() {
|
|
2325
|
-
return -1.1;
|
|
2326
|
-
},
|
|
2327
|
-
preloadInstance() {
|
|
964
|
+
};
|
|
965
|
+
stderr.write = (data) => {
|
|
966
|
+
callback("stderr", String(data));
|
|
2328
967
|
return true;
|
|
2329
|
-
}
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
rendererPackageName: packageInfo.name,
|
|
2336
|
-
rendererVersion: packageInfo.version
|
|
2337
|
-
});
|
|
2338
|
-
//#endregion
|
|
2339
|
-
//#region src/output.ts
|
|
2340
|
-
var OutputCaches = class {
|
|
2341
|
-
widths = /* @__PURE__ */ new Map();
|
|
2342
|
-
blockWidths = /* @__PURE__ */ new Map();
|
|
2343
|
-
styledChars = /* @__PURE__ */ new Map();
|
|
2344
|
-
getStyledChars(line) {
|
|
2345
|
-
let cached = this.styledChars.get(line);
|
|
2346
|
-
if (cached === void 0) {
|
|
2347
|
-
cached = styledCharsFromTokens(tokenize(line));
|
|
2348
|
-
this.styledChars.set(line, cached);
|
|
2349
|
-
}
|
|
2350
|
-
return cached;
|
|
2351
|
-
}
|
|
2352
|
-
getStringWidth(text) {
|
|
2353
|
-
let cached = this.widths.get(text);
|
|
2354
|
-
if (cached === void 0) {
|
|
2355
|
-
cached = stringWidth(text);
|
|
2356
|
-
this.widths.set(text, cached);
|
|
2357
|
-
}
|
|
2358
|
-
return cached;
|
|
2359
|
-
}
|
|
2360
|
-
getWidestLine(text) {
|
|
2361
|
-
let cached = this.blockWidths.get(text);
|
|
2362
|
-
if (cached === void 0) {
|
|
2363
|
-
let lineWidth = 0;
|
|
2364
|
-
for (const line of text.split("\n")) lineWidth = Math.max(lineWidth, this.getStringWidth(line));
|
|
2365
|
-
cached = lineWidth;
|
|
2366
|
-
this.blockWidths.set(text, cached);
|
|
2367
|
-
}
|
|
2368
|
-
return cached;
|
|
968
|
+
};
|
|
969
|
+
const internalConsole = new Console(stdout, stderr);
|
|
970
|
+
const originalMethods = /* @__PURE__ */ new Map();
|
|
971
|
+
for (const method of consoleMethods) {
|
|
972
|
+
originalMethods.set(method, console[method]);
|
|
973
|
+
console[method] = internalConsole[method];
|
|
2369
974
|
}
|
|
975
|
+
return () => {
|
|
976
|
+
for (const method of consoleMethods) console[method] = originalMethods.get(method);
|
|
977
|
+
originalMethods.clear();
|
|
978
|
+
};
|
|
2370
979
|
};
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
const { transformers } = options;
|
|
2383
|
-
if (!text) return;
|
|
2384
|
-
this.operations.push({
|
|
2385
|
-
type: "write",
|
|
2386
|
-
x,
|
|
2387
|
-
y,
|
|
2388
|
-
text,
|
|
2389
|
-
transformers
|
|
2390
|
-
});
|
|
2391
|
-
}
|
|
2392
|
-
clip(clip) {
|
|
2393
|
-
this.operations.push({
|
|
2394
|
-
type: "clip",
|
|
2395
|
-
clip
|
|
2396
|
-
});
|
|
2397
|
-
}
|
|
2398
|
-
unclip() {
|
|
2399
|
-
this.operations.push({ type: "unclip" });
|
|
2400
|
-
}
|
|
2401
|
-
get() {
|
|
2402
|
-
const output = [];
|
|
2403
|
-
for (let y = 0; y < this.height; y++) {
|
|
2404
|
-
const row = [];
|
|
2405
|
-
for (let x = 0; x < this.width; x++) row.push({
|
|
2406
|
-
type: "char",
|
|
2407
|
-
value: " ",
|
|
2408
|
-
fullWidth: false,
|
|
2409
|
-
styles: []
|
|
2410
|
-
});
|
|
2411
|
-
output.push(row);
|
|
2412
|
-
}
|
|
2413
|
-
const clips = [];
|
|
2414
|
-
for (const operation of this.operations) {
|
|
2415
|
-
if (operation.type === "clip") clips.push(operation.clip);
|
|
2416
|
-
if (operation.type === "unclip") clips.pop();
|
|
2417
|
-
if (operation.type === "write") {
|
|
2418
|
-
const { text, transformers } = operation;
|
|
2419
|
-
let { x, y } = operation;
|
|
2420
|
-
let lines = text.split("\n");
|
|
2421
|
-
const clip = clips.at(-1);
|
|
2422
|
-
if (clip) {
|
|
2423
|
-
const clipHorizontally = typeof clip?.x1 === "number" && typeof clip?.x2 === "number";
|
|
2424
|
-
const clipVertically = typeof clip?.y1 === "number" && typeof clip?.y2 === "number";
|
|
2425
|
-
if (clipHorizontally) {
|
|
2426
|
-
const width = this.caches.getWidestLine(text);
|
|
2427
|
-
if (x + width < clip.x1 || x > clip.x2) continue;
|
|
2428
|
-
}
|
|
2429
|
-
if (clipVertically) {
|
|
2430
|
-
const height = lines.length;
|
|
2431
|
-
if (y + height < clip.y1 || y > clip.y2) continue;
|
|
2432
|
-
}
|
|
2433
|
-
if (clipHorizontally) {
|
|
2434
|
-
lines = lines.map((line) => {
|
|
2435
|
-
const from = x < clip.x1 ? clip.x1 - x : 0;
|
|
2436
|
-
const width = this.caches.getStringWidth(line);
|
|
2437
|
-
const to = x + width > clip.x2 ? clip.x2 - x : width;
|
|
2438
|
-
return sliceAnsi(line, from, to);
|
|
2439
|
-
});
|
|
2440
|
-
if (x < clip.x1) x = clip.x1;
|
|
2441
|
-
}
|
|
2442
|
-
if (clipVertically) {
|
|
2443
|
-
const from = y < clip.y1 ? clip.y1 - y : 0;
|
|
2444
|
-
const height = lines.length;
|
|
2445
|
-
const to = y + height > clip.y2 ? clip.y2 - y : height;
|
|
2446
|
-
lines = lines.slice(from, to);
|
|
2447
|
-
if (y < clip.y1) y = clip.y1;
|
|
2448
|
-
}
|
|
2449
|
-
}
|
|
2450
|
-
let offsetY = 0;
|
|
2451
|
-
for (let [index, line] of lines.entries()) {
|
|
2452
|
-
const currentLine = output[y + offsetY];
|
|
2453
|
-
if (!currentLine) continue;
|
|
2454
|
-
for (const transformer of transformers) line = transformer(line, index);
|
|
2455
|
-
const characters = this.caches.getStyledChars(line);
|
|
2456
|
-
let offsetX = x;
|
|
2457
|
-
if (characters.length === 0) {
|
|
2458
|
-
offsetY++;
|
|
2459
|
-
continue;
|
|
2460
|
-
}
|
|
2461
|
-
const spaceCell = {
|
|
2462
|
-
type: "char",
|
|
2463
|
-
value: " ",
|
|
2464
|
-
fullWidth: false,
|
|
2465
|
-
styles: []
|
|
2466
|
-
};
|
|
2467
|
-
if (currentLine[offsetX]?.value === "" && offsetX > 0 && this.caches.getStringWidth(currentLine[offsetX - 1]?.value ?? "") > 1) currentLine[offsetX - 1] = spaceCell;
|
|
2468
|
-
for (const character of characters) {
|
|
2469
|
-
currentLine[offsetX] = character;
|
|
2470
|
-
const characterWidth = Math.max(1, this.caches.getStringWidth(character.value));
|
|
2471
|
-
if (characterWidth > 1) for (let columnOffset = 1; columnOffset < characterWidth; columnOffset++) currentLine[offsetX + columnOffset] = {
|
|
2472
|
-
type: "char",
|
|
2473
|
-
value: "",
|
|
2474
|
-
fullWidth: false,
|
|
2475
|
-
styles: character.styles
|
|
2476
|
-
};
|
|
2477
|
-
offsetX += characterWidth;
|
|
2478
|
-
}
|
|
2479
|
-
if (currentLine[offsetX]?.value === "") currentLine[offsetX] = spaceCell;
|
|
2480
|
-
offsetY++;
|
|
2481
|
-
}
|
|
2482
|
-
}
|
|
2483
|
-
}
|
|
2484
|
-
return {
|
|
2485
|
-
output: output.map((line) => {
|
|
2486
|
-
const lineWithoutEmptyItems = line.filter((item) => item !== void 0);
|
|
2487
|
-
return styledCharsToString(lineWithoutEmptyItems).trimEnd();
|
|
2488
|
-
}).join("\n"),
|
|
2489
|
-
height: output.length
|
|
2490
|
-
};
|
|
2491
|
-
}
|
|
980
|
+
const patchStreamWrite = (stream, onData) => {
|
|
981
|
+
const originalWrite = stream.write;
|
|
982
|
+
const patchedWrite = (chunk, encodingOrCallback, callback) => {
|
|
983
|
+
onData(typeof chunk === "string" ? chunk : chunk instanceof Uint8Array ? Buffer.from(chunk).toString() : String(chunk));
|
|
984
|
+
(typeof encodingOrCallback === "function" ? encodingOrCallback : typeof callback === "function" ? callback : void 0)?.();
|
|
985
|
+
return true;
|
|
986
|
+
};
|
|
987
|
+
stream.write = patchedWrite;
|
|
988
|
+
return () => {
|
|
989
|
+
stream.write = originalWrite;
|
|
990
|
+
};
|
|
2492
991
|
};
|
|
2493
992
|
//#endregion
|
|
2494
993
|
//#region src/get-max-width.ts
|
|
@@ -2496,17 +995,9 @@ const getMaxWidth = (yogaNode) => {
|
|
|
2496
995
|
return yogaNode.getComputedWidth() - yogaNode.getComputedPadding(Yoga.EDGE_LEFT) - yogaNode.getComputedPadding(Yoga.EDGE_RIGHT) - yogaNode.getComputedBorder(Yoga.EDGE_LEFT) - yogaNode.getComputedBorder(Yoga.EDGE_RIGHT);
|
|
2497
996
|
};
|
|
2498
997
|
//#endregion
|
|
2499
|
-
//#region src/indent-string.ts
|
|
2500
|
-
const indentString = (string, count = 1, options = {}) => {
|
|
2501
|
-
const { indent = " ", includeEmptyLines = false } = options;
|
|
2502
|
-
if (count === 0) return string;
|
|
2503
|
-
const regex = includeEmptyLines ? /^/gm : /^(?!\s*$)/gm;
|
|
2504
|
-
return string.replace(regex, indent.repeat(count));
|
|
2505
|
-
};
|
|
2506
|
-
//#endregion
|
|
2507
998
|
//#region src/render-background.ts
|
|
2508
999
|
const renderBackground = (x, y, node, output) => {
|
|
2509
|
-
if (
|
|
1000
|
+
if (node.style.backgroundColor === void 0) return;
|
|
2510
1001
|
const width = node.yogaNode.getComputedWidth();
|
|
2511
1002
|
const height = node.yogaNode.getComputedHeight();
|
|
2512
1003
|
const leftBorderWidth = node.style.borderStyle && node.style.borderLeft !== false ? 1 : 0;
|
|
@@ -2516,106 +1007,51 @@ const renderBackground = (x, y, node, output) => {
|
|
|
2516
1007
|
const contentWidth = width - leftBorderWidth - rightBorderWidth;
|
|
2517
1008
|
const contentHeight = height - topBorderHeight - bottomBorderHeight;
|
|
2518
1009
|
if (!(contentWidth > 0 && contentHeight > 0)) return;
|
|
2519
|
-
const
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
double: {
|
|
2536
|
-
topLeft: "╔",
|
|
2537
|
-
top: "═",
|
|
2538
|
-
topRight: "╗",
|
|
2539
|
-
right: "║",
|
|
2540
|
-
bottomRight: "╝",
|
|
2541
|
-
bottom: "═",
|
|
2542
|
-
bottomLeft: "╚",
|
|
2543
|
-
left: "║"
|
|
2544
|
-
},
|
|
2545
|
-
round: {
|
|
2546
|
-
topLeft: "╭",
|
|
2547
|
-
top: "─",
|
|
2548
|
-
topRight: "╮",
|
|
2549
|
-
right: "│",
|
|
2550
|
-
bottomRight: "╯",
|
|
2551
|
-
bottom: "─",
|
|
2552
|
-
bottomLeft: "╰",
|
|
2553
|
-
left: "│"
|
|
2554
|
-
},
|
|
2555
|
-
bold: {
|
|
2556
|
-
topLeft: "┏",
|
|
2557
|
-
top: "━",
|
|
2558
|
-
topRight: "┓",
|
|
2559
|
-
right: "┃",
|
|
2560
|
-
bottomRight: "┛",
|
|
2561
|
-
bottom: "━",
|
|
2562
|
-
bottomLeft: "┗",
|
|
2563
|
-
left: "┃"
|
|
2564
|
-
},
|
|
2565
|
-
singleDouble: {
|
|
2566
|
-
topLeft: "╓",
|
|
2567
|
-
top: "─",
|
|
2568
|
-
topRight: "╖",
|
|
2569
|
-
right: "║",
|
|
2570
|
-
bottomRight: "╜",
|
|
2571
|
-
bottom: "─",
|
|
2572
|
-
bottomLeft: "╙",
|
|
2573
|
-
left: "║"
|
|
2574
|
-
},
|
|
2575
|
-
doubleSingle: {
|
|
2576
|
-
topLeft: "╒",
|
|
2577
|
-
top: "═",
|
|
2578
|
-
topRight: "╕",
|
|
2579
|
-
right: "│",
|
|
2580
|
-
bottomRight: "╛",
|
|
2581
|
-
bottom: "═",
|
|
2582
|
-
bottomLeft: "╘",
|
|
2583
|
-
left: "│"
|
|
2584
|
-
},
|
|
2585
|
-
classic: {
|
|
2586
|
-
topLeft: "+",
|
|
2587
|
-
top: "-",
|
|
2588
|
-
topRight: "+",
|
|
2589
|
-
right: "|",
|
|
2590
|
-
bottomRight: "+",
|
|
2591
|
-
bottom: "-",
|
|
2592
|
-
bottomLeft: "+",
|
|
2593
|
-
left: "|"
|
|
2594
|
-
},
|
|
2595
|
-
arrow: {
|
|
2596
|
-
topLeft: "↘",
|
|
2597
|
-
top: "↓",
|
|
2598
|
-
topRight: "↙",
|
|
2599
|
-
right: "←",
|
|
2600
|
-
bottomRight: "↖",
|
|
2601
|
-
bottom: "↑",
|
|
2602
|
-
bottomLeft: "↗",
|
|
2603
|
-
left: "→"
|
|
2604
|
-
}
|
|
1010
|
+
const bounds = {
|
|
1011
|
+
x: x + leftBorderWidth,
|
|
1012
|
+
y: y + topBorderHeight,
|
|
1013
|
+
width: contentWidth,
|
|
1014
|
+
height: contentHeight
|
|
1015
|
+
};
|
|
1016
|
+
const lines = Array.from({ length: contentHeight }, (_unused, row) => Array.from({ length: contentWidth }, (_empty, column) => {
|
|
1017
|
+
const resetBackground = node.style.backgroundColor === "";
|
|
1018
|
+
const background = resetBackground ? void 0 : samplePaint(node.style.backgroundColor, bounds.x + column, bounds.y + row, bounds, output.paintContext);
|
|
1019
|
+
return createCell(" ", 1, {
|
|
1020
|
+
...background ? { background } : {},
|
|
1021
|
+
underline: "none",
|
|
1022
|
+
attributes: cellAttributes.none
|
|
1023
|
+
}, void 0, resetBackground ? { background: true } : void 0);
|
|
1024
|
+
}));
|
|
1025
|
+
output.writeCells(bounds.x, bounds.y, lines);
|
|
2605
1026
|
};
|
|
2606
1027
|
//#endregion
|
|
2607
1028
|
//#region src/render-border.ts
|
|
2608
|
-
const stylePiece = (segment, fg, bg, dim) => {
|
|
2609
|
-
let
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
1029
|
+
const stylePiece = (segment, x, y, bounds, context, fg, bg, dim) => {
|
|
1030
|
+
let column = x;
|
|
1031
|
+
return [...graphemes(segment)].map((grapheme) => {
|
|
1032
|
+
const foreground = fg ? samplePaint(fg, column, y, bounds, context) : void 0;
|
|
1033
|
+
const background = bg ? samplePaint(bg, column, y, bounds, context) : void 0;
|
|
1034
|
+
const width = Math.max(1, stringWidth(grapheme));
|
|
1035
|
+
column += width;
|
|
1036
|
+
return createCell(grapheme, width, {
|
|
1037
|
+
...foreground ? { foreground } : {},
|
|
1038
|
+
...background ? { background } : {},
|
|
1039
|
+
underline: "none",
|
|
1040
|
+
attributes: dim ? cellAttributes.faint : cellAttributes.none
|
|
1041
|
+
});
|
|
1042
|
+
});
|
|
2613
1043
|
};
|
|
2614
1044
|
const renderBorder = (x, y, node, output) => {
|
|
2615
1045
|
if (node.style.borderStyle) {
|
|
2616
1046
|
const width = node.yogaNode.getComputedWidth();
|
|
2617
1047
|
const height = node.yogaNode.getComputedHeight();
|
|
2618
|
-
const
|
|
1048
|
+
const bounds = {
|
|
1049
|
+
x,
|
|
1050
|
+
y,
|
|
1051
|
+
width,
|
|
1052
|
+
height
|
|
1053
|
+
};
|
|
1054
|
+
const box = typeof node.style.borderStyle === "string" ? BOXES[node.style.borderStyle] : node.style.borderStyle;
|
|
2619
1055
|
const topBorderColor = node.style.borderTopColor ?? node.style.borderColor;
|
|
2620
1056
|
const bottomBorderColor = node.style.borderBottomColor ?? node.style.borderColor;
|
|
2621
1057
|
const leftBorderColor = node.style.borderLeftColor ?? node.style.borderColor;
|
|
@@ -2633,36 +1069,200 @@ const renderBorder = (x, y, node, output) => {
|
|
|
2633
1069
|
const showLeftBorder = node.style.borderLeft !== false;
|
|
2634
1070
|
const showRightBorder = node.style.borderRight !== false;
|
|
2635
1071
|
const contentWidth = width - (showLeftBorder ? 1 : 0) - (showRightBorder ? 1 : 0);
|
|
2636
|
-
|
|
2637
|
-
topBorder &&= stylePiece(topBorder, topBorderColor, topBorderBackgroundColor, dimTopBorderColor);
|
|
1072
|
+
const topBorder = showTopBorder ? (showLeftBorder ? box.topLeft : "") + box.top.repeat(contentWidth) + (showRightBorder ? box.topRight : "") : void 0;
|
|
2638
1073
|
let verticalBorderHeight = height;
|
|
2639
1074
|
if (showTopBorder) verticalBorderHeight -= 1;
|
|
2640
1075
|
if (showBottomBorder) verticalBorderHeight -= 1;
|
|
2641
|
-
let leftBorder = "";
|
|
2642
|
-
if (showLeftBorder) leftBorder = (stylePiece(box.left, leftBorderColor, leftBorderBackgroundColor, dimLeftBorderColor) + "\n").repeat(verticalBorderHeight);
|
|
2643
|
-
let rightBorder = "";
|
|
2644
|
-
if (showRightBorder) rightBorder = (stylePiece(box.right, rightBorderColor, rightBorderBackgroundColor, dimRightBorderColor) + "\n").repeat(verticalBorderHeight);
|
|
2645
|
-
let bottomBorder = showBottomBorder ? (showLeftBorder ? box.bottomLeft : "") + box.bottom.repeat(contentWidth) + (showRightBorder ? box.bottomRight : "") : void 0;
|
|
2646
|
-
bottomBorder &&= stylePiece(bottomBorder, bottomBorderColor, bottomBorderBackgroundColor, dimBottomBorderColor);
|
|
2647
1076
|
const offsetY = showTopBorder ? 1 : 0;
|
|
2648
|
-
|
|
2649
|
-
if (
|
|
2650
|
-
if (
|
|
2651
|
-
if (
|
|
1077
|
+
const bottomBorder = showBottomBorder ? (showLeftBorder ? box.bottomLeft : "") + box.bottom.repeat(contentWidth) + (showRightBorder ? box.bottomRight : "") : void 0;
|
|
1078
|
+
if (topBorder) output.writeCells(x, y, [stylePiece(topBorder, x, y, bounds, output.paintContext, topBorderColor, topBorderBackgroundColor, dimTopBorderColor)]);
|
|
1079
|
+
if (showLeftBorder) output.writeCells(x, y + offsetY, Array.from({ length: verticalBorderHeight }, (_, row) => stylePiece(box.left, x, y + offsetY + row, bounds, output.paintContext, leftBorderColor, leftBorderBackgroundColor, dimLeftBorderColor)));
|
|
1080
|
+
if (showRightBorder) output.writeCells(x + width - 1, y + offsetY, Array.from({ length: verticalBorderHeight }, (_, row) => stylePiece(box.right, x + width - 1, y + offsetY + row, bounds, output.paintContext, rightBorderColor, rightBorderBackgroundColor, dimRightBorderColor)));
|
|
1081
|
+
if (bottomBorder) output.writeCells(x, y + height - 1, [stylePiece(bottomBorder, x, y + height - 1, bounds, output.paintContext, bottomBorderColor, bottomBorderBackgroundColor, dimBottomBorderColor)]);
|
|
2652
1082
|
}
|
|
2653
1083
|
};
|
|
2654
1084
|
//#endregion
|
|
2655
|
-
//#region src/
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
if (
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
1085
|
+
//#region src/structured-text.ts
|
|
1086
|
+
/** Whether a text subtree must retain the ANSI compatibility pipeline. */
|
|
1087
|
+
function hasCompatibilityText(node) {
|
|
1088
|
+
if (node.internal_transform && !node.internal_textStyle) return true;
|
|
1089
|
+
return node.childNodes.some((child) => child.nodeName !== "#text" && hasCompatibilityText(child));
|
|
1090
|
+
}
|
|
1091
|
+
/** Rasterizes an unwrapped native Text subtree into semantic cell lines. */
|
|
1092
|
+
function structuredTextLines(node) {
|
|
1093
|
+
const lines = [[]];
|
|
1094
|
+
appendNode(node, emptySemanticTextStyle, lines, false);
|
|
1095
|
+
return lines;
|
|
1096
|
+
}
|
|
1097
|
+
/** Samples semantic paints only after wrapping and final layout are known. */
|
|
1098
|
+
function sampleStructuredText(lines, bounds, context) {
|
|
1099
|
+
return lines.map((line, row) => {
|
|
1100
|
+
let column = 0;
|
|
1101
|
+
return line.map((cell) => {
|
|
1102
|
+
const foreground = cell.foregroundPaint ? samplePaint(cell.foregroundPaint, bounds.x + column, bounds.y + row, bounds, context) : cell.style.foreground;
|
|
1103
|
+
const background = cell.backgroundPaint ? samplePaint(cell.backgroundPaint, bounds.x + column, bounds.y + row, bounds, context) : cell.style.background;
|
|
1104
|
+
column += cell.width;
|
|
1105
|
+
return createCell(cell.grapheme, cell.width, {
|
|
1106
|
+
...cell.style,
|
|
1107
|
+
...foreground ? { foreground } : {},
|
|
1108
|
+
...background ? { background } : {}
|
|
1109
|
+
}, cell.hyperlink, cell.reset);
|
|
1110
|
+
});
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
function structuredTextBaseStyle(node) {
|
|
1114
|
+
return semanticTextStyleToCellStyle(mergeSemanticTextStyles(emptySemanticTextStyle, node.internal_textStyle));
|
|
1115
|
+
}
|
|
1116
|
+
/** Wraps or truncates semantic cells without converting them through ANSI. */
|
|
1117
|
+
function wrapStructuredText(input, maxWidth, wrap, baseStyle) {
|
|
1118
|
+
if (maxWidth < 1) return [[]];
|
|
1119
|
+
return input.flatMap((line) => {
|
|
1120
|
+
if (lineWidth(line) <= maxWidth) return [[...line]];
|
|
1121
|
+
if (wrap === "hard") return hardWrap(line, maxWidth);
|
|
1122
|
+
if (wrap === "wrap") return wordWrap(line, maxWidth);
|
|
1123
|
+
return [truncate(line, maxWidth, wrap, baseStyle)];
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
function wordWrap(line, maxWidth) {
|
|
1127
|
+
const words = [[]];
|
|
1128
|
+
const spaces = [];
|
|
1129
|
+
for (const cell of line) if (cell.grapheme === " ") {
|
|
1130
|
+
spaces.push(cell);
|
|
1131
|
+
words.push([]);
|
|
1132
|
+
} else words.at(-1).push(cell);
|
|
1133
|
+
const output = [[]];
|
|
1134
|
+
appendHard(output, words[0], maxWidth);
|
|
1135
|
+
for (let index = 1; index < words.length; index++) {
|
|
1136
|
+
appendHard(output, [spaces[index - 1]], maxWidth);
|
|
1137
|
+
const word = words[index];
|
|
1138
|
+
const current = output.at(-1);
|
|
1139
|
+
const wordWidth = lineWidth(word);
|
|
1140
|
+
const currentWidth = lineWidth(current);
|
|
1141
|
+
if (wordWidth <= maxWidth && currentWidth + wordWidth > maxWidth) output.push([]);
|
|
1142
|
+
else if (wordWidth > maxWidth && currentWidth > 0) {
|
|
1143
|
+
const remaining = maxWidth - currentWidth;
|
|
1144
|
+
const breaksHere = 1 + Math.floor((wordWidth - remaining - 1) / maxWidth);
|
|
1145
|
+
if (Math.floor((wordWidth - 1) / maxWidth) < breaksHere) output.push([]);
|
|
1146
|
+
}
|
|
1147
|
+
appendHard(output, word, maxWidth);
|
|
2662
1148
|
}
|
|
2663
|
-
return
|
|
2664
|
-
}
|
|
2665
|
-
|
|
1149
|
+
return output;
|
|
1150
|
+
}
|
|
1151
|
+
function hardWrap(line, maxWidth) {
|
|
1152
|
+
const output = [[]];
|
|
1153
|
+
appendHard(output, line, maxWidth);
|
|
1154
|
+
return output;
|
|
1155
|
+
}
|
|
1156
|
+
function appendHard(output, cells, maxWidth) {
|
|
1157
|
+
for (const cell of cells) {
|
|
1158
|
+
const current = output.at(-1);
|
|
1159
|
+
if (current.length > 0 && lineWidth(current) + cell.width > maxWidth) output.push([]);
|
|
1160
|
+
output.at(-1).push(cell);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
function truncate(line, maxWidth, wrap, baseStyle) {
|
|
1164
|
+
if (maxWidth === 1) return [ellipsis(baseStyle ?? cellStyleIntersection(line.at(0), line.at(-1)))];
|
|
1165
|
+
if (wrap === "truncate-start") {
|
|
1166
|
+
const right = sliceCells(line, lineWidth(line) - maxWidth + 1, lineWidth(line));
|
|
1167
|
+
return [ellipsis(right[0]?.style), ...right];
|
|
1168
|
+
}
|
|
1169
|
+
if (wrap === "truncate-middle") {
|
|
1170
|
+
const half = Math.min(Math.floor(maxWidth / 2), maxWidth - 1);
|
|
1171
|
+
const left = sliceCells(line, 0, half);
|
|
1172
|
+
const rightWidth = maxWidth - half - 1;
|
|
1173
|
+
const right = sliceCells(line, lineWidth(line) - rightWidth, lineWidth(line));
|
|
1174
|
+
return [
|
|
1175
|
+
...left,
|
|
1176
|
+
ellipsis(baseStyle ?? cellStyleIntersection(left.at(-1), right.at(0))),
|
|
1177
|
+
...right
|
|
1178
|
+
];
|
|
1179
|
+
}
|
|
1180
|
+
const left = sliceCells(line, 0, maxWidth - 1);
|
|
1181
|
+
return [...left, ellipsis(left.at(-1)?.style)];
|
|
1182
|
+
}
|
|
1183
|
+
function sliceCells(line, start, end) {
|
|
1184
|
+
const output = [];
|
|
1185
|
+
let column = 0;
|
|
1186
|
+
for (const cell of line) {
|
|
1187
|
+
const nextColumn = column + cell.width;
|
|
1188
|
+
if (column >= start && nextColumn <= end) output.push(cell);
|
|
1189
|
+
column = nextColumn;
|
|
1190
|
+
}
|
|
1191
|
+
return output;
|
|
1192
|
+
}
|
|
1193
|
+
function ellipsis(style = semanticTextStyleToCellStyle(emptySemanticTextStyle)) {
|
|
1194
|
+
return createCell("…", 1, style);
|
|
1195
|
+
}
|
|
1196
|
+
function cellStyleIntersection(left, right) {
|
|
1197
|
+
if (!left) return right?.style ?? semanticTextStyleToCellStyle(emptySemanticTextStyle);
|
|
1198
|
+
if (!right) return left.style;
|
|
1199
|
+
return {
|
|
1200
|
+
...sameColor(left.style.foreground, right.style.foreground) ? { foreground: left.style.foreground } : {},
|
|
1201
|
+
...sameColor(left.style.background, right.style.background) ? { background: left.style.background } : {},
|
|
1202
|
+
...sameColor(left.style.underlineColor, right.style.underlineColor) ? { underlineColor: left.style.underlineColor } : {},
|
|
1203
|
+
underline: left.style.underline === right.style.underline ? left.style.underline : "none",
|
|
1204
|
+
attributes: left.style.attributes & right.style.attributes
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
function sameColor(left, right) {
|
|
1208
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
1209
|
+
}
|
|
1210
|
+
function lineWidth(line) {
|
|
1211
|
+
return line.reduce((width, cell) => width + cell.width, 0);
|
|
1212
|
+
}
|
|
1213
|
+
function appendNode(node, inherited, lines, ansi) {
|
|
1214
|
+
if (node.nodeName === "#text") {
|
|
1215
|
+
if (ansi) appendAnsiText(node.nodeValue, inherited, lines);
|
|
1216
|
+
else appendText(node.nodeValue, inherited, lines);
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
const style = mergeSemanticTextStyles(inherited, node.internal_textStyle);
|
|
1220
|
+
for (const child of node.childNodes) appendNode(child, style, lines, ansi || node.internal_ansi === true);
|
|
1221
|
+
}
|
|
1222
|
+
function appendAnsiText(text, semantic, lines) {
|
|
1223
|
+
const base = semanticTextStyleToCellStyle(semantic);
|
|
1224
|
+
for (const cell of cellsFromAnsi(text)) {
|
|
1225
|
+
if (cell.grapheme === "\n" || cell.grapheme === "\r\n") {
|
|
1226
|
+
lines.push([]);
|
|
1227
|
+
continue;
|
|
1228
|
+
}
|
|
1229
|
+
const hasForeground = cell.style.foreground !== void 0;
|
|
1230
|
+
const hasBackground = cell.style.background !== void 0;
|
|
1231
|
+
lines.at(-1).push({
|
|
1232
|
+
...cell,
|
|
1233
|
+
style: {
|
|
1234
|
+
...cell.style.foreground ?? base.foreground ? { foreground: cell.style.foreground ?? base.foreground } : {},
|
|
1235
|
+
...cell.style.background ?? base.background ? { background: cell.style.background ?? base.background } : {},
|
|
1236
|
+
...cell.style.underlineColor ? { underlineColor: cell.style.underlineColor } : {},
|
|
1237
|
+
underline: cell.style.underline === "none" ? base.underline : cell.style.underline,
|
|
1238
|
+
attributes: base.attributes | cell.style.attributes
|
|
1239
|
+
},
|
|
1240
|
+
...!hasForeground && semantic.foreground ? { foregroundPaint: semantic.foreground } : {},
|
|
1241
|
+
...!hasBackground && semantic.background ? { backgroundPaint: semantic.background } : {}
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
function appendText(text, style, lines) {
|
|
1246
|
+
const cellStyle = semanticTextStyleToCellStyle(style);
|
|
1247
|
+
const plainText = tokenizeAnsi(text).filter((token) => token.type === "text").map((token) => token.value).join("");
|
|
1248
|
+
for (const segment of graphemes(stripAnsi(plainText))) {
|
|
1249
|
+
if (segment === "\n" || segment === "\r\n") {
|
|
1250
|
+
lines.push([]);
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1253
|
+
lines.at(-1).push({
|
|
1254
|
+
...createCell(segment, Math.max(1, stringWidth(segment)), cellStyle, void 0, style.resetForeground || style.resetBackground ? {
|
|
1255
|
+
foreground: style.resetForeground,
|
|
1256
|
+
background: style.resetBackground
|
|
1257
|
+
} : void 0),
|
|
1258
|
+
...style.foreground ? { foregroundPaint: style.foreground } : {},
|
|
1259
|
+
...style.background ? { backgroundPaint: style.background } : {}
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
//#endregion
|
|
1264
|
+
//#region src/paint-tree.ts
|
|
1265
|
+
const renderAccessibleText = (node, options = {}) => {
|
|
2666
1266
|
if (options.skipStaticElements && node.internal_static) return "";
|
|
2667
1267
|
if (node.yogaNode?.getDisplay() === Yoga.DISPLAY_NONE) return "";
|
|
2668
1268
|
let output = "";
|
|
@@ -2670,7 +1270,7 @@ const renderNodeToScreenReaderOutput = (node, options = {}) => {
|
|
|
2670
1270
|
else if (node.nodeName === "ink-box" || node.nodeName === "ink-root") {
|
|
2671
1271
|
const separator = node.style.flexDirection === "row" || node.style.flexDirection === "row-reverse" ? " " : "\n";
|
|
2672
1272
|
output = (node.style.flexDirection === "row-reverse" || node.style.flexDirection === "column-reverse" ? [...node.childNodes].reverse() : [...node.childNodes]).map((childNode) => {
|
|
2673
|
-
return
|
|
1273
|
+
return renderAccessibleText(childNode, {
|
|
2674
1274
|
parentRole: node.internal_accessibility?.role,
|
|
2675
1275
|
skipStaticElements: options.skipStaticElements
|
|
2676
1276
|
});
|
|
@@ -2686,7 +1286,7 @@ const renderNodeToScreenReaderOutput = (node, options = {}) => {
|
|
|
2686
1286
|
}
|
|
2687
1287
|
return output;
|
|
2688
1288
|
};
|
|
2689
|
-
const
|
|
1289
|
+
const paintTree = (node, output, options) => {
|
|
2690
1290
|
const { offsetX = 0, offsetY = 0, transformers = [], skipStaticElements } = options;
|
|
2691
1291
|
if (skipStaticElements && node.internal_static) return;
|
|
2692
1292
|
const { yogaNode } = node;
|
|
@@ -2694,19 +1294,28 @@ const renderNodeToOutput = (node, output, options) => {
|
|
|
2694
1294
|
if (yogaNode.getDisplay() === Yoga.DISPLAY_NONE) return;
|
|
2695
1295
|
const x = offsetX + yogaNode.getComputedLeft();
|
|
2696
1296
|
const y = offsetY + yogaNode.getComputedTop();
|
|
2697
|
-
|
|
2698
|
-
if (typeof node.internal_transform === "function") newTransformers = [node.internal_transform, ...transformers];
|
|
1297
|
+
const newTransformers = node.internal_transform ? [node.internal_transform, ...transformers] : transformers;
|
|
2699
1298
|
if (node.nodeName === "ink-text") {
|
|
2700
|
-
|
|
2701
|
-
if (text.length > 0) {
|
|
2702
|
-
const currentWidth = widestLine(text);
|
|
1299
|
+
if (squashTextNodes(node).length > 0) {
|
|
2703
1300
|
const maxWidth = getMaxWidth(yogaNode);
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
1301
|
+
const firstChildYoga = node.childNodes[0]?.yogaNode;
|
|
1302
|
+
const paddingX = firstChildYoga?.getComputedLeft() ?? 0;
|
|
1303
|
+
const paddingY = firstChildYoga?.getComputedTop() ?? 0;
|
|
1304
|
+
const lines = wrapStructuredText(structuredTextLines(node), maxWidth, node.style.textWrap ?? "wrap", structuredTextBaseStyle(node));
|
|
1305
|
+
const paintBounds = {
|
|
1306
|
+
x: x + paddingX,
|
|
1307
|
+
y: y + paddingY,
|
|
1308
|
+
width: Math.max(1, ...lines.map((line) => line.reduce((width, cell) => width + cell.width, 0))),
|
|
1309
|
+
height: lines.length
|
|
1310
|
+
};
|
|
1311
|
+
const sampled = sampleStructuredText(lines, paintBounds, output.paintContext);
|
|
1312
|
+
if (hasCompatibilityText(node)) {
|
|
1313
|
+
const textTransformers = collectTransformers(node, transformers);
|
|
1314
|
+
output.writeAnsi(paintBounds.x, paintBounds.y, sampled.map((line) => serializeLine(line, {
|
|
1315
|
+
colorProfile: output.paintContext.profile ?? "truecolor",
|
|
1316
|
+
trimEnd: false
|
|
1317
|
+
})).join("\n"), { transformers: textTransformers });
|
|
1318
|
+
} else output.writeCells(paintBounds.x, paintBounds.y, sampled);
|
|
2710
1319
|
}
|
|
2711
1320
|
return;
|
|
2712
1321
|
}
|
|
@@ -2731,7 +1340,7 @@ const renderNodeToOutput = (node, output, options) => {
|
|
|
2731
1340
|
}
|
|
2732
1341
|
}
|
|
2733
1342
|
if (node.nodeName === "ink-root" || node.nodeName === "ink-box") {
|
|
2734
|
-
for (const childNode of node.childNodes)
|
|
1343
|
+
for (const childNode of node.childNodes) paintTree(childNode, output, {
|
|
2735
1344
|
offsetX: x,
|
|
2736
1345
|
offsetY: y,
|
|
2737
1346
|
transformers: newTransformers,
|
|
@@ -2741,47 +1350,235 @@ const renderNodeToOutput = (node, output, options) => {
|
|
|
2741
1350
|
}
|
|
2742
1351
|
}
|
|
2743
1352
|
};
|
|
1353
|
+
function collectTransformers(node, inherited) {
|
|
1354
|
+
return [
|
|
1355
|
+
...node.childNodes.flatMap((child) => child.nodeName === "#text" ? [] : collectTransformers(child, [])),
|
|
1356
|
+
...node.internal_transform ? [node.internal_transform] : [],
|
|
1357
|
+
...inherited
|
|
1358
|
+
];
|
|
1359
|
+
}
|
|
1360
|
+
//#endregion
|
|
1361
|
+
//#region src/screen/canvas.ts
|
|
1362
|
+
/** Immediate structured drawing canvas with one explicit ANSI compatibility adapter. */
|
|
1363
|
+
var Canvas = class {
|
|
1364
|
+
width;
|
|
1365
|
+
height;
|
|
1366
|
+
paintContext;
|
|
1367
|
+
#screen;
|
|
1368
|
+
#clips = [];
|
|
1369
|
+
constructor(options) {
|
|
1370
|
+
this.width = options.width;
|
|
1371
|
+
this.height = options.height;
|
|
1372
|
+
this.paintContext = {
|
|
1373
|
+
profile: options.colorProfile ?? "truecolor",
|
|
1374
|
+
...options.paintContext
|
|
1375
|
+
};
|
|
1376
|
+
this.#screen = new Screen(this.width, this.height);
|
|
1377
|
+
}
|
|
1378
|
+
writeCells(x, y, lines) {
|
|
1379
|
+
const clip = this.#clips.at(-1);
|
|
1380
|
+
for (const [rowOffset, line] of lines.entries()) {
|
|
1381
|
+
const currentY = y + rowOffset;
|
|
1382
|
+
if (!this.#insideY(currentY, clip)) continue;
|
|
1383
|
+
let currentX = x;
|
|
1384
|
+
for (const cell of line) {
|
|
1385
|
+
const endX = currentX + cell.width;
|
|
1386
|
+
if (!(clip?.x1 !== void 0 && currentX < clip.x1 || clip?.x2 !== void 0 && endX > clip.x2)) this.#composeNativeCell(currentX, currentY, cell);
|
|
1387
|
+
currentX = endX;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
writeAnsi(x, y, text, options) {
|
|
1392
|
+
if (!text) return;
|
|
1393
|
+
let lines = text.split("\n");
|
|
1394
|
+
const clip = this.#clips.at(-1);
|
|
1395
|
+
if (clip?.y1 !== void 0 && y < clip.y1) {
|
|
1396
|
+
lines = lines.slice(clip.y1 - y);
|
|
1397
|
+
y = clip.y1;
|
|
1398
|
+
}
|
|
1399
|
+
if (clip?.y2 !== void 0) lines = lines.slice(0, Math.max(0, clip.y2 - y));
|
|
1400
|
+
for (const [lineIndex, original] of lines.entries()) {
|
|
1401
|
+
const currentY = y + lineIndex;
|
|
1402
|
+
if (!this.#insideY(currentY, clip)) continue;
|
|
1403
|
+
let line = original;
|
|
1404
|
+
let currentX = x;
|
|
1405
|
+
if (clip?.x1 !== void 0 && currentX < clip.x1) {
|
|
1406
|
+
line = sliceAnsi(line, clip.x1 - currentX);
|
|
1407
|
+
currentX = clip.x1;
|
|
1408
|
+
}
|
|
1409
|
+
if (clip?.x2 !== void 0) line = sliceAnsi(line, 0, Math.max(0, clip.x2 - currentX));
|
|
1410
|
+
for (const character of transformAnsiLine(line, lineIndex, options.transformers)) {
|
|
1411
|
+
const width = Math.max(1, stringWidth(character.value));
|
|
1412
|
+
if (clip?.x2 !== void 0 && currentX + width > clip.x2) break;
|
|
1413
|
+
this.#writeCompatibilityCell(currentX, currentY, character, width);
|
|
1414
|
+
currentX += width;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
clip(clip) {
|
|
1419
|
+
this.#clips.push(clip);
|
|
1420
|
+
}
|
|
1421
|
+
unclip() {
|
|
1422
|
+
this.#clips.pop();
|
|
1423
|
+
}
|
|
1424
|
+
finish() {
|
|
1425
|
+
return this.#screen;
|
|
1426
|
+
}
|
|
1427
|
+
#insideY(y, clip) {
|
|
1428
|
+
return y >= 0 && y < this.#screen.height && (clip?.y1 === void 0 || y >= clip.y1) && (clip?.y2 === void 0 || y < clip.y2);
|
|
1429
|
+
}
|
|
1430
|
+
#composeNativeCell(x, y, cell) {
|
|
1431
|
+
if (x >= this.#screen.width) return;
|
|
1432
|
+
this.#screen.composeCell(x, y, {
|
|
1433
|
+
content: {
|
|
1434
|
+
grapheme: cell.grapheme,
|
|
1435
|
+
width: cell.width
|
|
1436
|
+
},
|
|
1437
|
+
foreground: cell.reset?.foreground ? null : cell.style.foreground ?? null,
|
|
1438
|
+
background: cell.reset?.background ? null : cell.style.background,
|
|
1439
|
+
underlineColor: cell.style.underlineColor ?? null,
|
|
1440
|
+
underline: cell.style.underline,
|
|
1441
|
+
attributes: cell.style.attributes,
|
|
1442
|
+
hyperlink: cell.hyperlink ?? null
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
#writeCompatibilityCell(x, y, character, width) {
|
|
1446
|
+
if (x >= this.#screen.width) return;
|
|
1447
|
+
const cell = cellFromStyledChar(character, width);
|
|
1448
|
+
this.#screen.composeCell(x, y, {
|
|
1449
|
+
content: {
|
|
1450
|
+
grapheme: cell.grapheme,
|
|
1451
|
+
width: cell.width
|
|
1452
|
+
},
|
|
1453
|
+
foreground: cell.style.foreground ?? null,
|
|
1454
|
+
background: cell.style.background,
|
|
1455
|
+
underlineColor: cell.style.underlineColor ?? null,
|
|
1456
|
+
underline: cell.style.underline,
|
|
1457
|
+
attributes: cell.style.attributes,
|
|
1458
|
+
hyperlink: cell.hyperlink ?? null
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
};
|
|
2744
1462
|
//#endregion
|
|
2745
|
-
//#region src/
|
|
2746
|
-
const
|
|
1463
|
+
//#region src/render-frame.ts
|
|
1464
|
+
const renderDimension = (value) => Number.isFinite(value) ? Math.max(0, Math.ceil(value)) : 0;
|
|
1465
|
+
const renderFrame = (node, isScreenReaderEnabled, options = {}) => {
|
|
2747
1466
|
if (node.yogaNode) {
|
|
2748
1467
|
if (isScreenReaderEnabled) {
|
|
2749
|
-
const output =
|
|
2750
|
-
const outputHeight = output === "" ? 0 : output.split("\n").length;
|
|
1468
|
+
const output = renderAccessibleText(node, { skipStaticElements: true });
|
|
2751
1469
|
let staticOutput = "";
|
|
2752
|
-
if (node.staticNode) staticOutput =
|
|
1470
|
+
if (node.staticNode) staticOutput = renderAccessibleText(node.staticNode, { skipStaticElements: false });
|
|
2753
1471
|
return {
|
|
2754
|
-
output,
|
|
2755
|
-
|
|
2756
|
-
staticOutput: staticOutput ? `${staticOutput}\n` : ""
|
|
1472
|
+
accessibleText: output,
|
|
1473
|
+
staticAccessibleText: staticOutput
|
|
2757
1474
|
};
|
|
2758
1475
|
}
|
|
2759
|
-
const output = new
|
|
2760
|
-
width: node.yogaNode.getComputedWidth(),
|
|
2761
|
-
height: node.yogaNode.getComputedHeight()
|
|
1476
|
+
const output = new Canvas({
|
|
1477
|
+
width: renderDimension(node.yogaNode.getComputedWidth()),
|
|
1478
|
+
height: renderDimension(node.yogaNode.getComputedHeight()),
|
|
1479
|
+
colorProfile: options.colorProfile,
|
|
1480
|
+
paintContext: options.paintContext
|
|
2762
1481
|
});
|
|
2763
|
-
|
|
1482
|
+
paintTree(node, output, { skipStaticElements: true });
|
|
2764
1483
|
let staticOutput;
|
|
2765
1484
|
if (node.staticNode?.yogaNode) {
|
|
2766
|
-
staticOutput = new
|
|
2767
|
-
width: node.staticNode.yogaNode.getComputedWidth(),
|
|
2768
|
-
height: node.staticNode.yogaNode.getComputedHeight()
|
|
1485
|
+
staticOutput = new Canvas({
|
|
1486
|
+
width: renderDimension(node.staticNode.yogaNode.getComputedWidth()),
|
|
1487
|
+
height: renderDimension(node.staticNode.yogaNode.getComputedHeight()),
|
|
1488
|
+
colorProfile: options.colorProfile,
|
|
1489
|
+
paintContext: options.paintContext
|
|
2769
1490
|
});
|
|
2770
|
-
|
|
1491
|
+
paintTree(node.staticNode, staticOutput, { skipStaticElements: false });
|
|
1492
|
+
}
|
|
1493
|
+
return {
|
|
1494
|
+
screen: output.finish(),
|
|
1495
|
+
...staticOutput ? { staticScreen: staticOutput.finish() } : {}
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
return { accessibleText: "" };
|
|
1499
|
+
};
|
|
1500
|
+
//#endregion
|
|
1501
|
+
//#region src/terminal/inline-presenter.ts
|
|
1502
|
+
/** Full-rewrite fallback and cursor state for the structured inline renderer. */
|
|
1503
|
+
function createInlinePresenter(stream, options = {}) {
|
|
1504
|
+
let previousLineCount = 0;
|
|
1505
|
+
let previousOutput = "";
|
|
1506
|
+
let hasHiddenCursor = false;
|
|
1507
|
+
let cursorPosition;
|
|
1508
|
+
let cursorDirty = false;
|
|
1509
|
+
let previousCursorPosition;
|
|
1510
|
+
let cursorWasShown = false;
|
|
1511
|
+
const showCursor = options.showCursor ?? false;
|
|
1512
|
+
const activeCursor = () => cursorDirty ? cursorPosition : void 0;
|
|
1513
|
+
const hasChanges = (output, cursor) => output !== previousOutput || cursorPositionChanged(cursor, previousCursorPosition);
|
|
1514
|
+
const present = (output) => {
|
|
1515
|
+
if (!showCursor && !hasHiddenCursor) {
|
|
1516
|
+
cliCursor.hide(stream);
|
|
1517
|
+
hasHiddenCursor = true;
|
|
1518
|
+
}
|
|
1519
|
+
const cursor = activeCursor();
|
|
1520
|
+
cursorDirty = false;
|
|
1521
|
+
const cursorChanged = cursorPositionChanged(cursor, previousCursorPosition);
|
|
1522
|
+
if (!hasChanges(output, cursor)) return false;
|
|
1523
|
+
const lines = output.split("\n");
|
|
1524
|
+
const suffix = buildCursorSuffix(lines.length - 1, cursor);
|
|
1525
|
+
if (output === previousOutput && cursorChanged) stream.write(buildCursorOnlySequence({
|
|
1526
|
+
cursorWasShown,
|
|
1527
|
+
previousLineCount,
|
|
1528
|
+
previousCursorPosition,
|
|
1529
|
+
cursorPosition: cursor
|
|
1530
|
+
}));
|
|
1531
|
+
else {
|
|
1532
|
+
previousOutput = output;
|
|
1533
|
+
stream.write(buildReturnToBottomPrefix(cursorWasShown, previousLineCount, previousCursorPosition) + ansiEscapes.eraseLines(previousLineCount) + output + suffix);
|
|
1534
|
+
previousLineCount = lines.length;
|
|
1535
|
+
}
|
|
1536
|
+
previousCursorPosition = cursor ? { ...cursor } : void 0;
|
|
1537
|
+
cursorWasShown = cursor !== void 0;
|
|
1538
|
+
return true;
|
|
1539
|
+
};
|
|
1540
|
+
present.clear = () => {
|
|
1541
|
+
stream.write(buildReturnToBottomPrefix(cursorWasShown, previousLineCount, previousCursorPosition) + ansiEscapes.eraseLines(previousLineCount));
|
|
1542
|
+
previousOutput = "";
|
|
1543
|
+
previousLineCount = 0;
|
|
1544
|
+
previousCursorPosition = void 0;
|
|
1545
|
+
cursorWasShown = false;
|
|
1546
|
+
};
|
|
1547
|
+
present.done = () => {
|
|
1548
|
+
previousOutput = "";
|
|
1549
|
+
previousLineCount = 0;
|
|
1550
|
+
previousCursorPosition = void 0;
|
|
1551
|
+
cursorWasShown = false;
|
|
1552
|
+
if (!showCursor) {
|
|
1553
|
+
cliCursor.show(stream);
|
|
1554
|
+
hasHiddenCursor = false;
|
|
2771
1555
|
}
|
|
2772
|
-
const { output: generatedOutput, height: outputHeight } = output.get();
|
|
2773
|
-
return {
|
|
2774
|
-
output: generatedOutput,
|
|
2775
|
-
outputHeight,
|
|
2776
|
-
staticOutput: staticOutput ? `${staticOutput.get().output}\n` : ""
|
|
2777
|
-
};
|
|
2778
|
-
}
|
|
2779
|
-
return {
|
|
2780
|
-
output: "",
|
|
2781
|
-
outputHeight: 0,
|
|
2782
|
-
staticOutput: ""
|
|
2783
1556
|
};
|
|
2784
|
-
|
|
1557
|
+
present.reset = () => {
|
|
1558
|
+
previousOutput = "";
|
|
1559
|
+
previousLineCount = 0;
|
|
1560
|
+
previousCursorPosition = void 0;
|
|
1561
|
+
cursorWasShown = false;
|
|
1562
|
+
};
|
|
1563
|
+
present.sync = (output) => {
|
|
1564
|
+
const cursor = activeCursor();
|
|
1565
|
+
cursorDirty = false;
|
|
1566
|
+
const lines = output.split("\n");
|
|
1567
|
+
previousOutput = output;
|
|
1568
|
+
previousLineCount = lines.length;
|
|
1569
|
+
if (!cursor && cursorWasShown) stream.write(hideCursorEscape);
|
|
1570
|
+
if (cursor) stream.write(buildCursorSuffix(lines.length - 1, cursor));
|
|
1571
|
+
previousCursorPosition = cursor ? { ...cursor } : void 0;
|
|
1572
|
+
cursorWasShown = cursor !== void 0;
|
|
1573
|
+
};
|
|
1574
|
+
present.setCursorPosition = (position) => {
|
|
1575
|
+
cursorPosition = position;
|
|
1576
|
+
cursorDirty = true;
|
|
1577
|
+
};
|
|
1578
|
+
present.isCursorDirty = () => cursorDirty;
|
|
1579
|
+
present.willRender = (output) => hasChanges(output, activeCursor());
|
|
1580
|
+
return present;
|
|
1581
|
+
}
|
|
2785
1582
|
//#endregion
|
|
2786
1583
|
//#region src/throttle.ts
|
|
2787
1584
|
/**
|
|
@@ -2832,32 +1629,28 @@ const throttle = (fn, wait = 0) => {
|
|
|
2832
1629
|
return throttled;
|
|
2833
1630
|
};
|
|
2834
1631
|
//#endregion
|
|
2835
|
-
//#region src/terminal-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
const
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
}
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
if (env["COLUMNS"] && env["LINES"]) return create(env["COLUMNS"], env["LINES"]);
|
|
2856
|
-
return devTty() ?? {
|
|
2857
|
-
columns: 80,
|
|
2858
|
-
rows: 24
|
|
1632
|
+
//#region src/terminal/render-scheduler.ts
|
|
1633
|
+
/** Owns frame cadence independently of React reconciliation and terminal presentation. */
|
|
1634
|
+
function createRenderScheduler(render, options) {
|
|
1635
|
+
const frameInterval = options.maxFps > 0 ? Math.max(1, Math.ceil(1e3 / options.maxFps)) : 0;
|
|
1636
|
+
let pending = false;
|
|
1637
|
+
const throttled = options.unthrottled ? void 0 : throttle(render, frameInterval);
|
|
1638
|
+
return {
|
|
1639
|
+
intervalMs: options.unthrottled ? 0 : frameInterval,
|
|
1640
|
+
throttled,
|
|
1641
|
+
get pending() {
|
|
1642
|
+
return pending;
|
|
1643
|
+
},
|
|
1644
|
+
schedule: options.unthrottled ? render : () => {
|
|
1645
|
+
pending = true;
|
|
1646
|
+
throttled();
|
|
1647
|
+
},
|
|
1648
|
+
immediate: render,
|
|
1649
|
+
markRendered() {
|
|
1650
|
+
pending = false;
|
|
1651
|
+
}
|
|
2859
1652
|
};
|
|
2860
|
-
}
|
|
1653
|
+
}
|
|
2861
1654
|
//#endregion
|
|
2862
1655
|
//#region src/utils.ts
|
|
2863
1656
|
const resolveDimension = (value, fallback, defaultValue) => {
|
|
@@ -2884,57 +1677,31 @@ const getWindowSize = (stdout) => {
|
|
|
2884
1677
|
};
|
|
2885
1678
|
};
|
|
2886
1679
|
//#endregion
|
|
2887
|
-
//#region src/write-synchronized.ts
|
|
2888
|
-
function shouldSynchronize(stream, interactive) {
|
|
2889
|
-
return "isTTY" in stream && stream.isTTY && (interactive ?? !isInCi);
|
|
2890
|
-
}
|
|
2891
|
-
//#endregion
|
|
2892
1680
|
//#region src/ink.tsx
|
|
2893
1681
|
/** @jsxImportSource react */
|
|
2894
1682
|
const noop = () => {};
|
|
2895
|
-
const
|
|
2896
|
-
const
|
|
2897
|
-
|
|
2898
|
-
});
|
|
2899
|
-
const kittyQueryEscapeByte = 27;
|
|
2900
|
-
const kittyQueryOpenBracketByte = 91;
|
|
2901
|
-
const kittyQueryQuestionMarkByte = 63;
|
|
2902
|
-
const kittyQueryLetterByte = 117;
|
|
2903
|
-
const zeroByte = 48;
|
|
2904
|
-
const nineByte = 57;
|
|
2905
|
-
const isDigitByte = (byte) => byte >= zeroByte && byte <= nineByte;
|
|
2906
|
-
const matchKittyQueryResponse = (buffer, startIndex) => {
|
|
2907
|
-
if (buffer[startIndex] !== kittyQueryEscapeByte || buffer[startIndex + 1] !== kittyQueryOpenBracketByte || buffer[startIndex + 2] !== kittyQueryQuestionMarkByte) return;
|
|
2908
|
-
let index = startIndex + 3;
|
|
2909
|
-
const digitsStartIndex = index;
|
|
2910
|
-
while (index < buffer.length && isDigitByte(buffer[index])) index++;
|
|
2911
|
-
if (index === digitsStartIndex) return;
|
|
2912
|
-
if (index === buffer.length) return { state: "partial" };
|
|
2913
|
-
if (buffer[index] === kittyQueryLetterByte) return {
|
|
2914
|
-
state: "complete",
|
|
2915
|
-
endIndex: index
|
|
2916
|
-
};
|
|
2917
|
-
};
|
|
2918
|
-
const hasCompleteKittyQueryResponse = (buffer) => {
|
|
2919
|
-
for (let index = 0; index < buffer.length; index++) if (matchKittyQueryResponse(buffer, index)?.state === "complete") return true;
|
|
2920
|
-
return false;
|
|
2921
|
-
};
|
|
2922
|
-
const stripKittyQueryResponsesAndTrailingPartial = (buffer) => {
|
|
2923
|
-
const keptBytes = [];
|
|
2924
|
-
let index = 0;
|
|
2925
|
-
while (index < buffer.length) {
|
|
2926
|
-
const match = matchKittyQueryResponse(buffer, index);
|
|
2927
|
-
if (match?.state === "complete") {
|
|
2928
|
-
index = match.endIndex + 1;
|
|
2929
|
-
continue;
|
|
2930
|
-
}
|
|
2931
|
-
if (match?.state === "partial") break;
|
|
2932
|
-
keptBytes.push(buffer[index]);
|
|
2933
|
-
index++;
|
|
2934
|
-
}
|
|
2935
|
-
return keptBytes;
|
|
1683
|
+
const beforeExitCallbacks = /* @__PURE__ */ new Set();
|
|
1684
|
+
const runBeforeExitCallbacks = () => {
|
|
1685
|
+
for (const callback of beforeExitCallbacks) callback();
|
|
2936
1686
|
};
|
|
2937
|
-
|
|
1687
|
+
function registerBeforeExit(callback) {
|
|
1688
|
+
if (beforeExitCallbacks.size === 0) process.on("beforeExit", runBeforeExitCallbacks);
|
|
1689
|
+
beforeExitCallbacks.add(callback);
|
|
1690
|
+
return () => {
|
|
1691
|
+
beforeExitCallbacks.delete(callback);
|
|
1692
|
+
if (beforeExitCallbacks.size === 0) process.off("beforeExit", runBeforeExitCallbacks);
|
|
1693
|
+
};
|
|
1694
|
+
}
|
|
1695
|
+
function bottomRows(screen, height) {
|
|
1696
|
+
if (screen.height <= height) return screen;
|
|
1697
|
+
const cropped = new Screen(screen.width, height);
|
|
1698
|
+
const offset = screen.height - height;
|
|
1699
|
+
for (let y = 0; y < height; y++) for (let x = 0; x < screen.width; x++) {
|
|
1700
|
+
const cell = screen.cellAt(x, y + offset);
|
|
1701
|
+
if (cell && cell.width > 0) cropped.setCell(x, y, cell);
|
|
1702
|
+
}
|
|
1703
|
+
return cropped;
|
|
1704
|
+
}
|
|
2938
1705
|
const shouldClearTerminalForFrame = ({ isTTY, viewportRows, previousOutputHeight, nextOutputHeight, isUnmounting }) => {
|
|
2939
1706
|
if (!isTTY) return false;
|
|
2940
1707
|
const hadPreviousFrame = previousOutputHeight > 0;
|
|
@@ -2944,20 +1711,24 @@ const shouldClearTerminalForFrame = ({ isTTY, viewportRows, previousOutputHeight
|
|
|
2944
1711
|
const isFullscreen = nextOutputHeight >= viewportRows;
|
|
2945
1712
|
const isLeavingFullscreen = wasOverflowing && nextOutputHeight < viewportRows;
|
|
2946
1713
|
const shouldClearOnUnmount = isUnmounting && wasFullscreen;
|
|
2947
|
-
if (
|
|
1714
|
+
if (isWindows && (wasFullscreen || isFullscreen)) return true;
|
|
2948
1715
|
return wasOverflowing || isOverflowing && hadPreviousFrame || isLeavingFullscreen || shouldClearOnUnmount;
|
|
2949
1716
|
};
|
|
2950
1717
|
const isErrorInput = (value) => {
|
|
2951
|
-
return value instanceof Error ||
|
|
1718
|
+
return value instanceof Error || isNativeError(value);
|
|
2952
1719
|
};
|
|
2953
1720
|
const getWritableStreamState = (stdout) => {
|
|
2954
1721
|
return { canWriteToStdout: !stdout.destroyed && !stdout.writableEnded && (stdout.writable ?? true) };
|
|
2955
1722
|
};
|
|
2956
1723
|
const settleThrottle = (throttled, canWriteToStdout) => {
|
|
2957
|
-
if (!throttled
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
1724
|
+
if (!throttled) return;
|
|
1725
|
+
if (canWriteToStdout) throttled.flush();
|
|
1726
|
+
else throttled.cancel();
|
|
1727
|
+
};
|
|
1728
|
+
const writeBestEffort = (stream, data) => {
|
|
1729
|
+
try {
|
|
1730
|
+
stream.write(data);
|
|
1731
|
+
} catch {}
|
|
2961
1732
|
};
|
|
2962
1733
|
const createRenderPassthrough = (stream) => {
|
|
2963
1734
|
const passthrough = Object.create(stream);
|
|
@@ -2970,645 +1741,597 @@ const createRenderPassthrough = (stream) => {
|
|
|
2970
1741
|
passthrough.emit = stream.emit.bind(stream);
|
|
2971
1742
|
return passthrough;
|
|
2972
1743
|
};
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
1744
|
+
const createInk = (options) => {
|
|
1745
|
+
let captureTargets;
|
|
1746
|
+
if (options.patchConsole === "stdio") {
|
|
1747
|
+
captureTargets = {
|
|
1748
|
+
stdout: options.stdout,
|
|
1749
|
+
stderr: options.stderr
|
|
1750
|
+
};
|
|
1751
|
+
options = {
|
|
1752
|
+
...options,
|
|
1753
|
+
stdout: createRenderPassthrough(options.stdout),
|
|
1754
|
+
stderr: createRenderPassthrough(options.stderr)
|
|
1755
|
+
};
|
|
1756
|
+
}
|
|
1757
|
+
const rootNode = createNode("ink-root");
|
|
1758
|
+
rootNode.onComputeLayout = calculateLayout;
|
|
1759
|
+
const isScreenReaderEnabled = options.isScreenReaderEnabled ?? isScreenReader;
|
|
1760
|
+
const interactive = options.interactive ?? (!isInCi && Boolean(options.stdout.isTTY));
|
|
1761
|
+
const terminal = new TerminalSession({
|
|
1762
|
+
stdin: options.stdin,
|
|
1763
|
+
stdout: options.stdout,
|
|
1764
|
+
stderr: options.stderr,
|
|
1765
|
+
colorPolicy: options.colorProfile ?? "auto",
|
|
1766
|
+
onCapabilitiesChange: () => rootNode.onRender?.()
|
|
1767
|
+
});
|
|
1768
|
+
const terminalOsc = {
|
|
1769
|
+
publishProgress: (owner, state, value) => {
|
|
1770
|
+
terminal.publishProgress(owner, state, value);
|
|
1771
|
+
},
|
|
1772
|
+
copyToClipboard: (text, selection) => {
|
|
1773
|
+
terminal.copyToClipboard(text, selection);
|
|
1774
|
+
},
|
|
1775
|
+
publishTitle: (owner, title) => terminal.publishTitle(owner, title),
|
|
1776
|
+
setWorkingDirectory: (directory) => terminal.setWorkingDirectory(directory),
|
|
1777
|
+
notify: (title) => terminal.notify(title),
|
|
1778
|
+
setPointerShape: (shape) => terminal.setPointerShape(shape)
|
|
1779
|
+
};
|
|
1780
|
+
const capabilitiesStore = terminal.capabilities;
|
|
1781
|
+
const renderScheduler = createRenderScheduler(onRender, {
|
|
1782
|
+
unthrottled: options.debug || isScreenReaderEnabled,
|
|
1783
|
+
maxFps: options.maxFps ?? 30
|
|
1784
|
+
});
|
|
1785
|
+
rootNode.onRender = renderScheduler.schedule;
|
|
1786
|
+
rootNode.onImmediateRender = renderScheduler.immediate;
|
|
1787
|
+
rootNode.onStaticChange = handleStaticChange;
|
|
1788
|
+
const accessiblePresenter = isScreenReaderEnabled ? createInlinePresenter(options.stdout, { showCursor: true }) : void 0;
|
|
1789
|
+
let isUnmounted = false;
|
|
1790
|
+
let isUnmounting = false;
|
|
1791
|
+
const isConcurrent = options.concurrent ?? false;
|
|
1792
|
+
let lastOutput = "";
|
|
1793
|
+
let lastOutputToRender = "";
|
|
1794
|
+
let lastOutputHeight = 0;
|
|
1795
|
+
let lastScreen;
|
|
1796
|
+
let lastTerminalWidth = getWindowSize(options.stdout).columns;
|
|
1797
|
+
let lastTerminalHeight = getWindowSize(options.stdout).rows;
|
|
1798
|
+
let fullStaticOutput = "";
|
|
1799
|
+
let exitResult;
|
|
1800
|
+
let unsubscribeBeforeExit;
|
|
1801
|
+
let restoreConsole;
|
|
1802
|
+
const capturedStdioTails = {
|
|
3002
1803
|
stdout: "",
|
|
3003
1804
|
stderr: ""
|
|
3004
1805
|
};
|
|
3005
|
-
unsubscribeResize;
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
...options,
|
|
3024
|
-
stdout: createRenderPassthrough(options.stdout),
|
|
3025
|
-
stderr: createRenderPassthrough(options.stderr)
|
|
3026
|
-
};
|
|
3027
|
-
}
|
|
3028
|
-
this.options = options;
|
|
3029
|
-
this.rootNode = createNode("ink-root");
|
|
3030
|
-
this.rootNode.onComputeLayout = this.calculateLayout;
|
|
3031
|
-
this.isScreenReaderEnabled = options.isScreenReaderEnabled ?? process.env["SIGIL_SCREEN_READER"] === "true";
|
|
3032
|
-
this.interactive = this.resolveInteractiveOption(options.interactive);
|
|
3033
|
-
this.alternateScreen = false;
|
|
3034
|
-
const unthrottled = options.debug || this.isScreenReaderEnabled;
|
|
3035
|
-
const maxFps = options.maxFps ?? 30;
|
|
3036
|
-
const renderThrottleMs = maxFps > 0 ? Math.max(1, Math.ceil(1e3 / maxFps)) : 0;
|
|
3037
|
-
this.renderThrottleMs = unthrottled ? 0 : renderThrottleMs;
|
|
3038
|
-
if (unthrottled) {
|
|
3039
|
-
this.rootNode.onRender = this.onRender;
|
|
3040
|
-
this.throttledOnRender = void 0;
|
|
3041
|
-
} else {
|
|
3042
|
-
const throttled = throttle(this.onRender, renderThrottleMs);
|
|
3043
|
-
this.rootNode.onRender = () => {
|
|
3044
|
-
this.hasPendingThrottledRender = true;
|
|
3045
|
-
throttled();
|
|
3046
|
-
};
|
|
3047
|
-
this.throttledOnRender = throttled;
|
|
3048
|
-
}
|
|
3049
|
-
this.rootNode.onImmediateRender = this.onRender;
|
|
3050
|
-
this.rootNode.onStaticChange = this.handleStaticChange;
|
|
3051
|
-
this.log = logUpdate.create(options.stdout, { incremental: options.incrementalRendering });
|
|
3052
|
-
this.cursorPosition = void 0;
|
|
3053
|
-
this.throttledLog = unthrottled ? this.log : throttle((output) => {
|
|
3054
|
-
const shouldWrite = this.log.willRender(output);
|
|
3055
|
-
const sync = this.shouldSync();
|
|
3056
|
-
if (sync && shouldWrite) this.options.stdout.write(bsu);
|
|
3057
|
-
this.log(output);
|
|
3058
|
-
if (sync && shouldWrite) this.options.stdout.write(esu);
|
|
3059
|
-
});
|
|
3060
|
-
this.isUnmounted = false;
|
|
3061
|
-
this.isUnmounting = false;
|
|
3062
|
-
this.isConcurrent = options.concurrent ?? false;
|
|
3063
|
-
this.lastOutput = "";
|
|
3064
|
-
this.lastOutputToRender = "";
|
|
3065
|
-
this.lastOutputHeight = 0;
|
|
3066
|
-
this.lastTerminalWidth = getWindowSize(this.options.stdout).columns;
|
|
3067
|
-
this.lastTerminalHeight = getWindowSize(this.options.stdout).rows;
|
|
3068
|
-
this.fullStaticOutput = "";
|
|
3069
|
-
const rootTag = options.concurrent ? ConcurrentRoot : LegacyRoot;
|
|
3070
|
-
this.container = reconciler.createContainer(this.rootNode, rootTag, null, false, null, "id", () => {}, () => {}, () => {}, () => {});
|
|
3071
|
-
this.unsubscribeExit = signalExit(this.unmount.bind(this), { alwaysLast: false });
|
|
3072
|
-
this.setAlternateScreen(Boolean(options.alternateScreen));
|
|
3073
|
-
if (process.env["SIGIL_DEV"] === "true") reconciler.injectIntoDevTools();
|
|
3074
|
-
if (options.patchConsole) this.patchConsole();
|
|
3075
|
-
if (this.interactive) {
|
|
3076
|
-
options.stdout.on("resize", this.resized);
|
|
3077
|
-
this.unsubscribeResize = () => {
|
|
3078
|
-
options.stdout.off("resize", this.resized);
|
|
3079
|
-
};
|
|
3080
|
-
}
|
|
3081
|
-
this.initKittyKeyboard();
|
|
3082
|
-
this.exitPromise = new Promise((resolve, reject) => {
|
|
3083
|
-
this.resolveExitPromise = resolve;
|
|
3084
|
-
this.rejectExitPromise = reject;
|
|
3085
|
-
});
|
|
3086
|
-
this.exitPromise.catch(noop);
|
|
1806
|
+
let unsubscribeResize;
|
|
1807
|
+
let kittyProtocolEnabled = false;
|
|
1808
|
+
let kittyFlags;
|
|
1809
|
+
let cancelKittyDetection;
|
|
1810
|
+
let nextRenderCommit;
|
|
1811
|
+
let pauseInput;
|
|
1812
|
+
let resumeInput;
|
|
1813
|
+
const rootTag = isConcurrent ? ConcurrentRoot : LegacyRoot;
|
|
1814
|
+
const container = reconciler.createContainer(rootNode, rootTag, null, false, null, "id", () => {}, () => {}, () => {}, () => {});
|
|
1815
|
+
const unsubscribeExit = signalExit(unmount, { alwaysLast: false });
|
|
1816
|
+
setAlternateScreen(Boolean(options.alternateScreen));
|
|
1817
|
+
if (isSigilDev) reconciler.injectIntoDevTools();
|
|
1818
|
+
if (options.patchConsole) installConsolePatch();
|
|
1819
|
+
if (interactive) {
|
|
1820
|
+
options.stdout.on("resize", resized);
|
|
1821
|
+
unsubscribeResize = () => {
|
|
1822
|
+
options.stdout.off("resize", resized);
|
|
1823
|
+
};
|
|
3087
1824
|
}
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
1825
|
+
initKittyKeyboard();
|
|
1826
|
+
const { promise: exitPromise, resolve: resolveExitPromise, reject: rejectExitPromise } = Promise.withResolvers();
|
|
1827
|
+
exitPromise.catch(noop);
|
|
1828
|
+
function resized() {
|
|
1829
|
+
const currentWidth = getWindowSize(options.stdout).columns;
|
|
1830
|
+
const currentHeight = getWindowSize(options.stdout).rows;
|
|
1831
|
+
if (currentWidth < lastTerminalWidth || currentHeight !== lastTerminalHeight) {
|
|
1832
|
+
clearLiveOutput();
|
|
1833
|
+
resetLiveOutput();
|
|
1834
|
+
lastOutput = "";
|
|
1835
|
+
lastOutputToRender = "";
|
|
1836
|
+
lastOutputHeight = 0;
|
|
1837
|
+
}
|
|
1838
|
+
calculateLayout();
|
|
1839
|
+
emitLayoutListeners(rootNode);
|
|
1840
|
+
onRender();
|
|
1841
|
+
lastTerminalWidth = currentWidth;
|
|
1842
|
+
lastTerminalHeight = currentHeight;
|
|
1843
|
+
}
|
|
1844
|
+
function handleAppExit(errorOrResult) {
|
|
1845
|
+
if (isUnmounted || isUnmounting) return;
|
|
3108
1846
|
if (isErrorInput(errorOrResult)) {
|
|
3109
|
-
|
|
1847
|
+
unmount(errorOrResult);
|
|
3110
1848
|
return;
|
|
3111
1849
|
}
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
}
|
|
3115
|
-
setCursorPosition
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
}
|
|
3119
|
-
restoreLastOutput
|
|
3120
|
-
if (!
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
}
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
if (
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
1850
|
+
exitResult = errorOrResult;
|
|
1851
|
+
unmount();
|
|
1852
|
+
}
|
|
1853
|
+
function setCursorPosition(position) {
|
|
1854
|
+
terminal.setCursor(position);
|
|
1855
|
+
accessiblePresenter?.setCursorPosition(position);
|
|
1856
|
+
}
|
|
1857
|
+
function restoreLastOutput() {
|
|
1858
|
+
if (!interactive) return;
|
|
1859
|
+
if (isScreenReaderEnabled) {
|
|
1860
|
+
accessiblePresenter.setCursorPosition(terminal.cursor.position);
|
|
1861
|
+
accessiblePresenter(lastOutputToRender || lastOutput + "\n");
|
|
1862
|
+
} else if (lastScreen) terminal.present(lastScreen, {
|
|
1863
|
+
fullscreen: lastOutputToRender === lastOutput,
|
|
1864
|
+
forceRewrite: true
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
function clearLiveOutput() {
|
|
1868
|
+
if (isScreenReaderEnabled) accessiblePresenter.clear();
|
|
1869
|
+
else terminal.clearFrame();
|
|
1870
|
+
}
|
|
1871
|
+
function finishLiveOutput() {
|
|
1872
|
+
if (isScreenReaderEnabled) accessiblePresenter.done();
|
|
1873
|
+
else terminal.finishFrame();
|
|
1874
|
+
}
|
|
1875
|
+
function resetLiveOutput() {
|
|
1876
|
+
if (isScreenReaderEnabled) accessiblePresenter.reset();
|
|
1877
|
+
else terminal.resetFrame();
|
|
1878
|
+
}
|
|
1879
|
+
function calculateLayout() {
|
|
1880
|
+
const terminalWidth = getWindowSize(options.stdout).columns;
|
|
1881
|
+
rootNode.yogaNode.setWidth(terminalWidth);
|
|
1882
|
+
rootNode.yogaNode.calculateLayout(void 0, void 0, Yoga.DIRECTION_LTR);
|
|
1883
|
+
}
|
|
1884
|
+
function handleStaticChange() {
|
|
1885
|
+
fullStaticOutput = "";
|
|
1886
|
+
}
|
|
1887
|
+
function onRender() {
|
|
1888
|
+
renderScheduler.markRendered();
|
|
1889
|
+
if (isUnmounted) return;
|
|
1890
|
+
if (terminal.suspended) {
|
|
1891
|
+
if (nextRenderCommit) {
|
|
1892
|
+
nextRenderCommit.resolve();
|
|
1893
|
+
nextRenderCommit = void 0;
|
|
3139
1894
|
}
|
|
3140
1895
|
return;
|
|
3141
1896
|
}
|
|
3142
|
-
if (
|
|
3143
|
-
|
|
3144
|
-
|
|
1897
|
+
if (nextRenderCommit) {
|
|
1898
|
+
nextRenderCommit.resolve();
|
|
1899
|
+
nextRenderCommit = void 0;
|
|
3145
1900
|
}
|
|
3146
1901
|
const startTime = performance.now();
|
|
3147
|
-
const
|
|
3148
|
-
|
|
1902
|
+
const rendered = renderFrame(rootNode, isScreenReaderEnabled, {
|
|
1903
|
+
colorProfile: terminal.colorProfile,
|
|
1904
|
+
paintContext: {
|
|
1905
|
+
appearance: capabilitiesStore.current.theme.appearance,
|
|
1906
|
+
palette: capabilitiesStore.current.theme.palette
|
|
1907
|
+
}
|
|
1908
|
+
});
|
|
1909
|
+
const screen = rendered.screen;
|
|
1910
|
+
const output = rendered.accessibleText ?? (screen ? terminal.encode(screen) : "");
|
|
1911
|
+
const outputHeight = rendered.accessibleText === void 0 ? screen?.height ?? 0 : rendered.accessibleText === "" ? 0 : rendered.accessibleText.split("\n").length;
|
|
1912
|
+
const staticBody = rendered.staticAccessibleText ?? (rendered.staticScreen ? terminal.encode(rendered.staticScreen) : "");
|
|
1913
|
+
const staticOutput = staticBody ? `${staticBody}\n` : "";
|
|
1914
|
+
options.onRender?.({ renderTime: performance.now() - startTime });
|
|
3149
1915
|
const hasStaticOutput = staticOutput && staticOutput !== "\n";
|
|
3150
|
-
if (
|
|
3151
|
-
if (hasStaticOutput)
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
1916
|
+
if (options.debug) {
|
|
1917
|
+
if (hasStaticOutput) fullStaticOutput += staticOutput;
|
|
1918
|
+
lastOutput = output;
|
|
1919
|
+
lastOutputToRender = output;
|
|
1920
|
+
lastOutputHeight = outputHeight;
|
|
1921
|
+
options.stdout.write(fullStaticOutput + output);
|
|
3156
1922
|
return;
|
|
3157
1923
|
}
|
|
3158
|
-
if (!
|
|
3159
|
-
if (hasStaticOutput)
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
1924
|
+
if (!interactive) {
|
|
1925
|
+
if (hasStaticOutput) options.stdout.write(staticOutput);
|
|
1926
|
+
lastOutput = output;
|
|
1927
|
+
lastOutputToRender = output + "\n";
|
|
1928
|
+
lastOutputHeight = outputHeight;
|
|
3163
1929
|
return;
|
|
3164
1930
|
}
|
|
3165
|
-
if (
|
|
3166
|
-
const sync =
|
|
3167
|
-
if (sync)
|
|
1931
|
+
if (isScreenReaderEnabled) {
|
|
1932
|
+
const sync = shouldSync();
|
|
1933
|
+
if (sync) options.stdout.write(bsu);
|
|
3168
1934
|
if (hasStaticOutput) {
|
|
3169
|
-
const erase =
|
|
3170
|
-
|
|
3171
|
-
|
|
1935
|
+
const erase = lastOutputHeight > 0 ? ansiEscapes.eraseLines(lastOutputHeight) : "";
|
|
1936
|
+
options.stdout.write(erase + staticOutput);
|
|
1937
|
+
lastOutputHeight = 0;
|
|
3172
1938
|
}
|
|
3173
|
-
if (output ===
|
|
3174
|
-
if (sync)
|
|
1939
|
+
if (output === lastOutput && !hasStaticOutput) {
|
|
1940
|
+
if (sync) options.stdout.write(esu);
|
|
3175
1941
|
return;
|
|
3176
1942
|
}
|
|
3177
|
-
const terminalWidth = getWindowSize(
|
|
1943
|
+
const terminalWidth = getWindowSize(options.stdout).columns;
|
|
3178
1944
|
const wrappedOutput = wrapAnsi(output, terminalWidth, {
|
|
3179
1945
|
trim: false,
|
|
3180
1946
|
hard: true
|
|
3181
1947
|
});
|
|
3182
|
-
if (hasStaticOutput)
|
|
1948
|
+
if (hasStaticOutput) options.stdout.write(wrappedOutput);
|
|
3183
1949
|
else {
|
|
3184
|
-
const erase =
|
|
3185
|
-
|
|
1950
|
+
const erase = lastOutputHeight > 0 ? ansiEscapes.eraseLines(lastOutputHeight) : "";
|
|
1951
|
+
options.stdout.write(erase + wrappedOutput);
|
|
3186
1952
|
}
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
if (sync)
|
|
1953
|
+
lastOutput = output;
|
|
1954
|
+
lastOutputToRender = wrappedOutput;
|
|
1955
|
+
lastOutputHeight = wrappedOutput === "" ? 0 : wrappedOutput.split("\n").length;
|
|
1956
|
+
if (sync) options.stdout.write(esu);
|
|
3191
1957
|
return;
|
|
3192
1958
|
}
|
|
3193
|
-
if (hasStaticOutput)
|
|
3194
|
-
|
|
3195
|
-
}
|
|
3196
|
-
render(node) {
|
|
1959
|
+
if (hasStaticOutput) fullStaticOutput += staticOutput;
|
|
1960
|
+
renderInteractiveFrame(output, outputHeight, hasStaticOutput ? staticOutput : "", screen, false);
|
|
1961
|
+
}
|
|
1962
|
+
function render(node) {
|
|
3197
1963
|
const tree = /* @__PURE__ */ jsx(accessibilityContext.Provider, {
|
|
3198
|
-
value: { isScreenReaderEnabled
|
|
3199
|
-
children: /* @__PURE__ */ jsx(
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
1964
|
+
value: { isScreenReaderEnabled },
|
|
1965
|
+
children: /* @__PURE__ */ jsx(TerminalOscContext.Provider, {
|
|
1966
|
+
value: terminalOsc,
|
|
1967
|
+
children: /* @__PURE__ */ jsx(App, {
|
|
1968
|
+
stdin: options.stdin,
|
|
1969
|
+
stdout: options.stdout,
|
|
1970
|
+
stderr: options.stderr,
|
|
1971
|
+
exitOnCtrlC: options.exitOnCtrlC,
|
|
1972
|
+
interactive,
|
|
1973
|
+
renderThrottleMs: renderScheduler.intervalMs,
|
|
1974
|
+
terminalInput: terminal.input,
|
|
1975
|
+
writeToStdout,
|
|
1976
|
+
writeToStderr,
|
|
1977
|
+
setCursorPosition,
|
|
1978
|
+
onExit: handleAppExit,
|
|
1979
|
+
onWaitUntilRenderFlush: waitUntilRenderFlush,
|
|
1980
|
+
onSuspendTerminal: suspendTerminal,
|
|
1981
|
+
onRegisterInputControl: registerInputControl,
|
|
1982
|
+
children: node
|
|
1983
|
+
})
|
|
3214
1984
|
})
|
|
3215
1985
|
});
|
|
3216
|
-
if (
|
|
1986
|
+
if (isConcurrent) reconciler.updateContainer(tree, container, null, noop);
|
|
3217
1987
|
else {
|
|
3218
|
-
reconciler.updateContainerSync(tree,
|
|
1988
|
+
reconciler.updateContainerSync(tree, container, null, noop);
|
|
3219
1989
|
reconciler.flushSyncWork();
|
|
3220
1990
|
}
|
|
3221
1991
|
}
|
|
3222
|
-
writeToStdout(data) {
|
|
3223
|
-
if (
|
|
3224
|
-
if (
|
|
3225
|
-
if (
|
|
3226
|
-
|
|
1992
|
+
function writeToStdout(data) {
|
|
1993
|
+
if (isUnmounted) return;
|
|
1994
|
+
if (terminal.suspended) return;
|
|
1995
|
+
if (options.debug) {
|
|
1996
|
+
options.stdout.write(data + fullStaticOutput + lastOutput);
|
|
3227
1997
|
return;
|
|
3228
1998
|
}
|
|
3229
|
-
if (!
|
|
3230
|
-
|
|
1999
|
+
if (!interactive) {
|
|
2000
|
+
options.stdout.write(data);
|
|
3231
2001
|
return;
|
|
3232
2002
|
}
|
|
3233
|
-
const sync =
|
|
3234
|
-
if (sync)
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
if (sync)
|
|
3239
|
-
}
|
|
3240
|
-
writeToStderr(data) {
|
|
3241
|
-
if (
|
|
3242
|
-
if (
|
|
3243
|
-
if (
|
|
3244
|
-
|
|
3245
|
-
|
|
2003
|
+
const sync = shouldSync();
|
|
2004
|
+
if (sync) options.stdout.write(bsu);
|
|
2005
|
+
clearLiveOutput();
|
|
2006
|
+
options.stdout.write(data);
|
|
2007
|
+
restoreLastOutput();
|
|
2008
|
+
if (sync) options.stdout.write(esu);
|
|
2009
|
+
}
|
|
2010
|
+
function writeToStderr(data) {
|
|
2011
|
+
if (isUnmounted) return;
|
|
2012
|
+
if (terminal.suspended) return;
|
|
2013
|
+
if (options.debug) {
|
|
2014
|
+
options.stderr.write(data);
|
|
2015
|
+
options.stdout.write(fullStaticOutput + lastOutput);
|
|
3246
2016
|
return;
|
|
3247
2017
|
}
|
|
3248
|
-
if (!
|
|
3249
|
-
|
|
2018
|
+
if (!interactive) {
|
|
2019
|
+
options.stderr.write(data);
|
|
3250
2020
|
return;
|
|
3251
2021
|
}
|
|
3252
|
-
const sync =
|
|
3253
|
-
if (sync)
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
if (sync)
|
|
3258
|
-
}
|
|
3259
|
-
unmount(error) {
|
|
3260
|
-
if (
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
const { canWriteToStdout } = getWritableStreamState(stdout);
|
|
3268
|
-
if (canWriteToStdout) this.flushCapturedStdio();
|
|
3269
|
-
settleThrottle(this.throttledOnRender, canWriteToStdout);
|
|
2022
|
+
const sync = shouldSync();
|
|
2023
|
+
if (sync) options.stdout.write(bsu);
|
|
2024
|
+
clearLiveOutput();
|
|
2025
|
+
options.stderr.write(data);
|
|
2026
|
+
restoreLastOutput();
|
|
2027
|
+
if (sync) options.stdout.write(esu);
|
|
2028
|
+
}
|
|
2029
|
+
function unmount(error) {
|
|
2030
|
+
if (isUnmounted || isUnmounting) return;
|
|
2031
|
+
isUnmounting = true;
|
|
2032
|
+
unsubscribeBeforeExit?.();
|
|
2033
|
+
unsubscribeBeforeExit = void 0;
|
|
2034
|
+
const { canWriteToStdout } = getWritableStreamState(options.stdout);
|
|
2035
|
+
if (canWriteToStdout) flushCapturedStdio();
|
|
2036
|
+
settleThrottle(renderScheduler.throttled, canWriteToStdout);
|
|
3270
2037
|
if (canWriteToStdout) {
|
|
3271
|
-
if (!
|
|
3272
|
-
|
|
3273
|
-
|
|
2038
|
+
if (!renderScheduler.throttled || !renderScheduler.pending && fullStaticOutput === "") {
|
|
2039
|
+
calculateLayout();
|
|
2040
|
+
onRender();
|
|
3274
2041
|
}
|
|
3275
2042
|
}
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
if (typeof
|
|
2043
|
+
isUnmounted = true;
|
|
2044
|
+
unsubscribeExit();
|
|
2045
|
+
terminal.cleanup();
|
|
2046
|
+
if (typeof restoreConsole === "function") restoreConsole();
|
|
3280
2047
|
const finishUnmount = () => {
|
|
3281
|
-
if (typeof
|
|
3282
|
-
if (
|
|
2048
|
+
if (typeof unsubscribeResize === "function") unsubscribeResize();
|
|
2049
|
+
if (cancelKittyDetection) cancelKittyDetection();
|
|
3283
2050
|
if (canWriteToStdout) {
|
|
3284
|
-
if (
|
|
3285
|
-
if (
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
this.alternateScreen = false;
|
|
2051
|
+
if (kittyProtocolEnabled) writeBestEffort(options.stdout, ansiEscapes.popKittyKeyboard);
|
|
2052
|
+
if (terminal.alternateScreen) {
|
|
2053
|
+
terminal.setAlternateScreen(false);
|
|
2054
|
+
terminal.setCursorAppearance({ visible: true });
|
|
3289
2055
|
}
|
|
3290
|
-
if (!
|
|
3291
|
-
else if (!
|
|
2056
|
+
if (!interactive) options.stdout.write(options.debug ? "\n" : lastOutput + "\n");
|
|
2057
|
+
else if (!options.debug) finishLiveOutput();
|
|
3292
2058
|
}
|
|
3293
|
-
|
|
3294
|
-
instances.delete(
|
|
3295
|
-
const
|
|
2059
|
+
kittyProtocolEnabled = false;
|
|
2060
|
+
instances.delete(captureTargets?.stdout ?? options.stdout);
|
|
2061
|
+
const finalExitResult = exitResult;
|
|
3296
2062
|
const resolveOrReject = () => {
|
|
3297
|
-
if (isErrorInput(error))
|
|
3298
|
-
else
|
|
2063
|
+
if (isErrorInput(error)) rejectExitPromise(error);
|
|
2064
|
+
else resolveExitPromise(finalExitResult);
|
|
3299
2065
|
};
|
|
3300
2066
|
if (error !== void 0 && !isErrorInput(error)) resolveOrReject();
|
|
3301
|
-
else if (canWriteToStdout)
|
|
2067
|
+
else if (canWriteToStdout) options.stdout.write("", resolveOrReject);
|
|
3302
2068
|
else setImmediate(resolveOrReject);
|
|
3303
2069
|
};
|
|
3304
2070
|
const concurrentReconciler = reconciler;
|
|
3305
|
-
if (
|
|
3306
|
-
reconciler.updateContainerSync(null,
|
|
2071
|
+
if (isConcurrent) {
|
|
2072
|
+
reconciler.updateContainerSync(null, container, null, noop);
|
|
3307
2073
|
reconciler.flushSyncWork();
|
|
3308
2074
|
concurrentReconciler.flushPassiveEffects?.();
|
|
3309
2075
|
finishUnmount();
|
|
3310
2076
|
} else {
|
|
3311
|
-
reconciler.updateContainerSync(null,
|
|
2077
|
+
reconciler.updateContainerSync(null, container, null, noop);
|
|
3312
2078
|
reconciler.flushSyncWork();
|
|
3313
2079
|
finishUnmount();
|
|
3314
2080
|
}
|
|
3315
2081
|
}
|
|
3316
|
-
async waitUntilExit() {
|
|
3317
|
-
if (!
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
process.once("beforeExit", this.beforeExitHandler);
|
|
3322
|
-
}
|
|
3323
|
-
return this.exitPromise;
|
|
2082
|
+
async function waitUntilExit() {
|
|
2083
|
+
if (!unsubscribeBeforeExit) unsubscribeBeforeExit = registerBeforeExit(() => {
|
|
2084
|
+
unmount();
|
|
2085
|
+
});
|
|
2086
|
+
return exitPromise;
|
|
3324
2087
|
}
|
|
3325
|
-
async waitUntilRenderFlush() {
|
|
3326
|
-
if (
|
|
3327
|
-
await
|
|
2088
|
+
async function waitUntilRenderFlush() {
|
|
2089
|
+
if (isUnmounted || isUnmounting) {
|
|
2090
|
+
await awaitExit();
|
|
3328
2091
|
return;
|
|
3329
2092
|
}
|
|
3330
|
-
await
|
|
3331
|
-
if (
|
|
3332
|
-
await
|
|
2093
|
+
await setImmediate$1();
|
|
2094
|
+
if (isUnmounted || isUnmounting) {
|
|
2095
|
+
await awaitExit();
|
|
3333
2096
|
return;
|
|
3334
2097
|
}
|
|
3335
|
-
if (
|
|
3336
|
-
await Promise.race([
|
|
3337
|
-
if (
|
|
3338
|
-
|
|
3339
|
-
await
|
|
2098
|
+
if (isConcurrent && hasPendingConcurrentWork()) {
|
|
2099
|
+
await Promise.race([awaitNextRender(), awaitExit()]);
|
|
2100
|
+
if (isUnmounted || isUnmounting) {
|
|
2101
|
+
nextRenderCommit = void 0;
|
|
2102
|
+
await awaitExit();
|
|
3340
2103
|
return;
|
|
3341
2104
|
}
|
|
3342
2105
|
}
|
|
3343
2106
|
reconciler.flushSyncWork();
|
|
3344
|
-
const {
|
|
3345
|
-
|
|
3346
|
-
settleThrottle(this.throttledOnRender, canWriteToStdout);
|
|
3347
|
-
settleThrottle(this.throttledLog, canWriteToStdout);
|
|
2107
|
+
const { canWriteToStdout } = getWritableStreamState(options.stdout);
|
|
2108
|
+
settleThrottle(renderScheduler.throttled, canWriteToStdout);
|
|
3348
2109
|
if (canWriteToStdout) {
|
|
3349
2110
|
await new Promise((resolve) => {
|
|
3350
|
-
|
|
2111
|
+
options.stdout.write("", () => {
|
|
3351
2112
|
resolve();
|
|
3352
2113
|
});
|
|
3353
2114
|
});
|
|
3354
2115
|
return;
|
|
3355
2116
|
}
|
|
3356
|
-
await
|
|
2117
|
+
await setImmediate$1();
|
|
3357
2118
|
}
|
|
3358
|
-
clear() {
|
|
3359
|
-
if (
|
|
3360
|
-
|
|
3361
|
-
|
|
2119
|
+
function clear() {
|
|
2120
|
+
if (interactive && !options.debug) {
|
|
2121
|
+
clearLiveOutput();
|
|
2122
|
+
if (isScreenReaderEnabled) accessiblePresenter.sync(lastOutputToRender || lastOutput + "\n");
|
|
3362
2123
|
}
|
|
3363
2124
|
}
|
|
3364
|
-
|
|
3365
|
-
if (
|
|
2125
|
+
function installConsolePatch() {
|
|
2126
|
+
if (options.debug) return;
|
|
3366
2127
|
const restoreConsoleMethods = patchConsole((stream, data) => {
|
|
3367
|
-
if (
|
|
3368
|
-
if (stream === "stdout")
|
|
2128
|
+
if (options.onCapturedOutput?.(stream, data, "console") === true) return;
|
|
2129
|
+
if (stream === "stdout") writeToStdout(data);
|
|
3369
2130
|
if (stream === "stderr") {
|
|
3370
|
-
if (!data.startsWith("The above error occurred"))
|
|
2131
|
+
if (!data.startsWith("The above error occurred")) writeToStderr(data);
|
|
3371
2132
|
}
|
|
3372
2133
|
});
|
|
3373
|
-
const restoreDirectStdio =
|
|
3374
|
-
|
|
2134
|
+
const restoreDirectStdio = patchDirectStdio();
|
|
2135
|
+
restoreConsole = () => {
|
|
3375
2136
|
restoreConsoleMethods();
|
|
3376
2137
|
restoreDirectStdio?.();
|
|
3377
2138
|
};
|
|
3378
2139
|
}
|
|
3379
|
-
patchDirectStdio() {
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
(typeof encodingOrCallback === "function" ? encodingOrCallback : typeof callback === "function" ? callback : void 0)?.();
|
|
3388
|
-
return true;
|
|
3389
|
-
};
|
|
3390
|
-
stream.write = patchedWrite;
|
|
3391
|
-
return () => {
|
|
3392
|
-
stream.write = originalWrite;
|
|
3393
|
-
};
|
|
3394
|
-
};
|
|
3395
|
-
const restoreStdout = patch("stdout", targets.stdout);
|
|
3396
|
-
const restoreStderr = patch("stderr", targets.stderr);
|
|
2140
|
+
function patchDirectStdio() {
|
|
2141
|
+
if (!captureTargets) return;
|
|
2142
|
+
const restoreStdout = patchStreamWrite(captureTargets.stdout, (data) => {
|
|
2143
|
+
handleCapturedStdio("stdout", data);
|
|
2144
|
+
});
|
|
2145
|
+
const restoreStderr = patchStreamWrite(captureTargets.stderr, (data) => {
|
|
2146
|
+
handleCapturedStdio("stderr", data);
|
|
2147
|
+
});
|
|
3397
2148
|
return () => {
|
|
3398
2149
|
restoreStdout();
|
|
3399
2150
|
restoreStderr();
|
|
3400
2151
|
};
|
|
3401
2152
|
}
|
|
3402
|
-
handleCapturedStdio(stream, data) {
|
|
3403
|
-
if (
|
|
3404
|
-
const parts = (
|
|
3405
|
-
|
|
2153
|
+
function handleCapturedStdio(stream, data) {
|
|
2154
|
+
if (options.onCapturedOutput?.(stream, data, "stdio") === true) return;
|
|
2155
|
+
const parts = (capturedStdioTails[stream] + data).split(/\r?\n/);
|
|
2156
|
+
capturedStdioTails[stream] = parts.pop() ?? "";
|
|
3406
2157
|
if (parts.length === 0) return;
|
|
3407
2158
|
const payload = parts.join("\n") + "\n";
|
|
3408
|
-
if (stream === "stdout")
|
|
3409
|
-
else
|
|
2159
|
+
if (stream === "stdout") writeToStdout(payload);
|
|
2160
|
+
else writeToStderr(payload);
|
|
3410
2161
|
}
|
|
3411
|
-
flushCapturedStdio() {
|
|
2162
|
+
function flushCapturedStdio() {
|
|
3412
2163
|
for (const stream of ["stdout", "stderr"]) {
|
|
3413
|
-
const tail =
|
|
2164
|
+
const tail = capturedStdioTails[stream];
|
|
3414
2165
|
if (tail === "") continue;
|
|
3415
|
-
|
|
3416
|
-
if (stream === "stdout")
|
|
3417
|
-
else
|
|
2166
|
+
capturedStdioTails[stream] = "";
|
|
2167
|
+
if (stream === "stdout") writeToStdout(tail + "\n");
|
|
2168
|
+
else writeToStderr(tail + "\n");
|
|
3418
2169
|
}
|
|
3419
2170
|
}
|
|
3420
|
-
registerInputControl(
|
|
3421
|
-
|
|
3422
|
-
|
|
2171
|
+
function registerInputControl(pause, resume) {
|
|
2172
|
+
pauseInput = pause;
|
|
2173
|
+
resumeInput = resume;
|
|
3423
2174
|
}
|
|
3424
|
-
async suspendTerminal(callback) {
|
|
3425
|
-
|
|
2175
|
+
async function suspendTerminal(callback) {
|
|
2176
|
+
beginSuspend();
|
|
3426
2177
|
if (callback) {
|
|
3427
2178
|
try {
|
|
3428
2179
|
await callback();
|
|
3429
2180
|
} finally {
|
|
3430
|
-
await
|
|
2181
|
+
await endSuspend();
|
|
3431
2182
|
}
|
|
3432
2183
|
return;
|
|
3433
2184
|
}
|
|
3434
2185
|
const resume = async () => {
|
|
3435
|
-
await
|
|
2186
|
+
await endSuspend();
|
|
3436
2187
|
};
|
|
3437
2188
|
return {
|
|
3438
2189
|
resume,
|
|
3439
2190
|
[Symbol.asyncDispose]: resume
|
|
3440
2191
|
};
|
|
3441
2192
|
}
|
|
3442
|
-
setAlternateScreen(enabled) {
|
|
3443
|
-
|
|
3444
|
-
if (this.alternateScreen) {
|
|
3445
|
-
this.writeBestEffort(this.options.stdout, ansiEscapes.enterAlternativeScreen);
|
|
3446
|
-
this.writeBestEffort(this.options.stdout, hideCursorEscape);
|
|
3447
|
-
}
|
|
3448
|
-
}
|
|
3449
|
-
resolveInteractiveOption(interactive) {
|
|
3450
|
-
return interactive ?? (!isInCi && Boolean(this.options.stdout.isTTY));
|
|
3451
|
-
}
|
|
3452
|
-
resolveAlternateScreenOption(alternateScreen, interactive) {
|
|
3453
|
-
return Boolean(alternateScreen) && interactive && Boolean(this.options.stdout.isTTY);
|
|
2193
|
+
function setAlternateScreen(enabled) {
|
|
2194
|
+
terminal.setAlternateScreen(enabled && interactive && Boolean(options.stdout.isTTY), { hideCursor: true });
|
|
3454
2195
|
}
|
|
3455
|
-
shouldSync() {
|
|
3456
|
-
return
|
|
3457
|
-
}
|
|
3458
|
-
writeBestEffort(stream, data) {
|
|
3459
|
-
try {
|
|
3460
|
-
stream.write(data);
|
|
3461
|
-
} catch {}
|
|
2196
|
+
function shouldSync() {
|
|
2197
|
+
return Boolean(options.stdout.isTTY) && interactive;
|
|
3462
2198
|
}
|
|
3463
|
-
async awaitExit() {
|
|
2199
|
+
async function awaitExit() {
|
|
3464
2200
|
try {
|
|
3465
|
-
await
|
|
2201
|
+
await exitPromise;
|
|
3466
2202
|
} catch {}
|
|
3467
2203
|
}
|
|
3468
|
-
hasPendingConcurrentWork() {
|
|
3469
|
-
const concurrentContainer =
|
|
2204
|
+
function hasPendingConcurrentWork() {
|
|
2205
|
+
const concurrentContainer = container;
|
|
3470
2206
|
return (concurrentContainer.pendingLanes ?? 0) !== 0 && concurrentContainer.callbackNode !== void 0 && concurrentContainer.callbackNode !== null;
|
|
3471
2207
|
}
|
|
3472
|
-
async awaitNextRender() {
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
const promise = new Promise((resolve) => {
|
|
3476
|
-
resolveRender = resolve;
|
|
3477
|
-
});
|
|
3478
|
-
this.nextRenderCommit = {
|
|
3479
|
-
promise,
|
|
3480
|
-
resolve: resolveRender
|
|
3481
|
-
};
|
|
3482
|
-
}
|
|
3483
|
-
return this.nextRenderCommit.promise;
|
|
2208
|
+
async function awaitNextRender() {
|
|
2209
|
+
nextRenderCommit ??= Promise.withResolvers();
|
|
2210
|
+
return nextRenderCommit.promise;
|
|
3484
2211
|
}
|
|
3485
|
-
renderInteractiveFrame(output, outputHeight, staticOutput) {
|
|
2212
|
+
function renderInteractiveFrame(output, outputHeight, staticOutput, screen, hasOverflow) {
|
|
2213
|
+
if (!screen) return;
|
|
3486
2214
|
const hasStaticOutput = staticOutput !== "";
|
|
3487
|
-
const isTTY = Boolean(
|
|
3488
|
-
const viewportRows = isTTY ? getWindowSize(
|
|
2215
|
+
const isTTY = Boolean(options.stdout.isTTY);
|
|
2216
|
+
const viewportRows = isTTY ? getWindowSize(options.stdout).rows : 24;
|
|
3489
2217
|
if (isTTY && outputHeight > viewportRows) {
|
|
3490
2218
|
const lines = output.split("\n");
|
|
3491
2219
|
output = lines.slice(lines.length - viewportRows).join("\n");
|
|
3492
2220
|
outputHeight = viewportRows;
|
|
2221
|
+
screen = bottomRows(screen, viewportRows);
|
|
3493
2222
|
}
|
|
3494
|
-
const
|
|
2223
|
+
const isFullscreen = isTTY && outputHeight >= viewportRows;
|
|
2224
|
+
const outputToRender = isFullscreen ? output : output + "\n";
|
|
3495
2225
|
if (shouldClearTerminalForFrame({
|
|
3496
2226
|
isTTY,
|
|
3497
2227
|
viewportRows,
|
|
3498
|
-
previousOutputHeight:
|
|
2228
|
+
previousOutputHeight: lastOutputHeight,
|
|
3499
2229
|
nextOutputHeight: outputHeight,
|
|
3500
|
-
isUnmounting
|
|
2230
|
+
isUnmounting
|
|
3501
2231
|
})) {
|
|
3502
|
-
const sync =
|
|
3503
|
-
if (sync)
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
2232
|
+
const sync = shouldSync();
|
|
2233
|
+
if (sync) options.stdout.write(bsu);
|
|
2234
|
+
options.stdout.write(ansiEscapes.clearTerminal + fullStaticOutput + outputToRender);
|
|
2235
|
+
lastOutput = output;
|
|
2236
|
+
lastOutputToRender = outputToRender;
|
|
2237
|
+
lastOutputHeight = outputHeight;
|
|
2238
|
+
lastScreen = screen;
|
|
2239
|
+
terminal.resetFrame();
|
|
2240
|
+
if (sync) options.stdout.write(esu);
|
|
3510
2241
|
return;
|
|
3511
2242
|
}
|
|
2243
|
+
const willPresent = terminal.willPresent(screen, {
|
|
2244
|
+
fullscreen: isFullscreen,
|
|
2245
|
+
forceRewrite: hasStaticOutput || hasOverflow
|
|
2246
|
+
});
|
|
2247
|
+
const sync = shouldSync() && willPresent;
|
|
2248
|
+
if (sync) terminal.write(bsu);
|
|
3512
2249
|
if (hasStaticOutput) {
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
}
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
2250
|
+
terminal.clearFrame();
|
|
2251
|
+
terminal.write(staticOutput);
|
|
2252
|
+
}
|
|
2253
|
+
terminal.present(screen, {
|
|
2254
|
+
fullscreen: isFullscreen,
|
|
2255
|
+
forceRewrite: hasStaticOutput || hasOverflow
|
|
2256
|
+
});
|
|
2257
|
+
if (sync) terminal.write(esu);
|
|
2258
|
+
lastOutput = output;
|
|
2259
|
+
lastOutputToRender = outputToRender;
|
|
2260
|
+
lastOutputHeight = outputHeight;
|
|
2261
|
+
lastScreen = screen;
|
|
2262
|
+
}
|
|
2263
|
+
function initKittyKeyboard() {
|
|
2264
|
+
if (!options.kittyKeyboard) return;
|
|
2265
|
+
const opts = options.kittyKeyboard;
|
|
3527
2266
|
const mode = opts.mode ?? "auto";
|
|
3528
2267
|
if (mode === "disabled") return;
|
|
3529
2268
|
const flags = opts.flags ?? ["disambiguateEscapeCodes"];
|
|
3530
2269
|
if (mode === "enabled") {
|
|
3531
|
-
if (isTty(
|
|
2270
|
+
if (isTty(options.stdin) && options.stdout.isTTY) enableKittyProtocol(flags);
|
|
3532
2271
|
return;
|
|
3533
2272
|
}
|
|
3534
|
-
if (!
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
let responseBuffer = [];
|
|
3540
|
-
const cleanup = () => {
|
|
3541
|
-
this.cancelKittyDetection = void 0;
|
|
3542
|
-
clearTimeout(timer);
|
|
3543
|
-
stdin.removeListener("data", onData);
|
|
3544
|
-
const remaining = stripKittyQueryResponsesAndTrailingPartial(responseBuffer);
|
|
3545
|
-
responseBuffer = [];
|
|
3546
|
-
if (remaining.length > 0) stdin.unshift(Uint8Array.from(remaining));
|
|
3547
|
-
};
|
|
3548
|
-
const onData = (data) => {
|
|
3549
|
-
const chunk = typeof data === "string" ? textEncoder.encode(data) : data;
|
|
3550
|
-
for (const byte of chunk) responseBuffer.push(byte);
|
|
3551
|
-
if (hasCompleteKittyQueryResponse(responseBuffer)) {
|
|
3552
|
-
cleanup();
|
|
3553
|
-
if (!this.isUnmounted) this.enableKittyProtocol(flags);
|
|
3554
|
-
}
|
|
3555
|
-
};
|
|
3556
|
-
stdin.on("data", onData);
|
|
3557
|
-
const timer = setTimeout(cleanup, 200);
|
|
3558
|
-
this.cancelKittyDetection = cleanup;
|
|
3559
|
-
stdout.write(ansiEscapes.kittyQuery);
|
|
2273
|
+
if (!interactive || !isTty(options.stdin) || !options.stdout.isTTY) return;
|
|
2274
|
+
cancelKittyDetection = detectKittySupport(options.stdin, options.stdout, () => {
|
|
2275
|
+
cancelKittyDetection = void 0;
|
|
2276
|
+
if (!isUnmounted) enableKittyProtocol(flags);
|
|
2277
|
+
});
|
|
3560
2278
|
}
|
|
3561
|
-
enableKittyProtocol(flags) {
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
2279
|
+
function enableKittyProtocol(flags) {
|
|
2280
|
+
options.stdout.write(ansiEscapes.pushKittyKeyboard(resolveFlags(flags)));
|
|
2281
|
+
kittyProtocolEnabled = true;
|
|
2282
|
+
kittyFlags = flags;
|
|
3565
2283
|
}
|
|
3566
|
-
beginSuspend() {
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
if (!this.interactive || this.isUnmounted || this.isUnmounting) return;
|
|
2284
|
+
function beginSuspend() {
|
|
2285
|
+
terminal.beginSuspension();
|
|
2286
|
+
if (!interactive || isUnmounted || isUnmounting) return;
|
|
3570
2287
|
try {
|
|
3571
|
-
const {
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
settleThrottle(this.throttledLog, canWriteToStdout);
|
|
3575
|
-
if (canWriteToStdout) this.flushCapturedStdio();
|
|
2288
|
+
const { canWriteToStdout } = getWritableStreamState(options.stdout);
|
|
2289
|
+
settleThrottle(renderScheduler.throttled, canWriteToStdout);
|
|
2290
|
+
if (canWriteToStdout) flushCapturedStdio();
|
|
3576
2291
|
if (canWriteToStdout) {
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
if (
|
|
3580
|
-
if (
|
|
2292
|
+
clearLiveOutput();
|
|
2293
|
+
finishLiveOutput();
|
|
2294
|
+
if (kittyProtocolEnabled) writeBestEffort(options.stdout, ansiEscapes.popKittyKeyboard);
|
|
2295
|
+
if (terminal.alternateScreen) writeBestEffort(options.stdout, ansiEscapes.exitAlternativeScreen);
|
|
3581
2296
|
}
|
|
3582
|
-
|
|
2297
|
+
pauseInput?.();
|
|
3583
2298
|
} catch (error) {
|
|
3584
|
-
|
|
2299
|
+
terminal.resume();
|
|
3585
2300
|
try {
|
|
3586
|
-
|
|
2301
|
+
resumeInput?.();
|
|
3587
2302
|
} catch {}
|
|
3588
2303
|
throw error;
|
|
3589
2304
|
}
|
|
3590
2305
|
}
|
|
3591
|
-
async endSuspend() {
|
|
3592
|
-
if (!
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
if (!
|
|
3596
|
-
const {
|
|
3597
|
-
const { canWriteToStdout } = getWritableStreamState(stdout);
|
|
2306
|
+
async function endSuspend() {
|
|
2307
|
+
if (!terminal.suspended) return;
|
|
2308
|
+
terminal.resume();
|
|
2309
|
+
resumeInput?.();
|
|
2310
|
+
if (!interactive || isUnmounted || isUnmounting) return;
|
|
2311
|
+
const { canWriteToStdout } = getWritableStreamState(options.stdout);
|
|
3598
2312
|
if (canWriteToStdout) {
|
|
3599
|
-
if (
|
|
3600
|
-
if (
|
|
2313
|
+
if (terminal.alternateScreen) writeBestEffort(options.stdout, ansiEscapes.enterAlternativeScreen);
|
|
2314
|
+
if (kittyProtocolEnabled && kittyFlags) writeBestEffort(options.stdout, ansiEscapes.pushKittyKeyboard(resolveFlags(kittyFlags)));
|
|
3601
2315
|
}
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
2316
|
+
lastOutput = "";
|
|
2317
|
+
lastOutputToRender = "";
|
|
2318
|
+
lastOutputHeight = 0;
|
|
2319
|
+
resetLiveOutput();
|
|
3606
2320
|
try {
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
await
|
|
2321
|
+
calculateLayout();
|
|
2322
|
+
onRender();
|
|
2323
|
+
await waitUntilRenderFlush();
|
|
3610
2324
|
} catch {}
|
|
3611
2325
|
}
|
|
2326
|
+
return {
|
|
2327
|
+
render,
|
|
2328
|
+
unmount,
|
|
2329
|
+
waitUntilExit,
|
|
2330
|
+
waitUntilRenderFlush,
|
|
2331
|
+
clear,
|
|
2332
|
+
copyToClipboard: (text, selection) => terminal.copyToClipboard(text, selection),
|
|
2333
|
+
setProgress: (state, value) => terminal.setProgress(state, value)
|
|
2334
|
+
};
|
|
3612
2335
|
};
|
|
3613
2336
|
//#endregion
|
|
3614
2337
|
//#region src/render.ts
|
|
@@ -3624,24 +2347,25 @@ const render = (node, options) => {
|
|
|
3624
2347
|
exitOnCtrlC: true,
|
|
3625
2348
|
patchConsole: true,
|
|
3626
2349
|
maxFps: 30,
|
|
3627
|
-
incrementalRendering: false,
|
|
3628
2350
|
concurrent: false,
|
|
3629
2351
|
alternateScreen: false,
|
|
3630
2352
|
...getOptions(options)
|
|
3631
2353
|
};
|
|
3632
|
-
const instance = getInstance(inkOptions.stdout, () =>
|
|
2354
|
+
const instance = getInstance(inkOptions.stdout, () => createInk(inkOptions));
|
|
3633
2355
|
instance.render(node);
|
|
3634
2356
|
return {
|
|
3635
|
-
rerender: instance.render
|
|
2357
|
+
rerender: instance.render,
|
|
3636
2358
|
unmount() {
|
|
3637
2359
|
instance.unmount();
|
|
3638
2360
|
},
|
|
3639
|
-
waitUntilExit: instance.waitUntilExit
|
|
3640
|
-
waitUntilRenderFlush: instance.waitUntilRenderFlush
|
|
2361
|
+
waitUntilExit: instance.waitUntilExit,
|
|
2362
|
+
waitUntilRenderFlush: instance.waitUntilRenderFlush,
|
|
3641
2363
|
cleanup() {
|
|
3642
2364
|
instance.unmount();
|
|
3643
2365
|
},
|
|
3644
|
-
clear: instance.clear
|
|
2366
|
+
clear: instance.clear,
|
|
2367
|
+
copyToClipboard: instance.copyToClipboard,
|
|
2368
|
+
setProgress: instance.setProgress
|
|
3645
2369
|
};
|
|
3646
2370
|
};
|
|
3647
2371
|
const getOptions = (stdout = {}) => {
|
|
@@ -3692,6 +2416,7 @@ console.log(output);
|
|
|
3692
2416
|
*/
|
|
3693
2417
|
const renderToString = (node, options) => {
|
|
3694
2418
|
const columns = options?.columns ?? 80;
|
|
2419
|
+
const colorProfile = options?.colorProfile ?? colorProfileFromLevel(detectColorLevel());
|
|
3695
2420
|
const rootNode = createNode("ink-root");
|
|
3696
2421
|
let capturedStaticOutput = "";
|
|
3697
2422
|
rootNode.onComputeLayout = () => {
|
|
@@ -3699,7 +2424,11 @@ const renderToString = (node, options) => {
|
|
|
3699
2424
|
rootNode.yogaNode.calculateLayout(void 0, void 0, Yoga.DIRECTION_LTR);
|
|
3700
2425
|
};
|
|
3701
2426
|
rootNode.onImmediateRender = () => {
|
|
3702
|
-
const {
|
|
2427
|
+
const { staticScreen } = renderFrame(rootNode, false, { colorProfile });
|
|
2428
|
+
const staticOutput = staticScreen ? `${serializeScreen(staticScreen, {
|
|
2429
|
+
colorProfile,
|
|
2430
|
+
styles: colorProfile !== "none"
|
|
2431
|
+
})}\n` : "";
|
|
3703
2432
|
if (staticOutput && staticOutput !== "\n") capturedStaticOutput += staticOutput;
|
|
3704
2433
|
};
|
|
3705
2434
|
let uncaughtError;
|
|
@@ -3708,7 +2437,11 @@ const renderToString = (node, options) => {
|
|
|
3708
2437
|
}, () => {}, () => {}, () => {});
|
|
3709
2438
|
reconciler.updateContainerSync(node, container, null, () => {});
|
|
3710
2439
|
reconciler.flushSyncWork();
|
|
3711
|
-
const {
|
|
2440
|
+
const { screen } = renderFrame(rootNode, false, { colorProfile });
|
|
2441
|
+
const output = screen ? serializeScreen(screen, {
|
|
2442
|
+
colorProfile,
|
|
2443
|
+
styles: colorProfile !== "none"
|
|
2444
|
+
}) : "";
|
|
3712
2445
|
reconciler.updateContainerSync(null, container, null, () => {});
|
|
3713
2446
|
reconciler.flushSyncWork();
|
|
3714
2447
|
if (uncaughtError !== void 0) throw uncaughtError instanceof Error ? uncaughtError : new Error(String(uncaughtError));
|
|
@@ -3717,6 +2450,30 @@ const renderToString = (node, options) => {
|
|
|
3717
2450
|
return normalizedStaticOutput || output;
|
|
3718
2451
|
};
|
|
3719
2452
|
//#endregion
|
|
2453
|
+
//#region src/components/AnsiText.tsx
|
|
2454
|
+
/** @jsxImportSource react */
|
|
2455
|
+
/**
|
|
2456
|
+
* Renders explicitly trusted ANSI-styled output as structured terminal cells.
|
|
2457
|
+
* Ordinary `Text` continues to strip terminal control sequences.
|
|
2458
|
+
*/
|
|
2459
|
+
function AnsiText({ children, wrap = "wrap", "aria-label": ariaLabel, "aria-hidden": ariaHidden = false }) {
|
|
2460
|
+
const { isScreenReaderEnabled } = useContext(accessibilityContext);
|
|
2461
|
+
if (isScreenReaderEnabled) {
|
|
2462
|
+
if (ariaHidden) return null;
|
|
2463
|
+
return /* @__PURE__ */ jsx(Text, { children: ariaLabel ?? stripAnsi(children) });
|
|
2464
|
+
}
|
|
2465
|
+
return /* @__PURE__ */ jsx("ink-text", {
|
|
2466
|
+
style: {
|
|
2467
|
+
flexGrow: 0,
|
|
2468
|
+
flexShrink: 1,
|
|
2469
|
+
flexDirection: "row",
|
|
2470
|
+
textWrap: wrap
|
|
2471
|
+
},
|
|
2472
|
+
internal_ansi: true,
|
|
2473
|
+
children
|
|
2474
|
+
});
|
|
2475
|
+
}
|
|
2476
|
+
//#endregion
|
|
3720
2477
|
//#region src/components/Static.tsx
|
|
3721
2478
|
/** @jsxImportSource react */
|
|
3722
2479
|
/**
|
|
@@ -3769,6 +2526,44 @@ function Transform({ children, transform, accessibilityLabel }) {
|
|
|
3769
2526
|
});
|
|
3770
2527
|
}
|
|
3771
2528
|
//#endregion
|
|
2529
|
+
//#region src/hooks/use-stdout.ts
|
|
2530
|
+
/**
|
|
2531
|
+
A React hook that returns the stdout stream where Ink renders your app.
|
|
2532
|
+
*/
|
|
2533
|
+
const useStdout = () => useContext(StdoutContext);
|
|
2534
|
+
//#endregion
|
|
2535
|
+
//#region src/components/Hyperlink.tsx
|
|
2536
|
+
/**
|
|
2537
|
+
A clickable OSC 8 hyperlink — the counterpart to the router's `<Link>`, which
|
|
2538
|
+
navigates between screens. On terminals without hyperlink support it falls
|
|
2539
|
+
back to `text (url)`.
|
|
2540
|
+
|
|
2541
|
+
```tsx
|
|
2542
|
+
<Hyperlink url="https://example.com">Documentation</Hyperlink>
|
|
2543
|
+
```
|
|
2544
|
+
*/
|
|
2545
|
+
function Hyperlink({ url, fallback = true, children, ...textProps }) {
|
|
2546
|
+
const { stdout } = useStdout();
|
|
2547
|
+
if (!detectHyperlinkSupport(stdout)) return /* @__PURE__ */ jsxs(Text, {
|
|
2548
|
+
...textProps,
|
|
2549
|
+
children: [children, fallback ? /* @__PURE__ */ jsxs(Text, {
|
|
2550
|
+
dimColor: true,
|
|
2551
|
+
children: [
|
|
2552
|
+
" (",
|
|
2553
|
+
url,
|
|
2554
|
+
")"
|
|
2555
|
+
]
|
|
2556
|
+
}) : null]
|
|
2557
|
+
});
|
|
2558
|
+
return /* @__PURE__ */ jsx(Transform, {
|
|
2559
|
+
transform: (text) => link(text, url),
|
|
2560
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
2561
|
+
...textProps,
|
|
2562
|
+
children
|
|
2563
|
+
})
|
|
2564
|
+
});
|
|
2565
|
+
}
|
|
2566
|
+
//#endregion
|
|
3772
2567
|
//#region src/components/Newline.tsx
|
|
3773
2568
|
/**
|
|
3774
2569
|
Adds one or more newline (`\n`) characters. Must be used within `<Text>` components.
|
|
@@ -3788,488 +2583,60 @@ function Spacer() {
|
|
|
3788
2583
|
return /* @__PURE__ */ jsx(Box, { flexGrow: 1 });
|
|
3789
2584
|
}
|
|
3790
2585
|
//#endregion
|
|
3791
|
-
//#region src/
|
|
3792
|
-
const textDecoder = new TextDecoder();
|
|
3793
|
-
const metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/;
|
|
3794
|
-
const fnKeyRe = /^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/;
|
|
3795
|
-
const keyName = {
|
|
3796
|
-
OP: "f1",
|
|
3797
|
-
OQ: "f2",
|
|
3798
|
-
OR: "f3",
|
|
3799
|
-
OS: "f4",
|
|
3800
|
-
"[P": "f1",
|
|
3801
|
-
"[Q": "f2",
|
|
3802
|
-
"[R": "f3",
|
|
3803
|
-
"[S": "f4",
|
|
3804
|
-
"[11~": "f1",
|
|
3805
|
-
"[12~": "f2",
|
|
3806
|
-
"[13~": "f3",
|
|
3807
|
-
"[14~": "f4",
|
|
3808
|
-
"[[A": "f1",
|
|
3809
|
-
"[[B": "f2",
|
|
3810
|
-
"[[C": "f3",
|
|
3811
|
-
"[[D": "f4",
|
|
3812
|
-
"[[E": "f5",
|
|
3813
|
-
"[15~": "f5",
|
|
3814
|
-
"[17~": "f6",
|
|
3815
|
-
"[18~": "f7",
|
|
3816
|
-
"[19~": "f8",
|
|
3817
|
-
"[20~": "f9",
|
|
3818
|
-
"[21~": "f10",
|
|
3819
|
-
"[23~": "f11",
|
|
3820
|
-
"[24~": "f12",
|
|
3821
|
-
"[A": "up",
|
|
3822
|
-
"[B": "down",
|
|
3823
|
-
"[C": "right",
|
|
3824
|
-
"[D": "left",
|
|
3825
|
-
"[E": "clear",
|
|
3826
|
-
"[F": "end",
|
|
3827
|
-
"[H": "home",
|
|
3828
|
-
OA: "up",
|
|
3829
|
-
OB: "down",
|
|
3830
|
-
OC: "right",
|
|
3831
|
-
OD: "left",
|
|
3832
|
-
OE: "clear",
|
|
3833
|
-
OF: "end",
|
|
3834
|
-
OH: "home",
|
|
3835
|
-
"[1~": "home",
|
|
3836
|
-
"[2~": "insert",
|
|
3837
|
-
"[3~": "delete",
|
|
3838
|
-
"[4~": "end",
|
|
3839
|
-
"[5~": "pageup",
|
|
3840
|
-
"[6~": "pagedown",
|
|
3841
|
-
"[[5~": "pageup",
|
|
3842
|
-
"[[6~": "pagedown",
|
|
3843
|
-
"[7~": "home",
|
|
3844
|
-
"[8~": "end",
|
|
3845
|
-
"[a": "up",
|
|
3846
|
-
"[b": "down",
|
|
3847
|
-
"[c": "right",
|
|
3848
|
-
"[d": "left",
|
|
3849
|
-
"[e": "clear",
|
|
3850
|
-
"[2$": "insert",
|
|
3851
|
-
"[3$": "delete",
|
|
3852
|
-
"[5$": "pageup",
|
|
3853
|
-
"[6$": "pagedown",
|
|
3854
|
-
"[7$": "home",
|
|
3855
|
-
"[8$": "end",
|
|
3856
|
-
Oa: "up",
|
|
3857
|
-
Ob: "down",
|
|
3858
|
-
Oc: "right",
|
|
3859
|
-
Od: "left",
|
|
3860
|
-
Oe: "clear",
|
|
3861
|
-
"[2^": "insert",
|
|
3862
|
-
"[3^": "delete",
|
|
3863
|
-
"[5^": "pageup",
|
|
3864
|
-
"[6^": "pagedown",
|
|
3865
|
-
"[7^": "home",
|
|
3866
|
-
"[8^": "end",
|
|
3867
|
-
"[Z": "tab"
|
|
3868
|
-
};
|
|
3869
|
-
const nonAlphanumericKeys = [...Object.values(keyName), "backspace"];
|
|
3870
|
-
const isShiftKey = (code) => {
|
|
3871
|
-
return [
|
|
3872
|
-
"[a",
|
|
3873
|
-
"[b",
|
|
3874
|
-
"[c",
|
|
3875
|
-
"[d",
|
|
3876
|
-
"[e",
|
|
3877
|
-
"[2$",
|
|
3878
|
-
"[3$",
|
|
3879
|
-
"[5$",
|
|
3880
|
-
"[6$",
|
|
3881
|
-
"[7$",
|
|
3882
|
-
"[8$",
|
|
3883
|
-
"[Z"
|
|
3884
|
-
].includes(code);
|
|
3885
|
-
};
|
|
3886
|
-
const isCtrlKey = (code) => {
|
|
3887
|
-
return [
|
|
3888
|
-
"Oa",
|
|
3889
|
-
"Ob",
|
|
3890
|
-
"Oc",
|
|
3891
|
-
"Od",
|
|
3892
|
-
"Oe",
|
|
3893
|
-
"[2^",
|
|
3894
|
-
"[3^",
|
|
3895
|
-
"[5^",
|
|
3896
|
-
"[6^",
|
|
3897
|
-
"[7^",
|
|
3898
|
-
"[8^"
|
|
3899
|
-
].includes(code);
|
|
3900
|
-
};
|
|
3901
|
-
const kittyKeyRe = /^\x1b\[(\d+)(?:;(\d+)(?::(\d+))?(?:;([\d:]+))?)?u$/;
|
|
3902
|
-
const kittySpecialKeyRe = /^\x1b\[(\d+);(\d+):(\d+)([A-Za-z~])$/;
|
|
3903
|
-
const kittySpecialLetterKeys = {
|
|
3904
|
-
A: "up",
|
|
3905
|
-
B: "down",
|
|
3906
|
-
C: "right",
|
|
3907
|
-
D: "left",
|
|
3908
|
-
E: "clear",
|
|
3909
|
-
F: "end",
|
|
3910
|
-
H: "home",
|
|
3911
|
-
P: "f1",
|
|
3912
|
-
Q: "f2",
|
|
3913
|
-
R: "f3",
|
|
3914
|
-
S: "f4"
|
|
3915
|
-
};
|
|
3916
|
-
const kittySpecialNumberKeys = {
|
|
3917
|
-
2: "insert",
|
|
3918
|
-
3: "delete",
|
|
3919
|
-
5: "pageup",
|
|
3920
|
-
6: "pagedown",
|
|
3921
|
-
7: "home",
|
|
3922
|
-
8: "end",
|
|
3923
|
-
11: "f1",
|
|
3924
|
-
12: "f2",
|
|
3925
|
-
13: "f3",
|
|
3926
|
-
14: "f4",
|
|
3927
|
-
15: "f5",
|
|
3928
|
-
17: "f6",
|
|
3929
|
-
18: "f7",
|
|
3930
|
-
19: "f8",
|
|
3931
|
-
20: "f9",
|
|
3932
|
-
21: "f10",
|
|
3933
|
-
23: "f11",
|
|
3934
|
-
24: "f12"
|
|
3935
|
-
};
|
|
3936
|
-
const kittyCodepointNames = {
|
|
3937
|
-
27: "escape",
|
|
3938
|
-
9: "tab",
|
|
3939
|
-
127: "backspace",
|
|
3940
|
-
8: "backspace",
|
|
3941
|
-
57358: "capslock",
|
|
3942
|
-
57359: "scrolllock",
|
|
3943
|
-
57360: "numlock",
|
|
3944
|
-
57361: "printscreen",
|
|
3945
|
-
57362: "pause",
|
|
3946
|
-
57363: "menu",
|
|
3947
|
-
57376: "f13",
|
|
3948
|
-
57377: "f14",
|
|
3949
|
-
57378: "f15",
|
|
3950
|
-
57379: "f16",
|
|
3951
|
-
57380: "f17",
|
|
3952
|
-
57381: "f18",
|
|
3953
|
-
57382: "f19",
|
|
3954
|
-
57383: "f20",
|
|
3955
|
-
57384: "f21",
|
|
3956
|
-
57385: "f22",
|
|
3957
|
-
57386: "f23",
|
|
3958
|
-
57387: "f24",
|
|
3959
|
-
57388: "f25",
|
|
3960
|
-
57389: "f26",
|
|
3961
|
-
57390: "f27",
|
|
3962
|
-
57391: "f28",
|
|
3963
|
-
57392: "f29",
|
|
3964
|
-
57393: "f30",
|
|
3965
|
-
57394: "f31",
|
|
3966
|
-
57395: "f32",
|
|
3967
|
-
57396: "f33",
|
|
3968
|
-
57397: "f34",
|
|
3969
|
-
57398: "f35",
|
|
3970
|
-
57399: "kp0",
|
|
3971
|
-
57400: "kp1",
|
|
3972
|
-
57401: "kp2",
|
|
3973
|
-
57402: "kp3",
|
|
3974
|
-
57403: "kp4",
|
|
3975
|
-
57404: "kp5",
|
|
3976
|
-
57405: "kp6",
|
|
3977
|
-
57406: "kp7",
|
|
3978
|
-
57407: "kp8",
|
|
3979
|
-
57408: "kp9",
|
|
3980
|
-
57409: "kpdecimal",
|
|
3981
|
-
57410: "kpdivide",
|
|
3982
|
-
57411: "kpmultiply",
|
|
3983
|
-
57412: "kpsubtract",
|
|
3984
|
-
57413: "kpadd",
|
|
3985
|
-
57414: "kpenter",
|
|
3986
|
-
57415: "kpequal",
|
|
3987
|
-
57416: "kpseparator",
|
|
3988
|
-
57417: "kpleft",
|
|
3989
|
-
57418: "kpright",
|
|
3990
|
-
57419: "kpup",
|
|
3991
|
-
57420: "kpdown",
|
|
3992
|
-
57421: "kppageup",
|
|
3993
|
-
57422: "kppagedown",
|
|
3994
|
-
57423: "kphome",
|
|
3995
|
-
57424: "kpend",
|
|
3996
|
-
57425: "kpinsert",
|
|
3997
|
-
57426: "kpdelete",
|
|
3998
|
-
57427: "kpbegin",
|
|
3999
|
-
57428: "mediaplay",
|
|
4000
|
-
57429: "mediapause",
|
|
4001
|
-
57430: "mediaplaypause",
|
|
4002
|
-
57431: "mediareverse",
|
|
4003
|
-
57432: "mediastop",
|
|
4004
|
-
57433: "mediafastforward",
|
|
4005
|
-
57434: "mediarewind",
|
|
4006
|
-
57435: "mediatracknext",
|
|
4007
|
-
57436: "mediatrackprevious",
|
|
4008
|
-
57437: "mediarecord",
|
|
4009
|
-
57438: "lowervolume",
|
|
4010
|
-
57439: "raisevolume",
|
|
4011
|
-
57440: "mutevolume",
|
|
4012
|
-
57441: "leftshift",
|
|
4013
|
-
57442: "leftcontrol",
|
|
4014
|
-
57443: "leftalt",
|
|
4015
|
-
57444: "leftsuper",
|
|
4016
|
-
57445: "lefthyper",
|
|
4017
|
-
57446: "leftmeta",
|
|
4018
|
-
57447: "rightshift",
|
|
4019
|
-
57448: "rightcontrol",
|
|
4020
|
-
57449: "rightalt",
|
|
4021
|
-
57450: "rightsuper",
|
|
4022
|
-
57451: "righthyper",
|
|
4023
|
-
57452: "rightmeta",
|
|
4024
|
-
57453: "isoLevel3Shift",
|
|
4025
|
-
57454: "isoLevel5Shift"
|
|
4026
|
-
};
|
|
4027
|
-
const isValidCodepoint = (cp) => cp >= 0 && cp <= 1114111 && !(cp >= 55296 && cp <= 57343);
|
|
4028
|
-
const safeFromCodePoint = (cp) => isValidCodepoint(cp) ? String.fromCodePoint(cp) : "?";
|
|
4029
|
-
function resolveEventType(value) {
|
|
4030
|
-
if (value === 3) return "release";
|
|
4031
|
-
if (value === 2) return "repeat";
|
|
4032
|
-
return "press";
|
|
4033
|
-
}
|
|
4034
|
-
function parseKittyModifiers(modifiers) {
|
|
4035
|
-
return {
|
|
4036
|
-
ctrl: !!(modifiers & kittyModifiers.ctrl),
|
|
4037
|
-
shift: !!(modifiers & kittyModifiers.shift),
|
|
4038
|
-
meta: !!(modifiers & (kittyModifiers.meta | kittyModifiers.alt)),
|
|
4039
|
-
super: !!(modifiers & kittyModifiers.super),
|
|
4040
|
-
hyper: !!(modifiers & kittyModifiers.hyper),
|
|
4041
|
-
capsLock: !!(modifiers & kittyModifiers.capsLock),
|
|
4042
|
-
numLock: !!(modifiers & kittyModifiers.numLock)
|
|
4043
|
-
};
|
|
4044
|
-
}
|
|
4045
|
-
const parseKittyKeypress = (s) => {
|
|
4046
|
-
const match = kittyKeyRe.exec(s);
|
|
4047
|
-
if (!match) return null;
|
|
4048
|
-
const codepoint = parseInt(match[1], 10);
|
|
4049
|
-
const modifiers = match[2] ? Math.max(0, parseInt(match[2], 10) - 1) : 0;
|
|
4050
|
-
const eventType = match[3] ? parseInt(match[3], 10) : 1;
|
|
4051
|
-
const textField = match[4];
|
|
4052
|
-
if (!isValidCodepoint(codepoint)) return null;
|
|
4053
|
-
let text;
|
|
4054
|
-
if (textField) text = textField.split(":").map((cp) => safeFromCodePoint(parseInt(cp, 10))).join("");
|
|
4055
|
-
let name;
|
|
4056
|
-
let isPrintable;
|
|
4057
|
-
if (codepoint === 32) {
|
|
4058
|
-
name = "space";
|
|
4059
|
-
isPrintable = true;
|
|
4060
|
-
} else if (codepoint === 13) {
|
|
4061
|
-
name = "return";
|
|
4062
|
-
isPrintable = true;
|
|
4063
|
-
} else if (kittyCodepointNames[codepoint]) {
|
|
4064
|
-
name = kittyCodepointNames[codepoint];
|
|
4065
|
-
isPrintable = false;
|
|
4066
|
-
} else if (codepoint >= 1 && codepoint <= 26) {
|
|
4067
|
-
name = String.fromCodePoint(codepoint + 96);
|
|
4068
|
-
isPrintable = false;
|
|
4069
|
-
} else {
|
|
4070
|
-
name = safeFromCodePoint(codepoint).toLowerCase();
|
|
4071
|
-
isPrintable = true;
|
|
4072
|
-
}
|
|
4073
|
-
if (isPrintable && !text) text = safeFromCodePoint(codepoint);
|
|
4074
|
-
return {
|
|
4075
|
-
name,
|
|
4076
|
-
...parseKittyModifiers(modifiers),
|
|
4077
|
-
eventType: resolveEventType(eventType),
|
|
4078
|
-
sequence: s,
|
|
4079
|
-
raw: s,
|
|
4080
|
-
isKittyProtocol: true,
|
|
4081
|
-
isPrintable,
|
|
4082
|
-
text
|
|
4083
|
-
};
|
|
4084
|
-
};
|
|
4085
|
-
const parseKittySpecialKey = (s) => {
|
|
4086
|
-
const match = kittySpecialKeyRe.exec(s);
|
|
4087
|
-
if (!match) return null;
|
|
4088
|
-
const number = parseInt(match[1], 10);
|
|
4089
|
-
const modifiers = Math.max(0, parseInt(match[2], 10) - 1);
|
|
4090
|
-
const eventType = parseInt(match[3], 10);
|
|
4091
|
-
const terminator = match[4];
|
|
4092
|
-
const name = terminator === "~" ? kittySpecialNumberKeys[number] : kittySpecialLetterKeys[terminator];
|
|
4093
|
-
if (!name) return null;
|
|
4094
|
-
return {
|
|
4095
|
-
name,
|
|
4096
|
-
...parseKittyModifiers(modifiers),
|
|
4097
|
-
eventType: resolveEventType(eventType),
|
|
4098
|
-
sequence: s,
|
|
4099
|
-
raw: s,
|
|
4100
|
-
isKittyProtocol: true,
|
|
4101
|
-
isPrintable: false
|
|
4102
|
-
};
|
|
4103
|
-
};
|
|
4104
|
-
const parseKeypress = (s = "") => {
|
|
4105
|
-
let parts;
|
|
4106
|
-
if (s instanceof Uint8Array) {
|
|
4107
|
-
if (s[0] > 127 && s[1] === void 0) {
|
|
4108
|
-
s[0] -= 128;
|
|
4109
|
-
s = "\x1B" + textDecoder.decode(s);
|
|
4110
|
-
} else s = textDecoder.decode(s);
|
|
4111
|
-
} else if (s !== void 0 && typeof s !== "string") s = String(s);
|
|
4112
|
-
else if (!s) s = "";
|
|
4113
|
-
const kittyResult = parseKittyKeypress(s);
|
|
4114
|
-
if (kittyResult) return kittyResult;
|
|
4115
|
-
const kittySpecialResult = parseKittySpecialKey(s);
|
|
4116
|
-
if (kittySpecialResult) return kittySpecialResult;
|
|
4117
|
-
if (kittyKeyRe.test(s)) return {
|
|
4118
|
-
name: "",
|
|
4119
|
-
ctrl: false,
|
|
4120
|
-
meta: false,
|
|
4121
|
-
shift: false,
|
|
4122
|
-
sequence: s,
|
|
4123
|
-
raw: s,
|
|
4124
|
-
isKittyProtocol: true,
|
|
4125
|
-
isPrintable: false
|
|
4126
|
-
};
|
|
4127
|
-
const key = {
|
|
4128
|
-
name: "",
|
|
4129
|
-
ctrl: false,
|
|
4130
|
-
meta: false,
|
|
4131
|
-
shift: false,
|
|
4132
|
-
sequence: s,
|
|
4133
|
-
raw: s
|
|
4134
|
-
};
|
|
4135
|
-
key.sequence = key.sequence || s || key.name;
|
|
4136
|
-
if (s === "\r" || s === "\x1B\r") {
|
|
4137
|
-
key.raw = void 0;
|
|
4138
|
-
key.name = "return";
|
|
4139
|
-
key.meta = s.length === 2;
|
|
4140
|
-
} else if (s === "\n") key.name = "enter";
|
|
4141
|
-
else if (s === " ") key.name = "tab";
|
|
4142
|
-
else if (s === "\b" || s === "\x1B\b") {
|
|
4143
|
-
key.name = "backspace";
|
|
4144
|
-
key.meta = s.charAt(0) === "\x1B";
|
|
4145
|
-
} else if (s === "" || s === "\x1B") {
|
|
4146
|
-
key.name = "backspace";
|
|
4147
|
-
key.meta = s.charAt(0) === "\x1B";
|
|
4148
|
-
} else if (s === "\x1B" || s === "\x1B\x1B") {
|
|
4149
|
-
key.name = "escape";
|
|
4150
|
-
key.meta = s.length === 2;
|
|
4151
|
-
} else if (s === " " || s === "\x1B ") {
|
|
4152
|
-
key.name = "space";
|
|
4153
|
-
key.meta = s.length === 2;
|
|
4154
|
-
} else if (s.length === 1 && s <= "") {
|
|
4155
|
-
key.name = String.fromCharCode(s.charCodeAt(0) + "a".charCodeAt(0) - 1);
|
|
4156
|
-
key.ctrl = true;
|
|
4157
|
-
} else if (s.length === 1 && s >= "0" && s <= "9") key.name = "number";
|
|
4158
|
-
else if (s.length === 1 && s >= "a" && s <= "z") key.name = s;
|
|
4159
|
-
else if (s.length === 1 && s >= "A" && s <= "Z") {
|
|
4160
|
-
key.name = s.toLowerCase();
|
|
4161
|
-
key.shift = true;
|
|
4162
|
-
} else if (parts = metaKeyCodeRe.exec(s)) {
|
|
4163
|
-
key.name = parts[1].toLowerCase();
|
|
4164
|
-
key.meta = true;
|
|
4165
|
-
key.shift = /^[A-Z]$/.test(parts[1]);
|
|
4166
|
-
} else if (parts = fnKeyRe.exec(s)) {
|
|
4167
|
-
const segs = [...s];
|
|
4168
|
-
if (segs[0] === "\x1B" && segs[1] === "\x1B") key.meta = true;
|
|
4169
|
-
const code = [
|
|
4170
|
-
parts[1],
|
|
4171
|
-
parts[2],
|
|
4172
|
-
parts[4],
|
|
4173
|
-
parts[6]
|
|
4174
|
-
].filter(Boolean).join("");
|
|
4175
|
-
const modifier = (parts[3] || parts[5] || 1) - 1;
|
|
4176
|
-
key.ctrl = !!(modifier & 4);
|
|
4177
|
-
key.meta = key.meta || !!(modifier & 10);
|
|
4178
|
-
key.shift = !!(modifier & 1);
|
|
4179
|
-
key.code = code;
|
|
4180
|
-
key.name = keyName[code] ?? "";
|
|
4181
|
-
key.shift = isShiftKey(code) || key.shift;
|
|
4182
|
-
key.ctrl = isCtrlKey(code) || key.ctrl;
|
|
4183
|
-
}
|
|
4184
|
-
return key;
|
|
4185
|
-
};
|
|
4186
|
-
//#endregion
|
|
4187
|
-
//#region src/hooks/use-stdin.ts
|
|
2586
|
+
//#region src/hooks/use-capabilities.ts
|
|
4188
2587
|
/**
|
|
4189
|
-
|
|
2588
|
+
Returns everything knowable about the terminal: size, identity, platform,
|
|
2589
|
+
color depth, theme, and feature support.
|
|
2590
|
+
|
|
2591
|
+
A thin wrapper over the framework-free capabilities store (`getCapabilities`):
|
|
2592
|
+
environment-derived facts are available immediately; facts only the terminal
|
|
2593
|
+
itself can answer fill in after a lazy one-time query, and re-mounting
|
|
2594
|
+
consumers refreshes the dynamic facts (theme colors, pixel geometry).
|
|
2595
|
+
Re-renders on terminal resize and whenever query answers arrive.
|
|
4190
2596
|
*/
|
|
4191
|
-
const
|
|
4192
|
-
const
|
|
4193
|
-
|
|
4194
|
-
|
|
2597
|
+
const useCapabilities = () => {
|
|
2598
|
+
const { stdout } = useStdout();
|
|
2599
|
+
const { stdin } = useStdinContext();
|
|
2600
|
+
const store = getCapabilities(stdin, stdout);
|
|
2601
|
+
const capabilities = useSyncExternalStore(store.subscribe, () => store.current);
|
|
2602
|
+
useEffect(() => {
|
|
2603
|
+
store.query();
|
|
2604
|
+
}, [store]);
|
|
2605
|
+
return capabilities;
|
|
2606
|
+
};
|
|
4195
2607
|
/**
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
import {useInput} from 'ink';
|
|
2608
|
+
Calls `onChange` whenever the terminal changes: resizes (including in-band
|
|
2609
|
+
pixel geometry), color scheme switches, window focus, and query answers
|
|
2610
|
+
arriving. The React wrapper over `capabilities.subscribe()` for side effects —
|
|
2611
|
+
for rendering, use `useCapabilities` instead.
|
|
4201
2612
|
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
// Exit program
|
|
4206
|
-
}
|
|
2613
|
+
The callback always sees the latest render's closure and changing it does not
|
|
2614
|
+
resubscribe. Both the new and previous snapshot are passed, so handlers can
|
|
2615
|
+
react to the specific change:
|
|
4207
2616
|
|
|
4208
|
-
|
|
4209
|
-
|
|
2617
|
+
```tsx
|
|
2618
|
+
useCapabilitiesChange((next, previous) => {
|
|
2619
|
+
if (next.theme.appearance !== previous.theme.appearance) {
|
|
2620
|
+
// re-theme
|
|
4210
2621
|
}
|
|
4211
2622
|
});
|
|
4212
|
-
|
|
4213
|
-
return …
|
|
4214
|
-
};
|
|
4215
2623
|
```
|
|
4216
2624
|
*/
|
|
4217
|
-
const
|
|
4218
|
-
const {
|
|
2625
|
+
const useCapabilitiesChange = (onChange) => {
|
|
2626
|
+
const { stdout } = useStdout();
|
|
2627
|
+
const { stdin } = useStdinContext();
|
|
2628
|
+
const store = getCapabilities(stdin, stdout);
|
|
2629
|
+
const handleChange = useEffectEvent(onChange);
|
|
4219
2630
|
useEffect(() => {
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
}, [options.isActive, setRawMode]);
|
|
4226
|
-
const handleData = useEffectEvent((data) => {
|
|
4227
|
-
const keypress = parseKeypress(data);
|
|
4228
|
-
const key = {
|
|
4229
|
-
upArrow: keypress.name === "up",
|
|
4230
|
-
downArrow: keypress.name === "down",
|
|
4231
|
-
leftArrow: keypress.name === "left",
|
|
4232
|
-
rightArrow: keypress.name === "right",
|
|
4233
|
-
pageDown: keypress.name === "pagedown",
|
|
4234
|
-
pageUp: keypress.name === "pageup",
|
|
4235
|
-
home: keypress.name === "home",
|
|
4236
|
-
end: keypress.name === "end",
|
|
4237
|
-
return: keypress.name === "return",
|
|
4238
|
-
escape: keypress.name === "escape",
|
|
4239
|
-
ctrl: keypress.ctrl,
|
|
4240
|
-
shift: keypress.shift,
|
|
4241
|
-
tab: keypress.name === "tab",
|
|
4242
|
-
backspace: keypress.name === "backspace",
|
|
4243
|
-
delete: keypress.name === "delete",
|
|
4244
|
-
meta: keypress.meta,
|
|
4245
|
-
super: keypress.super ?? false,
|
|
4246
|
-
hyper: keypress.hyper ?? false,
|
|
4247
|
-
capsLock: keypress.capsLock ?? false,
|
|
4248
|
-
numLock: keypress.numLock ?? false,
|
|
4249
|
-
eventType: keypress.eventType
|
|
4250
|
-
};
|
|
4251
|
-
let input;
|
|
4252
|
-
if (keypress.isKittyProtocol) {
|
|
4253
|
-
if (keypress.isPrintable) input = keypress.text ?? keypress.name;
|
|
4254
|
-
else if (keypress.ctrl && keypress.name.length === 1) input = keypress.name;
|
|
4255
|
-
else input = "";
|
|
4256
|
-
} else if (keypress.ctrl) input = keypress.name ?? "";
|
|
4257
|
-
else input = keypress.sequence;
|
|
4258
|
-
if (!keypress.isKittyProtocol && nonAlphanumericKeys.includes(keypress.name)) input = "";
|
|
4259
|
-
if (input.startsWith("\x1B")) input = input.slice(1);
|
|
4260
|
-
if (input.length === 1 && /[A-Z]/.test(input)) key.shift = true;
|
|
4261
|
-
if (input === "c" && key.ctrl && internal_exitOnCtrlC) return;
|
|
4262
|
-
reconciler.discreteUpdates(() => {
|
|
4263
|
-
inputHandler(input, key);
|
|
2631
|
+
let previous = store.current;
|
|
2632
|
+
const unsubscribe = store.subscribe((next) => {
|
|
2633
|
+
const before = previous;
|
|
2634
|
+
previous = next;
|
|
2635
|
+
handleChange(next, before);
|
|
4264
2636
|
});
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
internal_eventEmitter.on("input", handleData);
|
|
4269
|
-
return () => {
|
|
4270
|
-
internal_eventEmitter.removeListener("input", handleData);
|
|
4271
|
-
};
|
|
4272
|
-
}, [options.isActive, internal_eventEmitter]);
|
|
2637
|
+
store.query();
|
|
2638
|
+
return unsubscribe;
|
|
2639
|
+
}, [store]);
|
|
4273
2640
|
};
|
|
4274
2641
|
//#endregion
|
|
4275
2642
|
//#region src/hooks/use-paste.ts
|
|
@@ -4333,66 +2700,12 @@ A React hook that returns app lifecycle methods like `exit()` and `waitUntilRend
|
|
|
4333
2700
|
*/
|
|
4334
2701
|
const useApp = () => useContext(AppContext);
|
|
4335
2702
|
//#endregion
|
|
4336
|
-
//#region src/hooks/use-stdout.ts
|
|
4337
|
-
/**
|
|
4338
|
-
A React hook that returns the stdout stream where Ink renders your app.
|
|
4339
|
-
*/
|
|
4340
|
-
const useStdout = () => useContext(StdoutContext);
|
|
4341
|
-
//#endregion
|
|
4342
2703
|
//#region src/hooks/use-stderr.ts
|
|
4343
2704
|
/**
|
|
4344
2705
|
A React hook that returns the stderr stream.
|
|
4345
2706
|
*/
|
|
4346
2707
|
const useStderr = () => useContext(StderrContext);
|
|
4347
2708
|
//#endregion
|
|
4348
|
-
//#region src/hooks/use-focus.ts
|
|
4349
|
-
/**
|
|
4350
|
-
A React hook that returns focus state and focus controls for the current component.
|
|
4351
|
-
A component that uses the `useFocus` hook becomes "focusable" to Ink, so when the user presses <kbd>Tab</kbd>, Ink will switch focus to this component. If there are multiple components that execute the `useFocus` hook, focus will be given to them in the order in which these components are rendered.
|
|
4352
|
-
*/
|
|
4353
|
-
const useFocus = ({ isActive = true, autoFocus = false, id: customId } = {}) => {
|
|
4354
|
-
const { isRawModeSupported, setRawMode } = useStdin();
|
|
4355
|
-
const { activeId, add, remove, activate, deactivate, focus } = useContext(FocusContext);
|
|
4356
|
-
const id = useMemo(() => {
|
|
4357
|
-
return customId ?? Math.random().toString().slice(2, 7);
|
|
4358
|
-
}, [customId]);
|
|
4359
|
-
useEffect(() => {
|
|
4360
|
-
add(id, { autoFocus });
|
|
4361
|
-
return () => {
|
|
4362
|
-
remove(id);
|
|
4363
|
-
};
|
|
4364
|
-
}, [
|
|
4365
|
-
id,
|
|
4366
|
-
autoFocus,
|
|
4367
|
-
add,
|
|
4368
|
-
remove
|
|
4369
|
-
]);
|
|
4370
|
-
useEffect(() => {
|
|
4371
|
-
if (isActive) activate(id);
|
|
4372
|
-
else deactivate(id);
|
|
4373
|
-
}, [
|
|
4374
|
-
isActive,
|
|
4375
|
-
id,
|
|
4376
|
-
activate,
|
|
4377
|
-
deactivate
|
|
4378
|
-
]);
|
|
4379
|
-
useEffect(() => {
|
|
4380
|
-
if (!isRawModeSupported || !isActive) return;
|
|
4381
|
-
setRawMode(true);
|
|
4382
|
-
return () => {
|
|
4383
|
-
setRawMode(false);
|
|
4384
|
-
};
|
|
4385
|
-
}, [
|
|
4386
|
-
isActive,
|
|
4387
|
-
isRawModeSupported,
|
|
4388
|
-
setRawMode
|
|
4389
|
-
]);
|
|
4390
|
-
return {
|
|
4391
|
-
isFocused: Boolean(id) && activeId === id,
|
|
4392
|
-
focus
|
|
4393
|
-
};
|
|
4394
|
-
};
|
|
4395
|
-
//#endregion
|
|
4396
2709
|
//#region src/hooks/use-focus-manager.ts
|
|
4397
2710
|
/**
|
|
4398
2711
|
A React hook that returns methods to enable or disable focus management for all components or manually switch focus to the next or previous components.
|
|
@@ -4535,6 +2848,54 @@ function normalizeAnimationInterval(interval) {
|
|
|
4535
2848
|
return Math.min(maximumTimerInterval, Math.max(1, interval));
|
|
4536
2849
|
}
|
|
4537
2850
|
//#endregion
|
|
2851
|
+
//#region src/hooks/use-terminal-osc.ts
|
|
2852
|
+
const useProgress = ({ state, value }) => {
|
|
2853
|
+
const terminal = useContext(TerminalOscContext);
|
|
2854
|
+
const owner = useRef(void 0);
|
|
2855
|
+
owner.current ??= Symbol("terminal-progress");
|
|
2856
|
+
useEffect(() => {
|
|
2857
|
+
terminal.publishProgress(owner.current, state, value);
|
|
2858
|
+
}, [
|
|
2859
|
+
state,
|
|
2860
|
+
terminal,
|
|
2861
|
+
value
|
|
2862
|
+
]);
|
|
2863
|
+
useEffect(() => {
|
|
2864
|
+
return () => {
|
|
2865
|
+
terminal.publishProgress(owner.current, "inactive");
|
|
2866
|
+
};
|
|
2867
|
+
}, [terminal]);
|
|
2868
|
+
};
|
|
2869
|
+
const useClipboard = () => {
|
|
2870
|
+
const terminal = useContext(TerminalOscContext);
|
|
2871
|
+
return useCallback((text, selection) => terminal.copyToClipboard(text, selection), [terminal]);
|
|
2872
|
+
};
|
|
2873
|
+
const useTitle = (title) => {
|
|
2874
|
+
const terminal = useContext(TerminalOscContext);
|
|
2875
|
+
const owner = useRef(void 0);
|
|
2876
|
+
owner.current ??= Symbol("terminal-title");
|
|
2877
|
+
useEffect(() => {
|
|
2878
|
+
terminal.publishTitle(owner.current, title);
|
|
2879
|
+
}, [terminal, title]);
|
|
2880
|
+
useEffect(() => () => terminal.publishTitle(owner.current, void 0), [terminal]);
|
|
2881
|
+
};
|
|
2882
|
+
const useWorkingDirectory = (directory) => {
|
|
2883
|
+
const terminal = useContext(TerminalOscContext);
|
|
2884
|
+
useEffect(() => {
|
|
2885
|
+
terminal.setWorkingDirectory(directory);
|
|
2886
|
+
}, [directory, terminal]);
|
|
2887
|
+
};
|
|
2888
|
+
const useNotification = () => {
|
|
2889
|
+
const terminal = useContext(TerminalOscContext);
|
|
2890
|
+
return useCallback((title) => terminal.notify(title), [terminal]);
|
|
2891
|
+
};
|
|
2892
|
+
const usePointerShape = (shape) => {
|
|
2893
|
+
const terminal = useContext(TerminalOscContext);
|
|
2894
|
+
useEffect(() => {
|
|
2895
|
+
terminal.setPointerShape(shape);
|
|
2896
|
+
}, [shape, terminal]);
|
|
2897
|
+
};
|
|
2898
|
+
//#endregion
|
|
4538
2899
|
//#region src/hooks/use-window-size.ts
|
|
4539
2900
|
/**
|
|
4540
2901
|
A React hook that returns the current terminal window dimensions and re-renders the component whenever the terminal is resized.
|
|
@@ -4649,4 +3010,4 @@ const measureElement = (node) => {
|
|
|
4649
3010
|
};
|
|
4650
3011
|
};
|
|
4651
3012
|
//#endregion
|
|
4652
|
-
export { Box, Newline, Spacer, Static, Text, Transform, kittyFlags, kittyModifiers, measureElement, render, renderToString, useAnimation, useApp, useBoxMetrics, useCursor, useFocus, useFocusManager, useInput, useIsScreenReaderEnabled, usePaste, useStderr, useStdin, useStdout, useWindowSize };
|
|
3013
|
+
export { AnsiText, Box, Hyperlink, Newline, Spacer, Static, Text, Transform, applyTerminalQuery, capabilities, createSupportsColor, detectCapabilities, detectColorLevel, detectHyperlinkSupport, detectTerminal, detectUnicodeSupport, getCapabilities, getTerminalQuery, kittyFlags, kittyModifiers, measureElement, queryTerminal, refreshTerminalQuery, render, renderToString, useAnimation, useApp, useBoxMetrics, useCapabilities, useCapabilitiesChange, useClipboard, useCursor, useFocus, useFocusManager, useInput, useIsScreenReaderEnabled, useNotification, usePaste, usePointerShape, useProgress, useStderr, useStdin, useStdout, useTitle, useWindowSize, useWorkingDirectory };
|