From 2c256df3484a189823b6818d43fb6128317cd3b0 Mon Sep 17 00:00:00 2001 From: gurix Date: Fri, 24 Apr 2026 10:25:09 +0200 Subject: [PATCH] Add my-rainbow-editor extension for pi --- my-rainbow-editor.ts | 62 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 my-rainbow-editor.ts diff --git a/my-rainbow-editor.ts b/my-rainbow-editor.ts new file mode 100644 index 0000000..9bebc23 --- /dev/null +++ b/my-rainbow-editor.ts @@ -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)); + }); +} \ No newline at end of file