Skip to content

feat: native text selection with keyboard and mouse #192

@oobagi

Description

@oobagi

Problem

There is no text selection support in the app. Users cannot select text with Shift+arrow keys or mouse click-drag, and cannot copy selected text to the clipboard. This makes it impossible to copy content from notes without relying on terminal-native selection, which doesn't respect the app's viewport or line wrapping.

Context

The current codebase has zero selection infrastructure:

  • No selection state model in the textarea (fork/bubbles/textarea/textarea.go)
  • No click-drag mouse handlers
  • No selection highlight rendering
  • No clipboard integration beyond the existing "copy path" command in browser

Mouse interaction is currently limited to:

  • View mode: Hover tracking and checklist toggle (editor.go:803-852)
  • Edit mode: No mouse interaction at all

The viewport (fork/bubbles/viewport/viewport.go) handles mouse wheel events but has no concept of selection ranges.

Possible approaches

Approach A: Phased implementation in the forked textarea

  • How: Build selection directly into fork/bubbles/textarea/textarea.go:
    1. Add selection anchor/cursor range tracking
    2. Implement Shift+arrow key selection
    3. Add mouse click-drag selection via MouseMsg events
    4. Render selection highlight in the textarea's View()
    5. Clipboard integration (Ctrl+C / Cmd+C to copy)
  • Pros: Full control, deeply integrated, works across wrapped lines
  • Cons: Significant effort, needs careful coordinate math across wrapped lines
  • Files: fork/bubbles/textarea/textarea.go, internal/editor/editor.go

Approach B: View-mode only selection via viewport

  • How: Implement selection only in view mode, where the viewport renders static content. Track selection as absolute line:col ranges in the viewport.
  • Pros: Simpler — no interaction with textarea editing. Covers the primary "read and copy" use case.
  • Cons: No selection in edit mode. Two different selection systems if edit mode is added later.
  • Files: fork/bubbles/viewport/viewport.go, internal/editor/editor.go

Approach C: Defer to terminal-native selection

  • How: Ensure the app doesn't interfere with terminal-native selection (some TUI mouse capture disables it). Add a modifier key (e.g., Option+click) to bypass mouse capture.
  • Pros: Zero implementation effort, leverages existing terminal behavior
  • Cons: Doesn't respect app layout, breaks on wrapped lines, not "native-feeling"
  • Files: internal/editor/editor.go (mouse capture toggle)

Tasks

  • Design selection state model (anchor position, cursor position, direction)
  • Implement Shift+arrow key selection in textarea (character, word, line granularity)
  • Implement mouse click-drag selection with MouseMsg events
  • Render selection highlight (background color) in textarea View()
  • Implement selection in view mode viewport
  • Add Ctrl+C / Cmd+C to copy selection to system clipboard
  • Handle selection across block boundaries in editor
  • Clear selection on non-selection actions (typing, cursor move without Shift)
  • Test selection across soft-wrapped lines

Test plan

  • Shift+Right/Left selects characters, highlight visible
  • Shift+Up/Down selects lines
  • Shift+Cmd+Right/Left selects to line start/end
  • Mouse click-drag creates selection in edit mode
  • Mouse click-drag creates selection in view mode
  • Ctrl+C / Cmd+C copies selected text to system clipboard
  • Selection renders correctly across soft-wrapped lines
  • Selection clears when typing or moving cursor without Shift
  • Double-click selects word, triple-click selects line (if implemented)
  • No regression: existing keyboard navigation still works

Scope

Type: feature
Size: large — consider phased implementation

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions