Skip to content

feat: add text selection and copy functionality to TUI #518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

BurgessTheGamer
Copy link

Summary

  • Adds click-and-drag text selection with visual highlighting
  • Implements copy to clipboard functionality via OSC52
  • Supports both single-line and multi-line selection

Features

  • Mouse Selection: Click and drag to select text
  • Visual Feedback: Selected text is highlighted with system-appropriate colors
  • Multi-line Support: Select across multiple lines seamlessly
  • Clean Copy: Text is copied without ANSI escape codes
  • Keyboard Shortcuts: Ctrl+Shift+C or Ctrl+Y to copy
  • Constrained Highlighting: Highlight stays within content boundaries

Implementation Details

  • Uses OSC52 escape sequences for clipboard integration
  • Handles centered content layout with proper coordinate mapping
  • Strips ANSI codes for clean clipboard content
  • Visual highlight uses muted system colors for better UX

Test Plan

  1. Run OpenCode TUI
  2. Click and drag to select text (single or multi-line)
  3. Press Ctrl+Shift+C or Ctrl+Y to copy
  4. Paste in another application - text should be clean without formatting codes
  5. Verify highlight doesn't spill outside content area

Screenshots

The selection highlight uses system-appropriate muted colors and stays within content boundaries:

  • Single-line selection works with proper visual feedback
  • Multi-line selection maintains alignment and formatting
  • Highlight color is subtle and doesn't interfere with readability

🤖 Generated with opencode

BurgessTheGamer and others added 5 commits June 27, 2025 15:01
- Implement visual scrollbar with click-to-jump and drag-to-scroll functionality
- Use OpenCode's overlay system for clean rendering without ANSI corruption
- Add mouse event handling for scrollbar interactions
- Theme-integrated styling with proper visual feedback
- Non-intrusive design that preserves chat content formatting

