Unify project/user flex column layout into layoutFlexTable with per-subject policy in model. Add office-tui-table skill and AGENTS notes; fix CI go mod tidy drift and test matrix Go version to match go.mod 1.25. Co-authored-by: Cursor <cursoragent@cursor.com>
3.2 KiB
3.2 KiB
name, description
| name | description |
|---|---|
| office-tui-table | Build and fix Bubble Tea list tables in cmd/office (DataTable, column layout, lipgloss cell rendering, pane width). Use when changing office center-pane tables, column widths, ANSI styling, or list toolbar alignment. |
office TUI table (cmd/office/ui)
Architecture
| Piece | File | Role |
|---|---|---|
DataTable |
table.go |
cursor, sort, viewport, header/row render |
| Column layout | table_layout.go |
flex vs horizontal-scroll policies |
| Flex policy | model/table_layout.go |
per-subject flex column key + min width |
| Cell render | table_render.go |
bubbles/table pattern + ANSI-safe padding |
| Subject row style | table_projects.go |
optional per-subject cell styles |
| Pane sizing | scroll.go |
paneContentWidth, paneLipglossWidth |
| Scrollbar pad | scrollbar.go |
padANSIWidth for styled lines |
Layout policies
-
Flex (all columns visible) — register in
model.TableFlexLayoutFor:- fixed columns keep
TableColumn.Width - one
FlexColumnKey(e.g.title,email) absorbs remainder layoutFlexTableshrinks fixed cols down tominFixedColumnWidthbefore flex min
- fixed columns keep
-
Scrolling (default) —
layoutScrollingTable:- horizontal
colScroll; subset of columns visible distributeColumnWidthsfills pane width
- horizontal
Add a new flex subject: one entry in TableFlexLayoutFor only — do not copy layoutProjectTable/layoutUserTable per subject.
Cell rendering (required pattern)
Never style.Width(w).Padding(0,1).Render(text) on styled cells — padding doubles display width and breaks JoinHorizontal.
Use renderTableCell from table_render.go (matches charmbracelet/bubbles/table):
renderTableCell(outerStyle, plainText, columnWidth)
- truncate plain text with
runewidth.TruncateinsiderenderTableCell - inner box:
Width(innerW).Inline(true)whereinnerW = width - outer.GetHorizontalFrameSize() - outer style carries padding, background, foreground
ANSI rules
- Never
runewidth.Truncate/padDisplayWidthon strings that already contain lipgloss ANSI codes — corrupts escapes and shows garbage like loneID. - Use
padANSIWidth(charmbracelet/x/ansi) for styled lines (headers, toolbar, scrollbar rows). - Do not wrap an already full-width styled header in another
lipgloss.Width()— pad once.
Pane width
Lipgloss bordered panes render 2 cells wider than Style.Width:
paneLipglossWidth(rendered) = rendered - 2for.Width()on pane stylepaneContentWidth(rendered) = rendered - 4for table/viewport inner size (border + padding)
Pass paneContentWidth(pw.List) to DataTable.SetSize and list toolbar.
Tests to add when touching tables
layoutFlexTablewidth sum equals pane widthTestProjectTableHeaderFitsPaneWidth/ per-line width at 68, 40, 30TestPadANSIWidthPreservesStyledLineTestThreePaneRenderedWidthMatchesTerminaltop border + table lines ≤ inner width
Anti-patterns
- Per-subject duplicate layout files (
table_foo.gowith copy-pasted shrink loops) - Skipping truncation on selected rows (causes multi-line rows in viewport)
- Using
bubbles/tablewidget directly — office needs column cursor, multi-select, subject-specific row styles