Skip to content

feat(tui): grid layout + auto-growing scroll input - #481

Merged
gemone merged 1 commit into
mainfrom
feat/tui-sessions-picker
Aug 9, 2026
Merged

gemone merged 1 commit into
mainfrom
feat/tui-sessions-picker

Conversation

@gemone

@gemone gemone commented Aug 9, 2026

Copy link
Copy Markdown
Owner

What

Redesign the TUI layout for streaming responsiveness — fully layout-driven, no dock hacks.

Layout: dock stacking → Grid

The old CSS mixed layout: vertical with height: 1fr and two dock: bottom widgets (input, footer). Replaced with a four-row Grid:

Screen { grid-size: 1 4; grid-rows: 1 1fr auto 1; grid-columns: 1fr; }
Header { dock: none; }                 # row 1 — title bar opts into the grid
#main (Horizontal)                     # row 2 — 1fr conversation + sidebar
TextArea#input { height: auto; ... }   # row 3 — auto-grow scroll input
CothisFooter#footer                    # row 4 — status bar

Every pane is placed by the grid; the footer's dock: bottom is removed from its own CSS (the grid owns placement).

Input: auto-growing scroll input

The input TextArea grows with content (min-height: 3, max-height: 8) then scrolls internally past the cap, so a long prompt never squeezes the conversation out of its 1fr row. Single input box; Ctrl+Enter send and /-command semantics unchanged.

Streaming path

Untouched — #407 (plain Static during the stream, one Markdown parse at finalisation, 50 ms refresh throttle) is already the optimal shape. The responsiveness win is the layout: the conversation gets the full remaining height.

Tooling: ty venv resolution

Adds [tool.ty.environment] python = ".venv" to the root pyproject.toml. The LSP auxiliary ty scanner launched ty server from a cwd where .venv auto-discovery missed, so it reported false unresolved-import findings for every third-party and first-party module (the real ty check was already clean). The directory form is portable across OSes — ty locates bin/python / Scripts/python.exe inside the venv itself.

Changes

  • packages/cothis-tui/src/cothis/tui.py: Grid CSS, Header { dock: none }, input auto-grow CSS, footer dock removal, docstring updated for the four-row layout.
  • pyproject.toml: [tool.ty.environment] python = ".venv".
  • tests/test_tui.py: two new layout-contract tests.
  • tests/test_tui_pty.py: docstring updated for the four-row grid; # noqa: B009 on the deliberate Windows-ty-safe getattr pattern.

Problem fixed

  • The pane layout was assembled from mixed layout modes + docks, producing an awkward arrangement where the conversation did not reliably own the remaining space.
  • The input box was a fixed 3 rows — a long prompt squeezed the conversation; it now grows and scrolls internally.
  • The LSP auxiliary ty scanner reported false unresolved-import errors because its ty server could not resolve the project venv.

Tests

  • test_grid_layout_stacks_panes_vertically — header < main < input < footer vertical order; conversation taller than input + footer; full width in single-session mode.
  • test_input_auto_grows_then_scrolls_internally — input grows past the min-height floor, caps at max-height, scrolls internally; conversation shrinks accordingly.

101 TUI tests green; ruff check + ty check clean (venv, from any cwd). CI green on all three OSes.

Pre-existing, not from this PR

test_startup_latency.py::test_cothis_help_under_startup_budget fails on this machine (1156 ms vs 1100 ms ceiling) — it reproduces on a clean checkout of origin/main (stash-verified). This PR touches no CLI startup path; CI runners pass it.

Replace the dock-based layout (docked input + footer + 1fr main) with a
four-row Grid (`grid-rows: 1 1fr auto 1`) so every pane is placed by the
layout system — no dock hacks, `Header { dock: none }` opts the title bar
into the grid. The input TextArea auto-grows with content (min 3 rows,
max 8) and scrolls internally past the cap, so a long prompt never
squeezes the conversation out of its 1fr row.

Streaming render path (#407: plain Static during stream, one Markdown
parse at finalise) is untouched — the responsiveness win comes from the
layout giving the conversation the full remaining height.

Also: point ty at the uv workspace venv via `[tool.ty.environment]
python = ".venv"` (directory form is portable across OSes) so the LSP
auxiliary scanner resolves third-party imports instead of reporting
false unresolved-import noise.

Tests: 2 new layout-contract tests (vertical stacking order + input
auto-grow/scroll cap). 101 TUI tests green, ruff + ty clean.
@gemone
gemone merged commit 34bbef7 into main Aug 9, 2026
3 checks passed
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.

1 participant