mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 07:04:45 +00:00
fix(tui): isolate blockquote rendering from default text style
This commit is contained in:
parent
3e611c135b
commit
f430dce00a
1 changed files with 36 additions and 17 deletions
|
|
@ -260,14 +260,19 @@ export class Markdown implements Component {
|
|||
};
|
||||
}
|
||||
|
||||
private renderToken(token: Token, width: number, nextTokenType?: string): string[] {
|
||||
private renderToken(
|
||||
token: Token,
|
||||
width: number,
|
||||
nextTokenType?: string,
|
||||
styleContext?: InlineStyleContext,
|
||||
): string[] {
|
||||
const lines: string[] = [];
|
||||
|
||||
switch (token.type) {
|
||||
case "heading": {
|
||||
const headingLevel = token.depth;
|
||||
const headingPrefix = `${"#".repeat(headingLevel)} `;
|
||||
const headingText = this.renderInlineTokens(token.tokens || []);
|
||||
const headingText = this.renderInlineTokens(token.tokens || [], styleContext);
|
||||
let styledHeading: string;
|
||||
if (headingLevel === 1) {
|
||||
styledHeading = this.theme.heading(this.theme.bold(this.theme.underline(headingText)));
|
||||
|
|
@ -284,7 +289,7 @@ export class Markdown implements Component {
|
|||
}
|
||||
|
||||
case "paragraph": {
|
||||
const paragraphText = this.renderInlineTokens(token.tokens || []);
|
||||
const paragraphText = this.renderInlineTokens(token.tokens || [], styleContext);
|
||||
lines.push(paragraphText);
|
||||
// Don't add spacing if next token is space or list
|
||||
if (nextTokenType && nextTokenType !== "list" && nextTokenType !== "space") {
|
||||
|
|
@ -316,7 +321,7 @@ export class Markdown implements Component {
|
|||
}
|
||||
|
||||
case "list": {
|
||||
const listLines = this.renderList(token as any, 0);
|
||||
const listLines = this.renderList(token as any, 0, styleContext);
|
||||
lines.push(...listLines);
|
||||
// Don't add spacing after lists if a space token follows
|
||||
// (the space token will handle it)
|
||||
|
|
@ -324,7 +329,7 @@ export class Markdown implements Component {
|
|||
}
|
||||
|
||||
case "table": {
|
||||
const tableLines = this.renderTable(token as any, width);
|
||||
const tableLines = this.renderTable(token as any, width, styleContext);
|
||||
lines.push(...tableLines);
|
||||
break;
|
||||
}
|
||||
|
|
@ -345,12 +350,19 @@ export class Markdown implements Component {
|
|||
|
||||
// Blockquotes contain block-level tokens (paragraph, list, code, etc.), so render
|
||||
// children with renderToken() instead of renderInlineTokens().
|
||||
// Default message style should not apply inside blockquotes.
|
||||
const quoteInlineStyleContext: InlineStyleContext = {
|
||||
applyText: (text: string) => text,
|
||||
stylePrefix: "",
|
||||
};
|
||||
const quoteTokens = token.tokens || [];
|
||||
const renderedQuoteLines: string[] = [];
|
||||
for (let i = 0; i < quoteTokens.length; i++) {
|
||||
const quoteToken = quoteTokens[i];
|
||||
const nextQuoteToken = quoteTokens[i + 1];
|
||||
renderedQuoteLines.push(...this.renderToken(quoteToken, quoteContentWidth, nextQuoteToken?.type));
|
||||
renderedQuoteLines.push(
|
||||
...this.renderToken(quoteToken, quoteContentWidth, nextQuoteToken?.type, quoteInlineStyleContext),
|
||||
);
|
||||
}
|
||||
|
||||
// Avoid rendering an extra empty quote line before the outer blockquote spacing.
|
||||
|
|
@ -490,7 +502,11 @@ export class Markdown implements Component {
|
|||
/**
|
||||
* Render a list with proper nesting support
|
||||
*/
|
||||
private renderList(token: Token & { items: any[]; ordered: boolean; start?: number }, depth: number): string[] {
|
||||
private renderList(
|
||||
token: Token & { items: any[]; ordered: boolean; start?: number },
|
||||
depth: number,
|
||||
styleContext?: InlineStyleContext,
|
||||
): string[] {
|
||||
const lines: string[] = [];
|
||||
const indent = " ".repeat(depth);
|
||||
// Use the list's start property (defaults to 1 for ordered lists)
|
||||
|
|
@ -501,7 +517,7 @@ export class Markdown implements Component {
|
|||
const bullet = token.ordered ? `${startNumber + i}. ` : "- ";
|
||||
|
||||
// Process item tokens to handle nested lists
|
||||
const itemLines = this.renderListItem(item.tokens || [], depth);
|
||||
const itemLines = this.renderListItem(item.tokens || [], depth, styleContext);
|
||||
|
||||
if (itemLines.length > 0) {
|
||||
// First line - check if it's a nested list
|
||||
|
|
@ -542,23 +558,25 @@ export class Markdown implements Component {
|
|||
* Render list item tokens, handling nested lists
|
||||
* Returns lines WITHOUT the parent indent (renderList will add it)
|
||||
*/
|
||||
private renderListItem(tokens: Token[], parentDepth: number): string[] {
|
||||
private renderListItem(tokens: Token[], parentDepth: number, styleContext?: InlineStyleContext): string[] {
|
||||
const lines: string[] = [];
|
||||
|
||||
for (const token of tokens) {
|
||||
if (token.type === "list") {
|
||||
// Nested list - render with one additional indent level
|
||||
// These lines will have their own indent, so we just add them as-is
|
||||
const nestedLines = this.renderList(token as any, parentDepth + 1);
|
||||
const nestedLines = this.renderList(token as any, parentDepth + 1, styleContext);
|
||||
lines.push(...nestedLines);
|
||||
} else if (token.type === "text") {
|
||||
// Text content (may have inline tokens)
|
||||
const text =
|
||||
token.tokens && token.tokens.length > 0 ? this.renderInlineTokens(token.tokens) : token.text || "";
|
||||
token.tokens && token.tokens.length > 0
|
||||
? this.renderInlineTokens(token.tokens, styleContext)
|
||||
: token.text || "";
|
||||
lines.push(text);
|
||||
} else if (token.type === "paragraph") {
|
||||
// Paragraph in list item
|
||||
const text = this.renderInlineTokens(token.tokens || []);
|
||||
const text = this.renderInlineTokens(token.tokens || [], styleContext);
|
||||
lines.push(text);
|
||||
} else if (token.type === "code") {
|
||||
// Code block in list item
|
||||
|
|
@ -578,7 +596,7 @@ export class Markdown implements Component {
|
|||
lines.push(this.theme.codeBlockBorder("```"));
|
||||
} else {
|
||||
// Other token types - try to render as inline
|
||||
const text = this.renderInlineTokens([token]);
|
||||
const text = this.renderInlineTokens([token], styleContext);
|
||||
if (text) {
|
||||
lines.push(text);
|
||||
}
|
||||
|
|
@ -620,6 +638,7 @@ export class Markdown implements Component {
|
|||
private renderTable(
|
||||
token: Token & { header: any[]; rows: any[][]; raw?: string },
|
||||
availableWidth: number,
|
||||
styleContext?: InlineStyleContext,
|
||||
): string[] {
|
||||
const lines: string[] = [];
|
||||
const numCols = token.header.length;
|
||||
|
|
@ -645,13 +664,13 @@ export class Markdown implements Component {
|
|||
const naturalWidths: number[] = [];
|
||||
const minWordWidths: number[] = [];
|
||||
for (let i = 0; i < numCols; i++) {
|
||||
const headerText = this.renderInlineTokens(token.header[i].tokens || []);
|
||||
const headerText = this.renderInlineTokens(token.header[i].tokens || [], styleContext);
|
||||
naturalWidths[i] = visibleWidth(headerText);
|
||||
minWordWidths[i] = Math.max(1, this.getLongestWordWidth(headerText, maxUnbrokenWordWidth));
|
||||
}
|
||||
for (const row of token.rows) {
|
||||
for (let i = 0; i < row.length; i++) {
|
||||
const cellText = this.renderInlineTokens(row[i].tokens || []);
|
||||
const cellText = this.renderInlineTokens(row[i].tokens || [], styleContext);
|
||||
naturalWidths[i] = Math.max(naturalWidths[i] || 0, visibleWidth(cellText));
|
||||
minWordWidths[i] = Math.max(
|
||||
minWordWidths[i] || 1,
|
||||
|
|
@ -736,7 +755,7 @@ export class Markdown implements Component {
|
|||
|
||||
// Render header with wrapping
|
||||
const headerCellLines: string[][] = token.header.map((cell, i) => {
|
||||
const text = this.renderInlineTokens(cell.tokens || []);
|
||||
const text = this.renderInlineTokens(cell.tokens || [], styleContext);
|
||||
return this.wrapCellText(text, columnWidths[i]);
|
||||
});
|
||||
const headerLineCount = Math.max(...headerCellLines.map((c) => c.length));
|
||||
|
|
@ -759,7 +778,7 @@ export class Markdown implements Component {
|
|||
for (let rowIndex = 0; rowIndex < token.rows.length; rowIndex++) {
|
||||
const row = token.rows[rowIndex];
|
||||
const rowCellLines: string[][] = row.map((cell, i) => {
|
||||
const text = this.renderInlineTokens(cell.tokens || []);
|
||||
const text = this.renderInlineTokens(cell.tokens || [], styleContext);
|
||||
return this.wrapCellText(text, columnWidths[i]);
|
||||
});
|
||||
const rowLineCount = Math.max(...rowCellLines.map((c) => c.length));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue