opencode icon indicating copy to clipboard operation
opencode copied to clipboard

feat(tui): copy console logs to clipboard on click

Open edlsh opened this issue 2 weeks ago • 7 comments

Closes #4885

When the debug console is visible, clicking anywhere on it copies all console logs to the clipboard and shows a toast notification.

Changes:

  • Add mouse click handler for console area
  • Track console visibility state
  • Fix incorrect command value (app.fpsapp.console)

edlsh avatar Dec 08 '25 14:12 edlsh

Someone did already say they wanted to work on it :/ https://github.com/sst/opencode/issues/4885#issuecomment-3616293089

rekram1-node avatar Dec 08 '25 18:12 rekram1-node

Would you like me to leave PR open or close it

edlsh avatar Dec 08 '25 18:12 edlsh

I'll merge this and then change the original issue. I think the console isn't scrollable and it should be

I'll msg that dude tho

rekram1-node avatar Dec 08 '25 18:12 rekram1-node

/review

rekram1-node avatar Dec 10 '25 16:12 rekram1-node

lgtm

github-actions[bot] avatar Dec 10 '25 16:12 github-actions[bot]

Bug Found: State Synchronization Issue

While reviewing this PR, I found a state synchronization bug that would cause the click-to-copy feature to stop working in certain scenarios.

The Problem

The current implementation uses a simple boolean flip:

const [consoleOpen, setConsoleOpen] = createSignal(!!process.env["SHOW_CONSOLE"])
// ...
setConsoleOpen((v) => !v)

However, opentui's toggle() method has 3 states, not 2:

Current State toggle() Action Result
hidden show+focus visible+focused
visible+focused hide hidden
visible+unfocused focus stays visible!

Bug Scenario

  1. Console is visible but user clicks elsewhere (unfocused)
  2. User triggers "Toggle console"
  3. opentui calls focus() - console stays visible
  4. But setConsoleOpen((v) => !v) flips to false
  5. State mismatch: console IS visible but consoleOpen is false
  6. Click-to-copy stops working because if (!consoleOpen()) return false

The Fix

Track both visible AND focused state to mirror opentui's actual behavior:

// Track console state to match opentui's 3-state toggle behavior
const [consoleState, setConsoleState] = createSignal<{ visible: boolean; focused: boolean }>({
  visible: !!process.env["SHOW_CONSOLE"],
  focused: !!process.env["SHOW_CONSOLE"], // show() also focuses
})

// In mouse handler:
if (!consoleState().visible) return false

// In toggle handler - mirror opentui's 3-state logic:
setConsoleState((s) => {
  if (s.visible) {
    if (s.focused) return { visible: false, focused: false }
    return { visible: true, focused: true }
  }
  return { visible: true, focused: true }
})

About SHOW_CONSOLE env var

To answer @rekram1-node's question: SHOW_CONSOLE is a legitimate env var already registered in opentui (packages/core/src/console.ts). It's used to show the console at startup. The PR correctly reads it to initialize state, syncing with opentui's internal behavior.


edlsh avatar Dec 10 '25 19:12 edlsh

So when the console is open u can do "ctrl+s" and it'll dump to a log file in cwd.

Talked w/ @kommander he suggested doing similar stuff but on the opentui side instead:

I'd rather allow selection in the console plus a button and a shortcut to copy to clipboard from opentui

But here in opencode we should prolly document the ctrl+s behavior.

Thoughts?

rekram1-node avatar Dec 12 '25 19:12 rekram1-node

I definitely think thats a better long term solution and would be much cleaner. Should prioritize getting the ctrl+s behavior documented.

edlsh avatar Dec 13 '25 10:12 edlsh

Created the opentui implementation here: https://github.com/sst/opentui/pull/411

Once that's merged, I'll update this PR to just wire up the onCopySelection callback.

Closing this for now.

edlsh avatar Dec 13 '25 11:12 edlsh

nice!!!

rekram1-node avatar Dec 13 '25 17:12 rekram1-node

Status Update

The opentui PR #411 has been merged (commit bd159ef85e5111a41928d16807ae2a51f1d0bce7), but a new npm version hasn't been published yet.

Current state:

  • Latest published: @opentui/[email protected] (Dec 11)
  • Needed commit: bd159ef8 (Dec 15) - contains onCopySelection callback

Ready to implement once published:

renderer.console.onCopySelection = async (text: string) => {
  const base64 = Buffer.from(text).toString('base64')
  const osc52 = \`\x1b]52;c;${base64}\x07\`
  const finalOsc52 = process.env['TMUX'] ? \`\x1bPtmux;\x1b${osc52}\x1b\\\` : osc52
  renderer.writeOut(finalOsc52)
  await Clipboard.copy(text)
    .then(() => toast.show({ message: 'Copied to clipboard', variant: 'info' }))
    .catch(toast.error)
}

This will wire up the console-specific copy selection. Note: The main TUI already has copy-on-select via the onMouseUp handler on the root box (lines 510-527 in app.tsx).

Next steps:

  1. Wait for opentui npm publish with commit bd159ef8
  2. Update @opentui/core and @opentui/solid in package.json
  3. Add the onCopySelection callback wiring
  4. Reopen this PR

edlsh avatar Dec 15 '25 18:12 edlsh

Nice!

rekram1-node avatar Dec 15 '25 18:12 rekram1-node

Updated implementation to use opentui's onCopySelection callback from PR #411.

Changes:

  • Updated @opentui/core and @opentui/solid to 0.1.61
  • Replaced manual click-to-copy with renderer.console.onCopySelection callback
  • Removed MouseParser and console state tracking (now handled by opentui internally)
  • Selection-based copy with keyboard shortcut (Ctrl+Shift+C) and [Copy] button in console

edlsh avatar Dec 17 '25 01:12 edlsh

@rekram1-node can you re open PR or do you want me to create new

edlsh avatar Dec 17 '25 01:12 edlsh