Remove the explorer behavior behind the retired panels

Focused main views now own selection, staging, patch construction, copying,
and context-size rerenders. Remove the parallel controller/helper stack and
its refresh scopes, while retaining custom-patch reset as mode behavior.

Co-Authored-By: GitHub Copilot <copilot@github.com>
This commit is contained in:
Stefan Haller
2026-10-04 19:01:03 +02:00
co-authored by GitHub Copilot
parent d6ed0cecc7
commit fb3ad64e80
23 changed files with 42 additions and 1601 deletions
-26
View File
@@ -245,38 +245,12 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | Go to previous hunk | |
| `` <right>, l `` | Go to next hunk | |
| `` v `` | Toggle range select | |
| `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. |
| `` <ctrl+o> `` | Copy selected text to clipboard | |
| `` o `` | Open file | Open file in default application. |
| `` e `` | Edit file | Open file in external editor. |
| `` <space> `` | Toggle lines in patch | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Exit custom patch builder | |
| `` / `` | Search the current view by text | |
## Main panel (staging)
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | Go to previous hunk | |
| `` <right>, l `` | Go to next hunk | |
| `` v `` | Toggle range select | |
| `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. |
| `` <ctrl+o> `` | Copy selected text to clipboard | |
| `` <space> `` | 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. |
| `` o `` | Open file | Open file in default application. |
| `` e `` | Edit file | Open file in external editor. |
| `` <esc> `` | Return to files panel | |
| `` <tab> `` | Switch view | Switch to other view (staged/unstaged changes). |
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
| `` c `` | Commit | Commit staged changes. |
| `` w `` | Commit changes without pre-commit hook | |
| `` C `` | Commit changes using git editor | |
| `` <ctrl+f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | Search the current view by text | |
## Menu
-26
View File
@@ -263,38 +263,12 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | 前のハンクに移動 | |
| `` <right>, l `` | 次のハンクに移動 | |
| `` v `` | 範囲選択を切り替え | |
| `` a `` | ハンクの選択を切り替える | Toggle line-by-line vs. hunk selection mode. |
| `` <ctrl+o> `` | 選択したテキストをクリップボードにコピー | |
| `` <space> `` | ステージ | 選択された部分のステージ / アンステージを切り替えます。 |
| `` d `` | 破棄 | ステージされていない変更が選択されている場合、`git reset`を使用して変更を破棄します。ステージされた変更が選択されている場合、変更をアンステージします。 |
| `` o `` | ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 |
| `` e `` | ファイルを編集 | 外部エディタでファイルを開きます。 |
| `` <esc> `` | ファイルパネルに戻る | |
| `` <tab> `` | ビューを切り替え | 他のビュー(ステージされた変更/ステージされていない変更)に切り替えます。 |
| `` E `` | ハンクを編集 | 選択したハンクを外部エディタで編集します。 |
| `` c `` | コミット | ステージされた変更をコミットします。 |
| `` w `` | pre-commitフックなしで変更をコミット | |
| `` C `` | Gitエディタを使用して変更をコミット | |
| `` <ctrl+f> `` | フィックスアップのベースコミットを検索 | 現在の変更が基づいているコミットを見つけて、コミットの修正/フィックスアップを行います。これにより、ブランチのコミットを一つずつ確認して、どのコミットを修正/フィックスアップすべきかを調べる手間が省けます。詳細はドキュメントを参照: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | 現在のビューをテキストで検索 | |
## メインパネル(パッチ作成)
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | 前のハンクに移動 | |
| `` <right>, l `` | 次のハンクに移動 | |
| `` v `` | 範囲選択を切り替え | |
| `` a `` | ハンクの選択を切り替える | Toggle line-by-line vs. hunk selection mode. |
| `` <ctrl+o> `` | 選択したテキストをクリップボードにコピー | |
| `` o `` | ファイルを開く | デフォルトのアプリケーションでファイルを開きます。 |
| `` e `` | ファイルを編集 | 外部エディタでファイルを開きます。 |
| `` <space> `` | パッチ内の行を切り替え | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | カスタムパッチビルダーを終了 | |
| `` / `` | 現在のビューをテキストで検索 | |
## メインパネル(マージ中)
-26
View File
@@ -199,38 +199,12 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | 이전 hunk를 선택 | |
| `` <right>, l `` | 다음 hunk를 선택 | |
| `` v `` | 드래그 선택 전환 | |
| `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. |
| `` <ctrl+o> `` | 선택한 텍스트를 클립보드에 복사 | |
| `` o `` | 파일 닫기 | Open file in default application. |
| `` e `` | 파일 편집 | Open file in external editor. |
| `` <space> `` | Line(s)을 패치에 추가/삭제 | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Exit custom patch builder | |
| `` / `` | 검색 시작 | |
## 메인 패널 (Staging)
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | 이전 hunk를 선택 | |
| `` <right>, l `` | 다음 hunk를 선택 | |
| `` v `` | 드래그 선택 전환 | |
| `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. |
| `` <ctrl+o> `` | 선택한 텍스트를 클립보드에 복사 | |
| `` <space> `` | 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. |
| `` o `` | 파일 닫기 | Open file in default application. |
| `` e `` | 파일 편집 | Open file in external editor. |
| `` <esc> `` | 파일 목록으로 돌아가기 | |
| `` <tab> `` | 패널 전환 | Switch to other view (staged/unstaged changes). |
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
| `` c `` | 커밋 변경내용 | 스테이징된 변경 사항 커밋. |
| `` w `` | Commit changes without pre-commit hook | |
| `` C `` | Git 편집기를 사용하여 변경 내용을 커밋합니다. | |
| `` <ctrl+f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | 검색 시작 | |
## 브랜치
-26
View File
@@ -253,16 +253,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | Selecteer de vorige hunk | |
| `` <right>, l `` | Selecteer de volgende hunk | |
| `` v `` | Toggle drag selecteer | |
| `` a `` | Wissel tussen hunk selectie aan of uit | Wissel tussen regel-voor-regel of hunk selectie modus. |
| `` <ctrl+o> `` | Copy selected text to clipboard | |
| `` o `` | Open bestand | Open bestand in standaardapplicatie. |
| `` e `` | Verander bestand | Open bestand in externe editor. |
| `` <space> `` | Voeg toe/verwijder lijn(en) in patch | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Sluit lijn-bij-lijn modus | |
| `` / `` | Start met zoeken | |
## Reflog
@@ -343,22 +333,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | Selecteer de vorige hunk | |
| `` <right>, l `` | Selecteer de volgende hunk | |
| `` v `` | Toggle drag selecteer | |
| `` a `` | Wissel tussen hunk selectie aan of uit | Wissel tussen regel-voor-regel of hunk selectie modus. |
| `` <ctrl+o> `` | Copy selected text to clipboard | |
| `` <space> `` | 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. |
| `` o `` | Open bestand | Open bestand in standaardapplicatie. |
| `` e `` | Verander bestand | Open bestand in externe editor. |
| `` <esc> `` | Ga terug naar het bestanden paneel | |
| `` <tab> `` | Ga naar een ander paneel | Switch to other view (staged/unstaged changes). |
| `` E `` | Edit hunk | Edit selected hunk in external editor. |
| `` c `` | Commit veranderingen | Commit gestagede wijzigingen. |
| `` w `` | Commit veranderingen zonder pre-commit hook | |
| `` C `` | Commit veranderingen met de git editor | |
| `` <ctrl+f> `` | Find base commit for fixup | Vind de commit waar je huidige wijzigingen bovenop zijn gebouwd met als doel die commit te amenden/fixen. Hierdoor hoef je dit niet met de hand te doen. Zie: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | Start met zoeken | |
## Stash
-26
View File
@@ -151,16 +151,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | Idź do poprzedniego fragmentu | |
| `` <right>, l `` | Idź do następnego fragmentu | |
| `` v `` | Przełącz zaznaczenie zakresu | |
| `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. |
| `` <ctrl+o> `` | Kopiuj zaznaczony tekst do schowka | |
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
| `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. |
| `` <space> `` | Przełącz linie w łatce | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Wyjdź z budowniczego niestandardowej łatki | |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
## Input prompt
@@ -254,22 +244,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | Idź do poprzedniego fragmentu | |
| `` <right>, l `` | Idź do następnego fragmentu | |
| `` v `` | Przełącz zaznaczenie zakresu | |
| `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. |
| `` <ctrl+o> `` | Kopiuj zaznaczony tekst do schowka | |
| `` <space> `` | 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. |
| `` o `` | Otwórz plik | Otwórz plik w domyślnej aplikacji. |
| `` e `` | Edytuj plik | Otwórz plik w zewnętrznym edytorze. |
| `` <esc> `` | Wróć do panelu plików | |
| `` <tab> `` | Przełącz widok | Przełącz na inny widok (zatwierdzone/niezatwierdzone zmiany). |
| `` E `` | Edytuj fragment | Edytuj wybrany fragment w zewnętrznym edytorze. |
| `` c `` | Commit | Zatwierdź zmiany zatwierdzone. |
| `` w `` | Zatwierdź zmiany bez hooka pre-commit | |
| `` C `` | Zatwierdź zmiany używając edytora git | |
| `` <ctrl+f> `` | Znajdź bazowy commit do poprawki | Znajdź commit, na którym opierają się Twoje obecne zmiany, w celu poprawienia/zmiany commita. To pozwala Ci uniknąć przeglądania commitów w Twojej gałęzi jeden po drugim, aby zobaczyć, który commit powinien być poprawiony/zmieniony. Zobacz dokumentację: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
## Panel potwierdzenia
-26
View File
@@ -257,22 +257,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | Ir para o local anterior | |
| `` <right>, l `` | Ir para o próximo trecho | |
| `` v `` | Toggle range select | |
| `` a `` | Toggle hunk selection | Ativa/desativa modo linha por linha vs. modo de seleção por partes. |
| `` <ctrl+o> `` | Copiar texto selecionado para área de transferência | |
| `` <space> `` | 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. |
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
| `` e `` | Editar arquivo | Abrir arquivo no editor externo. |
| `` <esc> `` | Retornar ao painel de arquivos | |
| `` <tab> `` | Mudar de visão | Alternar para outra visão (staged/não processadas alterações). |
| `` E `` | Editar hunk | Editar o local selecionado no editor externo. |
| `` c `` | Commit | Submeter mudanças em staging |
| `` w `` | Fazer commit de alterações sem pré-commit | |
| `` C `` | Enviar alteração usando um editor Git | |
| `` <ctrl+f> `` | Encontrar commit da base para corrigir | Encontre o commit em que as suas mudanças atuais estão se baseando, para alterar/consertar o commit. Isso poupa-te você de ter que olhar pelos commits da sua branch um por um para ver qual commit deve ser alterado/consertado<br>Veja a documentação:<br><https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | Pesquisar na visualização atual por texto | |
## Painel de confirmação
@@ -303,16 +287,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | Ir para o local anterior | |
| `` <right>, l `` | Ir para o próximo trecho | |
| `` v `` | Toggle range select | |
| `` a `` | Toggle hunk selection | Ativa/desativa modo linha por linha vs. modo de seleção por partes. |
| `` <ctrl+o> `` | Copiar texto selecionado para área de transferência | |
| `` o `` | Abrir arquivo | Abrir arquivo no aplicativo padrão. |
| `` e `` | Editar arquivo | Abrir arquivo no editor externo. |
| `` <space> `` | Alternar linhas no caminho | |
| `` d `` | Remover linhas do commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Sair do construtor de patch personalizado | |
| `` / `` | Pesquisar na visualização atual por texto | |
## Reflog
-26
View File
@@ -96,22 +96,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | Выбрать предыдущую часть | |
| `` <right>, l `` | Выбрать следующую часть | |
| `` v `` | Переключить выборку перетаскивания | |
| `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. |
| `` <ctrl+o> `` | Скопировать выделенный текст в буфер обмена | |
| `` <space> `` | Переключить индекс | Переключить строку в проиндексированные / непроиндексированные |
| `` d `` | Отменить изменение (git reset) | When unstaged change is selected, discard the change using `git reset`. When staged change is selected, unstage the change. |
| `` o `` | Открыть файл | Open file in default application. |
| `` e `` | Редактировать файл | Open file in external editor. |
| `` <esc> `` | Вернуться к панели файлов | |
| `` <tab> `` | Переключиться на другую панель (проиндексированные/непроиндексированные изменения) | Switch to other view (staged/unstaged changes). |
| `` E `` | Изменить эту часть | Edit selected hunk in external editor. |
| `` c `` | Сохранить изменения | Commit staged changes. |
| `` w `` | Закоммитить изменения без предварительного хука коммита | |
| `` C `` | Сохранить изменения с помощью редактора git | |
| `` <ctrl+f> `` | Find base commit for fixup | Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | Найти | |
## Главная панель (Обычный)
@@ -159,16 +143,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | Выбрать предыдущую часть | |
| `` <right>, l `` | Выбрать следующую часть | |
| `` v `` | Переключить выборку перетаскивания | |
| `` a `` | Toggle hunk selection | Toggle line-by-line vs. hunk selection mode. |
| `` <ctrl+o> `` | Скопировать выделенный текст в буфер обмена | |
| `` o `` | Открыть файл | Open file in default application. |
| `` e `` | Редактировать файл | Open file in external editor. |
| `` <space> `` | Добавить/удалить строку(и) для патча | |
| `` d `` | Remove lines from commit | Remove the selected lines from this commit. This runs an interactive rebase in the background, so you may get a merge conflict if a later commit also changes these lines. |
| `` <esc> `` | Выйти из сборщика пользовательских патчей | |
| `` / `` | Найти | |
## Журнал ссылок (Reflog)
@@ -253,16 +253,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | 选择上一个区块 | |
| `` <right>, l `` | 选择下一个区块 | |
| `` v `` | 切换拖动选择 | |
| `` a `` | 切换代码块选择 | 切换逐行选择与代码块选择模式。 |
| `` <ctrl+o> `` | 复制选中文本到剪贴板 | |
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
| `` <space> `` | 添加/移除 行到补丁 | |
| `` d `` | 从提交中移除行 | 从本次提交中移除所选行。此操作会在后台运行交互式变基,因此如果后续提交也修改了这些行,您可能会遇到合并冲突。 |
| `` <esc> `` | 退出逐行模式 | |
| `` / `` | 开始搜索 | |
## 标签
@@ -324,22 +314,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | 选择上一个区块 | |
| `` <right>, l `` | 选择下一个区块 | |
| `` v `` | 切换拖动选择 | |
| `` a `` | 切换代码块选择 | 切换逐行选择与代码块选择模式。 |
| `` <ctrl+o> `` | 复制选中文本到剪贴板 | |
| `` <space> `` | 切换暂存状态 | 切换行暂存状态 |
| `` d `` | 取消变更(git reset) | 当选择未暂存的变更时,使用git reset丢弃该变更。当选择已暂存的变更时,取消暂存该变更 |
| `` o `` | 打开文件 | 使用默认程序打开该文件 |
| `` e `` | 编辑文件 | 使用外部编辑器打开文件 |
| `` <esc> `` | 返回文件面板 | |
| `` <tab> `` | 切换到其他面板 | 切换到其他视图(已暂存/未暂存的变更) |
| `` E `` | 编辑代码块 | 在外部编辑器中编辑选中的代码块 |
| `` c `` | 提交变更 | 提交暂存文件 |
| `` w `` | 提交变更而无需预先提交钩子 | |
| `` C `` | 使用 Git 编辑器提交变更 | |
| `` <ctrl+f> `` | 找到用于修复的基准提交 | 找到您当前变更所基于的提交,以便于修正/改进该提交。这样做可以省去您逐一查看分支提交来确定应该修正/改进哪个提交的麻烦。请参阅文档: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | 开始搜索 | |
## 正常
@@ -56,16 +56,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | 選擇上一段 | |
| `` <right>, l `` | 選擇下一段 | |
| `` v `` | 切換拖曳選擇 | |
| `` a `` | 切換程式碼塊選擇 | 切換逐行選擇與程式碼塊選擇模式。 |
| `` <ctrl+o> `` | 複製所選文本至剪貼簿 | |
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
| `` e `` | 編輯檔案 | 使用外部編輯器開啟 |
| `` <space> `` | 向 (或從) 補丁中添加/刪除行 | |
| `` d `` | 從提交中移除行 | 從本次提交中移除所選行。此操作會在背景執行互動式變基,因此如果後續提交也修改了這些行,您可能會遇到合併衝突。 |
| `` <esc> `` | 退出自訂補丁建立器 | |
| `` / `` | 搜尋 | |
## 主面板(一般)
@@ -113,22 +103,6 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| Key | Action | Info |
|-----|--------|-------------|
| `` <left>, h `` | 選擇上一段 | |
| `` <right>, l `` | 選擇下一段 | |
| `` v `` | 切換拖曳選擇 | |
| `` a `` | 切換程式碼塊選擇 | 切換逐行選擇與程式碼塊選擇模式。 |
| `` <ctrl+o> `` | 複製所選文本至剪貼簿 | |
| `` <space> `` | 切換預存 | 切換現有行的狀態 (已預存/未預存) |
| `` d `` | 刪除變更 (git reset) | 選取未暫存的變更時,使用 `git reset` 捨棄變更。選取已暫存的變更時,取消暫存變更。 |
| `` o `` | 開啟檔案 | 使用預設軟體開啟 |
| `` e `` | 編輯檔案 | 使用外部編輯器開啟 |
| `` <esc> `` | 返回檔案面板 | |
| `` <tab> `` | 切換至另一個面板 (已預存/未預存更改) | 切換到其他檢視(已暫存/未暫存的變更)。 |
| `` E `` | 編輯程式碼塊 | 在外部編輯器中編輯選中的程式碼塊。 |
| `` c `` | 提交變更 | 提交暫存區變更 |
| `` w `` | 沒有預提交 hook 就提交更改 | |
| `` C `` | 使用 git 編輯器提交變更 | |
| `` <ctrl+f> `` | 尋找 fixup 的基礎提交 | 找出目前變更所依據的提交,以便 amend/fixup。這樣不必逐一檢視分支中的提交來找出要 amend/fixup 的提交。請見文件:<https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md> |
| `` / `` | 搜尋 | |
## 功能表
+3 -33
View File
@@ -52,8 +52,7 @@ func (gui *Gui) resetHelpersAndControllers() {
gpgHelper := helpers.NewGpgHelper(helperCommon)
viewHelper := helpers.NewViewHelper(helperCommon, gui.State.Contexts)
patchBuildingHelper := helpers.NewPatchBuildingHelper(helperCommon)
stagingHelper := helpers.NewStagingHelper(helperCommon)
customPatchHelper := helpers.NewCustomPatchHelper(helperCommon)
mergeConflictsHelper := helpers.NewMergeConflictsHelper(helperCommon)
searchHelper := helpers.NewSearchHelper(helperCommon)
@@ -61,8 +60,6 @@ func (gui *Gui) resetHelpersAndControllers() {
helperCommon,
refsHelper,
rebaseHelper,
patchBuildingHelper,
stagingHelper,
mergeConflictsHelper,
worktreeHelper,
searchHelper,
@@ -78,7 +75,7 @@ func (gui *Gui) resetHelpersAndControllers() {
modeHelper := helpers.NewModeHelper(
helperCommon,
diffHelper,
patchBuildingHelper,
customPatchHelper,
cherryPickHelper,
rebaseHelper,
bisectHelper,
@@ -92,8 +89,7 @@ func (gui *Gui) resetHelpersAndControllers() {
gui.helpers = &helpers.Helpers{
Refs: refsHelper,
Host: helpers.NewHostHelper(helperCommon),
PatchBuilding: patchBuildingHelper,
Staging: stagingHelper,
CustomPatch: customPatchHelper,
Bisect: bisectHelper,
Suggestions: suggestionsHelper,
Files: helpers.NewFilesHelper(helperCommon),
@@ -183,12 +179,8 @@ func (gui *Gui) resetHelpersAndControllers() {
gitFlowController := controllers.NewGitFlowController(common)
stashController := controllers.NewStashController(common)
commitFilesController := controllers.NewCommitFilesController(common)
patchExplorerControllerFactory := controllers.NewPatchExplorerControllerFactory(common)
stagingController := controllers.NewStagingController(common, gui.State.Contexts.Staging, gui.State.Contexts.StagingSecondary, false)
stagingSecondaryController := controllers.NewStagingController(common, gui.State.Contexts.StagingSecondary, gui.State.Contexts.Staging, true)
mainViewController := controllers.NewMainViewController(common, gui.State.Contexts.Normal, gui.State.Contexts.NormalSecondary)
secondaryViewController := controllers.NewMainViewController(common, gui.State.Contexts.NormalSecondary, gui.State.Contexts.Normal)
patchBuildingController := controllers.NewPatchBuildingController(common)
snakeController := controllers.NewSnakeController(common)
reflogCommitsController := controllers.NewReflogCommitsController(common)
subCommitsController := controllers.NewSubCommitsController(common)
@@ -285,28 +277,6 @@ func (gui *Gui) resetHelpersAndControllers() {
)
// TODO: add scroll controllers for main panels (need to bring some more functionality across for that e.g. reading more from the currently displayed git command)
controllers.AttachControllers(gui.State.Contexts.Staging,
stagingController,
patchExplorerControllerFactory.Create(gui.State.Contexts.Staging),
verticalScrollControllerFactory.Create(gui.State.Contexts.Staging),
)
controllers.AttachControllers(gui.State.Contexts.StagingSecondary,
stagingSecondaryController,
patchExplorerControllerFactory.Create(gui.State.Contexts.StagingSecondary),
verticalScrollControllerFactory.Create(gui.State.Contexts.StagingSecondary),
)
controllers.AttachControllers(gui.State.Contexts.CustomPatchBuilder,
patchBuildingController,
patchExplorerControllerFactory.Create(gui.State.Contexts.CustomPatchBuilder),
verticalScrollControllerFactory.Create(gui.State.Contexts.CustomPatchBuilder),
)
controllers.AttachControllers(gui.State.Contexts.CustomPatchBuilderSecondary,
verticalScrollControllerFactory.Create(gui.State.Contexts.CustomPatchBuilderSecondary),
)
controllers.AttachControllers(gui.State.Contexts.MergeConflicts,
mergeConflictsController,
)
@@ -5,7 +5,6 @@ import (
"fmt"
"math"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
@@ -76,20 +75,12 @@ func (self *ContextLinesController) applyChange() error {
self.c.Toast(fmt.Sprintf(self.c.Tr.DiffContextSizeChanged, self.c.UserConfig().Git.DiffContextSize))
currentContext := self.c.Context().CurrentSide()
switch currentContext.GetKey() {
// we make an exception for our staging and patch building contexts because they actually need to refresh their state afterwards.
case context.PATCH_BUILDING_MAIN_CONTEXT_KEY:
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.PATCH_BUILDING}})
case context.STAGING_MAIN_CONTEXT_KEY, context.STAGING_SECONDARY_CONTEXT_KEY:
self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STAGING}})
default:
// The diff is about to be rendered again with more or less context around
// each change, which reads as the lines you were looking at moving up or down
// the view; keep them where they are instead.
self.c.Helpers().DiffLine.PreserveDiffPositionOnRerender(self.c.Contexts().Normal.GetView())
self.c.Helpers().DiffLine.PreserveDiffPositionOnRerender(self.c.Contexts().NormalSecondary.GetView())
currentContext.HandleRenderToMain()
}
// The diff is about to be rendered again with more or less context around
// each change, which reads as the lines you were looking at moving up or down
// the view; keep them where they are instead.
self.c.Helpers().DiffLine.PreserveDiffPositionOnRerender(self.c.Contexts().Normal.GetView())
self.c.Helpers().DiffLine.PreserveDiffPositionOnRerender(self.c.Contexts().NormalSecondary.GetView())
currentContext.HandleRenderToMain()
return nil
}
@@ -30,7 +30,7 @@ func (self *CustomPatchOptionsMenuAction) Call() error {
{
Label: self.c.Tr.ResetPatch,
Tooltip: self.c.Tr.ResetPatchTooltip,
OnPress: self.c.Helpers().PatchBuilding.Reset,
OnPress: self.c.Helpers().CustomPatch.Reset,
Keys: menuKey('c'),
},
{
@@ -123,15 +123,7 @@ func (self *CustomPatchOptionsMenuAction) getPatchCommitIndex() int {
return -1
}
func (self *CustomPatchOptionsMenuAction) returnFocusFromPatchExplorerIfNecessary() {
if self.c.Context().Current().GetKey() == self.c.Contexts().CustomPatchBuilder.GetKey() {
self.c.Helpers().PatchBuilding.Escape()
}
}
func (self *CustomPatchOptionsMenuAction) handleDeletePatchFromCommit() error {
self.returnFocusFromPatchExplorerIfNecessary()
commits := self.c.Model().Commits
commitIndex := self.getPatchCommitIndex()
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
@@ -142,8 +134,6 @@ func (self *CustomPatchOptionsMenuAction) handleDeletePatchFromCommit() error {
}
func (self *CustomPatchOptionsMenuAction) handleMovePatchToSelectedCommit() error {
self.returnFocusFromPatchExplorerIfNecessary()
commits := self.c.Model().Commits
commitIndex := self.getPatchCommitIndex()
toCommitIndex := self.c.Contexts().LocalCommits.GetSelectedLineIdx()
@@ -155,8 +145,6 @@ func (self *CustomPatchOptionsMenuAction) handleMovePatchToSelectedCommit() erro
}
func (self *CustomPatchOptionsMenuAction) handleMovePatchIntoWorkingTree() error {
self.returnFocusFromPatchExplorerIfNecessary()
mustStash := self.c.Helpers().WorkingTree.IsWorkingTreeDirtyExceptSubmodules()
return self.c.ConfirmIf(mustStash, types.ConfirmOpts{
Title: self.c.Tr.MustStashTitle,
@@ -174,8 +162,6 @@ func (self *CustomPatchOptionsMenuAction) handleMovePatchIntoWorkingTree() error
}
func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
self.returnFocusFromPatchExplorerIfNecessary()
commitIndex := self.getPatchCommitIndex()
self.c.Helpers().Commits.OpenCommitMessagePanel(
&helpers.OpenCommitMessagePanelOpts{
@@ -209,8 +195,6 @@ func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommit() error {
}
func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommitBefore() error {
self.returnFocusFromPatchExplorerIfNecessary()
commitIndex := self.getPatchCommitIndex()
self.c.Helpers().Commits.OpenCommitMessagePanel(
&helpers.OpenCommitMessagePanelOpts{
@@ -244,8 +228,6 @@ func (self *CustomPatchOptionsMenuAction) handlePullPatchIntoNewCommitBefore() e
}
func (self *CustomPatchOptionsMenuAction) handleApplyPatch(reverse bool) error {
self.returnFocusFromPatchExplorerIfNecessary()
affectedUnstagedFiles := self.getAffectedUnstagedFiles()
mustStageFiles := len(affectedUnstagedFiles) > 0
@@ -0,0 +1,25 @@
package helpers
import "github.com/jesseduffield/lazygit/pkg/gui/types"
type CustomPatchHelper struct {
c *HelperCommon
}
func NewCustomPatchHelper(c *HelperCommon) *CustomPatchHelper {
return &CustomPatchHelper{c: c}
}
func (self *CustomPatchHelper) Reset() error {
self.c.Git().Patch.PatchBuilder.Reset()
self.c.Refresh(types.RefreshOptions{
Scope: []types.RefreshableView{types.COMMIT_FILES},
})
// Render again so that the pane that was previewing the patch goes with it. The
// panel asked to do that is the side panel rather than whichever context has the
// focus. Both main panes are rendered by the panel beneath them, so a reset from
// within the focused main view has to go through that panel too.
self.c.PostRefreshUpdate(self.c.Context().CurrentSide())
return nil
}
+2 -4
View File
@@ -28,8 +28,7 @@ type Helpers struct {
MergeConflicts *MergeConflictsHelper
CherryPick *CherryPickHelper
Host *HostHelper
PatchBuilding *PatchBuildingHelper
Staging *StagingHelper
CustomPatch *CustomPatchHelper
GPG *GpgHelper
Upstream *UpstreamHelper
AmendHelper *AmendHelper
@@ -68,8 +67,7 @@ func NewStubHelpers() *Helpers {
MergeConflicts: &MergeConflictsHelper{},
CherryPick: &CherryPickHelper{},
Host: &HostHelper{},
PatchBuilding: &PatchBuildingHelper{},
Staging: &StagingHelper{},
CustomPatch: &CustomPatchHelper{},
GPG: &GpgHelper{},
Upstream: &UpstreamHelper{},
AmendHelper: &AmendHelper{},
+4 -4
View File
@@ -14,7 +14,7 @@ type ModeHelper struct {
c *HelperCommon
diffHelper *DiffHelper
patchBuildingHelper *PatchBuildingHelper
customPatchHelper *CustomPatchHelper
cherryPickHelper *CherryPickHelper
mergeAndRebaseHelper *MergeAndRebaseHelper
bisectHelper *BisectHelper
@@ -24,7 +24,7 @@ type ModeHelper struct {
func NewModeHelper(
c *HelperCommon,
diffHelper *DiffHelper,
patchBuildingHelper *PatchBuildingHelper,
customPatchHelper *CustomPatchHelper,
cherryPickHelper *CherryPickHelper,
mergeAndRebaseHelper *MergeAndRebaseHelper,
bisectHelper *BisectHelper,
@@ -32,7 +32,7 @@ func NewModeHelper(
return &ModeHelper{
c: c,
diffHelper: diffHelper,
patchBuildingHelper: patchBuildingHelper,
customPatchHelper: customPatchHelper,
cherryPickHelper: cherryPickHelper,
mergeAndRebaseHelper: mergeAndRebaseHelper,
bisectHelper: bisectHelper,
@@ -73,7 +73,7 @@ func (self *ModeHelper) Statuses() []ModeStatus {
CancelLabel: func() string {
return self.c.Tr.ExitCustomPatchBuilder
},
Reset: self.patchBuildingHelper.Reset,
Reset: self.customPatchHelper.Reset,
},
{
IsActive: self.c.Modes().Filtering.Active,
@@ -1,109 +0,0 @@
package helpers
import (
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/gui/patch_exploring"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type PatchBuildingHelper struct {
c *HelperCommon
}
func NewPatchBuildingHelper(
c *HelperCommon,
) *PatchBuildingHelper {
return &PatchBuildingHelper{
c: c,
}
}
// takes us from the patch building panel back to the commit files panel
func (self *PatchBuildingHelper) Escape() {
self.c.Context().Pop()
}
// kills the custom patch and returns us back to the commit files panel if needed
func (self *PatchBuildingHelper) Reset() error {
self.c.Git().Patch.PatchBuilder.Reset()
// The patch-building view is the one thing with nothing left to show once the patch is
// gone, so it is the one thing left behind. Everywhere else the user is looking at
// something of their own — a commit's diff, the working tree's — which is still there.
if self.c.Context().CurrentStatic().GetKey() == self.c.Contexts().CustomPatchBuilder.GetKey() {
self.Escape()
}
self.c.Refresh(types.RefreshOptions{
Scope: []types.RefreshableView{types.COMMIT_FILES},
})
// Render again so that the pane that was previewing the patch goes with it. The
// panel asked to do that is the side panel rather than whichever context has the
// focus. Both main panes are rendered by the panel beneath them, so a reset from
// within the focused main view has to go through that panel too.
self.c.PostRefreshUpdate(self.c.Context().CurrentSide())
return nil
}
func (self *PatchBuildingHelper) RefreshPatchBuildingPanel(opts types.OnFocusOpts) {
selectedLineIdx := -1
if opts.ClickedWindowName == "main" {
selectedLineIdx = opts.ClickedViewLineIdx
}
if !self.c.Git().Patch.PatchBuilder.Active() {
self.Escape()
return
}
// get diff from commit file that's currently selected
file := self.c.Contexts().CommitFiles.GetSelectedFile()
if file == nil {
return
}
from, to := self.c.Contexts().CommitFiles.GetFromAndToForDiff()
from, reverse := self.c.Modes().Diffing.GetFromAndReverseArgsForDiff(from)
diff, err := self.c.Git().WorkingTree.ShowFileDiff(from, to, reverse, file.Path, file.PreviousPath, git_commands.DiffModePlain)
if err != nil {
return
}
secondaryDiff := self.c.Git().Patch.PatchBuilder.RenderPatchForFile(patch.RenderPatchForFileOpts{
Filename: file.Path,
PreviousPath: file.PreviousPath,
Plain: false,
Reverse: false,
TurnAddedFilesIntoDiffAgainstEmptyFile: true,
})
context := self.c.Contexts().CustomPatchBuilder
oldState := context.GetState()
state := patch_exploring.NewState(diff, selectedLineIdx, context.GetView(), oldState, self.c.UserConfig().Gui.UseHunkModeInStagingView)
context.SetState(state)
if state == nil {
self.Escape()
return
}
mainContent := context.GetContentToRender()
self.c.Contexts().CustomPatchBuilder.FocusSelection()
self.c.RenderToMainViews(types.RefreshMainOpts{
Pair: self.c.MainViewPairs().PatchBuilding,
Main: &types.ViewUpdateOpts{
Task: types.NewRenderStringWithoutScrollTask(mainContent),
Title: self.c.Tr.Patch,
},
Secondary: &types.ViewUpdateOpts{
Task: types.NewRenderStringWithoutScrollTask(secondaryDiff),
Title: self.c.Tr.CustomPatch,
},
})
}
+1 -40
View File
@@ -30,8 +30,6 @@ type RefreshHelper struct {
c *HelperCommon
refsHelper *RefsHelper
mergeAndRebaseHelper *MergeAndRebaseHelper
patchBuildingHelper *PatchBuildingHelper
stagingHelper *StagingHelper
mergeConflictsHelper *MergeConflictsHelper
worktreeHelper *WorktreeHelper
searchHelper *SearchHelper
@@ -62,8 +60,6 @@ func NewRefreshHelper(
c *HelperCommon,
refsHelper *RefsHelper,
mergeAndRebaseHelper *MergeAndRebaseHelper,
patchBuildingHelper *PatchBuildingHelper,
stagingHelper *StagingHelper,
mergeConflictsHelper *MergeConflictsHelper,
worktreeHelper *WorktreeHelper,
searchHelper *SearchHelper,
@@ -72,8 +68,6 @@ func NewRefreshHelper(
c: c,
refsHelper: refsHelper,
mergeAndRebaseHelper: mergeAndRebaseHelper,
patchBuildingHelper: patchBuildingHelper,
stagingHelper: stagingHelper,
mergeConflictsHelper: mergeConflictsHelper,
worktreeHelper: worktreeHelper,
searchHelper: searchHelper,
@@ -248,8 +242,6 @@ func (self *RefreshHelper) performRefresh(options types.RefreshOptions, calledFr
var scopeSet *set.Set[types.RefreshableView]
if len(options.Scope) == 0 {
// not refreshing staging/patch-building unless explicitly requested because we only need
// to refresh those while focused.
scopeSet = set.NewFromSlice([]types.RefreshableView{
types.COMMITS,
types.BRANCHES,
@@ -261,7 +253,6 @@ func (self *RefreshHelper) performRefresh(options types.RefreshOptions, calledFr
types.WORKTREES,
types.STATUS,
types.BISECT_INFO,
types.STAGING,
types.PULL_REQUESTS,
})
} else {
@@ -516,37 +507,9 @@ func (self *RefreshHelper) performRefresh(options types.RefreshOptions, calledFr
})
}
if scopeSet.Includes(types.STAGING) {
refresh("staging", func() {
fileWg.Wait()
// Bounce onto the UI thread so this runs after the files
// scope's model-update bounce — RefreshStagingPanel reads
// Model.Files (via Files.GetSelected) and would otherwise
// see the pre-refresh model. Guard on the generation so a
// repo switch mid-refresh drops it, like the model bounces.
self.onUIThreadUnlessRepoChanged(env, func() {
self.stagingHelper.RefreshStagingPanel(types.OnFocusOpts{})
})
})
}
if scopeSet.Includes(types.PATCH_BUILDING) {
refresh("patch building", func() {
// Bounce onto the UI thread, like the staging panel above:
// RefreshPatchBuildingPanel reads the commit-files selection and
// sets the patch view's origin, neither of which may run off the UI
// thread. Guard on the generation so a repo switch mid-refresh drops
// it, like the model bounces.
self.onUIThreadUnlessRepoChanged(env, func() {
self.patchBuildingHelper.RefreshPatchBuildingPanel(types.OnFocusOpts{})
})
})
}
if scopeSet.Includes(types.MERGE_CONFLICTS) {
refresh("merge conflicts", func() {
// Bounce onto the UI thread, like the staging and patch-building
// panels above: RefreshMergeState reads the current context and
// Bounce onto the UI thread: RefreshMergeState reads the current context and
// renders (or escapes) the merge-conflicts view, none of which may
// run off the UI thread.
self.onUIThreadUnlessRepoChanged(env, func() {
@@ -676,8 +639,6 @@ func getScopeNames(scopes []types.RefreshableView) []string {
types.WORKTREES: "worktrees",
types.STATUS: "status",
types.BISECT_INFO: "bisect",
types.STAGING: "staging",
types.PATCH_BUILDING: "patchBuilding",
types.MERGE_CONFLICTS: "mergeConflicts",
types.COMMIT_FILES: "commitFiles",
types.PULL_REQUESTS: "pullRequests",
@@ -50,7 +50,6 @@ func (self *RefsHelper) CheckoutRef(ref string, options types.CheckoutRefOptions
types.REFLOG,
types.WORKTREES,
types.BISECT_INFO,
types.STAGING,
}
if options.RefreshPullRequests {
scope = append(scope, types.PULL_REQUESTS)
@@ -1,128 +0,0 @@
package helpers
import (
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/patch_exploring"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type StagingHelper struct {
c *HelperCommon
}
func NewStagingHelper(
c *HelperCommon,
) *StagingHelper {
return &StagingHelper{
c: c,
}
}
// NOTE: used from outside this file
func (self *StagingHelper) RefreshStagingPanel(focusOpts types.OnFocusOpts) {
secondaryFocused := self.secondaryStagingFocused()
mainFocused := self.mainStagingFocused()
// this method could be called when the staging panel is not being used,
// in which case we don't want to do anything.
if !mainFocused && !secondaryFocused {
return
}
mainSelectedLineIdx := -1
secondarySelectedLineIdx := -1
if focusOpts.ClickedViewLineIdx > 0 {
if secondaryFocused {
secondarySelectedLineIdx = focusOpts.ClickedViewLineIdx
} else {
mainSelectedLineIdx = focusOpts.ClickedViewLineIdx
}
}
mainContext := self.c.Contexts().Staging
secondaryContext := self.c.Contexts().StagingSecondary
var file *models.File
node := self.c.Contexts().Files.GetSelected()
if node != nil {
file = node.File
}
if file == nil || (!file.HasUnstagedChanges && !file.HasStagedChanges) {
self.handleStagingEscape()
return
}
mainDiff := self.c.Git().WorkingTree.WorktreeFileDiff(file, git_commands.DiffModePlain, false)
secondaryDiff := self.c.Git().WorkingTree.WorktreeFileDiff(file, git_commands.DiffModePlain, true)
// grabbing locks here and releasing before we finish the function
// because pushing say the secondary context could mean entering this function
// again, and we don't want to have a deadlock
mainContext.GetMutex().Lock()
secondaryContext.GetMutex().Lock()
hunkMode := self.c.UserConfig().Gui.UseHunkModeInStagingView
mainContext.SetState(
patch_exploring.NewState(mainDiff, mainSelectedLineIdx, mainContext.GetView(), mainContext.GetState(), hunkMode),
)
secondaryContext.SetState(
patch_exploring.NewState(secondaryDiff, secondarySelectedLineIdx, secondaryContext.GetView(), secondaryContext.GetState(), hunkMode),
)
mainState := mainContext.GetState()
secondaryState := secondaryContext.GetState()
mainContent := mainContext.GetContentToRender()
secondaryContent := secondaryContext.GetContentToRender()
mainContext.GetMutex().Unlock()
secondaryContext.GetMutex().Unlock()
if mainState == nil && secondaryState == nil {
self.handleStagingEscape()
return
}
if mainState == nil && !secondaryFocused {
self.c.Context().Push(secondaryContext, focusOpts)
return
}
if secondaryState == nil && secondaryFocused {
self.c.Context().Push(mainContext, focusOpts)
return
}
if secondaryFocused {
self.c.Contexts().StagingSecondary.FocusSelection()
} else {
self.c.Contexts().Staging.FocusSelection()
}
self.c.RenderToMainViews(types.RefreshMainOpts{
Pair: self.c.MainViewPairs().Staging,
Main: &types.ViewUpdateOpts{
Task: types.NewRenderStringWithoutScrollTask(mainContent),
Title: self.c.Tr.UnstagedChanges,
},
Secondary: &types.ViewUpdateOpts{
Task: types.NewRenderStringWithoutScrollTask(secondaryContent),
Title: self.c.Tr.StagedChanges,
},
})
}
func (self *StagingHelper) handleStagingEscape() {
self.c.Context().Push(self.c.Contexts().Files, types.OnFocusOpts{})
}
func (self *StagingHelper) secondaryStagingFocused() bool {
return self.c.Context().CurrentStatic().GetKey() == self.c.Contexts().StagingSecondary.GetKey()
}
func (self *StagingHelper) mainStagingFocused() bool {
return self.c.Context().CurrentStatic().GetKey() == self.c.Contexts().Staging.GetKey()
}
@@ -1,277 +0,0 @@
package controllers
import (
"fmt"
"github.com/jesseduffield/lazygit/pkg/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/samber/lo"
)
type PatchBuildingController struct {
baseController
c *ControllerCommon
}
var _ types.IController = &PatchBuildingController{}
func NewPatchBuildingController(
c *ControllerCommon,
) *PatchBuildingController {
return &PatchBuildingController{
baseController: baseController{},
c: c,
}
}
func (self *PatchBuildingController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
return []*types.Binding{
{
Keys: opts.GetKeys(opts.Config.Universal.OpenFile),
Handler: self.OpenFile,
Description: self.c.Tr.OpenFile,
Tooltip: self.c.Tr.OpenFileTooltip,
},
{
Keys: opts.GetKeys(opts.Config.Universal.Edit),
Handler: self.EditFile,
Description: self.c.Tr.EditFile,
Tooltip: self.c.Tr.EditFileTooltip,
},
{
Keys: opts.GetKeys(opts.Config.Universal.Select),
Handler: self.ToggleSelectionAndRefresh,
Description: self.c.Tr.ToggleSelectionForPatch,
DisplayOnScreen: true,
},
{
Keys: opts.GetKeys(opts.Config.Universal.Remove),
Handler: self.discardSelection,
GetDisabledReason: self.getDisabledReasonForDiscard,
Description: self.c.Tr.RemoveSelectionFromPatch,
Tooltip: self.c.Tr.RemoveSelectionFromPatchTooltip,
DisplayOnScreen: true,
},
{
Keys: opts.GetKeys(opts.Config.Universal.Return),
Handler: self.Escape,
Description: self.c.Tr.ExitCustomPatchBuilder,
DescriptionFunc: self.EscapeDescription,
DisplayOnScreen: true,
},
}
}
func (self *PatchBuildingController) Context() types.Context {
return self.c.Contexts().CustomPatchBuilder
}
func (self *PatchBuildingController) context() types.IPatchExplorerContext {
return self.c.Contexts().CustomPatchBuilder
}
func (self *PatchBuildingController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return []*gocui.ViewMouseBinding{}
}
func (self *PatchBuildingController) GetOnFocus() func(types.OnFocusOpts) {
return func(opts types.OnFocusOpts) {
// no need to change wrap on the secondary view because it can't be interacted with
self.c.Views().PatchBuilding.Wrap = self.c.UserConfig().Gui.WrapLinesInStagingView
self.c.Helpers().PatchBuilding.RefreshPatchBuildingPanel(opts)
}
}
func (self *PatchBuildingController) GetOnFocusLost() func(types.OnFocusLostOpts) {
return func(opts types.OnFocusLostOpts) {
self.context().SetState(nil)
self.c.Views().PatchBuilding.Wrap = true
if self.c.Git().Patch.PatchBuilder.IsEmpty() {
self.c.Git().Patch.PatchBuilder.Reset()
}
}
}
func (self *PatchBuildingController) OpenFile() error {
self.context().GetMutex().Lock()
defer self.context().GetMutex().Unlock()
path := self.c.Contexts().CommitFiles.GetSelectedPath()
if path == "" {
return nil
}
return self.c.Helpers().Files.OpenFile(path)
}
func (self *PatchBuildingController) EditFile() error {
self.context().GetMutex().Lock()
defer self.context().GetMutex().Unlock()
path := self.c.Contexts().CommitFiles.GetSelectedPath()
if path == "" {
return nil
}
lineNumber := self.context().GetState().CurrentLineNumber()
lineNumber = self.c.Helpers().Diff.AdjustLineNumber(path, lineNumber, self.context().GetViewName())
return self.c.Helpers().Files.EditFileAtLine(path, lineNumber)
}
func (self *PatchBuildingController) ToggleSelectionAndRefresh() error {
if err := self.toggleSelection(); err != nil {
return err
}
self.c.Refresh(types.RefreshOptions{
Scope: []types.RefreshableView{types.PATCH_BUILDING, types.COMMIT_FILES},
})
return nil
}
func (self *PatchBuildingController) toggleSelection() error {
self.context().GetMutex().Lock()
defer self.context().GetMutex().Unlock()
file := self.c.Contexts().CommitFiles.GetSelectedFile()
if file == nil {
return nil
}
state := self.context().GetState()
// Get added/deleted lines in the selected patch range
lineIndicesToToggle := state.LineIndicesOfAddedOrDeletedLinesInSelectedPatchRange()
if len(lineIndicesToToggle) == 0 {
// Only context lines or header lines selected, so nothing to do
return nil
}
includedLineIndices, err := self.c.Git().Patch.PatchBuilder.GetFileIncLineIndices(file.Path, file.PreviousPath)
if err != nil {
return err
}
toggleFunc := self.c.Git().Patch.PatchBuilder.AddFileLineRange
firstSelectedChangeLineIsStaged := lo.Contains(includedLineIndices, lineIndicesToToggle[0])
if firstSelectedChangeLineIsStaged {
toggleFunc = self.c.Git().Patch.PatchBuilder.RemoveFileLineRange
}
// add range of lines to those set for the file
if err := toggleFunc(file.Path, file.PreviousPath, lineIndicesToToggle); err != nil {
// might actually want to return an error here
self.c.Log.Error(err)
}
if state.SelectingRange() {
state.SetLineSelectMode()
}
state.SelectNextStageableLineOfSameIncludedState(self.context().GetIncludedLineIndices(), firstSelectedChangeLineIsStaged)
return nil
}
func (self *PatchBuildingController) getDisabledReasonForDiscard() *types.DisabledReason {
if !self.c.Git().Patch.PatchBuilder.CanRebase {
return &types.DisabledReason{Text: self.c.Tr.CanOnlyDiscardFromLocalCommits, ShowErrorInPanel: true}
}
if self.c.Git().Status.WorkingTreeState().Any() {
return &types.DisabledReason{Text: self.c.Tr.CantPatchWhileRebasingError, ShowErrorInPanel: true}
}
if self.c.UserConfig().Git.DiffContextSize == 0 {
text := fmt.Sprintf(self.c.Tr.Actions.NotEnoughContextToRemoveLines,
self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView)
return &types.DisabledReason{Text: text, ShowErrorInPanel: true}
}
return nil
}
func (self *PatchBuildingController) discardSelection() error {
prompt := lo.Ternary(self.c.Git().Patch.PatchBuilder.IsEmpty(),
self.c.Tr.DiscardLinesFromCommitPrompt,
self.c.Tr.DiscardLinesFromCommitPromptWithReset)
self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.DiscardLinesFromCommitTitle,
Prompt: prompt,
HandleConfirm: func() error {
return self.discardSelectionFromCommit()
},
})
return nil
}
func (self *PatchBuildingController) discardSelectionFromCommit() error {
// Reset the current patch if there is one.
if !self.c.Git().Patch.PatchBuilder.IsEmpty() {
self.c.Git().Patch.PatchBuilder.Reset()
}
if err := self.toggleSelection(); err != nil {
return err
}
if self.c.Git().Patch.PatchBuilder.IsEmpty() {
return nil
}
commits := self.c.Model().Commits
commitIndex := self.getPatchCommitIndex()
return self.c.WithWaitingStatus(self.c.Tr.RebasingStatus, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.RemovePatchFromCommit)
err := self.c.Git().Patch.DeletePatchesFromCommit(commits, commitIndex)
// Escape pops the patch-building context, so run it on the UI thread
// before the refresh below.
_ = self.c.GocuiGui().OnUIThreadAndWait(func() {
self.c.Helpers().PatchBuilding.Escape()
})
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebaseWithRefreshOptions(
err, types.RefreshOptions{})
})
}
func (self *PatchBuildingController) getPatchCommitIndex() int {
for index, commit := range self.c.Model().Commits {
if commit.Hash() == self.c.Git().Patch.PatchBuilder.To {
return index
}
}
return -1
}
func (self *PatchBuildingController) Escape() error {
context := self.c.Contexts().CustomPatchBuilder
state := context.GetState()
if state.SelectingRange() || state.SelectingHunkEnabledByUser() {
state.SetLineSelectMode()
self.c.PostRefreshUpdate(context)
return nil
}
self.c.Helpers().PatchBuilding.Escape()
return nil
}
func (self *PatchBuildingController) EscapeDescription() string {
context := self.c.Contexts().CustomPatchBuilder
if state := context.GetState(); state != nil {
if state.SelectingRange() {
return self.c.Tr.DismissRangeSelect
}
if state.SelectingHunkEnabledByUser() {
return self.c.Tr.SelectLineByLine
}
}
return self.c.Tr.ExitCustomPatchBuilder
}
@@ -1,377 +0,0 @@
package controllers
import (
"github.com/jesseduffield/lazygit/pkg/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type PatchExplorerControllerFactory struct {
c *ControllerCommon
}
func NewPatchExplorerControllerFactory(c *ControllerCommon) *PatchExplorerControllerFactory {
return &PatchExplorerControllerFactory{
c: c,
}
}
func (self *PatchExplorerControllerFactory) Create(context types.IPatchExplorerContext) *PatchExplorerController {
controller := &PatchExplorerController{
baseController: baseController{},
c: self.c,
context: context,
}
controller.dragAutoscroller = helpers.NewDragAutoscroller(
self.c.HelperCommon,
context,
controller.canDragAutoscroll,
controller.handleDragAutoscroll,
)
return controller
}
type PatchExplorerController struct {
baseController
c *ControllerCommon
context types.IPatchExplorerContext
dragAutoscroller *helpers.DragAutoscroller
draggingWithMouse bool
}
func (self *PatchExplorerController) Context() types.Context {
return self.context
}
func (self *PatchExplorerController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
return []*types.Binding{
{
Tag: "navigation",
Keys: opts.GetKeys(opts.Config.Universal.PrevItem),
Handler: self.withRenderAndFocus(self.HandlePrevLine),
},
{
Tag: "navigation",
Keys: opts.GetKeys(opts.Config.Universal.NextItem),
Handler: self.withRenderAndFocus(self.HandleNextLine),
},
{
Tag: "navigation",
Keys: opts.GetKeys(opts.Config.Universal.RangeSelectUp),
Handler: self.withRenderAndFocus(self.HandlePrevLineRange),
Description: self.c.Tr.RangeSelectUp,
},
{
Tag: "navigation",
Keys: opts.GetKeys(opts.Config.Universal.RangeSelectDown),
Handler: self.withRenderAndFocus(self.HandleNextLineRange),
Description: self.c.Tr.RangeSelectDown,
},
{
Keys: opts.GetKeys(opts.Config.Main.PrevHunk),
Handler: self.withRenderAndFocus(self.HandlePrevHunk),
Description: self.c.Tr.PrevHunk,
},
{
Keys: opts.GetKeys(opts.Config.Main.NextHunk),
Handler: self.withRenderAndFocus(self.HandleNextHunk),
Description: self.c.Tr.NextHunk,
},
{
Keys: opts.GetKeys(opts.Config.Universal.ToggleRangeSelect),
Handler: self.withRenderAndFocus(self.HandleToggleSelectRange),
Description: self.c.Tr.ToggleRangeSelect,
},
{
Keys: opts.GetKeys(opts.Config.Main.ToggleSelectHunk),
Handler: self.withRenderAndFocus(self.HandleToggleSelectHunk),
Description: self.c.Tr.ToggleSelectHunk,
DescriptionFunc: func() string {
if state := self.context.GetState(); state != nil && state.SelectingHunk() {
return self.c.Tr.SelectLineByLine
}
return self.c.Tr.SelectHunk
},
Tooltip: self.c.Tr.ToggleSelectHunkTooltip,
DisplayOnScreen: true,
},
{
Tag: "navigation",
Keys: opts.GetKeys(opts.Config.Universal.PrevPage),
Handler: self.withRenderAndFocus(self.HandlePrevPage),
Description: self.c.Tr.PrevPage,
},
{
Tag: "navigation",
Keys: opts.GetKeys(opts.Config.Universal.NextPage),
Handler: self.withRenderAndFocus(self.HandleNextPage),
Description: self.c.Tr.NextPage,
},
{
Tag: "navigation",
Keys: opts.GetKeys(opts.Config.Universal.GotoTop),
Handler: self.withRenderAndFocus(self.HandleGotoTop),
Description: self.c.Tr.GotoTop,
},
{
Tag: "navigation",
Keys: opts.GetKeys(opts.Config.Universal.GotoBottom),
Description: self.c.Tr.GotoBottom,
Handler: self.withRenderAndFocus(self.HandleGotoBottom),
},
{
Tag: "navigation",
Keys: opts.GetKeys(opts.Config.Universal.ScrollLeft),
Handler: self.withRenderAndFocus(self.HandleScrollLeft),
},
{
Tag: "navigation",
Keys: opts.GetKeys(opts.Config.Universal.ScrollRight),
Handler: self.withRenderAndFocus(self.HandleScrollRight),
},
{
Keys: opts.GetKeys(opts.Config.Universal.CopyToClipboard),
Handler: self.withLock(self.CopySelectedToClipboard),
Description: self.c.Tr.CopySelectedTextToClipboard,
},
}
}
func (self *PatchExplorerController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return []*gocui.ViewMouseBinding{
{
ViewName: self.context.GetViewName(),
Key: gocui.MouseLeft,
Handler: func(opts gocui.ViewMouseBindingOpts) error {
if self.isFocused() {
return self.withRenderAndFocus(self.HandleMouseDown)()
}
self.c.Context().Push(self.context, types.OnFocusOpts{
ClickedWindowName: self.context.GetWindowName(),
ClickedViewLineIdx: opts.Y,
})
return nil
},
},
{
ViewName: self.context.GetViewName(),
Key: gocui.MouseLeft,
Modifier: gocui.ModMotion,
Handler: self.handleMouseDrag,
},
{
ViewName: self.context.GetViewName(),
Key: gocui.MouseRelease,
Handler: func(gocui.ViewMouseBindingOpts) error { return self.handleDragRelease() },
},
}
}
func (self *PatchExplorerController) handleMouseDrag(opts gocui.ViewMouseBindingOpts) error {
if err := self.withLock(func() error {
self.context.GetState().DragSelectLine(opts.Y)
self.renderDragSelection()
return nil
})(); err != nil {
return err
}
self.draggingWithMouse = true
originY, _ := self.context.GetViewTrait().ViewPortYBounds()
self.dragAutoscroller.Update(opts.Y - originY)
return nil
}
func (self *PatchExplorerController) canDragAutoscroll(int) bool {
state := self.context.GetState()
return state != nil && state.SelectingRange()
}
func (self *PatchExplorerController) handleDragAutoscroll(viewIndex int) bool {
if !self.canDragAutoscroll(0) {
return false
}
if err := self.withLock(func() error {
self.context.GetState().DragSelectLine(viewIndex)
self.renderDragSelection()
return nil
})(); err != nil {
return false
}
return true
}
func (self *PatchExplorerController) renderDragSelection() {
view := self.context.GetView()
state := self.context.GetState()
originY := view.OriginY()
startIndex, _ := state.SelectedViewRange()
view.SetRangeSelectStart(startIndex)
view.SetCursorY(state.GetSelectedViewLineIdx() - originY)
self.context.Render()
}
func (self *PatchExplorerController) handleDragRelease() error {
self.draggingWithMouse = false
self.dragAutoscroller.Cancel()
return nil
}
func (self *PatchExplorerController) GetOnFocusLost() func(types.OnFocusLostOpts) {
return func(types.OnFocusLostOpts) {
self.dragAutoscroller.Cancel()
if self.draggingWithMouse {
self.draggingWithMouse = false
self.c.GocuiGui().CancelMouseCapture()
}
}
}
func (self *PatchExplorerController) HandlePrevLine() error {
before := self.context.GetState().GetSelectedViewLineIdx()
self.context.GetState().CycleSelection(false)
after := self.context.GetState().GetSelectedViewLineIdx()
if self.context.GetState().SelectingLine() {
checkScrollUp(self.context.GetViewTrait(), self.c.UserConfig(), before, after)
}
return nil
}
func (self *PatchExplorerController) HandleNextLine() error {
before := self.context.GetState().GetSelectedViewLineIdx()
self.context.GetState().CycleSelection(true)
after := self.context.GetState().GetSelectedViewLineIdx()
if self.context.GetState().SelectingLine() {
checkScrollDown(self.context.GetViewTrait(), self.c.UserConfig(), before, after)
}
return nil
}
func (self *PatchExplorerController) HandlePrevLineRange() error {
s := self.context.GetState()
s.CycleRange(false)
return nil
}
func (self *PatchExplorerController) HandleNextLineRange() error {
s := self.context.GetState()
s.CycleRange(true)
return nil
}
func (self *PatchExplorerController) HandlePrevHunk() error {
self.context.GetState().SelectPreviousHunk()
return nil
}
func (self *PatchExplorerController) HandleNextHunk() error {
self.context.GetState().SelectNextHunk()
return nil
}
func (self *PatchExplorerController) HandleToggleSelectRange() error {
self.context.GetState().ToggleStickySelectRange()
return nil
}
func (self *PatchExplorerController) HandleToggleSelectHunk() error {
self.context.GetState().ToggleSelectHunk()
return nil
}
func (self *PatchExplorerController) HandleScrollLeft() error {
self.context.GetViewTrait().ScrollLeft()
return nil
}
func (self *PatchExplorerController) HandleScrollRight() error {
self.context.GetViewTrait().ScrollRight()
return nil
}
func (self *PatchExplorerController) HandlePrevPage() error {
self.context.GetState().AdjustSelectedLineIdx(-self.context.GetViewTrait().PageDelta())
return nil
}
func (self *PatchExplorerController) HandleNextPage() error {
self.context.GetState().AdjustSelectedLineIdx(self.context.GetViewTrait().PageDelta())
return nil
}
func (self *PatchExplorerController) HandleGotoTop() error {
self.context.GetState().SelectTop()
return nil
}
func (self *PatchExplorerController) HandleGotoBottom() error {
self.context.GetState().SelectBottom()
return nil
}
func (self *PatchExplorerController) HandleMouseDown() error {
self.context.GetState().SelectNewLineForRange(self.context.GetViewTrait().SelectedLineIdx())
return nil
}
func (self *PatchExplorerController) CopySelectedToClipboard() error {
selected := self.context.GetState().PlainRenderSelected()
self.c.LogAction(self.c.Tr.Actions.CopySelectedTextToClipboard)
if err := self.c.OS().CopyToClipboard(dropDiffPrefix(selected)); err != nil {
return err
}
return nil
}
func (self *PatchExplorerController) isFocused() bool {
return self.c.Context().Current().GetKey() == self.context.GetKey()
}
func (self *PatchExplorerController) withRenderAndFocus(f func() error) func() error {
return self.withLock(func() error {
if err := f(); err != nil {
return err
}
self.context.RenderAndFocus()
return nil
})
}
func (self *PatchExplorerController) withLock(f func() error) func() error {
return func() error {
self.context.GetMutex().Lock()
defer self.context.GetMutex().Unlock()
if self.context.GetState() == nil {
return nil
}
return f()
}
}
-358
View File
@@ -1,358 +0,0 @@
package controllers
import (
"fmt"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/git_commands"
"github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type StagingController struct {
baseController
c *ControllerCommon
context types.IPatchExplorerContext
otherContext types.IPatchExplorerContext
// if true, we're dealing with the secondary context i.e. dealing with staged file changes
staged bool
}
var _ types.IController = &StagingController{}
func NewStagingController(
c *ControllerCommon,
context types.IPatchExplorerContext,
otherContext types.IPatchExplorerContext,
staged bool,
) *StagingController {
return &StagingController{
baseController: baseController{},
c: c,
context: context,
otherContext: otherContext,
staged: staged,
}
}
func (self *StagingController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
return []*types.Binding{
{
Keys: opts.GetKeys(opts.Config.Universal.Select),
Handler: self.ToggleStaged,
Description: self.c.Tr.Stage,
Tooltip: self.c.Tr.StageSelectionTooltip,
DisplayOnScreen: true,
},
{
Keys: opts.GetKeys(opts.Config.Universal.Remove),
Handler: self.DiscardSelection,
Description: self.c.Tr.DiscardSelection,
Tooltip: self.c.Tr.DiscardSelectionTooltip,
DisplayOnScreen: true,
},
{
Keys: opts.GetKeys(opts.Config.Universal.OpenFile),
Handler: self.OpenFile,
Description: self.c.Tr.OpenFile,
Tooltip: self.c.Tr.OpenFileTooltip,
},
{
Keys: opts.GetKeys(opts.Config.Universal.Edit),
Handler: self.EditFile,
Description: self.c.Tr.EditFile,
Tooltip: self.c.Tr.EditFileTooltip,
},
{
Keys: opts.GetKeys(opts.Config.Universal.Return),
Handler: self.Escape,
Description: self.c.Tr.ReturnToFilesPanel,
DescriptionFunc: self.EscapeDescription,
DisplayOnScreen: true,
},
{
Keys: opts.GetKeys(opts.Config.Universal.TogglePanel),
Handler: self.TogglePanel,
Description: self.c.Tr.ToggleStagingView,
Tooltip: self.c.Tr.ToggleStagingViewTooltip,
DisplayOnScreen: true,
},
{
Keys: opts.GetKeys(opts.Config.Main.EditSelectHunk),
Handler: self.EditHunkAndRefresh,
Description: self.c.Tr.EditHunk,
Tooltip: self.c.Tr.EditHunkTooltip,
},
{
Keys: opts.GetKeys(opts.Config.Files.CommitChanges),
Handler: self.c.Helpers().WorkingTree.HandleCommitPress,
Description: self.c.Tr.Commit,
Tooltip: self.c.Tr.CommitTooltip,
},
{
Keys: opts.GetKeys(opts.Config.Files.CommitChangesWithoutHook),
Handler: self.c.Helpers().WorkingTree.HandleWIPCommitPress,
Description: self.c.Tr.CommitChangesWithoutHook,
},
{
Keys: opts.GetKeys(opts.Config.Files.CommitChangesWithEditor),
Handler: self.c.Helpers().WorkingTree.HandleCommitEditorPress,
Description: self.c.Tr.CommitChangesWithEditor,
},
{
Keys: opts.GetKeys(opts.Config.Files.FindBaseCommitForFixup),
Handler: self.c.Helpers().FixupHelper.HandleFindBaseCommitForFixupPress,
Description: self.c.Tr.FindBaseCommitForFixup,
Tooltip: self.c.Tr.FindBaseCommitForFixupTooltip,
},
}
}
func (self *StagingController) Context() types.Context {
return self.context
}
func (self *StagingController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return []*gocui.ViewMouseBinding{}
}
func (self *StagingController) GetOnFocus() func(types.OnFocusOpts) {
return func(opts types.OnFocusOpts) {
wrap := self.c.UserConfig().Gui.WrapLinesInStagingView
self.c.Views().Staging.Wrap = wrap
self.c.Views().StagingSecondary.Wrap = wrap
self.c.Helpers().Staging.RefreshStagingPanel(opts)
}
}
func (self *StagingController) GetOnFocusLost() func(types.OnFocusLostOpts) {
return func(opts types.OnFocusLostOpts) {
self.context.SetState(nil)
if opts.NewContextKey != self.otherContext.GetKey() {
self.c.Views().Staging.Wrap = true
self.c.Views().StagingSecondary.Wrap = true
}
}
}
func (self *StagingController) OpenFile() error {
self.context.GetMutex().Lock()
defer self.context.GetMutex().Unlock()
path := self.FilePath()
if path == "" {
return nil
}
return self.c.Helpers().Files.OpenFile(path)
}
func (self *StagingController) EditFile() error {
self.context.GetMutex().Lock()
defer self.context.GetMutex().Unlock()
path := self.FilePath()
if path == "" {
return nil
}
lineNumber := self.context.GetState().CurrentLineNumber()
lineNumber = self.c.Helpers().Diff.AdjustLineNumber(path, lineNumber, self.context.GetViewName())
return self.c.Helpers().Files.EditFileAtLine(path, lineNumber)
}
func (self *StagingController) Escape() error {
if self.context.GetState().SelectingRange() || self.context.GetState().SelectingHunkEnabledByUser() {
self.context.GetState().SetLineSelectMode()
self.c.PostRefreshUpdate(self.context)
return nil
}
self.c.Context().Pop()
return nil
}
func (self *StagingController) EscapeDescription() string {
if state := self.context.GetState(); state != nil {
if state.SelectingRange() {
return self.c.Tr.DismissRangeSelect
}
if state.SelectingHunkEnabledByUser() {
return self.c.Tr.SelectLineByLine
}
}
return self.c.Tr.ReturnToFilesPanel
}
func (self *StagingController) TogglePanel() error {
if self.otherContext.GetState() != nil {
self.c.Context().Push(self.otherContext, types.OnFocusOpts{})
}
return nil
}
func (self *StagingController) ToggleStaged() error {
if self.c.UserConfig().Git.DiffContextSize == 0 {
return fmt.Errorf(self.c.Tr.Actions.NotEnoughContextToStage,
self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView)
}
return self.applySelectionAndRefresh(self.staged)
}
func (self *StagingController) DiscardSelection() error {
if self.c.UserConfig().Git.DiffContextSize == 0 {
return fmt.Errorf(self.c.Tr.Actions.NotEnoughContextToDiscard,
self.c.UserConfig().Keybinding.Universal.IncreaseContextInDiffView)
}
return self.c.ConfirmIf(!self.staged && !self.c.UserConfig().Gui.SkipDiscardChangeWarning,
types.ConfirmOpts{
Title: self.c.Tr.DiscardChangeTitle,
Prompt: self.c.Tr.DiscardChangePrompt,
HandleConfirm: func() error { return self.applySelectionAndRefresh(true) },
})
}
func (self *StagingController) applySelectionAndRefresh(reverse bool) error {
if err := self.applySelection(reverse); err != nil {
return err
}
// Block input until the refresh has landed: it rebuilds the staging panel
// and moves the selection to the next stageable change, and a quick second
// keypress must act on that, not on the stale pre-refresh diff.
self.c.RefreshBlockingInput(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES, types.STAGING}})
return nil
}
func (self *StagingController) applySelection(reverse bool) error {
self.context.GetMutex().Lock()
defer self.context.GetMutex().Unlock()
state := self.context.GetState()
path := self.FilePath()
if path == "" {
return nil
}
firstLineIdx, lastLineIdx := state.SelectedPatchRange()
patchToApply := patch.
Parse(state.GetDiff()).
Transform(patch.TransformOpts{
Reverse: reverse,
IncludedLineIndices: patch.ExpandRange(firstLineIdx, lastLineIdx),
FileNameOverride: path,
}).
FormatPlain()
if patchToApply == "" {
return nil
}
// apply the patch then refresh this panel
// create a new temp file with the patch, then call git apply with that patch
self.c.LogAction(self.c.Tr.Actions.ApplyPatch)
err := self.c.Git().Patch.ApplyPatch(
patchToApply,
git_commands.ApplyPatchOpts{
Reverse: reverse,
Cached: !reverse || self.staged,
},
)
if err != nil {
return err
}
if state.SelectingRange() {
firstLine, _ := state.SelectedViewRange()
state.SelectLine(firstLine)
}
return nil
}
func (self *StagingController) EditHunkAndRefresh() error {
if err := self.editHunk(); err != nil {
return err
}
// Block input like applySelectionAndRefresh does; the refresh rebuilds the
// staging panel from the post-edit diff.
self.c.RefreshBlockingInput(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES, types.STAGING}})
return nil
}
func (self *StagingController) editHunk() error {
self.context.GetMutex().Lock()
defer self.context.GetMutex().Unlock()
state := self.context.GetState()
path := self.FilePath()
if path == "" {
return nil
}
hunkStartIdx, hunkEndIdx := state.CurrentHunkBounds()
patchText := patch.
Parse(state.GetDiff()).
Transform(patch.TransformOpts{
Reverse: self.staged,
IncludedLineIndices: patch.ExpandRange(hunkStartIdx, hunkEndIdx),
FileNameOverride: path,
}).
FormatPlain()
patchFilepath, err := self.c.Git().Patch.SaveTemporaryPatch(patchText)
if err != nil {
return err
}
lineOffset := 3
lineIdxInHunk := state.GetSelectedPatchLineIdx() - hunkStartIdx
if err := self.c.Helpers().Files.EditFileAtLineAndWait(patchFilepath, lineIdxInHunk+lineOffset); err != nil {
return err
}
editedPatchText, err := self.c.Git().File.Cat(patchFilepath)
if err != nil {
return err
}
self.c.LogAction(self.c.Tr.Actions.ApplyPatch)
lineCount := strings.Count(editedPatchText, "\n") + 1
newPatchText := patch.
Parse(editedPatchText).
Transform(patch.TransformOpts{
IncludedLineIndices: patch.ExpandRange(0, lineCount),
FileNameOverride: path,
}).
FormatPlain()
if err := self.c.Git().Patch.ApplyPatch(
newPatchText,
git_commands.ApplyPatchOpts{
Reverse: self.staged,
Cached: true,
},
); err != nil {
return err
}
return nil
}
func (self *StagingController) FilePath() string {
return self.c.Contexts().Files.GetSelectedPath()
}
-2
View File
@@ -16,8 +16,6 @@ const (
WORKTREES
STATUS
SUBMODULES
STAGING
PATCH_BUILDING
MERGE_CONFLICTS
COMMIT_FILES
// not actually views. Will refactor this later