forked from mikael-lovqvist/shell-utils
Fixed file name typo
This commit is contained in:
121
ansi-trunc.mjs
Executable file
121
ansi-trunc.mjs
Executable file
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/* 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();
|
||||
Reference in New Issue
Block a user