@opentui/core 0.1.60 → 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;
@@ -9390,6 +9391,22 @@ class OptimizedBuffer {
9390
9391
  this.guard();
9391
9392
  this.lib.bufferClearScissorRects(this.bufferPtr);
9392
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
+ }
9393
9410
  encodeUnicode(text) {
9394
9411
  this.guard();
9395
9412
  return this.lib.encodeUnicode(text, this._widthMethod);
@@ -10132,6 +10149,9 @@ registerEnvVar({
10132
10149
  type: "boolean",
10133
10150
  default: false
10134
10151
  });
10152
+ var globalTraceSymbols = null;
10153
+ var globalFFILogWriter = null;
10154
+ var exitHandlerRegistered = false;
10135
10155
  function getOpenTUILib(libPath) {
10136
10156
  const resolvedLibPath = libPath || targetLibPath;
10137
10157
  const rawSymbols = dlopen(resolvedLibPath, {
@@ -10319,6 +10339,22 @@ function getOpenTUILib(libPath) {
10319
10339
  args: ["ptr"],
10320
10340
  returns: "void"
10321
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
+ },
10322
10358
  addToHitGrid: {
10323
10359
  args: ["ptr", "i32", "i32", "u32", "u32", "u32"],
10324
10360
  returns: "void"
@@ -10859,6 +10895,14 @@ function getOpenTUILib(libPath) {
10859
10895
  args: ["ptr", "ptr"],
10860
10896
  returns: "void"
10861
10897
  },
10898
+ editorViewGetVisualSOL: {
10899
+ args: ["ptr", "ptr"],
10900
+ returns: "void"
10901
+ },
10902
+ editorViewGetVisualEOL: {
10903
+ args: ["ptr", "ptr"],
10904
+ returns: "void"
10905
+ },
10862
10906
  editorViewSetPlaceholderStyledText: {
10863
10907
  args: ["ptr", "ptr", "usize"],
10864
10908
  returns: "void"
@@ -10924,19 +10968,22 @@ function getOpenTUILib(libPath) {
10924
10968
  return rawSymbols;
10925
10969
  }
10926
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
+ }
10927
10980
  const debugSymbols = {};
10928
- const traceSymbols = {};
10929
10981
  let hasTracing = false;
10930
- let ffiLogWriter = null;
10931
10982
  Object.entries(symbols).forEach(([key, value]) => {
10932
10983
  debugSymbols[key] = value;
10933
10984
  });
10934
- if (env.OTUI_DEBUG_FFI) {
10935
- const now = new Date;
10936
- const timestamp = now.toISOString().replace(/[:.]/g, "-").replace(/T/, "_").split("Z")[0];
10937
- const logFilePath = `ffi_otui_debug_${timestamp}.log`;
10938
- ffiLogWriter = Bun.file(logFilePath).writer();
10939
- const writer = ffiLogWriter;
10985
+ if (env.OTUI_DEBUG_FFI && globalFFILogWriter) {
10986
+ const writer = globalFFILogWriter;
10940
10987
  const writeSync = (msg) => {
10941
10988
  const buffer = new TextEncoder().encode(msg + `
10942
10989
  `);
@@ -10958,89 +11005,104 @@ function convertToDebugSymbols(symbols) {
10958
11005
  hasTracing = true;
10959
11006
  Object.entries(symbols).forEach(([key, value]) => {
10960
11007
  if (typeof value === "function") {
10961
- traceSymbols[key] = [];
11008
+ if (!globalTraceSymbols[key]) {
11009
+ globalTraceSymbols[key] = [];
11010
+ }
10962
11011
  const originalFunc = debugSymbols[key];
10963
11012
  debugSymbols[key] = (...args) => {
10964
11013
  const start = performance.now();
10965
11014
  const result = originalFunc(...args);
10966
11015
  const end = performance.now();
10967
- traceSymbols[key].push(end - start);
11016
+ globalTraceSymbols[key].push(end - start);
10968
11017
  return result;
10969
11018
  };
10970
11019
  }
10971
11020
  });
10972
11021
  }
10973
- if (env.OTUI_DEBUG_FFI && ffiLogWriter) {
11022
+ if ((env.OTUI_DEBUG_FFI || env.OTUI_TRACE_FFI) && !exitHandlerRegistered) {
11023
+ exitHandlerRegistered = true;
10974
11024
  process.on("exit", () => {
10975
11025
  try {
10976
- ffiLogWriter.end();
11026
+ if (globalFFILogWriter) {
11027
+ globalFFILogWriter.end();
11028
+ }
10977
11029
  } catch (e) {}
10978
- });
10979
- }
10980
- if (hasTracing) {
10981
- process.on("exit", () => {
10982
- const allStats = [];
10983
- for (const [key, timings] of Object.entries(traceSymbols)) {
10984
- if (!Array.isArray(timings) || timings.length === 0) {
10985
- 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
+ });
10986
11059
  }
10987
- const sortedTimings = [...timings].sort((a, b) => a - b);
10988
- const count = sortedTimings.length;
10989
- const total = sortedTimings.reduce((acc, t2) => acc + t2, 0);
10990
- const average = total / count;
10991
- const min = sortedTimings[0];
10992
- const max = sortedTimings[count - 1];
10993
- const medianIndex = Math.floor(count / 2);
10994
- const p90Index = Math.floor(count * 0.9);
10995
- const p99Index = Math.floor(count * 0.99);
10996
- const median = sortedTimings[medianIndex];
10997
- const p90 = sortedTimings[Math.min(p90Index, count - 1)];
10998
- const p99 = sortedTimings[Math.min(p99Index, count - 1)];
10999
- allStats.push({
11000
- name: key,
11001
- count,
11002
- total,
11003
- average,
11004
- min,
11005
- max,
11006
- median,
11007
- p90,
11008
- p99
11009
- });
11010
- }
11011
- allStats.sort((a, b) => b.total - a.total);
11012
- console.log(`
11060
+ allStats.sort((a, b) => b.total - a.total);
11061
+ const lines = [];
11062
+ lines.push(`
11013
11063
  --- OpenTUI FFI Call Performance ---`);
11014
- console.log("Sorted by total time spent (descending)");
11015
- console.log("-------------------------------------------------------------------------------------------------------------------------");
11016
- if (allStats.length === 0) {
11017
- console.log("No trace data collected or all symbols had zero calls.");
11018
- } else {
11019
- const nameHeader = "Symbol";
11020
- const callsHeader = "Calls";
11021
- const totalHeader = "Total (ms)";
11022
- const avgHeader = "Avg (ms)";
11023
- const minHeader = "Min (ms)";
11024
- const maxHeader = "Max (ms)";
11025
- const medHeader = "Med (ms)";
11026
- const p90Header = "P90 (ms)";
11027
- const p99Header = "P99 (ms)";
11028
- const nameWidth = Math.max(nameHeader.length, ...allStats.map((s) => s.name.length));
11029
- const countWidth = Math.max(callsHeader.length, ...allStats.map((s) => String(s.count).length));
11030
- const totalWidth = Math.max(totalHeader.length, ...allStats.map((s) => s.total.toFixed(2).length));
11031
- const avgWidth = Math.max(avgHeader.length, ...allStats.map((s) => s.average.toFixed(2).length));
11032
- const minWidth = Math.max(minHeader.length, ...allStats.map((s) => s.min.toFixed(2).length));
11033
- const maxWidth = Math.max(maxHeader.length, ...allStats.map((s) => s.max.toFixed(2).length));
11034
- const medianWidth = Math.max(medHeader.length, ...allStats.map((s) => s.median.toFixed(2).length));
11035
- const p90Width = Math.max(p90Header.length, ...allStats.map((s) => s.p90.toFixed(2).length));
11036
- const p99Width = Math.max(p99Header.length, ...allStats.map((s) => s.p99.toFixed(2).length));
11037
- 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)}`);
11038
- console.log(`${"-".repeat(nameWidth)}-+-${"-".repeat(countWidth)}-+-${"-".repeat(totalWidth)}-+-${"-".repeat(avgWidth)}-+-${"-".repeat(minWidth)}-+-${"-".repeat(maxWidth)}-+-${"-".repeat(medianWidth)}-+-${"-".repeat(p90Width)}-+-${"-".repeat(p99Width)}`);
11039
- allStats.forEach((stat) => {
11040
- 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)}`);
11041
- });
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
+ }
11042
11105
  }
11043
- console.log("-------------------------------------------------------------------------------------------------------------------------");
11044
11106
  });
11045
11107
  }
11046
11108
  return debugSymbols;
@@ -11982,6 +12044,16 @@ class FFIRenderLib {
11982
12044
  this.opentui.symbols.editorViewGetEOL(view, ptr3(cursorBuffer));
11983
12045
  return VisualCursorStruct.unpack(cursorBuffer);
11984
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
+ }
11985
12057
  bufferPushScissorRect(buffer, x, y, width, height) {
11986
12058
  this.opentui.symbols.bufferPushScissorRect(buffer, x, y, width, height);
11987
12059
  }
@@ -11991,6 +12063,18 @@ class FFIRenderLib {
11991
12063
  bufferClearScissorRects(buffer) {
11992
12064
  this.opentui.symbols.bufferClearScissorRects(buffer);
11993
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
+ }
11994
12078
  getTerminalCapabilities(renderer) {
11995
12079
  const capsBuffer = new ArrayBuffer(TerminalCapabilitiesStruct.size);
11996
12080
  this.opentui.symbols.getTerminalCapabilities(renderer, ptr3(capsBuffer));
@@ -12483,6 +12567,7 @@ class Renderable extends BaseRenderable {
12483
12567
  _positionType = "relative";
12484
12568
  _overflow = "visible";
12485
12569
  _position = {};
12570
+ _opacity = 1;
12486
12571
  _flexShrink = 1;
12487
12572
  renderableMapById = new Map;
12488
12573
  _childrenInLayoutOrder = [];
@@ -12515,6 +12600,7 @@ class Renderable extends BaseRenderable {
12515
12600
  this.buffered = options.buffered ?? false;
12516
12601
  this._live = options.live ?? false;
12517
12602
  this._liveCount = this._live && this._visible ? 1 : 0;
12603
+ this._opacity = options.opacity !== undefined ? Math.max(0, Math.min(1, options.opacity)) : 1;
12518
12604
  this.yogaNode = src_default.Node.create(yogaConfig);
12519
12605
  this.yogaNode.setDisplay(this._visible ? Display.Flex : Display.None);
12520
12606
  this.setupYogaProperties(options);
@@ -12564,6 +12650,16 @@ class Renderable extends BaseRenderable {
12564
12650
  }
12565
12651
  this.requestRender();
12566
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
+ }
12567
12663
  hasSelection() {
12568
12664
  return false;
12569
12665
  }
@@ -12682,7 +12778,7 @@ class Renderable extends BaseRenderable {
12682
12778
  this.parent.childrenPrimarySortDirty = true;
12683
12779
  }
12684
12780
  get x() {
12685
- if (this.parent && this._positionType === "relative") {
12781
+ if (this.parent) {
12686
12782
  return this.parent.x + this._x + this._translateX;
12687
12783
  }
12688
12784
  return this._x + this._translateX;
@@ -12723,7 +12819,7 @@ class Renderable extends BaseRenderable {
12723
12819
  }
12724
12820
  }
12725
12821
  get y() {
12726
- if (this.parent && this._positionType === "relative") {
12822
+ if (this.parent) {
12727
12823
  return this.parent.y + this._y + this._translateY;
12728
12824
  }
12729
12825
  return this._y + this._translateY;
@@ -13308,6 +13404,10 @@ class Renderable extends BaseRenderable {
13308
13404
  }
13309
13405
  if (this._isDestroyed)
13310
13406
  return;
13407
+ const shouldPushOpacity = this._opacity < 1;
13408
+ if (shouldPushOpacity) {
13409
+ renderList.push({ action: "pushOpacity", opacity: this._opacity });
13410
+ }
13311
13411
  renderList.push({ action: "render", renderable: this });
13312
13412
  this.ensureZIndexSorted();
13313
13413
  const shouldPushScissor = this._overflow !== "visible" && this.width > 0 && this.height > 0;
@@ -13332,6 +13432,9 @@ class Renderable extends BaseRenderable {
13332
13432
  if (shouldPushScissor) {
13333
13433
  renderList.push({ action: "popScissorRect" });
13334
13434
  }
13435
+ if (shouldPushOpacity) {
13436
+ renderList.push({ action: "popOpacity" });
13437
+ }
13335
13438
  }
13336
13439
  render(buffer, deltaTime) {
13337
13440
  let renderBuffer = buffer;
@@ -13545,6 +13648,12 @@ class RootRenderable extends Renderable {
13545
13648
  case "popScissorRect":
13546
13649
  buffer.popScissorRect();
13547
13650
  break;
13651
+ case "pushOpacity":
13652
+ buffer.pushOpacity(command.opacity);
13653
+ break;
13654
+ case "popOpacity":
13655
+ buffer.popOpacity();
13656
+ break;
13548
13657
  }
13549
13658
  }
13550
13659
  }
@@ -13788,6 +13897,59 @@ class CapturedWritableStream extends Writable {
13788
13897
  }
13789
13898
  }
13790
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
+
13791
13953
  // src/console.ts
13792
13954
  function getCallerInfo() {
13793
13955
  const err = new Error;
@@ -13927,6 +14089,19 @@ var ConsolePosition;
13927
14089
  ConsolePosition2["LEFT"] = "left";
13928
14090
  ConsolePosition2["RIGHT"] = "right";
13929
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
+ ];
13930
14105
  var DEFAULT_CONSOLE_OPTIONS = {
13931
14106
  position: "bottom" /* BOTTOM */,
13932
14107
  sizePercent: 30,
@@ -13943,7 +14118,12 @@ var DEFAULT_CONSOLE_OPTIONS = {
13943
14118
  titleBarTextColor: "#FFFFFF",
13944
14119
  cursorColor: "#00A0FF",
13945
14120
  maxStoredLogs: 2000,
13946
- 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"
13947
14127
  };
13948
14128
  var INDENT_WIDTH = 2;
13949
14129
 
@@ -13966,10 +14146,34 @@ class TerminalConsole extends EventEmitter8 {
13966
14146
  _allLogEntries = [];
13967
14147
  _needsFrameBufferUpdate = false;
13968
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;
13969
14164
  markNeedsRerender() {
13970
14165
  this._needsFrameBufferUpdate = true;
13971
14166
  this.renderer.requestRender();
13972
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
+ }
13973
14177
  _rgbaInfo;
13974
14178
  _rgbaWarn;
13975
14179
  _rgbaError;
@@ -13980,6 +14184,8 @@ class TerminalConsole extends EventEmitter8 {
13980
14184
  _rgbaTitleBarText;
13981
14185
  _title;
13982
14186
  _rgbaCursor;
14187
+ _rgbaSelection;
14188
+ _rgbaCopyButton;
13983
14189
  _positions = [
13984
14190
  "top" /* TOP */,
13985
14191
  "right" /* RIGHT */,
@@ -14003,6 +14209,13 @@ class TerminalConsole extends EventEmitter8 {
14003
14209
  this._rgbaTitleBarText = parseColor(this.options.titleBarTextColor || this.options.colorDefault);
14004
14210
  this._title = this.options.title;
14005
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();
14006
14219
  this._updateConsoleDimensions();
14007
14220
  this._scrollToBottom(true);
14008
14221
  this._entryListener = (logEntry) => {
@@ -14013,6 +14226,20 @@ class TerminalConsole extends EventEmitter8 {
14013
14226
  this.show();
14014
14227
  }
14015
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
+ }
14016
14243
  activate() {
14017
14244
  terminalConsoleCache.activate();
14018
14245
  }
@@ -14039,8 +14266,8 @@ class TerminalConsole extends EventEmitter8 {
14039
14266
  this.markNeedsRerender();
14040
14267
  }
14041
14268
  _updateConsoleDimensions(termWidth, termHeight) {
14042
- const width = termWidth ?? this.renderer.terminalWidth;
14043
- const height = termHeight ?? this.renderer.terminalHeight;
14269
+ const width = termWidth ?? this.renderer.width;
14270
+ const height = termHeight ?? this.renderer.height;
14044
14271
  const sizePercent = this.options.sizePercent / 100;
14045
14272
  switch (this.options.position) {
14046
14273
  case "top" /* TOP */:
@@ -14071,68 +14298,103 @@ class TerminalConsole extends EventEmitter8 {
14071
14298
  this.currentLineIndex = Math.max(0, Math.min(this.currentLineIndex, this.consoleHeight - 1));
14072
14299
  }
14073
14300
  handleKeyPress(event) {
14074
- let needsRedraw = false;
14075
- const displayLineCount = this._displayLines.length;
14076
- const logAreaHeight = Math.max(1, this.consoleHeight - 1);
14077
- const maxScrollTop = Math.max(0, displayLineCount - logAreaHeight);
14078
- const currentPositionIndex = this._positions.indexOf(this.options.position);
14079
14301
  if (event.name === "escape") {
14080
14302
  this.blur();
14081
14303
  return;
14082
14304
  }
14083
- if (event.name === "up" && event.shift) {
14084
- if (this.scrollTopIndex > 0 || this.currentLineIndex > 0) {
14085
- this.scrollTopIndex = 0;
14086
- this.currentLineIndex = 0;
14087
- this.isScrolledToBottom = this._displayLines.length <= Math.max(1, this.consoleHeight - 1);
14088
- needsRedraw = true;
14089
- }
14090
- } else if (event.name === "down" && event.shift) {
14091
- const logAreaHeightForScroll = Math.max(1, this.consoleHeight - 1);
14092
- const maxScrollPossible = Math.max(0, this._displayLines.length - logAreaHeightForScroll);
14093
- if (this.scrollTopIndex < maxScrollPossible || !this.isScrolledToBottom) {
14094
- this._scrollToBottom(true);
14095
- needsRedraw = true;
14096
- }
14097
- } else if (event.name === "up") {
14098
- if (this.currentLineIndex > 0) {
14099
- this.currentLineIndex--;
14100
- needsRedraw = true;
14101
- } else if (this.scrollTopIndex > 0) {
14102
- this.scrollTopIndex--;
14103
- this.isScrolledToBottom = false;
14104
- needsRedraw = true;
14105
- }
14106
- } else if (event.name === "down") {
14107
- const canCursorMoveDown = this.currentLineIndex < logAreaHeight - 1 && this.scrollTopIndex + this.currentLineIndex < displayLineCount - 1;
14108
- if (canCursorMoveDown) {
14109
- this.currentLineIndex++;
14110
- needsRedraw = true;
14111
- } else if (this.scrollTopIndex < maxScrollTop) {
14112
- this.scrollTopIndex++;
14113
- this.isScrolledToBottom = this.scrollTopIndex === maxScrollTop;
14114
- needsRedraw = true;
14115
- }
14116
- } else if (event.name === "p" && event.ctrl) {
14117
- const prevIndex = (currentPositionIndex - 1 + this._positions.length) % this._positions.length;
14118
- this.options.position = this._positions[prevIndex];
14119
- this.resize(this.renderer.terminalWidth, this.renderer.terminalHeight);
14120
- } else if (event.name === "o" && event.ctrl) {
14121
- const nextIndex = (currentPositionIndex + 1) % this._positions.length;
14122
- this.options.position = this._positions[nextIndex];
14123
- this.resize(this.renderer.terminalWidth, this.renderer.terminalHeight);
14124
- } else if (event.name === "+" || event.name === "=" && event.shift) {
14125
- this.options.sizePercent = Math.min(100, this.options.sizePercent + 5);
14126
- this.resize(this.renderer.terminalWidth, this.renderer.terminalHeight);
14127
- } else if (event.name === "-") {
14128
- this.options.sizePercent = Math.max(10, this.options.sizePercent - 5);
14129
- this.resize(this.renderer.terminalWidth, this.renderer.terminalHeight);
14130
- } else if (event.name === "s" && event.ctrl) {
14131
- this.saveLogsToFile();
14132
- }
14133
- 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;
14134
14330
  this.markNeedsRerender();
14135
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;
14136
14398
  }
14137
14399
  attachStdin() {
14138
14400
  if (this.isFocused)
@@ -14249,6 +14511,7 @@ class TerminalConsole extends EventEmitter8 {
14249
14511
  }
14250
14512
  }
14251
14513
  destroy() {
14514
+ this.stopAutoScroll();
14252
14515
  this.hide();
14253
14516
  this.deactivate();
14254
14517
  terminalConsoleCache.off("entry", this._entryListener);
@@ -14268,13 +14531,26 @@ class TerminalConsole extends EventEmitter8 {
14268
14531
  const dynamicTitle = `${this._title}${this.isFocused ? " (Focused)" : ""}`;
14269
14532
  const titleX = Math.max(0, Math.floor((this.consoleWidth - dynamicTitle.length) / 2));
14270
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
+ }
14271
14545
  const startIndex = this.scrollTopIndex;
14272
14546
  const endIndex = Math.min(startIndex + logAreaHeight, displayLineCount);
14273
14547
  const visibleDisplayLines = displayLines.slice(startIndex, endIndex);
14274
14548
  let lineY = 1;
14275
- for (const displayLine of visibleDisplayLines) {
14549
+ for (let i = 0;i < visibleDisplayLines.length; i++) {
14276
14550
  if (lineY >= this.consoleHeight)
14277
14551
  break;
14552
+ const displayLine = visibleDisplayLines[i];
14553
+ const absoluteLineIndex = startIndex + i;
14278
14554
  let levelColor = this._rgbaDefault;
14279
14555
  switch (displayLine.level) {
14280
14556
  case "INFO" /* INFO */:
@@ -14299,7 +14575,24 @@ class TerminalConsole extends EventEmitter8 {
14299
14575
  } else {
14300
14576
  this.frameBuffer.drawText(" ", 0, lineY, this._rgbaDefault, this.backgroundColor);
14301
14577
  }
14302
- 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
+ }
14303
14596
  lineY++;
14304
14597
  }
14305
14598
  }
@@ -14322,6 +14615,24 @@ class TerminalConsole extends EventEmitter8 {
14322
14615
  toggleDebugMode() {
14323
14616
  this.setDebugMode(!this._debugModeEnabled);
14324
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
+ }
14325
14636
  _scrollToBottom(forceCursorToLastLine = false) {
14326
14637
  const displayLineCount = this._displayLines.length;
14327
14638
  const logAreaHeight = Math.max(1, this.consoleHeight - 1);
@@ -14379,6 +14690,214 @@ class TerminalConsole extends EventEmitter8 {
14379
14690
  this._displayLines.splice(0, this._displayLines.length - this.options.maxDisplayLines);
14380
14691
  }
14381
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
+ }
14382
14901
  saveLogsToFile() {
14383
14902
  try {
14384
14903
  const timestamp = Date.now();
@@ -14759,6 +15278,7 @@ class CliRenderer extends EventEmitter9 {
14759
15278
  _stdinBuffer;
14760
15279
  animationRequest = new Map;
14761
15280
  resizeTimeoutId = null;
15281
+ capabilityTimeoutId = null;
14762
15282
  resizeDebounceDelay = 100;
14763
15283
  enableMouseMovement = false;
14764
15284
  _useMouse = true;
@@ -15201,7 +15721,8 @@ Captured output:
15201
15721
  this._terminalIsSetup = true;
15202
15722
  this.lib.setupTerminal(this.rendererPtr, this._useAlternateScreen);
15203
15723
  this._capabilities = this.lib.getTerminalCapabilities(this.rendererPtr);
15204
- setTimeout(() => {
15724
+ this.capabilityTimeoutId = setTimeout(() => {
15725
+ this.capabilityTimeoutId = null;
15205
15726
  this.removeInputHandler(this.capabilityHandler);
15206
15727
  }, 5000);
15207
15728
  if (this._useMouse) {
@@ -15298,6 +15819,15 @@ Captured output:
15298
15819
  }
15299
15820
  this._latestPointer.x = mouseEvent.x;
15300
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
+ }
15301
15831
  if (mouseEvent.type === "scroll") {
15302
15832
  const maybeRenderableId2 = this.lib.checkHit(this.rendererPtr, mouseEvent.x, mouseEvent.y);
15303
15833
  const maybeRenderable2 = Renderable.renderablesByNumber.get(maybeRenderableId2);
@@ -15669,7 +16199,17 @@ Captured output:
15669
16199
  process.removeListener("uncaughtException", this.handleError);
15670
16200
  process.removeListener("unhandledRejection", this.handleError);
15671
16201
  process.removeListener("warning", this.warningHandler);
16202
+ process.removeListener("beforeExit", this.exitHandler);
15672
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
+ }
15673
16213
  if (this.memorySnapshotTimer) {
15674
16214
  clearInterval(this.memorySnapshotTimer);
15675
16215
  }
@@ -15982,7 +16522,7 @@ Captured output:
15982
16522
  }
15983
16523
  }
15984
16524
 
15985
- 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, buildKittyKeyboardFlags, 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 };
15986
16526
 
15987
- //# debugId=DF99D6EBE6E4045C64756E2164756E21
15988
- //# sourceMappingURL=index-916mvx7m.js.map
16527
+ //# debugId=0788E633A0C8647564756E2164756E21
16528
+ //# sourceMappingURL=index-rysm4rsr.js.map