fix: improve markdown rendering whitespace and list numbering

This commit is contained in:
mitchell 2026-05-25 23:18:40 -04:00
parent 0c71e2cd54
commit a887e1b185

View file

@ -41,7 +41,7 @@ class LmcRenderer extends Renderer {
const color = colors[depth - 1] ?? chalk.white; const color = colors[depth - 1] ?? chalk.white;
const text = this.parser.parseInline(tokens); const text = this.parser.parseInline(tokens);
return wrapAnsi( return wrapAnsi(
color.bold(`${"#".repeat(depth)} ${text}\n\n`), color.bold(`${"#".repeat(depth)} ${text}\n`),
this.columns, this.columns,
{ trim: false }, { trim: false },
); );
@ -49,23 +49,19 @@ class LmcRenderer extends Renderer {
override paragraph({ tokens }: Tokens.Paragraph) { override paragraph({ tokens }: Tokens.Paragraph) {
const text = this.parser.parseInline(tokens); const text = this.parser.parseInline(tokens);
return wrapAnsi(`${text}\n\n`, this.columns, { trim: false }); return wrapAnsi(`\n${text}\n`, this.columns, { trim: false });
} }
override blockquote({ tokens }: Tokens.Blockquote) { override blockquote({ tokens }: Tokens.Blockquote) {
const text = this.parser.parse(tokens).trim(); const text = this.parser.parse(tokens).trim();
const lines = wrapAnsi(text, this.columns - 2, { trim: false }) const lines = wrapAnsi(`\n${text}\n`, this.columns - 2, {
.replace(/\n+/g, "\n") trim: false,
.concat("\n") }).split("\n");
.split("\n"); const toRender = lines.map((line) => `> ${line}`).join("\n");
const toRender = lines return `${toRender.replaceAll(">", chalk.dim(">"))}\n`;
.map((line) => `> ${line}`)
.join("\n")
.concat("\n\n");
return toRender.replaceAll(">", chalk.dim(">"));
} }
override code({ text, lang, escaped: _ }: Tokens.Code) { override code({ text, lang }: Tokens.Code) {
let toRender = text; let toRender = text;
if (highlighter && lang) { if (highlighter && lang) {
@ -79,20 +75,26 @@ class LmcRenderer extends Renderer {
} catch {} } catch {}
} }
return `\`\`\`${chalk.blue(lang ?? "")}\n${toRender}\`\`\`\n`; return `\n\`\`\`${chalk.blue(lang ?? "")}\n${toRender}\n\`\`\`\n`;
} }
override list({ items }: Tokens.List) { override list({ items, ordered, start }: Tokens.List) {
const renderedItems = items.map((item) => this.listitem(item)).join(""); const num = start || 1;
const trimmed = renderedItems.replace(/\n+/g, "\n"); const renderedItems = items
return `${trimmed}\n`; .map((item, index) =>
this.listitem(item, ordered ? num + index : undefined),
)
.join("\n");
return `\n${renderedItems}\n`.replaceAll("\n\n", "\n");
} }
override listitem({ task, checked, tokens }: Tokens.ListItem) { override listitem({ task, checked, tokens }: Tokens.ListItem, num?: number) {
const text = this.parser.parse(tokens); const text = this.parser.parse(tokens);
let marker = ""; let marker = "";
if (task) { if (task) {
marker = checked ? "• [✓]" : "• [ ]"; marker = checked ? "• [✓]" : "• [ ]";
} else if (num !== undefined) {
marker = `${num}.`;
} else { } else {
marker = "•"; marker = "•";
} }
@ -101,12 +103,11 @@ class LmcRenderer extends Renderer {
return wrapAnsi(`${marker} ${text}`, cols, { trim: false }) return wrapAnsi(`${marker} ${text}`, cols, { trim: false })
.split("\n") .split("\n")
.map((line) => (line.length > 0 ? ` ${line}` : "")) .map((line) => (line.length > 0 ? ` ${line}` : ""))
.join("\n") .join("\n");
.concat("\n");
} }
override hr() { override hr() {
return `${chalk.dim("─".repeat(this.columns))}\n\n`; return `\n${chalk.dim("─".repeat(this.columns))}\n`;
} }
override table({ header, rows }: Tokens.Table) { override table({ header, rows }: Tokens.Table) {
@ -126,10 +127,10 @@ class LmcRenderer extends Renderer {
.header(headerCells) .header(headerCells)
.body(body) .body(body)
.border() .border()
.maxColWidth(Math.floor((this.columns - 3) / headerCells.length)) .maxColWidth(Math.floor((this.columns - 4) / headerCells.length))
.toString(); .toString();
return `${table}\n\n`; return `\n${table}\n`;
} }
override strong({ tokens }: Tokens.Strong) { override strong({ tokens }: Tokens.Strong) {
@ -157,7 +158,7 @@ class LmcRenderer extends Renderer {
} }
override image({ text: _ }: Tokens.Image) { override image({ text: _ }: Tokens.Image) {
return chalk.red("Images are unsupported (for now)\n"); return chalk.red("\nImages are unsupported (for now)\n");
} }
override text(token: Tokens.Text) { override text(token: Tokens.Text) {
@ -175,7 +176,11 @@ class LmcRenderer extends Renderer {
} }
override html({ text: _ }: Tokens.HTML | Tokens.Tag) { override html({ text: _ }: Tokens.HTML | Tokens.Tag) {
return chalk.red("HTML is unsupported\n"); return chalk.red("\nHTML is unsupported\n");
}
override br() {
return "\n";
} }
} }
@ -207,5 +212,5 @@ export async function renderMarkdown(
const rendered = await marked.parse(md); const rendered = await marked.parse(md);
return rendered.replace(/\n\n$/, "\n"); return rendered.trimStart();
} }