Add my-rainbow-editor extension for pi

This commit is contained in:
gurix
2026-04-24 10:25:09 +02:00
parent 1aa873ed33
commit 2c256df348
+62
View File
@@ -0,0 +1,62 @@
/**
* My Rainbow Editor Extension for pi
*
* This extension provides a custom TUI editor component for the pi coding agent.
* It takes the rendered lines of the default editor and applies a continuous
* rainbow color pattern to all characters. To prevent the TUI from breaking,
* it safely ignores and preserves existing ANSI escape codes (such as cursor
* placement and text selection sequences) during the colorization process.
*
* Usage: pi --extension ./my-rainbow-editor.ts
*/
import { CustomEditor, type ExtensionAPI } from "@mariozechner/pi-coding-agent";
const COLORS: [number, number, number][] = [
[233, 137, 115], // coral
[228, 186, 103], // yellow
[141, 192, 122], // green
[102, 194, 179], // teal
[121, 157, 207], // blue
[157, 134, 195], // purple
[206, 130, 172], // pink
];
const RESET = "\x1b[0m";
// Regex to split string on ANSI escape codes, keeping them intact
const ANSI_REGEX = /(\x1b(?:\[[0-9;?]*[a-zA-Z]|(?:\]|_)[^\x07\x1b]*(?:\x07|\x1b\\)))/;
function colorizeSafe(line: string): string {
const parts = line.split(ANSI_REGEX);
let out = "";
let charIndex = 0;
for (const part of parts) {
if (!part) continue;
// If this is an ANSI sequence, pass it through without colorizing
if (part.startsWith("\x1b")) {
out += part;
} else {
// Colorize regular characters individually
for (const char of part) {
const [r, g, b] = COLORS[charIndex % COLORS.length]!;
out += `\x1b[38;2;${r};${g};${b}m${char}`;
charIndex++;
}
}
}
// Append a single reset at the end of the line just to be safe
return out + RESET;
}
class MyRainbowEditor extends CustomEditor {
render(width: number): string[] {
// Render the original editor line, but safely add our rainbow colors
// on top without breaking the terminal cursor/selection ANSI sequences
return super.render(width).map(line => colorizeSafe(line));
}
}
export default function (pi: ExtensionAPI) {
pi.on("session_start", (_event, ctx) => {
ctx.ui.setEditorComponent((tui, theme, kb) => new MyRainbowEditor(tui, theme, kb));
});
}