Increasing or decreasing the diff context size (the `{`/`}` keybindings)
re-renders the diff with a different `git diff -U<n>` command. Because the
command key changes, the render reset the main view to the top — losing the
spot the user was reading, which is exactly the spot the context change is
about.
Preserve it instead, reusing the identity-based restore built for the escape
path. This is its sibling consumer: capture the lines around the anchor (the
selection, or the top visible line when there's none) as restore candidates,
and after the re-render land on the nearest one that survived, put back at the
same screen row. Prefer the anchor line itself, falling back outward only when
it didn't survive: a context line vanishes when the context size shrinks,
whereas additions and deletions always survive, so expansion stops at the
first change line in each direction and the candidate list always contains a
survivor. Landing on the nearest survivor keeps scrolling to a minimum, and a
context line that is still in the patch stays put (or stays selected).
This generalizes the shared restore helper to take a prioritized candidate
list (the escape path passes a single candidate). It covers the focused main
view and every side panel's diff, since they all render into the same "main"
view through the same path. A showing selection is re-established on the landed
line; otherwise the view stays in scroll mode.
Co-Authored-By: Claude Opus 4.8 (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.