Focus the main view (#4429)

- **PR Description**

This adds a new `0` keybinding to the side panels that focuses whatever
main view is currently displayed, with the goal of making it easier to
scroll the main view (using the normal navigation keys `,` `.` `<` `>`),
and being able to search the main view using `/`.

Alternatively to pressing `0` you can also click the main view to focus
it. Note that previously it was possible to go directly to the staging
panel by clicking in the main view when a file was selected; this now
takes a double click, because the first click just focuses the main
view, but you can go to staging from there by clicking again.

I'm reasonably happy with the overall behavior, but it takes some
getting used to, so we'll want to test this for a while to see if it
doesn't make the focus handling too confusing.

Fixes #3988.
This commit is contained in:
Stefan Haller 2025-04-21 18:05:38 +02:00 committed by GitHub
commit e4362eea60
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 760 additions and 173 deletions

View file

@ -501,6 +501,7 @@ keybinding:
- "3"
- "4"
- "5"
focusMainView: "0"
nextMatch: "n"
prevMatch: "N"
startSearch: /

View file

@ -68,6 +68,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` ` `` | Toggle file tree view | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | Search the current view by text | |
## Commit summary
@ -112,6 +113,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` C `` | Copy (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | Search the current view by text | |
@ -153,6 +155,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` f `` | Fetch | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | Search the current view by text | |
## Local branches
@ -178,6 +181,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` R `` | Rename branch | |
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -204,6 +208,9 @@ If you would instead like to start an interactive rebase from the selected commi
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | Scroll down | |
| `` mouse wheel up (fn+down) `` | Scroll up | |
| `` <tab> `` | Switch view | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | Search the current view by text | |
## Main panel (patch building)
@ -264,6 +271,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -282,6 +290,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` s `` | Sort order | |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -297,6 +306,14 @@ If you would instead like to start an interactive rebase from the selected commi
| `` f `` | Fetch | Fetch updates from the remote repository. This retrieves new commits and branches without merging them into your local branches. |
| `` / `` | Filter the current view by text | |
## Secondary
| Key | Action | Info |
|-----|--------|-------------|
| `` <tab> `` | Switch view | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | Search the current view by text | |
## Stash
| Key | Action | Info |
@ -306,6 +323,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` d `` | Drop | Remove the stash entry from the stash list. |
| `` n `` | New branch | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
| `` r `` | Rename stash | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -334,6 +352,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | Search the current view by text | |
@ -363,6 +382,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |

View file

@ -51,6 +51,14 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` ] `` | 次のタブ | |
| `` [ `` | 前のタブ | |
## Secondary
| Key | Action | Info |
|-----|--------|-------------|
| `` <tab> `` | パネルを切り替え | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | 検索を開始 | |
## Stash
| Key | Action | Info |
@ -60,6 +68,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` d `` | Drop | Remove the stash entry from the stash list. |
| `` n `` | 新しいブランチを作成 | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
| `` r `` | Stashを変更 | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -78,6 +87,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | 検索を開始 | |
@ -127,6 +137,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View files | |
| `` w `` | View worktree options | |
| `` / `` | 検索を開始 | |
@ -148,6 +159,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` ` `` | ファイルツリーの表示を切り替え | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | 検索を開始 | |
## コミットメッセージ
@ -192,6 +204,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` P `` | タグをpush | Push the selected tag to a remote. You'll be prompted to select a remote. |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | コミットを閲覧 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -226,6 +239,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` f `` | Fetch | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | 検索を開始 | |
## ブランチ
@ -251,6 +265,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` R `` | ブランチ名を変更 | |
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | コミットを閲覧 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -277,6 +292,9 @@ If you would instead like to start an interactive rebase from the selected commi
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | 下にスクロール | |
| `` mouse wheel up (fn+down) `` | 上にスクロール | |
| `` <tab> `` | パネルを切り替え | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | 検索を開始 | |
## メインパネル (Patch Building)
@ -348,6 +366,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` s `` | 並び替え | |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | コミットを閲覧 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -366,6 +385,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | コミットを閲覧 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |

View file

@ -65,10 +65,19 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 커밋 보기 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
## Secondary
| Key | Action | Info |
|-----|--------|-------------|
| `` <tab> `` | 패널 전환 | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | 검색 시작 | |
## Stash
| Key | Action | Info |
@ -78,6 +87,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` d `` | Drop | Remove the stash entry from the stash list. |
| `` n `` | 새 브랜치 생성 | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
| `` r `` | Rename stash | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View selected item's files | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -96,6 +106,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` <c-r> `` | Reset cherry-picked (copied) commits selection | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View selected item's files | |
| `` w `` | View worktree options | |
| `` / `` | 검색 시작 | |
@ -140,6 +151,9 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | 아래로 스크롤 | |
| `` mouse wheel up (fn+down) `` | 위로 스크롤 | |
| `` <tab> `` | 패널 전환 | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | 검색 시작 | |
## 메인 패널 (Patch Building)
@ -201,6 +215,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` R `` | 브랜치 이름 변경 | |
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 커밋 보기 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -254,6 +269,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` s `` | Sort order | |
| `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 커밋 보기 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -293,6 +309,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` C `` | 커밋을 복사 (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View selected item's files | |
| `` w `` | View worktree options | |
| `` / `` | 검색 시작 | |
@ -314,6 +331,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` ` `` | 파일 트리뷰로 전환 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | 검색 시작 | |
## 커밋메시지
@ -334,6 +352,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` P `` | 태그를 push | Push the selected tag to a remote. You'll be prompted to select a remote. |
| `` g `` | 초기화 | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 커밋 보기 | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -368,6 +387,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` f `` | Fetch | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | 검색 시작 | |
## 확인 패널

View file

@ -81,6 +81,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` f `` | Fetch | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | Start met zoeken | |
## Bevestigingspaneel
@ -113,6 +114,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` R `` | Hernoem branch | |
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Bekijk commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -141,6 +143,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
| `` ` `` | Toggle bestandsboom weergave | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | Start met zoeken | |
## Commits
@ -178,6 +181,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` C `` | Kopieer commit (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Bekijk gecommite bestanden | |
| `` w `` | View worktree options | |
| `` / `` | Start met zoeken | |
@ -212,6 +216,9 @@ If you would instead like to start an interactive rebase from the selected commi
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | Scroll omlaag | |
| `` mouse wheel up (fn+down) `` | Scroll omhoog | |
| `` <tab> `` | Ga naar een ander paneel | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | Start met zoeken | |
## Patch bouwen
@ -242,6 +249,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-r> `` | Reset cherry-picked (gekopieerde) commits selectie | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Bekijk commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -260,6 +268,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` s `` | Sort order | |
| `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Bekijk commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -275,6 +284,14 @@ If you would instead like to start an interactive rebase from the selected commi
| `` f `` | Fetch | Fetch remote |
| `` / `` | Filter the current view by text | |
## Secondary
| Key | Action | Info |
|-----|--------|-------------|
| `` <tab> `` | Ga naar een ander paneel | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | Start met zoeken | |
## Staging
| Key | Action | Info |
@ -306,6 +323,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` d `` | Laten vallen | Remove the stash entry from the stash list. |
| `` n `` | Nieuwe branch | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
| `` r `` | Rename stash | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Bekijk gecommite bestanden | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -334,6 +352,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-r> `` | Reset cherry-picked (gekopieerde) commits selectie | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Bekijk gecommite bestanden | |
| `` w `` | View worktree options | |
| `` / `` | Start met zoeken | |
@ -363,6 +382,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Bekijk commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |

View file

@ -86,10 +86,19 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| `` C `` | Kopiuj (cherry-pick) | Oznacz commit jako skopiowany. Następnie, w widoku lokalnych commitów, możesz nacisnąć `V`, aby wkleić (cherry-pick) skopiowane commity do sprawdzonej gałęzi. W dowolnym momencie możesz nacisnąć `<esc>`, aby anulować zaznaczenie. |
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Wyświetl pliki | |
| `` w `` | Zobacz opcje drzewa pracy | |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
## Dodatkowy
| Key | Action | Info |
|-----|--------|-------------|
| `` <tab> `` | Przełącz widok | Przełącz na inny widok (zatwierdzone/niezatwierdzone zmiany). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
## Drzewa pracy
| Key | Action | Info |
@ -138,6 +147,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| `` R `` | Zmień nazwę gałęzi | |
| `` u `` | Pokaż opcje upstream | Pokaż opcje dotyczące upstream gałęzi, np. ustawianie/usuwanie upstream i resetowanie do upstream. |
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Pokaż commity | |
| `` w `` | Zobacz opcje drzewa pracy | |
| `` / `` | Filtruj bieżący widok po tekście | |
@ -156,6 +166,9 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | Przewiń w dół | |
| `` mouse wheel up (fn+down) `` | Przewiń w górę | |
| `` <tab> `` | Przełącz widok | Przełącz na inny widok (zatwierdzone/niezatwierdzone zmiany). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
## Panel główny (scalanie)
@ -232,6 +245,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| `` f `` | Pobierz | Pobierz zmiany ze zdalnego serwera. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
## Pliki commita
@ -251,6 +265,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| `` ` `` | Przełącz widok drzewa plików | Przełącz widok plików między płaskim a drzewem. Płaski układ pokazuje wszystkie ścieżki plików na jednej liście, układ drzewa grupuje pliki według katalogów. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
## Podsumowanie commita
@ -274,6 +289,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| `` <c-r> `` | Resetuj wybrane (cherry-picked) commity | |
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Pokaż commity | |
| `` w `` | Zobacz opcje drzewa pracy | |
| `` / `` | Filtruj bieżący widok po tekście | |
@ -287,6 +303,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| `` d `` | Usuń | Usuń wpis schowka z listy schowka. |
| `` n `` | Nowa gałąź | Utwórz nową gałąź z wybranego wpisu schowka. Działa poprzez przełączenie git na commit, na którym wpis schowka został utworzony, tworzenie nowej gałęzi z tego commita, a następnie zastosowanie wpisu schowka do nowej gałęzi jako dodatkowego commita. |
| `` r `` | Zmień nazwę schowka | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Wyświetl pliki | |
| `` w `` | Zobacz opcje drzewa pracy | |
| `` / `` | Filtruj bieżący widok po tekście | |
@ -315,6 +332,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| `` <c-r> `` | Resetuj wybrane (cherry-picked) commity | |
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Wyświetl pliki | |
| `` w `` | Zobacz opcje drzewa pracy | |
| `` / `` | Szukaj w bieżącym widoku po tekście | |
@ -344,6 +362,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| `` P `` | Wyślij tag | Wyślij wybrany tag do zdalnego. Zostaniesz poproszony o wybranie zdalnego. |
| `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. |
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Pokaż commity | |
| `` w `` | Zobacz opcje drzewa pracy | |
| `` / `` | Filtruj bieżący widok po tekście | |
@ -373,6 +392,7 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita,
| `` s `` | Kolejność sortowania | |
| `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. |
| `` <c-t> `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Pokaż commity | |
| `` w `` | Zobacz opcje drzewa pracy | |
| `` / `` | Filtruj bieżący widok po tekście | |

View file

@ -83,6 +83,7 @@ Veja a documentação:
| `` f `` | Buscar | Buscar alterações do controle remoto. |
| `` - `` | Recolher todos os arquivos | Recolher todos os diretórios na árvore de arquivos |
| `` = `` | Expandir todos os arquivos | Expandir todos os diretórios na árvore do arquivo |
| `` 0 `` | Focus main view | |
| `` / `` | Search the current view by text | |
## Branches locais
@ -108,6 +109,7 @@ Veja a documentação:
| `` R `` | Rename branch | |
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -126,6 +128,7 @@ Veja a documentação:
| `` s `` | Sort order | |
| `` g `` | Restaurar | Ver opções de redefinição (soft/mixed/hard) para redefinir para o item selecionado. |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -147,6 +150,7 @@ Veja a documentação:
| `` ` `` | Alternar exibição de árvore de arquivo | Alternar a visualização de arquivo entre layout plano e layout de árvore. Layout plano mostra todos os caminhos de arquivo em uma única lista, layout de árvore agrupa arquivos por diretório. |
| `` - `` | Recolher todos os arquivos | Recolher todos os diretórios na árvore de arquivos |
| `` = `` | Expandir todos os arquivos | Expandir todos os diretórios na árvore do arquivo |
| `` 0 `` | Focus main view | |
| `` / `` | Search the current view by text | |
## Commits
@ -184,6 +188,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` C `` | Copiar (cherry-pick) | Marcar commit como copiado. Então, dentro da visualização local de commits, você pode pressionar `V` para colar (cherry-pick) o(s) commit(s) copiado(s) em seu branch de check-out. A qualquer momento você pode pressionar `<esc>` para cancelar a seleção. |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Ver arquivos | |
| `` w `` | View worktree options | |
| `` / `` | Search the current view by text | |
@ -206,6 +211,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` P `` | Push tag | Push the selected tag to a remote. You'll be prompted to select a remote. |
| `` g `` | Restaurar | Ver opções de redefinição (soft/mixed/hard) para redefinir para o item selecionado. |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -224,6 +230,9 @@ If you would instead like to start an interactive rebase from the selected commi
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | Rolar para baixo | |
| `` mouse wheel up (fn+down) `` | Rolar para cima | |
| `` <tab> `` | Mudar de visão | Alternar para outra visão (staged/não processadas alterações). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | Search the current view by text | |
## Painel Principal (preparação)
@ -294,6 +303,7 @@ Veja a documentação:
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | View commits | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -309,6 +319,14 @@ Veja a documentação:
| `` f `` | Buscar | Fetch updates from the remote repository. This retrieves new commits and branches without merging them into your local branches. |
| `` / `` | Filter the current view by text | |
## Secundário
| Key | Action | Info |
|-----|--------|-------------|
| `` <tab> `` | Mudar de visão | Alternar para outra visão (staged/não processadas alterações). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | Search the current view by text | |
## Stash
| Key | Action | Info |
@ -318,6 +336,7 @@ Veja a documentação:
| `` d `` | Descartar | Remova a entrada do stash da lista de armazenamento. |
| `` n `` | Nova branch | Criar um novo ramo a partir da entrada de lixo selecionada. Isso funciona verificando o commit do qual a entrada de lixo foi criada, criar um novo branch a partir desse commit e, em seguida, aplicar a entrada de lixo ao novo branch como um commit adicional. |
| `` r `` | Renomear o stasj | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Ver arquivos | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -346,6 +365,7 @@ Veja a documentação:
| `` <c-r> `` | Reset copied (cherry-picked) commits selection | |
| `` <c-t> `` | Abrir ferramenta de diff externa (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Ver arquivos | |
| `` w `` | View worktree options | |
| `` / `` | Search the current view by text | |

View file

@ -61,6 +61,14 @@ _Связки клавиш_
| `` d `` | Remove | Remove the selected worktree. This will both delete the worktree's directory, as well as metadata about the worktree in the .git directory. |
| `` / `` | Filter the current view by text | |
## Вторичный
| Key | Action | Info |
|-----|--------|-------------|
| `` <tab> `` | Переключиться на другую панель (проиндексированные/непроиндексированные изменения) | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | Найти | |
## Главная панель (Индексирование)
| Key | Action | Info |
@ -89,6 +97,9 @@ _Связки клавиш_
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | Прокрутить вниз | |
| `` mouse wheel up (fn+down) `` | Прокрутить вверх | |
| `` <tab> `` | Переключиться на другую панель (проиндексированные/непроиндексированные изменения) | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | Найти | |
## Главная панель (Слияние)
@ -135,6 +146,7 @@ _Связки клавиш_
| `` <c-r> `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Просмотреть коммиты | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -174,6 +186,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` C `` | Скопировать отобранные коммит (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Просмотреть файлы выбранного элемента | |
| `` w `` | View worktree options | |
| `` / `` | Найти | |
@ -201,6 +214,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` R `` | Переименовать ветку | |
| `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Просмотреть коммиты | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -234,6 +248,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-r> `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Просмотреть файлы выбранного элемента | |
| `` w `` | View worktree options | |
| `` / `` | Найти | |
@ -276,6 +291,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` ` `` | Переключить вид дерева файлов | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | Найти | |
## Статус
@ -299,6 +315,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` P `` | Отправить тег | Push the selected tag to a remote. You'll be prompted to select a remote. |
| `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Просмотреть коммиты | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -317,6 +334,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` s `` | Порядок сортировки | |
| `` g `` | Просмотреть параметры сброса | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | Open external diff tool (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Просмотреть коммиты | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |
@ -362,6 +380,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` f `` | Получить изменения | Fetch changes from remote. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | Найти | |
## Хранилище
@ -373,6 +392,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` d `` | Удалить припрятанные изменения из хранилища | Remove the stash entry from the stash list. |
| `` n `` | Новая ветка | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
| `` r `` | Переименовать хранилище | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | Просмотреть файлы выбранного элемента | |
| `` w `` | View worktree options | |
| `` / `` | Filter the current view by text | |

View file

@ -65,6 +65,7 @@ _图例`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 查看提交 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 通过文本过滤当前视图 | |
@ -83,6 +84,7 @@ _图例`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` <c-r> `` | 重置已拣选(复制)的提交 | |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 查看提交的文件 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 开始搜索 | |
@ -146,6 +148,7 @@ _图例`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `<esc>` 来取消选择。 |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 查看提交的文件 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 开始搜索 | |
@ -174,6 +177,7 @@ _图例`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` ` `` | 切换文件树视图 | 在平铺部署与树布局之间切换文件视图。平铺布局在一个列表中展示所有文件路径,树布局则根据目录分组展示。 |
| `` - `` | 折叠全部文件 | 折叠文件树中的全部目录 |
| `` = `` | 展开全部文件 | 展开文件树中的全部目录 |
| `` 0 `` | Focus main view | |
| `` / `` | 开始搜索 | |
## 文件
@ -206,6 +210,7 @@ _图例`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` f `` | 抓取 | 从远程获取变更 |
| `` - `` | 折叠全部文件 | 折叠文件树中的全部目录 |
| `` = `` | 展开全部文件 | 展开文件树中的全部目录 |
| `` 0 `` | Focus main view | |
| `` / `` | 开始搜索 | |
## 本地分支
@ -231,6 +236,7 @@ _图例`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` R `` | 重命名分支 | |
| `` u `` | 查看上游选项 | 查看与分支上游相关的选项,例如设置/取消设置上游和重置为上游。 |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 查看提交 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 通过文本过滤当前视图 | |
@ -261,10 +267,19 @@ _图例`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` P `` | 推送标签 | 推送选择的标签到远端。你将在弹窗中选择一个远端。 |
| `` g `` | 重置 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 查看提交 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 通过文本过滤当前视图 | |
## 次要
| Key | Action | Info |
|-----|--------|-------------|
| `` <tab> `` | 切换到其他面板 | 切换到其他视图(已暂存/未暂存的变更) |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | 开始搜索 | |
## 正在合并
| Key | Action | Info |
@ -309,6 +324,9 @@ _图例`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | 向下滚动 | |
| `` mouse wheel up (fn+down) `` | 向上滚动 | |
| `` <tab> `` | 切换到其他面板 | 切换到其他视图(已暂存/未暂存的变更) |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | 开始搜索 | |
## 状态
@ -344,6 +362,7 @@ _图例`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` d `` | 删除 | 从贮藏列表中删除该贮藏项 |
| `` n `` | 新分支 | 从选定的贮藏项创建一个新分支。这是通过 git 检查创建贮藏项的提交,从该提交创建一个新分支,然后将贮藏项作为附加提交应用到新分支来实现的。 |
| `` r `` | 重命名贮藏 | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 查看提交的文件 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 通过文本过滤当前视图 | |
@ -373,6 +392,7 @@ _图例`<c-b>` 意味着ctrl+b, `<a-b>意味着Alt+b, `B` 意味着shift+b_
| `` s `` | 排序 | |
| `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 |
| `` <c-t> `` | 使用外部差异比较工具(git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 查看提交 | |
| `` w `` | 查看工作区选项 | |
| `` / `` | 通过文本过滤当前视图 | |

View file

@ -72,6 +72,9 @@ _說明`<c-b>` 表示 CtrlB、`<a-b>` 表示 AltB`B`表示 ShiftB
|-----|--------|-------------|
| `` mouse wheel down (fn+up) `` | 向下捲動 | |
| `` mouse wheel up (fn+down) `` | 向上捲動 | |
| `` <tab> `` | 切換至另一個面板 (已預存/未預存更改) | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | 搜尋 | |
## 主面板(合併)
@ -133,6 +136,7 @@ _說明`<c-b>` 表示 CtrlB、`<a-b>` 表示 AltB`B`表示 ShiftB
| `` <c-r> `` | 重設選定的揀選 (複製) 提交 | |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 檢視所選項目的檔案 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
@ -196,6 +200,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` C `` | 複製提交 (揀選) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `<esc>` to cancel the selection. |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 檢視所選項目的檔案 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
@ -224,6 +229,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` ` `` | 顯示檔案樹狀視圖 | Toggle file view between flat and tree layout. Flat layout shows all file paths in a single list, tree layout groups files by directory. |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | 搜尋 | |
## 收藏 (Stash)
@ -235,6 +241,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` d `` | 捨棄 | Remove the stash entry from the stash list. |
| `` n `` | 新分支 | Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit. |
| `` r `` | 重新命名收藏 | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 檢視所選項目的檔案 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
@ -253,6 +260,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` <c-r> `` | 重設選定的揀選 (複製) 提交 | |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` * `` | Select commits of current branch | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 檢視提交 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
@ -280,6 +288,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` R `` | 重新命名分支 | |
| `` u `` | 檢視遠端設定 | 檢視有關遠端分支的設定(例如重設至遠端) |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 檢視提交 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
@ -295,6 +304,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` P `` | 推送標籤 | Push the selected tag to a remote. You'll be prompted to select a remote. |
| `` g `` | 重設 | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 檢視提交 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |
@ -329,6 +339,15 @@ If you would instead like to start an interactive rebase from the selected commi
| `` f `` | 擷取 | 同步遠端異動 |
| `` - `` | Collapse all files | Collapse all directories in the files tree |
| `` = `` | Expand all files | Expand all directories in the file tree |
| `` 0 `` | Focus main view | |
| `` / `` | 搜尋 | |
## 次要
| Key | Action | Info |
|-----|--------|-------------|
| `` <tab> `` | 切換至另一個面板 (已預存/未預存更改) | Switch to other view (staged/unstaged changes). |
| `` <esc> `` | Exit back to side panel | |
| `` / `` | 搜尋 | |
## 狀態
@ -373,6 +392,7 @@ If you would instead like to start an interactive rebase from the selected commi
| `` s `` | 排序規則 | |
| `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. |
| `` <c-t> `` | 開啟外部差異工具 (git difftool) | |
| `` 0 `` | Focus main view | |
| `` <enter> `` | 檢視提交 | |
| `` w `` | 檢視工作目錄選項 | |
| `` / `` | 搜尋 | |

2
go.mod
View file

@ -15,7 +15,7 @@ require (
github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/generics v0.0.0-20250406224309-4f541cb84918
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd
github.com/jesseduffield/gocui v0.3.1-0.20250408140206-7f1bb9232647
github.com/jesseduffield/gocui v0.3.1-0.20250421160159-82c9aaeba2b9
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e

4
go.sum
View file

@ -194,8 +194,8 @@ github.com/jesseduffield/generics v0.0.0-20250406224309-4f541cb84918 h1:meoUDZGF
github.com/jesseduffield/generics v0.0.0-20250406224309-4f541cb84918/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd h1:ViKj6qth8FgcIWizn9KiACWwPemWSymx62OPN0tHT+Q=
github.com/jesseduffield/go-git/v5 v5.14.1-0.20250407170251-e1a013310ccd/go.mod h1:lRhCiBr6XjQrvcQVa+UYsy/99d3wMXn/a0nSQlhnhlA=
github.com/jesseduffield/gocui v0.3.1-0.20250408140206-7f1bb9232647 h1:XpoXCyLGCB4mczPc1q/8dJefr6OB1xa7jyhH5a5eJqY=
github.com/jesseduffield/gocui v0.3.1-0.20250408140206-7f1bb9232647/go.mod h1:sLIyZ2J42R6idGdtemZzsiR3xY5EF0KsvYEGh3dQv3s=
github.com/jesseduffield/gocui v0.3.1-0.20250421160159-82c9aaeba2b9 h1:k23sCKHCNpAvwJP8Yr16CBUItuarmUHBGH7FaAm2glc=
github.com/jesseduffield/gocui v0.3.1-0.20250421160159-82c9aaeba2b9/go.mod h1:sLIyZ2J42R6idGdtemZzsiR3xY5EF0KsvYEGh3dQv3s=
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a h1:UDeJ3EBk04bXDLOPvuqM3on8HvyJfISw0+UMqW+0a4g=
github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a/go.mod h1:FSWDLKT0NQpntbDd1H3lbz51fhCVlMzy/J0S6nM727Q=
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=

View file

@ -1,7 +1,6 @@
package patch
import (
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)
@ -54,7 +53,7 @@ func (self *Patch) Lines() []*PatchLine {
// Returns the patch line index of the first line in the given hunk
func (self *Patch) HunkStartIdx(hunkIndex int) int {
hunkIndex = utils.Clamp(hunkIndex, 0, len(self.hunks)-1)
hunkIndex = lo.Clamp(hunkIndex, 0, len(self.hunks)-1)
result := len(self.header)
for i := 0; i < hunkIndex; i++ {
@ -65,7 +64,7 @@ func (self *Patch) HunkStartIdx(hunkIndex int) int {
// Returns the patch line index of the last line in the given hunk
func (self *Patch) HunkEndIdx(hunkIndex int) int {
hunkIndex = utils.Clamp(hunkIndex, 0, len(self.hunks)-1)
hunkIndex = lo.Clamp(hunkIndex, 0, len(self.hunks)-1)
return self.HunkStartIdx(hunkIndex) + self.hunks[hunkIndex].lineCount() - 1
}
@ -118,7 +117,7 @@ func (self *Patch) HunkContainingLine(idx int) int {
// Returns the patch line index of the next change (i.e. addition or deletion).
func (self *Patch) GetNextChangeIdx(idx int) int {
idx = utils.Clamp(idx, 0, self.LineCount()-1)
idx = lo.Clamp(idx, 0, self.LineCount()-1)
lines := self.Lines()

View file

@ -395,6 +395,7 @@ type KeybindingUniversalConfig struct {
NextBlockAlt2 string `yaml:"nextBlock-alt2"`
PrevBlockAlt2 string `yaml:"prevBlock-alt2"`
JumpToBlock []string `yaml:"jumpToBlock"`
FocusMainView string `yaml:"focusMainView"`
NextMatch string `yaml:"nextMatch"`
PrevMatch string `yaml:"prevMatch"`
StartSearch string `yaml:"startSearch"`
@ -876,6 +877,7 @@ func GetDefaultConfig() *UserConfig {
PrevBlockAlt2: "<backtab>",
NextBlockAlt2: "<tab>",
JumpToBlock: []string{"1", "2", "3", "4", "5"},
FocusMainView: "0",
NextMatch: "n",
PrevMatch: "N",
StartSearch: "/",

View file

@ -13,12 +13,13 @@ type BaseContext struct {
windowName string
onGetOptionsMap func() map[string]string
keybindingsFns []types.KeybindingsFn
mouseKeybindingsFns []types.MouseKeybindingsFn
onClickFn func() error
onRenderToMainFn func()
onFocusFn onFocusFn
onFocusLostFn onFocusLostFn
keybindingsFns []types.KeybindingsFn
mouseKeybindingsFns []types.MouseKeybindingsFn
onClickFn func() error
onClickFocusedMainViewFn onClickFocusedMainViewFn
onRenderToMainFn func()
onFocusFn onFocusFn
onFocusLostFn onFocusLostFn
focusable bool
transient bool
@ -31,8 +32,9 @@ type BaseContext struct {
}
type (
onFocusFn = func(types.OnFocusOpts)
onFocusLostFn = func(types.OnFocusLostOpts)
onFocusFn = func(types.OnFocusOpts)
onFocusLostFn = func(types.OnFocusLostOpts)
onClickFocusedMainViewFn = func(mainViewName string, clickedLineIdx int) error
)
var _ types.IBaseContext = &BaseContext{}
@ -144,10 +146,20 @@ func (self *BaseContext) AddOnClickFn(fn func() error) {
}
}
func (self *BaseContext) AddOnClickFocusedMainViewFn(fn onClickFocusedMainViewFn) {
if fn != nil {
self.onClickFocusedMainViewFn = fn
}
}
func (self *BaseContext) GetOnClick() func() error {
return self.onClickFn
}
func (self *BaseContext) GetOnClickFocusedMainView() onClickFocusedMainViewFn {
return self.onClickFocusedMainViewFn
}
func (self *BaseContext) AddOnRenderToMainFn(fn func()) {
if fn != nil {
self.onRenderToMainFn = fn

View file

@ -98,8 +98,8 @@ type ContextTree struct {
SubCommits *SubCommitsContext
Stash *StashContext
Suggestions *SuggestionsContext
Normal types.Context
NormalSecondary types.Context
Normal *MainContext
NormalSecondary *MainContext
Staging *PatchExplorerContext
StagingSecondary *PatchExplorerContext
CustomPatchBuilder *PatchExplorerContext

View file

@ -52,7 +52,7 @@ func (self *ListRenderer) ModelIndexToViewIndex(modelIndex int) int {
}
func (self *ListRenderer) ViewIndexToModelIndex(viewIndex int) int {
viewIndex = utils.Clamp(viewIndex, 0, self.list.Len()+self.numNonModelItems)
viewIndex = lo.Clamp(viewIndex, 0, self.list.Len()+self.numNonModelItems)
if self.modelIndicesByViewIndex != nil {
return self.modelIndicesByViewIndex[viewIndex]
}

View file

@ -0,0 +1,41 @@
package context
import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type MainContext struct {
*SimpleContext
*SearchTrait
}
var _ types.ISearchableContext = (*MainContext)(nil)
func NewMainContext(
view *gocui.View,
windowName string,
key types.ContextKey,
c *ContextCommon,
) *MainContext {
ctx := &MainContext{
SimpleContext: NewSimpleContext(
NewBaseContext(NewBaseContextOpts{
Kind: types.MAIN_CONTEXT,
View: view,
WindowName: windowName,
Key: key,
Focusable: true,
HighlightOnFocus: false,
})),
SearchTrait: NewSearchTrait(c),
}
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(func(int) error { return nil }))
return ctx
}
func (self *MainContext) ModelSearchResults(searchStr string, caseSensitive bool) []gocui.SearchPosition {
return nil
}

View file

@ -25,38 +25,22 @@ func NewContextTree(c *ContextCommon) *ContextTree {
Focusable: true,
}),
),
Files: NewWorkingTreeContext(c),
Submodules: NewSubmodulesContext(c),
Menu: NewMenuContext(c),
Remotes: NewRemotesContext(c),
Worktrees: NewWorktreesContext(c),
RemoteBranches: NewRemoteBranchesContext(c),
LocalCommits: NewLocalCommitsContext(c),
CommitFiles: commitFilesContext,
ReflogCommits: NewReflogCommitsContext(c),
SubCommits: NewSubCommitsContext(c),
Branches: NewBranchesContext(c),
Tags: NewTagsContext(c),
Stash: NewStashContext(c),
Suggestions: NewSuggestionsContext(c),
Normal: NewSimpleContext(
NewBaseContext(NewBaseContextOpts{
Kind: types.MAIN_CONTEXT,
View: c.Views().Main,
WindowName: "main",
Key: NORMAL_MAIN_CONTEXT_KEY,
Focusable: false,
}),
),
NormalSecondary: NewSimpleContext(
NewBaseContext(NewBaseContextOpts{
Kind: types.MAIN_CONTEXT,
View: c.Views().Secondary,
WindowName: "secondary",
Key: NORMAL_SECONDARY_CONTEXT_KEY,
Focusable: false,
}),
),
Files: NewWorkingTreeContext(c),
Submodules: NewSubmodulesContext(c),
Menu: NewMenuContext(c),
Remotes: NewRemotesContext(c),
Worktrees: NewWorktreesContext(c),
RemoteBranches: NewRemoteBranchesContext(c),
LocalCommits: NewLocalCommitsContext(c),
CommitFiles: commitFilesContext,
ReflogCommits: NewReflogCommitsContext(c),
SubCommits: NewSubCommitsContext(c),
Branches: NewBranchesContext(c),
Tags: NewTagsContext(c),
Stash: NewStashContext(c),
Suggestions: NewSuggestionsContext(c),
Normal: NewMainContext(c.Views().Main, "main", NORMAL_MAIN_CONTEXT_KEY, c),
NormalSecondary: NewMainContext(c.Views().Secondary, "secondary", NORMAL_SECONDARY_CONTEXT_KEY, c),
Staging: NewPatchExplorerContext(
c.Views().Staging,
"main",

View file

@ -3,6 +3,7 @@ package traits
import (
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)
type RangeSelectMode int
@ -85,7 +86,7 @@ func (self *ListCursor) clampValue(value int) int {
clampedValue := -1
length := self.getLength()
if length > 0 {
clampedValue = utils.Clamp(value, 0, length-1)
clampedValue = lo.Clamp(value, 0, length-1)
}
return clampedValue

View file

@ -180,7 +180,8 @@ func (gui *Gui) resetHelpersAndControllers() {
globalController := controllers.NewGlobalController(common)
contextLinesController := controllers.NewContextLinesController(common)
renameSimilarityThresholdController := controllers.NewRenameSimilarityThresholdController(common)
verticalScrollControllerFactory := controllers.NewVerticalScrollControllerFactory(common, &gui.viewBufferManagerMap)
verticalScrollControllerFactory := controllers.NewVerticalScrollControllerFactory(common)
viewSelectionControllerFactory := controllers.NewViewSelectionControllerFactory(common)
branchesController := controllers.NewBranchesController(common)
gitFlowController := controllers.NewGitFlowController(common)
@ -189,6 +190,8 @@ func (gui *Gui) resetHelpersAndControllers() {
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)
@ -263,6 +266,22 @@ func (gui *Gui) resetHelpersAndControllers() {
))
}
for _, context := range []types.Context{
gui.State.Contexts.Files,
gui.State.Contexts.Branches,
gui.State.Contexts.RemoteBranches,
gui.State.Contexts.Tags,
gui.State.Contexts.LocalCommits,
gui.State.Contexts.ReflogCommits,
gui.State.Contexts.SubCommits,
gui.State.Contexts.CommitFiles,
gui.State.Contexts.Stash,
} {
controllers.AttachControllers(context, controllers.NewSwitchToFocusedMainViewController(
common, context,
))
}
for _, context := range []controllers.ContainsCommits{
gui.State.Contexts.LocalCommits,
gui.State.Contexts.ReflogCommits,
@ -306,6 +325,18 @@ func (gui *Gui) resetHelpersAndControllers() {
mergeConflictsController,
)
controllers.AttachControllers(gui.State.Contexts.Normal,
mainViewController,
verticalScrollControllerFactory.Create(gui.State.Contexts.Normal),
viewSelectionControllerFactory.Create(gui.State.Contexts.Normal),
)
controllers.AttachControllers(gui.State.Contexts.NormalSecondary,
secondaryViewController,
verticalScrollControllerFactory.Create(gui.State.Contexts.NormalSecondary),
viewSelectionControllerFactory.Create(gui.State.Contexts.NormalSecondary),
)
controllers.AttachControllers(gui.State.Contexts.Files,
filesController,
)

View file

@ -7,6 +7,7 @@ func AttachControllers(context types.Context, controllers ...types.IController)
context.AddKeybindingsFn(controller.GetKeybindings)
context.AddMouseKeybindingsFn(controller.GetMouseKeybindings)
context.AddOnClickFn(controller.GetOnClick())
context.AddOnClickFocusedMainViewFn(controller.GetOnClickFocusedMainView())
context.AddOnRenderToMainFn(controller.GetOnRenderToMain())
context.AddOnFocusFn(controller.GetOnFocus())
context.AddOnFocusLostFn(controller.GetOnFocusLost())

View file

@ -19,6 +19,10 @@ func (self *baseController) GetOnClick() func() error {
return nil
}
func (self *baseController) GetOnClickFocusedMainView() func(mainViewName string, clickedLineIdx int) error {
return nil
}
func (self *baseController) GetOnRenderToMain() func() {
return nil
}

View file

@ -135,17 +135,6 @@ func (self *CommitFilesController) GetKeybindings(opts types.KeybindingsOpts) []
return bindings
}
func (self *CommitFilesController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return []*gocui.ViewMouseBinding{
{
ViewName: "patchBuilding",
Key: gocui.MouseLeft,
Handler: self.onClickMain,
FocusedView: self.context().GetViewName(),
},
}
}
func (self *CommitFilesController) context() *context.CommitFilesContext {
return self.c.Contexts().CommitFiles
}
@ -163,13 +152,8 @@ func (self *CommitFilesController) GetOnRenderToMain() func() {
cmdObj := self.c.Git().WorkingTree.ShowFileDiffCmdObj(from, to, reverse, node.GetPath(), false)
task := types.NewRunPtyTask(cmdObj.GetCmd())
pair := self.c.MainViewPairs().Normal
if node.File != nil {
pair = self.c.MainViewPairs().PatchBuilding
}
self.c.RenderToMainViews(types.RefreshMainOpts{
Pair: pair,
Pair: self.c.MainViewPairs().Normal,
Main: &types.ViewUpdateOpts{
Title: self.c.Tr.Patch,
SubTitle: self.c.Helpers().Diff.IgnoringWhitespaceSubTitle(),
@ -180,14 +164,6 @@ func (self *CommitFilesController) GetOnRenderToMain() func() {
}
}
func (self *CommitFilesController) onClickMain(opts gocui.ViewMouseBindingOpts) error {
node := self.context().GetSelected()
if node == nil {
return nil
}
return self.enterCommitFile(node, types.OnFocusOpts{ClickedWindowName: "main", ClickedViewLineIdx: opts.Y})
}
func (self *CommitFilesController) copyDiffToClipboard(path string, toastMessage string) error {
from, to := self.context().GetFromAndToForDiff()
from, reverse := self.c.Modes().Diffing.GetFromAndReverseArgsForDiff(from)
@ -555,6 +531,16 @@ func (self *CommitFilesController) expandAll() error {
return nil
}
func (self *CommitFilesController) GetOnClickFocusedMainView() func(mainViewName string, clickedLineIdx int) error {
return func(mainViewName string, clickedLineIdx int) error {
node := self.getSelectedItem()
if node != nil && node.File != nil {
return self.enterCommitFile(node, types.OnFocusOpts{ClickedWindowName: mainViewName, ClickedViewLineIdx: clickedLineIdx})
}
return nil
}
}
// NOTE: these functions are identical to those in files_controller.go (except for types) and
// could also be cleaned up with some generics
func normalisedSelectedCommitFileNodes(selectedNodes []*filetree.CommitFileNode) []*filetree.CommitFileNode {

View file

@ -208,36 +208,12 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
func (self *FilesController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return []*gocui.ViewMouseBinding{
{
ViewName: "main",
Key: gocui.MouseLeft,
Handler: self.onClickMain,
FocusedView: self.context().GetViewName(),
},
{
ViewName: "patchBuilding",
Key: gocui.MouseLeft,
Handler: self.onClickMain,
FocusedView: self.context().GetViewName(),
},
{
ViewName: "mergeConflicts",
Key: gocui.MouseLeft,
Handler: self.onClickMain,
FocusedView: self.context().GetViewName(),
},
{
ViewName: "secondary",
Key: gocui.MouseLeft,
Handler: self.onClickSecondary,
FocusedView: self.context().GetViewName(),
},
{
ViewName: "patchBuildingSecondary",
Key: gocui.MouseLeft,
Handler: self.onClickSecondary,
FocusedView: self.context().GetViewName(),
},
}
}
@ -304,11 +280,6 @@ func (self *FilesController) GetOnRenderToMain() func() {
self.c.Helpers().MergeConflicts.ResetMergeState()
pair := self.c.MainViewPairs().Normal
if node.File != nil {
pair = self.c.MainViewPairs().Staging
}
split := self.c.UserConfig().Gui.SplitDiff == "always" || (node.GetHasUnstagedChanges() && node.GetHasStagedChanges())
mainShowsStaged := !split && node.GetHasStagedChanges()
@ -318,7 +289,7 @@ func (self *FilesController) GetOnRenderToMain() func() {
title = self.c.Tr.StagedChanges
}
refreshOpts := types.RefreshMainOpts{
Pair: pair,
Pair: self.c.MainViewPairs().Normal,
Main: &types.ViewUpdateOpts{
Task: types.NewRunPtyTask(cmdObj.GetCmd()),
SubTitle: self.c.Helpers().Diff.IgnoringWhitespaceSubTitle(),
@ -352,6 +323,16 @@ func (self *FilesController) GetOnClick() func() error {
})
}
func (self *FilesController) GetOnClickFocusedMainView() func(mainViewName string, clickedLineIdx int) error {
return func(mainViewName string, clickedLineIdx int) error {
node := self.getSelectedItem()
if node != nil && node.File != nil {
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: mainViewName, ClickedViewLineIdx: clickedLineIdx})
}
return nil
}
}
// if we are dealing with a status for which there is no key in this map,
// then we won't optimistically render: we'll just let `git status` tell
// us what the new status is.
@ -574,7 +555,8 @@ func (self *FilesController) EnterFile(opts types.OnFocusOpts) error {
return self.handleNonInlineConflict(file)
}
self.c.Context().Push(self.c.Contexts().Staging, opts)
context := lo.Ternary(opts.ClickedWindowName == "secondary", self.c.Contexts().StagingSecondary, self.c.Contexts().Staging)
self.c.Context().Push(context, opts)
return nil
}
@ -1205,10 +1187,6 @@ func (self *FilesController) onClickMain(opts gocui.ViewMouseBindingOpts) error
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: "main", ClickedViewLineIdx: opts.Y})
}
func (self *FilesController) onClickSecondary(opts gocui.ViewMouseBindingOpts) error {
return self.EnterFile(types.OnFocusOpts{ClickedWindowName: "secondary", ClickedViewLineIdx: opts.Y})
}
func (self *FilesController) fetch() error {
return self.c.WithWaitingStatus(self.c.Tr.FetchingStatus, func(task gocui.Task) error {
if err := self.fetchAux(task); err != nil {

View file

@ -0,0 +1,118 @@
package controllers
import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type MainViewController struct {
baseController
c *ControllerCommon
context *context.MainContext
otherContext *context.MainContext
}
var _ types.IController = &MainViewController{}
func NewMainViewController(
c *ControllerCommon,
context *context.MainContext,
otherContext *context.MainContext,
) *MainViewController {
return &MainViewController{
baseController: baseController{},
c: c,
context: context,
otherContext: otherContext,
}
}
func (self *MainViewController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
return []*types.Binding{
{
Key: opts.GetKey(opts.Config.Universal.TogglePanel),
Handler: self.togglePanel,
Description: self.c.Tr.ToggleStagingView,
Tooltip: self.c.Tr.ToggleStagingViewTooltip,
DisplayOnScreen: true,
},
{
Key: opts.GetKey(opts.Config.Universal.Return),
Handler: self.escape,
Description: self.c.Tr.ExitFocusedMainView,
},
{
// overriding this because we want to read all of the task's output before we start searching
Key: opts.GetKey(opts.Config.Universal.StartSearch),
Handler: self.openSearch,
Description: self.c.Tr.StartSearch,
Tag: "navigation",
},
}
}
func (self *MainViewController) 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.onClick(opts)
}
self.context.SetParentContext(self.otherContext.GetParentContext())
self.c.Context().Push(self.context, types.OnFocusOpts{
ClickedWindowName: self.context.GetWindowName(),
ClickedViewLineIdx: opts.Y,
})
return nil
},
},
}
}
func (self *MainViewController) Context() types.Context {
return self.context
}
func (self *MainViewController) togglePanel() error {
if self.otherContext.GetView().Visible {
self.otherContext.SetParentContext(self.context.GetParentContext())
self.c.Context().Push(self.otherContext, types.OnFocusOpts{})
}
return nil
}
func (self *MainViewController) escape() error {
self.c.Context().Pop()
return nil
}
func (self *MainViewController) onClick(opts gocui.ViewMouseBindingOpts) error {
parentCtx := self.context.GetParentContext()
if parentCtx.GetOnClickFocusedMainView() != nil {
return parentCtx.GetOnClickFocusedMainView()(self.context.GetViewName(), opts.Y)
}
return nil
}
func (self *MainViewController) openSearch() error {
if manager := self.c.GetViewBufferManagerForView(self.context.GetView()); manager != nil {
manager.ReadToEnd(func() {
self.c.OnUIThread(func() error {
return self.c.Helpers().Search.OpenSearchPrompt(self.context)
})
})
}
return nil
}
func (self *MainViewController) isFocused() bool {
return self.c.Context().Current().GetKey() == self.context.GetKey()
}

View file

@ -0,0 +1,82 @@
package controllers
import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
// This controller is for all contexts that can focus their main view.
var _ types.IController = &SwitchToFocusedMainViewController{}
type SwitchToFocusedMainViewController struct {
baseController
c *ControllerCommon
context types.Context
}
func NewSwitchToFocusedMainViewController(
c *ControllerCommon,
context types.Context,
) *SwitchToFocusedMainViewController {
return &SwitchToFocusedMainViewController{
baseController: baseController{},
c: c,
context: context,
}
}
func (self *SwitchToFocusedMainViewController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
bindings := []*types.Binding{
{
Key: opts.GetKey(opts.Config.Universal.FocusMainView),
Handler: self.handleFocusMainView,
Description: self.c.Tr.FocusMainView,
},
}
return bindings
}
func (self *SwitchToFocusedMainViewController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return []*gocui.ViewMouseBinding{
{
ViewName: "main",
Key: gocui.MouseLeft,
Handler: self.onClickMain,
FocusedView: self.context.GetViewName(),
},
{
ViewName: "secondary",
Key: gocui.MouseLeft,
Handler: self.onClickSecondary,
FocusedView: self.context.GetViewName(),
},
}
}
func (self *SwitchToFocusedMainViewController) Context() types.Context {
return self.context
}
func (self *SwitchToFocusedMainViewController) onClickMain(opts gocui.ViewMouseBindingOpts) error {
return self.focusMainView("main")
}
func (self *SwitchToFocusedMainViewController) onClickSecondary(opts gocui.ViewMouseBindingOpts) error {
return self.focusMainView("secondary")
}
func (self *SwitchToFocusedMainViewController) handleFocusMainView() error {
return self.focusMainView("main")
}
func (self *SwitchToFocusedMainViewController) focusMainView(mainViewName string) error {
mainViewContext := self.c.Helpers().Window.GetContextForWindow(mainViewName)
mainViewContext.SetParentContext(self.context)
if context, ok := mainViewContext.(types.ISearchableContext); ok {
context.ClearSearchString()
}
self.c.Context().Push(mainViewContext, types.OnFocusOpts{})
return nil
}

View file

@ -3,29 +3,25 @@ package controllers
import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/tasks"
)
// given we have no fields here, arguably we shouldn't even need this factory
// struct, but we're maintaining consistency with the other files.
type VerticalScrollControllerFactory struct {
c *ControllerCommon
viewBufferManagerMap *map[string]*tasks.ViewBufferManager
c *ControllerCommon
}
func NewVerticalScrollControllerFactory(c *ControllerCommon, viewBufferManagerMap *map[string]*tasks.ViewBufferManager) *VerticalScrollControllerFactory {
func NewVerticalScrollControllerFactory(c *ControllerCommon) *VerticalScrollControllerFactory {
return &VerticalScrollControllerFactory{
c: c,
viewBufferManagerMap: viewBufferManagerMap,
c: c,
}
}
func (self *VerticalScrollControllerFactory) Create(context types.Context) types.IController {
return &VerticalScrollController{
baseController: baseController{},
c: self.c,
context: context,
viewBufferManagerMap: self.viewBufferManagerMap,
baseController: baseController{},
c: self.c,
context: context,
}
}
@ -33,8 +29,7 @@ type VerticalScrollController struct {
baseController
c *ControllerCommon
context types.Context
viewBufferManagerMap *map[string]*tasks.ViewBufferManager
context types.Context
}
func (self *VerticalScrollController) Context() types.Context {
@ -74,7 +69,7 @@ func (self *VerticalScrollController) HandleScrollDown() error {
scrollHeight := self.c.UserConfig().Gui.ScrollHeight
self.context.GetViewTrait().ScrollDown(scrollHeight)
if manager, ok := (*self.viewBufferManagerMap)[self.context.GetViewName()]; ok {
if manager := self.c.GetViewBufferManagerForView(self.context.GetView()); manager != nil {
manager.ReadLines(scrollHeight)
}

View file

@ -0,0 +1,109 @@
package controllers
import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/types"
)
type ViewSelectionControllerFactory struct {
c *ControllerCommon
}
func NewViewSelectionControllerFactory(c *ControllerCommon) *ViewSelectionControllerFactory {
return &ViewSelectionControllerFactory{
c: c,
}
}
func (self *ViewSelectionControllerFactory) Create(context types.Context) types.IController {
return &ViewSelectionController{
baseController: baseController{},
c: self.c,
context: context,
}
}
type ViewSelectionController struct {
baseController
c *ControllerCommon
context types.Context
}
func (self *ViewSelectionController) Context() types.Context {
return self.context
}
func (self *ViewSelectionController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
return []*types.Binding{
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItem), Handler: self.handlePrevLine},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevItemAlt), Handler: self.handlePrevLine},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItem), Handler: self.handleNextLine},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextItemAlt), Handler: self.handleNextLine},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.PrevPage), Handler: self.handlePrevPage, Description: self.c.Tr.PrevPage},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.NextPage), Handler: self.handleNextPage, Description: self.c.Tr.NextPage},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Handler: self.handleGotoTop, Description: self.c.Tr.GotoTop, Alternative: "<home>"},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoBottom), Handler: self.handleGotoBottom, Description: self.c.Tr.GotoBottom, Alternative: "<end>"},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTopAlt), Handler: self.handleGotoTop},
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoBottomAlt), Handler: self.handleGotoBottom},
}
}
func (self *ViewSelectionController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding {
return []*gocui.ViewMouseBinding{}
}
func (self *ViewSelectionController) handleLineChange(delta int) {
if delta > 0 {
if manager := self.c.GetViewBufferManagerForView(self.context.GetView()); manager != nil {
manager.ReadLines(delta)
}
}
v := self.Context().GetView()
if delta < 0 {
v.ScrollUp(-delta)
} else {
v.ScrollDown(delta)
}
}
func (self *ViewSelectionController) handlePrevLine() error {
self.handleLineChange(-1)
return nil
}
func (self *ViewSelectionController) handleNextLine() error {
self.handleLineChange(1)
return nil
}
func (self *ViewSelectionController) handlePrevPage() error {
self.handleLineChange(-self.context.GetViewTrait().PageDelta())
return nil
}
func (self *ViewSelectionController) handleNextPage() error {
self.handleLineChange(self.context.GetViewTrait().PageDelta())
return nil
}
func (self *ViewSelectionController) handleGotoTop() error {
v := self.Context().GetView()
self.handleLineChange(-v.ViewLinesHeight())
return nil
}
func (self *ViewSelectionController) handleGotoBottom() error {
if manager := self.c.GetViewBufferManagerForView(self.context.GetView()); manager != nil {
manager.ReadToEnd(func() {
self.c.OnUIThread(func() error {
v := self.Context().GetView()
self.handleLineChange(v.ViewLinesHeight())
return nil
})
})
}
return nil
}

View file

@ -20,7 +20,7 @@ func (gui *Gui) scrollDownView(view *gocui.View) {
scrollHeight := gui.c.UserConfig().Gui.ScrollHeight
view.ScrollDown(scrollHeight)
if manager, ok := gui.viewBufferManagerMap[view.Name()]; ok {
if manager := gui.getViewBufferManagerForView(view); manager != nil {
manager.ReadLines(scrollHeight)
}
}

View file

@ -578,6 +578,15 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs) types.Context {
return initialContext(contextTree, startArgs)
}
func (self *Gui) getViewBufferManagerForView(view *gocui.View) *tasks.ViewBufferManager {
manager, ok := self.viewBufferManagerMap[view.Name()]
if !ok {
return nil
}
return manager
}
func initialWindowViewNameMap(contextTree *context.ContextTree) *utils.ThreadSafeMap[string, string] {
result := utils.NewThreadSafeMap[string, string]()

View file

@ -7,6 +7,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/tasks"
)
// hacking this by including the gui struct for now until we split more things out
@ -128,6 +129,10 @@ func (self *guiCommon) MainViewPairs() types.MainViewPairs {
}
}
func (self *guiCommon) GetViewBufferManagerForView(view *gocui.View) *tasks.ViewBufferManager {
return self.gui.getViewBufferManagerForView(view)
}
func (self *guiCommon) State() types.IStateAccessor {
return self.gui.stateAccessor
}

View file

@ -32,10 +32,10 @@ func (gui *Gui) layout(g *gocui.Gui) error {
newMainHeight := viewDimensions["main"].Y1 - viewDimensions["main"].Y0 + 1
heightDiff := newMainHeight - prevMainHeight
if heightDiff > 0 {
if manager, ok := gui.viewBufferManagerMap["main"]; ok {
if manager := gui.getViewBufferManagerForView(gui.Views.Main); manager != nil {
manager.ReadLines(heightDiff)
}
if manager, ok := gui.viewBufferManagerMap["secondary"]; ok {
if manager := gui.getViewBufferManagerForView(gui.Views.Secondary); manager != nil {
manager.ReadLines(heightDiff)
}
}

View file

@ -4,6 +4,7 @@ import (
"strings"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/samber/lo"
)
// State represents the selection state of the merge conflict context.
@ -37,14 +38,14 @@ func (s *State) setConflictIndex(index int) {
if len(s.conflicts) == 0 {
s.conflictIndex = 0
} else {
s.conflictIndex = utils.Clamp(index, 0, len(s.conflicts)-1)
s.conflictIndex = lo.Clamp(index, 0, len(s.conflicts)-1)
}
s.setSelectionIndex(s.selectionIndex)
}
func (s *State) setSelectionIndex(index int) {
if selections := s.availableSelections(); len(selections) != 0 {
s.selectionIndex = utils.Clamp(index, 0, len(selections)-1)
s.selectionIndex = lo.Clamp(index, 0, len(selections)-1)
}
}

View file

@ -8,6 +8,7 @@ import (
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/tasks"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/sasha-s/go-deadlock"
"gopkg.in/ozeidan/fuzzy-patricia.v3/patricia"
@ -48,6 +49,9 @@ type IGuiCommon interface {
// used purely for the sake of RenderToMainViews to provide the pair of main views we want to render to
MainViewPairs() MainViewPairs
// return the view buffer manager for the given view, or nil if it doesn't have one
GetViewBufferManagerForView(view *gocui.View) *tasks.ViewBufferManager
// returns true if command completed successfully
RunSubprocess(cmdObj oscommands.ICmdObj) (bool, error)
RunSubprocessAndRefresh(oscommands.ICmdObj) error

View file

@ -94,6 +94,9 @@ type IBaseContext interface {
// our list controller can come along and wrap it in a list-specific click handler.
// We'll need to think of a better way to do this.
AddOnClickFn(func() error)
// Likewise for the focused main view: we need this to communicate between a
// side panel controller and the focused main view controller.
AddOnClickFocusedMainViewFn(func(mainViewName string, clickedLineIdx int) error)
AddOnRenderToMainFn(func())
AddOnFocusFn(func(OnFocusOpts))
@ -240,6 +243,7 @@ type HasKeybindings interface {
GetKeybindings(opts KeybindingsOpts) []*Binding
GetMouseKeybindings(opts KeybindingsOpts) []*gocui.ViewMouseBinding
GetOnClick() func() error
GetOnClickFocusedMainView() func(mainViewName string, clickedLineIdx int) error
GetOnRenderToMain() func()
GetOnFocus() func(OnFocusOpts)
GetOnFocusLost() func(OnFocusLostOpts)

View file

@ -4,6 +4,7 @@ import (
"time"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types"
"github.com/jesseduffield/lazygit/pkg/tasks"
"github.com/jesseduffield/lazygit/pkg/utils"
@ -143,5 +144,17 @@ func (gui *Gui) postRefreshUpdate(c types.Context) {
// correctly, and that integration tests see the up to date selection
// state.
c.FocusLine()
currentCtx := gui.State.ContextMgr.Current()
if currentCtx.GetKey() == context.NORMAL_MAIN_CONTEXT_KEY || currentCtx.GetKey() == context.NORMAL_SECONDARY_CONTEXT_KEY {
// Searching can't cope well with the view being updated while it is being searched.
// We might be able to fix the problems with this, but it doesn't seem easy, so for now
// just don't rerender the view while searching, on the assumption that users will probably
// either search or change their data, but not both at the same time.
if !currentCtx.GetView().IsSearching() {
parentCtx := currentCtx.GetParentContext()
parentCtx.HandleRenderToMain()
}
}
}
}

View file

@ -264,6 +264,7 @@ type TranslationSet struct {
IgnoreFile string
ExcludeFile string
RefreshFiles string
FocusMainView string
Merge string
RegularMerge string
MergeBranchTooltip string
@ -508,6 +509,7 @@ type TranslationSet struct {
EnterCommitFile string
EnterCommitFileTooltip string
ExitCustomPatchBuilder string
ExitFocusedMainView string
EnterUpstream string
InvalidUpstream string
ReturnToRemotesList string
@ -1328,6 +1330,7 @@ func EnglishTranslationSet() *TranslationSet {
IgnoreFile: `Add to .gitignore`,
ExcludeFile: `Add to .git/info/exclude`,
RefreshFiles: `Refresh files`,
FocusMainView: "Focus main view",
Merge: `Merge`,
RegularMerge: "Regular merge",
MergeBranchTooltip: "View options for merging the selected item into the current branch (regular merge, squash merge)",
@ -1581,6 +1584,7 @@ func EnglishTranslationSet() *TranslationSet {
EnterCommitFile: "Enter file / Toggle directory collapsed",
EnterCommitFileTooltip: "If a file is selected, enter the file so that you can add/remove individual lines to the custom patch. If a directory is selected, toggle the directory.",
ExitCustomPatchBuilder: `Exit custom patch builder`,
ExitFocusedMainView: "Exit back to side panel",
EnterUpstream: `Enter upstream as '<remote> <branchname>'`,
InvalidUpstream: "Invalid upstream. Must be in the format '<remote> <branchname>'",
ReturnToRemotesList: `Return to remotes list`,

View file

@ -48,7 +48,7 @@ var Apply = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Information().Content(Contains("Building patch"))
t.Views().PatchBuildingSecondary().Content(Contains("second line"))
t.Views().Secondary().Content(Contains("second line"))
t.Common().SelectPatchOption(MatchesRegexp(`Apply patch$`))

View file

@ -35,7 +35,7 @@ var ApplyInReverse = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Information().Content(Contains("Building patch"))
t.Views().PatchBuildingSecondary().Content(Contains("+file1 content"))
t.Views().Secondary().Content(Contains("+file1 content"))
t.Common().SelectPatchOption(Contains("Apply patch in reverse"))

View file

@ -44,13 +44,13 @@ var ApplyInReverseWithConflict = NewIntegrationTest(NewIntegrationTestArgs{
Tap(func() {
t.Views().Information().Content(Contains("Building patch"))
t.Views().PatchBuildingSecondary().Content(
t.Views().Secondary().Content(
Contains("+more file1 content"))
}).
SelectNextItem().
PressPrimaryAction()
t.Views().PatchBuildingSecondary().Content(
t.Views().Secondary().Content(
Contains("+more file1 content").Contains("+more file2 content"))
t.Common().SelectPatchOption(Contains("Apply patch in reverse"))

View file

@ -43,8 +43,8 @@ var MoveRangeToIndex = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Information().Content(Contains("Building patch"))
t.Views().PatchBuildingSecondary().Content(Contains("second line"))
t.Views().PatchBuildingSecondary().Content(Contains("file two content"))
t.Views().Secondary().Content(Contains("second line"))
t.Views().Secondary().Content(Contains("file two content"))
t.Common().SelectPatchOption(MatchesRegexp(`Move patch out into index$`))

View file

@ -35,7 +35,7 @@ var MoveToIndex = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Information().Content(Contains("Building patch"))
t.Views().PatchBuildingSecondary().Content(Contains("+file1 content"))
t.Views().Secondary().Content(Contains("+file1 content"))
t.Common().SelectPatchOption(Contains("Move patch out into index"))

View file

@ -53,7 +53,7 @@ var MoveToIndexPartial = NewIntegrationTest(NewIntegrationTestArgs{
Tap(func() {
t.Views().Information().Content(Contains("Building patch"))
t.Views().PatchBuildingSecondary().
t.Views().Secondary().
ContainsLines(
Contains(`-first line`),
Contains(`+first line2`),

View file

@ -33,7 +33,7 @@ var MoveToIndexWorksEvenIfNoprefixIsSet = NewIntegrationTest(NewIntegrationTestA
).
PressPrimaryAction()
t.Views().PatchBuildingSecondary().Content(Contains("+file1 content"))
t.Views().Secondary().Content(Contains("+file1 content"))
t.Common().SelectPatchOption(Contains("Move patch out into index"))

View file

@ -35,7 +35,7 @@ var RemoveFromCommit = NewIntegrationTest(NewIntegrationTestArgs{
t.Views().Information().Content(Contains("Building patch"))
t.Views().PatchBuildingSecondary().Content(Contains("+file1 content"))
t.Views().Secondary().Content(Contains("+file1 content"))
t.Common().SelectPatchOption(Contains("Remove patch from original commit"))

View file

@ -58,11 +58,12 @@ var StashStagedPartialFile = NewIntegrationTest(NewIntegrationTestArgs{
)
t.Views().Files().
Focus().
Lines(
Contains("file-staged"),
)
t.Views().Staging().
t.Views().Main().
Content(
Contains(" line1\n line2\n line3\n-line4\n+line4 mod"),
)

View file

@ -39,7 +39,7 @@ var RangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
// separately)
// In both views we're going to have 10 lines starting from 'line 1' going down to
// 'line 10'.
fileContent := ""
fileContent := "staged\n"
total := 10
for i := 1; i <= total; i++ {
remaining := total - i + 1
@ -47,10 +47,11 @@ var RangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
shell.EmptyCommit(fmt.Sprintf("line %d", remaining))
fileContent = fmt.Sprintf("%sline %d\n", fileContent, i)
}
shell.CreateFile("file1", fileContent)
shell.CreateFileAndAdd("file1", "staged\n")
shell.UpdateFile("file1", fileContent)
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
assertRangeSelectBehaviour := func(v *ViewDriver, otherView *ViewDriver, lineIdxOfFirstItem int) {
assertRangeSelectBehaviour := func(v *ViewDriver, focusOtherView func(), lineIdxOfFirstItem int) {
v.
SelectedLines(
Contains("line 1"),
@ -154,7 +155,7 @@ var RangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
)
// Click in view, press shift+arrow -> nonsticky range
otherView.Focus()
focusOtherView()
v.Click(1, lineIdxOfFirstItem).
SelectedLines(
Contains("line 1"),
@ -166,7 +167,7 @@ var RangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
)
}
assertRangeSelectBehaviour(t.Views().Commits().Focus(), t.Views().Branches(), 0)
assertRangeSelectBehaviour(t.Views().Commits().Focus(), func() { t.Views().Branches().Focus() }, 0)
t.Views().Files().
Focus().
@ -175,6 +176,6 @@ var RangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
).
PressEnter()
assertRangeSelectBehaviour(t.Views().Staging().IsFocused(), t.Views().Files(), 6)
assertRangeSelectBehaviour(t.Views().Staging().IsFocused(), func() { t.Views().Staging().PressTab() }, 6)
},
})

View file

@ -70,6 +70,9 @@ type LinesToRead struct {
// do an initial refresh. Only set for the initial read request; -1 for
// subsequent requests.
InitialRefreshAfter int
// Function to call after reading the lines is done
Then func()
}
func (m *ViewBufferManager) GetTaskKey() string {
@ -91,16 +94,28 @@ func NewViewBufferManager(
beforeStart: beforeStart,
refreshView: refreshView,
onEndOfInput: onEndOfInput,
readLines: make(chan LinesToRead, 1024),
readLines: nil,
onNewKey: onNewKey,
newGocuiTask: newGocuiTask,
}
}
func (self *ViewBufferManager) ReadLines(n int) {
go utils.Safe(func() {
self.readLines <- LinesToRead{Total: n, InitialRefreshAfter: -1}
})
if self.readLines != nil {
go utils.Safe(func() {
self.readLines <- LinesToRead{Total: n, InitialRefreshAfter: -1}
})
}
}
func (self *ViewBufferManager) ReadToEnd(then func()) {
if self.readLines != nil {
go utils.Safe(func() {
self.readLines <- LinesToRead{Total: -1, InitialRefreshAfter: -1, Then: then}
})
} else if then != nil {
then()
}
}
func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), prefix string, linesToRead LinesToRead, onDoneFn func()) func(TaskOpts) error {
@ -166,7 +181,6 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p
loadingMutex := deadlock.Mutex{}
// not sure if it's the right move to redefine this or not
self.readLines = make(chan LinesToRead, 1024)
scanner := bufio.NewScanner(r)
@ -233,11 +247,17 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p
case <-opts.Stop:
break outer
case linesToRead := <-self.readLines:
for i := 0; i < linesToRead.Total; i++ {
callThen := func() {
if linesToRead.Then != nil {
linesToRead.Then()
}
}
for i := 0; linesToRead.Total == -1 || i < linesToRead.Total; i++ {
var ok bool
var line []byte
select {
case <-opts.Stop:
callThen()
break outer
case line, ok = <-lineChan:
break
@ -257,6 +277,7 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p
// if we're here then there's nothing left to scan from the source
// so we're at the EOF and can flush the stale content
self.onEndOfInput()
callThen()
break outer
}
writeToView(append(line, '\n'))
@ -271,9 +292,12 @@ func (self *ViewBufferManager) NewCmdTask(start func() (*exec.Cmd, io.Reader), p
}
refreshViewIfStale()
onFirstPageShown()
callThen()
}
}
self.readLines = nil
refreshViewIfStale()
if err := cmd.Wait(); err != nil {
@ -349,6 +373,8 @@ func (self *ViewBufferManager) NewTask(f func(TaskOpts) error, key string) error
go utils.Safe(func() {
defer completeGocuiTask()
self.readLines = nil
self.taskIDMutex.Lock()
self.newTaskID++
taskID := self.newTaskID

View file

@ -52,7 +52,7 @@ func TestNewCmdTaskInstantStop(t *testing.T) {
return cmd, reader
}
fn := manager.NewCmdTask(start, "prefix\n", LinesToRead{20, -1}, onDone)
fn := manager.NewCmdTask(start, "prefix\n", LinesToRead{20, -1, nil}, onDone)
_ = fn(TaskOpts{Stop: stop, InitialContentLoaded: func() { task.Done() }})
@ -115,7 +115,7 @@ func TestNewCmdTask(t *testing.T) {
return cmd, reader
}
fn := manager.NewCmdTask(start, "prefix\n", LinesToRead{20, -1}, onDone)
fn := manager.NewCmdTask(start, "prefix\n", LinesToRead{20, -1, nil}, onDone)
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
@ -184,37 +184,37 @@ func TestNewCmdTaskRefresh(t *testing.T) {
{
"total < initialRefreshAfter",
150,
LinesToRead{100, 120},
LinesToRead{100, 120, nil},
[]int{100},
},
{
"total == initialRefreshAfter",
150,
LinesToRead{100, 100},
LinesToRead{100, 100, nil},
[]int{100},
},
{
"total > initialRefreshAfter",
150,
LinesToRead{100, 50},
LinesToRead{100, 50, nil},
[]int{50, 100},
},
{
"initialRefreshAfter == -1",
150,
LinesToRead{100, -1},
LinesToRead{100, -1, nil},
[]int{100},
},
{
"totalTaskLines < initialRefreshAfter",
25,
LinesToRead{100, 50},
LinesToRead{100, 50, nil},
[]int{25},
},
{
"totalTaskLines between total and initialRefreshAfter",
75,
LinesToRead{100, 50},
LinesToRead{100, 50, nil},
[]int{50, 75},
},
}

View file

@ -39,15 +39,6 @@ func SortRange(x int, y int) (int, int) {
return y, x
}
func Clamp(x int, min int, max int) int {
if x < min {
return min
} else if x > max {
return max
}
return x
}
func AsJson(i interface{}) string {
bytes, _ := json.MarshalIndent(i, "", " ")
return string(bytes)

View file

@ -1259,6 +1259,10 @@
"5"
]
},
"focusMainView": {
"type": "string",
"default": "0"
},
"nextMatch": {
"type": "string",
"default": "n"

View file

@ -519,9 +519,9 @@ func (v *View) setRune(x, y int, ch rune, fgColor, bgColor Attribute) {
}
fgColor = fgColor | AttrBold
if v.HighlightInactive {
bgColor = bgColor | v.InactiveViewSelBgColor
bgColor = (bgColor & AttrStyleBits) | v.InactiveViewSelBgColor
} else {
bgColor = bgColor | v.SelBgColor
bgColor = (bgColor & AttrStyleBits) | v.SelBgColor
}
}
}

2
vendor/modules.txt vendored
View file

@ -226,7 +226,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame
github.com/jesseduffield/go-git/v5/utils/merkletrie/noder
github.com/jesseduffield/go-git/v5/utils/sync
github.com/jesseduffield/go-git/v5/utils/trace
# github.com/jesseduffield/gocui v0.3.1-0.20250408140206-7f1bb9232647
# github.com/jesseduffield/gocui v0.3.1-0.20250421160159-82c9aaeba2b9
## explicit; go 1.12
github.com/jesseduffield/gocui
# github.com/jesseduffield/kill v0.0.0-20250101124109-e216ddbe133a