fix: Improve CLI progress display and prevent tree-sitter WASM memory crashes
Replaces fixed-width padding with terminal escape sequences for proper progress line clearing across different terminal widths. Adds periodic parser reset every 5000 parses per language to prevent WASM heap fragmentation that causes "memory access out of bounds" crashes in large repositories. Includes filename truncation to fit available terminal width.
This commit is contained in:
+25
-6
@@ -180,6 +180,16 @@ function progressBar(current: number, total: number, width: number = 30): string
|
||||
return `${bar} ${percentStr}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate a string to fit a given visible width, adding ellipsis if needed
|
||||
*/
|
||||
function truncate(str: string, maxWidth: number): string {
|
||||
if (maxWidth <= 0) return '';
|
||||
if (str.length <= maxWidth) return str;
|
||||
if (maxWidth <= 1) return str.charAt(0);
|
||||
return '\u2026' + str.slice(-(maxWidth - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Print a progress update (overwrites current line)
|
||||
*/
|
||||
@@ -192,15 +202,24 @@ function printProgress(progress: IndexProgress): void {
|
||||
};
|
||||
|
||||
const phaseName = phaseNames[progress.phase] || progress.phase;
|
||||
const file = progress.currentFile ? chalk.dim(` ${progress.currentFile}`) : '';
|
||||
const cols = process.stdout.columns || 80;
|
||||
|
||||
if (progress.total > 0) {
|
||||
const bar = progressBar(progress.current, progress.total);
|
||||
process.stdout.write(`\r${chalk.cyan(phaseName)}: ${bar}${file}`.padEnd(100));
|
||||
// "Phase: [bar] XX% filename" — calculate space left for filename
|
||||
// phaseName + ": " = phaseName.length + 2, bar visible = 30 + 1 + 4 = 35, space before file = 1
|
||||
const prefixWidth = phaseName.length + 2 + 35;
|
||||
const fileMaxWidth = cols - prefixWidth - 1;
|
||||
const file = progress.currentFile ? chalk.dim(` ${truncate(progress.currentFile, fileMaxWidth)}`) : '';
|
||||
process.stdout.write(`\r${chalk.cyan(phaseName)}: ${bar}${file}\x1b[K`);
|
||||
} else {
|
||||
// No known total (e.g. scanning) — show a running count
|
||||
const countStr = progress.current > 0 ? ` ${formatNumber(progress.current)} found` : '';
|
||||
const prefixWidth = phaseName.length + 1 + countStr.length;
|
||||
const fileMaxWidth = cols - prefixWidth - 1;
|
||||
const file = progress.currentFile ? chalk.dim(` ${truncate(progress.currentFile, fileMaxWidth)}`) : '';
|
||||
const count = progress.current > 0 ? ` ${chalk.green(formatNumber(progress.current))} found` : '';
|
||||
process.stdout.write(`\r${chalk.cyan(phaseName)}:${count}${file}`.padEnd(100));
|
||||
process.stdout.write(`\r${chalk.cyan(phaseName)}:${count}${file}\x1b[K`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +409,7 @@ program
|
||||
});
|
||||
|
||||
// Clear progress line
|
||||
process.stdout.write('\r' + ' '.repeat(100) + '\r');
|
||||
process.stdout.write('\r\x1b[K');
|
||||
|
||||
printIndexResult(result, projectPath);
|
||||
} else {
|
||||
@@ -488,7 +507,7 @@ program
|
||||
|
||||
// Clear progress line
|
||||
if (!options.quiet) {
|
||||
process.stdout.write('\r' + ' '.repeat(100) + '\r');
|
||||
process.stdout.write('\r\x1b[K');
|
||||
}
|
||||
|
||||
if (!options.quiet) {
|
||||
@@ -533,7 +552,7 @@ program
|
||||
|
||||
// Clear progress line
|
||||
if (!options.quiet) {
|
||||
process.stdout.write('\r' + ' '.repeat(100) + '\r');
|
||||
process.stdout.write('\r\x1b[K');
|
||||
}
|
||||
|
||||
const totalChanges = result.filesAdded + result.filesModified + result.filesRemoved;
|
||||
|
||||
Reference in New Issue
Block a user