1- import { memo , useState } from "react"
1+ import React , { memo , useState } from "react"
22import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
33
44import { useCopyToClipboard } from "@src/utils/clipboard"
55import { StandardTooltip } from "@src/components/ui"
66
77import MarkdownBlock from "../common/MarkdownBlock"
8+ import { parseTable } from "../common/TableParser"
89
9- export const Markdown = memo ( ( { markdown, partial } : { markdown ?: string ; partial ?: boolean } ) => {
10+ const splitMarkdownAndTables = ( markdownText : string , ts : number ) => {
11+ const segments : { type : 'text' | 'table' ; content : string | React . ReactNode } [ ] = [ ] ;
12+ const lines = markdownText . split ( / \r ? \n / ) ;
13+ let currentLineIndex = 0 ;
14+ let currentTextBuffer : string [ ] = [ ] ;
15+
16+ while ( currentLineIndex < lines . length ) {
17+ const line = lines [ currentLineIndex ] ;
18+ if ( line . trim ( ) . startsWith ( '|' ) && line . trim ( ) . endsWith ( '|' ) ) {
19+ let potentialTableLines : string [ ] = [ ] ;
20+ let tempIndex = currentLineIndex ;
21+ potentialTableLines . push ( lines [ tempIndex ] ) ;
22+ tempIndex ++ ;
23+ if ( tempIndex < lines . length && lines [ tempIndex ] . trim ( ) . match ( / ^ \| (?: \s * [ - : ] + \s * \| ) + \s * $ / ) ) {
24+ potentialTableLines . push ( lines [ tempIndex ] ) ;
25+ tempIndex ++ ;
26+ while ( tempIndex < lines . length && lines [ tempIndex ] . trim ( ) . startsWith ( '|' ) && lines [ tempIndex ] . trim ( ) . endsWith ( '|' ) ) {
27+ potentialTableLines . push ( lines [ tempIndex ] ) ;
28+ tempIndex ++ ;
29+ }
30+ const tableString = potentialTableLines . join ( '\n' ) ;
31+ const parsedTableContent = parseTable ( tableString , `chat-table-${ ts } -${ segments . length } ` ) ;
32+
33+ if ( parsedTableContent ) {
34+ if ( currentTextBuffer . length > 0 ) {
35+ segments . push ( { type : 'text' , content : currentTextBuffer . join ( '\n' ) } ) ;
36+ currentTextBuffer = [ ] ;
37+ }
38+ segments . push ( { type : 'table' , content : parsedTableContent } ) ;
39+ currentLineIndex = tempIndex ;
40+ continue ;
41+ }
42+ }
43+ }
44+ currentTextBuffer . push ( line ) ;
45+ currentLineIndex ++ ;
46+ }
47+ if ( currentTextBuffer . length > 0 ) {
48+ segments . push ( { type : 'text' , content : currentTextBuffer . join ( '\n' ) } ) ;
49+ }
50+
51+ return segments ;
52+ } ;
53+
54+ export const Markdown = memo ( ( { markdown, partial, ts } : { markdown ?: string ; partial ?: boolean ; ts ?: number } ) => {
1055 const [ isHovering , setIsHovering ] = useState ( false )
1156
1257 // Shorter feedback duration for copy button flash.
@@ -16,13 +61,21 @@ export const Markdown = memo(({ markdown, partial }: { markdown?: string; partia
1661 return null
1762 }
1863
64+ const segments = splitMarkdownAndTables ( markdown , ts || Date . now ( ) ) ;
65+
1966 return (
2067 < div
2168 onMouseEnter = { ( ) => setIsHovering ( true ) }
2269 onMouseLeave = { ( ) => setIsHovering ( false ) }
2370 style = { { position : "relative" } } >
2471 < div style = { { wordBreak : "break-word" , overflowWrap : "anywhere" , marginBottom : - 15 , marginTop : - 15 } } >
25- < MarkdownBlock markdown = { markdown } />
72+ { segments . map ( ( segment , index ) => {
73+ if ( segment . type === 'text' ) {
74+ return < MarkdownBlock key = { index } markdown = { segment . content as string } /> ;
75+ } else {
76+ return < React . Fragment key = { index } > { segment . content } </ React . Fragment > ;
77+ }
78+ } ) }
2679 </ div >
2780 { markdown && ! partial && isHovering && (
2881 < div
0 commit comments