The focused diff addresses patch lines by identity, so changing how much
context is rendered cannot invalidate an active patch. Remove the
explorer era refusal and prove that another line can still be toggled
correctly after the rerender.
Co-Authored-By: GitHub Copilot <copilot@github.com>
Focused main views now own selection, staging, patch construction, copying,
and context-size rerenders. Remove the parallel controller/helper stack and
its refresh scopes, while retaining custom-patch reset as mode behavior.
Co-Authored-By: GitHub Copilot <copilot@github.com>
Pressing { or } re-rendered the diff with less or more context around each
change and dropped you back at the top of it, so finding your way back to
what you were reading was on you.
Remember where the view is before triggering the re-render, and have the
restore put it back there. The line to remember is the selected one when a
selection is showing, and the middle visible line otherwise — what you are
looking at, rather than the view's top edge. It is remembered by identity,
because the new rendering puts it on a different line of the view, and it
is found again by the records a diff renderer states for its rows, or by
parsing the rendering as a diff where it still looks like one.
The line may not be there at all afterwards: shrinking the context takes
context lines away. So the lines around it come along as fallbacks, nearest
first, and the view lands on the nearest one that survived, put back on the
screen row it was on — leaving what you were reading where it was, give or
take the line that went. The walk that collects them covers the whole diff
rather than stopping at the nearest change on either side: those always
survive a context-size change, but not everything a re-render can do to a
diff is that considerate.
Under a diff renderer that says nothing about its rows there is nothing to
look for at all, and the view is left at the offset it had instead: often not
the line it was on, but always closer to it than the top of the diff. That is
what the re-render asks for besides the restore, since it is a different
command from the one that produced what is on screen and would otherwise be
taken for a diff the user has never seen.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Actually, we simply enable them in any panel, even those that can never show a
diff. Since the commands show a toast, that's enough feedback to understand what
happened; the change will take effect the next time you switch to a panel that
does show diffs.
Same for ( and ) to change the rename threshold.
Refresh is one of those functions that shouldn't require error handling (similar
to triggering a redraw of the UI, see
https://github.com/jesseduffield/lazygit/issues/3887).
As far as I see, the only reason why Refresh can currently return an error is
that the Then function returns one. The actual refresh errors, e.g. from the git
calls that are made to fetch data, are already logged and swallowed. Most of the
Then functions do only UI stuff such as selecting a list item, and always return
nil; there's only one that can return an error (updating the rebase todo file in
LocalCommitsController.startInteractiveRebaseWithEdit); it's not a critical
error if this fails, it is only used for setting rebase todo items to "edit"
when you start an interactive rebase by pressing 'e' on a range selection of
commits. We simply log this error instead of returning it.
This adds a bunch of tooltips to keybindings and updates some keybinding descriptions (i.e. labels).
It's in preparation for displaying more keybindings on-screen (in the bottom right of the screen),
and so due in part to laziness it shortens some descriptions so that we don't need to manage both
a short and long description (for on-screen vs in-menu). Nonetheless I've added a ShortDescription
field for when we do want to have both a short and long description.
You'll notice that some keybindings I deemed unworthy of the options view have longer descriptions,
because I could get away with it.
We want to show an error when the user tries to invoke an action that expects only
a single item to be selected.
We're using the GetDisabledReason field to enforce this (as well as DisabledReason
on menu items).
I've created a ListControllerTrait to store some shared convenience functions for this.