Skip to content

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

Closed
edlsh wants to merge 2 commits intoanomalyco:devfrom
edlsh:feat/console-click-to-copy
Closed

feat(tui): copy console logs to clipboard on click#5239
edlsh wants to merge 2 commits intoanomalyco:devfrom
edlsh:feat/console-click-to-copy

Conversation

@edlsh
Copy link
Copy Markdown
Contributor

@edlsh edlsh commented Dec 8, 2025

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 edlsh force-pushed the feat/console-click-to-copy branch from 83fa8d4 to 4b1879e Compare December 8, 2025 14:32
@rekram1-node
Copy link
Copy Markdown
Collaborator

Someone did already say they wanted to work on it :/
#4885 (comment)

@edlsh
Copy link
Copy Markdown
Contributor Author

edlsh commented Dec 8, 2025

Would you like me to leave PR open or close it

@rekram1-node
Copy link
Copy Markdown
Collaborator

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
Copy link
Copy Markdown
Collaborator

/review

@github-actions
Copy link
Copy Markdown
Contributor

lgtm

const exit = useExit()
const promptRef = usePromptRef()

const [consoleOpen, setConsoleOpen] = createSignal(!!process.env["SHOW_CONSOLE"])
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

what's this new env var for?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It determines whether the debug console panel is visible when the TUI starts. If SHOW_CONSOLE is set (to any truthy value), the console opens automatically on launch.

The click-to-copy feature would fail when console was visible but
unfocused because the state tracker assumed toggle() was a simple
on/off, but opentui's toggle() has 3 states:

- hidden → show+focus
- visible+focused → hide
- visible+unfocused → focus (stays visible!)

When user toggled an unfocused console, the old code would flip
consoleOpen to false even though the console remained visible,
breaking the click detection.

Now tracks both visible AND focused state to match opentui's
actual behavior, ensuring click-to-copy works reliably.

Closes #4885
@edlsh
Copy link
Copy Markdown
Contributor Author

edlsh commented Dec 10, 2025

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 edlsh requested a review from rekram1-node December 11, 2025 01:41
@rekram1-node
Copy link
Copy Markdown
Collaborator

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?

@edlsh
Copy link
Copy Markdown
Contributor Author

edlsh commented Dec 13, 2025

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

@edlsh
Copy link
Copy Markdown
Contributor Author

edlsh commented Dec 13, 2025

Created the opentui implementation here: anomalyco/opentui#411

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

Closing this for now.

@edlsh edlsh closed this Dec 13, 2025
@rekram1-node
Copy link
Copy Markdown
Collaborator

nice!!!

@edlsh
Copy link
Copy Markdown
Contributor Author

edlsh commented Dec 15, 2025

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/core@0.0.0-20251211-4403a69a (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

@rekram1-node
Copy link
Copy Markdown
Collaborator

Nice!

@edlsh
Copy link
Copy Markdown
Contributor Author

edlsh commented Dec 17, 2025

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
Copy link
Copy Markdown
Contributor Author

edlsh commented Dec 17, 2025

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

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.

[FEATURE]: Copy console text on click

2 participants