Skip to content

Commit 663d15f

Browse files
committed
Fix: Codeblock rendering issue
1 parent e09607c commit 663d15f

File tree

2 files changed

+68
-77
lines changed

2 files changed

+68
-77
lines changed

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

Lines changed: 58 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -80,73 +80,68 @@ const ChatRow = memo(
8080
export default ChatRow
8181

8282
// Define the new wrapper component with copy functionality
83-
const MarkdownWithCopy = memo(
84-
({ content, partial, isComplete }: { content: string; partial?: boolean; isComplete: boolean }) => {
85-
// Added isComplete prop
86-
const [isHovering, setIsHovering] = useState(false)
87-
// Assuming useCopyToClipboard is imported correctly (it is, line 5)
88-
const { copyWithFeedback } = useCopyToClipboard(200) // Use shorter feedback duration like original
83+
const MarkdownWithCopy = memo(({ content, partial }: { content: string; partial?: boolean }) => {
84+
const [isHovering, setIsHovering] = useState(false)
85+
// Assuming useCopyToClipboard is imported correctly (it is, line 5)
86+
const { copyWithFeedback } = useCopyToClipboard(200) // Use shorter feedback duration like original
8987

90-
return (
91-
<div
92-
onMouseEnter={() => setIsHovering(true)}
93-
onMouseLeave={() => setIsHovering(false)}
94-
style={{ position: "relative" }}>
95-
{/* Apply negative margins and text wrap styles */}
96-
<div style={{ wordBreak: "break-word", overflowWrap: "anywhere" }}>
97-
{/* Use the imported shared Markdown component */}
98-
{/* Pass isComplete down to Markdown */}
99-
<Markdown content={content} isComplete={isComplete} />
100-
</div>
101-
{/* Conditional Copy Button */}
102-
{content && !partial && isHovering && (
103-
<div
104-
style={{
105-
position: "absolute",
106-
bottom: "-4px",
107-
right: "8px",
108-
opacity: 0,
109-
animation: "fadeIn 0.2s ease-in-out forwards",
110-
borderRadius: "4px",
111-
}}>
112-
<style>
113-
{`
88+
return (
89+
<div
90+
onMouseEnter={() => setIsHovering(true)}
91+
onMouseLeave={() => setIsHovering(false)}
92+
style={{ position: "relative" }}>
93+
{/* Apply negative margins and text wrap styles */}
94+
<div style={{ wordBreak: "break-word", overflowWrap: "anywhere" }}>
95+
<Markdown content={content} isComplete={!partial} />
96+
</div>
97+
{/* Conditional Copy Button */}
98+
{content && !partial && isHovering && (
99+
<div
100+
style={{
101+
position: "absolute",
102+
bottom: "-4px",
103+
right: "8px",
104+
opacity: 0,
105+
animation: "fadeIn 0.2s ease-in-out forwards",
106+
borderRadius: "4px",
107+
}}>
108+
<style>
109+
{`
114110
@keyframes fadeIn {
115111
from { opacity: 0; }
116112
to { opacity: 1.0; }
117113
}
118114
`}
119-
</style>
120-
<VSCodeButton
121-
className="copy-button"
122-
appearance="icon"
123-
style={{
124-
height: "24px",
125-
border: "none",
126-
background: "var(--vscode-editor-background)",
127-
transition: "background 0.2s ease-in-out",
128-
}}
129-
onClick={async () => {
130-
const success = await copyWithFeedback(content) // Use content prop
131-
if (success) {
132-
const button = document.activeElement as HTMLElement
133-
if (button) {
134-
button.style.background = "var(--vscode-button-background)"
135-
setTimeout(() => {
136-
button.style.background = ""
137-
}, 200)
138-
}
115+
</style>
116+
<VSCodeButton
117+
className="copy-button"
118+
appearance="icon"
119+
style={{
120+
height: "24px",
121+
border: "none",
122+
background: "var(--vscode-editor-background)",
123+
transition: "background 0.2s ease-in-out",
124+
}}
125+
onClick={async () => {
126+
const success = await copyWithFeedback(content) // Use content prop
127+
if (success) {
128+
const button = document.activeElement as HTMLElement
129+
if (button) {
130+
button.style.background = "var(--vscode-button-background)"
131+
setTimeout(() => {
132+
button.style.background = ""
133+
}, 200)
139134
}
140-
}}
141-
title="Copy as markdown">
142-
<span className="codicon codicon-copy"></span>
143-
</VSCodeButton>
144-
</div>
145-
)}
146-
</div>
147-
)
148-
},
149-
)
135+
}
136+
}}
137+
title="Copy as markdown">
138+
<span className="codicon codicon-copy"></span>
139+
</VSCodeButton>
140+
</div>
141+
)}
142+
</div>
143+
)
144+
})
150145

151146
export const ChatRowContent = ({
152147
message,
@@ -898,11 +893,7 @@ export const ChatRowContent = ({
898893
case "text":
899894
return (
900895
<div>
901-
<MarkdownWithCopy
902-
content={message.text || ""}
903-
partial={message.partial}
904-
isComplete={!message.partial}
905-
/>
896+
<MarkdownWithCopy content={message.text || ""} partial={message.partial} />
906897
</div>
907898
)
908899
case "user_feedback":
@@ -961,11 +952,7 @@ export const ChatRowContent = ({
961952
{title}
962953
</div>
963954
<div style={{ color: "var(--vscode-charts-green)", paddingTop: 10 }}>
964-
<MarkdownWithCopy
965-
content={message.text || ""}
966-
partial={message.partial}
967-
isComplete={!message.partial}
968-
/>
955+
<MarkdownWithCopy content={message.text || ""} partial={message.partial} />
969956
</div>
970957
</>
971958
)
@@ -1012,11 +999,7 @@ export const ChatRowContent = ({
1012999
</div>
10131000
)}
10141001
<div style={{ paddingTop: 10 }}>
1015-
<MarkdownWithCopy
1016-
content={message.text || ""}
1017-
partial={message.partial}
1018-
isComplete={!message.partial}
1019-
/>
1002+
<MarkdownWithCopy content={message.text || ""} partial={message.partial} />
10201003
</div>
10211004
</>
10221005
)

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,24 @@ import { Separator } from "@/components/ui"
99
import { CodeBlock } from "./CodeBlock"
1010
import { Blockquote } from "./Blockquote"
1111

12-
const MemoizedReactMarkdown: FC<Options> = memo(
12+
const MemoizedReactMarkdown: FC<Options & { isComplete?: boolean }> = memo(
1313
ReactMarkdown,
14-
(prevProps, nextProps) => prevProps.children === nextProps.children && prevProps.className === nextProps.className,
14+
(prevProps: Options & { isComplete?: boolean }, nextProps: Options & { isComplete?: boolean }) => {
15+
// Compare children, className, and isComplete
16+
const childrenEqual = prevProps.children === nextProps.children
17+
const classNameEqual = prevProps.className === nextProps.className
18+
const isCompleteEqual = prevProps.isComplete === nextProps.isComplete
19+
// Only skip rendering if all relevant props are equal
20+
return childrenEqual && classNameEqual && isCompleteEqual
21+
},
1522
)
1623

1724
export function Markdown({ content, isComplete }: { content: string; isComplete?: boolean }) {
1825
// Added optional isComplete prop
1926
return (
2027
<MemoizedReactMarkdown
2128
remarkPlugins={[remarkGfm]}
29+
isComplete={isComplete}
2230
className="custom-markdown break-words text-[var(--vscode-font-size)]"
2331
components={{
2432
p({ children }) {

0 commit comments

Comments
 (0)