@opentui/core 0.1.25 → 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 +8 -7
- package/animation/Timeline.d.ts +2 -1
- 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-6kvgbzah.js → index-pxa2sv92.js} +1426 -117
- package/index-pxa2sv92.js.map +52 -0
- package/index.js +432 -248
- package/index.js.map +13 -11
- package/lib/KeyHandler.d.ts +51 -12
- package/lib/data-paths.d.ts +26 -0
- package/lib/debounce.d.ts +42 -0
- package/lib/env.d.ts +2 -1
- package/lib/hast-styled-text.d.ts +3 -23
- package/lib/index.d.ts +5 -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/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/Code.d.ts +31 -0
- package/renderables/Input.d.ts +2 -2
- 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 +10 -67
- 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 +4 -2
- package/testing/spy.d.ts +7 -0
- package/testing.d.ts +1 -0
- package/testing.js +17 -2
- package/testing.js.map +5 -4
- package/types.d.ts +2 -1
- package/index-6kvgbzah.js.map +0 -39
|
@@ -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") {
|
|
@@ -2191,6 +2195,62 @@ var ANSI = {
|
|
|
2191
2195
|
};
|
|
2192
2196
|
|
|
2193
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;
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2194
2254
|
class KeyHandler extends EventEmitter {
|
|
2195
2255
|
stdin;
|
|
2196
2256
|
useKittyKeyboard;
|
|
@@ -2210,7 +2270,7 @@ class KeyHandler extends EventEmitter {
|
|
|
2210
2270
|
this.pasteBuffer.push(Bun.stripANSI(data));
|
|
2211
2271
|
if (data.endsWith(ANSI.bracketedPasteEnd)) {
|
|
2212
2272
|
this.pasteMode = false;
|
|
2213
|
-
this.emit("paste", this.pasteBuffer.join(""));
|
|
2273
|
+
this.emit("paste", new PasteEvent(this.pasteBuffer.join("")));
|
|
2214
2274
|
this.pasteBuffer = [];
|
|
2215
2275
|
}
|
|
2216
2276
|
return;
|
|
@@ -2218,16 +2278,16 @@ class KeyHandler extends EventEmitter {
|
|
|
2218
2278
|
const parsedKey = parseKeypress(key, { useKittyKeyboard: this.useKittyKeyboard });
|
|
2219
2279
|
switch (parsedKey.eventType) {
|
|
2220
2280
|
case "press":
|
|
2221
|
-
this.emit("keypress", parsedKey);
|
|
2281
|
+
this.emit("keypress", new KeyEvent(parsedKey));
|
|
2222
2282
|
break;
|
|
2223
2283
|
case "repeat":
|
|
2224
|
-
this.emit("keyrepeat", parsedKey);
|
|
2284
|
+
this.emit("keyrepeat", new KeyEvent(parsedKey));
|
|
2225
2285
|
break;
|
|
2226
2286
|
case "release":
|
|
2227
|
-
this.emit("keyrelease", parsedKey);
|
|
2287
|
+
this.emit("keyrelease", new KeyEvent(parsedKey));
|
|
2228
2288
|
break;
|
|
2229
2289
|
default:
|
|
2230
|
-
this.emit("keypress", parsedKey);
|
|
2290
|
+
this.emit("keypress", new KeyEvent(parsedKey));
|
|
2231
2291
|
break;
|
|
2232
2292
|
}
|
|
2233
2293
|
};
|
|
@@ -2238,6 +2298,45 @@ class KeyHandler extends EventEmitter {
|
|
|
2238
2298
|
}
|
|
2239
2299
|
}
|
|
2240
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
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2241
2340
|
// src/lib/RGBA.ts
|
|
2242
2341
|
class RGBA {
|
|
2243
2342
|
buffer;
|
|
@@ -4089,60 +4188,9 @@ function isStyledText(obj) {
|
|
|
4089
4188
|
class StyledText {
|
|
4090
4189
|
[BrandedStyledText] = true;
|
|
4091
4190
|
chunks;
|
|
4092
|
-
textRenderable;
|
|
4093
4191
|
constructor(chunks) {
|
|
4094
4192
|
this.chunks = chunks;
|
|
4095
4193
|
}
|
|
4096
|
-
mount(textRenderable) {
|
|
4097
|
-
this.textRenderable = textRenderable;
|
|
4098
|
-
}
|
|
4099
|
-
insert(chunk, index) {
|
|
4100
|
-
const originalLength = this.chunks.length;
|
|
4101
|
-
if (this.textRenderable) {
|
|
4102
|
-
this.textRenderable.insertChunk(chunk, index ?? originalLength);
|
|
4103
|
-
let newChunks;
|
|
4104
|
-
if (index === undefined || index === originalLength) {
|
|
4105
|
-
newChunks = [...this.chunks, chunk];
|
|
4106
|
-
} else {
|
|
4107
|
-
newChunks = [...this.chunks.slice(0, index), chunk, ...this.chunks.slice(index)];
|
|
4108
|
-
}
|
|
4109
|
-
this.chunks = newChunks;
|
|
4110
|
-
}
|
|
4111
|
-
return this;
|
|
4112
|
-
}
|
|
4113
|
-
remove(chunk) {
|
|
4114
|
-
if (this.textRenderable) {
|
|
4115
|
-
this.textRenderable.removeChunk(chunk);
|
|
4116
|
-
const originalLength = this.chunks.length;
|
|
4117
|
-
const index = this.chunks.indexOf(chunk);
|
|
4118
|
-
if (index === -1)
|
|
4119
|
-
return this;
|
|
4120
|
-
let newChunks;
|
|
4121
|
-
if (index === originalLength - 1) {
|
|
4122
|
-
newChunks = this.chunks.slice(0, -1);
|
|
4123
|
-
} else {
|
|
4124
|
-
newChunks = [...this.chunks.slice(0, index), ...this.chunks.slice(index + 1)];
|
|
4125
|
-
}
|
|
4126
|
-
this.chunks = newChunks;
|
|
4127
|
-
}
|
|
4128
|
-
return this;
|
|
4129
|
-
}
|
|
4130
|
-
replace(chunk, oldChunk) {
|
|
4131
|
-
if (this.textRenderable) {
|
|
4132
|
-
this.textRenderable.replaceChunk(chunk, oldChunk);
|
|
4133
|
-
const index = this.chunks.indexOf(oldChunk);
|
|
4134
|
-
if (index === -1)
|
|
4135
|
-
return this;
|
|
4136
|
-
let newChunks;
|
|
4137
|
-
if (index === this.chunks.length - 1) {
|
|
4138
|
-
newChunks = [...this.chunks.slice(0, -1), chunk];
|
|
4139
|
-
} else {
|
|
4140
|
-
newChunks = [...this.chunks.slice(0, index), chunk, ...this.chunks.slice(index + 1)];
|
|
4141
|
-
}
|
|
4142
|
-
this.chunks = newChunks;
|
|
4143
|
-
}
|
|
4144
|
-
return this;
|
|
4145
|
-
}
|
|
4146
4194
|
}
|
|
4147
4195
|
function stringToStyledText(content) {
|
|
4148
4196
|
const chunk = {
|
|
@@ -4238,7 +4286,36 @@ function t(strings, ...values) {
|
|
|
4238
4286
|
return new StyledText(chunks);
|
|
4239
4287
|
}
|
|
4240
4288
|
|
|
4241
|
-
// 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
|
+
|
|
4242
4319
|
class SyntaxStyle {
|
|
4243
4320
|
styles;
|
|
4244
4321
|
mergedStyleCache;
|
|
@@ -4246,6 +4323,10 @@ class SyntaxStyle {
|
|
|
4246
4323
|
this.styles = styles;
|
|
4247
4324
|
this.mergedStyleCache = new Map;
|
|
4248
4325
|
}
|
|
4326
|
+
static fromTheme(theme) {
|
|
4327
|
+
const flatStyles = convertThemeToStyles(theme);
|
|
4328
|
+
return new SyntaxStyle(flatStyles);
|
|
4329
|
+
}
|
|
4249
4330
|
mergeStyles(...styleNames) {
|
|
4250
4331
|
const cacheKey = styleNames.join(":");
|
|
4251
4332
|
const cached = this.mergedStyleCache.get(cacheKey);
|
|
@@ -4253,7 +4334,7 @@ class SyntaxStyle {
|
|
|
4253
4334
|
return cached;
|
|
4254
4335
|
const styleDefinition = {};
|
|
4255
4336
|
for (const name of styleNames) {
|
|
4256
|
-
const style = this.
|
|
4337
|
+
const style = this.getStyle(name);
|
|
4257
4338
|
if (!style)
|
|
4258
4339
|
continue;
|
|
4259
4340
|
if (style.fg)
|
|
@@ -4283,6 +4364,18 @@ class SyntaxStyle {
|
|
|
4283
4364
|
this.mergedStyleCache.set(cacheKey, merged);
|
|
4284
4365
|
return merged;
|
|
4285
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
|
+
}
|
|
4286
4379
|
clearCache() {
|
|
4287
4380
|
this.mergedStyleCache.clear();
|
|
4288
4381
|
}
|
|
@@ -4290,6 +4383,8 @@ class SyntaxStyle {
|
|
|
4290
4383
|
return this.mergedStyleCache.size;
|
|
4291
4384
|
}
|
|
4292
4385
|
}
|
|
4386
|
+
|
|
4387
|
+
// src/lib/hast-styled-text.ts
|
|
4293
4388
|
function hastToTextChunks(node, syntaxStyle, parentStyles = []) {
|
|
4294
4389
|
const chunks = [];
|
|
4295
4390
|
if (node.type === "text") {
|
|
@@ -4321,6 +4416,55 @@ function hastToStyledText(hast, syntaxStyle) {
|
|
|
4321
4416
|
return new StyledText(chunks);
|
|
4322
4417
|
}
|
|
4323
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
|
+
|
|
4324
4468
|
// src/lib/yoga.options.ts
|
|
4325
4469
|
function parseAlign(value) {
|
|
4326
4470
|
switch (value.toLowerCase()) {
|
|
@@ -4824,9 +4968,19 @@ function singleton(key, factory) {
|
|
|
4824
4968
|
}
|
|
4825
4969
|
return bag[key];
|
|
4826
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
|
+
}
|
|
4827
4981
|
|
|
4828
4982
|
// src/lib/env.ts
|
|
4829
|
-
var envRegistry = {};
|
|
4983
|
+
var envRegistry = singleton("env-registry", () => ({}));
|
|
4830
4984
|
function registerEnvVar(config) {
|
|
4831
4985
|
const existing = envRegistry[config.name];
|
|
4832
4986
|
if (existing) {
|
|
@@ -4884,8 +5038,14 @@ class EnvStore {
|
|
|
4884
5038
|
has(key) {
|
|
4885
5039
|
return key in envRegistry;
|
|
4886
5040
|
}
|
|
5041
|
+
clearCache() {
|
|
5042
|
+
this.parsedValues.clear();
|
|
5043
|
+
}
|
|
4887
5044
|
}
|
|
4888
5045
|
var envStore = singleton("env-store", () => new EnvStore);
|
|
5046
|
+
function clearEnvCache() {
|
|
5047
|
+
envStore.clearCache();
|
|
5048
|
+
}
|
|
4889
5049
|
function generateEnvMarkdown() {
|
|
4890
5050
|
const configs = Object.values(envRegistry);
|
|
4891
5051
|
if (configs.length === 0) {
|
|
@@ -4974,9 +5134,1115 @@ var env = new Proxy({}, {
|
|
|
4974
5134
|
return;
|
|
4975
5135
|
}
|
|
4976
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";
|
|
5881
|
+
}
|
|
5882
|
+
get appName() {
|
|
5883
|
+
return this._appName;
|
|
5884
|
+
}
|
|
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
|
+
}
|
|
5897
|
+
}
|
|
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);
|
|
5904
|
+
}
|
|
5905
|
+
return this._globalConfigPath;
|
|
5906
|
+
}
|
|
5907
|
+
get globalConfigFile() {
|
|
5908
|
+
if (this._globalConfigFile === undefined) {
|
|
5909
|
+
this._globalConfigFile = path.join(this.globalConfigPath, "init.ts");
|
|
5910
|
+
}
|
|
5911
|
+
return this._globalConfigFile;
|
|
5912
|
+
}
|
|
5913
|
+
get localConfigFile() {
|
|
5914
|
+
if (this._localConfigFile === undefined) {
|
|
5915
|
+
this._localConfigFile = path.join(process.cwd(), `.${this._appName}.ts`);
|
|
5916
|
+
}
|
|
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);
|
|
5925
|
+
}
|
|
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}`;
|
|
6010
|
+
} else {
|
|
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}` };
|
|
6046
|
+
}
|
|
6047
|
+
}
|
|
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
|
+
}
|
|
6066
|
+
} else {
|
|
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
|
+
}
|
|
6075
|
+
}
|
|
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
|
+
});
|
|
6242
|
+
}
|
|
4977
6243
|
// src/zig.ts
|
|
4978
6244
|
import { dlopen, toArrayBuffer as toArrayBuffer2, JSCallback, ptr } from "bun:ffi";
|
|
4979
|
-
import { existsSync } from "fs";
|
|
6245
|
+
import { existsSync as existsSync2 } from "fs";
|
|
4980
6246
|
|
|
4981
6247
|
// src/buffer.ts
|
|
4982
6248
|
import { toArrayBuffer } from "bun:ffi";
|
|
@@ -5177,7 +6443,10 @@ class OptimizedBuffer {
|
|
|
5177
6443
|
// src/zig.ts
|
|
5178
6444
|
var module = await import(`@opentui/core-${process.platform}-${process.arch}/index.ts`);
|
|
5179
6445
|
var targetLibPath = module.default;
|
|
5180
|
-
if (
|
|
6446
|
+
if (/\$bunfs/.test(targetLibPath)) {
|
|
6447
|
+
targetLibPath = targetLibPath.replace("../", "");
|
|
6448
|
+
}
|
|
6449
|
+
if (!existsSync2(targetLibPath)) {
|
|
5181
6450
|
throw new Error(`opentui is not supported on the current platform: ${process.platform}-${process.arch}`);
|
|
5182
6451
|
}
|
|
5183
6452
|
registerEnvVar({
|
|
@@ -6281,7 +7550,7 @@ class TextBuffer {
|
|
|
6281
7550
|
}
|
|
6282
7551
|
|
|
6283
7552
|
// src/Renderable.ts
|
|
6284
|
-
import { EventEmitter as
|
|
7553
|
+
import { EventEmitter as EventEmitter4 } from "events";
|
|
6285
7554
|
|
|
6286
7555
|
// src/lib/renderable.validations.ts
|
|
6287
7556
|
function validateOptions(id, options) {
|
|
@@ -6374,7 +7643,7 @@ function isRenderable(obj) {
|
|
|
6374
7643
|
return !!obj?.[BrandedRenderable];
|
|
6375
7644
|
}
|
|
6376
7645
|
|
|
6377
|
-
class BaseRenderable extends
|
|
7646
|
+
class BaseRenderable extends EventEmitter4 {
|
|
6378
7647
|
[BrandedRenderable] = true;
|
|
6379
7648
|
static renderableNumber = 1;
|
|
6380
7649
|
_id;
|
|
@@ -6546,18 +7815,18 @@ class Renderable extends BaseRenderable {
|
|
|
6546
7815
|
this.requestRender();
|
|
6547
7816
|
this.keypressHandler = (key) => {
|
|
6548
7817
|
this._keyListeners["down"]?.(key);
|
|
6549
|
-
if (this.handleKeyPress) {
|
|
7818
|
+
if (!key.defaultPrevented && this.handleKeyPress) {
|
|
6550
7819
|
this.handleKeyPress(key);
|
|
6551
7820
|
}
|
|
6552
7821
|
};
|
|
6553
|
-
this.pasteHandler = (
|
|
6554
|
-
this._pasteListener?.call(this, text);
|
|
6555
|
-
if (this.handlePaste) {
|
|
6556
|
-
this.handlePaste(text);
|
|
7822
|
+
this.pasteHandler = (event) => {
|
|
7823
|
+
this._pasteListener?.call(this, event.text);
|
|
7824
|
+
if (!event.defaultPrevented && this.handlePaste) {
|
|
7825
|
+
this.handlePaste(event.text);
|
|
6557
7826
|
}
|
|
6558
7827
|
};
|
|
6559
|
-
this.ctx.
|
|
6560
|
-
this.ctx.
|
|
7828
|
+
this.ctx._internalKeyInput.onInternal("keypress", this.keypressHandler);
|
|
7829
|
+
this.ctx._internalKeyInput.onInternal("paste", this.pasteHandler);
|
|
6561
7830
|
this.emit("focused" /* FOCUSED */);
|
|
6562
7831
|
}
|
|
6563
7832
|
blur() {
|
|
@@ -6566,11 +7835,11 @@ class Renderable extends BaseRenderable {
|
|
|
6566
7835
|
this._focused = false;
|
|
6567
7836
|
this.requestRender();
|
|
6568
7837
|
if (this.keypressHandler) {
|
|
6569
|
-
this.ctx.
|
|
7838
|
+
this.ctx._internalKeyInput.offInternal("keypress", this.keypressHandler);
|
|
6570
7839
|
this.keypressHandler = null;
|
|
6571
7840
|
}
|
|
6572
7841
|
if (this.pasteHandler) {
|
|
6573
|
-
this.ctx.
|
|
7842
|
+
this.ctx._internalKeyInput.offInternal("paste", this.pasteHandler);
|
|
6574
7843
|
this.pasteHandler = null;
|
|
6575
7844
|
}
|
|
6576
7845
|
this.emit("blurred" /* BLURRED */);
|
|
@@ -7171,10 +8440,11 @@ class Renderable extends BaseRenderable {
|
|
|
7171
8440
|
if (renderable.parent === this) {
|
|
7172
8441
|
this.yogaNode.removeChild(renderable.getLayoutNode());
|
|
7173
8442
|
this._childrenInLayoutOrder.splice(this._childrenInLayoutOrder.indexOf(renderable), 1);
|
|
7174
|
-
} else
|
|
8443
|
+
} else {
|
|
7175
8444
|
this.replaceParent(renderable);
|
|
7176
8445
|
this.needsZIndexSort = true;
|
|
7177
8446
|
this.renderableMapById.set(renderable.id, renderable);
|
|
8447
|
+
this._childrenInZIndexOrder.push(renderable);
|
|
7178
8448
|
if (typeof renderable.onLifecyclePass === "function") {
|
|
7179
8449
|
this._ctx.registerLifecyclePass(renderable);
|
|
7180
8450
|
}
|
|
@@ -7219,6 +8489,16 @@ class Renderable extends BaseRenderable {
|
|
|
7219
8489
|
if (zIndexIndex !== -1) {
|
|
7220
8490
|
this._childrenInZIndexOrder.splice(zIndexIndex, 1);
|
|
7221
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
|
+
}
|
|
7222
8502
|
this.childrenPrimarySortDirty = true;
|
|
7223
8503
|
}
|
|
7224
8504
|
}
|
|
@@ -7327,7 +8607,8 @@ class Renderable extends BaseRenderable {
|
|
|
7327
8607
|
} catch (e) {}
|
|
7328
8608
|
}
|
|
7329
8609
|
destroyRecursively() {
|
|
7330
|
-
|
|
8610
|
+
const children = [...this._childrenInLayoutOrder];
|
|
8611
|
+
for (const child of children) {
|
|
7331
8612
|
child.destroyRecursively();
|
|
7332
8613
|
}
|
|
7333
8614
|
this.destroy();
|
|
@@ -7666,17 +8947,17 @@ function delegate(mapping, vnode) {
|
|
|
7666
8947
|
}
|
|
7667
8948
|
|
|
7668
8949
|
// src/console.ts
|
|
7669
|
-
import { EventEmitter as
|
|
8950
|
+
import { EventEmitter as EventEmitter6 } from "events";
|
|
7670
8951
|
import { Console } from "console";
|
|
7671
8952
|
import fs from "fs";
|
|
7672
|
-
import
|
|
8953
|
+
import path4 from "path";
|
|
7673
8954
|
import util2 from "util";
|
|
7674
8955
|
|
|
7675
8956
|
// src/lib/output.capture.ts
|
|
7676
8957
|
import { Writable } from "stream";
|
|
7677
|
-
import { EventEmitter as
|
|
8958
|
+
import { EventEmitter as EventEmitter5 } from "events";
|
|
7678
8959
|
|
|
7679
|
-
class Capture extends
|
|
8960
|
+
class Capture extends EventEmitter5 {
|
|
7680
8961
|
output = [];
|
|
7681
8962
|
constructor() {
|
|
7682
8963
|
super();
|
|
@@ -7752,7 +9033,7 @@ registerEnvVar({
|
|
|
7752
9033
|
default: false
|
|
7753
9034
|
});
|
|
7754
9035
|
|
|
7755
|
-
class TerminalConsoleCache extends
|
|
9036
|
+
class TerminalConsoleCache extends EventEmitter6 {
|
|
7756
9037
|
_cachedLogs = [];
|
|
7757
9038
|
MAX_CACHE_SIZE = 1000;
|
|
7758
9039
|
_collectCallerInfo = false;
|
|
@@ -7873,7 +9154,7 @@ var DEFAULT_CONSOLE_OPTIONS = {
|
|
|
7873
9154
|
};
|
|
7874
9155
|
var INDENT_WIDTH = 2;
|
|
7875
9156
|
|
|
7876
|
-
class TerminalConsole extends
|
|
9157
|
+
class TerminalConsole extends EventEmitter6 {
|
|
7877
9158
|
isVisible = false;
|
|
7878
9159
|
isFocused = false;
|
|
7879
9160
|
renderer;
|
|
@@ -8312,7 +9593,7 @@ class TerminalConsole extends EventEmitter4 {
|
|
|
8312
9593
|
try {
|
|
8313
9594
|
const timestamp = Date.now();
|
|
8314
9595
|
const filename = `_console_${timestamp}.log`;
|
|
8315
|
-
const filepath =
|
|
9596
|
+
const filepath = path4.join(process.cwd(), filename);
|
|
8316
9597
|
const allLogEntries = [...this._allLogEntries, ...terminalConsoleCache.cachedLogs];
|
|
8317
9598
|
const logLines = [];
|
|
8318
9599
|
for (const [date, level, args, callerInfo] of allLogEntries) {
|
|
@@ -8333,7 +9614,7 @@ class TerminalConsole extends EventEmitter4 {
|
|
|
8333
9614
|
}
|
|
8334
9615
|
|
|
8335
9616
|
// src/renderer.ts
|
|
8336
|
-
import { EventEmitter as
|
|
9617
|
+
import { EventEmitter as EventEmitter7 } from "events";
|
|
8337
9618
|
|
|
8338
9619
|
// src/lib/objects-in-viewport.ts
|
|
8339
9620
|
function getObjectsInViewport(viewport, objects, direction = "column", padding = 10, minTriggerSize = 16) {
|
|
@@ -8423,6 +9704,18 @@ registerEnvVar({
|
|
|
8423
9704
|
type: "boolean",
|
|
8424
9705
|
default: false
|
|
8425
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
|
+
});
|
|
8426
9719
|
|
|
8427
9720
|
class MouseEvent {
|
|
8428
9721
|
type;
|
|
@@ -8485,13 +9778,17 @@ var rendererTracker = singleton("RendererTracker", () => {
|
|
|
8485
9778
|
renderers.delete(renderer);
|
|
8486
9779
|
if (renderers.size === 0) {
|
|
8487
9780
|
process.stdin.pause();
|
|
9781
|
+
if (hasSingleton("tree-sitter-client")) {
|
|
9782
|
+
getTreeSitterClient().destroy();
|
|
9783
|
+
destroySingleton("tree-sitter-client");
|
|
9784
|
+
}
|
|
8488
9785
|
}
|
|
8489
9786
|
}
|
|
8490
9787
|
};
|
|
8491
9788
|
});
|
|
8492
9789
|
async function createCliRenderer(config = {}) {
|
|
8493
9790
|
if (process.argv.includes("--delay-start")) {
|
|
8494
|
-
await new Promise((
|
|
9791
|
+
await new Promise((resolve4) => setTimeout(resolve4, 5000));
|
|
8495
9792
|
}
|
|
8496
9793
|
const stdin = config.stdin || process.stdin;
|
|
8497
9794
|
const stdout = config.stdout || process.stdout;
|
|
@@ -8518,14 +9815,14 @@ var CliRenderEvents;
|
|
|
8518
9815
|
((CliRenderEvents2) => {
|
|
8519
9816
|
CliRenderEvents2["DEBUG_OVERLAY_TOGGLE"] = "debugOverlay:toggle";
|
|
8520
9817
|
})(CliRenderEvents ||= {});
|
|
8521
|
-
class CliRenderer extends
|
|
9818
|
+
class CliRenderer extends EventEmitter7 {
|
|
8522
9819
|
static animationFrameId = 0;
|
|
8523
9820
|
lib;
|
|
8524
9821
|
rendererPtr;
|
|
8525
9822
|
stdin;
|
|
8526
9823
|
stdout;
|
|
8527
9824
|
exitOnCtrlC;
|
|
8528
|
-
|
|
9825
|
+
_isDestroyed = false;
|
|
8529
9826
|
nextRenderBuffer;
|
|
8530
9827
|
currentRenderBuffer;
|
|
8531
9828
|
_isRunning = false;
|
|
@@ -8579,7 +9876,7 @@ class CliRenderer extends EventEmitter5 {
|
|
|
8579
9876
|
resizeDebounceDelay = 100;
|
|
8580
9877
|
enableMouseMovement = false;
|
|
8581
9878
|
_useMouse = true;
|
|
8582
|
-
_useAlternateScreen =
|
|
9879
|
+
_useAlternateScreen = env.OTUI_USE_ALTERNATE_SCREEN;
|
|
8583
9880
|
capturedRenderable;
|
|
8584
9881
|
lastOverRenderableNum = 0;
|
|
8585
9882
|
lastOverRenderable;
|
|
@@ -8610,9 +9907,9 @@ class CliRenderer extends EventEmitter5 {
|
|
|
8610
9907
|
handleError = ((error) => {
|
|
8611
9908
|
this.stop();
|
|
8612
9909
|
this.destroy();
|
|
8613
|
-
new Promise((
|
|
9910
|
+
new Promise((resolve4) => {
|
|
8614
9911
|
setTimeout(() => {
|
|
8615
|
-
|
|
9912
|
+
resolve4(true);
|
|
8616
9913
|
}, 100);
|
|
8617
9914
|
}).then(() => {
|
|
8618
9915
|
this.realStdoutWrite.call(this.stdout, `
|
|
@@ -8691,7 +9988,7 @@ Captured output:
|
|
|
8691
9988
|
this.maxStatSamples = config.maxStatSamples || 300;
|
|
8692
9989
|
this.enableMouseMovement = config.enableMouseMovement || true;
|
|
8693
9990
|
this._useMouse = config.useMouse ?? true;
|
|
8694
|
-
this._useAlternateScreen = config.useAlternateScreen ??
|
|
9991
|
+
this._useAlternateScreen = config.useAlternateScreen ?? env.OTUI_USE_ALTERNATE_SCREEN;
|
|
8695
9992
|
this.nextRenderBuffer = this.lib.getNextBuffer(this.rendererPtr);
|
|
8696
9993
|
this.currentRenderBuffer = this.lib.getCurrentBuffer(this.rendererPtr);
|
|
8697
9994
|
this.postProcessFns = config.postProcessFns || [];
|
|
@@ -8699,7 +9996,9 @@ Captured output:
|
|
|
8699
9996
|
if (this.memorySnapshotInterval > 0) {
|
|
8700
9997
|
this.startMemorySnapshotTimer();
|
|
8701
9998
|
}
|
|
8702
|
-
|
|
9999
|
+
if (env.OTUI_OVERRIDE_STDOUT) {
|
|
10000
|
+
this.stdout.write = this.interceptStdoutWrite.bind(this);
|
|
10001
|
+
}
|
|
8703
10002
|
process.on("SIGWINCH", this.sigwinchHandler);
|
|
8704
10003
|
process.on("warning", this.warningHandler);
|
|
8705
10004
|
process.on("uncaughtException", this.handleError);
|
|
@@ -8707,7 +10006,7 @@ Captured output:
|
|
|
8707
10006
|
process.on("exit", this.exitHandler);
|
|
8708
10007
|
this._console = new TerminalConsole(this, config.consoleOptions);
|
|
8709
10008
|
this.useConsole = config.useConsole ?? true;
|
|
8710
|
-
this._keyHandler = new
|
|
10009
|
+
this._keyHandler = new InternalKeyHandler(this.stdin, config.useKittyKeyboard ?? false);
|
|
8711
10010
|
global.requestAnimationFrame = (callback) => {
|
|
8712
10011
|
const id = CliRenderer.animationFrameId++;
|
|
8713
10012
|
this.animationRequest.set(id, callback);
|
|
@@ -8731,6 +10030,9 @@ Captured output:
|
|
|
8731
10030
|
}
|
|
8732
10031
|
this.setupInput();
|
|
8733
10032
|
}
|
|
10033
|
+
get isDestroyed() {
|
|
10034
|
+
return this._isDestroyed;
|
|
10035
|
+
}
|
|
8734
10036
|
registerLifecyclePass(renderable) {
|
|
8735
10037
|
this.lifecyclePasses.add(renderable);
|
|
8736
10038
|
}
|
|
@@ -8795,6 +10097,9 @@ Captured output:
|
|
|
8795
10097
|
get keyInput() {
|
|
8796
10098
|
return this._keyHandler;
|
|
8797
10099
|
}
|
|
10100
|
+
get _internalKeyInput() {
|
|
10101
|
+
return this._keyHandler;
|
|
10102
|
+
}
|
|
8798
10103
|
get terminalWidth() {
|
|
8799
10104
|
return this._terminalWidth;
|
|
8800
10105
|
}
|
|
@@ -8925,16 +10230,16 @@ Captured output:
|
|
|
8925
10230
|
if (this._terminalIsSetup)
|
|
8926
10231
|
return;
|
|
8927
10232
|
this._terminalIsSetup = true;
|
|
8928
|
-
await new Promise((
|
|
10233
|
+
await new Promise((resolve4) => {
|
|
8929
10234
|
const timeout = setTimeout(() => {
|
|
8930
10235
|
this.stdin.off("data", capListener);
|
|
8931
|
-
|
|
10236
|
+
resolve4(true);
|
|
8932
10237
|
}, 100);
|
|
8933
10238
|
const capListener = (str) => {
|
|
8934
10239
|
clearTimeout(timeout);
|
|
8935
10240
|
this.lib.processCapabilityResponse(this.rendererPtr, str);
|
|
8936
10241
|
this.stdin.off("data", capListener);
|
|
8937
|
-
|
|
10242
|
+
resolve4(true);
|
|
8938
10243
|
};
|
|
8939
10244
|
this.stdin.on("data", capListener);
|
|
8940
10245
|
this.lib.setupTerminal(this.rendererPtr, this._useAlternateScreen);
|
|
@@ -9091,7 +10396,7 @@ Captured output:
|
|
|
9091
10396
|
return false;
|
|
9092
10397
|
}
|
|
9093
10398
|
takeMemorySnapshot() {
|
|
9094
|
-
if (this.
|
|
10399
|
+
if (this._isDestroyed)
|
|
9095
10400
|
return;
|
|
9096
10401
|
const memoryUsage = process.memoryUsage();
|
|
9097
10402
|
this.lastMemorySnapshot = {
|
|
@@ -9124,7 +10429,7 @@ Captured output:
|
|
|
9124
10429
|
}
|
|
9125
10430
|
}
|
|
9126
10431
|
handleResize(width, height) {
|
|
9127
|
-
if (this.
|
|
10432
|
+
if (this._isDestroyed)
|
|
9128
10433
|
return;
|
|
9129
10434
|
if (this._splitHeight > 0) {
|
|
9130
10435
|
this.processResize(width, height);
|
|
@@ -9283,7 +10588,7 @@ Captured output:
|
|
|
9283
10588
|
this.controlState = this._isRunning ? "auto_started" /* AUTO_STARTED */ : "idle" /* IDLE */;
|
|
9284
10589
|
}
|
|
9285
10590
|
internalStart() {
|
|
9286
|
-
if (!this._isRunning && !this.
|
|
10591
|
+
if (!this._isRunning && !this._isDestroyed) {
|
|
9287
10592
|
this._isRunning = true;
|
|
9288
10593
|
if (this.memorySnapshotInterval > 0) {
|
|
9289
10594
|
this.startMemorySnapshotTimer();
|
|
@@ -9303,7 +10608,7 @@ Captured output:
|
|
|
9303
10608
|
this.internalStop();
|
|
9304
10609
|
}
|
|
9305
10610
|
internalStop() {
|
|
9306
|
-
if (this.isRunning && !this.
|
|
10611
|
+
if (this.isRunning && !this._isDestroyed) {
|
|
9307
10612
|
this._isRunning = false;
|
|
9308
10613
|
if (this.memorySnapshotTimer) {
|
|
9309
10614
|
clearInterval(this.memorySnapshotTimer);
|
|
@@ -9324,9 +10629,9 @@ Captured output:
|
|
|
9324
10629
|
if (this.memorySnapshotTimer) {
|
|
9325
10630
|
clearInterval(this.memorySnapshotTimer);
|
|
9326
10631
|
}
|
|
9327
|
-
if (this.
|
|
10632
|
+
if (this._isDestroyed)
|
|
9328
10633
|
return;
|
|
9329
|
-
this.
|
|
10634
|
+
this._isDestroyed = true;
|
|
9330
10635
|
if (this.renderTimeout) {
|
|
9331
10636
|
clearTimeout(this.renderTimeout);
|
|
9332
10637
|
this.renderTimeout = null;
|
|
@@ -9334,7 +10639,11 @@ Captured output:
|
|
|
9334
10639
|
this._isRunning = false;
|
|
9335
10640
|
this.waitingForPixelResolution = false;
|
|
9336
10641
|
this.capturedRenderable = undefined;
|
|
9337
|
-
|
|
10642
|
+
try {
|
|
10643
|
+
this.root.destroyRecursively();
|
|
10644
|
+
} catch (e) {
|
|
10645
|
+
console.error("Error destroying root renderable:", e instanceof Error ? e.stack : String(e));
|
|
10646
|
+
}
|
|
9338
10647
|
this._keyHandler.destroy();
|
|
9339
10648
|
this._console.deactivate();
|
|
9340
10649
|
this.disableStdoutInterception();
|
|
@@ -9359,7 +10668,7 @@ Captured output:
|
|
|
9359
10668
|
this.loop();
|
|
9360
10669
|
}
|
|
9361
10670
|
async loop() {
|
|
9362
|
-
if (this.rendering || this.
|
|
10671
|
+
if (this.rendering || this._isDestroyed)
|
|
9363
10672
|
return;
|
|
9364
10673
|
this.rendering = true;
|
|
9365
10674
|
if (this.renderTimeout) {
|
|
@@ -9403,17 +10712,17 @@ Captured output:
|
|
|
9403
10712
|
postProcessFn(this.nextRenderBuffer, deltaTime);
|
|
9404
10713
|
}
|
|
9405
10714
|
this._console.renderToBuffer(this.nextRenderBuffer);
|
|
9406
|
-
if (!this.
|
|
10715
|
+
if (!this._isDestroyed) {
|
|
9407
10716
|
this.renderNative();
|
|
9408
|
-
|
|
9409
|
-
|
|
9410
|
-
|
|
9411
|
-
|
|
9412
|
-
|
|
9413
|
-
|
|
9414
|
-
|
|
9415
|
-
|
|
9416
|
-
|
|
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
|
+
}
|
|
9417
10726
|
}
|
|
9418
10727
|
this.rendering = false;
|
|
9419
10728
|
if (this.immediateRerenderRequested) {
|
|
@@ -9572,7 +10881,7 @@ Captured output:
|
|
|
9572
10881
|
}
|
|
9573
10882
|
}
|
|
9574
10883
|
|
|
9575
|
-
export { __toESM, __commonJS, __export, __require, Edge, Gutter, exports_src, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, nonAlphanumericKeys, parseKeypress, ANSI, KeyHandler, 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, SyntaxStyle, hastToStyledText, parseAlign, parseBoxSizing, parseDimension, parseDirection, parseDisplay, parseEdge, parseFlexDirection, parseGutter, parseJustify, parseLogLevel, parseMeasureMode, parseOverflow, parsePositionType, parseUnit, parseWrap, MouseParser, Selection, convertGlobalToLocalSelection, ASCIIFontSelectionHelper, envRegistry, registerEnvVar, generateEnvMarkdown, generateEnvColored, env, 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 };
|
|
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 };
|
|
9576
10885
|
|
|
9577
|
-
//# debugId=
|
|
9578
|
-
//# sourceMappingURL=index-
|
|
10886
|
+
//# debugId=66FAF32C902A5E0B64756E2164756E21
|
|
10887
|
+
//# sourceMappingURL=index-pxa2sv92.js.map
|