@simon_he/vue-tui 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2262 -266
- package/dist/index.d.ts +180 -106
- package/dist/index.js +1966 -217
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { isAbsolutePath, normalizePath, parsePathQuery, resolvePath, resolveUserPath as resolveUserPath$1, resolveUserPath$1 as resolveUserPath, stripTrailingSlash, suggestPaths, suggestPaths$1 } from "./path-suggest-CZQYJIIg.js";
|
|
2
|
-
import process from "node:process";
|
|
2
|
+
import process$1 from "node:process";
|
|
3
3
|
import { appendFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { Buffer } from "node:buffer";
|
|
5
5
|
import { EventEmitter } from "node:events";
|
|
6
|
-
import { computed, createRenderer, defineComponent, effectScope, h, inject, onBeforeUnmount, onMounted, onScopeDispose, onUnmounted, provide, reactive, ref, shallowReactive, shallowRef, toRef, vShow, watch, watchEffect } from "vue";
|
|
6
|
+
import { computed, createRenderer, defineComponent, effectScope, h, inject, nextTick, onBeforeUnmount, onMounted, onScopeDispose, onUnmounted, provide, reactive, ref, shallowReactive, shallowRef, toRef, vShow, watch, watchEffect } from "vue";
|
|
7
7
|
|
|
8
8
|
//#region src/core/ansi-palette.ts
|
|
9
9
|
const ANSI_PALETTE_HEX = Object.freeze({
|
|
@@ -380,6 +380,308 @@ function ansiColors(level) {
|
|
|
380
380
|
return ANSI256_COLORS;
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
+
//#endregion
|
|
384
|
+
//#region src/observability/cli-latency.ts
|
|
385
|
+
const EVENT_OP_ID = Symbol("dimcode.cliLatencyOpId");
|
|
386
|
+
const DEFAULT_LOG_PATH = "/tmp/dimcode-cli-latency.jsonl";
|
|
387
|
+
const INVALIDATE_ASSOCIATION_WINDOW_MS = 32;
|
|
388
|
+
const MAX_OP_AGE_MS = 5e3;
|
|
389
|
+
let nextOpId = 1;
|
|
390
|
+
let singleton;
|
|
391
|
+
function now$2() {
|
|
392
|
+
return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
|
|
393
|
+
}
|
|
394
|
+
function diffMs(end, start) {
|
|
395
|
+
if (end == null || start == null) return null;
|
|
396
|
+
return Math.max(0, end - start);
|
|
397
|
+
}
|
|
398
|
+
function parseEnabled$1(value) {
|
|
399
|
+
const raw = String(value ?? "").trim().toLowerCase();
|
|
400
|
+
return raw === "1" || raw === "true" || raw === "yes";
|
|
401
|
+
}
|
|
402
|
+
function isTrackedEventType(type) {
|
|
403
|
+
return type === "keydown" || type === "beforeinput" || type === "input" || type === "paste";
|
|
404
|
+
}
|
|
405
|
+
function defineOpId(target, id) {
|
|
406
|
+
try {
|
|
407
|
+
Object.defineProperty(target, EVENT_OP_ID, {
|
|
408
|
+
configurable: true,
|
|
409
|
+
enumerable: false,
|
|
410
|
+
writable: true,
|
|
411
|
+
value: id
|
|
412
|
+
});
|
|
413
|
+
} catch {}
|
|
414
|
+
}
|
|
415
|
+
function readOpId(target) {
|
|
416
|
+
const value = target === null || target === void 0 ? void 0 : target[EVENT_OP_ID];
|
|
417
|
+
return typeof value === "number" ? value : null;
|
|
418
|
+
}
|
|
419
|
+
function createDisabledProfiler() {
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
function createProfiler() {
|
|
423
|
+
var _process$once;
|
|
424
|
+
const env = (process$1 === null || process$1 === void 0 ? void 0 : process$1.env) ?? {};
|
|
425
|
+
if (!parseEnabled$1(env.DIMCODE_PROFILE_INPUT_LATENCY)) return createDisabledProfiler();
|
|
426
|
+
const logPath = String(env.DIMCODE_PROFILE_INPUT_LATENCY_LOG_PATH ?? DEFAULT_LOG_PATH).trim() || DEFAULT_LOG_PATH;
|
|
427
|
+
const ops = new Map();
|
|
428
|
+
const pendingCommitIds = new Set();
|
|
429
|
+
const pendingWriteIds = new Set();
|
|
430
|
+
let currentDispatchOpId = null;
|
|
431
|
+
let lastDispatchOpId = null;
|
|
432
|
+
let lastDispatchEndedAt = null;
|
|
433
|
+
let currentFlushIds = [];
|
|
434
|
+
let lastRawInputAt = null;
|
|
435
|
+
const emit = (record) => {
|
|
436
|
+
try {
|
|
437
|
+
appendFileSync(logPath, `${JSON.stringify(record)}\n`);
|
|
438
|
+
} catch {}
|
|
439
|
+
};
|
|
440
|
+
const cleanupOp = (id) => {
|
|
441
|
+
ops.delete(id);
|
|
442
|
+
pendingCommitIds.delete(id);
|
|
443
|
+
pendingWriteIds.delete(id);
|
|
444
|
+
if (currentDispatchOpId === id) currentDispatchOpId = null;
|
|
445
|
+
if (lastDispatchOpId === id) {
|
|
446
|
+
lastDispatchOpId = null;
|
|
447
|
+
lastDispatchEndedAt = null;
|
|
448
|
+
}
|
|
449
|
+
if (currentFlushIds.includes(id)) currentFlushIds = currentFlushIds.filter((value) => value !== id);
|
|
450
|
+
};
|
|
451
|
+
const flushOp = (op, outcome) => {
|
|
452
|
+
const totalStart = op.rawInputAt ?? op.stdinDispatchAt ?? op.dispatchStartAt;
|
|
453
|
+
emit({
|
|
454
|
+
ts: op.createdAtIso,
|
|
455
|
+
id: op.id,
|
|
456
|
+
event: {
|
|
457
|
+
type: op.eventType,
|
|
458
|
+
key: op.key,
|
|
459
|
+
code: op.code,
|
|
460
|
+
defaultPrevented: op.defaultPrevented,
|
|
461
|
+
parser: op.parser
|
|
462
|
+
},
|
|
463
|
+
operation: op.operation,
|
|
464
|
+
stages: {
|
|
465
|
+
rawInputAt: op.rawInputAt,
|
|
466
|
+
stdinDispatchAt: op.stdinDispatchAt,
|
|
467
|
+
dispatchStartAt: op.dispatchStartAt,
|
|
468
|
+
dispatchEndAt: op.dispatchEndAt,
|
|
469
|
+
invalidateAt: op.invalidateAt,
|
|
470
|
+
flushStartAt: op.flushStartAt,
|
|
471
|
+
flushEndAt: op.flushEndAt,
|
|
472
|
+
commitAt: op.commitAt,
|
|
473
|
+
stdoutRenderStartAt: op.stdoutRenderStartAt,
|
|
474
|
+
writeStartAt: op.writeStartAt,
|
|
475
|
+
writeEndAt: op.writeEndAt
|
|
476
|
+
},
|
|
477
|
+
timingsMs: {
|
|
478
|
+
inputParseWait: diffMs(op.stdinDispatchAt, op.rawInputAt),
|
|
479
|
+
eventDispatch: diffMs(op.dispatchEndAt, op.dispatchStartAt),
|
|
480
|
+
dispatchToInvalidate: diffMs(op.invalidateAt, op.dispatchEndAt),
|
|
481
|
+
dispatchToFlush: diffMs(op.flushStartAt, op.dispatchEndAt),
|
|
482
|
+
flushToCommitDone: diffMs(op.flushEndAt, op.flushStartAt),
|
|
483
|
+
commitToRender: diffMs(op.stdoutRenderStartAt, op.commitAt),
|
|
484
|
+
renderToWriteStart: diffMs(op.writeStartAt, op.stdoutRenderStartAt),
|
|
485
|
+
write: op.writeDurationMs,
|
|
486
|
+
totalToWrite: diffMs(op.writeEndAt, totalStart)
|
|
487
|
+
},
|
|
488
|
+
scheduler: {
|
|
489
|
+
invalidatePriority: op.invalidatePriority,
|
|
490
|
+
invalidatePlane: op.invalidatePlane,
|
|
491
|
+
commitSync: op.commitSync,
|
|
492
|
+
commitPlaneCount: op.commitPlaneCount,
|
|
493
|
+
commitDirtyRows: op.commitDirtyRows,
|
|
494
|
+
stdoutQueuedDelayMs: op.stdoutQueuedDelayMs,
|
|
495
|
+
writeMode: op.writeMode,
|
|
496
|
+
writeBytes: op.writeBytes
|
|
497
|
+
},
|
|
498
|
+
outcome
|
|
499
|
+
});
|
|
500
|
+
cleanupOp(op.id);
|
|
501
|
+
};
|
|
502
|
+
const expireOldOps = () => {
|
|
503
|
+
const currentTime = now$2();
|
|
504
|
+
for (const op of ops.values()) {
|
|
505
|
+
if (currentTime - op.createdAt < MAX_OP_AGE_MS) continue;
|
|
506
|
+
flushOp(op, op.writeEndAt != null ? "completed" : "timeout");
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
const flushPendingOps = (outcome) => {
|
|
510
|
+
for (const op of Array.from(ops.values())) flushOp(op, op.writeEndAt != null ? "completed" : outcome);
|
|
511
|
+
};
|
|
512
|
+
const ensureOp = (event) => {
|
|
513
|
+
const type = String((event === null || event === void 0 ? void 0 : event.type) ?? "");
|
|
514
|
+
if (!isTrackedEventType(type)) return null;
|
|
515
|
+
const existingId = readOpId(event);
|
|
516
|
+
if (existingId != null) return ops.get(existingId) ?? null;
|
|
517
|
+
const id = nextOpId++;
|
|
518
|
+
const op = {
|
|
519
|
+
id,
|
|
520
|
+
createdAt: now$2(),
|
|
521
|
+
createdAtIso: new Date().toISOString(),
|
|
522
|
+
eventType: type,
|
|
523
|
+
key: String((event === null || event === void 0 ? void 0 : event.key) ?? ""),
|
|
524
|
+
code: String((event === null || event === void 0 ? void 0 : event.code) ?? ""),
|
|
525
|
+
operation: null,
|
|
526
|
+
rawInputAt: null,
|
|
527
|
+
stdinDispatchAt: null,
|
|
528
|
+
dispatchStartAt: null,
|
|
529
|
+
dispatchEndAt: null,
|
|
530
|
+
invalidateAt: null,
|
|
531
|
+
invalidatePriority: null,
|
|
532
|
+
invalidatePlane: null,
|
|
533
|
+
flushStartAt: null,
|
|
534
|
+
flushEndAt: null,
|
|
535
|
+
commitAt: null,
|
|
536
|
+
commitSync: null,
|
|
537
|
+
commitPlaneCount: null,
|
|
538
|
+
commitDirtyRows: null,
|
|
539
|
+
stdoutQueuedDelayMs: null,
|
|
540
|
+
stdoutRenderStartAt: null,
|
|
541
|
+
writeStartAt: null,
|
|
542
|
+
writeEndAt: null,
|
|
543
|
+
writeDurationMs: null,
|
|
544
|
+
writeMode: null,
|
|
545
|
+
writeBytes: null,
|
|
546
|
+
defaultPrevented: null,
|
|
547
|
+
parser: null
|
|
548
|
+
};
|
|
549
|
+
ops.set(id, op);
|
|
550
|
+
defineOpId(event, id);
|
|
551
|
+
expireOldOps();
|
|
552
|
+
return op;
|
|
553
|
+
};
|
|
554
|
+
const forIds = (ids, fn) => {
|
|
555
|
+
for (const id of ids) {
|
|
556
|
+
const op = ops.get(id);
|
|
557
|
+
if (!op) continue;
|
|
558
|
+
fn(op);
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
const resolveActiveOp = () => {
|
|
562
|
+
if (currentDispatchOpId != null) return ops.get(currentDispatchOpId) ?? null;
|
|
563
|
+
if (lastDispatchOpId != null && lastDispatchEndedAt != null && now$2() - lastDispatchEndedAt <= INVALIDATE_ASSOCIATION_WINDOW_MS) return ops.get(lastDispatchOpId) ?? null;
|
|
564
|
+
return null;
|
|
565
|
+
};
|
|
566
|
+
process$1 === null || process$1 === void 0 || (_process$once = process$1.once) === null || _process$once === void 0 || _process$once.call(process$1, "exit", () => {
|
|
567
|
+
flushPendingOps("process-exit");
|
|
568
|
+
});
|
|
569
|
+
return {
|
|
570
|
+
enabled: true,
|
|
571
|
+
recordRawInput(_info) {
|
|
572
|
+
lastRawInputAt = now$2();
|
|
573
|
+
expireOldOps();
|
|
574
|
+
},
|
|
575
|
+
recordStdinDispatch(event, info) {
|
|
576
|
+
const op = ensureOp(event);
|
|
577
|
+
if (!op) return;
|
|
578
|
+
if (op.rawInputAt == null && lastRawInputAt != null) op.rawInputAt = lastRawInputAt;
|
|
579
|
+
if (op.stdinDispatchAt == null) op.stdinDispatchAt = now$2();
|
|
580
|
+
if (!op.parser && (info === null || info === void 0 ? void 0 : info.parser)) op.parser = String(info.parser);
|
|
581
|
+
},
|
|
582
|
+
recordEventDispatchStart(event) {
|
|
583
|
+
const op = ensureOp(event);
|
|
584
|
+
if (!op) return;
|
|
585
|
+
currentDispatchOpId = op.id;
|
|
586
|
+
if (op.dispatchStartAt == null) op.dispatchStartAt = now$2();
|
|
587
|
+
},
|
|
588
|
+
recordEventDispatchEnd(event, info) {
|
|
589
|
+
const op = ensureOp(event);
|
|
590
|
+
if (!op) return;
|
|
591
|
+
op.defaultPrevented = Boolean(info.defaultPrevented);
|
|
592
|
+
if (op.dispatchEndAt == null) op.dispatchEndAt = now$2();
|
|
593
|
+
currentDispatchOpId = currentDispatchOpId === op.id ? null : currentDispatchOpId;
|
|
594
|
+
lastDispatchOpId = op.id;
|
|
595
|
+
lastDispatchEndedAt = op.dispatchEndAt;
|
|
596
|
+
},
|
|
597
|
+
recordSchedulerInvalidate(info) {
|
|
598
|
+
const op = resolveActiveOp();
|
|
599
|
+
if (!op) return;
|
|
600
|
+
if (op.invalidateAt == null) op.invalidateAt = now$2();
|
|
601
|
+
if (!op.invalidatePriority && (info === null || info === void 0 ? void 0 : info.priority)) op.invalidatePriority = String(info.priority);
|
|
602
|
+
if (!op.invalidatePlane && (info === null || info === void 0 ? void 0 : info.plane)) op.invalidatePlane = String(info.plane);
|
|
603
|
+
pendingCommitIds.add(op.id);
|
|
604
|
+
},
|
|
605
|
+
recordFlushStart(info) {
|
|
606
|
+
currentFlushIds = Array.from(pendingCommitIds);
|
|
607
|
+
if (!currentFlushIds.length) return;
|
|
608
|
+
const flushTime = now$2();
|
|
609
|
+
forIds(currentFlushIds, (op) => {
|
|
610
|
+
if (op.flushStartAt == null) op.flushStartAt = flushTime;
|
|
611
|
+
if (op.commitSync == null && (info === null || info === void 0 ? void 0 : info.sync) != null) op.commitSync = Boolean(info.sync);
|
|
612
|
+
if (op.commitPlaneCount == null && Array.isArray(info === null || info === void 0 ? void 0 : info.activePlanes)) op.commitPlaneCount = info.activePlanes.length;
|
|
613
|
+
});
|
|
614
|
+
},
|
|
615
|
+
recordFlushEnd() {
|
|
616
|
+
if (!currentFlushIds.length) return;
|
|
617
|
+
const flushTime = now$2();
|
|
618
|
+
forIds(currentFlushIds, (op) => {
|
|
619
|
+
if (op.flushEndAt == null) op.flushEndAt = flushTime;
|
|
620
|
+
});
|
|
621
|
+
currentFlushIds = [];
|
|
622
|
+
},
|
|
623
|
+
recordCommit(info) {
|
|
624
|
+
if (!pendingCommitIds.size) return;
|
|
625
|
+
const commitTime = now$2();
|
|
626
|
+
const ids = Array.from(pendingCommitIds);
|
|
627
|
+
pendingCommitIds.clear();
|
|
628
|
+
forIds(ids, (op) => {
|
|
629
|
+
if (op.flushEndAt == null && op.flushStartAt != null) op.flushEndAt = commitTime;
|
|
630
|
+
if (op.commitAt == null) op.commitAt = commitTime;
|
|
631
|
+
op.commitSync = (info === null || info === void 0 ? void 0 : info.sync) == null ? op.commitSync : Boolean(info.sync);
|
|
632
|
+
op.commitPlaneCount = Array.isArray(info === null || info === void 0 ? void 0 : info.planes) ? info.planes.length : op.commitPlaneCount;
|
|
633
|
+
op.commitDirtyRows = Array.isArray(info === null || info === void 0 ? void 0 : info.dirtyRows) ? info.dirtyRows.length : (info === null || info === void 0 ? void 0 : info.dirtyRows) === null ? null : op.commitDirtyRows;
|
|
634
|
+
pendingWriteIds.add(op.id);
|
|
635
|
+
});
|
|
636
|
+
},
|
|
637
|
+
recordStdoutQueued(delayMs) {
|
|
638
|
+
if (!pendingWriteIds.size) return;
|
|
639
|
+
forIds(pendingWriteIds, (op) => {
|
|
640
|
+
if (op.stdoutQueuedDelayMs == null) op.stdoutQueuedDelayMs = Math.max(0, delayMs);
|
|
641
|
+
});
|
|
642
|
+
},
|
|
643
|
+
recordStdoutRenderStart() {
|
|
644
|
+
if (!pendingWriteIds.size) return;
|
|
645
|
+
const renderTime = now$2();
|
|
646
|
+
forIds(pendingWriteIds, (op) => {
|
|
647
|
+
if (op.stdoutRenderStartAt == null) op.stdoutRenderStartAt = renderTime;
|
|
648
|
+
});
|
|
649
|
+
},
|
|
650
|
+
recordStdoutNoOutput() {
|
|
651
|
+
if (!pendingWriteIds.size) return;
|
|
652
|
+
const ids = Array.from(pendingWriteIds);
|
|
653
|
+
pendingWriteIds.clear();
|
|
654
|
+
forIds(ids, (op) => flushOp(op, "no-output"));
|
|
655
|
+
},
|
|
656
|
+
recordStdoutWrite(info) {
|
|
657
|
+
if (!pendingWriteIds.size) return;
|
|
658
|
+
const writeEndTime = now$2();
|
|
659
|
+
const ids = Array.from(pendingWriteIds);
|
|
660
|
+
pendingWriteIds.clear();
|
|
661
|
+
forIds(ids, (op) => {
|
|
662
|
+
op.writeEndAt = writeEndTime;
|
|
663
|
+
op.writeDurationMs = Math.max(0, info.durationMs);
|
|
664
|
+
op.writeStartAt = writeEndTime - op.writeDurationMs;
|
|
665
|
+
op.writeMode = String(info.mode ?? "");
|
|
666
|
+
op.writeBytes = Math.max(0, Math.floor(info.bytes));
|
|
667
|
+
flushOp(op, "completed");
|
|
668
|
+
});
|
|
669
|
+
},
|
|
670
|
+
markOperation(operation) {
|
|
671
|
+
const nextOperation = String(operation ?? "").trim();
|
|
672
|
+
if (!nextOperation) return;
|
|
673
|
+
const op = resolveActiveOp();
|
|
674
|
+
if (!op) return;
|
|
675
|
+
op.operation = nextOperation;
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
function getCliLatencyProfiler() {
|
|
680
|
+
if (singleton !== void 0) return singleton;
|
|
681
|
+
singleton = createProfiler();
|
|
682
|
+
return singleton;
|
|
683
|
+
}
|
|
684
|
+
|
|
383
685
|
//#endregion
|
|
384
686
|
//#region src/utils/newlines.ts
|
|
385
687
|
function normalizeNewlines(text) {
|
|
@@ -1286,7 +1588,7 @@ function parseMouseSgr(sequence) {
|
|
|
1286
1588
|
handled: false,
|
|
1287
1589
|
event: null
|
|
1288
1590
|
};
|
|
1289
|
-
const env = (process === null || process === void 0 ? void 0 : process.env) ?? {};
|
|
1591
|
+
const env = (process$1 === null || process$1 === void 0 ? void 0 : process$1.env) ?? {};
|
|
1290
1592
|
const invertWheel = String(env.DIMCODE_WHEEL_INVERT ?? env.VUE_TUI_WHEEL_INVERT ?? "") === "1";
|
|
1291
1593
|
const mouseDebugEnabled = String(env.DIMCODE_MOUSE_DEBUG ?? env.VUE_TUI_MOUSE_DEBUG ?? "") === "1";
|
|
1292
1594
|
const mouseDebugPath = String(env.DIMCODE_MOUSE_DEBUG_PATH ?? env.VUE_TUI_MOUSE_DEBUG_PATH ?? "/tmp/goatchain-mouse-debug.log");
|
|
@@ -1422,6 +1724,7 @@ function parseMouseSequence(sequence) {
|
|
|
1422
1724
|
const ESC$1 = "\x1B";
|
|
1423
1725
|
const BRACKETED_PASTE_START = "\x1B[200~";
|
|
1424
1726
|
const BRACKETED_PASTE_END = "\x1B[201~";
|
|
1727
|
+
const ESC_CONTINUATION_RESCUE_WINDOW_MS = 64;
|
|
1425
1728
|
function looksLikeQuotedPathPaste(value) {
|
|
1426
1729
|
if (!value) return false;
|
|
1427
1730
|
if (value.includes(ESC$1)) return false;
|
|
@@ -1524,6 +1827,11 @@ function extractCompleteSequences(buffer) {
|
|
|
1524
1827
|
remainder: ""
|
|
1525
1828
|
};
|
|
1526
1829
|
}
|
|
1830
|
+
function looksLikeSplitEscapeContinuation(value) {
|
|
1831
|
+
const first = value[0];
|
|
1832
|
+
if (first !== "[" && first !== "]" && first !== "P" && first !== "_" && first !== "O") return false;
|
|
1833
|
+
return isCompleteSequence(`${ESC$1}${value}`) !== "not-escape";
|
|
1834
|
+
}
|
|
1527
1835
|
var StdinBuffer = class extends EventEmitter {
|
|
1528
1836
|
constructor(options = {}) {
|
|
1529
1837
|
super();
|
|
@@ -1531,6 +1839,7 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
1531
1839
|
this.timeout = null;
|
|
1532
1840
|
this.timeoutMs = void 0;
|
|
1533
1841
|
this.escTimeoutMs = void 0;
|
|
1842
|
+
this.pendingEscContinuationAt = null;
|
|
1534
1843
|
this.pasteMode = false;
|
|
1535
1844
|
this.pasteBuffer = "";
|
|
1536
1845
|
this.timeoutMs = options.timeout ?? 10;
|
|
@@ -1547,6 +1856,11 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
1547
1856
|
str = `\x1B${String.fromCharCode(byte)}`;
|
|
1548
1857
|
} else str = data.toString();
|
|
1549
1858
|
else str = data;
|
|
1859
|
+
if (this.pendingEscContinuationAt != null) {
|
|
1860
|
+
const canRescue = Date.now() - this.pendingEscContinuationAt <= ESC_CONTINUATION_RESCUE_WINDOW_MS;
|
|
1861
|
+
this.pendingEscContinuationAt = null;
|
|
1862
|
+
if (canRescue && looksLikeSplitEscapeContinuation(str)) str = `${ESC$1}${str}`;
|
|
1863
|
+
}
|
|
1550
1864
|
if (str.length === 0 && this.buffer.length === 0) {
|
|
1551
1865
|
this.emit("data", "");
|
|
1552
1866
|
return;
|
|
@@ -1600,7 +1914,9 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
1600
1914
|
if (this.buffer.length > 0) {
|
|
1601
1915
|
const timeoutMs = this.buffer === ESC$1 ? this.escTimeoutMs : this.timeoutMs;
|
|
1602
1916
|
this.timeout = setTimeout(() => {
|
|
1917
|
+
const rescuableLoneEsc = this.buffer === ESC$1;
|
|
1603
1918
|
const flushed = this.flush();
|
|
1919
|
+
if (rescuableLoneEsc && flushed.length === 1 && flushed[0] === ESC$1) this.pendingEscContinuationAt = Date.now();
|
|
1604
1920
|
for (const sequence of flushed) this.emit("data", sequence);
|
|
1605
1921
|
}, timeoutMs);
|
|
1606
1922
|
}
|
|
@@ -1621,6 +1937,7 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
1621
1937
|
this.timeout = null;
|
|
1622
1938
|
}
|
|
1623
1939
|
this.buffer = "";
|
|
1940
|
+
this.pendingEscContinuationAt = null;
|
|
1624
1941
|
this.pasteMode = false;
|
|
1625
1942
|
this.pasteBuffer = "";
|
|
1626
1943
|
}
|
|
@@ -1634,6 +1951,10 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
1634
1951
|
|
|
1635
1952
|
//#endregion
|
|
1636
1953
|
//#region src/cli/input.ts
|
|
1954
|
+
const KITTY_KEYBOARD_PROTOCOL_ENABLE = "\x1B[>1u";
|
|
1955
|
+
const KITTY_KEYBOARD_PROTOCOL_DISABLE = "\x1B[<u";
|
|
1956
|
+
const XTERM_MODIFY_OTHER_KEYS_ENABLE = "\x1B[>4;2m";
|
|
1957
|
+
const XTERM_MODIFY_OTHER_KEYS_DISABLE = "\x1B[>4n";
|
|
1637
1958
|
function isPrintable(ch) {
|
|
1638
1959
|
if (ch.length === 0) return false;
|
|
1639
1960
|
if (ch.length === 1) {
|
|
@@ -1653,12 +1974,54 @@ function ctrlKeyFromChar(ch) {
|
|
|
1653
1974
|
if (code >= 1 && code <= 26) return String.fromCharCode(code + 96);
|
|
1654
1975
|
return null;
|
|
1655
1976
|
}
|
|
1977
|
+
function isUnhandledCtrlC(event) {
|
|
1978
|
+
return event.type === "keydown" && (event.key === "c" || event.key === "C") && event.ctrlKey === true && event.metaKey !== true && event.altKey !== true && event.shiftKey !== true;
|
|
1979
|
+
}
|
|
1980
|
+
function parseKeyboardProtocol(value) {
|
|
1981
|
+
const normalized = String(value ?? "").trim().toLowerCase();
|
|
1982
|
+
if (normalized === "auto" || normalized === "kitty" || normalized === "xterm" || normalized === "off") return normalized;
|
|
1983
|
+
return null;
|
|
1984
|
+
}
|
|
1985
|
+
function detectKeyboardProtocol(env) {
|
|
1986
|
+
const termProgram = String(env.TERM_PROGRAM ?? "").trim().toLowerCase();
|
|
1987
|
+
const term = String(env.TERM ?? "").trim().toLowerCase();
|
|
1988
|
+
const hasKittyProtocolTerminal = "GHOSTTY_RESOURCES_DIR" in env || "WEZTERM_PANE" in env || "KITTY_WINDOW_ID" in env || "KITTY_INSTALLATION_DIR" in env || "ALACRITTY_WINDOW_ID" in env || "ALACRITTY_LOG" in env || termProgram.includes("ghostty") || termProgram.includes("wezterm") || termProgram.includes("kitty") || termProgram.includes("alacritty");
|
|
1989
|
+
if (hasKittyProtocolTerminal) return "kitty";
|
|
1990
|
+
const isScreenLike = "TMUX" in env || term.includes("screen") || term.includes("tmux");
|
|
1991
|
+
const hasXtermKeyboardTerminal = termProgram.includes("iterm") || termProgram.includes("apple_terminal") || termProgram.includes("vscode") || term.includes("xterm") && !isScreenLike;
|
|
1992
|
+
return hasXtermKeyboardTerminal ? "xterm" : "off";
|
|
1993
|
+
}
|
|
1994
|
+
function resolveKeyboardProtocol(options) {
|
|
1995
|
+
var _options$env;
|
|
1996
|
+
const configured = parseKeyboardProtocol(options.keyboardProtocol) ?? "auto";
|
|
1997
|
+
if (configured !== "auto") return configured;
|
|
1998
|
+
const envOverride = parseKeyboardProtocol((_options$env = options.env) === null || _options$env === void 0 ? void 0 : _options$env.DIMCODE_KEYBOARD_PROTOCOL);
|
|
1999
|
+
if (envOverride && envOverride !== "auto") return envOverride;
|
|
2000
|
+
return detectKeyboardProtocol(options.env ?? {});
|
|
2001
|
+
}
|
|
2002
|
+
function getKeyboardProtocolSequences(protocol) {
|
|
2003
|
+
if (protocol === "kitty") return {
|
|
2004
|
+
enable: KITTY_KEYBOARD_PROTOCOL_ENABLE,
|
|
2005
|
+
disable: KITTY_KEYBOARD_PROTOCOL_DISABLE
|
|
2006
|
+
};
|
|
2007
|
+
if (protocol === "xterm") return {
|
|
2008
|
+
enable: XTERM_MODIFY_OTHER_KEYS_ENABLE,
|
|
2009
|
+
disable: XTERM_MODIFY_OTHER_KEYS_DISABLE
|
|
2010
|
+
};
|
|
2011
|
+
return null;
|
|
2012
|
+
}
|
|
1656
2013
|
function createStdinDriver(options) {
|
|
1657
|
-
const stdin = options.stdin ?? process.stdin;
|
|
1658
|
-
const stdout = options.stdout ?? process.stdout;
|
|
2014
|
+
const stdin = options.stdin ?? process$1.stdin;
|
|
2015
|
+
const stdout = options.stdout ?? process$1.stdout;
|
|
1659
2016
|
if (!stdin || !stdout) throw new Error("createStdinDriver requires Node process.stdin/stdout");
|
|
2017
|
+
const env = options.env ?? process$1.env ?? {};
|
|
1660
2018
|
const enableMouse = options.enableMouse ?? true;
|
|
1661
2019
|
const enableMouseMotion = options.enableMouseMotion ?? false;
|
|
2020
|
+
const keyboardProtocol = resolveKeyboardProtocol({
|
|
2021
|
+
keyboardProtocol: options.keyboardProtocol,
|
|
2022
|
+
env
|
|
2023
|
+
});
|
|
2024
|
+
const keyboardProtocolSequences = getKeyboardProtocolSequences(keyboardProtocol);
|
|
1662
2025
|
let disposed = false;
|
|
1663
2026
|
let swallowNextLF = false;
|
|
1664
2027
|
let lastMouseDown = null;
|
|
@@ -1668,55 +2031,61 @@ function createStdinDriver(options) {
|
|
|
1668
2031
|
});
|
|
1669
2032
|
const stdinBuffer = new StdinBuffer({
|
|
1670
2033
|
timeout: 50,
|
|
1671
|
-
escTimeout: enableMouse ?
|
|
2034
|
+
escTimeout: enableMouse ? 8 : 6
|
|
1672
2035
|
});
|
|
2036
|
+
const latency = getCliLatencyProfiler();
|
|
2037
|
+
const dispatchEvent = (event, parser) => {
|
|
2038
|
+
var _options$onExit;
|
|
2039
|
+
latency === null || latency === void 0 || latency.recordStdinDispatch(event, { parser });
|
|
2040
|
+
const prevented = Boolean(options.dispatch(event));
|
|
2041
|
+
if (isUnhandledCtrlC(event) && !prevented) (_options$onExit = options.onExit) === null || _options$onExit === void 0 || _options$onExit.call(options);
|
|
2042
|
+
return prevented;
|
|
2043
|
+
};
|
|
1673
2044
|
const handlePlainChar = (ch) => {
|
|
1674
2045
|
if (swallowNextLF) {
|
|
1675
2046
|
swallowNextLF = false;
|
|
1676
2047
|
if (ch === "\n") return;
|
|
1677
2048
|
}
|
|
1678
2049
|
if (ch === "") {
|
|
1679
|
-
|
|
1680
|
-
const prevented = Boolean(options.dispatch(keyEvent("c", "", { ctrlKey: true })));
|
|
1681
|
-
if (!prevented) (_options$onExit = options.onExit) === null || _options$onExit === void 0 || _options$onExit.call(options);
|
|
2050
|
+
dispatchEvent(keyEvent("c", "", { ctrlKey: true }), "plain");
|
|
1682
2051
|
return;
|
|
1683
2052
|
}
|
|
1684
2053
|
if (ch === "\r") {
|
|
1685
2054
|
swallowNextLF = true;
|
|
1686
|
-
|
|
2055
|
+
dispatchEvent(keyEvent("Enter", "Enter"), "plain");
|
|
1687
2056
|
return;
|
|
1688
2057
|
}
|
|
1689
2058
|
if (ch === "\n") {
|
|
1690
|
-
|
|
2059
|
+
dispatchEvent({
|
|
1691
2060
|
type: "input",
|
|
1692
2061
|
data: "\n",
|
|
1693
2062
|
inputType: "insertLineBreak",
|
|
1694
2063
|
text: "\n"
|
|
1695
|
-
});
|
|
2064
|
+
}, "plain");
|
|
1696
2065
|
return;
|
|
1697
2066
|
}
|
|
1698
2067
|
const ctrlKey = ctrlKeyFromChar(ch);
|
|
1699
2068
|
if (ctrlKey) {
|
|
1700
2069
|
if (ctrlKey === "i") {
|
|
1701
|
-
|
|
2070
|
+
dispatchEvent(keyEvent("Tab", "Tab"), "plain");
|
|
1702
2071
|
return;
|
|
1703
2072
|
}
|
|
1704
2073
|
if (ctrlKey === "h") {
|
|
1705
|
-
|
|
2074
|
+
dispatchEvent(keyEvent("Backspace", "Backspace"), "plain");
|
|
1706
2075
|
return;
|
|
1707
2076
|
}
|
|
1708
|
-
|
|
2077
|
+
dispatchEvent(keyEvent(ctrlKey, "", { ctrlKey: true }), "plain");
|
|
1709
2078
|
return;
|
|
1710
2079
|
}
|
|
1711
2080
|
if (ch === "") {
|
|
1712
|
-
|
|
2081
|
+
dispatchEvent(keyEvent("Backspace", "Backspace"), "plain");
|
|
1713
2082
|
return;
|
|
1714
2083
|
}
|
|
1715
2084
|
if (ch === " ") {
|
|
1716
|
-
|
|
2085
|
+
dispatchEvent(keyEvent("Tab", "Tab"), "plain");
|
|
1717
2086
|
return;
|
|
1718
2087
|
}
|
|
1719
|
-
if (isPrintable(ch))
|
|
2088
|
+
if (isPrintable(ch)) dispatchEvent(keyEvent(ch), "plain");
|
|
1720
2089
|
};
|
|
1721
2090
|
const handleMouseEvent = (event) => {
|
|
1722
2091
|
const ev = event;
|
|
@@ -1789,21 +2158,21 @@ function createStdinDriver(options) {
|
|
|
1789
2158
|
}
|
|
1790
2159
|
const kitty = parseKittySequence(sequence);
|
|
1791
2160
|
if (kitty.handled) {
|
|
1792
|
-
if (kitty.event)
|
|
2161
|
+
if (kitty.event) dispatchEvent(kitty.event, "kitty");
|
|
1793
2162
|
return;
|
|
1794
2163
|
}
|
|
1795
2164
|
const legacy = parseLegacySequence(sequence);
|
|
1796
2165
|
if (legacy.handled) {
|
|
1797
|
-
if (legacy.event)
|
|
2166
|
+
if (legacy.event) dispatchEvent(legacy.event, "legacy");
|
|
1798
2167
|
return;
|
|
1799
2168
|
}
|
|
1800
2169
|
if (sequence.startsWith("\x1B")) {
|
|
1801
2170
|
if (sequence.length === 2 && isPrintable(sequence[1])) {
|
|
1802
|
-
|
|
2171
|
+
dispatchEvent(keyEvent(sequence[1], "", { altKey: true }), "alt");
|
|
1803
2172
|
return;
|
|
1804
2173
|
}
|
|
1805
2174
|
if (sequence === "\x1B") {
|
|
1806
|
-
|
|
2175
|
+
dispatchEvent(keyEvent("Escape", "Escape"), "escape");
|
|
1807
2176
|
return;
|
|
1808
2177
|
}
|
|
1809
2178
|
return;
|
|
@@ -1813,10 +2182,10 @@ function createStdinDriver(options) {
|
|
|
1813
2182
|
stdinBuffer.on("data", handleSequence);
|
|
1814
2183
|
stdinBuffer.on("paste", (data) => {
|
|
1815
2184
|
const pastedText = normalizeNewlines(data);
|
|
1816
|
-
if (pastedText)
|
|
2185
|
+
if (pastedText) dispatchEvent({
|
|
1817
2186
|
type: "paste",
|
|
1818
2187
|
text: pastedText
|
|
1819
|
-
});
|
|
2188
|
+
}, "paste");
|
|
1820
2189
|
});
|
|
1821
2190
|
const decodeBytes = (bytes) => {
|
|
1822
2191
|
if (bytes.length === 1 && bytes[0] > 127) {
|
|
@@ -1829,6 +2198,7 @@ function createStdinDriver(options) {
|
|
|
1829
2198
|
};
|
|
1830
2199
|
const onData = (chunk) => {
|
|
1831
2200
|
if (disposed) return;
|
|
2201
|
+
latency === null || latency === void 0 || latency.recordRawInput();
|
|
1832
2202
|
if (typeof chunk === "string") {
|
|
1833
2203
|
stdinBuffer.process(chunk);
|
|
1834
2204
|
return;
|
|
@@ -1854,6 +2224,7 @@ function createStdinDriver(options) {
|
|
|
1854
2224
|
if (stdout.isTTY) {
|
|
1855
2225
|
stdout.write("\x1B[?2004h");
|
|
1856
2226
|
stdout.write("\x1B[?1004h");
|
|
2227
|
+
if (keyboardProtocolSequences) stdout.write(keyboardProtocolSequences.enable);
|
|
1857
2228
|
if (enableMouse) {
|
|
1858
2229
|
stdout.write("\x1B[?1007h");
|
|
1859
2230
|
if (enableMouseMotion) stdout.write("\x1B[?1000h\x1B[?1003h\x1B[?1006h");
|
|
@@ -1876,6 +2247,7 @@ function createStdinDriver(options) {
|
|
|
1876
2247
|
if (stdout.isTTY) {
|
|
1877
2248
|
stdout.write("\x1B[?2004l");
|
|
1878
2249
|
stdout.write("\x1B[?1004l");
|
|
2250
|
+
if (keyboardProtocolSequences) stdout.write(keyboardProtocolSequences.disable);
|
|
1879
2251
|
if (enableMouse) {
|
|
1880
2252
|
stdout.write("\x1B[?1007l");
|
|
1881
2253
|
if (enableMouseMotion) stdout.write("\x1B[?1000l\x1B[?1003l\x1B[?1006l");
|
|
@@ -2511,12 +2883,59 @@ function createGridBuffer(cols, rows) {
|
|
|
2511
2883
|
cursorStyle: DEFAULT_STYLE,
|
|
2512
2884
|
scrollback: [],
|
|
2513
2885
|
scrollbackLimit: 1e3,
|
|
2514
|
-
rowPool: []
|
|
2886
|
+
rowPool: [],
|
|
2887
|
+
soaFingerprints: null,
|
|
2888
|
+
fingerprintFn: null
|
|
2515
2889
|
};
|
|
2516
2890
|
}
|
|
2517
2891
|
function clamp$7(n, min, max) {
|
|
2518
2892
|
return Math.max(min, Math.min(max, n));
|
|
2519
2893
|
}
|
|
2894
|
+
/**
|
|
2895
|
+
* Register a fingerprint function on the buffer. This enables SoA fingerprint
|
|
2896
|
+
* pre-computation: cell writes will update fingerprints inline, and the renderer
|
|
2897
|
+
* can read them via getRowFingerprints() instead of per-cell hash computation.
|
|
2898
|
+
*/
|
|
2899
|
+
function setFingerprintFn(buffer, fn) {
|
|
2900
|
+
buffer.fingerprintFn = fn;
|
|
2901
|
+
const len = buffer.rows * buffer.cols;
|
|
2902
|
+
if (!len) {
|
|
2903
|
+
buffer.soaFingerprints = null;
|
|
2904
|
+
return;
|
|
2905
|
+
}
|
|
2906
|
+
buffer.soaFingerprints = new Uint32Array(len);
|
|
2907
|
+
for (let y = 0; y < buffer.rows; y++) {
|
|
2908
|
+
const row = getBufferRow(buffer, y);
|
|
2909
|
+
const physY = physicalRowIndex(buffer, y);
|
|
2910
|
+
const base = physY * buffer.cols;
|
|
2911
|
+
for (let x = 0; x < buffer.cols; x++) {
|
|
2912
|
+
const cell = row[x];
|
|
2913
|
+
buffer.soaFingerprints[base + x] = fn(cell.ch, cell.style);
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
/**
|
|
2918
|
+
* Get pre-computed fingerprints for a logical row as a TypedArray slice.
|
|
2919
|
+
* Returns null if fingerprinting is not enabled on this buffer.
|
|
2920
|
+
*/
|
|
2921
|
+
function getRowFingerprints(buffer, y) {
|
|
2922
|
+
if (!buffer.soaFingerprints) return null;
|
|
2923
|
+
const physY = physicalRowIndex(buffer, y);
|
|
2924
|
+
const base = physY * buffer.cols;
|
|
2925
|
+
return buffer.soaFingerprints.subarray(base, base + buffer.cols);
|
|
2926
|
+
}
|
|
2927
|
+
/** Update the SoA fingerprint for a single cell (called inline from putCell/fillRect). */
|
|
2928
|
+
function updateCellFingerprint(buffer, physY, x, ch, style) {
|
|
2929
|
+
if (!buffer.soaFingerprints || !buffer.fingerprintFn) return;
|
|
2930
|
+
buffer.soaFingerprints[physY * buffer.cols + x] = buffer.fingerprintFn(ch, style);
|
|
2931
|
+
}
|
|
2932
|
+
/** Update SoA fingerprints for a range of cells in a physical row. */
|
|
2933
|
+
function updateRangeFingerprint(buffer, physY, x0, x1, ch, style) {
|
|
2934
|
+
if (!buffer.soaFingerprints || !buffer.fingerprintFn) return;
|
|
2935
|
+
const fp = buffer.fingerprintFn(ch, style);
|
|
2936
|
+
const base = physY * buffer.cols;
|
|
2937
|
+
for (let x = x0; x < x1; x++) buffer.soaFingerprints[base + x] = fp;
|
|
2938
|
+
}
|
|
2520
2939
|
function physicalRowIndex(buffer, y) {
|
|
2521
2940
|
return (buffer.gridStart + y) % buffer.rows;
|
|
2522
2941
|
}
|
|
@@ -2575,8 +2994,14 @@ function putCell(buffer, x, y, ch, style) {
|
|
|
2575
2994
|
markDirty(buffer, y);
|
|
2576
2995
|
return;
|
|
2577
2996
|
}
|
|
2578
|
-
|
|
2997
|
+
const cell = createCell(ch, style);
|
|
2998
|
+
row[x] = cell;
|
|
2579
2999
|
if (width === 2 && x + 1 < buffer.cols) row[x + 1] = createContinuationCell(style);
|
|
3000
|
+
if (buffer.soaFingerprints) {
|
|
3001
|
+
const physY = physicalRowIndex(buffer, y);
|
|
3002
|
+
updateCellFingerprint(buffer, physY, x, cell.ch, cell.style);
|
|
3003
|
+
if (width === 2 && x + 1 < buffer.cols) updateCellFingerprint(buffer, physY, x + 1, "", cell.style);
|
|
3004
|
+
}
|
|
2580
3005
|
markDirty(buffer, y);
|
|
2581
3006
|
}
|
|
2582
3007
|
function fillRect(buffer, x, y, w, h$1, ch = " ", style) {
|
|
@@ -2596,6 +3021,10 @@ function fillRect(buffer, x, y, w, h$1, ch = " ", style) {
|
|
|
2596
3021
|
if ((_row$x = row[x0]) === null || _row$x === void 0 ? void 0 : _row$x.continuation) clearWideIfOverwriting(row, x0);
|
|
2597
3022
|
row.fill(fillCell, x0, x1);
|
|
2598
3023
|
if (x1 < buffer.cols && ((_row$x2 = row[x1]) === null || _row$x2 === void 0 ? void 0 : _row$x2.continuation)) row[x1] = blank;
|
|
3024
|
+
if (buffer.soaFingerprints) {
|
|
3025
|
+
const physY = physicalRowIndex(buffer, yy);
|
|
3026
|
+
updateRangeFingerprint(buffer, physY, x0, x1, fillCell.ch, fillCell.style);
|
|
3027
|
+
}
|
|
2599
3028
|
markDirty(buffer, yy);
|
|
2600
3029
|
}
|
|
2601
3030
|
return;
|
|
@@ -2654,6 +3083,18 @@ function blankRow(buffer) {
|
|
|
2654
3083
|
for (let x = 0; x < buffer.cols; x++) pooled[x] = blank;
|
|
2655
3084
|
return pooled;
|
|
2656
3085
|
}
|
|
3086
|
+
function recomputeFingerprintsForRows(buffer, startY, endY) {
|
|
3087
|
+
if (!buffer.soaFingerprints || !buffer.fingerprintFn) return;
|
|
3088
|
+
for (let y = startY; y < endY; y++) {
|
|
3089
|
+
const row = getBufferRow(buffer, y);
|
|
3090
|
+
const physY = physicalRowIndex(buffer, y);
|
|
3091
|
+
const base = physY * buffer.cols;
|
|
3092
|
+
for (let x = 0; x < buffer.cols; x++) {
|
|
3093
|
+
const cell = row[x];
|
|
3094
|
+
buffer.soaFingerprints[base + x] = buffer.fingerprintFn(cell.ch, cell.style);
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
2657
3098
|
function scrollBuffer(buffer, lines) {
|
|
2658
3099
|
const n = Math.trunc(lines);
|
|
2659
3100
|
if (n === 0 || buffer.rows === 0) return;
|
|
@@ -2682,6 +3123,63 @@ function scrollBuffer(buffer, lines) {
|
|
|
2682
3123
|
markAllDirty(buffer);
|
|
2683
3124
|
buffer.cursorY = clamp$7(buffer.cursorY - n, 0, Math.max(0, buffer.rows - 1));
|
|
2684
3125
|
}
|
|
3126
|
+
function scrollBufferRegion(buffer, startY, endY, lines) {
|
|
3127
|
+
const n = Math.trunc(lines);
|
|
3128
|
+
if (n === 0 || buffer.rows === 0) return [];
|
|
3129
|
+
const start = clamp$7(Math.floor(startY), 0, buffer.rows);
|
|
3130
|
+
const end = clamp$7(Math.floor(endY), 0, buffer.rows);
|
|
3131
|
+
const height = end - start;
|
|
3132
|
+
if (height <= 0) return [];
|
|
3133
|
+
const absDelta = Math.abs(n);
|
|
3134
|
+
const insertedRows = [];
|
|
3135
|
+
const replaceRegionWithBlankRows = () => {
|
|
3136
|
+
for (let y = start; y < end; y++) {
|
|
3137
|
+
const physY = physicalRowIndex(buffer, y);
|
|
3138
|
+
buffer.rowPool.push(buffer.grid[physY]);
|
|
3139
|
+
buffer.grid[physY] = blankRow(buffer);
|
|
3140
|
+
markDirty(buffer, y);
|
|
3141
|
+
insertedRows.push(y);
|
|
3142
|
+
}
|
|
3143
|
+
};
|
|
3144
|
+
if (absDelta >= height) {
|
|
3145
|
+
replaceRegionWithBlankRows();
|
|
3146
|
+
recomputeFingerprintsForRows(buffer, start, end);
|
|
3147
|
+
if (buffer.cursorY >= start && buffer.cursorY < end) buffer.cursorY = clamp$7(buffer.cursorY - n, start, Math.max(start, end - 1));
|
|
3148
|
+
return insertedRows;
|
|
3149
|
+
}
|
|
3150
|
+
const regionRows = [];
|
|
3151
|
+
for (let y = start; y < end; y++) regionRows.push(getBufferRow(buffer, y));
|
|
3152
|
+
const nextRows = Array.from({ length: height }, () => []);
|
|
3153
|
+
if (n > 0) {
|
|
3154
|
+
const movedCount = height - n;
|
|
3155
|
+
for (let i = 0; i < movedCount; i++) nextRows[i] = regionRows[i + n];
|
|
3156
|
+
for (let i = 0; i < n; i++) {
|
|
3157
|
+
buffer.rowPool.push(regionRows[i]);
|
|
3158
|
+
const y = end - n + i;
|
|
3159
|
+
nextRows[movedCount + i] = blankRow(buffer);
|
|
3160
|
+
markDirty(buffer, y);
|
|
3161
|
+
insertedRows.push(y);
|
|
3162
|
+
}
|
|
3163
|
+
} else {
|
|
3164
|
+
const insertedCount = -n;
|
|
3165
|
+
const movedCount = height - insertedCount;
|
|
3166
|
+
for (let i = 0; i < insertedCount; i++) {
|
|
3167
|
+
buffer.rowPool.push(regionRows[height - insertedCount + i]);
|
|
3168
|
+
const y = start + i;
|
|
3169
|
+
nextRows[i] = blankRow(buffer);
|
|
3170
|
+
markDirty(buffer, y);
|
|
3171
|
+
insertedRows.push(y);
|
|
3172
|
+
}
|
|
3173
|
+
for (let i = 0; i < movedCount; i++) nextRows[insertedCount + i] = regionRows[i];
|
|
3174
|
+
}
|
|
3175
|
+
for (let i = 0; i < height; i++) {
|
|
3176
|
+
const physY = physicalRowIndex(buffer, start + i);
|
|
3177
|
+
buffer.grid[physY] = nextRows[i];
|
|
3178
|
+
}
|
|
3179
|
+
recomputeFingerprintsForRows(buffer, start, end);
|
|
3180
|
+
if (buffer.cursorY >= start && buffer.cursorY < end) buffer.cursorY = clamp$7(buffer.cursorY - n, start, Math.max(start, end - 1));
|
|
3181
|
+
return insertedRows;
|
|
3182
|
+
}
|
|
2685
3183
|
function resizeBuffer(buffer, cols, rows) {
|
|
2686
3184
|
const nextCols = Math.max(0, Math.floor(cols));
|
|
2687
3185
|
const nextRows = Math.max(0, Math.floor(rows));
|
|
@@ -2712,6 +3210,20 @@ function resizeBuffer(buffer, cols, rows) {
|
|
|
2712
3210
|
buffer.dirtyAll = nextRows > 0;
|
|
2713
3211
|
buffer.cursorX = clamp$7(buffer.cursorX, 0, Math.max(0, nextCols));
|
|
2714
3212
|
buffer.cursorY = clamp$7(buffer.cursorY, 0, Math.max(0, nextRows - 1));
|
|
3213
|
+
if (buffer.fingerprintFn) {
|
|
3214
|
+
const len = nextRows * nextCols;
|
|
3215
|
+
if (len > 0) {
|
|
3216
|
+
buffer.soaFingerprints = new Uint32Array(len);
|
|
3217
|
+
for (let y = 0; y < nextRows; y++) {
|
|
3218
|
+
const row = nextGrid[y];
|
|
3219
|
+
const base = y * nextCols;
|
|
3220
|
+
for (let x = 0; x < nextCols; x++) {
|
|
3221
|
+
const cell = row[x];
|
|
3222
|
+
buffer.soaFingerprints[base + x] = buffer.fingerprintFn(cell.ch, cell.style);
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
} else buffer.soaFingerprints = null;
|
|
3226
|
+
}
|
|
2715
3227
|
}
|
|
2716
3228
|
function snapshotText(buffer) {
|
|
2717
3229
|
const out = [];
|
|
@@ -2874,6 +3386,32 @@ function scrollPlaneCoverage(state, lines) {
|
|
|
2874
3386
|
state.coverage.splice(rows + n, -n);
|
|
2875
3387
|
for (let i = 0; i < -n; i++) state.coverage.unshift(new Uint8Array(cols));
|
|
2876
3388
|
}
|
|
3389
|
+
function scrollPlaneCoverageRegion(state, startY, endY, lines) {
|
|
3390
|
+
const n = Math.trunc(lines);
|
|
3391
|
+
if (n === 0 || state.coverage.length === 0) return;
|
|
3392
|
+
const start = Math.max(0, Math.min(state.coverage.length, Math.floor(startY)));
|
|
3393
|
+
const end = Math.max(0, Math.min(state.coverage.length, Math.floor(endY)));
|
|
3394
|
+
const height = end - start;
|
|
3395
|
+
if (height <= 0) return;
|
|
3396
|
+
const cols = state.buffer.cols;
|
|
3397
|
+
if (Math.abs(n) >= height) {
|
|
3398
|
+
for (let y = start; y < end; y++) state.coverage[y] = new Uint8Array(cols);
|
|
3399
|
+
return;
|
|
3400
|
+
}
|
|
3401
|
+
const region = state.coverage.slice(start, end);
|
|
3402
|
+
const next = Array.from({ length: height }, () => new Uint8Array(0));
|
|
3403
|
+
if (n > 0) {
|
|
3404
|
+
const movedCount = height - n;
|
|
3405
|
+
for (let i = 0; i < movedCount; i++) next[i] = region[i + n];
|
|
3406
|
+
for (let i = 0; i < n; i++) next[movedCount + i] = new Uint8Array(cols);
|
|
3407
|
+
} else {
|
|
3408
|
+
const insertedCount = -n;
|
|
3409
|
+
const movedCount = height - insertedCount;
|
|
3410
|
+
for (let i = 0; i < insertedCount; i++) next[i] = new Uint8Array(cols);
|
|
3411
|
+
for (let i = 0; i < movedCount; i++) next[insertedCount + i] = region[i];
|
|
3412
|
+
}
|
|
3413
|
+
for (let i = 0; i < height; i++) state.coverage[start + i] = next[i];
|
|
3414
|
+
}
|
|
2877
3415
|
function resizePlaneState(state, cols, rows) {
|
|
2878
3416
|
resizeBuffer(state.buffer, cols, rows);
|
|
2879
3417
|
state.coverage = resizeCoverage(state.coverage, state.buffer.cols, state.buffer.rows);
|
|
@@ -2902,6 +3440,14 @@ function resetPlaneRowsForRender(terminal, plane, dirtyRows) {
|
|
|
2902
3440
|
const internals = terminal[TERMINAL_PLANE_INTERNALS];
|
|
2903
3441
|
internals === null || internals === void 0 || internals.resetRowsForRender(plane, dirtyRows);
|
|
2904
3442
|
}
|
|
3443
|
+
function getPlaneRowCoverageKind(terminal, plane, y) {
|
|
3444
|
+
const internals = terminal[TERMINAL_PLANE_INTERNALS];
|
|
3445
|
+
return (internals === null || internals === void 0 ? void 0 : internals.getRowCoverageKind(plane, y)) ?? 0;
|
|
3446
|
+
}
|
|
3447
|
+
function scrollPlaneRows(terminal, plane, startY, endY, lines) {
|
|
3448
|
+
const internals = terminal[TERMINAL_PLANE_INTERNALS];
|
|
3449
|
+
internals === null || internals === void 0 || internals.scrollRows(plane, startY, endY, lines);
|
|
3450
|
+
}
|
|
2905
3451
|
function createTerminal(opts) {
|
|
2906
3452
|
const emitter = new Emitter();
|
|
2907
3453
|
const compositeBuffer = createGridBuffer(opts.cols, opts.rows);
|
|
@@ -2911,6 +3457,7 @@ function createTerminal(opts) {
|
|
|
2911
3457
|
let pendingCommit = false;
|
|
2912
3458
|
let pendingCommitAllPlanes = false;
|
|
2913
3459
|
let pendingCommitPlanes = null;
|
|
3460
|
+
const pendingPlaneScrollOps = new Map();
|
|
2914
3461
|
const planeTerminals = new Map();
|
|
2915
3462
|
let base;
|
|
2916
3463
|
compositeBuffer.cursorVisible = false;
|
|
@@ -3031,8 +3578,145 @@ function createTerminal(opts) {
|
|
|
3031
3578
|
scrollBuffer(state.buffer, lines);
|
|
3032
3579
|
scrollPlaneCoverage(state, lines);
|
|
3033
3580
|
}
|
|
3581
|
+
function normalizeScrollOperation(startY, endY, delta, totalRows) {
|
|
3582
|
+
const start = Math.max(0, Math.min(totalRows, Math.floor(startY)));
|
|
3583
|
+
const end = Math.max(0, Math.min(totalRows, Math.floor(endY)));
|
|
3584
|
+
const height = end - start;
|
|
3585
|
+
const lines = Math.trunc(delta);
|
|
3586
|
+
if (height <= 0 || lines === 0 || Math.abs(lines) >= height) return null;
|
|
3587
|
+
return {
|
|
3588
|
+
startY: start,
|
|
3589
|
+
endY: end,
|
|
3590
|
+
delta: lines
|
|
3591
|
+
};
|
|
3592
|
+
}
|
|
3593
|
+
function recordPendingScrollOp(plane, op) {
|
|
3594
|
+
const prev = pendingPlaneScrollOps.get(plane);
|
|
3595
|
+
if (prev && prev.startY === op.startY && prev.endY === op.endY) {
|
|
3596
|
+
const nextDelta = prev.delta + op.delta;
|
|
3597
|
+
if (nextDelta === 0) {
|
|
3598
|
+
pendingPlaneScrollOps.delete(plane);
|
|
3599
|
+
return;
|
|
3600
|
+
}
|
|
3601
|
+
const next = normalizeScrollOperation(op.startY, op.endY, nextDelta, compositeBuffer.rows);
|
|
3602
|
+
if (!next) {
|
|
3603
|
+
pendingPlaneScrollOps.delete(plane);
|
|
3604
|
+
return;
|
|
3605
|
+
}
|
|
3606
|
+
pendingPlaneScrollOps.set(plane, next);
|
|
3607
|
+
return;
|
|
3608
|
+
}
|
|
3609
|
+
pendingPlaneScrollOps.set(plane, op);
|
|
3610
|
+
}
|
|
3611
|
+
function takePendingScrollOps(planes) {
|
|
3612
|
+
const planesToTake = (planes === null || planes === void 0 ? void 0 : planes.length) ? planes : TERMINAL_RENDER_PLANES;
|
|
3613
|
+
const out = [];
|
|
3614
|
+
for (const plane of planesToTake) {
|
|
3615
|
+
const op = pendingPlaneScrollOps.get(plane);
|
|
3616
|
+
if (!op) continue;
|
|
3617
|
+
pendingPlaneScrollOps.delete(plane);
|
|
3618
|
+
out.push({
|
|
3619
|
+
plane,
|
|
3620
|
+
...op
|
|
3621
|
+
});
|
|
3622
|
+
}
|
|
3623
|
+
return out.length ? out : null;
|
|
3624
|
+
}
|
|
3625
|
+
function higherPlanesFor(plane) {
|
|
3626
|
+
const planeIndex = TERMINAL_RENDER_PLANES.indexOf(plane);
|
|
3627
|
+
if (planeIndex < 0) return [];
|
|
3628
|
+
return TERMINAL_RENDER_PLANES.slice(planeIndex + 1);
|
|
3629
|
+
}
|
|
3630
|
+
function higherPlaneCoverageKind(plane, y) {
|
|
3631
|
+
const higherPlanes = higherPlanesFor(plane);
|
|
3632
|
+
if (!higherPlanes.length || y < 0 || y >= compositeBuffer.rows) return 0;
|
|
3633
|
+
let covered = 0;
|
|
3634
|
+
for (let x = 0; x < compositeBuffer.cols; x++) {
|
|
3635
|
+
let cellCovered = false;
|
|
3636
|
+
for (const higherPlane of higherPlanes) {
|
|
3637
|
+
var _state$coverage$y2;
|
|
3638
|
+
const state = planeStates.get(higherPlane);
|
|
3639
|
+
if (state === null || state === void 0 || (_state$coverage$y2 = state.coverage[y]) === null || _state$coverage$y2 === void 0 ? void 0 : _state$coverage$y2[x]) {
|
|
3640
|
+
cellCovered = true;
|
|
3641
|
+
break;
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3644
|
+
if (cellCovered) covered++;
|
|
3645
|
+
}
|
|
3646
|
+
if (covered === 0) return 0;
|
|
3647
|
+
if (covered >= compositeBuffer.cols) return 2;
|
|
3648
|
+
return 1;
|
|
3649
|
+
}
|
|
3650
|
+
function prepareCompositeScrollOps(pendingOps) {
|
|
3651
|
+
if (!(pendingOps === null || pendingOps === void 0 ? void 0 : pendingOps.length)) return {
|
|
3652
|
+
scrollOperations: null,
|
|
3653
|
+
extraDirtyRows: []
|
|
3654
|
+
};
|
|
3655
|
+
const scrollOperations = [];
|
|
3656
|
+
const extraDirtyRows = new Set();
|
|
3657
|
+
for (const pending of pendingOps) {
|
|
3658
|
+
const blockedRows = new Set();
|
|
3659
|
+
const partiallyBlockedRows = new Set();
|
|
3660
|
+
for (let y = pending.startY; y < pending.endY; y++) {
|
|
3661
|
+
const coverageKind = higherPlaneCoverageKind(pending.plane, y);
|
|
3662
|
+
if (coverageKind === 0) continue;
|
|
3663
|
+
blockedRows.add(y);
|
|
3664
|
+
if (coverageKind === 1) partiallyBlockedRows.add(y);
|
|
3665
|
+
}
|
|
3666
|
+
if (!blockedRows.size) {
|
|
3667
|
+
scrollOperations.push({
|
|
3668
|
+
startY: pending.startY,
|
|
3669
|
+
endY: pending.endY,
|
|
3670
|
+
delta: pending.delta
|
|
3671
|
+
});
|
|
3672
|
+
continue;
|
|
3673
|
+
}
|
|
3674
|
+
const absDelta = Math.abs(pending.delta);
|
|
3675
|
+
for (let y = pending.startY; y < pending.endY; y++) if (partiallyBlockedRows.has(y)) extraDirtyRows.add(y);
|
|
3676
|
+
let bandStart = -1;
|
|
3677
|
+
const flushBand = (bandEnd) => {
|
|
3678
|
+
if (bandStart < 0 || bandEnd <= bandStart) return;
|
|
3679
|
+
const bandHeight = bandEnd - bandStart;
|
|
3680
|
+
if (absDelta >= bandHeight) {
|
|
3681
|
+
for (let y = bandStart; y < bandEnd; y++) extraDirtyRows.add(y);
|
|
3682
|
+
bandStart = -1;
|
|
3683
|
+
return;
|
|
3684
|
+
}
|
|
3685
|
+
scrollOperations.push({
|
|
3686
|
+
startY: bandStart,
|
|
3687
|
+
endY: bandEnd,
|
|
3688
|
+
delta: pending.delta
|
|
3689
|
+
});
|
|
3690
|
+
if (pending.delta > 0) for (let y = bandEnd - absDelta; y < bandEnd; y++) extraDirtyRows.add(y);
|
|
3691
|
+
else for (let y = bandStart; y < bandStart + absDelta; y++) extraDirtyRows.add(y);
|
|
3692
|
+
bandStart = -1;
|
|
3693
|
+
};
|
|
3694
|
+
for (let y = pending.startY; y < pending.endY; y++) {
|
|
3695
|
+
if (blockedRows.has(y)) {
|
|
3696
|
+
flushBand(y);
|
|
3697
|
+
continue;
|
|
3698
|
+
}
|
|
3699
|
+
if (bandStart < 0) bandStart = y;
|
|
3700
|
+
}
|
|
3701
|
+
flushBand(pending.endY);
|
|
3702
|
+
}
|
|
3703
|
+
return {
|
|
3704
|
+
scrollOperations: scrollOperations.length ? scrollOperations : null,
|
|
3705
|
+
extraDirtyRows: Array.from(extraDirtyRows).sort((a, b) => a - b)
|
|
3706
|
+
};
|
|
3707
|
+
}
|
|
3708
|
+
function scrollRowsForPlane(plane, startY, endY, lines) {
|
|
3709
|
+
const state = getPlaneState(plane);
|
|
3710
|
+
const op = normalizeScrollOperation(startY, endY, lines, state.buffer.rows);
|
|
3711
|
+
if (!op) return;
|
|
3712
|
+
scrollBufferRegion(state.buffer, op.startY, op.endY, op.delta);
|
|
3713
|
+
scrollPlaneCoverageRegion(state, op.startY, op.endY, op.delta);
|
|
3714
|
+
recordPendingScrollOp(plane, op);
|
|
3715
|
+
}
|
|
3034
3716
|
function composeRows(rows) {
|
|
3035
3717
|
const blank = createBlankCell();
|
|
3718
|
+
const fpFn = compositeBuffer.fingerprintFn;
|
|
3719
|
+
const fpArr = compositeBuffer.soaFingerprints;
|
|
3036
3720
|
const rowList = rows ?? Array.from({ length: compositeBuffer.rows }, (_, index) => index);
|
|
3037
3721
|
for (const y of rowList) {
|
|
3038
3722
|
if (y < 0 || y >= compositeBuffer.rows) continue;
|
|
@@ -3056,6 +3740,14 @@ function createTerminal(opts) {
|
|
|
3056
3740
|
if (x === 0 || dst[x - 1].width !== 2 || dst[x - 1].continuation) dst[x] = blank;
|
|
3057
3741
|
}
|
|
3058
3742
|
}
|
|
3743
|
+
if (fpFn && fpArr) {
|
|
3744
|
+
const physY = (compositeBuffer.gridStart + y) % compositeBuffer.rows;
|
|
3745
|
+
const base$1 = physY * cols;
|
|
3746
|
+
for (let x = 0; x < cols; x++) {
|
|
3747
|
+
const cell = dst[x];
|
|
3748
|
+
fpArr[base$1 + x] = fpFn(cell.ch, cell.style);
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3059
3751
|
markDirty(compositeBuffer, y);
|
|
3060
3752
|
}
|
|
3061
3753
|
}
|
|
@@ -3228,6 +3920,14 @@ function createTerminal(opts) {
|
|
|
3228
3920
|
const all = state.buffer.scrollback.map((row) => row.map((cell) => cell.continuation ? " " : cell.ch || " ").join(""));
|
|
3229
3921
|
if (count == null) return all;
|
|
3230
3922
|
return all.slice(Math.max(0, all.length - Math.max(0, Math.floor(count))));
|
|
3923
|
+
},
|
|
3924
|
+
setFingerprintFn(fn) {
|
|
3925
|
+
assertNotDisposed();
|
|
3926
|
+
base.setFingerprintFn(fn);
|
|
3927
|
+
},
|
|
3928
|
+
getRowFingerprints(y) {
|
|
3929
|
+
assertNotDisposed();
|
|
3930
|
+
return base.getRowFingerprints(y);
|
|
3231
3931
|
}
|
|
3232
3932
|
};
|
|
3233
3933
|
planeTerminals.set(plane, api);
|
|
@@ -3302,6 +4002,9 @@ function createTerminal(opts) {
|
|
|
3302
4002
|
return pendingDirtyRowsForPlanes((meta === null || meta === void 0 ? void 0 : meta.planes) ?? null);
|
|
3303
4003
|
}
|
|
3304
4004
|
const planesToCompose = (meta === null || meta === void 0 || (_meta$planes2 = meta.planes) === null || _meta$planes2 === void 0 ? void 0 : _meta$planes2.length) ? meta.planes : TERMINAL_RENDER_PLANES;
|
|
4005
|
+
const pendingScrollOps = takePendingScrollOps(planesToCompose);
|
|
4006
|
+
const preparedScroll = prepareCompositeScrollOps(pendingScrollOps);
|
|
4007
|
+
const scrollOperations = preparedScroll.scrollOperations;
|
|
3305
4008
|
let composeAllRows = false;
|
|
3306
4009
|
const dirtyRows = new Set();
|
|
3307
4010
|
for (const plane of planesToCompose) {
|
|
@@ -3314,13 +4017,17 @@ function createTerminal(opts) {
|
|
|
3314
4017
|
}
|
|
3315
4018
|
for (const y of rows) dirtyRows.add(y);
|
|
3316
4019
|
}
|
|
4020
|
+
for (const y of preparedScroll.extraDirtyRows) dirtyRows.add(y);
|
|
3317
4021
|
const normalizedDirtyRows = composeAllRows ? null : Array.from(dirtyRows).sort((a, b) => a - b);
|
|
4022
|
+
if (scrollOperations) for (const op of scrollOperations) scrollBufferRegion(compositeBuffer, op.startY, op.endY, op.delta);
|
|
3318
4023
|
if (normalizedDirtyRows !== null && normalizedDirtyRows.length === 0) {
|
|
3319
4024
|
const pendingCompositeRows = collectAndClearDirtyRows(compositeBuffer);
|
|
3320
4025
|
if (pendingCompositeRows !== null && pendingCompositeRows.length === 0) return pendingCompositeRows;
|
|
3321
4026
|
emitter.emit("commit", {
|
|
3322
4027
|
dirtyRows: pendingCompositeRows,
|
|
3323
|
-
planes: (meta === null || meta === void 0 ? void 0 : meta.planes) ?? null
|
|
4028
|
+
planes: (meta === null || meta === void 0 ? void 0 : meta.planes) ?? null,
|
|
4029
|
+
sync: meta === null || meta === void 0 ? void 0 : meta.sync,
|
|
4030
|
+
scrollOperations
|
|
3324
4031
|
});
|
|
3325
4032
|
return pendingCompositeRows;
|
|
3326
4033
|
}
|
|
@@ -3331,7 +4038,9 @@ function createTerminal(opts) {
|
|
|
3331
4038
|
if (committedRows !== null && committedRows.length === 0) return committedRows;
|
|
3332
4039
|
emitter.emit("commit", {
|
|
3333
4040
|
dirtyRows: committedRows,
|
|
3334
|
-
planes: (meta === null || meta === void 0 ? void 0 : meta.planes) ?? null
|
|
4041
|
+
planes: (meta === null || meta === void 0 ? void 0 : meta.planes) ?? null,
|
|
4042
|
+
sync: meta === null || meta === void 0 ? void 0 : meta.sync,
|
|
4043
|
+
scrollOperations
|
|
3335
4044
|
});
|
|
3336
4045
|
return committedRows;
|
|
3337
4046
|
},
|
|
@@ -3386,6 +4095,14 @@ function createTerminal(opts) {
|
|
|
3386
4095
|
const all = state.buffer.scrollback.map((row) => row.map((cell) => cell.continuation ? " " : cell.ch || " ").join(""));
|
|
3387
4096
|
if (count == null) return all;
|
|
3388
4097
|
return all.slice(Math.max(0, all.length - Math.max(0, Math.floor(count))));
|
|
4098
|
+
},
|
|
4099
|
+
setFingerprintFn(fn) {
|
|
4100
|
+
assertNotDisposed();
|
|
4101
|
+
setFingerprintFn(compositeBuffer, fn);
|
|
4102
|
+
},
|
|
4103
|
+
getRowFingerprints(y) {
|
|
4104
|
+
assertNotDisposed();
|
|
4105
|
+
return getRowFingerprints(compositeBuffer, y);
|
|
3389
4106
|
}
|
|
3390
4107
|
};
|
|
3391
4108
|
base[TERMINAL_PLANE_INTERNALS] = {
|
|
@@ -3398,6 +4115,20 @@ function createTerminal(opts) {
|
|
|
3398
4115
|
return;
|
|
3399
4116
|
}
|
|
3400
4117
|
for (const y of rows) clearPlaneCoverageRow(state, y);
|
|
4118
|
+
},
|
|
4119
|
+
getRowCoverageKind(plane, y) {
|
|
4120
|
+
const state = getPlaneState(plane);
|
|
4121
|
+
if (y < 0 || y >= state.coverage.length) return 0;
|
|
4122
|
+
const row = state.coverage[y];
|
|
4123
|
+
if (!(row === null || row === void 0 ? void 0 : row.length)) return 0;
|
|
4124
|
+
let covered = 0;
|
|
4125
|
+
for (let x = 0; x < row.length; x++) if (row[x]) covered++;
|
|
4126
|
+
if (covered === 0) return 0;
|
|
4127
|
+
if (covered >= row.length) return 2;
|
|
4128
|
+
return 1;
|
|
4129
|
+
},
|
|
4130
|
+
scrollRows(plane, startY, endY, lines) {
|
|
4131
|
+
scrollRowsForPlane(plane, startY, endY, lines);
|
|
3401
4132
|
}
|
|
3402
4133
|
};
|
|
3403
4134
|
return base;
|
|
@@ -3542,6 +4273,7 @@ function createCliEventManager(options) {
|
|
|
3542
4273
|
let hoverPath = [];
|
|
3543
4274
|
const record = options === null || options === void 0 ? void 0 : options.record;
|
|
3544
4275
|
const onFocusChange = options === null || options === void 0 ? void 0 : options.onFocusChange;
|
|
4276
|
+
const latency = getCliLatencyProfiler();
|
|
3545
4277
|
const MODAL_FOCUS_Z_THRESHOLD = 100;
|
|
3546
4278
|
const MODAL_ROOT_MIN_AREA = 40;
|
|
3547
4279
|
function focusLockTarget() {
|
|
@@ -3719,7 +4451,7 @@ function createCliEventManager(options) {
|
|
|
3719
4451
|
handler(event);
|
|
3720
4452
|
} catch (err) {
|
|
3721
4453
|
try {
|
|
3722
|
-
const env = process === null || process === void 0 ? void 0 : process.env;
|
|
4454
|
+
const env = process$1 === null || process$1 === void 0 ? void 0 : process$1.env;
|
|
3723
4455
|
if ((env === null || env === void 0 ? void 0 : env.DIMCODE_DEBUG) === "1") {
|
|
3724
4456
|
const timestamp = new Date().toISOString().split("T")[1].slice(0, -1);
|
|
3725
4457
|
appendFileSync("/tmp/goatchain-debug.log", `[${timestamp}] [EVENT-MGR] ERROR in handler ${node.id}.${handlerKey}: ${err}\n`);
|
|
@@ -3921,51 +4653,65 @@ function createCliEventManager(options) {
|
|
|
3921
4653
|
},
|
|
3922
4654
|
dispatch(event) {
|
|
3923
4655
|
record === null || record === void 0 || record(event);
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
capturedId = (target === null || target === void 0 ? void 0 : target.id) ?? null;
|
|
3931
|
-
updateHover(target, event);
|
|
3932
|
-
dispatchPointerEvent("pointerdown", event, target);
|
|
3933
|
-
return false;
|
|
3934
|
-
}
|
|
3935
|
-
if (event.type === "pointermove" && capturedId) {
|
|
3936
|
-
const target = nodes.get(capturedId) ?? null;
|
|
3937
|
-
if (!target) return false;
|
|
3938
|
-
updateHover(target, event);
|
|
3939
|
-
const path = ancestorsForTarget(target);
|
|
3940
|
-
const ev = buildPointerEvent("pointermove", path, event);
|
|
3941
|
-
dispatchWithPhases("pointermove", path, target, ev);
|
|
3942
|
-
return ev.defaultPrevented;
|
|
3943
|
-
}
|
|
3944
|
-
if (event.type === "pointermove") {
|
|
3945
|
-
const list = candidatesAt(event.cellX, event.cellY);
|
|
3946
|
-
const target = pickTarget(list);
|
|
3947
|
-
updateHover(target, event);
|
|
3948
|
-
dispatchPointerEvent("pointermove", event, target);
|
|
3949
|
-
return false;
|
|
4656
|
+
latency === null || latency === void 0 || latency.recordEventDispatchStart(event);
|
|
4657
|
+
let prevented = false;
|
|
4658
|
+
try {
|
|
4659
|
+
if (event.type === "keydown" || event.type === "keyup") {
|
|
4660
|
+
prevented = dispatchToFocused(event.type, event);
|
|
4661
|
+
return prevented;
|
|
3950
4662
|
}
|
|
3951
|
-
if (event.type === "pointerup"
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
4663
|
+
if (event.type === "pointerdown" || event.type === "pointermove" || event.type === "pointerup" || event.type === "click" || event.type === "dblclick" || event.type === "contextmenu" || event.type === "wheel") {
|
|
4664
|
+
if (event.type === "pointerdown") {
|
|
4665
|
+
const list = candidatesAt(event.cellX, event.cellY);
|
|
4666
|
+
const target = pickTarget(list);
|
|
4667
|
+
if (target === null || target === void 0 ? void 0 : target.focusable) setFocus(target.id);
|
|
4668
|
+
capturedId = (target === null || target === void 0 ? void 0 : target.id) ?? null;
|
|
4669
|
+
updateHover(target, event);
|
|
4670
|
+
dispatchPointerEvent("pointerdown", event, target);
|
|
4671
|
+
return prevented;
|
|
4672
|
+
}
|
|
4673
|
+
if (event.type === "pointermove" && capturedId) {
|
|
4674
|
+
const target = nodes.get(capturedId) ?? null;
|
|
4675
|
+
if (!target) return prevented;
|
|
4676
|
+
updateHover(target, event);
|
|
4677
|
+
const path = ancestorsForTarget(target);
|
|
4678
|
+
const ev = buildPointerEvent("pointermove", path, event);
|
|
4679
|
+
dispatchWithPhases("pointermove", path, target, ev);
|
|
4680
|
+
prevented = ev.defaultPrevented;
|
|
4681
|
+
return prevented;
|
|
4682
|
+
}
|
|
4683
|
+
if (event.type === "pointermove") {
|
|
4684
|
+
const list = candidatesAt(event.cellX, event.cellY);
|
|
4685
|
+
const target = pickTarget(list);
|
|
4686
|
+
updateHover(target, event);
|
|
4687
|
+
dispatchPointerEvent("pointermove", event, target);
|
|
4688
|
+
return prevented;
|
|
4689
|
+
}
|
|
4690
|
+
if (event.type === "pointerup" && capturedId) {
|
|
4691
|
+
const target = nodes.get(capturedId) ?? null;
|
|
4692
|
+
const path = target ? ancestorsForTarget(target) : [];
|
|
4693
|
+
const ev = buildPointerEvent("pointerup", path, event);
|
|
4694
|
+
dispatchWithPhases("pointerup", path, target, ev);
|
|
4695
|
+
capturedId = null;
|
|
4696
|
+
prevented = ev.defaultPrevented;
|
|
4697
|
+
return prevented;
|
|
4698
|
+
}
|
|
4699
|
+
if (event.type === "pointerup") {
|
|
4700
|
+
dispatchPointerEvent("pointerup", event);
|
|
4701
|
+
capturedId = null;
|
|
4702
|
+
return prevented;
|
|
4703
|
+
}
|
|
4704
|
+
dispatchPointerEvent(event.type, event);
|
|
4705
|
+
return prevented;
|
|
3958
4706
|
}
|
|
3959
|
-
if (event.type === "
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
return false;
|
|
4707
|
+
if (event.type === "beforeinput" || event.type === "input" || event.type === "compositionstart" || event.type === "compositionupdate" || event.type === "compositionend" || event.type === "paste") {
|
|
4708
|
+
prevented = dispatchToFocusedText(event.type, event);
|
|
4709
|
+
return prevented;
|
|
3963
4710
|
}
|
|
3964
|
-
|
|
3965
|
-
|
|
4711
|
+
return prevented;
|
|
4712
|
+
} finally {
|
|
4713
|
+
latency === null || latency === void 0 || latency.recordEventDispatchEnd(event, { defaultPrevented: prevented });
|
|
3966
4714
|
}
|
|
3967
|
-
if (event.type === "beforeinput" || event.type === "input" || event.type === "compositionstart" || event.type === "compositionupdate" || event.type === "compositionend" || event.type === "paste") return dispatchToFocusedText(event.type, event);
|
|
3968
|
-
return false;
|
|
3969
4715
|
},
|
|
3970
4716
|
debugNodes() {
|
|
3971
4717
|
return Array.from(nodes.values()).map((n) => ({
|
|
@@ -5057,7 +5803,7 @@ function formatClockTime(ms) {
|
|
|
5057
5803
|
}
|
|
5058
5804
|
function createTuiProfiler(name) {
|
|
5059
5805
|
var _unref;
|
|
5060
|
-
const env = process === null || process === void 0 ? void 0 : process.env;
|
|
5806
|
+
const env = process$1 === null || process$1 === void 0 ? void 0 : process$1.env;
|
|
5061
5807
|
if (!parseEnabled(env === null || env === void 0 ? void 0 : env.DIMCODE_PROFILE_TUI)) return null;
|
|
5062
5808
|
const format = parseLogFormat(env === null || env === void 0 ? void 0 : env.DIMCODE_PROFILE_TUI_FORMAT);
|
|
5063
5809
|
const logDest = parseLogDest(env === null || env === void 0 ? void 0 : env.DIMCODE_PROFILE_TUI_LOG_DEST);
|
|
@@ -5080,8 +5826,8 @@ function createTuiProfiler(name) {
|
|
|
5080
5826
|
const invalidatePlaneCounts = new Map();
|
|
5081
5827
|
const renderPlaneCounts = new Map();
|
|
5082
5828
|
const logEveryMs = Number((env === null || env === void 0 ? void 0 : env.DIMCODE_PROFILE_TUI_LOG_EVERY_MS) ?? 1e3);
|
|
5083
|
-
const now$
|
|
5084
|
-
let lastLogAt = now$
|
|
5829
|
+
const now$3 = defaultNow;
|
|
5830
|
+
let lastLogAt = now$3();
|
|
5085
5831
|
function incrementPlaneCount(target, key) {
|
|
5086
5832
|
const normalized = String(key ?? "all").trim() || "all";
|
|
5087
5833
|
target.set(normalized, (target.get(normalized) ?? 0) + 1);
|
|
@@ -5094,7 +5840,7 @@ function createTuiProfiler(name) {
|
|
|
5094
5840
|
if (dest === "stdout" || dest === "both") console.log(line);
|
|
5095
5841
|
}
|
|
5096
5842
|
function flushLog() {
|
|
5097
|
-
const at = now$
|
|
5843
|
+
const at = now$3();
|
|
5098
5844
|
const elapsed = at - lastLogAt;
|
|
5099
5845
|
if (elapsed <= 0) return;
|
|
5100
5846
|
lastLogAt = at;
|
|
@@ -5165,7 +5911,7 @@ function createTuiProfiler(name) {
|
|
|
5165
5911
|
const timer = setInterval(flushLog, Number.isFinite(logEveryMs) ? Math.max(100, logEveryMs) : 1e3);
|
|
5166
5912
|
(_unref = timer.unref) === null || _unref === void 0 || _unref.call(timer);
|
|
5167
5913
|
return {
|
|
5168
|
-
now: now$
|
|
5914
|
+
now: now$3,
|
|
5169
5915
|
recordInvalidate(info) {
|
|
5170
5916
|
invalidates++;
|
|
5171
5917
|
incrementPlaneCount(invalidatePlaneCounts, (info === null || info === void 0 ? void 0 : info.plane) ?? "all");
|
|
@@ -5536,7 +6282,7 @@ function write(data) {
|
|
|
5536
6282
|
* Check if debug logging is enabled via environment variable
|
|
5537
6283
|
*/
|
|
5538
6284
|
function isDebugEnabled() {
|
|
5539
|
-
const env = process === null || process === void 0 ? void 0 : process.env;
|
|
6285
|
+
const env = process$1 === null || process$1 === void 0 ? void 0 : process$1.env;
|
|
5540
6286
|
return (env === null || env === void 0 ? void 0 : env.DIMCODE_DEBUG) === "1" || (env === null || env === void 0 ? void 0 : env.DEBUG) === "1";
|
|
5541
6287
|
}
|
|
5542
6288
|
|
|
@@ -6012,6 +6758,26 @@ function createRenderManager(terminal) {
|
|
|
6012
6758
|
if (y > state.dirtyMaxY) state.dirtyMaxY = y;
|
|
6013
6759
|
}
|
|
6014
6760
|
}
|
|
6761
|
+
function markRows(plane, rows) {
|
|
6762
|
+
if (!rows.length) return;
|
|
6763
|
+
const state = getDirtyState(plane);
|
|
6764
|
+
for (let i = 0; i < rows.length; i++) {
|
|
6765
|
+
const y = Math.floor(rows[i] ?? -1);
|
|
6766
|
+
if (y < 0 || y >= terminalRows) continue;
|
|
6767
|
+
if (state.dirtyRowBits[y] === 0) {
|
|
6768
|
+
state.dirtyRowBits[y] = 1;
|
|
6769
|
+
state.dirtyRowCount++;
|
|
6770
|
+
if (y < state.dirtyMinY) state.dirtyMinY = y;
|
|
6771
|
+
if (y > state.dirtyMaxY) state.dirtyMaxY = y;
|
|
6772
|
+
}
|
|
6773
|
+
}
|
|
6774
|
+
}
|
|
6775
|
+
function scrollPlane(plane, startY, endY, delta) {
|
|
6776
|
+
scrollPlaneRows(terminal, plane, startY, endY, delta);
|
|
6777
|
+
}
|
|
6778
|
+
function invalidatePlane(plane) {
|
|
6779
|
+
getDirtyState(plane).allRowsDirty = true;
|
|
6780
|
+
}
|
|
6015
6781
|
function register(node) {
|
|
6016
6782
|
const id = `r${nextNodeId++}`;
|
|
6017
6783
|
const rect = node.rect ?? null;
|
|
@@ -6039,8 +6805,13 @@ function createRenderManager(terminal) {
|
|
|
6039
6805
|
const nextPlane = next.plane ?? prev.plane;
|
|
6040
6806
|
const nextRect = next.rect ?? prev.rect;
|
|
6041
6807
|
const { y0, y1 } = rectToYBounds(nextRect);
|
|
6042
|
-
|
|
6043
|
-
|
|
6808
|
+
const dirtyRowsHint = next.dirtyRowsHint;
|
|
6809
|
+
const canUseDirtyRowsHint = nextPlane === prev.plane && dirtyRowsHint != null && dirtyRowsHint.length > 0;
|
|
6810
|
+
if (canUseDirtyRowsHint) markRows(nextPlane, dirtyRowsHint);
|
|
6811
|
+
else {
|
|
6812
|
+
markRect(prev.plane, prev.rect);
|
|
6813
|
+
markRect(nextPlane, nextRect);
|
|
6814
|
+
}
|
|
6044
6815
|
const full = Object.freeze({
|
|
6045
6816
|
...prev,
|
|
6046
6817
|
stack: next.stack ?? prev.stack,
|
|
@@ -6102,10 +6873,11 @@ function createRenderManager(terminal) {
|
|
|
6102
6873
|
return false;
|
|
6103
6874
|
}
|
|
6104
6875
|
function render(options) {
|
|
6876
|
+
var _process;
|
|
6105
6877
|
const renderStart = profiler === null || profiler === void 0 ? void 0 : profiler.now();
|
|
6106
6878
|
const activePlanes = (options === null || options === void 0 ? void 0 : options.activePlanes) ?? null;
|
|
6107
6879
|
const requestedPlanes = activePlanes ?? TERMINAL_RENDER_PLANES;
|
|
6108
|
-
const env = process === null ||
|
|
6880
|
+
const env = (_process = process) === null || _process === void 0 ? void 0 : _process.env;
|
|
6109
6881
|
if ((env === null || env === void 0 ? void 0 : env.DIMCODE_DEBUG) === "1") renderMgrDebugLog.render("[RENDER-MANAGER] render() called");
|
|
6110
6882
|
if (!hasPendingDirtyWork(requestedPlanes)) {
|
|
6111
6883
|
if ((env === null || env === void 0 ? void 0 : env.DIMCODE_DEBUG) === "1") renderMgrDebugLog.render("[RENDER-MANAGER] render() skipped (no dirty rows)");
|
|
@@ -6213,6 +6985,8 @@ function createRenderManager(terminal) {
|
|
|
6213
6985
|
return {
|
|
6214
6986
|
rootStack,
|
|
6215
6987
|
createStack,
|
|
6988
|
+
invalidatePlane,
|
|
6989
|
+
scrollPlane,
|
|
6216
6990
|
register,
|
|
6217
6991
|
update,
|
|
6218
6992
|
unregister,
|
|
@@ -6257,6 +7031,7 @@ function createTerminalApp(options) {
|
|
|
6257
7031
|
rows: options.rows
|
|
6258
7032
|
});
|
|
6259
7033
|
const trace = createTraceStore({ enabled: Boolean(globalThis.__VT_DEBUG_TRACE__) });
|
|
7034
|
+
const latency = getCliLatencyProfiler();
|
|
6260
7035
|
const profiler = createTuiProfiler("cli-scheduler");
|
|
6261
7036
|
const events = createCliEventManager({
|
|
6262
7037
|
record: (event) => {
|
|
@@ -6278,7 +7053,12 @@ function createTerminalApp(options) {
|
|
|
6278
7053
|
}
|
|
6279
7054
|
});
|
|
6280
7055
|
const render = createRenderManager(terminal);
|
|
6281
|
-
const offCommit = terminal.on("commit", ({ dirtyRows, planes }) => {
|
|
7056
|
+
const offCommit = terminal.on("commit", ({ dirtyRows, planes, sync }) => {
|
|
7057
|
+
latency === null || latency === void 0 || latency.recordCommit({
|
|
7058
|
+
dirtyRows,
|
|
7059
|
+
planes,
|
|
7060
|
+
sync
|
|
7061
|
+
});
|
|
6282
7062
|
if (!trace.enabled.value) return;
|
|
6283
7063
|
trace.push({
|
|
6284
7064
|
type: "commit",
|
|
@@ -6295,10 +7075,10 @@ function createTerminalApp(options) {
|
|
|
6295
7075
|
let lastFlushAtMs = 0;
|
|
6296
7076
|
let scheduledAtMs = 0;
|
|
6297
7077
|
let timer = null;
|
|
7078
|
+
let pendingInvalidateAfterFlush = false;
|
|
6298
7079
|
let pendingInvalidateAllPlanes = false;
|
|
6299
7080
|
const pendingInvalidatePlanes = new Set();
|
|
6300
|
-
const env = (process === null || process === void 0 ? void 0 : process.env) ?? {};
|
|
6301
|
-
const isGhostty = "GHOSTTY_RESOURCES_DIR" in env;
|
|
7081
|
+
const env = (process$1 === null || process$1 === void 0 ? void 0 : process$1.env) ?? {};
|
|
6302
7082
|
const throttleMs = (() => {
|
|
6303
7083
|
const raw = env.DIMCODE_TUI_THROTTLE_MS;
|
|
6304
7084
|
if (!raw) return 0;
|
|
@@ -6307,8 +7087,8 @@ function createTerminalApp(options) {
|
|
|
6307
7087
|
})();
|
|
6308
7088
|
const frameThrottleMs = (() => {
|
|
6309
7089
|
var _process$stdout;
|
|
6310
|
-
if (!(process === null || process === void 0 || (_process$stdout = process.stdout) === null || _process$stdout === void 0 ? void 0 : _process$stdout.isTTY)) return 0;
|
|
6311
|
-
return
|
|
7090
|
+
if (!(process$1 === null || process$1 === void 0 || (_process$stdout = process$1.stdout) === null || _process$stdout === void 0 ? void 0 : _process$stdout.isTTY)) return 0;
|
|
7091
|
+
return 16;
|
|
6312
7092
|
})();
|
|
6313
7093
|
function queueInvalidatePlane(plane) {
|
|
6314
7094
|
if (!plane) {
|
|
@@ -6330,16 +7110,31 @@ function createTerminalApp(options) {
|
|
|
6330
7110
|
pendingInvalidatePlanes.clear();
|
|
6331
7111
|
return activePlanes;
|
|
6332
7112
|
}
|
|
6333
|
-
function flush() {
|
|
7113
|
+
function flush(sync) {
|
|
6334
7114
|
if (disposed) return;
|
|
6335
7115
|
scheduled = false;
|
|
6336
7116
|
flushing = true;
|
|
6337
7117
|
const activePlanes = takeActivePlanes();
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
7118
|
+
latency === null || latency === void 0 || latency.recordFlushStart({
|
|
7119
|
+
sync,
|
|
7120
|
+
activePlanes
|
|
7121
|
+
});
|
|
7122
|
+
try {
|
|
7123
|
+
render.render({ activePlanes });
|
|
7124
|
+
terminal.commit({
|
|
7125
|
+
planes: activePlanes,
|
|
7126
|
+
sync
|
|
7127
|
+
});
|
|
7128
|
+
} finally {
|
|
7129
|
+
latency === null || latency === void 0 || latency.recordFlushEnd();
|
|
7130
|
+
flushing = false;
|
|
7131
|
+
lastFlushAtMs = Date.now();
|
|
7132
|
+
scheduledAtMs = 0;
|
|
7133
|
+
}
|
|
7134
|
+
if (pendingInvalidateAfterFlush) {
|
|
7135
|
+
pendingInvalidateAfterFlush = false;
|
|
7136
|
+
flush(true);
|
|
7137
|
+
}
|
|
6343
7138
|
}
|
|
6344
7139
|
function clearScheduledTimer() {
|
|
6345
7140
|
if (!timer) return;
|
|
@@ -6360,7 +7155,7 @@ function createTerminalApp(options) {
|
|
|
6360
7155
|
}
|
|
6361
7156
|
clearScheduledTimer();
|
|
6362
7157
|
scheduledAtMs = nowMs;
|
|
6363
|
-
if (typeof process.nextTick === "function") process.nextTick(() => {
|
|
7158
|
+
if (typeof process$1.nextTick === "function") process$1.nextTick(() => {
|
|
6364
7159
|
flush();
|
|
6365
7160
|
});
|
|
6366
7161
|
else if (typeof globalThis.setImmediate === "function") globalThis.setImmediate(() => {
|
|
@@ -6375,14 +7170,26 @@ function createTerminalApp(options) {
|
|
|
6375
7170
|
if (flushing) return;
|
|
6376
7171
|
clearScheduledTimer();
|
|
6377
7172
|
scheduled = false;
|
|
6378
|
-
flush();
|
|
7173
|
+
flush(true);
|
|
6379
7174
|
}
|
|
6380
7175
|
function invalidate(options$1) {
|
|
6381
7176
|
if (disposed) return;
|
|
6382
|
-
if (flushing) return;
|
|
6383
7177
|
const priority = (options$1 === null || options$1 === void 0 ? void 0 : options$1.priority) ?? "normal";
|
|
7178
|
+
latency === null || latency === void 0 || latency.recordSchedulerInvalidate({
|
|
7179
|
+
priority,
|
|
7180
|
+
plane: (options$1 === null || options$1 === void 0 ? void 0 : options$1.plane) ?? null
|
|
7181
|
+
});
|
|
7182
|
+
if (flushing) {
|
|
7183
|
+
queueInvalidatePlane(options$1 === null || options$1 === void 0 ? void 0 : options$1.plane);
|
|
7184
|
+
pendingInvalidateAfterFlush = true;
|
|
7185
|
+
return;
|
|
7186
|
+
}
|
|
6384
7187
|
queueInvalidatePlane(options$1 === null || options$1 === void 0 ? void 0 : options$1.plane);
|
|
6385
7188
|
profiler === null || profiler === void 0 || profiler.recordInvalidate({ plane: (options$1 === null || options$1 === void 0 ? void 0 : options$1.plane) ?? null });
|
|
7189
|
+
if (priority === "high") {
|
|
7190
|
+
flushNow();
|
|
7191
|
+
return;
|
|
7192
|
+
}
|
|
6386
7193
|
const nowMs = Date.now();
|
|
6387
7194
|
const throttleDelayMs = throttleMs > 0 ? Math.max(0, lastFlushAtMs + throttleMs - nowMs) : 0;
|
|
6388
7195
|
const laneDelayMs = priority === "low" ? Math.max(throttleDelayMs, frameThrottleMs || 16) : priority === "normal" ? Math.max(throttleDelayMs, frameThrottleMs) : 0;
|
|
@@ -6519,6 +7326,7 @@ function createTerminalApp(options) {
|
|
|
6519
7326
|
dispose() {
|
|
6520
7327
|
if (disposed) return;
|
|
6521
7328
|
disposed = true;
|
|
7329
|
+
clearScheduledTimer();
|
|
6522
7330
|
if (mounted) app.unmount();
|
|
6523
7331
|
offResize === null || offResize === void 0 || offResize();
|
|
6524
7332
|
offCommit === null || offCommit === void 0 || offCommit();
|
|
@@ -6602,7 +7410,7 @@ function parseWriteMode(raw) {
|
|
|
6602
7410
|
}
|
|
6603
7411
|
function createStdoutRenderer(terminal, options) {
|
|
6604
7412
|
var _ref3;
|
|
6605
|
-
const output = (options === null || options === void 0 ? void 0 : options.output) ?? process.stdout;
|
|
7413
|
+
const output = (options === null || options === void 0 ? void 0 : options.output) ?? process$1.stdout;
|
|
6606
7414
|
if (!output) throw new Error("createStdoutRenderer requires a Node stdout-like output");
|
|
6607
7415
|
const out = output;
|
|
6608
7416
|
const clear = (options === null || options === void 0 ? void 0 : options.clear) ?? true;
|
|
@@ -6612,22 +7420,23 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6612
7420
|
let palette = options === null || options === void 0 ? void 0 : options.palette;
|
|
6613
7421
|
const trackResize = (options === null || options === void 0 ? void 0 : options.trackResize) ?? true;
|
|
6614
7422
|
const getImeAnchor = options === null || options === void 0 ? void 0 : options.getImeAnchor;
|
|
7423
|
+
const cliLatency = getCliLatencyProfiler();
|
|
6615
7424
|
const profiler = createTuiProfiler("stdout-renderer");
|
|
6616
7425
|
function resolveUseSyncOutput() {
|
|
6617
7426
|
if ((options === null || options === void 0 ? void 0 : options.useSyncOutput) != null) return options.useSyncOutput;
|
|
6618
|
-
const env$1 = (process === null || process === void 0 ? void 0 : process.env) ?? {};
|
|
7427
|
+
const env$1 = (process$1 === null || process$1 === void 0 ? void 0 : process$1.env) ?? {};
|
|
6619
7428
|
const envValue = env$1.DIMCODE_SYNC_OUTPUT;
|
|
6620
7429
|
if (envValue != null) {
|
|
6621
7430
|
const v = String(envValue).trim().toLowerCase();
|
|
6622
7431
|
return v === "1" || v === "true" || v === "yes";
|
|
6623
7432
|
}
|
|
6624
|
-
const term = String(env$1.TERM ?? "").toLowerCase();
|
|
6625
|
-
const termProgram = String(env$1.TERM_PROGRAM ?? "").toLowerCase();
|
|
7433
|
+
const term$1 = String(env$1.TERM ?? "").toLowerCase();
|
|
7434
|
+
const termProgram$1 = String(env$1.TERM_PROGRAM ?? "").toLowerCase();
|
|
6626
7435
|
const termProgramVersion = env$1.TERM_PROGRAM_VERSION;
|
|
6627
7436
|
const isGhostty$1 = "GHOSTTY_RESOURCES_DIR" in env$1;
|
|
6628
|
-
const isProblematicTerminal = isGhostty$1 || termProgram.includes("apple_terminal") || term.includes("screen") && !term.includes("tmux");
|
|
7437
|
+
const isProblematicTerminal = isGhostty$1 || termProgram$1.includes("apple_terminal") || term$1.includes("screen") && !term$1.includes("tmux");
|
|
6629
7438
|
if (isProblematicTerminal) return false;
|
|
6630
|
-
const isGoodTerminal = termProgram.includes("iterm") && termProgramVersion && compareVersion(String(termProgramVersion), "3.5.0") >= 0;
|
|
7439
|
+
const isGoodTerminal = termProgram$1.includes("iterm") && termProgramVersion && compareVersion(String(termProgramVersion), "3.5.0") >= 0;
|
|
6631
7440
|
if (isGoodTerminal) return true;
|
|
6632
7441
|
return false;
|
|
6633
7442
|
}
|
|
@@ -6647,8 +7456,8 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6647
7456
|
return 0;
|
|
6648
7457
|
}
|
|
6649
7458
|
const useSyncOutput = resolveUseSyncOutput();
|
|
6650
|
-
const isGhostty = "GHOSTTY_RESOURCES_DIR" in ((process === null || process === void 0 ? void 0 : process.env) ?? {});
|
|
6651
|
-
const env = (process === null || process === void 0 ? void 0 : process.env) ?? {};
|
|
7459
|
+
const isGhostty = "GHOSTTY_RESOURCES_DIR" in ((process$1 === null || process$1 === void 0 ? void 0 : process$1.env) ?? {});
|
|
7460
|
+
const env = (process$1 === null || process$1 === void 0 ? void 0 : process$1.env) ?? {};
|
|
6652
7461
|
const forcedWriteMode = parseWriteMode(env.DIMCODE_TUI_WRITE_MODE ?? env.VUE_TUI_WRITE_MODE);
|
|
6653
7462
|
const forcedChunkSize = Number(env.DIMCODE_TUI_CHUNK_SIZE ?? env.VUE_TUI_CHUNK_SIZE);
|
|
6654
7463
|
const chunkSize = Number.isFinite(forcedChunkSize) ? Math.max(512, Math.floor(forcedChunkSize)) : 8 * 1024;
|
|
@@ -6663,12 +7472,15 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6663
7472
|
if (Number.isFinite(n)) return Math.min(1, Math.max(.05, n));
|
|
6664
7473
|
return .6;
|
|
6665
7474
|
})();
|
|
6666
|
-
const disableCursorPos = isGhostty && (process === null || process === void 0 || (_ref3 = process.env) === null || _ref3 === void 0 ? void 0 : _ref3.DIMCODE_DISABLE_CURSOR_POS) === "1";
|
|
6667
|
-
const
|
|
7475
|
+
const disableCursorPos = isGhostty && (process$1 === null || process$1 === void 0 || (_ref3 = process$1.env) === null || _ref3 === void 0 ? void 0 : _ref3.DIMCODE_DISABLE_CURSOR_POS) === "1";
|
|
7476
|
+
const termProgram = String(env.TERM_PROGRAM ?? "").trim().toLowerCase();
|
|
7477
|
+
const term = String(env.TERM ?? "").trim().toLowerCase();
|
|
7478
|
+
const isVscodeTerminal = termProgram === "vscode" || "VSCODE_PID" in env || "VSCODE_IPC_HOOK_CLI" in env;
|
|
7479
|
+
const useConservativeDirtyRowRendering = out.isTTY !== false && !isVscodeTerminal && (isGhostty || "KITTY_WINDOW_ID" in env || "ALACRITTY_WINDOW_ID" in env || "ALACRITTY_LOG" in env || "WEZTERM_PANE" in env || "WEZTERM_EXECUTABLE" in env || termProgram.includes("kitty") || termProgram.includes("alacritty") || termProgram.includes("wezterm") || term.includes("kitty") || term.includes("alacritty"));
|
|
6668
7480
|
const enableOsc8Links = (() => {
|
|
6669
7481
|
if (!out.isTTY) return false;
|
|
6670
7482
|
const raw = String(env.DIMCODE_TUI_LINKS ?? "").trim().toLowerCase();
|
|
6671
|
-
if (!raw) return !
|
|
7483
|
+
if (!raw) return !isVscodeTerminal;
|
|
6672
7484
|
return !(raw === "0" || raw === "false" || raw === "no");
|
|
6673
7485
|
})();
|
|
6674
7486
|
let disposed = false;
|
|
@@ -6676,12 +7488,16 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6676
7488
|
let pendingRender = false;
|
|
6677
7489
|
let renderTimer = null;
|
|
6678
7490
|
let writeEmaMs = 0;
|
|
7491
|
+
let lastCursorX = null;
|
|
7492
|
+
let lastCursorY = null;
|
|
6679
7493
|
let accumulatedAllRows = false;
|
|
6680
7494
|
let accumulatedDirtyBits = null;
|
|
6681
7495
|
let accumulatedDirtyCount = 0;
|
|
6682
7496
|
let accumulatedDirtyMin = Number.POSITIVE_INFINITY;
|
|
6683
7497
|
let accumulatedDirtyMax = -1;
|
|
6684
|
-
|
|
7498
|
+
let accumulatedScrollOperations = null;
|
|
7499
|
+
let accumulatedSkipUnchangedDirtyRows = true;
|
|
7500
|
+
const MIN_FRAME_MS = !out.isTTY ? 0 : 16;
|
|
6685
7501
|
function clampCellToViewport(cell, size) {
|
|
6686
7502
|
const maxX = Math.max(0, Math.floor(size.cols) - 1);
|
|
6687
7503
|
const maxY = Math.max(0, Math.floor(size.rows) - 1);
|
|
@@ -6697,25 +7513,43 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6697
7513
|
function resolveColorMode() {
|
|
6698
7514
|
const opt = (options === null || options === void 0 ? void 0 : options.colorMode) ?? "auto";
|
|
6699
7515
|
if (opt !== "auto") return opt;
|
|
6700
|
-
const env$1 = (process === null || process === void 0 ? void 0 : process.env) ?? {};
|
|
7516
|
+
const env$1 = (process$1 === null || process$1 === void 0 ? void 0 : process$1.env) ?? {};
|
|
6701
7517
|
return detectTerminalColorCapability({
|
|
6702
7518
|
env: env$1,
|
|
6703
7519
|
isTTY: Boolean(out.isTTY),
|
|
6704
|
-
platform: String((process === null || process === void 0 ? void 0 : process.platform) ?? "")
|
|
7520
|
+
platform: String((process$1 === null || process$1 === void 0 ? void 0 : process$1.platform) ?? "")
|
|
6705
7521
|
}).mode;
|
|
6706
7522
|
}
|
|
6707
7523
|
const colorMode = resolveColorMode();
|
|
6708
7524
|
const enableDim = colorMode === "truecolor";
|
|
7525
|
+
const COLOR_INDEX = {
|
|
7526
|
+
black: 1,
|
|
7527
|
+
red: 2,
|
|
7528
|
+
green: 3,
|
|
7529
|
+
yellow: 4,
|
|
7530
|
+
blue: 5,
|
|
7531
|
+
magenta: 6,
|
|
7532
|
+
cyan: 7,
|
|
7533
|
+
white: 8,
|
|
7534
|
+
blackBright: 9,
|
|
7535
|
+
redBright: 10,
|
|
7536
|
+
greenBright: 11,
|
|
7537
|
+
yellowBright: 12,
|
|
7538
|
+
blueBright: 13,
|
|
7539
|
+
magentaBright: 14,
|
|
7540
|
+
cyanBright: 15,
|
|
7541
|
+
whiteBright: 16
|
|
7542
|
+
};
|
|
6709
7543
|
let styleKeyCache$1 = new WeakMap();
|
|
6710
7544
|
function styleKey$1(style) {
|
|
6711
7545
|
const cached = styleKeyCache$1.get(style);
|
|
6712
|
-
if (cached) return cached;
|
|
6713
|
-
const key =
|
|
7546
|
+
if (cached !== void 0) return cached;
|
|
7547
|
+
const key = (COLOR_INDEX[style.fg] ?? 0) | (COLOR_INDEX[style.bg ?? defaultBg] ?? 0) << 5 | (style.bold ? 1024 : 0) | (enableDim && style.dim ? 2048 : 0) | (style.italic ? 4096 : 0) | (style.underline ? 8192 : 0) | (style.inverse ? 16384 : 0) | (style.href ? 32768 : 0);
|
|
6714
7548
|
styleKeyCache$1.set(style, key);
|
|
6715
7549
|
return key;
|
|
6716
7550
|
}
|
|
6717
7551
|
function styleKeyFromParts(style) {
|
|
6718
|
-
return
|
|
7552
|
+
return (COLOR_INDEX[style.fg] ?? 0) | (COLOR_INDEX[style.bg ?? defaultBg] ?? 0) << 5 | (style.bold ? 1024 : 0) | (enableDim && style.dim ? 2048 : 0) | (style.italic ? 4096 : 0) | (style.underline ? 8192 : 0) | (style.inverse ? 16384 : 0) | (style.href ? 32768 : 0);
|
|
6719
7553
|
}
|
|
6720
7554
|
function openColor(fg) {
|
|
6721
7555
|
if (!fg) return "";
|
|
@@ -6747,7 +7581,45 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6747
7581
|
return result;
|
|
6748
7582
|
}
|
|
6749
7583
|
let lastRenderedRows = 0;
|
|
6750
|
-
let
|
|
7584
|
+
let fpCols = 0;
|
|
7585
|
+
let fpRows = 0;
|
|
7586
|
+
let currentFP = new Uint32Array(0);
|
|
7587
|
+
let prevFP = new Uint32Array(0);
|
|
7588
|
+
let fpPrevValid = false;
|
|
7589
|
+
let prevOverlayBlockedRows = [];
|
|
7590
|
+
let prevOverlayPartialRows = [];
|
|
7591
|
+
function ensureFingerprints(cols, rows) {
|
|
7592
|
+
if (cols === fpCols && rows === fpRows) return;
|
|
7593
|
+
fpCols = cols;
|
|
7594
|
+
fpRows = rows;
|
|
7595
|
+
const len = cols * rows;
|
|
7596
|
+
currentFP = new Uint32Array(len);
|
|
7597
|
+
prevFP = new Uint32Array(len);
|
|
7598
|
+
fpPrevValid = false;
|
|
7599
|
+
prevOverlayBlockedRows = [];
|
|
7600
|
+
prevOverlayPartialRows = [];
|
|
7601
|
+
}
|
|
7602
|
+
function charHash16(ch) {
|
|
7603
|
+
if (ch.length <= 1) return ch.charCodeAt(0) || 0;
|
|
7604
|
+
let h$1 = 33052;
|
|
7605
|
+
for (let i = 0; i < ch.length; i++) {
|
|
7606
|
+
h$1 ^= ch.charCodeAt(i);
|
|
7607
|
+
h$1 = h$1 * 257 & 65535;
|
|
7608
|
+
}
|
|
7609
|
+
return h$1;
|
|
7610
|
+
}
|
|
7611
|
+
function fingerprintRow(row, y, cols) {
|
|
7612
|
+
const rowFP = terminal.getRowFingerprints(y);
|
|
7613
|
+
if (rowFP && rowFP.length >= cols) {
|
|
7614
|
+
currentFP.set(rowFP.subarray(0, cols), y * fpCols);
|
|
7615
|
+
return;
|
|
7616
|
+
}
|
|
7617
|
+
const base = y * fpCols;
|
|
7618
|
+
for (let x = 0; x < cols; x++) {
|
|
7619
|
+
const cell = row[x];
|
|
7620
|
+
currentFP[base + x] = styleKey$1(cell.style) << 16 | charHash16(cell.ch);
|
|
7621
|
+
}
|
|
7622
|
+
}
|
|
6751
7623
|
const rowCursorToCol1 = [];
|
|
6752
7624
|
const rowClearToEol = [];
|
|
6753
7625
|
const rowTextPartsScratch = [];
|
|
@@ -6765,13 +7637,6 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6765
7637
|
rowClearToEol[y] = `\u001B[${y + 1};1H\u001B[K`;
|
|
6766
7638
|
}
|
|
6767
7639
|
};
|
|
6768
|
-
const ensureRenderedRowCache = (rows) => {
|
|
6769
|
-
if (renderedRowCache.length > rows) {
|
|
6770
|
-
renderedRowCache.length = rows;
|
|
6771
|
-
return;
|
|
6772
|
-
}
|
|
6773
|
-
while (renderedRowCache.length < rows) renderedRowCache.push([]);
|
|
6774
|
-
};
|
|
6775
7640
|
const expandSpanStart = (row, startX) => {
|
|
6776
7641
|
var _row$x;
|
|
6777
7642
|
let x = Math.max(0, Math.min(row.length, startX));
|
|
@@ -6788,30 +7653,279 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6788
7653
|
}
|
|
6789
7654
|
return x;
|
|
6790
7655
|
};
|
|
6791
|
-
const resolveChangedSpan = (row,
|
|
6792
|
-
if (!
|
|
7656
|
+
const resolveChangedSpan = (row, y, cols) => {
|
|
7657
|
+
if (!fpCols || y >= fpRows || !fpPrevValid) return row.length ? {
|
|
7658
|
+
startX: 0,
|
|
7659
|
+
endXExclusive: row.length
|
|
7660
|
+
} : null;
|
|
7661
|
+
const base = y * fpCols;
|
|
7662
|
+
let startX = -1;
|
|
7663
|
+
let endXExclusive = -1;
|
|
7664
|
+
for (let x = 0; x < cols; x++) {
|
|
7665
|
+
if (currentFP[base + x] === prevFP[base + x]) continue;
|
|
7666
|
+
if (startX === -1) startX = x;
|
|
7667
|
+
endXExclusive = x + 1;
|
|
7668
|
+
}
|
|
7669
|
+
if (startX === -1) return null;
|
|
7670
|
+
const expandedStart = expandSpanStart(row, startX);
|
|
7671
|
+
const expandedEnd = expandSpanEnd(row, endXExclusive);
|
|
7672
|
+
return expandedEnd > expandedStart ? {
|
|
7673
|
+
startX: expandedStart,
|
|
7674
|
+
endXExclusive: expandedEnd
|
|
7675
|
+
} : null;
|
|
7676
|
+
};
|
|
7677
|
+
const resolveChangedSpanAgainstFill = (row, y, cols, fillFingerprint) => {
|
|
7678
|
+
if (!fpCols || y >= fpRows) return row.length ? {
|
|
6793
7679
|
startX: 0,
|
|
6794
7680
|
endXExclusive: row.length
|
|
6795
7681
|
} : null;
|
|
7682
|
+
const base = y * fpCols;
|
|
6796
7683
|
let startX = -1;
|
|
6797
7684
|
let endXExclusive = -1;
|
|
6798
|
-
for (let x = 0; x <
|
|
6799
|
-
if (
|
|
7685
|
+
for (let x = 0; x < cols; x++) {
|
|
7686
|
+
if (currentFP[base + x] === fillFingerprint) continue;
|
|
6800
7687
|
if (startX === -1) startX = x;
|
|
6801
7688
|
endXExclusive = x + 1;
|
|
6802
7689
|
}
|
|
6803
|
-
if (startX === -1
|
|
6804
|
-
const expandedStart =
|
|
6805
|
-
const expandedEnd =
|
|
7690
|
+
if (startX === -1) return null;
|
|
7691
|
+
const expandedStart = expandSpanStart(row, startX);
|
|
7692
|
+
const expandedEnd = expandSpanEnd(row, endXExclusive);
|
|
6806
7693
|
return expandedEnd > expandedStart ? {
|
|
6807
7694
|
startX: expandedStart,
|
|
6808
7695
|
endXExclusive: expandedEnd
|
|
6809
7696
|
} : null;
|
|
6810
7697
|
};
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
7698
|
+
const resolveChangedSpanAgainstReference = (row, y, cols) => {
|
|
7699
|
+
if (!fpCols || y >= fpRows) return row.length ? {
|
|
7700
|
+
startX: 0,
|
|
7701
|
+
endXExclusive: row.length
|
|
7702
|
+
} : null;
|
|
7703
|
+
const rowFP = terminal.getRowFingerprints(y);
|
|
7704
|
+
const base = y * fpCols;
|
|
7705
|
+
let startX = -1;
|
|
7706
|
+
let endXExclusive = -1;
|
|
7707
|
+
for (let x = 0; x < cols; x++) {
|
|
7708
|
+
const fingerprint = rowFP && rowFP.length >= cols ? rowFP[x] : styleKey$1(row[x].style) << 16 | charHash16(row[x].ch);
|
|
7709
|
+
if (fingerprint === currentFP[base + x]) continue;
|
|
7710
|
+
if (startX === -1) startX = x;
|
|
7711
|
+
endXExclusive = x + 1;
|
|
7712
|
+
}
|
|
7713
|
+
if (startX === -1) return null;
|
|
7714
|
+
const expandedStart = expandSpanStart(row, startX);
|
|
7715
|
+
const expandedEnd = expandSpanEnd(row, endXExclusive);
|
|
7716
|
+
return expandedEnd > expandedStart ? {
|
|
7717
|
+
startX: expandedStart,
|
|
7718
|
+
endXExclusive: expandedEnd
|
|
7719
|
+
} : null;
|
|
7720
|
+
};
|
|
7721
|
+
const rowMatchesPreviousFrame = (y, cols) => {
|
|
7722
|
+
if (!fpCols || y < 0 || y >= fpRows || !fpPrevValid) return false;
|
|
7723
|
+
const rowFP = terminal.getRowFingerprints(y);
|
|
7724
|
+
const row = rowFP && rowFP.length >= cols ? null : terminal.getRow(y);
|
|
7725
|
+
const base = y * fpCols;
|
|
7726
|
+
for (let x = 0; x < cols; x++) {
|
|
7727
|
+
const fingerprint = rowFP && rowFP.length >= cols ? rowFP[x] : styleKey$1(row[x].style) << 16 | charHash16(row[x].ch);
|
|
7728
|
+
if (fingerprint !== prevFP[base + x]) return false;
|
|
7729
|
+
}
|
|
7730
|
+
return true;
|
|
7731
|
+
};
|
|
7732
|
+
const rowHasNonDefaultBlankCell = (source, y, cols) => {
|
|
7733
|
+
if (!fpCols || y < 0 || y >= fpRows) return false;
|
|
7734
|
+
const blankFP = styleKeyFromParts({ bg: defaultBg }) << 16 | charHash16(" ");
|
|
7735
|
+
const base = y * fpCols;
|
|
7736
|
+
const limit = Math.min(cols, fpCols);
|
|
7737
|
+
for (let x = 0; x < limit; x++) if (source[base + x] !== blankFP) return true;
|
|
6814
7738
|
return false;
|
|
7739
|
+
};
|
|
7740
|
+
function overlayPlaneCoverageRows(totalRows) {
|
|
7741
|
+
const blockedRows = [];
|
|
7742
|
+
const partialRows = [];
|
|
7743
|
+
for (let y = 0; y < totalRows; y++) {
|
|
7744
|
+
const kind = getPlaneRowCoverageKind(terminal, "overlay", y);
|
|
7745
|
+
if (!kind) continue;
|
|
7746
|
+
blockedRows.push(y);
|
|
7747
|
+
if (kind === 1) partialRows.push(y);
|
|
7748
|
+
}
|
|
7749
|
+
return {
|
|
7750
|
+
blockedRows,
|
|
7751
|
+
partialRows
|
|
7752
|
+
};
|
|
7753
|
+
}
|
|
7754
|
+
const enableScrollRegions = (() => {
|
|
7755
|
+
const raw = String(env.DIMCODE_TUI_SCROLL_REGIONS ?? "").trim();
|
|
7756
|
+
if (raw === "0" || raw === "false") return false;
|
|
7757
|
+
if (isGhostty || isVscodeTerminal) return false;
|
|
7758
|
+
return out.isTTY !== false;
|
|
7759
|
+
})();
|
|
7760
|
+
function prepareExplicitScrollOperations(operations, blockedRows) {
|
|
7761
|
+
if (!operations.length || !(blockedRows === null || blockedRows === void 0 ? void 0 : blockedRows.size)) return {
|
|
7762
|
+
operations,
|
|
7763
|
+
hiddenRows: new Set(),
|
|
7764
|
+
trimmed: false,
|
|
7765
|
+
blockedInterior: false
|
|
7766
|
+
};
|
|
7767
|
+
const hiddenRows = new Set();
|
|
7768
|
+
const prepared = [];
|
|
7769
|
+
let trimmed = false;
|
|
7770
|
+
for (const op of operations) {
|
|
7771
|
+
let startY = op.startY;
|
|
7772
|
+
let endY = op.endY;
|
|
7773
|
+
while (startY < endY && blockedRows.has(startY)) {
|
|
7774
|
+
hiddenRows.add(startY);
|
|
7775
|
+
startY++;
|
|
7776
|
+
trimmed = true;
|
|
7777
|
+
}
|
|
7778
|
+
while (endY > startY && blockedRows.has(endY - 1)) {
|
|
7779
|
+
hiddenRows.add(endY - 1);
|
|
7780
|
+
endY--;
|
|
7781
|
+
trimmed = true;
|
|
7782
|
+
}
|
|
7783
|
+
for (let y = startY; y < endY; y++) {
|
|
7784
|
+
if (!blockedRows.has(y)) continue;
|
|
7785
|
+
return {
|
|
7786
|
+
operations: null,
|
|
7787
|
+
hiddenRows,
|
|
7788
|
+
trimmed,
|
|
7789
|
+
blockedInterior: true
|
|
7790
|
+
};
|
|
7791
|
+
}
|
|
7792
|
+
if (endY <= startY || Math.abs(op.delta) >= endY - startY) return {
|
|
7793
|
+
operations: null,
|
|
7794
|
+
hiddenRows,
|
|
7795
|
+
trimmed,
|
|
7796
|
+
blockedInterior: false
|
|
7797
|
+
};
|
|
7798
|
+
prepared.push(startY === op.startY && endY === op.endY ? op : {
|
|
7799
|
+
startY,
|
|
7800
|
+
endY,
|
|
7801
|
+
delta: op.delta
|
|
7802
|
+
});
|
|
7803
|
+
}
|
|
7804
|
+
return {
|
|
7805
|
+
operations: prepared,
|
|
7806
|
+
hiddenRows,
|
|
7807
|
+
trimmed,
|
|
7808
|
+
blockedInterior: false
|
|
7809
|
+
};
|
|
7810
|
+
}
|
|
7811
|
+
/**
|
|
7812
|
+
* Detect if the current frame represents a pure vertical scroll by comparing
|
|
7813
|
+
* current fingerprints against previous fingerprints with various shift offsets.
|
|
7814
|
+
* Returns the shift delta and which rows are newly revealed, or null if no
|
|
7815
|
+
* scroll pattern is detected.
|
|
7816
|
+
*/
|
|
7817
|
+
function largestDirtyBand(rows, blockedRows) {
|
|
7818
|
+
if (rows.length === 0) return null;
|
|
7819
|
+
const blocked = (blockedRows === null || blockedRows === void 0 ? void 0 : blockedRows.length) ? new Set(blockedRows) : null;
|
|
7820
|
+
let bestStart = -1;
|
|
7821
|
+
let bestEnd = -1;
|
|
7822
|
+
let bandStart = -1;
|
|
7823
|
+
let prev = -1;
|
|
7824
|
+
for (let i = 0; i < rows.length; i++) {
|
|
7825
|
+
const y = rows[i];
|
|
7826
|
+
if (blocked === null || blocked === void 0 ? void 0 : blocked.has(y)) {
|
|
7827
|
+
if (bandStart !== -1 && prev + 1 - bandStart > bestEnd - bestStart) {
|
|
7828
|
+
bestStart = bandStart;
|
|
7829
|
+
bestEnd = prev + 1;
|
|
7830
|
+
}
|
|
7831
|
+
bandStart = -1;
|
|
7832
|
+
prev = -1;
|
|
7833
|
+
continue;
|
|
7834
|
+
}
|
|
7835
|
+
if (bandStart === -1) {
|
|
7836
|
+
bandStart = y;
|
|
7837
|
+
prev = y;
|
|
7838
|
+
if (bestStart === -1) {
|
|
7839
|
+
bestStart = y;
|
|
7840
|
+
bestEnd = y + 1;
|
|
7841
|
+
}
|
|
7842
|
+
continue;
|
|
7843
|
+
}
|
|
7844
|
+
if (y === prev + 1) {
|
|
7845
|
+
prev = y;
|
|
7846
|
+
continue;
|
|
7847
|
+
}
|
|
7848
|
+
if (prev + 1 - bandStart > bestEnd - bestStart) {
|
|
7849
|
+
bestStart = bandStart;
|
|
7850
|
+
bestEnd = prev + 1;
|
|
7851
|
+
}
|
|
7852
|
+
bandStart = y;
|
|
7853
|
+
prev = y;
|
|
7854
|
+
}
|
|
7855
|
+
if (bandStart !== -1 && prev + 1 - bandStart > bestEnd - bestStart) {
|
|
7856
|
+
bestStart = bandStart;
|
|
7857
|
+
bestEnd = prev + 1;
|
|
7858
|
+
}
|
|
7859
|
+
if (bestStart === -1) return null;
|
|
7860
|
+
const outsideRows = [];
|
|
7861
|
+
for (const y of rows) if ((blocked === null || blocked === void 0 ? void 0 : blocked.has(y)) || y < bestStart || y >= bestEnd) outsideRows.push(y);
|
|
7862
|
+
return {
|
|
7863
|
+
start: bestStart,
|
|
7864
|
+
end: bestEnd,
|
|
7865
|
+
outsideRows
|
|
7866
|
+
};
|
|
7867
|
+
}
|
|
7868
|
+
function detectScrollShift(cols, dirtyRows, blockedRows) {
|
|
7869
|
+
if (!fpPrevValid || !fpCols || cols !== fpCols) return null;
|
|
7870
|
+
const band = largestDirtyBand(dirtyRows, blockedRows);
|
|
7871
|
+
if (!band || band.end - band.start < 3) return null;
|
|
7872
|
+
const maxDelta = Math.min(12, Math.max(5, band.end - band.start - 1));
|
|
7873
|
+
for (let delta = -maxDelta; delta <= maxDelta; delta++) {
|
|
7874
|
+
if (delta === 0) continue;
|
|
7875
|
+
let matches = 0;
|
|
7876
|
+
let checked = 0;
|
|
7877
|
+
let mismatches = 0;
|
|
7878
|
+
for (let y = band.start; y < band.end; y++) {
|
|
7879
|
+
const srcY = y + delta;
|
|
7880
|
+
if (srcY < band.start || srcY >= band.end) continue;
|
|
7881
|
+
const informative = rowHasNonDefaultBlankCell(currentFP, y, cols) || rowHasNonDefaultBlankCell(prevFP, srcY, cols);
|
|
7882
|
+
if (!informative) continue;
|
|
7883
|
+
checked++;
|
|
7884
|
+
const curBase = y * fpCols;
|
|
7885
|
+
const prevBase = srcY * fpCols;
|
|
7886
|
+
let rowMatch = true;
|
|
7887
|
+
for (let x = 0; x < cols; x++) if (currentFP[curBase + x] !== prevFP[prevBase + x]) {
|
|
7888
|
+
rowMatch = false;
|
|
7889
|
+
break;
|
|
7890
|
+
}
|
|
7891
|
+
if (rowMatch) matches++;
|
|
7892
|
+
else mismatches++;
|
|
7893
|
+
}
|
|
7894
|
+
if (checked > 0 && matches >= 3 && mismatches <= Math.ceil(checked * .2)) {
|
|
7895
|
+
const absDelta = Math.abs(delta);
|
|
7896
|
+
let newRowStart;
|
|
7897
|
+
let newRowEnd;
|
|
7898
|
+
if (delta > 0) {
|
|
7899
|
+
newRowStart = Math.max(band.start, band.end - absDelta);
|
|
7900
|
+
newRowEnd = band.end;
|
|
7901
|
+
} else {
|
|
7902
|
+
newRowStart = band.start;
|
|
7903
|
+
newRowEnd = Math.min(band.end, band.start + absDelta);
|
|
7904
|
+
}
|
|
7905
|
+
const extraDirty = [...band.outsideRows];
|
|
7906
|
+
for (let y = band.start; y < band.end; y++) {
|
|
7907
|
+
const srcY = y + delta;
|
|
7908
|
+
if (srcY < band.start || srcY >= band.end) continue;
|
|
7909
|
+
const curBase = y * fpCols;
|
|
7910
|
+
const prevBase = srcY * fpCols;
|
|
7911
|
+
let rowMatch = true;
|
|
7912
|
+
for (let x = 0; x < cols; x++) if (currentFP[curBase + x] !== prevFP[prevBase + x]) {
|
|
7913
|
+
rowMatch = false;
|
|
7914
|
+
break;
|
|
7915
|
+
}
|
|
7916
|
+
if (!rowMatch) extraDirty.push(y);
|
|
7917
|
+
}
|
|
7918
|
+
return {
|
|
7919
|
+
regionStart: band.start,
|
|
7920
|
+
regionEnd: band.end,
|
|
7921
|
+
delta,
|
|
7922
|
+
newRowStart,
|
|
7923
|
+
newRowEnd,
|
|
7924
|
+
extraDirtyRows: extraDirty
|
|
7925
|
+
};
|
|
7926
|
+
}
|
|
7927
|
+
}
|
|
7928
|
+
return null;
|
|
6815
7929
|
}
|
|
6816
7930
|
/**
|
|
6817
7931
|
* Write data in chunks to avoid overwhelming terminal buffers.
|
|
@@ -6849,24 +7963,60 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6849
7963
|
* Internal function that actually renders the frame to stdout.
|
|
6850
7964
|
* When dirtyRows is provided, only those rows are repainted.
|
|
6851
7965
|
*/
|
|
6852
|
-
function doRender(dirtyRows) {
|
|
7966
|
+
function doRender(dirtyRows, scrollOperations, skipUnchangedDirtyRows = false) {
|
|
6853
7967
|
if (isDebugEnabled()) getDebugLog().render(`doRender() START: dirtyRows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) ?? "null"}`);
|
|
6854
7968
|
if (disposed) return;
|
|
7969
|
+
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutRenderStart();
|
|
6855
7970
|
pendingRender = false;
|
|
6856
7971
|
accumulatedAllRows = false;
|
|
6857
7972
|
accumulatedDirtyBits = null;
|
|
6858
7973
|
accumulatedDirtyCount = 0;
|
|
6859
7974
|
accumulatedDirtyMin = Number.POSITIVE_INFINITY;
|
|
6860
7975
|
accumulatedDirtyMax = -1;
|
|
7976
|
+
accumulatedScrollOperations = null;
|
|
7977
|
+
accumulatedSkipUnchangedDirtyRows = true;
|
|
6861
7978
|
lastFrameTime = Date.now();
|
|
6862
7979
|
const renderStart = performance.now();
|
|
6863
7980
|
const size = terminal.size();
|
|
6864
7981
|
ensureRowEscapes(Math.max(size.rows, lastRenderedRows));
|
|
6865
|
-
|
|
7982
|
+
ensureFingerprints(size.cols, size.rows);
|
|
6866
7983
|
const bgSeq = openBg(defaultBg);
|
|
6867
7984
|
const bgOnlyStyle = { bg: defaultBg };
|
|
6868
7985
|
const bgKey = styleKeyFromParts({ bg: defaultBg });
|
|
7986
|
+
const blankFP = bgKey << 16 | charHash16(" ");
|
|
7987
|
+
const cellFingerprint = (cell) => styleKey$1(cell.style) << 16 | charHash16(cell.ch);
|
|
7988
|
+
const lastOccupiedColumnInRow = (row, cols) => {
|
|
7989
|
+
const limit = Math.min(row.length, cols);
|
|
7990
|
+
for (let x = limit - 1; x >= 0; x--) if (cellFingerprint(row[x]) !== blankFP) return x;
|
|
7991
|
+
return -1;
|
|
7992
|
+
};
|
|
7993
|
+
const lastOccupiedColumnInReference = (source, y, cols) => {
|
|
7994
|
+
if (!fpCols || y < 0 || y >= fpRows) return -1;
|
|
7995
|
+
const limit = Math.min(fpCols, cols);
|
|
7996
|
+
const base = y * fpCols;
|
|
7997
|
+
for (let x = limit - 1; x >= 0; x--) if (source[base + x] !== blankFP) return x;
|
|
7998
|
+
return -1;
|
|
7999
|
+
};
|
|
8000
|
+
const shouldRewriteRowTail = (row, y, cols, reference) => lastOccupiedColumnInRow(row, cols) < lastOccupiedColumnInReference(reference, y, cols);
|
|
6869
8001
|
let dirtySorted = true;
|
|
8002
|
+
const normalizedScrollOperations = (() => {
|
|
8003
|
+
if (!(scrollOperations === null || scrollOperations === void 0 ? void 0 : scrollOperations.length)) return null;
|
|
8004
|
+
const outOps = [];
|
|
8005
|
+
for (const op of scrollOperations) {
|
|
8006
|
+
const startY = Math.max(0, Math.min(size.rows, Math.floor(op.startY)));
|
|
8007
|
+
const endY = Math.max(0, Math.min(size.rows, Math.floor(op.endY)));
|
|
8008
|
+
const delta = Math.trunc(op.delta);
|
|
8009
|
+
if (endY <= startY || delta === 0 || Math.abs(delta) >= endY - startY) continue;
|
|
8010
|
+
outOps.push({
|
|
8011
|
+
startY,
|
|
8012
|
+
endY,
|
|
8013
|
+
delta
|
|
8014
|
+
});
|
|
8015
|
+
}
|
|
8016
|
+
if (!outOps.length) return null;
|
|
8017
|
+
outOps.sort((a, b) => a.startY - b.startY);
|
|
8018
|
+
return outOps;
|
|
8019
|
+
})();
|
|
6870
8020
|
let rowsToRender = (() => {
|
|
6871
8021
|
if (!dirtyRows || dirtyRows.length === 0) return null;
|
|
6872
8022
|
const outRows = [];
|
|
@@ -6887,11 +8037,14 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6887
8037
|
if (!sorted) outRows.sort((a, b) => a - b);
|
|
6888
8038
|
return outRows;
|
|
6889
8039
|
})();
|
|
6890
|
-
if (
|
|
8040
|
+
if (fpPrevValid && rowsToRender) currentFP.set(prevFP);
|
|
6891
8041
|
const frameParts = [];
|
|
6892
8042
|
frameParts.push(!isGhostty && useSyncOutput ? SYNC_START : "");
|
|
6893
8043
|
frameParts.push("\x1B[?7l");
|
|
6894
8044
|
frameParts.push(SGR_RESET, bgSeq);
|
|
8045
|
+
let lastRenderedY = -1;
|
|
8046
|
+
let lastRenderWasFullRow = false;
|
|
8047
|
+
let hasFrameOutput = false;
|
|
6895
8048
|
let activeStyleKey = null;
|
|
6896
8049
|
let activeStyle = {
|
|
6897
8050
|
fg: null,
|
|
@@ -6942,11 +8095,10 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6942
8095
|
const renderRow$1 = (y, row, startX = 0, endXExclusive = row.length, clearToEol = true) => {
|
|
6943
8096
|
const spanStart = Math.max(0, Math.min(row.length, Math.floor(startX)));
|
|
6944
8097
|
const spanEnd = Math.max(spanStart, Math.min(row.length, Math.floor(endXExclusive)));
|
|
6945
|
-
if (spanStart >= spanEnd && !clearToEol)
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
}
|
|
6949
|
-
if (!disableCursorPos) frameParts.push(spanStart === 0 ? rowCursorToCol1[y] : `\u001B[${y + 1};${spanStart + 1}H`);
|
|
8098
|
+
if (spanStart >= spanEnd && !clearToEol) return;
|
|
8099
|
+
hasFrameOutput = true;
|
|
8100
|
+
if (!disableCursorPos) if (spanStart === 0 && lastRenderWasFullRow && y === lastRenderedY + 1) frameParts.push("\r\n");
|
|
8101
|
+
else frameParts.push(spanStart === 0 ? rowCursorToCol1[y] : `\u001B[${y + 1};${spanStart + 1}H`);
|
|
6950
8102
|
let currentKey = null;
|
|
6951
8103
|
let currentStyle = null;
|
|
6952
8104
|
const currentTextParts = rowTextPartsScratch;
|
|
@@ -6964,7 +8116,7 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6964
8116
|
if (needsWideCursorFix(cell, ch)) currentTextParts.push(`\u001B[${y + 1};${x + 1 + (cell.width ?? 1)}H`);
|
|
6965
8117
|
continue;
|
|
6966
8118
|
}
|
|
6967
|
-
if (key === currentKey) {
|
|
8119
|
+
if (key === currentKey && !(key & 32768 && nextStyle.href !== (currentStyle === null || currentStyle === void 0 ? void 0 : currentStyle.href))) {
|
|
6968
8120
|
currentTextParts.push(ch);
|
|
6969
8121
|
if (needsWideCursorFix(cell, ch)) currentTextParts.push(`\u001B[${y + 1};${x + 1 + (cell.width ?? 1)}H`);
|
|
6970
8122
|
continue;
|
|
@@ -6985,29 +8137,237 @@ function createStdoutRenderer(terminal, options) {
|
|
|
6985
8137
|
if (activeStyleKey !== bgKey) emitStyle(bgOnlyStyle, bgKey);
|
|
6986
8138
|
frameParts.push("\x1B[K");
|
|
6987
8139
|
}
|
|
6988
|
-
|
|
8140
|
+
lastRenderedY = y;
|
|
8141
|
+
lastRenderWasFullRow = spanStart === 0 && clearToEol;
|
|
6989
8142
|
};
|
|
6990
|
-
|
|
8143
|
+
const overlayCoverage = overlayPlaneCoverageRows(size.rows);
|
|
8144
|
+
const overlayRows = Array.from(new Set([...overlayCoverage.blockedRows, ...prevOverlayBlockedRows])).sort((a, b) => a - b);
|
|
8145
|
+
const overlayRowSet = overlayRows.length ? new Set(overlayRows) : null;
|
|
8146
|
+
const overlayPartialRows = Array.from(new Set([...overlayCoverage.partialRows, ...prevOverlayPartialRows])).sort((a, b) => a - b);
|
|
8147
|
+
const overlayPartialRowSet = overlayPartialRows.length ? new Set(overlayPartialRows) : null;
|
|
8148
|
+
const overlayTouchedRowSet = (() => {
|
|
8149
|
+
if (!overlayRowSet && !overlayPartialRowSet) return null;
|
|
8150
|
+
return new Set([...overlayRowSet ? Array.from(overlayRowSet) : [], ...overlayPartialRowSet ? Array.from(overlayPartialRowSet) : []]);
|
|
8151
|
+
})();
|
|
8152
|
+
let explicitScrollOperations = normalizedScrollOperations;
|
|
8153
|
+
let hiddenExplicitDirtyRows = null;
|
|
8154
|
+
let allowInferredScrollRegions = true;
|
|
8155
|
+
if (explicitScrollOperations && overlayRows.length) {
|
|
8156
|
+
const preparedExplicit = prepareExplicitScrollOperations(explicitScrollOperations, overlayRowSet);
|
|
8157
|
+
hiddenExplicitDirtyRows = preparedExplicit.hiddenRows.size ? preparedExplicit.hiddenRows : null;
|
|
8158
|
+
if (preparedExplicit.operations) {
|
|
8159
|
+
explicitScrollOperations = preparedExplicit.operations;
|
|
8160
|
+
if (preparedExplicit.trimmed && isDebugEnabled()) getDebugLog().render(` Explicit scroll ops clipped around overlay rows: ${normalizedScrollOperations.map((op, index) => `${op.startY}-${op.endY - 1}:${op.delta}->${explicitScrollOperations[index].startY}-${explicitScrollOperations[index].endY - 1}:${explicitScrollOperations[index].delta}`).join(", ")}`);
|
|
8161
|
+
} else {
|
|
8162
|
+
allowInferredScrollRegions = false;
|
|
8163
|
+
const expandedRows = new Set(rowsToRender ?? []);
|
|
8164
|
+
for (const op of explicitScrollOperations) for (let y = op.startY; y < op.endY; y++) expandedRows.add(y);
|
|
8165
|
+
rowsToRender = Array.from(expandedRows).sort((a, b) => a - b);
|
|
8166
|
+
dirtySorted = true;
|
|
8167
|
+
explicitScrollOperations = null;
|
|
8168
|
+
hiddenExplicitDirtyRows = null;
|
|
8169
|
+
if (isDebugEnabled()) getDebugLog().render(preparedExplicit.blockedInterior ? " Explicit scroll ops split by interior overlay rows; falling back to region repaint" : " Explicit scroll ops could not be clipped safely; falling back to region repaint");
|
|
8170
|
+
}
|
|
8171
|
+
}
|
|
8172
|
+
const scrollRowsCandidate = rowsToRender;
|
|
8173
|
+
if (explicitScrollOperations && rowsToRender && (!enableScrollRegions || !fpPrevValid)) {
|
|
8174
|
+
const expandedRows = new Set(rowsToRender);
|
|
8175
|
+
for (const op of explicitScrollOperations) for (let y = op.startY; y < op.endY; y++) {
|
|
8176
|
+
if (hiddenExplicitDirtyRows === null || hiddenExplicitDirtyRows === void 0 ? void 0 : hiddenExplicitDirtyRows.has(y)) continue;
|
|
8177
|
+
expandedRows.add(y);
|
|
8178
|
+
}
|
|
8179
|
+
rowsToRender = Array.from(expandedRows).sort((a, b) => a - b);
|
|
8180
|
+
dirtySorted = true;
|
|
8181
|
+
explicitScrollOperations = null;
|
|
8182
|
+
hiddenExplicitDirtyRows = null;
|
|
8183
|
+
if (isDebugEnabled()) getDebugLog().render(enableScrollRegions ? " Explicit scroll ops fell back to region repaint because previous fingerprints are unavailable" : " Explicit scroll ops fell back to region repaint because scroll regions are disabled");
|
|
8184
|
+
}
|
|
8185
|
+
const denseDirtyRows = Boolean(rowsToRender && rowsToRender.length >= size.rows * dirtyFullThreshold);
|
|
8186
|
+
if (denseDirtyRows) rowsToRender = null;
|
|
8187
|
+
let profiledRowCount = rowsToRender ? rowsToRender.length : size.rows;
|
|
8188
|
+
const useScrollRegions = enableScrollRegions && fpPrevValid && scrollRowsCandidate && scrollRowsCandidate.length >= 3 && allowInferredScrollRegions;
|
|
8189
|
+
let scrollHandled = false;
|
|
8190
|
+
if (enableScrollRegions && explicitScrollOperations && scrollRowsCandidate && fpPrevValid) {
|
|
8191
|
+
if (currentFP.length === prevFP.length) currentFP.set(prevFP);
|
|
8192
|
+
const insertedRows = new Set();
|
|
8193
|
+
const explicitRowsToRender = new Set();
|
|
8194
|
+
for (const y of scrollRowsCandidate) {
|
|
8195
|
+
if (hiddenExplicitDirtyRows === null || hiddenExplicitDirtyRows === void 0 ? void 0 : hiddenExplicitDirtyRows.has(y)) continue;
|
|
8196
|
+
explicitRowsToRender.add(y);
|
|
8197
|
+
}
|
|
8198
|
+
if (isDebugEnabled()) getDebugLog().render(` Explicit scroll ops: ${explicitScrollOperations.map((op) => `${op.startY}-${op.endY - 1}:${op.delta}`).join(", ")}`);
|
|
8199
|
+
for (const op of explicitScrollOperations) {
|
|
8200
|
+
hasFrameOutput = true;
|
|
8201
|
+
frameParts.push(`\u001B[${op.startY + 1};${op.endY}r`);
|
|
8202
|
+
if (op.delta > 0) {
|
|
8203
|
+
frameParts.push(`\u001B[${op.endY};1H`);
|
|
8204
|
+
frameParts.push(`\u001B[${op.delta}S`);
|
|
8205
|
+
for (let y = op.startY; y < op.endY - op.delta; y++) {
|
|
8206
|
+
const dstBase = y * fpCols;
|
|
8207
|
+
const srcBase = (y + op.delta) * fpCols;
|
|
8208
|
+
for (let x = 0; x < size.cols; x++) currentFP[dstBase + x] = prevFP[srcBase + x];
|
|
8209
|
+
}
|
|
8210
|
+
for (let y = op.endY - op.delta; y < op.endY; y++) {
|
|
8211
|
+
const base = y * fpCols;
|
|
8212
|
+
insertedRows.add(y);
|
|
8213
|
+
explicitRowsToRender.add(y);
|
|
8214
|
+
for (let x = 0; x < size.cols; x++) currentFP[base + x] = blankFP;
|
|
8215
|
+
}
|
|
8216
|
+
} else {
|
|
8217
|
+
const absDelta = -op.delta;
|
|
8218
|
+
frameParts.push(`\u001B[${op.startY + 1};1H`);
|
|
8219
|
+
frameParts.push(`\u001B[${absDelta}T`);
|
|
8220
|
+
for (let y = op.endY - 1; y >= op.startY + absDelta; y--) {
|
|
8221
|
+
const dstBase = y * fpCols;
|
|
8222
|
+
const srcBase = (y - absDelta) * fpCols;
|
|
8223
|
+
for (let x = 0; x < size.cols; x++) currentFP[dstBase + x] = prevFP[srcBase + x];
|
|
8224
|
+
}
|
|
8225
|
+
for (let y = op.startY; y < op.startY + absDelta; y++) {
|
|
8226
|
+
const base = y * fpCols;
|
|
8227
|
+
insertedRows.add(y);
|
|
8228
|
+
explicitRowsToRender.add(y);
|
|
8229
|
+
for (let x = 0; x < size.cols; x++) currentFP[base + x] = blankFP;
|
|
8230
|
+
}
|
|
8231
|
+
}
|
|
8232
|
+
frameParts.push("\x1B[r");
|
|
8233
|
+
}
|
|
8234
|
+
const explicitDirtyRows = Array.from(explicitRowsToRender).sort((a, b) => a - b);
|
|
8235
|
+
const overlayDirtyRows = overlayTouchedRowSet ? explicitDirtyRows.filter((y) => overlayTouchedRowSet.has(y)) : [];
|
|
8236
|
+
const paintedExplicitRows = [];
|
|
8237
|
+
for (const y of explicitDirtyRows) {
|
|
8238
|
+
const row = terminal.getRow(y);
|
|
8239
|
+
const overlayRow = overlayTouchedRowSet === null || overlayTouchedRowSet === void 0 ? void 0 : overlayTouchedRowSet.has(y);
|
|
8240
|
+
if (overlayRow || useConservativeDirtyRowRendering) {
|
|
8241
|
+
fingerprintRow(row, y, size.cols);
|
|
8242
|
+
renderRow$1(y, row);
|
|
8243
|
+
paintedExplicitRows.push(y);
|
|
8244
|
+
continue;
|
|
8245
|
+
}
|
|
8246
|
+
const span = (() => {
|
|
8247
|
+
if (insertedRows.has(y)) {
|
|
8248
|
+
fingerprintRow(row, y, size.cols);
|
|
8249
|
+
return resolveChangedSpanAgainstFill(row, y, size.cols, blankFP);
|
|
8250
|
+
}
|
|
8251
|
+
return resolveChangedSpanAgainstReference(row, y, size.cols);
|
|
8252
|
+
})();
|
|
8253
|
+
if (!span) {
|
|
8254
|
+
if (!skipUnchangedDirtyRows) fingerprintRow(row, y, size.cols);
|
|
8255
|
+
if (!skipUnchangedDirtyRows) {
|
|
8256
|
+
renderRow$1(y, row);
|
|
8257
|
+
paintedExplicitRows.push(y);
|
|
8258
|
+
}
|
|
8259
|
+
continue;
|
|
8260
|
+
}
|
|
8261
|
+
const rewriteTail = !insertedRows.has(y) && shouldRewriteRowTail(row, y, size.cols, currentFP);
|
|
8262
|
+
fingerprintRow(row, y, size.cols);
|
|
8263
|
+
renderRow$1(y, row, span.startX, rewriteTail ? row.length : span.endXExclusive, rewriteTail || span.endXExclusive >= row.length);
|
|
8264
|
+
paintedExplicitRows.push(y);
|
|
8265
|
+
}
|
|
8266
|
+
if (isDebugEnabled() && overlayDirtyRows.length) getDebugLog().render(` Explicit scroll ops overlay rows: [${overlayDirtyRows.join(", ")}]`);
|
|
8267
|
+
profiledRowCount = explicitDirtyRows.length;
|
|
8268
|
+
scrollHandled = true;
|
|
8269
|
+
} else if (useScrollRegions && scrollRowsCandidate) {
|
|
8270
|
+
for (let y = 0; y < size.rows; y++) fingerprintRow(terminal.getRow(y), y, size.cols);
|
|
8271
|
+
const shift = detectScrollShift(size.cols, scrollRowsCandidate, overlayRows);
|
|
8272
|
+
if (shift) {
|
|
8273
|
+
if (currentFP.length === prevFP.length) currentFP.set(prevFP);
|
|
8274
|
+
hasFrameOutput = true;
|
|
8275
|
+
if (isDebugEnabled()) getDebugLog().render(` Scroll region: delta=${shift.delta}, region=${shift.regionStart}-${shift.regionEnd - 1}, new rows=${shift.newRowStart}-${shift.newRowEnd - 1}`);
|
|
8276
|
+
frameParts.push(`\u001B[${shift.regionStart + 1};${shift.regionEnd}r`);
|
|
8277
|
+
if (shift.delta > 0) {
|
|
8278
|
+
frameParts.push(`\u001B[${shift.regionEnd};1H`);
|
|
8279
|
+
frameParts.push(`\u001B[${shift.delta}S`);
|
|
8280
|
+
} else {
|
|
8281
|
+
frameParts.push(`\u001B[${shift.regionStart + 1};1H`);
|
|
8282
|
+
frameParts.push(`\u001B[${-shift.delta}T`);
|
|
8283
|
+
}
|
|
8284
|
+
frameParts.push("\x1B[r");
|
|
8285
|
+
if (shift.delta > 0) {
|
|
8286
|
+
for (let y = shift.regionStart; y < shift.regionEnd - shift.delta; y++) {
|
|
8287
|
+
const dstBase = y * fpCols;
|
|
8288
|
+
const srcBase = (y + shift.delta) * fpCols;
|
|
8289
|
+
for (let x = 0; x < size.cols; x++) currentFP[dstBase + x] = prevFP[srcBase + x];
|
|
8290
|
+
}
|
|
8291
|
+
for (let y = shift.regionEnd - shift.delta; y < shift.regionEnd; y++) {
|
|
8292
|
+
const base = y * fpCols;
|
|
8293
|
+
for (let x = 0; x < size.cols; x++) currentFP[base + x] = blankFP;
|
|
8294
|
+
}
|
|
8295
|
+
} else {
|
|
8296
|
+
const absDelta = -shift.delta;
|
|
8297
|
+
for (let y = shift.regionEnd - 1; y >= shift.regionStart + absDelta; y--) {
|
|
8298
|
+
const dstBase = y * fpCols;
|
|
8299
|
+
const srcBase = (y - absDelta) * fpCols;
|
|
8300
|
+
for (let x = 0; x < size.cols; x++) currentFP[dstBase + x] = prevFP[srcBase + x];
|
|
8301
|
+
}
|
|
8302
|
+
for (let y = shift.regionStart; y < shift.regionStart + absDelta; y++) {
|
|
8303
|
+
const base = y * fpCols;
|
|
8304
|
+
for (let x = 0; x < size.cols; x++) currentFP[base + x] = blankFP;
|
|
8305
|
+
}
|
|
8306
|
+
}
|
|
8307
|
+
for (let y = shift.newRowStart; y < shift.newRowEnd; y++) {
|
|
8308
|
+
const row = terminal.getRow(y);
|
|
8309
|
+
fingerprintRow(row, y, size.cols);
|
|
8310
|
+
renderRow$1(y, row);
|
|
8311
|
+
}
|
|
8312
|
+
const extraDirtyRows = overlayRowSet ? shift.extraDirtyRows.filter((y) => !overlayRowSet.has(y) || Boolean(overlayPartialRowSet === null || overlayPartialRowSet === void 0 ? void 0 : overlayPartialRowSet.has(y))) : shift.extraDirtyRows;
|
|
8313
|
+
for (const y of extraDirtyRows) {
|
|
8314
|
+
const row = terminal.getRow(y);
|
|
8315
|
+
const overlayRow = overlayTouchedRowSet === null || overlayTouchedRowSet === void 0 ? void 0 : overlayTouchedRowSet.has(y);
|
|
8316
|
+
if (overlayRow || useConservativeDirtyRowRendering) {
|
|
8317
|
+
fingerprintRow(row, y, size.cols);
|
|
8318
|
+
renderRow$1(y, row);
|
|
8319
|
+
continue;
|
|
8320
|
+
}
|
|
8321
|
+
const span = resolveChangedSpanAgainstReference(row, y, size.cols);
|
|
8322
|
+
if (!span) {
|
|
8323
|
+
if (!skipUnchangedDirtyRows) {
|
|
8324
|
+
fingerprintRow(row, y, size.cols);
|
|
8325
|
+
renderRow$1(y, row);
|
|
8326
|
+
}
|
|
8327
|
+
continue;
|
|
8328
|
+
}
|
|
8329
|
+
const rewriteTail = shouldRewriteRowTail(row, y, size.cols, currentFP);
|
|
8330
|
+
renderRow$1(y, row, span.startX, rewriteTail ? row.length : span.endXExclusive, rewriteTail || span.endXExclusive >= row.length);
|
|
8331
|
+
fingerprintRow(row, y, size.cols);
|
|
8332
|
+
}
|
|
8333
|
+
for (let y = shift.newRowStart; y < shift.newRowEnd; y++) fingerprintRow(terminal.getRow(y), y, size.cols);
|
|
8334
|
+
const renderedRows = new Set();
|
|
8335
|
+
for (let y = shift.newRowStart; y < shift.newRowEnd; y++) renderedRows.add(y);
|
|
8336
|
+
for (const y of extraDirtyRows) renderedRows.add(y);
|
|
8337
|
+
profiledRowCount = renderedRows.size;
|
|
8338
|
+
scrollHandled = true;
|
|
8339
|
+
}
|
|
8340
|
+
}
|
|
8341
|
+
if (!scrollHandled && denseDirtyRows && scrollRowsCandidate && useScrollRegions) {
|
|
8342
|
+
rowsToRender = scrollRowsCandidate;
|
|
8343
|
+
profiledRowCount = rowsToRender.length;
|
|
8344
|
+
if (isDebugEnabled()) getDebugLog().render(` Dense dirty rows fell back to partial render: ${rowsToRender.length} rows`);
|
|
8345
|
+
}
|
|
8346
|
+
if (scrollHandled) {} else if (!rowsToRender) {
|
|
6991
8347
|
if (isDebugEnabled()) getDebugLog().render(` Full render: ${size.rows} rows`);
|
|
6992
8348
|
for (let y = 0; y < size.rows; y++) {
|
|
6993
8349
|
const row = terminal.getRow(y);
|
|
8350
|
+
fingerprintRow(row, y, size.cols);
|
|
6994
8351
|
renderRow$1(y, row);
|
|
6995
8352
|
}
|
|
6996
8353
|
} else {
|
|
6997
|
-
const
|
|
6998
|
-
if (isDebugEnabled()) getDebugLog().render(` Partial render: ${rowsToRender.length} dirty rows: [${rowsToRender.join(", ")}]${
|
|
8354
|
+
const overlayDirtyRows = overlayTouchedRowSet ? rowsToRender.filter((y) => overlayTouchedRowSet.has(y)) : [];
|
|
8355
|
+
if (isDebugEnabled()) getDebugLog().render(` Partial render: ${rowsToRender.length} dirty rows: [${rowsToRender.join(", ")}]${overlayDirtyRows.length ? ` (overlay-full-row: [${overlayDirtyRows.join(", ")}])` : ""}`);
|
|
6999
8356
|
for (const y of rowsToRender) {
|
|
7000
8357
|
const row = terminal.getRow(y);
|
|
7001
|
-
|
|
8358
|
+
fingerprintRow(row, y, size.cols);
|
|
8359
|
+
const overlayRow = overlayTouchedRowSet === null || overlayTouchedRowSet === void 0 ? void 0 : overlayTouchedRowSet.has(y);
|
|
8360
|
+
if (overlayRow || useConservativeDirtyRowRendering) {
|
|
7002
8361
|
renderRow$1(y, row);
|
|
7003
8362
|
continue;
|
|
7004
8363
|
}
|
|
7005
|
-
const span = resolveChangedSpan(row,
|
|
8364
|
+
const span = resolveChangedSpan(row, y, size.cols);
|
|
7006
8365
|
if (!span) {
|
|
7007
|
-
renderRow$1(y, row);
|
|
8366
|
+
if (!skipUnchangedDirtyRows) renderRow$1(y, row);
|
|
7008
8367
|
continue;
|
|
7009
8368
|
}
|
|
7010
|
-
|
|
8369
|
+
const rewriteTail = shouldRewriteRowTail(row, y, size.cols, prevFP);
|
|
8370
|
+
renderRow$1(y, row, span.startX, rewriteTail ? row.length : span.endXExclusive, rewriteTail || span.endXExclusive >= row.length);
|
|
7011
8371
|
}
|
|
7012
8372
|
}
|
|
7013
8373
|
if (!rowsToRender && lastRenderedRows > size.rows) {
|
|
@@ -7016,17 +8376,38 @@ function createStdoutRenderer(terminal, options) {
|
|
|
7016
8376
|
frameParts.push(SGR_RESET, bgSeq);
|
|
7017
8377
|
activeStyleKey = bgKey;
|
|
7018
8378
|
}
|
|
7019
|
-
for (let i = 0; i < extraRows; i++)
|
|
8379
|
+
for (let i = 0; i < extraRows; i++) {
|
|
8380
|
+
hasFrameOutput = true;
|
|
8381
|
+
frameParts.push(rowClearToEol[size.rows + i]);
|
|
8382
|
+
}
|
|
7020
8383
|
}
|
|
7021
8384
|
if (!rowsToRender) lastRenderedRows = size.rows;
|
|
7022
|
-
|
|
8385
|
+
const tmpFP = prevFP;
|
|
8386
|
+
prevFP = currentFP;
|
|
8387
|
+
currentFP = tmpFP;
|
|
8388
|
+
fpPrevValid = true;
|
|
8389
|
+
prevOverlayBlockedRows = overlayCoverage.blockedRows;
|
|
8390
|
+
prevOverlayPartialRows = overlayCoverage.partialRows;
|
|
8391
|
+
let emittedCursorPos = null;
|
|
7023
8392
|
if (getImeAnchor) {
|
|
7024
8393
|
const anchor = getImeAnchor();
|
|
7025
8394
|
if (anchor) {
|
|
7026
8395
|
const { x, y } = clampCellToViewport(anchor, size);
|
|
7027
|
-
|
|
8396
|
+
if (hasFrameOutput || x !== lastCursorX || y !== lastCursorY) {
|
|
8397
|
+
hasFrameOutput = true;
|
|
8398
|
+
emittedCursorPos = {
|
|
8399
|
+
x,
|
|
8400
|
+
y
|
|
8401
|
+
};
|
|
8402
|
+
frameParts.push(`\u001B[${y + 1};${x + 1}H`);
|
|
8403
|
+
}
|
|
7028
8404
|
}
|
|
7029
8405
|
}
|
|
8406
|
+
if (!hasFrameOutput) {
|
|
8407
|
+
if (isDebugEnabled()) getDebugLog().render(" No-op frame skipped");
|
|
8408
|
+
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutNoOutput();
|
|
8409
|
+
return;
|
|
8410
|
+
}
|
|
7030
8411
|
if (enableOsc8Links && activeStyle.href) frameParts.push(OSC8_CLOSE);
|
|
7031
8412
|
frameParts.push(SGR_RESET);
|
|
7032
8413
|
frameParts.push("\x1B[?7h");
|
|
@@ -7034,9 +8415,9 @@ function createStdoutRenderer(terminal, options) {
|
|
|
7034
8415
|
const frame = frameParts.join("");
|
|
7035
8416
|
if (profiler) profiler.recordRender({
|
|
7036
8417
|
durationMs: profiler.now() - renderStart,
|
|
7037
|
-
rows:
|
|
8418
|
+
rows: profiledRowCount,
|
|
7038
8419
|
nodes: 0,
|
|
7039
|
-
fullRepaint: !rowsToRender,
|
|
8420
|
+
fullRepaint: !rowsToRender && !scrollHandled,
|
|
7040
8421
|
sorted: dirtySorted
|
|
7041
8422
|
});
|
|
7042
8423
|
if (isDebugEnabled()) {
|
|
@@ -7134,6 +8515,13 @@ function createStdoutRenderer(terminal, options) {
|
|
|
7134
8515
|
{
|
|
7135
8516
|
const writeMs = performance.now() - writeStart;
|
|
7136
8517
|
writeEmaMs = writeEmaMs === 0 ? writeMs : writeEmaMs * .85 + writeMs * .15;
|
|
8518
|
+
if (emittedCursorPos) {
|
|
8519
|
+
lastCursorX = emittedCursorPos.x;
|
|
8520
|
+
lastCursorY = emittedCursorPos.y;
|
|
8521
|
+
} else {
|
|
8522
|
+
lastCursorX = null;
|
|
8523
|
+
lastCursorY = null;
|
|
8524
|
+
}
|
|
7137
8525
|
recordStdoutFrame({
|
|
7138
8526
|
at: Date.now(),
|
|
7139
8527
|
bytes: frame.length,
|
|
@@ -7146,6 +8534,11 @@ function createStdoutRenderer(terminal, options) {
|
|
|
7146
8534
|
bytes: frame.length,
|
|
7147
8535
|
mode: writeMode === "sync" ? "sync" : writeMode === "chunked" ? "chunked" : "stream"
|
|
7148
8536
|
});
|
|
8537
|
+
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutWrite({
|
|
8538
|
+
durationMs: writeMs,
|
|
8539
|
+
bytes: frame.length,
|
|
8540
|
+
mode: writeMode === "sync" ? "sync" : writeMode === "chunked" ? "chunked" : "stream"
|
|
8541
|
+
});
|
|
7149
8542
|
}
|
|
7150
8543
|
if (isDebugEnabled()) {
|
|
7151
8544
|
const totalTime = (performance.now() - renderStart).toFixed(2);
|
|
@@ -7158,9 +8551,20 @@ function createStdoutRenderer(terminal, options) {
|
|
|
7158
8551
|
* Prevents excessive renders that cause flickering in Bun binaries.
|
|
7159
8552
|
* Accumulates dirty rows while waiting for next frame to ensure no updates are lost.
|
|
7160
8553
|
*/
|
|
7161
|
-
function render(dirtyRows) {
|
|
8554
|
+
function render(dirtyRows, sync, scrollOperations, skipUnchangedDirtyRows = false) {
|
|
7162
8555
|
if (disposed) return;
|
|
7163
8556
|
if (isDebugEnabled()) getDebugLog().render(`render() called: dirtyRows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) ?? "null"}, pending=${pendingRender}, elapsed=${Date.now() - lastFrameTime}ms`);
|
|
8557
|
+
const isSmallSyncPatch = Boolean(sync && (dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) && dirtyRows.length <= 12 && !(scrollOperations === null || scrollOperations === void 0 ? void 0 : scrollOperations.length));
|
|
8558
|
+
if (isSmallSyncPatch) skipUnchangedDirtyRows = false;
|
|
8559
|
+
if ((dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) && skipUnchangedDirtyRows && fpPrevValid && !(scrollOperations === null || scrollOperations === void 0 ? void 0 : scrollOperations.length) && dirtyRows.length < terminal.size().rows) {
|
|
8560
|
+
const cols = terminal.size().cols;
|
|
8561
|
+
const nextDirtyRows = dirtyRows.filter((y) => !rowMatchesPreviousFrame(y, cols));
|
|
8562
|
+
if (nextDirtyRows.length === 0) {
|
|
8563
|
+
if (isDebugEnabled()) getDebugLog().render(`Skipped unchanged dirty commit: ${dirtyRows.length} rows`);
|
|
8564
|
+
return;
|
|
8565
|
+
}
|
|
8566
|
+
dirtyRows = nextDirtyRows;
|
|
8567
|
+
}
|
|
7164
8568
|
const ensureDirtyBits = (rowCount) => {
|
|
7165
8569
|
if (!accumulatedDirtyBits || accumulatedDirtyBits.length !== rowCount) {
|
|
7166
8570
|
accumulatedDirtyBits = new Uint8Array(rowCount);
|
|
@@ -7182,12 +8586,43 @@ function createStdoutRenderer(terminal, options) {
|
|
|
7182
8586
|
out$1.length = outLen;
|
|
7183
8587
|
return outLen ? out$1 : null;
|
|
7184
8588
|
};
|
|
8589
|
+
const buildAccumulatedScrollOperations = () => {
|
|
8590
|
+
return (accumulatedScrollOperations === null || accumulatedScrollOperations === void 0 ? void 0 : accumulatedScrollOperations.length) ? accumulatedScrollOperations : null;
|
|
8591
|
+
};
|
|
8592
|
+
const mergeScrollOperations = (next) => {
|
|
8593
|
+
if (!(next === null || next === void 0 ? void 0 : next.length) || accumulatedAllRows) return;
|
|
8594
|
+
const merged = accumulatedScrollOperations ? accumulatedScrollOperations.slice() : [];
|
|
8595
|
+
for (const op of next) {
|
|
8596
|
+
const startY = Math.floor(op.startY);
|
|
8597
|
+
const endY = Math.floor(op.endY);
|
|
8598
|
+
const delta = Math.trunc(op.delta);
|
|
8599
|
+
if (endY <= startY || delta === 0) continue;
|
|
8600
|
+
const existingIndex = merged.findIndex((existing) => existing.startY === startY && existing.endY === endY);
|
|
8601
|
+
if (existingIndex >= 0) {
|
|
8602
|
+
const existing = merged[existingIndex];
|
|
8603
|
+
const nextDelta = existing.delta + delta;
|
|
8604
|
+
if (nextDelta === 0) merged.splice(existingIndex, 1);
|
|
8605
|
+
else merged[existingIndex] = {
|
|
8606
|
+
startY,
|
|
8607
|
+
endY,
|
|
8608
|
+
delta: nextDelta
|
|
8609
|
+
};
|
|
8610
|
+
} else merged.push({
|
|
8611
|
+
startY,
|
|
8612
|
+
endY,
|
|
8613
|
+
delta
|
|
8614
|
+
});
|
|
8615
|
+
}
|
|
8616
|
+
accumulatedScrollOperations = merged.length ? merged : null;
|
|
8617
|
+
};
|
|
7185
8618
|
if (!dirtyRows || dirtyRows.length === 0) {
|
|
7186
8619
|
accumulatedAllRows = true;
|
|
7187
8620
|
accumulatedDirtyBits = null;
|
|
7188
8621
|
accumulatedDirtyCount = 0;
|
|
7189
8622
|
accumulatedDirtyMin = Number.POSITIVE_INFINITY;
|
|
7190
8623
|
accumulatedDirtyMax = -1;
|
|
8624
|
+
accumulatedScrollOperations = null;
|
|
8625
|
+
accumulatedSkipUnchangedDirtyRows = false;
|
|
7191
8626
|
} else if (!accumulatedAllRows) {
|
|
7192
8627
|
const rowCount = terminal.size().rows;
|
|
7193
8628
|
const bits = ensureDirtyBits(rowCount);
|
|
@@ -7201,13 +8636,35 @@ function createStdoutRenderer(terminal, options) {
|
|
|
7201
8636
|
if (y > accumulatedDirtyMax) accumulatedDirtyMax = y;
|
|
7202
8637
|
}
|
|
7203
8638
|
}
|
|
8639
|
+
mergeScrollOperations(scrollOperations);
|
|
8640
|
+
accumulatedSkipUnchangedDirtyRows && (accumulatedSkipUnchangedDirtyRows = skipUnchangedDirtyRows);
|
|
8641
|
+
}
|
|
8642
|
+
const now$3 = Date.now();
|
|
8643
|
+
const elapsed = now$3 - lastFrameTime;
|
|
8644
|
+
const queuedDelayMs = Math.max(0, MIN_FRAME_MS - elapsed);
|
|
8645
|
+
if (pendingRender && !sync) {
|
|
8646
|
+
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(queuedDelayMs);
|
|
8647
|
+
return;
|
|
8648
|
+
}
|
|
8649
|
+
if (sync) {
|
|
8650
|
+
if (pendingRender) {
|
|
8651
|
+
pendingRender = false;
|
|
8652
|
+
if (renderTimer) {
|
|
8653
|
+
clearTimeout(renderTimer);
|
|
8654
|
+
renderTimer = null;
|
|
8655
|
+
}
|
|
8656
|
+
}
|
|
8657
|
+
const rows = buildAccumulatedRows();
|
|
8658
|
+
const pendingScrolls = buildAccumulatedScrollOperations();
|
|
8659
|
+
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(0);
|
|
8660
|
+
doRender(rows, pendingScrolls, accumulatedSkipUnchangedDirtyRows);
|
|
8661
|
+
return;
|
|
7204
8662
|
}
|
|
7205
|
-
if (pendingRender) return;
|
|
7206
|
-
const now$2 = Date.now();
|
|
7207
|
-
const elapsed = now$2 - lastFrameTime;
|
|
7208
8663
|
if (elapsed >= MIN_FRAME_MS) {
|
|
7209
8664
|
const rows = buildAccumulatedRows();
|
|
7210
|
-
|
|
8665
|
+
const pendingScrolls = buildAccumulatedScrollOperations();
|
|
8666
|
+
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(0);
|
|
8667
|
+
doRender(rows, pendingScrolls, accumulatedSkipUnchangedDirtyRows);
|
|
7211
8668
|
} else {
|
|
7212
8669
|
pendingRender = true;
|
|
7213
8670
|
if (renderTimer) clearTimeout(renderTimer);
|
|
@@ -7215,19 +8672,24 @@ function createStdoutRenderer(terminal, options) {
|
|
|
7215
8672
|
renderTimer = null;
|
|
7216
8673
|
if (!disposed) {
|
|
7217
8674
|
const rows = buildAccumulatedRows();
|
|
7218
|
-
|
|
8675
|
+
const pendingScrolls = buildAccumulatedScrollOperations();
|
|
8676
|
+
doRender(rows, pendingScrolls, accumulatedSkipUnchangedDirtyRows);
|
|
7219
8677
|
}
|
|
7220
|
-
},
|
|
8678
|
+
}, queuedDelayMs);
|
|
8679
|
+
cliLatency === null || cliLatency === void 0 || cliLatency.recordStdoutQueued(queuedDelayMs);
|
|
7221
8680
|
}
|
|
7222
8681
|
}
|
|
8682
|
+
terminal.setFingerprintFn((ch, style) => {
|
|
8683
|
+
return styleKey$1(style) << 16 | charHash16(ch);
|
|
8684
|
+
});
|
|
7223
8685
|
if (altScreen && out.isTTY) out.write("\x1B[?1049h");
|
|
7224
8686
|
if (hideCursor) out.write("\x1B[?25l");
|
|
7225
8687
|
if (clear) out.write(`${SGR_RESET}${openBg(defaultBg)}\u001B[2J\u001B[H${SGR_RESET}`);
|
|
7226
|
-
const off = terminal.on("commit", ({ dirtyRows }) => {
|
|
7227
|
-
if (isDebugEnabled()) getDebugLog().render(`Commit event: dirtyRows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) ?? "null"}, rows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.join(",")) ?? "all"}`);
|
|
7228
|
-
render(dirtyRows);
|
|
8688
|
+
const off = terminal.on("commit", ({ dirtyRows, scrollOperations, sync }) => {
|
|
8689
|
+
if (isDebugEnabled()) getDebugLog().render(`Commit event: dirtyRows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.length) ?? "null"}, rows=${(dirtyRows === null || dirtyRows === void 0 ? void 0 : dirtyRows.join(",")) ?? "all"}${(scrollOperations === null || scrollOperations === void 0 ? void 0 : scrollOperations.length) ? `, scrollOps=${scrollOperations.map((op) => `${op.startY}-${op.endY - 1}:${op.delta}`).join("|")}` : ""}${sync ? " (sync)" : ""}`);
|
|
8690
|
+
render(dirtyRows, sync, scrollOperations, true);
|
|
7229
8691
|
});
|
|
7230
|
-
const resizeSource = (options === null || options === void 0 ? void 0 : options.output) ?? process.stdout;
|
|
8692
|
+
const resizeSource = (options === null || options === void 0 ? void 0 : options.output) ?? process$1.stdout;
|
|
7231
8693
|
const canTrackResize = Boolean(trackResize && out.isTTY && typeof (resizeSource === null || resizeSource === void 0 ? void 0 : resizeSource.on) === "function");
|
|
7232
8694
|
const onResize = () => {
|
|
7233
8695
|
const cols = Number(resizeSource === null || resizeSource === void 0 ? void 0 : resizeSource.columns);
|
|
@@ -7255,6 +8717,8 @@ function createStdoutRenderer(terminal, options) {
|
|
|
7255
8717
|
rows: size.rows
|
|
7256
8718
|
});
|
|
7257
8719
|
out.write(`\u001B[${cy + 1};${cx + 1}H`);
|
|
8720
|
+
lastCursorX = cx;
|
|
8721
|
+
lastCursorY = cy;
|
|
7258
8722
|
}
|
|
7259
8723
|
/** Show or hide the terminal cursor */
|
|
7260
8724
|
function showCursor(visible) {
|
|
@@ -7288,7 +8752,10 @@ function createStdoutRenderer(terminal, options) {
|
|
|
7288
8752
|
if (next.defaultBg && next.defaultBg !== defaultBg) defaultBg = next.defaultBg;
|
|
7289
8753
|
if ("palette" in next) palette = next.palette;
|
|
7290
8754
|
styleKeyCache$1 = new WeakMap();
|
|
7291
|
-
|
|
8755
|
+
fpRows = 0;
|
|
8756
|
+
fpPrevValid = false;
|
|
8757
|
+
prevOverlayBlockedRows = [];
|
|
8758
|
+
prevOverlayPartialRows = [];
|
|
7292
8759
|
render();
|
|
7293
8760
|
};
|
|
7294
8761
|
return {
|
|
@@ -7486,12 +8953,22 @@ const rowCache = new WeakMap();
|
|
|
7486
8953
|
function segmentsToKey(segments) {
|
|
7487
8954
|
return segments.map((s) => `${s.key}:${s.text}:${s.cols}:${s.wide}`).join("|");
|
|
7488
8955
|
}
|
|
8956
|
+
function isPlainStyle(style) {
|
|
8957
|
+
return !style.fg && !style.bg && !style.bold && !style.dim && !style.italic && !style.underline && !style.inverse && !style.href;
|
|
8958
|
+
}
|
|
8959
|
+
function isTransparentBlankRow(segments) {
|
|
8960
|
+
return segments.length === 1 && isPlainStyle(segments[0].style) && segments[0].text.trim().length === 0;
|
|
8961
|
+
}
|
|
7489
8962
|
function renderRow(terminal, metrics$1, wideScaleX, y, lineEl) {
|
|
7490
8963
|
const segments = computeRowSegments(terminal, y);
|
|
7491
8964
|
const newKey = segmentsToKey(segments);
|
|
7492
8965
|
const cachedKey = rowCache.get(lineEl);
|
|
7493
8966
|
if (cachedKey === newKey) return;
|
|
7494
8967
|
rowCache.set(lineEl, newKey);
|
|
8968
|
+
if (isTransparentBlankRow(segments)) {
|
|
8969
|
+
lineEl.replaceChildren();
|
|
8970
|
+
return;
|
|
8971
|
+
}
|
|
7495
8972
|
const fragment = document.createDocumentFragment();
|
|
7496
8973
|
for (const seg of segments) {
|
|
7497
8974
|
const span = document.createElement("span");
|
|
@@ -7512,6 +8989,7 @@ function createDomRenderer(terminal, container) {
|
|
|
7512
8989
|
container.style.whiteSpace = "pre";
|
|
7513
8990
|
container.style.display = "inline-block";
|
|
7514
8991
|
container.style.overflow = "hidden";
|
|
8992
|
+
container.style.position = "relative";
|
|
7515
8993
|
container.style.userSelect = "text";
|
|
7516
8994
|
container.style.outline = "none";
|
|
7517
8995
|
container.style.contain = "layout style";
|
|
@@ -7519,21 +8997,93 @@ function createDomRenderer(terminal, container) {
|
|
|
7519
8997
|
installAnsiPaletteCssVars(container);
|
|
7520
8998
|
let metrics$1 = measureCell(container);
|
|
7521
8999
|
let wideScaleX = 1;
|
|
7522
|
-
|
|
9000
|
+
const planeLayers = new Map();
|
|
7523
9001
|
let raf = 0;
|
|
7524
|
-
const pending = new
|
|
9002
|
+
const pending = new Map();
|
|
7525
9003
|
let disposed = false;
|
|
9004
|
+
function applyPlaneOffset(plane, offsetPx) {
|
|
9005
|
+
const layer = planeLayers.get(plane);
|
|
9006
|
+
if (!layer) return;
|
|
9007
|
+
const next = Number.isFinite(offsetPx) ? offsetPx : 0;
|
|
9008
|
+
if (layer.offsetPx === next) return;
|
|
9009
|
+
layer.offsetPx = next;
|
|
9010
|
+
layer.contentEl.style.transform = next ? `translateY(${next}px)` : "translateY(0px)";
|
|
9011
|
+
}
|
|
9012
|
+
function applyPlaneViewport(plane, viewport) {
|
|
9013
|
+
const layer = planeLayers.get(plane);
|
|
9014
|
+
if (!layer) return;
|
|
9015
|
+
const totalHeight = terminal.size().rows * metrics$1.cellHeight;
|
|
9016
|
+
if (!viewport) {
|
|
9017
|
+
layer.viewportTopPx = 0;
|
|
9018
|
+
layer.viewportHeightPx = null;
|
|
9019
|
+
layer.el.style.clipPath = "none";
|
|
9020
|
+
return;
|
|
9021
|
+
}
|
|
9022
|
+
const topPx = Math.max(0, Math.min(totalHeight, Math.floor(viewport.topPx)));
|
|
9023
|
+
const heightPx = Math.max(0, Math.min(totalHeight - topPx, Math.floor(viewport.heightPx)));
|
|
9024
|
+
layer.viewportTopPx = topPx;
|
|
9025
|
+
layer.viewportHeightPx = heightPx;
|
|
9026
|
+
if (topPx === 0 && heightPx >= totalHeight) {
|
|
9027
|
+
layer.el.style.clipPath = "none";
|
|
9028
|
+
return;
|
|
9029
|
+
}
|
|
9030
|
+
const bottomPx = Math.max(0, totalHeight - topPx - heightPx);
|
|
9031
|
+
layer.el.style.clipPath = `inset(${topPx}px 0px ${bottomPx}px 0px)`;
|
|
9032
|
+
}
|
|
7526
9033
|
function rebuildLines() {
|
|
7527
9034
|
const { rows, cols } = terminal.size();
|
|
7528
9035
|
container.style.width = `${cols * metrics$1.cellWidth}px`;
|
|
7529
9036
|
container.style.height = `${rows * metrics$1.cellHeight}px`;
|
|
7530
9037
|
const fragment = document.createDocumentFragment();
|
|
7531
|
-
|
|
7532
|
-
const
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
9038
|
+
for (let i = 0; i < TERMINAL_RENDER_PLANES.length; i++) {
|
|
9039
|
+
const plane = TERMINAL_RENDER_PLANES[i];
|
|
9040
|
+
const planeTerminal = getPlaneTerminal(terminal, plane);
|
|
9041
|
+
let layer = planeLayers.get(plane);
|
|
9042
|
+
if (!layer) {
|
|
9043
|
+
const el = document.createElement("div");
|
|
9044
|
+
const contentEl = document.createElement("div");
|
|
9045
|
+
el.dataset.vtPlane = plane;
|
|
9046
|
+
el.style.pointerEvents = "none";
|
|
9047
|
+
contentEl.style.position = "absolute";
|
|
9048
|
+
contentEl.style.left = "0";
|
|
9049
|
+
contentEl.style.top = "0";
|
|
9050
|
+
layer = {
|
|
9051
|
+
el,
|
|
9052
|
+
contentEl,
|
|
9053
|
+
lines: [],
|
|
9054
|
+
offsetPx: 0,
|
|
9055
|
+
terminal: planeTerminal,
|
|
9056
|
+
viewportTopPx: 0,
|
|
9057
|
+
viewportHeightPx: null
|
|
9058
|
+
};
|
|
9059
|
+
planeLayers.set(plane, layer);
|
|
9060
|
+
}
|
|
9061
|
+
layer.terminal = planeTerminal;
|
|
9062
|
+
layer.el.style.position = "absolute";
|
|
9063
|
+
layer.el.style.left = "0";
|
|
9064
|
+
layer.el.style.top = "0";
|
|
9065
|
+
layer.el.style.width = `${cols * metrics$1.cellWidth}px`;
|
|
9066
|
+
layer.el.style.height = `${rows * metrics$1.cellHeight}px`;
|
|
9067
|
+
layer.el.style.overflow = "hidden";
|
|
9068
|
+
layer.el.style.zIndex = String(i);
|
|
9069
|
+
layer.contentEl.style.width = `${cols * metrics$1.cellWidth}px`;
|
|
9070
|
+
layer.contentEl.style.height = `${rows * metrics$1.cellHeight}px`;
|
|
9071
|
+
applyPlaneOffset(plane, layer.offsetPx);
|
|
9072
|
+
applyPlaneViewport(plane, layer.viewportHeightPx == null ? null : {
|
|
9073
|
+
topPx: layer.viewportTopPx,
|
|
9074
|
+
heightPx: layer.viewportHeightPx
|
|
9075
|
+
});
|
|
9076
|
+
const lineFragment = document.createDocumentFragment();
|
|
9077
|
+
layer.lines = Array.from({ length: rows }, () => {
|
|
9078
|
+
const line = document.createElement("div");
|
|
9079
|
+
line.style.cssText = `height:${metrics$1.cellHeight}px;width:${cols * metrics$1.cellWidth}px;overflow:hidden;contain:layout style`;
|
|
9080
|
+
lineFragment.appendChild(line);
|
|
9081
|
+
return line;
|
|
9082
|
+
});
|
|
9083
|
+
layer.contentEl.replaceChildren(lineFragment);
|
|
9084
|
+
layer.el.replaceChildren(layer.contentEl);
|
|
9085
|
+
fragment.appendChild(layer.el);
|
|
9086
|
+
}
|
|
7537
9087
|
container.replaceChildren(fragment);
|
|
7538
9088
|
}
|
|
7539
9089
|
function refresh() {
|
|
@@ -7542,22 +9092,46 @@ function createDomRenderer(terminal, container) {
|
|
|
7542
9092
|
wideScaleX = wideW > 0 ? Math.max(1, Math.min(2, metrics$1.cellWidth * 2 / wideW)) : 1;
|
|
7543
9093
|
rebuildLines();
|
|
7544
9094
|
const size = terminal.size();
|
|
7545
|
-
for (
|
|
9095
|
+
for (const plane of TERMINAL_RENDER_PLANES) {
|
|
9096
|
+
const layer = planeLayers.get(plane);
|
|
9097
|
+
if (!layer) continue;
|
|
9098
|
+
for (let y = 0; y < size.rows; y++) renderRow(layer.terminal, metrics$1, wideScaleX, y, layer.lines[y]);
|
|
9099
|
+
}
|
|
7546
9100
|
}
|
|
7547
9101
|
function flushPending() {
|
|
7548
9102
|
raf = 0;
|
|
7549
9103
|
if (disposed) return;
|
|
7550
|
-
for (const
|
|
7551
|
-
const
|
|
7552
|
-
|
|
9104
|
+
for (const plane of TERMINAL_RENDER_PLANES) {
|
|
9105
|
+
const layer = planeLayers.get(plane);
|
|
9106
|
+
const rows = pending.get(plane);
|
|
9107
|
+
if (!layer || !(rows === null || rows === void 0 ? void 0 : rows.size)) continue;
|
|
9108
|
+
for (const y of rows) {
|
|
9109
|
+
const line = layer.lines[y];
|
|
9110
|
+
if (line) renderRow(layer.terminal, metrics$1, wideScaleX, y, line);
|
|
9111
|
+
}
|
|
9112
|
+
rows.clear();
|
|
7553
9113
|
}
|
|
7554
|
-
pending.clear();
|
|
7555
9114
|
}
|
|
7556
|
-
const offCommit = terminal.on("commit", ({ dirtyRows }) => {
|
|
9115
|
+
const offCommit = terminal.on("commit", ({ dirtyRows, planes }) => {
|
|
9116
|
+
const activePlanes = (planes === null || planes === void 0 ? void 0 : planes.length) ? planes : TERMINAL_RENDER_PLANES;
|
|
7557
9117
|
if (dirtyRows === null) {
|
|
7558
9118
|
const size = terminal.size();
|
|
7559
|
-
for (
|
|
7560
|
-
|
|
9119
|
+
for (const plane of activePlanes) {
|
|
9120
|
+
let rows = pending.get(plane);
|
|
9121
|
+
if (!rows) {
|
|
9122
|
+
rows = new Set();
|
|
9123
|
+
pending.set(plane, rows);
|
|
9124
|
+
}
|
|
9125
|
+
for (let y = 0; y < size.rows; y++) rows.add(y);
|
|
9126
|
+
}
|
|
9127
|
+
} else for (const plane of activePlanes) {
|
|
9128
|
+
let rows = pending.get(plane);
|
|
9129
|
+
if (!rows) {
|
|
9130
|
+
rows = new Set();
|
|
9131
|
+
pending.set(plane, rows);
|
|
9132
|
+
}
|
|
9133
|
+
for (const y of dirtyRows) rows.add(y);
|
|
9134
|
+
}
|
|
7561
9135
|
if (!raf) {
|
|
7562
9136
|
raf = -1;
|
|
7563
9137
|
const id = requestAnimationFrame(() => {
|
|
@@ -7583,7 +9157,14 @@ function createDomRenderer(terminal, container) {
|
|
|
7583
9157
|
offResize();
|
|
7584
9158
|
if (raf > 0) cancelAnimationFrame(raf);
|
|
7585
9159
|
pending.clear();
|
|
9160
|
+
planeLayers.clear();
|
|
7586
9161
|
container.replaceChildren();
|
|
9162
|
+
},
|
|
9163
|
+
setPlaneOffset(plane, offsetPx) {
|
|
9164
|
+
applyPlaneOffset(plane, offsetPx);
|
|
9165
|
+
},
|
|
9166
|
+
setPlaneViewport(plane, viewport) {
|
|
9167
|
+
applyPlaneViewport(plane, viewport);
|
|
7587
9168
|
}
|
|
7588
9169
|
};
|
|
7589
9170
|
}
|
|
@@ -7592,7 +9173,7 @@ function createDomRenderer(terminal, container) {
|
|
|
7592
9173
|
//#region src/runtime/index.ts
|
|
7593
9174
|
function isNodeLike() {
|
|
7594
9175
|
var _process$versions;
|
|
7595
|
-
return typeof (process === null || process === void 0 || (_process$versions = process.versions) === null || _process$versions === void 0 ? void 0 : _process$versions.node) === "string";
|
|
9176
|
+
return typeof (process$1 === null || process$1 === void 0 || (_process$versions = process$1.versions) === null || _process$versions === void 0 ? void 0 : _process$versions.node) === "string";
|
|
7596
9177
|
}
|
|
7597
9178
|
function detectEnv() {
|
|
7598
9179
|
const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
|
|
@@ -7732,26 +9313,39 @@ function useTerminal() {
|
|
|
7732
9313
|
//#endregion
|
|
7733
9314
|
//#region src/vue/composables/use-render-node.ts
|
|
7734
9315
|
const pendingInvalidateByScheduler = new WeakMap();
|
|
7735
|
-
function
|
|
9316
|
+
function mergePriority(prev, next) {
|
|
9317
|
+
if (prev === "high" || next === "high") return "high";
|
|
9318
|
+
if (prev === "normal" || next === "normal") return "normal";
|
|
9319
|
+
return "low";
|
|
9320
|
+
}
|
|
9321
|
+
function requestBatchedInvalidate(scheduler, plane, priority) {
|
|
7736
9322
|
let state = pendingInvalidateByScheduler.get(scheduler);
|
|
7737
9323
|
if (!state) {
|
|
7738
9324
|
state = {
|
|
7739
9325
|
queued: false,
|
|
7740
|
-
plane: null
|
|
9326
|
+
plane: null,
|
|
9327
|
+
priority: "low"
|
|
7741
9328
|
};
|
|
7742
9329
|
pendingInvalidateByScheduler.set(scheduler, state);
|
|
7743
9330
|
}
|
|
7744
9331
|
if (state.queued) {
|
|
7745
9332
|
state.plane = state.plane == null || state.plane === plane ? plane : null;
|
|
9333
|
+
state.priority = mergePriority(state.priority, priority);
|
|
7746
9334
|
return;
|
|
7747
9335
|
}
|
|
7748
9336
|
state.plane = plane;
|
|
9337
|
+
state.priority = priority;
|
|
7749
9338
|
state.queued = true;
|
|
7750
9339
|
queueMicrotask(() => {
|
|
7751
9340
|
state.queued = false;
|
|
7752
9341
|
const queuedPlane = state.plane;
|
|
9342
|
+
const queuedPriority = state.priority;
|
|
7753
9343
|
state.plane = null;
|
|
7754
|
-
|
|
9344
|
+
state.priority = "low";
|
|
9345
|
+
scheduler.invalidate(queuedPlane || queuedPriority !== "normal" ? {
|
|
9346
|
+
plane: queuedPlane ?? void 0,
|
|
9347
|
+
priority: queuedPriority
|
|
9348
|
+
} : void 0);
|
|
7755
9349
|
});
|
|
7756
9350
|
}
|
|
7757
9351
|
function useRenderNode(getOptions) {
|
|
@@ -7759,11 +9353,13 @@ function useRenderNode(getOptions) {
|
|
|
7759
9353
|
const parentStack = useRenderStack();
|
|
7760
9354
|
const plane = inject(RenderPlaneContextKey, ref("default"));
|
|
7761
9355
|
const id = ref(null);
|
|
9356
|
+
const lastPlane = ref(plane.value);
|
|
7762
9357
|
const options = computed(() => getOptions());
|
|
7763
9358
|
const stop = watchEffect(() => {
|
|
7764
9359
|
const opt = options.value;
|
|
7765
9360
|
opt.deps;
|
|
7766
9361
|
const stack = opt.stack ?? parentStack.value;
|
|
9362
|
+
lastPlane.value = plane.value;
|
|
7767
9363
|
if (!stack) return;
|
|
7768
9364
|
if (!id.value) {
|
|
7769
9365
|
const node = render.register({
|
|
@@ -7774,23 +9370,24 @@ function useRenderNode(getOptions) {
|
|
|
7774
9370
|
paint: opt.paint
|
|
7775
9371
|
});
|
|
7776
9372
|
id.value = node.id;
|
|
7777
|
-
requestBatchedInvalidate(scheduler, plane.value);
|
|
9373
|
+
requestBatchedInvalidate(scheduler, plane.value, opt.priority ?? "normal");
|
|
7778
9374
|
return;
|
|
7779
9375
|
}
|
|
7780
9376
|
render.update(id.value, {
|
|
7781
9377
|
stack,
|
|
7782
9378
|
zIndex: opt.zIndex ?? 0,
|
|
7783
9379
|
rect: opt.rect ?? null,
|
|
9380
|
+
dirtyRowsHint: opt.dirtyRowsHint,
|
|
7784
9381
|
plane: plane.value,
|
|
7785
9382
|
paint: opt.paint
|
|
7786
9383
|
});
|
|
7787
|
-
requestBatchedInvalidate(scheduler, plane.value);
|
|
9384
|
+
requestBatchedInvalidate(scheduler, plane.value, opt.priority ?? "normal");
|
|
7788
9385
|
});
|
|
7789
9386
|
onBeforeUnmount(() => {
|
|
7790
9387
|
stop();
|
|
7791
9388
|
if (id.value) {
|
|
7792
9389
|
render.unregister(id.value);
|
|
7793
|
-
requestBatchedInvalidate(scheduler,
|
|
9390
|
+
requestBatchedInvalidate(scheduler, lastPlane.value, "normal");
|
|
7794
9391
|
}
|
|
7795
9392
|
});
|
|
7796
9393
|
return { id };
|
|
@@ -8976,11 +10573,14 @@ function mentionIndexAt$1(value, mentionToken, index) {
|
|
|
8976
10573
|
return countMentionTokens$1(value, mentionToken, index);
|
|
8977
10574
|
}
|
|
8978
10575
|
function createPromptMentionPlugin(options = {}) {
|
|
10576
|
+
const latency = getCliLatencyProfiler();
|
|
8979
10577
|
return {
|
|
8980
10578
|
name: "promptMention",
|
|
8981
10579
|
install: (ctx) => {
|
|
8982
10580
|
const getProps = () => ctx.getProps();
|
|
8983
10581
|
const promptOverlayStack = ctx.render.createStack(ctx.render.rootStack, 1e4);
|
|
10582
|
+
let lastTopClampedRect = null;
|
|
10583
|
+
let lastPromptRect = null;
|
|
8984
10584
|
const derivedStyleCache = new WeakMap();
|
|
8985
10585
|
const reactiveProps = reactive({
|
|
8986
10586
|
promptSuggestions: getProps().promptSuggestions,
|
|
@@ -9028,6 +10628,20 @@ function createPromptMentionPlugin(options = {}) {
|
|
|
9028
10628
|
multilineToken: "",
|
|
9029
10629
|
mentionToken: ctx.mentionToken
|
|
9030
10630
|
});
|
|
10631
|
+
watch(() => {
|
|
10632
|
+
if (!ctx.visible.value || !promptMention.promptVisible.value) return null;
|
|
10633
|
+
const rect = promptMention.promptRect.value;
|
|
10634
|
+
return [
|
|
10635
|
+
Math.floor(rect.x),
|
|
10636
|
+
Math.floor(rect.y),
|
|
10637
|
+
Math.floor(rect.w),
|
|
10638
|
+
Math.floor(rect.h)
|
|
10639
|
+
].join(":");
|
|
10640
|
+
}, (nextRectKey, prevRectKey) => {
|
|
10641
|
+
if (!prevRectKey || nextRectKey === prevRectKey) return;
|
|
10642
|
+
ctx.render.invalidatePlane("default");
|
|
10643
|
+
ctx.scheduler.invalidate({ priority: "high" });
|
|
10644
|
+
});
|
|
9031
10645
|
ctx.registerChipStyleProvider({
|
|
9032
10646
|
getStyle: (baseStyle, chip) => {
|
|
9033
10647
|
if (chip.kind !== "mention") return null;
|
|
@@ -9105,6 +10719,12 @@ function createPromptMentionPlugin(options = {}) {
|
|
|
9105
10719
|
query: ctx0.query
|
|
9106
10720
|
});
|
|
9107
10721
|
if (handled !== false) {
|
|
10722
|
+
const value = ctx.getValue();
|
|
10723
|
+
const before$1 = value.slice(0, ctx0.tokenStart);
|
|
10724
|
+
const after$1 = value.slice(ctx0.tokenEnd);
|
|
10725
|
+
const nextValue$1 = `${before$1}${after$1}`;
|
|
10726
|
+
ctx.pushUndoSnapshot(nextValue$1);
|
|
10727
|
+
ctx.applyEdit(nextValue$1, ctx0.tokenStart);
|
|
9108
10728
|
promptMention.promptSuppressedKey.value = ctx0.key;
|
|
9109
10729
|
ctx.scheduler.invalidate();
|
|
9110
10730
|
return;
|
|
@@ -9141,8 +10761,17 @@ function createPromptMentionPlugin(options = {}) {
|
|
|
9141
10761
|
}
|
|
9142
10762
|
function handlePromptKeydown(e) {
|
|
9143
10763
|
if (!promptMention.promptVisible.value) return false;
|
|
10764
|
+
const markPromptOperation = (suffix) => {
|
|
10765
|
+
const ctx0 = promptMention.activeContext.value;
|
|
10766
|
+
const mentionTrigger = getProps().mentionTrigger || "@";
|
|
10767
|
+
const skillTrigger = getProps().skillTrigger || "";
|
|
10768
|
+
const tokenText = String((ctx0 === null || ctx0 === void 0 ? void 0 : ctx0.tokenText) ?? "");
|
|
10769
|
+
const scope = tokenText.startsWith(mentionTrigger) ? "prompt.mention" : skillTrigger && tokenText.startsWith(skillTrigger) ? "prompt.skill" : "prompt.command";
|
|
10770
|
+
latency === null || latency === void 0 || latency.markOperation(`${scope}.${suffix}`);
|
|
10771
|
+
};
|
|
9144
10772
|
const len = promptMention.promptMatches.value.length;
|
|
9145
10773
|
if (e.key === "ArrowDown") {
|
|
10774
|
+
markPromptOperation("navigate.next");
|
|
9146
10775
|
e.preventDefault();
|
|
9147
10776
|
if (len <= 0) promptMention.promptActive.value = 0;
|
|
9148
10777
|
else if (promptMention.promptActive.value >= len - 1) promptMention.promptActive.value = 0;
|
|
@@ -9151,6 +10780,7 @@ function createPromptMentionPlugin(options = {}) {
|
|
|
9151
10780
|
return true;
|
|
9152
10781
|
}
|
|
9153
10782
|
if (e.key === "ArrowUp") {
|
|
10783
|
+
markPromptOperation("navigate.prev");
|
|
9154
10784
|
e.preventDefault();
|
|
9155
10785
|
if (len <= 0) promptMention.promptActive.value = 0;
|
|
9156
10786
|
else if (promptMention.promptActive.value <= 0) promptMention.promptActive.value = len - 1;
|
|
@@ -9172,11 +10802,13 @@ function createPromptMentionPlugin(options = {}) {
|
|
|
9172
10802
|
const typed = String((ctx0 === null || ctx0 === void 0 ? void 0 : ctx0.tokenText) ?? "");
|
|
9173
10803
|
const candidate = String((match === null || match === void 0 || (_match$item = match.item) === null || _match$item === void 0 ? void 0 : _match$item.value) ?? "");
|
|
9174
10804
|
if (!typed || !candidate.startsWith(typed)) return false;
|
|
10805
|
+
markPromptOperation("accept");
|
|
9175
10806
|
e.preventDefault();
|
|
9176
10807
|
acceptPrompt(promptMention.promptActive.value);
|
|
9177
10808
|
return true;
|
|
9178
10809
|
}
|
|
9179
10810
|
if (e.key === "Tab" && (isMention || isSkill)) {
|
|
10811
|
+
markPromptOperation("accept");
|
|
9180
10812
|
e.preventDefault();
|
|
9181
10813
|
if (len === 0) return true;
|
|
9182
10814
|
const list = promptMention.promptMatches.value;
|
|
@@ -9186,12 +10818,14 @@ function createPromptMentionPlugin(options = {}) {
|
|
|
9186
10818
|
return true;
|
|
9187
10819
|
}
|
|
9188
10820
|
if (len === 0) return false;
|
|
10821
|
+
markPromptOperation("accept");
|
|
9189
10822
|
e.preventDefault();
|
|
9190
10823
|
acceptPrompt(promptMention.promptActive.value);
|
|
9191
10824
|
return true;
|
|
9192
10825
|
}
|
|
9193
10826
|
if (e.key === "Escape") {
|
|
9194
10827
|
var _promptMention$active;
|
|
10828
|
+
markPromptOperation("dismiss");
|
|
9195
10829
|
e.preventDefault();
|
|
9196
10830
|
promptMention.promptSuppressedKey.value = ((_promptMention$active = promptMention.activeContext.value) === null || _promptMention$active === void 0 ? void 0 : _promptMention$active.key) ?? null;
|
|
9197
10831
|
ctx.scheduler.invalidate();
|
|
@@ -9203,6 +10837,20 @@ function createPromptMentionPlugin(options = {}) {
|
|
|
9203
10837
|
useRenderNode(() => ({
|
|
9204
10838
|
zIndex: getProps().zIndex + 5,
|
|
9205
10839
|
stack: promptOverlayStack,
|
|
10840
|
+
dirtyRowsHint: (() => {
|
|
10841
|
+
const currentRect = ctx.visible.value && promptMention.promptVisible.value ? {
|
|
10842
|
+
y: Math.floor(promptMention.promptRect.value.y),
|
|
10843
|
+
h: Math.max(0, Math.floor(promptMention.promptRect.value.h))
|
|
10844
|
+
} : null;
|
|
10845
|
+
const rects = [lastPromptRect, currentRect].filter(Boolean);
|
|
10846
|
+
if (!rects.length) return void 0;
|
|
10847
|
+
const maxRows = ctx.terminal.size().rows;
|
|
10848
|
+
const start = Math.max(0, Math.min(...rects.map((rect) => rect.y)) - 1);
|
|
10849
|
+
const end = Math.min(maxRows, Math.max(...rects.map((rect) => rect.y + rect.h)) + 1);
|
|
10850
|
+
if (end <= start) return void 0;
|
|
10851
|
+
return Array.from({ length: end - start }, (_, index) => start + index);
|
|
10852
|
+
})(),
|
|
10853
|
+
priority: "high",
|
|
9206
10854
|
rect: ctx.visible.value && promptMention.promptVisible.value ? promptMention.promptRect.value : {
|
|
9207
10855
|
x: 0,
|
|
9208
10856
|
y: 0,
|
|
@@ -9229,6 +10877,10 @@ function createPromptMentionPlugin(options = {}) {
|
|
|
9229
10877
|
if (!ctx.visible.value || !promptMention.promptVisible.value) return;
|
|
9230
10878
|
const r = promptMention.promptRect.value;
|
|
9231
10879
|
if (r.w < 3 || r.h < 3) return;
|
|
10880
|
+
lastPromptRect = {
|
|
10881
|
+
y: Math.floor(r.y),
|
|
10882
|
+
h: Math.max(0, Math.floor(r.h))
|
|
10883
|
+
};
|
|
9232
10884
|
const base = getProps().style ?? ctx.defaultStyle.value;
|
|
9233
10885
|
const selectedOverride = { bg: "blue" };
|
|
9234
10886
|
const styleKey$1 = base && typeof base === "object" ? base : null;
|
|
@@ -9278,6 +10930,19 @@ function createPromptMentionPlugin(options = {}) {
|
|
|
9278
10930
|
const contentW = Math.max(0, innerW - sidePad * 2);
|
|
9279
10931
|
const contentX = x0 + 1 + sidePad;
|
|
9280
10932
|
const borderStyle = derived.borderStyle;
|
|
10933
|
+
if (lastTopClampedRect && y0 > 0) {
|
|
10934
|
+
ctx.terminal.write(spaces(lastTopClampedRect.w), {
|
|
10935
|
+
x: lastTopClampedRect.x,
|
|
10936
|
+
y: 0,
|
|
10937
|
+
style: getProps().style ?? ctx.defaultStyle.value
|
|
10938
|
+
});
|
|
10939
|
+
lastTopClampedRect = null;
|
|
10940
|
+
}
|
|
10941
|
+
if (y0 === 0) lastTopClampedRect = {
|
|
10942
|
+
x: x0,
|
|
10943
|
+
w
|
|
10944
|
+
};
|
|
10945
|
+
else lastTopClampedRect = null;
|
|
9281
10946
|
ctx.terminal.write(`┌${repeatChar("─", innerW)}┐`, {
|
|
9282
10947
|
x: x0,
|
|
9283
10948
|
y: y0,
|
|
@@ -11543,6 +13208,8 @@ const TerminalProvider = defineComponent({
|
|
|
11543
13208
|
let rafToken = 0;
|
|
11544
13209
|
let pendingInvalidate = false;
|
|
11545
13210
|
let timer = null;
|
|
13211
|
+
let holdNormalInvalidates = false;
|
|
13212
|
+
let holdReleaseToken = 0;
|
|
11546
13213
|
let pendingInvalidateAllPlanes = false;
|
|
11547
13214
|
const pendingInvalidatePlanes = new Set();
|
|
11548
13215
|
let imeComposing = false;
|
|
@@ -11571,11 +13238,14 @@ const TerminalProvider = defineComponent({
|
|
|
11571
13238
|
pendingInvalidatePlanes.clear();
|
|
11572
13239
|
return activePlanes;
|
|
11573
13240
|
}
|
|
11574
|
-
function flush() {
|
|
13241
|
+
function flush(sync = false) {
|
|
11575
13242
|
if (unmounting) return;
|
|
11576
13243
|
const activePlanes = takeActivePlanes();
|
|
11577
13244
|
render.render({ activePlanes });
|
|
11578
|
-
terminal.commit({
|
|
13245
|
+
terminal.commit({
|
|
13246
|
+
planes: activePlanes,
|
|
13247
|
+
sync
|
|
13248
|
+
});
|
|
11579
13249
|
updateImePositionAfterFlush === null || updateImePositionAfterFlush === void 0 || updateImePositionAfterFlush();
|
|
11580
13250
|
}
|
|
11581
13251
|
function clearTimer() {
|
|
@@ -11583,6 +13253,16 @@ const TerminalProvider = defineComponent({
|
|
|
11583
13253
|
clearTimeout(timer);
|
|
11584
13254
|
timer = null;
|
|
11585
13255
|
}
|
|
13256
|
+
function scheduleNormalInvalidateRelease() {
|
|
13257
|
+
const token = ++holdReleaseToken;
|
|
13258
|
+
nextTick(() => {
|
|
13259
|
+
if (token !== holdReleaseToken) return;
|
|
13260
|
+
holdNormalInvalidates = false;
|
|
13261
|
+
if (unmounting || !pendingInvalidate) return;
|
|
13262
|
+
pendingInvalidate = false;
|
|
13263
|
+
invalidate({ priority: "normal" });
|
|
13264
|
+
});
|
|
13265
|
+
}
|
|
11586
13266
|
function flushNow() {
|
|
11587
13267
|
if (unmounting) return;
|
|
11588
13268
|
pendingInvalidate = false;
|
|
@@ -11592,7 +13272,9 @@ const TerminalProvider = defineComponent({
|
|
|
11592
13272
|
raf = 0;
|
|
11593
13273
|
}
|
|
11594
13274
|
clearTimer();
|
|
11595
|
-
|
|
13275
|
+
holdNormalInvalidates = true;
|
|
13276
|
+
scheduleNormalInvalidateRelease();
|
|
13277
|
+
flush(true);
|
|
11596
13278
|
}
|
|
11597
13279
|
function invalidate(options) {
|
|
11598
13280
|
if (unmounting) return;
|
|
@@ -11603,6 +13285,10 @@ const TerminalProvider = defineComponent({
|
|
|
11603
13285
|
flushNow();
|
|
11604
13286
|
return;
|
|
11605
13287
|
}
|
|
13288
|
+
if (holdNormalInvalidates) {
|
|
13289
|
+
pendingInvalidate = true;
|
|
13290
|
+
return;
|
|
13291
|
+
}
|
|
11606
13292
|
if (priority === "low") {
|
|
11607
13293
|
if (timer || raf) return;
|
|
11608
13294
|
profiler === null || profiler === void 0 || profiler.recordInvalidate({ plane: (options === null || options === void 0 ? void 0 : options.plane) ?? null });
|
|
@@ -12145,6 +13831,8 @@ const TerminalProvider = defineComponent({
|
|
|
12145
13831
|
onBeforeUnmount(() => {
|
|
12146
13832
|
unmounting = true;
|
|
12147
13833
|
offCommit === null || offCommit === void 0 || offCommit();
|
|
13834
|
+
clearTimer();
|
|
13835
|
+
holdReleaseToken++;
|
|
12148
13836
|
if (raf > 0) cancelAnimationFrame(raf);
|
|
12149
13837
|
raf = 0;
|
|
12150
13838
|
scope.stop();
|
|
@@ -13073,7 +14761,10 @@ const TInput = defineComponent({
|
|
|
13073
14761
|
emit("update:modelValue", nextValue);
|
|
13074
14762
|
emit("input", nextValue);
|
|
13075
14763
|
if (commit) emit("change", nextValue);
|
|
13076
|
-
scheduler.
|
|
14764
|
+
scheduler.flushNow();
|
|
14765
|
+
nextTick(() => {
|
|
14766
|
+
scheduler.flushNow();
|
|
14767
|
+
});
|
|
13077
14768
|
}
|
|
13078
14769
|
function applyMove(nextCursor, extend) {
|
|
13079
14770
|
const prev = cursor.value;
|
|
@@ -13090,7 +14781,7 @@ const TInput = defineComponent({
|
|
|
13090
14781
|
} else desiredCol.value = indexToLineCellColInline(value, props.multilineTexts, props.mentions, cursor.value).col;
|
|
13091
14782
|
ensureCursorVisible();
|
|
13092
14783
|
syncImeAnchorNow();
|
|
13093
|
-
scheduler.
|
|
14784
|
+
scheduler.flushNow();
|
|
13094
14785
|
}
|
|
13095
14786
|
watch([
|
|
13096
14787
|
() => absRect.value.w,
|
|
@@ -13209,7 +14900,11 @@ const TInput = defineComponent({
|
|
|
13209
14900
|
terminal,
|
|
13210
14901
|
scheduler,
|
|
13211
14902
|
defaultStyle,
|
|
13212
|
-
render
|
|
14903
|
+
render: {
|
|
14904
|
+
rootStack: render.rootStack,
|
|
14905
|
+
createStack: render.createStack,
|
|
14906
|
+
invalidatePlane: render.invalidatePlane
|
|
14907
|
+
},
|
|
13213
14908
|
visible,
|
|
13214
14909
|
rawAbsRect,
|
|
13215
14910
|
eventZ,
|
|
@@ -13306,7 +15001,7 @@ const TInput = defineComponent({
|
|
|
13306
15001
|
emitMentions(nextMentions);
|
|
13307
15002
|
ensureCursorVisible();
|
|
13308
15003
|
syncImeAnchorNow();
|
|
13309
|
-
scheduler.
|
|
15004
|
+
scheduler.flushNow();
|
|
13310
15005
|
}
|
|
13311
15006
|
function removePendingPasteImage(placeholderPath) {
|
|
13312
15007
|
const current = getCurrentMentions();
|
|
@@ -13966,10 +15661,12 @@ const TInput = defineComponent({
|
|
|
13966
15661
|
clearAll();
|
|
13967
15662
|
return;
|
|
13968
15663
|
}
|
|
13969
|
-
|
|
13970
|
-
|
|
13971
|
-
|
|
13972
|
-
|
|
15664
|
+
const manager = events.value;
|
|
15665
|
+
if (manager && manager.getFocused()) {
|
|
15666
|
+
manager.focus(null);
|
|
15667
|
+
return;
|
|
15668
|
+
}
|
|
15669
|
+
applyBlur();
|
|
13973
15670
|
return;
|
|
13974
15671
|
}
|
|
13975
15672
|
if (isPrintableKey(e)) {
|
|
@@ -14207,6 +15904,7 @@ const TInput = defineComponent({
|
|
|
14207
15904
|
var _chipStyleProvider$va;
|
|
14208
15905
|
return {
|
|
14209
15906
|
zIndex: props.zIndex,
|
|
15907
|
+
priority: pendingValue.value != null ? "high" : "normal",
|
|
14210
15908
|
rect: visible.value ? absRect.value : {
|
|
14211
15909
|
x: 0,
|
|
14212
15910
|
y: 0,
|
|
@@ -14239,6 +15937,7 @@ const TInput = defineComponent({
|
|
|
14239
15937
|
blinkOn.value,
|
|
14240
15938
|
defaultStyle.value,
|
|
14241
15939
|
((_chipStyleProvider$va = chipStyleProvider.value) === null || _chipStyleProvider$va === void 0 ? void 0 : _chipStyleProvider$va.version.value) ?? 0,
|
|
15940
|
+
pendingValue.value,
|
|
14242
15941
|
props.skillHighlightStyle,
|
|
14243
15942
|
props.skillTrigger
|
|
14244
15943
|
],
|
|
@@ -14857,25 +16556,29 @@ const TJsonEditor = defineComponent({
|
|
|
14857
16556
|
//#endregion
|
|
14858
16557
|
//#region src/vue/utils/wheel-scroll.ts
|
|
14859
16558
|
const LINE_UNIT_THRESHOLD = 3;
|
|
14860
|
-
const PIXELS_PER_LINE =
|
|
16559
|
+
const PIXELS_PER_LINE = .75;
|
|
14861
16560
|
const ACCEL_WINDOW_MS = 120;
|
|
14862
|
-
const MAX_ACCEL =
|
|
16561
|
+
const MAX_ACCEL = 26;
|
|
14863
16562
|
const EDGE_BOUNCE_MS = 120;
|
|
14864
16563
|
const MIN_TICK_INTERVAL_MS = 6;
|
|
14865
16564
|
function clamp$3(n, min, max) {
|
|
14866
16565
|
return Math.max(min, Math.min(max, n));
|
|
14867
16566
|
}
|
|
14868
|
-
function isLineUnitDelta(deltaY) {
|
|
16567
|
+
function isLineUnitDelta(deltaY, mode = "auto") {
|
|
16568
|
+
if (mode === "line") return true;
|
|
16569
|
+
if (mode === "pixel") return false;
|
|
14869
16570
|
const abs = Math.abs(deltaY);
|
|
14870
16571
|
return abs > 0 && abs <= LINE_UNIT_THRESHOLD && Number.isInteger(deltaY);
|
|
14871
16572
|
}
|
|
14872
|
-
function normalizeDelta(deltaY) {
|
|
16573
|
+
function normalizeDelta(deltaY, mode = "auto") {
|
|
16574
|
+
if (mode === "line") return deltaY;
|
|
16575
|
+
if (mode === "pixel") return deltaY / PIXELS_PER_LINE;
|
|
14873
16576
|
const abs = Math.abs(deltaY);
|
|
14874
16577
|
if (abs <= LINE_UNIT_THRESHOLD && Number.isInteger(deltaY)) return deltaY;
|
|
14875
16578
|
return deltaY / PIXELS_PER_LINE;
|
|
14876
16579
|
}
|
|
14877
|
-
function accelFactor(now$
|
|
14878
|
-
const dt = now$
|
|
16580
|
+
function accelFactor(now$3, lastAt) {
|
|
16581
|
+
const dt = now$3 - lastAt;
|
|
14879
16582
|
if (!Number.isFinite(dt) || dt <= 0 || dt > ACCEL_WINDOW_MS) return 1;
|
|
14880
16583
|
const t = 1 - dt / ACCEL_WINDOW_MS;
|
|
14881
16584
|
return 1 + t * (MAX_ACCEL - 1);
|
|
@@ -14885,15 +16588,17 @@ function createWheelScrollState() {
|
|
|
14885
16588
|
accumulator: 0,
|
|
14886
16589
|
lastAt: 0,
|
|
14887
16590
|
lastEdgeDir: 0,
|
|
14888
|
-
lastEdgeAt: 0
|
|
16591
|
+
lastEdgeAt: 0,
|
|
16592
|
+
lastLineUnitDir: 0
|
|
14889
16593
|
};
|
|
14890
16594
|
}
|
|
14891
|
-
function applyWheelScroll(state, deltaY, scrollTop, maxTop, now$
|
|
16595
|
+
function applyWheelScroll(state, deltaY, scrollTop, maxTop, now$3 = Date.now(), deltaMode = "auto", options = {}) {
|
|
14892
16596
|
if (!Number.isFinite(deltaY) || deltaY === 0 || maxTop <= 0) {
|
|
14893
16597
|
if (maxTop <= 0) {
|
|
14894
16598
|
state.accumulator = 0;
|
|
14895
16599
|
state.lastEdgeDir = 0;
|
|
14896
16600
|
state.lastEdgeAt = 0;
|
|
16601
|
+
state.lastLineUnitDir = 0;
|
|
14897
16602
|
}
|
|
14898
16603
|
return {
|
|
14899
16604
|
nextTop: scrollTop,
|
|
@@ -14901,16 +16606,18 @@ function applyWheelScroll(state, deltaY, scrollTop, maxTop, now$2 = Date.now())
|
|
|
14901
16606
|
lines: 0
|
|
14902
16607
|
};
|
|
14903
16608
|
}
|
|
14904
|
-
const dt = state.lastAt ? now$
|
|
14905
|
-
const lineUnits = isLineUnitDelta(deltaY);
|
|
14906
|
-
|
|
16609
|
+
const dt = state.lastAt ? now$3 - state.lastAt : Infinity;
|
|
16610
|
+
const lineUnits = isLineUnitDelta(deltaY, deltaMode);
|
|
16611
|
+
const inputDir = Math.sign(normalizeDelta(deltaY, deltaMode));
|
|
16612
|
+
if (lineUnits && dt !== Infinity && dt >= 0 && dt < MIN_TICK_INTERVAL_MS && inputDir === state.lastLineUnitDir) return {
|
|
14907
16613
|
nextTop: scrollTop,
|
|
14908
16614
|
dir: 0,
|
|
14909
16615
|
lines: 0
|
|
14910
16616
|
};
|
|
14911
|
-
|
|
14912
|
-
state.lastAt
|
|
14913
|
-
state.
|
|
16617
|
+
state.lastLineUnitDir = lineUnits ? inputDir : 0;
|
|
16618
|
+
const accel = lineUnits ? 1 : options.disableAcceleration ? 1 : state.lastAt ? accelFactor(now$3, state.lastAt) : 1;
|
|
16619
|
+
state.lastAt = now$3;
|
|
16620
|
+
state.accumulator += normalizeDelta(deltaY, deltaMode) * accel;
|
|
14914
16621
|
const lines = Math.trunc(state.accumulator);
|
|
14915
16622
|
if (lines === 0) return {
|
|
14916
16623
|
nextTop: scrollTop,
|
|
@@ -14923,7 +16630,7 @@ function applyWheelScroll(state, deltaY, scrollTop, maxTop, now$2 = Date.now())
|
|
|
14923
16630
|
const atBottom = scrollTop >= maxTop;
|
|
14924
16631
|
if (dir < 0 && atTop || dir > 0 && atBottom) {
|
|
14925
16632
|
state.lastEdgeDir = dir;
|
|
14926
|
-
state.lastEdgeAt = now$
|
|
16633
|
+
state.lastEdgeAt = now$3;
|
|
14927
16634
|
state.accumulator = 0;
|
|
14928
16635
|
return {
|
|
14929
16636
|
nextTop: scrollTop,
|
|
@@ -14931,7 +16638,7 @@ function applyWheelScroll(state, deltaY, scrollTop, maxTop, now$2 = Date.now())
|
|
|
14931
16638
|
lines: 0
|
|
14932
16639
|
};
|
|
14933
16640
|
}
|
|
14934
|
-
if (state.lastEdgeDir !== 0 && now$
|
|
16641
|
+
if (state.lastEdgeDir !== 0 && now$3 - state.lastEdgeAt < EDGE_BOUNCE_MS && dir === -state.lastEdgeDir && (atTop || atBottom)) return {
|
|
14935
16642
|
nextTop: scrollTop,
|
|
14936
16643
|
dir: 0,
|
|
14937
16644
|
lines: 0
|
|
@@ -14960,6 +16667,26 @@ function applyWheelScroll(state, deltaY, scrollTop, maxTop, now$2 = Date.now())
|
|
|
14960
16667
|
function clamp$2(n, min, max) {
|
|
14961
16668
|
return Math.max(min, Math.min(max, n));
|
|
14962
16669
|
}
|
|
16670
|
+
function getWheelScrollInput$1(e) {
|
|
16671
|
+
const deltaY = Number(e.deltaY ?? 0);
|
|
16672
|
+
const deltaMode = typeof e.deltaMode === "number" ? e.deltaMode : void 0;
|
|
16673
|
+
if (Number.isInteger(deltaY) && deltaY !== 0 && Math.abs(deltaY) >= 100 && Math.abs(deltaY) % 100 === 0 && (deltaMode == null || deltaMode === 0)) return {
|
|
16674
|
+
deltaY: deltaY / 100,
|
|
16675
|
+
mode: "line"
|
|
16676
|
+
};
|
|
16677
|
+
if (deltaMode === 1) return {
|
|
16678
|
+
deltaY,
|
|
16679
|
+
mode: "line"
|
|
16680
|
+
};
|
|
16681
|
+
if (deltaMode === 0) return {
|
|
16682
|
+
deltaY,
|
|
16683
|
+
mode: "pixel"
|
|
16684
|
+
};
|
|
16685
|
+
return {
|
|
16686
|
+
deltaY,
|
|
16687
|
+
mode: "auto"
|
|
16688
|
+
};
|
|
16689
|
+
}
|
|
14963
16690
|
const TList = defineComponent({
|
|
14964
16691
|
name: "TList",
|
|
14965
16692
|
props: {
|
|
@@ -15152,11 +16879,12 @@ const TList = defineComponent({
|
|
|
15152
16879
|
if (idx >= 0 && idx < props.items.length) commit(idx);
|
|
15153
16880
|
},
|
|
15154
16881
|
wheel: (e) => {
|
|
15155
|
-
const
|
|
16882
|
+
const { deltaY, mode } = getWheelScrollInput$1(e);
|
|
16883
|
+
const delta = deltaY;
|
|
15156
16884
|
if (!delta) return;
|
|
15157
16885
|
const h$1 = Math.max(0, props.h);
|
|
15158
16886
|
const maxTop = Math.max(0, props.items.length - h$1);
|
|
15159
|
-
const { nextTop, dir } = applyWheelScroll(wheelState, delta, scrollTop.value, maxTop);
|
|
16887
|
+
const { nextTop, dir } = applyWheelScroll(wheelState, delta, scrollTop.value, maxTop, Date.now(), mode);
|
|
15160
16888
|
if (!dir || nextTop === scrollTop.value) return;
|
|
15161
16889
|
scrollTop.value = nextTop;
|
|
15162
16890
|
const visibleStart = nextTop;
|
|
@@ -15493,6 +17221,26 @@ const TMultilineModal = defineComponent({
|
|
|
15493
17221
|
function clamp$1(n, min, max) {
|
|
15494
17222
|
return Math.max(min, Math.min(max, n));
|
|
15495
17223
|
}
|
|
17224
|
+
function getWheelScrollInput(e) {
|
|
17225
|
+
const deltaY = Number(e.deltaY ?? 0);
|
|
17226
|
+
const deltaMode = typeof e.deltaMode === "number" ? e.deltaMode : void 0;
|
|
17227
|
+
if (Number.isInteger(deltaY) && deltaY !== 0 && Math.abs(deltaY) >= 100 && Math.abs(deltaY) % 100 === 0 && (deltaMode == null || deltaMode === 0)) return {
|
|
17228
|
+
deltaY: deltaY / 100,
|
|
17229
|
+
mode: "line"
|
|
17230
|
+
};
|
|
17231
|
+
if (deltaMode === 1) return {
|
|
17232
|
+
deltaY,
|
|
17233
|
+
mode: "line"
|
|
17234
|
+
};
|
|
17235
|
+
if (deltaMode === 0) return {
|
|
17236
|
+
deltaY,
|
|
17237
|
+
mode: "pixel"
|
|
17238
|
+
};
|
|
17239
|
+
return {
|
|
17240
|
+
deltaY,
|
|
17241
|
+
mode: "auto"
|
|
17242
|
+
};
|
|
17243
|
+
}
|
|
15496
17244
|
function isCtrlLike(e) {
|
|
15497
17245
|
return Boolean(e.ctrlKey || e.metaKey);
|
|
15498
17246
|
}
|
|
@@ -15910,11 +17658,12 @@ const TPathPicker = defineComponent({
|
|
|
15910
17658
|
await trySelect(s.absPath);
|
|
15911
17659
|
},
|
|
15912
17660
|
wheel: (e) => {
|
|
15913
|
-
const
|
|
17661
|
+
const { deltaY, mode } = getWheelScrollInput(e);
|
|
17662
|
+
const delta = deltaY;
|
|
15914
17663
|
if (!delta) return;
|
|
15915
17664
|
const h$1 = Math.max(0, listH.value);
|
|
15916
17665
|
const maxTop = Math.max(0, suggestions.value.length - h$1);
|
|
15917
|
-
const { nextTop, dir } = applyWheelScroll(wheelState, delta, scrollTop.value, maxTop);
|
|
17666
|
+
const { nextTop, dir } = applyWheelScroll(wheelState, delta, scrollTop.value, maxTop, Date.now(), mode);
|
|
15918
17667
|
if (!dir || nextTop === scrollTop.value) return;
|
|
15919
17668
|
scrollTop.value = nextTop;
|
|
15920
17669
|
const visibleStart = nextTop;
|
|
@@ -16986,4 +18735,4 @@ const TRouterView = defineComponent({
|
|
|
16986
18735
|
});
|
|
16987
18736
|
|
|
16988
18737
|
//#endregion
|
|
16989
|
-
export { ANSI16_COLORS, ANSI256_COLORS, ANSI8_COLORS, SGR_RESET, TAnchor, TBox, TDebugOverlay, TDialog, TERMINAL_RENDER_PLANES, TFlow, TInput, TInputBox, TInputPluginsContextKey, TJsonEditor, TList, TMultilineModal, TPathPicker, TRenderLayer, TRenderPlane, TRouterView, TSelect, TText, TTransition, TView, TerminalProvider, ansiColors, ansiStyles, applyWheelScroll, charCellWidth, clearTextCaches, createCliEventManager, createDefaultTInputHostAdapter, createDomRenderer, createEventManager, createNodeMentionPathProvider, createNodePathPickerProvider, createPromptMentionPlugin, createRuntime, createStdinDriver, createStdoutRenderer, createTInputHostPlugin, createTerminal, createTerminalApp, createTerminalRouter, createTextRestrictionPlugin, createTraceStore, createWheelScrollState, defaultTInputHostPlugin, detectTerminalColorCapability, formatInlineCellLine, getStdoutRendererMetrics, lintJsonText, normalizeNewlines, padEndByCells, parseAnsiSgr, readEventLog, resolveUserPath$1 as resolveUserPath, rgbToAnsi256, sanitizeInlineText, sanitizeTextBlock, sliceByCells, sliceByCellsRange, spaces, suggestPaths, textCellWidth, truecolorBgOpen, truecolorFgOpen, useLayout, useRenderNode, useRoute, useRouter, useTerminal, useTerminalNode, useTerminalRuntime, useVisibility, wrapByCells, writeEventLog, writeSnapshot };
|
|
18738
|
+
export { ANSI16_COLORS, ANSI256_COLORS, ANSI8_COLORS, SGR_RESET, TAnchor, TBox, TDebugOverlay, TDialog, TERMINAL_RENDER_PLANES, TFlow, TInput, TInputBox, TInputPluginsContextKey, TJsonEditor, TList, TMultilineModal, TPathPicker, TRenderLayer, TRenderPlane, TRouterView, TSelect, TText, TTransition, TView, TerminalProvider, ansiColors, ansiStyles, applyWheelScroll, charCellWidth, clearTextCaches, createCliEventManager, createDefaultTInputHostAdapter, createDomRenderer, createEventManager, createNodeMentionPathProvider, createNodePathPickerProvider, createPromptMentionPlugin, createRuntime, createStdinDriver, createStdoutRenderer, createTInputHostPlugin, createTerminal, createTerminalApp, createTerminalRouter, createTextRestrictionPlugin, createTraceStore, createWheelScrollState, defaultTInputHostPlugin, detectTerminalColorCapability, formatInlineCellLine, getCliLatencyProfiler, getStdoutRendererMetrics, lintJsonText, normalizeNewlines, padEndByCells, parseAnsiSgr, readEventLog, resolveUserPath$1 as resolveUserPath, rgbToAnsi256, sanitizeInlineText, sanitizeTextBlock, sliceByCells, sliceByCellsRange, spaces, suggestPaths, textCellWidth, truecolorBgOpen, truecolorFgOpen, useLayout, useRenderNode, useRoute, useRouter, useTerminal, useTerminalNode, useTerminalRuntime, useVisibility, wrapByCells, writeEventLog, writeSnapshot };
|