Merge limoni-port: full Bubble Tea/lipgloss → Limoni TUI port #1

Merged
muse-lantern merged 18 commits from limoni-port into main 2026-10-16 16:28:14 +00:00
Member
No description provided.
Replace the Bubble Tea model and lipgloss rendering with the Limoni
TUI library (github.com/thebanri/limoni v0.12.0):

- lib/edit: theme.go lipgloss styles -> cell.Style (amber palette
  #0d0a00/#ffb000/#7a5500/#ff6600/#1a1400 preserved); highlight.go
  segments carry cell.Style; render.go View() string -> DrawEditor
  drawing cells directly via widgets.Label; edit.go drops tea.Model
  (Init/Update) and gains HandleMouse (wheel scroll, left-press
  cursor placement). Buffer/highlight/config logic untouched.
- cmd/res-edit: main.go tea.NewProgram -> limoni.Run with a Draw
  function (event-driven, no FPS loop); keys.go full key dispatch
  on limoni.KeyEvent (Ctrl chords via k.Ctrl, F1/F2 via driver
  package); new palette.go (Limoni-native command palette),
  help.go (Limoni help overlay), theme.go (chrome styles).
  Slow-terminal branch keeps WithoutMouse().
- cmd_test.go adapted to the new key API; added a limoni/uitest
  end-to-end test (open file, type, save, quit).

Proof-of-concept for residual/.agent#30. Ctrl bindings only;
no Alt bindings.
lib/tui/theme: lipgloss styles/colors become cell.Style/cell.Color.
Same exported names (LAmber, StyleStatusBar, Overlay*, ...); cell.Style
carries no padding/border, so callers add spacing and draw borders.
Linux-console ANSI mapping, InitTheme/InitUnified/InitInherit, and the
OSC palette helpers are preserved.

lib/tui/list: cursor/scroll logic and FilterContains unchanged;
RenderListRow (lipgloss string) becomes DrawListRow(f, x, y, ...).
widgets.List can't back it - different selection model and layout
coupling - so the row draw stays custom.

lib/tui/overlay: string builders become DrawHelpOverlay (single
column, content-sized, centered) and DrawHelpOverlayMultiCol
(adaptive 1-3 columns), plus HelpBoxH / HelpScrollMax /
HelpScrollMaxMultiCol / BuildHelpLines (now styled runs). The TwoCol
variant had no callers and was dropped.

lib/cmd/ui: ConfirmDialog, InputPrompt, MenuBar, Palette,
StatusMessage ported to HandleKey(limoni.KeyEvent) + Draw(f, ...)
with the same state machines, keybindings, and visuals. tea.Cmd /
tea.Tick are gone: StatusMessage.Update() is called per frame to
expire messages. Palette.SetTermHeight is a documented no-op (the
Limoni host positions the dropdown via DrawDropdown).

Tests: existing list/theme tests pass; added limoni/uitest tests
for the overlay, confirm dialog, palette, and input prompt.

Tool-layer callers (console menus, auth selector, res-demo) still
use the old string APIs and will be ported in the next step.
res-demo is the catch-all test/demo harness for the core library, so it
goes first, alongside the libs: porting it validates the new Limoni lib
APIs before the other tools are ported against them.

The tabbed bubbletea TUI becomes a Limoni Draw app (tab bar, scrollable
captured demo output, plain-text help overlay, status bar). Captured demo
output is stripped of ANSI escapes for frame display; the UI chrome stays
unthemed by design. WithoutMouse on slow terminals.

Lib gap found via the demo: the direct-write paths (and the demo's theme
section) needed a string-rendering replacement for lipgloss Style.Render,
so lib/tui/theme gains Render(st, s), Width(s), and StripANSI(s). A
default (inherited-theme) style renders no escape sequences.

Tests: limoni/uitest drives the demo headlessly — tab bar renders, arrow
keys and number keys switch tabs, Esc toggles the help overlay, Ctrl+Q
quits.
Bubble Tea model and lipgloss styles become a Limoni Draw app.
Keybindings and theme-editing behavior unchanged.
login_ui, auth/login (model, branding), auth/selector move from
Bubble Tea/lipgloss to Limoni Draw. Login flow states and session
carousel behavior unchanged.

Note: not compile-verified in this environment (PAM headers
absent); needs a build check where libpam-dev is available.
menu, menu_apps, menu_help, menu_main, menu_settings and statusbar
move from lipgloss string rendering to Limoni cell drawing inside
the console render loop. Menu structure and keybindings unchanged.
lipgloss prompt styling becomes cell.Style drawing. Prompt
behavior unchanged.
The TUI stripped all ANSI from captured demo output, so the theme
demo's colors never reached the screen (not a Termux issue). Now:

- ansi.go: parseANSI interprets SGR sequences back into cell.Style
  (the inverse of theme.Render); OSC and non-SGR escapes are skipped.
  drawContent draws styled segments instead of stripping.
- main.go: theme.InitUnified() at startup — loads
  ~/.config/residual/theme.toml, creating it from the template on first
  run through the standalone residual/config library.
- Chrome (tab bar, status bar, help overlay) draws with the theme
  package's style variables.
- demo_tui_palette.go: palette swatch color blocks.

Tests: SGR parser unit tests (round-trip, reset, 256/truecolor,
OSC skip, modifiers) plus TUI-tab styled-content and navigation
coverage.
Label (clipped styled text), Span/Spans/SpansWidth, Truncate
(ellipsis), LabelW (fixed-width), Box (bordered box). Replaces the
copy-pasted drawLabel/drawText helpers across the tools.
Replace copy-pasted drawLabel/drawText/label helpers with the shared
draw.Label (and draw.Spans semantics in res-theme). No visual changes;
the shared version clips to the frame like the best local copies did.
PaletteStyles + SetStyles let tools with their own chrome (res-edit's
dual unified/neutral modes) reuse the palette logic. res-edit's
300-line palette.go copy is deleted; behavior is pixel-identical via
injected chrome styles. The shared dropdown rendering restores the
original bubbletea behavior (dim description on selected row).
New Widgets tab: live playground for every lib widget (Palette,
InputPrompt, MenuBar, ConfirmDialog, StatusMessage, List, help
overlay) and the draw primitives. A widget without a demo here is
incomplete. uitest coverage for tab navigation and widget
interaction.
Add MenuBarStyles{Bar,Selected,Dim,Plain,Marker} + SetStyles, mirroring
the Palette pattern. The dropdown now draws full-width rows (label with
right-aligned shortcut, single style per row); the selected-row marker
is configurable (default '▸ '). Also: confirming releases focus so keys
return to the host app, and the first category highlights when the bar
is focused but closed. DrawBar/DrawDropdown are exported separately so
hosts can control overlay z-order; Draw composes both.

Add uitest coverage: open, nav with separator/disabled skipping,
category switching, confirm returns ID + releases focus, Esc closes.
categoryXOffset added a phantom 1-cell gap per preceding category, but
DrawBar renders categories back-to-back with no gap, so each dropdown
drifted right of its label (Edit +1, View +2). The dropdown is bare
text, not boxed, so flush alignment is the correct look.
Missed in the draw package extraction — still used the old 2-arg
draw.Label(s, style) signature. Now uses draw.Label(f, x, y, s, st)
via the local drawText closure.
A 6MB compiled binary was committed at the repo root in 950bff8.
Binaries don't belong in the repo.
/res-demo was committed by accident in 950bff8 because only /res-edit
was ignored. Now all eight binaries are covered.
muse-lantern changed title from limoni-port to Merge limoni-port: full Bubble Tea/lipgloss → Limoni TUI port 2026-10-16 16:27:47 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
residual/core!1
No description provided.