with one click
pi-tui-patch
// Regenerate the pi-tui patch for boxed code blocks when updating the @earendil-works/pi-tui dependency. Use when upgrading pi-tui or when the patch fails to apply.
// Regenerate the pi-tui patch for boxed code blocks when updating the @earendil-works/pi-tui dependency. Use when upgrading pi-tui or when the patch fails to apply.
| name | pi-tui-patch |
| description | Regenerate the pi-tui patch for boxed code blocks when updating the @earendil-works/pi-tui dependency. Use when upgrading pi-tui or when the patch fails to apply. |
This project patches @earendil-works/pi-tui to render code blocks with box borders instead of backtick markers.
@earendil-works/pi-tui to a new versionbun installpatches/@earendil-works%2Fpi-tui@<version>.patch
Modifies dist/components/markdown.js to:
BOX_CHARS constant for box drawing charactersrenderCodeBlock() method that renders code with borders:
╭─ javascript ──────────╮
│ const x = 1; │
╰───────────────────────╯
renderToken() case "code"bun remove @earendil-works/pi-tui
bun add @earendil-works/pi-tui@<new-version>
Change the version in patchedDependencies:
"patchedDependencies": {
"@earendil-works/pi-tui@<new-version>": "patches/@earendil-works%2Fpi-tui@<new-version>.patch"
}
rm patches/@earendil-works%2Fpi-tui@<old-version>.patch
Edit node_modules/@earendil-works/pi-tui/dist/components/markdown.js:
Add after markdownParser.setOptions(...):
// Box drawing characters for code blocks
const BOX_CHARS = {
topLeft: "╭",
topRight: "╮",
bottomLeft: "╰",
bottomRight: "╯",
horizontal: "─",
vertical: "│",
};
Add the renderCodeBlock method after getDefaultInlineStyleContext():
/**
* Render a code block with a box border and language label.
*/
renderCodeBlock(code, lang, availableWidth) {
const lines = [];
const borderStyle = this.theme.codeBlockBorder;
// Get highlighted or plain code lines
let codeLines;
if (this.theme.highlightCode) {
codeLines = this.theme.highlightCode(code, lang);
} else {
codeLines = code.split("\n").map(line => this.theme.codeBlock(line));
}
// Calculate the maximum line width (visible characters only)
let maxLineWidth = 0;
for (const line of codeLines) {
const lineWidth = visibleWidth(line);
if (lineWidth > maxLineWidth) {
maxLineWidth = lineWidth;
}
}
// Box inner width: max of (longest line + padding, lang label + padding)
const langLabel = lang || "";
const minWidthForLabel = langLabel.length + 4;
const innerWidth = Math.max(maxLineWidth + 2, minWidthForLabel);
// Build top border with language label
let topBorder;
if (langLabel) {
const labelPart = `${BOX_CHARS.horizontal} ${langLabel} `;
const remainingWidth = innerWidth - labelPart.length;
topBorder = BOX_CHARS.topLeft + labelPart + BOX_CHARS.horizontal.repeat(Math.max(0, remainingWidth)) + BOX_CHARS.topRight;
} else {
topBorder = BOX_CHARS.topLeft + BOX_CHARS.horizontal.repeat(innerWidth) + BOX_CHARS.topRight;
}
lines.push(borderStyle(topBorder));
// Render each code line with side borders
for (const codeLine of codeLines) {
const lineWidth = visibleWidth(codeLine);
const padding = " ".repeat(Math.max(0, innerWidth - lineWidth - 1));
const line = borderStyle(BOX_CHARS.vertical) + " " + codeLine + padding + borderStyle(BOX_CHARS.vertical);
lines.push(line);
}
// Build bottom border
const bottomBorder = BOX_CHARS.bottomLeft + BOX_CHARS.horizontal.repeat(innerWidth) + BOX_CHARS.bottomRight;
lines.push(borderStyle(bottomBorder));
return lines;
}
Replace the "code" case in renderToken():
Find:
case "code": {
lines.push(this.theme.codeBlockBorder(`\`\`\`${token.lang || ""}`));
// ... backtick rendering ...
lines.push(this.theme.codeBlockBorder("```"));
Replace with:
case "code": {
const codeBlockLines = this.renderCodeBlock(token.text, token.lang, width);
lines.push(...codeBlockLines);
bun patch --commit @earendil-works/pi-tui
bun run typecheck
bun run src/index.ts README.md
The full patched markdown.js can be found by applying the current patch and examining the result:
cat node_modules/@earendil-works/pi-tui/dist/components/markdown.js