Skip to content

Use CSS Grid and Flexbox for editor layout - #950

Draft
Michael Greene (mgreenegit) wants to merge 4 commits into
microsoft:mainfrom
mgreenegit:fix/editor-height-small-viewports
Draft

Michael Greene (mgreenegit) wants to merge 4 commits into
microsoft:mainfrom
mgreenegit:fix/editor-height-small-viewports

Conversation

@mgreenegit

@mgreenegit Michael Greene (mgreenegit) commented Sep 11, 2026

Copy link
Copy Markdown
Member

Direction

This revision replaces the earlier attr_fill_height proposal in response to
the requested CSS Grid/Flexbox direction.
It uses Taffy to execute CSS Grid and Flexbox layout algorithms, rather than
introducing another hand-written remaining-height allocator.

The application is deliberately small: lay out the existing menu, editor/search
area, and status bar. No console, provider, AI, command, setting, or stylesheet
language is introduced.

Problem

The editor currently reconstructs its available height by subtracting fixed
reservations: 2 rows normally, 4 with Search, and 5 with Replace. This duplicates
information already present in the UI tree and can request a negative intrinsic
height in short viewports.

The adjacent TODO says:

The layout code should be able to just figure out the height on its own.

This change removes that reservation table and TODO. The parent layout now sizes
the surrounding controls from their measured content and allocates the editor
the remaining space.

Small first use of both layout models

  • CSS Grid at the root: one column, with content-sized menu/status rows and a
    flexible middle row. This follows the structure of
    the review's example.
  • CSS Flexbox inside the middle row: a column containing a nonshrinking search
    region and a growing/shrinking document region. Search and Replace contribute
    their actual measured heights; the document code no longer knows those values.
  • Explicit zero minimums: the flexible grid track is minmax(0, 1fr), and the
    document flex item has a zero minimum and zero flex basis. This is intentional:
    bare 1fr has an automatic minimum and can allow content to dictate the track's
    minimum size. The document must be allowed to shrink to zero when space runs out.

An empty placeholder participates in the same layout when no document is open.
The new container preserves focus inheritance into the text area.

This does not make arbitrarily small terminals fully usable. Fixed/content-sized
controls can still overflow; the existing terminal clipping boundary remains in
effect. The safety goal is nonnegative document geometry, not a new overflow UI.

Implementation boundary

Context::attr_css_style opts a node into typed CSS geometry. Styled blocks become
nested Taffy containers; their unstyled widget children remain intrinsic boxes.
Unmarked blocks, tables, scrollareas, rendering, and event handling retain their
existing implementations. Existing floating nodes stay outside the normal stack.

Taffy solves a frame-local tree and rounds positions/sizes to terminal cells. The
adapter maps its results back to Edit's rectangles, keeping unclipped origins
separate from visible bounds so nested overflow does not move descendants.

Style values own allocations, so they live on Context, which is dropped
normally. Arena nodes retain only indices. The arena-allocated/copied Node and
Tree types do not acquire owning fields.

The public surface is intentionally a typed geometry API, not a CSS parser or
browser renderer
:

  • Only Grid and Flexbox displays are admitted.
  • Existing widgets provide their current-frame intrinsic metrics. Labels remain
    single-line; textareas retain Edit's own wrapping and scrolling. This is not
    CSS text reflow or a new implementation of widget measurement.
  • CSS padding/margins participate in geometry. CSS border widths are reserved by
    the adapter for existing TUI padding/border/scrollbar insets; callers use
    attr_border for terminal borders.
  • Other widget renderers and the specialized table/scrollarea algorithms are not
    replaced. Their inset conversion now also prevents negative inner dimensions.

Dependency and size cost

This introduces Taffy 0.14.0 (MIT), pinned for this proposal, with default
features disabled and only std, grid, flexbox, and taffy_tree enabled.
Its declared Rust minimum is 1.71, below this workspace's 1.93 minimum.

The lockfile gains three packages: taffy, arrayvec, and slotmap; other needed
packages were already present. No unrelated dependency versions are updated.

The binary-size cost is material and should be part of the review. With the
same local Windows x86-64 managed Rust toolchain and normal release profile:

