Skip to content

ISSUE-627: Fix file tree navigation while filter active#707

Open
herbenderbler wants to merge 1 commit into
wagoodman:mainfrom
herbenderbler:ISSUE-627/expand-file-tree-with-active-filter
Open

ISSUE-627: Fix file tree navigation while filter active#707
herbenderbler wants to merge 1 commit into
wagoodman:mainfrom
herbenderbler:ISSUE-627/expand-file-tree-with-active-filter

Conversation

@herbenderbler

@herbenderbler herbenderbler commented Jun 15, 2026

Copy link
Copy Markdown

Fixes #627

Synopsis

When a path filter was active, the file tree became unnavigable. Pressing
Space (collapse/expand) or the arrow keys did nothing and the highlighted row
could be misaligned from the node that actions operated on.

The reported reproduction:

  1. dive alpine
  2. Tab to focus the file tree
  3. Ctrl+Space to collapse all directories
  4. Ctrl+F, type ls to filter
  5. Tab Tab to leave the filter input while keeping the filter active
  6. Space to try to expand bin — nothing happens

Root cause

dive keeps two trees:

  • ViewTree is what you see. Update() keeps a directory visible if it (or
    any descendant) matches the filter, so ancestor directories of a match (e.g.
    /etc when filtering network) stay on screen even though they do not match
    the regex themselves.
  • ModelTree is what the cursor navigates. All positioning logic
    (getAbsPositionNode, CursorLeft, CursorRight, ToggleCollapse) walked
    the ModelTree with an evaluator that required each node to match the regex
    itself
    .

Because VisitDepthParentFirst prunes the entire subtree of any node that fails
the evaluator, a non matching ancestor like /etc was never counted and its
matching children were never reached. The cursor index space therefore diverged
from the rendered tree. In the collapse all case nothing satisfied the
evaluator at all, so getAbsPositionNode returned nil and collapse/expand
became a no op.

Fix

Navigation now derives visibility from the same Data.ViewInfo.Hidden flag that
Update() already computes (filter aware, ancestor preserving) and that
VisibleSize() and rendering already use. The per node regex test was removed
from the navigation evaluators:

// before
return !parentCollapsed && !curNode.Data.ViewInfo.Hidden && regexMatch
// after
return !parentCollapsed && !curNode.Data.ViewInfo.Hidden

With the filter interpreted in exactly one place (Update), the redundant
filterRegex parameter was dropped from getAbsPositionNode, CurrentNode,
CursorLeft, CursorRight, and ToggleCollapse. The cursor index space now
matches the rendered tree exactly, so directories such as /etc are selectable
and expandable while a filter is active.

How to test

Manual verification through a Docker daemon

Requires a running Docker daemon. From the repo root:

go run ./cmd/dive alpine

Inside the TUI, follow the issue's exact steps:

  1. Tab to focus the file tree pane
  2. Ctrl+Space to collapse all directories
  3. Ctrl+F, type ls, to apply the filter
  4. Tab Tab to leave the filter input while keeping the filter active
  5. Move the cursor to a directory such as bin and press Space (or Right)

Expected: the directory expands/collapses and the cursor stays aligned with the
highlighted row. Before the fix this was a no op.

A deeper image makes the desync more obvious:

go run ./cmd/dive ubuntu

Repeat the steps above. Also try without collapse all: Ctrl+F, type passwd,
Tab Tab, move onto the visible etc directory, then press Space/Right
and confirm the directory under the cursor is the one that toggles.

Clear the filter and confirm unfiltered navigation is unchanged.

Regression tests

No Docker required.

# the two new regression tests
go test ./cmd/dive/cli/internal/ui/v1/viewmodel/ -run 'TestFileTreeNavigate' -v

# filter and navigation tests together (guards rendered output too)
go test ./cmd/dive/cli/internal/ui/v1/viewmodel/ \
  -run 'TestFileTreeNavigate|TestFileTreeFilterTree|TestFileTreeDirCursorRight|TestFileTreeHideTypeWithFilter' -v

# full UI suite plus build and vet
go build ./... && go vet ./cmd/dive/cli/internal/ui/... && go test ./cmd/dive/cli/internal/ui/...

The new tests are:

  • TestFileTreeNavigateWithActiveFilter — filtering network keeps /etc
    (a non matching ancestor of the match) selectable and collapsible.
  • TestFileTreeNavigateCollapseAllThenFilter — the issue's exact sequence
    (collapse all, then filter, then expand) leaves /etc selectable and
    expandable.

Both fail against the previous behavior with CurrentNode() returning nil
(the navigation unresponsive symptom) and pass with the fix. Existing snapshot
tests continue to pass, confirming the rendered output is unchanged.

Navigation evaluators required each node to match the filter regex, while rendering kept ancestor directories of matches visible. This desynced the cursor index from the rendered tree, so collapse and expand became a no op under an active filter. Derive cursor visibility from the Hidden flag that Update already computes instead.
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.

Navigate the file-tree with an active filter

1 participant