Skip to content

feat(ui): add adaptive file tree sidebar - #921

Merged
benvinegar merged 5 commits into
mainfrom
feat/adaptive-file-sidebar
Aug 30, 2026
Merged

benvinegar merged 5 commits into
mainfrom
feat/adaptive-file-sidebar

Conversation

@benvinegar

@benvinegar benvinegar commented Aug 30, 2026

Copy link
Copy Markdown
Member

Summary

  • adapt the built-in file sidebar between compact grouped paths and a fully expanded hierarchy at the preferred 34-column pane width
  • split the bundled renderer into FlexFileSidebar, FlatFileSidebar, and TreeFileSidebar while retaining one shared scrollbox and virtualized row renderer
  • preserve review-stream order, file identities, selection follow, fixed stats lanes, and HunkFileNav parity

Why

The compact grouped sidebar works in narrow panes, but the default wider sidebar has enough room to expose path structure one directory at a time. This makes nested changesets easier to scan without changing review navigation.

I evaluated Pierre Computer Company's @pierre/trees. Its renderer is browser/Preact/shadow-DOM specific and its headless path store is private, so this PR does not add either dependency. It independently adapts the useful conventions: path-first hierarchy, one-row directory entries, indentation, and fixed metadata lanes.

Approach

FlexFileSidebar derives the available content width and selects:

  • FlatFileSidebar at 31 content columns or fewer
  • TreeFileSidebar at 32 content columns or more (the default 34-column pane width)

The tree projection walks files in authoritative review order and emits directory rows from the longest shared path prefix. It intentionally repeats a branch when interleaved review order returns to it instead of regrouping or sorting files.

Directories are static and always expanded. Collapse state, directory focus, sticky ancestors, and language-specific icons are intentionally out of scope.

Visual evidence

Real Hunk TUI, split mode, GitHub dark default, Linux, 220×24:

Wide (>30 content columns)       Narrow (≤30 content columns)
  src/                           src/extensions/default/ui/sidebar/
    extensions/                    M index.test.tsx
      default/                     M index.tsx
        ui/
          sidebar/
            M index.test.tsx
            M index.tsx

Dragging the divider through the threshold is covered by real PTY integration tests, including a regression where the first motion replaces the row OpenTUI would otherwise capture.

Verification

  • bun run typecheck
  • bun run lint
  • bun run deps:check
  • changed-file oxfmt --check
  • bun run test — 2,055 passed, 10 skipped
  • bun run test:integration — 136 passed, 1 platform skip
  • bun run test:tty-smoke — 9 passed
  • bun run install:bin
  • manual real-TTY smoke: source-built binary, actual working-tree diff, split mode at 220×24

Platform tested: Linux. macOS and Windows were not manually tested; the pure path projection includes absolute and UNC-style root coverage.

This PR description was generated by Pi using gpt-5.6-sol

@vercel

vercel Bot commented Aug 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hunk-web Ignored Ignored Preview Aug 30, 2026 5:28pm

Request Review

@benvinegar
benvinegar marked this pull request as ready for review August 30, 2026 17:43
@greptile-apps

greptile-apps Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds an adaptive built-in file sidebar that switches between compact grouped paths and an expanded ordered hierarchy based on available width.

  • Splits sidebar rendering into flexible, flat, and tree variants sharing virtualization, scrolling, selection, and statistics lanes.
  • Adds ordered tree projection and directory-row rendering while retaining stable file identities.
  • Captures pane-resize mouse gestures on press so projection changes do not interrupt divider drags.
  • Extends component, navigation, resize, virtualization, and PTY integration coverage.

Confidence Score: 4/5

The PR appears safe to merge after the non-blocking sidebar module filename convention is addressed.

The adaptive projection, selection, virtualization, and resize behavior are covered without an established runtime defect; the only accepted issue is the new component file's naming convention.

Files Needing Attention: src/extensions/default/ui/sidebar/FileSidebars.tsx

Important Files Changed

Filename Overview
src/extensions/default/ui/sidebar/FileSidebars.tsx Introduces adaptive sidebar variants and shared virtualized rendering; the new filename violates the repository's dash-case convention.
src/ui/lib/files.ts Adds width-mode resolution and an order-preserving tree projection with stable file identities.
src/ui/components/panes/FileListItem.tsx Adds directory rows, bounded hierarchy indentation, and explicit filename ellipsis behavior.
src/ui/App.tsx Captures pane-resize gestures on the stable body renderable and releases capture when resizing ends.
src/ui/lib/mouseCapture.ts Centralizes the existing OpenTUI internal mouse-capture seam for resize and copy-selection gestures.
src/opentui/HunkFileNav.tsx Gives the public file-navigation primitive parity with adaptive flat and tree projections.
test/pty/layout.test.ts Adds real-PTY coverage for threshold switching and resize capture across projection replacement.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    W[Sidebar width] --> M{Content width >= 32?}
    M -->|No| F[Flat grouped entries]
    M -->|Yes| T[Expanded tree entries]
    F --> V[Shared virtualized row renderer]
    T --> V
    V --> S[Stable scrollbox]
    S --> N[Shared file selection and navigation]
Loading
Prompt To Fix All With AI
### Issue 1
src/extensions/default/ui/sidebar/FileSidebars.tsx:1
**PascalCase sidebar module filename**

The new `FileSidebars.tsx` module violates the repository's enforced dash-case convention for TypeScript filenames, adding lint and maintenance inconsistency. Rename the module and update its imports.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(ui): retain sidebar resize drags" | Re-trigger Greptile

@@ -0,0 +1,245 @@
import type { ScrollBoxRenderable } from "@opentui/core";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 PascalCase sidebar module filename

The new FileSidebars.tsx module violates the repository's enforced dash-case convention for TypeScript filenames, adding lint and maintenance inconsistency. Rename the module and update its imports.

Context Used: guidelines.mdc Cursor rule (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/extensions/default/ui/sidebar/FileSidebars.tsx
Line: 1

Comment:
**PascalCase sidebar module filename**

The new `FileSidebars.tsx` module violates the repository's enforced dash-case convention for TypeScript filenames, adding lint and maintenance inconsistency. Rename the module and update its imports.

**Context Used:** guidelines.mdc Cursor rule ([source](https://github.com/modem-dev/modem/blob/main/.cursor/rules/guidelines.mdc))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@benvinegar
benvinegar merged commit 7f7d84c into main Aug 30, 2026
13 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