With sync vs async now derived from the calling thread, the Mode field
and its SYNC/ASYNC constants no longer carry any information: Refresh is
always async, RefreshFromWorker always sync. Drop the field, the type,
and the Mode argument at every call site, and reduce the debug log's
mode name to a plain sync/async derived from calledFromWorker.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`b` on a merge conflict is meant to keep both sides. With the diff3
conflict style git additionally renders the common ancestor between the
two sides, and the old ALL selection kept everything between the
outermost markers, dragging that ancestor into the resolved file.
Rename the selection from ALL to BOTH and restrict it to the top and
bottom hunks so the common base is dropped. Without the diff3 style
there is no ancestor section, so the behaviour there is unchanged.
The user-facing keybinding config was already named pickBothHunks; only
the internal enum, handler, translation and log string still said "all".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Convert the remaining *Alt/*Alt[12] sibling fields (PrevItem/NextItem,
GotoTop/GotoBottom, PrevBlock/NextBlock, ScrollUpMain/ScrollDownMain,
OptionMenu, ConfirmInEditor, DiffingMenu) so the merge mechanism folds
their values into the corresponding main multi-key binding at config
load. The redundant alt-only Binding registrations across the various
controllers and the global keybindings file are gone: the merged main
field already carries every key, so the for-loop in SetKeybinding
registers them all.
Previously the patch_explorer and merge_conflicts controllers reused
Universal.PrevBlock/NextBlock for moving between hunks (or conflicts) in the
main view, sharing keys with the global side-window cycle. The two operations
are conceptually distinct: cycling side windows is a global navigation gesture,
while next/prev hunk acts on the diff in the main view. Tying them together also
blocks adding <tab>/<backtab> as side- window-cycle keys, because <tab> already
means "toggle panel" in the staging view.
Add Main.PrevHunk/NextHunk to the existing KeybindingMainConfig (which already
groups bindings for the main view across staging, patch building, and merge
conflicts) and switch both controllers to it. The defaults match the active key
set those controllers had before (<left>/<right>/h/l), so the user-visible
behavior is unchanged.
I copied all files except dot files (.github and .gitignore), the _examples
folder, and go.mod/go.sum.
At some point we may want to copy the files back to the gocui repo when other
clients (e.g. lazydocker) want to use the newer versions of them.
Replace merge-tool with merge options menu that allows resolving all
conflicts for selected files as ours, theirs, or union, while still
providing access to the merge tool.
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.
As part of making lazygit more discoverable, there are certain keys which you almost certainly
need to press when you're in a given mode e.g. 'v' to paste commits when cherry-picking. This
commit prominently shows these keybinding suggestions alongside the others in the option view.
I'm using the same colours for these keybindings as is associated with the mode elsewhere e.g.
yellow for rebasing and cyan for cherry-picking. The cherry-picking one is a bit weird because
we also use cyan text to show loaders and app status at the bottom left so it may be confusing,
but I haven't personally found it awkward from having tested it out myself.
Previously we would render these options whenever a new context was activated, but now that we
need to re-render options whenever a mode changes, I'm instead rendering them on each screen
re-render (i.e. in the layout function). Given how cheap it is to render this text, I think
it's fine performance-wise.
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.
We're not fully standardising here: different contexts can store their range state however
they like. What we are standardising on is that now the view is always responsible for
highlighting the selected lines, meaning the context/controller needs to tell the view
where the range start is.
Two convenient benefits from this change:
1) we no longer need bespoke code in integration tests for asserting on selected lines because
we can just ask the view
2) line selection in staging/patch-building/merge-conflicts views now look the same as in
list views i.e. the highlight applies to the whole line (including trailing space)
I also noticed a bug with merge conflicts not rendering the selection on focus though I suspect
it wasn't a bug with any real consequences when the view wasn't displaying the selection.
I'm going to scrap the selectedRangeBgColor config and just let it use the single line
background color. Hopefully nobody cares, but there's really no need for an extra config.
We have not been good at consistent casing so far. Now we use 'Sentence case' everywhere. EVERYWHERE.
Also Removing 'Lc' prefix from i18n field names: the 'Lc' stood for lowercase but now that everything
is in 'Sentence case' there's no need for the distinction.
I've got a couple lower case things I've kept: namely, things that show up in parentheses.
This begins a big refactor of moving more code out of the Gui struct into contexts, controllers, and helpers. We also move some code into structs in the
gui package purely for the sake of better encapsulation
The "open" command is supposed to behave in the same way as double-clicking a
file in the Finder/Explorer. The concept of jumping to a specific line in the
file doesn't make sense for this; use "edit" instead.