feat(tui): Bubble Tea v2, shared keymap, mouse, focus and OSC 52 copy #80

Merged
jwarykowski merged 3 commits from feat/bubbletea-v2 into master 2026-10-25 05:20:49 +00:00
Owner

Moves the TUI to Bubble Tea v2 and uses what it adds, plus a store fix found in a review.

Store:

  • Lines Load doesn't parse (an unknown meta key, hand-written text) stay attached to their item and are written back, so a save no longer drops them. Lines above the first item are still dropped.
  • saveConfig writes atomically through the new store.WriteFile, so a stow-symlinked config.toml stays a symlink.

Bubble Tea v2 (bubbles, lipgloss and ntcharts v2 too):

  • Window title shepherd · <board> · done/total (plus ● when unsaved), tab progress bar (OSC 9;4), real terminal cursor in the text input and note editor.
  • y copies through OSC 52, so it works over SSH and in tmux (set-clipboard on); atotto is no longer imported.
  • Focus: regaining it checks the disk at once; losing it saves, unless autosave = 0. Disk polling now runs in a Cmd, and a read that lands after an edit is dropped.
  • shift+enter / ctrl+enter finish a note where the terminal tells them apart from enter.
  • Opt-in mouse (mouse = true or the settings screen): wheel scrolls, click selects a row or lane card, double-click opens detail. Off by default because it takes over text selection.
  • Pastes reach the open input or note editor.

TUI cleanup:

  • keymap.go: the list, global and detail handlers dispatch on key.Bindings and the footer grids render from them. A test fails if two bindings share a key.
  • update.go split into update_boards.go, update_settings.go and update_detail.go.
  • Fixes a bug also on master: past the first screenful, the table view's cursor row was off-screen.

Verification: format, vet, test and lint pass. With mouse off, all ten TUI screens (each view, detail, help, settings, boards, global) and stats --no-color are identical to master in tmux. The cursor position and title were checked in tmux. Not checked by hand: real mouse input and the tab progress bar.

Behaviour changes:

  • Copy needs a terminal with OSC 52.
  • Blur triggers a save.
Moves the TUI to Bubble Tea v2 and uses what it adds, plus a store fix found in a review. Store: - Lines `Load` doesn't parse (an unknown meta key, hand-written text) stay attached to their item and are written back, so a save no longer drops them. Lines above the first item are still dropped. - `saveConfig` writes atomically through the new `store.WriteFile`, so a stow-symlinked `config.toml` stays a symlink. Bubble Tea v2 (bubbles, lipgloss and ntcharts v2 too): - Window title `shepherd · <board> · done/total` (plus `●` when unsaved), tab progress bar (OSC 9;4), real terminal cursor in the text input and note editor. - `y` copies through OSC 52, so it works over SSH and in tmux (`set-clipboard on`); atotto is no longer imported. - Focus: regaining it checks the disk at once; losing it saves, unless `autosave = 0`. Disk polling now runs in a `Cmd`, and a read that lands after an edit is dropped. - `shift+enter` / `ctrl+enter` finish a note where the terminal tells them apart from `enter`. - Opt-in mouse (`mouse = true` or the settings screen): wheel scrolls, click selects a row or lane card, double-click opens detail. Off by default because it takes over text selection. - Pastes reach the open input or note editor. TUI cleanup: - `keymap.go`: the list, global and detail handlers dispatch on `key.Binding`s and the footer grids render from them. A test fails if two bindings share a key. - `update.go` split into `update_boards.go`, `update_settings.go` and `update_detail.go`. - Fixes a bug also on master: past the first screenful, the table view's cursor row was off-screen. Verification: format, vet, test and lint pass. With mouse off, all ten TUI screens (each view, detail, help, settings, boards, global) and `stats --no-color` are identical to master in tmux. The cursor position and title were checked in tmux. Not checked by hand: real mouse input and the tab progress bar. Behaviour changes: - Copy needs a terminal with OSC 52. - Blur triggers a save.
Lines Load doesn't parse (a newer version's meta key, hand-written text,
a misplaced meta line) now stay attached to their item in Item.Extra and
are written back verbatim, so a save no longer drops them. Lines above
the first item are still dropped.

Save's atomic, symlink-following write is now store.WriteFile, for reuse.
Move to charm.land bubbletea/bubbles/lipgloss v2 and ntcharts v2:
- View returns tea.View (alt screen, window title, tab progress bar,
  focus reporting, real cursor for the text input and note editor);
  tests assert on render().
- Cursor highlight follows the reported terminal background.
- Pastes (tea.PasteMsg) go to the open input or note editor.
- stats --no-color strips ANSI itself; panel and table widths adjusted
  for lipgloss v2's border-inclusive Width and the v2 table viewport.

TUI:
- keymap.go: list, global and detail handlers dispatch on key.Bindings
  and the footer grids render from them, so keys and hints can't drift.
- Disk polling runs in a Cmd (checkDisk -> diskMsg); a read that lands
  after an edit is dropped. Focus checks the disk at once; blur saves
  unless autosave is off.
- y copies via OSC 52 (tea.SetClipboard); atotto is no longer imported.
- shift+enter/ctrl+enter finish a note where the terminal tells them
  apart from enter.
- Opt-in mouse (config: mouse = true, or the settings screen): wheel
  scrolls, click selects a row or lane card, double-click opens detail.
- Table view windows its rows so the cursor row stays on screen.
- update.go split into update_boards/settings/detail.go.
- saveConfig writes atomically through store.WriteFile.
docs: TUI file layout, keymap, mouse and OSC 52 copy
All checks were successful
pull-request / lint-and-test (pull_request) Successful in 1m19s
da7c89e441
jwarykowski deleted branch feat/bubbletea-v2 2026-10-25 05:20:50 +00:00
Sign in to join this conversation.
No description provided.