diff --git a/docs-master/keybindings/Keybindings_en.md b/docs-master/keybindings/Keybindings_en.md index 749cdd9e8..63bb3a24c 100644 --- a/docs-master/keybindings/Keybindings_en.md +++ b/docs-master/keybindings/Keybindings_en.md @@ -227,6 +227,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | Toggle range select | | | `` e `` | Edit file | Open file in external editor. | | `` `` | Stage | Toggle selection staged / unstaged. | +| `` d `` | Discard | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. | | `` `` | Copy selected text to clipboard | | | `` , h `` | Go to previous hunk | | | `` , l `` | Go to next hunk | | @@ -341,6 +342,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | Toggle range select | | | `` e `` | Edit file | Open file in external editor. | | `` `` | Stage | Toggle selection staged / unstaged. | +| `` d `` | Discard | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. | | `` `` | Copy selected text to clipboard | | | `` , h `` | Go to previous hunk | | | `` , l `` | Go to next hunk | | diff --git a/docs-master/keybindings/Keybindings_ja.md b/docs-master/keybindings/Keybindings_ja.md index 331becbd0..786750b16 100644 --- a/docs-master/keybindings/Keybindings_ja.md +++ b/docs-master/keybindings/Keybindings_ja.md @@ -196,6 +196,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | 範囲選択を切り替え | | | `` e `` | ファイルを編集 | 外部エディタでファイルを開きます。 | | `` `` | ステージ | 選択された部分のステージ / アンステージを切り替えます。 | +| `` d `` | 破棄 | ステージされていない変更が選択されている場合、`git reset`を使用して変更を破棄します。ステージされた変更が選択されている場合、変更をアンステージします。 | | `` `` | 選択したテキストをクリップボードにコピー | | | `` , h `` | 前のハンクに移動 | | | `` , l `` | 次のハンクに移動 | | @@ -318,6 +319,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | 範囲選択を切り替え | | | `` e `` | ファイルを編集 | 外部エディタでファイルを開きます。 | | `` `` | ステージ | 選択された部分のステージ / アンステージを切り替えます。 | +| `` d `` | 破棄 | ステージされていない変更が選択されている場合、`git reset`を使用して変更を破棄します。ステージされた変更が選択されている場合、変更をアンステージします。 | | `` `` | 選択したテキストをクリップボードにコピー | | | `` , h `` | 前のハンクに移動 | | | `` , l `` | 次のハンクに移動 | | diff --git a/docs-master/keybindings/Keybindings_ko.md b/docs-master/keybindings/Keybindings_ko.md index adf015638..3adec5eb8 100644 --- a/docs-master/keybindings/Keybindings_ko.md +++ b/docs-master/keybindings/Keybindings_ko.md @@ -88,6 +88,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | 드래그 선택 전환 | | | `` e `` | 파일 편집 | Open file in external editor. | | `` `` | Staged 전환 | 선택한 행을 staged / unstaged | +| `` d `` | 변경을 삭제 (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. | | `` `` | 선택한 텍스트를 클립보드에 복사 | | | `` , h `` | 이전 hunk를 선택 | | | `` , l `` | 다음 hunk를 선택 | | @@ -175,6 +176,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | 드래그 선택 전환 | | | `` e `` | 파일 편집 | Open file in external editor. | | `` `` | Staged 전환 | 선택한 행을 staged / unstaged | +| `` d `` | 변경을 삭제 (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. | | `` `` | 선택한 텍스트를 클립보드에 복사 | | | `` , h `` | 이전 hunk를 선택 | | | `` , l `` | 다음 hunk를 선택 | | diff --git a/docs-master/keybindings/Keybindings_nl.md b/docs-master/keybindings/Keybindings_nl.md index e2db96275..065a98df2 100644 --- a/docs-master/keybindings/Keybindings_nl.md +++ b/docs-master/keybindings/Keybindings_nl.md @@ -235,6 +235,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | Toggle drag selecteer | | | `` e `` | Verander bestand | Open bestand in externe editor. | | `` `` | Toggle staged | Toggle lijnen staged / unstaged | +| `` d `` | Verwijdert change (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. | | `` `` | Copy selected text to clipboard | | | `` , h `` | Selecteer de vorige hunk | | | `` , l `` | Selecteer de volgende hunk | | @@ -319,6 +320,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | Toggle drag selecteer | | | `` e `` | Verander bestand | Open bestand in externe editor. | | `` `` | Toggle staged | Toggle lijnen staged / unstaged | +| `` d `` | Verwijdert change (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. | | `` `` | Copy selected text to clipboard | | | `` , h `` | Selecteer de vorige hunk | | | `` , l `` | Selecteer de volgende hunk | | diff --git a/docs-master/keybindings/Keybindings_pl.md b/docs-master/keybindings/Keybindings_pl.md index 0b1f4c763..58d7eeb80 100644 --- a/docs-master/keybindings/Keybindings_pl.md +++ b/docs-master/keybindings/Keybindings_pl.md @@ -103,6 +103,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | Przełącz zaznaczenie zakresu | | | `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. | | `` `` | Zatwierdź | Przełącz zaznaczenie zatwierdzone/niezatwierdzone. | +| `` d `` | Odrzuć | Gdy zaznaczona jest niezatwierdzona zmiana, odrzuć ją używając `git reset`. Gdy zaznaczona jest zatwierdzona zmiana, cofnij zatwierdzenie. | | `` `` | Kopiuj zaznaczony tekst do schowka | | | `` , h `` | Idź do poprzedniego fragmentu | | | `` , l `` | Idź do następnego fragmentu | | @@ -214,6 +215,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | Przełącz zaznaczenie zakresu | | | `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. | | `` `` | Zatwierdź | Przełącz zaznaczenie zatwierdzone/niezatwierdzone. | +| `` d `` | Odrzuć | Gdy zaznaczona jest niezatwierdzona zmiana, odrzuć ją używając `git reset`. Gdy zaznaczona jest zatwierdzona zmiana, cofnij zatwierdzenie. | | `` `` | Kopiuj zaznaczony tekst do schowka | | | `` , h `` | Idź do poprzedniego fragmentu | | | `` , l `` | Idź do następnego fragmentu | | diff --git a/docs-master/keybindings/Keybindings_pt.md b/docs-master/keybindings/Keybindings_pt.md index 8f8d2814b..ff80a02db 100644 --- a/docs-master/keybindings/Keybindings_pt.md +++ b/docs-master/keybindings/Keybindings_pt.md @@ -239,6 +239,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | Toggle range select | | | `` e `` | Editar arquivo | Abrir arquivo no editor externo. | | `` `` | Etapa | Ativar/desativar seleção em staged/unstaged | +| `` d `` | Descartar | Quando a mudança não desejada for selecionada, descarte a mudança usando `git reset`. Quando a mudança em fase é selecionada, despare a mudança. | | `` `` | Copiar texto selecionado para área de transferência | | | `` , h `` | Ir para o local anterior | | | `` , l `` | Ir para o próximo trecho | | @@ -350,6 +351,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | Toggle range select | | | `` e `` | Editar arquivo | Abrir arquivo no editor externo. | | `` `` | Etapa | Ativar/desativar seleção em staged/unstaged | +| `` d `` | Descartar | Quando a mudança não desejada for selecionada, descarte a mudança usando `git reset`. Quando a mudança em fase é selecionada, despare a mudança. | | `` `` | Copiar texto selecionado para área de transferência | | | `` , h `` | Ir para o local anterior | | | `` , l `` | Ir para o próximo trecho | | diff --git a/docs-master/keybindings/Keybindings_ru.md b/docs-master/keybindings/Keybindings_ru.md index 399e86305..7545311a0 100644 --- a/docs-master/keybindings/Keybindings_ru.md +++ b/docs-master/keybindings/Keybindings_ru.md @@ -78,6 +78,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | Переключить выборку перетаскивания | | | `` e `` | Редактировать файл | Open file in external editor. | | `` `` | Переключить индекс | Переключить строку в проиндексированные / непроиндексированные | +| `` d `` | Отменить изменение (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. | | `` `` | Скопировать выделенный текст в буфер обмена | | | `` , h `` | Выбрать предыдущую часть | | | `` , l `` | Выбрать следующую часть | | @@ -119,6 +120,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | Переключить выборку перетаскивания | | | `` e `` | Редактировать файл | Open file in external editor. | | `` `` | Переключить индекс | Переключить строку в проиндексированные / непроиндексированные | +| `` d `` | Отменить изменение (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. | | `` `` | Скопировать выделенный текст в буфер обмена | | | `` , h `` | Выбрать предыдущую часть | | | `` , l `` | Выбрать следующую часть | | diff --git a/docs-master/keybindings/Keybindings_zh-CN.md b/docs-master/keybindings/Keybindings_zh-CN.md index 9e12bc5d2..a18cd0177 100644 --- a/docs-master/keybindings/Keybindings_zh-CN.md +++ b/docs-master/keybindings/Keybindings_zh-CN.md @@ -290,6 +290,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | 切换拖动选择 | | | `` e `` | 编辑文件 | 使用外部编辑器打开文件 | | `` `` | 切换暂存状态 | 切换行暂存状态 | +| `` d `` | 取消变更(git reset) | 当选择未暂存的变更时,使用git reset丢弃该变更。当选择已暂存的变更时,取消暂存该变更 | | `` `` | 复制选中文本到剪贴板 | | | `` , h `` | 选择上一个区块 | | | `` , l `` | 选择下一个区块 | | @@ -347,6 +348,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | 切换拖动选择 | | | `` e `` | 编辑文件 | 使用外部编辑器打开文件 | | `` `` | 切换暂存状态 | 切换行暂存状态 | +| `` d `` | 取消变更(git reset) | 当选择未暂存的变更时,使用git reset丢弃该变更。当选择已暂存的变更时,取消暂存该变更 | | `` `` | 复制选中文本到剪贴板 | | | `` , h `` | 选择上一个区块 | | | `` , l `` | 选择下一个区块 | | diff --git a/docs-master/keybindings/Keybindings_zh-TW.md b/docs-master/keybindings/Keybindings_zh-TW.md index 2adf9ac93..7edb92940 100644 --- a/docs-master/keybindings/Keybindings_zh-TW.md +++ b/docs-master/keybindings/Keybindings_zh-TW.md @@ -79,6 +79,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | 切換拖曳選擇 | | | `` e `` | 編輯檔案 | 使用外部編輯器開啟 | | `` `` | 切換預存 | 切換現有行的狀態 (已預存/未預存) | +| `` d `` | 刪除變更 (git reset) | 選取未暫存的變更時,使用 `git reset` 捨棄變更。選取已暫存的變更時,取消暫存變更。 | | `` `` | 複製所選文本至剪貼簿 | | | `` , h `` | 選擇上一段 | | | `` , l `` | 選擇下一段 | | @@ -369,6 +370,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` v `` | 切換拖曳選擇 | | | `` e `` | 編輯檔案 | 使用外部編輯器開啟 | | `` `` | 切換預存 | 切換現有行的狀態 (已預存/未預存) | +| `` d `` | 刪除變更 (git reset) | 選取未暫存的變更時,使用 `git reset` 捨棄變更。選取已暫存的變更時,取消暫存變更。 | | `` `` | 複製所選文本至剪貼簿 | | | `` , h `` | 選擇上一段 | | | `` , l `` | 選擇下一段 | | diff --git a/pkg/gui/controllers/main_view_controller.go b/pkg/gui/controllers/main_view_controller.go index 92d4d57e4..46fee9ab7 100644 --- a/pkg/gui/controllers/main_view_controller.go +++ b/pkg/gui/controllers/main_view_controller.go @@ -88,6 +88,15 @@ func (self *MainViewController) GetKeybindings(opts types.KeybindingsOpts) []*ty Tooltip: self.c.Tr.StageSelectionTooltip, DisplayOnScreen: true, }, + { + Keys: opts.GetKeys(opts.Config.Universal.Remove), + Handler: self.discardSelection, + Description: self.c.Tr.DiscardSelection, + DescriptionFunc: self.workingTreeActionDescription(self.c.Tr.DiscardSelection), + GetDisabledReason: self.diffSelectionDisabledReason, + Tooltip: self.c.Tr.DiscardSelectionTooltip, + DisplayOnScreen: true, + }, { Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard), Handler: self.copySelection, @@ -341,6 +350,18 @@ func revealSelectionAfterAction( }) } +// discardSelection takes the selected diff lines back out of what they are part of, +// which — like the primary action — is the panel's business, and so is the re-render +// that follows. +func (self *MainViewController) discardSelection() error { + actions := self.focusedMainViewActions() + if actions == nil { + return nil + } + first, last := self.context.GetView().SelectedLineRange() + return actions.DiscardSelection(self.context, first, last) +} + // workingTreeActionDescription gives a command's description only where the command // applies — over the working tree's diff — so that it is listed there and nowhere else. func (self *MainViewController) workingTreeActionDescription(description string) func() string { diff --git a/pkg/gui/controllers/working_tree_diff_actions.go b/pkg/gui/controllers/working_tree_diff_actions.go index d97cb004b..4b2b8bf7f 100644 --- a/pkg/gui/controllers/working_tree_diff_actions.go +++ b/pkg/gui/controllers/working_tree_diff_actions.go @@ -70,6 +70,35 @@ func (self *WorkingTreeDiffActions) PrimaryAction(pane types.DiffPaneContext, fi git_commands.ApplyPatchOpts{Reverse: onStagedSide, Cached: true}) } +// DiscardSelection takes the selected diff lines out of the working tree — or, on the +// staged side, out of the index, which is where "discard this" means "I don't want it +// staged". +func (self *WorkingTreeDiffActions) DiscardSelection(pane types.DiffPaneContext, firstLineIdx int, lastLineIdx int) error { + if self.c.UserConfig().Git.DiffContextSize == 0 { + return fmt.Errorf(self.c.Tr.Actions.NotEnoughContextToDiscard, + self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView) + } + + infos, onStagedSide, ok := self.diffLineSelection(pane, firstLineIdx, lastLineIdx) + if !ok { + return nil + } + + // Either way the change is applied backwards; which side it is applied to decides + // how destructive that is. On the staged side it goes to the index; this is the + // same as unstaging, so nothing is lost. On the unstaged side it goes to the + // working tree, where the change is gone for good, so we ask first. + return self.c.ConfirmIf(!onStagedSide && !self.c.UserConfig().Gui.SkipDiscardChangeWarning, + types.ConfirmOpts{ + Title: self.c.Tr.DiscardChangeTitle, + Prompt: self.c.Tr.DiscardChangePrompt, + HandleConfirm: func() error { + return self.applyDiffLineSelection(pane, firstLineIdx, infos, onStagedSide, + git_commands.ApplyPatchOpts{Reverse: true, Cached: onStagedSide}) + }, + }) +} + // diffLineSelection resolves what the user has selected in a pane of the focused main // view to the change lines to act on, and reports whether they are the staged side of // the diff — which is a question about the pane, so it is the same for every file of a diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index b282be62c..2384ad10f 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -254,6 +254,10 @@ type FocusedMainViewActions interface { // the current selection in the given pane: a single line, a range, or a hunk. The // panel re-renders the diff itself, being the one that knows what it did to it. PrimaryAction(pane DiffPaneContext, firstLineIdx int, lastLineIdx int) error + + // DiscardSelection takes the selected diff lines back out of whatever they are part + // of: the working tree for the files panel. + DiscardSelection(pane DiffPaneContext, firstLineIdx int, lastLineIdx int) error } type IListContext interface { diff --git a/pkg/integration/tests/main_view/discard_diff_lines.go b/pkg/integration/tests/main_view/discard_diff_lines.go new file mode 100644 index 000000000..699b4d506 --- /dev/null +++ b/pkg/integration/tests/main_view/discard_diff_lines.go @@ -0,0 +1,70 @@ +package main_view + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var DiscardDiffLines = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Discard a hunk of the working tree's diff from the focused main view, and unstage one from the staged half", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(cfg *config.AppConfig) { + cfg.GetUserConfig().Gui.UseHunkModeInStagingView = false + }, + SetupRepo: func(shell *Shell) { + shell.CreateFileAndAdd("file1", "one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n") + shell.Commit("one") + + shell.UpdateFileAndAdd("file1", "one\nSTAGED\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten\n") + shell.UpdateFile("file1", "one\nSTAGED\ntwo\nthree\nfour\nfive\nsix\nseven\nUNSTAGED\neight\nnine\nten\n") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + IsFocused(). + Lines( + Contains("MM file1").IsSelected(), + ). + Press(keys.Universal.FocusMainView) + + // Discarding from the unstaged side throws the change away, so it asks first. + t.Views().Main(). + IsFocused(). + SelectedLines( + Contains("+UNSTAGED"), + ). + Press(keys.Universal.Remove). + Tap(func() { + t.ExpectPopup().Confirmation(). + Title(Equals("Discard change")). + Content(Contains("Are you sure you want to discard this change")). + Confirm() + }) + + // Nothing is unstaged any more, so that pane is gone and the focus has followed + // the file's remaining changes into the staged one. + t.Views().Files().Lines( + Contains("M file1"), + ) + t.Views().Main().IsInvisible() + + // There the same key means "I don't want this staged", which is unstaging, so it + // doesn't ask. + t.Views().Secondary(). + IsFocused(). + Title(Equals("Staged changes")). + SelectedLines( + Contains("+STAGED"), + ). + Press(keys.Universal.Remove) + + t.Views().Files().Lines( + Contains(" M file1"), + ) + t.Views().Secondary().IsInvisible() + t.Views().Main(). + IsFocused(). + Title(Equals("Unstaged changes")). + Content(Contains("+STAGED")) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index a4da58735..4ed11be70 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -369,6 +369,7 @@ var tests = []*components.IntegrationTest{ main_view.ClickSelectsDiffLine, main_view.CopyRowsThatAreNoDiffLine, main_view.CopySelectedDiffLines, + main_view.DiscardDiffLines, main_view.DragRangeWithAutoscroll, main_view.DragSelectsDiffLineRange, main_view.EditSelectedDiffLine,