Skip to content

Commit b990949

Browse files
markdown table rendering added
1 parent f96021f commit b990949

File tree

5 files changed

+771
-3
lines changed

5 files changed

+771
-3
lines changed

webview-ui/src/components/chat/Markdown.tsx

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,57 @@
1-
import { memo, useState } from "react"
1+
import React, { memo, useState } from "react"
22
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
33

44
import { useCopyToClipboard } from "@src/utils/clipboard"
55
import { StandardTooltip } from "@src/components/ui"
66

77
import 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

Comments
 (0)