diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2024-01-19 10:56:16 +1100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-19 10:56:16 +1100 |
commit | 74e07080d0f5ae21de91b074b4fc5140c148843b (patch) | |
tree | bdd463c87265dbf8bf122e681ce36e6c24ce7144 | |
parent | 8a94663df167b5e78f70ef570b9c8ef82aa5da99 (diff) | |
parent | ab3004bcd56792a0caba4c6436567ca92c904d61 (diff) |
Add range selection ability on list contexts (#3207)
- **PR Description**
Issue: https://github.com/jesseduffield/lazygit/issues/3196
This PR adds the ability to select a range of items in list contexts. It
does this in two ways:
* Sticky range select: like what we already have in the staging view,
you press 'v' to toggle range select and then use up/down keys to extend
the range
* Non-sticky range select: rather than explicitly toggling this on/off,
you use shift+up/down to extend the range
The PR adds the ability to range select in all list contexts, but it's
up to individual actions to opt-in to supporting a range. This PR only
supports it for copying a range of commits for cherry-picking. We can
add more support iteratively so that we're not merging a single giant
PR. For all actions requiring selection of a single-item, an error will
be shown if a range is selected.
Other use cases we want to support in the near future:
* marking commits as pick/drop/fixup/squash/etc when mid-rebase
* fixup/squash/drop when outside rebase
* moving commits up/down (in or out of rebase)
* staging/unstaging multiple files
* discarding multiple files
## Updated keybindings
Because the 'v' binding is now globally dedicated to toggling range
select, I've changed the cherry-pick copy/paste keys from 'c' and 'v' to
'shift+C' and 'shift+V' respectively. I've also nullified the 'v'
keybinding on the 'view divergence from upstream' option in the upstream
options menu (conveniently it was the first option in the menu so you
can press enter on it).
## Standardised range select display
As a bonus, this PR standardises how we display a range select. We
already had range select support in the patch explorer view and merge
conflicts view, but they were directly rendering the highlighted
selection (i.e. blue background colour) in the content written to the
view, rather than tell the view which lines were selected and have the
view highlight them itself. A convenient benefit here is that now the
entire line is highlighted, including trailing space, rather than just
the content of the line. Another convenient benefit is that our
integration tests can now easily ask the view which lines are selected,
rather than depending on the specific context, because the view keeps
track of it.
I've removed the selectedRangeBgColor config option because
selectedLineBgColor should be fine. I don't see the need for two
options, but tell me if you think otherwise.
Also, another thing we're standardising on: hitting escape will cancel
the range select, which in the staging/patch-building views means if
you're selecting a range, you'll need to hit escape twice to exit out of
the view. For consistency, we're also applying this logic if you have a
hunk selected. I personally would much prefer this and have several
times accidentally exited out of the view when trying to cancel a range
select by pressing escape. In lazygit in general, 'escape' means 'exit
out of the innermost mode' and I would consider range select to be a
kind of mode.
## Sticky vs non-sticky range interaction
Here's the state machine that explains how the sticky and non-sticky
range select modes interact. Although users will typically pick one or
the other, it's important to be clear on what the logic is if you swap
between them:
```
(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
```
Also if you press escape in either range mode, it cancels the range
select.
## Some implementation details
* when the action involves toggling e.g. toggling cherry-pick copy or
toggling staged, we decide what to do based on the selection: for
example with staging: if there are any unstaged changes in the
selection, we'll stage everything, otherwise we unstage everything. This
is the logic we already had when staging individual directories.
* we retain range selection if a view loses focus
* where we previously set SetSelectedLineIdx all over the place (e.g.
setting selected line idx to 0 when checking out a branch) we're now
using SetSelection which also resets the range select. There are only a
couple of places where we would still want to use SetSelectedLineIdx
(e.g. when the user moves up/down a page, because they would want to
retain range select in that case)
- **Please check if the PR fulfills these requirements**
* [x] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [ ] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [x] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [x] Docs (specifically `docs/Config.md`) have been updated if
necessary
* [ ] You've read through your own file changes for silly mistakes etc
<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->