@simon_he/vue-tui 1.0.0 → 1.0.2
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/README.md +55 -20
- package/dist/{TSelect-BwJJbuTt.js → TSelect-DR0FomSu.js} +90 -41
- package/dist/{TTree-DK_DQBYm.js → TTree-kzhlB5P0.js} +110 -28
- package/dist/agent.cjs +673 -165
- package/dist/agent.js +3 -3
- package/dist/cli.cjs +1081 -166
- package/dist/cli.d.cts +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +846 -164
- package/dist/core/buffer/buffer.d.ts +2 -2
- package/dist/core/types.d.ts +0 -4
- package/dist/core.cjs +20 -5
- package/dist/core.js +1 -1
- package/dist/{create-terminal-C2oiWFJU.js → create-terminal-DBFNYr8f.js} +15 -6
- package/dist/{dom-renderer-BqGijQID.js → dom-renderer-BniJSQyX.js} +1 -1
- package/dist/experimental.cjs +583 -121
- package/dist/experimental.js +1 -1
- package/dist/index.cjs +235 -81
- package/dist/index.js +4 -4
- package/dist/renderer/cli/index.d.ts +1 -1
- package/dist/renderer/cli/stdout-renderer.d.ts +50 -7
- package/dist/renderer-dom.js +2 -2
- package/dist/{tlog-theme-qPBt5rge.js → tlog-theme-CvLFNMwk.js} +539 -100
- package/dist/vue/components/TVirtualRows.d.ts +18 -0
- package/dist/vue/transcript/types.d.ts +4 -0
- package/dist/vue.cjs +235 -81
- package/dist/vue.js +4 -4
- package/package.json +30 -11
|
@@ -1008,6 +1008,15 @@ function normalizeInt$9(value) {
|
|
|
1008
1008
|
const n = Math.floor(Number(value));
|
|
1009
1009
|
return Number.isFinite(n) ? n : 0;
|
|
1010
1010
|
}
|
|
1011
|
+
function normalizeChangedRange(range, count) {
|
|
1012
|
+
if (!range) return null;
|
|
1013
|
+
const start = clamp$10(normalizeInt$9(range.start), 0, count);
|
|
1014
|
+
const end = clamp$10(normalizeInt$9(range.end), start, count);
|
|
1015
|
+
return {
|
|
1016
|
+
start,
|
|
1017
|
+
end
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1011
1020
|
function getWheelScrollInput$1(e) {
|
|
1012
1021
|
const deltaY = Number(e.deltaY ?? 0);
|
|
1013
1022
|
const deltaMode = typeof e.deltaMode === "number" ? e.deltaMode : void 0;
|
|
@@ -1066,6 +1075,10 @@ const TVirtualRows = defineComponent({
|
|
|
1066
1075
|
type: Number,
|
|
1067
1076
|
required: true
|
|
1068
1077
|
},
|
|
1078
|
+
itemChangedRange: {
|
|
1079
|
+
type: Function,
|
|
1080
|
+
default: void 0
|
|
1081
|
+
},
|
|
1069
1082
|
getItem: {
|
|
1070
1083
|
type: Function,
|
|
1071
1084
|
required: true
|
|
@@ -1269,6 +1282,20 @@ const TVirtualRows = defineComponent({
|
|
|
1269
1282
|
reason: "scroll"
|
|
1270
1283
|
});
|
|
1271
1284
|
}
|
|
1285
|
+
function markScrollDamage(prevTop, nextTop, strategy = "auto") {
|
|
1286
|
+
const r = normalizedRect();
|
|
1287
|
+
const h$1 = r.h;
|
|
1288
|
+
const delta = nextTop - prevTop;
|
|
1289
|
+
if (h$1 <= 0 || !delta) return;
|
|
1290
|
+
const size = terminal.size();
|
|
1291
|
+
const ownsFullRows = Math.floor(r.x) === 0 && Math.floor(r.w) >= size.cols;
|
|
1292
|
+
const withinTerminalRows = r.y >= 0 && r.y + h$1 <= size.rows;
|
|
1293
|
+
const canUseScrollPlane = strategy === "auto" && props.rowScrollMode === "unsafe-full-row" && rendererCapabilities.value.scrollOperations && ownsFullRows && withinTerminalRows && !isClipped() && Math.abs(delta) < h$1 && !dirtyRowsHint?.length;
|
|
1294
|
+
if (canUseScrollPlane) {
|
|
1295
|
+
render.unsafeScrollPlaneRows(plane.value, r.y, r.y + h$1, delta);
|
|
1296
|
+
markRowsDirty(exposedRowsForDelta$1(r.y, h$1, delta));
|
|
1297
|
+
} else markViewportDirty();
|
|
1298
|
+
}
|
|
1272
1299
|
function applyScrollTop(nextTop, options) {
|
|
1273
1300
|
const r = normalizedRect();
|
|
1274
1301
|
const h$1 = r.h;
|
|
@@ -1284,14 +1311,7 @@ const TVirtualRows = defineComponent({
|
|
|
1284
1311
|
}
|
|
1285
1312
|
setCurrentScrollTop(clampedTop);
|
|
1286
1313
|
if (options?.emitUpdate !== false) emit("update:scrollTop", clampedTop);
|
|
1287
|
-
|
|
1288
|
-
const ownsFullRows = Math.floor(r.x) === 0 && Math.floor(r.w) >= size.cols;
|
|
1289
|
-
const withinTerminalRows = r.y >= 0 && r.y + h$1 <= size.rows;
|
|
1290
|
-
const canUseScrollPlane = (options?.strategy ?? "auto") === "auto" && props.rowScrollMode === "unsafe-full-row" && rendererCapabilities.value.scrollOperations && ownsFullRows && withinTerminalRows && !isClipped() && Math.abs(delta) < h$1 && !dirtyRowsHint?.length;
|
|
1291
|
-
if (canUseScrollPlane) {
|
|
1292
|
-
render.unsafeScrollPlaneRows(plane.value, r.y, r.y + h$1, delta);
|
|
1293
|
-
markRowsDirty(exposedRowsForDelta$1(r.y, h$1, delta));
|
|
1294
|
-
} else markViewportDirty();
|
|
1314
|
+
markScrollDamage(prevTop, clampedTop, options?.strategy);
|
|
1295
1315
|
if (options?.emitScroll) emitScroll(clampedTop);
|
|
1296
1316
|
return true;
|
|
1297
1317
|
}
|
|
@@ -1359,7 +1379,10 @@ const TVirtualRows = defineComponent({
|
|
|
1359
1379
|
invalidateSelf("normal");
|
|
1360
1380
|
}
|
|
1361
1381
|
function invalidateRange(start, end) {
|
|
1362
|
-
|
|
1382
|
+
markItemRangeDirty(start, end);
|
|
1383
|
+
}
|
|
1384
|
+
function markItemRangeDirty(start, end) {
|
|
1385
|
+
if (!hasPaintableViewport()) return false;
|
|
1363
1386
|
const r = normalizedRect();
|
|
1364
1387
|
const { y: clipY } = clipOffsets();
|
|
1365
1388
|
const top = currentScrollTop() + clipY;
|
|
@@ -1370,9 +1393,10 @@ const TVirtualRows = defineComponent({
|
|
|
1370
1393
|
const y = r.y + (index - top);
|
|
1371
1394
|
if (y >= r.y && y < r.y + r.h) rows.push(y);
|
|
1372
1395
|
}
|
|
1373
|
-
if (!rows.length) return;
|
|
1396
|
+
if (!rows.length) return true;
|
|
1374
1397
|
markRowsDirty(rows);
|
|
1375
1398
|
invalidateSelf("normal");
|
|
1399
|
+
return true;
|
|
1376
1400
|
}
|
|
1377
1401
|
function invalidateIndex(index) {
|
|
1378
1402
|
const n = normalizeInt$9(index);
|
|
@@ -1581,8 +1605,9 @@ const TVirtualRows = defineComponent({
|
|
|
1581
1605
|
return;
|
|
1582
1606
|
}
|
|
1583
1607
|
cancelWheelScrollFrame();
|
|
1608
|
+
const prevTop = controlledScrollTop.value;
|
|
1584
1609
|
controlledScrollTop.value = nextTop;
|
|
1585
|
-
|
|
1610
|
+
markScrollDamage(prevTop, nextTop);
|
|
1586
1611
|
selection.refresh(pendingSelectionScrollFocusRemap ? { remapFocus: true } : void 0);
|
|
1587
1612
|
pendingSelectionScrollFocusRemap = false;
|
|
1588
1613
|
invalidateSelf("high");
|
|
@@ -1602,7 +1627,7 @@ const TVirtualRows = defineComponent({
|
|
|
1602
1627
|
() => absRect.value.y,
|
|
1603
1628
|
() => absRect.value.w,
|
|
1604
1629
|
() => absRect.value.h
|
|
1605
|
-
], () => {
|
|
1630
|
+
], (next, prev) => {
|
|
1606
1631
|
resetWheelScrollState(wheelState);
|
|
1607
1632
|
const nextTop = clampScrollTop(currentScrollTop());
|
|
1608
1633
|
if (isScrollControlled()) {
|
|
@@ -1611,6 +1636,14 @@ const TVirtualRows = defineComponent({
|
|
|
1611
1636
|
emitScroll(nextTop);
|
|
1612
1637
|
}
|
|
1613
1638
|
} else setCurrentScrollTop(nextTop);
|
|
1639
|
+
const onlyItemVersionChanged = Boolean(prev && next[0] === prev[0] && next[1] !== prev[1] && next[2] === prev[2] && next[3] === prev[3] && next[4] === prev[4] && next[5] === prev[5] && next[6] === prev[6] && next[7] === prev[7] && next[8] === prev[8] && next[9] === prev[9]);
|
|
1640
|
+
if (onlyItemVersionChanged) {
|
|
1641
|
+
const changedRange = normalizeChangedRange(props.itemChangedRange?.(), itemCount.value);
|
|
1642
|
+
if (changedRange) {
|
|
1643
|
+
markItemRangeDirty(changedRange.start, changedRange.end);
|
|
1644
|
+
return;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1614
1647
|
markViewportDirty();
|
|
1615
1648
|
invalidateSelf("normal");
|
|
1616
1649
|
}, { immediate: true });
|
|
@@ -1632,7 +1665,6 @@ const TVirtualRows = defineComponent({
|
|
|
1632
1665
|
absRect.value,
|
|
1633
1666
|
fullRect.value,
|
|
1634
1667
|
itemCount.value,
|
|
1635
|
-
props.itemVersion,
|
|
1636
1668
|
props.getItem,
|
|
1637
1669
|
props.paintItem,
|
|
1638
1670
|
props.selectionSpanText,
|
|
@@ -1717,8 +1749,11 @@ const EMPTY_LAYOUT = Object.freeze({
|
|
|
1717
1749
|
visualRows: Object.freeze([]),
|
|
1718
1750
|
rowStarts: new Map(),
|
|
1719
1751
|
rowEnds: new Map(),
|
|
1720
|
-
regions: Object.freeze([])
|
|
1752
|
+
regions: Object.freeze([]),
|
|
1753
|
+
fixedRows: false,
|
|
1754
|
+
rowCount: 0
|
|
1721
1755
|
});
|
|
1756
|
+
const MAX_KEYED_ROW_LAYOUT_CACHE_ENTRIES = 2048;
|
|
1722
1757
|
function clamp$9(n, min, max) {
|
|
1723
1758
|
return Math.max(min, Math.min(max, n));
|
|
1724
1759
|
}
|
|
@@ -1726,6 +1761,15 @@ function normalizeInt$8(value) {
|
|
|
1726
1761
|
const n = Math.floor(Number(value));
|
|
1727
1762
|
return Number.isFinite(n) ? n : 0;
|
|
1728
1763
|
}
|
|
1764
|
+
function normalizedChangedRange(range, count) {
|
|
1765
|
+
if (!range) return null;
|
|
1766
|
+
const start = clamp$9(normalizeInt$8(range.start), 0, count);
|
|
1767
|
+
const end = clamp$9(normalizeInt$8(range.end), start, count);
|
|
1768
|
+
return {
|
|
1769
|
+
start,
|
|
1770
|
+
end
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1729
1773
|
function sourceSegmentsForRegion(row) {
|
|
1730
1774
|
if (row.kind === "message") return row.segments;
|
|
1731
1775
|
if (row.kind === "approval") {
|
|
@@ -1756,8 +1800,26 @@ function rowHasRegionId(row, rowKey, id) {
|
|
|
1756
1800
|
}
|
|
1757
1801
|
return false;
|
|
1758
1802
|
}
|
|
1759
|
-
function
|
|
1760
|
-
|
|
1803
|
+
function cachedLayoutHasRegionId(entry, id) {
|
|
1804
|
+
if (!entry || !id) return false;
|
|
1805
|
+
for (const visualRow of entry.visualRows) if (visualRow.hitRegions.some((region) => region.id === id)) return true;
|
|
1806
|
+
return false;
|
|
1807
|
+
}
|
|
1808
|
+
function rowLayoutIdentityKey(rowKey, rowVersion) {
|
|
1809
|
+
return JSON.stringify([rowKey, rowVersion]);
|
|
1810
|
+
}
|
|
1811
|
+
function reindexVisualRows(rows, rowIndex) {
|
|
1812
|
+
return rows.map((visualRow) => ({
|
|
1813
|
+
...visualRow,
|
|
1814
|
+
rowIndex,
|
|
1815
|
+
hitRegions: visualRow.hitRegions.map((region) => ({
|
|
1816
|
+
...region,
|
|
1817
|
+
rowIndex
|
|
1818
|
+
}))
|
|
1819
|
+
}));
|
|
1820
|
+
}
|
|
1821
|
+
function sameCachedLayout(entry, next, matchRowIndex = true) {
|
|
1822
|
+
return Boolean(entry) && (next.usesSourceRowVersion || entry.version === next.version) && entry.rowVersion === next.rowVersion && entry.usesSourceRowVersion === next.usesSourceRowVersion && (next.usesSourceRowVersion || entry.row === next.row) && (!matchRowIndex || entry.rowIndex === next.rowIndex) && entry.rowKey === next.rowKey && entry.width === next.width && entry.wrap === next.wrap && entry.baseStyle === next.baseStyle && entry.hoverStyle === next.hoverStyle && entry.focusStyle === next.focusStyle && entry.hoverRegionId === next.hoverRegionId && entry.focusedRegionId === next.focusedRegionId;
|
|
1761
1823
|
}
|
|
1762
1824
|
const TTranscriptView = defineComponent({
|
|
1763
1825
|
name: "TTranscriptView",
|
|
@@ -1861,6 +1923,10 @@ const TTranscriptView = defineComponent({
|
|
|
1861
1923
|
const hoveredRegion = ref(null);
|
|
1862
1924
|
const focusedRegion = ref(null);
|
|
1863
1925
|
const rowLayoutCache = new Map();
|
|
1926
|
+
const keyedRowLayoutCache = new Map();
|
|
1927
|
+
let previousWrappedLayout = null;
|
|
1928
|
+
let previousWrappedDeps = null;
|
|
1929
|
+
let canUseWrappedChangedRangeRepaint = false;
|
|
1864
1930
|
let warnedLargeFlattenedRows = false;
|
|
1865
1931
|
function isScrollControlled() {
|
|
1866
1932
|
return Object.prototype.hasOwnProperty.call(instance?.vnode.props ?? {}, "scrollTop");
|
|
@@ -1868,14 +1934,176 @@ const TTranscriptView = defineComponent({
|
|
|
1868
1934
|
function currentScrollTop() {
|
|
1869
1935
|
return normalizeInt$8(isScrollControlled() ? props.scrollTop : innerScrollTop.value);
|
|
1870
1936
|
}
|
|
1937
|
+
function currentScrollTopForRowCount(count) {
|
|
1938
|
+
const viewportRows = Math.max(0, normalizeInt$8(props.h));
|
|
1939
|
+
const maxTop = Math.max(0, count - viewportRows);
|
|
1940
|
+
return clamp$9(currentScrollTop(), 0, maxTop);
|
|
1941
|
+
}
|
|
1942
|
+
function rememberKeyedRowLayout(entry) {
|
|
1943
|
+
if (!entry.usesSourceRowVersion) return;
|
|
1944
|
+
keyedRowLayoutCache.set(rowLayoutIdentityKey(entry.rowKey, entry.rowVersion), entry);
|
|
1945
|
+
if (keyedRowLayoutCache.size <= MAX_KEYED_ROW_LAYOUT_CACHE_ENTRIES) return;
|
|
1946
|
+
const first = keyedRowLayoutCache.keys().next().value;
|
|
1947
|
+
if (first != null) keyedRowLayoutCache.delete(first);
|
|
1948
|
+
}
|
|
1949
|
+
function layoutSourceRow(rowIndex, options) {
|
|
1950
|
+
const sourceRowVersion = props.source.getRowVersion?.(rowIndex);
|
|
1951
|
+
let cached = rowLayoutCache.get(rowIndex);
|
|
1952
|
+
const usesSourceRowVersion = sourceRowVersion != null;
|
|
1953
|
+
let row = cached?.row;
|
|
1954
|
+
let rowKey = cached?.rowKey;
|
|
1955
|
+
let canUseCachedRow = false;
|
|
1956
|
+
if (usesSourceRowVersion && cached?.usesSourceRowVersion && cached.rowVersion === sourceRowVersion) if (props.source.getRowKey) {
|
|
1957
|
+
rowKey = props.source.getRowKey(rowIndex);
|
|
1958
|
+
canUseCachedRow = rowKey === cached.rowKey;
|
|
1959
|
+
} else {
|
|
1960
|
+
rowKey = cached.rowKey;
|
|
1961
|
+
canUseCachedRow = true;
|
|
1962
|
+
}
|
|
1963
|
+
if (!canUseCachedRow && usesSourceRowVersion && props.source.getRowKey) {
|
|
1964
|
+
rowKey = props.source.getRowKey(rowIndex);
|
|
1965
|
+
cached = keyedRowLayoutCache.get(rowLayoutIdentityKey(rowKey, sourceRowVersion));
|
|
1966
|
+
if (cached) {
|
|
1967
|
+
row = cached.row;
|
|
1968
|
+
canUseCachedRow = true;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
if (!canUseCachedRow || row == null || rowKey == null) {
|
|
1972
|
+
row = props.source.getRow(rowIndex);
|
|
1973
|
+
rowKey = props.source.getRowKey?.(rowIndex) ?? row.key;
|
|
1974
|
+
canUseCachedRow = false;
|
|
1975
|
+
}
|
|
1976
|
+
const nextHoverRegionId = canUseCachedRow ? cachedLayoutHasRegionId(cached, options.hoverRegionId) ? options.hoverRegionId : null : rowHasRegionId(row, rowKey, options.hoverRegionId) ? options.hoverRegionId : null;
|
|
1977
|
+
const nextFocusedRegionId = canUseCachedRow ? cachedLayoutHasRegionId(cached, options.focusedRegionId) ? options.focusedRegionId : null : rowHasRegionId(row, rowKey, options.focusedRegionId) ? options.focusedRegionId : null;
|
|
1978
|
+
const cacheKey = {
|
|
1979
|
+
version: props.version,
|
|
1980
|
+
rowVersion: sourceRowVersion ?? props.version,
|
|
1981
|
+
usesSourceRowVersion,
|
|
1982
|
+
row,
|
|
1983
|
+
rowIndex,
|
|
1984
|
+
rowKey,
|
|
1985
|
+
width: options.width,
|
|
1986
|
+
wrap: props.wrap,
|
|
1987
|
+
baseStyle: options.baseStyle,
|
|
1988
|
+
hoverStyle: props.hoverStyle,
|
|
1989
|
+
focusStyle: props.focusStyle,
|
|
1990
|
+
hoverRegionId: nextHoverRegionId,
|
|
1991
|
+
focusedRegionId: nextFocusedRegionId
|
|
1992
|
+
};
|
|
1993
|
+
const cacheMatches = sameCachedLayout(cached, cacheKey);
|
|
1994
|
+
const reindexableCacheMatches = !cacheMatches && canUseCachedRow && sameCachedLayout(cached, cacheKey, false);
|
|
1995
|
+
const rows = cacheMatches ? cached.visualRows : reindexableCacheMatches ? reindexVisualRows(cached.visualRows, rowIndex) : layoutTranscriptRow({
|
|
1996
|
+
row,
|
|
1997
|
+
rowIndex,
|
|
1998
|
+
rowKey,
|
|
1999
|
+
width: options.width,
|
|
2000
|
+
baseStyle: options.baseStyle,
|
|
2001
|
+
hoverRegionId: nextHoverRegionId,
|
|
2002
|
+
focusedRegionId: nextFocusedRegionId,
|
|
2003
|
+
hoverStyle: props.hoverStyle,
|
|
2004
|
+
focusStyle: props.focusStyle,
|
|
2005
|
+
wrap: props.wrap
|
|
2006
|
+
});
|
|
2007
|
+
if (rows !== cached?.visualRows) {
|
|
2008
|
+
const entry = {
|
|
2009
|
+
...cacheKey,
|
|
2010
|
+
visualRows: rows
|
|
2011
|
+
};
|
|
2012
|
+
rowLayoutCache.set(rowIndex, entry);
|
|
2013
|
+
rememberKeyedRowLayout(entry);
|
|
2014
|
+
}
|
|
2015
|
+
return {
|
|
2016
|
+
rows,
|
|
2017
|
+
cacheHit: cacheMatches || reindexableCacheMatches
|
|
2018
|
+
};
|
|
2019
|
+
}
|
|
2020
|
+
function pruneRowLayoutCache(count) {
|
|
2021
|
+
for (const rowIndex of rowLayoutCache.keys()) if (rowIndex >= count) rowLayoutCache.delete(rowIndex);
|
|
2022
|
+
}
|
|
2023
|
+
function sameWrappedDeps(a, b) {
|
|
2024
|
+
return Boolean(a) && a.width === b.width && a.baseStyle === b.baseStyle && a.hoverStyle === b.hoverStyle && a.focusStyle === b.focusStyle && a.hoverRegionId === b.hoverRegionId && a.focusedRegionId === b.focusedRegionId;
|
|
2025
|
+
}
|
|
2026
|
+
function visibleRegionsForVisualRows(visualRows) {
|
|
2027
|
+
const top = clamp$9(currentScrollTop(), 0, visualRows.length);
|
|
2028
|
+
const bottom = Math.min(visualRows.length, top + Math.max(0, normalizeInt$8(props.h)));
|
|
2029
|
+
const regions = [];
|
|
2030
|
+
for (let index = top; index < bottom; index++) regions.push(...visualRows[index]?.hitRegions ?? []);
|
|
2031
|
+
return regions;
|
|
2032
|
+
}
|
|
2033
|
+
function tryUpdateWrappedLayoutFromChangedRange(count, changedRange, deps) {
|
|
2034
|
+
const previous = previousWrappedLayout;
|
|
2035
|
+
if (!previous || previous.fixedRows || previous.rowCount !== count) return null;
|
|
2036
|
+
if (!changedRange || !sameWrappedDeps(previousWrappedDeps, deps)) return null;
|
|
2037
|
+
const changedCount = changedRange.end - changedRange.start;
|
|
2038
|
+
if (changedCount <= 0) {
|
|
2039
|
+
canUseWrappedChangedRangeRepaint = true;
|
|
2040
|
+
return {
|
|
2041
|
+
state: {
|
|
2042
|
+
...previous,
|
|
2043
|
+
regions: visibleRegionsForVisualRows(previous.visualRows)
|
|
2044
|
+
},
|
|
2045
|
+
cacheHit: count,
|
|
2046
|
+
cacheMiss: 0
|
|
2047
|
+
};
|
|
2048
|
+
}
|
|
2049
|
+
const oldVisualStart = previous.rowStarts.get(changedRange.start);
|
|
2050
|
+
const oldVisualEnd = previous.rowEnds.get(changedRange.end - 1);
|
|
2051
|
+
if (oldVisualStart == null || oldVisualEnd == null) return null;
|
|
2052
|
+
const nextRows = [];
|
|
2053
|
+
const changedRowHeights = [];
|
|
2054
|
+
let cacheHit = count - changedCount;
|
|
2055
|
+
let cacheMiss = 0;
|
|
2056
|
+
for (let rowIndex = changedRange.start; rowIndex < changedRange.end; rowIndex++) {
|
|
2057
|
+
const result = layoutSourceRow(rowIndex, {
|
|
2058
|
+
width: deps.width,
|
|
2059
|
+
baseStyle: deps.baseStyle,
|
|
2060
|
+
hoverRegionId: deps.hoverRegionId,
|
|
2061
|
+
focusedRegionId: deps.focusedRegionId
|
|
2062
|
+
});
|
|
2063
|
+
if (result.cacheHit) cacheHit++;
|
|
2064
|
+
else cacheMiss++;
|
|
2065
|
+
changedRowHeights.push(result.rows.length);
|
|
2066
|
+
nextRows.push(...result.rows);
|
|
2067
|
+
}
|
|
2068
|
+
if (nextRows.length !== oldVisualEnd - oldVisualStart) return null;
|
|
2069
|
+
canUseWrappedChangedRangeRepaint = true;
|
|
2070
|
+
const visualRows = previous.visualRows;
|
|
2071
|
+
for (let index = 0; index < nextRows.length; index++) visualRows[oldVisualStart + index] = nextRows[index];
|
|
2072
|
+
const rowStarts = previous.rowStarts;
|
|
2073
|
+
const rowEnds = previous.rowEnds;
|
|
2074
|
+
let visualCursor = oldVisualStart;
|
|
2075
|
+
for (let rowIndex = changedRange.start, offset = 0; rowIndex < changedRange.end; rowIndex++, offset++) {
|
|
2076
|
+
rowStarts.set(rowIndex, visualCursor);
|
|
2077
|
+
visualCursor += changedRowHeights[offset] ?? 0;
|
|
2078
|
+
rowEnds.set(rowIndex, visualCursor);
|
|
2079
|
+
}
|
|
2080
|
+
const state = {
|
|
2081
|
+
visualRows,
|
|
2082
|
+
rowStarts,
|
|
2083
|
+
rowEnds,
|
|
2084
|
+
regions: visibleRegionsForVisualRows(visualRows),
|
|
2085
|
+
fixedRows: false,
|
|
2086
|
+
rowCount: count
|
|
2087
|
+
};
|
|
2088
|
+
previousWrappedLayout = state;
|
|
2089
|
+
return {
|
|
2090
|
+
state,
|
|
2091
|
+
cacheHit,
|
|
2092
|
+
cacheMiss
|
|
2093
|
+
};
|
|
2094
|
+
}
|
|
1871
2095
|
const layoutState = computed(() => {
|
|
1872
2096
|
props.version;
|
|
2097
|
+
canUseWrappedChangedRangeRepaint = false;
|
|
1873
2098
|
const perfEnabled = observability.framePerf.enabled.value;
|
|
1874
2099
|
const perfStartedAt = perfEnabled ? framePerfNow() : 0;
|
|
1875
2100
|
const width = Math.max(1, Math.floor(props.w));
|
|
1876
2101
|
const count = Math.max(0, normalizeInt$8(props.source.rowCount()));
|
|
1877
2102
|
if (!count) {
|
|
1878
2103
|
rowLayoutCache.clear();
|
|
2104
|
+
keyedRowLayoutCache.clear();
|
|
2105
|
+
previousWrappedLayout = null;
|
|
2106
|
+
previousWrappedDeps = null;
|
|
1879
2107
|
if (perfEnabled) observability.framePerf.recordComponent({
|
|
1880
2108
|
name: "TTranscriptView",
|
|
1881
2109
|
id: instance?.uid == null ? void 0 : String(instance.uid),
|
|
@@ -1890,7 +2118,9 @@ const TTranscriptView = defineComponent({
|
|
|
1890
2118
|
});
|
|
1891
2119
|
return EMPTY_LAYOUT;
|
|
1892
2120
|
}
|
|
2121
|
+
const fixedRows = props.wrap === false;
|
|
1893
2122
|
const visualRows = [];
|
|
2123
|
+
if (fixedRows) visualRows.length = count;
|
|
1894
2124
|
const rowStarts = new Map();
|
|
1895
2125
|
const rowEnds = new Map();
|
|
1896
2126
|
const regions = [];
|
|
@@ -1899,56 +2129,71 @@ const TTranscriptView = defineComponent({
|
|
|
1899
2129
|
const focusedRegionId = focusedRegion.value?.id ?? null;
|
|
1900
2130
|
let cacheHit = 0;
|
|
1901
2131
|
let cacheMiss = 0;
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
row
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
2132
|
+
const sourceChangedRange = normalizedChangedRange(props.source.getChangedRange?.(), count);
|
|
2133
|
+
const wrappedDeps = {
|
|
2134
|
+
width,
|
|
2135
|
+
baseStyle,
|
|
2136
|
+
hoverStyle: props.hoverStyle,
|
|
2137
|
+
focusStyle: props.focusStyle,
|
|
2138
|
+
hoverRegionId,
|
|
2139
|
+
focusedRegionId
|
|
2140
|
+
};
|
|
2141
|
+
if (fixedRows) {
|
|
2142
|
+
previousWrappedLayout = null;
|
|
2143
|
+
previousWrappedDeps = null;
|
|
2144
|
+
const top = currentScrollTopForRowCount(count);
|
|
2145
|
+
const bottom = Math.min(count, top + Math.max(0, normalizeInt$8(props.h)));
|
|
2146
|
+
for (let rowIndex = top; rowIndex < bottom; rowIndex++) {
|
|
2147
|
+
rowStarts.set(rowIndex, rowIndex);
|
|
2148
|
+
rowEnds.set(rowIndex, rowIndex + 1);
|
|
2149
|
+
const result = layoutSourceRow(rowIndex, {
|
|
2150
|
+
width,
|
|
2151
|
+
baseStyle,
|
|
2152
|
+
hoverRegionId,
|
|
2153
|
+
focusedRegionId
|
|
2154
|
+
});
|
|
2155
|
+
if (result.cacheHit) cacheHit++;
|
|
2156
|
+
else cacheMiss++;
|
|
2157
|
+
const row = result.rows[0];
|
|
2158
|
+
visualRows[rowIndex] = row;
|
|
2159
|
+
regions.push(...row.hitRegions);
|
|
2160
|
+
}
|
|
2161
|
+
} else {
|
|
2162
|
+
const incremental = tryUpdateWrappedLayoutFromChangedRange(count, sourceChangedRange, wrappedDeps);
|
|
2163
|
+
if (incremental) {
|
|
2164
|
+
if (perfEnabled) observability.framePerf.recordComponent({
|
|
2165
|
+
name: "TTranscriptView",
|
|
2166
|
+
id: instance?.uid == null ? void 0 : String(instance.uid),
|
|
2167
|
+
phase: "layout",
|
|
2168
|
+
durationMs: framePerfNow() - perfStartedAt,
|
|
2169
|
+
itemCount: count,
|
|
2170
|
+
renderedCount: incremental.state.visualRows.length,
|
|
2171
|
+
cacheHit: incremental.cacheHit,
|
|
2172
|
+
cacheMiss: incremental.cacheMiss,
|
|
2173
|
+
width,
|
|
2174
|
+
version: props.version
|
|
2175
|
+
});
|
|
2176
|
+
return incremental.state;
|
|
2177
|
+
}
|
|
2178
|
+
for (let rowIndex = 0; rowIndex < count; rowIndex++) {
|
|
2179
|
+
rowStarts.set(rowIndex, visualRows.length);
|
|
2180
|
+
const result = layoutSourceRow(rowIndex, {
|
|
2181
|
+
width,
|
|
2182
|
+
baseStyle,
|
|
2183
|
+
hoverRegionId,
|
|
2184
|
+
focusedRegionId
|
|
2185
|
+
});
|
|
2186
|
+
if (result.cacheHit) cacheHit++;
|
|
2187
|
+
else cacheMiss++;
|
|
2188
|
+
for (const visualRow of result.rows) {
|
|
2189
|
+
visualRows.push(visualRow);
|
|
2190
|
+
regions.push(...visualRow.hitRegions);
|
|
2191
|
+
}
|
|
2192
|
+
rowEnds.set(rowIndex, visualRows.length);
|
|
1947
2193
|
}
|
|
1948
|
-
rowEnds.set(rowIndex, visualRows.length);
|
|
1949
2194
|
}
|
|
1950
|
-
|
|
1951
|
-
if (!warnedLargeFlattenedRows && globalThis.__VT_DEBUG_PERF__ && visualRows.length > 5e3) {
|
|
2195
|
+
pruneRowLayoutCache(count);
|
|
2196
|
+
if (!warnedLargeFlattenedRows && !fixedRows && globalThis.__VT_DEBUG_PERF__ && visualRows.length > 5e3) {
|
|
1952
2197
|
warnedLargeFlattenedRows = true;
|
|
1953
2198
|
console.warn("[vue-tui] TTranscriptView flattens all transcript rows; use TLogView or windowed source for large retained output.");
|
|
1954
2199
|
}
|
|
@@ -1958,18 +2203,28 @@ const TTranscriptView = defineComponent({
|
|
|
1958
2203
|
phase: "layout",
|
|
1959
2204
|
durationMs: framePerfNow() - perfStartedAt,
|
|
1960
2205
|
itemCount: count,
|
|
1961
|
-
renderedCount: visualRows.length,
|
|
2206
|
+
renderedCount: fixedRows ? cacheHit + cacheMiss : visualRows.length,
|
|
1962
2207
|
cacheHit,
|
|
1963
2208
|
cacheMiss,
|
|
1964
2209
|
width,
|
|
1965
2210
|
version: props.version
|
|
1966
2211
|
});
|
|
1967
|
-
|
|
2212
|
+
const state = {
|
|
1968
2213
|
visualRows,
|
|
1969
2214
|
rowStarts,
|
|
1970
2215
|
rowEnds,
|
|
1971
|
-
regions
|
|
2216
|
+
regions,
|
|
2217
|
+
fixedRows,
|
|
2218
|
+
rowCount: count
|
|
1972
2219
|
};
|
|
2220
|
+
if (fixedRows) {
|
|
2221
|
+
previousWrappedLayout = null;
|
|
2222
|
+
previousWrappedDeps = null;
|
|
2223
|
+
} else {
|
|
2224
|
+
previousWrappedLayout = state;
|
|
2225
|
+
previousWrappedDeps = wrappedDeps;
|
|
2226
|
+
}
|
|
2227
|
+
return state;
|
|
1973
2228
|
});
|
|
1974
2229
|
const maxScrollTop = computed(() => Math.max(0, layoutState.value.visualRows.length - Math.max(0, normalizeInt$8(props.h))));
|
|
1975
2230
|
function setScrollTop(top) {
|
|
@@ -2007,7 +2262,12 @@ const TTranscriptView = defineComponent({
|
|
|
2007
2262
|
if (!region) return [];
|
|
2008
2263
|
const rows = layoutState.value.visualRows;
|
|
2009
2264
|
const indexes = [];
|
|
2010
|
-
|
|
2265
|
+
const top = layoutState.value.fixedRows ? clamp$9(currentScrollTop(), 0, rows.length) : 0;
|
|
2266
|
+
const bottom = layoutState.value.fixedRows ? Math.min(rows.length, top + Math.max(0, normalizeInt$8(props.h))) : rows.length;
|
|
2267
|
+
for (let i = top; i < bottom; i++) {
|
|
2268
|
+
const row = getVisualRow(i);
|
|
2269
|
+
if (row?.hitRegions.some((candidate) => candidate.id === region.id)) indexes.push(i);
|
|
2270
|
+
}
|
|
2011
2271
|
return indexes;
|
|
2012
2272
|
}
|
|
2013
2273
|
function invalidateRegion(region) {
|
|
@@ -2034,7 +2294,7 @@ const TTranscriptView = defineComponent({
|
|
|
2034
2294
|
const bottom = Math.min(rows.length, top + Math.max(0, normalizeInt$8(props.h)));
|
|
2035
2295
|
const seen = new Set();
|
|
2036
2296
|
const regions = [];
|
|
2037
|
-
for (let i = top; i < bottom; i++) for (const region of
|
|
2297
|
+
for (let i = top; i < bottom; i++) for (const region of getVisualRow(i)?.hitRegions ?? []) {
|
|
2038
2298
|
if (seen.has(region.id)) continue;
|
|
2039
2299
|
seen.add(region.id);
|
|
2040
2300
|
regions.push(region);
|
|
@@ -2045,7 +2305,7 @@ const TTranscriptView = defineComponent({
|
|
|
2045
2305
|
const rows = layoutState.value.visualRows;
|
|
2046
2306
|
const top = clamp$9(currentScrollTop(), 0, rows.length);
|
|
2047
2307
|
const bottom = Math.min(rows.length, top + Math.max(0, normalizeInt$8(props.h)));
|
|
2048
|
-
for (let i = top; i < bottom; i++) if (
|
|
2308
|
+
for (let i = top; i < bottom; i++) if (getVisualRow(i)?.hitRegions.some((region) => region.id === id)) return true;
|
|
2049
2309
|
return false;
|
|
2050
2310
|
}
|
|
2051
2311
|
function reconcileActiveRegions() {
|
|
@@ -2102,8 +2362,8 @@ const TTranscriptView = defineComponent({
|
|
|
2102
2362
|
}
|
|
2103
2363
|
function scrollToRow(index, options) {
|
|
2104
2364
|
const rowIndex = clamp$9(normalizeInt$8(index), 0, Math.max(0, props.source.rowCount() - 1));
|
|
2105
|
-
const visualIndex = layoutState.value.rowStarts.get(rowIndex) ?? 0;
|
|
2106
|
-
const rowEnd = layoutState.value.rowEnds.get(rowIndex) ?? visualIndex + 1;
|
|
2365
|
+
const visualIndex = layoutState.value.fixedRows ? rowIndex : layoutState.value.rowStarts.get(rowIndex) ?? 0;
|
|
2366
|
+
const rowEnd = layoutState.value.fixedRows ? rowIndex + 1 : layoutState.value.rowEnds.get(rowIndex) ?? visualIndex + 1;
|
|
2107
2367
|
const viewportRows = Math.max(1, normalizeInt$8(props.h));
|
|
2108
2368
|
const rowHeight = Math.max(1, rowEnd - visualIndex);
|
|
2109
2369
|
let top = visualIndex;
|
|
@@ -2114,19 +2374,33 @@ const TTranscriptView = defineComponent({
|
|
|
2114
2374
|
setScrollTop(top);
|
|
2115
2375
|
}
|
|
2116
2376
|
function invalidateRow(index) {
|
|
2117
|
-
const start = layoutState.value.rowStarts.get(index);
|
|
2118
|
-
const end = layoutState.value.rowEnds.get(index);
|
|
2377
|
+
const start = layoutState.value.fixedRows ? index : layoutState.value.rowStarts.get(index);
|
|
2378
|
+
const end = layoutState.value.fixedRows ? index + 1 : layoutState.value.rowEnds.get(index);
|
|
2119
2379
|
if (start == null || end == null) return;
|
|
2120
2380
|
rowsRef.value?.invalidateRange(start, end);
|
|
2121
2381
|
}
|
|
2122
2382
|
function invalidateRange(start, end) {
|
|
2123
2383
|
const first = clamp$9(normalizeInt$8(start), 0, props.source.rowCount());
|
|
2124
2384
|
const last = clamp$9(normalizeInt$8(end), first, props.source.rowCount());
|
|
2125
|
-
const visualStart = layoutState.value.rowStarts.get(first);
|
|
2126
|
-
const visualEnd = layoutState.value.rowEnds.get(last - 1);
|
|
2385
|
+
const visualStart = layoutState.value.fixedRows ? first : layoutState.value.rowStarts.get(first);
|
|
2386
|
+
const visualEnd = layoutState.value.fixedRows ? last : layoutState.value.rowEnds.get(last - 1);
|
|
2127
2387
|
if (visualStart == null || visualEnd == null) return;
|
|
2128
2388
|
rowsRef.value?.invalidateRange(visualStart, visualEnd);
|
|
2129
2389
|
}
|
|
2390
|
+
function virtualRowsChangedRange() {
|
|
2391
|
+
const state = layoutState.value;
|
|
2392
|
+
const changedRange = normalizedChangedRange(props.source.getChangedRange?.(), state.rowCount);
|
|
2393
|
+
if (!changedRange) return null;
|
|
2394
|
+
if (state.fixedRows || changedRange.end <= changedRange.start) return changedRange;
|
|
2395
|
+
if (!canUseWrappedChangedRangeRepaint) return null;
|
|
2396
|
+
const visualStart = state.rowStarts.get(changedRange.start);
|
|
2397
|
+
const visualEnd = state.rowEnds.get(changedRange.end - 1);
|
|
2398
|
+
if (visualStart == null || visualEnd == null) return null;
|
|
2399
|
+
return {
|
|
2400
|
+
start: visualStart,
|
|
2401
|
+
end: visualEnd
|
|
2402
|
+
};
|
|
2403
|
+
}
|
|
2130
2404
|
expose({
|
|
2131
2405
|
scrollToBottom,
|
|
2132
2406
|
scrollToTop,
|
|
@@ -2209,7 +2483,19 @@ const TTranscriptView = defineComponent({
|
|
|
2209
2483
|
return text;
|
|
2210
2484
|
}
|
|
2211
2485
|
function getVisualRow(index) {
|
|
2212
|
-
|
|
2486
|
+
const state = layoutState.value;
|
|
2487
|
+
const cached = state.visualRows[index];
|
|
2488
|
+
if (cached || !state.fixedRows) return cached;
|
|
2489
|
+
if (index < 0 || index >= state.visualRows.length) return void 0;
|
|
2490
|
+
const result = layoutSourceRow(index, {
|
|
2491
|
+
width: Math.max(1, Math.floor(props.w)),
|
|
2492
|
+
baseStyle: props.style ?? defaultStyle.value,
|
|
2493
|
+
hoverRegionId: hoveredRegion.value?.id ?? null,
|
|
2494
|
+
focusedRegionId: focusedRegion.value?.id ?? null
|
|
2495
|
+
});
|
|
2496
|
+
const row = result.rows[0];
|
|
2497
|
+
if (row) state.visualRows[index] = row;
|
|
2498
|
+
return row;
|
|
2213
2499
|
}
|
|
2214
2500
|
function selectionTextForVisualRow(visualRow) {
|
|
2215
2501
|
if (!visualRow) return "";
|
|
@@ -2234,6 +2520,7 @@ const TTranscriptView = defineComponent({
|
|
|
2234
2520
|
zIndex: props.zIndex,
|
|
2235
2521
|
itemCount: layoutState.value.visualRows.length,
|
|
2236
2522
|
itemVersion: props.version,
|
|
2523
|
+
itemChangedRange: virtualRowsChangedRange,
|
|
2237
2524
|
getItem: getVisualRow,
|
|
2238
2525
|
paintItem: paintVisualRow,
|
|
2239
2526
|
renderItemNodes: renderVisualRowNodes,
|
|
@@ -2632,12 +2919,128 @@ function wrapStyledSegmentsByCells(segments, width) {
|
|
|
2632
2919
|
});
|
|
2633
2920
|
rowCells += cells;
|
|
2634
2921
|
};
|
|
2635
|
-
for (const seg of segments)
|
|
2922
|
+
for (const seg of segments) {
|
|
2923
|
+
const cells = textCellWidth(seg.text);
|
|
2924
|
+
if (cells === seg.text.length) {
|
|
2925
|
+
for (let i = 0; i < seg.text.length;) {
|
|
2926
|
+
if (rowCells >= width) openRow();
|
|
2927
|
+
const take = Math.min(width - rowCells, seg.text.length - i);
|
|
2928
|
+
if (take <= 0) break;
|
|
2929
|
+
row.push({
|
|
2930
|
+
text: seg.text.slice(i, i + take),
|
|
2931
|
+
cells: take,
|
|
2932
|
+
style: seg.style
|
|
2933
|
+
});
|
|
2934
|
+
rowCells += take;
|
|
2935
|
+
i += take;
|
|
2936
|
+
}
|
|
2937
|
+
continue;
|
|
2938
|
+
}
|
|
2939
|
+
forEachTextCellSegment(seg.text, (piece) => {
|
|
2940
|
+
if (!piece.text || piece.cells <= 0) return;
|
|
2941
|
+
pushWrappedPiece(piece.text, piece.cells, seg.style);
|
|
2942
|
+
});
|
|
2943
|
+
}
|
|
2944
|
+
return rows;
|
|
2945
|
+
}
|
|
2946
|
+
function countWrappedTextRows(text, width) {
|
|
2947
|
+
width = Math.max(1, Math.floor(width));
|
|
2948
|
+
if (!text) return 1;
|
|
2949
|
+
const cells = textCellWidth(text);
|
|
2950
|
+
if (cells <= 0) return 1;
|
|
2951
|
+
if (cells === text.length) return Math.max(1, Math.ceil(cells / width));
|
|
2952
|
+
let rows = 1;
|
|
2953
|
+
let rowCells = 0;
|
|
2954
|
+
forEachTextCellSegment(text, (piece) => {
|
|
2636
2955
|
if (!piece.text || piece.cells <= 0) return;
|
|
2637
|
-
|
|
2956
|
+
const pieceCells = piece.cells;
|
|
2957
|
+
if (rowCells > 0 && rowCells + pieceCells > width) {
|
|
2958
|
+
rows++;
|
|
2959
|
+
rowCells = 0;
|
|
2960
|
+
}
|
|
2961
|
+
if (pieceCells > width) {
|
|
2962
|
+
let remaining = pieceCells;
|
|
2963
|
+
while (remaining > 0) {
|
|
2964
|
+
if (rowCells >= width) {
|
|
2965
|
+
rows++;
|
|
2966
|
+
rowCells = 0;
|
|
2967
|
+
}
|
|
2968
|
+
const take = Math.min(width - rowCells, remaining);
|
|
2969
|
+
rowCells += take;
|
|
2970
|
+
remaining -= take;
|
|
2971
|
+
}
|
|
2972
|
+
return;
|
|
2973
|
+
}
|
|
2974
|
+
if (rowCells >= width) {
|
|
2975
|
+
rows++;
|
|
2976
|
+
rowCells = 0;
|
|
2977
|
+
}
|
|
2978
|
+
rowCells += pieceCells;
|
|
2638
2979
|
});
|
|
2639
2980
|
return rows;
|
|
2640
2981
|
}
|
|
2982
|
+
function countWrappedPlainTextRows(text, width) {
|
|
2983
|
+
width = Math.max(1, Math.floor(width));
|
|
2984
|
+
if (!text) return 1;
|
|
2985
|
+
let rows = 0;
|
|
2986
|
+
let rowCells = 0;
|
|
2987
|
+
let sawText = false;
|
|
2988
|
+
forEachTextCellSegment(text, (piece) => {
|
|
2989
|
+
if (!piece.text || piece.cells <= 0) return;
|
|
2990
|
+
sawText = true;
|
|
2991
|
+
const cells = piece.cells;
|
|
2992
|
+
if (rowCells > 0 && rowCells + cells > width) {
|
|
2993
|
+
rows++;
|
|
2994
|
+
rowCells = 0;
|
|
2995
|
+
}
|
|
2996
|
+
rowCells += cells;
|
|
2997
|
+
if (rowCells >= width) {
|
|
2998
|
+
rows++;
|
|
2999
|
+
rowCells = 0;
|
|
3000
|
+
}
|
|
3001
|
+
});
|
|
3002
|
+
return Math.max(1, rows + (rowCells > 0 || !sawText ? 1 : 0));
|
|
3003
|
+
}
|
|
3004
|
+
function countAsciiAnsiTextCells(text) {
|
|
3005
|
+
let cells = 0;
|
|
3006
|
+
for (let i = 0; i < text.length; i++) {
|
|
3007
|
+
const code = text.charCodeAt(i);
|
|
3008
|
+
if (code > 127) return null;
|
|
3009
|
+
if (code === 27) {
|
|
3010
|
+
const next = text[i + 1];
|
|
3011
|
+
if (next === "[") {
|
|
3012
|
+
let j = i + 2;
|
|
3013
|
+
while (j < text.length) {
|
|
3014
|
+
const c = text.charCodeAt(j);
|
|
3015
|
+
if (c >= 64 && c <= 126) break;
|
|
3016
|
+
j++;
|
|
3017
|
+
}
|
|
3018
|
+
if (j >= text.length) return null;
|
|
3019
|
+
i = j;
|
|
3020
|
+
continue;
|
|
3021
|
+
}
|
|
3022
|
+
if (next === "]") {
|
|
3023
|
+
let j = i + 2;
|
|
3024
|
+
while (j < text.length) {
|
|
3025
|
+
const c = text.charCodeAt(j);
|
|
3026
|
+
if (c === 7) break;
|
|
3027
|
+
if (c === 27 && text[j + 1] === "\\") {
|
|
3028
|
+
j++;
|
|
3029
|
+
break;
|
|
3030
|
+
}
|
|
3031
|
+
j++;
|
|
3032
|
+
}
|
|
3033
|
+
if (j >= text.length) return null;
|
|
3034
|
+
i = j;
|
|
3035
|
+
continue;
|
|
3036
|
+
}
|
|
3037
|
+
return null;
|
|
3038
|
+
}
|
|
3039
|
+
if (code <= 31 || code === 127) return null;
|
|
3040
|
+
cells++;
|
|
3041
|
+
}
|
|
3042
|
+
return cells;
|
|
3043
|
+
}
|
|
2641
3044
|
const TLogView = defineComponent({
|
|
2642
3045
|
name: "TLogView",
|
|
2643
3046
|
props: {
|
|
@@ -2806,6 +3209,7 @@ const TLogView = defineComponent({
|
|
|
2806
3209
|
const renderLineCache = new Map();
|
|
2807
3210
|
const wrapLineCache = new Map();
|
|
2808
3211
|
const ansiLineCache = new Map();
|
|
3212
|
+
const ansiTextCache = new Map();
|
|
2809
3213
|
const ansiWrapCache = new Map();
|
|
2810
3214
|
const ansiRowCache = new Map();
|
|
2811
3215
|
const linkifyLineCache = new Map();
|
|
@@ -2946,6 +3350,9 @@ const TLogView = defineComponent({
|
|
|
2946
3350
|
linkKey
|
|
2947
3351
|
]);
|
|
2948
3352
|
}
|
|
3353
|
+
function ansiTextCacheKey(key) {
|
|
3354
|
+
return JSON.stringify(["ansi-text", key]);
|
|
3355
|
+
}
|
|
2949
3356
|
function linkifyLineCacheKey(key, baseStyleKey, linkKey, optionsKey) {
|
|
2950
3357
|
return JSON.stringify([
|
|
2951
3358
|
"linkify-line",
|
|
@@ -3014,6 +3421,12 @@ const TLogView = defineComponent({
|
|
|
3014
3421
|
const entries = Array.from(ansiLineCache.values()).sort((a, b) => a.touchedAt - b.touchedAt);
|
|
3015
3422
|
for (const entry of entries.slice(0, ansiLineCache.size - max)) ansiLineCache.delete(entry.key);
|
|
3016
3423
|
}
|
|
3424
|
+
function trimAnsiTextCache() {
|
|
3425
|
+
const max = DEFAULT_LOG_RENDER_CACHE_SIZE;
|
|
3426
|
+
if (ansiTextCache.size <= max) return;
|
|
3427
|
+
const entries = Array.from(ansiTextCache.values()).sort((a, b) => a.touchedAt - b.touchedAt);
|
|
3428
|
+
for (const entry of entries.slice(0, ansiTextCache.size - max)) ansiTextCache.delete(entry.key);
|
|
3429
|
+
}
|
|
3017
3430
|
function trimAnsiWrapCache() {
|
|
3018
3431
|
const max = DEFAULT_LOG_WRAP_CACHE_SIZE;
|
|
3019
3432
|
if (ansiWrapCache.size <= max) return;
|
|
@@ -3048,6 +3461,7 @@ const TLogView = defineComponent({
|
|
|
3048
3461
|
renderLineCache.clear();
|
|
3049
3462
|
wrapLineCache.clear();
|
|
3050
3463
|
ansiLineCache.clear();
|
|
3464
|
+
ansiTextCache.clear();
|
|
3051
3465
|
ansiWrapCache.clear();
|
|
3052
3466
|
ansiRowCache.clear();
|
|
3053
3467
|
linkifyLineCache.clear();
|
|
@@ -3125,6 +3539,23 @@ const TLogView = defineComponent({
|
|
|
3125
3539
|
});
|
|
3126
3540
|
return segments;
|
|
3127
3541
|
}
|
|
3542
|
+
function ansiPlainTextForLine(index, count) {
|
|
3543
|
+
if (index < 0 || index >= count) return "";
|
|
3544
|
+
const rawKey = lineKey(index);
|
|
3545
|
+
const key = ansiTextCacheKey(rawKey);
|
|
3546
|
+
const cached = ansiTextCache.get(key);
|
|
3547
|
+
if (cached) {
|
|
3548
|
+
cached.touchedAt = ++cacheClock;
|
|
3549
|
+
return cached.value;
|
|
3550
|
+
}
|
|
3551
|
+
const text = sanitizeAnsiInlineText(props.source.getLine(index));
|
|
3552
|
+
ansiTextCache.set(key, {
|
|
3553
|
+
key,
|
|
3554
|
+
value: text,
|
|
3555
|
+
touchedAt: ++cacheClock
|
|
3556
|
+
});
|
|
3557
|
+
return text;
|
|
3558
|
+
}
|
|
3128
3559
|
function ansiWrappedRowsForLine(index, count, width, baseStyle, baseStyleKey, linkKey = linkStyleCacheKey()) {
|
|
3129
3560
|
if (index < 0 || index >= count) return [[]];
|
|
3130
3561
|
width = Math.max(1, Math.floor(width));
|
|
@@ -3481,8 +3912,8 @@ const TLogView = defineComponent({
|
|
|
3481
3912
|
lineMatches.push(matchIndex);
|
|
3482
3913
|
invalidateSearchMarkers();
|
|
3483
3914
|
}
|
|
3484
|
-
function searchableTextForLine(index, count
|
|
3485
|
-
if (props.ansi) return
|
|
3915
|
+
function searchableTextForLine(index, count) {
|
|
3916
|
+
if (props.ansi) return ansiPlainTextForLine(index, count);
|
|
3486
3917
|
return sanitizeInlineText(props.source.getLine(index));
|
|
3487
3918
|
}
|
|
3488
3919
|
function normalizeSearchResultPreviewWidth(value) {
|
|
@@ -3495,8 +3926,8 @@ const TLogView = defineComponent({
|
|
|
3495
3926
|
if (!Number.isFinite(n)) return DEFAULT_SEARCH_RESULTS_CONTEXT_CELLS;
|
|
3496
3927
|
return Math.max(0, n);
|
|
3497
3928
|
}
|
|
3498
|
-
function previewForMatch(match, count,
|
|
3499
|
-
const text = searchableTextForLine(match.index, count
|
|
3929
|
+
function previewForMatch(match, count, options) {
|
|
3930
|
+
const text = searchableTextForLine(match.index, count);
|
|
3500
3931
|
const totalCells = textCellWidth(text);
|
|
3501
3932
|
const matchCells = Math.max(1, match.endCell - match.startCell);
|
|
3502
3933
|
const previewWidth = Math.max(options.previewWidth, matchCells);
|
|
@@ -3526,7 +3957,7 @@ const TLogView = defineComponent({
|
|
|
3526
3957
|
matchEndCell
|
|
3527
3958
|
};
|
|
3528
3959
|
}
|
|
3529
|
-
function cachedLineSearchMatches(index, count, search
|
|
3960
|
+
function cachedLineSearchMatches(index, count, search) {
|
|
3530
3961
|
const rawKey = lineKey(index);
|
|
3531
3962
|
const key = searchLineCacheKey(rawKey, search.key);
|
|
3532
3963
|
const cached = searchLineCache.get(key);
|
|
@@ -3534,7 +3965,7 @@ const TLogView = defineComponent({
|
|
|
3534
3965
|
cached.touchedAt = ++cacheClock;
|
|
3535
3966
|
return cached.matches;
|
|
3536
3967
|
}
|
|
3537
|
-
const matches = search.findLineMatches(searchableTextForLine(index, count
|
|
3968
|
+
const matches = search.findLineMatches(searchableTextForLine(index, count));
|
|
3538
3969
|
searchLineCache.set(key, {
|
|
3539
3970
|
key,
|
|
3540
3971
|
matches,
|
|
@@ -3542,9 +3973,9 @@ const TLogView = defineComponent({
|
|
|
3542
3973
|
});
|
|
3543
3974
|
return matches;
|
|
3544
3975
|
}
|
|
3545
|
-
function scanSearchLine(index, count, search,
|
|
3976
|
+
function scanSearchLine(index, count, search, maxMatches, absoluteBase) {
|
|
3546
3977
|
if (searchMatches.length >= maxMatches) return;
|
|
3547
|
-
const lineMatches = cachedLineSearchMatches(index, count, search
|
|
3978
|
+
const lineMatches = cachedLineSearchMatches(index, count, search);
|
|
3548
3979
|
for (const match of lineMatches) {
|
|
3549
3980
|
if (searchMatches.length >= maxMatches) return;
|
|
3550
3981
|
addSearchMatch({
|
|
@@ -3572,11 +4003,9 @@ const TLogView = defineComponent({
|
|
|
3572
4003
|
const count = lineCount();
|
|
3573
4004
|
const maxMatches = maxSearchMatches();
|
|
3574
4005
|
const absoluteBase = firstLineIndex();
|
|
3575
|
-
const base = props.style ?? defaultStyle.value;
|
|
3576
|
-
const baseStyleKey = styleCacheKey(base);
|
|
3577
4006
|
let scanned = 0;
|
|
3578
4007
|
while (searchCursor < count && searchMatches.length < maxMatches && (scanned === 0 || ctx.now() - started < budget)) {
|
|
3579
|
-
scanSearchLine(searchCursor, count, compiledSearch,
|
|
4008
|
+
scanSearchLine(searchCursor, count, compiledSearch, maxMatches, absoluteBase);
|
|
3580
4009
|
searchCursor++;
|
|
3581
4010
|
scanned++;
|
|
3582
4011
|
}
|
|
@@ -3601,6 +4030,7 @@ const TLogView = defineComponent({
|
|
|
3601
4030
|
plane: plane.value,
|
|
3602
4031
|
reason: "data"
|
|
3603
4032
|
});
|
|
4033
|
+
trimAnsiTextCache();
|
|
3604
4034
|
trimSearchLineCache();
|
|
3605
4035
|
}
|
|
3606
4036
|
function requestSearchScan() {
|
|
@@ -3846,14 +4276,22 @@ const TLogView = defineComponent({
|
|
|
3846
4276
|
}
|
|
3847
4277
|
if (count > visualIndexLineCount) appendEstimatedVisualLines(visualIndexLineCount, count);
|
|
3848
4278
|
}
|
|
3849
|
-
function measureVisualLine(index) {
|
|
4279
|
+
function measureVisualLine(index, options) {
|
|
3850
4280
|
ensureVisualIndex();
|
|
3851
4281
|
if (index < 0 || index >= visualIndexLineCount) return 0;
|
|
3852
4282
|
const key = lineKey(index);
|
|
3853
4283
|
if (visualKeys[index] === key) return 0;
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
4284
|
+
let nextCount;
|
|
4285
|
+
if (options?.countOnly === true) if (props.ansi) {
|
|
4286
|
+
const raw = props.source.getLine(index);
|
|
4287
|
+
const asciiCells = countAsciiAnsiTextCells(raw);
|
|
4288
|
+
nextCount = asciiCells == null ? countWrappedTextRows(ansiPlainTextForLine(index, visualIndexLineCount), visualIndexWidth) : Math.max(1, Math.ceil(asciiCells / visualIndexWidth));
|
|
4289
|
+
} else nextCount = countWrappedPlainTextRows(sanitizeInlineText(props.source.getLine(index)), visualIndexWidth);
|
|
4290
|
+
else {
|
|
4291
|
+
const base = props.style ?? defaultStyle.value;
|
|
4292
|
+
const rows = props.ansi ? ansiWrappedRowsForLine(index, visualIndexLineCount, visualIndexWidth, base, styleCacheKey(base)) : wrappedRowsForLine(index, visualIndexLineCount, visualIndexWidth);
|
|
4293
|
+
nextCount = Math.max(1, rows.length);
|
|
4294
|
+
}
|
|
3857
4295
|
const prevCount = visualCounts[index] ?? 1;
|
|
3858
4296
|
if (nextCount !== prevCount) {
|
|
3859
4297
|
visualCounts[index] = nextCount;
|
|
@@ -3896,6 +4334,7 @@ const TLogView = defineComponent({
|
|
|
3896
4334
|
if (visualMeasureCursor >= target) {
|
|
3897
4335
|
syncVisualIndexStatus();
|
|
3898
4336
|
emitVisualIndex();
|
|
4337
|
+
trimAnsiTextCache();
|
|
3899
4338
|
return;
|
|
3900
4339
|
}
|
|
3901
4340
|
const started = ctx.now();
|
|
@@ -3907,7 +4346,7 @@ const TLogView = defineComponent({
|
|
|
3907
4346
|
const effectiveTop = currentScrollTop() + topAdjustment;
|
|
3908
4347
|
const start = visualStartForLine(index);
|
|
3909
4348
|
const prevCount = visualCounts[index] ?? 1;
|
|
3910
|
-
const delta = measureVisualLine(index);
|
|
4349
|
+
const delta = measureVisualLine(index, { countOnly: true });
|
|
3911
4350
|
if (delta !== 0 && effectiveTop >= start + prevCount) topAdjustment += delta;
|
|
3912
4351
|
visualMeasureCursor++;
|
|
3913
4352
|
measuredLineCount = visualMeasureCursor;
|
|
@@ -3940,6 +4379,7 @@ const TLogView = defineComponent({
|
|
|
3940
4379
|
}
|
|
3941
4380
|
syncVisualIndexStatus();
|
|
3942
4381
|
emitVisualIndex();
|
|
4382
|
+
trimAnsiTextCache();
|
|
3943
4383
|
}
|
|
3944
4384
|
function requestVisualIndexMeasurement(restartFrom = measuredLineCount) {
|
|
3945
4385
|
if (!props.wrap) {
|
|
@@ -3953,6 +4393,7 @@ const TLogView = defineComponent({
|
|
|
3953
4393
|
if (measuredLineCount >= target) {
|
|
3954
4394
|
syncVisualIndexStatus();
|
|
3955
4395
|
emitVisualIndex();
|
|
4396
|
+
trimAnsiTextCache();
|
|
3956
4397
|
return;
|
|
3957
4398
|
}
|
|
3958
4399
|
const generation = ++visualMeasureGeneration;
|
|
@@ -4490,7 +4931,7 @@ const TLogView = defineComponent({
|
|
|
4490
4931
|
if (options?.emitScroll) emitScroll(clampedTop);
|
|
4491
4932
|
return true;
|
|
4492
4933
|
}
|
|
4493
|
-
const scrollPlan =
|
|
4934
|
+
const scrollPlan = prepareUnsafeFullRowScroll({
|
|
4494
4935
|
render,
|
|
4495
4936
|
plane: plane.value,
|
|
4496
4937
|
rect: r,
|
|
@@ -4501,7 +4942,7 @@ const TLogView = defineComponent({
|
|
|
4501
4942
|
isClipped: isClipped(),
|
|
4502
4943
|
hasPendingDirtyRows: Boolean(dirtyRowsHint?.length),
|
|
4503
4944
|
strategy
|
|
4504
|
-
})
|
|
4945
|
+
});
|
|
4505
4946
|
if (scrollPlan) {
|
|
4506
4947
|
const rows = options?.extraDirtyRows?.length ? [...scrollPlan.exposedRows, ...options.extraDirtyRows] : scrollPlan.exposedRows;
|
|
4507
4948
|
if (markRowsDirty(rows)) {
|
|
@@ -4981,14 +5422,12 @@ const TLogView = defineComponent({
|
|
|
4981
5422
|
match: copySearchMatch(match)
|
|
4982
5423
|
}));
|
|
4983
5424
|
const count = lineCount();
|
|
4984
|
-
const base = props.style ?? defaultStyle.value;
|
|
4985
|
-
const baseStyleKey = styleCacheKey(base);
|
|
4986
5425
|
const previewWidth = normalizeSearchResultPreviewWidth(options?.previewWidth);
|
|
4987
5426
|
const contextCells = normalizeSearchResultContextCells(options?.contextCells);
|
|
4988
5427
|
return searchMatches.slice(offset, offset + limit).map((match, index) => ({
|
|
4989
5428
|
matchIndex: offset + index,
|
|
4990
5429
|
match: copySearchMatch(match),
|
|
4991
|
-
preview: previewForMatch(match, count,
|
|
5430
|
+
preview: previewForMatch(match, count, {
|
|
4992
5431
|
previewWidth,
|
|
4993
5432
|
contextCells
|
|
4994
5433
|
})
|