@opentui/core 0.1.59 → 0.1.61

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.
@@ -2319,6 +2319,7 @@ var parseKeypress = (s = "", options = {}) => {
2319
2319
  const segs = [...s];
2320
2320
  if (segs[0] === "\x1B" && segs[1] === "\x1B") {
2321
2321
  key.option = true;
2322
+ key.meta = true;
2322
2323
  }
2323
2324
  const code = [parts[1], parts[2], parts[4], parts[6]].filter(Boolean).join("");
2324
2325
  const modifier = parseInt(parts[3] || parts[5] || "1", 10) - 1;
@@ -8266,6 +8267,7 @@ class ExtmarksController {
8266
8267
  originalInsertChar;
8267
8268
  originalDeleteRange;
8268
8269
  originalSetText;
8270
+ originalReplaceText;
8269
8271
  originalClear;
8270
8272
  originalNewLine;
8271
8273
  originalDeleteLine;
@@ -8286,6 +8288,7 @@ class ExtmarksController {
8286
8288
  this.originalInsertChar = editBuffer.insertChar.bind(editBuffer);
8287
8289
  this.originalDeleteRange = editBuffer.deleteRange.bind(editBuffer);
8288
8290
  this.originalSetText = editBuffer.setText.bind(editBuffer);
8291
+ this.originalReplaceText = editBuffer.replaceText.bind(editBuffer);
8289
8292
  this.originalClear = editBuffer.clear.bind(editBuffer);
8290
8293
  this.originalNewLine = editBuffer.newLine.bind(editBuffer);
8291
8294
  this.originalDeleteLine = editBuffer.deleteLine.bind(editBuffer);
@@ -8551,16 +8554,22 @@ class ExtmarksController {
8551
8554
  this.originalInsertChar(char);
8552
8555
  this.adjustExtmarksAfterInsertion(currentOffset, 1);
8553
8556
  };
8554
- this.editBuffer.setText = (text, opts) => {
8557
+ this.editBuffer.setText = (text) => {
8555
8558
  if (this.destroyed) {
8556
- this.originalSetText(text, opts);
8559
+ this.originalSetText(text);
8557
8560
  return;
8558
8561
  }
8559
- if (opts?.history !== false) {
8560
- this.saveSnapshot();
8562
+ this.clear();
8563
+ this.originalSetText(text);
8564
+ };
8565
+ this.editBuffer.replaceText = (text) => {
8566
+ if (this.destroyed) {
8567
+ this.originalReplaceText(text);
8568
+ return;
8561
8569
  }
8570
+ this.saveSnapshot();
8562
8571
  this.clear();
8563
- this.originalSetText(text, opts);
8572
+ this.originalReplaceText(text);
8564
8573
  };
8565
8574
  this.editBuffer.clear = () => {
8566
8575
  if (this.destroyed) {
@@ -8879,6 +8888,7 @@ class ExtmarksController {
8879
8888
  this.editBuffer.insertChar = this.originalInsertChar;
8880
8889
  this.editBuffer.deleteRange = this.originalDeleteRange;
8881
8890
  this.editBuffer.setText = this.originalSetText;
8891
+ this.editBuffer.replaceText = this.originalReplaceText;
8882
8892
  this.editBuffer.clear = this.originalClear;
8883
8893
  this.editBuffer.newLine = this.originalNewLine;
8884
8894
  this.editBuffer.deleteLine = this.originalDeleteLine;
@@ -9381,6 +9391,22 @@ class OptimizedBuffer {
9381
9391
  this.guard();
9382
9392
  this.lib.bufferClearScissorRects(this.bufferPtr);
9383
9393
  }
9394
+ pushOpacity(opacity) {
9395
+ this.guard();
9396
+ this.lib.bufferPushOpacity(this.bufferPtr, Math.max(0, Math.min(1, opacity)));
9397
+ }
9398
+ popOpacity() {
9399
+ this.guard();
9400
+ this.lib.bufferPopOpacity(this.bufferPtr);
9401
+ }
9402
+ getCurrentOpacity() {
9403
+ this.guard();
9404
+ return this.lib.bufferGetCurrentOpacity(this.bufferPtr);
9405
+ }
9406
+ clearOpacity() {
9407
+ this.guard();
9408
+ this.lib.bufferClearOpacity(this.bufferPtr);
9409
+ }
9384
9410
  encodeUnicode(text) {
9385
9411
  this.guard();
9386
9412
  return this.lib.encodeUnicode(text, this._widthMethod);
@@ -10123,6 +10149,9 @@ registerEnvVar({
10123
10149
  type: "boolean",
10124
10150
  default: false
10125
10151
  });
10152
+ var globalTraceSymbols = null;
10153
+ var globalFFILogWriter = null;
10154
+ var exitHandlerRegistered = false;
10126
10155
  function getOpenTUILib(libPath) {
10127
10156
  const resolvedLibPath = libPath || targetLibPath;
10128
10157
  const rawSymbols = dlopen(resolvedLibPath, {
@@ -10310,6 +10339,22 @@ function getOpenTUILib(libPath) {
10310
10339
  args: ["ptr"],
10311
10340
  returns: "void"
10312
10341
  },
10342
+ bufferPushOpacity: {
10343
+ args: ["ptr", "f32"],
10344
+ returns: "void"
10345
+ },
10346
+ bufferPopOpacity: {
10347
+ args: ["ptr"],
10348
+ returns: "void"
10349
+ },
10350
+ bufferGetCurrentOpacity: {
10351
+ args: ["ptr"],
10352
+ returns: "f32"
10353
+ },
10354
+ bufferClearOpacity: {
10355
+ args: ["ptr"],
10356
+ returns: "void"
10357
+ },
10313
10358
  addToHitGrid: {
10314
10359
  args: ["ptr", "i32", "i32", "u32", "u32", "u32"],
10315
10360
  returns: "void"
@@ -10346,13 +10391,13 @@ function getOpenTUILib(libPath) {
10346
10391
  args: ["ptr"],
10347
10392
  returns: "void"
10348
10393
  },
10349
- setUseKittyKeyboard: {
10350
- args: ["ptr", "bool"],
10394
+ setKittyKeyboardFlags: {
10395
+ args: ["ptr", "u8"],
10351
10396
  returns: "void"
10352
10397
  },
10353
- getUseKittyKeyboard: {
10398
+ getKittyKeyboardFlags: {
10354
10399
  args: ["ptr"],
10355
- returns: "bool"
10400
+ returns: "u8"
10356
10401
  },
10357
10402
  setupTerminal: {
10358
10403
  args: ["ptr", "bool"],
@@ -10635,11 +10680,19 @@ function getOpenTUILib(libPath) {
10635
10680
  returns: "void"
10636
10681
  },
10637
10682
  editBufferSetText: {
10638
- args: ["ptr", "ptr", "usize", "bool"],
10683
+ args: ["ptr", "ptr", "usize"],
10639
10684
  returns: "void"
10640
10685
  },
10641
10686
  editBufferSetTextFromMem: {
10642
- args: ["ptr", "u8", "bool"],
10687
+ args: ["ptr", "u8"],
10688
+ returns: "void"
10689
+ },
10690
+ editBufferReplaceText: {
10691
+ args: ["ptr", "ptr", "usize"],
10692
+ returns: "void"
10693
+ },
10694
+ editBufferReplaceTextFromMem: {
10695
+ args: ["ptr", "u8"],
10643
10696
  returns: "void"
10644
10697
  },
10645
10698
  editBufferGetText: {
@@ -10842,6 +10895,14 @@ function getOpenTUILib(libPath) {
10842
10895
  args: ["ptr", "ptr"],
10843
10896
  returns: "void"
10844
10897
  },
10898
+ editorViewGetVisualSOL: {
10899
+ args: ["ptr", "ptr"],
10900
+ returns: "void"
10901
+ },
10902
+ editorViewGetVisualEOL: {
10903
+ args: ["ptr", "ptr"],
10904
+ returns: "void"
10905
+ },
10845
10906
  editorViewSetPlaceholderStyledText: {
10846
10907
  args: ["ptr", "ptr", "usize"],
10847
10908
  returns: "void"
@@ -10907,19 +10968,22 @@ function getOpenTUILib(libPath) {
10907
10968
  return rawSymbols;
10908
10969
  }
10909
10970
  function convertToDebugSymbols(symbols) {
10971
+ if (!globalTraceSymbols) {
10972
+ globalTraceSymbols = {};
10973
+ }
10974
+ if (env.OTUI_DEBUG_FFI && !globalFFILogWriter) {
10975
+ const now = new Date;
10976
+ const timestamp = now.toISOString().replace(/[:.]/g, "-").replace(/T/, "_").split("Z")[0];
10977
+ const logFilePath = `ffi_otui_debug_${timestamp}.log`;
10978
+ globalFFILogWriter = Bun.file(logFilePath).writer();
10979
+ }
10910
10980
  const debugSymbols = {};
10911
- const traceSymbols = {};
10912
10981
  let hasTracing = false;
10913
- let ffiLogWriter = null;
10914
10982
  Object.entries(symbols).forEach(([key, value]) => {
10915
10983
  debugSymbols[key] = value;
10916
10984
  });
10917
- if (env.OTUI_DEBUG_FFI) {
10918
- const now = new Date;
10919
- const timestamp = now.toISOString().replace(/[:.]/g, "-").replace(/T/, "_").split("Z")[0];
10920
- const logFilePath = `ffi_otui_debug_${timestamp}.log`;
10921
- ffiLogWriter = Bun.file(logFilePath).writer();
10922
- const writer = ffiLogWriter;
10985
+ if (env.OTUI_DEBUG_FFI && globalFFILogWriter) {
10986
+ const writer = globalFFILogWriter;
10923
10987
  const writeSync = (msg) => {
10924
10988
  const buffer = new TextEncoder().encode(msg + `
10925
10989
  `);
@@ -10941,89 +11005,104 @@ function convertToDebugSymbols(symbols) {
10941
11005
  hasTracing = true;
10942
11006
  Object.entries(symbols).forEach(([key, value]) => {
10943
11007
  if (typeof value === "function") {
10944
- traceSymbols[key] = [];
11008
+ if (!globalTraceSymbols[key]) {
11009
+ globalTraceSymbols[key] = [];
11010
+ }
10945
11011
  const originalFunc = debugSymbols[key];
10946
11012
  debugSymbols[key] = (...args) => {
10947
11013
  const start = performance.now();
10948
11014
  const result = originalFunc(...args);
10949
11015
  const end = performance.now();
10950
- traceSymbols[key].push(end - start);
11016
+ globalTraceSymbols[key].push(end - start);
10951
11017
  return result;
10952
11018
  };
10953
11019
  }
10954
11020
  });
10955
11021
  }
10956
- if (env.OTUI_DEBUG_FFI && ffiLogWriter) {
11022
+ if ((env.OTUI_DEBUG_FFI || env.OTUI_TRACE_FFI) && !exitHandlerRegistered) {
11023
+ exitHandlerRegistered = true;
10957
11024
  process.on("exit", () => {
10958
11025
  try {
10959
- ffiLogWriter.end();
11026
+ if (globalFFILogWriter) {
11027
+ globalFFILogWriter.end();
11028
+ }
10960
11029
  } catch (e) {}
10961
- });
10962
- }
10963
- if (hasTracing) {
10964
- process.on("exit", () => {
10965
- const allStats = [];
10966
- for (const [key, timings] of Object.entries(traceSymbols)) {
10967
- if (!Array.isArray(timings) || timings.length === 0) {
10968
- continue;
11030
+ if (globalTraceSymbols) {
11031
+ const allStats = [];
11032
+ for (const [key, timings] of Object.entries(globalTraceSymbols)) {
11033
+ if (!Array.isArray(timings) || timings.length === 0) {
11034
+ continue;
11035
+ }
11036
+ const sortedTimings = [...timings].sort((a, b) => a - b);
11037
+ const count = sortedTimings.length;
11038
+ const total = sortedTimings.reduce((acc, t2) => acc + t2, 0);
11039
+ const average = total / count;
11040
+ const min = sortedTimings[0];
11041
+ const max = sortedTimings[count - 1];
11042
+ const medianIndex = Math.floor(count / 2);
11043
+ const p90Index = Math.floor(count * 0.9);
11044
+ const p99Index = Math.floor(count * 0.99);
11045
+ const median = sortedTimings[medianIndex];
11046
+ const p90 = sortedTimings[Math.min(p90Index, count - 1)];
11047
+ const p99 = sortedTimings[Math.min(p99Index, count - 1)];
11048
+ allStats.push({
11049
+ name: key,
11050
+ count,
11051
+ total,
11052
+ average,
11053
+ min,
11054
+ max,
11055
+ median,
11056
+ p90,
11057
+ p99
11058
+ });
10969
11059
  }
10970
- const sortedTimings = [...timings].sort((a, b) => a - b);
10971
- const count = sortedTimings.length;
10972
- const total = sortedTimings.reduce((acc, t2) => acc + t2, 0);
10973
- const average = total / count;
10974
- const min = sortedTimings[0];
10975
- const max = sortedTimings[count - 1];
10976
- const medianIndex = Math.floor(count / 2);
10977
- const p90Index = Math.floor(count * 0.9);
10978
- const p99Index = Math.floor(count * 0.99);
10979
- const median = sortedTimings[medianIndex];
10980
- const p90 = sortedTimings[Math.min(p90Index, count - 1)];
10981
- const p99 = sortedTimings[Math.min(p99Index, count - 1)];
10982
- allStats.push({
10983
- name: key,
10984
- count,
10985
- total,
10986
- average,
10987
- min,
10988
- max,
10989
- median,
10990
- p90,
10991
- p99
10992
- });
10993
- }
10994
- allStats.sort((a, b) => b.total - a.total);
10995
- console.log(`
11060
+ allStats.sort((a, b) => b.total - a.total);
11061
+ const lines = [];
11062
+ lines.push(`
10996
11063
  --- OpenTUI FFI Call Performance ---`);
10997
- console.log("Sorted by total time spent (descending)");
10998
- console.log("-------------------------------------------------------------------------------------------------------------------------");
10999
- if (allStats.length === 0) {
11000
- console.log("No trace data collected or all symbols had zero calls.");
11001
- } else {
11002
- const nameHeader = "Symbol";
11003
- const callsHeader = "Calls";
11004
- const totalHeader = "Total (ms)";
11005
- const avgHeader = "Avg (ms)";
11006
- const minHeader = "Min (ms)";
11007
- const maxHeader = "Max (ms)";
11008
- const medHeader = "Med (ms)";
11009
- const p90Header = "P90 (ms)";
11010
- const p99Header = "P99 (ms)";
11011
- const nameWidth = Math.max(nameHeader.length, ...allStats.map((s) => s.name.length));
11012
- const countWidth = Math.max(callsHeader.length, ...allStats.map((s) => String(s.count).length));
11013
- const totalWidth = Math.max(totalHeader.length, ...allStats.map((s) => s.total.toFixed(2).length));
11014
- const avgWidth = Math.max(avgHeader.length, ...allStats.map((s) => s.average.toFixed(2).length));
11015
- const minWidth = Math.max(minHeader.length, ...allStats.map((s) => s.min.toFixed(2).length));
11016
- const maxWidth = Math.max(maxHeader.length, ...allStats.map((s) => s.max.toFixed(2).length));
11017
- const medianWidth = Math.max(medHeader.length, ...allStats.map((s) => s.median.toFixed(2).length));
11018
- const p90Width = Math.max(p90Header.length, ...allStats.map((s) => s.p90.toFixed(2).length));
11019
- const p99Width = Math.max(p99Header.length, ...allStats.map((s) => s.p99.toFixed(2).length));
11020
- console.log(`${nameHeader.padEnd(nameWidth)} | ${callsHeader.padStart(countWidth)} | ${totalHeader.padStart(totalWidth)} | ${avgHeader.padStart(avgWidth)} | ${minHeader.padStart(minWidth)} | ${maxHeader.padStart(maxWidth)} | ${medHeader.padStart(medianWidth)} | ${p90Header.padStart(p90Width)} | ${p99Header.padStart(p99Width)}`);
11021
- console.log(`${"-".repeat(nameWidth)}-+-${"-".repeat(countWidth)}-+-${"-".repeat(totalWidth)}-+-${"-".repeat(avgWidth)}-+-${"-".repeat(minWidth)}-+-${"-".repeat(maxWidth)}-+-${"-".repeat(medianWidth)}-+-${"-".repeat(p90Width)}-+-${"-".repeat(p99Width)}`);
11022
- allStats.forEach((stat) => {
11023
- console.log(`${stat.name.padEnd(nameWidth)} | ${String(stat.count).padStart(countWidth)} | ${stat.total.toFixed(2).padStart(totalWidth)} | ${stat.average.toFixed(2).padStart(avgWidth)} | ${stat.min.toFixed(2).padStart(minWidth)} | ${stat.max.toFixed(2).padStart(maxWidth)} | ${stat.median.toFixed(2).padStart(medianWidth)} | ${stat.p90.toFixed(2).padStart(p90Width)} | ${stat.p99.toFixed(2).padStart(p99Width)}`);
11024
- });
11064
+ lines.push("Sorted by total time spent (descending)");
11065
+ lines.push("-------------------------------------------------------------------------------------------------------------------------");
11066
+ if (allStats.length === 0) {
11067
+ lines.push("No trace data collected or all symbols had zero calls.");
11068
+ } else {
11069
+ const nameHeader = "Symbol";
11070
+ const callsHeader = "Calls";
11071
+ const totalHeader = "Total (ms)";
11072
+ const avgHeader = "Avg (ms)";
11073
+ const minHeader = "Min (ms)";
11074
+ const maxHeader = "Max (ms)";
11075
+ const medHeader = "Med (ms)";
11076
+ const p90Header = "P90 (ms)";
11077
+ const p99Header = "P99 (ms)";
11078
+ const nameWidth = Math.max(nameHeader.length, ...allStats.map((s) => s.name.length));
11079
+ const countWidth = Math.max(callsHeader.length, ...allStats.map((s) => String(s.count).length));
11080
+ const totalWidth = Math.max(totalHeader.length, ...allStats.map((s) => s.total.toFixed(2).length));
11081
+ const avgWidth = Math.max(avgHeader.length, ...allStats.map((s) => s.average.toFixed(2).length));
11082
+ const minWidth = Math.max(minHeader.length, ...allStats.map((s) => s.min.toFixed(2).length));
11083
+ const maxWidth = Math.max(maxHeader.length, ...allStats.map((s) => s.max.toFixed(2).length));
11084
+ const medianWidth = Math.max(medHeader.length, ...allStats.map((s) => s.median.toFixed(2).length));
11085
+ const p90Width = Math.max(p90Header.length, ...allStats.map((s) => s.p90.toFixed(2).length));
11086
+ const p99Width = Math.max(p99Header.length, ...allStats.map((s) => s.p99.toFixed(2).length));
11087
+ lines.push(`${nameHeader.padEnd(nameWidth)} | ${callsHeader.padStart(countWidth)} | ${totalHeader.padStart(totalWidth)} | ${avgHeader.padStart(avgWidth)} | ${minHeader.padStart(minWidth)} | ${maxHeader.padStart(maxWidth)} | ${medHeader.padStart(medianWidth)} | ${p90Header.padStart(p90Width)} | ${p99Header.padStart(p99Width)}`);
11088
+ lines.push(`${"-".repeat(nameWidth)}-+-${"-".repeat(countWidth)}-+-${"-".repeat(totalWidth)}-+-${"-".repeat(avgWidth)}-+-${"-".repeat(minWidth)}-+-${"-".repeat(maxWidth)}-+-${"-".repeat(medianWidth)}-+-${"-".repeat(p90Width)}-+-${"-".repeat(p99Width)}`);
11089
+ allStats.forEach((stat) => {
11090
+ lines.push(`${stat.name.padEnd(nameWidth)} | ${String(stat.count).padStart(countWidth)} | ${stat.total.toFixed(2).padStart(totalWidth)} | ${stat.average.toFixed(2).padStart(avgWidth)} | ${stat.min.toFixed(2).padStart(minWidth)} | ${stat.max.toFixed(2).padStart(maxWidth)} | ${stat.median.toFixed(2).padStart(medianWidth)} | ${stat.p90.toFixed(2).padStart(p90Width)} | ${stat.p99.toFixed(2).padStart(p99Width)}`);
11091
+ });
11092
+ }
11093
+ lines.push("-------------------------------------------------------------------------------------------------------------------------");
11094
+ const output = lines.join(`
11095
+ `);
11096
+ console.log(output);
11097
+ try {
11098
+ const now = new Date;
11099
+ const timestamp = now.toISOString().replace(/[:.]/g, "-").replace(/T/, "_").split("Z")[0];
11100
+ const traceFilePath = `ffi_otui_trace_${timestamp}.log`;
11101
+ Bun.write(traceFilePath, output);
11102
+ } catch (e) {
11103
+ console.error("Failed to write FFI trace file:", e);
11104
+ }
11025
11105
  }
11026
- console.log("-------------------------------------------------------------------------------------------------------------------------");
11027
11106
  });
11028
11107
  }
11029
11108
  return debugSymbols;
@@ -11349,11 +11428,11 @@ class FFIRenderLib {
11349
11428
  disableKittyKeyboard(renderer) {
11350
11429
  this.opentui.symbols.disableKittyKeyboard(renderer);
11351
11430
  }
11352
- setUseKittyKeyboard(renderer, use) {
11353
- this.opentui.symbols.setUseKittyKeyboard(renderer, use);
11431
+ setKittyKeyboardFlags(renderer, flags) {
11432
+ this.opentui.symbols.setKittyKeyboardFlags(renderer, flags);
11354
11433
  }
11355
- getUseKittyKeyboard(renderer) {
11356
- return this.opentui.symbols.getUseKittyKeyboard(renderer);
11434
+ getKittyKeyboardFlags(renderer) {
11435
+ return this.opentui.symbols.getKittyKeyboardFlags(renderer);
11357
11436
  }
11358
11437
  setupTerminal(renderer, useAlternateScreen) {
11359
11438
  this.opentui.symbols.setupTerminal(renderer, useAlternateScreen);
@@ -11729,11 +11808,17 @@ class FFIRenderLib {
11729
11808
  destroyEditBuffer(buffer) {
11730
11809
  this.opentui.symbols.destroyEditBuffer(buffer);
11731
11810
  }
11732
- editBufferSetText(buffer, textBytes, retainHistory = true) {
11733
- this.opentui.symbols.editBufferSetText(buffer, textBytes, textBytes.length, retainHistory);
11811
+ editBufferSetText(buffer, textBytes) {
11812
+ this.opentui.symbols.editBufferSetText(buffer, textBytes, textBytes.length);
11813
+ }
11814
+ editBufferSetTextFromMem(buffer, memId) {
11815
+ this.opentui.symbols.editBufferSetTextFromMem(buffer, memId);
11816
+ }
11817
+ editBufferReplaceText(buffer, textBytes) {
11818
+ this.opentui.symbols.editBufferReplaceText(buffer, textBytes, textBytes.length);
11734
11819
  }
11735
- editBufferSetTextFromMem(buffer, memId, retainHistory = true) {
11736
- this.opentui.symbols.editBufferSetTextFromMem(buffer, memId, retainHistory);
11820
+ editBufferReplaceTextFromMem(buffer, memId) {
11821
+ this.opentui.symbols.editBufferReplaceTextFromMem(buffer, memId);
11737
11822
  }
11738
11823
  editBufferGetText(buffer, maxLength) {
11739
11824
  const outBuffer = new Uint8Array(maxLength);
@@ -11959,6 +12044,16 @@ class FFIRenderLib {
11959
12044
  this.opentui.symbols.editorViewGetEOL(view, ptr3(cursorBuffer));
11960
12045
  return VisualCursorStruct.unpack(cursorBuffer);
11961
12046
  }
12047
+ editorViewGetVisualSOL(view) {
12048
+ const cursorBuffer = new ArrayBuffer(VisualCursorStruct.size);
12049
+ this.opentui.symbols.editorViewGetVisualSOL(view, ptr3(cursorBuffer));
12050
+ return VisualCursorStruct.unpack(cursorBuffer);
12051
+ }
12052
+ editorViewGetVisualEOL(view) {
12053
+ const cursorBuffer = new ArrayBuffer(VisualCursorStruct.size);
12054
+ this.opentui.symbols.editorViewGetVisualEOL(view, ptr3(cursorBuffer));
12055
+ return VisualCursorStruct.unpack(cursorBuffer);
12056
+ }
11962
12057
  bufferPushScissorRect(buffer, x, y, width, height) {
11963
12058
  this.opentui.symbols.bufferPushScissorRect(buffer, x, y, width, height);
11964
12059
  }
@@ -11968,6 +12063,18 @@ class FFIRenderLib {
11968
12063
  bufferClearScissorRects(buffer) {
11969
12064
  this.opentui.symbols.bufferClearScissorRects(buffer);
11970
12065
  }
12066
+ bufferPushOpacity(buffer, opacity) {
12067
+ this.opentui.symbols.bufferPushOpacity(buffer, opacity);
12068
+ }
12069
+ bufferPopOpacity(buffer) {
12070
+ this.opentui.symbols.bufferPopOpacity(buffer);
12071
+ }
12072
+ bufferGetCurrentOpacity(buffer) {
12073
+ return this.opentui.symbols.bufferGetCurrentOpacity(buffer);
12074
+ }
12075
+ bufferClearOpacity(buffer) {
12076
+ this.opentui.symbols.bufferClearOpacity(buffer);
12077
+ }
11971
12078
  getTerminalCapabilities(renderer) {
11972
12079
  const capsBuffer = new ArrayBuffer(TerminalCapabilitiesStruct.size);
11973
12080
  this.opentui.symbols.getTerminalCapabilities(renderer, ptr3(capsBuffer));
@@ -12460,6 +12567,7 @@ class Renderable extends BaseRenderable {
12460
12567
  _positionType = "relative";
12461
12568
  _overflow = "visible";
12462
12569
  _position = {};
12570
+ _opacity = 1;
12463
12571
  _flexShrink = 1;
12464
12572
  renderableMapById = new Map;
12465
12573
  _childrenInLayoutOrder = [];
@@ -12492,6 +12600,7 @@ class Renderable extends BaseRenderable {
12492
12600
  this.buffered = options.buffered ?? false;
12493
12601
  this._live = options.live ?? false;
12494
12602
  this._liveCount = this._live && this._visible ? 1 : 0;
12603
+ this._opacity = options.opacity !== undefined ? Math.max(0, Math.min(1, options.opacity)) : 1;
12495
12604
  this.yogaNode = src_default.Node.create(yogaConfig);
12496
12605
  this.yogaNode.setDisplay(this._visible ? Display.Flex : Display.None);
12497
12606
  this.setupYogaProperties(options);
@@ -12541,6 +12650,16 @@ class Renderable extends BaseRenderable {
12541
12650
  }
12542
12651
  this.requestRender();
12543
12652
  }
12653
+ get opacity() {
12654
+ return this._opacity;
12655
+ }
12656
+ set opacity(value) {
12657
+ const clamped = Math.max(0, Math.min(1, value));
12658
+ if (this._opacity !== clamped) {
12659
+ this._opacity = clamped;
12660
+ this.requestRender();
12661
+ }
12662
+ }
12544
12663
  hasSelection() {
12545
12664
  return false;
12546
12665
  }
@@ -12659,7 +12778,7 @@ class Renderable extends BaseRenderable {
12659
12778
  this.parent.childrenPrimarySortDirty = true;
12660
12779
  }
12661
12780
  get x() {
12662
- if (this.parent && this._positionType === "relative") {
12781
+ if (this.parent) {
12663
12782
  return this.parent.x + this._x + this._translateX;
12664
12783
  }
12665
12784
  return this._x + this._translateX;
@@ -12700,7 +12819,7 @@ class Renderable extends BaseRenderable {
12700
12819
  }
12701
12820
  }
12702
12821
  get y() {
12703
- if (this.parent && this._positionType === "relative") {
12822
+ if (this.parent) {
12704
12823
  return this.parent.y + this._y + this._translateY;
12705
12824
  }
12706
12825
  return this._y + this._translateY;
@@ -13285,6 +13404,10 @@ class Renderable extends BaseRenderable {
13285
13404
  }
13286
13405
  if (this._isDestroyed)
13287
13406
  return;
13407
+ const shouldPushOpacity = this._opacity < 1;
13408
+ if (shouldPushOpacity) {
13409
+ renderList.push({ action: "pushOpacity", opacity: this._opacity });
13410
+ }
13288
13411
  renderList.push({ action: "render", renderable: this });
13289
13412
  this.ensureZIndexSorted();
13290
13413
  const shouldPushScissor = this._overflow !== "visible" && this.width > 0 && this.height > 0;
@@ -13309,6 +13432,9 @@ class Renderable extends BaseRenderable {
13309
13432
  if (shouldPushScissor) {
13310
13433
  renderList.push({ action: "popScissorRect" });
13311
13434
  }
13435
+ if (shouldPushOpacity) {
13436
+ renderList.push({ action: "popOpacity" });
13437
+ }
13312
13438
  }
13313
13439
  render(buffer, deltaTime) {
13314
13440
  let renderBuffer = buffer;
@@ -13522,6 +13648,12 @@ class RootRenderable extends Renderable {
13522
13648
  case "popScissorRect":
13523
13649
  buffer.popScissorRect();
13524
13650
  break;
13651
+ case "pushOpacity":
13652
+ buffer.pushOpacity(command.opacity);
13653
+ break;
13654
+ case "popOpacity":
13655
+ buffer.popOpacity();
13656
+ break;
13525
13657
  }
13526
13658
  }
13527
13659
  }
@@ -13765,6 +13897,59 @@ class CapturedWritableStream extends Writable {
13765
13897
  }
13766
13898
  }
13767
13899
 
13900
+ // src/lib/keymapping.ts
13901
+ var defaultKeyAliases = {
13902
+ enter: "return",
13903
+ esc: "escape"
13904
+ };
13905
+ function mergeKeyAliases(defaults, custom) {
13906
+ return { ...defaults, ...custom };
13907
+ }
13908
+ function mergeKeyBindings(defaults, custom) {
13909
+ const map = new Map;
13910
+ for (const binding of defaults) {
13911
+ const key = getKeyBindingKey(binding);
13912
+ map.set(key, binding);
13913
+ }
13914
+ for (const binding of custom) {
13915
+ const key = getKeyBindingKey(binding);
13916
+ map.set(key, binding);
13917
+ }
13918
+ return Array.from(map.values());
13919
+ }
13920
+ function getKeyBindingKey(binding) {
13921
+ return `${binding.name}:${binding.ctrl ? 1 : 0}:${binding.shift ? 1 : 0}:${binding.meta ? 1 : 0}:${binding.super ? 1 : 0}`;
13922
+ }
13923
+ function buildKeyBindingsMap(bindings, aliasMap) {
13924
+ const map = new Map;
13925
+ const aliases = aliasMap || {};
13926
+ for (const binding of bindings) {
13927
+ const key = getKeyBindingKey(binding);
13928
+ map.set(key, binding.action);
13929
+ }
13930
+ for (const binding of bindings) {
13931
+ const normalizedName = aliases[binding.name] || binding.name;
13932
+ if (normalizedName !== binding.name) {
13933
+ const aliasedKey = getKeyBindingKey({ ...binding, name: normalizedName });
13934
+ map.set(aliasedKey, binding.action);
13935
+ }
13936
+ }
13937
+ return map;
13938
+ }
13939
+ function keyBindingToString(binding) {
13940
+ const parts = [];
13941
+ if (binding.ctrl)
13942
+ parts.push("ctrl");
13943
+ if (binding.shift)
13944
+ parts.push("shift");
13945
+ if (binding.meta)
13946
+ parts.push("meta");
13947
+ if (binding.super)
13948
+ parts.push("super");
13949
+ parts.push(binding.name);
13950
+ return parts.join("+");
13951
+ }
13952
+
13768
13953
  // src/console.ts
13769
13954
  function getCallerInfo() {
13770
13955
  const err = new Error;
@@ -13904,6 +14089,19 @@ var ConsolePosition;
13904
14089
  ConsolePosition2["LEFT"] = "left";
13905
14090
  ConsolePosition2["RIGHT"] = "right";
13906
14091
  })(ConsolePosition ||= {});
14092
+ var defaultConsoleKeybindings = [
14093
+ { name: "up", action: "scroll-up" },
14094
+ { name: "down", action: "scroll-down" },
14095
+ { name: "up", shift: true, action: "scroll-to-top" },
14096
+ { name: "down", shift: true, action: "scroll-to-bottom" },
14097
+ { name: "p", ctrl: true, action: "position-previous" },
14098
+ { name: "o", ctrl: true, action: "position-next" },
14099
+ { name: "+", action: "size-increase" },
14100
+ { name: "=", shift: true, action: "size-increase" },
14101
+ { name: "-", action: "size-decrease" },
14102
+ { name: "s", ctrl: true, action: "save-logs" },
14103
+ { name: "c", ctrl: true, shift: true, action: "copy-selection" }
14104
+ ];
13907
14105
  var DEFAULT_CONSOLE_OPTIONS = {
13908
14106
  position: "bottom" /* BOTTOM */,
13909
14107
  sizePercent: 30,
@@ -13920,7 +14118,12 @@ var DEFAULT_CONSOLE_OPTIONS = {
13920
14118
  titleBarTextColor: "#FFFFFF",
13921
14119
  cursorColor: "#00A0FF",
13922
14120
  maxStoredLogs: 2000,
13923
- maxDisplayLines: 3000
14121
+ maxDisplayLines: 3000,
14122
+ onCopySelection: undefined,
14123
+ keyBindings: undefined,
14124
+ keyAliasMap: undefined,
14125
+ selectionColor: RGBA.fromValues(0.3, 0.5, 0.8, 0.5),
14126
+ copyButtonColor: "#00A0FF"
13924
14127
  };
13925
14128
  var INDENT_WIDTH = 2;
13926
14129
 
@@ -13943,10 +14146,34 @@ class TerminalConsole extends EventEmitter8 {
13943
14146
  _allLogEntries = [];
13944
14147
  _needsFrameBufferUpdate = false;
13945
14148
  _entryListener;
14149
+ _selectionStart = null;
14150
+ _selectionEnd = null;
14151
+ _isSelecting = false;
14152
+ _copyButtonBounds = {
14153
+ x: 0,
14154
+ y: 0,
14155
+ width: 0,
14156
+ height: 0
14157
+ };
14158
+ _autoScrollInterval = null;
14159
+ _keyBindingsMap;
14160
+ _keyAliasMap;
14161
+ _keyBindings;
14162
+ _mergedKeyBindings;
14163
+ _actionHandlers;
13946
14164
  markNeedsRerender() {
13947
14165
  this._needsFrameBufferUpdate = true;
13948
14166
  this.renderer.requestRender();
13949
14167
  }
14168
+ getCopyButtonLabel() {
14169
+ const copyBindings = this._mergedKeyBindings.filter((b) => b.action === "copy-selection");
14170
+ const copyBinding = copyBindings[copyBindings.length - 1];
14171
+ if (copyBinding) {
14172
+ const shortcut = keyBindingToString(copyBinding);
14173
+ return `[Copy (${shortcut})]`;
14174
+ }
14175
+ return "[Copy]";
14176
+ }
13950
14177
  _rgbaInfo;
13951
14178
  _rgbaWarn;
13952
14179
  _rgbaError;
@@ -13957,6 +14184,8 @@ class TerminalConsole extends EventEmitter8 {
13957
14184
  _rgbaTitleBarText;
13958
14185
  _title;
13959
14186
  _rgbaCursor;
14187
+ _rgbaSelection;
14188
+ _rgbaCopyButton;
13960
14189
  _positions = [
13961
14190
  "top" /* TOP */,
13962
14191
  "right" /* RIGHT */,
@@ -13980,6 +14209,13 @@ class TerminalConsole extends EventEmitter8 {
13980
14209
  this._rgbaTitleBarText = parseColor(this.options.titleBarTextColor || this.options.colorDefault);
13981
14210
  this._title = this.options.title;
13982
14211
  this._rgbaCursor = parseColor(this.options.cursorColor);
14212
+ this._rgbaSelection = parseColor(this.options.selectionColor);
14213
+ this._rgbaCopyButton = parseColor(this.options.copyButtonColor);
14214
+ this._keyAliasMap = mergeKeyAliases(defaultKeyAliases, options.keyAliasMap || {});
14215
+ this._keyBindings = options.keyBindings || [];
14216
+ this._mergedKeyBindings = mergeKeyBindings(defaultConsoleKeybindings, this._keyBindings);
14217
+ this._keyBindingsMap = buildKeyBindingsMap(this._mergedKeyBindings, this._keyAliasMap);
14218
+ this._actionHandlers = this.buildActionHandlers();
13983
14219
  this._updateConsoleDimensions();
13984
14220
  this._scrollToBottom(true);
13985
14221
  this._entryListener = (logEntry) => {
@@ -13990,6 +14226,20 @@ class TerminalConsole extends EventEmitter8 {
13990
14226
  this.show();
13991
14227
  }
13992
14228
  }
14229
+ buildActionHandlers() {
14230
+ return new Map([
14231
+ ["scroll-up", () => this.scrollUp()],
14232
+ ["scroll-down", () => this.scrollDown()],
14233
+ ["scroll-to-top", () => this.scrollToTop()],
14234
+ ["scroll-to-bottom", () => this.scrollToBottomAction()],
14235
+ ["position-previous", () => this.positionPrevious()],
14236
+ ["position-next", () => this.positionNext()],
14237
+ ["size-increase", () => this.sizeIncrease()],
14238
+ ["size-decrease", () => this.sizeDecrease()],
14239
+ ["save-logs", () => this.saveLogsAction()],
14240
+ ["copy-selection", () => this.triggerCopyAction()]
14241
+ ]);
14242
+ }
13993
14243
  activate() {
13994
14244
  terminalConsoleCache.activate();
13995
14245
  }
@@ -14016,8 +14266,8 @@ class TerminalConsole extends EventEmitter8 {
14016
14266
  this.markNeedsRerender();
14017
14267
  }
14018
14268
  _updateConsoleDimensions(termWidth, termHeight) {
14019
- const width = termWidth ?? this.renderer.terminalWidth;
14020
- const height = termHeight ?? this.renderer.terminalHeight;
14269
+ const width = termWidth ?? this.renderer.width;
14270
+ const height = termHeight ?? this.renderer.height;
14021
14271
  const sizePercent = this.options.sizePercent / 100;
14022
14272
  switch (this.options.position) {
14023
14273
  case "top" /* TOP */:
@@ -14048,68 +14298,103 @@ class TerminalConsole extends EventEmitter8 {
14048
14298
  this.currentLineIndex = Math.max(0, Math.min(this.currentLineIndex, this.consoleHeight - 1));
14049
14299
  }
14050
14300
  handleKeyPress(event) {
14051
- let needsRedraw = false;
14052
- const displayLineCount = this._displayLines.length;
14053
- const logAreaHeight = Math.max(1, this.consoleHeight - 1);
14054
- const maxScrollTop = Math.max(0, displayLineCount - logAreaHeight);
14055
- const currentPositionIndex = this._positions.indexOf(this.options.position);
14056
14301
  if (event.name === "escape") {
14057
14302
  this.blur();
14058
14303
  return;
14059
14304
  }
14060
- if (event.name === "up" && event.shift) {
14061
- if (this.scrollTopIndex > 0 || this.currentLineIndex > 0) {
14062
- this.scrollTopIndex = 0;
14063
- this.currentLineIndex = 0;
14064
- this.isScrolledToBottom = this._displayLines.length <= Math.max(1, this.consoleHeight - 1);
14065
- needsRedraw = true;
14066
- }
14067
- } else if (event.name === "down" && event.shift) {
14068
- const logAreaHeightForScroll = Math.max(1, this.consoleHeight - 1);
14069
- const maxScrollPossible = Math.max(0, this._displayLines.length - logAreaHeightForScroll);
14070
- if (this.scrollTopIndex < maxScrollPossible || !this.isScrolledToBottom) {
14071
- this._scrollToBottom(true);
14072
- needsRedraw = true;
14073
- }
14074
- } else if (event.name === "up") {
14075
- if (this.currentLineIndex > 0) {
14076
- this.currentLineIndex--;
14077
- needsRedraw = true;
14078
- } else if (this.scrollTopIndex > 0) {
14079
- this.scrollTopIndex--;
14080
- this.isScrolledToBottom = false;
14081
- needsRedraw = true;
14082
- }
14083
- } else if (event.name === "down") {
14084
- const canCursorMoveDown = this.currentLineIndex < logAreaHeight - 1 && this.scrollTopIndex + this.currentLineIndex < displayLineCount - 1;
14085
- if (canCursorMoveDown) {
14086
- this.currentLineIndex++;
14087
- needsRedraw = true;
14088
- } else if (this.scrollTopIndex < maxScrollTop) {
14089
- this.scrollTopIndex++;
14090
- this.isScrolledToBottom = this.scrollTopIndex === maxScrollTop;
14091
- needsRedraw = true;
14092
- }
14093
- } else if (event.name === "p" && event.ctrl) {
14094
- const prevIndex = (currentPositionIndex - 1 + this._positions.length) % this._positions.length;
14095
- this.options.position = this._positions[prevIndex];
14096
- this.resize(this.renderer.terminalWidth, this.renderer.terminalHeight);
14097
- } else if (event.name === "o" && event.ctrl) {
14098
- const nextIndex = (currentPositionIndex + 1) % this._positions.length;
14099
- this.options.position = this._positions[nextIndex];
14100
- this.resize(this.renderer.terminalWidth, this.renderer.terminalHeight);
14101
- } else if (event.name === "+" || event.name === "=" && event.shift) {
14102
- this.options.sizePercent = Math.min(100, this.options.sizePercent + 5);
14103
- this.resize(this.renderer.terminalWidth, this.renderer.terminalHeight);
14104
- } else if (event.name === "-") {
14105
- this.options.sizePercent = Math.max(10, this.options.sizePercent - 5);
14106
- this.resize(this.renderer.terminalWidth, this.renderer.terminalHeight);
14107
- } else if (event.name === "s" && event.ctrl) {
14108
- this.saveLogsToFile();
14109
- }
14110
- if (needsRedraw) {
14305
+ const bindingKey = getKeyBindingKey({
14306
+ name: event.name,
14307
+ ctrl: event.ctrl,
14308
+ shift: event.shift,
14309
+ meta: event.meta,
14310
+ super: event.super,
14311
+ action: "scroll-up"
14312
+ });
14313
+ const action = this._keyBindingsMap.get(bindingKey);
14314
+ if (action) {
14315
+ const handler = this._actionHandlers.get(action);
14316
+ if (handler) {
14317
+ handler();
14318
+ return;
14319
+ }
14320
+ }
14321
+ }
14322
+ scrollUp() {
14323
+ const logAreaHeight = Math.max(1, this.consoleHeight - 1);
14324
+ if (this.currentLineIndex > 0) {
14325
+ this.currentLineIndex--;
14326
+ this.markNeedsRerender();
14327
+ } else if (this.scrollTopIndex > 0) {
14328
+ this.scrollTopIndex--;
14329
+ this.isScrolledToBottom = false;
14111
14330
  this.markNeedsRerender();
14112
14331
  }
14332
+ return true;
14333
+ }
14334
+ scrollDown() {
14335
+ const displayLineCount = this._displayLines.length;
14336
+ const logAreaHeight = Math.max(1, this.consoleHeight - 1);
14337
+ const maxScrollTop = Math.max(0, displayLineCount - logAreaHeight);
14338
+ const canCursorMoveDown = this.currentLineIndex < logAreaHeight - 1 && this.scrollTopIndex + this.currentLineIndex < displayLineCount - 1;
14339
+ if (canCursorMoveDown) {
14340
+ this.currentLineIndex++;
14341
+ this.markNeedsRerender();
14342
+ } else if (this.scrollTopIndex < maxScrollTop) {
14343
+ this.scrollTopIndex++;
14344
+ this.isScrolledToBottom = this.scrollTopIndex === maxScrollTop;
14345
+ this.markNeedsRerender();
14346
+ }
14347
+ return true;
14348
+ }
14349
+ scrollToTop() {
14350
+ if (this.scrollTopIndex > 0 || this.currentLineIndex > 0) {
14351
+ this.scrollTopIndex = 0;
14352
+ this.currentLineIndex = 0;
14353
+ this.isScrolledToBottom = this._displayLines.length <= Math.max(1, this.consoleHeight - 1);
14354
+ this.markNeedsRerender();
14355
+ }
14356
+ return true;
14357
+ }
14358
+ scrollToBottomAction() {
14359
+ const logAreaHeightForScroll = Math.max(1, this.consoleHeight - 1);
14360
+ const maxScrollPossible = Math.max(0, this._displayLines.length - logAreaHeightForScroll);
14361
+ if (this.scrollTopIndex < maxScrollPossible || !this.isScrolledToBottom) {
14362
+ this._scrollToBottom(true);
14363
+ this.markNeedsRerender();
14364
+ }
14365
+ return true;
14366
+ }
14367
+ positionPrevious() {
14368
+ const currentPositionIndex = this._positions.indexOf(this.options.position);
14369
+ const prevIndex = (currentPositionIndex - 1 + this._positions.length) % this._positions.length;
14370
+ this.options.position = this._positions[prevIndex];
14371
+ this.resize(this.renderer.width, this.renderer.height);
14372
+ return true;
14373
+ }
14374
+ positionNext() {
14375
+ const currentPositionIndex = this._positions.indexOf(this.options.position);
14376
+ const nextIndex = (currentPositionIndex + 1) % this._positions.length;
14377
+ this.options.position = this._positions[nextIndex];
14378
+ this.resize(this.renderer.width, this.renderer.height);
14379
+ return true;
14380
+ }
14381
+ sizeIncrease() {
14382
+ this.options.sizePercent = Math.min(100, this.options.sizePercent + 5);
14383
+ this.resize(this.renderer.width, this.renderer.height);
14384
+ return true;
14385
+ }
14386
+ sizeDecrease() {
14387
+ this.options.sizePercent = Math.max(10, this.options.sizePercent - 5);
14388
+ this.resize(this.renderer.width, this.renderer.height);
14389
+ return true;
14390
+ }
14391
+ saveLogsAction() {
14392
+ this.saveLogsToFile();
14393
+ return true;
14394
+ }
14395
+ triggerCopyAction() {
14396
+ this.triggerCopy();
14397
+ return true;
14113
14398
  }
14114
14399
  attachStdin() {
14115
14400
  if (this.isFocused)
@@ -14226,6 +14511,7 @@ class TerminalConsole extends EventEmitter8 {
14226
14511
  }
14227
14512
  }
14228
14513
  destroy() {
14514
+ this.stopAutoScroll();
14229
14515
  this.hide();
14230
14516
  this.deactivate();
14231
14517
  terminalConsoleCache.off("entry", this._entryListener);
@@ -14245,13 +14531,26 @@ class TerminalConsole extends EventEmitter8 {
14245
14531
  const dynamicTitle = `${this._title}${this.isFocused ? " (Focused)" : ""}`;
14246
14532
  const titleX = Math.max(0, Math.floor((this.consoleWidth - dynamicTitle.length) / 2));
14247
14533
  this.frameBuffer.drawText(dynamicTitle, titleX, 0, this._rgbaTitleBarText, this._rgbaTitleBar);
14534
+ const copyLabel = this.getCopyButtonLabel();
14535
+ const copyButtonX = this.consoleWidth - copyLabel.length - 1;
14536
+ if (copyButtonX >= 0) {
14537
+ const copyButtonEnabled = this.hasSelection();
14538
+ const disabledColor = RGBA.fromInts(100, 100, 100, 255);
14539
+ const copyColor = copyButtonEnabled ? this._rgbaCopyButton : disabledColor;
14540
+ this.frameBuffer.drawText(copyLabel, copyButtonX, 0, copyColor, this._rgbaTitleBar);
14541
+ this._copyButtonBounds = { x: copyButtonX, y: 0, width: copyLabel.length, height: 1 };
14542
+ } else {
14543
+ this._copyButtonBounds = { x: -1, y: -1, width: 0, height: 0 };
14544
+ }
14248
14545
  const startIndex = this.scrollTopIndex;
14249
14546
  const endIndex = Math.min(startIndex + logAreaHeight, displayLineCount);
14250
14547
  const visibleDisplayLines = displayLines.slice(startIndex, endIndex);
14251
14548
  let lineY = 1;
14252
- for (const displayLine of visibleDisplayLines) {
14549
+ for (let i = 0;i < visibleDisplayLines.length; i++) {
14253
14550
  if (lineY >= this.consoleHeight)
14254
14551
  break;
14552
+ const displayLine = visibleDisplayLines[i];
14553
+ const absoluteLineIndex = startIndex + i;
14255
14554
  let levelColor = this._rgbaDefault;
14256
14555
  switch (displayLine.level) {
14257
14556
  case "INFO" /* INFO */:
@@ -14276,7 +14575,24 @@ class TerminalConsole extends EventEmitter8 {
14276
14575
  } else {
14277
14576
  this.frameBuffer.drawText(" ", 0, lineY, this._rgbaDefault, this.backgroundColor);
14278
14577
  }
14279
- this.frameBuffer.drawText(`${linePrefix}${textToDraw.substring(0, textAvailableWidth)}`, 1, lineY, levelColor);
14578
+ const fullText = `${linePrefix}${textToDraw.substring(0, textAvailableWidth)}`;
14579
+ const selectionRange = this.getLineSelectionRange(absoluteLineIndex);
14580
+ if (selectionRange) {
14581
+ const adjustedStart = Math.max(0, selectionRange.start);
14582
+ const adjustedEnd = Math.min(fullText.length, selectionRange.end);
14583
+ if (adjustedStart > 0) {
14584
+ this.frameBuffer.drawText(fullText.substring(0, adjustedStart), 1, lineY, levelColor);
14585
+ }
14586
+ if (adjustedStart < adjustedEnd) {
14587
+ this.frameBuffer.fillRect(1 + adjustedStart, lineY, adjustedEnd - adjustedStart, 1, this._rgbaSelection);
14588
+ this.frameBuffer.drawText(fullText.substring(adjustedStart, adjustedEnd), 1 + adjustedStart, lineY, levelColor, this._rgbaSelection);
14589
+ }
14590
+ if (adjustedEnd < fullText.length) {
14591
+ this.frameBuffer.drawText(fullText.substring(adjustedEnd), 1 + adjustedEnd, lineY, levelColor);
14592
+ }
14593
+ } else {
14594
+ this.frameBuffer.drawText(fullText, 1, lineY, levelColor);
14595
+ }
14280
14596
  lineY++;
14281
14597
  }
14282
14598
  }
@@ -14299,6 +14615,24 @@ class TerminalConsole extends EventEmitter8 {
14299
14615
  toggleDebugMode() {
14300
14616
  this.setDebugMode(!this._debugModeEnabled);
14301
14617
  }
14618
+ set keyBindings(bindings) {
14619
+ this._keyBindings = bindings;
14620
+ this._mergedKeyBindings = mergeKeyBindings(defaultConsoleKeybindings, bindings);
14621
+ this._keyBindingsMap = buildKeyBindingsMap(this._mergedKeyBindings, this._keyAliasMap);
14622
+ this.markNeedsRerender();
14623
+ }
14624
+ set keyAliasMap(aliases) {
14625
+ this._keyAliasMap = mergeKeyAliases(defaultKeyAliases, aliases);
14626
+ this._mergedKeyBindings = mergeKeyBindings(defaultConsoleKeybindings, this._keyBindings);
14627
+ this._keyBindingsMap = buildKeyBindingsMap(this._mergedKeyBindings, this._keyAliasMap);
14628
+ this.markNeedsRerender();
14629
+ }
14630
+ set onCopySelection(callback) {
14631
+ this.options.onCopySelection = callback;
14632
+ }
14633
+ get onCopySelection() {
14634
+ return this.options.onCopySelection;
14635
+ }
14302
14636
  _scrollToBottom(forceCursorToLastLine = false) {
14303
14637
  const displayLineCount = this._displayLines.length;
14304
14638
  const logAreaHeight = Math.max(1, this.consoleHeight - 1);
@@ -14356,6 +14690,214 @@ class TerminalConsole extends EventEmitter8 {
14356
14690
  this._displayLines.splice(0, this._displayLines.length - this.options.maxDisplayLines);
14357
14691
  }
14358
14692
  }
14693
+ hasSelection() {
14694
+ if (this._selectionStart === null || this._selectionEnd === null)
14695
+ return false;
14696
+ return this._selectionStart.line !== this._selectionEnd.line || this._selectionStart.col !== this._selectionEnd.col;
14697
+ }
14698
+ normalizeSelection() {
14699
+ if (!this._selectionStart || !this._selectionEnd)
14700
+ return null;
14701
+ const start = this._selectionStart;
14702
+ const end = this._selectionEnd;
14703
+ const startBeforeEnd = start.line < end.line || start.line === end.line && start.col <= end.col;
14704
+ if (startBeforeEnd) {
14705
+ return {
14706
+ startLine: start.line,
14707
+ startCol: start.col,
14708
+ endLine: end.line,
14709
+ endCol: end.col
14710
+ };
14711
+ } else {
14712
+ return {
14713
+ startLine: end.line,
14714
+ startCol: end.col,
14715
+ endLine: start.line,
14716
+ endCol: start.col
14717
+ };
14718
+ }
14719
+ }
14720
+ getSelectedText() {
14721
+ const selection2 = this.normalizeSelection();
14722
+ if (!selection2)
14723
+ return "";
14724
+ const lines = [];
14725
+ for (let i = selection2.startLine;i <= selection2.endLine; i++) {
14726
+ if (i < 0 || i >= this._displayLines.length)
14727
+ continue;
14728
+ const line = this._displayLines[i];
14729
+ const linePrefix = line.indent ? " ".repeat(INDENT_WIDTH) : "";
14730
+ const textAvailableWidth = this.consoleWidth - 1 - (line.indent ? INDENT_WIDTH : 0);
14731
+ const fullText = linePrefix + line.text.substring(0, textAvailableWidth);
14732
+ let text = fullText;
14733
+ if (i === selection2.startLine && i === selection2.endLine) {
14734
+ text = fullText.substring(selection2.startCol, selection2.endCol);
14735
+ } else if (i === selection2.startLine) {
14736
+ text = fullText.substring(selection2.startCol);
14737
+ } else if (i === selection2.endLine) {
14738
+ text = fullText.substring(0, selection2.endCol);
14739
+ }
14740
+ lines.push(text);
14741
+ }
14742
+ return lines.join(`
14743
+ `);
14744
+ }
14745
+ clearSelection() {
14746
+ this._selectionStart = null;
14747
+ this._selectionEnd = null;
14748
+ this._isSelecting = false;
14749
+ this.stopAutoScroll();
14750
+ }
14751
+ stopAutoScroll() {
14752
+ if (this._autoScrollInterval !== null) {
14753
+ clearInterval(this._autoScrollInterval);
14754
+ this._autoScrollInterval = null;
14755
+ }
14756
+ }
14757
+ startAutoScroll(direction) {
14758
+ this.stopAutoScroll();
14759
+ this._autoScrollInterval = setInterval(() => {
14760
+ if (direction === "up") {
14761
+ if (this.scrollTopIndex > 0) {
14762
+ this.scrollTopIndex--;
14763
+ this.isScrolledToBottom = false;
14764
+ if (this._selectionEnd) {
14765
+ this._selectionEnd = {
14766
+ line: this.scrollTopIndex,
14767
+ col: this._selectionEnd.col
14768
+ };
14769
+ }
14770
+ this.markNeedsRerender();
14771
+ } else {
14772
+ this.stopAutoScroll();
14773
+ }
14774
+ } else {
14775
+ const displayLineCount = this._displayLines.length;
14776
+ const logAreaHeight = Math.max(1, this.consoleHeight - 1);
14777
+ const maxScrollTop = Math.max(0, displayLineCount - logAreaHeight);
14778
+ if (this.scrollTopIndex < maxScrollTop) {
14779
+ this.scrollTopIndex++;
14780
+ this.isScrolledToBottom = this.scrollTopIndex === maxScrollTop;
14781
+ if (this._selectionEnd) {
14782
+ const maxLine = this.scrollTopIndex + logAreaHeight - 1;
14783
+ this._selectionEnd = {
14784
+ line: Math.min(maxLine, displayLineCount - 1),
14785
+ col: this._selectionEnd.col
14786
+ };
14787
+ }
14788
+ this.markNeedsRerender();
14789
+ } else {
14790
+ this.stopAutoScroll();
14791
+ }
14792
+ }
14793
+ }, 50);
14794
+ }
14795
+ triggerCopy() {
14796
+ if (!this.hasSelection())
14797
+ return;
14798
+ const text = this.getSelectedText();
14799
+ if (text && this.options.onCopySelection) {
14800
+ try {
14801
+ this.options.onCopySelection(text);
14802
+ } catch {}
14803
+ this.clearSelection();
14804
+ this.markNeedsRerender();
14805
+ }
14806
+ }
14807
+ getLineSelectionRange(lineIndex) {
14808
+ const selection2 = this.normalizeSelection();
14809
+ if (!selection2)
14810
+ return null;
14811
+ if (lineIndex < selection2.startLine || lineIndex > selection2.endLine) {
14812
+ return null;
14813
+ }
14814
+ const line = this._displayLines[lineIndex];
14815
+ if (!line)
14816
+ return null;
14817
+ const linePrefix = line.indent ? " ".repeat(INDENT_WIDTH) : "";
14818
+ const textAvailableWidth = this.consoleWidth - 1 - (line.indent ? INDENT_WIDTH : 0);
14819
+ const fullTextLength = linePrefix.length + Math.min(line.text.length, textAvailableWidth);
14820
+ let start = 0;
14821
+ let end = fullTextLength;
14822
+ if (lineIndex === selection2.startLine) {
14823
+ start = Math.max(0, selection2.startCol);
14824
+ }
14825
+ if (lineIndex === selection2.endLine) {
14826
+ end = Math.min(fullTextLength, selection2.endCol);
14827
+ }
14828
+ if (start >= end)
14829
+ return null;
14830
+ return { start, end };
14831
+ }
14832
+ handleMouse(event) {
14833
+ if (!this.isVisible)
14834
+ return false;
14835
+ const localX = event.x - this.consoleX;
14836
+ const localY = event.y - this.consoleY;
14837
+ if (localX < 0 || localX >= this.consoleWidth || localY < 0 || localY >= this.consoleHeight) {
14838
+ return false;
14839
+ }
14840
+ if (event.type === "scroll" && event.scroll) {
14841
+ if (event.scroll.direction === "up") {
14842
+ this.scrollUp();
14843
+ } else if (event.scroll.direction === "down") {
14844
+ this.scrollDown();
14845
+ }
14846
+ return true;
14847
+ }
14848
+ if (localY === 0) {
14849
+ if (event.type === "down" && event.button === 0 && localX >= this._copyButtonBounds.x && localX < this._copyButtonBounds.x + this._copyButtonBounds.width) {
14850
+ this.triggerCopy();
14851
+ return true;
14852
+ }
14853
+ return true;
14854
+ }
14855
+ const lineIndex = this.scrollTopIndex + (localY - 1);
14856
+ const colIndex = Math.max(0, localX - 1);
14857
+ if (event.type === "down" && event.button === 0) {
14858
+ this.clearSelection();
14859
+ this._selectionStart = { line: lineIndex, col: colIndex };
14860
+ this._selectionEnd = { line: lineIndex, col: colIndex };
14861
+ this._isSelecting = true;
14862
+ this.markNeedsRerender();
14863
+ return true;
14864
+ }
14865
+ if (event.type === "drag" && this._isSelecting) {
14866
+ this._selectionEnd = { line: lineIndex, col: colIndex };
14867
+ const logAreaHeight = Math.max(1, this.consoleHeight - 1);
14868
+ const relativeY = localY - 1;
14869
+ if (relativeY <= 0) {
14870
+ this.startAutoScroll("up");
14871
+ } else if (relativeY >= logAreaHeight - 1) {
14872
+ this.startAutoScroll("down");
14873
+ } else {
14874
+ this.stopAutoScroll();
14875
+ }
14876
+ this.markNeedsRerender();
14877
+ return true;
14878
+ }
14879
+ if (event.type === "up") {
14880
+ if (this._isSelecting) {
14881
+ this._selectionEnd = { line: lineIndex, col: colIndex };
14882
+ this._isSelecting = false;
14883
+ this.stopAutoScroll();
14884
+ this.markNeedsRerender();
14885
+ }
14886
+ return true;
14887
+ }
14888
+ return true;
14889
+ }
14890
+ get visible() {
14891
+ return this.isVisible;
14892
+ }
14893
+ get bounds() {
14894
+ return {
14895
+ x: this.consoleX,
14896
+ y: this.consoleY,
14897
+ width: this.consoleWidth,
14898
+ height: this.consoleHeight
14899
+ };
14900
+ }
14359
14901
  saveLogsToFile() {
14360
14902
  try {
14361
14903
  const timestamp = Date.now();
@@ -14555,6 +15097,18 @@ registerEnvVar({
14555
15097
  type: "boolean",
14556
15098
  default: false
14557
15099
  });
15100
+ var KITTY_FLAG_ALTERNATE_KEYS = 1;
15101
+ var KITTY_FLAG_EVENT_TYPES = 2;
15102
+ function buildKittyKeyboardFlags(config) {
15103
+ if (!config) {
15104
+ return 0;
15105
+ }
15106
+ let flags = KITTY_FLAG_ALTERNATE_KEYS;
15107
+ if (config.events) {
15108
+ flags |= KITTY_FLAG_EVENT_TYPES;
15109
+ }
15110
+ return flags;
15111
+ }
14558
15112
 
14559
15113
  class MouseEvent {
14560
15114
  type;
@@ -14639,8 +15193,9 @@ async function createCliRenderer(config = {}) {
14639
15193
  config.useThread = false;
14640
15194
  }
14641
15195
  ziglib.setUseThread(rendererPtr, config.useThread);
14642
- const useKittyKeyboard = config.useKittyKeyboard ?? true;
14643
- ziglib.setUseKittyKeyboard(rendererPtr, useKittyKeyboard);
15196
+ const kittyConfig = config.useKittyKeyboard ?? {};
15197
+ const kittyFlags = buildKittyKeyboardFlags(kittyConfig);
15198
+ ziglib.setKittyKeyboardFlags(rendererPtr, kittyFlags);
14644
15199
  const renderer = new CliRenderer(ziglib, rendererPtr, stdin, stdout, width, height, config);
14645
15200
  await renderer.setupTerminal();
14646
15201
  return renderer;
@@ -14723,6 +15278,7 @@ class CliRenderer extends EventEmitter9 {
14723
15278
  _stdinBuffer;
14724
15279
  animationRequest = new Map;
14725
15280
  resizeTimeoutId = null;
15281
+ capabilityTimeoutId = null;
14726
15282
  resizeDebounceDelay = 100;
14727
15283
  enableMouseMovement = false;
14728
15284
  _useMouse = true;
@@ -14856,7 +15412,9 @@ Captured output:
14856
15412
  process.on("uncaughtException", this.handleError);
14857
15413
  process.on("unhandledRejection", this.handleError);
14858
15414
  process.on("beforeExit", this.exitHandler);
14859
- this._keyHandler = new InternalKeyHandler(config.useKittyKeyboard ?? true);
15415
+ const kittyConfig = config.useKittyKeyboard ?? {};
15416
+ const useKittyForParsing = kittyConfig !== null;
15417
+ this._keyHandler = new InternalKeyHandler(useKittyForParsing);
14860
15418
  this._keyHandler.on("keypress", (event) => {
14861
15419
  if (this.exitOnCtrlC && event.name === "c" && event.ctrl) {
14862
15420
  process.nextTick(() => {
@@ -15057,10 +15615,11 @@ Captured output:
15057
15615
  return [...this._debugInputs];
15058
15616
  }
15059
15617
  get useKittyKeyboard() {
15060
- return this.lib.getUseKittyKeyboard(this.rendererPtr);
15618
+ return this.lib.getKittyKeyboardFlags(this.rendererPtr) > 0;
15061
15619
  }
15062
15620
  set useKittyKeyboard(use) {
15063
- this.lib.setUseKittyKeyboard(this.rendererPtr, use);
15621
+ const flags = use ? KITTY_FLAG_ALTERNATE_KEYS : 0;
15622
+ this.lib.setKittyKeyboardFlags(this.rendererPtr, flags);
15064
15623
  }
15065
15624
  set experimental_splitHeight(splitHeight) {
15066
15625
  if (splitHeight < 0)
@@ -15162,7 +15721,8 @@ Captured output:
15162
15721
  this._terminalIsSetup = true;
15163
15722
  this.lib.setupTerminal(this.rendererPtr, this._useAlternateScreen);
15164
15723
  this._capabilities = this.lib.getTerminalCapabilities(this.rendererPtr);
15165
- setTimeout(() => {
15724
+ this.capabilityTimeoutId = setTimeout(() => {
15725
+ this.capabilityTimeoutId = null;
15166
15726
  this.removeInputHandler(this.capabilityHandler);
15167
15727
  }, 5000);
15168
15728
  if (this._useMouse) {
@@ -15259,6 +15819,15 @@ Captured output:
15259
15819
  }
15260
15820
  this._latestPointer.x = mouseEvent.x;
15261
15821
  this._latestPointer.y = mouseEvent.y;
15822
+ if (this._console.visible) {
15823
+ const consoleBounds = this._console.bounds;
15824
+ if (mouseEvent.x >= consoleBounds.x && mouseEvent.x < consoleBounds.x + consoleBounds.width && mouseEvent.y >= consoleBounds.y && mouseEvent.y < consoleBounds.y + consoleBounds.height) {
15825
+ const event2 = new MouseEvent(null, mouseEvent);
15826
+ const handled = this._console.handleMouse(event2);
15827
+ if (handled)
15828
+ return true;
15829
+ }
15830
+ }
15262
15831
  if (mouseEvent.type === "scroll") {
15263
15832
  const maybeRenderableId2 = this.lib.checkHit(this.rendererPtr, mouseEvent.x, mouseEvent.y);
15264
15833
  const maybeRenderable2 = Renderable.renderablesByNumber.get(maybeRenderableId2);
@@ -15630,7 +16199,17 @@ Captured output:
15630
16199
  process.removeListener("uncaughtException", this.handleError);
15631
16200
  process.removeListener("unhandledRejection", this.handleError);
15632
16201
  process.removeListener("warning", this.warningHandler);
16202
+ process.removeListener("beforeExit", this.exitHandler);
15633
16203
  capture.removeListener("write", this.captureCallback);
16204
+ this.removeExitListeners();
16205
+ if (this.resizeTimeoutId !== null) {
16206
+ clearTimeout(this.resizeTimeoutId);
16207
+ this.resizeTimeoutId = null;
16208
+ }
16209
+ if (this.capabilityTimeoutId !== null) {
16210
+ clearTimeout(this.capabilityTimeoutId);
16211
+ this.capabilityTimeoutId = null;
16212
+ }
15634
16213
  if (this.memorySnapshotTimer) {
15635
16214
  clearInterval(this.memorySnapshotTimer);
15636
16215
  }
@@ -15943,7 +16522,7 @@ Captured output:
15943
16522
  }
15944
16523
  }
15945
16524
 
15946
- export { __toESM, __commonJS, __export, __require, Edge, Gutter, MeasureMode, exports_src, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, nonAlphanumericKeys, parseKeypress, 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, hastToStyledText, LinearScrollAccel, MacOSScrollAccel, StdinBuffer, 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, ExtmarksController, createExtmarksController, TerminalPalette, createTerminalPalette, TextBuffer, LogLevel2 as LogLevel, setRenderLibPath, resolveRenderLib, OptimizedBuffer, h, isVNode, maybeMakeRenderable, wrapWithDelegates, instantiate, delegate, isValidPercentage, LayoutEvents, RenderableEvents, isRenderable, BaseRenderable, Renderable, RootRenderable, ANSI, capture, ConsolePosition, TerminalConsole, getObjectsInViewport, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, RendererControlState, CliRenderer };
16525
+ export { __toESM, __commonJS, __export, __require, Edge, Gutter, MeasureMode, exports_src, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, nonAlphanumericKeys, parseKeypress, 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, hastToStyledText, LinearScrollAccel, MacOSScrollAccel, StdinBuffer, 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, ExtmarksController, createExtmarksController, TerminalPalette, createTerminalPalette, TextBuffer, LogLevel2 as LogLevel, setRenderLibPath, resolveRenderLib, OptimizedBuffer, h, isVNode, maybeMakeRenderable, wrapWithDelegates, instantiate, delegate, isValidPercentage, LayoutEvents, RenderableEvents, isRenderable, BaseRenderable, Renderable, RootRenderable, ANSI, defaultKeyAliases, mergeKeyAliases, mergeKeyBindings, getKeyBindingKey, buildKeyBindingsMap, capture, ConsolePosition, TerminalConsole, getObjectsInViewport, buildKittyKeyboardFlags, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, RendererControlState, CliRenderer };
15947
16526
 
15948
- //# debugId=50CCF62F4F782D5964756E2164756E21
15949
- //# sourceMappingURL=index-crebvcxc.js.map
16527
+ //# debugId=0788E633A0C8647564756E2164756E21
16528
+ //# sourceMappingURL=index-rysm4rsr.js.map