Files
shell-utils/ansi-trunc.mjs
2026-02-22 04:13:12 +01:00

122 lines
2.4 KiB
JavaScript
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/* VIBE ALERT
This code was generated using OpenAIs 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();