Initial commit
This commit is contained in:
119
ansi-tunc.mjs
Normal file
119
ansi-tunc.mjs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/* 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();
|
||||||
72
grep-mtime-sorter.mjs
Normal file
72
grep-mtime-sorter.mjs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/* 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 { stat } from 'node:fs/promises';
|
||||||
|
|
||||||
|
const lineRe = /^\x1b\[35m\x1b\[K(.*?)\x1b/;
|
||||||
|
|
||||||
|
|
||||||
|
function isoFormat(timestamp) {
|
||||||
|
if (timestamp) {
|
||||||
|
const d = new Date(timestamp * 1000);
|
||||||
|
const pad = (n) => String(n).padStart(2, '0');
|
||||||
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||||||
|
} else {
|
||||||
|
return 'Unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMtime(line) {
|
||||||
|
const m = lineRe.exec(line);
|
||||||
|
if (m) {
|
||||||
|
const filename = m[1];
|
||||||
|
try {
|
||||||
|
const s = await stat(filename);
|
||||||
|
return s.mtimeMs / 1000;
|
||||||
|
} catch {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('Malformed input: ANSI prefix not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const input = await new Promise((resolve) => {
|
||||||
|
let data = '';
|
||||||
|
process.stdin.setEncoding('utf8');
|
||||||
|
process.stdin.on('data', (chunk) => { data += chunk; });
|
||||||
|
process.stdin.on('end', () => { resolve(data); });
|
||||||
|
});
|
||||||
|
|
||||||
|
const lines = input.split(/(?<=\n)/);
|
||||||
|
|
||||||
|
const pairs = await Promise.all(
|
||||||
|
lines.map(async (line, index) => {
|
||||||
|
const t = await getMtime(line);
|
||||||
|
return { t, index };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
pairs.sort((a, b) => {
|
||||||
|
if (a.t !== b.t) {
|
||||||
|
return a.t - b.t;
|
||||||
|
} else {
|
||||||
|
return a.index - b.index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const { t, index } of pairs) {
|
||||||
|
const ts = isoFormat(t).padStart(16, ' ');
|
||||||
|
process.stdout.write(`\x1b[94m${ts}\x1b[0m `);
|
||||||
|
process.stdout.write(lines[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await main();
|
||||||
10
package.json
Normal file
10
package.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "ansi-tools",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"private": true,
|
||||||
|
"bin": {
|
||||||
|
"ansi-trunc": "./ansi-trunc.mjs",
|
||||||
|
"grep-mtime-sorter": "./grep-mtime-sorter.mjs"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user