Skip to content

Fix transitions of entering and exiting filtering mode (e.g. by path or author) - #5897

Merged
stefanhaller merged 6 commits into
masterfrom
fix-filtering-transition
Aug 5, 2026
Merged

Fix transitions of entering and exiting filtering mode (e.g. by path or author)#5897
stefanhaller merged 6 commits into
masterfrom
fix-filtering-transition

Conversation

@stefanhaller

Copy link
Copy Markdown
Collaborator

Entering or leaving filtering mode switched the screen mode and the focused panel immediately, then reloaded the commit list in the background. The result was an unfiltered list presented in the layout that says "you are filtering", with nothing to say that anything was still happening — and in a big repo that state can last seconds.

This is a regression in 0.64.0 (more specifically, from #5790): before that we stopped blocking the UI thread on refreshes, the reload happened before any of it, so the two always agreed; the price was a frozen UI for the duration.

Do neither: reload on a worker, so the UI stays live, and hold back everything the user can see of the change until the new lists are ready, so they still land together in one frame. A waiting status says what is going on in the meantime, and blocking input means the keys pressed while it runs arrive after the change rather than acting on a list that is about to be replaced.

@stefanhaller stefanhaller added the bug Something isn't working label Aug 5, 2026
Whether a graph can be drawn was read from the filtering mode, while the
graph itself is drawn over the commit list in the model. Those two only
agree once the list has been reloaded for the new mode, and a filtering
mode change reloads the list in the background, so in between we can be
asked to draw a graph over a list the graph makes no sense for.

That is not just cosmetic. Commits in a filtered list are almost never
each other's parents, so no pipe ever terminates: the pipe set grows by
one per row and every continuing pipe rescans it, which is cubic in the
length of the list. Escaping out of filtering mode with a filtered list
of 13000 commits — as you get once the 300 commit limit has been lifted,
which happens for good as soon as the selection passes COMMIT_THRESHOLD
— wedges the UI thread for around twenty minutes.

Record whether the list was loaded with a filter, right where the list
itself is stored, and decide from that. The graph now also stays up while
the pre-change list is still on display, rather than vanishing a moment
before the list it belongs to.
The mode it suppresses is active for any working tree state, not just a
rebase: merging, cherry-picking and reverting show through the same
indicator. Name it after what it hides.
Blocking keyboard input and hiding the working tree state mode are two
separate concerns; they were fused into one helper because every caller
so far wanted both. A caller that blocks input for something other than a
rebase would then hide the "Rebasing" indicator for the duration of its
operation, which has nothing to do with it.

Make it an explicit option instead, so blocking input on its own doesn't
imply anything about the modes on display.
Setting a filter and clearing it are the same transition in opposite
directions: mutate the mode, bring the screen mode in line with it,
reload the views that depend on the filter, and put the selection
somewhere sensible in the reloaded commit list. They were implemented
twice, once in the filtering menu and once in ModeHelper, which is how
the two came to repaint the commit list in different ways.

Derive the screen mode and the panel switch from whether a filter is
active after the change, so both directions fall out of the same code,
and give ModeHelper the entry points for both. The filtering menu is
left with nothing but the menu.
Entering or leaving filtering mode switched the screen mode and the
focused panel immediately, then reloaded the commit list in the
background. The result was an unfiltered list presented in the layout
that says "you are filtering", with nothing to say that anything was
still happening — and in a big repo that state can last seconds.

Before we stopped blocking the UI thread on refreshes, the reload
happened before any of it, so the two always agreed; the price was a
frozen UI for the duration.

Do neither: reload on a worker, so the UI stays live, and hold back
everything the user can see of the change until the new lists are ready,
so they still land together in one frame. A waiting status says what is
going on in the meantime, and blocking input means the keys pressed while
it runs arrive after the change rather than acting on a list that is
about to be replaced.
The commit list a filtering mode change leaves behind has nothing to do
with the one that was showing, so the scroll position it inherits says
nothing about where the selection ended up, and the selection can land
anywhere off screen. PostRefreshUpdate only moves the cursor within the
existing scroll position, so ask for the scroll separately, the way the
commits refresh does when it moves the selection itself.

Exiting filtering mode looked like it worked, but only by accident: the
commits refresh recognizes the commit that was selected before it ran,
selects it again at its new index, and scrolls because the index moved.
That does nothing for the case where the commit is gone from the list, or
for entering filtering mode, where we select the first commit ourselves.
@stefanhaller
stefanhaller force-pushed the fix-filtering-transition branch from d0decc7 to 1b901c7 Compare August 5, 2026 15:29
@stefanhaller
stefanhaller merged commit bd76666 into master Aug 5, 2026
14 checks passed
@stefanhaller
stefanhaller deleted the fix-filtering-transition branch August 5, 2026 15:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant