@opentui/core 0.1.101 → 0.1.103

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.
@@ -1969,23 +1969,126 @@ class InternalKeyHandler extends KeyHandler {
1969
1969
  }
1970
1970
 
1971
1971
  // src/lib/RGBA.ts
1972
+ var COLOR_TAG_RGB = 256;
1973
+ var COLOR_TAG_DEFAULT = 257;
1974
+ var DEFAULT_FOREGROUND_RGB = [255, 255, 255];
1975
+ var DEFAULT_BACKGROUND_RGB = [0, 0, 0];
1976
+ var RGBA_BUFFER_STRIDE = 5;
1977
+ var ANSI16_RGB = [
1978
+ [0, 0, 0],
1979
+ [128, 0, 0],
1980
+ [0, 128, 0],
1981
+ [128, 128, 0],
1982
+ [0, 0, 128],
1983
+ [128, 0, 128],
1984
+ [0, 128, 128],
1985
+ [192, 192, 192],
1986
+ [128, 128, 128],
1987
+ [255, 0, 0],
1988
+ [0, 255, 0],
1989
+ [255, 255, 0],
1990
+ [0, 0, 255],
1991
+ [255, 0, 255],
1992
+ [0, 255, 255],
1993
+ [255, 255, 255]
1994
+ ];
1995
+ var ANSI_256_CUBE_LEVELS = [0, 95, 135, 175, 215, 255];
1996
+ function normalizeColorTag(tag) {
1997
+ const normalizedTag = tag != null && Number.isFinite(tag) ? Math.round(tag) : COLOR_TAG_RGB;
1998
+ if (normalizedTag === COLOR_TAG_RGB || normalizedTag === COLOR_TAG_DEFAULT) {
1999
+ return normalizedTag;
2000
+ }
2001
+ if (Number.isInteger(normalizedTag) && normalizedTag >= 0 && normalizedTag <= 255) {
2002
+ return normalizedTag;
2003
+ }
2004
+ return COLOR_TAG_RGB;
2005
+ }
2006
+ function normalizeRGBABuffer(buffer) {
2007
+ if (buffer.length === RGBA_BUFFER_STRIDE) {
2008
+ buffer[4] = normalizeColorTag(buffer[4]);
2009
+ return buffer;
2010
+ }
2011
+ const normalized = new Float32Array(RGBA_BUFFER_STRIDE);
2012
+ normalized[0] = buffer[0] ?? 0;
2013
+ normalized[1] = buffer[1] ?? 0;
2014
+ normalized[2] = buffer[2] ?? 0;
2015
+ normalized[3] = buffer[3] ?? 0;
2016
+ normalized[4] = COLOR_TAG_RGB;
2017
+ return normalized;
2018
+ }
2019
+ function withTag(rgba, tag) {
2020
+ const tagged = RGBA.clone(rgba);
2021
+ tagged.tag = tag;
2022
+ return tagged;
2023
+ }
2024
+ function rgbaForAnsi256Index(index) {
2025
+ const [r, g, b] = ansi256IndexToRgb(index);
2026
+ return RGBA.fromInts(r, g, b);
2027
+ }
2028
+ function normalizeIndexedColorIndex(index) {
2029
+ if (!Number.isInteger(index) || index < 0 || index > 255) {
2030
+ throw new RangeError(`Indexed color must be an integer in the range 0..255, got ${index}`);
2031
+ }
2032
+ return index;
2033
+ }
2034
+ function ansi256IndexToRgb(index) {
2035
+ const normalizedIndex = normalizeIndexedColorIndex(index);
2036
+ if (normalizedIndex < ANSI16_RGB.length) {
2037
+ return ANSI16_RGB[normalizedIndex];
2038
+ }
2039
+ if (normalizedIndex < 232) {
2040
+ const cubeIndex = normalizedIndex - 16;
2041
+ const r = Math.floor(cubeIndex / 36);
2042
+ const g = Math.floor(cubeIndex / 6) % 6;
2043
+ const b = cubeIndex % 6;
2044
+ return [ANSI_256_CUBE_LEVELS[r], ANSI_256_CUBE_LEVELS[g], ANSI_256_CUBE_LEVELS[b]];
2045
+ }
2046
+ const value = 8 + (normalizedIndex - 232) * 10;
2047
+ return [value, value, value];
2048
+ }
2049
+ function decodeColorTag(tag) {
2050
+ if (tag === COLOR_TAG_DEFAULT) {
2051
+ return { kind: "default" };
2052
+ }
2053
+ if (tag === COLOR_TAG_RGB) {
2054
+ return { kind: "rgb" };
2055
+ }
2056
+ return { kind: "indexed", index: normalizeIndexedColorIndex(tag) };
2057
+ }
2058
+
1972
2059
  class RGBA {
1973
2060
  buffer;
1974
2061
  constructor(buffer) {
1975
- this.buffer = buffer;
2062
+ this.buffer = normalizeRGBABuffer(buffer);
1976
2063
  }
1977
2064
  static fromArray(array) {
1978
2065
  return new RGBA(array);
1979
2066
  }
1980
- static fromValues(r, g, b, a = 1) {
1981
- return new RGBA(new Float32Array([r, g, b, a]));
2067
+ static fromValues(r, g, b, a = 1, tag = COLOR_TAG_RGB) {
2068
+ return new RGBA(new Float32Array([r, g, b, a, normalizeColorTag(tag)]));
1982
2069
  }
1983
- static fromInts(r, g, b, a = 255) {
1984
- return new RGBA(new Float32Array([r / 255, g / 255, b / 255, a / 255]));
2070
+ static clone(rgba) {
2071
+ return RGBA.fromValues(rgba.r, rgba.g, rgba.b, rgba.a, rgba.tag);
2072
+ }
2073
+ static fromInts(r, g, b, a = 255, tag = COLOR_TAG_RGB) {
2074
+ return new RGBA(new Float32Array([r / 255, g / 255, b / 255, a / 255, normalizeColorTag(tag)]));
1985
2075
  }
1986
2076
  static fromHex(hex) {
1987
2077
  return hexToRgb(hex);
1988
2078
  }
2079
+ static fromIndex(index, snapshot) {
2080
+ const normalizedIndex = normalizeIndexedColorIndex(index);
2081
+ return withTag(snapshot ? parseColor(snapshot) : rgbaForAnsi256Index(normalizedIndex), normalizedIndex);
2082
+ }
2083
+ static defaultForeground(snapshot) {
2084
+ return withTag(snapshot ? parseColor(snapshot) : RGBA.fromInts(...DEFAULT_FOREGROUND_RGB), COLOR_TAG_DEFAULT);
2085
+ }
2086
+ static defaultBackground(snapshot) {
2087
+ return withTag(snapshot ? parseColor(snapshot) : RGBA.fromInts(...DEFAULT_BACKGROUND_RGB), COLOR_TAG_DEFAULT);
2088
+ }
2089
+ static getIntentTag(rgba) {
2090
+ return rgba.tag;
2091
+ }
1989
2092
  toInts() {
1990
2093
  return [Math.round(this.r * 255), Math.round(this.g * 255), Math.round(this.b * 255), Math.round(this.a * 255)];
1991
2094
  }
@@ -2013,6 +2116,12 @@ class RGBA {
2013
2116
  set a(value) {
2014
2117
  this.buffer[3] = value;
2015
2118
  }
2119
+ get tag() {
2120
+ return normalizeColorTag(this.buffer[4]);
2121
+ }
2122
+ set tag(value) {
2123
+ this.buffer[4] = normalizeColorTag(value);
2124
+ }
2016
2125
  map(fn) {
2017
2126
  return [fn(this.r), fn(this.g), fn(this.b), fn(this.a)];
2018
2127
  }
@@ -2022,9 +2131,15 @@ class RGBA {
2022
2131
  equals(other) {
2023
2132
  if (!other)
2024
2133
  return false;
2025
- return this.r === other.r && this.g === other.g && this.b === other.b && this.a === other.a;
2134
+ return this.r === other.r && this.g === other.g && this.b === other.b && this.a === other.a && this.tag === other.tag;
2026
2135
  }
2027
2136
  }
2137
+ function normalizeColorValue(value) {
2138
+ if (value == null)
2139
+ return null;
2140
+ const rgba = parseColor(value);
2141
+ return { rgba, tag: rgba.tag };
2142
+ }
2028
2143
  function hexToRgb(hex) {
2029
2144
  hex = hex.replace(/^#/, "");
2030
2145
  if (hex.length === 3) {
@@ -6867,7 +6982,8 @@ var DEFAULT_PROTOCOL_CONTEXT = {
6867
6982
  kittyKeyboardEnabled: false,
6868
6983
  privateCapabilityRepliesActive: false,
6869
6984
  pixelResolutionQueryActive: false,
6870
- explicitWidthCprActive: false
6985
+ explicitWidthCprActive: false,
6986
+ startupCursorCprActive: false
6871
6987
  };
6872
6988
  var RXVT_DOLLAR_CSI_RE = /^\x1b\[\d+\$$/;
6873
6989
  var SYSTEM_CLOCK = new SystemClock;
@@ -7056,11 +7172,14 @@ function canStillBeKittySpecial(state) {
7056
7172
  function canStillBeExplicitWidthCpr(state) {
7057
7173
  return state.firstParamValue === 1 && state.semicolons === 1;
7058
7174
  }
7175
+ function canStillBeStartupCursorCpr(state) {
7176
+ return state.semicolons === 1;
7177
+ }
7059
7178
  function canStillBePixelResolution(state) {
7060
7179
  return state.firstParamValue === 4 && state.semicolons === 2;
7061
7180
  }
7062
7181
  function canDeferParametricCsi(state, context) {
7063
- return context.kittyKeyboardEnabled && (canStillBeKittyU(state) || canStillBeKittySpecial(state)) || context.explicitWidthCprActive && canStillBeExplicitWidthCpr(state) || context.pixelResolutionQueryActive && canStillBePixelResolution(state);
7182
+ return context.kittyKeyboardEnabled && (canStillBeKittyU(state) || canStillBeKittySpecial(state)) || context.explicitWidthCprActive && canStillBeExplicitWidthCpr(state) || context.startupCursorCprActive && canStillBeStartupCursorCpr(state) || context.pixelResolutionQueryActive && canStillBePixelResolution(state);
7064
7183
  }
7065
7184
  function canCompleteDeferredParametricCsi(state, byte, context) {
7066
7185
  if (context.kittyKeyboardEnabled) {
@@ -7073,11 +7192,20 @@ function canCompleteDeferredParametricCsi(state, byte, context) {
7073
7192
  if (context.explicitWidthCprActive && state.hasDigit && state.firstParamValue === 1 && state.semicolons === 1 && byte === 82) {
7074
7193
  return true;
7075
7194
  }
7195
+ if (context.startupCursorCprActive && state.hasDigit && state.semicolons === 1 && byte === 82) {
7196
+ return true;
7197
+ }
7076
7198
  if (context.pixelResolutionQueryActive && state.hasDigit && state.firstParamValue === 4 && state.semicolons === 2 && byte === 116) {
7077
7199
  return true;
7078
7200
  }
7079
7201
  return false;
7080
7202
  }
7203
+ function classifyParametricCsiProtocol(state, finalByte) {
7204
+ if (finalByte === 82 && state.semicolons === 1 && state.segments === 1 && state.hasDigit) {
7205
+ return "cpr";
7206
+ }
7207
+ return "csi";
7208
+ }
7081
7209
  function canDeferPrivateReplyCsi(context) {
7082
7210
  return context.privateCapabilityRepliesActive;
7083
7211
  }
@@ -7184,7 +7312,8 @@ class StdinParser {
7184
7312
  kittyKeyboardEnabled: options.protocolContext?.kittyKeyboardEnabled ?? false,
7185
7313
  privateCapabilityRepliesActive: options.protocolContext?.privateCapabilityRepliesActive ?? false,
7186
7314
  pixelResolutionQueryActive: options.protocolContext?.pixelResolutionQueryActive ?? false,
7187
- explicitWidthCprActive: options.protocolContext?.explicitWidthCprActive ?? false
7315
+ explicitWidthCprActive: options.protocolContext?.explicitWidthCprActive ?? false,
7316
+ startupCursorCprActive: options.protocolContext?.startupCursorCprActive ?? false
7188
7317
  };
7189
7318
  }
7190
7319
  get bufferCapacity() {
@@ -7686,7 +7815,8 @@ class StdinParser {
7686
7815
  }
7687
7816
  if (byte >= 64 && byte <= 126) {
7688
7817
  const end = this.cursor + 1;
7689
- this.emitKeyOrResponse("csi", decodeUtf8(bytes.subarray(this.unitStart, end)));
7818
+ const protocol = classifyParametricCsiProtocol(this.state, byte);
7819
+ this.emitKeyOrResponse(protocol, decodeUtf8(bytes.subarray(this.unitStart, end)));
7690
7820
  this.state = { tag: "ground" };
7691
7821
  this.consumePrefix(end);
7692
7822
  continue;
@@ -10648,6 +10778,38 @@ class TerminalPalette {
10648
10778
  function createTerminalPalette(stdin, stdout, writeFn, isLegacyTmux, oscSource, clock) {
10649
10779
  return new TerminalPalette(stdin, stdout, writeFn, isLegacyTmux, oscSource, clock);
10650
10780
  }
10781
+ var DEFAULT_FOREGROUND_FALLBACK = RGBA.fromInts(...DEFAULT_FOREGROUND_RGB);
10782
+ var DEFAULT_BACKGROUND_FALLBACK = RGBA.fromInts(...DEFAULT_BACKGROUND_RGB);
10783
+ var fallbackAnsi256Palette = null;
10784
+ function getFallbackAnsi256Palette() {
10785
+ if (!fallbackAnsi256Palette) {
10786
+ fallbackAnsi256Palette = Array.from({ length: 256 }, (_, index) => {
10787
+ const [r, g, b] = ansi256IndexToRgb(index);
10788
+ return RGBA.fromInts(r, g, b);
10789
+ });
10790
+ }
10791
+ return fallbackAnsi256Palette;
10792
+ }
10793
+ function normalizeTerminalPalette(colors) {
10794
+ const fallbackPalette = getFallbackAnsi256Palette();
10795
+ return {
10796
+ palette: Array.from({ length: 256 }, (_, index) => {
10797
+ const detected = colors?.palette[index];
10798
+ return detected ? RGBA.fromHex(detected) : RGBA.clone(fallbackPalette[index]);
10799
+ }),
10800
+ defaultForeground: colors?.defaultForeground ? RGBA.fromHex(colors.defaultForeground) : RGBA.clone(DEFAULT_FOREGROUND_FALLBACK),
10801
+ defaultBackground: colors?.defaultBackground ? RGBA.fromHex(colors.defaultBackground) : RGBA.clone(DEFAULT_BACKGROUND_FALLBACK)
10802
+ };
10803
+ }
10804
+ function buildTerminalPaletteSignature(colors) {
10805
+ const normalized = normalizeTerminalPalette(colors);
10806
+ const paletteSignature = normalized.palette.map((color) => color.toInts().join(",")).join(";");
10807
+ return [
10808
+ paletteSignature,
10809
+ normalized.defaultForeground.toInts().join(","),
10810
+ normalized.defaultBackground.toInts().join(",")
10811
+ ].join("|");
10812
+ }
10651
10813
 
10652
10814
  // src/lib/paste.ts
10653
10815
  var PASTE_TEXT_DECODER = new TextDecoder;
@@ -10745,6 +10907,7 @@ class OptimizedBuffer {
10745
10907
  _widthMethod;
10746
10908
  respectAlpha = false;
10747
10909
  _rawBuffers = null;
10910
+ _rawColorTags = null;
10748
10911
  _destroyed = false;
10749
10912
  get ptr() {
10750
10913
  return this.bufferPtr;
@@ -10753,23 +10916,38 @@ class OptimizedBuffer {
10753
10916
  if (this._destroyed)
10754
10917
  throw new Error(`Buffer ${this.id} is destroyed`);
10755
10918
  }
10919
+ ensureRawBufferViews() {
10920
+ if (this._rawBuffers !== null && this._rawColorTags !== null) {
10921
+ return;
10922
+ }
10923
+ const size = this._width * this._height;
10924
+ const charPtr = this.lib.bufferGetCharPtr(this.bufferPtr);
10925
+ const fgPtr = this.lib.bufferGetFgPtr(this.bufferPtr);
10926
+ const bgPtr = this.lib.bufferGetBgPtr(this.bufferPtr);
10927
+ const fgTagPtr = this.lib.bufferGetFgTagPtr(this.bufferPtr);
10928
+ const bgTagPtr = this.lib.bufferGetBgTagPtr(this.bufferPtr);
10929
+ const attributesPtr = this.lib.bufferGetAttributesPtr(this.bufferPtr);
10930
+ this._rawBuffers = {
10931
+ char: new Uint32Array(toArrayBuffer(charPtr, 0, size * 4)),
10932
+ fg: new Float32Array(toArrayBuffer(fgPtr, 0, size * 4 * 4)),
10933
+ bg: new Float32Array(toArrayBuffer(bgPtr, 0, size * 4 * 4)),
10934
+ attributes: new Uint32Array(toArrayBuffer(attributesPtr, 0, size * 4))
10935
+ };
10936
+ this._rawColorTags = {
10937
+ fg: new Uint16Array(toArrayBuffer(fgTagPtr, 0, size * 2)),
10938
+ bg: new Uint16Array(toArrayBuffer(bgTagPtr, 0, size * 2))
10939
+ };
10940
+ }
10756
10941
  get buffers() {
10757
10942
  this.guard();
10758
- if (this._rawBuffers === null) {
10759
- const size = this._width * this._height;
10760
- const charPtr = this.lib.bufferGetCharPtr(this.bufferPtr);
10761
- const fgPtr = this.lib.bufferGetFgPtr(this.bufferPtr);
10762
- const bgPtr = this.lib.bufferGetBgPtr(this.bufferPtr);
10763
- const attributesPtr = this.lib.bufferGetAttributesPtr(this.bufferPtr);
10764
- this._rawBuffers = {
10765
- char: new Uint32Array(toArrayBuffer(charPtr, 0, size * 4)),
10766
- fg: new Float32Array(toArrayBuffer(fgPtr, 0, size * 4 * 4)),
10767
- bg: new Float32Array(toArrayBuffer(bgPtr, 0, size * 4 * 4)),
10768
- attributes: new Uint32Array(toArrayBuffer(attributesPtr, 0, size * 4))
10769
- };
10770
- }
10943
+ this.ensureRawBufferViews();
10771
10944
  return this._rawBuffers;
10772
10945
  }
10946
+ get rawColorTags() {
10947
+ this.guard();
10948
+ this.ensureRawBufferViews();
10949
+ return this._rawColorTags;
10950
+ }
10773
10951
  constructor(lib, ptr2, width, height, options) {
10774
10952
  this.id = options.id || `fb_${OptimizedBuffer.fbIdCounter++}`;
10775
10953
  this.lib = lib;
@@ -10814,6 +10992,7 @@ class OptimizedBuffer {
10814
10992
  getSpanLines() {
10815
10993
  this.guard();
10816
10994
  const { char, fg: fg2, bg: bg2, attributes } = this.buffers;
10995
+ const { fg: fgTag, bg: bgTag } = this.rawColorTags;
10817
10996
  const lines = [];
10818
10997
  const CHAR_FLAG_CONTINUATION = 3221225472 | 0;
10819
10998
  const CHAR_FLAG_MASK = 3221225472 | 0;
@@ -10828,8 +11007,8 @@ class OptimizedBuffer {
10828
11007
  for (let x = 0;x < this._width; x++) {
10829
11008
  const i = y * this._width + x;
10830
11009
  const cp = char[i];
10831
- const cellFg = RGBA.fromValues(fg2[i * 4], fg2[i * 4 + 1], fg2[i * 4 + 2], fg2[i * 4 + 3]);
10832
- const cellBg = RGBA.fromValues(bg2[i * 4], bg2[i * 4 + 1], bg2[i * 4 + 2], bg2[i * 4 + 3]);
11010
+ const cellFg = RGBA.fromValues(fg2[i * 4], fg2[i * 4 + 1], fg2[i * 4 + 2], fg2[i * 4 + 3], fgTag[i]);
11011
+ const cellBg = RGBA.fromValues(bg2[i * 4], bg2[i * 4 + 1], bg2[i * 4 + 2], bg2[i * 4 + 3], bgTag[i]);
10833
11012
  const cellAttrs = attributes[i] & 255;
10834
11013
  const isContinuation = (cp & CHAR_FLAG_MASK) === CHAR_FLAG_CONTINUATION;
10835
11014
  const cellChar = isContinuation ? "" : lineChars[charIdx++] ?? " ";
@@ -10957,6 +11136,7 @@ class OptimizedBuffer {
10957
11136
  this._width = width;
10958
11137
  this._height = height;
10959
11138
  this._rawBuffers = null;
11139
+ this._rawColorTags = null;
10960
11140
  this.lib.bufferResize(this.bufferPtr, width, height);
10961
11141
  }
10962
11142
  drawBox(options) {
@@ -11650,16 +11830,30 @@ var StyledChunkStruct = defineStruct([
11650
11830
  unpackTransform: rgbaUnpackTransform
11651
11831
  }
11652
11832
  ],
11833
+ ["fg_tag", "u16", { default: COLOR_TAG_RGB }],
11834
+ ["bg_tag", "u16", { default: COLOR_TAG_RGB }],
11653
11835
  ["attributes", "u32", { default: 0 }],
11654
11836
  ["link", "char*", { default: "" }],
11655
11837
  ["link_len", "u64", { lengthOf: "link" }]
11656
11838
  ], {
11657
11839
  mapValue: (chunk) => {
11840
+ const normalizedFg = normalizeColorValue(chunk.fg ?? null);
11841
+ const normalizedBg = normalizeColorValue(chunk.bg ?? null);
11658
11842
  if (!chunk.link || typeof chunk.link === "string") {
11659
- return chunk;
11843
+ return {
11844
+ ...chunk,
11845
+ fg: normalizedFg?.rgba ?? null,
11846
+ bg: normalizedBg?.rgba ?? null,
11847
+ fg_tag: normalizedFg?.tag ?? COLOR_TAG_RGB,
11848
+ bg_tag: normalizedBg?.tag ?? COLOR_TAG_RGB
11849
+ };
11660
11850
  }
11661
11851
  return {
11662
11852
  ...chunk,
11853
+ fg: normalizedFg?.rgba ?? null,
11854
+ bg: normalizedBg?.rgba ?? null,
11855
+ fg_tag: normalizedFg?.tag ?? COLOR_TAG_RGB,
11856
+ bg_tag: normalizedBg?.tag ?? COLOR_TAG_RGB,
11663
11857
  link: chunk.link.url
11664
11858
  };
11665
11859
  }
@@ -11688,6 +11882,7 @@ var TerminalCapabilitiesStruct = defineStruct([
11688
11882
  ["kitty_keyboard", "bool_u8"],
11689
11883
  ["kitty_graphics", "bool_u8"],
11690
11884
  ["rgb", "bool_u8"],
11885
+ ["ansi256", "bool_u8"],
11691
11886
  ["unicode", UnicodeMethodEnum],
11692
11887
  ["sgr_pixels", "bool_u8"],
11693
11888
  ["color_scheme_updates", "bool_u8"],
@@ -11895,6 +12090,10 @@ function getOpenTUILib(libPath) {
11895
12090
  args: ["ptr", "bool"],
11896
12091
  returns: "void"
11897
12092
  },
12093
+ setClearOnShutdown: {
12094
+ args: ["ptr", "bool"],
12095
+ returns: "void"
12096
+ },
11898
12097
  setBackgroundColor: {
11899
12098
  args: ["ptr", "ptr"],
11900
12099
  returns: "void"
@@ -11903,6 +12102,22 @@ function getOpenTUILib(libPath) {
11903
12102
  args: ["ptr", "u32"],
11904
12103
  returns: "void"
11905
12104
  },
12105
+ resetSplitScrollback: {
12106
+ args: ["ptr", "u32", "u32"],
12107
+ returns: "u32"
12108
+ },
12109
+ syncSplitScrollback: {
12110
+ args: ["ptr", "u32"],
12111
+ returns: "u32"
12112
+ },
12113
+ setPendingSplitFooterTransition: {
12114
+ args: ["ptr", "u8", "u32", "u32", "u32", "u32"],
12115
+ returns: "void"
12116
+ },
12117
+ clearPendingSplitFooterTransition: {
12118
+ args: ["ptr"],
12119
+ returns: "void"
12120
+ },
11906
12121
  updateStats: {
11907
12122
  args: ["ptr", "f64", "u32", "f64"],
11908
12123
  returns: "void"
@@ -11915,6 +12130,14 @@ function getOpenTUILib(libPath) {
11915
12130
  args: ["ptr", "bool"],
11916
12131
  returns: "void"
11917
12132
  },
12133
+ repaintSplitFooter: {
12134
+ args: ["ptr", "u32", "bool"],
12135
+ returns: "u32"
12136
+ },
12137
+ commitSplitFooterSnapshot: {
12138
+ args: ["ptr", "ptr", "u32", "bool", "bool", "u32", "bool", "bool", "bool"],
12139
+ returns: "u32"
12140
+ },
11918
12141
  getNextBuffer: {
11919
12142
  args: ["ptr"],
11920
12143
  returns: "ptr"
@@ -11923,10 +12146,18 @@ function getOpenTUILib(libPath) {
11923
12146
  args: ["ptr"],
11924
12147
  returns: "ptr"
11925
12148
  },
12149
+ rendererSetPaletteState: {
12150
+ args: ["ptr", "ptr", "usize", "ptr", "ptr", "u32"],
12151
+ returns: "void"
12152
+ },
11926
12153
  queryPixelResolution: {
11927
12154
  args: ["ptr"],
11928
12155
  returns: "void"
11929
12156
  },
12157
+ queryThemeColors: {
12158
+ args: ["ptr"],
12159
+ returns: "void"
12160
+ },
11930
12161
  createOptimizedBuffer: {
11931
12162
  args: ["u32", "u32", "bool", "u8", "ptr", "usize"],
11932
12163
  returns: "ptr"
@@ -11963,6 +12194,14 @@ function getOpenTUILib(libPath) {
11963
12194
  args: ["ptr"],
11964
12195
  returns: "ptr"
11965
12196
  },
12197
+ bufferGetFgTagPtr: {
12198
+ args: ["ptr"],
12199
+ returns: "ptr"
12200
+ },
12201
+ bufferGetBgTagPtr: {
12202
+ args: ["ptr"],
12203
+ returns: "ptr"
12204
+ },
11966
12205
  bufferGetAttributesPtr: {
11967
12206
  args: ["ptr"],
11968
12207
  returns: "ptr"
@@ -12387,6 +12626,10 @@ function getOpenTUILib(libPath) {
12387
12626
  args: ["ptr", "u8"],
12388
12627
  returns: "void"
12389
12628
  },
12629
+ textBufferViewSetFirstLineOffset: {
12630
+ args: ["ptr", "u32"],
12631
+ returns: "void"
12632
+ },
12390
12633
  textBufferViewSetViewportSize: {
12391
12634
  args: ["ptr", "u32", "u32"],
12392
12635
  returns: "void"
@@ -12760,7 +13003,7 @@ function getOpenTUILib(libPath) {
12760
13003
  returns: "void"
12761
13004
  },
12762
13005
  syntaxStyleRegister: {
12763
- args: ["ptr", "ptr", "usize", "ptr", "ptr", "u8"],
13006
+ args: ["ptr", "ptr", "usize", "ptr", "ptr", "u32"],
12764
13007
  returns: "u32"
12765
13008
  },
12766
13009
  syntaxStyleResolveByName: {
@@ -13124,12 +13367,27 @@ class FFIRenderLib {
13124
13367
  setUseThread(renderer, useThread) {
13125
13368
  this.opentui.symbols.setUseThread(renderer, useThread);
13126
13369
  }
13370
+ setClearOnShutdown(renderer, clear) {
13371
+ this.opentui.symbols.setClearOnShutdown(renderer, clear);
13372
+ }
13127
13373
  setBackgroundColor(renderer, color) {
13128
13374
  this.opentui.symbols.setBackgroundColor(renderer, color.buffer);
13129
13375
  }
13130
13376
  setRenderOffset(renderer, offset) {
13131
13377
  this.opentui.symbols.setRenderOffset(renderer, offset);
13132
13378
  }
13379
+ resetSplitScrollback(renderer, seedRows, pinnedRenderOffset) {
13380
+ return this.opentui.symbols.resetSplitScrollback(renderer, seedRows, pinnedRenderOffset);
13381
+ }
13382
+ syncSplitScrollback(renderer, pinnedRenderOffset) {
13383
+ return this.opentui.symbols.syncSplitScrollback(renderer, pinnedRenderOffset);
13384
+ }
13385
+ setPendingSplitFooterTransition(renderer, mode, sourceTopLine, sourceHeight, targetTopLine, targetHeight) {
13386
+ this.opentui.symbols.setPendingSplitFooterTransition(renderer, mode, sourceTopLine, sourceHeight, targetTopLine, targetHeight);
13387
+ }
13388
+ clearPendingSplitFooterTransition(renderer) {
13389
+ this.opentui.symbols.clearPendingSplitFooterTransition(renderer);
13390
+ }
13133
13391
  updateStats(renderer, time, fps, frameCallbackTime) {
13134
13392
  this.opentui.symbols.updateStats(renderer, time, fps, frameCallbackTime);
13135
13393
  }
@@ -13154,6 +13412,18 @@ class FFIRenderLib {
13154
13412
  const height = this.opentui.symbols.getBufferHeight(bufferPtr);
13155
13413
  return new OptimizedBuffer(this, bufferPtr, width, height, { id: "current buffer", widthMethod: "unicode" });
13156
13414
  }
13415
+ rendererSetPaletteState(renderer, palette, defaultForeground, defaultBackground, paletteEpoch) {
13416
+ const paletteBuffer = new Float32Array(palette.length * 4);
13417
+ for (let index = 0;index < palette.length; index++) {
13418
+ const color = palette[index];
13419
+ const base = index * 4;
13420
+ paletteBuffer[base] = color.r;
13421
+ paletteBuffer[base + 1] = color.g;
13422
+ paletteBuffer[base + 2] = color.b;
13423
+ paletteBuffer[base + 3] = color.a;
13424
+ }
13425
+ this.opentui.symbols.rendererSetPaletteState(renderer, paletteBuffer, paletteBuffer.length, defaultForeground.buffer, defaultBackground.buffer, paletteEpoch >>> 0);
13426
+ }
13157
13427
  bufferGetCharPtr(buffer) {
13158
13428
  const ptr5 = this.opentui.symbols.bufferGetCharPtr(buffer);
13159
13429
  if (!ptr5) {
@@ -13175,6 +13445,20 @@ class FFIRenderLib {
13175
13445
  }
13176
13446
  return ptr5;
13177
13447
  }
13448
+ bufferGetFgTagPtr(buffer) {
13449
+ const ptr5 = this.opentui.symbols.bufferGetFgTagPtr(buffer);
13450
+ if (!ptr5) {
13451
+ throw new Error("Failed to get fg tag pointer");
13452
+ }
13453
+ return ptr5;
13454
+ }
13455
+ bufferGetBgTagPtr(buffer) {
13456
+ const ptr5 = this.opentui.symbols.bufferGetBgTagPtr(buffer);
13457
+ if (!ptr5) {
13458
+ throw new Error("Failed to get bg tag pointer");
13459
+ }
13460
+ return ptr5;
13461
+ }
13178
13462
  bufferGetAttributesPtr(buffer) {
13179
13463
  const ptr5 = this.opentui.symbols.bufferGetAttributesPtr(buffer);
13180
13464
  if (!ptr5) {
@@ -13319,6 +13603,12 @@ class FFIRenderLib {
13319
13603
  render(renderer, force) {
13320
13604
  this.opentui.symbols.render(renderer, force);
13321
13605
  }
13606
+ repaintSplitFooter(renderer, pinnedRenderOffset, force) {
13607
+ return this.opentui.symbols.repaintSplitFooter(renderer, pinnedRenderOffset, force);
13608
+ }
13609
+ commitSplitFooterSnapshot(renderer, snapshot, rowColumns, startOnNewLine, trailingNewline, pinnedRenderOffset, force, beginFrame = true, finalizeFrame = true) {
13610
+ return this.opentui.symbols.commitSplitFooterSnapshot(renderer, snapshot.ptr, rowColumns, startOnNewLine, trailingNewline, pinnedRenderOffset, force, beginFrame, finalizeFrame);
13611
+ }
13322
13612
  createOptimizedBuffer(width, height, widthMethod, respectAlpha = false, id) {
13323
13613
  if (Number.isNaN(width) || Number.isNaN(height)) {
13324
13614
  console.error(new Error(`Invalid dimensions for OptimizedBuffer: ${width}x${height}`).stack);
@@ -13426,6 +13716,9 @@ class FFIRenderLib {
13426
13716
  queryPixelResolution(renderer) {
13427
13717
  this.opentui.symbols.queryPixelResolution(renderer);
13428
13718
  }
13719
+ queryThemeColors(renderer) {
13720
+ this.opentui.symbols.queryThemeColors(renderer);
13721
+ }
13429
13722
  writeOut(renderer, data) {
13430
13723
  const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
13431
13724
  if (bytes.length === 0)
@@ -13598,6 +13891,9 @@ class FFIRenderLib {
13598
13891
  const modeValue = mode === "none" ? 0 : mode === "char" ? 1 : 2;
13599
13892
  this.opentui.symbols.textBufferViewSetWrapMode(view, modeValue);
13600
13893
  }
13894
+ textBufferViewSetFirstLineOffset(view, offset) {
13895
+ this.opentui.symbols.textBufferViewSetFirstLineOffset(view, offset);
13896
+ }
13601
13897
  textBufferViewSetViewportSize(view, width, height) {
13602
13898
  this.opentui.symbols.textBufferViewSetViewportSize(view, width, height);
13603
13899
  }
@@ -14127,6 +14423,7 @@ class FFIRenderLib {
14127
14423
  kitty_keyboard: caps.kitty_keyboard,
14128
14424
  kitty_graphics: caps.kitty_graphics,
14129
14425
  rgb: caps.rgb,
14426
+ ansi256: caps.ansi256,
14130
14427
  unicode: caps.unicode,
14131
14428
  sgr_pixels: caps.sgr_pixels,
14132
14429
  color_scheme_updates: caps.color_scheme_updates,
@@ -16051,6 +16348,139 @@ function delegate(mapping, vnode) {
16051
16348
  return vnode;
16052
16349
  }
16053
16350
 
16351
+ // src/text-buffer-view.ts
16352
+ class TextBufferView {
16353
+ lib;
16354
+ viewPtr;
16355
+ textBuffer;
16356
+ _destroyed = false;
16357
+ constructor(lib, ptr5, textBuffer) {
16358
+ this.lib = lib;
16359
+ this.viewPtr = ptr5;
16360
+ this.textBuffer = textBuffer;
16361
+ }
16362
+ static create(textBuffer) {
16363
+ const lib = resolveRenderLib();
16364
+ const viewPtr = lib.createTextBufferView(textBuffer.ptr);
16365
+ return new TextBufferView(lib, viewPtr, textBuffer);
16366
+ }
16367
+ guard() {
16368
+ if (this._destroyed)
16369
+ throw new Error("TextBufferView is destroyed");
16370
+ }
16371
+ get ptr() {
16372
+ this.guard();
16373
+ return this.viewPtr;
16374
+ }
16375
+ setSelection(start, end, bgColor, fgColor) {
16376
+ this.guard();
16377
+ this.lib.textBufferViewSetSelection(this.viewPtr, start, end, bgColor || null, fgColor || null);
16378
+ }
16379
+ updateSelection(end, bgColor, fgColor) {
16380
+ this.guard();
16381
+ this.lib.textBufferViewUpdateSelection(this.viewPtr, end, bgColor || null, fgColor || null);
16382
+ }
16383
+ resetSelection() {
16384
+ this.guard();
16385
+ this.lib.textBufferViewResetSelection(this.viewPtr);
16386
+ }
16387
+ getSelection() {
16388
+ this.guard();
16389
+ return this.lib.textBufferViewGetSelection(this.viewPtr);
16390
+ }
16391
+ hasSelection() {
16392
+ this.guard();
16393
+ return this.getSelection() !== null;
16394
+ }
16395
+ setLocalSelection(anchorX, anchorY, focusX, focusY, bgColor, fgColor) {
16396
+ this.guard();
16397
+ return this.lib.textBufferViewSetLocalSelection(this.viewPtr, anchorX, anchorY, focusX, focusY, bgColor || null, fgColor || null);
16398
+ }
16399
+ updateLocalSelection(anchorX, anchorY, focusX, focusY, bgColor, fgColor) {
16400
+ this.guard();
16401
+ return this.lib.textBufferViewUpdateLocalSelection(this.viewPtr, anchorX, anchorY, focusX, focusY, bgColor || null, fgColor || null);
16402
+ }
16403
+ resetLocalSelection() {
16404
+ this.guard();
16405
+ this.lib.textBufferViewResetLocalSelection(this.viewPtr);
16406
+ }
16407
+ setWrapWidth(width) {
16408
+ this.guard();
16409
+ this.lib.textBufferViewSetWrapWidth(this.viewPtr, width ?? 0);
16410
+ }
16411
+ setWrapMode(mode) {
16412
+ this.guard();
16413
+ this.lib.textBufferViewSetWrapMode(this.viewPtr, mode);
16414
+ }
16415
+ setFirstLineOffset(offset) {
16416
+ this.guard();
16417
+ this.lib.textBufferViewSetFirstLineOffset(this.viewPtr, offset);
16418
+ }
16419
+ setViewportSize(width, height) {
16420
+ this.guard();
16421
+ this.lib.textBufferViewSetViewportSize(this.viewPtr, width, height);
16422
+ }
16423
+ setViewport(x, y, width, height) {
16424
+ this.guard();
16425
+ this.lib.textBufferViewSetViewport(this.viewPtr, x, y, width, height);
16426
+ }
16427
+ get lineInfo() {
16428
+ this.guard();
16429
+ return this.lib.textBufferViewGetLineInfo(this.viewPtr);
16430
+ }
16431
+ get logicalLineInfo() {
16432
+ this.guard();
16433
+ return this.lib.textBufferViewGetLogicalLineInfo(this.viewPtr);
16434
+ }
16435
+ getSelectedText() {
16436
+ this.guard();
16437
+ const byteSize = this.textBuffer.byteSize;
16438
+ if (byteSize === 0)
16439
+ return "";
16440
+ const selectedBytes = this.lib.textBufferViewGetSelectedTextBytes(this.viewPtr, byteSize);
16441
+ if (!selectedBytes)
16442
+ return "";
16443
+ return this.lib.decoder.decode(selectedBytes);
16444
+ }
16445
+ getPlainText() {
16446
+ this.guard();
16447
+ const byteSize = this.textBuffer.byteSize;
16448
+ if (byteSize === 0)
16449
+ return "";
16450
+ const plainBytes = this.lib.textBufferViewGetPlainTextBytes(this.viewPtr, byteSize);
16451
+ if (!plainBytes)
16452
+ return "";
16453
+ return this.lib.decoder.decode(plainBytes);
16454
+ }
16455
+ setTabIndicator(indicator) {
16456
+ this.guard();
16457
+ const codePoint = typeof indicator === "string" ? indicator.codePointAt(0) ?? 0 : indicator;
16458
+ this.lib.textBufferViewSetTabIndicator(this.viewPtr, codePoint);
16459
+ }
16460
+ setTabIndicatorColor(color) {
16461
+ this.guard();
16462
+ this.lib.textBufferViewSetTabIndicatorColor(this.viewPtr, color);
16463
+ }
16464
+ setTruncate(truncate) {
16465
+ this.guard();
16466
+ this.lib.textBufferViewSetTruncate(this.viewPtr, truncate);
16467
+ }
16468
+ measureForDimensions(width, height) {
16469
+ this.guard();
16470
+ return this.lib.textBufferViewMeasureForDimensions(this.viewPtr, width, height);
16471
+ }
16472
+ getVirtualLineCount() {
16473
+ this.guard();
16474
+ return this.lib.textBufferViewGetVirtualLineCount(this.viewPtr);
16475
+ }
16476
+ destroy() {
16477
+ if (this._destroyed)
16478
+ return;
16479
+ this._destroyed = true;
16480
+ this.lib.destroyTextBufferView(this.viewPtr);
16481
+ }
16482
+ }
16483
+
16054
16484
  // src/edit-buffer.ts
16055
16485
  import { EventEmitter as EventEmitter6 } from "events";
16056
16486
 
@@ -16555,54 +16985,1490 @@ class EditorView {
16555
16985
  }
16556
16986
  }
16557
16987
 
16558
- // src/console.ts
16559
- import { EventEmitter as EventEmitter8 } from "events";
16560
- import { Console } from "console";
16561
- import fs from "fs";
16562
- import path5 from "path";
16563
- import util2 from "util";
16564
-
16565
- // src/lib/output.capture.ts
16566
- import { Writable } from "stream";
16567
- import { EventEmitter as EventEmitter7 } from "events";
16988
+ // src/syntax-style.ts
16989
+ function convertThemeToStyles(theme) {
16990
+ const flatStyles = {};
16991
+ for (const tokenStyle of theme) {
16992
+ const styleDefinition = {};
16993
+ if (tokenStyle.style.foreground) {
16994
+ styleDefinition.fg = parseColor(tokenStyle.style.foreground);
16995
+ }
16996
+ if (tokenStyle.style.background) {
16997
+ styleDefinition.bg = parseColor(tokenStyle.style.background);
16998
+ }
16999
+ if (tokenStyle.style.bold !== undefined) {
17000
+ styleDefinition.bold = tokenStyle.style.bold;
17001
+ }
17002
+ if (tokenStyle.style.italic !== undefined) {
17003
+ styleDefinition.italic = tokenStyle.style.italic;
17004
+ }
17005
+ if (tokenStyle.style.underline !== undefined) {
17006
+ styleDefinition.underline = tokenStyle.style.underline;
17007
+ }
17008
+ if (tokenStyle.style.dim !== undefined) {
17009
+ styleDefinition.dim = tokenStyle.style.dim;
17010
+ }
17011
+ for (const scope of tokenStyle.scope) {
17012
+ flatStyles[scope] = styleDefinition;
17013
+ }
17014
+ }
17015
+ return flatStyles;
17016
+ }
16568
17017
 
16569
- class Capture extends EventEmitter7 {
16570
- output = [];
16571
- constructor() {
16572
- super();
17018
+ class SyntaxStyle {
17019
+ lib;
17020
+ stylePtr;
17021
+ _destroyed = false;
17022
+ nameCache = new Map;
17023
+ styleDefs = new Map;
17024
+ mergedCache = new Map;
17025
+ constructor(lib, ptr5) {
17026
+ this.lib = lib;
17027
+ this.stylePtr = ptr5;
16573
17028
  }
16574
- get size() {
16575
- return this.output.length;
17029
+ static create() {
17030
+ const lib = resolveRenderLib();
17031
+ const ptr5 = lib.createSyntaxStyle();
17032
+ return new SyntaxStyle(lib, ptr5);
16576
17033
  }
16577
- write(stream, data) {
16578
- this.output.push({ stream, output: data });
16579
- this.emit("write", stream, data);
17034
+ static fromTheme(theme) {
17035
+ const style = SyntaxStyle.create();
17036
+ const flatStyles = convertThemeToStyles(theme);
17037
+ for (const [name, styleDef] of Object.entries(flatStyles)) {
17038
+ style.registerStyle(name, styleDef);
17039
+ }
17040
+ return style;
16580
17041
  }
16581
- claimOutput() {
16582
- const output = this.output.map((o) => o.output).join("");
16583
- this.clear();
16584
- return output;
17042
+ static fromStyles(styles) {
17043
+ const style = SyntaxStyle.create();
17044
+ for (const [name, styleDef] of Object.entries(styles)) {
17045
+ style.registerStyle(name, styleDef);
17046
+ }
17047
+ return style;
16585
17048
  }
16586
- clear() {
16587
- this.output = [];
17049
+ guard() {
17050
+ if (this._destroyed)
17051
+ throw new Error("NativeSyntaxStyle is destroyed");
16588
17052
  }
16589
- }
16590
-
16591
- class CapturedWritableStream extends Writable {
16592
- stream;
16593
- capture;
16594
- isTTY = true;
16595
- columns = process.stdout.columns || 80;
16596
- rows = process.stdout.rows || 24;
16597
- constructor(stream, capture) {
16598
- super();
16599
- this.stream = stream;
16600
- this.capture = capture;
17053
+ registerStyle(name, style) {
17054
+ this.guard();
17055
+ const attributes = createTextAttributes({
17056
+ bold: style.bold,
17057
+ italic: style.italic,
17058
+ underline: style.underline,
17059
+ dim: style.dim
17060
+ });
17061
+ const id = this.lib.syntaxStyleRegister(this.stylePtr, name, style.fg || null, style.bg || null, attributes);
17062
+ this.nameCache.set(name, id);
17063
+ this.styleDefs.set(name, style);
17064
+ return id;
16601
17065
  }
16602
- _write(chunk, encoding, callback) {
16603
- const data = chunk.toString();
16604
- this.capture.write(this.stream, data);
16605
- callback();
17066
+ resolveStyleId(name) {
17067
+ this.guard();
17068
+ const cached = this.nameCache.get(name);
17069
+ if (cached !== undefined)
17070
+ return cached;
17071
+ const id = this.lib.syntaxStyleResolveByName(this.stylePtr, name);
17072
+ if (id !== null) {
17073
+ this.nameCache.set(name, id);
17074
+ }
17075
+ return id;
17076
+ }
17077
+ getStyleId(name) {
17078
+ this.guard();
17079
+ const id = this.resolveStyleId(name);
17080
+ if (id !== null)
17081
+ return id;
17082
+ if (name.includes(".")) {
17083
+ const baseName = name.split(".")[0];
17084
+ return this.resolveStyleId(baseName);
17085
+ }
17086
+ return null;
17087
+ }
17088
+ get ptr() {
17089
+ this.guard();
17090
+ return this.stylePtr;
17091
+ }
17092
+ getStyleCount() {
17093
+ this.guard();
17094
+ return this.lib.syntaxStyleGetStyleCount(this.stylePtr);
17095
+ }
17096
+ clearNameCache() {
17097
+ this.nameCache.clear();
17098
+ }
17099
+ getStyle(name) {
17100
+ this.guard();
17101
+ if (Object.prototype.hasOwnProperty.call(this.styleDefs, name)) {
17102
+ return;
17103
+ }
17104
+ const style = this.styleDefs.get(name);
17105
+ if (style)
17106
+ return style;
17107
+ if (name.includes(".")) {
17108
+ const baseName = name.split(".")[0];
17109
+ if (Object.prototype.hasOwnProperty.call(this.styleDefs, baseName)) {
17110
+ return;
17111
+ }
17112
+ return this.styleDefs.get(baseName);
17113
+ }
17114
+ return;
17115
+ }
17116
+ mergeStyles(...styleNames) {
17117
+ this.guard();
17118
+ const cacheKey = styleNames.join(":");
17119
+ const cached = this.mergedCache.get(cacheKey);
17120
+ if (cached)
17121
+ return cached;
17122
+ const styleDefinition = {};
17123
+ for (const name of styleNames) {
17124
+ const style = this.getStyle(name);
17125
+ if (!style)
17126
+ continue;
17127
+ if (style.fg)
17128
+ styleDefinition.fg = style.fg;
17129
+ if (style.bg)
17130
+ styleDefinition.bg = style.bg;
17131
+ if (style.bold !== undefined)
17132
+ styleDefinition.bold = style.bold;
17133
+ if (style.italic !== undefined)
17134
+ styleDefinition.italic = style.italic;
17135
+ if (style.underline !== undefined)
17136
+ styleDefinition.underline = style.underline;
17137
+ if (style.dim !== undefined)
17138
+ styleDefinition.dim = style.dim;
17139
+ }
17140
+ const attributes = createTextAttributes({
17141
+ bold: styleDefinition.bold,
17142
+ italic: styleDefinition.italic,
17143
+ underline: styleDefinition.underline,
17144
+ dim: styleDefinition.dim
17145
+ });
17146
+ const merged = {
17147
+ fg: styleDefinition.fg,
17148
+ bg: styleDefinition.bg,
17149
+ attributes
17150
+ };
17151
+ this.mergedCache.set(cacheKey, merged);
17152
+ return merged;
17153
+ }
17154
+ clearCache() {
17155
+ this.guard();
17156
+ this.mergedCache.clear();
17157
+ }
17158
+ getCacheSize() {
17159
+ this.guard();
17160
+ return this.mergedCache.size;
17161
+ }
17162
+ getAllStyles() {
17163
+ this.guard();
17164
+ return new Map(this.styleDefs);
17165
+ }
17166
+ getRegisteredNames() {
17167
+ this.guard();
17168
+ return Array.from(this.styleDefs.keys());
17169
+ }
17170
+ destroy() {
17171
+ if (this._destroyed)
17172
+ return;
17173
+ this._destroyed = true;
17174
+ this.nameCache.clear();
17175
+ this.styleDefs.clear();
17176
+ this.mergedCache.clear();
17177
+ this.lib.destroySyntaxStyle(this.stylePtr);
17178
+ }
17179
+ }
17180
+
17181
+ // src/renderables/Box.ts
17182
+ function isGapType(value) {
17183
+ if (value === undefined) {
17184
+ return true;
17185
+ }
17186
+ if (typeof value === "number" && !Number.isNaN(value)) {
17187
+ return true;
17188
+ }
17189
+ return isValidPercentage(value);
17190
+ }
17191
+
17192
+ class BoxRenderable extends Renderable {
17193
+ _backgroundColor;
17194
+ _border;
17195
+ _borderStyle;
17196
+ _borderColor;
17197
+ _focusedBorderColor;
17198
+ _customBorderCharsObj;
17199
+ _customBorderChars;
17200
+ borderSides;
17201
+ shouldFill;
17202
+ _title;
17203
+ _titleAlignment;
17204
+ _bottomTitle;
17205
+ _bottomTitleAlignment;
17206
+ _defaultOptions = {
17207
+ backgroundColor: "transparent",
17208
+ borderStyle: "single",
17209
+ border: false,
17210
+ borderColor: "#FFFFFF",
17211
+ shouldFill: true,
17212
+ titleAlignment: "left",
17213
+ bottomTitleAlignment: "left",
17214
+ focusedBorderColor: "#00AAFF"
17215
+ };
17216
+ constructor(ctx, options) {
17217
+ super(ctx, options);
17218
+ if (options.focusable === true) {
17219
+ this._focusable = true;
17220
+ }
17221
+ this._backgroundColor = parseColor(options.backgroundColor || this._defaultOptions.backgroundColor);
17222
+ this._border = options.border ?? this._defaultOptions.border;
17223
+ if (!options.border && (options.borderStyle || options.borderColor || options.focusedBorderColor || options.customBorderChars)) {
17224
+ this._border = true;
17225
+ }
17226
+ this._borderStyle = parseBorderStyle(options.borderStyle, this._defaultOptions.borderStyle);
17227
+ this._borderColor = parseColor(options.borderColor || this._defaultOptions.borderColor);
17228
+ this._focusedBorderColor = parseColor(options.focusedBorderColor || this._defaultOptions.focusedBorderColor);
17229
+ this._customBorderCharsObj = options.customBorderChars;
17230
+ this._customBorderChars = this._customBorderCharsObj ? borderCharsToArray(this._customBorderCharsObj) : undefined;
17231
+ this.borderSides = getBorderSides(this._border);
17232
+ this.shouldFill = options.shouldFill ?? this._defaultOptions.shouldFill;
17233
+ this._title = options.title;
17234
+ this._titleAlignment = options.titleAlignment || this._defaultOptions.titleAlignment;
17235
+ this._bottomTitle = options.bottomTitle;
17236
+ this._bottomTitleAlignment = options.bottomTitleAlignment || this._defaultOptions.bottomTitleAlignment;
17237
+ this.applyYogaBorders();
17238
+ const hasInitialGapProps = options.gap !== undefined || options.rowGap !== undefined || options.columnGap !== undefined;
17239
+ if (hasInitialGapProps) {
17240
+ this.applyYogaGap(options);
17241
+ }
17242
+ }
17243
+ initializeBorder() {
17244
+ if (this._border === false) {
17245
+ this._border = true;
17246
+ this.borderSides = getBorderSides(this._border);
17247
+ this.applyYogaBorders();
17248
+ }
17249
+ }
17250
+ get customBorderChars() {
17251
+ return this._customBorderCharsObj;
17252
+ }
17253
+ set customBorderChars(value) {
17254
+ this._customBorderCharsObj = value;
17255
+ this._customBorderChars = value ? borderCharsToArray(value) : undefined;
17256
+ this.requestRender();
17257
+ }
17258
+ get backgroundColor() {
17259
+ return this._backgroundColor;
17260
+ }
17261
+ set backgroundColor(value) {
17262
+ const newColor = parseColor(value ?? this._defaultOptions.backgroundColor);
17263
+ if (this._backgroundColor !== newColor) {
17264
+ this._backgroundColor = newColor;
17265
+ this.requestRender();
17266
+ }
17267
+ }
17268
+ get border() {
17269
+ return this._border;
17270
+ }
17271
+ set border(value) {
17272
+ if (this._border !== value) {
17273
+ this._border = value;
17274
+ this.borderSides = getBorderSides(value);
17275
+ this.applyYogaBorders();
17276
+ this.requestRender();
17277
+ }
17278
+ }
17279
+ get borderStyle() {
17280
+ return this._borderStyle;
17281
+ }
17282
+ set borderStyle(value) {
17283
+ const _value = parseBorderStyle(value, this._defaultOptions.borderStyle);
17284
+ if (this._borderStyle !== _value || !this._border) {
17285
+ this._borderStyle = _value;
17286
+ this._customBorderChars = undefined;
17287
+ this.initializeBorder();
17288
+ this.requestRender();
17289
+ }
17290
+ }
17291
+ get borderColor() {
17292
+ return this._borderColor;
17293
+ }
17294
+ set borderColor(value) {
17295
+ const newColor = parseColor(value ?? this._defaultOptions.borderColor);
17296
+ if (this._borderColor !== newColor) {
17297
+ this._borderColor = newColor;
17298
+ this.initializeBorder();
17299
+ this.requestRender();
17300
+ }
17301
+ }
17302
+ get focusedBorderColor() {
17303
+ return this._focusedBorderColor;
17304
+ }
17305
+ set focusedBorderColor(value) {
17306
+ const newColor = parseColor(value ?? this._defaultOptions.focusedBorderColor);
17307
+ if (this._focusedBorderColor !== newColor) {
17308
+ this._focusedBorderColor = newColor;
17309
+ this.initializeBorder();
17310
+ if (this._focused) {
17311
+ this.requestRender();
17312
+ }
17313
+ }
17314
+ }
17315
+ get title() {
17316
+ return this._title;
17317
+ }
17318
+ set title(value) {
17319
+ if (this._title !== value) {
17320
+ this._title = value;
17321
+ this.requestRender();
17322
+ }
17323
+ }
17324
+ get titleAlignment() {
17325
+ return this._titleAlignment;
17326
+ }
17327
+ set titleAlignment(value) {
17328
+ if (this._titleAlignment !== value) {
17329
+ this._titleAlignment = value;
17330
+ this.requestRender();
17331
+ }
17332
+ }
17333
+ get bottomTitle() {
17334
+ return this._bottomTitle;
17335
+ }
17336
+ set bottomTitle(value) {
17337
+ if (this._bottomTitle !== value) {
17338
+ this._bottomTitle = value;
17339
+ this.requestRender();
17340
+ }
17341
+ }
17342
+ get bottomTitleAlignment() {
17343
+ return this._bottomTitleAlignment;
17344
+ }
17345
+ set bottomTitleAlignment(value) {
17346
+ if (this._bottomTitleAlignment !== value) {
17347
+ this._bottomTitleAlignment = value;
17348
+ this.requestRender();
17349
+ }
17350
+ }
17351
+ renderSelf(buffer) {
17352
+ const hasBorder = this.borderSides.top || this.borderSides.right || this.borderSides.bottom || this.borderSides.left;
17353
+ const hasVisibleFill = this.shouldFill && this._backgroundColor.a > 0;
17354
+ if (!hasBorder && !hasVisibleFill) {
17355
+ return;
17356
+ }
17357
+ const hasFocusWithin = this._focusable && (this._focused || this._hasFocusedDescendant);
17358
+ const currentBorderColor = hasFocusWithin ? this._focusedBorderColor : this._borderColor;
17359
+ const screenX = this._screenX;
17360
+ const screenY = this._screenY;
17361
+ buffer.drawBox({
17362
+ x: screenX,
17363
+ y: screenY,
17364
+ width: this.width,
17365
+ height: this.height,
17366
+ borderStyle: this._borderStyle,
17367
+ customBorderChars: this._customBorderChars,
17368
+ border: this._border,
17369
+ borderColor: currentBorderColor,
17370
+ backgroundColor: this._backgroundColor,
17371
+ shouldFill: this.shouldFill,
17372
+ title: this._title,
17373
+ titleAlignment: this._titleAlignment,
17374
+ bottomTitle: this._bottomTitle,
17375
+ bottomTitleAlignment: this._bottomTitleAlignment
17376
+ });
17377
+ }
17378
+ getScissorRect() {
17379
+ const baseRect = super.getScissorRect();
17380
+ if (!this.borderSides.top && !this.borderSides.right && !this.borderSides.bottom && !this.borderSides.left) {
17381
+ return baseRect;
17382
+ }
17383
+ const leftInset = this.borderSides.left ? 1 : 0;
17384
+ const rightInset = this.borderSides.right ? 1 : 0;
17385
+ const topInset = this.borderSides.top ? 1 : 0;
17386
+ const bottomInset = this.borderSides.bottom ? 1 : 0;
17387
+ return {
17388
+ x: baseRect.x + leftInset,
17389
+ y: baseRect.y + topInset,
17390
+ width: Math.max(0, baseRect.width - leftInset - rightInset),
17391
+ height: Math.max(0, baseRect.height - topInset - bottomInset)
17392
+ };
17393
+ }
17394
+ applyYogaBorders() {
17395
+ const node = this.yogaNode;
17396
+ node.setBorder(Edge.Left, this.borderSides.left ? 1 : 0);
17397
+ node.setBorder(Edge.Right, this.borderSides.right ? 1 : 0);
17398
+ node.setBorder(Edge.Top, this.borderSides.top ? 1 : 0);
17399
+ node.setBorder(Edge.Bottom, this.borderSides.bottom ? 1 : 0);
17400
+ this.requestRender();
17401
+ }
17402
+ applyYogaGap(options) {
17403
+ const node = this.yogaNode;
17404
+ if (isGapType(options.gap)) {
17405
+ node.setGap(Gutter.All, options.gap);
17406
+ }
17407
+ if (isGapType(options.rowGap)) {
17408
+ node.setGap(Gutter.Row, options.rowGap);
17409
+ }
17410
+ if (isGapType(options.columnGap)) {
17411
+ node.setGap(Gutter.Column, options.columnGap);
17412
+ }
17413
+ }
17414
+ set gap(gap) {
17415
+ if (isGapType(gap)) {
17416
+ this.yogaNode.setGap(Gutter.All, gap);
17417
+ this.requestRender();
17418
+ }
17419
+ }
17420
+ set rowGap(rowGap) {
17421
+ if (isGapType(rowGap)) {
17422
+ this.yogaNode.setGap(Gutter.Row, rowGap);
17423
+ this.requestRender();
17424
+ }
17425
+ }
17426
+ set columnGap(columnGap) {
17427
+ if (isGapType(columnGap)) {
17428
+ this.yogaNode.setGap(Gutter.Column, columnGap);
17429
+ this.requestRender();
17430
+ }
17431
+ }
17432
+ }
17433
+
17434
+ // src/renderables/TextBufferRenderable.ts
17435
+ class TextBufferRenderable extends Renderable {
17436
+ selectable = true;
17437
+ _defaultFg;
17438
+ _defaultBg;
17439
+ _defaultAttributes;
17440
+ _selectionBg;
17441
+ _selectionFg;
17442
+ _wrapMode = "word";
17443
+ lastLocalSelection = null;
17444
+ _tabIndicator;
17445
+ _tabIndicatorColor;
17446
+ _scrollX = 0;
17447
+ _scrollY = 0;
17448
+ _truncate = false;
17449
+ _firstLineOffset = 0;
17450
+ textBuffer;
17451
+ textBufferView;
17452
+ _textBufferSyntaxStyle;
17453
+ _defaultOptions = {
17454
+ fg: RGBA.fromValues(1, 1, 1, 1),
17455
+ bg: RGBA.fromValues(0, 0, 0, 0),
17456
+ selectionBg: undefined,
17457
+ selectionFg: undefined,
17458
+ selectable: true,
17459
+ attributes: 0,
17460
+ wrapMode: "word",
17461
+ tabIndicator: undefined,
17462
+ tabIndicatorColor: undefined,
17463
+ truncate: false
17464
+ };
17465
+ constructor(ctx, options) {
17466
+ super(ctx, options);
17467
+ this._defaultFg = parseColor(options.fg ?? this._defaultOptions.fg);
17468
+ this._defaultBg = parseColor(options.bg ?? this._defaultOptions.bg);
17469
+ this._defaultAttributes = options.attributes ?? this._defaultOptions.attributes;
17470
+ this._selectionBg = options.selectionBg ? parseColor(options.selectionBg) : this._defaultOptions.selectionBg;
17471
+ this._selectionFg = options.selectionFg ? parseColor(options.selectionFg) : this._defaultOptions.selectionFg;
17472
+ this.selectable = options.selectable ?? this._defaultOptions.selectable;
17473
+ this._wrapMode = options.wrapMode ?? this._defaultOptions.wrapMode;
17474
+ this._tabIndicator = options.tabIndicator ?? this._defaultOptions.tabIndicator;
17475
+ this._tabIndicatorColor = options.tabIndicatorColor ? parseColor(options.tabIndicatorColor) : this._defaultOptions.tabIndicatorColor;
17476
+ this._truncate = options.truncate ?? this._defaultOptions.truncate;
17477
+ this.textBuffer = TextBuffer.create(this._ctx.widthMethod);
17478
+ this.textBufferView = TextBufferView.create(this.textBuffer);
17479
+ this._firstLineOffset = ctx.claimFirstLineOffset?.(this) ?? 0;
17480
+ this._textBufferSyntaxStyle = SyntaxStyle.create();
17481
+ this.textBuffer.setSyntaxStyle(this._textBufferSyntaxStyle);
17482
+ this.textBufferView.setWrapMode(this._wrapMode);
17483
+ this.textBufferView.setFirstLineOffset(this._firstLineOffset);
17484
+ this.setupMeasureFunc();
17485
+ this.textBuffer.setDefaultFg(this._defaultFg);
17486
+ this.textBuffer.setDefaultBg(this._defaultBg);
17487
+ this.textBuffer.setDefaultAttributes(this._defaultAttributes);
17488
+ if (this._tabIndicator !== undefined) {
17489
+ this.textBufferView.setTabIndicator(this._tabIndicator);
17490
+ }
17491
+ if (this._tabIndicatorColor !== undefined) {
17492
+ this.textBufferView.setTabIndicatorColor(this._tabIndicatorColor);
17493
+ }
17494
+ if (this._wrapMode !== "none" && this.width > 0) {
17495
+ this.textBufferView.setWrapWidth(this.width);
17496
+ }
17497
+ if (this.width > 0 && this.height > 0) {
17498
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, this.width, this.height);
17499
+ }
17500
+ this.textBufferView.setTruncate(this._truncate);
17501
+ this.updateTextInfo();
17502
+ }
17503
+ onMouseEvent(event) {
17504
+ if (event.type === "scroll") {
17505
+ this.handleScroll(event);
17506
+ }
17507
+ }
17508
+ handleScroll(event) {
17509
+ if (!event.scroll)
17510
+ return;
17511
+ const { direction, delta } = event.scroll;
17512
+ if (direction === "up") {
17513
+ this.scrollY -= delta;
17514
+ } else if (direction === "down") {
17515
+ this.scrollY += delta;
17516
+ }
17517
+ if (this._wrapMode === "none") {
17518
+ if (direction === "left") {
17519
+ this.scrollX -= delta;
17520
+ } else if (direction === "right") {
17521
+ this.scrollX += delta;
17522
+ }
17523
+ }
17524
+ }
17525
+ get lineInfo() {
17526
+ return this.textBufferView.logicalLineInfo;
17527
+ }
17528
+ get lineCount() {
17529
+ return this.textBuffer.getLineCount();
17530
+ }
17531
+ get virtualLineCount() {
17532
+ return this.textBufferView.getVirtualLineCount();
17533
+ }
17534
+ get scrollY() {
17535
+ return this._scrollY;
17536
+ }
17537
+ set scrollY(value) {
17538
+ const maxScrollY = Math.max(0, this.scrollHeight - this.height);
17539
+ const clamped = Math.max(0, Math.min(value, maxScrollY));
17540
+ if (this._scrollY !== clamped) {
17541
+ this._scrollY = clamped;
17542
+ this.updateViewportOffset();
17543
+ this.requestRender();
17544
+ }
17545
+ }
17546
+ get scrollX() {
17547
+ return this._scrollX;
17548
+ }
17549
+ set scrollX(value) {
17550
+ const maxScrollX = Math.max(0, this.scrollWidth - this.width);
17551
+ const clamped = Math.max(0, Math.min(value, maxScrollX));
17552
+ if (this._scrollX !== clamped) {
17553
+ this._scrollX = clamped;
17554
+ this.updateViewportOffset();
17555
+ this.requestRender();
17556
+ }
17557
+ }
17558
+ get scrollWidth() {
17559
+ return this.lineInfo.lineWidthColsMax;
17560
+ }
17561
+ get scrollHeight() {
17562
+ return this.lineInfo.lineStartCols.length;
17563
+ }
17564
+ get maxScrollY() {
17565
+ return Math.max(0, this.scrollHeight - this.height);
17566
+ }
17567
+ get maxScrollX() {
17568
+ return Math.max(0, this.scrollWidth - this.width);
17569
+ }
17570
+ updateViewportOffset() {
17571
+ if (this.width > 0 && this.height > 0) {
17572
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, this.width, this.height);
17573
+ }
17574
+ }
17575
+ get plainText() {
17576
+ return this.textBuffer.getPlainText();
17577
+ }
17578
+ get textLength() {
17579
+ return this.textBuffer.length;
17580
+ }
17581
+ get fg() {
17582
+ return this._defaultFg;
17583
+ }
17584
+ set fg(value) {
17585
+ const newColor = parseColor(value ?? this._defaultOptions.fg);
17586
+ if (this._defaultFg !== newColor) {
17587
+ this._defaultFg = newColor;
17588
+ this.textBuffer.setDefaultFg(this._defaultFg);
17589
+ this.onFgChanged(newColor);
17590
+ this.requestRender();
17591
+ }
17592
+ }
17593
+ get selectionBg() {
17594
+ return this._selectionBg;
17595
+ }
17596
+ set selectionBg(value) {
17597
+ const newColor = value ? parseColor(value) : this._defaultOptions.selectionBg;
17598
+ if (this._selectionBg !== newColor) {
17599
+ this._selectionBg = newColor;
17600
+ if (this.lastLocalSelection) {
17601
+ this.updateLocalSelection(this.lastLocalSelection);
17602
+ }
17603
+ this.requestRender();
17604
+ }
17605
+ }
17606
+ get selectionFg() {
17607
+ return this._selectionFg;
17608
+ }
17609
+ set selectionFg(value) {
17610
+ const newColor = value ? parseColor(value) : this._defaultOptions.selectionFg;
17611
+ if (this._selectionFg !== newColor) {
17612
+ this._selectionFg = newColor;
17613
+ if (this.lastLocalSelection) {
17614
+ this.updateLocalSelection(this.lastLocalSelection);
17615
+ }
17616
+ this.requestRender();
17617
+ }
17618
+ }
17619
+ get bg() {
17620
+ return this._defaultBg;
17621
+ }
17622
+ set bg(value) {
17623
+ const newColor = parseColor(value ?? this._defaultOptions.bg);
17624
+ if (this._defaultBg !== newColor) {
17625
+ this._defaultBg = newColor;
17626
+ this.textBuffer.setDefaultBg(this._defaultBg);
17627
+ this.onBgChanged(newColor);
17628
+ this.requestRender();
17629
+ }
17630
+ }
17631
+ get attributes() {
17632
+ return this._defaultAttributes;
17633
+ }
17634
+ set attributes(value) {
17635
+ if (this._defaultAttributes !== value) {
17636
+ this._defaultAttributes = value;
17637
+ this.textBuffer.setDefaultAttributes(this._defaultAttributes);
17638
+ this.onAttributesChanged(value);
17639
+ this.requestRender();
17640
+ }
17641
+ }
17642
+ get wrapMode() {
17643
+ return this._wrapMode;
17644
+ }
17645
+ set wrapMode(value) {
17646
+ if (this._wrapMode !== value) {
17647
+ this._wrapMode = value;
17648
+ this.textBufferView.setWrapMode(this._wrapMode);
17649
+ if (value !== "none" && this.width > 0) {
17650
+ this.textBufferView.setWrapWidth(this.width);
17651
+ }
17652
+ this.yogaNode.markDirty();
17653
+ this.requestRender();
17654
+ }
17655
+ }
17656
+ get tabIndicator() {
17657
+ return this._tabIndicator;
17658
+ }
17659
+ set tabIndicator(value) {
17660
+ if (this._tabIndicator !== value) {
17661
+ this._tabIndicator = value;
17662
+ if (value !== undefined) {
17663
+ this.textBufferView.setTabIndicator(value);
17664
+ }
17665
+ this.requestRender();
17666
+ }
17667
+ }
17668
+ get tabIndicatorColor() {
17669
+ return this._tabIndicatorColor;
17670
+ }
17671
+ set tabIndicatorColor(value) {
17672
+ const newColor = value ? parseColor(value) : undefined;
17673
+ if (this._tabIndicatorColor !== newColor) {
17674
+ this._tabIndicatorColor = newColor;
17675
+ if (newColor !== undefined) {
17676
+ this.textBufferView.setTabIndicatorColor(newColor);
17677
+ }
17678
+ this.requestRender();
17679
+ }
17680
+ }
17681
+ get truncate() {
17682
+ return this._truncate;
17683
+ }
17684
+ set truncate(value) {
17685
+ if (this._truncate !== value) {
17686
+ this._truncate = value;
17687
+ this.textBufferView.setTruncate(value);
17688
+ this.requestRender();
17689
+ }
17690
+ }
17691
+ onResize(width, height) {
17692
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, width, height);
17693
+ this.yogaNode.markDirty();
17694
+ this.requestRender();
17695
+ this.emit("line-info-change");
17696
+ }
17697
+ refreshLocalSelection() {
17698
+ if (this.lastLocalSelection) {
17699
+ return this.updateLocalSelection(this.lastLocalSelection);
17700
+ }
17701
+ return false;
17702
+ }
17703
+ updateLocalSelection(localSelection) {
17704
+ if (!localSelection?.isActive) {
17705
+ this.textBufferView.resetLocalSelection();
17706
+ return true;
17707
+ }
17708
+ return this.textBufferView.setLocalSelection(localSelection.anchorX, localSelection.anchorY, localSelection.focusX, localSelection.focusY, this._selectionBg, this._selectionFg);
17709
+ }
17710
+ updateTextInfo() {
17711
+ if (this.lastLocalSelection) {
17712
+ this.updateLocalSelection(this.lastLocalSelection);
17713
+ }
17714
+ this.yogaNode.markDirty();
17715
+ this.requestRender();
17716
+ this.emit("line-info-change");
17717
+ }
17718
+ setupMeasureFunc() {
17719
+ const measureFunc = (width, widthMode, height, heightMode) => {
17720
+ let effectiveWidth;
17721
+ if (widthMode === MeasureMode.Undefined || isNaN(width)) {
17722
+ effectiveWidth = 0;
17723
+ } else {
17724
+ effectiveWidth = width;
17725
+ }
17726
+ const effectiveHeight = isNaN(height) ? 1 : height;
17727
+ const measureResult = this.textBufferView.measureForDimensions(Math.floor(effectiveWidth), Math.floor(effectiveHeight));
17728
+ const measuredWidth = measureResult ? Math.max(1, measureResult.widthColsMax) : 1;
17729
+ const measuredHeight = measureResult ? Math.max(1, measureResult.lineCount) : 1;
17730
+ if (widthMode === MeasureMode.AtMost && this._positionType !== "absolute") {
17731
+ return {
17732
+ width: Math.min(effectiveWidth, measuredWidth),
17733
+ height: Math.min(effectiveHeight, measuredHeight)
17734
+ };
17735
+ }
17736
+ return {
17737
+ width: measuredWidth,
17738
+ height: measuredHeight
17739
+ };
17740
+ };
17741
+ this.yogaNode.setMeasureFunc(measureFunc);
17742
+ }
17743
+ shouldStartSelection(x, y) {
17744
+ if (!this.selectable)
17745
+ return false;
17746
+ const localX = x - this.x;
17747
+ const localY = y - this.y;
17748
+ return localX >= 0 && localX < this.width && localY >= 0 && localY < this.height;
17749
+ }
17750
+ onSelectionChanged(selection2) {
17751
+ const localSelection = convertGlobalToLocalSelection(selection2, this.x, this.y);
17752
+ this.lastLocalSelection = localSelection;
17753
+ let changed;
17754
+ if (!localSelection?.isActive) {
17755
+ this.textBufferView.resetLocalSelection();
17756
+ changed = true;
17757
+ } else if (selection2?.isStart) {
17758
+ changed = this.textBufferView.setLocalSelection(localSelection.anchorX, localSelection.anchorY, localSelection.focusX, localSelection.focusY, this._selectionBg, this._selectionFg);
17759
+ } else {
17760
+ changed = this.textBufferView.updateLocalSelection(localSelection.anchorX, localSelection.anchorY, localSelection.focusX, localSelection.focusY, this._selectionBg, this._selectionFg);
17761
+ }
17762
+ if (changed) {
17763
+ this.requestRender();
17764
+ }
17765
+ return this.hasSelection();
17766
+ }
17767
+ getSelectedText() {
17768
+ return this.textBufferView.getSelectedText();
17769
+ }
17770
+ hasSelection() {
17771
+ return this.textBufferView.hasSelection();
17772
+ }
17773
+ getSelection() {
17774
+ return this.textBufferView.getSelection();
17775
+ }
17776
+ render(buffer, deltaTime) {
17777
+ if (!this.visible)
17778
+ return;
17779
+ const screenX = this._screenX;
17780
+ const screenY = this._screenY;
17781
+ this.markClean();
17782
+ this._ctx.addToHitGrid(screenX, screenY, this.width, this.height, this.num);
17783
+ this.renderSelf(buffer);
17784
+ if (this.buffered && this.frameBuffer) {
17785
+ buffer.drawFrameBuffer(screenX, screenY, this.frameBuffer);
17786
+ }
17787
+ }
17788
+ renderSelf(buffer) {
17789
+ if (this.textBuffer.ptr) {
17790
+ buffer.drawTextBuffer(this.textBufferView, this._screenX, this._screenY);
17791
+ }
17792
+ }
17793
+ destroy() {
17794
+ if (this.isDestroyed)
17795
+ return;
17796
+ this.textBuffer.setSyntaxStyle(null);
17797
+ this._textBufferSyntaxStyle.destroy();
17798
+ this.textBufferView.destroy();
17799
+ this.textBuffer.destroy();
17800
+ super.destroy();
17801
+ }
17802
+ onFgChanged(newColor) {}
17803
+ onBgChanged(newColor) {}
17804
+ onAttributesChanged(newAttributes) {}
17805
+ }
17806
+
17807
+ // src/renderables/Code.ts
17808
+ class CodeRenderable extends TextBufferRenderable {
17809
+ _content;
17810
+ _filetype;
17811
+ _syntaxStyle;
17812
+ _isHighlighting = false;
17813
+ _treeSitterClient;
17814
+ _highlightsDirty = false;
17815
+ _highlightSnapshotId = 0;
17816
+ _conceal;
17817
+ _drawUnstyledText;
17818
+ _shouldRenderTextBuffer = true;
17819
+ _streaming;
17820
+ _hadInitialContent = false;
17821
+ _lastHighlights = [];
17822
+ _onHighlight;
17823
+ _onChunks;
17824
+ _highlightingPromise = Promise.resolve();
17825
+ _contentDefaultOptions = {
17826
+ content: "",
17827
+ conceal: true,
17828
+ drawUnstyledText: true,
17829
+ streaming: false
17830
+ };
17831
+ constructor(ctx, options) {
17832
+ super(ctx, options);
17833
+ this._content = options.content ?? this._contentDefaultOptions.content;
17834
+ this._filetype = options.filetype;
17835
+ this._syntaxStyle = options.syntaxStyle;
17836
+ this._treeSitterClient = options.treeSitterClient ?? getTreeSitterClient();
17837
+ this._conceal = options.conceal ?? this._contentDefaultOptions.conceal;
17838
+ this._drawUnstyledText = options.drawUnstyledText ?? this._contentDefaultOptions.drawUnstyledText;
17839
+ this._streaming = options.streaming ?? this._contentDefaultOptions.streaming;
17840
+ this._onHighlight = options.onHighlight;
17841
+ this._onChunks = options.onChunks;
17842
+ if (this._content.length > 0) {
17843
+ this.textBuffer.setText(this._content);
17844
+ this.updateTextInfo();
17845
+ this._shouldRenderTextBuffer = this._drawUnstyledText || !this._filetype;
17846
+ }
17847
+ this._highlightsDirty = this._content.length > 0;
17848
+ }
17849
+ get content() {
17850
+ return this._content;
17851
+ }
17852
+ set content(value) {
17853
+ if (this._content !== value) {
17854
+ this._content = value;
17855
+ this._highlightsDirty = true;
17856
+ this._highlightSnapshotId++;
17857
+ if (this._streaming && !this._drawUnstyledText && this._filetype) {
17858
+ this.requestRender();
17859
+ return;
17860
+ }
17861
+ this.textBuffer.setText(value);
17862
+ this.updateTextInfo();
17863
+ }
17864
+ }
17865
+ get filetype() {
17866
+ return this._filetype;
17867
+ }
17868
+ set filetype(value) {
17869
+ if (this._filetype !== value) {
17870
+ this._filetype = value;
17871
+ this._highlightsDirty = true;
17872
+ }
17873
+ }
17874
+ get syntaxStyle() {
17875
+ return this._syntaxStyle;
17876
+ }
17877
+ set syntaxStyle(value) {
17878
+ if (this._syntaxStyle !== value) {
17879
+ this._syntaxStyle = value;
17880
+ this._highlightsDirty = true;
17881
+ }
17882
+ }
17883
+ get conceal() {
17884
+ return this._conceal;
17885
+ }
17886
+ set conceal(value) {
17887
+ if (this._conceal !== value) {
17888
+ this._conceal = value;
17889
+ this._highlightsDirty = true;
17890
+ }
17891
+ }
17892
+ get drawUnstyledText() {
17893
+ return this._drawUnstyledText;
17894
+ }
17895
+ set drawUnstyledText(value) {
17896
+ if (this._drawUnstyledText !== value) {
17897
+ this._drawUnstyledText = value;
17898
+ this._highlightsDirty = true;
17899
+ }
17900
+ }
17901
+ get streaming() {
17902
+ return this._streaming;
17903
+ }
17904
+ set streaming(value) {
17905
+ if (this._streaming !== value) {
17906
+ this._streaming = value;
17907
+ this._hadInitialContent = false;
17908
+ this._lastHighlights = [];
17909
+ this._highlightsDirty = true;
17910
+ }
17911
+ }
17912
+ get treeSitterClient() {
17913
+ return this._treeSitterClient;
17914
+ }
17915
+ set treeSitterClient(value) {
17916
+ if (this._treeSitterClient !== value) {
17917
+ this._treeSitterClient = value;
17918
+ this._highlightsDirty = true;
17919
+ }
17920
+ }
17921
+ get onHighlight() {
17922
+ return this._onHighlight;
17923
+ }
17924
+ set onHighlight(value) {
17925
+ if (this._onHighlight !== value) {
17926
+ this._onHighlight = value;
17927
+ this._highlightsDirty = true;
17928
+ }
17929
+ }
17930
+ get onChunks() {
17931
+ return this._onChunks;
17932
+ }
17933
+ set onChunks(value) {
17934
+ if (this._onChunks !== value) {
17935
+ this._onChunks = value;
17936
+ this._highlightsDirty = true;
17937
+ }
17938
+ }
17939
+ get isHighlighting() {
17940
+ return this._isHighlighting;
17941
+ }
17942
+ get highlightingDone() {
17943
+ return this._highlightingPromise;
17944
+ }
17945
+ async transformChunks(chunks, context) {
17946
+ if (!this._onChunks)
17947
+ return chunks;
17948
+ const modified = await this._onChunks(chunks, context);
17949
+ return modified ?? chunks;
17950
+ }
17951
+ ensureVisibleTextBeforeHighlight() {
17952
+ if (this.isDestroyed)
17953
+ return;
17954
+ const content = this._content;
17955
+ if (!this._filetype) {
17956
+ this._shouldRenderTextBuffer = true;
17957
+ return;
17958
+ }
17959
+ const isInitialContent = this._streaming && !this._hadInitialContent;
17960
+ const shouldDrawUnstyledNow = this._streaming ? isInitialContent && this._drawUnstyledText : this._drawUnstyledText;
17961
+ if (this._streaming && !isInitialContent) {
17962
+ this._shouldRenderTextBuffer = true;
17963
+ } else if (shouldDrawUnstyledNow) {
17964
+ this.textBuffer.setText(content);
17965
+ this._shouldRenderTextBuffer = true;
17966
+ } else {
17967
+ this._shouldRenderTextBuffer = false;
17968
+ }
17969
+ }
17970
+ async startHighlight() {
17971
+ const content = this._content;
17972
+ const filetype = this._filetype;
17973
+ const snapshotId = ++this._highlightSnapshotId;
17974
+ if (!filetype)
17975
+ return;
17976
+ const isInitialContent = this._streaming && !this._hadInitialContent;
17977
+ if (isInitialContent) {
17978
+ this._hadInitialContent = true;
17979
+ }
17980
+ this._isHighlighting = true;
17981
+ try {
17982
+ const result = await this._treeSitterClient.highlightOnce(content, filetype);
17983
+ if (snapshotId !== this._highlightSnapshotId) {
17984
+ return;
17985
+ }
17986
+ if (this.isDestroyed)
17987
+ return;
17988
+ let highlights = result.highlights ?? [];
17989
+ if (this._onHighlight && highlights.length >= 0) {
17990
+ const context = {
17991
+ content,
17992
+ filetype,
17993
+ syntaxStyle: this._syntaxStyle
17994
+ };
17995
+ const modified = await this._onHighlight(highlights, context);
17996
+ if (modified !== undefined) {
17997
+ highlights = modified;
17998
+ }
17999
+ }
18000
+ if (snapshotId !== this._highlightSnapshotId) {
18001
+ return;
18002
+ }
18003
+ if (this.isDestroyed)
18004
+ return;
18005
+ if (highlights.length > 0) {
18006
+ if (this._streaming) {
18007
+ this._lastHighlights = highlights;
18008
+ }
18009
+ }
18010
+ if (highlights.length > 0 || this._onChunks) {
18011
+ const context = {
18012
+ content,
18013
+ filetype,
18014
+ syntaxStyle: this._syntaxStyle,
18015
+ highlights
18016
+ };
18017
+ let chunks = treeSitterToTextChunks(content, highlights, this._syntaxStyle, {
18018
+ enabled: this._conceal
18019
+ });
18020
+ chunks = await this.transformChunks(chunks, context);
18021
+ if (snapshotId !== this._highlightSnapshotId) {
18022
+ return;
18023
+ }
18024
+ if (this.isDestroyed)
18025
+ return;
18026
+ const styledText = new StyledText(chunks);
18027
+ this.textBuffer.setStyledText(styledText);
18028
+ } else {
18029
+ this.textBuffer.setText(content);
18030
+ }
18031
+ this._shouldRenderTextBuffer = true;
18032
+ this._isHighlighting = false;
18033
+ this._highlightsDirty = false;
18034
+ this.updateTextInfo();
18035
+ this.requestRender();
18036
+ } catch (error) {
18037
+ if (snapshotId !== this._highlightSnapshotId) {
18038
+ return;
18039
+ }
18040
+ console.warn("Code highlighting failed, falling back to plain text:", error);
18041
+ if (this.isDestroyed)
18042
+ return;
18043
+ this.textBuffer.setText(content);
18044
+ this._shouldRenderTextBuffer = true;
18045
+ this._isHighlighting = false;
18046
+ this._highlightsDirty = false;
18047
+ this.updateTextInfo();
18048
+ this.requestRender();
18049
+ }
18050
+ }
18051
+ getLineHighlights(lineIdx) {
18052
+ return this.textBuffer.getLineHighlights(lineIdx);
18053
+ }
18054
+ renderSelf(buffer) {
18055
+ if (this._highlightsDirty) {
18056
+ if (this.isDestroyed)
18057
+ return;
18058
+ if (this._content.length === 0) {
18059
+ this._shouldRenderTextBuffer = false;
18060
+ this._highlightsDirty = false;
18061
+ } else if (!this._filetype) {
18062
+ this._shouldRenderTextBuffer = true;
18063
+ this._highlightsDirty = false;
18064
+ } else {
18065
+ this.ensureVisibleTextBeforeHighlight();
18066
+ this._highlightsDirty = false;
18067
+ this._highlightingPromise = this.startHighlight();
18068
+ }
18069
+ }
18070
+ if (!this._shouldRenderTextBuffer)
18071
+ return;
18072
+ super.renderSelf(buffer);
18073
+ }
18074
+ }
18075
+
18076
+ // src/renderables/TextNode.ts
18077
+ var BrandedTextNodeRenderable = Symbol.for("@opentui/core/TextNodeRenderable");
18078
+ function isTextNodeRenderable(obj) {
18079
+ return !!obj?.[BrandedTextNodeRenderable];
18080
+ }
18081
+ function styledTextToTextNodes(styledText) {
18082
+ return styledText.chunks.map((chunk) => {
18083
+ const node = new TextNodeRenderable({
18084
+ fg: chunk.fg,
18085
+ bg: chunk.bg,
18086
+ attributes: chunk.attributes,
18087
+ link: chunk.link
18088
+ });
18089
+ node.add(chunk.text);
18090
+ return node;
18091
+ });
18092
+ }
18093
+
18094
+ class TextNodeRenderable extends BaseRenderable {
18095
+ [BrandedTextNodeRenderable] = true;
18096
+ _fg;
18097
+ _bg;
18098
+ _attributes;
18099
+ _link;
18100
+ _children = [];
18101
+ parent = null;
18102
+ constructor(options) {
18103
+ super(options);
18104
+ this._fg = options.fg ? parseColor(options.fg) : undefined;
18105
+ this._bg = options.bg ? parseColor(options.bg) : undefined;
18106
+ this._attributes = options.attributes ?? 0;
18107
+ this._link = options.link;
18108
+ }
18109
+ get children() {
18110
+ return this._children;
18111
+ }
18112
+ set children(children) {
18113
+ this._children = children;
18114
+ this.requestRender();
18115
+ }
18116
+ requestRender() {
18117
+ this.markDirty();
18118
+ this.parent?.requestRender();
18119
+ }
18120
+ add(obj, index) {
18121
+ if (typeof obj === "string") {
18122
+ if (index !== undefined) {
18123
+ this._children.splice(index, 0, obj);
18124
+ this.requestRender();
18125
+ return index;
18126
+ }
18127
+ const insertIndex = this._children.length;
18128
+ this._children.push(obj);
18129
+ this.requestRender();
18130
+ return insertIndex;
18131
+ }
18132
+ if (isTextNodeRenderable(obj)) {
18133
+ if (index !== undefined) {
18134
+ this._children.splice(index, 0, obj);
18135
+ obj.parent = this;
18136
+ this.requestRender();
18137
+ return index;
18138
+ }
18139
+ const insertIndex = this._children.length;
18140
+ this._children.push(obj);
18141
+ obj.parent = this;
18142
+ this.requestRender();
18143
+ return insertIndex;
18144
+ }
18145
+ if (isStyledText(obj)) {
18146
+ const textNodes = styledTextToTextNodes(obj);
18147
+ if (index !== undefined) {
18148
+ this._children.splice(index, 0, ...textNodes);
18149
+ textNodes.forEach((node) => node.parent = this);
18150
+ this.requestRender();
18151
+ return index;
18152
+ }
18153
+ const insertIndex = this._children.length;
18154
+ this._children.push(...textNodes);
18155
+ textNodes.forEach((node) => node.parent = this);
18156
+ this.requestRender();
18157
+ return insertIndex;
18158
+ }
18159
+ throw new Error("TextNodeRenderable only accepts strings, TextNodeRenderable instances, or StyledText instances");
18160
+ }
18161
+ replace(obj, index) {
18162
+ this._children[index] = obj;
18163
+ if (typeof obj !== "string") {
18164
+ obj.parent = this;
18165
+ }
18166
+ this.requestRender();
18167
+ }
18168
+ insertBefore(child, anchorNode) {
18169
+ if (!anchorNode || !isTextNodeRenderable(anchorNode)) {
18170
+ throw new Error("Anchor must be a TextNodeRenderable");
18171
+ }
18172
+ const anchorIndex = this._children.indexOf(anchorNode);
18173
+ if (anchorIndex === -1) {
18174
+ throw new Error("Anchor node not found in children");
18175
+ }
18176
+ if (typeof child === "string") {
18177
+ this._children.splice(anchorIndex, 0, child);
18178
+ } else if (isTextNodeRenderable(child)) {
18179
+ this._children.splice(anchorIndex, 0, child);
18180
+ child.parent = this;
18181
+ } else if (child instanceof StyledText) {
18182
+ const textNodes = styledTextToTextNodes(child);
18183
+ this._children.splice(anchorIndex, 0, ...textNodes);
18184
+ textNodes.forEach((node) => node.parent = this);
18185
+ } else {
18186
+ throw new Error("Child must be a string, TextNodeRenderable, or StyledText instance");
18187
+ }
18188
+ this.requestRender();
18189
+ return this;
18190
+ }
18191
+ remove(id) {
18192
+ const childIndex = this.getRenderableIndex(id);
18193
+ if (childIndex === -1) {
18194
+ throw new Error("Child not found in children");
18195
+ }
18196
+ const child = this._children[childIndex];
18197
+ this._children.splice(childIndex, 1);
18198
+ child.parent = null;
18199
+ this.requestRender();
18200
+ return this;
18201
+ }
18202
+ clear() {
18203
+ this._children = [];
18204
+ this.requestRender();
18205
+ }
18206
+ mergeStyles(parentStyle) {
18207
+ return {
18208
+ fg: this._fg ?? parentStyle.fg,
18209
+ bg: this._bg ?? parentStyle.bg,
18210
+ attributes: this._attributes | parentStyle.attributes,
18211
+ link: this._link ?? parentStyle.link
18212
+ };
18213
+ }
18214
+ gatherWithInheritedStyle(parentStyle = {
18215
+ fg: undefined,
18216
+ bg: undefined,
18217
+ attributes: 0
18218
+ }) {
18219
+ const currentStyle = this.mergeStyles(parentStyle);
18220
+ const chunks = [];
18221
+ for (const child of this._children) {
18222
+ if (typeof child === "string") {
18223
+ chunks.push({
18224
+ __isChunk: true,
18225
+ text: child,
18226
+ fg: currentStyle.fg,
18227
+ bg: currentStyle.bg,
18228
+ attributes: currentStyle.attributes,
18229
+ link: currentStyle.link
18230
+ });
18231
+ } else {
18232
+ const childChunks = child.gatherWithInheritedStyle(currentStyle);
18233
+ chunks.push(...childChunks);
18234
+ }
18235
+ }
18236
+ this.markClean();
18237
+ return chunks;
18238
+ }
18239
+ static fromString(text, options = {}) {
18240
+ const node = new TextNodeRenderable(options);
18241
+ node.add(text);
18242
+ return node;
18243
+ }
18244
+ static fromNodes(nodes, options = {}) {
18245
+ const node = new TextNodeRenderable(options);
18246
+ for (const childNode of nodes) {
18247
+ node.add(childNode);
18248
+ }
18249
+ return node;
18250
+ }
18251
+ toChunks(parentStyle = {
18252
+ fg: undefined,
18253
+ bg: undefined,
18254
+ attributes: 0
18255
+ }) {
18256
+ return this.gatherWithInheritedStyle(parentStyle);
18257
+ }
18258
+ getChildren() {
18259
+ return this._children.filter((child) => typeof child !== "string");
18260
+ }
18261
+ getChildrenCount() {
18262
+ return this._children.length;
18263
+ }
18264
+ getRenderable(id) {
18265
+ return this._children.find((child) => typeof child !== "string" && child.id === id);
18266
+ }
18267
+ getRenderableIndex(id) {
18268
+ return this._children.findIndex((child) => isTextNodeRenderable(child) && child.id === id);
18269
+ }
18270
+ get fg() {
18271
+ return this._fg;
18272
+ }
18273
+ set fg(fg2) {
18274
+ if (!fg2) {
18275
+ this._fg = undefined;
18276
+ this.requestRender();
18277
+ return;
18278
+ }
18279
+ this._fg = parseColor(fg2);
18280
+ this.requestRender();
18281
+ }
18282
+ set bg(bg2) {
18283
+ if (!bg2) {
18284
+ this._bg = undefined;
18285
+ this.requestRender();
18286
+ return;
18287
+ }
18288
+ this._bg = parseColor(bg2);
18289
+ this.requestRender();
18290
+ }
18291
+ get bg() {
18292
+ return this._bg;
18293
+ }
18294
+ set attributes(attributes) {
18295
+ this._attributes = attributes;
18296
+ this.requestRender();
18297
+ }
18298
+ get attributes() {
18299
+ return this._attributes;
18300
+ }
18301
+ set link(link2) {
18302
+ this._link = link2;
18303
+ this.requestRender();
18304
+ }
18305
+ get link() {
18306
+ return this._link;
18307
+ }
18308
+ findDescendantById(id) {
18309
+ return;
18310
+ }
18311
+ }
18312
+
18313
+ class RootTextNodeRenderable extends TextNodeRenderable {
18314
+ ctx;
18315
+ textParent;
18316
+ constructor(ctx, options, textParent) {
18317
+ super(options);
18318
+ this.ctx = ctx;
18319
+ this.textParent = textParent;
18320
+ }
18321
+ requestRender() {
18322
+ this.markDirty();
18323
+ this.ctx.requestRender();
18324
+ }
18325
+ }
18326
+
18327
+ // src/renderables/Text.ts
18328
+ class TextRenderable extends TextBufferRenderable {
18329
+ _text;
18330
+ _hasManualStyledText = false;
18331
+ rootTextNode;
18332
+ _contentDefaultOptions = {
18333
+ content: ""
18334
+ };
18335
+ constructor(ctx, options) {
18336
+ super(ctx, options);
18337
+ const content = options.content ?? this._contentDefaultOptions.content;
18338
+ const styledText = typeof content === "string" ? stringToStyledText(content) : content;
18339
+ this._text = styledText;
18340
+ this._hasManualStyledText = options.content !== undefined && content !== "";
18341
+ this.rootTextNode = new RootTextNodeRenderable(ctx, {
18342
+ id: `${this.id}-root`,
18343
+ fg: this._defaultFg,
18344
+ bg: this._defaultBg,
18345
+ attributes: this._defaultAttributes
18346
+ }, this);
18347
+ this.updateTextBuffer(styledText);
18348
+ }
18349
+ updateTextBuffer(styledText) {
18350
+ this.textBuffer.setStyledText(styledText);
18351
+ this.clearChunks(styledText);
18352
+ }
18353
+ clearChunks(styledText) {}
18354
+ get content() {
18355
+ return this._text;
18356
+ }
18357
+ get chunks() {
18358
+ return this._text.chunks;
18359
+ }
18360
+ get textNode() {
18361
+ return this.rootTextNode;
18362
+ }
18363
+ set content(value) {
18364
+ this._hasManualStyledText = true;
18365
+ const styledText = typeof value === "string" ? stringToStyledText(value) : value;
18366
+ if (this._text !== styledText) {
18367
+ this._text = styledText;
18368
+ this.updateTextBuffer(styledText);
18369
+ this.updateTextInfo();
18370
+ }
18371
+ }
18372
+ updateTextFromNodes() {
18373
+ if (this.rootTextNode.isDirty && !this._hasManualStyledText) {
18374
+ const chunks = this.rootTextNode.gatherWithInheritedStyle({
18375
+ fg: this._defaultFg,
18376
+ bg: this._defaultBg,
18377
+ attributes: this._defaultAttributes,
18378
+ link: undefined
18379
+ });
18380
+ this.textBuffer.setStyledText(new StyledText(chunks));
18381
+ this.refreshLocalSelection();
18382
+ this.yogaNode.markDirty();
18383
+ }
18384
+ }
18385
+ add(obj, index) {
18386
+ return this.rootTextNode.add(obj, index);
18387
+ }
18388
+ remove(id) {
18389
+ this.rootTextNode.remove(id);
18390
+ }
18391
+ insertBefore(obj, anchor) {
18392
+ this.rootTextNode.insertBefore(obj, anchor);
18393
+ return this.rootTextNode.children.indexOf(obj);
18394
+ }
18395
+ getTextChildren() {
18396
+ return this.rootTextNode.getChildren();
18397
+ }
18398
+ clear() {
18399
+ this.rootTextNode.clear();
18400
+ const emptyStyledText = stringToStyledText("");
18401
+ this._text = emptyStyledText;
18402
+ this.updateTextBuffer(emptyStyledText);
18403
+ this.updateTextInfo();
18404
+ this.requestRender();
18405
+ }
18406
+ onLifecyclePass = () => {
18407
+ this.updateTextFromNodes();
18408
+ };
18409
+ onFgChanged(newColor) {
18410
+ this.rootTextNode.fg = newColor;
18411
+ }
18412
+ onBgChanged(newColor) {
18413
+ this.rootTextNode.bg = newColor;
18414
+ }
18415
+ onAttributesChanged(newAttributes) {
18416
+ this.rootTextNode.attributes = newAttributes;
18417
+ }
18418
+ destroy() {
18419
+ this.rootTextNode.children.length = 0;
18420
+ super.destroy();
18421
+ }
18422
+ }
18423
+
18424
+ // src/console.ts
18425
+ import { EventEmitter as EventEmitter8 } from "events";
18426
+ import { Console } from "console";
18427
+ import fs from "fs";
18428
+ import path5 from "path";
18429
+ import util2 from "util";
18430
+
18431
+ // src/lib/output.capture.ts
18432
+ import { Writable } from "stream";
18433
+ import { EventEmitter as EventEmitter7 } from "events";
18434
+
18435
+ class Capture extends EventEmitter7 {
18436
+ output = [];
18437
+ constructor() {
18438
+ super();
18439
+ }
18440
+ get size() {
18441
+ return this.output.length;
18442
+ }
18443
+ write(stream, data) {
18444
+ this.output.push({ stream, output: data });
18445
+ this.emit("write", stream, data);
18446
+ }
18447
+ claimOutput() {
18448
+ const output = this.output.map((o) => o.output).join("");
18449
+ this.clear();
18450
+ return output;
18451
+ }
18452
+ clear() {
18453
+ this.output = [];
18454
+ }
18455
+ }
18456
+
18457
+ class CapturedWritableStream extends Writable {
18458
+ stream;
18459
+ capture;
18460
+ isTTY = true;
18461
+ columns = process.stdout.columns || 80;
18462
+ rows = process.stdout.rows || 24;
18463
+ constructor(stream, capture) {
18464
+ super();
18465
+ this.stream = stream;
18466
+ this.capture = capture;
18467
+ }
18468
+ _write(chunk, encoding, callback) {
18469
+ const data = chunk.toString();
18470
+ this.capture.write(this.stream, data);
18471
+ callback();
16606
18472
  }
16607
18473
  getColorDepth() {
16608
18474
  return process.stdout.getColorDepth?.() || 8;
@@ -18734,6 +20600,27 @@ function getObjectsInViewport(viewport, objects, direction = "column", padding =
18734
20600
  return visibleChildren;
18735
20601
  }
18736
20602
 
20603
+ // src/lib/render-geometry.ts
20604
+ function calculateRenderGeometry(screenMode, terminalWidth, terminalHeight, footerHeight) {
20605
+ const safeTerminalWidth = Math.max(terminalWidth, 0);
20606
+ const safeTerminalHeight = Math.max(terminalHeight, 0);
20607
+ if (screenMode !== "split-footer") {
20608
+ return {
20609
+ effectiveFooterHeight: 0,
20610
+ renderOffset: 0,
20611
+ renderWidth: safeTerminalWidth,
20612
+ renderHeight: safeTerminalHeight
20613
+ };
20614
+ }
20615
+ const effectiveFooterHeight = Math.min(footerHeight, safeTerminalHeight);
20616
+ return {
20617
+ effectiveFooterHeight,
20618
+ renderOffset: safeTerminalHeight - effectiveFooterHeight,
20619
+ renderWidth: safeTerminalWidth,
20620
+ renderHeight: effectiveFooterHeight
20621
+ };
20622
+ }
20623
+
18737
20624
  // src/lib/terminal-capability-detection.ts
18738
20625
  function isCapabilityResponse(sequence) {
18739
20626
  if (/\x1b\[\?\d+(?:;\d+)*\$y/.test(sequence)) {
@@ -18767,30 +20654,155 @@ function parsePixelResolution(sequence) {
18767
20654
  height: parseInt(match[1])
18768
20655
  };
18769
20656
  }
18770
- return null;
20657
+ return null;
20658
+ }
20659
+
20660
+ // src/renderer-theme-mode.ts
20661
+ var OSC_THEME_RESPONSE = /\x1b](10|11);(?:(?:rgb:)([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)|#([0-9a-fA-F]{6}))(?:\x07|\x1b\\)/g;
20662
+ function scaleOscThemeComponent(component) {
20663
+ const value = parseInt(component, 16);
20664
+ const maxValue = (1 << 4 * component.length) - 1;
20665
+ return Math.round(value / maxValue * 255).toString(16).padStart(2, "0");
20666
+ }
20667
+ function oscThemeColorToHex(r, g, b, hex6) {
20668
+ if (hex6) {
20669
+ return `#${hex6.toLowerCase()}`;
20670
+ }
20671
+ if (r && g && b) {
20672
+ return `#${scaleOscThemeComponent(r)}${scaleOscThemeComponent(g)}${scaleOscThemeComponent(b)}`;
20673
+ }
20674
+ return "#000000";
20675
+ }
20676
+ function inferThemeModeFromBackgroundColor(color) {
20677
+ const [r, g, b] = parseColor(color).toInts();
20678
+ const brightness = (r * 299 + g * 587 + b * 114) / 1000;
20679
+ return brightness > 128 ? "light" : "dark";
20680
+ }
20681
+
20682
+ class RendererThemeMode {
20683
+ host;
20684
+ clock;
20685
+ static QUERY_TIMEOUT_MS = 250;
20686
+ _themeMode = null;
20687
+ themeQueryPending = true;
20688
+ themeOscForeground = null;
20689
+ themeOscBackground = null;
20690
+ themeRefreshTimeoutId = null;
20691
+ waiters = new Set;
20692
+ constructor(host, clock2) {
20693
+ this.host = host;
20694
+ this.clock = clock2;
20695
+ }
20696
+ get themeMode() {
20697
+ return this._themeMode;
20698
+ }
20699
+ waitForThemeMode(timeoutMs, isDestroyed) {
20700
+ if (this._themeMode !== null || isDestroyed || timeoutMs === 0) {
20701
+ return Promise.resolve(this._themeMode);
20702
+ }
20703
+ return new Promise((resolve4) => {
20704
+ const waiter = {
20705
+ resolve: resolve4,
20706
+ timeoutHandle: null
20707
+ };
20708
+ if (timeoutMs > 0) {
20709
+ waiter.timeoutHandle = this.clock.setTimeout(() => {
20710
+ this.waiters.delete(waiter);
20711
+ waiter.timeoutHandle = null;
20712
+ resolve4(this._themeMode);
20713
+ }, timeoutMs);
20714
+ }
20715
+ this.waiters.add(waiter);
20716
+ });
20717
+ }
20718
+ cancelRefresh() {
20719
+ if (this.themeRefreshTimeoutId === null) {
20720
+ return;
20721
+ }
20722
+ this.clock.clearTimeout(this.themeRefreshTimeoutId);
20723
+ this.themeRefreshTimeoutId = null;
20724
+ this.themeQueryPending = false;
20725
+ }
20726
+ dispose() {
20727
+ this.cancelRefresh();
20728
+ for (const waiter of this.waiters) {
20729
+ if (waiter.timeoutHandle !== null) {
20730
+ this.clock.clearTimeout(waiter.timeoutHandle);
20731
+ }
20732
+ waiter.resolve(this._themeMode);
20733
+ }
20734
+ this.waiters.clear();
20735
+ }
20736
+ handleSequence(sequence) {
20737
+ if (sequence === "\x1B[?997;1n" || sequence === "\x1B[?997;2n") {
20738
+ this.requestThemeOscColors();
20739
+ return { handled: true, changedMode: null };
20740
+ }
20741
+ let handledOscThemeResponse = false;
20742
+ let match;
20743
+ OSC_THEME_RESPONSE.lastIndex = 0;
20744
+ while (match = OSC_THEME_RESPONSE.exec(sequence)) {
20745
+ handledOscThemeResponse = true;
20746
+ const color = oscThemeColorToHex(match[2], match[3], match[4], match[5]);
20747
+ if (match[1] === "10") {
20748
+ this.themeOscForeground = color;
20749
+ } else {
20750
+ this.themeOscBackground = color;
20751
+ }
20752
+ }
20753
+ if (!handledOscThemeResponse) {
20754
+ return { handled: false, changedMode: null };
20755
+ }
20756
+ if (!this.themeQueryPending) {
20757
+ return { handled: true, changedMode: null };
20758
+ }
20759
+ if (!this.themeOscForeground || !this.themeOscBackground) {
20760
+ return { handled: true, changedMode: null };
20761
+ }
20762
+ const nextMode = inferThemeModeFromBackgroundColor(this.themeOscBackground);
20763
+ const changedMode = this.applyThemeMode(nextMode);
20764
+ this.completeThemeQuery();
20765
+ return { handled: true, changedMode };
20766
+ }
20767
+ clearThemeRefreshTimeout() {
20768
+ if (this.themeRefreshTimeoutId === null) {
20769
+ return;
20770
+ }
20771
+ this.clock.clearTimeout(this.themeRefreshTimeoutId);
20772
+ this.themeRefreshTimeoutId = null;
20773
+ }
20774
+ completeThemeQuery() {
20775
+ this.clearThemeRefreshTimeout();
20776
+ this.themeQueryPending = false;
20777
+ }
20778
+ requestThemeOscColors() {
20779
+ this.themeQueryPending = true;
20780
+ this.themeOscForeground = null;
20781
+ this.themeOscBackground = null;
20782
+ this.host.queryThemeColors();
20783
+ this.clearThemeRefreshTimeout();
20784
+ this.themeRefreshTimeoutId = this.clock.setTimeout(() => {
20785
+ this.completeThemeQuery();
20786
+ }, RendererThemeMode.QUERY_TIMEOUT_MS);
20787
+ }
20788
+ applyThemeMode(mode) {
20789
+ const changed = this._themeMode !== mode;
20790
+ this._themeMode = mode;
20791
+ if (!changed) {
20792
+ return null;
20793
+ }
20794
+ for (const waiter of this.waiters) {
20795
+ if (waiter.timeoutHandle !== null) {
20796
+ this.clock.clearTimeout(waiter.timeoutHandle);
20797
+ }
20798
+ waiter.resolve(mode);
20799
+ }
20800
+ this.waiters.clear();
20801
+ return mode;
20802
+ }
18771
20803
  }
18772
20804
 
18773
20805
  // src/renderer.ts
18774
- var OSC_THEME_RESPONSE = /\x1b](10|11);(?:(?:rgb:)([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)|#([0-9a-fA-F]{6}))(?:\x07|\x1b\\)/g;
18775
- function scaleOscThemeComponent(component) {
18776
- const value = parseInt(component, 16);
18777
- const maxValue = (1 << 4 * component.length) - 1;
18778
- return Math.round(value / maxValue * 255).toString(16).padStart(2, "0");
18779
- }
18780
- function oscThemeColorToHex(r, g, b, hex6) {
18781
- if (hex6) {
18782
- return `#${hex6.toLowerCase()}`;
18783
- }
18784
- if (r && g && b) {
18785
- return `#${scaleOscThemeComponent(r)}${scaleOscThemeComponent(g)}${scaleOscThemeComponent(b)}`;
18786
- }
18787
- return "#000000";
18788
- }
18789
- function inferThemeModeFromBackgroundColor(color) {
18790
- const [r, g, b] = parseColor(color).toInts();
18791
- const brightness = (r * 299 + g * 587 + b * 114) / 1000;
18792
- return brightness > 128 ? "light" : "dark";
18793
- }
18794
20806
  registerEnvVar({
18795
20807
  name: "OTUI_DUMP_CAPTURES",
18796
20808
  description: "Dump captured stdout and console caches when the renderer exit handler runs.",
@@ -18828,6 +20840,9 @@ registerEnvVar({
18828
20840
  default: false
18829
20841
  });
18830
20842
  var DEFAULT_FOOTER_HEIGHT = 12;
20843
+ var MAX_SCROLLBACK_SURFACE_HEIGHT_PASSES = 4;
20844
+ var TRANSPARENT_RGBA = RGBA.fromValues(0, 0, 0, 0);
20845
+ var scrollbackSurfaceCounter = 0;
18831
20846
  function normalizeFooterHeight(footerHeight) {
18832
20847
  if (footerHeight === undefined) {
18833
20848
  return DEFAULT_FOOTER_HEIGHT;
@@ -18860,6 +20875,101 @@ function resolveModes(config) {
18860
20875
  externalOutputMode
18861
20876
  };
18862
20877
  }
20878
+
20879
+ class ExternalOutputQueue {
20880
+ commits = [];
20881
+ get size() {
20882
+ return this.commits.length;
20883
+ }
20884
+ writeSnapshot(commit) {
20885
+ this.commits.push(commit);
20886
+ }
20887
+ claim(limit = Number.POSITIVE_INFINITY) {
20888
+ if (this.commits.length === 0) {
20889
+ return [];
20890
+ }
20891
+ const clampedLimit = Number.isFinite(limit) ? Math.max(1, Math.trunc(limit)) : this.commits.length;
20892
+ if (clampedLimit >= this.commits.length) {
20893
+ const output2 = this.commits;
20894
+ this.commits = [];
20895
+ return output2;
20896
+ }
20897
+ const output = this.commits.slice(0, clampedLimit);
20898
+ this.commits = this.commits.slice(clampedLimit);
20899
+ return output;
20900
+ }
20901
+ clear() {
20902
+ for (const commit of this.commits) {
20903
+ commit.snapshot.destroy();
20904
+ }
20905
+ this.commits = [];
20906
+ }
20907
+ }
20908
+ var CHAR_FLAG_CONTINUATION = 3221225472 >>> 0;
20909
+ var CHAR_FLAG_MASK = 3221225472 >>> 0;
20910
+
20911
+ class ScrollbackSnapshotRenderContext extends EventEmitter9 {
20912
+ width;
20913
+ height;
20914
+ frameId = 0;
20915
+ widthMethod;
20916
+ capabilities = null;
20917
+ hasSelection = false;
20918
+ currentFocusedRenderable = null;
20919
+ keyInput;
20920
+ _internalKeyInput;
20921
+ lifecyclePasses = new Set;
20922
+ constructor(width, height, widthMethod) {
20923
+ super();
20924
+ this.width = width;
20925
+ this.height = height;
20926
+ this.widthMethod = widthMethod;
20927
+ this.keyInput = new KeyHandler;
20928
+ this._internalKeyInput = new InternalKeyHandler;
20929
+ }
20930
+ addToHitGrid(_x, _y, _width, _height, _id) {}
20931
+ pushHitGridScissorRect(_x, _y, _width, _height) {}
20932
+ popHitGridScissorRect() {}
20933
+ clearHitGridScissorRects() {}
20934
+ requestRender() {}
20935
+ setCursorPosition(_x, _y, _visible) {}
20936
+ setCursorStyle(_options) {}
20937
+ setCursorColor(_color) {}
20938
+ setMousePointer(_shape) {}
20939
+ requestLive() {}
20940
+ dropLive() {}
20941
+ getSelection() {
20942
+ return null;
20943
+ }
20944
+ get currentFocusedEditor() {
20945
+ if (!this.currentFocusedRenderable)
20946
+ return null;
20947
+ if (!isEditBufferRenderable(this.currentFocusedRenderable))
20948
+ return null;
20949
+ return this.currentFocusedRenderable;
20950
+ }
20951
+ requestSelectionUpdate() {}
20952
+ focusRenderable(renderable) {
20953
+ this.currentFocusedRenderable = renderable;
20954
+ }
20955
+ blurRenderable(renderable) {
20956
+ if (this.currentFocusedRenderable === renderable) {
20957
+ this.currentFocusedRenderable = null;
20958
+ }
20959
+ }
20960
+ registerLifecyclePass(renderable) {
20961
+ this.lifecyclePasses.add(renderable);
20962
+ }
20963
+ unregisterLifecyclePass(renderable) {
20964
+ this.lifecyclePasses.delete(renderable);
20965
+ }
20966
+ getLifecyclePasses() {
20967
+ return this.lifecyclePasses;
20968
+ }
20969
+ clearSelection() {}
20970
+ startSelection(_renderable, _x, _y) {}
20971
+ updateSelection(_currentRenderable, _x, _y, _options) {}
20972
+ }
18863
20973
  var DEFAULT_FORWARDED_ENV_KEYS = [
18864
20974
  "TMUX",
18865
20975
  "TERM",
@@ -18980,9 +21090,9 @@ async function createCliRenderer(config = {}) {
18980
21090
  const { screenMode, footerHeight } = resolveModes(config);
18981
21091
  const width = stdout.columns || 80;
18982
21092
  const height = stdout.rows || 24;
18983
- const renderHeight = screenMode === "split-footer" ? footerHeight : height;
21093
+ const geometry = calculateRenderGeometry(screenMode, width, height, footerHeight);
18984
21094
  const ziglib = resolveRenderLib();
18985
- const rendererPtr = ziglib.createRenderer(width, renderHeight, {
21095
+ const rendererPtr = ziglib.createRenderer(geometry.renderWidth, geometry.renderHeight, {
18986
21096
  remote: config.remote ?? false,
18987
21097
  testing: config.testing ?? false
18988
21098
  });
@@ -19099,6 +21209,8 @@ class CliRenderer extends EventEmitter9 {
19099
21209
  animationRequest = new Map;
19100
21210
  resizeTimeoutId = null;
19101
21211
  capabilityTimeoutId = null;
21212
+ splitStartupSeedTimeoutId = null;
21213
+ pendingSplitStartupCursorSeed = false;
19102
21214
  resizeDebounceDelay = 100;
19103
21215
  enableMouseMovement = false;
19104
21216
  _useMouse = true;
@@ -19106,6 +21218,7 @@ class CliRenderer extends EventEmitter9 {
19106
21218
  _screenMode = "alternate-screen";
19107
21219
  _footerHeight = DEFAULT_FOOTER_HEIGHT;
19108
21220
  _externalOutputMode = "passthrough";
21221
+ clearOnShutdown = true;
19109
21222
  _suspendedMouseEnabled = false;
19110
21223
  _previousControlState = "idle" /* IDLE */;
19111
21224
  capturedRenderable;
@@ -19116,15 +21229,15 @@ class CliRenderer extends EventEmitter9 {
19116
21229
  clipboard;
19117
21230
  _splitHeight = 0;
19118
21231
  renderOffset = 0;
21232
+ splitTailColumn = 0;
21233
+ pendingSplitFooterTransition = null;
21234
+ forceFullRepaintRequested = false;
21235
+ maxSplitCommitsPerFrame = 8;
19119
21236
  _terminalWidth = 0;
19120
21237
  _terminalHeight = 0;
19121
21238
  _terminalIsSetup = false;
21239
+ externalOutputQueue = new ExternalOutputQueue;
19122
21240
  realStdoutWrite;
19123
- captureCallback = () => {
19124
- if (this._splitHeight > 0) {
19125
- this.requestRender();
19126
- }
19127
- };
19128
21241
  _useConsole = true;
19129
21242
  sigwinchHandler = (() => {
19130
21243
  const width = this.stdout.columns || 80;
@@ -19144,18 +21257,20 @@ class CliRenderer extends EventEmitter9 {
19144
21257
  lifecyclePasses = new Set;
19145
21258
  _openConsoleOnError = true;
19146
21259
  _paletteDetector = null;
21260
+ _paletteCache = new Map;
19147
21261
  _cachedPalette = null;
19148
21262
  _paletteDetectionPromise = null;
21263
+ _paletteDetectionSize = 0;
21264
+ _paletteEpoch = 0;
21265
+ _publishedPaletteSignature = null;
21266
+ _palettePublishGeneration = 0;
19149
21267
  _onDestroy;
19150
- _themeMode = null;
19151
- _themeModeSource = "none";
19152
- _themeFallbackPending = true;
19153
- _themeOscForeground = null;
19154
- _themeOscBackground = null;
21268
+ themeModeState;
19155
21269
  _terminalFocusState = null;
19156
21270
  sequenceHandlers = [];
19157
21271
  prependedInputHandlers = [];
19158
21272
  shouldRestoreModesOnNextFocus = false;
21273
+ themeModeHandler;
19159
21274
  idleResolvers = [];
19160
21275
  _debugInputs = [];
19161
21276
  _debugModeEnabled = env.OTUI_DEBUG;
@@ -19167,8 +21282,15 @@ class CliRenderer extends EventEmitter9 {
19167
21282
  }).bind(this);
19168
21283
  dumpOutputCache(optionalMessage = "") {
19169
21284
  const cachedLogs = this.console.getCachedLogs();
19170
- const capturedOutput = capture.claimOutput();
19171
- if (capturedOutput.length > 0 || cachedLogs.length > 0) {
21285
+ const capturedConsoleOutput = capture.claimOutput();
21286
+ const capturedExternalOutputCommits = this.externalOutputQueue.claim();
21287
+ let capturedExternalOutput = "";
21288
+ for (const commit of capturedExternalOutputCommits) {
21289
+ capturedExternalOutput += `[snapshot ${commit.snapshot.width}x${commit.snapshot.height}]
21290
+ `;
21291
+ commit.snapshot.destroy();
21292
+ }
21293
+ if (capturedConsoleOutput.length > 0 || capturedExternalOutput.length > 0 || cachedLogs.length > 0) {
19172
21294
  this.realStdoutWrite.call(this.stdout, optionalMessage);
19173
21295
  }
19174
21296
  if (cachedLogs.length > 0) {
@@ -19176,11 +21298,18 @@ class CliRenderer extends EventEmitter9 {
19176
21298
  `);
19177
21299
  this.realStdoutWrite.call(this.stdout, cachedLogs);
19178
21300
  }
19179
- if (capturedOutput.length > 0) {
21301
+ if (capturedConsoleOutput.length > 0) {
21302
+ this.realStdoutWrite.call(this.stdout, `
21303
+ Captured console output:
21304
+ `);
21305
+ this.realStdoutWrite.call(this.stdout, capturedConsoleOutput + `
21306
+ `);
21307
+ }
21308
+ if (capturedExternalOutput.length > 0) {
19180
21309
  this.realStdoutWrite.call(this.stdout, `
19181
- Captured output:
21310
+ Captured external output:
19182
21311
  `);
19183
- this.realStdoutWrite.call(this.stdout, capturedOutput + `
21312
+ this.realStdoutWrite.call(this.stdout, capturedExternalOutput + `
19184
21313
  `);
19185
21314
  }
19186
21315
  this.realStdoutWrite.call(this.stdout, ANSI.reset);
@@ -19209,14 +21338,19 @@ Captured output:
19209
21338
  this.lib = lib;
19210
21339
  this._terminalWidth = stdout.columns ?? width;
19211
21340
  this._terminalHeight = stdout.rows ?? height;
19212
- this.width = width;
19213
- this.height = height;
19214
21341
  this._useThread = config.useThread === undefined ? false : config.useThread;
19215
21342
  const { screenMode, footerHeight, externalOutputMode } = resolveModes(config);
21343
+ this._externalOutputMode = externalOutputMode;
21344
+ const initialGeometry = calculateRenderGeometry(screenMode, this._terminalWidth, this._terminalHeight, footerHeight);
21345
+ this.width = initialGeometry.renderWidth;
21346
+ this.height = initialGeometry.renderHeight;
21347
+ this._splitHeight = initialGeometry.effectiveFooterHeight;
21348
+ this.renderOffset = screenMode === "split-footer" ? 0 : initialGeometry.renderOffset;
19216
21349
  this._footerHeight = footerHeight;
19217
- this._screenMode = screenMode;
19218
21350
  this.rendererPtr = rendererPtr;
19219
- const forwardEnvKeys = config.forwardEnvKeys ?? [...DEFAULT_FORWARDED_ENV_KEYS];
21351
+ this.clearOnShutdown = config.clearOnShutdown ?? true;
21352
+ this.lib.setClearOnShutdown(this.rendererPtr, this.clearOnShutdown);
21353
+ const forwardEnvKeys = config.forwardEnvKeys ?? (config.remote ? [] : [...DEFAULT_FORWARDED_ENV_KEYS]);
19220
21354
  for (const key of forwardEnvKeys) {
19221
21355
  const value = process.env[key];
19222
21356
  if (value === undefined)
@@ -19239,6 +21373,18 @@ Captured output:
19239
21373
  this.targetFps = config.targetFps || 30;
19240
21374
  this.maxFps = config.maxFps || 60;
19241
21375
  this.clock = config.clock ?? new SystemClock;
21376
+ this.themeModeState = new RendererThemeMode({
21377
+ queryThemeColors: () => {
21378
+ this.lib.queryThemeColors(this.rendererPtr);
21379
+ }
21380
+ }, this.clock);
21381
+ this.themeModeHandler = (sequence) => {
21382
+ const result = this.themeModeState.handleSequence(sequence);
21383
+ if (result.changedMode) {
21384
+ this.emit("theme_mode" /* THEME_MODE */, result.changedMode);
21385
+ }
21386
+ return result.handled;
21387
+ };
19242
21388
  this.memorySnapshotInterval = config.memorySnapshotInterval ?? 0;
19243
21389
  this.gatherStats = config.gatherStats || false;
19244
21390
  this.maxStatSamples = config.maxStatSamples || 300;
@@ -19283,7 +21429,8 @@ Captured output:
19283
21429
  kittyKeyboardEnabled: useKittyForParsing,
19284
21430
  privateCapabilityRepliesActive: false,
19285
21431
  pixelResolutionQueryActive: false,
19286
- explicitWidthCprActive: false
21432
+ explicitWidthCprActive: false,
21433
+ startupCursorCprActive: false
19287
21434
  },
19288
21435
  clock: this.clock
19289
21436
  });
@@ -19293,7 +21440,7 @@ Captured output:
19293
21440
  });
19294
21441
  this.consoleMode = config.consoleMode ?? "console-overlay";
19295
21442
  this.applyScreenMode(screenMode, false, false);
19296
- this.externalOutputMode = externalOutputMode;
21443
+ this.stdout.write = externalOutputMode === "capture-stdout" ? this.interceptStdoutWrite : this.realStdoutWrite;
19297
21444
  this._openConsoleOnError = config.openConsoleOnError ?? true;
19298
21445
  this._onDestroy = config.onDestroy;
19299
21446
  global.requestAnimationFrame = (callback) => {
@@ -19520,127 +21667,701 @@ Captured output:
19520
21667
  this._targetFps = targetFps;
19521
21668
  this.targetFrameTime = 1000 / this._targetFps;
19522
21669
  }
19523
- get maxFps() {
19524
- return this._maxFps;
21670
+ get maxFps() {
21671
+ return this._maxFps;
21672
+ }
21673
+ set maxFps(maxFps) {
21674
+ this._maxFps = maxFps;
21675
+ this.minTargetFrameTime = 1000 / this._maxFps;
21676
+ }
21677
+ get useMouse() {
21678
+ return this._useMouse;
21679
+ }
21680
+ set useMouse(useMouse) {
21681
+ if (this._useMouse === useMouse)
21682
+ return;
21683
+ this._useMouse = useMouse;
21684
+ if (useMouse) {
21685
+ this.enableMouse();
21686
+ } else {
21687
+ this.disableMouse();
21688
+ }
21689
+ }
21690
+ get screenMode() {
21691
+ return this._screenMode;
21692
+ }
21693
+ set screenMode(mode) {
21694
+ if (this.externalOutputMode === "capture-stdout" && mode !== "split-footer") {
21695
+ throw new Error('externalOutputMode "capture-stdout" requires screenMode "split-footer"');
21696
+ }
21697
+ this.applyScreenMode(mode);
21698
+ }
21699
+ get footerHeight() {
21700
+ return this._footerHeight;
21701
+ }
21702
+ set footerHeight(footerHeight) {
21703
+ const normalizedFooterHeight = normalizeFooterHeight(footerHeight);
21704
+ if (normalizedFooterHeight === this._footerHeight) {
21705
+ return;
21706
+ }
21707
+ this._footerHeight = normalizedFooterHeight;
21708
+ if (this.screenMode === "split-footer") {
21709
+ this.applyScreenMode("split-footer");
21710
+ }
21711
+ }
21712
+ get externalOutputMode() {
21713
+ return this._externalOutputMode;
21714
+ }
21715
+ set externalOutputMode(mode) {
21716
+ if (mode === "capture-stdout" && this.screenMode !== "split-footer") {
21717
+ throw new Error('externalOutputMode "capture-stdout" requires screenMode "split-footer"');
21718
+ }
21719
+ const previousMode = this._externalOutputMode;
21720
+ if (previousMode === mode) {
21721
+ return;
21722
+ }
21723
+ if (previousMode === "capture-stdout" && mode === "passthrough" && this._splitHeight > 0) {
21724
+ this.flushPendingSplitOutputBeforeTransition();
21725
+ }
21726
+ this._externalOutputMode = mode;
21727
+ this.stdout.write = mode === "capture-stdout" ? this.interceptStdoutWrite : this.realStdoutWrite;
21728
+ if (this._screenMode === "split-footer" && this._splitHeight > 0 && mode === "capture-stdout") {
21729
+ this.clearPendingSplitFooterTransition();
21730
+ this.resetSplitScrollback(this.getSplitCursorSeedRows());
21731
+ return;
21732
+ }
21733
+ if (this._screenMode === "split-footer" && this._splitHeight > 0 && previousMode === "capture-stdout" && mode === "passthrough") {
21734
+ this.clearPendingSplitFooterTransition();
21735
+ return;
21736
+ }
21737
+ this.syncSplitFooterState();
21738
+ }
21739
+ get liveRequestCount() {
21740
+ return this.liveRequestCounter;
21741
+ }
21742
+ get currentControlState() {
21743
+ return this._controlState;
21744
+ }
21745
+ get capabilities() {
21746
+ return this._capabilities;
21747
+ }
21748
+ get themeMode() {
21749
+ return this.themeModeState.themeMode;
21750
+ }
21751
+ waitForThemeMode(timeoutMs = 1000) {
21752
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
21753
+ throw new Error("timeoutMs must be a non-negative finite number");
21754
+ }
21755
+ return this.themeModeState.waitForThemeMode(timeoutMs, this._isDestroyed);
21756
+ }
21757
+ getDebugInputs() {
21758
+ return [...this._debugInputs];
21759
+ }
21760
+ get useKittyKeyboard() {
21761
+ return this.lib.getKittyKeyboardFlags(this.rendererPtr) > 0;
21762
+ }
21763
+ set useKittyKeyboard(use) {
21764
+ const flags = use ? KITTY_FLAG_DISAMBIGUATE | KITTY_FLAG_ALTERNATE_KEYS : 0;
21765
+ this.lib.setKittyKeyboardFlags(this.rendererPtr, flags);
21766
+ }
21767
+ createScrollbackSurface(options = {}) {
21768
+ if (this._screenMode !== "split-footer" || this._externalOutputMode !== "capture-stdout") {
21769
+ throw new Error('createScrollbackSurface requires screenMode "split-footer" and externalOutputMode "capture-stdout"');
21770
+ }
21771
+ const renderer = this;
21772
+ const surfaceId = scrollbackSurfaceCounter++;
21773
+ const startOnNewLine = options.startOnNewLine ?? true;
21774
+ const firstLineOffset = !startOnNewLine && renderer.splitTailColumn > 0 && renderer.splitTailColumn < renderer.width ? renderer.splitTailColumn : 0;
21775
+ const snapshotContext = new ScrollbackSnapshotRenderContext(renderer.width, 1, renderer.widthMethod);
21776
+ let firstLineOffsetOwner = null;
21777
+ const renderContext = Object.create(snapshotContext);
21778
+ Object.defineProperty(renderContext, "claimFirstLineOffset", {
21779
+ value: (renderable) => {
21780
+ if (firstLineOffsetOwner?.isDestroyed) {
21781
+ firstLineOffsetOwner = null;
21782
+ }
21783
+ if (firstLineOffsetOwner) {
21784
+ return 0;
21785
+ }
21786
+ firstLineOffsetOwner = renderable ?? null;
21787
+ return firstLineOffset;
21788
+ },
21789
+ enumerable: true,
21790
+ configurable: true
21791
+ });
21792
+ const internalRoot = new RootRenderable(renderContext);
21793
+ const publicRoot = new BoxRenderable(renderContext, {
21794
+ id: `scrollback-surface-root-${surfaceId}`,
21795
+ position: "absolute",
21796
+ left: 0,
21797
+ top: 0,
21798
+ width: renderer.width,
21799
+ height: "auto",
21800
+ border: false,
21801
+ backgroundColor: "transparent",
21802
+ shouldFill: false,
21803
+ flexDirection: "column"
21804
+ });
21805
+ internalRoot.add(publicRoot);
21806
+ let surfaceWidth = renderer.width;
21807
+ let surfaceHeight = 1;
21808
+ let surfaceWidthMethod = renderer.widthMethod;
21809
+ let surfaceDestroyed = false;
21810
+ let hasRendered = false;
21811
+ let nextCommitStartOnNewLine = startOnNewLine;
21812
+ let backingBuffer = OptimizedBuffer.create(surfaceWidth, surfaceHeight, surfaceWidthMethod, {
21813
+ id: `scrollback-surface-buffer-${surfaceId}`
21814
+ });
21815
+ const destroyListener = () => {
21816
+ destroySurface();
21817
+ };
21818
+ const assertNotDestroyed = () => {
21819
+ if (surfaceDestroyed) {
21820
+ throw new Error("ScrollbackSurface is destroyed");
21821
+ }
21822
+ };
21823
+ const assertRendered = () => {
21824
+ if (!hasRendered) {
21825
+ throw new Error("ScrollbackSurface.commitRows requires render() before commitRows()");
21826
+ }
21827
+ };
21828
+ const assertGeometryStillCurrent = () => {
21829
+ if (renderer.width !== surfaceWidth || renderer.widthMethod !== surfaceWidthMethod) {
21830
+ throw new Error("ScrollbackSurface.commitRows requires render() after renderer geometry changes");
21831
+ }
21832
+ };
21833
+ const assertRowRange = (startRow, endRowExclusive) => {
21834
+ if (!Number.isInteger(startRow) || !Number.isInteger(endRowExclusive)) {
21835
+ throw new Error("ScrollbackSurface.commitRows requires finite integer row bounds");
21836
+ }
21837
+ if (startRow < 0) {
21838
+ throw new Error("ScrollbackSurface.commitRows requires startRow >= 0");
21839
+ }
21840
+ if (endRowExclusive < startRow) {
21841
+ throw new Error("ScrollbackSurface.commitRows requires endRowExclusive >= startRow");
21842
+ }
21843
+ if (endRowExclusive > surfaceHeight) {
21844
+ throw new Error("ScrollbackSurface.commitRows row range exceeds rendered surface height");
21845
+ }
21846
+ };
21847
+ const collectPendingCodeRenderables = (node) => {
21848
+ const pending = [];
21849
+ if (node instanceof CodeRenderable && node.isHighlighting) {
21850
+ pending.push(node);
21851
+ }
21852
+ for (const child of node.getChildren()) {
21853
+ pending.push(...collectPendingCodeRenderables(child));
21854
+ }
21855
+ return pending;
21856
+ };
21857
+ const waitForPendingHighlights = async (pending, timeoutMs) => {
21858
+ await new Promise((resolve4, reject) => {
21859
+ let settled = false;
21860
+ const timeoutHandle = renderer.clock.setTimeout(() => {
21861
+ if (settled) {
21862
+ return;
21863
+ }
21864
+ settled = true;
21865
+ reject(new Error("ScrollbackSurface.settle timed out waiting for CodeRenderable highlighting"));
21866
+ }, timeoutMs);
21867
+ Promise.all(pending.map((renderable) => renderable.highlightingDone)).then(() => {
21868
+ if (settled) {
21869
+ return;
21870
+ }
21871
+ settled = true;
21872
+ renderer.clock.clearTimeout(timeoutHandle);
21873
+ resolve4();
21874
+ }, (error) => {
21875
+ if (settled) {
21876
+ return;
21877
+ }
21878
+ settled = true;
21879
+ renderer.clock.clearTimeout(timeoutHandle);
21880
+ reject(error);
21881
+ });
21882
+ });
21883
+ };
21884
+ const renderSurface = () => {
21885
+ assertNotDestroyed();
21886
+ const width = renderer.width;
21887
+ const widthMethod = renderer.widthMethod;
21888
+ snapshotContext.width = width;
21889
+ snapshotContext.widthMethod = widthMethod;
21890
+ publicRoot.width = width;
21891
+ const renderPass = (height) => {
21892
+ snapshotContext.height = height;
21893
+ internalRoot.resize(width, height);
21894
+ backingBuffer.resize(width, height);
21895
+ backingBuffer.clear(TRANSPARENT_RGBA);
21896
+ snapshotContext.frameId += 1;
21897
+ internalRoot.render(backingBuffer, 0);
21898
+ };
21899
+ let targetHeight = Math.max(1, surfaceHeight);
21900
+ if (surfaceWidthMethod !== widthMethod) {
21901
+ backingBuffer.destroy();
21902
+ backingBuffer = OptimizedBuffer.create(width, targetHeight, widthMethod, {
21903
+ id: `scrollback-surface-buffer-${surfaceId}`
21904
+ });
21905
+ } else {
21906
+ backingBuffer.resize(width, targetHeight);
21907
+ }
21908
+ for (let pass = 0;pass < MAX_SCROLLBACK_SURFACE_HEIGHT_PASSES; pass += 1) {
21909
+ renderPass(targetHeight);
21910
+ const measuredHeight = Math.max(1, publicRoot.height);
21911
+ if (measuredHeight === targetHeight) {
21912
+ surfaceWidth = width;
21913
+ surfaceHeight = measuredHeight;
21914
+ surfaceWidthMethod = widthMethod;
21915
+ hasRendered = true;
21916
+ return;
21917
+ }
21918
+ targetHeight = measuredHeight;
21919
+ }
21920
+ renderPass(targetHeight);
21921
+ surfaceWidth = width;
21922
+ surfaceHeight = targetHeight;
21923
+ surfaceWidthMethod = widthMethod;
21924
+ hasRendered = true;
21925
+ };
21926
+ const settleSurface = async (timeoutMs = 2000) => {
21927
+ assertNotDestroyed();
21928
+ const startedAt = renderer.clock.now();
21929
+ renderSurface();
21930
+ while (true) {
21931
+ assertNotDestroyed();
21932
+ const pending = collectPendingCodeRenderables(publicRoot);
21933
+ if (pending.length === 0) {
21934
+ return;
21935
+ }
21936
+ const remainingMs = timeoutMs - (renderer.clock.now() - startedAt);
21937
+ if (remainingMs <= 0) {
21938
+ throw new Error("ScrollbackSurface.settle timed out waiting for CodeRenderable highlighting");
21939
+ }
21940
+ await waitForPendingHighlights(pending, remainingMs);
21941
+ assertNotDestroyed();
21942
+ renderSurface();
21943
+ }
21944
+ };
21945
+ const commitRows = (startRow, endRowExclusive, commitOptions = {}) => {
21946
+ assertNotDestroyed();
21947
+ assertRendered();
21948
+ assertGeometryStillCurrent();
21949
+ assertRowRange(startRow, endRowExclusive);
21950
+ if (startRow === endRowExclusive) {
21951
+ return;
21952
+ }
21953
+ const rowCount = endRowExclusive - startRow;
21954
+ const commitBuffer = OptimizedBuffer.create(surfaceWidth, rowCount, surfaceWidthMethod, {
21955
+ id: `scrollback-surface-commit-${surfaceId}`
21956
+ });
21957
+ try {
21958
+ commitBuffer.drawFrameBuffer(0, 0, backingBuffer, 0, startRow, surfaceWidth, rowCount);
21959
+ renderer.enqueueRenderedScrollbackCommit({
21960
+ snapshot: commitBuffer,
21961
+ rowColumns: commitOptions.rowColumns,
21962
+ startOnNewLine: nextCommitStartOnNewLine,
21963
+ trailingNewline: commitOptions.trailingNewline ?? false
21964
+ });
21965
+ nextCommitStartOnNewLine = false;
21966
+ } catch (error) {
21967
+ commitBuffer.destroy();
21968
+ throw error;
21969
+ }
21970
+ };
21971
+ const destroySurface = () => {
21972
+ if (surfaceDestroyed) {
21973
+ return;
21974
+ }
21975
+ surfaceDestroyed = true;
21976
+ renderer.off("destroy" /* DESTROY */, destroyListener);
21977
+ let destroyError = null;
21978
+ try {
21979
+ internalRoot.destroyRecursively();
21980
+ } catch (error) {
21981
+ destroyError = error;
21982
+ }
21983
+ try {
21984
+ backingBuffer.destroy();
21985
+ } catch (error) {
21986
+ if (destroyError === null) {
21987
+ destroyError = error;
21988
+ }
21989
+ }
21990
+ renderContext.removeAllListeners();
21991
+ snapshotContext.removeAllListeners();
21992
+ if (destroyError !== null) {
21993
+ throw destroyError;
21994
+ }
21995
+ };
21996
+ renderer.on("destroy" /* DESTROY */, destroyListener);
21997
+ return {
21998
+ get renderContext() {
21999
+ return renderContext;
22000
+ },
22001
+ get root() {
22002
+ return publicRoot;
22003
+ },
22004
+ get width() {
22005
+ return surfaceWidth;
22006
+ },
22007
+ get height() {
22008
+ return surfaceHeight;
22009
+ },
22010
+ get isDestroyed() {
22011
+ return surfaceDestroyed;
22012
+ },
22013
+ render: renderSurface,
22014
+ settle: settleSurface,
22015
+ commitRows,
22016
+ destroy: destroySurface
22017
+ };
22018
+ }
22019
+ writeToScrollback(write) {
22020
+ if (this._screenMode !== "split-footer" || this._externalOutputMode !== "capture-stdout") {
22021
+ throw new Error('writeToScrollback requires screenMode "split-footer" and externalOutputMode "capture-stdout"');
22022
+ }
22023
+ const snapshotContext = new ScrollbackSnapshotRenderContext(this.width, this.height, this.widthMethod);
22024
+ const snapshot = write({
22025
+ width: this.width,
22026
+ widthMethod: this.widthMethod,
22027
+ tailColumn: this.splitTailColumn,
22028
+ renderContext: snapshotContext
22029
+ });
22030
+ if (!snapshot || !snapshot.root) {
22031
+ throw new Error("writeToScrollback must return a snapshot root renderable");
22032
+ }
22033
+ let renderFailed = false;
22034
+ let snapshotRoot = null;
22035
+ let snapshotBuffer = null;
22036
+ try {
22037
+ const rootRenderable = snapshot.root;
22038
+ const snapshotWidth = this.getSnapshotWidth(snapshot.width, rootRenderable.width);
22039
+ const snapshotHeight = this.getSnapshotHeight(snapshot.height, rootRenderable.height);
22040
+ snapshotContext.width = snapshotWidth;
22041
+ snapshotContext.height = snapshotHeight;
22042
+ snapshotContext.widthMethod = this.widthMethod;
22043
+ snapshotRoot = new RootRenderable(snapshotContext);
22044
+ snapshotBuffer = OptimizedBuffer.create(snapshotWidth, snapshotHeight, this.widthMethod, {
22045
+ id: "scrollback-snapshot-commit"
22046
+ });
22047
+ snapshotRoot.add(rootRenderable);
22048
+ snapshotRoot.render(snapshotBuffer, 0);
22049
+ this.enqueueRenderedScrollbackCommit({
22050
+ snapshot: snapshotBuffer,
22051
+ rowColumns: snapshot.rowColumns,
22052
+ startOnNewLine: snapshot.startOnNewLine,
22053
+ trailingNewline: snapshot.trailingNewline
22054
+ });
22055
+ } catch (error) {
22056
+ renderFailed = true;
22057
+ snapshotBuffer?.destroy();
22058
+ throw error;
22059
+ } finally {
22060
+ let cleanupError = null;
22061
+ try {
22062
+ if (snapshotRoot) {
22063
+ snapshotRoot.destroyRecursively();
22064
+ } else {
22065
+ snapshot.root.destroyRecursively();
22066
+ }
22067
+ } catch (error) {
22068
+ cleanupError = error;
22069
+ }
22070
+ try {
22071
+ snapshot.teardown?.();
22072
+ } catch (error) {
22073
+ if (cleanupError === null) {
22074
+ cleanupError = error;
22075
+ }
22076
+ }
22077
+ if (!renderFailed && cleanupError) {
22078
+ throw cleanupError;
22079
+ }
22080
+ }
22081
+ }
22082
+ getSnapshotWidth(value, fallback) {
22083
+ const rawValue = value ?? fallback;
22084
+ if (!Number.isFinite(rawValue)) {
22085
+ throw new Error("writeToScrollback produced a non-finite width");
22086
+ }
22087
+ return Math.min(Math.max(Math.trunc(rawValue), 1), Math.max(this.width, 1));
19525
22088
  }
19526
- set maxFps(maxFps) {
19527
- this._maxFps = maxFps;
19528
- this.minTargetFrameTime = 1000 / this._maxFps;
22089
+ getSnapshotHeight(value, fallback) {
22090
+ const rawValue = value ?? fallback;
22091
+ if (!Number.isFinite(rawValue)) {
22092
+ throw new Error("writeToScrollback produced a non-finite height");
22093
+ }
22094
+ return Math.max(Math.trunc(rawValue), 1);
19529
22095
  }
19530
- get useMouse() {
19531
- return this._useMouse;
22096
+ getSnapshotRowWidths(snapshot, rowColumns) {
22097
+ const widths = [];
22098
+ const limit = Math.min(Math.max(Math.trunc(rowColumns), 0), snapshot.width);
22099
+ const chars = snapshot.buffers.char;
22100
+ for (let y = 0;y < snapshot.height; y += 1) {
22101
+ let x = limit;
22102
+ while (x > 0) {
22103
+ const cp = chars[y * snapshot.width + x - 1];
22104
+ if (cp === 0 || (cp & CHAR_FLAG_MASK) === CHAR_FLAG_CONTINUATION) {
22105
+ x -= 1;
22106
+ continue;
22107
+ }
22108
+ break;
22109
+ }
22110
+ widths.push(x);
22111
+ }
22112
+ return widths;
19532
22113
  }
19533
- set useMouse(useMouse) {
19534
- if (this._useMouse === useMouse)
22114
+ publishSplitTailColumns(columns) {
22115
+ if (columns <= 0) {
19535
22116
  return;
19536
- this._useMouse = useMouse;
19537
- if (useMouse) {
19538
- this.enableMouse();
19539
- } else {
19540
- this.disableMouse();
19541
22117
  }
22118
+ const width = Math.max(this.width, 1);
22119
+ let tail = this.splitTailColumn;
22120
+ let remaining = columns;
22121
+ while (remaining > 0) {
22122
+ if (tail >= width) {
22123
+ tail = 0;
22124
+ }
22125
+ const step = Math.min(remaining, width - tail);
22126
+ tail += step;
22127
+ remaining -= step;
22128
+ if (remaining > 0 && tail >= width) {
22129
+ tail = 0;
22130
+ }
22131
+ }
22132
+ this.splitTailColumn = tail;
19542
22133
  }
19543
- get screenMode() {
19544
- return this._screenMode;
22134
+ recordSplitCommit(commit) {
22135
+ if (commit.startOnNewLine && this.splitTailColumn > 0) {
22136
+ this.splitTailColumn = 0;
22137
+ }
22138
+ const rowWidths = this.getSnapshotRowWidths(commit.snapshot, commit.rowColumns);
22139
+ for (const [index, rowWidth] of rowWidths.entries()) {
22140
+ this.publishSplitTailColumns(rowWidth);
22141
+ if (index < rowWidths.length - 1 || commit.trailingNewline) {
22142
+ this.splitTailColumn = 0;
22143
+ }
22144
+ }
19545
22145
  }
19546
- set screenMode(mode) {
19547
- if (this.externalOutputMode === "capture-stdout" && mode !== "split-footer") {
19548
- throw new Error('externalOutputMode "capture-stdout" requires screenMode "split-footer"');
22146
+ enqueueRenderedScrollbackCommit(options) {
22147
+ if (this._screenMode !== "split-footer" || this._externalOutputMode !== "capture-stdout") {
22148
+ throw new Error('scrollback commit requires screenMode "split-footer" and externalOutputMode "capture-stdout"');
19549
22149
  }
19550
- this.applyScreenMode(mode);
22150
+ const rowColumns = Math.min(Math.max(Math.trunc(options.rowColumns ?? options.snapshot.width), 0), options.snapshot.width);
22151
+ this.enqueueSplitCommit({
22152
+ snapshot: options.snapshot,
22153
+ rowColumns,
22154
+ startOnNewLine: options.startOnNewLine ?? true,
22155
+ trailingNewline: options.trailingNewline ?? true
22156
+ });
22157
+ this.requestRender();
19551
22158
  }
19552
- get footerHeight() {
19553
- return this._footerHeight;
22159
+ enqueueSplitCommit(commit) {
22160
+ this.recordSplitCommit(commit);
22161
+ this.externalOutputQueue.writeSnapshot(commit);
22162
+ }
22163
+ createStdoutSnapshotCommit(line, trailingNewline) {
22164
+ const snapshotContext = new ScrollbackSnapshotRenderContext(this.width, 1, this.widthMethod);
22165
+ const maxWidth = Math.max(1, this.width);
22166
+ const lineCells = [...line];
22167
+ const rowColumns = Math.min(lineCells.length, maxWidth);
22168
+ const renderedLine = lineCells.slice(0, maxWidth).join("");
22169
+ const snapshotRoot = new RootRenderable(snapshotContext);
22170
+ const snapshotRenderable = new TextRenderable(snapshotContext, {
22171
+ id: "captured-stdout-snapshot",
22172
+ position: "absolute",
22173
+ left: 0,
22174
+ top: 0,
22175
+ width: Math.max(1, rowColumns),
22176
+ height: 1,
22177
+ content: renderedLine
22178
+ });
22179
+ const snapshotBuffer = OptimizedBuffer.create(Math.max(1, rowColumns), 1, this.widthMethod, {
22180
+ id: "captured-stdout-snapshot"
22181
+ });
22182
+ try {
22183
+ snapshotRoot.add(snapshotRenderable);
22184
+ snapshotRoot.render(snapshotBuffer, 0);
22185
+ return {
22186
+ snapshot: snapshotBuffer,
22187
+ rowColumns,
22188
+ startOnNewLine: false,
22189
+ trailingNewline
22190
+ };
22191
+ } catch (error) {
22192
+ snapshotBuffer.destroy();
22193
+ throw error;
22194
+ } finally {
22195
+ snapshotRoot.destroyRecursively();
22196
+ }
19554
22197
  }
19555
- set footerHeight(footerHeight) {
19556
- const normalizedFooterHeight = normalizeFooterHeight(footerHeight);
19557
- if (normalizedFooterHeight === this._footerHeight) {
19558
- return;
22198
+ splitStdoutRows(text) {
22199
+ const rows = [];
22200
+ let current = "";
22201
+ for (const char of text) {
22202
+ if (char === "\r") {
22203
+ current = "";
22204
+ continue;
22205
+ }
22206
+ if (char === `
22207
+ `) {
22208
+ rows.push({ line: current, trailingNewline: true });
22209
+ current = "";
22210
+ continue;
22211
+ }
22212
+ current += char;
19559
22213
  }
19560
- this._footerHeight = normalizedFooterHeight;
19561
- if (this.screenMode === "split-footer") {
19562
- this.applyScreenMode("split-footer");
22214
+ if (current.length > 0) {
22215
+ rows.push({ line: current, trailingNewline: false });
19563
22216
  }
22217
+ return rows;
19564
22218
  }
19565
- get externalOutputMode() {
19566
- return this._externalOutputMode;
19567
- }
19568
- set externalOutputMode(mode) {
19569
- if (mode === "capture-stdout" && this.screenMode !== "split-footer") {
19570
- throw new Error('externalOutputMode "capture-stdout" requires screenMode "split-footer"');
22219
+ createStdoutSnapshotCommits(text) {
22220
+ if (text.length === 0) {
22221
+ return [];
19571
22222
  }
19572
- this._externalOutputMode = mode;
19573
- this.stdout.write = mode === "capture-stdout" ? this.interceptStdoutWrite : this.realStdoutWrite;
19574
- }
19575
- get liveRequestCount() {
19576
- return this.liveRequestCounter;
22223
+ const commits = [];
22224
+ const chunkWidth = Math.max(1, this.width);
22225
+ for (const row of this.splitStdoutRows(text)) {
22226
+ const rowCells = [...row.line];
22227
+ if (rowCells.length === 0) {
22228
+ commits.push(this.createStdoutSnapshotCommit("", row.trailingNewline));
22229
+ continue;
22230
+ }
22231
+ let offset = 0;
22232
+ while (offset < rowCells.length) {
22233
+ const chunk = rowCells.slice(offset, offset + chunkWidth).join("");
22234
+ offset += chunkWidth;
22235
+ const isLastChunk = offset >= rowCells.length;
22236
+ commits.push(this.createStdoutSnapshotCommit(chunk, isLastChunk ? row.trailingNewline : false));
22237
+ }
22238
+ }
22239
+ return commits;
19577
22240
  }
19578
- get currentControlState() {
19579
- return this._controlState;
22241
+ flushPendingSplitCommits(forceFooterRepaint = false) {
22242
+ const commits = this.externalOutputQueue.claim(this.maxSplitCommitsPerFrame);
22243
+ let hasCommittedOutput = false;
22244
+ const lastCommitIndex = commits.length - 1;
22245
+ for (const [index, commit] of commits.entries()) {
22246
+ const forceCommit = forceFooterRepaint && index === lastCommitIndex;
22247
+ const beginFrame = index === 0;
22248
+ const finalizeFrame = index === lastCommitIndex;
22249
+ try {
22250
+ this.renderOffset = this.lib.commitSplitFooterSnapshot(this.rendererPtr, commit.snapshot, commit.rowColumns, commit.startOnNewLine, commit.trailingNewline, this.getSplitPinnedRenderOffset(), forceCommit, beginFrame, finalizeFrame);
22251
+ hasCommittedOutput = true;
22252
+ } finally {
22253
+ commit.snapshot.destroy();
22254
+ }
22255
+ }
22256
+ if (!hasCommittedOutput) {
22257
+ this.renderOffset = this.lib.repaintSplitFooter(this.rendererPtr, this.getSplitPinnedRenderOffset(), forceFooterRepaint);
22258
+ }
22259
+ this.pendingSplitFooterTransition = null;
22260
+ if (this.externalOutputQueue.size > 0) {
22261
+ this.requestRender();
22262
+ }
19580
22263
  }
19581
- get capabilities() {
19582
- return this._capabilities;
22264
+ interceptStdoutWrite = (chunk, encoding, callback) => {
22265
+ const resolvedCallback = typeof encoding === "function" ? encoding : callback;
22266
+ const resolvedEncoding = typeof encoding === "string" ? encoding : undefined;
22267
+ const text = typeof chunk === "string" ? chunk : chunk?.toString(resolvedEncoding) ?? "";
22268
+ if (this._externalOutputMode === "capture-stdout" && this._screenMode === "split-footer" && this._splitHeight > 0) {
22269
+ const commits = this.createStdoutSnapshotCommits(text);
22270
+ for (const commit of commits) {
22271
+ this.enqueueSplitCommit(commit);
22272
+ }
22273
+ if (commits.length > 0) {
22274
+ this.requestRender();
22275
+ }
22276
+ }
22277
+ if (typeof resolvedCallback === "function") {
22278
+ process.nextTick(resolvedCallback);
22279
+ }
22280
+ return true;
22281
+ };
22282
+ getSplitPinnedRenderOffset() {
22283
+ return this._screenMode === "split-footer" ? Math.max(this._terminalHeight - this._splitHeight, 0) : 0;
19583
22284
  }
19584
- get themeMode() {
19585
- return this._themeMode;
22285
+ getSplitCursorSeedRows() {
22286
+ const cursorState = this.lib.getCursorState(this.rendererPtr);
22287
+ const cursorRow = Number.isFinite(cursorState.y) ? Math.max(Math.trunc(cursorState.y), 1) : 1;
22288
+ return Math.min(cursorRow, Math.max(this._terminalHeight, 1));
19586
22289
  }
19587
- waitForThemeMode(timeoutMs = 1000) {
19588
- if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
19589
- throw new Error("timeoutMs must be a non-negative finite number");
22290
+ flushPendingSplitOutputBeforeTransition(forceFooterRepaint = false) {
22291
+ if (this._screenMode !== "split-footer" || this._splitHeight <= 0 || this._externalOutputMode !== "capture-stdout") {
22292
+ return;
19590
22293
  }
19591
- if (this._themeMode !== null || this._isDestroyed || timeoutMs === 0) {
19592
- return Promise.resolve(this._themeMode);
22294
+ if (this.externalOutputQueue.size === 0 && !forceFooterRepaint) {
22295
+ return;
19593
22296
  }
19594
- return new Promise((resolve4) => {
19595
- let timeoutHandle = null;
19596
- const cleanup = () => {
19597
- if (timeoutHandle !== null) {
19598
- this.clock.clearTimeout(timeoutHandle);
19599
- timeoutHandle = null;
19600
- }
19601
- this.off("theme_mode" /* THEME_MODE */, handleThemeMode);
19602
- this.off("destroy" /* DESTROY */, handleDestroy);
19603
- };
19604
- const finish = () => {
19605
- cleanup();
19606
- resolve4(this._themeMode);
19607
- };
19608
- const handleThemeMode = () => {
19609
- finish();
19610
- };
19611
- const handleDestroy = () => {
19612
- finish();
19613
- };
19614
- this.on("theme_mode" /* THEME_MODE */, handleThemeMode);
19615
- this.on("destroy" /* DESTROY */, handleDestroy);
19616
- timeoutHandle = this.clock.setTimeout(finish, timeoutMs);
19617
- });
22297
+ this.flushPendingSplitCommits(forceFooterRepaint);
19618
22298
  }
19619
- getDebugInputs() {
19620
- return [...this._debugInputs];
22299
+ resetSplitScrollback(seedRows = 0) {
22300
+ this.splitTailColumn = 0;
22301
+ this.renderOffset = this.lib.resetSplitScrollback(this.rendererPtr, seedRows, this.getSplitPinnedRenderOffset());
19621
22302
  }
19622
- get useKittyKeyboard() {
19623
- return this.lib.getKittyKeyboardFlags(this.rendererPtr) > 0;
22303
+ syncSplitScrollback() {
22304
+ this.renderOffset = this.lib.syncSplitScrollback(this.rendererPtr, this.getSplitPinnedRenderOffset());
19624
22305
  }
19625
- set useKittyKeyboard(use) {
19626
- const flags = use ? KITTY_FLAG_DISAMBIGUATE | KITTY_FLAG_ALTERNATE_KEYS : 0;
19627
- this.lib.setKittyKeyboardFlags(this.rendererPtr, flags);
22306
+ clearPendingSplitFooterTransition() {
22307
+ if (this.pendingSplitFooterTransition === null) {
22308
+ return;
22309
+ }
22310
+ this.pendingSplitFooterTransition = null;
22311
+ this.lib.clearPendingSplitFooterTransition(this.rendererPtr);
19628
22312
  }
19629
- interceptStdoutWrite = (chunk, encoding, callback) => {
19630
- const text = chunk.toString();
19631
- capture.write("stdout", text);
19632
- if (this._splitHeight > 0) {
19633
- this.requestRender();
22313
+ setPendingSplitFooterTransition(transition) {
22314
+ this.pendingSplitFooterTransition = transition;
22315
+ this.lib.setPendingSplitFooterTransition(this.rendererPtr, transition.mode === "viewport-scroll" ? 1 : 2, transition.sourceTopLine, transition.sourceHeight, transition.targetTopLine, transition.targetHeight);
22316
+ }
22317
+ syncSplitFooterState() {
22318
+ const splitActive = this._screenMode === "split-footer" && this._splitHeight > 0;
22319
+ if (!splitActive) {
22320
+ this.clearPendingSplitFooterTransition();
22321
+ this.splitTailColumn = 0;
22322
+ this.lib.resetSplitScrollback(this.rendererPtr, 0, 0);
22323
+ this.renderOffset = 0;
22324
+ this.lib.setRenderOffset(this.rendererPtr, this.renderOffset);
22325
+ return;
19634
22326
  }
19635
- if (typeof callback === "function") {
19636
- process.nextTick(callback);
22327
+ if (this._externalOutputMode === "capture-stdout") {
22328
+ this.syncSplitScrollback();
22329
+ } else {
22330
+ this.clearPendingSplitFooterTransition();
22331
+ this.splitTailColumn = 0;
22332
+ this.lib.resetSplitScrollback(this.rendererPtr, 0, 0);
22333
+ this.renderOffset = this.getSplitPinnedRenderOffset();
22334
+ this.lib.setRenderOffset(this.rendererPtr, this.renderOffset);
19637
22335
  }
19638
- return true;
19639
- };
22336
+ }
22337
+ clearStaleSplitSurfaceRows(previousTopLine, previousHeight, nextTopLine, nextHeight) {
22338
+ if (!this._terminalIsSetup || previousHeight <= 0 || this._terminalHeight <= 0) {
22339
+ return;
22340
+ }
22341
+ const terminalBottom = this._terminalHeight;
22342
+ const previousStart = Math.max(1, previousTopLine);
22343
+ const previousEnd = Math.min(terminalBottom, previousTopLine + previousHeight - 1);
22344
+ if (previousEnd < previousStart) {
22345
+ return;
22346
+ }
22347
+ const nextStart = Math.max(1, nextTopLine);
22348
+ const nextEnd = Math.min(terminalBottom, nextTopLine + Math.max(nextHeight, 0) - 1);
22349
+ let clear = "";
22350
+ for (let line = previousStart;line <= previousEnd; line += 1) {
22351
+ if (line >= nextStart && line <= nextEnd) {
22352
+ continue;
22353
+ }
22354
+ clear += `${ANSI.moveCursor(line, 1)}\x1B[2K`;
22355
+ }
22356
+ if (clear.length > 0) {
22357
+ this.writeOut(clear);
22358
+ }
22359
+ }
19640
22360
  applyScreenMode(screenMode, emitResize = true, requestRender = true) {
19641
22361
  const prevScreenMode = this._screenMode;
19642
22362
  const prevSplitHeight = this._splitHeight;
19643
- const nextSplitHeight = screenMode === "split-footer" ? this._footerHeight : 0;
22363
+ const nextGeometry = calculateRenderGeometry(screenMode, this._terminalWidth, this._terminalHeight, this._footerHeight);
22364
+ const nextSplitHeight = nextGeometry.effectiveFooterHeight;
19644
22365
  if (prevScreenMode === screenMode && prevSplitHeight === nextSplitHeight) {
19645
22366
  return;
19646
22367
  }
@@ -19648,10 +22369,24 @@ Captured output:
19648
22369
  const nextUseAlternateScreen = screenMode === "alternate-screen";
19649
22370
  const terminalScreenModeChanged = this._terminalIsSetup && prevUseAlternateScreen !== nextUseAlternateScreen;
19650
22371
  const leavingSplitFooter = prevSplitHeight > 0 && nextSplitHeight === 0;
22372
+ if (this._terminalIsSetup && prevSplitHeight > 0) {
22373
+ this.flushPendingSplitOutputBeforeTransition();
22374
+ }
22375
+ const previousSurfaceTopLine = this.renderOffset + 1;
22376
+ const previousPinnedRenderOffset = Math.max(this._terminalHeight - prevSplitHeight, 0);
22377
+ const splitWasSettled = prevSplitHeight === 0 || this.renderOffset >= previousPinnedRenderOffset;
22378
+ const shouldUseViewportScrollTransitions = this._externalOutputMode !== "capture-stdout" || splitWasSettled;
22379
+ const shouldDeferSplitFooterResizeTransition = this._terminalIsSetup && prevScreenMode === "split-footer" && screenMode === "split-footer" && this._externalOutputMode === "capture-stdout" && prevSplitHeight > 0 && nextSplitHeight > 0 && !terminalScreenModeChanged;
22380
+ const splitStartupSeedBlocksFirstNativeFrame = this.pendingSplitStartupCursorSeed && this.splitStartupSeedTimeoutId !== null;
22381
+ const splitTransitionSourceTopLine = this.pendingSplitFooterTransition?.sourceTopLine ?? previousSurfaceTopLine;
22382
+ const splitTransitionSourceHeight = this.pendingSplitFooterTransition?.sourceHeight ?? prevSplitHeight;
22383
+ const splitTransitionMode = this.pendingSplitFooterTransition?.mode ?? (splitWasSettled ? "viewport-scroll" : "clear-stale-rows");
19651
22384
  if (this._terminalIsSetup && leavingSplitFooter) {
19652
- this.flushStdoutCache(this._terminalHeight, true);
22385
+ this.clearPendingSplitFooterTransition();
22386
+ this.renderOffset = 0;
22387
+ this.lib.setRenderOffset(this.rendererPtr, 0);
19653
22388
  }
19654
- if (this._terminalIsSetup && !terminalScreenModeChanged) {
22389
+ if (this._terminalIsSetup && !terminalScreenModeChanged && shouldUseViewportScrollTransitions && !shouldDeferSplitFooterResizeTransition) {
19655
22390
  if (prevSplitHeight === 0 && nextSplitHeight > 0) {
19656
22391
  const freedLines = this._terminalHeight - nextSplitHeight;
19657
22392
  const scrollDown = ANSI.scrollDown(freedLines);
@@ -19666,18 +22401,39 @@ Captured output:
19666
22401
  this.writeOut(scrollUp);
19667
22402
  }
19668
22403
  }
19669
- if (prevSplitHeight === 0 && nextSplitHeight > 0) {
19670
- capture.on("write", this.captureCallback);
19671
- } else if (prevSplitHeight > 0 && nextSplitHeight === 0) {
19672
- capture.off("write", this.captureCallback);
19673
- }
19674
22404
  this._screenMode = screenMode;
19675
22405
  this._splitHeight = nextSplitHeight;
19676
- this.renderOffset = nextSplitHeight > 0 ? this._terminalHeight - nextSplitHeight : 0;
19677
- this.width = this._terminalWidth;
19678
- this.height = nextSplitHeight > 0 ? nextSplitHeight : this._terminalHeight;
19679
- this.lib.setRenderOffset(this.rendererPtr, this.renderOffset);
22406
+ this.width = nextGeometry.renderWidth;
22407
+ this.height = nextGeometry.renderHeight;
19680
22408
  this.lib.resizeRenderer(this.rendererPtr, this.width, this.height);
22409
+ if (this._screenMode === "split-footer" && this._externalOutputMode === "capture-stdout") {
22410
+ if (prevScreenMode !== "split-footer") {
22411
+ this.resetSplitScrollback(this.getSplitCursorSeedRows());
22412
+ } else {
22413
+ this.syncSplitScrollback();
22414
+ }
22415
+ if (shouldDeferSplitFooterResizeTransition) {
22416
+ if (splitStartupSeedBlocksFirstNativeFrame) {
22417
+ this.clearPendingSplitFooterTransition();
22418
+ } else {
22419
+ this.setPendingSplitFooterTransition({
22420
+ mode: splitTransitionMode,
22421
+ sourceTopLine: splitTransitionSourceTopLine,
22422
+ sourceHeight: splitTransitionSourceHeight,
22423
+ targetTopLine: this.renderOffset + 1,
22424
+ targetHeight: nextSplitHeight
22425
+ });
22426
+ }
22427
+ this.forceFullRepaintRequested = true;
22428
+ } else if (!shouldUseViewportScrollTransitions && prevSplitHeight > 0 && nextSplitHeight > 0) {
22429
+ this.clearPendingSplitFooterTransition();
22430
+ this.clearStaleSplitSurfaceRows(previousSurfaceTopLine, prevSplitHeight, this.renderOffset + 1, nextSplitHeight);
22431
+ } else {
22432
+ this.clearPendingSplitFooterTransition();
22433
+ }
22434
+ } else {
22435
+ this.syncSplitFooterState();
22436
+ }
19681
22437
  this.nextRenderBuffer = this.lib.getNextBuffer(this.rendererPtr);
19682
22438
  this.currentRenderBuffer = this.lib.getCurrentBuffer(this.rendererPtr);
19683
22439
  this._console.resize(this.width, this.height);
@@ -19697,12 +22453,18 @@ Captured output:
19697
22453
  }
19698
22454
  }
19699
22455
  flushStdoutCache(space, force = false) {
19700
- if (capture.size === 0 && !force)
22456
+ if (this.externalOutputQueue.size === 0 && !force)
19701
22457
  return false;
19702
- const output = capture.claimOutput();
19703
- const rendererStartLine = this._terminalHeight - this._splitHeight;
22458
+ const outputCommits = this.externalOutputQueue.claim();
22459
+ let output = "";
22460
+ for (const commit of outputCommits) {
22461
+ output += `[snapshot ${commit.snapshot.width}x${commit.snapshot.height}]
22462
+ `;
22463
+ commit.snapshot.destroy();
22464
+ }
22465
+ const rendererStartLine = this.renderOffset + 1;
19704
22466
  const flush = ANSI.moveCursorAndClear(rendererStartLine, 1);
19705
- const outputLine = this._terminalHeight - this._splitHeight;
22467
+ const outputLine = this.renderOffset + 1;
19706
22468
  const move = ANSI.moveCursor(outputLine, 1);
19707
22469
  let clear = "";
19708
22470
  if (space > 0) {
@@ -19744,9 +22506,11 @@ Captured output:
19744
22506
  if (this._terminalIsSetup)
19745
22507
  return;
19746
22508
  this._terminalIsSetup = true;
22509
+ const startupCursorCprActive = this._screenMode === "split-footer" && this._externalOutputMode === "capture-stdout";
19747
22510
  this.updateStdinParserProtocolContext({
19748
22511
  privateCapabilityRepliesActive: true,
19749
- explicitWidthCprActive: true
22512
+ explicitWidthCprActive: true,
22513
+ startupCursorCprActive
19750
22514
  });
19751
22515
  this.lib.setupTerminal(this.rendererPtr, this._screenMode === "alternate-screen");
19752
22516
  this._capabilities = this.lib.getTerminalCapabilities(this.rendererPtr);
@@ -19760,16 +22524,42 @@ Captured output:
19760
22524
  }
19761
22525
  this.capabilityTimeoutId = this.clock.setTimeout(() => {
19762
22526
  this.capabilityTimeoutId = null;
22527
+ this.pendingSplitStartupCursorSeed = false;
22528
+ if (this.splitStartupSeedTimeoutId !== null) {
22529
+ this.clock.clearTimeout(this.splitStartupSeedTimeoutId);
22530
+ this.splitStartupSeedTimeoutId = null;
22531
+ }
22532
+ if (this._screenMode === "split-footer" && this._externalOutputMode === "capture-stdout") {
22533
+ this.requestRender();
22534
+ }
19763
22535
  this.removeInputHandler(this.capabilityHandler);
19764
22536
  this.updateStdinParserProtocolContext({
19765
22537
  privateCapabilityRepliesActive: false,
19766
- explicitWidthCprActive: false
22538
+ explicitWidthCprActive: false,
22539
+ startupCursorCprActive: false
19767
22540
  }, true);
19768
22541
  }, 5000);
19769
22542
  if (this._useMouse) {
19770
22543
  this.enableMouse();
19771
22544
  }
22545
+ if (this._screenMode === "split-footer" && this._externalOutputMode === "capture-stdout") {
22546
+ this.pendingSplitStartupCursorSeed = true;
22547
+ if (this.splitStartupSeedTimeoutId !== null) {
22548
+ this.clock.clearTimeout(this.splitStartupSeedTimeoutId);
22549
+ }
22550
+ this.splitStartupSeedTimeoutId = this.clock.setTimeout(() => {
22551
+ this.splitStartupSeedTimeoutId = null;
22552
+ if (!this.pendingSplitStartupCursorSeed) {
22553
+ return;
22554
+ }
22555
+ this.updateStdinParserProtocolContext({ startupCursorCprActive: false });
22556
+ if (this._screenMode === "split-footer" && this._externalOutputMode === "capture-stdout") {
22557
+ this.requestRender();
22558
+ }
22559
+ }, 120);
22560
+ }
19772
22561
  this.queryPixelResolution();
22562
+ this.ensureNativePaletteState();
19773
22563
  }
19774
22564
  stdinListener = ((chunk) => {
19775
22565
  const data = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
@@ -19804,14 +22594,36 @@ Captured output:
19804
22594
  this.oscSubscribers.delete(handler);
19805
22595
  };
19806
22596
  }
19807
- capabilityHandler = ((sequence) => {
19808
- if (isCapabilityResponse(sequence)) {
19809
- this.lib.processCapabilityResponse(this.rendererPtr, sequence);
19810
- this._capabilities = this.lib.getTerminalCapabilities(this.rendererPtr);
19811
- this.emit("capabilities" /* CAPABILITIES */, this._capabilities);
19812
- return true;
22597
+ processCapabilitySequence(sequence, hasCursorReport) {
22598
+ const hasStandardCapabilitySignature = isCapabilityResponse(sequence);
22599
+ const shouldProcessAsCapability = hasStandardCapabilitySignature || hasCursorReport && this.capabilityTimeoutId !== null;
22600
+ if (!shouldProcessAsCapability) {
22601
+ return false;
19813
22602
  }
19814
- return false;
22603
+ this.lib.processCapabilityResponse(this.rendererPtr, sequence);
22604
+ this._capabilities = this.lib.getTerminalCapabilities(this.rendererPtr);
22605
+ if (hasStandardCapabilitySignature) {
22606
+ this.forceFullRepaintRequested = true;
22607
+ this.requestRender();
22608
+ }
22609
+ this.emit("capabilities" /* CAPABILITIES */, this._capabilities);
22610
+ const hadPendingSplitStartupCursorSeed = this.pendingSplitStartupCursorSeed;
22611
+ if (hadPendingSplitStartupCursorSeed && hasCursorReport && this._screenMode === "split-footer" && this._externalOutputMode === "capture-stdout") {
22612
+ this.resetSplitScrollback(this.getSplitCursorSeedRows());
22613
+ this.clearPendingSplitFooterTransition();
22614
+ this.pendingSplitStartupCursorSeed = false;
22615
+ this.updateStdinParserProtocolContext({ startupCursorCprActive: false });
22616
+ if (this.splitStartupSeedTimeoutId !== null) {
22617
+ this.clock.clearTimeout(this.splitStartupSeedTimeoutId);
22618
+ this.splitStartupSeedTimeoutId = null;
22619
+ }
22620
+ this.requestRender();
22621
+ }
22622
+ const consumeStartupCursorReport = hadPendingSplitStartupCursorSeed && hasCursorReport && this.splitStartupSeedTimeoutId !== null;
22623
+ return hasStandardCapabilitySignature || consumeStartupCursorReport;
22624
+ }
22625
+ capabilityHandler = ((sequence) => {
22626
+ return this.processCapabilitySequence(sequence, false);
19815
22627
  }).bind(this);
19816
22628
  focusHandler = ((sequence) => {
19817
22629
  if (sequence === "\x1B[I") {
@@ -19835,52 +22647,6 @@ Captured output:
19835
22647
  }
19836
22648
  return false;
19837
22649
  }).bind(this);
19838
- themeModeHandler = ((sequence) => {
19839
- if (sequence === "\x1B[?997;1n") {
19840
- this.applyThemeMode("dark", "csi");
19841
- this._themeFallbackPending = false;
19842
- return true;
19843
- }
19844
- if (sequence === "\x1B[?997;2n") {
19845
- this.applyThemeMode("light", "csi");
19846
- this._themeFallbackPending = false;
19847
- return true;
19848
- }
19849
- let handledOscThemeResponse = false;
19850
- let match;
19851
- OSC_THEME_RESPONSE.lastIndex = 0;
19852
- while (match = OSC_THEME_RESPONSE.exec(sequence)) {
19853
- handledOscThemeResponse = true;
19854
- const color = oscThemeColorToHex(match[2], match[3], match[4], match[5]);
19855
- if (match[1] === "10") {
19856
- this._themeOscForeground = color;
19857
- } else {
19858
- this._themeOscBackground = color;
19859
- }
19860
- }
19861
- if (!handledOscThemeResponse) {
19862
- return false;
19863
- }
19864
- if (!this._themeFallbackPending) {
19865
- return true;
19866
- }
19867
- if (this._themeOscForeground && this._themeOscBackground) {
19868
- this.applyThemeMode(inferThemeModeFromBackgroundColor(this._themeOscBackground), "osc");
19869
- this._themeFallbackPending = false;
19870
- }
19871
- return true;
19872
- }).bind(this);
19873
- applyThemeMode(mode, source) {
19874
- if (source === "osc" && this._themeModeSource === "csi") {
19875
- return;
19876
- }
19877
- const changed = this._themeMode !== mode;
19878
- this._themeMode = mode;
19879
- this._themeModeSource = source;
19880
- if (changed) {
19881
- this.emit("theme_mode" /* THEME_MODE */, mode);
19882
- }
19883
- }
19884
22650
  dispatchSequenceHandlers(sequence) {
19885
22651
  if (this._debugModeEnabled) {
19886
22652
  this._debugInputs.push({
@@ -19925,6 +22691,9 @@ Captured output:
19925
22691
  subscriber(event.sequence);
19926
22692
  }
19927
22693
  }
22694
+ if (event.protocol === "cpr" && this.processCapabilitySequence(event.sequence, true)) {
22695
+ return;
22696
+ }
19928
22697
  this.dispatchSequenceHandlers(event.sequence);
19929
22698
  return;
19930
22699
  }
@@ -20211,28 +22980,45 @@ Captured output:
20211
22980
  processResize(width, height) {
20212
22981
  if (width === this._terminalWidth && height === this._terminalHeight)
20213
22982
  return;
22983
+ if (this._terminalIsSetup && this._controlState !== "explicit_suspended" /* EXPLICIT_SUSPENDED */) {
22984
+ this.flushPendingSplitOutputBeforeTransition();
22985
+ }
22986
+ const pendingSplitFooterTransition = this.pendingSplitFooterTransition;
22987
+ const previousGeometry = calculateRenderGeometry(this._screenMode, this._terminalWidth, this._terminalHeight, this._footerHeight);
20214
22988
  const prevWidth = this._terminalWidth;
22989
+ const previousTerminalHeight = this._terminalHeight;
22990
+ const visiblePreviousSplitHeight = pendingSplitFooterTransition?.sourceHeight ?? previousGeometry.effectiveFooterHeight;
20215
22991
  this._terminalWidth = width;
20216
22992
  this._terminalHeight = height;
20217
22993
  this.queryPixelResolution();
20218
22994
  this.setCapturedRenderable(undefined);
20219
22995
  this.stdinParser?.resetMouseState();
20220
- if (this._splitHeight > 0) {
20221
- if (width < prevWidth) {
20222
- const start = this._terminalHeight - this._splitHeight * 2;
20223
- const flush = ANSI.moveCursorAndClear(start, 1);
22996
+ const nextGeometry = calculateRenderGeometry(this._screenMode, this._terminalWidth, this._terminalHeight, this._footerHeight);
22997
+ const splitFooterActive = this._screenMode === "split-footer";
22998
+ if (splitFooterActive) {
22999
+ let clearStart = null;
23000
+ if (width < prevWidth && visiblePreviousSplitHeight > 0) {
23001
+ clearStart = Math.max(previousTerminalHeight - visiblePreviousSplitHeight * 2, 1);
23002
+ }
23003
+ if (pendingSplitFooterTransition !== null) {
23004
+ clearStart = clearStart === null ? pendingSplitFooterTransition.sourceTopLine : Math.min(clearStart, pendingSplitFooterTransition.sourceTopLine);
23005
+ }
23006
+ if (clearStart !== null) {
23007
+ const flush = ANSI.moveCursorAndClear(clearStart, 1);
20224
23008
  this.writeOut(flush);
20225
23009
  }
20226
- this.renderOffset = height - this._splitHeight;
20227
- this.width = width;
20228
- this.height = this._splitHeight;
20229
23010
  this.currentRenderBuffer.clear(this.backgroundColor);
20230
- this.lib.setRenderOffset(this.rendererPtr, this.renderOffset);
20231
- } else {
20232
- this.width = width;
20233
- this.height = height;
20234
23011
  }
23012
+ this.clearPendingSplitFooterTransition();
23013
+ this._splitHeight = nextGeometry.effectiveFooterHeight;
23014
+ this.width = nextGeometry.renderWidth;
23015
+ this.height = nextGeometry.renderHeight;
20235
23016
  this.lib.resizeRenderer(this.rendererPtr, this.width, this.height);
23017
+ if (this._screenMode === "split-footer" && this._externalOutputMode === "capture-stdout") {
23018
+ this.syncSplitScrollback();
23019
+ } else {
23020
+ this.syncSplitFooterState();
23021
+ }
20236
23022
  this.nextRenderBuffer = this.lib.getNextBuffer(this.rendererPtr);
20237
23023
  this.currentRenderBuffer = this.lib.getCurrentBuffer(this.rendererPtr);
20238
23024
  this._console.resize(this.width, this.height);
@@ -20380,6 +23166,9 @@ Captured output:
20380
23166
  this._previousControlState = this._controlState;
20381
23167
  this._controlState = "explicit_suspended" /* EXPLICIT_SUSPENDED */;
20382
23168
  this.internalPause();
23169
+ if (this._terminalIsSetup) {
23170
+ this.flushPendingSplitOutputBeforeTransition(true);
23171
+ }
20383
23172
  this._suspendedMouseEnabled = this._useMouse;
20384
23173
  this.disableMouse();
20385
23174
  this.removeExitListeners();
@@ -20387,10 +23176,12 @@ Captured output:
20387
23176
  this.updateStdinParserProtocolContext({
20388
23177
  privateCapabilityRepliesActive: false,
20389
23178
  pixelResolutionQueryActive: false,
20390
- explicitWidthCprActive: false
23179
+ explicitWidthCprActive: false,
23180
+ startupCursorCprActive: false
20391
23181
  });
20392
23182
  this.stdinParser?.reset();
20393
23183
  this.stdin.removeListener("data", this.stdinListener);
23184
+ this.themeModeState.cancelRefresh();
20394
23185
  this.lib.suspendRenderer(this.rendererPtr);
20395
23186
  if (this.stdin.setRawMode) {
20396
23187
  this.stdin.setRawMode(false);
@@ -20406,6 +23197,9 @@ Captured output:
20406
23197
  this.stdin.resume();
20407
23198
  this.addExitListeners();
20408
23199
  this.lib.resumeRenderer(this.rendererPtr);
23200
+ if (this._screenMode === "split-footer" && this._splitHeight > 0) {
23201
+ this.syncSplitFooterState();
23202
+ }
20409
23203
  if (this._suspendedMouseEnabled) {
20410
23204
  this.enableMouse();
20411
23205
  }
@@ -20467,7 +23261,6 @@ Captured output:
20467
23261
  process.removeListener("unhandledRejection", this.handleError);
20468
23262
  process.removeListener("warning", this.warningHandler);
20469
23263
  process.removeListener("beforeExit", this.exitHandler);
20470
- capture.removeListener("write", this.captureCallback);
20471
23264
  this.removeExitListeners();
20472
23265
  if (this.resizeTimeoutId !== null) {
20473
23266
  this.clock.clearTimeout(this.resizeTimeoutId);
@@ -20477,6 +23270,10 @@ Captured output:
20477
23270
  this.clock.clearTimeout(this.capabilityTimeoutId);
20478
23271
  this.capabilityTimeoutId = null;
20479
23272
  }
23273
+ if (this.splitStartupSeedTimeoutId !== null) {
23274
+ this.clock.clearTimeout(this.splitStartupSeedTimeoutId);
23275
+ this.splitStartupSeedTimeoutId = null;
23276
+ }
20480
23277
  if (this.memorySnapshotTimer) {
20481
23278
  this.clock.clearInterval(this.memorySnapshotTimer);
20482
23279
  this.memorySnapshotTimer = null;
@@ -20485,12 +23282,14 @@ Captured output:
20485
23282
  this.clock.clearTimeout(this.renderTimeout);
20486
23283
  this.renderTimeout = null;
20487
23284
  }
23285
+ this.themeModeState.cancelRefresh();
20488
23286
  this._isRunning = false;
20489
23287
  this.waitingForPixelResolution = false;
20490
23288
  this.updateStdinParserProtocolContext({
20491
23289
  privateCapabilityRepliesActive: false,
20492
23290
  pixelResolutionQueryActive: false,
20493
- explicitWidthCprActive: false
23291
+ explicitWidthCprActive: false,
23292
+ startupCursorCprActive: false
20494
23293
  }, true);
20495
23294
  this._useMouse = false;
20496
23295
  this.setCapturedRenderable(undefined);
@@ -20517,8 +23316,14 @@ Captured output:
20517
23316
  this._paletteDetector.cleanup();
20518
23317
  this._paletteDetector = null;
20519
23318
  }
23319
+ this._paletteCache.clear();
20520
23320
  this._paletteDetectionPromise = null;
23321
+ this._paletteDetectionSize = 0;
20521
23322
  this._cachedPalette = null;
23323
+ this._publishedPaletteSignature = null;
23324
+ this._paletteEpoch = 0;
23325
+ this._palettePublishGeneration = 0;
23326
+ this.themeModeState.dispose();
20522
23327
  this.emit("destroy" /* DESTROY */);
20523
23328
  try {
20524
23329
  this.root.destroyRecursively();
@@ -20529,6 +23334,16 @@ Captured output:
20529
23334
  this.stdinParser = null;
20530
23335
  this.oscSubscribers.clear();
20531
23336
  this._console.destroy();
23337
+ if (this._splitHeight > 0 && this._terminalIsSetup && this._controlState !== "explicit_suspended" /* EXPLICIT_SUSPENDED */) {
23338
+ this.flushPendingSplitOutputBeforeTransition(true);
23339
+ this.renderOffset = 0;
23340
+ if (this.clearOnShutdown) {
23341
+ this.lib.setRenderOffset(this.rendererPtr, 0);
23342
+ }
23343
+ }
23344
+ this._externalOutputMode = "passthrough";
23345
+ this.stdout.write = this.realStdoutWrite;
23346
+ this.externalOutputQueue.clear();
20532
23347
  this.lib.destroyRenderer(this.rendererPtr);
20533
23348
  rendererTracker.removeRenderer(this);
20534
23349
  if (this._onDestroy) {
@@ -20637,12 +23452,22 @@ Captured output:
20637
23452
  console.error("Rendering called concurrently");
20638
23453
  throw new Error("Rendering called concurrently");
20639
23454
  }
20640
- let force = false;
20641
- if (this._splitHeight > 0) {
20642
- force = this.flushStdoutCache(this._splitHeight);
20643
- }
20644
23455
  this.renderingNative = true;
20645
- this.lib.render(this.rendererPtr, force);
23456
+ if (this.pendingSplitStartupCursorSeed && this.splitStartupSeedTimeoutId !== null && this._splitHeight > 0 && this._externalOutputMode === "capture-stdout") {
23457
+ this.renderingNative = false;
23458
+ return;
23459
+ }
23460
+ if (this._splitHeight > 0 && this._externalOutputMode === "capture-stdout") {
23461
+ const forceSplitRepaint = this.forceFullRepaintRequested;
23462
+ this.forceFullRepaintRequested = false;
23463
+ this.flushPendingSplitCommits(forceSplitRepaint);
23464
+ this.pendingSplitFooterTransition = null;
23465
+ } else {
23466
+ const force = this.forceFullRepaintRequested;
23467
+ this.forceFullRepaintRequested = false;
23468
+ this.pendingSplitFooterTransition = null;
23469
+ this.lib.render(this.rendererPtr, force);
23470
+ }
20646
23471
  this.renderingNative = false;
20647
23472
  }
20648
23473
  collectStatSample(frameTime) {
@@ -20786,13 +23611,63 @@ Captured output:
20786
23611
  }
20787
23612
  }
20788
23613
  get paletteDetectionStatus() {
20789
- if (this._cachedPalette)
20790
- return "cached";
20791
23614
  if (this._paletteDetectionPromise)
20792
23615
  return "detecting";
23616
+ if (this._paletteCache.size > 0)
23617
+ return "cached";
20793
23618
  return "idle";
20794
23619
  }
23620
+ getCachedPaletteBySize(size) {
23621
+ const exactMatch = this._paletteCache.get(size);
23622
+ if (exactMatch) {
23623
+ return exactMatch;
23624
+ }
23625
+ const largerSize = [...this._paletteCache.keys()].sort((a, b) => a - b).find((candidate) => candidate >= size);
23626
+ if (largerSize === undefined) {
23627
+ return null;
23628
+ }
23629
+ const source = this._paletteCache.get(largerSize);
23630
+ if (!source) {
23631
+ return null;
23632
+ }
23633
+ const projected = {
23634
+ ...source,
23635
+ palette: source.palette.slice(0, size)
23636
+ };
23637
+ this._paletteCache.set(size, projected);
23638
+ return projected;
23639
+ }
23640
+ ensurePaletteDetector() {
23641
+ if (!this._paletteDetector) {
23642
+ const isLegacyTmux = this.capabilities?.terminal?.name?.toLowerCase()?.includes("tmux") && this.capabilities?.terminal?.version?.localeCompare("3.6") < 0;
23643
+ this._paletteDetector = createTerminalPalette(this.stdin, this.stdout, this.writeOut.bind(this), isLegacyTmux, {
23644
+ subscribeOsc: this.subscribeOsc.bind(this)
23645
+ }, this.clock);
23646
+ }
23647
+ return this._paletteDetector;
23648
+ }
23649
+ syncNativePaletteState(colors) {
23650
+ const signature = buildTerminalPaletteSignature(colors);
23651
+ if (this._publishedPaletteSignature !== null && this._publishedPaletteSignature !== signature) {
23652
+ this._paletteEpoch = this._paletteEpoch + 1 >>> 0;
23653
+ }
23654
+ this._publishedPaletteSignature = signature;
23655
+ const normalized = normalizeTerminalPalette(colors);
23656
+ this.lib.rendererSetPaletteState(this.rendererPtr, normalized.palette, normalized.defaultForeground, normalized.defaultBackground, this._paletteEpoch);
23657
+ }
23658
+ ensureNativePaletteState() {
23659
+ if (!this._terminalIsSetup || this._isDestroyed)
23660
+ return;
23661
+ const publishGeneration = this._palettePublishGeneration;
23662
+ this.getPalette({ size: 256 }).then((colors) => {
23663
+ if (this._palettePublishGeneration === publishGeneration) {
23664
+ this.syncNativePaletteState(colors);
23665
+ }
23666
+ this.requestRender();
23667
+ }).catch(() => {});
23668
+ }
20795
23669
  clearPaletteCache() {
23670
+ this._paletteCache.clear();
20796
23671
  this._cachedPalette = null;
20797
23672
  }
20798
23673
  async getPalette(options) {
@@ -20800,31 +23675,65 @@ Captured output:
20800
23675
  throw new Error("Cannot detect palette while renderer is suspended");
20801
23676
  }
20802
23677
  const requestedSize = options?.size ?? 16;
20803
- if (this._cachedPalette && this._cachedPalette.palette.length !== requestedSize) {
20804
- this._cachedPalette = null;
20805
- }
20806
- if (this._cachedPalette) {
20807
- return this._cachedPalette;
23678
+ const detectionTimeout = options?.timeout;
23679
+ const cachedPalette = this.getCachedPaletteBySize(requestedSize);
23680
+ if (cachedPalette) {
23681
+ this._cachedPalette = cachedPalette;
23682
+ return cachedPalette;
20808
23683
  }
20809
23684
  if (this._paletteDetectionPromise) {
20810
- return this._paletteDetectionPromise;
20811
- }
20812
- if (!this._paletteDetector) {
20813
- const isLegacyTmux = this.capabilities?.terminal?.name?.toLowerCase()?.includes("tmux") && this.capabilities?.terminal?.version?.localeCompare("3.6") < 0;
20814
- this._paletteDetector = createTerminalPalette(this.stdin, this.stdout, this.writeOut.bind(this), isLegacyTmux, {
20815
- subscribeOsc: this.subscribeOsc.bind(this)
20816
- }, this.clock);
23685
+ if (this._paletteDetectionSize >= requestedSize) {
23686
+ return this._paletteDetectionPromise.then((palette) => {
23687
+ const cached = this.getCachedPaletteBySize(requestedSize);
23688
+ if (cached) {
23689
+ this._cachedPalette = cached;
23690
+ return cached;
23691
+ }
23692
+ const projected = {
23693
+ ...palette,
23694
+ palette: palette.palette.slice(0, requestedSize)
23695
+ };
23696
+ this._paletteCache.set(requestedSize, projected);
23697
+ this._cachedPalette = projected;
23698
+ return projected;
23699
+ });
23700
+ }
23701
+ await this._paletteDetectionPromise;
23702
+ const afterWait = this.getCachedPaletteBySize(requestedSize);
23703
+ if (afterWait) {
23704
+ this._cachedPalette = afterWait;
23705
+ return afterWait;
23706
+ }
20817
23707
  }
20818
- this._paletteDetectionPromise = this._paletteDetector.detect(options).then((result) => {
23708
+ const detector = this.ensurePaletteDetector();
23709
+ const publishGeneration = this._palettePublishGeneration;
23710
+ this._paletteDetectionSize = requestedSize;
23711
+ this._paletteDetectionPromise = detector.detect({ ...options, timeout: detectionTimeout }).then((result) => {
23712
+ this._paletteCache.set(result.palette.length, result);
20819
23713
  this._cachedPalette = result;
20820
23714
  this._paletteDetectionPromise = null;
23715
+ this._paletteDetectionSize = 0;
23716
+ if (this._palettePublishGeneration === publishGeneration) {
23717
+ if (result.palette.length >= 256) {
23718
+ this.syncNativePaletteState(result);
23719
+ } else if (this._terminalIsSetup && !this._paletteCache.has(256)) {
23720
+ this.ensureNativePaletteState();
23721
+ }
23722
+ }
20821
23723
  return result;
23724
+ }).catch((error) => {
23725
+ this._paletteDetectionPromise = null;
23726
+ this._paletteDetectionSize = 0;
23727
+ throw error;
20822
23728
  });
20823
- return this._paletteDetectionPromise;
23729
+ const detected = await this._paletteDetectionPromise;
23730
+ const finalPalette = this.getCachedPaletteBySize(requestedSize) ?? detected;
23731
+ this._cachedPalette = finalPalette;
23732
+ return finalPalette;
20824
23733
  }
20825
23734
  }
20826
23735
 
20827
- export { __toESM, __commonJS, __export, __require, Edge, Gutter, MeasureMode, exports_src, isValidBorderStyle, parseBorderStyle, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, KeyEvent, PasteEvent, KeyHandler, InternalKeyHandler, RGBA, hexToRgb, rgbToHex, hsvToRgb, parseColor, fonts, measureText, getCharacterPositions, coordinateToCharacterIndex, renderFontToFrameBuffer, TextAttributes, ATTRIBUTE_BASE_BITS, ATTRIBUTE_BASE_MASK, getBaseAttributes, DebugOverlayCorner, TargetChannel, createTextAttributes, attributesWithLink, getLinkId, 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, link, t, hastToStyledText, SystemClock, nonAlphanumericKeys, parseKeypress, LinearScrollAccel, MacOSScrollAccel, parseAlign, parseAlignItems, parseBoxSizing, parseDimension, parseDirection, parseDisplay, parseEdge, parseFlexDirection, parseGutter, parseJustify, parseLogLevel, parseMeasureMode, parseOverflow, parsePositionType, parseUnit, parseWrap, MouseParser, Selection, convertGlobalToLocalSelection, ASCIIFontSelectionHelper, envRegistry, registerEnvVar, clearEnvCache, generateEnvMarkdown, generateEnvColored, env, StdinParser, treeSitterToTextChunks, treeSitterToStyledText, addDefaultParsers, TreeSitterClient, DataPathsManager, getDataPaths, extensionToFiletype, basenameToFiletype, extToFiletype, pathToFiletype, infoStringToFiletype, main, getTreeSitterClient, ExtmarksController, createExtmarksController, TerminalPalette, createTerminalPalette, decodePasteBytes, stripAnsiSequences, detectLinks, TextBuffer, SpanInfoStruct, LogLevel2 as LogLevel, setRenderLibPath, resolveRenderLib, OptimizedBuffer, h, isVNode, maybeMakeRenderable, wrapWithDelegates, instantiate, delegate, isValidPercentage, LayoutEvents, RenderableEvents, isRenderable, BaseRenderable, Renderable, RootRenderable, EditBuffer, EditorView, ANSI, defaultKeyAliases, mergeKeyAliases, mergeKeyBindings, getKeyBindingAction, buildKeyBindingsMap, capture, ConsolePosition, TerminalConsole, getObjectsInViewport, EditBufferRenderableEvents, isEditBufferRenderable, EditBufferRenderable, buildKittyKeyboardFlags, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, RendererControlState, CliRenderer };
23736
+ export { __toESM, __commonJS, __export, __require, MeasureMode, exports_src, isValidBorderStyle, parseBorderStyle, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, KeyEvent, PasteEvent, KeyHandler, InternalKeyHandler, COLOR_TAG_RGB, COLOR_TAG_DEFAULT, DEFAULT_FOREGROUND_RGB, DEFAULT_BACKGROUND_RGB, normalizeIndexedColorIndex, ansi256IndexToRgb, decodeColorTag, RGBA, normalizeColorValue, hexToRgb, rgbToHex, hsvToRgb, parseColor, fonts, measureText, getCharacterPositions, coordinateToCharacterIndex, renderFontToFrameBuffer, TextAttributes, ATTRIBUTE_BASE_BITS, ATTRIBUTE_BASE_MASK, getBaseAttributes, DebugOverlayCorner, TargetChannel, createTextAttributes, attributesWithLink, getLinkId, 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, link, t, hastToStyledText, SystemClock, nonAlphanumericKeys, parseKeypress, LinearScrollAccel, MacOSScrollAccel, parseAlign, parseAlignItems, parseBoxSizing, parseDimension, parseDirection, parseDisplay, parseEdge, parseFlexDirection, parseGutter, parseJustify, parseLogLevel, parseMeasureMode, parseOverflow, parsePositionType, parseUnit, parseWrap, MouseParser, Selection, convertGlobalToLocalSelection, ASCIIFontSelectionHelper, envRegistry, registerEnvVar, clearEnvCache, generateEnvMarkdown, generateEnvColored, env, StdinParser, treeSitterToTextChunks, treeSitterToStyledText, addDefaultParsers, TreeSitterClient, DataPathsManager, getDataPaths, extensionToFiletype, basenameToFiletype, extToFiletype, pathToFiletype, infoStringToFiletype, main, getTreeSitterClient, ExtmarksController, createExtmarksController, TerminalPalette, createTerminalPalette, normalizeTerminalPalette, buildTerminalPaletteSignature, decodePasteBytes, stripAnsiSequences, detectLinks, TextBuffer, SpanInfoStruct, LogLevel2 as LogLevel, setRenderLibPath, resolveRenderLib, OptimizedBuffer, h, isVNode, maybeMakeRenderable, wrapWithDelegates, instantiate, delegate, LayoutEvents, RenderableEvents, isRenderable, BaseRenderable, Renderable, RootRenderable, TextBufferView, EditBuffer, EditorView, convertThemeToStyles, SyntaxStyle, ANSI, BoxRenderable, TextBufferRenderable, CodeRenderable, isTextNodeRenderable, TextNodeRenderable, RootTextNodeRenderable, TextRenderable, defaultKeyAliases, mergeKeyAliases, mergeKeyBindings, getKeyBindingAction, buildKeyBindingsMap, capture, ConsolePosition, TerminalConsole, getObjectsInViewport, EditBufferRenderableEvents, isEditBufferRenderable, EditBufferRenderable, calculateRenderGeometry, buildKittyKeyboardFlags, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, RendererControlState, CliRenderer };
20828
23737
 
20829
- //# debugId=9682C54D228A139264756E2164756E21
20830
- //# sourceMappingURL=index-xsfpee0k.js.map
23738
+ //# debugId=B1BCF94D9F983F0164756E2164756E21
23739
+ //# sourceMappingURL=index-4pvh4sbk.js.map