forked from mikael-lovqvist/shell-utils
120 lines
2.4 KiB
JavaScript
120 lines
2.4 KiB
JavaScript
/* VIBE ALERT
|
||
|
||
This code was generated using OpenAI’s ChatGPT (GPT-5.2 Thinking, large language model).
|
||
The output has not been independently reviewed, audited, or comprehensively validated,
|
||
and has only been superficially tested. It should be considered experimental and not fully vetted for production use.
|
||
|
||
*/
|
||
|
||
import fs from 'node:fs';
|
||
import readline from 'node:readline';
|
||
|
||
const ansiRegex = /\x1b\[(?:[0-9]{1,3}(?:;[0-9]{1,3})*)?[mK]?/g;
|
||
|
||
function tokenize(line) {
|
||
const tokens = [];
|
||
let lastIndex = 0;
|
||
|
||
for (const match of line.matchAll(ansiRegex)) {
|
||
const index = match.index;
|
||
|
||
if (index > lastIndex) {
|
||
tokens.push({ type: 'text', value: line.slice(lastIndex, index) });
|
||
}
|
||
|
||
tokens.push({ type: 'ansi', value: match[0] });
|
||
lastIndex = index + match[0].length;
|
||
}
|
||
|
||
if (lastIndex < line.length) {
|
||
tokens.push({ type: 'text', value: line.slice(lastIndex) });
|
||
}
|
||
|
||
return tokens;
|
||
}
|
||
|
||
function truncateLine(line, maxLength, tabSize=4) {
|
||
let col = 0;
|
||
let result = '';
|
||
|
||
const tokens = tokenize(line);
|
||
|
||
for (const token of tokens) {
|
||
if (col >= maxLength) {
|
||
break;
|
||
}
|
||
|
||
if (token.type === 'ansi') {
|
||
result += token.value;
|
||
} else {
|
||
let i = 0;
|
||
|
||
while (i < token.value.length && col < maxLength) {
|
||
const ch = token.value[i];
|
||
|
||
if (ch === '\t') {
|
||
const w = tabSize - (col % tabSize);
|
||
|
||
if (col + w > maxLength) {
|
||
i = token.value.length;
|
||
} else {
|
||
result += ' '.repeat(w);
|
||
col += w;
|
||
i++;
|
||
}
|
||
} else {
|
||
result += ch;
|
||
col += 1;
|
||
i++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return result.replace(/\s+$/, '') + '\x1b[0m';
|
||
}
|
||
function parseArgs(argv) {
|
||
let filename = '/dev/stdin';
|
||
let length = 50;
|
||
|
||
for (let i = 2; i < argv.length; i++) {
|
||
const arg = argv[i];
|
||
|
||
if (arg === '-l' || arg === '--length') {
|
||
const value = argv[i + 1];
|
||
if (value) {
|
||
length = parseInt(value, 10);
|
||
i++;
|
||
}
|
||
} else {
|
||
filename = arg;
|
||
}
|
||
}
|
||
|
||
return { filename, length };
|
||
}
|
||
|
||
async function main() {
|
||
const { filename, length } = parseArgs(process.argv);
|
||
|
||
let inputStream;
|
||
|
||
if (filename === '/dev/stdin') {
|
||
inputStream = process.stdin;
|
||
} else {
|
||
inputStream = fs.createReadStream(filename, { encoding: 'utf8' });
|
||
}
|
||
|
||
const rl = readline.createInterface({
|
||
input: inputStream,
|
||
crlfDelay: Infinity,
|
||
});
|
||
|
||
for await (const line of rl) {
|
||
const truncated = truncateLine(line, length);
|
||
process.stdout.write(truncated + '\n');
|
||
}
|
||
}
|
||
|
||
await main();
|