Skip to content

feat(vscode): add per-message Copy Markdown action on assistant replies#106

Merged
ktmage merged 1 commit into
ktmage:developmentfrom
zeug-zz:feat/copy-markdown-button
Jun 12, 2026
Merged

feat(vscode): add per-message Copy Markdown action on assistant replies#106
ktmage merged 1 commit into
ktmage:developmentfrom
zeug-zz:feat/copy-markdown-button

Conversation

@zeug-zz

@zeug-zz zeug-zz commented Jun 8, 2026

Copy link
Copy Markdown

Add a per-message clipboard action under assistant messages that copies the raw Markdown source (including code fences and raw KaTeX) via the existing copyToClipboard webview message.

What changes

  • Export getAssistantMarkdownSource(parts) and getCopyableAssistantMarkdownSource(parts, { isUser, isShell }) from MessageItem.tsx.
    • getAssistantMarkdownSource joins visible TextPart.text values with \n\n and returns null when there is nothing copyable.
    • getCopyableAssistantMarkdownSource short-circuits to null for user messages and shell-result assistant messages so only normal assistant replies qualify.
  • Render a <button type="button"> with an inline double-pages SVG clipboard icon when copyable Markdown source exists. The button is hidden for user messages, shell user/assistant messages, and messages with no copyable text.
  • Locales updated: en, es, ja, ko, pt-br, ru, zh-cn, zh-tw.
  • Reuses the existing webview-to-extension copyToClipboard message path — no new extension-host clipboard APIs.

Impact

  • 13 files changed, +631 / −5
  • Tests: 1566/1566 pass (33 new tests on top of the KaTeX PR baseline)
  • pnpm check introduces no new warnings in the touched files
  • No new runtime dependencies
  • No breaking changes to existing rendered Markdown, KaTeX rendering, code-block copy buttons, file-path links, user-message edit behavior, or shell-result rendering
  • Native selection copy behavior is unchanged in this PR; selection-aware Markdown copy is a possible follow-up

Add a small clipboard action under every assistant message that posts
the raw Markdown source (including code fences and raw KaTeX) via the
existing copyToClipboard message, so users can paste the answer
elsewhere without losing formatting or math.

- Export getAssistantMarkdownSource(parts) and
  getCopyableAssistantMarkdownSource(parts, { isUser, isShell }) from
  MessageItem.tsx. The former joins visible TextPart.text values with
  "\n\n" and returns null when there is nothing copyable; the latter
  short-circuits to null for user messages and shell-result assistant
  messages so only normal assistant replies qualify.
- Render a <button type="button"> with an inline double-pages SVG
  clipboard icon when copyable Markdown source exists. The button is
  hidden for user messages, shell user/assistant messages, and
  messages whose non-text parts produce no copyable text. A 1.5s
  checkmark-icon feedback mirrors the existing code-block copy UX.
  aria-label and title stay as the localized "message.copyMarkdown"
  string for screen readers; the visible content is the icon, not the
  label.
- Add message.copyMarkdown to all 8 locales (en, ja, ko, zh-cn,
  zh-tw, es, pt-br, ru). The value is used for aria-label and title;
  the button body is the icon.
- Add a .copyMarkdownButton block to MessageItem.module.css with
  hover (--vscode-foreground + --vscode-toolbar-hoverBackground),
  :focus-visible outline (--vscode-focusBorder), and a .copied
  modifier using --vscode-charts-green. The icon button does not
  declare user-select, so its label text inside aria-label/title
  remains native-selectable.
- Switch package.json activationEvents from [] to
  ["onView:opencode.chatView"] to make view-triggered activation
  explicit instead of relying on implicit auto-activation.
- Add 24 new MessageItem.test.tsx cases covering: getAssistantMarkdownSource
  and getCopyableAssistantMarkdownSource (10), render/hide
  conditions for the Copy Markdown button (7), postMessage payload
  shape including raw KaTeX and "\n\n"-joined multi-part sources
  (6), code-block vs message-level copy independence (2), and
  native copy/selection independence (5). Use vi.useFakeTimers to
  assert the 1.5s copied-icon feedback reverts.
- Add 2 TextPartView.test.tsx cases asserting the code-block copy
  button still posts only the <pre><code> text and excludes the
  code fence and surrounding prose.
- No changes to TextPartView.tsx, vscode-api.ts, the extension host,
  the clipboard transport type, KaTeX rendering, CSP, or the
  code-block copy path.
@ktmage

ktmage commented Jun 9, 2026

Copy link
Copy Markdown
Owner

@zeug-zz これレビューしちゃってもいいですか?良さそうだったらreviewerに入れてください!

@zeug-zz

zeug-zz commented Jun 9, 2026

Copy link
Copy Markdown
Author

@zeug-zz これレビューしちゃってもいいですか?良さそうだったらreviewerに入れてください!

@ktmage yes go ahead! Feel free to self-assign as reviewer, I don't have the permissions to add you from this side.

@ktmage ktmage self-requested a review June 9, 2026 23:33
@zeug-zz zeug-zz force-pushed the feat/copy-markdown-button branch 2 times, most recently from 3f7b0d8 to e371598 Compare June 10, 2026 19:52

@ktmage ktmage left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm! thankyou~~~

Comment on lines +37 to +39
"activationEvents": [
"onView:opencode.chatView"
],

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thankyou~~~~~~

@ktmage ktmage merged commit 2a1a5f6 into ktmage:development Jun 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants