@opentui/core 0.1.24 → 0.1.26
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/3d.js +1 -1
- package/README.md +5 -1
- package/Renderable.d.ts +18 -8
- package/animation/Timeline.d.ts +2 -1
- package/ansi.d.ts +2 -17
- package/assets/javascript/highlights.scm +205 -0
- package/assets/javascript/tree-sitter-javascript.wasm +0 -0
- package/assets/typescript/highlights.scm +604 -0
- package/assets/typescript/tree-sitter-typescript.wasm +0 -0
- package/{index-0yx9rnxg.js → index-pxa2sv92.js} +1798 -258
- package/index-pxa2sv92.js.map +52 -0
- package/index.js +449 -246
- package/index.js.map +15 -13
- package/lib/KeyHandler.d.ts +51 -9
- package/lib/data-paths.d.ts +26 -0
- package/lib/debounce.d.ts +42 -0
- package/lib/env.d.ts +42 -0
- package/lib/hast-styled-text.d.ts +3 -23
- package/lib/index.d.ts +6 -0
- package/lib/parse.keypress.d.ts +2 -2
- package/lib/queue.d.ts +15 -0
- package/lib/scroll-acceleration.d.ts +43 -0
- package/{singleton.d.ts → lib/singleton.d.ts} +2 -0
- package/lib/styled-text.d.ts +0 -15
- package/lib/syntax-style.d.ts +36 -0
- package/lib/tree-sitter/assets/update.d.ts +11 -0
- package/lib/tree-sitter/client.d.ts +46 -0
- package/lib/tree-sitter/default-parsers.d.ts +2 -0
- package/lib/tree-sitter/download-utils.d.ts +21 -0
- package/lib/tree-sitter/index.d.ts +10 -0
- package/lib/tree-sitter/parser.worker.d.ts +1 -0
- package/lib/tree-sitter/resolve-ft.d.ts +2 -0
- package/lib/tree-sitter/types.d.ts +64 -0
- package/lib/tree-sitter-styled-text.d.ts +7 -0
- package/lib/validate-dir-name.d.ts +1 -0
- package/package.json +21 -8
- package/parser.worker.js +640 -0
- package/parser.worker.js.map +11 -0
- package/renderables/ASCIIFont.d.ts +1 -1
- package/renderables/Code.d.ts +31 -0
- package/renderables/Input.d.ts +4 -4
- package/renderables/ScrollBar.d.ts +2 -2
- package/renderables/ScrollBox.d.ts +7 -3
- package/renderables/Select.d.ts +2 -2
- package/renderables/TabSelect.d.ts +2 -2
- package/renderables/Text.d.ts +11 -65
- package/renderables/TextBufferRenderable.d.ts +81 -0
- package/renderables/TextNode.d.ts +1 -0
- package/renderables/index.d.ts +2 -0
- package/renderer.d.ts +5 -3
- package/testing/mock-keys.d.ts +1 -0
- package/testing/spy.d.ts +7 -0
- package/testing/test-renderer.d.ts +1 -0
- package/testing.d.ts +1 -0
- package/testing.js +31 -6
- package/testing.js.map +6 -5
- package/types.d.ts +2 -1
- package/zig.d.ts +1 -0
- package/index-0yx9rnxg.js.map +0 -38
|
@@ -1763,7 +1763,7 @@ var BorderCharArrays = {
|
|
|
1763
1763
|
};
|
|
1764
1764
|
|
|
1765
1765
|
// src/lib/parse.keypress.ts
|
|
1766
|
-
import { Buffer } from "buffer";
|
|
1766
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
1767
1767
|
|
|
1768
1768
|
// src/lib/parse.keypress-kitty.ts
|
|
1769
1769
|
var kittyKeyMap = {
|
|
@@ -2080,7 +2080,7 @@ var isCtrlKey = (code) => {
|
|
|
2080
2080
|
};
|
|
2081
2081
|
var parseKeypress = (s = "", options = {}) => {
|
|
2082
2082
|
let parts;
|
|
2083
|
-
if (
|
|
2083
|
+
if (Buffer2.isBuffer(s)) {
|
|
2084
2084
|
if (s[0] > 127 && s[1] === undefined) {
|
|
2085
2085
|
s[0] -= 128;
|
|
2086
2086
|
s = "\x1B" + String(s);
|
|
@@ -2143,6 +2143,10 @@ var parseKeypress = (s = "", options = {}) => {
|
|
|
2143
2143
|
key.meta = true;
|
|
2144
2144
|
key.shift = /^[A-Z]$/.test(parts[1]);
|
|
2145
2145
|
key.name = parts[1];
|
|
2146
|
+
} else if (s.length === 2 && s[0] === "\x1B" && s[1] <= "\x1A") {
|
|
2147
|
+
key.meta = true;
|
|
2148
|
+
key.ctrl = true;
|
|
2149
|
+
key.name = String.fromCharCode(s.charCodeAt(1) + 97 - 1);
|
|
2146
2150
|
} else if (parts = fnKeyRe.exec(s)) {
|
|
2147
2151
|
const segs = [...s];
|
|
2148
2152
|
if (segs[0] === "\x1B" && segs[1] === "\x1B") {
|
|
@@ -2175,57 +2179,162 @@ var parseKeypress = (s = "", options = {}) => {
|
|
|
2175
2179
|
// src/lib/KeyHandler.ts
|
|
2176
2180
|
import { EventEmitter } from "events";
|
|
2177
2181
|
|
|
2178
|
-
// src/
|
|
2179
|
-
var
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2182
|
+
// src/ansi.ts
|
|
2183
|
+
var ANSI = {
|
|
2184
|
+
switchToAlternateScreen: "\x1B[?1049h",
|
|
2185
|
+
switchToMainScreen: "\x1B[?1049l",
|
|
2186
|
+
reset: "\x1B[0m",
|
|
2187
|
+
scrollDown: (lines) => `\x1B[${lines}T`,
|
|
2188
|
+
scrollUp: (lines) => `\x1B[${lines}S`,
|
|
2189
|
+
moveCursor: (row, col) => `\x1B[${row};${col}H`,
|
|
2190
|
+
moveCursorAndClear: (row, col) => `\x1B[${row};${col}H\x1B[J`,
|
|
2191
|
+
setRgbBackground: (r, g, b) => `\x1B[48;2;${r};${g};${b}m`,
|
|
2192
|
+
resetBackground: "\x1B[49m",
|
|
2193
|
+
bracketedPasteStart: "\x1B[200~",
|
|
2194
|
+
bracketedPasteEnd: "\x1B[201~"
|
|
2195
|
+
};
|
|
2196
|
+
|
|
2197
|
+
// src/lib/KeyHandler.ts
|
|
2198
|
+
class KeyEvent {
|
|
2199
|
+
name;
|
|
2200
|
+
ctrl;
|
|
2201
|
+
meta;
|
|
2202
|
+
shift;
|
|
2203
|
+
option;
|
|
2204
|
+
sequence;
|
|
2205
|
+
number;
|
|
2206
|
+
raw;
|
|
2207
|
+
eventType;
|
|
2208
|
+
code;
|
|
2209
|
+
super;
|
|
2210
|
+
hyper;
|
|
2211
|
+
capsLock;
|
|
2212
|
+
numLock;
|
|
2213
|
+
baseCode;
|
|
2214
|
+
_defaultPrevented = false;
|
|
2215
|
+
constructor(key) {
|
|
2216
|
+
this.name = key.name;
|
|
2217
|
+
this.ctrl = key.ctrl;
|
|
2218
|
+
this.meta = key.meta;
|
|
2219
|
+
this.shift = key.shift;
|
|
2220
|
+
this.option = key.option;
|
|
2221
|
+
this.sequence = key.sequence;
|
|
2222
|
+
this.number = key.number;
|
|
2223
|
+
this.raw = key.raw;
|
|
2224
|
+
this.eventType = key.eventType;
|
|
2225
|
+
this.code = key.code;
|
|
2226
|
+
this.super = key.super;
|
|
2227
|
+
this.hyper = key.hyper;
|
|
2228
|
+
this.capsLock = key.capsLock;
|
|
2229
|
+
this.numLock = key.numLock;
|
|
2230
|
+
this.baseCode = key.baseCode;
|
|
2231
|
+
}
|
|
2232
|
+
get defaultPrevented() {
|
|
2233
|
+
return this._defaultPrevented;
|
|
2234
|
+
}
|
|
2235
|
+
preventDefault() {
|
|
2236
|
+
this._defaultPrevented = true;
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
class PasteEvent {
|
|
2241
|
+
text;
|
|
2242
|
+
_defaultPrevented = false;
|
|
2243
|
+
constructor(text) {
|
|
2244
|
+
this.text = text;
|
|
2245
|
+
}
|
|
2246
|
+
get defaultPrevented() {
|
|
2247
|
+
return this._defaultPrevented;
|
|
2248
|
+
}
|
|
2249
|
+
preventDefault() {
|
|
2250
|
+
this._defaultPrevented = true;
|
|
2184
2251
|
}
|
|
2185
|
-
return bag[key];
|
|
2186
2252
|
}
|
|
2187
2253
|
|
|
2188
|
-
// src/lib/KeyHandler.ts
|
|
2189
2254
|
class KeyHandler extends EventEmitter {
|
|
2190
2255
|
stdin;
|
|
2191
2256
|
useKittyKeyboard;
|
|
2257
|
+
listener;
|
|
2258
|
+
pasteMode = false;
|
|
2259
|
+
pasteBuffer = [];
|
|
2192
2260
|
constructor(stdin, useKittyKeyboard = false) {
|
|
2193
2261
|
super();
|
|
2194
2262
|
this.stdin = stdin || process.stdin;
|
|
2195
2263
|
this.useKittyKeyboard = useKittyKeyboard;
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2264
|
+
this.listener = (key) => {
|
|
2265
|
+
let data = key.toString();
|
|
2266
|
+
if (data.startsWith(ANSI.bracketedPasteStart)) {
|
|
2267
|
+
this.pasteMode = true;
|
|
2268
|
+
}
|
|
2269
|
+
if (this.pasteMode) {
|
|
2270
|
+
this.pasteBuffer.push(Bun.stripANSI(data));
|
|
2271
|
+
if (data.endsWith(ANSI.bracketedPasteEnd)) {
|
|
2272
|
+
this.pasteMode = false;
|
|
2273
|
+
this.emit("paste", new PasteEvent(this.pasteBuffer.join("")));
|
|
2274
|
+
this.pasteBuffer = [];
|
|
2275
|
+
}
|
|
2276
|
+
return;
|
|
2277
|
+
}
|
|
2202
2278
|
const parsedKey = parseKeypress(key, { useKittyKeyboard: this.useKittyKeyboard });
|
|
2203
2279
|
switch (parsedKey.eventType) {
|
|
2204
2280
|
case "press":
|
|
2205
|
-
this.emit("keypress", parsedKey);
|
|
2281
|
+
this.emit("keypress", new KeyEvent(parsedKey));
|
|
2206
2282
|
break;
|
|
2207
2283
|
case "repeat":
|
|
2208
|
-
this.emit("keyrepeat", parsedKey);
|
|
2284
|
+
this.emit("keyrepeat", new KeyEvent(parsedKey));
|
|
2209
2285
|
break;
|
|
2210
2286
|
case "release":
|
|
2211
|
-
this.emit("keyrelease", parsedKey);
|
|
2287
|
+
this.emit("keyrelease", new KeyEvent(parsedKey));
|
|
2212
2288
|
break;
|
|
2213
2289
|
default:
|
|
2214
|
-
this.emit("keypress", parsedKey);
|
|
2290
|
+
this.emit("keypress", new KeyEvent(parsedKey));
|
|
2215
2291
|
break;
|
|
2216
2292
|
}
|
|
2217
|
-
}
|
|
2293
|
+
};
|
|
2294
|
+
this.stdin.on("data", this.listener);
|
|
2218
2295
|
}
|
|
2219
2296
|
destroy() {
|
|
2220
|
-
this.stdin.
|
|
2297
|
+
this.stdin.removeListener("data", this.listener);
|
|
2221
2298
|
}
|
|
2222
2299
|
}
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2300
|
+
|
|
2301
|
+
class InternalKeyHandler extends KeyHandler {
|
|
2302
|
+
renderableHandlers = new Map;
|
|
2303
|
+
constructor(stdin, useKittyKeyboard = false) {
|
|
2304
|
+
super(stdin, useKittyKeyboard);
|
|
2305
|
+
}
|
|
2306
|
+
emit(event, ...args) {
|
|
2307
|
+
return this.emitWithPriority(event, ...args);
|
|
2308
|
+
}
|
|
2309
|
+
emitWithPriority(event, ...args) {
|
|
2310
|
+
const hasGlobalListeners = super.emit(event, ...args);
|
|
2311
|
+
const renderableSet = this.renderableHandlers.get(event);
|
|
2312
|
+
let hasRenderableListeners = false;
|
|
2313
|
+
if (renderableSet && renderableSet.size > 0) {
|
|
2314
|
+
hasRenderableListeners = true;
|
|
2315
|
+
if (event === "keypress" || event === "keyrepeat" || event === "keyrelease" || event === "paste") {
|
|
2316
|
+
const keyEvent = args[0];
|
|
2317
|
+
if (keyEvent.defaultPrevented)
|
|
2318
|
+
return hasGlobalListeners || hasRenderableListeners;
|
|
2319
|
+
}
|
|
2320
|
+
for (const handler of renderableSet) {
|
|
2321
|
+
handler(...args);
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
return hasGlobalListeners || hasRenderableListeners;
|
|
2325
|
+
}
|
|
2326
|
+
onInternal(event, handler) {
|
|
2327
|
+
if (!this.renderableHandlers.has(event)) {
|
|
2328
|
+
this.renderableHandlers.set(event, new Set);
|
|
2329
|
+
}
|
|
2330
|
+
this.renderableHandlers.get(event).add(handler);
|
|
2331
|
+
}
|
|
2332
|
+
offInternal(event, handler) {
|
|
2333
|
+
const handlers = this.renderableHandlers.get(event);
|
|
2334
|
+
if (handlers) {
|
|
2335
|
+
handlers.delete(handler);
|
|
2336
|
+
}
|
|
2227
2337
|
}
|
|
2228
|
-
return keyHandler;
|
|
2229
2338
|
}
|
|
2230
2339
|
|
|
2231
2340
|
// src/lib/RGBA.ts
|
|
@@ -4079,60 +4188,9 @@ function isStyledText(obj) {
|
|
|
4079
4188
|
class StyledText {
|
|
4080
4189
|
[BrandedStyledText] = true;
|
|
4081
4190
|
chunks;
|
|
4082
|
-
textRenderable;
|
|
4083
4191
|
constructor(chunks) {
|
|
4084
4192
|
this.chunks = chunks;
|
|
4085
4193
|
}
|
|
4086
|
-
mount(textRenderable) {
|
|
4087
|
-
this.textRenderable = textRenderable;
|
|
4088
|
-
}
|
|
4089
|
-
insert(chunk, index) {
|
|
4090
|
-
const originalLength = this.chunks.length;
|
|
4091
|
-
if (this.textRenderable) {
|
|
4092
|
-
this.textRenderable.insertChunk(chunk, index ?? originalLength);
|
|
4093
|
-
let newChunks;
|
|
4094
|
-
if (index === undefined || index === originalLength) {
|
|
4095
|
-
newChunks = [...this.chunks, chunk];
|
|
4096
|
-
} else {
|
|
4097
|
-
newChunks = [...this.chunks.slice(0, index), chunk, ...this.chunks.slice(index)];
|
|
4098
|
-
}
|
|
4099
|
-
this.chunks = newChunks;
|
|
4100
|
-
}
|
|
4101
|
-
return this;
|
|
4102
|
-
}
|
|
4103
|
-
remove(chunk) {
|
|
4104
|
-
if (this.textRenderable) {
|
|
4105
|
-
this.textRenderable.removeChunk(chunk);
|
|
4106
|
-
const originalLength = this.chunks.length;
|
|
4107
|
-
const index = this.chunks.indexOf(chunk);
|
|
4108
|
-
if (index === -1)
|
|
4109
|
-
return this;
|
|
4110
|
-
let newChunks;
|
|
4111
|
-
if (index === originalLength - 1) {
|
|
4112
|
-
newChunks = this.chunks.slice(0, -1);
|
|
4113
|
-
} else {
|
|
4114
|
-
newChunks = [...this.chunks.slice(0, index), ...this.chunks.slice(index + 1)];
|
|
4115
|
-
}
|
|
4116
|
-
this.chunks = newChunks;
|
|
4117
|
-
}
|
|
4118
|
-
return this;
|
|
4119
|
-
}
|
|
4120
|
-
replace(chunk, oldChunk) {
|
|
4121
|
-
if (this.textRenderable) {
|
|
4122
|
-
this.textRenderable.replaceChunk(chunk, oldChunk);
|
|
4123
|
-
const index = this.chunks.indexOf(oldChunk);
|
|
4124
|
-
if (index === -1)
|
|
4125
|
-
return this;
|
|
4126
|
-
let newChunks;
|
|
4127
|
-
if (index === this.chunks.length - 1) {
|
|
4128
|
-
newChunks = [...this.chunks.slice(0, -1), chunk];
|
|
4129
|
-
} else {
|
|
4130
|
-
newChunks = [...this.chunks.slice(0, index), chunk, ...this.chunks.slice(index + 1)];
|
|
4131
|
-
}
|
|
4132
|
-
this.chunks = newChunks;
|
|
4133
|
-
}
|
|
4134
|
-
return this;
|
|
4135
|
-
}
|
|
4136
4194
|
}
|
|
4137
4195
|
function stringToStyledText(content) {
|
|
4138
4196
|
const chunk = {
|
|
@@ -4228,7 +4286,36 @@ function t(strings, ...values) {
|
|
|
4228
4286
|
return new StyledText(chunks);
|
|
4229
4287
|
}
|
|
4230
4288
|
|
|
4231
|
-
// src/lib/
|
|
4289
|
+
// src/lib/syntax-style.ts
|
|
4290
|
+
function convertThemeToStyles(theme) {
|
|
4291
|
+
const flatStyles = {};
|
|
4292
|
+
for (const tokenStyle of theme) {
|
|
4293
|
+
const styleDefinition = {};
|
|
4294
|
+
if (tokenStyle.style.foreground) {
|
|
4295
|
+
styleDefinition.fg = parseColor(tokenStyle.style.foreground);
|
|
4296
|
+
}
|
|
4297
|
+
if (tokenStyle.style.background) {
|
|
4298
|
+
styleDefinition.bg = parseColor(tokenStyle.style.background);
|
|
4299
|
+
}
|
|
4300
|
+
if (tokenStyle.style.bold !== undefined) {
|
|
4301
|
+
styleDefinition.bold = tokenStyle.style.bold;
|
|
4302
|
+
}
|
|
4303
|
+
if (tokenStyle.style.italic !== undefined) {
|
|
4304
|
+
styleDefinition.italic = tokenStyle.style.italic;
|
|
4305
|
+
}
|
|
4306
|
+
if (tokenStyle.style.underline !== undefined) {
|
|
4307
|
+
styleDefinition.underline = tokenStyle.style.underline;
|
|
4308
|
+
}
|
|
4309
|
+
if (tokenStyle.style.dim !== undefined) {
|
|
4310
|
+
styleDefinition.dim = tokenStyle.style.dim;
|
|
4311
|
+
}
|
|
4312
|
+
for (const scope of tokenStyle.scope) {
|
|
4313
|
+
flatStyles[scope] = styleDefinition;
|
|
4314
|
+
}
|
|
4315
|
+
}
|
|
4316
|
+
return flatStyles;
|
|
4317
|
+
}
|
|
4318
|
+
|
|
4232
4319
|
class SyntaxStyle {
|
|
4233
4320
|
styles;
|
|
4234
4321
|
mergedStyleCache;
|
|
@@ -4236,6 +4323,10 @@ class SyntaxStyle {
|
|
|
4236
4323
|
this.styles = styles;
|
|
4237
4324
|
this.mergedStyleCache = new Map;
|
|
4238
4325
|
}
|
|
4326
|
+
static fromTheme(theme) {
|
|
4327
|
+
const flatStyles = convertThemeToStyles(theme);
|
|
4328
|
+
return new SyntaxStyle(flatStyles);
|
|
4329
|
+
}
|
|
4239
4330
|
mergeStyles(...styleNames) {
|
|
4240
4331
|
const cacheKey = styleNames.join(":");
|
|
4241
4332
|
const cached = this.mergedStyleCache.get(cacheKey);
|
|
@@ -4243,7 +4334,7 @@ class SyntaxStyle {
|
|
|
4243
4334
|
return cached;
|
|
4244
4335
|
const styleDefinition = {};
|
|
4245
4336
|
for (const name of styleNames) {
|
|
4246
|
-
const style = this.
|
|
4337
|
+
const style = this.getStyle(name);
|
|
4247
4338
|
if (!style)
|
|
4248
4339
|
continue;
|
|
4249
4340
|
if (style.fg)
|
|
@@ -4273,6 +4364,18 @@ class SyntaxStyle {
|
|
|
4273
4364
|
this.mergedStyleCache.set(cacheKey, merged);
|
|
4274
4365
|
return merged;
|
|
4275
4366
|
}
|
|
4367
|
+
getStyle(name) {
|
|
4368
|
+
if (Object.prototype.hasOwnProperty.call(this.styles, name)) {
|
|
4369
|
+
return this.styles[name];
|
|
4370
|
+
}
|
|
4371
|
+
if (name.includes(".")) {
|
|
4372
|
+
const baseName = name.split(".")[0];
|
|
4373
|
+
if (Object.prototype.hasOwnProperty.call(this.styles, baseName)) {
|
|
4374
|
+
return this.styles[baseName];
|
|
4375
|
+
}
|
|
4376
|
+
}
|
|
4377
|
+
return;
|
|
4378
|
+
}
|
|
4276
4379
|
clearCache() {
|
|
4277
4380
|
this.mergedStyleCache.clear();
|
|
4278
4381
|
}
|
|
@@ -4280,6 +4383,8 @@ class SyntaxStyle {
|
|
|
4280
4383
|
return this.mergedStyleCache.size;
|
|
4281
4384
|
}
|
|
4282
4385
|
}
|
|
4386
|
+
|
|
4387
|
+
// src/lib/hast-styled-text.ts
|
|
4283
4388
|
function hastToTextChunks(node, syntaxStyle, parentStyles = []) {
|
|
4284
4389
|
const chunks = [];
|
|
4285
4390
|
if (node.type === "text") {
|
|
@@ -4311,6 +4416,55 @@ function hastToStyledText(hast, syntaxStyle) {
|
|
|
4311
4416
|
return new StyledText(chunks);
|
|
4312
4417
|
}
|
|
4313
4418
|
|
|
4419
|
+
// src/lib/scroll-acceleration.ts
|
|
4420
|
+
class LinearScrollAccel {
|
|
4421
|
+
tick(_now) {
|
|
4422
|
+
return 1;
|
|
4423
|
+
}
|
|
4424
|
+
reset() {}
|
|
4425
|
+
}
|
|
4426
|
+
|
|
4427
|
+
class MacOSScrollAccel {
|
|
4428
|
+
opts;
|
|
4429
|
+
lastTickTime = 0;
|
|
4430
|
+
velocityHistory = [];
|
|
4431
|
+
historySize = 3;
|
|
4432
|
+
streakTimeout = 150;
|
|
4433
|
+
minTickInterval = 6;
|
|
4434
|
+
constructor(opts = {}) {
|
|
4435
|
+
this.opts = opts;
|
|
4436
|
+
}
|
|
4437
|
+
tick(now = Date.now()) {
|
|
4438
|
+
const A = this.opts.A ?? 0.8;
|
|
4439
|
+
const tau = this.opts.tau ?? 3;
|
|
4440
|
+
const maxMultiplier = this.opts.maxMultiplier ?? 6;
|
|
4441
|
+
const dt = this.lastTickTime ? now - this.lastTickTime : Infinity;
|
|
4442
|
+
if (dt === Infinity || dt > this.streakTimeout) {
|
|
4443
|
+
this.lastTickTime = now;
|
|
4444
|
+
this.velocityHistory = [];
|
|
4445
|
+
return 1;
|
|
4446
|
+
}
|
|
4447
|
+
if (dt < this.minTickInterval) {
|
|
4448
|
+
return 1;
|
|
4449
|
+
}
|
|
4450
|
+
this.lastTickTime = now;
|
|
4451
|
+
this.velocityHistory.push(dt);
|
|
4452
|
+
if (this.velocityHistory.length > this.historySize) {
|
|
4453
|
+
this.velocityHistory.shift();
|
|
4454
|
+
}
|
|
4455
|
+
const avgInterval = this.velocityHistory.reduce((a, b) => a + b, 0) / this.velocityHistory.length;
|
|
4456
|
+
const referenceInterval = 100;
|
|
4457
|
+
const velocity = referenceInterval / avgInterval;
|
|
4458
|
+
const x = velocity / tau;
|
|
4459
|
+
const multiplier = 1 + A * (Math.exp(x) - 1);
|
|
4460
|
+
return Math.min(multiplier, maxMultiplier);
|
|
4461
|
+
}
|
|
4462
|
+
reset() {
|
|
4463
|
+
this.lastTickTime = 0;
|
|
4464
|
+
this.velocityHistory = [];
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4467
|
+
|
|
4314
4468
|
// src/lib/yoga.options.ts
|
|
4315
4469
|
function parseAlign(value) {
|
|
4316
4470
|
switch (value.toLowerCase()) {
|
|
@@ -4739,74 +4893,1356 @@ function convertGlobalToLocalSelection(globalSelection, localX, localY) {
|
|
|
4739
4893
|
};
|
|
4740
4894
|
}
|
|
4741
4895
|
|
|
4742
|
-
class ASCIIFontSelectionHelper {
|
|
4743
|
-
getText;
|
|
4744
|
-
getFont;
|
|
4745
|
-
localSelection = null;
|
|
4746
|
-
constructor(getText, getFont) {
|
|
4747
|
-
this.getText = getText;
|
|
4748
|
-
this.getFont = getFont;
|
|
4896
|
+
class ASCIIFontSelectionHelper {
|
|
4897
|
+
getText;
|
|
4898
|
+
getFont;
|
|
4899
|
+
localSelection = null;
|
|
4900
|
+
constructor(getText, getFont) {
|
|
4901
|
+
this.getText = getText;
|
|
4902
|
+
this.getFont = getFont;
|
|
4903
|
+
}
|
|
4904
|
+
hasSelection() {
|
|
4905
|
+
return this.localSelection !== null;
|
|
4906
|
+
}
|
|
4907
|
+
getSelection() {
|
|
4908
|
+
return this.localSelection;
|
|
4909
|
+
}
|
|
4910
|
+
shouldStartSelection(localX, localY, width, height) {
|
|
4911
|
+
if (localX < 0 || localX >= width || localY < 0 || localY >= height) {
|
|
4912
|
+
return false;
|
|
4913
|
+
}
|
|
4914
|
+
const text = this.getText();
|
|
4915
|
+
const font = this.getFont();
|
|
4916
|
+
const charIndex = coordinateToCharacterIndex(localX, text, font);
|
|
4917
|
+
return charIndex >= 0 && charIndex <= text.length;
|
|
4918
|
+
}
|
|
4919
|
+
onLocalSelectionChanged(localSelection, width, height) {
|
|
4920
|
+
const previousSelection = this.localSelection;
|
|
4921
|
+
if (!localSelection?.isActive) {
|
|
4922
|
+
this.localSelection = null;
|
|
4923
|
+
return previousSelection !== null;
|
|
4924
|
+
}
|
|
4925
|
+
const text = this.getText();
|
|
4926
|
+
const font = this.getFont();
|
|
4927
|
+
const selStart = { x: localSelection.anchorX, y: localSelection.anchorY };
|
|
4928
|
+
const selEnd = { x: localSelection.focusX, y: localSelection.focusY };
|
|
4929
|
+
if (height - 1 < selStart.y || 0 > selEnd.y) {
|
|
4930
|
+
this.localSelection = null;
|
|
4931
|
+
return previousSelection !== null;
|
|
4932
|
+
}
|
|
4933
|
+
let startCharIndex = 0;
|
|
4934
|
+
let endCharIndex = text.length;
|
|
4935
|
+
if (selStart.y > height - 1) {
|
|
4936
|
+
this.localSelection = null;
|
|
4937
|
+
return previousSelection !== null;
|
|
4938
|
+
} else if (selStart.y >= 0 && selStart.y <= height - 1) {
|
|
4939
|
+
if (selStart.x > 0) {
|
|
4940
|
+
startCharIndex = coordinateToCharacterIndex(selStart.x, text, font);
|
|
4941
|
+
}
|
|
4942
|
+
}
|
|
4943
|
+
if (selEnd.y < 0) {
|
|
4944
|
+
this.localSelection = null;
|
|
4945
|
+
return previousSelection !== null;
|
|
4946
|
+
} else if (selEnd.y >= 0 && selEnd.y <= height - 1) {
|
|
4947
|
+
if (selEnd.x >= 0) {
|
|
4948
|
+
endCharIndex = coordinateToCharacterIndex(selEnd.x, text, font);
|
|
4949
|
+
} else {
|
|
4950
|
+
endCharIndex = 0;
|
|
4951
|
+
}
|
|
4952
|
+
}
|
|
4953
|
+
if (startCharIndex < endCharIndex && startCharIndex >= 0 && endCharIndex <= text.length) {
|
|
4954
|
+
this.localSelection = { start: startCharIndex, end: endCharIndex };
|
|
4955
|
+
} else {
|
|
4956
|
+
this.localSelection = null;
|
|
4957
|
+
}
|
|
4958
|
+
return previousSelection?.start !== this.localSelection?.start || previousSelection?.end !== this.localSelection?.end;
|
|
4959
|
+
}
|
|
4960
|
+
}
|
|
4961
|
+
|
|
4962
|
+
// src/lib/singleton.ts
|
|
4963
|
+
var singletonCacheSymbol = Symbol.for("@opentui/core/singleton");
|
|
4964
|
+
function singleton(key, factory) {
|
|
4965
|
+
const bag = globalThis[singletonCacheSymbol] ??= {};
|
|
4966
|
+
if (!(key in bag)) {
|
|
4967
|
+
bag[key] = factory();
|
|
4968
|
+
}
|
|
4969
|
+
return bag[key];
|
|
4970
|
+
}
|
|
4971
|
+
function destroySingleton(key) {
|
|
4972
|
+
const bag = globalThis[singletonCacheSymbol];
|
|
4973
|
+
if (bag && key in bag) {
|
|
4974
|
+
delete bag[key];
|
|
4975
|
+
}
|
|
4976
|
+
}
|
|
4977
|
+
function hasSingleton(key) {
|
|
4978
|
+
const bag = globalThis[singletonCacheSymbol];
|
|
4979
|
+
return bag && key in bag;
|
|
4980
|
+
}
|
|
4981
|
+
|
|
4982
|
+
// src/lib/env.ts
|
|
4983
|
+
var envRegistry = singleton("env-registry", () => ({}));
|
|
4984
|
+
function registerEnvVar(config) {
|
|
4985
|
+
const existing = envRegistry[config.name];
|
|
4986
|
+
if (existing) {
|
|
4987
|
+
if (existing.description !== config.description || existing.type !== config.type || existing.default !== config.default) {
|
|
4988
|
+
throw new Error(`Environment variable "${config.name}" is already registered with different configuration. ` + `Existing: ${JSON.stringify(existing)}, New: ${JSON.stringify(config)}`);
|
|
4989
|
+
}
|
|
4990
|
+
return;
|
|
4991
|
+
}
|
|
4992
|
+
envRegistry[config.name] = config;
|
|
4993
|
+
}
|
|
4994
|
+
function normalizeBoolean(value) {
|
|
4995
|
+
const lowerValue = value.toLowerCase();
|
|
4996
|
+
return ["true", "1", "on", "yes"].includes(lowerValue);
|
|
4997
|
+
}
|
|
4998
|
+
function parseEnvValue(config) {
|
|
4999
|
+
const envValue = process.env[config.name];
|
|
5000
|
+
if (envValue === undefined && config.default !== undefined) {
|
|
5001
|
+
return config.default;
|
|
5002
|
+
}
|
|
5003
|
+
if (envValue === undefined) {
|
|
5004
|
+
throw new Error(`Required environment variable ${config.name} is not set. ${config.description}`);
|
|
5005
|
+
}
|
|
5006
|
+
switch (config.type) {
|
|
5007
|
+
case "boolean":
|
|
5008
|
+
return typeof envValue === "boolean" ? envValue : normalizeBoolean(envValue);
|
|
5009
|
+
case "number":
|
|
5010
|
+
const numValue = Number(envValue);
|
|
5011
|
+
if (isNaN(numValue)) {
|
|
5012
|
+
throw new Error(`Environment variable ${config.name} must be a valid number, got: ${envValue}`);
|
|
5013
|
+
}
|
|
5014
|
+
return numValue;
|
|
5015
|
+
case "string":
|
|
5016
|
+
default:
|
|
5017
|
+
return envValue;
|
|
5018
|
+
}
|
|
5019
|
+
}
|
|
5020
|
+
|
|
5021
|
+
class EnvStore {
|
|
5022
|
+
parsedValues = new Map;
|
|
5023
|
+
get(key) {
|
|
5024
|
+
if (this.parsedValues.has(key)) {
|
|
5025
|
+
return this.parsedValues.get(key);
|
|
5026
|
+
}
|
|
5027
|
+
if (!(key in envRegistry)) {
|
|
5028
|
+
throw new Error(`Environment variable ${key} is not registered.`);
|
|
5029
|
+
}
|
|
5030
|
+
try {
|
|
5031
|
+
const value = parseEnvValue(envRegistry[key]);
|
|
5032
|
+
this.parsedValues.set(key, value);
|
|
5033
|
+
return value;
|
|
5034
|
+
} catch (error) {
|
|
5035
|
+
throw new Error(`Failed to parse env var ${key}: ${error instanceof Error ? error.message : String(error)}`);
|
|
5036
|
+
}
|
|
5037
|
+
}
|
|
5038
|
+
has(key) {
|
|
5039
|
+
return key in envRegistry;
|
|
5040
|
+
}
|
|
5041
|
+
clearCache() {
|
|
5042
|
+
this.parsedValues.clear();
|
|
5043
|
+
}
|
|
5044
|
+
}
|
|
5045
|
+
var envStore = singleton("env-store", () => new EnvStore);
|
|
5046
|
+
function clearEnvCache() {
|
|
5047
|
+
envStore.clearCache();
|
|
5048
|
+
}
|
|
5049
|
+
function generateEnvMarkdown() {
|
|
5050
|
+
const configs = Object.values(envRegistry);
|
|
5051
|
+
if (configs.length === 0) {
|
|
5052
|
+
return `# Environment Variables
|
|
5053
|
+
|
|
5054
|
+
No environment variables registered.
|
|
5055
|
+
`;
|
|
5056
|
+
}
|
|
5057
|
+
let markdown = `# Environment Variables
|
|
5058
|
+
|
|
5059
|
+
`;
|
|
5060
|
+
for (const config of configs) {
|
|
5061
|
+
markdown += `## ${config.name}
|
|
5062
|
+
|
|
5063
|
+
`;
|
|
5064
|
+
markdown += `${config.description}
|
|
5065
|
+
|
|
5066
|
+
`;
|
|
5067
|
+
markdown += `**Type:** \`${config.type || "string"}\`
|
|
5068
|
+
`;
|
|
5069
|
+
if (config.default !== undefined) {
|
|
5070
|
+
const defaultValue = typeof config.default === "string" ? `"${config.default}"` : String(config.default);
|
|
5071
|
+
markdown += `**Default:** \`${defaultValue}\`
|
|
5072
|
+
`;
|
|
5073
|
+
} else {
|
|
5074
|
+
markdown += `**Default:** *Required*
|
|
5075
|
+
`;
|
|
5076
|
+
}
|
|
5077
|
+
markdown += `
|
|
5078
|
+
`;
|
|
5079
|
+
}
|
|
5080
|
+
return markdown;
|
|
5081
|
+
}
|
|
5082
|
+
function generateEnvColored() {
|
|
5083
|
+
const configs = Object.values(envRegistry);
|
|
5084
|
+
if (configs.length === 0) {
|
|
5085
|
+
return `\x1B[1;36mEnvironment Variables\x1B[0m
|
|
5086
|
+
|
|
5087
|
+
No environment variables registered.
|
|
5088
|
+
`;
|
|
5089
|
+
}
|
|
5090
|
+
let output = `\x1B[1;36mEnvironment Variables\x1B[0m
|
|
5091
|
+
|
|
5092
|
+
`;
|
|
5093
|
+
for (const config of configs) {
|
|
5094
|
+
output += `\x1B[1;33m${config.name}\x1B[0m
|
|
5095
|
+
`;
|
|
5096
|
+
output += `${config.description}
|
|
5097
|
+
`;
|
|
5098
|
+
output += `\x1B[32mType:\x1B[0m \x1B[36m${config.type || "string"}\x1B[0m
|
|
5099
|
+
`;
|
|
5100
|
+
if (config.default !== undefined) {
|
|
5101
|
+
const defaultValue = typeof config.default === "string" ? `"${config.default}"` : String(config.default);
|
|
5102
|
+
output += `\x1B[32mDefault:\x1B[0m \x1B[35m${defaultValue}\x1B[0m
|
|
5103
|
+
`;
|
|
5104
|
+
} else {
|
|
5105
|
+
output += `\x1B[32mDefault:\x1B[0m \x1B[31mRequired\x1B[0m
|
|
5106
|
+
`;
|
|
5107
|
+
}
|
|
5108
|
+
output += `
|
|
5109
|
+
`;
|
|
5110
|
+
}
|
|
5111
|
+
return output;
|
|
5112
|
+
}
|
|
5113
|
+
var env = new Proxy({}, {
|
|
5114
|
+
get(target, prop) {
|
|
5115
|
+
if (typeof prop !== "string") {
|
|
5116
|
+
return;
|
|
5117
|
+
}
|
|
5118
|
+
return envStore.get(prop);
|
|
5119
|
+
},
|
|
5120
|
+
has(target, prop) {
|
|
5121
|
+
return envStore.has(prop);
|
|
5122
|
+
},
|
|
5123
|
+
ownKeys() {
|
|
5124
|
+
return Object.keys(envRegistry);
|
|
5125
|
+
},
|
|
5126
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
5127
|
+
if (envStore.has(prop)) {
|
|
5128
|
+
return {
|
|
5129
|
+
enumerable: true,
|
|
5130
|
+
configurable: true,
|
|
5131
|
+
get: () => envStore.get(prop)
|
|
5132
|
+
};
|
|
5133
|
+
}
|
|
5134
|
+
return;
|
|
5135
|
+
}
|
|
5136
|
+
});
|
|
5137
|
+
|
|
5138
|
+
// src/lib/tree-sitter-styled-text.ts
|
|
5139
|
+
function treeSitterToTextChunks(content, highlights, syntaxStyle) {
|
|
5140
|
+
const chunks = [];
|
|
5141
|
+
const defaultStyle = syntaxStyle.getStyle("default");
|
|
5142
|
+
let currentIndex = 0;
|
|
5143
|
+
for (let i = 0;i < highlights.length; i++) {
|
|
5144
|
+
const [startIndex, endIndex, group] = highlights[i];
|
|
5145
|
+
if (startIndex < currentIndex)
|
|
5146
|
+
continue;
|
|
5147
|
+
if (currentIndex < startIndex) {
|
|
5148
|
+
const text2 = content.slice(currentIndex, startIndex);
|
|
5149
|
+
chunks.push({
|
|
5150
|
+
__isChunk: true,
|
|
5151
|
+
text: text2,
|
|
5152
|
+
fg: defaultStyle?.fg,
|
|
5153
|
+
bg: defaultStyle?.bg,
|
|
5154
|
+
attributes: defaultStyle ? createTextAttributes({
|
|
5155
|
+
bold: defaultStyle.bold,
|
|
5156
|
+
italic: defaultStyle.italic,
|
|
5157
|
+
underline: defaultStyle.underline,
|
|
5158
|
+
dim: defaultStyle.dim
|
|
5159
|
+
}) : 0
|
|
5160
|
+
});
|
|
5161
|
+
currentIndex = startIndex;
|
|
5162
|
+
}
|
|
5163
|
+
let resolvedStyle = syntaxStyle.getStyle(group);
|
|
5164
|
+
let j = i + 1;
|
|
5165
|
+
while (j < highlights.length && highlights[j][0] === startIndex) {
|
|
5166
|
+
const [, , nextGroup] = highlights[j];
|
|
5167
|
+
const nextStyle = syntaxStyle.getStyle(nextGroup);
|
|
5168
|
+
if (nextStyle) {
|
|
5169
|
+
resolvedStyle = nextStyle;
|
|
5170
|
+
}
|
|
5171
|
+
j++;
|
|
5172
|
+
}
|
|
5173
|
+
i = j - 1;
|
|
5174
|
+
const text = content.slice(startIndex, endIndex);
|
|
5175
|
+
const styleToUse = resolvedStyle || defaultStyle;
|
|
5176
|
+
chunks.push({
|
|
5177
|
+
__isChunk: true,
|
|
5178
|
+
text,
|
|
5179
|
+
fg: styleToUse?.fg,
|
|
5180
|
+
bg: styleToUse?.bg,
|
|
5181
|
+
attributes: styleToUse ? createTextAttributes({
|
|
5182
|
+
bold: styleToUse.bold,
|
|
5183
|
+
italic: styleToUse.italic,
|
|
5184
|
+
underline: styleToUse.underline,
|
|
5185
|
+
dim: styleToUse.dim
|
|
5186
|
+
}) : 0
|
|
5187
|
+
});
|
|
5188
|
+
currentIndex = endIndex;
|
|
5189
|
+
}
|
|
5190
|
+
if (currentIndex < content.length) {
|
|
5191
|
+
const text = content.slice(currentIndex);
|
|
5192
|
+
chunks.push({
|
|
5193
|
+
__isChunk: true,
|
|
5194
|
+
text,
|
|
5195
|
+
fg: defaultStyle?.fg,
|
|
5196
|
+
bg: defaultStyle?.bg,
|
|
5197
|
+
attributes: defaultStyle ? createTextAttributes({
|
|
5198
|
+
bold: defaultStyle.bold,
|
|
5199
|
+
italic: defaultStyle.italic,
|
|
5200
|
+
underline: defaultStyle.underline,
|
|
5201
|
+
dim: defaultStyle.dim
|
|
5202
|
+
}) : 0
|
|
5203
|
+
});
|
|
5204
|
+
}
|
|
5205
|
+
return chunks;
|
|
5206
|
+
}
|
|
5207
|
+
async function treeSitterToStyledText(content, filetype, syntaxStyle, client) {
|
|
5208
|
+
const result = await client.highlightOnce(content, filetype);
|
|
5209
|
+
if (result.highlights && result.highlights.length > 0) {
|
|
5210
|
+
const chunks = treeSitterToTextChunks(content, result.highlights, syntaxStyle);
|
|
5211
|
+
return new StyledText(chunks);
|
|
5212
|
+
} else {
|
|
5213
|
+
const defaultStyle = syntaxStyle.mergeStyles("default");
|
|
5214
|
+
const chunks = [
|
|
5215
|
+
{
|
|
5216
|
+
__isChunk: true,
|
|
5217
|
+
text: content,
|
|
5218
|
+
fg: defaultStyle.fg,
|
|
5219
|
+
bg: defaultStyle.bg,
|
|
5220
|
+
attributes: defaultStyle.attributes
|
|
5221
|
+
}
|
|
5222
|
+
];
|
|
5223
|
+
return new StyledText(chunks);
|
|
5224
|
+
}
|
|
5225
|
+
}
|
|
5226
|
+
|
|
5227
|
+
// src/lib/tree-sitter/client.ts
|
|
5228
|
+
import { EventEmitter as EventEmitter2 } from "events";
|
|
5229
|
+
|
|
5230
|
+
// src/lib/debounce.ts
|
|
5231
|
+
var TIMERS_MAP = new Map;
|
|
5232
|
+
|
|
5233
|
+
class DebounceController {
|
|
5234
|
+
scopeId;
|
|
5235
|
+
constructor(scopeId) {
|
|
5236
|
+
this.scopeId = scopeId;
|
|
5237
|
+
if (!TIMERS_MAP.has(this.scopeId)) {
|
|
5238
|
+
TIMERS_MAP.set(this.scopeId, new Map);
|
|
5239
|
+
}
|
|
5240
|
+
}
|
|
5241
|
+
debounce(id, ms, fn) {
|
|
5242
|
+
const scopeMap = TIMERS_MAP.get(this.scopeId);
|
|
5243
|
+
return new Promise((resolve, reject) => {
|
|
5244
|
+
if (scopeMap.has(id)) {
|
|
5245
|
+
clearTimeout(scopeMap.get(id));
|
|
5246
|
+
}
|
|
5247
|
+
const timerId = setTimeout(() => {
|
|
5248
|
+
try {
|
|
5249
|
+
resolve(fn());
|
|
5250
|
+
} catch (error) {
|
|
5251
|
+
reject(error);
|
|
5252
|
+
}
|
|
5253
|
+
scopeMap.delete(id);
|
|
5254
|
+
}, ms);
|
|
5255
|
+
scopeMap.set(id, timerId);
|
|
5256
|
+
});
|
|
5257
|
+
}
|
|
5258
|
+
clearDebounce(id) {
|
|
5259
|
+
const scopeMap = TIMERS_MAP.get(this.scopeId);
|
|
5260
|
+
if (scopeMap && scopeMap.has(id)) {
|
|
5261
|
+
clearTimeout(scopeMap.get(id));
|
|
5262
|
+
scopeMap.delete(id);
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
clear() {
|
|
5266
|
+
const scopeMap = TIMERS_MAP.get(this.scopeId);
|
|
5267
|
+
if (scopeMap) {
|
|
5268
|
+
scopeMap.forEach((timerId) => clearTimeout(timerId));
|
|
5269
|
+
scopeMap.clear();
|
|
5270
|
+
}
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5273
|
+
function createDebounce(scopeId) {
|
|
5274
|
+
return new DebounceController(scopeId);
|
|
5275
|
+
}
|
|
5276
|
+
function clearDebounceScope(scopeId) {
|
|
5277
|
+
const scopeMap = TIMERS_MAP.get(scopeId);
|
|
5278
|
+
if (scopeMap) {
|
|
5279
|
+
scopeMap.forEach((timerId) => clearTimeout(timerId));
|
|
5280
|
+
scopeMap.clear();
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
|
|
5284
|
+
// src/lib/queue.ts
|
|
5285
|
+
class ProcessQueue {
|
|
5286
|
+
processor;
|
|
5287
|
+
queue = [];
|
|
5288
|
+
processing = false;
|
|
5289
|
+
autoProcess = true;
|
|
5290
|
+
constructor(processor, autoProcess = true) {
|
|
5291
|
+
this.processor = processor;
|
|
5292
|
+
this.autoProcess = autoProcess;
|
|
5293
|
+
}
|
|
5294
|
+
enqueue(item) {
|
|
5295
|
+
this.queue.push(item);
|
|
5296
|
+
if (!this.processing && this.autoProcess) {
|
|
5297
|
+
this.processQueue();
|
|
5298
|
+
}
|
|
5299
|
+
}
|
|
5300
|
+
processQueue() {
|
|
5301
|
+
if (this.queue.length === 0) {
|
|
5302
|
+
return;
|
|
5303
|
+
}
|
|
5304
|
+
this.processing = true;
|
|
5305
|
+
queueMicrotask(async () => {
|
|
5306
|
+
if (this.queue.length === 0) {
|
|
5307
|
+
this.processing = false;
|
|
5308
|
+
return;
|
|
5309
|
+
}
|
|
5310
|
+
const item = this.queue.shift();
|
|
5311
|
+
try {
|
|
5312
|
+
await this.processor(item);
|
|
5313
|
+
} catch (error) {
|
|
5314
|
+
console.error("Error processing queue item:", error);
|
|
5315
|
+
}
|
|
5316
|
+
if (this.queue.length > 0) {
|
|
5317
|
+
this.processQueue();
|
|
5318
|
+
} else {
|
|
5319
|
+
this.processing = false;
|
|
5320
|
+
}
|
|
5321
|
+
});
|
|
5322
|
+
}
|
|
5323
|
+
clear() {
|
|
5324
|
+
this.queue = [];
|
|
5325
|
+
}
|
|
5326
|
+
isProcessing() {
|
|
5327
|
+
return this.processing;
|
|
5328
|
+
}
|
|
5329
|
+
size() {
|
|
5330
|
+
return this.queue.length;
|
|
5331
|
+
}
|
|
5332
|
+
}
|
|
5333
|
+
|
|
5334
|
+
// src/lib/tree-sitter/default-parsers.ts
|
|
5335
|
+
import { resolve, dirname } from "path";
|
|
5336
|
+
import { fileURLToPath } from "url";
|
|
5337
|
+
import javascript_highlights from "./assets/javascript/highlights.scm" with { type: "file" };
|
|
5338
|
+
import javascript_language from "./assets/javascript/tree-sitter-javascript.wasm" with { type: "file" };
|
|
5339
|
+
import typescript_highlights from "./assets/typescript/highlights.scm" with { type: "file" };
|
|
5340
|
+
import typescript_language from "./assets/typescript/tree-sitter-typescript.wasm" with { type: "file" };
|
|
5341
|
+
var _cachedParsers;
|
|
5342
|
+
function getParsers() {
|
|
5343
|
+
if (!_cachedParsers) {
|
|
5344
|
+
_cachedParsers = [
|
|
5345
|
+
{
|
|
5346
|
+
filetype: "javascript",
|
|
5347
|
+
queries: {
|
|
5348
|
+
highlights: [resolve(dirname(fileURLToPath(import.meta.url)), javascript_highlights)]
|
|
5349
|
+
},
|
|
5350
|
+
wasm: resolve(dirname(fileURLToPath(import.meta.url)), javascript_language)
|
|
5351
|
+
},
|
|
5352
|
+
{
|
|
5353
|
+
filetype: "typescript",
|
|
5354
|
+
queries: {
|
|
5355
|
+
highlights: [resolve(dirname(fileURLToPath(import.meta.url)), typescript_highlights)]
|
|
5356
|
+
},
|
|
5357
|
+
wasm: resolve(dirname(fileURLToPath(import.meta.url)), typescript_language)
|
|
5358
|
+
}
|
|
5359
|
+
];
|
|
5360
|
+
}
|
|
5361
|
+
return _cachedParsers;
|
|
5362
|
+
}
|
|
5363
|
+
|
|
5364
|
+
// src/lib/tree-sitter/client.ts
|
|
5365
|
+
import { resolve as resolve2, isAbsolute } from "path";
|
|
5366
|
+
import { existsSync } from "fs";
|
|
5367
|
+
import { parse } from "path";
|
|
5368
|
+
registerEnvVar({
|
|
5369
|
+
name: "OTUI_TREE_SITTER_WORKER_PATH",
|
|
5370
|
+
description: "Path to the TreeSitter worker",
|
|
5371
|
+
type: "string",
|
|
5372
|
+
default: ""
|
|
5373
|
+
});
|
|
5374
|
+
var DEFAULT_PARSERS = getParsers();
|
|
5375
|
+
function addDefaultParsers(parsers) {
|
|
5376
|
+
for (const parser of parsers) {
|
|
5377
|
+
const existingIndex = DEFAULT_PARSERS.findIndex((p) => p.filetype === parser.filetype);
|
|
5378
|
+
if (existingIndex >= 0) {
|
|
5379
|
+
DEFAULT_PARSERS[existingIndex] = parser;
|
|
5380
|
+
} else {
|
|
5381
|
+
DEFAULT_PARSERS.push(parser);
|
|
5382
|
+
}
|
|
5383
|
+
}
|
|
5384
|
+
}
|
|
5385
|
+
var isUrl = (path) => path.startsWith("http://") || path.startsWith("https://");
|
|
5386
|
+
|
|
5387
|
+
class TreeSitterClient extends EventEmitter2 {
|
|
5388
|
+
initialized = false;
|
|
5389
|
+
worker;
|
|
5390
|
+
buffers = new Map;
|
|
5391
|
+
initializePromise;
|
|
5392
|
+
initializeResolvers;
|
|
5393
|
+
messageCallbacks = new Map;
|
|
5394
|
+
messageIdCounter = 0;
|
|
5395
|
+
editQueues = new Map;
|
|
5396
|
+
debouncer;
|
|
5397
|
+
options;
|
|
5398
|
+
constructor(options) {
|
|
5399
|
+
super();
|
|
5400
|
+
this.options = options;
|
|
5401
|
+
this.debouncer = createDebounce("tree-sitter-client");
|
|
5402
|
+
this.startWorker();
|
|
5403
|
+
}
|
|
5404
|
+
emitError(error, bufferId) {
|
|
5405
|
+
if (this.listenerCount("error") > 0) {
|
|
5406
|
+
this.emit("error", error, bufferId);
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
emitWarning(warning, bufferId) {
|
|
5410
|
+
if (this.listenerCount("warning") > 0) {
|
|
5411
|
+
this.emit("warning", warning, bufferId);
|
|
5412
|
+
}
|
|
5413
|
+
}
|
|
5414
|
+
startWorker() {
|
|
5415
|
+
if (this.worker) {
|
|
5416
|
+
return;
|
|
5417
|
+
}
|
|
5418
|
+
let worker_path;
|
|
5419
|
+
if (env.OTUI_TREE_SITTER_WORKER_PATH) {
|
|
5420
|
+
worker_path = env.OTUI_TREE_SITTER_WORKER_PATH;
|
|
5421
|
+
} else if (typeof OTUI_TREE_SITTER_WORKER_PATH !== "undefined") {
|
|
5422
|
+
worker_path = OTUI_TREE_SITTER_WORKER_PATH;
|
|
5423
|
+
} else if (this.options.workerPath) {
|
|
5424
|
+
worker_path = this.options.workerPath;
|
|
5425
|
+
} else {
|
|
5426
|
+
worker_path = new URL("./parser.worker.js", import.meta.url).href;
|
|
5427
|
+
if (!existsSync(resolve2(import.meta.dirname, "parser.worker.js"))) {
|
|
5428
|
+
worker_path = new URL("./parser.worker.ts", import.meta.url).href;
|
|
5429
|
+
}
|
|
5430
|
+
}
|
|
5431
|
+
this.worker = new Worker(worker_path);
|
|
5432
|
+
this.worker.onmessage = this.handleWorkerMessage.bind(this);
|
|
5433
|
+
this.worker.onerror = (error) => {
|
|
5434
|
+
console.error("TreeSitter worker error:", error.message);
|
|
5435
|
+
if (this.initializeResolvers) {
|
|
5436
|
+
clearTimeout(this.initializeResolvers.timeoutId);
|
|
5437
|
+
this.initializeResolvers.reject(new Error(`Worker error: ${error.message}`));
|
|
5438
|
+
this.initializeResolvers = undefined;
|
|
5439
|
+
}
|
|
5440
|
+
this.emitError(`Worker error: ${error.message}`);
|
|
5441
|
+
};
|
|
5442
|
+
}
|
|
5443
|
+
stopWorker() {
|
|
5444
|
+
if (!this.worker) {
|
|
5445
|
+
return;
|
|
5446
|
+
}
|
|
5447
|
+
this.worker.terminate();
|
|
5448
|
+
this.worker = undefined;
|
|
5449
|
+
}
|
|
5450
|
+
handleReset() {
|
|
5451
|
+
this.buffers.clear();
|
|
5452
|
+
this.stopWorker();
|
|
5453
|
+
this.startWorker();
|
|
5454
|
+
this.initializePromise = undefined;
|
|
5455
|
+
this.initializeResolvers = undefined;
|
|
5456
|
+
return this.initialize();
|
|
5457
|
+
}
|
|
5458
|
+
async initialize() {
|
|
5459
|
+
if (this.initializePromise) {
|
|
5460
|
+
return this.initializePromise;
|
|
5461
|
+
}
|
|
5462
|
+
this.initializePromise = new Promise((resolve3, reject) => {
|
|
5463
|
+
const timeoutMs = this.options.initTimeout ?? 1e4;
|
|
5464
|
+
const timeoutId = setTimeout(() => {
|
|
5465
|
+
const error = new Error("Worker initialization timed out");
|
|
5466
|
+
console.error("TreeSitter client:", error.message);
|
|
5467
|
+
this.initializeResolvers = undefined;
|
|
5468
|
+
reject(error);
|
|
5469
|
+
}, timeoutMs);
|
|
5470
|
+
this.initializeResolvers = { resolve: resolve3, reject, timeoutId };
|
|
5471
|
+
this.worker?.postMessage({
|
|
5472
|
+
type: "INIT",
|
|
5473
|
+
dataPath: this.options.dataPath
|
|
5474
|
+
});
|
|
5475
|
+
});
|
|
5476
|
+
await this.initializePromise;
|
|
5477
|
+
await this.registerDefaultParsers();
|
|
5478
|
+
return this.initializePromise;
|
|
5479
|
+
}
|
|
5480
|
+
async registerDefaultParsers() {
|
|
5481
|
+
for (const parser of DEFAULT_PARSERS) {
|
|
5482
|
+
this.addFiletypeParser(parser);
|
|
5483
|
+
}
|
|
5484
|
+
}
|
|
5485
|
+
resolvePath(path) {
|
|
5486
|
+
if (isUrl(path)) {
|
|
5487
|
+
return path;
|
|
5488
|
+
}
|
|
5489
|
+
if (/\$bunfs/.test(path)) {
|
|
5490
|
+
return "/$bunfs/root/" + parse(path).base;
|
|
5491
|
+
}
|
|
5492
|
+
if (!isAbsolute(path)) {
|
|
5493
|
+
return resolve2(path);
|
|
5494
|
+
}
|
|
5495
|
+
return path;
|
|
5496
|
+
}
|
|
5497
|
+
addFiletypeParser(filetypeParser) {
|
|
5498
|
+
const resolvedParser = {
|
|
5499
|
+
...filetypeParser,
|
|
5500
|
+
wasm: this.resolvePath(filetypeParser.wasm),
|
|
5501
|
+
queries: {
|
|
5502
|
+
highlights: filetypeParser.queries.highlights.map((path) => this.resolvePath(path))
|
|
5503
|
+
}
|
|
5504
|
+
};
|
|
5505
|
+
this.worker?.postMessage({ type: "ADD_FILETYPE_PARSER", filetypeParser: resolvedParser });
|
|
5506
|
+
}
|
|
5507
|
+
async getPerformance() {
|
|
5508
|
+
const messageId = `performance_${this.messageIdCounter++}`;
|
|
5509
|
+
return new Promise((resolve3) => {
|
|
5510
|
+
this.messageCallbacks.set(messageId, resolve3);
|
|
5511
|
+
this.worker?.postMessage({ type: "GET_PERFORMANCE", messageId });
|
|
5512
|
+
});
|
|
5513
|
+
}
|
|
5514
|
+
async highlightOnce(content, filetype) {
|
|
5515
|
+
if (!this.initialized) {
|
|
5516
|
+
try {
|
|
5517
|
+
await this.initialize();
|
|
5518
|
+
} catch (error) {
|
|
5519
|
+
return { error: "Could not highlight because of initialization error" };
|
|
5520
|
+
}
|
|
5521
|
+
}
|
|
5522
|
+
const messageId = `oneshot_${this.messageIdCounter++}`;
|
|
5523
|
+
return new Promise((resolve3) => {
|
|
5524
|
+
this.messageCallbacks.set(messageId, resolve3);
|
|
5525
|
+
this.worker?.postMessage({
|
|
5526
|
+
type: "ONESHOT_HIGHLIGHT",
|
|
5527
|
+
content,
|
|
5528
|
+
filetype,
|
|
5529
|
+
messageId
|
|
5530
|
+
});
|
|
5531
|
+
});
|
|
5532
|
+
}
|
|
5533
|
+
handleWorkerMessage(event) {
|
|
5534
|
+
const { type, bufferId, error, highlights, warning, messageId, hasParser, performance: performance2, version } = event.data;
|
|
5535
|
+
if (type === "HIGHLIGHT_RESPONSE") {
|
|
5536
|
+
const buffer = this.buffers.get(bufferId);
|
|
5537
|
+
if (!buffer || !buffer.hasParser)
|
|
5538
|
+
return;
|
|
5539
|
+
if (buffer.version !== version) {
|
|
5540
|
+
this.resetBuffer(bufferId, buffer.version, buffer.content);
|
|
5541
|
+
return;
|
|
5542
|
+
}
|
|
5543
|
+
this.emit("highlights:response", bufferId, version, highlights);
|
|
5544
|
+
}
|
|
5545
|
+
if (type === "INIT_RESPONSE") {
|
|
5546
|
+
if (this.initializeResolvers) {
|
|
5547
|
+
clearTimeout(this.initializeResolvers.timeoutId);
|
|
5548
|
+
if (error) {
|
|
5549
|
+
console.error("TreeSitter client initialization failed:", error);
|
|
5550
|
+
this.initializeResolvers.reject(new Error(error));
|
|
5551
|
+
} else {
|
|
5552
|
+
this.initialized = true;
|
|
5553
|
+
this.initializeResolvers.resolve();
|
|
5554
|
+
}
|
|
5555
|
+
this.initializeResolvers = undefined;
|
|
5556
|
+
return;
|
|
5557
|
+
}
|
|
5558
|
+
}
|
|
5559
|
+
if (type === "PARSER_INIT_RESPONSE") {
|
|
5560
|
+
const callback = this.messageCallbacks.get(messageId);
|
|
5561
|
+
if (callback) {
|
|
5562
|
+
this.messageCallbacks.delete(messageId);
|
|
5563
|
+
callback({ hasParser, warning, error });
|
|
5564
|
+
}
|
|
5565
|
+
return;
|
|
5566
|
+
}
|
|
5567
|
+
if (type === "PRELOAD_PARSER_RESPONSE") {
|
|
5568
|
+
const callback = this.messageCallbacks.get(messageId);
|
|
5569
|
+
if (callback) {
|
|
5570
|
+
this.messageCallbacks.delete(messageId);
|
|
5571
|
+
callback({ hasParser });
|
|
5572
|
+
}
|
|
5573
|
+
return;
|
|
5574
|
+
}
|
|
5575
|
+
if (type === "BUFFER_DISPOSED") {
|
|
5576
|
+
const callback = this.messageCallbacks.get(`dispose_${bufferId}`);
|
|
5577
|
+
if (callback) {
|
|
5578
|
+
this.messageCallbacks.delete(`dispose_${bufferId}`);
|
|
5579
|
+
callback(true);
|
|
5580
|
+
}
|
|
5581
|
+
this.emit("buffer:disposed", bufferId);
|
|
5582
|
+
return;
|
|
5583
|
+
}
|
|
5584
|
+
if (type === "PERFORMANCE_RESPONSE") {
|
|
5585
|
+
const callback = this.messageCallbacks.get(messageId);
|
|
5586
|
+
if (callback) {
|
|
5587
|
+
this.messageCallbacks.delete(messageId);
|
|
5588
|
+
callback(performance2);
|
|
5589
|
+
}
|
|
5590
|
+
return;
|
|
5591
|
+
}
|
|
5592
|
+
if (type === "ONESHOT_HIGHLIGHT_RESPONSE") {
|
|
5593
|
+
const callback = this.messageCallbacks.get(messageId);
|
|
5594
|
+
if (callback) {
|
|
5595
|
+
this.messageCallbacks.delete(messageId);
|
|
5596
|
+
callback({ highlights, warning, error });
|
|
5597
|
+
}
|
|
5598
|
+
return;
|
|
5599
|
+
}
|
|
5600
|
+
if (type === "UPDATE_DATA_PATH_RESPONSE") {
|
|
5601
|
+
const callback = this.messageCallbacks.get(messageId);
|
|
5602
|
+
if (callback) {
|
|
5603
|
+
this.messageCallbacks.delete(messageId);
|
|
5604
|
+
callback({ error });
|
|
5605
|
+
}
|
|
5606
|
+
return;
|
|
5607
|
+
}
|
|
5608
|
+
if (warning) {
|
|
5609
|
+
this.emitWarning(warning, bufferId);
|
|
5610
|
+
return;
|
|
5611
|
+
}
|
|
5612
|
+
if (error) {
|
|
5613
|
+
this.emitError(error, bufferId);
|
|
5614
|
+
return;
|
|
5615
|
+
}
|
|
5616
|
+
if (type === "WORKER_LOG") {
|
|
5617
|
+
const { logType, data } = event.data;
|
|
5618
|
+
const message = data.join(" ");
|
|
5619
|
+
this.emit("worker:log", logType, message);
|
|
5620
|
+
if (logType === "log") {
|
|
5621
|
+
console.log("Worker stdout:", ...data);
|
|
5622
|
+
} else if (logType === "error") {
|
|
5623
|
+
console.error("Worker stderr:", ...data);
|
|
5624
|
+
}
|
|
5625
|
+
return;
|
|
5626
|
+
}
|
|
5627
|
+
}
|
|
5628
|
+
async preloadParser(filetype) {
|
|
5629
|
+
const messageId = `has_parser_${this.messageIdCounter++}`;
|
|
5630
|
+
const response = await new Promise((resolve3) => {
|
|
5631
|
+
this.messageCallbacks.set(messageId, resolve3);
|
|
5632
|
+
this.worker?.postMessage({
|
|
5633
|
+
type: "PRELOAD_PARSER",
|
|
5634
|
+
filetype,
|
|
5635
|
+
messageId
|
|
5636
|
+
});
|
|
5637
|
+
});
|
|
5638
|
+
return response.hasParser;
|
|
5639
|
+
}
|
|
5640
|
+
async createBuffer(id, content, filetype, version = 1, autoInitialize = true) {
|
|
5641
|
+
if (!this.initialized) {
|
|
5642
|
+
if (!autoInitialize) {
|
|
5643
|
+
this.emitError("Could not create buffer because client is not initialized");
|
|
5644
|
+
return false;
|
|
5645
|
+
}
|
|
5646
|
+
try {
|
|
5647
|
+
await this.initialize();
|
|
5648
|
+
} catch (error) {
|
|
5649
|
+
this.emitError("Could not create buffer because of initialization error");
|
|
5650
|
+
return false;
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
if (this.buffers.has(id)) {
|
|
5654
|
+
throw new Error(`Buffer with id ${id} already exists`);
|
|
5655
|
+
}
|
|
5656
|
+
this.buffers.set(id, { id, content, filetype, version, hasParser: false });
|
|
5657
|
+
const messageId = `init_${this.messageIdCounter++}`;
|
|
5658
|
+
const response = await new Promise((resolve3) => {
|
|
5659
|
+
this.messageCallbacks.set(messageId, resolve3);
|
|
5660
|
+
this.worker?.postMessage({
|
|
5661
|
+
type: "INITIALIZE_PARSER",
|
|
5662
|
+
bufferId: id,
|
|
5663
|
+
version,
|
|
5664
|
+
content,
|
|
5665
|
+
filetype,
|
|
5666
|
+
messageId
|
|
5667
|
+
});
|
|
5668
|
+
});
|
|
5669
|
+
if (!response.hasParser) {
|
|
5670
|
+
this.emit("buffer:initialized", id, false);
|
|
5671
|
+
if (filetype !== "plaintext") {
|
|
5672
|
+
this.emitWarning(response.warning || response.error || "Buffer has no parser", id);
|
|
5673
|
+
}
|
|
5674
|
+
return false;
|
|
5675
|
+
}
|
|
5676
|
+
const bufferState = { id, content, filetype, version, hasParser: true };
|
|
5677
|
+
this.buffers.set(id, bufferState);
|
|
5678
|
+
this.emit("buffer:initialized", id, true);
|
|
5679
|
+
return true;
|
|
5680
|
+
}
|
|
5681
|
+
async updateBuffer(id, edits, newContent, version) {
|
|
5682
|
+
if (!this.initialized) {
|
|
5683
|
+
return;
|
|
5684
|
+
}
|
|
5685
|
+
const buffer = this.buffers.get(id);
|
|
5686
|
+
if (!buffer || !buffer.hasParser) {
|
|
5687
|
+
return;
|
|
5688
|
+
}
|
|
5689
|
+
this.buffers.set(id, { ...buffer, content: newContent, version });
|
|
5690
|
+
if (!this.editQueues.has(id)) {
|
|
5691
|
+
this.editQueues.set(id, new ProcessQueue((item) => this.processEdit(id, item.edits, item.newContent, item.version, item.isReset)));
|
|
5692
|
+
}
|
|
5693
|
+
const bufferQueue = this.editQueues.get(id);
|
|
5694
|
+
bufferQueue.enqueue({ edits, newContent, version });
|
|
5695
|
+
}
|
|
5696
|
+
async processEdit(bufferId, edits, newContent, version, isReset = false) {
|
|
5697
|
+
this.worker?.postMessage({
|
|
5698
|
+
type: isReset ? "RESET_BUFFER" : "HANDLE_EDITS",
|
|
5699
|
+
bufferId,
|
|
5700
|
+
version,
|
|
5701
|
+
content: newContent,
|
|
5702
|
+
edits
|
|
5703
|
+
});
|
|
5704
|
+
}
|
|
5705
|
+
async removeBuffer(bufferId) {
|
|
5706
|
+
if (!this.initialized) {
|
|
5707
|
+
return;
|
|
5708
|
+
}
|
|
5709
|
+
this.buffers.delete(bufferId);
|
|
5710
|
+
if (this.editQueues.has(bufferId)) {
|
|
5711
|
+
this.editQueues.get(bufferId)?.clear();
|
|
5712
|
+
this.editQueues.delete(bufferId);
|
|
5713
|
+
}
|
|
5714
|
+
if (this.worker) {
|
|
5715
|
+
await new Promise((resolve3) => {
|
|
5716
|
+
const messageId = `dispose_${bufferId}`;
|
|
5717
|
+
this.messageCallbacks.set(messageId, resolve3);
|
|
5718
|
+
try {
|
|
5719
|
+
this.worker.postMessage({
|
|
5720
|
+
type: "DISPOSE_BUFFER",
|
|
5721
|
+
bufferId
|
|
5722
|
+
});
|
|
5723
|
+
} catch (error) {
|
|
5724
|
+
console.error("Error disposing buffer", error);
|
|
5725
|
+
resolve3(false);
|
|
5726
|
+
}
|
|
5727
|
+
setTimeout(() => {
|
|
5728
|
+
if (this.messageCallbacks.has(messageId)) {
|
|
5729
|
+
this.messageCallbacks.delete(messageId);
|
|
5730
|
+
console.warn({ bufferId }, "Timed out waiting for buffer to be disposed");
|
|
5731
|
+
resolve3(false);
|
|
5732
|
+
}
|
|
5733
|
+
}, 3000);
|
|
5734
|
+
});
|
|
5735
|
+
}
|
|
5736
|
+
this.debouncer.clearDebounce(`reset-${bufferId}`);
|
|
5737
|
+
}
|
|
5738
|
+
async destroy() {
|
|
5739
|
+
if (this.initializeResolvers) {
|
|
5740
|
+
clearTimeout(this.initializeResolvers.timeoutId);
|
|
5741
|
+
this.initializeResolvers = undefined;
|
|
5742
|
+
}
|
|
5743
|
+
for (const [messageId, callback] of this.messageCallbacks.entries()) {
|
|
5744
|
+
if (typeof callback === "function") {
|
|
5745
|
+
try {
|
|
5746
|
+
callback({ error: "Client destroyed" });
|
|
5747
|
+
} catch (e) {}
|
|
5748
|
+
}
|
|
5749
|
+
}
|
|
5750
|
+
this.messageCallbacks.clear();
|
|
5751
|
+
clearDebounceScope("tree-sitter-client");
|
|
5752
|
+
this.debouncer.clear();
|
|
5753
|
+
this.editQueues.clear();
|
|
5754
|
+
this.buffers.clear();
|
|
5755
|
+
this.stopWorker();
|
|
5756
|
+
this.initialized = false;
|
|
5757
|
+
this.initializePromise = undefined;
|
|
5758
|
+
}
|
|
5759
|
+
async resetBuffer(bufferId, version, content) {
|
|
5760
|
+
if (!this.initialized) {
|
|
5761
|
+
return;
|
|
5762
|
+
}
|
|
5763
|
+
const buffer = this.buffers.get(bufferId);
|
|
5764
|
+
if (!buffer || !buffer.hasParser) {
|
|
5765
|
+
this.emitError("Cannot reset buffer with no parser", bufferId);
|
|
5766
|
+
return;
|
|
5767
|
+
}
|
|
5768
|
+
this.buffers.set(bufferId, { ...buffer, content, version });
|
|
5769
|
+
this.debouncer.debounce(`reset-${bufferId}`, 10, () => this.processEdit(bufferId, [], content, version, true));
|
|
5770
|
+
}
|
|
5771
|
+
getBuffer(bufferId) {
|
|
5772
|
+
return this.buffers.get(bufferId);
|
|
5773
|
+
}
|
|
5774
|
+
getAllBuffers() {
|
|
5775
|
+
return Array.from(this.buffers.values());
|
|
5776
|
+
}
|
|
5777
|
+
isInitialized() {
|
|
5778
|
+
return this.initialized;
|
|
5779
|
+
}
|
|
5780
|
+
async setDataPath(dataPath) {
|
|
5781
|
+
if (this.options.dataPath === dataPath) {
|
|
5782
|
+
return;
|
|
5783
|
+
}
|
|
5784
|
+
this.options.dataPath = dataPath;
|
|
5785
|
+
if (this.initialized && this.worker) {
|
|
5786
|
+
const messageId = `update_datapath_${this.messageIdCounter++}`;
|
|
5787
|
+
return new Promise((resolve3, reject) => {
|
|
5788
|
+
this.messageCallbacks.set(messageId, (response) => {
|
|
5789
|
+
if (response.error) {
|
|
5790
|
+
reject(new Error(response.error));
|
|
5791
|
+
} else {
|
|
5792
|
+
resolve3();
|
|
5793
|
+
}
|
|
5794
|
+
});
|
|
5795
|
+
this.worker.postMessage({
|
|
5796
|
+
type: "UPDATE_DATA_PATH",
|
|
5797
|
+
dataPath,
|
|
5798
|
+
messageId
|
|
5799
|
+
});
|
|
5800
|
+
});
|
|
5801
|
+
}
|
|
5802
|
+
}
|
|
5803
|
+
}
|
|
5804
|
+
|
|
5805
|
+
// src/lib/data-paths.ts
|
|
5806
|
+
import os from "os";
|
|
5807
|
+
import path from "path";
|
|
5808
|
+
import { EventEmitter as EventEmitter3 } from "events";
|
|
5809
|
+
|
|
5810
|
+
// src/lib/validate-dir-name.ts
|
|
5811
|
+
function isValidDirectoryName(name) {
|
|
5812
|
+
if (!name || typeof name !== "string") {
|
|
5813
|
+
return false;
|
|
5814
|
+
}
|
|
5815
|
+
if (name.trim().length === 0) {
|
|
5816
|
+
return false;
|
|
5817
|
+
}
|
|
5818
|
+
const reservedNames = [
|
|
5819
|
+
"CON",
|
|
5820
|
+
"PRN",
|
|
5821
|
+
"AUX",
|
|
5822
|
+
"NUL",
|
|
5823
|
+
"COM1",
|
|
5824
|
+
"COM2",
|
|
5825
|
+
"COM3",
|
|
5826
|
+
"COM4",
|
|
5827
|
+
"COM5",
|
|
5828
|
+
"COM6",
|
|
5829
|
+
"COM7",
|
|
5830
|
+
"COM8",
|
|
5831
|
+
"COM9",
|
|
5832
|
+
"LPT1",
|
|
5833
|
+
"LPT2",
|
|
5834
|
+
"LPT3",
|
|
5835
|
+
"LPT4",
|
|
5836
|
+
"LPT5",
|
|
5837
|
+
"LPT6",
|
|
5838
|
+
"LPT7",
|
|
5839
|
+
"LPT8",
|
|
5840
|
+
"LPT9"
|
|
5841
|
+
];
|
|
5842
|
+
if (reservedNames.includes(name.toUpperCase())) {
|
|
5843
|
+
return false;
|
|
5844
|
+
}
|
|
5845
|
+
const invalidChars = /[<>:"|?*\/\\\x00-\x1f]/;
|
|
5846
|
+
if (invalidChars.test(name)) {
|
|
5847
|
+
return false;
|
|
5848
|
+
}
|
|
5849
|
+
if (name.endsWith(".") || name.endsWith(" ")) {
|
|
5850
|
+
return false;
|
|
5851
|
+
}
|
|
5852
|
+
if (name === "." || name === "..") {
|
|
5853
|
+
return false;
|
|
5854
|
+
}
|
|
5855
|
+
return true;
|
|
5856
|
+
}
|
|
5857
|
+
|
|
5858
|
+
// src/lib/data-paths.ts
|
|
5859
|
+
registerEnvVar({
|
|
5860
|
+
name: "XDG_CONFIG_HOME",
|
|
5861
|
+
description: "Base directory for user-specific configuration files",
|
|
5862
|
+
type: "string",
|
|
5863
|
+
default: ""
|
|
5864
|
+
});
|
|
5865
|
+
registerEnvVar({
|
|
5866
|
+
name: "XDG_DATA_HOME",
|
|
5867
|
+
description: "Base directory for user-specific data files",
|
|
5868
|
+
type: "string",
|
|
5869
|
+
default: ""
|
|
5870
|
+
});
|
|
5871
|
+
|
|
5872
|
+
class DataPathsManager extends EventEmitter3 {
|
|
5873
|
+
_appName;
|
|
5874
|
+
_globalConfigPath;
|
|
5875
|
+
_globalConfigFile;
|
|
5876
|
+
_localConfigFile;
|
|
5877
|
+
_globalDataPath;
|
|
5878
|
+
constructor() {
|
|
5879
|
+
super();
|
|
5880
|
+
this._appName = "opentui";
|
|
4749
5881
|
}
|
|
4750
|
-
|
|
4751
|
-
return this.
|
|
5882
|
+
get appName() {
|
|
5883
|
+
return this._appName;
|
|
4752
5884
|
}
|
|
4753
|
-
|
|
4754
|
-
|
|
5885
|
+
set appName(value) {
|
|
5886
|
+
if (!isValidDirectoryName(value)) {
|
|
5887
|
+
throw new Error(`Invalid app name "${value}": must be a valid directory name`);
|
|
5888
|
+
}
|
|
5889
|
+
if (this._appName !== value) {
|
|
5890
|
+
this._appName = value;
|
|
5891
|
+
this._globalConfigPath = undefined;
|
|
5892
|
+
this._globalConfigFile = undefined;
|
|
5893
|
+
this._localConfigFile = undefined;
|
|
5894
|
+
this._globalDataPath = undefined;
|
|
5895
|
+
this.emit("paths:changed", this.toObject());
|
|
5896
|
+
}
|
|
4755
5897
|
}
|
|
4756
|
-
|
|
4757
|
-
if (
|
|
4758
|
-
|
|
5898
|
+
get globalConfigPath() {
|
|
5899
|
+
if (this._globalConfigPath === undefined) {
|
|
5900
|
+
const homeDir = os.homedir();
|
|
5901
|
+
const xdgConfigHome = env.XDG_CONFIG_HOME;
|
|
5902
|
+
const baseConfigDir = xdgConfigHome || path.join(homeDir, ".config");
|
|
5903
|
+
this._globalConfigPath = path.join(baseConfigDir, this._appName);
|
|
4759
5904
|
}
|
|
4760
|
-
|
|
4761
|
-
const font = this.getFont();
|
|
4762
|
-
const charIndex = coordinateToCharacterIndex(localX, text, font);
|
|
4763
|
-
return charIndex >= 0 && charIndex <= text.length;
|
|
5905
|
+
return this._globalConfigPath;
|
|
4764
5906
|
}
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
this.localSelection = null;
|
|
4769
|
-
return previousSelection !== null;
|
|
5907
|
+
get globalConfigFile() {
|
|
5908
|
+
if (this._globalConfigFile === undefined) {
|
|
5909
|
+
this._globalConfigFile = path.join(this.globalConfigPath, "init.ts");
|
|
4770
5910
|
}
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
this.localSelection = null;
|
|
4777
|
-
return previousSelection !== null;
|
|
5911
|
+
return this._globalConfigFile;
|
|
5912
|
+
}
|
|
5913
|
+
get localConfigFile() {
|
|
5914
|
+
if (this._localConfigFile === undefined) {
|
|
5915
|
+
this._localConfigFile = path.join(process.cwd(), `.${this._appName}.ts`);
|
|
4778
5916
|
}
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
}
|
|
5917
|
+
return this._localConfigFile;
|
|
5918
|
+
}
|
|
5919
|
+
get globalDataPath() {
|
|
5920
|
+
if (this._globalDataPath === undefined) {
|
|
5921
|
+
const homeDir = os.homedir();
|
|
5922
|
+
const xdgDataHome = env.XDG_DATA_HOME;
|
|
5923
|
+
const baseDataDir = xdgDataHome || path.join(homeDir, ".local/share");
|
|
5924
|
+
this._globalDataPath = path.join(baseDataDir, this._appName);
|
|
4788
5925
|
}
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
5926
|
+
return this._globalDataPath;
|
|
5927
|
+
}
|
|
5928
|
+
toObject() {
|
|
5929
|
+
return {
|
|
5930
|
+
globalConfigPath: this.globalConfigPath,
|
|
5931
|
+
globalConfigFile: this.globalConfigFile,
|
|
5932
|
+
localConfigFile: this.localConfigFile,
|
|
5933
|
+
globalDataPath: this.globalDataPath
|
|
5934
|
+
};
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
function getDataPaths() {
|
|
5938
|
+
return singleton("data-paths-opentui", () => new DataPathsManager);
|
|
5939
|
+
}
|
|
5940
|
+
|
|
5941
|
+
// src/lib/tree-sitter/resolve-ft.ts
|
|
5942
|
+
function extToFiletype(extension) {
|
|
5943
|
+
const extensionToFiletype = new Map([
|
|
5944
|
+
["js", "javascript"],
|
|
5945
|
+
["jsx", "javascriptreact"],
|
|
5946
|
+
["ts", "typescript"],
|
|
5947
|
+
["tsx", "typescriptreact"],
|
|
5948
|
+
["md", "markdown"],
|
|
5949
|
+
["json", "json"],
|
|
5950
|
+
["py", "python"],
|
|
5951
|
+
["rb", "ruby"],
|
|
5952
|
+
["go", "go"],
|
|
5953
|
+
["rs", "rust"],
|
|
5954
|
+
["c", "c"],
|
|
5955
|
+
["cpp", "cpp"],
|
|
5956
|
+
["h", "c"],
|
|
5957
|
+
["hpp", "cpp"],
|
|
5958
|
+
["html", "html"],
|
|
5959
|
+
["css", "css"],
|
|
5960
|
+
["scss", "scss"],
|
|
5961
|
+
["less", "less"],
|
|
5962
|
+
["sh", "shell"],
|
|
5963
|
+
["bash", "shell"],
|
|
5964
|
+
["zsh", "shell"],
|
|
5965
|
+
["vim", "vim"],
|
|
5966
|
+
["yaml", "yaml"],
|
|
5967
|
+
["yml", "yaml"],
|
|
5968
|
+
["toml", "toml"],
|
|
5969
|
+
["xml", "xml"],
|
|
5970
|
+
["zig", "zig"]
|
|
5971
|
+
]);
|
|
5972
|
+
return extensionToFiletype.get(extension);
|
|
5973
|
+
}
|
|
5974
|
+
function pathToFiletype(path2) {
|
|
5975
|
+
if (typeof path2 !== "string")
|
|
5976
|
+
return;
|
|
5977
|
+
const lastDot = path2.lastIndexOf(".");
|
|
5978
|
+
if (lastDot === -1 || lastDot === path2.length - 1) {
|
|
5979
|
+
return;
|
|
5980
|
+
}
|
|
5981
|
+
const extension = path2.substring(lastDot + 1);
|
|
5982
|
+
return extToFiletype(extension);
|
|
5983
|
+
}
|
|
5984
|
+
|
|
5985
|
+
// src/lib/tree-sitter/assets/update.ts
|
|
5986
|
+
import { readFile, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
5987
|
+
import * as path3 from "path";
|
|
5988
|
+
|
|
5989
|
+
// src/lib/tree-sitter/download-utils.ts
|
|
5990
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
5991
|
+
import * as path2 from "path";
|
|
5992
|
+
|
|
5993
|
+
class DownloadUtils {
|
|
5994
|
+
static hashUrl(url) {
|
|
5995
|
+
let hash = 0;
|
|
5996
|
+
for (let i = 0;i < url.length; i++) {
|
|
5997
|
+
const char = url.charCodeAt(i);
|
|
5998
|
+
hash = (hash << 5) - hash + char;
|
|
5999
|
+
hash = hash & hash;
|
|
6000
|
+
}
|
|
6001
|
+
return Math.abs(hash).toString(16);
|
|
6002
|
+
}
|
|
6003
|
+
static async downloadOrLoad(source, cacheDir, cacheSubdir, fileExtension, useHashForCache = true, filetype) {
|
|
6004
|
+
const isUrl2 = source.startsWith("http://") || source.startsWith("https://");
|
|
6005
|
+
if (isUrl2) {
|
|
6006
|
+
let cacheFileName;
|
|
6007
|
+
if (useHashForCache) {
|
|
6008
|
+
const hash = this.hashUrl(source);
|
|
6009
|
+
cacheFileName = filetype ? `${filetype}-${hash}${fileExtension}` : `${hash}${fileExtension}`;
|
|
4795
6010
|
} else {
|
|
4796
|
-
|
|
6011
|
+
cacheFileName = path2.basename(source);
|
|
6012
|
+
}
|
|
6013
|
+
const cacheFile = path2.join(cacheDir, cacheSubdir, cacheFileName);
|
|
6014
|
+
await mkdir(path2.dirname(cacheFile), { recursive: true });
|
|
6015
|
+
try {
|
|
6016
|
+
const cachedContent = await Bun.file(cacheFile).arrayBuffer();
|
|
6017
|
+
if (cachedContent.byteLength > 0) {
|
|
6018
|
+
console.log(`Loaded from cache: ${cacheFile} (${source})`);
|
|
6019
|
+
return { content: cachedContent, filePath: cacheFile };
|
|
6020
|
+
}
|
|
6021
|
+
} catch (error) {}
|
|
6022
|
+
try {
|
|
6023
|
+
console.log(`Downloading from URL: ${source}`);
|
|
6024
|
+
const response = await fetch(source);
|
|
6025
|
+
if (!response.ok) {
|
|
6026
|
+
return { error: `Failed to fetch from ${source}: ${response.statusText}` };
|
|
6027
|
+
}
|
|
6028
|
+
const content = await response.arrayBuffer();
|
|
6029
|
+
try {
|
|
6030
|
+
await writeFile(cacheFile, Buffer.from(content));
|
|
6031
|
+
console.log(`Cached: ${source}`);
|
|
6032
|
+
} catch (cacheError) {
|
|
6033
|
+
console.warn(`Failed to cache: ${cacheError}`);
|
|
6034
|
+
}
|
|
6035
|
+
return { content, filePath: cacheFile };
|
|
6036
|
+
} catch (error) {
|
|
6037
|
+
return { error: `Error downloading from ${source}: ${error}` };
|
|
6038
|
+
}
|
|
6039
|
+
} else {
|
|
6040
|
+
try {
|
|
6041
|
+
console.log(`Loading from local path: ${source}`);
|
|
6042
|
+
const content = await Bun.file(source).arrayBuffer();
|
|
6043
|
+
return { content, filePath: source };
|
|
6044
|
+
} catch (error) {
|
|
6045
|
+
return { error: `Error loading from local path ${source}: ${error}` };
|
|
4797
6046
|
}
|
|
4798
6047
|
}
|
|
4799
|
-
|
|
4800
|
-
|
|
6048
|
+
}
|
|
6049
|
+
static async downloadToPath(source, targetPath) {
|
|
6050
|
+
const isUrl2 = source.startsWith("http://") || source.startsWith("https://");
|
|
6051
|
+
await mkdir(path2.dirname(targetPath), { recursive: true });
|
|
6052
|
+
if (isUrl2) {
|
|
6053
|
+
try {
|
|
6054
|
+
console.log(`Downloading from URL: ${source}`);
|
|
6055
|
+
const response = await fetch(source);
|
|
6056
|
+
if (!response.ok) {
|
|
6057
|
+
return { error: `Failed to fetch from ${source}: ${response.statusText}` };
|
|
6058
|
+
}
|
|
6059
|
+
const content = await response.arrayBuffer();
|
|
6060
|
+
await writeFile(targetPath, Buffer.from(content));
|
|
6061
|
+
console.log(`Downloaded: ${source} -> ${targetPath}`);
|
|
6062
|
+
return { content, filePath: targetPath };
|
|
6063
|
+
} catch (error) {
|
|
6064
|
+
return { error: `Error downloading from ${source}: ${error}` };
|
|
6065
|
+
}
|
|
4801
6066
|
} else {
|
|
4802
|
-
|
|
6067
|
+
try {
|
|
6068
|
+
console.log(`Copying from local path: ${source}`);
|
|
6069
|
+
const content = await Bun.file(source).arrayBuffer();
|
|
6070
|
+
await writeFile(targetPath, Buffer.from(content));
|
|
6071
|
+
return { content, filePath: targetPath };
|
|
6072
|
+
} catch (error) {
|
|
6073
|
+
return { error: `Error copying from local path ${source}: ${error}` };
|
|
6074
|
+
}
|
|
4803
6075
|
}
|
|
4804
|
-
return previousSelection?.start !== this.localSelection?.start || previousSelection?.end !== this.localSelection?.end;
|
|
4805
6076
|
}
|
|
6077
|
+
static async fetchHighlightQueries(sources, cacheDir, filetype) {
|
|
6078
|
+
const queryPromises = sources.map((source) => this.fetchHighlightQuery(source, cacheDir, filetype));
|
|
6079
|
+
const queryResults = await Promise.all(queryPromises);
|
|
6080
|
+
const validQueries = queryResults.filter((query) => query.trim().length > 0);
|
|
6081
|
+
return validQueries.join(`
|
|
6082
|
+
`);
|
|
6083
|
+
}
|
|
6084
|
+
static async fetchHighlightQuery(source, cacheDir, filetype) {
|
|
6085
|
+
const result = await this.downloadOrLoad(source, cacheDir, "queries", ".scm", true, filetype);
|
|
6086
|
+
if (result.error) {
|
|
6087
|
+
console.error(`Error fetching highlight query from ${source}:`, result.error);
|
|
6088
|
+
return "";
|
|
6089
|
+
}
|
|
6090
|
+
if (result.content) {
|
|
6091
|
+
return new TextDecoder().decode(result.content);
|
|
6092
|
+
}
|
|
6093
|
+
return "";
|
|
6094
|
+
}
|
|
6095
|
+
}
|
|
6096
|
+
|
|
6097
|
+
// src/lib/tree-sitter/assets/update.ts
|
|
6098
|
+
var __dirname = "/Users/runner/work/opentui/opentui/packages/core/src/lib/tree-sitter/assets";
|
|
6099
|
+
function getDefaultOptions() {
|
|
6100
|
+
return {
|
|
6101
|
+
configPath: path3.resolve(__dirname, "../parsers-config.json"),
|
|
6102
|
+
assetsDir: path3.resolve(__dirname),
|
|
6103
|
+
outputPath: path3.resolve(__dirname, "../default-parsers.ts")
|
|
6104
|
+
};
|
|
6105
|
+
}
|
|
6106
|
+
async function loadConfig(configPath) {
|
|
6107
|
+
const configContent = await readFile(configPath, "utf-8");
|
|
6108
|
+
return JSON.parse(configContent);
|
|
6109
|
+
}
|
|
6110
|
+
async function downloadLanguage(filetype, languageUrl, assetsDir, outputPath) {
|
|
6111
|
+
const languageDir = path3.join(assetsDir, filetype);
|
|
6112
|
+
const languageFilename = path3.basename(languageUrl);
|
|
6113
|
+
const languagePath = path3.join(languageDir, languageFilename);
|
|
6114
|
+
const result = await DownloadUtils.downloadToPath(languageUrl, languagePath);
|
|
6115
|
+
if (result.error) {
|
|
6116
|
+
throw new Error(`Failed to download language for ${filetype}: ${result.error}`);
|
|
6117
|
+
}
|
|
6118
|
+
return "./" + path3.relative(path3.dirname(outputPath), languagePath);
|
|
6119
|
+
}
|
|
6120
|
+
async function downloadAndCombineQueries(filetype, queryUrls, assetsDir, outputPath) {
|
|
6121
|
+
const queriesDir = path3.join(assetsDir, filetype);
|
|
6122
|
+
const highlightsPath = path3.join(queriesDir, "highlights.scm");
|
|
6123
|
+
const queryContents = [];
|
|
6124
|
+
for (let i = 0;i < queryUrls.length; i++) {
|
|
6125
|
+
const queryUrl = queryUrls[i];
|
|
6126
|
+
console.log(` Downloading query ${i + 1}/${queryUrls.length}: ${queryUrl}`);
|
|
6127
|
+
try {
|
|
6128
|
+
const response = await fetch(queryUrl);
|
|
6129
|
+
if (!response.ok) {
|
|
6130
|
+
console.warn(`Failed to download query from ${queryUrl}: ${response.statusText}`);
|
|
6131
|
+
continue;
|
|
6132
|
+
}
|
|
6133
|
+
const content = await response.text();
|
|
6134
|
+
if (content.trim()) {
|
|
6135
|
+
queryContents.push(`; Query from: ${queryUrl}
|
|
6136
|
+
${content}`);
|
|
6137
|
+
console.log(` \u2713 Downloaded ${content.split(`
|
|
6138
|
+
`).length} lines`);
|
|
6139
|
+
}
|
|
6140
|
+
} catch (error) {
|
|
6141
|
+
console.warn(`Failed to download query from ${queryUrl}: ${error}`);
|
|
6142
|
+
continue;
|
|
6143
|
+
}
|
|
6144
|
+
}
|
|
6145
|
+
const combinedContent = queryContents.join(`
|
|
6146
|
+
|
|
6147
|
+
`);
|
|
6148
|
+
await writeFile2(highlightsPath, combinedContent, "utf-8");
|
|
6149
|
+
console.log(` Combined ${queryContents.length} queries into ${highlightsPath}`);
|
|
6150
|
+
return "./" + path3.relative(path3.dirname(outputPath), highlightsPath);
|
|
6151
|
+
}
|
|
6152
|
+
async function generateDefaultParsersFile(parsers, outputPath) {
|
|
6153
|
+
const imports = parsers.map((parser) => {
|
|
6154
|
+
const safeFiletype = parser.filetype.replace(/[^a-zA-Z0-9]/g, "_");
|
|
6155
|
+
return `import ${safeFiletype}_highlights from "${parser.highlightsPath}" with { type: "file" }
|
|
6156
|
+
import ${safeFiletype}_language from "${parser.languagePath}" with { type: "file" }`;
|
|
6157
|
+
}).join(`
|
|
6158
|
+
`);
|
|
6159
|
+
const parserDefinitions = parsers.map((parser) => {
|
|
6160
|
+
const safeFiletype = parser.filetype.replace(/[^a-zA-Z0-9]/g, "_");
|
|
6161
|
+
return ` {
|
|
6162
|
+
filetype: "${parser.filetype}",
|
|
6163
|
+
queries: {
|
|
6164
|
+
highlights: [resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_highlights)],
|
|
6165
|
+
},
|
|
6166
|
+
wasm: resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_language),
|
|
6167
|
+
}`;
|
|
6168
|
+
}).join(`,
|
|
6169
|
+
`);
|
|
6170
|
+
const fileContent = `// This file is generated by assets/update.ts - DO NOT EDIT MANUALLY
|
|
6171
|
+
// Run 'bun assets/update.ts' to regenerate this file
|
|
6172
|
+
// Last generated: ${new Date().toISOString()}
|
|
6173
|
+
|
|
6174
|
+
import type { FiletypeParserOptions } from "./types"
|
|
6175
|
+
import { resolve, dirname } from "path"
|
|
6176
|
+
import { fileURLToPath } from "url"
|
|
6177
|
+
|
|
6178
|
+
${imports}
|
|
6179
|
+
|
|
6180
|
+
// Cached parsers to avoid re-resolving paths on every call
|
|
6181
|
+
let _cachedParsers: FiletypeParserOptions[] | undefined
|
|
6182
|
+
|
|
6183
|
+
export function getParsers(): FiletypeParserOptions[] {
|
|
6184
|
+
if (!_cachedParsers) {
|
|
6185
|
+
_cachedParsers = [
|
|
6186
|
+
${parserDefinitions},
|
|
6187
|
+
]
|
|
6188
|
+
}
|
|
6189
|
+
return _cachedParsers
|
|
6190
|
+
}
|
|
6191
|
+
`;
|
|
6192
|
+
await mkdir2(path3.dirname(outputPath), { recursive: true });
|
|
6193
|
+
await writeFile2(outputPath, fileContent, "utf-8");
|
|
6194
|
+
console.log(`Generated ${path3.basename(outputPath)} with ${parsers.length} parsers`);
|
|
6195
|
+
}
|
|
6196
|
+
async function main(options) {
|
|
6197
|
+
const opts = { ...getDefaultOptions(), ...options };
|
|
6198
|
+
try {
|
|
6199
|
+
console.log("Loading parsers configuration...");
|
|
6200
|
+
console.log(` Config: ${opts.configPath}`);
|
|
6201
|
+
console.log(` Assets Dir: ${opts.assetsDir}`);
|
|
6202
|
+
console.log(` Output: ${opts.outputPath}`);
|
|
6203
|
+
const config = await loadConfig(opts.configPath);
|
|
6204
|
+
console.log(`Found ${config.parsers.length} parsers to process`);
|
|
6205
|
+
const generatedParsers = [];
|
|
6206
|
+
for (const parser of config.parsers) {
|
|
6207
|
+
console.log(`Processing ${parser.filetype}...`);
|
|
6208
|
+
console.log(` Downloading language...`);
|
|
6209
|
+
const languagePath = await downloadLanguage(parser.filetype, parser.wasm, opts.assetsDir, opts.outputPath);
|
|
6210
|
+
console.log(` Downloading ${parser.queries.highlights.length} highlight queries...`);
|
|
6211
|
+
const highlightsPath = await downloadAndCombineQueries(parser.filetype, parser.queries.highlights, opts.assetsDir, opts.outputPath);
|
|
6212
|
+
generatedParsers.push({
|
|
6213
|
+
filetype: parser.filetype,
|
|
6214
|
+
languagePath,
|
|
6215
|
+
highlightsPath
|
|
6216
|
+
});
|
|
6217
|
+
console.log(` \u2713 Completed ${parser.filetype}`);
|
|
6218
|
+
}
|
|
6219
|
+
console.log("Generating output file...");
|
|
6220
|
+
await generateDefaultParsersFile(generatedParsers, opts.outputPath);
|
|
6221
|
+
console.log("\u2705 Update completed successfully!");
|
|
6222
|
+
} catch (error) {
|
|
6223
|
+
console.error("\u274C Update failed:", error);
|
|
6224
|
+
process.exit(1);
|
|
6225
|
+
}
|
|
6226
|
+
}
|
|
6227
|
+
if (false) {}
|
|
6228
|
+
|
|
6229
|
+
// src/lib/tree-sitter/index.ts
|
|
6230
|
+
function getTreeSitterClient() {
|
|
6231
|
+
const dataPathsManager = getDataPaths();
|
|
6232
|
+
const defaultOptions = {
|
|
6233
|
+
dataPath: dataPathsManager.globalDataPath
|
|
6234
|
+
};
|
|
6235
|
+
return singleton("tree-sitter-client", () => {
|
|
6236
|
+
const client2 = new TreeSitterClient(defaultOptions);
|
|
6237
|
+
dataPathsManager.on("paths:changed", (paths) => {
|
|
6238
|
+
client2.setDataPath(paths.globalDataPath);
|
|
6239
|
+
});
|
|
6240
|
+
return client2;
|
|
6241
|
+
});
|
|
4806
6242
|
}
|
|
4807
6243
|
// src/zig.ts
|
|
4808
6244
|
import { dlopen, toArrayBuffer as toArrayBuffer2, JSCallback, ptr } from "bun:ffi";
|
|
4809
|
-
import { existsSync } from "fs";
|
|
6245
|
+
import { existsSync as existsSync2 } from "fs";
|
|
4810
6246
|
|
|
4811
6247
|
// src/buffer.ts
|
|
4812
6248
|
import { toArrayBuffer } from "bun:ffi";
|
|
@@ -5007,9 +6443,24 @@ class OptimizedBuffer {
|
|
|
5007
6443
|
// src/zig.ts
|
|
5008
6444
|
var module = await import(`@opentui/core-${process.platform}-${process.arch}/index.ts`);
|
|
5009
6445
|
var targetLibPath = module.default;
|
|
5010
|
-
if (
|
|
6446
|
+
if (/\$bunfs/.test(targetLibPath)) {
|
|
6447
|
+
targetLibPath = targetLibPath.replace("../", "");
|
|
6448
|
+
}
|
|
6449
|
+
if (!existsSync2(targetLibPath)) {
|
|
5011
6450
|
throw new Error(`opentui is not supported on the current platform: ${process.platform}-${process.arch}`);
|
|
5012
6451
|
}
|
|
6452
|
+
registerEnvVar({
|
|
6453
|
+
name: "OTUI_DEBUG_FFI",
|
|
6454
|
+
description: "Enable debug logging for the FFI bindings.",
|
|
6455
|
+
type: "boolean",
|
|
6456
|
+
default: false
|
|
6457
|
+
});
|
|
6458
|
+
registerEnvVar({
|
|
6459
|
+
name: "OTUI_TRACE_FFI",
|
|
6460
|
+
description: "Enable tracing for the FFI bindings.",
|
|
6461
|
+
type: "boolean",
|
|
6462
|
+
default: false
|
|
6463
|
+
});
|
|
5013
6464
|
function getOpenTUILib(libPath) {
|
|
5014
6465
|
const resolvedLibPath = libPath || targetLibPath;
|
|
5015
6466
|
const rawSymbols = dlopen(resolvedLibPath, {
|
|
@@ -5057,6 +6508,10 @@ function getOpenTUILib(libPath) {
|
|
|
5057
6508
|
args: ["ptr"],
|
|
5058
6509
|
returns: "ptr"
|
|
5059
6510
|
},
|
|
6511
|
+
queryPixelResolution: {
|
|
6512
|
+
args: ["ptr"],
|
|
6513
|
+
returns: "void"
|
|
6514
|
+
},
|
|
5060
6515
|
createOptimizedBuffer: {
|
|
5061
6516
|
args: ["u32", "u32", "bool", "u8", "ptr", "usize"],
|
|
5062
6517
|
returns: "ptr"
|
|
@@ -5346,7 +6801,7 @@ function getOpenTUILib(libPath) {
|
|
|
5346
6801
|
returns: "void"
|
|
5347
6802
|
}
|
|
5348
6803
|
});
|
|
5349
|
-
if (
|
|
6804
|
+
if (env.OTUI_DEBUG_FFI || env.OTUI_TRACE_FFI) {
|
|
5350
6805
|
return {
|
|
5351
6806
|
symbols: convertToDebugSymbols(rawSymbols.symbols)
|
|
5352
6807
|
};
|
|
@@ -5360,7 +6815,7 @@ function convertToDebugSymbols(symbols) {
|
|
|
5360
6815
|
Object.entries(symbols).forEach(([key, value]) => {
|
|
5361
6816
|
debugSymbols[key] = value;
|
|
5362
6817
|
});
|
|
5363
|
-
if (
|
|
6818
|
+
if (env.OTUI_DEBUG_FFI) {
|
|
5364
6819
|
Object.entries(symbols).forEach(([key, value]) => {
|
|
5365
6820
|
if (typeof value === "function") {
|
|
5366
6821
|
debugSymbols[key] = (...args) => {
|
|
@@ -5372,7 +6827,7 @@ function convertToDebugSymbols(symbols) {
|
|
|
5372
6827
|
}
|
|
5373
6828
|
});
|
|
5374
6829
|
}
|
|
5375
|
-
if (
|
|
6830
|
+
if (env.OTUI_TRACE_FFI) {
|
|
5376
6831
|
hasTracing = true;
|
|
5377
6832
|
Object.entries(symbols).forEach(([key, value]) => {
|
|
5378
6833
|
if (typeof value === "function") {
|
|
@@ -5734,6 +7189,9 @@ class FFIRenderLib {
|
|
|
5734
7189
|
setupTerminal(renderer, useAlternateScreen) {
|
|
5735
7190
|
this.opentui.symbols.setupTerminal(renderer, useAlternateScreen);
|
|
5736
7191
|
}
|
|
7192
|
+
queryPixelResolution(renderer) {
|
|
7193
|
+
this.opentui.symbols.queryPixelResolution(renderer);
|
|
7194
|
+
}
|
|
5737
7195
|
createTextBuffer(widthMethod) {
|
|
5738
7196
|
const widthMethodCode = widthMethod === "wcwidth" ? 0 : 1;
|
|
5739
7197
|
const bufferPtr = this.opentui.symbols.createTextBuffer(widthMethodCode);
|
|
@@ -6092,7 +7550,7 @@ class TextBuffer {
|
|
|
6092
7550
|
}
|
|
6093
7551
|
|
|
6094
7552
|
// src/Renderable.ts
|
|
6095
|
-
import { EventEmitter as
|
|
7553
|
+
import { EventEmitter as EventEmitter4 } from "events";
|
|
6096
7554
|
|
|
6097
7555
|
// src/lib/renderable.validations.ts
|
|
6098
7556
|
function validateOptions(id, options) {
|
|
@@ -6185,7 +7643,7 @@ function isRenderable(obj) {
|
|
|
6185
7643
|
return !!obj?.[BrandedRenderable];
|
|
6186
7644
|
}
|
|
6187
7645
|
|
|
6188
|
-
class BaseRenderable extends
|
|
7646
|
+
class BaseRenderable extends EventEmitter4 {
|
|
6189
7647
|
[BrandedRenderable] = true;
|
|
6190
7648
|
static renderableNumber = 1;
|
|
6191
7649
|
_id;
|
|
@@ -6222,6 +7680,9 @@ class BaseRenderable extends EventEmitter2 {
|
|
|
6222
7680
|
this._visible = value;
|
|
6223
7681
|
}
|
|
6224
7682
|
}
|
|
7683
|
+
var yogaConfig = src_default.Config.create();
|
|
7684
|
+
yogaConfig.setUseWebDefaults(false);
|
|
7685
|
+
yogaConfig.setPointScaleFactor(1);
|
|
6225
7686
|
|
|
6226
7687
|
class Renderable extends BaseRenderable {
|
|
6227
7688
|
static renderablesByNumber = new Map;
|
|
@@ -6242,11 +7703,13 @@ class Renderable extends BaseRenderable {
|
|
|
6242
7703
|
_focusable = false;
|
|
6243
7704
|
_focused = false;
|
|
6244
7705
|
keypressHandler = null;
|
|
7706
|
+
pasteHandler = null;
|
|
6245
7707
|
_live = false;
|
|
6246
7708
|
_liveCount = 0;
|
|
6247
7709
|
_sizeChangeListener = undefined;
|
|
6248
7710
|
_mouseListener = null;
|
|
6249
7711
|
_mouseListeners = {};
|
|
7712
|
+
_pasteListener = undefined;
|
|
6250
7713
|
_keyListeners = {};
|
|
6251
7714
|
yogaNode;
|
|
6252
7715
|
_positionType = "relative";
|
|
@@ -6283,7 +7746,7 @@ class Renderable extends BaseRenderable {
|
|
|
6283
7746
|
this.buffered = options.buffered ?? false;
|
|
6284
7747
|
this._live = options.live ?? false;
|
|
6285
7748
|
this._liveCount = this._live && this._visible ? 1 : 0;
|
|
6286
|
-
this.yogaNode = src_default.Node.create();
|
|
7749
|
+
this.yogaNode = src_default.Node.create(yogaConfig);
|
|
6287
7750
|
this.yogaNode.setDisplay(this._visible ? Display.Flex : Display.None);
|
|
6288
7751
|
this.setupYogaProperties(options);
|
|
6289
7752
|
this.applyEventOptions(options);
|
|
@@ -6352,11 +7815,18 @@ class Renderable extends BaseRenderable {
|
|
|
6352
7815
|
this.requestRender();
|
|
6353
7816
|
this.keypressHandler = (key) => {
|
|
6354
7817
|
this._keyListeners["down"]?.(key);
|
|
6355
|
-
if (this.handleKeyPress) {
|
|
7818
|
+
if (!key.defaultPrevented && this.handleKeyPress) {
|
|
6356
7819
|
this.handleKeyPress(key);
|
|
6357
7820
|
}
|
|
6358
7821
|
};
|
|
6359
|
-
this.
|
|
7822
|
+
this.pasteHandler = (event) => {
|
|
7823
|
+
this._pasteListener?.call(this, event.text);
|
|
7824
|
+
if (!event.defaultPrevented && this.handlePaste) {
|
|
7825
|
+
this.handlePaste(event.text);
|
|
7826
|
+
}
|
|
7827
|
+
};
|
|
7828
|
+
this.ctx._internalKeyInput.onInternal("keypress", this.keypressHandler);
|
|
7829
|
+
this.ctx._internalKeyInput.onInternal("paste", this.pasteHandler);
|
|
6360
7830
|
this.emit("focused" /* FOCUSED */);
|
|
6361
7831
|
}
|
|
6362
7832
|
blur() {
|
|
@@ -6365,9 +7835,13 @@ class Renderable extends BaseRenderable {
|
|
|
6365
7835
|
this._focused = false;
|
|
6366
7836
|
this.requestRender();
|
|
6367
7837
|
if (this.keypressHandler) {
|
|
6368
|
-
this.ctx.
|
|
7838
|
+
this.ctx._internalKeyInput.offInternal("keypress", this.keypressHandler);
|
|
6369
7839
|
this.keypressHandler = null;
|
|
6370
7840
|
}
|
|
7841
|
+
if (this.pasteHandler) {
|
|
7842
|
+
this.ctx._internalKeyInput.offInternal("paste", this.pasteHandler);
|
|
7843
|
+
this.pasteHandler = null;
|
|
7844
|
+
}
|
|
6371
7845
|
this.emit("blurred" /* BLURRED */);
|
|
6372
7846
|
}
|
|
6373
7847
|
get focused() {
|
|
@@ -6396,9 +7870,11 @@ class Renderable extends BaseRenderable {
|
|
|
6396
7870
|
for (const child of this._childrenInLayoutOrder) {
|
|
6397
7871
|
if (child.id === id)
|
|
6398
7872
|
return child;
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
7873
|
+
if (isRenderable(child)) {
|
|
7874
|
+
const found = child.findDescendantById(id);
|
|
7875
|
+
if (found)
|
|
7876
|
+
return found;
|
|
7877
|
+
}
|
|
6402
7878
|
}
|
|
6403
7879
|
return;
|
|
6404
7880
|
}
|
|
@@ -6551,8 +8027,7 @@ class Renderable extends BaseRenderable {
|
|
|
6551
8027
|
if (options.flexShrink !== undefined) {
|
|
6552
8028
|
node.setFlexShrink(options.flexShrink);
|
|
6553
8029
|
} else {
|
|
6554
|
-
|
|
6555
|
-
node.setFlexShrink(shrinkValue);
|
|
8030
|
+
node.setFlexShrink(1);
|
|
6556
8031
|
}
|
|
6557
8032
|
if (options.flexDirection !== undefined) {
|
|
6558
8033
|
node.setFlexDirection(parseFlexDirection(options.flexDirection));
|
|
@@ -6965,10 +8440,11 @@ class Renderable extends BaseRenderable {
|
|
|
6965
8440
|
if (renderable.parent === this) {
|
|
6966
8441
|
this.yogaNode.removeChild(renderable.getLayoutNode());
|
|
6967
8442
|
this._childrenInLayoutOrder.splice(this._childrenInLayoutOrder.indexOf(renderable), 1);
|
|
6968
|
-
} else
|
|
8443
|
+
} else {
|
|
6969
8444
|
this.replaceParent(renderable);
|
|
6970
8445
|
this.needsZIndexSort = true;
|
|
6971
8446
|
this.renderableMapById.set(renderable.id, renderable);
|
|
8447
|
+
this._childrenInZIndexOrder.push(renderable);
|
|
6972
8448
|
if (typeof renderable.onLifecyclePass === "function") {
|
|
6973
8449
|
this._ctx.registerLifecyclePass(renderable);
|
|
6974
8450
|
}
|
|
@@ -7013,6 +8489,16 @@ class Renderable extends BaseRenderable {
|
|
|
7013
8489
|
if (zIndexIndex !== -1) {
|
|
7014
8490
|
this._childrenInZIndexOrder.splice(zIndexIndex, 1);
|
|
7015
8491
|
}
|
|
8492
|
+
if (this._forceLayoutUpdateFor) {
|
|
8493
|
+
const forceIndex = this._forceLayoutUpdateFor.findIndex((obj2) => obj2.id === id);
|
|
8494
|
+
if (forceIndex !== -1) {
|
|
8495
|
+
this._forceLayoutUpdateFor?.splice(forceIndex, 1);
|
|
8496
|
+
}
|
|
8497
|
+
}
|
|
8498
|
+
const newChildIndex = this._newChildren.findIndex((obj2) => obj2.id === id);
|
|
8499
|
+
if (newChildIndex !== -1) {
|
|
8500
|
+
this._newChildren?.splice(newChildIndex, 1);
|
|
8501
|
+
}
|
|
7016
8502
|
this.childrenPrimarySortDirty = true;
|
|
7017
8503
|
}
|
|
7018
8504
|
}
|
|
@@ -7121,7 +8607,8 @@ class Renderable extends BaseRenderable {
|
|
|
7121
8607
|
} catch (e) {}
|
|
7122
8608
|
}
|
|
7123
8609
|
destroyRecursively() {
|
|
7124
|
-
|
|
8610
|
+
const children = [...this._childrenInLayoutOrder];
|
|
8611
|
+
for (const child of children) {
|
|
7125
8612
|
child.destroyRecursively();
|
|
7126
8613
|
}
|
|
7127
8614
|
this.destroy();
|
|
@@ -7196,6 +8683,12 @@ class Renderable extends BaseRenderable {
|
|
|
7196
8683
|
else
|
|
7197
8684
|
delete this._mouseListeners["scroll"];
|
|
7198
8685
|
}
|
|
8686
|
+
set onPaste(handler) {
|
|
8687
|
+
this._pasteListener = handler;
|
|
8688
|
+
}
|
|
8689
|
+
get onPaste() {
|
|
8690
|
+
return this._pasteListener;
|
|
8691
|
+
}
|
|
7199
8692
|
set onKeyDown(handler) {
|
|
7200
8693
|
if (handler)
|
|
7201
8694
|
this._keyListeners["down"] = handler;
|
|
@@ -7222,23 +8715,20 @@ class Renderable extends BaseRenderable {
|
|
|
7222
8715
|
this.onMouseOver = options.onMouseOver;
|
|
7223
8716
|
this.onMouseOut = options.onMouseOut;
|
|
7224
8717
|
this.onMouseScroll = options.onMouseScroll;
|
|
8718
|
+
this.onPaste = options.onPaste;
|
|
7225
8719
|
this.onKeyDown = options.onKeyDown;
|
|
7226
8720
|
this.onSizeChange = options.onSizeChange;
|
|
7227
8721
|
}
|
|
7228
8722
|
}
|
|
7229
8723
|
|
|
7230
8724
|
class RootRenderable extends Renderable {
|
|
7231
|
-
yogaConfig;
|
|
7232
8725
|
renderList = [];
|
|
7233
8726
|
constructor(ctx) {
|
|
7234
8727
|
super(ctx, { id: "__root__", zIndex: 0, visible: true, width: ctx.width, height: ctx.height, enableLayout: true });
|
|
7235
|
-
this.yogaConfig = src_default.Config.create();
|
|
7236
|
-
this.yogaConfig.setUseWebDefaults(false);
|
|
7237
|
-
this.yogaConfig.setPointScaleFactor(1);
|
|
7238
8728
|
if (this.yogaNode) {
|
|
7239
8729
|
this.yogaNode.free();
|
|
7240
8730
|
}
|
|
7241
|
-
this.yogaNode = src_default.Node.create(
|
|
8731
|
+
this.yogaNode = src_default.Node.create(yogaConfig);
|
|
7242
8732
|
this.yogaNode.setWidth(ctx.width);
|
|
7243
8733
|
this.yogaNode.setHeight(ctx.height);
|
|
7244
8734
|
this.yogaNode.setFlexDirection(FlexDirection.Column);
|
|
@@ -7288,11 +8778,6 @@ class RootRenderable extends Renderable {
|
|
|
7288
8778
|
this.height = height;
|
|
7289
8779
|
this.emit("resized" /* RESIZED */, { width, height });
|
|
7290
8780
|
}
|
|
7291
|
-
destroySelf() {
|
|
7292
|
-
try {
|
|
7293
|
-
this.yogaConfig.free();
|
|
7294
|
-
} catch (error) {}
|
|
7295
|
-
}
|
|
7296
8781
|
}
|
|
7297
8782
|
|
|
7298
8783
|
// src/renderables/composition/vnode.ts
|
|
@@ -7462,17 +8947,17 @@ function delegate(mapping, vnode) {
|
|
|
7462
8947
|
}
|
|
7463
8948
|
|
|
7464
8949
|
// src/console.ts
|
|
7465
|
-
import { EventEmitter as
|
|
8950
|
+
import { EventEmitter as EventEmitter6 } from "events";
|
|
7466
8951
|
import { Console } from "console";
|
|
7467
8952
|
import fs from "fs";
|
|
7468
|
-
import
|
|
8953
|
+
import path4 from "path";
|
|
7469
8954
|
import util2 from "util";
|
|
7470
8955
|
|
|
7471
8956
|
// src/lib/output.capture.ts
|
|
7472
8957
|
import { Writable } from "stream";
|
|
7473
|
-
import { EventEmitter as
|
|
8958
|
+
import { EventEmitter as EventEmitter5 } from "events";
|
|
7474
8959
|
|
|
7475
|
-
class Capture extends
|
|
8960
|
+
class Capture extends EventEmitter5 {
|
|
7476
8961
|
output = [];
|
|
7477
8962
|
constructor() {
|
|
7478
8963
|
super();
|
|
@@ -7535,8 +9020,20 @@ function getCallerInfo() {
|
|
|
7535
9020
|
return { functionName, fullPath, fileName, lineNumber, columnNumber };
|
|
7536
9021
|
}
|
|
7537
9022
|
var capture = singleton("ConsoleCapture", () => new Capture);
|
|
9023
|
+
registerEnvVar({
|
|
9024
|
+
name: "OTUI_USE_CONSOLE",
|
|
9025
|
+
description: "Whether to use the console. Will not capture console output if set to false.",
|
|
9026
|
+
type: "boolean",
|
|
9027
|
+
default: true
|
|
9028
|
+
});
|
|
9029
|
+
registerEnvVar({
|
|
9030
|
+
name: "SHOW_CONSOLE",
|
|
9031
|
+
description: "Show the console at startup if set to true.",
|
|
9032
|
+
type: "boolean",
|
|
9033
|
+
default: false
|
|
9034
|
+
});
|
|
7538
9035
|
|
|
7539
|
-
class TerminalConsoleCache extends
|
|
9036
|
+
class TerminalConsoleCache extends EventEmitter6 {
|
|
7540
9037
|
_cachedLogs = [];
|
|
7541
9038
|
MAX_CACHE_SIZE = 1000;
|
|
7542
9039
|
_collectCallerInfo = false;
|
|
@@ -7552,7 +9049,7 @@ class TerminalConsoleCache extends EventEmitter4 {
|
|
|
7552
9049
|
this.overrideConsoleMethods();
|
|
7553
9050
|
}
|
|
7554
9051
|
setupConsoleCapture() {
|
|
7555
|
-
if (
|
|
9052
|
+
if (!env.OTUI_USE_CONSOLE)
|
|
7556
9053
|
return;
|
|
7557
9054
|
const mockStdout = new CapturedWritableStream("stdout", capture);
|
|
7558
9055
|
const mockStderr = new CapturedWritableStream("stderr", capture);
|
|
@@ -7657,7 +9154,7 @@ var DEFAULT_CONSOLE_OPTIONS = {
|
|
|
7657
9154
|
};
|
|
7658
9155
|
var INDENT_WIDTH = 2;
|
|
7659
9156
|
|
|
7660
|
-
class TerminalConsole extends
|
|
9157
|
+
class TerminalConsole extends EventEmitter6 {
|
|
7661
9158
|
isVisible = false;
|
|
7662
9159
|
isFocused = false;
|
|
7663
9160
|
renderer;
|
|
@@ -7717,7 +9214,7 @@ class TerminalConsole extends EventEmitter4 {
|
|
|
7717
9214
|
terminalConsoleCache.on("entry", (logEntry) => {
|
|
7718
9215
|
this._handleNewLog(logEntry);
|
|
7719
9216
|
});
|
|
7720
|
-
if (
|
|
9217
|
+
if (env.SHOW_CONSOLE) {
|
|
7721
9218
|
this.show();
|
|
7722
9219
|
}
|
|
7723
9220
|
}
|
|
@@ -8096,7 +9593,7 @@ class TerminalConsole extends EventEmitter4 {
|
|
|
8096
9593
|
try {
|
|
8097
9594
|
const timestamp = Date.now();
|
|
8098
9595
|
const filename = `_console_${timestamp}.log`;
|
|
8099
|
-
const filepath =
|
|
9596
|
+
const filepath = path4.join(process.cwd(), filename);
|
|
8100
9597
|
const allLogEntries = [...this._allLogEntries, ...terminalConsoleCache.cachedLogs];
|
|
8101
9598
|
const logLines = [];
|
|
8102
9599
|
for (const [date, level, args, callerInfo] of allLogEntries) {
|
|
@@ -8116,39 +9613,8 @@ class TerminalConsole extends EventEmitter4 {
|
|
|
8116
9613
|
}
|
|
8117
9614
|
}
|
|
8118
9615
|
|
|
8119
|
-
// src/ansi.ts
|
|
8120
|
-
var ANSI = {
|
|
8121
|
-
switchToAlternateScreen: "\x1B[?1049h",
|
|
8122
|
-
switchToMainScreen: "\x1B[?1049l",
|
|
8123
|
-
reset: "\x1B[0m",
|
|
8124
|
-
hideCursor: "\x1B[?25l",
|
|
8125
|
-
showCursor: "\x1B[?25h",
|
|
8126
|
-
resetCursorColor: "\x1B]12;default\x07",
|
|
8127
|
-
saveCursorState: "\x1B[s",
|
|
8128
|
-
restoreCursorState: "\x1B[u",
|
|
8129
|
-
queryPixelSize: "\x1B[14t",
|
|
8130
|
-
scrollDown: (lines) => `\x1B[${lines}T`,
|
|
8131
|
-
scrollUp: (lines) => `\x1B[${lines}S`,
|
|
8132
|
-
moveCursor: (row, col) => `\x1B[${row};${col}H`,
|
|
8133
|
-
moveCursorAndClear: (row, col) => `\x1B[${row};${col}H\x1B[J`,
|
|
8134
|
-
clearFromCursor: "\x1B[J",
|
|
8135
|
-
setRgbBackground: (r, g, b) => `\x1B[48;2;${r};${g};${b}m`,
|
|
8136
|
-
resetBackground: "\x1B[49m",
|
|
8137
|
-
enableMouseTracking: "\x1B[?1000h",
|
|
8138
|
-
disableMouseTracking: "\x1B[?1000l",
|
|
8139
|
-
enableButtonEventTracking: "\x1B[?1002h",
|
|
8140
|
-
disableButtonEventTracking: "\x1B[?1002l",
|
|
8141
|
-
enableAnyEventTracking: "\x1B[?1003h",
|
|
8142
|
-
disableAnyEventTracking: "\x1B[?1003l",
|
|
8143
|
-
enableSGRMouseMode: "\x1B[?1006h",
|
|
8144
|
-
disableSGRMouseMode: "\x1B[?1006l",
|
|
8145
|
-
makeRoomForRenderer: (height) => `
|
|
8146
|
-
`.repeat(height) + `\x1B[${height}A`,
|
|
8147
|
-
clearRendererSpace: (height) => `\x1B[${height}A\x1B[1G\x1B[J`
|
|
8148
|
-
};
|
|
8149
|
-
|
|
8150
9616
|
// src/renderer.ts
|
|
8151
|
-
import { EventEmitter as
|
|
9617
|
+
import { EventEmitter as EventEmitter7 } from "events";
|
|
8152
9618
|
|
|
8153
9619
|
// src/lib/objects-in-viewport.ts
|
|
8154
9620
|
function getObjectsInViewport(viewport, objects, direction = "column", padding = 10, minTriggerSize = 16) {
|
|
@@ -8226,6 +9692,31 @@ function getObjectsInViewport(viewport, objects, direction = "column", padding =
|
|
|
8226
9692
|
}
|
|
8227
9693
|
|
|
8228
9694
|
// src/renderer.ts
|
|
9695
|
+
registerEnvVar({
|
|
9696
|
+
name: "OTUI_DUMP_CAPTURES",
|
|
9697
|
+
description: "Dump captured output when the renderer exits.",
|
|
9698
|
+
type: "boolean",
|
|
9699
|
+
default: false
|
|
9700
|
+
});
|
|
9701
|
+
registerEnvVar({
|
|
9702
|
+
name: "OTUI_NO_NATIVE_RENDER",
|
|
9703
|
+
description: "Disable native rendering. This will not actually output ansi and is useful for debugging.",
|
|
9704
|
+
type: "boolean",
|
|
9705
|
+
default: false
|
|
9706
|
+
});
|
|
9707
|
+
registerEnvVar({
|
|
9708
|
+
name: "OTUI_USE_ALTERNATE_SCREEN",
|
|
9709
|
+
description: "Whether to use the console. Will not capture console output if set to false.",
|
|
9710
|
+
type: "boolean",
|
|
9711
|
+
default: true
|
|
9712
|
+
});
|
|
9713
|
+
registerEnvVar({
|
|
9714
|
+
name: "OTUI_OVERRIDE_STDOUT",
|
|
9715
|
+
description: "Override the stdout stream. This is useful for debugging.",
|
|
9716
|
+
type: "boolean",
|
|
9717
|
+
default: true
|
|
9718
|
+
});
|
|
9719
|
+
|
|
8229
9720
|
class MouseEvent {
|
|
8230
9721
|
type;
|
|
8231
9722
|
button;
|
|
@@ -8277,9 +9768,27 @@ singleton("ProcessExitSignals", () => {
|
|
|
8277
9768
|
});
|
|
8278
9769
|
});
|
|
8279
9770
|
});
|
|
9771
|
+
var rendererTracker = singleton("RendererTracker", () => {
|
|
9772
|
+
const renderers = new Set;
|
|
9773
|
+
return {
|
|
9774
|
+
addRenderer: (renderer) => {
|
|
9775
|
+
renderers.add(renderer);
|
|
9776
|
+
},
|
|
9777
|
+
removeRenderer: (renderer) => {
|
|
9778
|
+
renderers.delete(renderer);
|
|
9779
|
+
if (renderers.size === 0) {
|
|
9780
|
+
process.stdin.pause();
|
|
9781
|
+
if (hasSingleton("tree-sitter-client")) {
|
|
9782
|
+
getTreeSitterClient().destroy();
|
|
9783
|
+
destroySingleton("tree-sitter-client");
|
|
9784
|
+
}
|
|
9785
|
+
}
|
|
9786
|
+
}
|
|
9787
|
+
};
|
|
9788
|
+
});
|
|
8280
9789
|
async function createCliRenderer(config = {}) {
|
|
8281
9790
|
if (process.argv.includes("--delay-start")) {
|
|
8282
|
-
await new Promise((
|
|
9791
|
+
await new Promise((resolve4) => setTimeout(resolve4, 5000));
|
|
8283
9792
|
}
|
|
8284
9793
|
const stdin = config.stdin || process.stdin;
|
|
8285
9794
|
const stdout = config.stdout || process.stdout;
|
|
@@ -8306,14 +9815,14 @@ var CliRenderEvents;
|
|
|
8306
9815
|
((CliRenderEvents2) => {
|
|
8307
9816
|
CliRenderEvents2["DEBUG_OVERLAY_TOGGLE"] = "debugOverlay:toggle";
|
|
8308
9817
|
})(CliRenderEvents ||= {});
|
|
8309
|
-
class CliRenderer extends
|
|
9818
|
+
class CliRenderer extends EventEmitter7 {
|
|
8310
9819
|
static animationFrameId = 0;
|
|
8311
9820
|
lib;
|
|
8312
9821
|
rendererPtr;
|
|
8313
9822
|
stdin;
|
|
8314
9823
|
stdout;
|
|
8315
9824
|
exitOnCtrlC;
|
|
8316
|
-
|
|
9825
|
+
_isDestroyed = false;
|
|
8317
9826
|
nextRenderBuffer;
|
|
8318
9827
|
currentRenderBuffer;
|
|
8319
9828
|
_isRunning = false;
|
|
@@ -8367,7 +9876,7 @@ class CliRenderer extends EventEmitter5 {
|
|
|
8367
9876
|
resizeDebounceDelay = 100;
|
|
8368
9877
|
enableMouseMovement = false;
|
|
8369
9878
|
_useMouse = true;
|
|
8370
|
-
_useAlternateScreen =
|
|
9879
|
+
_useAlternateScreen = env.OTUI_USE_ALTERNATE_SCREEN;
|
|
8371
9880
|
capturedRenderable;
|
|
8372
9881
|
lastOverRenderableNum = 0;
|
|
8373
9882
|
lastOverRenderable;
|
|
@@ -8398,9 +9907,9 @@ class CliRenderer extends EventEmitter5 {
|
|
|
8398
9907
|
handleError = ((error) => {
|
|
8399
9908
|
this.stop();
|
|
8400
9909
|
this.destroy();
|
|
8401
|
-
new Promise((
|
|
9910
|
+
new Promise((resolve4) => {
|
|
8402
9911
|
setTimeout(() => {
|
|
8403
|
-
|
|
9912
|
+
resolve4(true);
|
|
8404
9913
|
}, 100);
|
|
8405
9914
|
}).then(() => {
|
|
8406
9915
|
this.realStdoutWrite.call(this.stdout, `
|
|
@@ -8408,17 +9917,7 @@ class CliRenderer extends EventEmitter5 {
|
|
|
8408
9917
|
this.realStdoutWrite.call(this.stdout, `
|
|
8409
9918
|
=== FATAL ERROR OCCURRED ===
|
|
8410
9919
|
`);
|
|
8411
|
-
this.
|
|
8412
|
-
`);
|
|
8413
|
-
this.realStdoutWrite.call(this.stdout, this.console.getCachedLogs());
|
|
8414
|
-
this.realStdoutWrite.call(this.stdout, `
|
|
8415
|
-
Captured output:
|
|
8416
|
-
`);
|
|
8417
|
-
const capturedOutput = capture.claimOutput();
|
|
8418
|
-
if (capturedOutput) {
|
|
8419
|
-
this.realStdoutWrite.call(this.stdout, capturedOutput + `
|
|
8420
|
-
`);
|
|
8421
|
-
}
|
|
9920
|
+
this.dumpOutputCache();
|
|
8422
9921
|
this.realStdoutWrite.call(this.stdout, `
|
|
8423
9922
|
Error details:
|
|
8424
9923
|
`);
|
|
@@ -8431,14 +9930,39 @@ Error details:
|
|
|
8431
9930
|
process.exit(1);
|
|
8432
9931
|
});
|
|
8433
9932
|
}).bind(this);
|
|
9933
|
+
dumpOutputCache(optionalMessage = "") {
|
|
9934
|
+
const cachedLogs = this.console.getCachedLogs();
|
|
9935
|
+
const capturedOutput = capture.claimOutput();
|
|
9936
|
+
if (capturedOutput.length > 0 || cachedLogs.length > 0) {
|
|
9937
|
+
this.realStdoutWrite.call(this.stdout, optionalMessage);
|
|
9938
|
+
}
|
|
9939
|
+
if (cachedLogs.length > 0) {
|
|
9940
|
+
this.realStdoutWrite.call(this.stdout, `Console cache:
|
|
9941
|
+
`);
|
|
9942
|
+
this.realStdoutWrite.call(this.stdout, cachedLogs);
|
|
9943
|
+
}
|
|
9944
|
+
if (capturedOutput.length > 0) {
|
|
9945
|
+
this.realStdoutWrite.call(this.stdout, `
|
|
9946
|
+
Captured output:
|
|
9947
|
+
`);
|
|
9948
|
+
this.realStdoutWrite.call(this.stdout, capturedOutput + `
|
|
9949
|
+
`);
|
|
9950
|
+
}
|
|
9951
|
+
this.realStdoutWrite.call(this.stdout, ANSI.reset);
|
|
9952
|
+
}
|
|
8434
9953
|
exitHandler = (() => {
|
|
8435
9954
|
this.destroy();
|
|
9955
|
+
if (env.OTUI_DUMP_CAPTURES) {
|
|
9956
|
+
this.dumpOutputCache(`=== CAPTURED OUTPUT ===
|
|
9957
|
+
`);
|
|
9958
|
+
}
|
|
8436
9959
|
}).bind(this);
|
|
8437
9960
|
warningHandler = ((warning) => {
|
|
8438
9961
|
console.warn(JSON.stringify(warning.message, null, 2));
|
|
8439
9962
|
}).bind(this);
|
|
8440
9963
|
constructor(lib, rendererPtr, stdin, stdout, width, height, config = {}) {
|
|
8441
9964
|
super();
|
|
9965
|
+
rendererTracker.addRenderer(this);
|
|
8442
9966
|
this.stdin = stdin;
|
|
8443
9967
|
this.stdout = stdout;
|
|
8444
9968
|
this.realStdoutWrite = stdout.write;
|
|
@@ -8464,7 +9988,7 @@ Error details:
|
|
|
8464
9988
|
this.maxStatSamples = config.maxStatSamples || 300;
|
|
8465
9989
|
this.enableMouseMovement = config.enableMouseMovement || true;
|
|
8466
9990
|
this._useMouse = config.useMouse ?? true;
|
|
8467
|
-
this._useAlternateScreen = config.useAlternateScreen ??
|
|
9991
|
+
this._useAlternateScreen = config.useAlternateScreen ?? env.OTUI_USE_ALTERNATE_SCREEN;
|
|
8468
9992
|
this.nextRenderBuffer = this.lib.getNextBuffer(this.rendererPtr);
|
|
8469
9993
|
this.currentRenderBuffer = this.lib.getCurrentBuffer(this.rendererPtr);
|
|
8470
9994
|
this.postProcessFns = config.postProcessFns || [];
|
|
@@ -8472,7 +9996,9 @@ Error details:
|
|
|
8472
9996
|
if (this.memorySnapshotInterval > 0) {
|
|
8473
9997
|
this.startMemorySnapshotTimer();
|
|
8474
9998
|
}
|
|
8475
|
-
|
|
9999
|
+
if (env.OTUI_OVERRIDE_STDOUT) {
|
|
10000
|
+
this.stdout.write = this.interceptStdoutWrite.bind(this);
|
|
10001
|
+
}
|
|
8476
10002
|
process.on("SIGWINCH", this.sigwinchHandler);
|
|
8477
10003
|
process.on("warning", this.warningHandler);
|
|
8478
10004
|
process.on("uncaughtException", this.handleError);
|
|
@@ -8480,7 +10006,7 @@ Error details:
|
|
|
8480
10006
|
process.on("exit", this.exitHandler);
|
|
8481
10007
|
this._console = new TerminalConsole(this, config.consoleOptions);
|
|
8482
10008
|
this.useConsole = config.useConsole ?? true;
|
|
8483
|
-
this._keyHandler = new
|
|
10009
|
+
this._keyHandler = new InternalKeyHandler(this.stdin, config.useKittyKeyboard ?? false);
|
|
8484
10010
|
global.requestAnimationFrame = (callback) => {
|
|
8485
10011
|
const id = CliRenderer.animationFrameId++;
|
|
8486
10012
|
this.animationRequest.set(id, callback);
|
|
@@ -8495,7 +10021,7 @@ Error details:
|
|
|
8495
10021
|
global.window = {};
|
|
8496
10022
|
}
|
|
8497
10023
|
global.window.requestAnimationFrame = requestAnimationFrame;
|
|
8498
|
-
if (
|
|
10024
|
+
if (env.OTUI_NO_NATIVE_RENDER) {
|
|
8499
10025
|
this.renderNative = () => {
|
|
8500
10026
|
if (this._splitHeight > 0) {
|
|
8501
10027
|
this.flushStdoutCache(this._splitHeight);
|
|
@@ -8504,6 +10030,9 @@ Error details:
|
|
|
8504
10030
|
}
|
|
8505
10031
|
this.setupInput();
|
|
8506
10032
|
}
|
|
10033
|
+
get isDestroyed() {
|
|
10034
|
+
return this._isDestroyed;
|
|
10035
|
+
}
|
|
8507
10036
|
registerLifecyclePass(renderable) {
|
|
8508
10037
|
this.lifecyclePasses.add(renderable);
|
|
8509
10038
|
}
|
|
@@ -8568,6 +10097,9 @@ Error details:
|
|
|
8568
10097
|
get keyInput() {
|
|
8569
10098
|
return this._keyHandler;
|
|
8570
10099
|
}
|
|
10100
|
+
get _internalKeyInput() {
|
|
10101
|
+
return this._keyHandler;
|
|
10102
|
+
}
|
|
8571
10103
|
get terminalWidth() {
|
|
8572
10104
|
return this._terminalWidth;
|
|
8573
10105
|
}
|
|
@@ -8698,21 +10230,16 @@ Error details:
|
|
|
8698
10230
|
if (this._terminalIsSetup)
|
|
8699
10231
|
return;
|
|
8700
10232
|
this._terminalIsSetup = true;
|
|
8701
|
-
|
|
8702
|
-
this.stdin.setRawMode(true);
|
|
8703
|
-
}
|
|
8704
|
-
this.stdin.resume();
|
|
8705
|
-
this.stdin.setEncoding("utf8");
|
|
8706
|
-
await new Promise((resolve) => {
|
|
10233
|
+
await new Promise((resolve4) => {
|
|
8707
10234
|
const timeout = setTimeout(() => {
|
|
8708
10235
|
this.stdin.off("data", capListener);
|
|
8709
|
-
|
|
10236
|
+
resolve4(true);
|
|
8710
10237
|
}, 100);
|
|
8711
10238
|
const capListener = (str) => {
|
|
8712
10239
|
clearTimeout(timeout);
|
|
8713
10240
|
this.lib.processCapabilityResponse(this.rendererPtr, str);
|
|
8714
10241
|
this.stdin.off("data", capListener);
|
|
8715
|
-
|
|
10242
|
+
resolve4(true);
|
|
8716
10243
|
};
|
|
8717
10244
|
this.stdin.on("data", capListener);
|
|
8718
10245
|
this.lib.setupTerminal(this.rendererPtr, this._useAlternateScreen);
|
|
@@ -8739,7 +10266,7 @@ Error details:
|
|
|
8739
10266
|
}
|
|
8740
10267
|
if (this.exitOnCtrlC && str === "\x03") {
|
|
8741
10268
|
process.nextTick(() => {
|
|
8742
|
-
|
|
10269
|
+
this.destroy();
|
|
8743
10270
|
});
|
|
8744
10271
|
return;
|
|
8745
10272
|
}
|
|
@@ -8749,6 +10276,11 @@ Error details:
|
|
|
8749
10276
|
this.emit("key", data);
|
|
8750
10277
|
}).bind(this);
|
|
8751
10278
|
setupInput() {
|
|
10279
|
+
if (this.stdin.setRawMode) {
|
|
10280
|
+
this.stdin.setRawMode(true);
|
|
10281
|
+
}
|
|
10282
|
+
this.stdin.resume();
|
|
10283
|
+
this.stdin.setEncoding("utf8");
|
|
8752
10284
|
this.stdin.on("data", this.stdinListener);
|
|
8753
10285
|
}
|
|
8754
10286
|
handleMouseData(data) {
|
|
@@ -8864,7 +10396,7 @@ Error details:
|
|
|
8864
10396
|
return false;
|
|
8865
10397
|
}
|
|
8866
10398
|
takeMemorySnapshot() {
|
|
8867
|
-
if (this.
|
|
10399
|
+
if (this._isDestroyed)
|
|
8868
10400
|
return;
|
|
8869
10401
|
const memoryUsage = process.memoryUsage();
|
|
8870
10402
|
this.lastMemorySnapshot = {
|
|
@@ -8897,7 +10429,7 @@ Error details:
|
|
|
8897
10429
|
}
|
|
8898
10430
|
}
|
|
8899
10431
|
handleResize(width, height) {
|
|
8900
|
-
if (this.
|
|
10432
|
+
if (this._isDestroyed)
|
|
8901
10433
|
return;
|
|
8902
10434
|
if (this._splitHeight > 0) {
|
|
8903
10435
|
this.processResize(width, height);
|
|
@@ -8914,7 +10446,7 @@ Error details:
|
|
|
8914
10446
|
}
|
|
8915
10447
|
queryPixelResolution() {
|
|
8916
10448
|
this.waitingForPixelResolution = true;
|
|
8917
|
-
this.
|
|
10449
|
+
this.lib.queryPixelResolution(this.rendererPtr);
|
|
8918
10450
|
}
|
|
8919
10451
|
processResize(width, height) {
|
|
8920
10452
|
if (width === this._terminalWidth && height === this._terminalHeight)
|
|
@@ -8977,9 +10509,6 @@ Error details:
|
|
|
8977
10509
|
this.lib.setDebugOverlay(this.rendererPtr, this.debugOverlay.enabled, this.debugOverlay.corner);
|
|
8978
10510
|
this.requestRender();
|
|
8979
10511
|
}
|
|
8980
|
-
clearTerminal() {
|
|
8981
|
-
this.lib.clearTerminal(this.rendererPtr);
|
|
8982
|
-
}
|
|
8983
10512
|
setTerminalTitle(title) {
|
|
8984
10513
|
this.lib.setTerminalTitle(this.rendererPtr, title);
|
|
8985
10514
|
}
|
|
@@ -9059,7 +10588,7 @@ Error details:
|
|
|
9059
10588
|
this.controlState = this._isRunning ? "auto_started" /* AUTO_STARTED */ : "idle" /* IDLE */;
|
|
9060
10589
|
}
|
|
9061
10590
|
internalStart() {
|
|
9062
|
-
if (!this._isRunning && !this.
|
|
10591
|
+
if (!this._isRunning && !this._isDestroyed) {
|
|
9063
10592
|
this._isRunning = true;
|
|
9064
10593
|
if (this.memorySnapshotInterval > 0) {
|
|
9065
10594
|
this.startMemorySnapshotTimer();
|
|
@@ -9079,7 +10608,7 @@ Error details:
|
|
|
9079
10608
|
this.internalStop();
|
|
9080
10609
|
}
|
|
9081
10610
|
internalStop() {
|
|
9082
|
-
if (this.isRunning && !this.
|
|
10611
|
+
if (this.isRunning && !this._isDestroyed) {
|
|
9083
10612
|
this._isRunning = false;
|
|
9084
10613
|
if (this.memorySnapshotTimer) {
|
|
9085
10614
|
clearInterval(this.memorySnapshotTimer);
|
|
@@ -9092,32 +10621,41 @@ Error details:
|
|
|
9092
10621
|
}
|
|
9093
10622
|
}
|
|
9094
10623
|
destroy() {
|
|
9095
|
-
this.stdin.removeListener("data", this.stdinListener);
|
|
9096
10624
|
process.removeListener("SIGWINCH", this.sigwinchHandler);
|
|
9097
10625
|
process.removeListener("uncaughtException", this.handleError);
|
|
9098
10626
|
process.removeListener("unhandledRejection", this.handleError);
|
|
9099
|
-
process.removeListener("exit", this.exitHandler);
|
|
9100
10627
|
process.removeListener("warning", this.warningHandler);
|
|
9101
10628
|
capture.removeListener("write", this.captureCallback);
|
|
9102
10629
|
if (this.memorySnapshotTimer) {
|
|
9103
10630
|
clearInterval(this.memorySnapshotTimer);
|
|
9104
10631
|
}
|
|
9105
|
-
if (this.
|
|
9106
|
-
this.stdin.setRawMode(false);
|
|
9107
|
-
}
|
|
9108
|
-
if (this.isDestroyed)
|
|
10632
|
+
if (this._isDestroyed)
|
|
9109
10633
|
return;
|
|
9110
|
-
this.
|
|
10634
|
+
this._isDestroyed = true;
|
|
10635
|
+
if (this.renderTimeout) {
|
|
10636
|
+
clearTimeout(this.renderTimeout);
|
|
10637
|
+
this.renderTimeout = null;
|
|
10638
|
+
}
|
|
10639
|
+
this._isRunning = false;
|
|
9111
10640
|
this.waitingForPixelResolution = false;
|
|
9112
10641
|
this.capturedRenderable = undefined;
|
|
9113
|
-
|
|
10642
|
+
try {
|
|
10643
|
+
this.root.destroyRecursively();
|
|
10644
|
+
} catch (e) {
|
|
10645
|
+
console.error("Error destroying root renderable:", e instanceof Error ? e.stack : String(e));
|
|
10646
|
+
}
|
|
9114
10647
|
this._keyHandler.destroy();
|
|
9115
10648
|
this._console.deactivate();
|
|
9116
10649
|
this.disableStdoutInterception();
|
|
9117
10650
|
if (this._splitHeight > 0) {
|
|
9118
10651
|
this.flushStdoutCache(this._splitHeight, true);
|
|
9119
10652
|
}
|
|
10653
|
+
if (this.stdin.setRawMode) {
|
|
10654
|
+
this.stdin.setRawMode(false);
|
|
10655
|
+
}
|
|
10656
|
+
this.stdin.removeListener("data", this.stdinListener);
|
|
9120
10657
|
this.lib.destroyRenderer(this.rendererPtr);
|
|
10658
|
+
rendererTracker.removeRenderer(this);
|
|
9121
10659
|
}
|
|
9122
10660
|
startRenderLoop() {
|
|
9123
10661
|
if (!this._isRunning)
|
|
@@ -9130,7 +10668,7 @@ Error details:
|
|
|
9130
10668
|
this.loop();
|
|
9131
10669
|
}
|
|
9132
10670
|
async loop() {
|
|
9133
|
-
if (this.rendering || this.
|
|
10671
|
+
if (this.rendering || this._isDestroyed)
|
|
9134
10672
|
return;
|
|
9135
10673
|
this.rendering = true;
|
|
9136
10674
|
if (this.renderTimeout) {
|
|
@@ -9174,15 +10712,17 @@ Error details:
|
|
|
9174
10712
|
postProcessFn(this.nextRenderBuffer, deltaTime);
|
|
9175
10713
|
}
|
|
9176
10714
|
this._console.renderToBuffer(this.nextRenderBuffer);
|
|
9177
|
-
this.
|
|
9178
|
-
|
|
9179
|
-
|
|
9180
|
-
|
|
9181
|
-
this.
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
10715
|
+
if (!this._isDestroyed) {
|
|
10716
|
+
this.renderNative();
|
|
10717
|
+
const overallFrameTime = performance.now() - overallStart;
|
|
10718
|
+
this.lib.updateStats(this.rendererPtr, overallFrameTime, this.renderStats.fps, this.renderStats.frameCallbackTime);
|
|
10719
|
+
if (this.gatherStats) {
|
|
10720
|
+
this.collectStatSample(overallFrameTime);
|
|
10721
|
+
}
|
|
10722
|
+
if (this._isRunning) {
|
|
10723
|
+
const delay = Math.max(1, this.targetFrameTime - Math.floor(overallFrameTime));
|
|
10724
|
+
this.renderTimeout = setTimeout(() => this.loop(), delay);
|
|
10725
|
+
}
|
|
9186
10726
|
}
|
|
9187
10727
|
this.rendering = false;
|
|
9188
10728
|
if (this.immediateRerenderRequested) {
|
|
@@ -9341,7 +10881,7 @@ Error details:
|
|
|
9341
10881
|
}
|
|
9342
10882
|
}
|
|
9343
10883
|
|
|
9344
|
-
export { __toESM, __commonJS, __export, __require, Edge, Gutter, exports_src, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, nonAlphanumericKeys, parseKeypress, KeyHandler,
|
|
10884
|
+
export { __toESM, __commonJS, __export, __require, Edge, Gutter, exports_src, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, nonAlphanumericKeys, parseKeypress, ANSI, KeyEvent, PasteEvent, KeyHandler, InternalKeyHandler, RGBA, hexToRgb, rgbToHex, hsvToRgb, parseColor, fonts, measureText, getCharacterPositions, coordinateToCharacterIndex, renderFontToFrameBuffer, TextAttributes, DebugOverlayCorner, createTextAttributes, visualizeRenderableTree, isStyledText, StyledText, stringToStyledText, black, red, green, yellow, blue, magenta, cyan, white, brightBlack, brightRed, brightGreen, brightYellow, brightBlue, brightMagenta, brightCyan, brightWhite, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, bold, italic, underline, strikethrough, dim, reverse, blink, fg, bg, t, convertThemeToStyles, SyntaxStyle, hastToStyledText, LinearScrollAccel, MacOSScrollAccel, parseAlign, parseBoxSizing, parseDimension, parseDirection, parseDisplay, parseEdge, parseFlexDirection, parseGutter, parseJustify, parseLogLevel, parseMeasureMode, parseOverflow, parsePositionType, parseUnit, parseWrap, MouseParser, Selection, convertGlobalToLocalSelection, ASCIIFontSelectionHelper, envRegistry, registerEnvVar, clearEnvCache, generateEnvMarkdown, generateEnvColored, env, treeSitterToTextChunks, treeSitterToStyledText, addDefaultParsers, TreeSitterClient, DataPathsManager, getDataPaths, extToFiletype, pathToFiletype, main, getTreeSitterClient, TextBuffer, LogLevel2 as LogLevel, setRenderLibPath, resolveRenderLib, OptimizedBuffer, h, isVNode, maybeMakeRenderable, wrapWithDelegates, instantiate, delegate, isValidPercentage, LayoutEvents, RenderableEvents, isRenderable, BaseRenderable, Renderable, RootRenderable, capture, ConsolePosition, TerminalConsole, getObjectsInViewport, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, CliRenderer };
|
|
9345
10885
|
|
|
9346
|
-
//# debugId=
|
|
9347
|
-
//# sourceMappingURL=index-
|
|
10886
|
+
//# debugId=66FAF32C902A5E0B64756E2164756E21
|
|
10887
|
+
//# sourceMappingURL=index-pxa2sv92.js.map
|