startall 0.0.10 → 0.0.11
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/index.js +153 -33
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -357,6 +357,10 @@ class ProcessManager {
|
|
|
357
357
|
this.splitMode = false; // Whether waiting for split command after Ctrl+b
|
|
358
358
|
this.showSplitMenu = false; // Whether to show the command palette
|
|
359
359
|
this.splitMenuIndex = 0; // Selected item in split menu
|
|
360
|
+
this.paneScrollPositions = new Map(); // Store scroll positions per pane ID
|
|
361
|
+
this.paneScrollBoxes = new Map(); // Store ScrollBox references per pane ID
|
|
362
|
+
this.paneFilterState = new Map(); // Track filter state per pane to detect changes
|
|
363
|
+
this.paneLineCount = new Map(); // Track how many lines we've rendered per pane
|
|
360
364
|
|
|
361
365
|
// Assign colors to each script
|
|
362
366
|
this.processColors = new Map();
|
|
@@ -1811,9 +1815,94 @@ class ProcessManager {
|
|
|
1811
1815
|
}
|
|
1812
1816
|
|
|
1813
1817
|
updateRunningUI() {
|
|
1814
|
-
//
|
|
1815
|
-
|
|
1816
|
-
|
|
1818
|
+
// Update existing panes instead of rebuilding everything
|
|
1819
|
+
if (this.paneScrollBoxes.size > 0) {
|
|
1820
|
+
// Update each pane's content
|
|
1821
|
+
for (const [paneId, scrollBox] of this.paneScrollBoxes.entries()) {
|
|
1822
|
+
const pane = findPaneById(this.paneRoot, paneId);
|
|
1823
|
+
if (pane && scrollBox && scrollBox.content) {
|
|
1824
|
+
// Check if filter state changed or if paused (requires rebuild)
|
|
1825
|
+
const currentFilterState = JSON.stringify({
|
|
1826
|
+
filter: pane.filter || '',
|
|
1827
|
+
hidden: pane.hidden || [],
|
|
1828
|
+
processes: pane.processes || [],
|
|
1829
|
+
colorFilter: pane.colorFilter || null,
|
|
1830
|
+
});
|
|
1831
|
+
const previousFilterState = this.paneFilterState.get(paneId);
|
|
1832
|
+
const filterChanged = currentFilterState !== previousFilterState;
|
|
1833
|
+
const needsRebuild = filterChanged || this.isPaused;
|
|
1834
|
+
|
|
1835
|
+
if (needsRebuild) {
|
|
1836
|
+
// Filter changed - need to rebuild all content
|
|
1837
|
+
this.paneFilterState.set(paneId, currentFilterState);
|
|
1838
|
+
|
|
1839
|
+
// Remove all children
|
|
1840
|
+
if (scrollBox.content.children) {
|
|
1841
|
+
while (scrollBox.content.children.length > 0) {
|
|
1842
|
+
const child = scrollBox.content.children[0];
|
|
1843
|
+
if (child && child.id) {
|
|
1844
|
+
scrollBox.content.remove(child.id);
|
|
1845
|
+
} else {
|
|
1846
|
+
break;
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
// Rebuild all content
|
|
1852
|
+
const height = scrollBox.height || this.renderer.height - 6;
|
|
1853
|
+
this.buildPaneOutput(pane, scrollBox.content, height);
|
|
1854
|
+
|
|
1855
|
+
// Update line count after rebuild
|
|
1856
|
+
const lines = this.getOutputLinesForPane(pane);
|
|
1857
|
+
this.paneLineCount.set(paneId, lines.length);
|
|
1858
|
+
|
|
1859
|
+
// Auto-scroll to bottom after filter change
|
|
1860
|
+
if (!this.isPaused) {
|
|
1861
|
+
scrollBox.scrollTo({ x: 0, y: Number.MAX_SAFE_INTEGER });
|
|
1862
|
+
}
|
|
1863
|
+
} else {
|
|
1864
|
+
// No filter change - just append new lines
|
|
1865
|
+
const lines = this.getOutputLinesForPane(pane);
|
|
1866
|
+
const lastRenderedCount = this.paneLineCount.get(paneId) || 0;
|
|
1867
|
+
|
|
1868
|
+
if (lines.length > lastRenderedCount) {
|
|
1869
|
+
const newLines = lines.slice(lastRenderedCount);
|
|
1870
|
+
|
|
1871
|
+
for (let i = 0; i < newLines.length; i++) {
|
|
1872
|
+
const line = newLines[i];
|
|
1873
|
+
const lineIndex = lastRenderedCount + i;
|
|
1874
|
+
const processColor = this.processColors.get(line.process) || COLORS.text;
|
|
1875
|
+
const trimmedText = line.text.trim();
|
|
1876
|
+
|
|
1877
|
+
const outputLine = new TextRenderable(this.renderer, {
|
|
1878
|
+
id: `output-${pane.id}-${lineIndex}`,
|
|
1879
|
+
content: t`${fg(processColor)(`[${line.process}]`)} ${trimmedText}`,
|
|
1880
|
+
bg: '#000000',
|
|
1881
|
+
});
|
|
1882
|
+
|
|
1883
|
+
scrollBox.content.add(outputLine);
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
// Update line count
|
|
1887
|
+
this.paneLineCount.set(paneId, lines.length);
|
|
1888
|
+
|
|
1889
|
+
// Auto-scroll to bottom if not paused
|
|
1890
|
+
if (!this.isPaused) {
|
|
1891
|
+
scrollBox.scrollTo({ x: 0, y: Number.MAX_SAFE_INTEGER });
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
// Update scrollbar visibility based on pause state
|
|
1897
|
+
if (scrollBox.verticalScrollBar) {
|
|
1898
|
+
scrollBox.verticalScrollBar.width = this.isPaused ? 1 : 0;
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
} else {
|
|
1903
|
+
// First time or no panes exist - do full rebuild
|
|
1904
|
+
this.buildRunningUI();
|
|
1905
|
+
}
|
|
1817
1906
|
}
|
|
1818
1907
|
|
|
1819
1908
|
// Build a single pane's output area
|
|
@@ -1821,36 +1910,24 @@ class ProcessManager {
|
|
|
1821
1910
|
const isFocused = pane.id === this.focusedPaneId;
|
|
1822
1911
|
const lines = this.getOutputLinesForPane(pane);
|
|
1823
1912
|
|
|
1824
|
-
//
|
|
1825
|
-
const
|
|
1826
|
-
let linesToShow = this.isPaused ? lines : lines.slice(-outputHeight);
|
|
1913
|
+
// Don't slice - show all lines and let ScrollBox handle scrolling
|
|
1914
|
+
const linesToShow = lines;
|
|
1827
1915
|
|
|
1828
|
-
// Add lines
|
|
1829
|
-
for (let i =
|
|
1916
|
+
// Add lines (oldest first, so newest is at bottom)
|
|
1917
|
+
for (let i = 0; i < linesToShow.length; i++) {
|
|
1830
1918
|
const line = linesToShow[i];
|
|
1831
1919
|
const processColor = this.processColors.get(line.process) || COLORS.text;
|
|
1832
1920
|
|
|
1833
|
-
//
|
|
1921
|
+
// Trim whitespace and let text wrap naturally - ScrollBox will handle overflow
|
|
1922
|
+
const trimmedText = line.text.trim();
|
|
1834
1923
|
const outputLine = new TextRenderable(this.renderer, {
|
|
1835
1924
|
id: `output-${pane.id}-${i}`,
|
|
1836
|
-
content: t`${fg(processColor)(`[${line.process}]`)} ${
|
|
1925
|
+
content: t`${fg(processColor)(`[${line.process}]`)} ${trimmedText}`,
|
|
1837
1926
|
bg: '#000000', // Black background for pane content
|
|
1838
1927
|
});
|
|
1839
1928
|
|
|
1840
1929
|
container.add(outputLine);
|
|
1841
1930
|
}
|
|
1842
|
-
|
|
1843
|
-
// Fill remaining vertical space with blank lines
|
|
1844
|
-
const emptyLinesNeeded = Math.max(0, outputHeight - linesToShow.length);
|
|
1845
|
-
for (let j = 0; j < emptyLinesNeeded; j++) {
|
|
1846
|
-
const emptyLine = new TextRenderable(this.renderer, {
|
|
1847
|
-
id: `empty-${pane.id}-${j}`,
|
|
1848
|
-
content: ' ',
|
|
1849
|
-
bg: '#000000', // Black background for empty lines
|
|
1850
|
-
});
|
|
1851
|
-
|
|
1852
|
-
container.add(emptyLine);
|
|
1853
|
-
}
|
|
1854
1931
|
}
|
|
1855
1932
|
|
|
1856
1933
|
// Count how many vertical panes exist (for width calculation)
|
|
@@ -1900,22 +1977,54 @@ class ProcessManager {
|
|
|
1900
1977
|
backgroundColor: '#000000', // Black background for pane container
|
|
1901
1978
|
});
|
|
1902
1979
|
|
|
1903
|
-
// Output content - use
|
|
1980
|
+
// Output content - use ScrollBox to handle text wrapping properly
|
|
1904
1981
|
// Use passed height or calculate default for line count calculation
|
|
1905
1982
|
const height = availableHeight ? Math.max(5, availableHeight - 2) : Math.max(5, this.renderer.height - 6);
|
|
1906
1983
|
|
|
1907
|
-
const outputBox = new
|
|
1984
|
+
const outputBox = new ScrollBoxRenderable(this.renderer, {
|
|
1908
1985
|
id: `pane-output-${pane.id}`,
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1986
|
+
height: height,
|
|
1987
|
+
scrollX: false, // Disable horizontal scrollbar entirely
|
|
1988
|
+
scrollY: true, // Enable vertical scrolling
|
|
1989
|
+
focusable: true, // Enable mouse interactions and keyboard scrolling
|
|
1990
|
+
style: {
|
|
1991
|
+
rootOptions: {
|
|
1992
|
+
flexGrow: 1,
|
|
1993
|
+
flexShrink: 1,
|
|
1994
|
+
flexBasis: 0,
|
|
1995
|
+
paddingLeft: 1,
|
|
1996
|
+
backgroundColor: '#000000',
|
|
1997
|
+
},
|
|
1998
|
+
contentOptions: {
|
|
1999
|
+
backgroundColor: '#000000',
|
|
2000
|
+
width: '100%', // Fill container width for proper text wrapping
|
|
2001
|
+
},
|
|
2002
|
+
},
|
|
1916
2003
|
});
|
|
1917
2004
|
|
|
1918
|
-
|
|
2005
|
+
// Show scrollbar when paused, hide when not paused
|
|
2006
|
+
if (outputBox.verticalScrollBar) {
|
|
2007
|
+
outputBox.verticalScrollBar.width = this.isPaused ? 1 : 0;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
// Store ScrollBox reference for this pane
|
|
2011
|
+
this.paneScrollBoxes.set(pane.id, outputBox);
|
|
2012
|
+
|
|
2013
|
+
this.buildPaneOutput(pane, outputBox.content, height);
|
|
2014
|
+
|
|
2015
|
+
// Restore or set scroll position
|
|
2016
|
+
setTimeout(() => {
|
|
2017
|
+
if (!outputBox || !outputBox.scrollTo) return;
|
|
2018
|
+
|
|
2019
|
+
if (this.isPaused && this.paneScrollPositions.has(pane.id)) {
|
|
2020
|
+
// Restore saved scroll position when paused
|
|
2021
|
+
const savedPos = this.paneScrollPositions.get(pane.id);
|
|
2022
|
+
outputBox.scrollTo(savedPos);
|
|
2023
|
+
} else if (!this.isPaused) {
|
|
2024
|
+
// Auto-scroll to bottom when not paused
|
|
2025
|
+
outputBox.scrollTo({ x: 0, y: Number.MAX_SAFE_INTEGER });
|
|
2026
|
+
}
|
|
2027
|
+
}, 0);
|
|
1919
2028
|
|
|
1920
2029
|
paneContainer.add(outputBox);
|
|
1921
2030
|
return paneContainer;
|
|
@@ -2011,6 +2120,16 @@ class ProcessManager {
|
|
|
2011
2120
|
}
|
|
2012
2121
|
|
|
2013
2122
|
buildRunningUI() {
|
|
2123
|
+
// Save scroll positions before destroying
|
|
2124
|
+
for (const [paneId, scrollBox] of this.paneScrollBoxes.entries()) {
|
|
2125
|
+
if (scrollBox) {
|
|
2126
|
+
this.paneScrollPositions.set(paneId, {
|
|
2127
|
+
x: scrollBox.scrollLeft || 0,
|
|
2128
|
+
y: scrollBox.scrollTop || 0,
|
|
2129
|
+
});
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2014
2133
|
// Remove old containers if they exist - use destroyRecursively to clean up all children
|
|
2015
2134
|
if (this.selectionContainer) {
|
|
2016
2135
|
this.renderer.root.remove(this.selectionContainer);
|
|
@@ -2029,8 +2148,9 @@ class ProcessManager {
|
|
|
2029
2148
|
this.runningContainer.destroyRecursively();
|
|
2030
2149
|
this.runningContainer = null;
|
|
2031
2150
|
}
|
|
2032
|
-
// Clear outputBox reference since
|
|
2151
|
+
// Clear outputBox reference and scrollbox map since they were destroyed
|
|
2033
2152
|
this.outputBox = null;
|
|
2153
|
+
this.paneScrollBoxes.clear();
|
|
2034
2154
|
|
|
2035
2155
|
// Create main container - full screen with black background
|
|
2036
2156
|
const mainContainer = new BoxRenderable(this.renderer, {
|