@mariozechner/pi-tui 0.7.18 → 0.7.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/markdown.d.ts +4 -5
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +47 -157
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/text.d.ts.map +1 -1
- package/dist/components/text.js +27 -82
- package/dist/components/text.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +12 -2
- package/dist/tui.js.map +1 -1
- package/dist/utils.d.ts +28 -5
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +180 -6
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -29,19 +29,18 @@ export declare class Markdown implements Component {
|
|
|
29
29
|
setText(text: string): void;
|
|
30
30
|
render(width: number): string[];
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
33
|
-
* Used for padding lines that don't have text content.
|
|
32
|
+
* Parse background color from defaultTextStyle to RGB values
|
|
34
33
|
*/
|
|
35
|
-
private
|
|
34
|
+
private parseBgColor;
|
|
36
35
|
/**
|
|
37
36
|
* Apply default text style to a string.
|
|
38
37
|
* This is the base styling applied to all text content.
|
|
38
|
+
* NOTE: Background color is NOT applied here - it's applied at the padding stage
|
|
39
|
+
* to ensure it extends to the full line width.
|
|
39
40
|
*/
|
|
40
41
|
private applyDefaultStyle;
|
|
41
42
|
private renderToken;
|
|
42
43
|
private renderInlineTokens;
|
|
43
|
-
private wrapLine;
|
|
44
|
-
private wrapSingleLine;
|
|
45
44
|
/**
|
|
46
45
|
* Render a list with proper nesting support
|
|
47
46
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/components/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAM3C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,kBAAkB;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yBAAyB;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,QAAS,YAAW,SAAS;IACzC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAG5C,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAW;IAE/B,YAAY,IAAI,GAAE,MAAW,EAAE,QAAQ,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAU,EAAE,gBAAgB,CAAC,EAAE,gBAAgB,EAK7G;IAED,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAM1B;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAuF9B;IAED;;;OAGG;IACH,OAAO,CAAC,YAAY;IAiBpB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAsDzB,OAAO,CAAC,WAAW;IAyFnB,OAAO,CAAC,kBAAkB;IAyE1B,OAAO,CAAC,QAAQ;IA0BhB,OAAO,CAAC,cAAc;IAmFtB;;OAEG;IACH,OAAO,CAAC,UAAU;IA8ClB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAsCtB;;OAEG;IACH,OAAO,CAAC,WAAW;CAqDnB","sourcesContent":["import { Chalk } from \"chalk\";\nimport { marked, type Token } from \"marked\";\nimport type { Component } from \"../tui.js\";\nimport { visibleWidth } from \"../utils.js\";\n\n// Use a chalk instance with color level 3 for consistent ANSI output\nconst colorChalk = new Chalk({ level: 3 });\n\n/**\n * Default text styling for markdown content.\n * Applied to all text unless overridden by markdown formatting.\n */\nexport interface DefaultTextStyle {\n\t/** Foreground color - named color or hex string like \"#ff0000\" */\n\tcolor?: string;\n\t/** Background color - named color or hex string like \"#ff0000\" */\n\tbgColor?: string;\n\t/** Bold text */\n\tbold?: boolean;\n\t/** Italic text */\n\titalic?: boolean;\n\t/** Strikethrough text */\n\tstrikethrough?: boolean;\n\t/** Underline text */\n\tunderline?: boolean;\n}\n\nexport class Markdown implements Component {\n\tprivate text: string;\n\tprivate paddingX: number; // Left/right padding\n\tprivate paddingY: number; // Top/bottom padding\n\tprivate defaultTextStyle?: DefaultTextStyle;\n\n\t// Cache for rendered output\n\tprivate cachedText?: string;\n\tprivate cachedWidth?: number;\n\tprivate cachedLines?: string[];\n\n\tconstructor(text: string = \"\", paddingX: number = 1, paddingY: number = 1, defaultTextStyle?: DefaultTextStyle) {\n\t\tthis.text = text;\n\t\tthis.paddingX = paddingX;\n\t\tthis.paddingY = paddingY;\n\t\tthis.defaultTextStyle = defaultTextStyle;\n\t}\n\n\tsetText(text: string): void {\n\t\tthis.text = text;\n\t\t// Invalidate cache when text changes\n\t\tthis.cachedText = undefined;\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\trender(width: number): string[] {\n\t\t// Check cache\n\t\tif (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\t// Calculate available width for content (subtract horizontal padding)\n\t\tconst contentWidth = Math.max(1, width - this.paddingX * 2);\n\n\t\t// Don't render anything if there's no actual text\n\t\tif (!this.text || this.text.trim() === \"\") {\n\t\t\tconst result: string[] = [];\n\t\t\t// Update cache\n\t\t\tthis.cachedText = this.text;\n\t\t\tthis.cachedWidth = width;\n\t\t\tthis.cachedLines = result;\n\t\t\treturn result;\n\t\t}\n\n\t\t// Replace tabs with 3 spaces for consistent rendering\n\t\tconst normalizedText = this.text.replace(/\\t/g, \" \");\n\n\t\t// Parse markdown to HTML-like tokens\n\t\tconst tokens = marked.lexer(normalizedText);\n\n\t\t// Convert tokens to styled terminal output\n\t\tconst renderedLines: string[] = [];\n\n\t\tfor (let i = 0; i < tokens.length; i++) {\n\t\t\tconst token = tokens[i];\n\t\t\tconst nextToken = tokens[i + 1];\n\t\t\tconst tokenLines = this.renderToken(token, contentWidth, nextToken?.type);\n\t\t\trenderedLines.push(...tokenLines);\n\t\t}\n\n\t\t// Wrap lines to fit content width\n\t\tconst wrappedLines: string[] = [];\n\t\tfor (const line of renderedLines) {\n\t\t\twrappedLines.push(...this.wrapLine(line, contentWidth));\n\t\t}\n\n\t\t// Add padding and apply background color if specified\n\t\tconst leftPad = \" \".repeat(this.paddingX);\n\t\tconst paddedLines: string[] = [];\n\n\t\tfor (const line of wrappedLines) {\n\t\t\t// Calculate visible length\n\t\t\tconst visibleLength = visibleWidth(line);\n\t\t\t// Right padding to fill to width (accounting for left padding and content)\n\t\t\tconst rightPadLength = Math.max(0, width - this.paddingX - visibleLength);\n\t\t\tconst rightPad = \" \".repeat(rightPadLength);\n\n\t\t\t// Add left padding, content, and right padding\n\t\t\tlet paddedLine = leftPad + line + rightPad;\n\n\t\t\t// Apply background color to entire line if specified\n\t\t\tif (this.defaultTextStyle?.bgColor) {\n\t\t\t\tpaddedLine = this.applyBgColor(paddedLine);\n\t\t\t}\n\n\t\t\tpaddedLines.push(paddedLine);\n\t\t}\n\n\t\t// Add top padding (empty lines)\n\t\tconst emptyLine = \" \".repeat(width);\n\t\tconst topPadding: string[] = [];\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tconst paddedEmptyLine = this.defaultTextStyle?.bgColor ? this.applyBgColor(emptyLine) : emptyLine;\n\t\t\ttopPadding.push(paddedEmptyLine);\n\t\t}\n\n\t\t// Add bottom padding (empty lines)\n\t\tconst bottomPadding: string[] = [];\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tconst paddedEmptyLine = this.defaultTextStyle?.bgColor ? this.applyBgColor(emptyLine) : emptyLine;\n\t\t\tbottomPadding.push(paddedEmptyLine);\n\t\t}\n\n\t\t// Combine top padding, content, and bottom padding\n\t\tconst result = [...topPadding, ...paddedLines, ...bottomPadding];\n\n\t\t// Update cache\n\t\tthis.cachedText = this.text;\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedLines = result;\n\n\t\treturn result.length > 0 ? result : [\"\"];\n\t}\n\n\t/**\n\t * Apply only background color from default style.\n\t * Used for padding lines that don't have text content.\n\t */\n\tprivate applyBgColor(text: string): string {\n\t\tif (!this.defaultTextStyle?.bgColor) {\n\t\t\treturn text;\n\t\t}\n\n\t\tif (this.defaultTextStyle.bgColor.startsWith(\"#\")) {\n\t\t\t// Hex color\n\t\t\tconst hex = this.defaultTextStyle.bgColor.substring(1);\n\t\t\tconst r = Number.parseInt(hex.substring(0, 2), 16);\n\t\t\tconst g = Number.parseInt(hex.substring(2, 4), 16);\n\t\t\tconst b = Number.parseInt(hex.substring(4, 6), 16);\n\t\t\treturn colorChalk.bgRgb(r, g, b)(text);\n\t\t}\n\t\t// Named background color (bgRed, bgBlue, etc.)\n\t\treturn (colorChalk as any)[this.defaultTextStyle.bgColor](text);\n\t}\n\n\t/**\n\t * Apply default text style to a string.\n\t * This is the base styling applied to all text content.\n\t */\n\tprivate applyDefaultStyle(text: string): string {\n\t\tif (!this.defaultTextStyle) {\n\t\t\treturn text;\n\t\t}\n\n\t\tlet styled = text;\n\n\t\t// Apply color\n\t\tif (this.defaultTextStyle.color) {\n\t\t\tif (this.defaultTextStyle.color.startsWith(\"#\")) {\n\t\t\t\t// Hex color\n\t\t\t\tconst hex = this.defaultTextStyle.color.substring(1);\n\t\t\t\tconst r = Number.parseInt(hex.substring(0, 2), 16);\n\t\t\t\tconst g = Number.parseInt(hex.substring(2, 4), 16);\n\t\t\t\tconst b = Number.parseInt(hex.substring(4, 6), 16);\n\t\t\t\tstyled = colorChalk.rgb(r, g, b)(styled);\n\t\t\t} else {\n\t\t\t\t// Named color\n\t\t\t\tstyled = (colorChalk as any)[this.defaultTextStyle.color](styled);\n\t\t\t}\n\t\t}\n\n\t\t// Apply background color\n\t\tif (this.defaultTextStyle.bgColor) {\n\t\t\tif (this.defaultTextStyle.bgColor.startsWith(\"#\")) {\n\t\t\t\t// Hex color\n\t\t\t\tconst hex = this.defaultTextStyle.bgColor.substring(1);\n\t\t\t\tconst r = Number.parseInt(hex.substring(0, 2), 16);\n\t\t\t\tconst g = Number.parseInt(hex.substring(2, 4), 16);\n\t\t\t\tconst b = Number.parseInt(hex.substring(4, 6), 16);\n\t\t\t\tstyled = colorChalk.bgRgb(r, g, b)(styled);\n\t\t\t} else {\n\t\t\t\t// Named background color (bgRed, bgBlue, etc.)\n\t\t\t\tstyled = (colorChalk as any)[this.defaultTextStyle.bgColor](styled);\n\t\t\t}\n\t\t}\n\n\t\t// Apply text decorations\n\t\tif (this.defaultTextStyle.bold) {\n\t\t\tstyled = colorChalk.bold(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.italic) {\n\t\t\tstyled = colorChalk.italic(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.strikethrough) {\n\t\t\tstyled = colorChalk.strikethrough(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.underline) {\n\t\t\tstyled = colorChalk.underline(styled);\n\t\t}\n\n\t\treturn styled;\n\t}\n\n\tprivate renderToken(token: Token, width: number, nextTokenType?: string): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tswitch (token.type) {\n\t\t\tcase \"heading\": {\n\t\t\t\tconst headingLevel = token.depth;\n\t\t\t\tconst headingPrefix = \"#\".repeat(headingLevel) + \" \";\n\t\t\t\tconst headingText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tif (headingLevel === 1) {\n\t\t\t\t\tlines.push(colorChalk.bold.underline.yellow(headingText));\n\t\t\t\t} else if (headingLevel === 2) {\n\t\t\t\t\tlines.push(colorChalk.bold.yellow(headingText));\n\t\t\t\t} else {\n\t\t\t\t\tlines.push(colorChalk.bold(headingPrefix + headingText));\n\t\t\t\t}\n\t\t\t\tlines.push(\"\"); // Add spacing after headings\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"paragraph\": {\n\t\t\t\tconst paragraphText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tlines.push(paragraphText);\n\t\t\t\t// Don't add spacing if next token is space or list\n\t\t\t\tif (nextTokenType && nextTokenType !== \"list\" && nextTokenType !== \"space\") {\n\t\t\t\t\tlines.push(\"\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"code\": {\n\t\t\t\tlines.push(colorChalk.gray(\"```\" + (token.lang || \"\")));\n\t\t\t\t// Split code by newlines and style each line\n\t\t\t\tconst codeLines = token.text.split(\"\\n\");\n\t\t\t\tfor (const codeLine of codeLines) {\n\t\t\t\t\tlines.push(colorChalk.dim(\" \") + colorChalk.green(codeLine));\n\t\t\t\t}\n\t\t\t\tlines.push(colorChalk.gray(\"```\"));\n\t\t\t\tlines.push(\"\"); // Add spacing after code blocks\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"list\": {\n\t\t\t\tconst listLines = this.renderList(token as any, 0);\n\t\t\t\tlines.push(...listLines);\n\t\t\t\t// Don't add spacing after lists if a space token follows\n\t\t\t\t// (the space token will handle it)\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"table\": {\n\t\t\t\tconst tableLines = this.renderTable(token as any);\n\t\t\t\tlines.push(...tableLines);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"blockquote\": {\n\t\t\t\tconst quoteText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tconst quoteLines = quoteText.split(\"\\n\");\n\t\t\t\tfor (const quoteLine of quoteLines) {\n\t\t\t\t\tlines.push(colorChalk.gray(\"│ \") + colorChalk.italic(quoteLine));\n\t\t\t\t}\n\t\t\t\tlines.push(\"\"); // Add spacing after blockquotes\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"hr\":\n\t\t\t\tlines.push(colorChalk.gray(\"─\".repeat(Math.min(width, 80))));\n\t\t\t\tlines.push(\"\"); // Add spacing after horizontal rules\n\t\t\t\tbreak;\n\n\t\t\tcase \"html\":\n\t\t\t\t// Skip HTML for terminal output\n\t\t\t\tbreak;\n\n\t\t\tcase \"space\":\n\t\t\t\t// Space tokens represent blank lines in markdown\n\t\t\t\tlines.push(\"\");\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t// Handle any other token types as plain text\n\t\t\t\tif (\"text\" in token && typeof token.text === \"string\") {\n\t\t\t\t\tlines.push(token.text);\n\t\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\tprivate renderInlineTokens(tokens: Token[]): string {\n\t\tlet result = \"\";\n\n\t\tfor (const token of tokens) {\n\t\t\tswitch (token.type) {\n\t\t\t\tcase \"text\":\n\t\t\t\t\t// Text tokens in list items can have nested tokens for inline formatting\n\t\t\t\t\tif (token.tokens && token.tokens.length > 0) {\n\t\t\t\t\t\tresult += this.renderInlineTokens(token.tokens);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Apply default style to plain text\n\t\t\t\t\t\tresult += this.applyDefaultStyle(token.text);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"strong\": {\n\t\t\t\t\t// Apply bold, then reapply default style after\n\t\t\t\t\tconst boldContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.bold(boldContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"em\": {\n\t\t\t\t\t// Apply italic, then reapply default style after\n\t\t\t\t\tconst italicContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.italic(italicContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"codespan\":\n\t\t\t\t\t// Apply code styling, then reapply default style after\n\t\t\t\t\tresult +=\n\t\t\t\t\t\tcolorChalk.gray(\"`\") +\n\t\t\t\t\t\tcolorChalk.cyan(token.text) +\n\t\t\t\t\t\tcolorChalk.gray(\"`\") +\n\t\t\t\t\t\tthis.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"link\": {\n\t\t\t\t\tconst linkText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\t// If link text matches href, only show the link once\n\t\t\t\t\tif (linkText === token.href) {\n\t\t\t\t\t\tresult += colorChalk.underline.blue(linkText) + this.applyDefaultStyle(\"\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult +=\n\t\t\t\t\t\t\tcolorChalk.underline.blue(linkText) +\n\t\t\t\t\t\t\tcolorChalk.gray(` (${token.href})`) +\n\t\t\t\t\t\t\tthis.applyDefaultStyle(\"\");\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"br\":\n\t\t\t\t\tresult += \"\\n\";\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"del\": {\n\t\t\t\t\tconst delContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.strikethrough(delContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\t// Handle any other inline token types as plain text\n\t\t\t\t\tif (\"text\" in token && typeof token.text === \"string\") {\n\t\t\t\t\t\tresult += this.applyDefaultStyle(token.text);\n\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate wrapLine(line: string, width: number): string[] {\n\t\t// Handle ANSI escape codes properly when wrapping\n\t\tconst wrapped: string[] = [];\n\n\t\t// Handle undefined or null lines\n\t\tif (!line) {\n\t\t\treturn [\"\"];\n\t\t}\n\n\t\t// Split by newlines first - wrap each line individually\n\t\tconst splitLines = line.split(\"\\n\");\n\t\tfor (const splitLine of splitLines) {\n\t\t\tconst visibleLength = visibleWidth(splitLine);\n\n\t\t\tif (visibleLength <= width) {\n\t\t\t\twrapped.push(splitLine);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// This line needs wrapping\n\t\t\twrapped.push(...this.wrapSingleLine(splitLine, width));\n\t\t}\n\n\t\treturn wrapped.length > 0 ? wrapped : [\"\"];\n\t}\n\n\tprivate wrapSingleLine(line: string, width: number): string[] {\n\t\tconst wrapped: string[] = [];\n\n\t\t// Track active ANSI codes to preserve them across wrapped lines\n\t\tconst activeAnsiCodes: string[] = [];\n\t\tlet currentLine = \"\";\n\t\tlet currentLength = 0;\n\t\tlet i = 0;\n\n\t\twhile (i < line.length) {\n\t\t\tif (line[i] === \"\\x1b\" && line[i + 1] === \"[\") {\n\t\t\t\t// ANSI escape sequence - parse and track it\n\t\t\t\tlet j = i + 2;\n\t\t\t\twhile (j < line.length && line[j] && !/[mGKHJ]/.test(line[j]!)) {\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t\tif (j < line.length) {\n\t\t\t\t\tconst ansiCode = line.substring(i, j + 1);\n\t\t\t\t\tcurrentLine += ansiCode;\n\n\t\t\t\t\t// Track styling codes (ending with 'm')\n\t\t\t\t\tif (line[j] === \"m\") {\n\t\t\t\t\t\t// Reset code\n\t\t\t\t\t\tif (ansiCode === \"\\x1b[0m\" || ansiCode === \"\\x1b[m\") {\n\t\t\t\t\t\t\tactiveAnsiCodes.length = 0;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Add to active codes (replacing similar ones)\n\t\t\t\t\t\t\tactiveAnsiCodes.push(ansiCode);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ti = j + 1;\n\t\t\t\t} else {\n\t\t\t\t\t// Incomplete ANSI sequence at end - don't include it\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Regular character - extract full grapheme cluster\n\t\t\t\t// Handle multi-byte characters (emoji, surrogate pairs, etc.)\n\t\t\t\tlet char: string;\n\t\t\t\tlet charByteLength: number;\n\n\t\t\t\t// Check for surrogate pair (emoji and other multi-byte chars)\n\t\t\t\tconst codePoint = line.charCodeAt(i);\n\t\t\t\tif (codePoint >= 0xd800 && codePoint <= 0xdbff && i + 1 < line.length) {\n\t\t\t\t\t// High surrogate - get the pair\n\t\t\t\t\tchar = line.substring(i, i + 2);\n\t\t\t\t\tcharByteLength = 2;\n\t\t\t\t} else {\n\t\t\t\t\t// Regular character\n\t\t\t\t\tchar = line[i];\n\t\t\t\t\tcharByteLength = 1;\n\t\t\t\t}\n\n\t\t\t\tconst charWidth = visibleWidth(char);\n\n\t\t\t\t// Check if adding this character would exceed width\n\t\t\t\tif (currentLength + charWidth > width) {\n\t\t\t\t\t// Need to wrap - close current line with reset if needed\n\t\t\t\t\tif (activeAnsiCodes.length > 0) {\n\t\t\t\t\t\twrapped.push(currentLine + \"\\x1b[0m\");\n\t\t\t\t\t\t// Start new line with active codes\n\t\t\t\t\t\tcurrentLine = activeAnsiCodes.join(\"\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\twrapped.push(currentLine);\n\t\t\t\t\t\tcurrentLine = \"\";\n\t\t\t\t\t}\n\t\t\t\t\tcurrentLength = 0;\n\t\t\t\t}\n\n\t\t\t\tcurrentLine += char;\n\t\t\t\tcurrentLength += charWidth;\n\t\t\t\ti += charByteLength;\n\t\t\t}\n\t\t}\n\n\t\tif (currentLine) {\n\t\t\twrapped.push(currentLine);\n\t\t}\n\n\t\treturn wrapped.length > 0 ? wrapped : [\"\"];\n\t}\n\n\t/**\n\t * Render a list with proper nesting support\n\t */\n\tprivate renderList(token: Token & { items: any[]; ordered: boolean }, depth: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst indent = \" \".repeat(depth);\n\n\t\tfor (let i = 0; i < token.items.length; i++) {\n\t\t\tconst item = token.items[i];\n\t\t\tconst bullet = token.ordered ? `${i + 1}. ` : \"- \";\n\n\t\t\t// Process item tokens to handle nested lists\n\t\t\tconst itemLines = this.renderListItem(item.tokens || [], depth);\n\n\t\t\tif (itemLines.length > 0) {\n\t\t\t\t// First line - check if it's a nested list\n\t\t\t\t// A nested list will start with indent (spaces) followed by cyan bullet\n\t\t\t\tconst firstLine = itemLines[0];\n\t\t\t\tconst isNestedList = /^\\s+\\x1b\\[36m[-\\d]/.test(firstLine); // starts with spaces + cyan + bullet char\n\n\t\t\t\tif (isNestedList) {\n\t\t\t\t\t// This is a nested list, just add it as-is (already has full indent)\n\t\t\t\t\tlines.push(firstLine);\n\t\t\t\t} else {\n\t\t\t\t\t// Regular text content - add indent and bullet\n\t\t\t\t\tlines.push(indent + colorChalk.cyan(bullet) + firstLine);\n\t\t\t\t}\n\n\t\t\t\t// Rest of the lines\n\t\t\t\tfor (let j = 1; j < itemLines.length; j++) {\n\t\t\t\t\tconst line = itemLines[j];\n\t\t\t\t\tconst isNestedListLine = /^\\s+\\x1b\\[36m[-\\d]/.test(line); // starts with spaces + cyan + bullet char\n\n\t\t\t\t\tif (isNestedListLine) {\n\t\t\t\t\t\t// Nested list line - already has full indent\n\t\t\t\t\t\tlines.push(line);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Regular content - add parent indent + 2 spaces for continuation\n\t\t\t\t\t\tlines.push(indent + \" \" + line);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlines.push(indent + colorChalk.cyan(bullet));\n\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Render list item tokens, handling nested lists\n\t * Returns lines WITHOUT the parent indent (renderList will add it)\n\t */\n\tprivate renderListItem(tokens: Token[], parentDepth: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tfor (const token of tokens) {\n\t\t\tif (token.type === \"list\") {\n\t\t\t\t// Nested list - render with one additional indent level\n\t\t\t\t// These lines will have their own indent, so we just add them as-is\n\t\t\t\tconst nestedLines = this.renderList(token as any, parentDepth + 1);\n\t\t\t\tlines.push(...nestedLines);\n\t\t\t} else if (token.type === \"text\") {\n\t\t\t\t// Text content (may have inline tokens)\n\t\t\t\tconst text =\n\t\t\t\t\ttoken.tokens && token.tokens.length > 0 ? this.renderInlineTokens(token.tokens) : token.text || \"\";\n\t\t\t\tlines.push(text);\n\t\t\t} else if (token.type === \"paragraph\") {\n\t\t\t\t// Paragraph in list item\n\t\t\t\tconst text = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tlines.push(text);\n\t\t\t} else if (token.type === \"code\") {\n\t\t\t\t// Code block in list item\n\t\t\t\tlines.push(colorChalk.gray(\"```\" + (token.lang || \"\")));\n\t\t\t\tconst codeLines = token.text.split(\"\\n\");\n\t\t\t\tfor (const codeLine of codeLines) {\n\t\t\t\t\tlines.push(colorChalk.dim(\" \") + colorChalk.green(codeLine));\n\t\t\t\t}\n\t\t\t\tlines.push(colorChalk.gray(\"```\"));\n\t\t\t} else {\n\t\t\t\t// Other token types - try to render as inline\n\t\t\t\tconst text = this.renderInlineTokens([token]);\n\t\t\t\tif (text) {\n\t\t\t\t\tlines.push(text);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Render a table\n\t */\n\tprivate renderTable(token: Token & { header: any[]; rows: any[][] }): string[] {\n\t\tconst lines: string[] = [];\n\n\t\t// Calculate column widths\n\t\tconst columnWidths: number[] = [];\n\n\t\t// Check header\n\t\tfor (let i = 0; i < token.header.length; i++) {\n\t\t\tconst headerText = this.renderInlineTokens(token.header[i].tokens || []);\n\t\t\tconst width = visibleWidth(headerText);\n\t\t\tcolumnWidths[i] = Math.max(columnWidths[i] || 0, width);\n\t\t}\n\n\t\t// Check rows\n\t\tfor (const row of token.rows) {\n\t\t\tfor (let i = 0; i < row.length; i++) {\n\t\t\t\tconst cellText = this.renderInlineTokens(row[i].tokens || []);\n\t\t\t\tconst width = visibleWidth(cellText);\n\t\t\t\tcolumnWidths[i] = Math.max(columnWidths[i] || 0, width);\n\t\t\t}\n\t\t}\n\n\t\t// Limit column widths to reasonable max\n\t\tconst maxColWidth = 40;\n\t\tfor (let i = 0; i < columnWidths.length; i++) {\n\t\t\tcolumnWidths[i] = Math.min(columnWidths[i], maxColWidth);\n\t\t}\n\n\t\t// Render header\n\t\tconst headerCells = token.header.map((cell, i) => {\n\t\t\tconst text = this.renderInlineTokens(cell.tokens || []);\n\t\t\treturn colorChalk.bold(text.padEnd(columnWidths[i]));\n\t\t});\n\t\tlines.push(\"│ \" + headerCells.join(\" │ \") + \" │\");\n\n\t\t// Render separator\n\t\tconst separatorCells = columnWidths.map((width) => \"─\".repeat(width));\n\t\tlines.push(\"├─\" + separatorCells.join(\"─┼─\") + \"─┤\");\n\n\t\t// Render rows\n\t\tfor (const row of token.rows) {\n\t\t\tconst rowCells = row.map((cell, i) => {\n\t\t\t\tconst text = this.renderInlineTokens(cell.tokens || []);\n\t\t\t\tconst visWidth = visibleWidth(text);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, columnWidths[i] - visWidth));\n\t\t\t\treturn text + padding;\n\t\t\t});\n\t\t\tlines.push(\"│ \" + rowCells.join(\" │ \") + \" │\");\n\t\t}\n\n\t\tlines.push(\"\"); // Add spacing after table\n\t\treturn lines;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/components/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAM3C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,kBAAkB;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yBAAyB;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,qBAAa,QAAS,YAAW,SAAS;IACzC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAG5C,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAC,CAAW;IAE/B,YAAY,IAAI,GAAE,MAAW,EAAE,QAAQ,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAU,EAAE,gBAAgB,CAAC,EAAE,gBAAgB,EAK7G;IAED,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAM1B;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA6E9B;IAED;;OAEG;IACH,OAAO,CAAC,YAAY;IA8BpB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,WAAW;IAyFnB,OAAO,CAAC,kBAAkB;IAqE1B;;OAEG;IACH,OAAO,CAAC,UAAU;IA8ClB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAsCtB;;OAEG;IACH,OAAO,CAAC,WAAW;CAqDnB","sourcesContent":["import { Chalk } from \"chalk\";\nimport { marked, type Token } from \"marked\";\nimport type { Component } from \"../tui.js\";\nimport { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from \"../utils.js\";\n\n// Use a chalk instance with color level 3 for consistent ANSI output\nconst colorChalk = new Chalk({ level: 3 });\n\n/**\n * Default text styling for markdown content.\n * Applied to all text unless overridden by markdown formatting.\n */\nexport interface DefaultTextStyle {\n\t/** Foreground color - named color or hex string like \"#ff0000\" */\n\tcolor?: string;\n\t/** Background color - named color or hex string like \"#ff0000\" */\n\tbgColor?: string;\n\t/** Bold text */\n\tbold?: boolean;\n\t/** Italic text */\n\titalic?: boolean;\n\t/** Strikethrough text */\n\tstrikethrough?: boolean;\n\t/** Underline text */\n\tunderline?: boolean;\n}\n\nexport class Markdown implements Component {\n\tprivate text: string;\n\tprivate paddingX: number; // Left/right padding\n\tprivate paddingY: number; // Top/bottom padding\n\tprivate defaultTextStyle?: DefaultTextStyle;\n\n\t// Cache for rendered output\n\tprivate cachedText?: string;\n\tprivate cachedWidth?: number;\n\tprivate cachedLines?: string[];\n\n\tconstructor(text: string = \"\", paddingX: number = 1, paddingY: number = 1, defaultTextStyle?: DefaultTextStyle) {\n\t\tthis.text = text;\n\t\tthis.paddingX = paddingX;\n\t\tthis.paddingY = paddingY;\n\t\tthis.defaultTextStyle = defaultTextStyle;\n\t}\n\n\tsetText(text: string): void {\n\t\tthis.text = text;\n\t\t// Invalidate cache when text changes\n\t\tthis.cachedText = undefined;\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\trender(width: number): string[] {\n\t\t// Check cache\n\t\tif (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\t// Calculate available width for content (subtract horizontal padding)\n\t\tconst contentWidth = Math.max(1, width - this.paddingX * 2);\n\n\t\t// Don't render anything if there's no actual text\n\t\tif (!this.text || this.text.trim() === \"\") {\n\t\t\tconst result: string[] = [];\n\t\t\t// Update cache\n\t\t\tthis.cachedText = this.text;\n\t\t\tthis.cachedWidth = width;\n\t\t\tthis.cachedLines = result;\n\t\t\treturn result;\n\t\t}\n\n\t\t// Replace tabs with 3 spaces for consistent rendering\n\t\tconst normalizedText = this.text.replace(/\\t/g, \" \");\n\n\t\t// Parse markdown to HTML-like tokens\n\t\tconst tokens = marked.lexer(normalizedText);\n\n\t\t// Convert tokens to styled terminal output\n\t\tconst renderedLines: string[] = [];\n\n\t\tfor (let i = 0; i < tokens.length; i++) {\n\t\t\tconst token = tokens[i];\n\t\t\tconst nextToken = tokens[i + 1];\n\t\t\tconst tokenLines = this.renderToken(token, contentWidth, nextToken?.type);\n\t\t\trenderedLines.push(...tokenLines);\n\t\t}\n\n\t\t// Wrap lines (NO padding, NO background yet)\n\t\tconst wrappedLines: string[] = [];\n\t\tfor (const line of renderedLines) {\n\t\t\twrappedLines.push(...wrapTextWithAnsi(line, contentWidth));\n\t\t}\n\n\t\t// Add margins and background to each wrapped line\n\t\tconst leftMargin = \" \".repeat(this.paddingX);\n\t\tconst rightMargin = \" \".repeat(this.paddingX);\n\t\tconst bgRgb = this.defaultTextStyle?.bgColor ? this.parseBgColor() : undefined;\n\t\tconst contentLines: string[] = [];\n\n\t\tfor (const line of wrappedLines) {\n\t\t\tconst lineWithMargins = leftMargin + line + rightMargin;\n\n\t\t\tif (bgRgb) {\n\t\t\t\tcontentLines.push(applyBackgroundToLine(lineWithMargins, width, bgRgb));\n\t\t\t} else {\n\t\t\t\t// No background - just pad to width\n\t\t\t\tconst visibleLen = visibleWidth(lineWithMargins);\n\t\t\t\tconst paddingNeeded = Math.max(0, width - visibleLen);\n\t\t\t\tcontentLines.push(lineWithMargins + \" \".repeat(paddingNeeded));\n\t\t\t}\n\t\t}\n\n\t\t// Add top/bottom padding (empty lines)\n\t\tconst emptyLine = \" \".repeat(width);\n\t\tconst emptyLines: string[] = [];\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tconst line = bgRgb ? applyBackgroundToLine(emptyLine, width, bgRgb) : emptyLine;\n\t\t\temptyLines.push(line);\n\t\t}\n\n\t\t// Combine top padding, content, and bottom padding\n\t\tconst result = [...emptyLines, ...contentLines, ...emptyLines];\n\n\t\t// Update cache\n\t\tthis.cachedText = this.text;\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedLines = result;\n\n\t\treturn result.length > 0 ? result : [\"\"];\n\t}\n\n\t/**\n\t * Parse background color from defaultTextStyle to RGB values\n\t */\n\tprivate parseBgColor(): { r: number; g: number; b: number } | undefined {\n\t\tif (!this.defaultTextStyle?.bgColor) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (this.defaultTextStyle.bgColor.startsWith(\"#\")) {\n\t\t\t// Hex color\n\t\t\tconst hex = this.defaultTextStyle.bgColor.substring(1);\n\t\t\treturn {\n\t\t\t\tr: Number.parseInt(hex.substring(0, 2), 16),\n\t\t\t\tg: Number.parseInt(hex.substring(2, 4), 16),\n\t\t\t\tb: Number.parseInt(hex.substring(4, 6), 16),\n\t\t\t};\n\t\t}\n\n\t\t// Named colors - map to RGB (common terminal colors)\n\t\tconst colorMap: Record<string, { r: number; g: number; b: number }> = {\n\t\t\tbgBlack: { r: 0, g: 0, b: 0 },\n\t\t\tbgRed: { r: 255, g: 0, b: 0 },\n\t\t\tbgGreen: { r: 0, g: 255, b: 0 },\n\t\t\tbgYellow: { r: 255, g: 255, b: 0 },\n\t\t\tbgBlue: { r: 0, g: 0, b: 255 },\n\t\t\tbgMagenta: { r: 255, g: 0, b: 255 },\n\t\t\tbgCyan: { r: 0, g: 255, b: 255 },\n\t\t\tbgWhite: { r: 255, g: 255, b: 255 },\n\t\t};\n\n\t\treturn colorMap[this.defaultTextStyle.bgColor];\n\t}\n\n\t/**\n\t * Apply default text style to a string.\n\t * This is the base styling applied to all text content.\n\t * NOTE: Background color is NOT applied here - it's applied at the padding stage\n\t * to ensure it extends to the full line width.\n\t */\n\tprivate applyDefaultStyle(text: string): string {\n\t\tif (!this.defaultTextStyle) {\n\t\t\treturn text;\n\t\t}\n\n\t\tlet styled = text;\n\n\t\t// Apply foreground color (NOT background - that's applied at padding stage)\n\t\tif (this.defaultTextStyle.color) {\n\t\t\tif (this.defaultTextStyle.color.startsWith(\"#\")) {\n\t\t\t\t// Hex color\n\t\t\t\tconst hex = this.defaultTextStyle.color.substring(1);\n\t\t\t\tconst r = Number.parseInt(hex.substring(0, 2), 16);\n\t\t\t\tconst g = Number.parseInt(hex.substring(2, 4), 16);\n\t\t\t\tconst b = Number.parseInt(hex.substring(4, 6), 16);\n\t\t\t\tstyled = colorChalk.rgb(r, g, b)(styled);\n\t\t\t} else {\n\t\t\t\t// Named color\n\t\t\t\tstyled = (colorChalk as any)[this.defaultTextStyle.color](styled);\n\t\t\t}\n\t\t}\n\n\t\t// Apply text decorations\n\t\tif (this.defaultTextStyle.bold) {\n\t\t\tstyled = colorChalk.bold(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.italic) {\n\t\t\tstyled = colorChalk.italic(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.strikethrough) {\n\t\t\tstyled = colorChalk.strikethrough(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.underline) {\n\t\t\tstyled = colorChalk.underline(styled);\n\t\t}\n\n\t\treturn styled;\n\t}\n\n\tprivate renderToken(token: Token, width: number, nextTokenType?: string): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tswitch (token.type) {\n\t\t\tcase \"heading\": {\n\t\t\t\tconst headingLevel = token.depth;\n\t\t\t\tconst headingPrefix = \"#\".repeat(headingLevel) + \" \";\n\t\t\t\tconst headingText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tif (headingLevel === 1) {\n\t\t\t\t\tlines.push(colorChalk.bold.underline.yellow(headingText));\n\t\t\t\t} else if (headingLevel === 2) {\n\t\t\t\t\tlines.push(colorChalk.bold.yellow(headingText));\n\t\t\t\t} else {\n\t\t\t\t\tlines.push(colorChalk.bold(headingPrefix + headingText));\n\t\t\t\t}\n\t\t\t\tlines.push(\"\"); // Add spacing after headings\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"paragraph\": {\n\t\t\t\tconst paragraphText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tlines.push(paragraphText);\n\t\t\t\t// Don't add spacing if next token is space or list\n\t\t\t\tif (nextTokenType && nextTokenType !== \"list\" && nextTokenType !== \"space\") {\n\t\t\t\t\tlines.push(\"\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"code\": {\n\t\t\t\tlines.push(colorChalk.gray(\"```\" + (token.lang || \"\")));\n\t\t\t\t// Split code by newlines and style each line\n\t\t\t\tconst codeLines = token.text.split(\"\\n\");\n\t\t\t\tfor (const codeLine of codeLines) {\n\t\t\t\t\tlines.push(colorChalk.dim(\" \") + colorChalk.green(codeLine));\n\t\t\t\t}\n\t\t\t\tlines.push(colorChalk.gray(\"```\"));\n\t\t\t\tlines.push(\"\"); // Add spacing after code blocks\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"list\": {\n\t\t\t\tconst listLines = this.renderList(token as any, 0);\n\t\t\t\tlines.push(...listLines);\n\t\t\t\t// Don't add spacing after lists if a space token follows\n\t\t\t\t// (the space token will handle it)\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"table\": {\n\t\t\t\tconst tableLines = this.renderTable(token as any);\n\t\t\t\tlines.push(...tableLines);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"blockquote\": {\n\t\t\t\tconst quoteText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tconst quoteLines = quoteText.split(\"\\n\");\n\t\t\t\tfor (const quoteLine of quoteLines) {\n\t\t\t\t\tlines.push(colorChalk.gray(\"│ \") + colorChalk.italic(quoteLine));\n\t\t\t\t}\n\t\t\t\tlines.push(\"\"); // Add spacing after blockquotes\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"hr\":\n\t\t\t\tlines.push(colorChalk.gray(\"─\".repeat(Math.min(width, 80))));\n\t\t\t\tlines.push(\"\"); // Add spacing after horizontal rules\n\t\t\t\tbreak;\n\n\t\t\tcase \"html\":\n\t\t\t\t// Skip HTML for terminal output\n\t\t\t\tbreak;\n\n\t\t\tcase \"space\":\n\t\t\t\t// Space tokens represent blank lines in markdown\n\t\t\t\tlines.push(\"\");\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t// Handle any other token types as plain text\n\t\t\t\tif (\"text\" in token && typeof token.text === \"string\") {\n\t\t\t\t\tlines.push(token.text);\n\t\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\tprivate renderInlineTokens(tokens: Token[]): string {\n\t\tlet result = \"\";\n\n\t\tfor (const token of tokens) {\n\t\t\tswitch (token.type) {\n\t\t\t\tcase \"text\":\n\t\t\t\t\t// Text tokens in list items can have nested tokens for inline formatting\n\t\t\t\t\tif (token.tokens && token.tokens.length > 0) {\n\t\t\t\t\t\tresult += this.renderInlineTokens(token.tokens);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Apply default style to plain text\n\t\t\t\t\t\tresult += this.applyDefaultStyle(token.text);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"strong\": {\n\t\t\t\t\t// Apply bold, then reapply default style after\n\t\t\t\t\tconst boldContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.bold(boldContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"em\": {\n\t\t\t\t\t// Apply italic, then reapply default style after\n\t\t\t\t\tconst italicContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.italic(italicContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"codespan\":\n\t\t\t\t\t// Apply code styling without backticks\n\t\t\t\t\tresult += colorChalk.cyan(token.text) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"link\": {\n\t\t\t\t\tconst linkText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\t// If link text matches href, only show the link once\n\t\t\t\t\tif (linkText === token.href) {\n\t\t\t\t\t\tresult += colorChalk.underline.blue(linkText) + this.applyDefaultStyle(\"\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult +=\n\t\t\t\t\t\t\tcolorChalk.underline.blue(linkText) +\n\t\t\t\t\t\t\tcolorChalk.gray(` (${token.href})`) +\n\t\t\t\t\t\t\tthis.applyDefaultStyle(\"\");\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"br\":\n\t\t\t\t\tresult += \"\\n\";\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"del\": {\n\t\t\t\t\tconst delContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.strikethrough(delContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\t// Handle any other inline token types as plain text\n\t\t\t\t\tif (\"text\" in token && typeof token.text === \"string\") {\n\t\t\t\t\t\tresult += this.applyDefaultStyle(token.text);\n\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Render a list with proper nesting support\n\t */\n\tprivate renderList(token: Token & { items: any[]; ordered: boolean }, depth: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst indent = \" \".repeat(depth);\n\n\t\tfor (let i = 0; i < token.items.length; i++) {\n\t\t\tconst item = token.items[i];\n\t\t\tconst bullet = token.ordered ? `${i + 1}. ` : \"- \";\n\n\t\t\t// Process item tokens to handle nested lists\n\t\t\tconst itemLines = this.renderListItem(item.tokens || [], depth);\n\n\t\t\tif (itemLines.length > 0) {\n\t\t\t\t// First line - check if it's a nested list\n\t\t\t\t// A nested list will start with indent (spaces) followed by cyan bullet\n\t\t\t\tconst firstLine = itemLines[0];\n\t\t\t\tconst isNestedList = /^\\s+\\x1b\\[36m[-\\d]/.test(firstLine); // starts with spaces + cyan + bullet char\n\n\t\t\t\tif (isNestedList) {\n\t\t\t\t\t// This is a nested list, just add it as-is (already has full indent)\n\t\t\t\t\tlines.push(firstLine);\n\t\t\t\t} else {\n\t\t\t\t\t// Regular text content - add indent and bullet\n\t\t\t\t\tlines.push(indent + colorChalk.cyan(bullet) + firstLine);\n\t\t\t\t}\n\n\t\t\t\t// Rest of the lines\n\t\t\t\tfor (let j = 1; j < itemLines.length; j++) {\n\t\t\t\t\tconst line = itemLines[j];\n\t\t\t\t\tconst isNestedListLine = /^\\s+\\x1b\\[36m[-\\d]/.test(line); // starts with spaces + cyan + bullet char\n\n\t\t\t\t\tif (isNestedListLine) {\n\t\t\t\t\t\t// Nested list line - already has full indent\n\t\t\t\t\t\tlines.push(line);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Regular content - add parent indent + 2 spaces for continuation\n\t\t\t\t\t\tlines.push(indent + \" \" + line);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlines.push(indent + colorChalk.cyan(bullet));\n\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Render list item tokens, handling nested lists\n\t * Returns lines WITHOUT the parent indent (renderList will add it)\n\t */\n\tprivate renderListItem(tokens: Token[], parentDepth: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tfor (const token of tokens) {\n\t\t\tif (token.type === \"list\") {\n\t\t\t\t// Nested list - render with one additional indent level\n\t\t\t\t// These lines will have their own indent, so we just add them as-is\n\t\t\t\tconst nestedLines = this.renderList(token as any, parentDepth + 1);\n\t\t\t\tlines.push(...nestedLines);\n\t\t\t} else if (token.type === \"text\") {\n\t\t\t\t// Text content (may have inline tokens)\n\t\t\t\tconst text =\n\t\t\t\t\ttoken.tokens && token.tokens.length > 0 ? this.renderInlineTokens(token.tokens) : token.text || \"\";\n\t\t\t\tlines.push(text);\n\t\t\t} else if (token.type === \"paragraph\") {\n\t\t\t\t// Paragraph in list item\n\t\t\t\tconst text = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tlines.push(text);\n\t\t\t} else if (token.type === \"code\") {\n\t\t\t\t// Code block in list item\n\t\t\t\tlines.push(colorChalk.gray(\"```\" + (token.lang || \"\")));\n\t\t\t\tconst codeLines = token.text.split(\"\\n\");\n\t\t\t\tfor (const codeLine of codeLines) {\n\t\t\t\t\tlines.push(colorChalk.dim(\" \") + colorChalk.green(codeLine));\n\t\t\t\t}\n\t\t\t\tlines.push(colorChalk.gray(\"```\"));\n\t\t\t} else {\n\t\t\t\t// Other token types - try to render as inline\n\t\t\t\tconst text = this.renderInlineTokens([token]);\n\t\t\t\tif (text) {\n\t\t\t\t\tlines.push(text);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Render a table\n\t */\n\tprivate renderTable(token: Token & { header: any[]; rows: any[][] }): string[] {\n\t\tconst lines: string[] = [];\n\n\t\t// Calculate column widths\n\t\tconst columnWidths: number[] = [];\n\n\t\t// Check header\n\t\tfor (let i = 0; i < token.header.length; i++) {\n\t\t\tconst headerText = this.renderInlineTokens(token.header[i].tokens || []);\n\t\t\tconst width = visibleWidth(headerText);\n\t\t\tcolumnWidths[i] = Math.max(columnWidths[i] || 0, width);\n\t\t}\n\n\t\t// Check rows\n\t\tfor (const row of token.rows) {\n\t\t\tfor (let i = 0; i < row.length; i++) {\n\t\t\t\tconst cellText = this.renderInlineTokens(row[i].tokens || []);\n\t\t\t\tconst width = visibleWidth(cellText);\n\t\t\t\tcolumnWidths[i] = Math.max(columnWidths[i] || 0, width);\n\t\t\t}\n\t\t}\n\n\t\t// Limit column widths to reasonable max\n\t\tconst maxColWidth = 40;\n\t\tfor (let i = 0; i < columnWidths.length; i++) {\n\t\t\tcolumnWidths[i] = Math.min(columnWidths[i], maxColWidth);\n\t\t}\n\n\t\t// Render header\n\t\tconst headerCells = token.header.map((cell, i) => {\n\t\t\tconst text = this.renderInlineTokens(cell.tokens || []);\n\t\t\treturn colorChalk.bold(text.padEnd(columnWidths[i]));\n\t\t});\n\t\tlines.push(\"│ \" + headerCells.join(\" │ \") + \" │\");\n\n\t\t// Render separator\n\t\tconst separatorCells = columnWidths.map((width) => \"─\".repeat(width));\n\t\tlines.push(\"├─\" + separatorCells.join(\"─┼─\") + \"─┤\");\n\n\t\t// Render rows\n\t\tfor (const row of token.rows) {\n\t\t\tconst rowCells = row.map((cell, i) => {\n\t\t\t\tconst text = this.renderInlineTokens(cell.tokens || []);\n\t\t\t\tconst visWidth = visibleWidth(text);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, columnWidths[i] - visWidth));\n\t\t\t\treturn text + padding;\n\t\t\t});\n\t\t\tlines.push(\"│ \" + rowCells.join(\" │ \") + \" │\");\n\t\t}\n\n\t\tlines.push(\"\"); // Add spacing after table\n\t\treturn lines;\n\t}\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Chalk } from "chalk";
|
|
2
2
|
import { marked } from "marked";
|
|
3
|
-
import { visibleWidth } from "../utils.js";
|
|
3
|
+
import { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from "../utils.js";
|
|
4
4
|
// Use a chalk instance with color level 3 for consistent ANSI output
|
|
5
5
|
const colorChalk = new Chalk({ level: 3 });
|
|
6
6
|
export class Markdown {
|
|
@@ -53,43 +53,37 @@ export class Markdown {
|
|
|
53
53
|
const tokenLines = this.renderToken(token, contentWidth, nextToken?.type);
|
|
54
54
|
renderedLines.push(...tokenLines);
|
|
55
55
|
}
|
|
56
|
-
// Wrap lines
|
|
56
|
+
// Wrap lines (NO padding, NO background yet)
|
|
57
57
|
const wrappedLines = [];
|
|
58
58
|
for (const line of renderedLines) {
|
|
59
|
-
wrappedLines.push(...
|
|
59
|
+
wrappedLines.push(...wrapTextWithAnsi(line, contentWidth));
|
|
60
60
|
}
|
|
61
|
-
// Add
|
|
62
|
-
const
|
|
63
|
-
const
|
|
61
|
+
// Add margins and background to each wrapped line
|
|
62
|
+
const leftMargin = " ".repeat(this.paddingX);
|
|
63
|
+
const rightMargin = " ".repeat(this.paddingX);
|
|
64
|
+
const bgRgb = this.defaultTextStyle?.bgColor ? this.parseBgColor() : undefined;
|
|
65
|
+
const contentLines = [];
|
|
64
66
|
for (const line of wrappedLines) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
paddedLine = this.applyBgColor(paddedLine);
|
|
67
|
+
const lineWithMargins = leftMargin + line + rightMargin;
|
|
68
|
+
if (bgRgb) {
|
|
69
|
+
contentLines.push(applyBackgroundToLine(lineWithMargins, width, bgRgb));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// No background - just pad to width
|
|
73
|
+
const visibleLen = visibleWidth(lineWithMargins);
|
|
74
|
+
const paddingNeeded = Math.max(0, width - visibleLen);
|
|
75
|
+
contentLines.push(lineWithMargins + " ".repeat(paddingNeeded));
|
|
75
76
|
}
|
|
76
|
-
paddedLines.push(paddedLine);
|
|
77
77
|
}
|
|
78
|
-
// Add top padding (empty lines)
|
|
78
|
+
// Add top/bottom padding (empty lines)
|
|
79
79
|
const emptyLine = " ".repeat(width);
|
|
80
|
-
const
|
|
80
|
+
const emptyLines = [];
|
|
81
81
|
for (let i = 0; i < this.paddingY; i++) {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
// Add bottom padding (empty lines)
|
|
86
|
-
const bottomPadding = [];
|
|
87
|
-
for (let i = 0; i < this.paddingY; i++) {
|
|
88
|
-
const paddedEmptyLine = this.defaultTextStyle?.bgColor ? this.applyBgColor(emptyLine) : emptyLine;
|
|
89
|
-
bottomPadding.push(paddedEmptyLine);
|
|
82
|
+
const line = bgRgb ? applyBackgroundToLine(emptyLine, width, bgRgb) : emptyLine;
|
|
83
|
+
emptyLines.push(line);
|
|
90
84
|
}
|
|
91
85
|
// Combine top padding, content, and bottom padding
|
|
92
|
-
const result = [...
|
|
86
|
+
const result = [...emptyLines, ...contentLines, ...emptyLines];
|
|
93
87
|
// Update cache
|
|
94
88
|
this.cachedText = this.text;
|
|
95
89
|
this.cachedWidth = width;
|
|
@@ -97,34 +91,46 @@ export class Markdown {
|
|
|
97
91
|
return result.length > 0 ? result : [""];
|
|
98
92
|
}
|
|
99
93
|
/**
|
|
100
|
-
*
|
|
101
|
-
* Used for padding lines that don't have text content.
|
|
94
|
+
* Parse background color from defaultTextStyle to RGB values
|
|
102
95
|
*/
|
|
103
|
-
|
|
96
|
+
parseBgColor() {
|
|
104
97
|
if (!this.defaultTextStyle?.bgColor) {
|
|
105
|
-
return
|
|
98
|
+
return undefined;
|
|
106
99
|
}
|
|
107
100
|
if (this.defaultTextStyle.bgColor.startsWith("#")) {
|
|
108
101
|
// Hex color
|
|
109
102
|
const hex = this.defaultTextStyle.bgColor.substring(1);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
103
|
+
return {
|
|
104
|
+
r: Number.parseInt(hex.substring(0, 2), 16),
|
|
105
|
+
g: Number.parseInt(hex.substring(2, 4), 16),
|
|
106
|
+
b: Number.parseInt(hex.substring(4, 6), 16),
|
|
107
|
+
};
|
|
114
108
|
}
|
|
115
|
-
// Named
|
|
116
|
-
|
|
109
|
+
// Named colors - map to RGB (common terminal colors)
|
|
110
|
+
const colorMap = {
|
|
111
|
+
bgBlack: { r: 0, g: 0, b: 0 },
|
|
112
|
+
bgRed: { r: 255, g: 0, b: 0 },
|
|
113
|
+
bgGreen: { r: 0, g: 255, b: 0 },
|
|
114
|
+
bgYellow: { r: 255, g: 255, b: 0 },
|
|
115
|
+
bgBlue: { r: 0, g: 0, b: 255 },
|
|
116
|
+
bgMagenta: { r: 255, g: 0, b: 255 },
|
|
117
|
+
bgCyan: { r: 0, g: 255, b: 255 },
|
|
118
|
+
bgWhite: { r: 255, g: 255, b: 255 },
|
|
119
|
+
};
|
|
120
|
+
return colorMap[this.defaultTextStyle.bgColor];
|
|
117
121
|
}
|
|
118
122
|
/**
|
|
119
123
|
* Apply default text style to a string.
|
|
120
124
|
* This is the base styling applied to all text content.
|
|
125
|
+
* NOTE: Background color is NOT applied here - it's applied at the padding stage
|
|
126
|
+
* to ensure it extends to the full line width.
|
|
121
127
|
*/
|
|
122
128
|
applyDefaultStyle(text) {
|
|
123
129
|
if (!this.defaultTextStyle) {
|
|
124
130
|
return text;
|
|
125
131
|
}
|
|
126
132
|
let styled = text;
|
|
127
|
-
// Apply color
|
|
133
|
+
// Apply foreground color (NOT background - that's applied at padding stage)
|
|
128
134
|
if (this.defaultTextStyle.color) {
|
|
129
135
|
if (this.defaultTextStyle.color.startsWith("#")) {
|
|
130
136
|
// Hex color
|
|
@@ -139,21 +145,6 @@ export class Markdown {
|
|
|
139
145
|
styled = colorChalk[this.defaultTextStyle.color](styled);
|
|
140
146
|
}
|
|
141
147
|
}
|
|
142
|
-
// Apply background color
|
|
143
|
-
if (this.defaultTextStyle.bgColor) {
|
|
144
|
-
if (this.defaultTextStyle.bgColor.startsWith("#")) {
|
|
145
|
-
// Hex color
|
|
146
|
-
const hex = this.defaultTextStyle.bgColor.substring(1);
|
|
147
|
-
const r = Number.parseInt(hex.substring(0, 2), 16);
|
|
148
|
-
const g = Number.parseInt(hex.substring(2, 4), 16);
|
|
149
|
-
const b = Number.parseInt(hex.substring(4, 6), 16);
|
|
150
|
-
styled = colorChalk.bgRgb(r, g, b)(styled);
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
// Named background color (bgRed, bgBlue, etc.)
|
|
154
|
-
styled = colorChalk[this.defaultTextStyle.bgColor](styled);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
148
|
// Apply text decorations
|
|
158
149
|
if (this.defaultTextStyle.bold) {
|
|
159
150
|
styled = colorChalk.bold(styled);
|
|
@@ -275,12 +266,8 @@ export class Markdown {
|
|
|
275
266
|
break;
|
|
276
267
|
}
|
|
277
268
|
case "codespan":
|
|
278
|
-
// Apply code styling
|
|
279
|
-
result +=
|
|
280
|
-
colorChalk.gray("`") +
|
|
281
|
-
colorChalk.cyan(token.text) +
|
|
282
|
-
colorChalk.gray("`") +
|
|
283
|
-
this.applyDefaultStyle("");
|
|
269
|
+
// Apply code styling without backticks
|
|
270
|
+
result += colorChalk.cyan(token.text) + this.applyDefaultStyle("");
|
|
284
271
|
break;
|
|
285
272
|
case "link": {
|
|
286
273
|
const linkText = this.renderInlineTokens(token.tokens || []);
|
|
@@ -313,103 +300,6 @@ export class Markdown {
|
|
|
313
300
|
}
|
|
314
301
|
return result;
|
|
315
302
|
}
|
|
316
|
-
wrapLine(line, width) {
|
|
317
|
-
// Handle ANSI escape codes properly when wrapping
|
|
318
|
-
const wrapped = [];
|
|
319
|
-
// Handle undefined or null lines
|
|
320
|
-
if (!line) {
|
|
321
|
-
return [""];
|
|
322
|
-
}
|
|
323
|
-
// Split by newlines first - wrap each line individually
|
|
324
|
-
const splitLines = line.split("\n");
|
|
325
|
-
for (const splitLine of splitLines) {
|
|
326
|
-
const visibleLength = visibleWidth(splitLine);
|
|
327
|
-
if (visibleLength <= width) {
|
|
328
|
-
wrapped.push(splitLine);
|
|
329
|
-
continue;
|
|
330
|
-
}
|
|
331
|
-
// This line needs wrapping
|
|
332
|
-
wrapped.push(...this.wrapSingleLine(splitLine, width));
|
|
333
|
-
}
|
|
334
|
-
return wrapped.length > 0 ? wrapped : [""];
|
|
335
|
-
}
|
|
336
|
-
wrapSingleLine(line, width) {
|
|
337
|
-
const wrapped = [];
|
|
338
|
-
// Track active ANSI codes to preserve them across wrapped lines
|
|
339
|
-
const activeAnsiCodes = [];
|
|
340
|
-
let currentLine = "";
|
|
341
|
-
let currentLength = 0;
|
|
342
|
-
let i = 0;
|
|
343
|
-
while (i < line.length) {
|
|
344
|
-
if (line[i] === "\x1b" && line[i + 1] === "[") {
|
|
345
|
-
// ANSI escape sequence - parse and track it
|
|
346
|
-
let j = i + 2;
|
|
347
|
-
while (j < line.length && line[j] && !/[mGKHJ]/.test(line[j])) {
|
|
348
|
-
j++;
|
|
349
|
-
}
|
|
350
|
-
if (j < line.length) {
|
|
351
|
-
const ansiCode = line.substring(i, j + 1);
|
|
352
|
-
currentLine += ansiCode;
|
|
353
|
-
// Track styling codes (ending with 'm')
|
|
354
|
-
if (line[j] === "m") {
|
|
355
|
-
// Reset code
|
|
356
|
-
if (ansiCode === "\x1b[0m" || ansiCode === "\x1b[m") {
|
|
357
|
-
activeAnsiCodes.length = 0;
|
|
358
|
-
}
|
|
359
|
-
else {
|
|
360
|
-
// Add to active codes (replacing similar ones)
|
|
361
|
-
activeAnsiCodes.push(ansiCode);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
i = j + 1;
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
// Incomplete ANSI sequence at end - don't include it
|
|
368
|
-
break;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
// Regular character - extract full grapheme cluster
|
|
373
|
-
// Handle multi-byte characters (emoji, surrogate pairs, etc.)
|
|
374
|
-
let char;
|
|
375
|
-
let charByteLength;
|
|
376
|
-
// Check for surrogate pair (emoji and other multi-byte chars)
|
|
377
|
-
const codePoint = line.charCodeAt(i);
|
|
378
|
-
if (codePoint >= 0xd800 && codePoint <= 0xdbff && i + 1 < line.length) {
|
|
379
|
-
// High surrogate - get the pair
|
|
380
|
-
char = line.substring(i, i + 2);
|
|
381
|
-
charByteLength = 2;
|
|
382
|
-
}
|
|
383
|
-
else {
|
|
384
|
-
// Regular character
|
|
385
|
-
char = line[i];
|
|
386
|
-
charByteLength = 1;
|
|
387
|
-
}
|
|
388
|
-
const charWidth = visibleWidth(char);
|
|
389
|
-
// Check if adding this character would exceed width
|
|
390
|
-
if (currentLength + charWidth > width) {
|
|
391
|
-
// Need to wrap - close current line with reset if needed
|
|
392
|
-
if (activeAnsiCodes.length > 0) {
|
|
393
|
-
wrapped.push(currentLine + "\x1b[0m");
|
|
394
|
-
// Start new line with active codes
|
|
395
|
-
currentLine = activeAnsiCodes.join("");
|
|
396
|
-
}
|
|
397
|
-
else {
|
|
398
|
-
wrapped.push(currentLine);
|
|
399
|
-
currentLine = "";
|
|
400
|
-
}
|
|
401
|
-
currentLength = 0;
|
|
402
|
-
}
|
|
403
|
-
currentLine += char;
|
|
404
|
-
currentLength += charWidth;
|
|
405
|
-
i += charByteLength;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
if (currentLine) {
|
|
409
|
-
wrapped.push(currentLine);
|
|
410
|
-
}
|
|
411
|
-
return wrapped.length > 0 ? wrapped : [""];
|
|
412
|
-
}
|
|
413
303
|
/**
|
|
414
304
|
* Render a list with proper nesting support
|
|
415
305
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/components/markdown.ts"],"names":[],"mappings":"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","sourcesContent":["import { Chalk } from \"chalk\";\nimport { marked, type Token } from \"marked\";\nimport type { Component } from \"../tui.js\";\nimport { visibleWidth } from \"../utils.js\";\n\n// Use a chalk instance with color level 3 for consistent ANSI output\nconst colorChalk = new Chalk({ level: 3 });\n\n/**\n * Default text styling for markdown content.\n * Applied to all text unless overridden by markdown formatting.\n */\nexport interface DefaultTextStyle {\n\t/** Foreground color - named color or hex string like \"#ff0000\" */\n\tcolor?: string;\n\t/** Background color - named color or hex string like \"#ff0000\" */\n\tbgColor?: string;\n\t/** Bold text */\n\tbold?: boolean;\n\t/** Italic text */\n\titalic?: boolean;\n\t/** Strikethrough text */\n\tstrikethrough?: boolean;\n\t/** Underline text */\n\tunderline?: boolean;\n}\n\nexport class Markdown implements Component {\n\tprivate text: string;\n\tprivate paddingX: number; // Left/right padding\n\tprivate paddingY: number; // Top/bottom padding\n\tprivate defaultTextStyle?: DefaultTextStyle;\n\n\t// Cache for rendered output\n\tprivate cachedText?: string;\n\tprivate cachedWidth?: number;\n\tprivate cachedLines?: string[];\n\n\tconstructor(text: string = \"\", paddingX: number = 1, paddingY: number = 1, defaultTextStyle?: DefaultTextStyle) {\n\t\tthis.text = text;\n\t\tthis.paddingX = paddingX;\n\t\tthis.paddingY = paddingY;\n\t\tthis.defaultTextStyle = defaultTextStyle;\n\t}\n\n\tsetText(text: string): void {\n\t\tthis.text = text;\n\t\t// Invalidate cache when text changes\n\t\tthis.cachedText = undefined;\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\trender(width: number): string[] {\n\t\t// Check cache\n\t\tif (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\t// Calculate available width for content (subtract horizontal padding)\n\t\tconst contentWidth = Math.max(1, width - this.paddingX * 2);\n\n\t\t// Don't render anything if there's no actual text\n\t\tif (!this.text || this.text.trim() === \"\") {\n\t\t\tconst result: string[] = [];\n\t\t\t// Update cache\n\t\t\tthis.cachedText = this.text;\n\t\t\tthis.cachedWidth = width;\n\t\t\tthis.cachedLines = result;\n\t\t\treturn result;\n\t\t}\n\n\t\t// Replace tabs with 3 spaces for consistent rendering\n\t\tconst normalizedText = this.text.replace(/\\t/g, \" \");\n\n\t\t// Parse markdown to HTML-like tokens\n\t\tconst tokens = marked.lexer(normalizedText);\n\n\t\t// Convert tokens to styled terminal output\n\t\tconst renderedLines: string[] = [];\n\n\t\tfor (let i = 0; i < tokens.length; i++) {\n\t\t\tconst token = tokens[i];\n\t\t\tconst nextToken = tokens[i + 1];\n\t\t\tconst tokenLines = this.renderToken(token, contentWidth, nextToken?.type);\n\t\t\trenderedLines.push(...tokenLines);\n\t\t}\n\n\t\t// Wrap lines to fit content width\n\t\tconst wrappedLines: string[] = [];\n\t\tfor (const line of renderedLines) {\n\t\t\twrappedLines.push(...this.wrapLine(line, contentWidth));\n\t\t}\n\n\t\t// Add padding and apply background color if specified\n\t\tconst leftPad = \" \".repeat(this.paddingX);\n\t\tconst paddedLines: string[] = [];\n\n\t\tfor (const line of wrappedLines) {\n\t\t\t// Calculate visible length\n\t\t\tconst visibleLength = visibleWidth(line);\n\t\t\t// Right padding to fill to width (accounting for left padding and content)\n\t\t\tconst rightPadLength = Math.max(0, width - this.paddingX - visibleLength);\n\t\t\tconst rightPad = \" \".repeat(rightPadLength);\n\n\t\t\t// Add left padding, content, and right padding\n\t\t\tlet paddedLine = leftPad + line + rightPad;\n\n\t\t\t// Apply background color to entire line if specified\n\t\t\tif (this.defaultTextStyle?.bgColor) {\n\t\t\t\tpaddedLine = this.applyBgColor(paddedLine);\n\t\t\t}\n\n\t\t\tpaddedLines.push(paddedLine);\n\t\t}\n\n\t\t// Add top padding (empty lines)\n\t\tconst emptyLine = \" \".repeat(width);\n\t\tconst topPadding: string[] = [];\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tconst paddedEmptyLine = this.defaultTextStyle?.bgColor ? this.applyBgColor(emptyLine) : emptyLine;\n\t\t\ttopPadding.push(paddedEmptyLine);\n\t\t}\n\n\t\t// Add bottom padding (empty lines)\n\t\tconst bottomPadding: string[] = [];\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tconst paddedEmptyLine = this.defaultTextStyle?.bgColor ? this.applyBgColor(emptyLine) : emptyLine;\n\t\t\tbottomPadding.push(paddedEmptyLine);\n\t\t}\n\n\t\t// Combine top padding, content, and bottom padding\n\t\tconst result = [...topPadding, ...paddedLines, ...bottomPadding];\n\n\t\t// Update cache\n\t\tthis.cachedText = this.text;\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedLines = result;\n\n\t\treturn result.length > 0 ? result : [\"\"];\n\t}\n\n\t/**\n\t * Apply only background color from default style.\n\t * Used for padding lines that don't have text content.\n\t */\n\tprivate applyBgColor(text: string): string {\n\t\tif (!this.defaultTextStyle?.bgColor) {\n\t\t\treturn text;\n\t\t}\n\n\t\tif (this.defaultTextStyle.bgColor.startsWith(\"#\")) {\n\t\t\t// Hex color\n\t\t\tconst hex = this.defaultTextStyle.bgColor.substring(1);\n\t\t\tconst r = Number.parseInt(hex.substring(0, 2), 16);\n\t\t\tconst g = Number.parseInt(hex.substring(2, 4), 16);\n\t\t\tconst b = Number.parseInt(hex.substring(4, 6), 16);\n\t\t\treturn colorChalk.bgRgb(r, g, b)(text);\n\t\t}\n\t\t// Named background color (bgRed, bgBlue, etc.)\n\t\treturn (colorChalk as any)[this.defaultTextStyle.bgColor](text);\n\t}\n\n\t/**\n\t * Apply default text style to a string.\n\t * This is the base styling applied to all text content.\n\t */\n\tprivate applyDefaultStyle(text: string): string {\n\t\tif (!this.defaultTextStyle) {\n\t\t\treturn text;\n\t\t}\n\n\t\tlet styled = text;\n\n\t\t// Apply color\n\t\tif (this.defaultTextStyle.color) {\n\t\t\tif (this.defaultTextStyle.color.startsWith(\"#\")) {\n\t\t\t\t// Hex color\n\t\t\t\tconst hex = this.defaultTextStyle.color.substring(1);\n\t\t\t\tconst r = Number.parseInt(hex.substring(0, 2), 16);\n\t\t\t\tconst g = Number.parseInt(hex.substring(2, 4), 16);\n\t\t\t\tconst b = Number.parseInt(hex.substring(4, 6), 16);\n\t\t\t\tstyled = colorChalk.rgb(r, g, b)(styled);\n\t\t\t} else {\n\t\t\t\t// Named color\n\t\t\t\tstyled = (colorChalk as any)[this.defaultTextStyle.color](styled);\n\t\t\t}\n\t\t}\n\n\t\t// Apply background color\n\t\tif (this.defaultTextStyle.bgColor) {\n\t\t\tif (this.defaultTextStyle.bgColor.startsWith(\"#\")) {\n\t\t\t\t// Hex color\n\t\t\t\tconst hex = this.defaultTextStyle.bgColor.substring(1);\n\t\t\t\tconst r = Number.parseInt(hex.substring(0, 2), 16);\n\t\t\t\tconst g = Number.parseInt(hex.substring(2, 4), 16);\n\t\t\t\tconst b = Number.parseInt(hex.substring(4, 6), 16);\n\t\t\t\tstyled = colorChalk.bgRgb(r, g, b)(styled);\n\t\t\t} else {\n\t\t\t\t// Named background color (bgRed, bgBlue, etc.)\n\t\t\t\tstyled = (colorChalk as any)[this.defaultTextStyle.bgColor](styled);\n\t\t\t}\n\t\t}\n\n\t\t// Apply text decorations\n\t\tif (this.defaultTextStyle.bold) {\n\t\t\tstyled = colorChalk.bold(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.italic) {\n\t\t\tstyled = colorChalk.italic(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.strikethrough) {\n\t\t\tstyled = colorChalk.strikethrough(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.underline) {\n\t\t\tstyled = colorChalk.underline(styled);\n\t\t}\n\n\t\treturn styled;\n\t}\n\n\tprivate renderToken(token: Token, width: number, nextTokenType?: string): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tswitch (token.type) {\n\t\t\tcase \"heading\": {\n\t\t\t\tconst headingLevel = token.depth;\n\t\t\t\tconst headingPrefix = \"#\".repeat(headingLevel) + \" \";\n\t\t\t\tconst headingText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tif (headingLevel === 1) {\n\t\t\t\t\tlines.push(colorChalk.bold.underline.yellow(headingText));\n\t\t\t\t} else if (headingLevel === 2) {\n\t\t\t\t\tlines.push(colorChalk.bold.yellow(headingText));\n\t\t\t\t} else {\n\t\t\t\t\tlines.push(colorChalk.bold(headingPrefix + headingText));\n\t\t\t\t}\n\t\t\t\tlines.push(\"\"); // Add spacing after headings\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"paragraph\": {\n\t\t\t\tconst paragraphText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tlines.push(paragraphText);\n\t\t\t\t// Don't add spacing if next token is space or list\n\t\t\t\tif (nextTokenType && nextTokenType !== \"list\" && nextTokenType !== \"space\") {\n\t\t\t\t\tlines.push(\"\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"code\": {\n\t\t\t\tlines.push(colorChalk.gray(\"```\" + (token.lang || \"\")));\n\t\t\t\t// Split code by newlines and style each line\n\t\t\t\tconst codeLines = token.text.split(\"\\n\");\n\t\t\t\tfor (const codeLine of codeLines) {\n\t\t\t\t\tlines.push(colorChalk.dim(\" \") + colorChalk.green(codeLine));\n\t\t\t\t}\n\t\t\t\tlines.push(colorChalk.gray(\"```\"));\n\t\t\t\tlines.push(\"\"); // Add spacing after code blocks\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"list\": {\n\t\t\t\tconst listLines = this.renderList(token as any, 0);\n\t\t\t\tlines.push(...listLines);\n\t\t\t\t// Don't add spacing after lists if a space token follows\n\t\t\t\t// (the space token will handle it)\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"table\": {\n\t\t\t\tconst tableLines = this.renderTable(token as any);\n\t\t\t\tlines.push(...tableLines);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"blockquote\": {\n\t\t\t\tconst quoteText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tconst quoteLines = quoteText.split(\"\\n\");\n\t\t\t\tfor (const quoteLine of quoteLines) {\n\t\t\t\t\tlines.push(colorChalk.gray(\"│ \") + colorChalk.italic(quoteLine));\n\t\t\t\t}\n\t\t\t\tlines.push(\"\"); // Add spacing after blockquotes\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"hr\":\n\t\t\t\tlines.push(colorChalk.gray(\"─\".repeat(Math.min(width, 80))));\n\t\t\t\tlines.push(\"\"); // Add spacing after horizontal rules\n\t\t\t\tbreak;\n\n\t\t\tcase \"html\":\n\t\t\t\t// Skip HTML for terminal output\n\t\t\t\tbreak;\n\n\t\t\tcase \"space\":\n\t\t\t\t// Space tokens represent blank lines in markdown\n\t\t\t\tlines.push(\"\");\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t// Handle any other token types as plain text\n\t\t\t\tif (\"text\" in token && typeof token.text === \"string\") {\n\t\t\t\t\tlines.push(token.text);\n\t\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\tprivate renderInlineTokens(tokens: Token[]): string {\n\t\tlet result = \"\";\n\n\t\tfor (const token of tokens) {\n\t\t\tswitch (token.type) {\n\t\t\t\tcase \"text\":\n\t\t\t\t\t// Text tokens in list items can have nested tokens for inline formatting\n\t\t\t\t\tif (token.tokens && token.tokens.length > 0) {\n\t\t\t\t\t\tresult += this.renderInlineTokens(token.tokens);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Apply default style to plain text\n\t\t\t\t\t\tresult += this.applyDefaultStyle(token.text);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"strong\": {\n\t\t\t\t\t// Apply bold, then reapply default style after\n\t\t\t\t\tconst boldContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.bold(boldContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"em\": {\n\t\t\t\t\t// Apply italic, then reapply default style after\n\t\t\t\t\tconst italicContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.italic(italicContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"codespan\":\n\t\t\t\t\t// Apply code styling, then reapply default style after\n\t\t\t\t\tresult +=\n\t\t\t\t\t\tcolorChalk.gray(\"`\") +\n\t\t\t\t\t\tcolorChalk.cyan(token.text) +\n\t\t\t\t\t\tcolorChalk.gray(\"`\") +\n\t\t\t\t\t\tthis.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"link\": {\n\t\t\t\t\tconst linkText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\t// If link text matches href, only show the link once\n\t\t\t\t\tif (linkText === token.href) {\n\t\t\t\t\t\tresult += colorChalk.underline.blue(linkText) + this.applyDefaultStyle(\"\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult +=\n\t\t\t\t\t\t\tcolorChalk.underline.blue(linkText) +\n\t\t\t\t\t\t\tcolorChalk.gray(` (${token.href})`) +\n\t\t\t\t\t\t\tthis.applyDefaultStyle(\"\");\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"br\":\n\t\t\t\t\tresult += \"\\n\";\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"del\": {\n\t\t\t\t\tconst delContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.strikethrough(delContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\t// Handle any other inline token types as plain text\n\t\t\t\t\tif (\"text\" in token && typeof token.text === \"string\") {\n\t\t\t\t\t\tresult += this.applyDefaultStyle(token.text);\n\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate wrapLine(line: string, width: number): string[] {\n\t\t// Handle ANSI escape codes properly when wrapping\n\t\tconst wrapped: string[] = [];\n\n\t\t// Handle undefined or null lines\n\t\tif (!line) {\n\t\t\treturn [\"\"];\n\t\t}\n\n\t\t// Split by newlines first - wrap each line individually\n\t\tconst splitLines = line.split(\"\\n\");\n\t\tfor (const splitLine of splitLines) {\n\t\t\tconst visibleLength = visibleWidth(splitLine);\n\n\t\t\tif (visibleLength <= width) {\n\t\t\t\twrapped.push(splitLine);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// This line needs wrapping\n\t\t\twrapped.push(...this.wrapSingleLine(splitLine, width));\n\t\t}\n\n\t\treturn wrapped.length > 0 ? wrapped : [\"\"];\n\t}\n\n\tprivate wrapSingleLine(line: string, width: number): string[] {\n\t\tconst wrapped: string[] = [];\n\n\t\t// Track active ANSI codes to preserve them across wrapped lines\n\t\tconst activeAnsiCodes: string[] = [];\n\t\tlet currentLine = \"\";\n\t\tlet currentLength = 0;\n\t\tlet i = 0;\n\n\t\twhile (i < line.length) {\n\t\t\tif (line[i] === \"\\x1b\" && line[i + 1] === \"[\") {\n\t\t\t\t// ANSI escape sequence - parse and track it\n\t\t\t\tlet j = i + 2;\n\t\t\t\twhile (j < line.length && line[j] && !/[mGKHJ]/.test(line[j]!)) {\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t\tif (j < line.length) {\n\t\t\t\t\tconst ansiCode = line.substring(i, j + 1);\n\t\t\t\t\tcurrentLine += ansiCode;\n\n\t\t\t\t\t// Track styling codes (ending with 'm')\n\t\t\t\t\tif (line[j] === \"m\") {\n\t\t\t\t\t\t// Reset code\n\t\t\t\t\t\tif (ansiCode === \"\\x1b[0m\" || ansiCode === \"\\x1b[m\") {\n\t\t\t\t\t\t\tactiveAnsiCodes.length = 0;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Add to active codes (replacing similar ones)\n\t\t\t\t\t\t\tactiveAnsiCodes.push(ansiCode);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ti = j + 1;\n\t\t\t\t} else {\n\t\t\t\t\t// Incomplete ANSI sequence at end - don't include it\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Regular character - extract full grapheme cluster\n\t\t\t\t// Handle multi-byte characters (emoji, surrogate pairs, etc.)\n\t\t\t\tlet char: string;\n\t\t\t\tlet charByteLength: number;\n\n\t\t\t\t// Check for surrogate pair (emoji and other multi-byte chars)\n\t\t\t\tconst codePoint = line.charCodeAt(i);\n\t\t\t\tif (codePoint >= 0xd800 && codePoint <= 0xdbff && i + 1 < line.length) {\n\t\t\t\t\t// High surrogate - get the pair\n\t\t\t\t\tchar = line.substring(i, i + 2);\n\t\t\t\t\tcharByteLength = 2;\n\t\t\t\t} else {\n\t\t\t\t\t// Regular character\n\t\t\t\t\tchar = line[i];\n\t\t\t\t\tcharByteLength = 1;\n\t\t\t\t}\n\n\t\t\t\tconst charWidth = visibleWidth(char);\n\n\t\t\t\t// Check if adding this character would exceed width\n\t\t\t\tif (currentLength + charWidth > width) {\n\t\t\t\t\t// Need to wrap - close current line with reset if needed\n\t\t\t\t\tif (activeAnsiCodes.length > 0) {\n\t\t\t\t\t\twrapped.push(currentLine + \"\\x1b[0m\");\n\t\t\t\t\t\t// Start new line with active codes\n\t\t\t\t\t\tcurrentLine = activeAnsiCodes.join(\"\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\twrapped.push(currentLine);\n\t\t\t\t\t\tcurrentLine = \"\";\n\t\t\t\t\t}\n\t\t\t\t\tcurrentLength = 0;\n\t\t\t\t}\n\n\t\t\t\tcurrentLine += char;\n\t\t\t\tcurrentLength += charWidth;\n\t\t\t\ti += charByteLength;\n\t\t\t}\n\t\t}\n\n\t\tif (currentLine) {\n\t\t\twrapped.push(currentLine);\n\t\t}\n\n\t\treturn wrapped.length > 0 ? wrapped : [\"\"];\n\t}\n\n\t/**\n\t * Render a list with proper nesting support\n\t */\n\tprivate renderList(token: Token & { items: any[]; ordered: boolean }, depth: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst indent = \" \".repeat(depth);\n\n\t\tfor (let i = 0; i < token.items.length; i++) {\n\t\t\tconst item = token.items[i];\n\t\t\tconst bullet = token.ordered ? `${i + 1}. ` : \"- \";\n\n\t\t\t// Process item tokens to handle nested lists\n\t\t\tconst itemLines = this.renderListItem(item.tokens || [], depth);\n\n\t\t\tif (itemLines.length > 0) {\n\t\t\t\t// First line - check if it's a nested list\n\t\t\t\t// A nested list will start with indent (spaces) followed by cyan bullet\n\t\t\t\tconst firstLine = itemLines[0];\n\t\t\t\tconst isNestedList = /^\\s+\\x1b\\[36m[-\\d]/.test(firstLine); // starts with spaces + cyan + bullet char\n\n\t\t\t\tif (isNestedList) {\n\t\t\t\t\t// This is a nested list, just add it as-is (already has full indent)\n\t\t\t\t\tlines.push(firstLine);\n\t\t\t\t} else {\n\t\t\t\t\t// Regular text content - add indent and bullet\n\t\t\t\t\tlines.push(indent + colorChalk.cyan(bullet) + firstLine);\n\t\t\t\t}\n\n\t\t\t\t// Rest of the lines\n\t\t\t\tfor (let j = 1; j < itemLines.length; j++) {\n\t\t\t\t\tconst line = itemLines[j];\n\t\t\t\t\tconst isNestedListLine = /^\\s+\\x1b\\[36m[-\\d]/.test(line); // starts with spaces + cyan + bullet char\n\n\t\t\t\t\tif (isNestedListLine) {\n\t\t\t\t\t\t// Nested list line - already has full indent\n\t\t\t\t\t\tlines.push(line);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Regular content - add parent indent + 2 spaces for continuation\n\t\t\t\t\t\tlines.push(indent + \" \" + line);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlines.push(indent + colorChalk.cyan(bullet));\n\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Render list item tokens, handling nested lists\n\t * Returns lines WITHOUT the parent indent (renderList will add it)\n\t */\n\tprivate renderListItem(tokens: Token[], parentDepth: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tfor (const token of tokens) {\n\t\t\tif (token.type === \"list\") {\n\t\t\t\t// Nested list - render with one additional indent level\n\t\t\t\t// These lines will have their own indent, so we just add them as-is\n\t\t\t\tconst nestedLines = this.renderList(token as any, parentDepth + 1);\n\t\t\t\tlines.push(...nestedLines);\n\t\t\t} else if (token.type === \"text\") {\n\t\t\t\t// Text content (may have inline tokens)\n\t\t\t\tconst text =\n\t\t\t\t\ttoken.tokens && token.tokens.length > 0 ? this.renderInlineTokens(token.tokens) : token.text || \"\";\n\t\t\t\tlines.push(text);\n\t\t\t} else if (token.type === \"paragraph\") {\n\t\t\t\t// Paragraph in list item\n\t\t\t\tconst text = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tlines.push(text);\n\t\t\t} else if (token.type === \"code\") {\n\t\t\t\t// Code block in list item\n\t\t\t\tlines.push(colorChalk.gray(\"```\" + (token.lang || \"\")));\n\t\t\t\tconst codeLines = token.text.split(\"\\n\");\n\t\t\t\tfor (const codeLine of codeLines) {\n\t\t\t\t\tlines.push(colorChalk.dim(\" \") + colorChalk.green(codeLine));\n\t\t\t\t}\n\t\t\t\tlines.push(colorChalk.gray(\"```\"));\n\t\t\t} else {\n\t\t\t\t// Other token types - try to render as inline\n\t\t\t\tconst text = this.renderInlineTokens([token]);\n\t\t\t\tif (text) {\n\t\t\t\t\tlines.push(text);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Render a table\n\t */\n\tprivate renderTable(token: Token & { header: any[]; rows: any[][] }): string[] {\n\t\tconst lines: string[] = [];\n\n\t\t// Calculate column widths\n\t\tconst columnWidths: number[] = [];\n\n\t\t// Check header\n\t\tfor (let i = 0; i < token.header.length; i++) {\n\t\t\tconst headerText = this.renderInlineTokens(token.header[i].tokens || []);\n\t\t\tconst width = visibleWidth(headerText);\n\t\t\tcolumnWidths[i] = Math.max(columnWidths[i] || 0, width);\n\t\t}\n\n\t\t// Check rows\n\t\tfor (const row of token.rows) {\n\t\t\tfor (let i = 0; i < row.length; i++) {\n\t\t\t\tconst cellText = this.renderInlineTokens(row[i].tokens || []);\n\t\t\t\tconst width = visibleWidth(cellText);\n\t\t\t\tcolumnWidths[i] = Math.max(columnWidths[i] || 0, width);\n\t\t\t}\n\t\t}\n\n\t\t// Limit column widths to reasonable max\n\t\tconst maxColWidth = 40;\n\t\tfor (let i = 0; i < columnWidths.length; i++) {\n\t\t\tcolumnWidths[i] = Math.min(columnWidths[i], maxColWidth);\n\t\t}\n\n\t\t// Render header\n\t\tconst headerCells = token.header.map((cell, i) => {\n\t\t\tconst text = this.renderInlineTokens(cell.tokens || []);\n\t\t\treturn colorChalk.bold(text.padEnd(columnWidths[i]));\n\t\t});\n\t\tlines.push(\"│ \" + headerCells.join(\" │ \") + \" │\");\n\n\t\t// Render separator\n\t\tconst separatorCells = columnWidths.map((width) => \"─\".repeat(width));\n\t\tlines.push(\"├─\" + separatorCells.join(\"─┼─\") + \"─┤\");\n\n\t\t// Render rows\n\t\tfor (const row of token.rows) {\n\t\t\tconst rowCells = row.map((cell, i) => {\n\t\t\t\tconst text = this.renderInlineTokens(cell.tokens || []);\n\t\t\t\tconst visWidth = visibleWidth(text);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, columnWidths[i] - visWidth));\n\t\t\t\treturn text + padding;\n\t\t\t});\n\t\t\tlines.push(\"│ \" + rowCells.join(\" │ \") + \" │\");\n\t\t}\n\n\t\tlines.push(\"\"); // Add spacing after table\n\t\treturn lines;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/components/markdown.ts"],"names":[],"mappings":"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","sourcesContent":["import { Chalk } from \"chalk\";\nimport { marked, type Token } from \"marked\";\nimport type { Component } from \"../tui.js\";\nimport { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from \"../utils.js\";\n\n// Use a chalk instance with color level 3 for consistent ANSI output\nconst colorChalk = new Chalk({ level: 3 });\n\n/**\n * Default text styling for markdown content.\n * Applied to all text unless overridden by markdown formatting.\n */\nexport interface DefaultTextStyle {\n\t/** Foreground color - named color or hex string like \"#ff0000\" */\n\tcolor?: string;\n\t/** Background color - named color or hex string like \"#ff0000\" */\n\tbgColor?: string;\n\t/** Bold text */\n\tbold?: boolean;\n\t/** Italic text */\n\titalic?: boolean;\n\t/** Strikethrough text */\n\tstrikethrough?: boolean;\n\t/** Underline text */\n\tunderline?: boolean;\n}\n\nexport class Markdown implements Component {\n\tprivate text: string;\n\tprivate paddingX: number; // Left/right padding\n\tprivate paddingY: number; // Top/bottom padding\n\tprivate defaultTextStyle?: DefaultTextStyle;\n\n\t// Cache for rendered output\n\tprivate cachedText?: string;\n\tprivate cachedWidth?: number;\n\tprivate cachedLines?: string[];\n\n\tconstructor(text: string = \"\", paddingX: number = 1, paddingY: number = 1, defaultTextStyle?: DefaultTextStyle) {\n\t\tthis.text = text;\n\t\tthis.paddingX = paddingX;\n\t\tthis.paddingY = paddingY;\n\t\tthis.defaultTextStyle = defaultTextStyle;\n\t}\n\n\tsetText(text: string): void {\n\t\tthis.text = text;\n\t\t// Invalidate cache when text changes\n\t\tthis.cachedText = undefined;\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\trender(width: number): string[] {\n\t\t// Check cache\n\t\tif (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\t// Calculate available width for content (subtract horizontal padding)\n\t\tconst contentWidth = Math.max(1, width - this.paddingX * 2);\n\n\t\t// Don't render anything if there's no actual text\n\t\tif (!this.text || this.text.trim() === \"\") {\n\t\t\tconst result: string[] = [];\n\t\t\t// Update cache\n\t\t\tthis.cachedText = this.text;\n\t\t\tthis.cachedWidth = width;\n\t\t\tthis.cachedLines = result;\n\t\t\treturn result;\n\t\t}\n\n\t\t// Replace tabs with 3 spaces for consistent rendering\n\t\tconst normalizedText = this.text.replace(/\\t/g, \" \");\n\n\t\t// Parse markdown to HTML-like tokens\n\t\tconst tokens = marked.lexer(normalizedText);\n\n\t\t// Convert tokens to styled terminal output\n\t\tconst renderedLines: string[] = [];\n\n\t\tfor (let i = 0; i < tokens.length; i++) {\n\t\t\tconst token = tokens[i];\n\t\t\tconst nextToken = tokens[i + 1];\n\t\t\tconst tokenLines = this.renderToken(token, contentWidth, nextToken?.type);\n\t\t\trenderedLines.push(...tokenLines);\n\t\t}\n\n\t\t// Wrap lines (NO padding, NO background yet)\n\t\tconst wrappedLines: string[] = [];\n\t\tfor (const line of renderedLines) {\n\t\t\twrappedLines.push(...wrapTextWithAnsi(line, contentWidth));\n\t\t}\n\n\t\t// Add margins and background to each wrapped line\n\t\tconst leftMargin = \" \".repeat(this.paddingX);\n\t\tconst rightMargin = \" \".repeat(this.paddingX);\n\t\tconst bgRgb = this.defaultTextStyle?.bgColor ? this.parseBgColor() : undefined;\n\t\tconst contentLines: string[] = [];\n\n\t\tfor (const line of wrappedLines) {\n\t\t\tconst lineWithMargins = leftMargin + line + rightMargin;\n\n\t\t\tif (bgRgb) {\n\t\t\t\tcontentLines.push(applyBackgroundToLine(lineWithMargins, width, bgRgb));\n\t\t\t} else {\n\t\t\t\t// No background - just pad to width\n\t\t\t\tconst visibleLen = visibleWidth(lineWithMargins);\n\t\t\t\tconst paddingNeeded = Math.max(0, width - visibleLen);\n\t\t\t\tcontentLines.push(lineWithMargins + \" \".repeat(paddingNeeded));\n\t\t\t}\n\t\t}\n\n\t\t// Add top/bottom padding (empty lines)\n\t\tconst emptyLine = \" \".repeat(width);\n\t\tconst emptyLines: string[] = [];\n\t\tfor (let i = 0; i < this.paddingY; i++) {\n\t\t\tconst line = bgRgb ? applyBackgroundToLine(emptyLine, width, bgRgb) : emptyLine;\n\t\t\temptyLines.push(line);\n\t\t}\n\n\t\t// Combine top padding, content, and bottom padding\n\t\tconst result = [...emptyLines, ...contentLines, ...emptyLines];\n\n\t\t// Update cache\n\t\tthis.cachedText = this.text;\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedLines = result;\n\n\t\treturn result.length > 0 ? result : [\"\"];\n\t}\n\n\t/**\n\t * Parse background color from defaultTextStyle to RGB values\n\t */\n\tprivate parseBgColor(): { r: number; g: number; b: number } | undefined {\n\t\tif (!this.defaultTextStyle?.bgColor) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (this.defaultTextStyle.bgColor.startsWith(\"#\")) {\n\t\t\t// Hex color\n\t\t\tconst hex = this.defaultTextStyle.bgColor.substring(1);\n\t\t\treturn {\n\t\t\t\tr: Number.parseInt(hex.substring(0, 2), 16),\n\t\t\t\tg: Number.parseInt(hex.substring(2, 4), 16),\n\t\t\t\tb: Number.parseInt(hex.substring(4, 6), 16),\n\t\t\t};\n\t\t}\n\n\t\t// Named colors - map to RGB (common terminal colors)\n\t\tconst colorMap: Record<string, { r: number; g: number; b: number }> = {\n\t\t\tbgBlack: { r: 0, g: 0, b: 0 },\n\t\t\tbgRed: { r: 255, g: 0, b: 0 },\n\t\t\tbgGreen: { r: 0, g: 255, b: 0 },\n\t\t\tbgYellow: { r: 255, g: 255, b: 0 },\n\t\t\tbgBlue: { r: 0, g: 0, b: 255 },\n\t\t\tbgMagenta: { r: 255, g: 0, b: 255 },\n\t\t\tbgCyan: { r: 0, g: 255, b: 255 },\n\t\t\tbgWhite: { r: 255, g: 255, b: 255 },\n\t\t};\n\n\t\treturn colorMap[this.defaultTextStyle.bgColor];\n\t}\n\n\t/**\n\t * Apply default text style to a string.\n\t * This is the base styling applied to all text content.\n\t * NOTE: Background color is NOT applied here - it's applied at the padding stage\n\t * to ensure it extends to the full line width.\n\t */\n\tprivate applyDefaultStyle(text: string): string {\n\t\tif (!this.defaultTextStyle) {\n\t\t\treturn text;\n\t\t}\n\n\t\tlet styled = text;\n\n\t\t// Apply foreground color (NOT background - that's applied at padding stage)\n\t\tif (this.defaultTextStyle.color) {\n\t\t\tif (this.defaultTextStyle.color.startsWith(\"#\")) {\n\t\t\t\t// Hex color\n\t\t\t\tconst hex = this.defaultTextStyle.color.substring(1);\n\t\t\t\tconst r = Number.parseInt(hex.substring(0, 2), 16);\n\t\t\t\tconst g = Number.parseInt(hex.substring(2, 4), 16);\n\t\t\t\tconst b = Number.parseInt(hex.substring(4, 6), 16);\n\t\t\t\tstyled = colorChalk.rgb(r, g, b)(styled);\n\t\t\t} else {\n\t\t\t\t// Named color\n\t\t\t\tstyled = (colorChalk as any)[this.defaultTextStyle.color](styled);\n\t\t\t}\n\t\t}\n\n\t\t// Apply text decorations\n\t\tif (this.defaultTextStyle.bold) {\n\t\t\tstyled = colorChalk.bold(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.italic) {\n\t\t\tstyled = colorChalk.italic(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.strikethrough) {\n\t\t\tstyled = colorChalk.strikethrough(styled);\n\t\t}\n\t\tif (this.defaultTextStyle.underline) {\n\t\t\tstyled = colorChalk.underline(styled);\n\t\t}\n\n\t\treturn styled;\n\t}\n\n\tprivate renderToken(token: Token, width: number, nextTokenType?: string): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tswitch (token.type) {\n\t\t\tcase \"heading\": {\n\t\t\t\tconst headingLevel = token.depth;\n\t\t\t\tconst headingPrefix = \"#\".repeat(headingLevel) + \" \";\n\t\t\t\tconst headingText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tif (headingLevel === 1) {\n\t\t\t\t\tlines.push(colorChalk.bold.underline.yellow(headingText));\n\t\t\t\t} else if (headingLevel === 2) {\n\t\t\t\t\tlines.push(colorChalk.bold.yellow(headingText));\n\t\t\t\t} else {\n\t\t\t\t\tlines.push(colorChalk.bold(headingPrefix + headingText));\n\t\t\t\t}\n\t\t\t\tlines.push(\"\"); // Add spacing after headings\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"paragraph\": {\n\t\t\t\tconst paragraphText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tlines.push(paragraphText);\n\t\t\t\t// Don't add spacing if next token is space or list\n\t\t\t\tif (nextTokenType && nextTokenType !== \"list\" && nextTokenType !== \"space\") {\n\t\t\t\t\tlines.push(\"\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"code\": {\n\t\t\t\tlines.push(colorChalk.gray(\"```\" + (token.lang || \"\")));\n\t\t\t\t// Split code by newlines and style each line\n\t\t\t\tconst codeLines = token.text.split(\"\\n\");\n\t\t\t\tfor (const codeLine of codeLines) {\n\t\t\t\t\tlines.push(colorChalk.dim(\" \") + colorChalk.green(codeLine));\n\t\t\t\t}\n\t\t\t\tlines.push(colorChalk.gray(\"```\"));\n\t\t\t\tlines.push(\"\"); // Add spacing after code blocks\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"list\": {\n\t\t\t\tconst listLines = this.renderList(token as any, 0);\n\t\t\t\tlines.push(...listLines);\n\t\t\t\t// Don't add spacing after lists if a space token follows\n\t\t\t\t// (the space token will handle it)\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"table\": {\n\t\t\t\tconst tableLines = this.renderTable(token as any);\n\t\t\t\tlines.push(...tableLines);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"blockquote\": {\n\t\t\t\tconst quoteText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tconst quoteLines = quoteText.split(\"\\n\");\n\t\t\t\tfor (const quoteLine of quoteLines) {\n\t\t\t\t\tlines.push(colorChalk.gray(\"│ \") + colorChalk.italic(quoteLine));\n\t\t\t\t}\n\t\t\t\tlines.push(\"\"); // Add spacing after blockquotes\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase \"hr\":\n\t\t\t\tlines.push(colorChalk.gray(\"─\".repeat(Math.min(width, 80))));\n\t\t\t\tlines.push(\"\"); // Add spacing after horizontal rules\n\t\t\t\tbreak;\n\n\t\t\tcase \"html\":\n\t\t\t\t// Skip HTML for terminal output\n\t\t\t\tbreak;\n\n\t\t\tcase \"space\":\n\t\t\t\t// Space tokens represent blank lines in markdown\n\t\t\t\tlines.push(\"\");\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t// Handle any other token types as plain text\n\t\t\t\tif (\"text\" in token && typeof token.text === \"string\") {\n\t\t\t\t\tlines.push(token.text);\n\t\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\tprivate renderInlineTokens(tokens: Token[]): string {\n\t\tlet result = \"\";\n\n\t\tfor (const token of tokens) {\n\t\t\tswitch (token.type) {\n\t\t\t\tcase \"text\":\n\t\t\t\t\t// Text tokens in list items can have nested tokens for inline formatting\n\t\t\t\t\tif (token.tokens && token.tokens.length > 0) {\n\t\t\t\t\t\tresult += this.renderInlineTokens(token.tokens);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Apply default style to plain text\n\t\t\t\t\t\tresult += this.applyDefaultStyle(token.text);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"strong\": {\n\t\t\t\t\t// Apply bold, then reapply default style after\n\t\t\t\t\tconst boldContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.bold(boldContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"em\": {\n\t\t\t\t\t// Apply italic, then reapply default style after\n\t\t\t\t\tconst italicContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.italic(italicContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"codespan\":\n\t\t\t\t\t// Apply code styling without backticks\n\t\t\t\t\tresult += colorChalk.cyan(token.text) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"link\": {\n\t\t\t\t\tconst linkText = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\t// If link text matches href, only show the link once\n\t\t\t\t\tif (linkText === token.href) {\n\t\t\t\t\t\tresult += colorChalk.underline.blue(linkText) + this.applyDefaultStyle(\"\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult +=\n\t\t\t\t\t\t\tcolorChalk.underline.blue(linkText) +\n\t\t\t\t\t\t\tcolorChalk.gray(` (${token.href})`) +\n\t\t\t\t\t\t\tthis.applyDefaultStyle(\"\");\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"br\":\n\t\t\t\t\tresult += \"\\n\";\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"del\": {\n\t\t\t\t\tconst delContent = this.renderInlineTokens(token.tokens || []);\n\t\t\t\t\tresult += colorChalk.strikethrough(delContent) + this.applyDefaultStyle(\"\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdefault:\n\t\t\t\t\t// Handle any other inline token types as plain text\n\t\t\t\t\tif (\"text\" in token && typeof token.text === \"string\") {\n\t\t\t\t\t\tresult += this.applyDefaultStyle(token.text);\n\t\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Render a list with proper nesting support\n\t */\n\tprivate renderList(token: Token & { items: any[]; ordered: boolean }, depth: number): string[] {\n\t\tconst lines: string[] = [];\n\t\tconst indent = \" \".repeat(depth);\n\n\t\tfor (let i = 0; i < token.items.length; i++) {\n\t\t\tconst item = token.items[i];\n\t\t\tconst bullet = token.ordered ? `${i + 1}. ` : \"- \";\n\n\t\t\t// Process item tokens to handle nested lists\n\t\t\tconst itemLines = this.renderListItem(item.tokens || [], depth);\n\n\t\t\tif (itemLines.length > 0) {\n\t\t\t\t// First line - check if it's a nested list\n\t\t\t\t// A nested list will start with indent (spaces) followed by cyan bullet\n\t\t\t\tconst firstLine = itemLines[0];\n\t\t\t\tconst isNestedList = /^\\s+\\x1b\\[36m[-\\d]/.test(firstLine); // starts with spaces + cyan + bullet char\n\n\t\t\t\tif (isNestedList) {\n\t\t\t\t\t// This is a nested list, just add it as-is (already has full indent)\n\t\t\t\t\tlines.push(firstLine);\n\t\t\t\t} else {\n\t\t\t\t\t// Regular text content - add indent and bullet\n\t\t\t\t\tlines.push(indent + colorChalk.cyan(bullet) + firstLine);\n\t\t\t\t}\n\n\t\t\t\t// Rest of the lines\n\t\t\t\tfor (let j = 1; j < itemLines.length; j++) {\n\t\t\t\t\tconst line = itemLines[j];\n\t\t\t\t\tconst isNestedListLine = /^\\s+\\x1b\\[36m[-\\d]/.test(line); // starts with spaces + cyan + bullet char\n\n\t\t\t\t\tif (isNestedListLine) {\n\t\t\t\t\t\t// Nested list line - already has full indent\n\t\t\t\t\t\tlines.push(line);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Regular content - add parent indent + 2 spaces for continuation\n\t\t\t\t\t\tlines.push(indent + \" \" + line);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlines.push(indent + colorChalk.cyan(bullet));\n\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Render list item tokens, handling nested lists\n\t * Returns lines WITHOUT the parent indent (renderList will add it)\n\t */\n\tprivate renderListItem(tokens: Token[], parentDepth: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tfor (const token of tokens) {\n\t\t\tif (token.type === \"list\") {\n\t\t\t\t// Nested list - render with one additional indent level\n\t\t\t\t// These lines will have their own indent, so we just add them as-is\n\t\t\t\tconst nestedLines = this.renderList(token as any, parentDepth + 1);\n\t\t\t\tlines.push(...nestedLines);\n\t\t\t} else if (token.type === \"text\") {\n\t\t\t\t// Text content (may have inline tokens)\n\t\t\t\tconst text =\n\t\t\t\t\ttoken.tokens && token.tokens.length > 0 ? this.renderInlineTokens(token.tokens) : token.text || \"\";\n\t\t\t\tlines.push(text);\n\t\t\t} else if (token.type === \"paragraph\") {\n\t\t\t\t// Paragraph in list item\n\t\t\t\tconst text = this.renderInlineTokens(token.tokens || []);\n\t\t\t\tlines.push(text);\n\t\t\t} else if (token.type === \"code\") {\n\t\t\t\t// Code block in list item\n\t\t\t\tlines.push(colorChalk.gray(\"```\" + (token.lang || \"\")));\n\t\t\t\tconst codeLines = token.text.split(\"\\n\");\n\t\t\t\tfor (const codeLine of codeLines) {\n\t\t\t\t\tlines.push(colorChalk.dim(\" \") + colorChalk.green(codeLine));\n\t\t\t\t}\n\t\t\t\tlines.push(colorChalk.gray(\"```\"));\n\t\t\t} else {\n\t\t\t\t// Other token types - try to render as inline\n\t\t\t\tconst text = this.renderInlineTokens([token]);\n\t\t\t\tif (text) {\n\t\t\t\t\tlines.push(text);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Render a table\n\t */\n\tprivate renderTable(token: Token & { header: any[]; rows: any[][] }): string[] {\n\t\tconst lines: string[] = [];\n\n\t\t// Calculate column widths\n\t\tconst columnWidths: number[] = [];\n\n\t\t// Check header\n\t\tfor (let i = 0; i < token.header.length; i++) {\n\t\t\tconst headerText = this.renderInlineTokens(token.header[i].tokens || []);\n\t\t\tconst width = visibleWidth(headerText);\n\t\t\tcolumnWidths[i] = Math.max(columnWidths[i] || 0, width);\n\t\t}\n\n\t\t// Check rows\n\t\tfor (const row of token.rows) {\n\t\t\tfor (let i = 0; i < row.length; i++) {\n\t\t\t\tconst cellText = this.renderInlineTokens(row[i].tokens || []);\n\t\t\t\tconst width = visibleWidth(cellText);\n\t\t\t\tcolumnWidths[i] = Math.max(columnWidths[i] || 0, width);\n\t\t\t}\n\t\t}\n\n\t\t// Limit column widths to reasonable max\n\t\tconst maxColWidth = 40;\n\t\tfor (let i = 0; i < columnWidths.length; i++) {\n\t\t\tcolumnWidths[i] = Math.min(columnWidths[i], maxColWidth);\n\t\t}\n\n\t\t// Render header\n\t\tconst headerCells = token.header.map((cell, i) => {\n\t\t\tconst text = this.renderInlineTokens(cell.tokens || []);\n\t\t\treturn colorChalk.bold(text.padEnd(columnWidths[i]));\n\t\t});\n\t\tlines.push(\"│ \" + headerCells.join(\" │ \") + \" │\");\n\n\t\t// Render separator\n\t\tconst separatorCells = columnWidths.map((width) => \"─\".repeat(width));\n\t\tlines.push(\"├─\" + separatorCells.join(\"─┼─\") + \"─┤\");\n\n\t\t// Render rows\n\t\tfor (const row of token.rows) {\n\t\t\tconst rowCells = row.map((cell, i) => {\n\t\t\t\tconst text = this.renderInlineTokens(cell.tokens || []);\n\t\t\t\tconst visWidth = visibleWidth(text);\n\t\t\t\tconst padding = \" \".repeat(Math.max(0, columnWidths[i] - visWidth));\n\t\t\t\treturn text + padding;\n\t\t\t});\n\t\t\tlines.push(\"│ \" + rowCells.join(\" │ \") + \" │\");\n\t\t}\n\n\t\tlines.push(\"\"); // Add spacing after table\n\t\treturn lines;\n\t}\n}\n"]}
|