summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2024-01-19 10:56:16 +1100
committerGitHub <noreply@github.com>2024-01-19 10:56:16 +1100
commit74e07080d0f5ae21de91b074b4fc5140c148843b (patch)
treebdd463c87265dbf8bf122e681ce36e6c24ce7144
parent8a94663df167b5e78f70ef570b9c8ef82aa5da99 (diff)
parentab3004bcd56792a0caba4c6436567ca92c904d61 (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 -->
-rw-r--r--.vscode/launch.json6
-rw-r--r--README.md2
-rw-r--r--docs/Config.md18
-rw-r--r--docs/README.md3
-rw-r--r--docs/Range_Select.md14
-rw-r--r--docs/dev/Codebase_Guide.md1
-rw-r--r--docs/keybindings/Keybindings_en.md20
-rw-r--r--docs/keybindings/Keybindings_ja.md16
-rw-r--r--docs/keybindings/Keybindings_ko.md16
-rw-r--r--docs/keybindings/Keybindings_nl.md16
-rw-r--r--docs/keybindings/Keybindings_pl.md20
-rw-r--r--docs/keybindings/Keybindings_ru.md16
-rw-r--r--docs/keybindings/Keybindings_zh-CN.md16
-rw-r--r--docs/keybindings/Keybindings_zh-TW.md16
-rw-r--r--go.mod6
-rw-r--r--go.sum10
-rw-r--r--pkg/commands/patch/format.go24
-rw-r--r--pkg/commands/patch/patch_builder.go4
-rw-r--r--pkg/config/user_config.go32
-rw-r--r--pkg/gui/context/commit_files_context.go2
-rw-r--r--pkg/gui/context/filtered_list_view_model.go2
-rw-r--r--pkg/gui/context/list_context_trait.go17
-rw-r--r--pkg/gui/context/local_commits_context.go2
-rw-r--r--pkg/gui/context/menu_context.go5
-rw-r--r--pkg/gui/context/merge_conflicts_context.go27
-rw-r--r--pkg/gui/context/patch_explorer_context.go5
-rw-r--r--pkg/gui/context/sub_commits_context.go2
-rw-r--r--pkg/gui/context/suggestions_context.go7
-rw-r--r--pkg/gui/context/traits/list_cursor.go126
-rw-r--r--pkg/gui/context/view_trait.go8
-rw-r--r--pkg/gui/context/working_tree_context.go2
-rw-r--r--pkg/gui/controllers/basic_commits_controller.go85
-rw-r--r--pkg/gui/controllers/bisect_controller.go59
-rw-r--r--pkg/gui/controllers/branches_controller.go161
-rw-r--r--pkg/gui/controllers/command_log_controller.go4
-rw-r--r--pkg/gui/controllers/commit_description_controller.go4
-rw-r--r--pkg/gui/controllers/commit_message_controller.go4
-rw-r--r--pkg/gui/controllers/commits_files_controller.go76
-rw-r--r--pkg/gui/controllers/confirmation_controller.go4
-rw-r--r--pkg/gui/controllers/context_lines_controller.go4
-rw-r--r--pkg/gui/controllers/custom_patch_options_menu_action.go13
-rw-r--r--pkg/gui/controllers/files_controller.go105
-rw-r--r--pkg/gui/controllers/files_remove_controller.go39
-rw-r--r--pkg/gui/controllers/filtering_menu_action.go2
-rw-r--r--pkg/gui/controllers/git_flow_controller.go33
-rw-r--r--pkg/gui/controllers/global_controller.go4
-rw-r--r--pkg/gui/controllers/helpers/cherry_pick_helper.go30
-rw-r--r--pkg/gui/controllers/helpers/fixup_helper.go2
-rw-r--r--pkg/gui/controllers/helpers/merge_and_rebase_helper.go1
-rw-r--r--pkg/gui/controllers/helpers/merge_conflicts_helper.go10
-rw-r--r--pkg/gui/controllers/helpers/refs_helper.go14
-rw-r--r--pkg/gui/controllers/helpers/search_helper.go4
-rw-r--r--pkg/gui/controllers/helpers/sub_commits_helper.go2
-rw-r--r--pkg/gui/controllers/jump_to_side_window_controller.go4
-rw-r--r--pkg/gui/controllers/list_controller.go59
-rw-r--r--pkg/gui/controllers/list_controller_trait.go95
-rw-r--r--pkg/gui/controllers/local_commits_controller.go243
-rw-r--r--pkg/gui/controllers/menu_controller.go34
-rw-r--r--pkg/gui/controllers/merge_conflicts_controller.go18
-rw-r--r--pkg/gui/controllers/patch_building_controller.go12
-rw-r--r--pkg/gui/controllers/patch_explorer_controller.go39
-rw-r--r--pkg/gui/controllers/quit_actions.go7
-rw-r--r--pkg/gui/controllers/reflog_commits_controller.go11
-rw-r--r--pkg/gui/controllers/remote_branches_controller.go76
-rw-r--r--pkg/gui/controllers/remotes_controller.go57
-rw-r--r--pkg/gui/controllers/search_prompt_controller.go4
-rw-r--r--pkg/gui/controllers/side_window_controller.go8
-rw-r--r--pkg/gui/controllers/snake_controller.go4
-rw-r--r--pkg/gui/controllers/staging_controller.go9
-rw-r--r--pkg/gui/controllers/stash_controller.go62
-rw-r--r--pkg/gui/controllers/status_controller.go4
-rw-r--r--pkg/gui/controllers/sub_commits_controller.go11
-rw-r--r--pkg/gui/controllers/submodules_controller.go69
-rw-r--r--pkg/gui/controllers/suggestions_controller.go19
-rw-r--r--pkg/gui/controllers/switch_to_diff_files_controller.go38
-rw-r--r--pkg/gui/controllers/switch_to_sub_commits_controller.go27
-rw-r--r--pkg/gui/controllers/tags_controller.go61
-rw-r--r--pkg/gui/controllers/undo_controller.go4
-rw-r--r--pkg/gui/controllers/worktree_options_controller.go29
-rw-r--r--pkg/gui/controllers/worktrees_controller.go55
-rw-r--r--pkg/gui/filetree/commit_file_tree_view_model.go2
-rw-r--r--pkg/gui/filetree/file_tree_view_model.go6
-rw-r--r--pkg/gui/global_handlers.go22
-rw-r--r--pkg/gui/gui.go2
-rw-r--r--pkg/gui/gui_driver.go10
-rw-r--r--pkg/gui/keybindings.go72
-rw-r--r--pkg/gui/keybindings/keybindings.go122
-rw-r--r--pkg/gui/layout.go10
-rw-r--r--pkg/gui/menu_panel.go2
-rw-r--r--pkg/gui/mergeconflicts/rendering.go10
-rw-r--r--pkg/gui/patch_exploring/state.go66
-rw-r--r--pkg/gui/types/context.go14
-rw-r--r--pkg/gui/views.go6
-rw-r--r--pkg/i18n/chinese.go3
-rw-r--r--pkg/i18n/dutch.go3
-rw-r--r--pkg/i18n/english.go18
-rw-r--r--pkg/i18n/japanese.go7
-rw-r--r--pkg/i18n/korean.go3
-rw-r--r--pkg/i18n/polish.go1
-rw-r--r--pkg/i18n/russian.go3
-rw-r--r--pkg/i18n/traditional_chinese.go3
-rw-r--r--pkg/integration/components/view_driver.go88
-rw-r--r--pkg/integration/components/views.go93
-rw-r--r--pkg/integration/tests/cherry_pick/cherry_pick_range.go85
-rw-r--r--pkg/integration/tests/commit/stage_range_of_lines.go2
-rw-r--r--pkg/integration/tests/demo/stage_lines.go2
-rw-r--r--pkg/integration/tests/file/copy_menu.go4
-rw-r--r--pkg/integration/tests/patch_building/specific_selection.go10
-rw-r--r--