@opentui/core 0.2.3 → 0.2.5

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.
@@ -7140,6 +7140,9 @@ function canStillBeExplicitWidthCpr(state) {
7140
7140
  function canStillBeStartupCursorCpr(state) {
7141
7141
  return state.semicolons === 1;
7142
7142
  }
7143
+ function canStillBeStartupCursorCprPrefix(state) {
7144
+ return state.segments === 1 && state.semicolons <= 1;
7145
+ }
7143
7146
  function canStillBePixelResolution(state) {
7144
7147
  return state.firstParamValue === 4 && state.semicolons === 2;
7145
7148
  }
@@ -7290,6 +7293,61 @@ class StdinParser {
7290
7293
  this.reconcileDeferredStateWithProtocolContext();
7291
7294
  this.reconcileTimeoutState();
7292
7295
  }
7296
+ getAbortableStartupCursorCprState() {
7297
+ if (this.pending.length === 0) {
7298
+ return null;
7299
+ }
7300
+ switch (this.state.tag) {
7301
+ case "csi": {
7302
+ const bytes = this.pending.view();
7303
+ const firstParamStart = this.unitStart + 2;
7304
+ if (this.cursor < firstParamStart) {
7305
+ return null;
7306
+ }
7307
+ let firstParamValue = null;
7308
+ for (let index = firstParamStart;index < this.cursor; index += 1) {
7309
+ const byte = bytes[index];
7310
+ if (!isAsciiDigit(byte)) {
7311
+ return null;
7312
+ }
7313
+ firstParamValue = (firstParamValue ?? 0) * 10 + (byte - 48);
7314
+ }
7315
+ return {
7316
+ tag: "csi_parametric_ignored",
7317
+ semicolons: 0,
7318
+ segments: 1,
7319
+ hasDigit: this.cursor > firstParamStart,
7320
+ firstParamValue
7321
+ };
7322
+ }
7323
+ case "csi_parametric":
7324
+ case "csi_parametric_deferred":
7325
+ if (!canStillBeStartupCursorCprPrefix(this.state) || this.protocolContext.explicitWidthCprActive && canStillBeExplicitWidthCpr(this.state)) {
7326
+ return null;
7327
+ }
7328
+ return {
7329
+ tag: "csi_parametric_ignored",
7330
+ semicolons: this.state.semicolons,
7331
+ segments: this.state.segments,
7332
+ hasDigit: this.state.hasDigit,
7333
+ firstParamValue: this.state.firstParamValue
7334
+ };
7335
+ }
7336
+ return null;
7337
+ }
7338
+ abortPendingStartupCursorCpr() {
7339
+ this.ensureAlive();
7340
+ const nextState = this.getAbortableStartupCursorCprState();
7341
+ if (!nextState) {
7342
+ return;
7343
+ }
7344
+ this.state = nextState;
7345
+ if (this.pendingSinceMs === null) {
7346
+ this.markPending();
7347
+ }
7348
+ this.forceFlush = false;
7349
+ this.reconcileTimeoutState();
7350
+ }
7293
7351
  push(data) {
7294
7352
  this.ensureAlive();
7295
7353
  if (data.length === 0) {
@@ -7826,6 +7884,61 @@ class StdinParser {
7826
7884
  this.consumePrefix(this.cursor);
7827
7885
  continue;
7828
7886
  }
7887
+ case "csi_parametric_ignored": {
7888
+ if (this.cursor >= bytes.length) {
7889
+ if (!this.forceFlush) {
7890
+ this.markPending();
7891
+ return;
7892
+ }
7893
+ this.state = { tag: "ground" };
7894
+ this.consumePrefix(this.cursor);
7895
+ continue;
7896
+ }
7897
+ if (byte === ESC) {
7898
+ this.state = { tag: "ground" };
7899
+ this.consumePrefix(this.cursor);
7900
+ continue;
7901
+ }
7902
+ if (isAsciiDigit(byte)) {
7903
+ this.cursor += 1;
7904
+ this.state = {
7905
+ tag: "csi_parametric_ignored",
7906
+ semicolons: this.state.semicolons,
7907
+ segments: this.state.segments,
7908
+ hasDigit: true,
7909
+ firstParamValue: this.state.semicolons === 0 ? (this.state.firstParamValue ?? 0) * 10 + (byte - 48) : this.state.firstParamValue
7910
+ };
7911
+ continue;
7912
+ }
7913
+ if (byte === 59 && this.state.semicolons === 0 && this.state.hasDigit) {
7914
+ if (this.protocolContext.explicitWidthCprActive && this.state.firstParamValue === 1) {
7915
+ this.state = { tag: "csi" };
7916
+ continue;
7917
+ }
7918
+ this.cursor += 1;
7919
+ this.state = {
7920
+ tag: "csi_parametric_ignored",
7921
+ semicolons: 1,
7922
+ segments: 1,
7923
+ hasDigit: false,
7924
+ firstParamValue: this.state.firstParamValue
7925
+ };
7926
+ continue;
7927
+ }
7928
+ if (byte === 82 && this.state.semicolons === 1 && this.state.hasDigit) {
7929
+ const end = this.cursor + 1;
7930
+ this.state = { tag: "ground" };
7931
+ this.consumePrefix(end);
7932
+ continue;
7933
+ }
7934
+ if (this.state.semicolons === 0) {
7935
+ this.state = { tag: "csi" };
7936
+ continue;
7937
+ }
7938
+ this.state = { tag: "ground" };
7939
+ this.consumePrefix(this.cursor);
7940
+ continue;
7941
+ }
7829
7942
  case "csi_private_reply": {
7830
7943
  if (this.cursor >= bytes.length) {
7831
7944
  if (!this.forceFlush) {
@@ -12615,8 +12728,12 @@ function getOpenTUILib(libPath) {
12615
12728
  args: ["ptr", "u32"],
12616
12729
  returns: "u32"
12617
12730
  },
12731
+ getSplitOutputOffset: {
12732
+ args: ["ptr", "u32"],
12733
+ returns: "u32"
12734
+ },
12618
12735
  setPendingSplitFooterTransition: {
12619
- args: ["ptr", "u8", "u32", "u32", "u32", "u32"],
12736
+ args: ["ptr", "u8", "u32", "u32", "u32", "u32", "u32"],
12620
12737
  returns: "void"
12621
12738
  },
12622
12739
  clearPendingSplitFooterTransition: {
@@ -13882,8 +13999,11 @@ class FFIRenderLib {
13882
13999
  syncSplitScrollback(renderer, pinnedRenderOffset) {
13883
14000
  return this.opentui.symbols.syncSplitScrollback(renderer, pinnedRenderOffset);
13884
14001
  }
13885
- setPendingSplitFooterTransition(renderer, mode, sourceTopLine, sourceHeight, targetTopLine, targetHeight) {
13886
- this.opentui.symbols.setPendingSplitFooterTransition(renderer, mode, sourceTopLine, sourceHeight, targetTopLine, targetHeight);
14002
+ getSplitOutputOffset(renderer, surfaceOffset) {
14003
+ return this.opentui.symbols.getSplitOutputOffset(renderer, surfaceOffset);
14004
+ }
14005
+ setPendingSplitFooterTransition(renderer, mode, sourceTopLine, sourceHeight, targetTopLine, targetHeight, scrollLines) {
14006
+ this.opentui.symbols.setPendingSplitFooterTransition(renderer, mode, sourceTopLine, sourceHeight, targetTopLine, targetHeight, scrollLines);
13887
14007
  }
13888
14008
  clearPendingSplitFooterTransition(renderer) {
13889
14009
  this.opentui.symbols.clearPendingSplitFooterTransition(renderer);
@@ -21380,6 +21500,9 @@ class ExternalOutputQueue {
21380
21500
  writeSnapshot(commit) {
21381
21501
  this.commits.push(commit);
21382
21502
  }
21503
+ peek() {
21504
+ return this.commits;
21505
+ }
21383
21506
  claim(limit = Number.POSITIVE_INFINITY) {
21384
21507
  if (this.commits.length === 0) {
21385
21508
  return [];
@@ -21721,6 +21844,8 @@ class CliRenderer extends EventEmitter9 {
21721
21844
  clearOnShutdown = true;
21722
21845
  _suspendedMouseEnabled = false;
21723
21846
  _previousControlState = "idle" /* IDLE */;
21847
+ pendingSuspendedTerminalSetup = false;
21848
+ suspendedNonAltSurfacePreserved = false;
21724
21849
  capturedRenderable;
21725
21850
  lastOverRenderableNum = 0;
21726
21851
  lastOverRenderable;
@@ -21737,6 +21862,7 @@ class CliRenderer extends EventEmitter9 {
21737
21862
  _terminalHeight = 0;
21738
21863
  _terminalIsSetup = false;
21739
21864
  externalOutputQueue = new ExternalOutputQueue;
21865
+ pendingExternalOutputMode = null;
21740
21866
  realStdoutWrite;
21741
21867
  _useConsole = true;
21742
21868
  sigwinchHandler = (() => {
@@ -22205,6 +22331,13 @@ Captured external output:
22205
22331
  }
22206
22332
  set screenMode(mode) {
22207
22333
  if (this.externalOutputMode === "capture-stdout" && mode !== "split-footer") {
22334
+ if (this.pendingExternalOutputMode === "passthrough") {
22335
+ this.flushPendingSplitOutputBeforeLeavingSplitFooter();
22336
+ }
22337
+ if (this.externalOutputMode !== "capture-stdout") {
22338
+ this.applyScreenMode(mode);
22339
+ return;
22340
+ }
22208
22341
  throw new Error('externalOutputMode "capture-stdout" requires screenMode "split-footer"');
22209
22342
  }
22210
22343
  this.applyScreenMode(mode);
@@ -22231,16 +22364,49 @@ Captured external output:
22231
22364
  }
22232
22365
  const previousMode = this._externalOutputMode;
22233
22366
  if (previousMode === mode) {
22367
+ if (this.pendingExternalOutputMode !== null && this.pendingExternalOutputMode !== mode) {
22368
+ this.pendingExternalOutputMode = null;
22369
+ }
22370
+ return;
22371
+ }
22372
+ const canFlushSplitOutputBeforeTransition = this.canFlushSplitOutputBeforeTransition();
22373
+ const isSplitCaptureToPassthrough = previousMode === "capture-stdout" && mode === "passthrough" && this._screenMode === "split-footer" && this._splitHeight > 0;
22374
+ if (isSplitCaptureToPassthrough && this.externalOutputQueue.size > 0 && !canFlushSplitOutputBeforeTransition) {
22375
+ this.pendingExternalOutputMode = "passthrough";
22234
22376
  return;
22235
22377
  }
22236
- if (previousMode === "capture-stdout" && mode === "passthrough" && this._splitHeight > 0) {
22378
+ if (isSplitCaptureToPassthrough && canFlushSplitOutputBeforeTransition) {
22237
22379
  this.flushPendingSplitOutputBeforeTransition();
22238
22380
  }
22381
+ this.pendingExternalOutputMode = null;
22382
+ this.applyExternalOutputMode(mode);
22383
+ this.afterExternalOutputModeChanged(previousMode, mode);
22384
+ }
22385
+ applyExternalOutputMode(mode) {
22239
22386
  this._externalOutputMode = mode;
22240
22387
  this.stdout.write = mode === "capture-stdout" ? this.interceptStdoutWrite : this.realStdoutWrite;
22388
+ }
22389
+ afterExternalOutputModeChanged(previousMode, mode) {
22241
22390
  if (this._screenMode === "split-footer" && this._splitHeight > 0 && mode === "capture-stdout") {
22391
+ const previousSurfaceTopLine = this.renderOffset + 1;
22392
+ const previousSurfaceHeight = this._splitHeight;
22242
22393
  this.clearPendingSplitFooterTransition();
22243
22394
  this.resetSplitScrollback(this.getSplitCursorSeedRows());
22395
+ if (previousMode === "passthrough" && this._terminalIsSetup) {
22396
+ const nextSurfaceTopLine = this.renderOffset + 1;
22397
+ if (previousSurfaceTopLine !== nextSurfaceTopLine) {
22398
+ this.setPendingSplitFooterTransition({
22399
+ mode: "clear-stale-rows",
22400
+ sourceTopLine: previousSurfaceTopLine,
22401
+ sourceHeight: previousSurfaceHeight,
22402
+ targetTopLine: nextSurfaceTopLine,
22403
+ targetHeight: this._splitHeight,
22404
+ scrollLines: 0
22405
+ });
22406
+ this.forceFullRepaintRequested = true;
22407
+ }
22408
+ }
22409
+ this.requestRender();
22244
22410
  return;
22245
22411
  }
22246
22412
  if (this._screenMode === "split-footer" && this._splitHeight > 0 && previousMode === "capture-stdout" && mode === "passthrough") {
@@ -22249,6 +22415,31 @@ Captured external output:
22249
22415
  }
22250
22416
  this.syncSplitFooterState();
22251
22417
  }
22418
+ applyPendingExternalOutputModeIfReady() {
22419
+ const pendingMode = this.pendingExternalOutputMode;
22420
+ if (pendingMode === null || this.externalOutputQueue.size > 0) {
22421
+ return;
22422
+ }
22423
+ const previousMode = this._externalOutputMode;
22424
+ this.pendingExternalOutputMode = null;
22425
+ if (previousMode === pendingMode) {
22426
+ return;
22427
+ }
22428
+ this.applyExternalOutputMode(pendingMode);
22429
+ this.afterExternalOutputModeChanged(previousMode, pendingMode);
22430
+ }
22431
+ flushPendingSplitOutputBeforeLeavingSplitFooter() {
22432
+ if (this.pendingExternalOutputMode !== "passthrough") {
22433
+ return;
22434
+ }
22435
+ if (this.isSplitCursorSeedFrameBlocked() && this._controlState !== "explicit_suspended" /* EXPLICIT_SUSPENDED */) {
22436
+ this.abortSplitStartupCursorSeed();
22437
+ }
22438
+ this.flushPendingSplitOutputBeforeTransition();
22439
+ if (this.pendingExternalOutputMode !== null) {
22440
+ throw new Error("Cannot leave split-footer while captured output is pending");
22441
+ }
22442
+ }
22252
22443
  get liveRequestCount() {
22253
22444
  return this.liveRequestCounter;
22254
22445
  }
@@ -22284,7 +22475,8 @@ Captured external output:
22284
22475
  const renderer = this;
22285
22476
  const surfaceId = scrollbackSurfaceCounter++;
22286
22477
  const startOnNewLine = options.startOnNewLine ?? true;
22287
- const firstLineOffset = !startOnNewLine && renderer.splitTailColumn > 0 && renderer.splitTailColumn < renderer.width ? renderer.splitTailColumn : 0;
22478
+ const tailColumn = renderer.getPendingSplitTailColumn();
22479
+ const firstLineOffset = !startOnNewLine && tailColumn > 0 && tailColumn < renderer.width ? tailColumn : 0;
22288
22480
  const snapshotContext = new ScrollbackSnapshotRenderContext(renderer.width, 1, renderer.widthMethod);
22289
22481
  let firstLineOffsetOwner = null;
22290
22482
  const renderContext = Object.create(snapshotContext);
@@ -22473,7 +22665,7 @@ Captured external output:
22473
22665
  snapshot: commitBuffer,
22474
22666
  rowColumns: commitOptions.rowColumns,
22475
22667
  startOnNewLine: nextCommitStartOnNewLine,
22476
- trailingNewline: commitOptions.trailingNewline ?? false
22668
+ trailingNewline: commitOptions.trailingNewline ?? true
22477
22669
  });
22478
22670
  nextCommitStartOnNewLine = false;
22479
22671
  } catch (error) {
@@ -22537,7 +22729,7 @@ Captured external output:
22537
22729
  const snapshot = write({
22538
22730
  width: this.width,
22539
22731
  widthMethod: this.widthMethod,
22540
- tailColumn: this.splitTailColumn,
22732
+ tailColumn: this.getPendingSplitTailColumn(),
22541
22733
  renderContext: snapshotContext
22542
22734
  });
22543
22735
  if (!snapshot || !snapshot.root) {
@@ -22624,12 +22816,11 @@ Captured external output:
22624
22816
  }
22625
22817
  return widths;
22626
22818
  }
22627
- publishSplitTailColumns(columns) {
22819
+ advanceSplitTailColumn(tailColumn, columns, width) {
22628
22820
  if (columns <= 0) {
22629
- return;
22821
+ return tailColumn;
22630
22822
  }
22631
- const width = Math.max(this.width, 1);
22632
- let tail = this.splitTailColumn;
22823
+ let tail = tailColumn;
22633
22824
  let remaining = columns;
22634
22825
  while (remaining > 0) {
22635
22826
  if (tail >= width) {
@@ -22642,19 +22833,32 @@ Captured external output:
22642
22833
  tail = 0;
22643
22834
  }
22644
22835
  }
22645
- this.splitTailColumn = tail;
22836
+ return tail;
22646
22837
  }
22647
- recordSplitCommit(commit) {
22648
- if (commit.startOnNewLine && this.splitTailColumn > 0) {
22649
- this.splitTailColumn = 0;
22838
+ getSplitTailColumnAfterCommit(commit, initialTailColumn, width) {
22839
+ let tailColumn = initialTailColumn;
22840
+ if (commit.startOnNewLine && tailColumn > 0) {
22841
+ tailColumn = 0;
22650
22842
  }
22651
22843
  const rowWidths = this.getSnapshotRowWidths(commit.snapshot, commit.rowColumns);
22652
22844
  for (const [index, rowWidth] of rowWidths.entries()) {
22653
- this.publishSplitTailColumns(rowWidth);
22845
+ tailColumn = this.advanceSplitTailColumn(tailColumn, rowWidth, width);
22654
22846
  if (index < rowWidths.length - 1 || commit.trailingNewline) {
22655
- this.splitTailColumn = 0;
22847
+ tailColumn = 0;
22656
22848
  }
22657
22849
  }
22850
+ return tailColumn;
22851
+ }
22852
+ recordSplitCommit(commit) {
22853
+ this.splitTailColumn = this.getSplitTailColumnAfterCommit(commit, this.splitTailColumn, Math.max(this.width, 1));
22854
+ }
22855
+ getPendingSplitTailColumn() {
22856
+ const width = Math.max(this.width, 1);
22857
+ let tailColumn = this.splitTailColumn;
22858
+ for (const commit of this.externalOutputQueue.peek()) {
22859
+ tailColumn = this.getSplitTailColumnAfterCommit(commit, tailColumn, width);
22860
+ }
22861
+ return tailColumn;
22658
22862
  }
22659
22863
  enqueueRenderedScrollbackCommit(options) {
22660
22864
  if (this._screenMode !== "split-footer" || this._externalOutputMode !== "capture-stdout") {
@@ -22670,7 +22874,6 @@ Captured external output:
22670
22874
  this.requestRender();
22671
22875
  }
22672
22876
  enqueueSplitCommit(commit) {
22673
- this.recordSplitCommit(commit);
22674
22877
  this.externalOutputQueue.writeSnapshot(commit);
22675
22878
  }
22676
22879
  createStdoutSnapshotCommit(line, trailingNewline) {
@@ -22751,8 +22954,8 @@ Captured external output:
22751
22954
  }
22752
22955
  return commits;
22753
22956
  }
22754
- flushPendingSplitCommits(forceFooterRepaint = false) {
22755
- const commits = this.externalOutputQueue.claim(this.maxSplitCommitsPerFrame);
22957
+ flushPendingSplitCommits(forceFooterRepaint = false, drainAll = false) {
22958
+ const commits = this.externalOutputQueue.claim(drainAll ? Number.POSITIVE_INFINITY : this.maxSplitCommitsPerFrame);
22756
22959
  let hasCommittedOutput = false;
22757
22960
  const lastCommitIndex = commits.length - 1;
22758
22961
  for (const [index, commit] of commits.entries()) {
@@ -22761,6 +22964,7 @@ Captured external output:
22761
22964
  const finalizeFrame = index === lastCommitIndex;
22762
22965
  try {
22763
22966
  this.renderOffset = this.lib.commitSplitFooterSnapshot(this.rendererPtr, commit.snapshot, commit.rowColumns, commit.startOnNewLine, commit.trailingNewline, this.getSplitPinnedRenderOffset(), forceCommit, beginFrame, finalizeFrame);
22967
+ this.recordSplitCommit(commit);
22764
22968
  hasCommittedOutput = true;
22765
22969
  } finally {
22766
22970
  commit.snapshot.destroy();
@@ -22772,6 +22976,8 @@ Captured external output:
22772
22976
  this.pendingSplitFooterTransition = null;
22773
22977
  if (this.externalOutputQueue.size > 0) {
22774
22978
  this.requestRender();
22979
+ } else {
22980
+ this.applyPendingExternalOutputModeIfReady();
22775
22981
  }
22776
22982
  }
22777
22983
  interceptStdoutWrite = (chunk, encoding, callback) => {
@@ -22800,14 +23006,37 @@ Captured external output:
22800
23006
  const cursorRow = Number.isFinite(cursorState.y) ? Math.max(Math.trunc(cursorState.y), 1) : 1;
22801
23007
  return Math.min(cursorRow, Math.max(this._terminalHeight, 1));
22802
23008
  }
22803
- flushPendingSplitOutputBeforeTransition(forceFooterRepaint = false) {
22804
- if (this._screenMode !== "split-footer" || this._splitHeight <= 0 || this._externalOutputMode !== "capture-stdout") {
23009
+ isSplitCursorSeedFrameBlocked() {
23010
+ return this._screenMode === "split-footer" && this._externalOutputMode === "capture-stdout" && this._splitHeight > 0 && this.pendingSplitStartupCursorSeed && this.splitStartupSeedTimeoutId !== null;
23011
+ }
23012
+ canFlushSplitOutputBeforeTransition(allowSuspended = false) {
23013
+ return this._terminalIsSetup && (allowSuspended || this._controlState !== "explicit_suspended" /* EXPLICIT_SUSPENDED */) && !this.isSplitCursorSeedFrameBlocked();
23014
+ }
23015
+ clearSplitStartupCursorSeed() {
23016
+ this.pendingSplitStartupCursorSeed = false;
23017
+ if (this.splitStartupSeedTimeoutId !== null) {
23018
+ this.clock.clearTimeout(this.splitStartupSeedTimeoutId);
23019
+ this.splitStartupSeedTimeoutId = null;
23020
+ }
23021
+ }
23022
+ abortSplitStartupCursorSeed() {
23023
+ this.clearSplitStartupCursorSeed();
23024
+ this.stdinParser?.abortPendingStartupCursorCpr();
23025
+ this.updateStdinParserProtocolContext({ startupCursorCprActive: false });
23026
+ }
23027
+ flushPendingSplitOutputBeforeTransition(forceFooterRepaint = false, options = {}) {
23028
+ const hasDeferredCapturedOutput = this.externalOutputQueue.size > 0 || this.pendingExternalOutputMode !== null;
23029
+ if (this._screenMode !== "split-footer" || this._splitHeight <= 0 || this._externalOutputMode !== "capture-stdout" && !(options.allowPassthrough && hasDeferredCapturedOutput)) {
23030
+ return;
23031
+ }
23032
+ if (!this.canFlushSplitOutputBeforeTransition(options.allowSuspended ?? false)) {
22805
23033
  return;
22806
23034
  }
22807
23035
  if (this.externalOutputQueue.size === 0 && !forceFooterRepaint) {
23036
+ this.applyPendingExternalOutputModeIfReady();
22808
23037
  return;
22809
23038
  }
22810
- this.flushPendingSplitCommits(forceFooterRepaint);
23039
+ this.flushPendingSplitCommits(this._externalOutputMode === "capture-stdout" ? forceFooterRepaint : false, true);
22811
23040
  }
22812
23041
  resetSplitScrollback(seedRows = 0) {
22813
23042
  this.splitTailColumn = 0;
@@ -22816,6 +23045,9 @@ Captured external output:
22816
23045
  syncSplitScrollback() {
22817
23046
  this.renderOffset = this.lib.syncSplitScrollback(this.rendererPtr, this.getSplitPinnedRenderOffset());
22818
23047
  }
23048
+ getSplitOutputOffset(surfaceOffset = this.renderOffset) {
23049
+ return this.lib.getSplitOutputOffset(this.rendererPtr, surfaceOffset);
23050
+ }
22819
23051
  clearPendingSplitFooterTransition() {
22820
23052
  if (this.pendingSplitFooterTransition === null) {
22821
23053
  return;
@@ -22825,7 +23057,7 @@ Captured external output:
22825
23057
  }
22826
23058
  setPendingSplitFooterTransition(transition) {
22827
23059
  this.pendingSplitFooterTransition = transition;
22828
- this.lib.setPendingSplitFooterTransition(this.rendererPtr, transition.mode === "viewport-scroll" ? 1 : 2, transition.sourceTopLine, transition.sourceHeight, transition.targetTopLine, transition.targetHeight);
23060
+ this.lib.setPendingSplitFooterTransition(this.rendererPtr, transition.mode === "viewport-scroll" ? 1 : 2, transition.sourceTopLine, transition.sourceHeight, transition.targetTopLine, transition.targetHeight, transition.scrollLines ?? 0);
22829
23061
  }
22830
23062
  syncSplitFooterState() {
22831
23063
  const splitActive = this._screenMode === "split-footer" && this._splitHeight > 0;
@@ -22878,38 +23110,47 @@ Captured external output:
22878
23110
  if (prevScreenMode === screenMode && prevSplitHeight === nextSplitHeight) {
22879
23111
  return;
22880
23112
  }
23113
+ const terminalWritable = this._terminalIsSetup && this._controlState !== "explicit_suspended" /* EXPLICIT_SUSPENDED */;
22881
23114
  const prevUseAlternateScreen = prevScreenMode === "alternate-screen";
22882
23115
  const nextUseAlternateScreen = screenMode === "alternate-screen";
22883
23116
  const terminalScreenModeChanged = this._terminalIsSetup && prevUseAlternateScreen !== nextUseAlternateScreen;
22884
23117
  const leavingSplitFooter = prevSplitHeight > 0 && nextSplitHeight === 0;
22885
- if (this._terminalIsSetup && prevSplitHeight > 0) {
23118
+ if (terminalWritable && prevSplitHeight > 0) {
22886
23119
  this.flushPendingSplitOutputBeforeTransition();
22887
23120
  }
22888
23121
  const previousSurfaceTopLine = this.renderOffset + 1;
22889
- const previousPinnedRenderOffset = Math.max(this._terminalHeight - prevSplitHeight, 0);
22890
- const splitWasSettled = prevSplitHeight === 0 || this.renderOffset >= previousPinnedRenderOffset;
22891
- const shouldUseViewportScrollTransitions = this._externalOutputMode !== "capture-stdout" || splitWasSettled;
22892
23122
  const shouldDeferSplitFooterResizeTransition = this._terminalIsSetup && prevScreenMode === "split-footer" && screenMode === "split-footer" && this._externalOutputMode === "capture-stdout" && prevSplitHeight > 0 && nextSplitHeight > 0 && !terminalScreenModeChanged;
22893
23123
  const splitStartupSeedBlocksFirstNativeFrame = this.pendingSplitStartupCursorSeed && this.splitStartupSeedTimeoutId !== null;
22894
23124
  const splitTransitionSourceTopLine = this.pendingSplitFooterTransition?.sourceTopLine ?? previousSurfaceTopLine;
22895
23125
  const splitTransitionSourceHeight = this.pendingSplitFooterTransition?.sourceHeight ?? prevSplitHeight;
22896
- const splitTransitionMode = this.pendingSplitFooterTransition?.mode ?? (splitWasSettled ? "viewport-scroll" : "clear-stale-rows");
22897
- if (this._terminalIsSetup && leavingSplitFooter) {
23126
+ const splitTransitionSourceSurfaceOffset = Math.max(splitTransitionSourceTopLine - 1, 0);
23127
+ const splitTransitionSourceOutputOffset = prevScreenMode === "split-footer" && prevSplitHeight > 0 && this._externalOutputMode === "capture-stdout" ? this.getSplitOutputOffset(splitTransitionSourceSurfaceOffset) : splitTransitionSourceSurfaceOffset;
23128
+ const nextPinnedRenderOffset = nextGeometry.renderOffset;
23129
+ const nextSplitOutputOffset = screenMode === "split-footer" && nextSplitHeight > 0 && this._externalOutputMode === "capture-stdout" ? this.getSplitOutputOffset(nextPinnedRenderOffset) : nextPinnedRenderOffset;
23130
+ const pendingSplitFooterTransition = this.pendingSplitFooterTransition;
23131
+ const pendingSplitFooterReturn = pendingSplitFooterTransition !== null && nextSplitHeight === splitTransitionSourceHeight;
23132
+ const pendingSplitFooterViewportReturn = pendingSplitFooterReturn && pendingSplitFooterTransition.mode === "viewport-scroll" && (pendingSplitFooterTransition.scrollLines ?? 0) > 0;
23133
+ const shrinkingSplitFooter = nextSplitHeight > 0 && nextSplitHeight < splitTransitionSourceHeight;
23134
+ const growingSplitFooter = nextSplitHeight > splitTransitionSourceHeight && splitTransitionSourceHeight > 0;
23135
+ const nextSplitSurfaceOffset = screenMode !== "split-footer" || nextSplitHeight === 0 ? 0 : pendingSplitFooterViewportReturn ? pendingSplitFooterTransition.targetTopLine - 1 : pendingSplitFooterReturn ? splitTransitionSourceSurfaceOffset : shrinkingSplitFooter && splitTransitionSourceSurfaceOffset > 0 ? splitTransitionSourceSurfaceOffset : shrinkingSplitFooter ? nextSplitOutputOffset : growingSplitFooter ? Math.max(nextSplitOutputOffset, Math.min(splitTransitionSourceSurfaceOffset, nextPinnedRenderOffset)) : nextPinnedRenderOffset;
23136
+ const splitTransitionTargetTopLine = nextSplitSurfaceOffset + 1;
23137
+ const splitViewportScrollLines = pendingSplitFooterViewportReturn ? pendingSplitFooterTransition.scrollLines ?? 0 : nextSplitHeight > 0 && !pendingSplitFooterReturn ? Math.max(splitTransitionSourceOutputOffset - nextSplitOutputOffset, 0) : 0;
23138
+ const splitTransitionMode = (!shrinkingSplitFooter || pendingSplitFooterViewportReturn) && splitViewportScrollLines > 0 ? "viewport-scroll" : "clear-stale-rows";
23139
+ const splitFooterSurfaceMovesDown = nextSplitSurfaceOffset > splitTransitionSourceSurfaceOffset;
23140
+ const splitFooterSurfaceLeavesStaleRows = splitFooterSurfaceMovesDown || shrinkingSplitFooter;
23141
+ const shouldClearSplitSurfaceRowsImmediately = terminalWritable && !terminalScreenModeChanged && !shouldDeferSplitFooterResizeTransition && splitFooterSurfaceLeavesStaleRows && nextSplitHeight > 0;
23142
+ if (terminalWritable && leavingSplitFooter) {
22898
23143
  this.clearPendingSplitFooterTransition();
22899
23144
  this.renderOffset = 0;
22900
23145
  this.lib.setRenderOffset(this.rendererPtr, 0);
22901
23146
  }
22902
- if (this._terminalIsSetup && !terminalScreenModeChanged && shouldUseViewportScrollTransitions && !shouldDeferSplitFooterResizeTransition) {
23147
+ if (terminalWritable && !terminalScreenModeChanged && !shouldDeferSplitFooterResizeTransition) {
22903
23148
  if (prevSplitHeight === 0 && nextSplitHeight > 0) {
22904
23149
  const freedLines = this._terminalHeight - nextSplitHeight;
22905
23150
  const scrollDown = ANSI.scrollDown(freedLines);
22906
23151
  this.writeOut(scrollDown);
22907
- } else if (prevSplitHeight > nextSplitHeight && nextSplitHeight > 0) {
22908
- const freedLines = prevSplitHeight - nextSplitHeight;
22909
- const scrollDown = ANSI.scrollDown(freedLines);
22910
- this.writeOut(scrollDown);
22911
- } else if (prevSplitHeight < nextSplitHeight && prevSplitHeight > 0) {
22912
- const additionalLines = nextSplitHeight - prevSplitHeight;
23152
+ } else if (splitViewportScrollLines > 0) {
23153
+ const additionalLines = splitViewportScrollLines;
22913
23154
  const scrollUp = ANSI.scrollUp(additionalLines);
22914
23155
  this.writeOut(scrollUp);
22915
23156
  }
@@ -22923,7 +23164,8 @@ Captured external output:
22923
23164
  if (prevScreenMode !== "split-footer") {
22924
23165
  this.resetSplitScrollback(this.getSplitCursorSeedRows());
22925
23166
  } else {
22926
- this.syncSplitScrollback();
23167
+ this.renderOffset = nextSplitSurfaceOffset;
23168
+ this.lib.setRenderOffset(this.rendererPtr, this.renderOffset);
22927
23169
  }
22928
23170
  if (shouldDeferSplitFooterResizeTransition) {
22929
23171
  if (splitStartupSeedBlocksFirstNativeFrame) {
@@ -22933,28 +23175,37 @@ Captured external output:
22933
23175
  mode: splitTransitionMode,
22934
23176
  sourceTopLine: splitTransitionSourceTopLine,
22935
23177
  sourceHeight: splitTransitionSourceHeight,
22936
- targetTopLine: this.renderOffset + 1,
22937
- targetHeight: nextSplitHeight
23178
+ targetTopLine: splitTransitionTargetTopLine,
23179
+ targetHeight: nextSplitHeight,
23180
+ scrollLines: splitViewportScrollLines
22938
23181
  });
22939
23182
  }
22940
23183
  this.forceFullRepaintRequested = true;
22941
- } else if (!shouldUseViewportScrollTransitions && prevSplitHeight > 0 && nextSplitHeight > 0) {
23184
+ } else if (shouldClearSplitSurfaceRowsImmediately) {
22942
23185
  this.clearPendingSplitFooterTransition();
22943
- this.clearStaleSplitSurfaceRows(previousSurfaceTopLine, prevSplitHeight, this.renderOffset + 1, nextSplitHeight);
23186
+ this.clearStaleSplitSurfaceRows(splitTransitionSourceTopLine, splitTransitionSourceHeight, splitTransitionTargetTopLine, nextSplitHeight);
22944
23187
  } else {
22945
23188
  this.clearPendingSplitFooterTransition();
22946
23189
  }
22947
23190
  } else {
22948
23191
  this.syncSplitFooterState();
23192
+ if (shouldClearSplitSurfaceRowsImmediately) {
23193
+ this.clearStaleSplitSurfaceRows(splitTransitionSourceTopLine, splitTransitionSourceHeight, this.renderOffset + 1, nextSplitHeight);
23194
+ }
22949
23195
  }
22950
23196
  this.nextRenderBuffer = this.lib.getNextBuffer(this.rendererPtr);
22951
23197
  this.currentRenderBuffer = this.lib.getCurrentBuffer(this.rendererPtr);
22952
23198
  this._console.resize(this.width, this.height);
22953
23199
  this.root.resize(this.width, this.height);
22954
23200
  if (terminalScreenModeChanged) {
22955
- this.lib.suspendRenderer(this.rendererPtr);
22956
- this.lib.setupTerminal(this.rendererPtr, nextUseAlternateScreen);
22957
- if (this._useMouse) {
23201
+ if (terminalWritable) {
23202
+ this.lib.suspendRenderer(this.rendererPtr);
23203
+ this.lib.setupTerminal(this.rendererPtr, nextUseAlternateScreen);
23204
+ this.pendingSuspendedTerminalSetup = false;
23205
+ } else {
23206
+ this.pendingSuspendedTerminalSetup = true;
23207
+ }
23208
+ if (terminalWritable && this._useMouse) {
22958
23209
  this.enableMouse();
22959
23210
  }
22960
23211
  }
@@ -23037,11 +23288,7 @@ Captured external output:
23037
23288
  }
23038
23289
  this.capabilityTimeoutId = this.clock.setTimeout(() => {
23039
23290
  this.capabilityTimeoutId = null;
23040
- this.pendingSplitStartupCursorSeed = false;
23041
- if (this.splitStartupSeedTimeoutId !== null) {
23042
- this.clock.clearTimeout(this.splitStartupSeedTimeoutId);
23043
- this.splitStartupSeedTimeoutId = null;
23044
- }
23291
+ this.clearSplitStartupCursorSeed();
23045
23292
  if (this._screenMode === "split-footer" && this._externalOutputMode === "capture-stdout") {
23046
23293
  this.requestRender();
23047
23294
  }
@@ -23070,6 +23317,7 @@ Captured external output:
23070
23317
  if (this._screenMode === "split-footer" && this._externalOutputMode === "capture-stdout") {
23071
23318
  this.requestRender();
23072
23319
  }
23320
+ this.flushPendingSplitOutputBeforeTransition(false, { allowPassthrough: true });
23073
23321
  }, 120);
23074
23322
  }
23075
23323
  this.queryPixelResolution();
@@ -23130,13 +23378,12 @@ Captured external output:
23130
23378
  if (hadPendingSplitStartupCursorSeed && hasCursorReport && this._screenMode === "split-footer" && this._externalOutputMode === "capture-stdout") {
23131
23379
  this.resetSplitScrollback(this.getSplitCursorSeedRows());
23132
23380
  this.clearPendingSplitFooterTransition();
23133
- this.pendingSplitStartupCursorSeed = false;
23381
+ this.clearSplitStartupCursorSeed();
23134
23382
  this.updateStdinParserProtocolContext({ startupCursorCprActive: false });
23135
- if (this.splitStartupSeedTimeoutId !== null) {
23136
- this.clock.clearTimeout(this.splitStartupSeedTimeoutId);
23137
- this.splitStartupSeedTimeoutId = null;
23138
- }
23139
23383
  this.requestRender();
23384
+ if (this.pendingExternalOutputMode === "passthrough") {
23385
+ this.flushPendingSplitOutputBeforeTransition();
23386
+ }
23140
23387
  }
23141
23388
  const consumeStartupCursorReport = hadPendingSplitStartupCursorSeed && hasCursorReport && this.splitStartupSeedTimeoutId !== null;
23142
23389
  return hasStandardCapabilitySignature || consumeStartupCursorReport;
@@ -23499,7 +23746,7 @@ Captured external output:
23499
23746
  processResize(width, height) {
23500
23747
  if (width === this._terminalWidth && height === this._terminalHeight)
23501
23748
  return;
23502
- if (this._terminalIsSetup && this._controlState !== "explicit_suspended" /* EXPLICIT_SUSPENDED */) {
23749
+ if (this._terminalIsSetup && this._controlState !== "explicit_suspended" /* EXPLICIT_SUSPENDED */ && !this.isSplitCursorSeedFrameBlocked()) {
23503
23750
  this.flushPendingSplitOutputBeforeTransition();
23504
23751
  }
23505
23752
  const pendingSplitFooterTransition = this.pendingSplitFooterTransition;
@@ -23686,7 +23933,11 @@ Captured external output:
23686
23933
  this._controlState = "explicit_suspended" /* EXPLICIT_SUSPENDED */;
23687
23934
  this.internalPause();
23688
23935
  if (this._terminalIsSetup) {
23689
- this.flushPendingSplitOutputBeforeTransition(true);
23936
+ this.clearSplitStartupCursorSeed();
23937
+ this.flushPendingSplitOutputBeforeTransition(true, { allowSuspended: true });
23938
+ this.suspendedNonAltSurfacePreserved = this._screenMode !== "alternate-screen" && this.renderOffset > 0;
23939
+ } else {
23940
+ this.suspendedNonAltSurfacePreserved = false;
23690
23941
  }
23691
23942
  this._suspendedMouseEnabled = this._useMouse;
23692
23943
  this.disableMouse();
@@ -23715,7 +23966,19 @@ Captured external output:
23715
23966
  this.stdin.on("data", this.stdinListener);
23716
23967
  this.stdin.resume();
23717
23968
  this.addExitListeners();
23718
- this.lib.resumeRenderer(this.rendererPtr);
23969
+ const resumePreservedNonAltSurface = this.pendingSuspendedTerminalSetup && this._screenMode !== "alternate-screen" && this.suspendedNonAltSurfacePreserved && this.renderOffset > 0;
23970
+ if (this.pendingSuspendedTerminalSetup) {
23971
+ this.pendingSuspendedTerminalSetup = false;
23972
+ if (resumePreservedNonAltSurface) {
23973
+ this.lib.resumeRenderer(this.rendererPtr);
23974
+ } else {
23975
+ this.lib.setupTerminal(this.rendererPtr, this._screenMode === "alternate-screen");
23976
+ }
23977
+ } else {
23978
+ this.lib.resumeRenderer(this.rendererPtr);
23979
+ }
23980
+ this.suspendedNonAltSurfacePreserved = false;
23981
+ this.flushPendingSplitOutputBeforeTransition(false, { allowSuspended: true, allowPassthrough: true });
23719
23982
  if (this._screenMode === "split-footer" && this._splitHeight > 0) {
23720
23983
  this.syncSplitFooterState();
23721
23984
  }
@@ -23790,10 +24053,7 @@ Captured external output:
23790
24053
  this.clock.clearTimeout(this.capabilityTimeoutId);
23791
24054
  this.capabilityTimeoutId = null;
23792
24055
  }
23793
- if (this.splitStartupSeedTimeoutId !== null) {
23794
- this.clock.clearTimeout(this.splitStartupSeedTimeoutId);
23795
- this.splitStartupSeedTimeoutId = null;
23796
- }
24056
+ this.clearSplitStartupCursorSeed();
23797
24057
  if (this.memorySnapshotTimer) {
23798
24058
  this.clock.clearInterval(this.memorySnapshotTimer);
23799
24059
  this.memorySnapshotTimer = null;
@@ -23862,6 +24122,7 @@ Captured external output:
23862
24122
  }
23863
24123
  }
23864
24124
  this._externalOutputMode = "passthrough";
24125
+ this.pendingExternalOutputMode = null;
23865
24126
  this.stdout.write = this.realStdoutWrite;
23866
24127
  this.externalOutputQueue.clear();
23867
24128
  this.lib.destroyRenderer(this.rendererPtr);
@@ -23973,14 +24234,14 @@ Captured external output:
23973
24234
  throw new Error("Rendering called concurrently");
23974
24235
  }
23975
24236
  this.renderingNative = true;
23976
- if (this.pendingSplitStartupCursorSeed && this.splitStartupSeedTimeoutId !== null && this._splitHeight > 0 && this._externalOutputMode === "capture-stdout") {
24237
+ if (this.isSplitCursorSeedFrameBlocked()) {
23977
24238
  this.renderingNative = false;
23978
24239
  return;
23979
24240
  }
23980
24241
  if (this._splitHeight > 0 && this._externalOutputMode === "capture-stdout") {
23981
24242
  const forceSplitRepaint = this.forceFullRepaintRequested;
23982
24243
  this.forceFullRepaintRequested = false;
23983
- this.flushPendingSplitCommits(forceSplitRepaint);
24244
+ this.flushPendingSplitCommits(forceSplitRepaint, this.pendingExternalOutputMode === "passthrough");
23984
24245
  this.pendingSplitFooterTransition = null;
23985
24246
  } else {
23986
24247
  const force = this.forceFullRepaintRequested;
@@ -24295,5 +24556,5 @@ Captured external output:
24295
24556
 
24296
24557
  export { __export, __require, MeasureMode, exports_src, isValidBorderStyle, parseBorderStyle, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, KeyEvent, PasteEvent, KeyHandler, InternalKeyHandler, DEFAULT_FOREGROUND_RGB, DEFAULT_BACKGROUND_RGB, normalizeIndexedColorIndex, ansi256IndexToRgb, 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, terminalNamedSingleStrokeKeys, 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, stringWidth2 as stringWidth, ExtmarksController, createExtmarksController, TerminalPalette, createTerminalPalette, normalizeTerminalPalette, buildTerminalPaletteSignature, decodePasteBytes, stripAnsiSequences, detectLinks, toArrayBuffer, 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 };
24297
24558
 
24298
- //# debugId=A8199A30ABCACF0064756E2164756E21
24299
- //# sourceMappingURL=index-hmk8xzt3.js.map
24559
+ //# debugId=355172C54650946864756E2164756E21
24560
+ //# sourceMappingURL=index-s460mpf9.js.map