Skip to content

Commit 5140b67

Browse files
committed
Add a button to copy markdown out of the chat
1 parent c7bfcf3 commit 5140b67

File tree

3 files changed

+66
-7
lines changed

3 files changed

+66
-7
lines changed

.changeset/real-rockets-sort.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"roo-cline": patch
3+
---
4+
5+
Add a button to copy markdown out of the chat

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Give it a try and let us know what you think in the reddit: https://www.reddit.c
3535
- Sound effects for feedback
3636
- Option to use browsers of different sizes and adjust screenshot quality
3737
- Quick prompt copying from history
38+
- Copy markdown from chat messages
3839
- OpenRouter compression support
3940
- Includes current time in the system prompt
4041
- Uses a file system watcher to more reliably watch for file system changes

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

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { VSCodeBadge, VSCodeButton, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"
22
import deepEqual from "fast-deep-equal"
3-
import React, { memo, useEffect, useMemo, useRef } from "react"
3+
import React, { memo, useEffect, useMemo, useRef, useState } from "react"
44
import { useSize } from "react-use"
55
import {
66
ClineApiReqInfo,
@@ -551,7 +551,7 @@ export const ChatRowContent = ({
551551
case "text":
552552
return (
553553
<div>
554-
<Markdown markdown={message.text} />
554+
<Markdown markdown={message.text} partial={message.partial} />
555555
</div>
556556
)
557557
case "user_feedback":
@@ -703,7 +703,7 @@ export const ChatRowContent = ({
703703
</div>
704704
)}
705705
<div style={{ paddingTop: 10 }}>
706-
<Markdown markdown={message.text} />
706+
<Markdown markdown={message.text} partial={message.partial} />
707707
</div>
708708
</>
709709
)
@@ -876,7 +876,7 @@ export const ChatRowContent = ({
876876
{title}
877877
</div>
878878
<div style={{ color: "var(--vscode-charts-green)", paddingTop: 10 }}>
879-
<Markdown markdown={message.text} />
879+
<Markdown markdown={message.text} partial={message.partial} />
880880
</div>
881881
</div>
882882
)
@@ -918,10 +918,63 @@ export const ProgressIndicator = () => (
918918
</div>
919919
)
920920

921-
const Markdown = memo(({ markdown }: { markdown?: string }) => {
921+
const Markdown = memo(({ markdown, partial }: { markdown?: string; partial?: boolean }) => {
922+
const [isHovering, setIsHovering] = useState(false);
923+
922924
return (
923-
<div style={{ wordBreak: "break-word", overflowWrap: "anywhere", marginBottom: -15, marginTop: -15 }}>
924-
<MarkdownBlock markdown={markdown} />
925+
<div
926+
onMouseEnter={() => setIsHovering(true)}
927+
onMouseLeave={() => setIsHovering(false)}
928+
style={{ position: "relative" }}
929+
>
930+
<div style={{ wordBreak: "break-word", overflowWrap: "anywhere", marginBottom: -15, marginTop: -15 }}>
931+
<MarkdownBlock markdown={markdown} />
932+
</div>
933+
{markdown && !partial && isHovering && (
934+
<div
935+
style={{
936+
position: "absolute",
937+
bottom: "-4px",
938+
right: "8px",
939+
opacity: 0,
940+
animation: "fadeIn 0.2s ease-in-out forwards",
941+
borderRadius: "4px"
942+
}}
943+
>
944+
<style>
945+
{`
946+
@keyframes fadeIn {
947+
from { opacity: 0; }
948+
to { opacity: 1.0; }
949+
}
950+
`}
951+
</style>
952+
<VSCodeButton
953+
className="copy-button"
954+
appearance="icon"
955+
style={{
956+
height: "24px",
957+
border: "none",
958+
background: "var(--vscode-editor-background)",
959+
transition: "background 0.2s ease-in-out"
960+
}}
961+
onClick={() => {
962+
navigator.clipboard.writeText(markdown);
963+
// Flash the button background briefly to indicate success
964+
const button = document.activeElement as HTMLElement;
965+
if (button) {
966+
button.style.background = "var(--vscode-button-background)";
967+
setTimeout(() => {
968+
button.style.background = "";
969+
}, 200);
970+
}
971+
}}
972+
title="Copy as markdown"
973+
>
974+
<span className="codicon codicon-copy"></span>
975+
</VSCodeButton>
976+
</div>
977+
)}
925978
</div>
926979
)
927980
})

0 commit comments

Comments
 (0)