feat(tui): copy console logs to clipboard on click
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.fps→app.console)
Someone did already say they wanted to work on it :/ https://github.com/sst/opencode/issues/4885#issuecomment-3616293089
Would you like me to leave PR open or close it
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
/review
lgtm
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
- Console is visible but user clicks elsewhere (unfocused)
- User triggers "Toggle console"
- opentui calls
focus()- console stays visible - But
setConsoleOpen((v) => !v)flips tofalse - State mismatch: console IS visible but
consoleOpenisfalse - 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.
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?
I definitely think thats a better long term solution and would be much cleaner. Should prioritize getting the ctrl+s behavior documented.
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.
nice!!!
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) - containsonCopySelectioncallback
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:
- Wait for opentui npm publish with commit
bd159ef8 - Update
@opentui/coreand@opentui/solidin package.json - Add the
onCopySelectioncallback wiring - Reopen this PR
Nice!
Updated implementation to use opentui's onCopySelection callback from PR #411.
Changes:
- Updated
@opentui/coreand@opentui/solidto0.1.61 - Replaced manual click-to-copy with
renderer.console.onCopySelectioncallback - Removed
MouseParserand console state tracking (now handled by opentui internally) - Selection-based copy with keyboard shortcut (
Ctrl+Shift+C) and [Copy] button in console
@rekram1-node can you re open PR or do you want me to create new