This should arguably have been done in b133318b40 already; it's becoming more
important now because we're going to extend the common code with more logic in
the next commit.
It starts a rebase on the bottom-most commit of the range, and sets all the
selected commits to "edit" (skipping merge commits, because they can't be
edited).
A common workflow for me is to create a fixup commit from only some of my
current changes; to do that, I enter a file, stage a few hunks, and then want to
invoke ctrl-f to find the base commit for these changes. Currently I need to esc
back to the files panel in order to do that; it's more convenient to be able to
do this right from the staging panel.
This commit introduces a new feature to the commit view, allowing users
to filter commits based on the author's name or email address. Similar
to the existing path filtering functionality, accessible through <c-s>,
this feature allows users to filter the commit history by the currently
selected commit's author if the commit view is focused, or by typing in
the author's name or email address.
This feature adds an entry to the filtering menu, to provide users with
a familiar and intuitive experience
Calling "git reset" on the command line (without further arguments) defaults to
--mixed, which is reason enough to make it the default for us, too.
But I also find myself using --mixed more often than --soft. The main use case
for me is that I made a bunch of WIP commits, and want to turn them into real
commits when I'm done hacking. I select the last commit before the WIP commits
and reset to it, leaving all changes of all those commits in the working
directory. Since I want to start staging things from there, I prefer those
modifications to be unstaged at that point, which is what --mixed does.
This fixes two problems:
- each time the custom commands panel was opened, the history of commands would
be shown in reversed order compared to last time. (The reason is that
lo.Reverse modifies the slice in place rather than just returning a new,
reversed slice.)
- when executing a previous command again (either by typing it in again, or by
picking it from the history), it should move to the beginning of the history,
but didn't.
We fix this by storing the history in reversed order (as the user sees it in
the panel), this makes the logic simpler. We just have to prepend rather
than append newly added commands now.
While this is theoretically a breaking change, it's not worth bothering because
the order was wrong for existing users in 50% of the cases anyway.
Scenario:
- show the files of a commit, escape out of it again
- start an interactive rebase of a stack of branches, with the rebase.updateRefs
git config set to true
- select one of the update-ref todos
- trigger a refresh (either manually or by bringing lazygit's terminal window to
the front)
This results in an error message "fatal: ambiguous argument '': unknown revision
or path not in the working tree."
Fix this by putting another band-aid on the check for the commit files refresh.
This is the easiest way to fix the problem, but I don't think it's the best one.
We shouldn't be refreshing the commit files context at all if it isn't visible,
because it's pointless; there's no way to switch to it again except by calling
viewFiles again with a specific ref. But I'm too lazy too figure out how to do
that right now.
After discarding file changes from the commit, the was still referencing
these indexes as being part of the range select. The consequence was
needing to hit escape twice to exit commit files in some situations.
Canceling the range select after discarding changes fixes that.
The waiting status shouldn't happen until after the user has responded
to the popup.
Since we're not giving a standalone prompt about clearing the patch, all
of the business in `discard` doesn't need to be in a function any more
It can be tedious after each cherry-pick opearation to clear the
selection by pressing escape in order for lazygit to stop displaying
info about copied commits. Also, it seems to be a rare case to
cherry-pick commits to more than one destination.
The simplest solution to address this issue is to clear the selection
upon paste.
The only exception is a merge conflict. Initially, I wanted to clear
selected commits in this scenario too. During a discussion we found out
that it may be convenient to have the copied commits still around.
Aborting the rebase and pasting the commits in the middle of a branch
can be a valid use case.
To do that, change the "Apply fixup commits" command to show a menu with the two
choices "in current branch" and "above the selected commit"; we make "in current
branch" the default, as it's the more useful one most of the time, even though
it is a breaking change for those who are used to "shift-S enter" meaning
"squash above selected".
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.
This is useful if you want to move a range of commits, so you select them, and
then realize it's better to do it in an interactive rebase. Pressing 'i'
preserves the range now.
This helps work around bugs in editors that may get confused about relative
paths (like nvim-remote, see https://github.com/neovim/neovim/issues/18519), and
shouldn't have any negative effect on others.
As part of this, you must now press enter on a merge conflict file
to focus the merge view; you can no longer press space and if you do
it will raise an error.
I prefer this because I almost never use sticky range selections. Also, this
fixes the issue that just clicking a line in a diff (without dragging) already
creates a range selection. It still does, technically, but it's no longer a
problem because a non-sticky one-line range selection behaves the same as a
non-range selection.
Something dumb that we're currently doing is expecting list items
to define an ID method which returns a string. We use that when copying
items to clipboard with ctrl+o and when getting a ref name for diffing.
This commit gets us a little deeper into that hole by explicitly requiring
list items to implement that method so that we can easily use the new
helper functions in list_controller_trait.go.
In future we need to just remove the whole ID thing entirely but I'm too
lazy to do that right now.
This wasn't necessary before, because the only available branch sorting option
was by recency, so the sort order couldn't change except by checking out
branches. Now, you can sort by committer date, so the branch order can change by
fetching; in this case it's important to keep the same branch selected. One
important use case is to rebase the checked-out branch onto master; you select
master, press "f" to fetch it (this can now change its position in the list),
and then press "r" to rebase. To make this work smoothly it's important to keep
master selected after pressing "f".
We don't need it there so no need to enable it.
I'm leaving the disabled reason checks there, even though they're now redundant,
because they're only one-liners and they communicate intent.
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.
This requires us to change the 'v' keybinding for paste to something else,
now that 'v' is used globally for toggling range select. So I'm using
'shift+v' and I'm likewise changing 'c' to 'shift+c' for copying, so
that they're consistent.
We will need to clearly communicate this change in keybindings.
The only time we should call SetSelectedLineIdx is when we are happy for a
select range to be retained which means things like moving the selected line
index to top top/bottom or up/down a page as the user navigates.
But in every other case we should now call SetSelection because that will
set the selected index and cancel the range which is almost always what we
want.
This is the highest priority of the escape actions because it's the thing you're
most likely to want to do upon hitting escape if you have a range selected.
Applying this to the staging/patch-building views is tricky: if we want this logic
for when a range of lines is selected, we'll also need to apply it when a hunk
is selected too. I still think it's worth it though: I've often accidentally
escaped from the staging view when trying to cancel a range selection.
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.
This adds range select ability in two ways:
1) Sticky: like what we already have with the staging view i.e. press v then use arrow keys
2) Non-sticky: where you just use shift+up/down to expand the range
The state machine works like this:
(no range, press 'v') -> sticky range
(no range, press arrow) -> no range
(no range, press shift+arrow) -> nonsticky range
(sticky range, press 'v') -> no range
(sticky range, press arrow) -> sticky range
(sticky range, press shift+arrow) -> nonsticky range
(nonsticky range, press 'v') -> no range
(nonsticky range, press arrow) -> no range
(nonsticky range, press shift+arrow) -> nonsticky range