Add markdown-body-color extension — color unwrapped markdown paragraphs
pi-tui's Markdown component only colors paragraph text when the caller passes a defaultTextStyle.color wrapper. Pi-coding-agent does this for thinking blocks but not for regular assistant content, so paragraphs emit uncoloured and inherit the terminal profile's foreground color (green on many themes). This extension monkey-patches Markdown.prototype.render to install a fallback defaultTextStyle (inkPurple #d4c5e8 by default, overridable via PI_MARKDOWN_BODY_COLOR) when one isn't already set. Thinking blocks and other custom-colored markdowns are untouched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
!/README.md
|
||||
!/ai-server/
|
||||
!/local-llama.ts
|
||||
!/markdown-body-color.ts
|
||||
!/mechanicus-banner.ts
|
||||
!/scripts/
|
||||
!/themes/
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* markdown-body-color — force a theme-aware color on markdown paragraph text.
|
||||
*
|
||||
* Why: pi-tui's Markdown component only wraps paragraph text in a color when
|
||||
* the caller passes a `defaultTextStyle.color` fn (assistant-message.js does
|
||||
* this for thinking blocks but not for regular assistant content). Without it,
|
||||
* paragraph output is emitted uncoloured and inherits the terminal profile's
|
||||
* foreground color — which on many terminal themes is green.
|
||||
*
|
||||
* Fix: monkey-patch Markdown.prototype.render so that if no defaultTextStyle
|
||||
* is set at render time, we install one that wraps output in the active pi
|
||||
* theme's `text` token color. This leaves thinking blocks and custom-colored
|
||||
* markdowns alone (they already have their own defaultTextStyle).
|
||||
*/
|
||||
|
||||
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
||||
import { Markdown } from "@mariozechner/pi-tui";
|
||||
|
||||
// Hardcoded fallback — matches themes/dark-mechanicus.json "inkPurple" var.
|
||||
// Override via PI_MARKDOWN_BODY_COLOR env var (hex, e.g. "#d4c5e8").
|
||||
const FALLBACK_HEX = process.env.PI_MARKDOWN_BODY_COLOR ?? "#d4c5e8";
|
||||
|
||||
function hexToRgb(hex: string): [number, number, number] {
|
||||
const m = hex.replace(/^#/, "");
|
||||
const n = parseInt(m.length === 3
|
||||
? m.split("").map((c) => c + c).join("")
|
||||
: m, 16);
|
||||
return [(n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff];
|
||||
}
|
||||
|
||||
const [R, G, B] = hexToRgb(FALLBACK_HEX);
|
||||
const OPEN = `\x1b[38;2;${R};${G};${B}m`;
|
||||
const CLOSE = `\x1b[39m`;
|
||||
|
||||
function wrapWithBodyColor(text: string): string {
|
||||
// Re-open the color after any existing `\x1b[39m` (default-fg reset) so
|
||||
// nested styled runs inside a paragraph don't bleed back to terminal fg.
|
||||
const safe = text.split(CLOSE).join(CLOSE + OPEN);
|
||||
return OPEN + safe + CLOSE;
|
||||
}
|
||||
|
||||
let patched = false;
|
||||
|
||||
export default function (_pi: ExtensionAPI) {
|
||||
if (patched) return;
|
||||
patched = true;
|
||||
|
||||
const proto = Markdown.prototype as any;
|
||||
const originalRender = proto.render;
|
||||
|
||||
proto.render = function (width: number) {
|
||||
if (!this.defaultTextStyle) {
|
||||
this.defaultTextStyle = { color: wrapWithBodyColor };
|
||||
// Force cache invalidation so the first post-patch render colors content.
|
||||
if (typeof this.invalidate === "function") this.invalidate();
|
||||
}
|
||||
return originalRender.call(this, width);
|
||||
};
|
||||
|
||||
console.log(
|
||||
`[markdown-body-color] Default markdown body color = ${FALLBACK_HEX}`,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user