🤖 Generated with [opencode](https://opencode.ai)

Co-Authored-By: opencode <[email protected]>
- Add lastScroll field to track mouse wheel events
- Add BUGGED_SCROLL_KEYS map to prevent key injection during scrolling
- Integrate scroll bug fix while preserving scrollbar functionality
- Resolves merge conflict with main dev branch
- Add M and m to BUGGED_SCROLL_KEYS map
- Preserve all mouse event handling for scrollbar
- All conflicts resolved and tested
Resolved conflicts:
- Preserved scrollbar mouse event handling (MouseWheelMsg, MouseClickMsg, MouseReleaseMsg, MouseMotionMsg)
- Integrated lastScroll tracking from dev branch
- Maintained compatibility with both features
- Implement click-and-drag text selection with visual highlighting
- Add multi-line selection support with proper coordinate mapping
- Integrate OSC52 for clipboard copy (Ctrl+Shift+C / Ctrl+Y)
- Constrain highlight to content area to prevent spillover
- Use system-appropriate muted colors for selection highlight
- Extract clean text without ANSI codes for clipboard
- Handle centered content layout correctly

This feature allows users to select and copy text from the chat
interface, making it easier to extract code snippets, commands,
or other content from OpenCode responses.

🤖 Generated with [opencode](https://opencode.ai)

Co-Authored-By: opencode <[email protected]>
@BurgessTheGamer BurgessTheGamer force-pushed the feat/text-selection-copy branch from 2ff5c23 to 20aee66 Compare June 28, 2025 22:25
@adamdotdevin
Copy link
Collaborator

i'll try to pull this down early tomorrow, or monday at latest. curious though, mind posting a video?

@BurgessTheGamer
Copy link
Author

i'll try to pull this down early tomorrow, or monday at latest. curious though, mind posting a video?

0628.mp4

this is how its looking currently

@adamdotdevin
Copy link
Collaborator

is it selecting the left border in that video?

@BurgessTheGamer
Copy link
Author

BurgessTheGamer commented Jun 29, 2025

yes, formatting is a little weird grabbing the borders, trying to see if i can fix it. can be better

- Add comprehensive text cleaning function to remove UI formatting
- Strip border characters (┃, │, |, ║, ┆, ┊) from copied text
- Intelligently format prose as paragraphs (join lines)
- Preserve code block and list formatting when detected
- Remove excessive whitespace and normalize indentation
- Fix cache type reference (MessageCache instead of cache.Cache)

This ensures copied text is clean and properly formatted for
pasting into other applications without UI artifacts.

🤖 Generated with [opencode](https://opencode.ai)

Co-Authored-By: opencode <[email protected]>
@BurgessTheGamer
Copy link
Author

0628.1.1.mp4

thats is much better

@BurgessTheGamer
Copy link
Author

still a weird character bug that happens on highlight sometimes but functional!

- Convert string to runes before slicing to avoid breaking multi-byte characters
- Fixes diamond question mark artifacts (�) that appeared when selection boundaries split UTF-8 characters
- Ensures proper highlighting for all Unicode text including emojis and accented characters

🤖 Generated with [opencode](https://opencode.ai)

Co-Authored-By: opencode <[email protected]>
@BurgessTheGamer
Copy link
Author

still a weird character bug that happens on highlight sometimes but functional!

fixed

0628.3.mp4

BurgessTheGamer and others added 2 commits June 29, 2025 19:26
Adds automatic LSP integration for Aiken (.ak files) with:
- Auto-detection of .ak files
- Automatic installation via aikup if not present
- Full language server capabilities (diagnostics, completion, hover)
- Updated documentation with configuration examples

This enables intelligent code assistance for Cardano smart contract development.

🤖 Generated with [opencode](https://opencode.ai)

Co-Authored-By: opencode <[email protected]>
@BurgessTheGamer BurgessTheGamer force-pushed the feat/text-selection-copy branch from 6c94c2b to ee693a5 Compare June 30, 2025 03:31
BurgessTheGamer and others added 10 commits June 29, 2025 20:35
- Implement natural growth up to 8 lines, then fixed height with scrolling
- Add automatic cursor visibility tracking within viewport
- Preserve chat visibility when editing long text content
- Maintain all existing text editing capabilities

Technical implementation:
- Enhanced textarea component with scrollOffset and viewport behavior
- Modified SetHeight to support MaxHeight-based growth limiting
- Added ensureCursorVisible() for automatic scroll adjustment
- Updated View() method to render only visible lines within viewport

🤖 Generated with [opencode](https://opencode.ai)

Co-Authored-By: opencode <[email protected]>
- Restore AGENTS.md documentation and opencode-dev-launcher.sh script
- Add height-limited text input checkpoint to completed features
- Document new git workflow requirements:
  * Always save to personal repository first
  * Ask before submitting PRs (no auto-submission)
  * Separate PRs for each new feature
- Update current development status section
- Establish clear workflow for future development

🤖 Generated with [opencode](https://opencode.ai)

Co-Authored-By: opencode <[email protected]>
- Add click-to-jump functionality on scrollbar track
- Implement drag-to-scroll with smooth thumb movement
- Add mouse state management (isDragging, dragStartY, dragStartOffset)
- Handle MouseClickMsg, MouseMotionMsg, and MouseReleaseMsg events
- Calculate proportional positioning for accurate scroll control
- Preserve existing keyboard scrolling (Page Up/Down)

Technical implementation:
- Added shouldShowScrollbar() helper method
- Enhanced handleScrollbarClick() with thumb vs track detection
- Implemented handleScrollbarDrag() with delta calculation
- Mouse coordinates properly mapped to scroll positions
- Drag state properly reset on mouse release
Mouse Interaction Fixes:
- Add coordinate translation in editor component for mouse events
- Account for border (1px) and prompt (2 chars) offset
- Translate MouseClickMsg, MouseMotionMsg, and MouseReleaseMsg coordinates
- Enable proper mouse interaction with text input scrollbar

Scrollbar Positioning Improvements:
- Move scrollbar from textarea content to editor container border
- Add renderEditorScrollbar() method to editor component
- Position scrollbar on right border edge for cleaner appearance
- Remove scrollbar overlay from textarea View() method
- Add ScrollOffset() accessor method to textarea

Technical Details:
- Mouse coordinates now properly translated: X-3, Y-2 for textarea position
- Scrollbar rendered at container level with proper border positioning
- Maintains all existing scrollbar functionality (click, drag, proportional)
- Cleaner visual separation between content and scrollbar
Mouse Interaction Fixes:
- Move scrollbar mouse handling from textarea to editor component level
- Add mouse state tracking to editorComponent (isDragging, dragStartY, dragStartOffset)
- Implement handleEditorScrollbarClick() for click-to-jump and drag initiation
- Implement handleEditorScrollbarDrag() for smooth drag scrolling
- Add setTextareaScrollOffset() to control textarea scroll position

Coordinate System Fixes:
- Handle mouse coordinates at editor level before translation
- Check scrollbar clicks at container coordinates (width-1, accounting for borders)
- Proper scrollbar area detection (Y: 2 to 2+visibleLines-1)
- Convert to scrollbar-relative coordinates for accurate positioning

Technical Implementation:
- Add clamp() utility method for bounds checking
- Preserve existing textarea mouse handling for non-scrollbar clicks
- Maintain drag state across mouse motion events
- Reset drag state on mouse release

This fixes the clicking issue by handling scrollbar interactions at the correct
coordinate system level (editor container) rather than translated textarea coordinates.
- Implemented scrollbar overlay for textarea when content exceeds MaxHeight
- Added ScrollOffset() and SetScrollOffset() methods to textarea
- Added mouse event handling for scrollbar clicks and dragging
- Styled scrollbar to match OpenCode design (thin track, solid thumb)
- Scrollbar appears inside the right border as an overlay
- Fixed scrollbar placement to account for border and padding
- Scrollbar now properly spans the content area (lines 2 to n-2)
- Added debug logging to help diagnose positioning issues
- Ensures scrollbar doesn't overlap with border corners
- Remove top and bottom borders when scrollbar is present for cleaner look
- Adjust scrollbar positioning for borderless mode (padding only)
- Update mouse click/drag handlers for new positioning
- Prevent ensureCursorVisible from interfering with scrollbar control
- Scrollbar now provides smooth scrolling without cursor jumping
- Text input now never shows top/bottom borders, not just when scrollbar appears
- Gives consistent clean look matching OpenCode style
- Updated mouse coordinate adjustments for borderless design
- Log mouse click coordinates and scrollbar detection
- Log scrollbar state calculations (thumb position, size, etc)
- Log drag operations and position updates
- Track mouse release events for drag termination
- Will help diagnose clicking and scrolling issues
- Track mouse motion to detect when hovering over scrollbar
- Change scrollbar appearance on hover:
  - Track changes from thin line │ to thick line ┃
  - Track color changes from BackgroundElement to Border
  - Thumb becomes bold on hover
- Trigger redraw when hover state changes
- Makes scrollbar more noticeable and easier to target

This improves UX by providing visual feedback when the mouse is
over the scrollbar, making it clearer where to click.
- Added separate isHoveringScrollbar method with wider hit zone (2 chars)
- Keep precise 1-char hit zone for actual clicks
- Enhanced hover visual feedback:
  - Track changes to thicker line with brighter color
  - Thumb gets background color and bold on hover
- Added debug logging for hover detection
- Simplified hover styling logic for better maintainability

This should make the hover effect more reliable and noticeable.
- Removed hover animation code completely
- Simplified track click to center thumb on click position (like messages)
- Simplified drag calculation to match messages scrollbar logic
- Removed complex offset calculations in favor of simpler approach
- This should make the scrollbar behavior more consistent and reliable
- Provides more room for editing longer messages
- Better visibility of context when writing multi-line content
- May help with scrollbar interaction by providing more space
- Added bounds checking to prevent negative coordinates
- Added detailed comments explaining the coordinate adjustments
- Added debug logging for negative coordinate cases
- Applied same fixes to mouse motion events
- This should fix missed clicks near the edges of the textarea
… line off

- Removed the Y -= 1 adjustment that was causing clicks to register one line below
- The Y coordinate from the mouse event is already correct
- Updated debug logging to reflect the actual coordinates
- This should fix the click position being off by one line
- Changed Y adjustment from -2 to -1
- The editor has top padding but no top border
- This should center clicks properly on the mouse position
- The Y coordinate from mouse events is already correct
- No adjustment needed for padding or borders
- This should fix clicks being one line below the mouse position
- The textarea expects viewport-relative coordinates
- We need to adjust for the editor's top padding
- This should fix clicks being 2 lines below the mouse
- Changed Y adjustment from -1 to -2
- This accounts for top padding plus an additional line offset
- Should fix clicks being exactly one line off
- Accept clicks 1 character to the left of the scrollbar
- This gives a 2-character wide hit zone while keeping visual at 1 char
- Prevents accidental text selection when trying to click scrollbar
- Makes scrollbar easier to target with mouse
- Fixed bottom boundary check to use >= instead of >
- Added +1 tolerance to bottom boundary for easier clicking
- Consistent boundary checking in both isClickOnScrollbar and handleScrollbarClick
- This should fix clicks at the very top and bottom of scrollbar not registering
- Implemented visual scrollbar with drag and click functionality
- Drag works flawlessly, click-to-jump mostly works
- Known issue: dynamic editor positioning causes Y-coordinate misalignment
- Updated AGENTS.md with current progress and technical challenges
…ains

- Scrollbar fully functional except bottom 1-2 pixels
- Identified root cause: parent bounds check excludes bottom edge
- Updated AGENTS.md with detailed technical analysis
- Changed bounds check from < to <= for bottom edge detection
- Fixes issue where bottom 1-2 pixels of scrollbar were not clickable
- Scrollbar now fully interactive across entire height
BurgessTheGamer added a commit to BurgessTheGamer/opencode that referenced this pull request Jun 30, 2025
- Updated to use opencode-sdk-go v0.1.0-alpha.7
- Removed references to removed commands field
- Preserved text selection functionality
- Integrated with dev branch changes to renderText signatures
- Maintained OSC52 clipboard integration
@delorenj
Copy link

delorenj commented Jul 2, 2025

still a weird character bug that happens on highlight sometimes but functional!

fixed
0628.3.mp4

This is 🔥 man!

@thdxr thdxr self-assigned this Jul 2, 2025
@likelymichael
Copy link

Why was this closed?

@BurgessTheGamer
Copy link
Author

It doesn't work the same with all of the changes that have been made and also image

@adamdotdevin
Copy link
Collaborator

hey @BurgessTheGamer, sorry for the lack of communication on my end. i would love for this feature to be a community contribution, but it's going to be tough logistically; this PR in particular is a pretty huge diff, and the first four files modified when i opened it up to review seem to be unrelated to the feature:
Screenshot 2025-07-16 at 3 32 56 PM

it's hard to feel like a +2k line diff is going to be tight enough to merge with a start like that. happy to have a conversation if i misjudged this PR unfairly.

@BurgessTheGamer
Copy link
Author

No worries, I'm still learning a handful of things, as well as this aspect of PRs. I spoke with my friend who is more experienced and he let me know something similar about the length, so no hard feelings. Just wanting to clear space 😄 this was definitely massive haha

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.

5 participants