Build Executable size
Unmodified base 826b4c0 515,072 bytes
This implementation 809,984 bytes
Difference +294,912 bytes (+57.26%)

These are executable sizes, not downloads or installer sizes. This proposal does
not claim that a small adapter makes the dependency free. It makes the tradeoff
explicit: use an existing CSS layout implementation rather than maintain a
partial local reimplementation. Layout latency and allocation overhead have not
been characterized.

Verification

The replacement was developed and tested in an isolated source snapshot inside
the development repository, based on the PR's upstream base. Independent pending
console/container edits were not included.

Local Windows verification used managed Rust 1.97.1-ms-20260901.3:

cargo test --locked --all-features --all-targets
  library: 54 passed, 1 existing ignored
  binary:   4 passed
  existing benchmark smoke checks: passed

cargo clippy --locked --workspace --all-features --all-targets -- --no-deps --deny warnings
  passed

cargo test --locked --package edit --doc
  2 passed

cargo build --locked --release --package edit
  passed; --version smoke check passed

The eleven new adapter regressions exercise nested Grid/Flexbox, fractional
tracks and their automatic versus zero minimums, flex growth/shrinkage, integer
rounding, legacy insets, tiny/zero viewports, floating-node exclusion, legacy
table/scrollarea behavior, and style ownership. A CSS row nested inside a legacy
block also has a regression: its CSS intrinsic size must not be overwritten by
the old vertical-stack measurement.

Two additional tests call the application's actual draw path. They cover no
document, empty and long documents, hidden/disabled Search, Search and Replace,
widths 1/2/80, shrinking/growing heights 1-8, 24, 80, and 32767, and retained
keyboard focus after a tiny viewport is restored.

These are geometry and interaction tests, not an external-terminal end-to-end
test, a reproduced-crash claim, or a claim of browser-wide CSS conformance.

Upstream CI run 35231717154
passed on both Windows and Ubuntu at 6f675bd: formatting, all-feature/all-target
tests, and workspace Clippy with warnings denied. The focus regression respects
the existing platform policy: Unix documents append a final newline; Windows
documents do not do so by default.

Suggested review order

  1. The Grid root and Flexbox editor integration in main.rs and draw_editor.rs.
  2. The opt-in style lifetime and dispatch changes in tui.rs.
  3. The Taffy adapter, clipping/inset policy, and regressions in tui/css_layout.rs.
  4. The dependency and executable-size tradeoff.

The previous fill-height implementation is superseded, not retained alongside
this one. Acceptance of this layout slice does not imply acceptance of any
feature from the separate console/provider experiment.

@mgreenegit
Michael Greene (mgreenegit) marked this pull request as ready for review September 11, 2026 21:55
@mgreenegit Michael Greene (mgreenegit) changed the title Clamp editor intrinsic height in small viewports Let layout determine the editor's remaining height Sep 16, 2026

@lhecker Leonard Hecker (lhecker) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe this is the right direction. My intention was to implement CSS grid & flexbox support in the near term (or at least a subset of those). Like this: https://jsfiddle.net/vkubqc4d/

Keep native widgets as measured leaves and styles outside the arena. Cover CSS geometry, legacy boundaries, clipping, and intrinsic measurement.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Compose a Grid application root and Flexbox editor/search column instead of subtracting fixed row reservations. Test actual draw geometry and focus across search modes, document states, and small viewports.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mgreenegit
Michael Greene (mgreenegit) force-pushed the fix/editor-height-small-viewports branch from 53b2842 to 9321dee Compare September 17, 2026 14:00
@mgreenegit Michael Greene (mgreenegit) changed the title Let layout determine the editor's remaining height Use CSS Grid and Flexbox for editor layout Sep 17, 2026
Apply the exact line wrapping reported by the upstream formatting check without changing layout behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Compare the full saved buffer using the existing serialization helper. Unix documents intentionally append a final newline; this is not a layout or focus regression.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@mgreenegit
Michael Greene (mgreenegit) marked this pull request as draft September 17, 2026 15:04
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.

2 participants