Skip to content

fix(run-r): add per-block copy buttons and restore IDE action buttons#188

Open
gadenbuie wants to merge 1 commit intomainfrom
fix/run-r-result-code-action-buttons
Open

fix(run-r): add per-block copy buttons and restore IDE action buttons#188
gadenbuie wants to merge 1 commit intomainfrom
fix/run-r-result-code-action-buttons

Conversation

@gadenbuie
Copy link
Copy Markdown
Collaborator

Summary

Two features of btw-run-r-result were broken in the new React shinychat. In the React rewrite, btw-run-r-result is rendered as a raw HTML island via <shinychat-raw-html> and never passes through React's markdown pipeline. This means shinychat's CopyableCodeBlock component and the shiny-markdown-stream MutationObserver in btw_app.js no longer reach btw's code blocks.

btw-run-r.jsaddBlockCopyButtons()

New method called at the end of render(). Adds a .btw-block-copy-btn button to each <pre> inside .btw-run-output, copying that block's plain text content to the clipboard. Idempotent (guards against duplicate buttons on re-render). After adding buttons, dispatches a "btw-run-r-rendered" custom event so btw_app.js can install IDE action buttons without coupling the two files.

btw_app.js — update IDE enhancement for new React shinychat

  • STREAM_SELECTOR now matches both "shiny-markdown-stream" (old Lit) and ".shiny-chat-message-content" (new React). All querySelectorAll and el.matches() calls use this constant.
  • attachObserver now calls callback(el) immediately on attach. In React, .shiny-chat-message-content is inserted with its full subtree in one commit, so the per-element MutationObserver never fires for that initial content.
  • New enhanceBtwCodeActions(result) handles .btw-block-copy-btn buttons inside btw-run-r-result, adding IDE action buttons (insert at cursor, new file, console) to .btw-output-source blocks only.
  • Button order: IDE action buttons are appended before the copy button in both functions, so copy is always rightmost.

btw-run-r.css / btw_app.css — icon styles

.btw-block-copy-btn uses <i class="bi"> markup with a CSS mask-image icon (same vscode codicon as .code-copy-button). btw-run-r.css carries self-contained icon rules so the button renders in any shinychat version. btw_app.css resets the button to static position and full opacity when inside .code-action-wrapper. btw-run-r.css hides .code-copy-button inside btw output blocks to prevent old shinychat from adding a duplicate.

Verification

In a btw shinychat app, ask a question that causes the model to call btw_tool_run_r() (e.g. "What are 5 random numbers between 1 and 100?"). Each output block in the result card should now have a copy button (visible on hover). In the btw IDE app, source code blocks should also show the insert-at-cursor, new-file, and run-in-console action buttons.

In the new React shinychat, btw-run-r-result is rendered as a raw HTML
island (via <shinychat-raw-html>) and never passes through React's
markdown pipeline. As a result, two features that previously worked were
broken:

1. Per-block copy buttons: shinychat's CopyableCodeBlock React component
   is never reached for code blocks inside HTML islands, so no copy
   buttons were added to source/output/message/warning/error blocks.

2. IDE action buttons (insert at cursor, insert in new file, run in
   console): btw_app.js enhanced code blocks by observing
   shiny-markdown-stream (the old Lit element) and finding
   .code-copy-button nodes. Both the element name and class are different
   in the new React shinychat.

Changes:

btw-run-r.js — add addBlockCopyButtons() method
  Called at the end of render(). Adds a .btw-block-copy-btn button to
  each <pre> inside .btw-run-output, copying that block's text content.
  Idempotent (guards against duplicate buttons on re-render). After
  adding buttons, dispatches a "btw-run-r-rendered" custom event so
  btw_app.js can install IDE action buttons without btw-run-r.js needing
  to import from the app layer.

btw_app.js — update IDE enhancement for new React shinychat
  - STREAM_SELECTOR now matches both "shiny-markdown-stream" (old Lit)
    and ".shiny-chat-message-content" (new React). All three querySelectorAll
    and el.matches() calls use this constant.
  - attachObserver now calls callback(el) immediately on attach. In React,
    .shiny-chat-message-content is inserted with its full subtree in one
    commit, so the per-element MutationObserver never fires for that
    initial content; the immediate callback handles it.
  - Add enhanceBtwCodeActions(result): handles .btw-block-copy-btn buttons
    inside btw-run-r-result, adding IDE action buttons to .btw-output-source
    blocks only. Wired up via the "btw-run-r-rendered" event.
  - Button order: IDE action buttons are appended before the copy button
    in both enhanceCodeActions and enhanceBtwCodeActions, so copy is
    always rightmost.

btw-run-r.css / btw_app.css — styles for .btw-block-copy-btn
  The button uses <i class="bi"> markup and a CSS mask-image icon (same
  vscode codicon as .code-copy-button) so no inline SVG is needed.
  btw-run-r.css carries the self-contained icon rules so the button
  renders correctly in any shinychat version. btw_app.css adds a reset
  for when the button is moved inside .code-action-wrapper (static
  position, full opacity, auto sizing).
  btw-run-r.css hides .code-copy-button inside btw output blocks to
  prevent the old shinychat pipeline from adding a duplicate button.
@gadenbuie gadenbuie marked this pull request as ready for review April 14, 2026 14:23
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.

1 participant