From bb8f6b376d83a9b70406279c87ab8b163fb32a38 Mon Sep 17 00:00:00 2001 From: zfflxx <106017702+zfflxx@users.noreply.github.com> Date: Mon, 7 Jul 2025 13:33:46 +0800 Subject: Fix nested markdown Rendering for table headers and rows #3331 (#3362) Co-authored-by: Ryan Fang --- packages/cli/src/ui/utils/MarkdownDisplay.tsx | 144 +------------------------- 1 file changed, 1 insertion(+), 143 deletions(-) (limited to 'packages/cli/src/ui/utils/MarkdownDisplay.tsx') diff --git a/packages/cli/src/ui/utils/MarkdownDisplay.tsx b/packages/cli/src/ui/utils/MarkdownDisplay.tsx index 55f1ce57..572ae12e 100644 --- a/packages/cli/src/ui/utils/MarkdownDisplay.tsx +++ b/packages/cli/src/ui/utils/MarkdownDisplay.tsx @@ -9,6 +9,7 @@ import { Text, Box } from 'ink'; import { Colors } from '../colors.js'; import { colorizeCode } from './CodeColorizer.js'; import { TableRenderer } from './TableRenderer.js'; +import { RenderInline } from './InlineMarkdownRenderer.js'; interface MarkdownDisplayProps { text: string; @@ -18,12 +19,6 @@ interface MarkdownDisplayProps { } // Constants for Markdown parsing and rendering -const BOLD_MARKER_LENGTH = 2; // For "**" -const ITALIC_MARKER_LENGTH = 1; // For "*" or "_" -const STRIKETHROUGH_MARKER_LENGTH = 2; // For "~~" -const INLINE_CODE_MARKER_LENGTH = 1; // For "`" -const UNDERLINE_TAG_START_LENGTH = 3; // For "" -const UNDERLINE_TAG_END_LENGTH = 4; // For "" const EMPTY_LINE_HEIGHT = 1; const CODE_BLOCK_PADDING = 1; @@ -277,143 +272,6 @@ const MarkdownDisplayInternal: React.FC = ({ // Helper functions (adapted from static methods of MarkdownRenderer) -interface RenderInlineProps { - text: string; -} - -const RenderInlineInternal: React.FC = ({ text }) => { - const nodes: React.ReactNode[] = []; - let lastIndex = 0; - const inlineRegex = - /(\*\*.*?\*\*|\*.*?\*|_.*?_|~~.*?~~|\[.*?\]\(.*?\)|`+.+?`+|.*?<\/u>)/g; - let match; - - while ((match = inlineRegex.exec(text)) !== null) { - if (match.index > lastIndex) { - nodes.push( - - {text.slice(lastIndex, match.index)} - , - ); - } - - const fullMatch = match[0]; - let renderedNode: React.ReactNode = null; - const key = `m-${match.index}`; - - try { - if ( - fullMatch.startsWith('**') && - fullMatch.endsWith('**') && - fullMatch.length > BOLD_MARKER_LENGTH * 2 - ) { - renderedNode = ( - - {fullMatch.slice(BOLD_MARKER_LENGTH, -BOLD_MARKER_LENGTH)} - - ); - } else if ( - fullMatch.length > ITALIC_MARKER_LENGTH * 2 && - ((fullMatch.startsWith('*') && fullMatch.endsWith('*')) || - (fullMatch.startsWith('_') && fullMatch.endsWith('_'))) && - !/\w/.test(text.substring(match.index - 1, match.index)) && - !/\w/.test( - text.substring(inlineRegex.lastIndex, inlineRegex.lastIndex + 1), - ) && - !/\S[./\\]/.test(text.substring(match.index - 2, match.index)) && - !/[./\\]\S/.test( - text.substring(inlineRegex.lastIndex, inlineRegex.lastIndex + 2), - ) - ) { - renderedNode = ( - - {fullMatch.slice(ITALIC_MARKER_LENGTH, -ITALIC_MARKER_LENGTH)} - - ); - } else if ( - fullMatch.startsWith('~~') && - fullMatch.endsWith('~~') && - fullMatch.length > STRIKETHROUGH_MARKER_LENGTH * 2 - ) { - renderedNode = ( - - {fullMatch.slice( - STRIKETHROUGH_MARKER_LENGTH, - -STRIKETHROUGH_MARKER_LENGTH, - )} - - ); - } else if ( - fullMatch.startsWith('`') && - fullMatch.endsWith('`') && - fullMatch.length > INLINE_CODE_MARKER_LENGTH - ) { - const codeMatch = fullMatch.match(/^(`+)(.+?)\1$/s); - if (codeMatch && codeMatch[2]) { - renderedNode = ( - - {codeMatch[2]} - - ); - } else { - renderedNode = ( - - {fullMatch.slice( - INLINE_CODE_MARKER_LENGTH, - -INLINE_CODE_MARKER_LENGTH, - )} - - ); - } - } else if ( - fullMatch.startsWith('[') && - fullMatch.includes('](') && - fullMatch.endsWith(')') - ) { - const linkMatch = fullMatch.match(/\[(.*?)\]\((.*?)\)/); - if (linkMatch) { - const linkText = linkMatch[1]; - const url = linkMatch[2]; - renderedNode = ( - - {linkText} - ({url}) - - ); - } - } else if ( - fullMatch.startsWith('') && - fullMatch.endsWith('') && - fullMatch.length > - UNDERLINE_TAG_START_LENGTH + UNDERLINE_TAG_END_LENGTH - 1 // -1 because length is compared to combined length of start and end tags - ) { - renderedNode = ( - - {fullMatch.slice( - UNDERLINE_TAG_START_LENGTH, - -UNDERLINE_TAG_END_LENGTH, - )} - - ); - } - } catch (e) { - console.error('Error parsing inline markdown part:', fullMatch, e); - renderedNode = null; - } - - nodes.push(renderedNode ?? {fullMatch}); - lastIndex = inlineRegex.lastIndex; - } - - if (lastIndex < text.length) { - nodes.push({text.slice(lastIndex)}); - } - - return <>{nodes.filter((node) => node !== null)}; -}; - -const RenderInline = React.memo(RenderInlineInternal); - interface RenderCodeBlockProps { content: string[]; lang: string | null; -- cgit v1.2.3