mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-03-21 21:47:32 +02:00
View filtering (#2680)
This commit is contained in:
commit
1a36cb9f3f
@ -36,6 +36,9 @@ gui:
|
|||||||
- bold
|
- bold
|
||||||
inactiveBorderColor:
|
inactiveBorderColor:
|
||||||
- white
|
- white
|
||||||
|
searchingActiveBorderColor:
|
||||||
|
- cyan
|
||||||
|
- bold
|
||||||
optionsTextColor:
|
optionsTextColor:
|
||||||
- blue
|
- blue
|
||||||
selectedLineBgColor:
|
selectedLineBgColor:
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
# Documentation Overview
|
# Documentation Overview
|
||||||
|
|
||||||
* [Configuration](./Config.md).
|
* [Configuration](./Config.md).
|
||||||
* [Custom Commands](./Custom_Command_Keybindings.md)
|
* [Custom Commands](./Custom_Command_Keybindings.md)
|
||||||
* [Custom Pagers](./Custom_Pagers.md)
|
* [Custom Pagers](./Custom_Pagers.md)
|
||||||
* [Keybindings](./keybindings)
|
* [Keybindings](./keybindings)
|
||||||
* [Undo/Redo](./Undoing.md)
|
* [Undo/Redo](./Undoing.md)
|
||||||
|
* [Searching/Filtering](./Searching.md)
|
||||||
|
21
docs/Searching.md
Normal file
21
docs/Searching.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Searching/Filtering
|
||||||
|
|
||||||
|
## View searching/filtering
|
||||||
|
|
||||||
|
Depending on the currently focused view, hitting '/' will bring up a filter or search prompt. When filtering, the contents of the view will be filtered down to only those lines which match the query string. When searching, the contents of the view are not filtered, but matching lines are highlighted and you can iterate through matches with `n`/`N`.
|
||||||
|
|
||||||
|
We intend to support filtering for the files view soon, but at the moment it uses searching. We intend to continue using search for the commits view because you typically care about the commits that come before/after a matching commit.
|
||||||
|
|
||||||
|
If you would like both filtering and searching to be enabled on a given view, please raise an issue for this.
|
||||||
|
|
||||||
|
## Filtering files by status
|
||||||
|
|
||||||
|
You can filter the files view to only show staged/unstaged files by pressing `<c-b>` in the files view.
|
||||||
|
|
||||||
|
## Filtering commits by file path
|
||||||
|
|
||||||
|
You can filter the commits view to only show commits which contain changes to a given file path.
|
||||||
|
|
||||||
|
You can do this in a couple of ways:
|
||||||
|
1) Start lazygit with the -f flag e.g. `lazygit -f my/path`
|
||||||
|
2) From within lazygit, press `<c-s>` and then enter the path of the file you want to filter by
|
@ -36,8 +36,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>,</kbd>: Previous page
|
<kbd>,</kbd>: Previous page
|
||||||
<kbd>.</kbd>: Next page
|
<kbd>.</kbd>: Next page
|
||||||
<kbd><</kbd>: Scroll to top
|
<kbd><</kbd>: Scroll to top
|
||||||
<kbd>/</kbd>: Start search
|
|
||||||
<kbd>></kbd>: Scroll to bottom
|
<kbd>></kbd>: Scroll to bottom
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
<kbd>H</kbd>: Scroll left
|
<kbd>H</kbd>: Scroll left
|
||||||
<kbd>L</kbd>: Scroll right
|
<kbd>L</kbd>: Scroll right
|
||||||
<kbd>]</kbd>: Next tab
|
<kbd>]</kbd>: Next tab
|
||||||
@ -56,6 +56,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>a</kbd>: Toggle all files included in patch
|
<kbd>a</kbd>: Toggle all files included in patch
|
||||||
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
||||||
<kbd>`</kbd>: Toggle file tree view
|
<kbd>`</kbd>: Toggle file tree view
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Commit summary
|
## Commit summary
|
||||||
@ -96,6 +97,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: Copy commit (cherry-pick)
|
<kbd>c</kbd>: Copy commit (cherry-pick)
|
||||||
<kbd>C</kbd>: Copy commit range (cherry-pick)
|
<kbd>C</kbd>: Copy commit range (cherry-pick)
|
||||||
<kbd><enter></kbd>: View selected item's files
|
<kbd><enter></kbd>: View selected item's files
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Confirmation panel
|
## Confirmation panel
|
||||||
@ -111,7 +113,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd><c-o></kbd>: Copy the file name to the clipboard
|
<kbd><c-o></kbd>: Copy the file name to the clipboard
|
||||||
<kbd>d</kbd>: View 'discard changes' options
|
<kbd>d</kbd>: View 'discard changes' options
|
||||||
<kbd><space></kbd>: Toggle staged
|
<kbd><space></kbd>: Toggle staged
|
||||||
<kbd><c-b></kbd>: Filter files (staged/unstaged)
|
<kbd><c-b></kbd>: Filter files by status
|
||||||
<kbd>c</kbd>: Commit changes
|
<kbd>c</kbd>: Commit changes
|
||||||
<kbd>w</kbd>: Commit changes without pre-commit hook
|
<kbd>w</kbd>: Commit changes without pre-commit hook
|
||||||
<kbd>A</kbd>: Amend last commit
|
<kbd>A</kbd>: Amend last commit
|
||||||
@ -129,6 +131,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>`</kbd>: Toggle file tree view
|
<kbd>`</kbd>: Toggle file tree view
|
||||||
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
||||||
<kbd>f</kbd>: Fetch
|
<kbd>f</kbd>: Fetch
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Local branches
|
## Local branches
|
||||||
@ -152,6 +155,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>R</kbd>: Rename branch
|
<kbd>R</kbd>: Rename branch
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
<kbd>u</kbd>: Set/Unset upstream
|
||||||
<kbd><enter></kbd>: View commits
|
<kbd><enter></kbd>: View commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Main panel (merging)
|
## Main panel (merging)
|
||||||
@ -190,6 +194,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: Edit file
|
<kbd>e</kbd>: Edit file
|
||||||
<kbd><space></kbd>: Add/Remove line(s) to patch
|
<kbd><space></kbd>: Add/Remove line(s) to patch
|
||||||
<kbd><esc></kbd>: Exit custom patch builder
|
<kbd><esc></kbd>: Exit custom patch builder
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Main panel (staging)
|
## Main panel (staging)
|
||||||
@ -211,6 +216,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: Commit changes
|
<kbd>c</kbd>: Commit changes
|
||||||
<kbd>w</kbd>: Commit changes without pre-commit hook
|
<kbd>w</kbd>: Commit changes without pre-commit hook
|
||||||
<kbd>C</kbd>: Commit changes using git editor
|
<kbd>C</kbd>: Commit changes using git editor
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Menu
|
## Menu
|
||||||
@ -218,6 +224,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<pre>
|
<pre>
|
||||||
<kbd><enter></kbd>: Execute
|
<kbd><enter></kbd>: Execute
|
||||||
<kbd><esc></kbd>: Close
|
<kbd><esc></kbd>: Close
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Reflog
|
## Reflog
|
||||||
@ -233,6 +240,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: Copy commit range (cherry-pick)
|
<kbd>C</kbd>: Copy commit range (cherry-pick)
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
||||||
<kbd><enter></kbd>: View commits
|
<kbd><enter></kbd>: View commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Remote branches
|
## Remote branches
|
||||||
@ -245,9 +253,9 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>r</kbd>: Rebase checked-out branch onto this branch
|
<kbd>r</kbd>: Rebase checked-out branch onto this branch
|
||||||
<kbd>d</kbd>: Delete branch
|
<kbd>d</kbd>: Delete branch
|
||||||
<kbd>u</kbd>: Set as upstream of checked-out branch
|
<kbd>u</kbd>: Set as upstream of checked-out branch
|
||||||
<kbd><esc></kbd>: Return to remotes list
|
|
||||||
<kbd>g</kbd>: View reset options
|
<kbd>g</kbd>: View reset options
|
||||||
<kbd><enter></kbd>: View commits
|
<kbd><enter></kbd>: View commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Remotes
|
## Remotes
|
||||||
@ -257,6 +265,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: Add new remote
|
<kbd>n</kbd>: Add new remote
|
||||||
<kbd>d</kbd>: Remove remote
|
<kbd>d</kbd>: Remove remote
|
||||||
<kbd>e</kbd>: Edit remote
|
<kbd>e</kbd>: Edit remote
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Stash
|
## Stash
|
||||||
@ -268,6 +277,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: New branch
|
<kbd>n</kbd>: New branch
|
||||||
<kbd>r</kbd>: Rename stash
|
<kbd>r</kbd>: Rename stash
|
||||||
<kbd><enter></kbd>: View selected item's files
|
<kbd><enter></kbd>: View selected item's files
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
@ -293,6 +303,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: Copy commit range (cherry-pick)
|
<kbd>C</kbd>: Copy commit range (cherry-pick)
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
||||||
<kbd><enter></kbd>: View selected item's files
|
<kbd><enter></kbd>: View selected item's files
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Submodules
|
## Submodules
|
||||||
@ -306,6 +317,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: Update submodule URL
|
<kbd>e</kbd>: Update submodule URL
|
||||||
<kbd>i</kbd>: Initialize submodule
|
<kbd>i</kbd>: Initialize submodule
|
||||||
<kbd>b</kbd>: View bulk submodule options
|
<kbd>b</kbd>: View bulk submodule options
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Tags
|
## Tags
|
||||||
@ -317,4 +329,5 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: Create tag
|
<kbd>n</kbd>: Create tag
|
||||||
<kbd>g</kbd>: View reset options
|
<kbd>g</kbd>: View reset options
|
||||||
<kbd><enter></kbd>: View commits
|
<kbd><enter></kbd>: View commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
@ -36,8 +36,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>,</kbd>: 前のページ
|
<kbd>,</kbd>: 前のページ
|
||||||
<kbd>.</kbd>: 次のページ
|
<kbd>.</kbd>: 次のページ
|
||||||
<kbd><</kbd>: 最上部までスクロール
|
<kbd><</kbd>: 最上部までスクロール
|
||||||
<kbd>/</kbd>: 検索を開始
|
|
||||||
<kbd>></kbd>: 最下部までスクロール
|
<kbd>></kbd>: 最下部までスクロール
|
||||||
|
<kbd>/</kbd>: 検索を開始
|
||||||
<kbd>H</kbd>: 左スクロール
|
<kbd>H</kbd>: 左スクロール
|
||||||
<kbd>L</kbd>: 右スクロール
|
<kbd>L</kbd>: 右スクロール
|
||||||
<kbd>]</kbd>: 次のタブ
|
<kbd>]</kbd>: 次のタブ
|
||||||
@ -53,6 +53,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: 新しいブランチを作成
|
<kbd>n</kbd>: 新しいブランチを作成
|
||||||
<kbd>r</kbd>: Stashを変更
|
<kbd>r</kbd>: Stashを変更
|
||||||
<kbd><enter></kbd>: View selected item's files
|
<kbd><enter></kbd>: View selected item's files
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Sub-commits
|
## Sub-commits
|
||||||
@ -68,6 +69,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
|
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
||||||
<kbd><enter></kbd>: View selected item's files
|
<kbd><enter></kbd>: View selected item's files
|
||||||
|
<kbd>/</kbd>: 検索を開始
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## コミット
|
## コミット
|
||||||
@ -101,6 +103,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: コミットをコピー (cherry-pick)
|
<kbd>c</kbd>: コミットをコピー (cherry-pick)
|
||||||
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
|
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
|
||||||
<kbd><enter></kbd>: View selected item's files
|
<kbd><enter></kbd>: View selected item's files
|
||||||
|
<kbd>/</kbd>: 検索を開始
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## コミットファイル
|
## コミットファイル
|
||||||
@ -115,6 +118,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>a</kbd>: Toggle all files included in patch
|
<kbd>a</kbd>: Toggle all files included in patch
|
||||||
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
||||||
<kbd>`</kbd>: ファイルツリーの表示を切り替え
|
<kbd>`</kbd>: ファイルツリーの表示を切り替え
|
||||||
|
<kbd>/</kbd>: 検索を開始
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## コミットメッセージ
|
## コミットメッセージ
|
||||||
@ -135,6 +139,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: サブモジュールのURLを更新
|
<kbd>e</kbd>: サブモジュールのURLを更新
|
||||||
<kbd>i</kbd>: サブモジュールを初期化
|
<kbd>i</kbd>: サブモジュールを初期化
|
||||||
<kbd>b</kbd>: View bulk submodule options
|
<kbd>b</kbd>: View bulk submodule options
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## ステータス
|
## ステータス
|
||||||
@ -156,6 +161,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: タグを作成
|
<kbd>n</kbd>: タグを作成
|
||||||
<kbd>g</kbd>: View reset options
|
<kbd>g</kbd>: View reset options
|
||||||
<kbd><enter></kbd>: コミットを閲覧
|
<kbd><enter></kbd>: コミットを閲覧
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## ファイル
|
## ファイル
|
||||||
@ -182,6 +188,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>`</kbd>: ファイルツリーの表示を切り替え
|
<kbd>`</kbd>: ファイルツリーの表示を切り替え
|
||||||
<kbd>M</kbd>: Git mergetoolを開く
|
<kbd>M</kbd>: Git mergetoolを開く
|
||||||
<kbd>f</kbd>: Fetch
|
<kbd>f</kbd>: Fetch
|
||||||
|
<kbd>/</kbd>: 検索を開始
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## ブランチ
|
## ブランチ
|
||||||
@ -205,6 +212,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>R</kbd>: ブランチ名を変更
|
<kbd>R</kbd>: ブランチ名を変更
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
<kbd>u</kbd>: Set/Unset upstream
|
||||||
<kbd><enter></kbd>: コミットを閲覧
|
<kbd><enter></kbd>: コミットを閲覧
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## メインパネル (Merging)
|
## メインパネル (Merging)
|
||||||
@ -243,6 +251,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: ファイルを編集
|
<kbd>e</kbd>: ファイルを編集
|
||||||
<kbd><space></kbd>: 行をパッチに追加/削除
|
<kbd><space></kbd>: 行をパッチに追加/削除
|
||||||
<kbd><esc></kbd>: Exit custom patch builder
|
<kbd><esc></kbd>: Exit custom patch builder
|
||||||
|
<kbd>/</kbd>: 検索を開始
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## メインパネル (Staging)
|
## メインパネル (Staging)
|
||||||
@ -264,6 +273,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: 変更をコミット
|
<kbd>c</kbd>: 変更をコミット
|
||||||
<kbd>w</kbd>: pre-commitフックを実行せずに変更をコミット
|
<kbd>w</kbd>: pre-commitフックを実行せずに変更をコミット
|
||||||
<kbd>C</kbd>: gitエディタを使用して変更をコミット
|
<kbd>C</kbd>: gitエディタを使用して変更をコミット
|
||||||
|
<kbd>/</kbd>: 検索を開始
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## メニュー
|
## メニュー
|
||||||
@ -271,6 +281,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<pre>
|
<pre>
|
||||||
<kbd><enter></kbd>: 実行
|
<kbd><enter></kbd>: 実行
|
||||||
<kbd><esc></kbd>: 閉じる
|
<kbd><esc></kbd>: 閉じる
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## リモート
|
## リモート
|
||||||
@ -280,6 +291,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: リモートを新規追加
|
<kbd>n</kbd>: リモートを新規追加
|
||||||
<kbd>d</kbd>: リモートを削除
|
<kbd>d</kbd>: リモートを削除
|
||||||
<kbd>e</kbd>: リモートを編集
|
<kbd>e</kbd>: リモートを編集
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## リモートブランチ
|
## リモートブランチ
|
||||||
@ -292,9 +304,9 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>r</kbd>: Rebase checked-out branch onto this branch
|
<kbd>r</kbd>: Rebase checked-out branch onto this branch
|
||||||
<kbd>d</kbd>: ブランチを削除
|
<kbd>d</kbd>: ブランチを削除
|
||||||
<kbd>u</kbd>: Set as upstream of checked-out branch
|
<kbd>u</kbd>: Set as upstream of checked-out branch
|
||||||
<kbd><esc></kbd>: リモート一覧に戻る
|
|
||||||
<kbd>g</kbd>: View reset options
|
<kbd>g</kbd>: View reset options
|
||||||
<kbd><enter></kbd>: コミットを閲覧
|
<kbd><enter></kbd>: コミットを閲覧
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 参照ログ
|
## 参照ログ
|
||||||
@ -310,6 +322,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
|
<kbd>C</kbd>: コミットを範囲コピー (cherry-pick)
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
||||||
<kbd><enter></kbd>: コミットを閲覧
|
<kbd><enter></kbd>: コミットを閲覧
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 確認パネル
|
## 確認パネル
|
||||||
|
@ -36,8 +36,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>,</kbd>: 이전 페이지
|
<kbd>,</kbd>: 이전 페이지
|
||||||
<kbd>.</kbd>: 다음 페이지
|
<kbd>.</kbd>: 다음 페이지
|
||||||
<kbd><</kbd>: 맨 위로 스크롤
|
<kbd><</kbd>: 맨 위로 스크롤
|
||||||
<kbd>/</kbd>: 검색 시작
|
|
||||||
<kbd>></kbd>: 맨 아래로 스크롤
|
<kbd>></kbd>: 맨 아래로 스크롤
|
||||||
|
<kbd>/</kbd>: 검색 시작
|
||||||
<kbd>H</kbd>: 우 스크롤
|
<kbd>H</kbd>: 우 스크롤
|
||||||
<kbd>L</kbd>: 좌 스크롤
|
<kbd>L</kbd>: 좌 스크롤
|
||||||
<kbd>]</kbd>: 이전 탭
|
<kbd>]</kbd>: 이전 탭
|
||||||
@ -57,6 +57,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
|
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
||||||
<kbd><enter></kbd>: 커밋 보기
|
<kbd><enter></kbd>: 커밋 보기
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Stash
|
## Stash
|
||||||
@ -68,6 +69,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: 새 브랜치 생성
|
<kbd>n</kbd>: 새 브랜치 생성
|
||||||
<kbd>r</kbd>: Rename stash
|
<kbd>r</kbd>: Rename stash
|
||||||
<kbd><enter></kbd>: View selected item's files
|
<kbd><enter></kbd>: View selected item's files
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Sub-commits
|
## Sub-commits
|
||||||
@ -83,6 +85,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
|
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
||||||
<kbd><enter></kbd>: View selected item's files
|
<kbd><enter></kbd>: View selected item's files
|
||||||
|
<kbd>/</kbd>: 검색 시작
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 메뉴
|
## 메뉴
|
||||||
@ -90,6 +93,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<pre>
|
<pre>
|
||||||
<kbd><enter></kbd>: 실행
|
<kbd><enter></kbd>: 실행
|
||||||
<kbd><esc></kbd>: 닫기
|
<kbd><esc></kbd>: 닫기
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 메인 패널 (Merging)
|
## 메인 패널 (Merging)
|
||||||
@ -128,6 +132,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: 파일 편집
|
<kbd>e</kbd>: 파일 편집
|
||||||
<kbd><space></kbd>: Line(s)을 패치에 추가/삭제
|
<kbd><space></kbd>: Line(s)을 패치에 추가/삭제
|
||||||
<kbd><esc></kbd>: Exit custom patch builder
|
<kbd><esc></kbd>: Exit custom patch builder
|
||||||
|
<kbd>/</kbd>: 검색 시작
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 메인 패널 (Staging)
|
## 메인 패널 (Staging)
|
||||||
@ -149,6 +154,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: 커밋 변경내용
|
<kbd>c</kbd>: 커밋 변경내용
|
||||||
<kbd>w</kbd>: Commit changes without pre-commit hook
|
<kbd>w</kbd>: Commit changes without pre-commit hook
|
||||||
<kbd>C</kbd>: Git 편집기를 사용하여 변경 내용을 커밋합니다.
|
<kbd>C</kbd>: Git 편집기를 사용하여 변경 내용을 커밋합니다.
|
||||||
|
<kbd>/</kbd>: 검색 시작
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 브랜치
|
## 브랜치
|
||||||
@ -172,6 +178,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>R</kbd>: 브랜치 이름 변경
|
<kbd>R</kbd>: 브랜치 이름 변경
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
<kbd>u</kbd>: Set/Unset upstream
|
||||||
<kbd><enter></kbd>: 커밋 보기
|
<kbd><enter></kbd>: 커밋 보기
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 상태
|
## 상태
|
||||||
@ -195,6 +202,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: 서브모듈의 URL을 수정
|
<kbd>e</kbd>: 서브모듈의 URL을 수정
|
||||||
<kbd>i</kbd>: 서브모듈 초기화
|
<kbd>i</kbd>: 서브모듈 초기화
|
||||||
<kbd>b</kbd>: View bulk submodule options
|
<kbd>b</kbd>: View bulk submodule options
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 원격
|
## 원격
|
||||||
@ -204,6 +212,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: 새로운 Remote 추가
|
<kbd>n</kbd>: 새로운 Remote 추가
|
||||||
<kbd>d</kbd>: Remote를 삭제
|
<kbd>d</kbd>: Remote를 삭제
|
||||||
<kbd>e</kbd>: Remote를 수정
|
<kbd>e</kbd>: Remote를 수정
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 원격 브랜치
|
## 원격 브랜치
|
||||||
@ -216,9 +225,9 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스
|
<kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스
|
||||||
<kbd>d</kbd>: 브랜치 삭제
|
<kbd>d</kbd>: 브랜치 삭제
|
||||||
<kbd>u</kbd>: Set as upstream of checked-out branch
|
<kbd>u</kbd>: Set as upstream of checked-out branch
|
||||||
<kbd><esc></kbd>: 원격목록으로 돌아가기
|
|
||||||
<kbd>g</kbd>: View reset options
|
<kbd>g</kbd>: View reset options
|
||||||
<kbd><enter></kbd>: 커밋 보기
|
<kbd><enter></kbd>: 커밋 보기
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 커밋
|
## 커밋
|
||||||
@ -252,6 +261,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: 커밋을 복사 (cherry-pick)
|
<kbd>c</kbd>: 커밋을 복사 (cherry-pick)
|
||||||
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
|
<kbd>C</kbd>: 커밋을 범위로 복사 (cherry-pick)
|
||||||
<kbd><enter></kbd>: View selected item's files
|
<kbd><enter></kbd>: View selected item's files
|
||||||
|
<kbd>/</kbd>: 검색 시작
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 커밋 파일
|
## 커밋 파일
|
||||||
@ -266,6 +276,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>a</kbd>: Toggle all files included in patch
|
<kbd>a</kbd>: Toggle all files included in patch
|
||||||
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
||||||
<kbd>`</kbd>: 파일 트리뷰로 전환
|
<kbd>`</kbd>: 파일 트리뷰로 전환
|
||||||
|
<kbd>/</kbd>: 검색 시작
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 커밋메시지
|
## 커밋메시지
|
||||||
@ -284,6 +295,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: 태그를 생성
|
<kbd>n</kbd>: 태그를 생성
|
||||||
<kbd>g</kbd>: View reset options
|
<kbd>g</kbd>: View reset options
|
||||||
<kbd><enter></kbd>: 커밋 보기
|
<kbd><enter></kbd>: 커밋 보기
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 파일
|
## 파일
|
||||||
@ -310,6 +322,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>`</kbd>: 파일 트리뷰로 전환
|
<kbd>`</kbd>: 파일 트리뷰로 전환
|
||||||
<kbd>M</kbd>: Git mergetool를 열기
|
<kbd>M</kbd>: Git mergetool를 열기
|
||||||
<kbd>f</kbd>: Fetch
|
<kbd>f</kbd>: Fetch
|
||||||
|
<kbd>/</kbd>: 검색 시작
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 확인 패널
|
## 확인 패널
|
||||||
|
@ -36,8 +36,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>,</kbd>: Vorige pagina
|
<kbd>,</kbd>: Vorige pagina
|
||||||
<kbd>.</kbd>: Volgende pagina
|
<kbd>.</kbd>: Volgende pagina
|
||||||
<kbd><</kbd>: Scroll naar boven
|
<kbd><</kbd>: Scroll naar boven
|
||||||
<kbd>/</kbd>: Start met zoeken
|
|
||||||
<kbd>></kbd>: Scroll naar beneden
|
<kbd>></kbd>: Scroll naar beneden
|
||||||
|
<kbd>/</kbd>: Start met zoeken
|
||||||
<kbd>H</kbd>: Scroll left
|
<kbd>H</kbd>: Scroll left
|
||||||
<kbd>L</kbd>: Scroll right
|
<kbd>L</kbd>: Scroll right
|
||||||
<kbd>]</kbd>: Volgende tabblad
|
<kbd>]</kbd>: Volgende tabblad
|
||||||
@ -50,7 +50,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd><c-o></kbd>: Kopieer de bestandsnaam naar het klembord
|
<kbd><c-o></kbd>: Kopieer de bestandsnaam naar het klembord
|
||||||
<kbd>d</kbd>: Bekijk 'veranderingen ongedaan maken' opties
|
<kbd>d</kbd>: Bekijk 'veranderingen ongedaan maken' opties
|
||||||
<kbd><space></kbd>: Toggle staged
|
<kbd><space></kbd>: Toggle staged
|
||||||
<kbd><c-b></kbd>: Filter files (staged/unstaged)
|
<kbd><c-b></kbd>: Filter files by status
|
||||||
<kbd>c</kbd>: Commit veranderingen
|
<kbd>c</kbd>: Commit veranderingen
|
||||||
<kbd>w</kbd>: Commit veranderingen zonder pre-commit hook
|
<kbd>w</kbd>: Commit veranderingen zonder pre-commit hook
|
||||||
<kbd>A</kbd>: Wijzig laatste commit
|
<kbd>A</kbd>: Wijzig laatste commit
|
||||||
@ -68,6 +68,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>`</kbd>: Toggle bestandsboom weergave
|
<kbd>`</kbd>: Toggle bestandsboom weergave
|
||||||
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
||||||
<kbd>f</kbd>: Fetch
|
<kbd>f</kbd>: Fetch
|
||||||
|
<kbd>/</kbd>: Start met zoeken
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Bevestigingspaneel
|
## Bevestigingspaneel
|
||||||
@ -98,6 +99,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>R</kbd>: Hernoem branch
|
<kbd>R</kbd>: Hernoem branch
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
<kbd>u</kbd>: Set/Unset upstream
|
||||||
<kbd><enter></kbd>: Bekijk commits
|
<kbd><enter></kbd>: Bekijk commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Commit bericht
|
## Commit bericht
|
||||||
@ -119,6 +121,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>a</kbd>: Toggle all files included in patch
|
<kbd>a</kbd>: Toggle all files included in patch
|
||||||
<kbd><enter></kbd>: Enter bestand om geselecteerde regels toe te voegen aan de patch
|
<kbd><enter></kbd>: Enter bestand om geselecteerde regels toe te voegen aan de patch
|
||||||
<kbd>`</kbd>: Toggle bestandsboom weergave
|
<kbd>`</kbd>: Toggle bestandsboom weergave
|
||||||
|
<kbd>/</kbd>: Start met zoeken
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Commits
|
## Commits
|
||||||
@ -152,6 +155,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: Kopieer commit (cherry-pick)
|
<kbd>c</kbd>: Kopieer commit (cherry-pick)
|
||||||
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
|
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
|
||||||
<kbd><enter></kbd>: Bekijk gecommite bestanden
|
<kbd><enter></kbd>: Bekijk gecommite bestanden
|
||||||
|
<kbd>/</kbd>: Start met zoeken
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Menu
|
## Menu
|
||||||
@ -159,6 +163,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<pre>
|
<pre>
|
||||||
<kbd><enter></kbd>: Uitvoeren
|
<kbd><enter></kbd>: Uitvoeren
|
||||||
<kbd><esc></kbd>: Sluiten
|
<kbd><esc></kbd>: Sluiten
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Mergen
|
## Mergen
|
||||||
@ -197,6 +202,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: Verander bestand
|
<kbd>e</kbd>: Verander bestand
|
||||||
<kbd><space></kbd>: Voeg toe/verwijder lijn(en) in patch
|
<kbd><space></kbd>: Voeg toe/verwijder lijn(en) in patch
|
||||||
<kbd><esc></kbd>: Sluit lijn-bij-lijn modus
|
<kbd><esc></kbd>: Sluit lijn-bij-lijn modus
|
||||||
|
<kbd>/</kbd>: Start met zoeken
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Reflog
|
## Reflog
|
||||||
@ -212,6 +218,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
|
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (gekopieerde) commits selectie
|
<kbd><c-r></kbd>: Reset cherry-picked (gekopieerde) commits selectie
|
||||||
<kbd><enter></kbd>: Bekijk commits
|
<kbd><enter></kbd>: Bekijk commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Remote branches
|
## Remote branches
|
||||||
@ -224,9 +231,9 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>r</kbd>: Rebase branch
|
<kbd>r</kbd>: Rebase branch
|
||||||
<kbd>d</kbd>: Verwijder branch
|
<kbd>d</kbd>: Verwijder branch
|
||||||
<kbd>u</kbd>: Stel in als upstream van uitgecheckte branch
|
<kbd>u</kbd>: Stel in als upstream van uitgecheckte branch
|
||||||
<kbd><esc></kbd>: Ga terug naar remotes lijst
|
|
||||||
<kbd>g</kbd>: Bekijk reset opties
|
<kbd>g</kbd>: Bekijk reset opties
|
||||||
<kbd><enter></kbd>: Bekijk commits
|
<kbd><enter></kbd>: Bekijk commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Remotes
|
## Remotes
|
||||||
@ -236,6 +243,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: Voeg een nieuwe remote toe
|
<kbd>n</kbd>: Voeg een nieuwe remote toe
|
||||||
<kbd>d</kbd>: Verwijder remote
|
<kbd>d</kbd>: Verwijder remote
|
||||||
<kbd>e</kbd>: Wijzig remote
|
<kbd>e</kbd>: Wijzig remote
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Staging
|
## Staging
|
||||||
@ -257,6 +265,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: Commit veranderingen
|
<kbd>c</kbd>: Commit veranderingen
|
||||||
<kbd>w</kbd>: Commit veranderingen zonder pre-commit hook
|
<kbd>w</kbd>: Commit veranderingen zonder pre-commit hook
|
||||||
<kbd>C</kbd>: Commit veranderingen met de git editor
|
<kbd>C</kbd>: Commit veranderingen met de git editor
|
||||||
|
<kbd>/</kbd>: Start met zoeken
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Stash
|
## Stash
|
||||||
@ -268,6 +277,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: Nieuwe branch
|
<kbd>n</kbd>: Nieuwe branch
|
||||||
<kbd>r</kbd>: Rename stash
|
<kbd>r</kbd>: Rename stash
|
||||||
<kbd><enter></kbd>: Bekijk gecommite bestanden
|
<kbd><enter></kbd>: Bekijk gecommite bestanden
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
@ -293,6 +303,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
|
<kbd>C</kbd>: Kopieer commit reeks (cherry-pick)
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (gekopieerde) commits selectie
|
<kbd><c-r></kbd>: Reset cherry-picked (gekopieerde) commits selectie
|
||||||
<kbd><enter></kbd>: Bekijk gecommite bestanden
|
<kbd><enter></kbd>: Bekijk gecommite bestanden
|
||||||
|
<kbd>/</kbd>: Start met zoeken
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Submodules
|
## Submodules
|
||||||
@ -306,6 +317,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: Update submodule URL
|
<kbd>e</kbd>: Update submodule URL
|
||||||
<kbd>i</kbd>: Initialiseer submodule
|
<kbd>i</kbd>: Initialiseer submodule
|
||||||
<kbd>b</kbd>: Bekijk bulk submodule opties
|
<kbd>b</kbd>: Bekijk bulk submodule opties
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Tags
|
## Tags
|
||||||
@ -317,4 +329,5 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: Creëer tag
|
<kbd>n</kbd>: Creëer tag
|
||||||
<kbd>g</kbd>: Bekijk reset opties
|
<kbd>g</kbd>: Bekijk reset opties
|
||||||
<kbd><enter></kbd>: Bekijk commits
|
<kbd><enter></kbd>: Bekijk commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
@ -36,8 +36,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>,</kbd>: Previous page
|
<kbd>,</kbd>: Previous page
|
||||||
<kbd>.</kbd>: Next page
|
<kbd>.</kbd>: Next page
|
||||||
<kbd><</kbd>: Scroll to top
|
<kbd><</kbd>: Scroll to top
|
||||||
<kbd>/</kbd>: Start search
|
|
||||||
<kbd>></kbd>: Scroll to bottom
|
<kbd>></kbd>: Scroll to bottom
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
<kbd>H</kbd>: Scroll left
|
<kbd>H</kbd>: Scroll left
|
||||||
<kbd>L</kbd>: Scroll right
|
<kbd>L</kbd>: Scroll right
|
||||||
<kbd>]</kbd>: Next tab
|
<kbd>]</kbd>: Next tab
|
||||||
@ -82,6 +82,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: Kopiuj commit (przebieranie)
|
<kbd>c</kbd>: Kopiuj commit (przebieranie)
|
||||||
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
|
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
|
||||||
<kbd><enter></kbd>: Przeglądaj pliki commita
|
<kbd><enter></kbd>: Przeglądaj pliki commita
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Confirmation panel
|
## Confirmation panel
|
||||||
@ -112,6 +113,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>R</kbd>: Rename branch
|
<kbd>R</kbd>: Rename branch
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
<kbd>u</kbd>: Set/Unset upstream
|
||||||
<kbd><enter></kbd>: View commits
|
<kbd><enter></kbd>: View commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Main panel (patch building)
|
## Main panel (patch building)
|
||||||
@ -127,6 +129,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: Edytuj plik
|
<kbd>e</kbd>: Edytuj plik
|
||||||
<kbd><space></kbd>: Add/Remove line(s) to patch
|
<kbd><space></kbd>: Add/Remove line(s) to patch
|
||||||
<kbd><esc></kbd>: Wyście z trybu "linia po linii"
|
<kbd><esc></kbd>: Wyście z trybu "linia po linii"
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Menu
|
## Menu
|
||||||
@ -134,6 +137,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<pre>
|
<pre>
|
||||||
<kbd><enter></kbd>: Wykonaj
|
<kbd><enter></kbd>: Wykonaj
|
||||||
<kbd><esc></kbd>: Zamknij
|
<kbd><esc></kbd>: Zamknij
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Pliki
|
## Pliki
|
||||||
@ -142,7 +146,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd><c-o></kbd>: Copy the file name to the clipboard
|
<kbd><c-o></kbd>: Copy the file name to the clipboard
|
||||||
<kbd>d</kbd>: Pokaż opcje porzucania zmian
|
<kbd>d</kbd>: Pokaż opcje porzucania zmian
|
||||||
<kbd><space></kbd>: Przełącz stan poczekalni
|
<kbd><space></kbd>: Przełącz stan poczekalni
|
||||||
<kbd><c-b></kbd>: Filter files (staged/unstaged)
|
<kbd><c-b></kbd>: Filter files by status
|
||||||
<kbd>c</kbd>: Zatwierdź zmiany
|
<kbd>c</kbd>: Zatwierdź zmiany
|
||||||
<kbd>w</kbd>: Zatwierdź zmiany bez skryptu pre-commit
|
<kbd>w</kbd>: Zatwierdź zmiany bez skryptu pre-commit
|
||||||
<kbd>A</kbd>: Zmień ostatni commit
|
<kbd>A</kbd>: Zmień ostatni commit
|
||||||
@ -160,6 +164,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>`</kbd>: Toggle file tree view
|
<kbd>`</kbd>: Toggle file tree view
|
||||||
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
<kbd>M</kbd>: Open external merge tool (git mergetool)
|
||||||
<kbd>f</kbd>: Pobierz
|
<kbd>f</kbd>: Pobierz
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Pliki commita
|
## Pliki commita
|
||||||
@ -174,6 +179,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>a</kbd>: Toggle all files included in patch
|
<kbd>a</kbd>: Toggle all files included in patch
|
||||||
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
<kbd><enter></kbd>: Enter file to add selected lines to the patch (or toggle directory collapsed)
|
||||||
<kbd>`</kbd>: Toggle file tree view
|
<kbd>`</kbd>: Toggle file tree view
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Poczekalnia
|
## Poczekalnia
|
||||||
@ -195,6 +201,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: Zatwierdź zmiany
|
<kbd>c</kbd>: Zatwierdź zmiany
|
||||||
<kbd>w</kbd>: Zatwierdź zmiany bez skryptu pre-commit
|
<kbd>w</kbd>: Zatwierdź zmiany bez skryptu pre-commit
|
||||||
<kbd>C</kbd>: Zatwierdź zmiany używając edytora
|
<kbd>C</kbd>: Zatwierdź zmiany używając edytora
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Reflog
|
## Reflog
|
||||||
@ -210,6 +217,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
|
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
||||||
<kbd><enter></kbd>: View commits
|
<kbd><enter></kbd>: View commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Remote branches
|
## Remote branches
|
||||||
@ -222,9 +230,9 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>r</kbd>: Zmiana bazy gałęzi
|
<kbd>r</kbd>: Zmiana bazy gałęzi
|
||||||
<kbd>d</kbd>: Usuń gałąź
|
<kbd>d</kbd>: Usuń gałąź
|
||||||
<kbd>u</kbd>: Set as upstream of checked-out branch
|
<kbd>u</kbd>: Set as upstream of checked-out branch
|
||||||
<kbd><esc></kbd>: Wróć do listy repozytoriów zdalnych
|
|
||||||
<kbd>g</kbd>: Wyświetl opcje resetu
|
<kbd>g</kbd>: Wyświetl opcje resetu
|
||||||
<kbd><enter></kbd>: View commits
|
<kbd><enter></kbd>: View commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Remotes
|
## Remotes
|
||||||
@ -234,6 +242,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: Add new remote
|
<kbd>n</kbd>: Add new remote
|
||||||
<kbd>d</kbd>: Remove remote
|
<kbd>d</kbd>: Remove remote
|
||||||
<kbd>e</kbd>: Edit remote
|
<kbd>e</kbd>: Edit remote
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Scalanie
|
## Scalanie
|
||||||
@ -261,6 +270,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: Nowa gałąź
|
<kbd>n</kbd>: Nowa gałąź
|
||||||
<kbd>r</kbd>: Rename stash
|
<kbd>r</kbd>: Rename stash
|
||||||
<kbd><enter></kbd>: Przeglądaj pliki commita
|
<kbd><enter></kbd>: Przeglądaj pliki commita
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
@ -286,6 +296,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
|
<kbd>C</kbd>: Kopiuj zakres commitów (przebieranie)
|
||||||
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
<kbd><c-r></kbd>: Reset cherry-picked (copied) commits selection
|
||||||
<kbd><enter></kbd>: Przeglądaj pliki commita
|
<kbd><enter></kbd>: Przeglądaj pliki commita
|
||||||
|
<kbd>/</kbd>: Search the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Submodules
|
## Submodules
|
||||||
@ -299,6 +310,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: Update submodule URL
|
<kbd>e</kbd>: Update submodule URL
|
||||||
<kbd>i</kbd>: Initialize submodule
|
<kbd>i</kbd>: Initialize submodule
|
||||||
<kbd>b</kbd>: View bulk submodule options
|
<kbd>b</kbd>: View bulk submodule options
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Tags
|
## Tags
|
||||||
@ -310,6 +322,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: Create tag
|
<kbd>n</kbd>: Create tag
|
||||||
<kbd>g</kbd>: Wyświetl opcje resetu
|
<kbd>g</kbd>: Wyświetl opcje resetu
|
||||||
<kbd><enter></kbd>: View commits
|
<kbd><enter></kbd>: View commits
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Zwykłe
|
## Zwykłe
|
||||||
|
@ -36,8 +36,8 @@ _Связки клавиш_
|
|||||||
<kbd>,</kbd>: Предыдущая страница
|
<kbd>,</kbd>: Предыдущая страница
|
||||||
<kbd>.</kbd>: Следующая страница
|
<kbd>.</kbd>: Следующая страница
|
||||||
<kbd><</kbd>: Пролистать наверх
|
<kbd><</kbd>: Пролистать наверх
|
||||||
<kbd>/</kbd>: Найти
|
|
||||||
<kbd>></kbd>: Прокрутить вниз
|
<kbd>></kbd>: Прокрутить вниз
|
||||||
|
<kbd>/</kbd>: Найти
|
||||||
<kbd>H</kbd>: Прокрутить влево
|
<kbd>H</kbd>: Прокрутить влево
|
||||||
<kbd>L</kbd>: Прокрутить вправо
|
<kbd>L</kbd>: Прокрутить вправо
|
||||||
<kbd>]</kbd>: Следующая вкладка
|
<kbd>]</kbd>: Следующая вкладка
|
||||||
@ -63,6 +63,7 @@ _Связки клавиш_
|
|||||||
<kbd>c</kbd>: Сохранить изменения
|
<kbd>c</kbd>: Сохранить изменения
|
||||||
<kbd>w</kbd>: Закоммитить изменения без предварительного хука коммита
|
<kbd>w</kbd>: Закоммитить изменения без предварительного хука коммита
|
||||||
<kbd>C</kbd>: Сохранить изменения с помощью редактора git
|
<kbd>C</kbd>: Сохранить изменения с помощью редактора git
|
||||||
|
<kbd>/</kbd>: Найти
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Главная панель (Обычный)
|
## Главная панель (Обычный)
|
||||||
@ -101,6 +102,7 @@ _Связки клавиш_
|
|||||||
<kbd>e</kbd>: Редактировать файл
|
<kbd>e</kbd>: Редактировать файл
|
||||||
<kbd><space></kbd>: Добавить/удалить строку(и) для патча
|
<kbd><space></kbd>: Добавить/удалить строку(и) для патча
|
||||||
<kbd><esc></kbd>: Выйти из сборщика пользовательских патчей
|
<kbd><esc></kbd>: Выйти из сборщика пользовательских патчей
|
||||||
|
<kbd>/</kbd>: Найти
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Журнал ссылок (Reflog)
|
## Журнал ссылок (Reflog)
|
||||||
@ -116,6 +118,7 @@ _Связки клавиш_
|
|||||||
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
|
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
|
||||||
<kbd><c-r></kbd>: Сбросить отобранную (скопированную | cherry-picked) выборку коммитов
|
<kbd><c-r></kbd>: Сбросить отобранную (скопированную | cherry-picked) выборку коммитов
|
||||||
<kbd><enter></kbd>: Просмотреть коммиты
|
<kbd><enter></kbd>: Просмотреть коммиты
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Коммиты
|
## Коммиты
|
||||||
@ -149,6 +152,7 @@ _Связки клавиш_
|
|||||||
<kbd>c</kbd>: Скопировать отобранные коммит (cherry-pick)
|
<kbd>c</kbd>: Скопировать отобранные коммит (cherry-pick)
|
||||||
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
|
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
|
||||||
<kbd><enter></kbd>: Просмотреть файлы выбранного элемента
|
<kbd><enter></kbd>: Просмотреть файлы выбранного элемента
|
||||||
|
<kbd>/</kbd>: Найти
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Локальные Ветки
|
## Локальные Ветки
|
||||||
@ -172,6 +176,7 @@ _Связки клавиш_
|
|||||||
<kbd>R</kbd>: Переименовать ветку
|
<kbd>R</kbd>: Переименовать ветку
|
||||||
<kbd>u</kbd>: Установить/убрать upstream-ветку
|
<kbd>u</kbd>: Установить/убрать upstream-ветку
|
||||||
<kbd><enter></kbd>: Просмотреть коммиты
|
<kbd><enter></kbd>: Просмотреть коммиты
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Меню
|
## Меню
|
||||||
@ -179,6 +184,7 @@ _Связки клавиш_
|
|||||||
<pre>
|
<pre>
|
||||||
<kbd><enter></kbd>: Выполнить
|
<kbd><enter></kbd>: Выполнить
|
||||||
<kbd><esc></kbd>: Закрыть
|
<kbd><esc></kbd>: Закрыть
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Панель Подтверждения
|
## Панель Подтверждения
|
||||||
@ -201,6 +207,7 @@ _Связки клавиш_
|
|||||||
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
|
<kbd>C</kbd>: Скопировать несколько отобранных коммитов (cherry-pick)
|
||||||
<kbd><c-r></kbd>: Сбросить отобранную (скопированную | cherry-picked) выборку коммитов
|
<kbd><c-r></kbd>: Сбросить отобранную (скопированную | cherry-picked) выборку коммитов
|
||||||
<kbd><enter></kbd>: Просмотреть файлы выбранного элемента
|
<kbd><enter></kbd>: Просмотреть файлы выбранного элемента
|
||||||
|
<kbd>/</kbd>: Найти
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Подмодули
|
## Подмодули
|
||||||
@ -214,6 +221,7 @@ _Связки клавиш_
|
|||||||
<kbd>e</kbd>: Обновить URL подмодуля
|
<kbd>e</kbd>: Обновить URL подмодуля
|
||||||
<kbd>i</kbd>: Инициализировать подмодуль
|
<kbd>i</kbd>: Инициализировать подмодуль
|
||||||
<kbd>b</kbd>: Просмотреть параметры массового подмодуля
|
<kbd>b</kbd>: Просмотреть параметры массового подмодуля
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Сводка коммита
|
## Сводка коммита
|
||||||
@ -235,6 +243,7 @@ _Связки клавиш_
|
|||||||
<kbd>a</kbd>: Переключить все файлы, включённые в патч
|
<kbd>a</kbd>: Переключить все файлы, включённые в патч
|
||||||
<kbd><enter></kbd>: Введите файл, чтобы добавить выбранные строки в патч (или свернуть каталог переключения)
|
<kbd><enter></kbd>: Введите файл, чтобы добавить выбранные строки в патч (или свернуть каталог переключения)
|
||||||
<kbd>`</kbd>: Переключить вид дерева файлов
|
<kbd>`</kbd>: Переключить вид дерева файлов
|
||||||
|
<kbd>/</kbd>: Найти
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Статус
|
## Статус
|
||||||
@ -256,6 +265,7 @@ _Связки клавиш_
|
|||||||
<kbd>n</kbd>: Создать тег
|
<kbd>n</kbd>: Создать тег
|
||||||
<kbd>g</kbd>: Просмотреть параметры сброса
|
<kbd>g</kbd>: Просмотреть параметры сброса
|
||||||
<kbd><enter></kbd>: Просмотреть коммиты
|
<kbd><enter></kbd>: Просмотреть коммиты
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Удалённые ветки
|
## Удалённые ветки
|
||||||
@ -268,9 +278,9 @@ _Связки клавиш_
|
|||||||
<kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку
|
<kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку
|
||||||
<kbd>d</kbd>: Удалить ветку
|
<kbd>d</kbd>: Удалить ветку
|
||||||
<kbd>u</kbd>: Установить как upstream-ветку переключённую ветку
|
<kbd>u</kbd>: Установить как upstream-ветку переключённую ветку
|
||||||
<kbd><esc></kbd>: Вернуться к списку удалённых репозитории
|
|
||||||
<kbd>g</kbd>: Просмотреть параметры сброса
|
<kbd>g</kbd>: Просмотреть параметры сброса
|
||||||
<kbd><enter></kbd>: Просмотреть коммиты
|
<kbd><enter></kbd>: Просмотреть коммиты
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Удалённые репозитории
|
## Удалённые репозитории
|
||||||
@ -280,6 +290,7 @@ _Связки клавиш_
|
|||||||
<kbd>n</kbd>: Добавить новую удалённую ветку
|
<kbd>n</kbd>: Добавить новую удалённую ветку
|
||||||
<kbd>d</kbd>: Удалить удалённую ветку
|
<kbd>d</kbd>: Удалить удалённую ветку
|
||||||
<kbd>e</kbd>: Редактировать удалённый репозитории
|
<kbd>e</kbd>: Редактировать удалённый репозитории
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Файлы
|
## Файлы
|
||||||
@ -306,6 +317,7 @@ _Связки клавиш_
|
|||||||
<kbd>`</kbd>: Переключить вид дерева файлов
|
<kbd>`</kbd>: Переключить вид дерева файлов
|
||||||
<kbd>M</kbd>: Открыть внешний инструмент слияния (git mergetool)
|
<kbd>M</kbd>: Открыть внешний инструмент слияния (git mergetool)
|
||||||
<kbd>f</kbd>: Получить изменения
|
<kbd>f</kbd>: Получить изменения
|
||||||
|
<kbd>/</kbd>: Найти
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## Хранилище
|
## Хранилище
|
||||||
@ -317,4 +329,5 @@ _Связки клавиш_
|
|||||||
<kbd>n</kbd>: Новая ветка
|
<kbd>n</kbd>: Новая ветка
|
||||||
<kbd>r</kbd>: Переименовать хранилище
|
<kbd>r</kbd>: Переименовать хранилище
|
||||||
<kbd><enter></kbd>: Просмотреть файлы выбранного элемента
|
<kbd><enter></kbd>: Просмотреть файлы выбранного элемента
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
@ -36,8 +36,8 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>,</kbd>: 上一页
|
<kbd>,</kbd>: 上一页
|
||||||
<kbd>.</kbd>: 下一页
|
<kbd>.</kbd>: 下一页
|
||||||
<kbd><</kbd>: 滚动到顶部
|
<kbd><</kbd>: 滚动到顶部
|
||||||
<kbd>/</kbd>: 开始搜索
|
|
||||||
<kbd>></kbd>: 滚动到底部
|
<kbd>></kbd>: 滚动到底部
|
||||||
|
<kbd>/</kbd>: 开始搜索
|
||||||
<kbd>H</kbd>: 向左滚动
|
<kbd>H</kbd>: 向左滚动
|
||||||
<kbd>L</kbd>: 向右滚动
|
<kbd>L</kbd>: 向右滚动
|
||||||
<kbd>]</kbd>: 下一个标签
|
<kbd>]</kbd>: 下一个标签
|
||||||
@ -57,6 +57,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: 复制提交范围(拣选)
|
<kbd>C</kbd>: 复制提交范围(拣选)
|
||||||
<kbd><c-r></kbd>: 重置已拣选(复制)的提交
|
<kbd><c-r></kbd>: 重置已拣选(复制)的提交
|
||||||
<kbd><enter></kbd>: 查看提交
|
<kbd><enter></kbd>: 查看提交
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 分支页面
|
## 分支页面
|
||||||
@ -80,6 +81,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>R</kbd>: 重命名分支
|
<kbd>R</kbd>: 重命名分支
|
||||||
<kbd>u</kbd>: Set/Unset upstream
|
<kbd>u</kbd>: Set/Unset upstream
|
||||||
<kbd><enter></kbd>: 查看提交
|
<kbd><enter></kbd>: 查看提交
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 子提交
|
## 子提交
|
||||||
@ -95,6 +97,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>C</kbd>: 复制提交范围(拣选)
|
<kbd>C</kbd>: 复制提交范围(拣选)
|
||||||
<kbd><c-r></kbd>: 重置已拣选(复制)的提交
|
<kbd><c-r></kbd>: 重置已拣选(复制)的提交
|
||||||
<kbd><enter></kbd>: 查看提交的文件
|
<kbd><enter></kbd>: 查看提交的文件
|
||||||
|
<kbd>/</kbd>: 开始搜索
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 子模块
|
## 子模块
|
||||||
@ -108,6 +111,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: 更新子模块 URL
|
<kbd>e</kbd>: 更新子模块 URL
|
||||||
<kbd>i</kbd>: 初始化子模块
|
<kbd>i</kbd>: 初始化子模块
|
||||||
<kbd>b</kbd>: 查看批量子模块选项
|
<kbd>b</kbd>: 查看批量子模块选项
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 提交
|
## 提交
|
||||||
@ -141,6 +145,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: 复制提交(拣选)
|
<kbd>c</kbd>: 复制提交(拣选)
|
||||||
<kbd>C</kbd>: 复制提交范围(拣选)
|
<kbd>C</kbd>: 复制提交范围(拣选)
|
||||||
<kbd><enter></kbd>: 查看提交的文件
|
<kbd><enter></kbd>: 查看提交的文件
|
||||||
|
<kbd>/</kbd>: 开始搜索
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 提交文件
|
## 提交文件
|
||||||
@ -155,6 +160,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>a</kbd>: Toggle all files included in patch
|
<kbd>a</kbd>: Toggle all files included in patch
|
||||||
<kbd><enter></kbd>: 输入文件以将所选行添加到补丁中(或切换目录折叠)
|
<kbd><enter></kbd>: 输入文件以将所选行添加到补丁中(或切换目录折叠)
|
||||||
<kbd>`</kbd>: 切换文件树视图
|
<kbd>`</kbd>: 切换文件树视图
|
||||||
|
<kbd>/</kbd>: 开始搜索
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 提交讯息
|
## 提交讯息
|
||||||
@ -170,7 +176,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd><c-o></kbd>: 将文件名复制到剪贴板
|
<kbd><c-o></kbd>: 将文件名复制到剪贴板
|
||||||
<kbd>d</kbd>: 查看'放弃更改'选项
|
<kbd>d</kbd>: 查看'放弃更改'选项
|
||||||
<kbd><space></kbd>: 切换暂存状态
|
<kbd><space></kbd>: 切换暂存状态
|
||||||
<kbd><c-b></kbd>: Filter files (staged/unstaged)
|
<kbd><c-b></kbd>: Filter files by status
|
||||||
<kbd>c</kbd>: 提交更改
|
<kbd>c</kbd>: 提交更改
|
||||||
<kbd>w</kbd>: 提交更改而无需预先提交钩子
|
<kbd>w</kbd>: 提交更改而无需预先提交钩子
|
||||||
<kbd>A</kbd>: 修补最后一次提交
|
<kbd>A</kbd>: 修补最后一次提交
|
||||||
@ -188,6 +194,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>`</kbd>: 切换文件树视图
|
<kbd>`</kbd>: 切换文件树视图
|
||||||
<kbd>M</kbd>: 打开外部合并工具 (git mergetool)
|
<kbd>M</kbd>: 打开外部合并工具 (git mergetool)
|
||||||
<kbd>f</kbd>: 抓取
|
<kbd>f</kbd>: 抓取
|
||||||
|
<kbd>/</kbd>: 开始搜索
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 构建补丁中
|
## 构建补丁中
|
||||||
@ -203,6 +210,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>e</kbd>: 编辑文件
|
<kbd>e</kbd>: 编辑文件
|
||||||
<kbd><space></kbd>: 添加/移除 行到补丁
|
<kbd><space></kbd>: 添加/移除 行到补丁
|
||||||
<kbd><esc></kbd>: 退出逐行模式
|
<kbd><esc></kbd>: 退出逐行模式
|
||||||
|
<kbd>/</kbd>: 开始搜索
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 标签页面
|
## 标签页面
|
||||||
@ -214,6 +222,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: 创建标签
|
<kbd>n</kbd>: 创建标签
|
||||||
<kbd>g</kbd>: 查看重置选项
|
<kbd>g</kbd>: 查看重置选项
|
||||||
<kbd><enter></kbd>: 查看提交
|
<kbd><enter></kbd>: 查看提交
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 正在合并
|
## 正在合并
|
||||||
@ -251,6 +260,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>c</kbd>: 提交更改
|
<kbd>c</kbd>: 提交更改
|
||||||
<kbd>w</kbd>: 提交更改而无需预先提交钩子
|
<kbd>w</kbd>: 提交更改而无需预先提交钩子
|
||||||
<kbd>C</kbd>: 提交更改(使用编辑器编辑提交信息)
|
<kbd>C</kbd>: 提交更改(使用编辑器编辑提交信息)
|
||||||
|
<kbd>/</kbd>: 开始搜索
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 正常
|
## 正常
|
||||||
@ -282,6 +292,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<pre>
|
<pre>
|
||||||
<kbd><enter></kbd>: 执行
|
<kbd><enter></kbd>: 执行
|
||||||
<kbd><esc></kbd>: 关闭
|
<kbd><esc></kbd>: 关闭
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 贮藏
|
## 贮藏
|
||||||
@ -293,6 +304,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: 新分支
|
<kbd>n</kbd>: 新分支
|
||||||
<kbd>r</kbd>: Rename stash
|
<kbd>r</kbd>: Rename stash
|
||||||
<kbd><enter></kbd>: 查看提交的文件
|
<kbd><enter></kbd>: 查看提交的文件
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 远程分支
|
## 远程分支
|
||||||
@ -305,9 +317,9 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>r</kbd>: 将已检出的分支变基到该分支
|
<kbd>r</kbd>: 将已检出的分支变基到该分支
|
||||||
<kbd>d</kbd>: 删除分支
|
<kbd>d</kbd>: 删除分支
|
||||||
<kbd>u</kbd>: 设置为检出分支的上游
|
<kbd>u</kbd>: 设置为检出分支的上游
|
||||||
<kbd><esc></kbd>: 返回远程仓库列表
|
|
||||||
<kbd>g</kbd>: 查看重置选项
|
<kbd>g</kbd>: 查看重置选项
|
||||||
<kbd><enter></kbd>: 查看提交
|
<kbd><enter></kbd>: 查看提交
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 远程页面
|
## 远程页面
|
||||||
@ -317,4 +329,5 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
|
|||||||
<kbd>n</kbd>: 添加新的远程仓库
|
<kbd>n</kbd>: 添加新的远程仓库
|
||||||
<kbd>d</kbd>: 删除远程
|
<kbd>d</kbd>: 删除远程
|
||||||
<kbd>e</kbd>: 编辑远程仓库
|
<kbd>e</kbd>: 编辑远程仓库
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
@ -36,8 +36,8 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>,</kbd>: 上一頁
|
<kbd>,</kbd>: 上一頁
|
||||||
<kbd>.</kbd>: 下一頁
|
<kbd>.</kbd>: 下一頁
|
||||||
<kbd><</kbd>: 捲動到頂部
|
<kbd><</kbd>: 捲動到頂部
|
||||||
<kbd>/</kbd>: 開始搜尋
|
|
||||||
<kbd>></kbd>: 捲動到底部
|
<kbd>></kbd>: 捲動到底部
|
||||||
|
<kbd>/</kbd>: 開始搜尋
|
||||||
<kbd>H</kbd>: 向左捲動
|
<kbd>H</kbd>: 向左捲動
|
||||||
<kbd>L</kbd>: 向右捲動
|
<kbd>L</kbd>: 向右捲動
|
||||||
<kbd>]</kbd>: 下一個索引標籤
|
<kbd>]</kbd>: 下一個索引標籤
|
||||||
@ -57,6 +57,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>C</kbd>: 複製提交範圍 (揀選)
|
<kbd>C</kbd>: 複製提交範圍 (揀選)
|
||||||
<kbd><c-r></kbd>: 重設選定的揀選 (複製) 提交
|
<kbd><c-r></kbd>: 重設選定的揀選 (複製) 提交
|
||||||
<kbd><enter></kbd>: 檢視提交
|
<kbd><enter></kbd>: 檢視提交
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 主視窗 (一般)
|
## 主視窗 (一般)
|
||||||
@ -101,6 +102,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>c</kbd>: 提交變更
|
<kbd>c</kbd>: 提交變更
|
||||||
<kbd>w</kbd>: 沒有預提交 hook 就提交更改
|
<kbd>w</kbd>: 沒有預提交 hook 就提交更改
|
||||||
<kbd>C</kbd>: 使用 git 編輯器提交變更
|
<kbd>C</kbd>: 使用 git 編輯器提交變更
|
||||||
|
<kbd>/</kbd>: 開始搜尋
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 主面板 (補丁生成)
|
## 主面板 (補丁生成)
|
||||||
@ -116,6 +118,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>e</kbd>: 編輯檔案
|
<kbd>e</kbd>: 編輯檔案
|
||||||
<kbd><space></kbd>: 向 (或從) 補丁中添加/刪除行
|
<kbd><space></kbd>: 向 (或從) 補丁中添加/刪除行
|
||||||
<kbd><esc></kbd>: 退出自訂補丁建立器
|
<kbd><esc></kbd>: 退出自訂補丁建立器
|
||||||
|
<kbd>/</kbd>: 開始搜尋
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 功能表
|
## 功能表
|
||||||
@ -123,6 +126,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<pre>
|
<pre>
|
||||||
<kbd><enter></kbd>: 執行
|
<kbd><enter></kbd>: 執行
|
||||||
<kbd><esc></kbd>: 關閉
|
<kbd><esc></kbd>: 關閉
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 子提交
|
## 子提交
|
||||||
@ -138,6 +142,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>C</kbd>: 複製提交範圍 (揀選)
|
<kbd>C</kbd>: 複製提交範圍 (揀選)
|
||||||
<kbd><c-r></kbd>: 重設選定的揀選 (複製) 提交
|
<kbd><c-r></kbd>: 重設選定的揀選 (複製) 提交
|
||||||
<kbd><enter></kbd>: 檢視所選項目的檔案
|
<kbd><enter></kbd>: 檢視所選項目的檔案
|
||||||
|
<kbd>/</kbd>: 開始搜尋
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 子模組
|
## 子模組
|
||||||
@ -151,6 +156,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>e</kbd>: 更新子模組 URL
|
<kbd>e</kbd>: 更新子模組 URL
|
||||||
<kbd>i</kbd>: 初始化子模組
|
<kbd>i</kbd>: 初始化子模組
|
||||||
<kbd>b</kbd>: 查看批量子模組選項
|
<kbd>b</kbd>: 查看批量子模組選項
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 提交
|
## 提交
|
||||||
@ -184,6 +190,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>c</kbd>: 複製提交 (揀選)
|
<kbd>c</kbd>: 複製提交 (揀選)
|
||||||
<kbd>C</kbd>: 複製提交範圍 (揀選)
|
<kbd>C</kbd>: 複製提交範圍 (揀選)
|
||||||
<kbd><enter></kbd>: 檢視所選項目的檔案
|
<kbd><enter></kbd>: 檢視所選項目的檔案
|
||||||
|
<kbd>/</kbd>: 開始搜尋
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 提交摘要
|
## 提交摘要
|
||||||
@ -205,6 +212,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>a</kbd>: 切換所有檔案是否包含在補丁中
|
<kbd>a</kbd>: 切換所有檔案是否包含在補丁中
|
||||||
<kbd><enter></kbd>: 輸入檔案以將選定的行添加至補丁(或切換目錄折疊)
|
<kbd><enter></kbd>: 輸入檔案以將選定的行添加至補丁(或切換目錄折疊)
|
||||||
<kbd>`</kbd>: 切換檔案樹狀視圖
|
<kbd>`</kbd>: 切換檔案樹狀視圖
|
||||||
|
<kbd>/</kbd>: 開始搜尋
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 收藏 (Stash)
|
## 收藏 (Stash)
|
||||||
@ -216,6 +224,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>n</kbd>: 新分支
|
<kbd>n</kbd>: 新分支
|
||||||
<kbd>r</kbd>: 重新命名收藏
|
<kbd>r</kbd>: 重新命名收藏
|
||||||
<kbd><enter></kbd>: 檢視所選項目的檔案
|
<kbd><enter></kbd>: 檢視所選項目的檔案
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 本地分支
|
## 本地分支
|
||||||
@ -239,6 +248,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>R</kbd>: 重新命名分支
|
<kbd>R</kbd>: 重新命名分支
|
||||||
<kbd>u</kbd>: 設定/取消設定上游
|
<kbd>u</kbd>: 設定/取消設定上游
|
||||||
<kbd><enter></kbd>: 檢視提交
|
<kbd><enter></kbd>: 檢視提交
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 標籤
|
## 標籤
|
||||||
@ -250,6 +260,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>n</kbd>: 建立標籤
|
<kbd>n</kbd>: 建立標籤
|
||||||
<kbd>g</kbd>: 檢視重設選項
|
<kbd>g</kbd>: 檢視重設選項
|
||||||
<kbd><enter></kbd>: 檢視提交
|
<kbd><enter></kbd>: 檢視提交
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 檔案
|
## 檔案
|
||||||
@ -276,6 +287,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>`</kbd>: 切換檔案樹狀視圖
|
<kbd>`</kbd>: 切換檔案樹狀視圖
|
||||||
<kbd>M</kbd>: 開啟外部合併工具 (git mergetool)
|
<kbd>M</kbd>: 開啟外部合併工具 (git mergetool)
|
||||||
<kbd>f</kbd>: 擷取
|
<kbd>f</kbd>: 擷取
|
||||||
|
<kbd>/</kbd>: 開始搜尋
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 狀態
|
## 狀態
|
||||||
@ -302,6 +314,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>n</kbd>: 新增遠端
|
<kbd>n</kbd>: 新增遠端
|
||||||
<kbd>d</kbd>: 移除遠端
|
<kbd>d</kbd>: 移除遠端
|
||||||
<kbd>e</kbd>: 編輯遠端
|
<kbd>e</kbd>: 編輯遠端
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
## 遠端分支
|
## 遠端分支
|
||||||
@ -314,7 +327,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
|
|||||||
<kbd>r</kbd>: 將已檢出的分支變基至此分支
|
<kbd>r</kbd>: 將已檢出的分支變基至此分支
|
||||||
<kbd>d</kbd>: 刪除分支
|
<kbd>d</kbd>: 刪除分支
|
||||||
<kbd>u</kbd>: 將此分支設為當前分支之上游
|
<kbd>u</kbd>: 將此分支設為當前分支之上游
|
||||||
<kbd><esc></kbd>: 返回遠端列表
|
|
||||||
<kbd>g</kbd>: 檢視重設選項
|
<kbd>g</kbd>: 檢視重設選項
|
||||||
<kbd><enter></kbd>: 檢視提交
|
<kbd><enter></kbd>: 檢視提交
|
||||||
|
<kbd>/</kbd>: Filter the current view by text
|
||||||
</pre>
|
</pre>
|
||||||
|
8
go.mod
8
go.mod
@ -18,7 +18,7 @@ require (
|
|||||||
github.com/integrii/flaggy v1.4.0
|
github.com/integrii/flaggy v1.4.0
|
||||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68
|
||||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
|
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20230601121845-cb89273fdd4e
|
github.com/jesseduffield/gocui v0.3.1-0.20230702054502-d6c452fc12ce
|
||||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
|
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10
|
||||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5
|
||||||
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e
|
||||||
@ -67,8 +67,8 @@ require (
|
|||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
||||||
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
|
golang.org/x/exp v0.0.0-20220318154914-8dddf5d87bd8 // indirect
|
||||||
golang.org/x/net v0.7.0 // indirect
|
golang.org/x/net v0.7.0 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
golang.org/x/sys v0.9.0 // indirect
|
||||||
golang.org/x/term v0.8.0 // indirect
|
golang.org/x/term v0.9.0 // indirect
|
||||||
golang.org/x/text v0.9.0 // indirect
|
golang.org/x/text v0.10.0 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
)
|
)
|
||||||
|
15
go.sum
15
go.sum
@ -72,8 +72,8 @@ github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68 h1:EQP2Tv8T
|
|||||||
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
|
github.com/jesseduffield/generics v0.0.0-20220320043834-727e535cbe68/go.mod h1:+LLj9/WUPAP8LqCchs7P+7X0R98HiFujVFANdNaxhGk=
|
||||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
|
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d h1:bO+OmbreIv91rCe8NmscRwhFSqkDJtzWCPV4Y+SQuXE=
|
||||||
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
|
github.com/jesseduffield/go-git/v5 v5.1.2-0.20221018185014-fdd53fef665d/go.mod h1:nGNEErzf+NRznT+N2SWqmHnDnF9aLgANB1CUNEan09o=
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20230601121845-cb89273fdd4e h1:NpsrRAbYUmMkxDgNAVSlu3LxtfwdDe140vWVo/VldgA=
|
github.com/jesseduffield/gocui v0.3.1-0.20230702054502-d6c452fc12ce h1:Xgm21B1an/outcRxnkDfMT6wKb6SKBR05jXOyfPA8WQ=
|
||||||
github.com/jesseduffield/gocui v0.3.1-0.20230601121845-cb89273fdd4e/go.mod h1:dJ/BEUt3OWtaRg/PmuJWendRqREhre9JQ1SLvqrVJ8s=
|
github.com/jesseduffield/gocui v0.3.1-0.20230702054502-d6c452fc12ce/go.mod h1:dJ/BEUt3OWtaRg/PmuJWendRqREhre9JQ1SLvqrVJ8s=
|
||||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
|
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0=
|
||||||
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
|
github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo=
|
||||||
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
|
github.com/jesseduffield/lazycore v0.0.0-20221012050358-03d2e40243c5 h1:CDuQmfOjAtb1Gms6a1p5L2P8RhbLUq5t8aL7PiQd2uY=
|
||||||
@ -206,21 +206,22 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||||
|
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
@ -23,3 +23,7 @@ func (f *CommitFile) Added() bool {
|
|||||||
func (f *CommitFile) Deleted() bool {
|
func (f *CommitFile) Deleted() bool {
|
||||||
return f.ChangeStatus == "D"
|
return f.ChangeStatus == "D"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *CommitFile) GetPath() string {
|
||||||
|
return f.Name
|
||||||
|
}
|
||||||
|
@ -60,15 +60,16 @@ type GuiConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ThemeConfig struct {
|
type ThemeConfig struct {
|
||||||
ActiveBorderColor []string `yaml:"activeBorderColor"`
|
ActiveBorderColor []string `yaml:"activeBorderColor"`
|
||||||
InactiveBorderColor []string `yaml:"inactiveBorderColor"`
|
InactiveBorderColor []string `yaml:"inactiveBorderColor"`
|
||||||
OptionsTextColor []string `yaml:"optionsTextColor"`
|
SearchingActiveBorderColor []string `yaml:"searchingActiveBorderColor"`
|
||||||
SelectedLineBgColor []string `yaml:"selectedLineBgColor"`
|
OptionsTextColor []string `yaml:"optionsTextColor"`
|
||||||
SelectedRangeBgColor []string `yaml:"selectedRangeBgColor"`
|
SelectedLineBgColor []string `yaml:"selectedLineBgColor"`
|
||||||
CherryPickedCommitBgColor []string `yaml:"cherryPickedCommitBgColor"`
|
SelectedRangeBgColor []string `yaml:"selectedRangeBgColor"`
|
||||||
CherryPickedCommitFgColor []string `yaml:"cherryPickedCommitFgColor"`
|
CherryPickedCommitBgColor []string `yaml:"cherryPickedCommitBgColor"`
|
||||||
UnstagedChangesColor []string `yaml:"unstagedChangesColor"`
|
CherryPickedCommitFgColor []string `yaml:"cherryPickedCommitFgColor"`
|
||||||
DefaultFgColor []string `yaml:"defaultFgColor"`
|
UnstagedChangesColor []string `yaml:"unstagedChangesColor"`
|
||||||
|
DefaultFgColor []string `yaml:"defaultFgColor"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommitLengthConfig struct {
|
type CommitLengthConfig struct {
|
||||||
@ -409,15 +410,16 @@ func GetDefaultConfig() *UserConfig {
|
|||||||
TimeFormat: "02 Jan 06",
|
TimeFormat: "02 Jan 06",
|
||||||
ShortTimeFormat: time.Kitchen,
|
ShortTimeFormat: time.Kitchen,
|
||||||
Theme: ThemeConfig{
|
Theme: ThemeConfig{
|
||||||
ActiveBorderColor: []string{"green", "bold"},
|
ActiveBorderColor: []string{"green", "bold"},
|
||||||
InactiveBorderColor: []string{"default"},
|
SearchingActiveBorderColor: []string{"cyan", "bold"},
|
||||||
OptionsTextColor: []string{"blue"},
|
InactiveBorderColor: []string{"default"},
|
||||||
SelectedLineBgColor: []string{"blue"},
|
OptionsTextColor: []string{"blue"},
|
||||||
SelectedRangeBgColor: []string{"blue"},
|
SelectedLineBgColor: []string{"blue"},
|
||||||
CherryPickedCommitBgColor: []string{"cyan"},
|
SelectedRangeBgColor: []string{"blue"},
|
||||||
CherryPickedCommitFgColor: []string{"blue"},
|
CherryPickedCommitBgColor: []string{"cyan"},
|
||||||
UnstagedChangesColor: []string{"red"},
|
CherryPickedCommitFgColor: []string{"blue"},
|
||||||
DefaultFgColor: []string{"default"},
|
UnstagedChangesColor: []string{"red"},
|
||||||
|
DefaultFgColor: []string{"default"},
|
||||||
},
|
},
|
||||||
CommitLength: CommitLengthConfig{Show: true},
|
CommitLength: CommitLengthConfig{Show: true},
|
||||||
SkipNoStagedFilesWarning: false,
|
SkipNoStagedFilesWarning: false,
|
||||||
|
@ -135,10 +135,6 @@ func (gui *Gui) getRandomTip() string {
|
|||||||
"To escape a mode, for example cherry-picking, patch-building, diffing, or filtering mode, you can just spam the '%s' button. Unless of course you have `quitOnTopLevelReturn` enabled in your config",
|
"To escape a mode, for example cherry-picking, patch-building, diffing, or filtering mode, you can just spam the '%s' button. Unless of course you have `quitOnTopLevelReturn` enabled in your config",
|
||||||
formattedKey(config.Universal.Return),
|
formattedKey(config.Universal.Return),
|
||||||
),
|
),
|
||||||
fmt.Sprintf(
|
|
||||||
"To search for a string in your panel, press '%s'",
|
|
||||||
formattedKey(config.Universal.StartSearch),
|
|
||||||
),
|
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"You can page through the items of a panel using '%s' and '%s'",
|
"You can page through the items of a panel using '%s' and '%s'",
|
||||||
formattedKey(config.Universal.PrevPage),
|
formattedKey(config.Universal.PrevPage),
|
||||||
|
@ -200,9 +200,9 @@ func (self *ContextMgr) RemoveContexts(contextsToRemove []types.Context) error {
|
|||||||
func (self *ContextMgr) deactivateContext(c types.Context, opts types.OnFocusLostOpts) error {
|
func (self *ContextMgr) deactivateContext(c types.Context, opts types.OnFocusLostOpts) error {
|
||||||
view, _ := self.gui.c.GocuiGui().View(c.GetViewName())
|
view, _ := self.gui.c.GocuiGui().View(c.GetViewName())
|
||||||
|
|
||||||
if view != nil && view.IsSearching() {
|
if opts.NewContextKey != context.SEARCH_CONTEXT_KEY {
|
||||||
if err := self.gui.onSearchEscape(); err != nil {
|
if c.GetKind() == types.MAIN_CONTEXT || c.GetKind() == types.TEMPORARY_POPUP {
|
||||||
return err
|
self.gui.helpers.Search.CancelSearchIfSearching(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,6 +234,8 @@ func (self *ContextMgr) ActivateContext(c types.Context, opts types.OnFocusOpts)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.gui.helpers.Search.RenderSearchStatus(c)
|
||||||
|
|
||||||
desiredTitle := c.Title()
|
desiredTitle := c.Title()
|
||||||
if desiredTitle != "" {
|
if desiredTitle != "" {
|
||||||
v.Title = desiredTitle
|
v.Title = desiredTitle
|
||||||
@ -326,6 +328,30 @@ func (self *ContextMgr) IsCurrent(c types.Context) bool {
|
|||||||
return self.Current().GetKey() == c.GetKey()
|
return self.Current().GetKey() == c.GetKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *ContextMgr) AllFilterable() []types.IFilterableContext {
|
||||||
|
var result []types.IFilterableContext
|
||||||
|
|
||||||
|
for _, context := range self.allContexts.Flatten() {
|
||||||
|
if ctx, ok := context.(types.IFilterableContext); ok {
|
||||||
|
result = append(result, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ContextMgr) AllSearchable() []types.ISearchableContext {
|
||||||
|
var result []types.ISearchableContext
|
||||||
|
|
||||||
|
for _, context := range self.allContexts.Flatten() {
|
||||||
|
if ctx, ok := context.(types.ISearchableContext); ok {
|
||||||
|
result = append(result, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// all list contexts
|
// all list contexts
|
||||||
func (self *ContextMgr) AllList() []types.IListContext {
|
func (self *ContextMgr) AllList() []types.IListContext {
|
||||||
var listContexts []types.IListContext
|
var listContexts []types.IListContext
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type BranchesContext struct {
|
type BranchesContext struct {
|
||||||
*BasicViewModel[*models.Branch]
|
*FilteredListViewModel[*models.Branch]
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,11 +17,16 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func NewBranchesContext(c *ContextCommon) *BranchesContext {
|
func NewBranchesContext(c *ContextCommon) *BranchesContext {
|
||||||
viewModel := NewBasicViewModel(func() []*models.Branch { return c.Model().Branches })
|
viewModel := NewFilteredListViewModel(
|
||||||
|
func() []*models.Branch { return c.Model().Branches },
|
||||||
|
func(branch *models.Branch) []string {
|
||||||
|
return []string{branch.Name}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
getDisplayStrings := func(startIdx int, length int) [][]string {
|
getDisplayStrings := func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetBranchListDisplayStrings(
|
return presentation.GetBranchListDisplayStrings(
|
||||||
c.Model().Branches,
|
viewModel.GetItems(),
|
||||||
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
||||||
c.Modes().Diffing.Ref,
|
c.Modes().Diffing.Ref,
|
||||||
c.Tr,
|
c.Tr,
|
||||||
@ -30,7 +35,7 @@ func NewBranchesContext(c *ContextCommon) *BranchesContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self := &BranchesContext{
|
self := &BranchesContext{
|
||||||
BasicViewModel: viewModel,
|
FilteredListViewModel: viewModel,
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
View: c.Views().Branches,
|
View: c.Views().Branches,
|
||||||
|
@ -13,6 +13,7 @@ type CommitFilesContext struct {
|
|||||||
*filetree.CommitFileTreeViewModel
|
*filetree.CommitFileTreeViewModel
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
*DynamicTitleBuilder
|
*DynamicTitleBuilder
|
||||||
|
*SearchTrait
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -38,9 +39,10 @@ func NewCommitFilesContext(c *ContextCommon) *CommitFilesContext {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return &CommitFilesContext{
|
ctx := &CommitFilesContext{
|
||||||
CommitFileTreeViewModel: viewModel,
|
CommitFileTreeViewModel: viewModel,
|
||||||
DynamicTitleBuilder: NewDynamicTitleBuilder(c.Tr.CommitFilesDynamicTitle),
|
DynamicTitleBuilder: NewDynamicTitleBuilder(c.Tr.CommitFilesDynamicTitle),
|
||||||
|
SearchTrait: NewSearchTrait(c),
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(
|
Context: NewSimpleContext(
|
||||||
NewBaseContext(NewBaseContextOpts{
|
NewBaseContext(NewBaseContextOpts{
|
||||||
@ -57,6 +59,13 @@ func NewCommitFilesContext(c *ContextCommon) *CommitFilesContext {
|
|||||||
c: c,
|
c: c,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(func(selectedLineIdx int) error {
|
||||||
|
ctx.GetList().SetSelectedLineIdx(selectedLineIdx)
|
||||||
|
return ctx.HandleFocus(types.OnFocusOpts{})
|
||||||
|
}))
|
||||||
|
|
||||||
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *CommitFilesContext) GetSelectedItemId() string {
|
func (self *CommitFilesContext) GetSelectedItemId() string {
|
||||||
|
93
pkg/gui/context/filtered_list.go
Normal file
93
pkg/gui/context/filtered_list.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
|
"github.com/sasha-s/go-deadlock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FilteredList[T any] struct {
|
||||||
|
filteredIndices []int // if nil, we are not filtering
|
||||||
|
|
||||||
|
getList func() []T
|
||||||
|
getFilterFields func(T) []string
|
||||||
|
filter string
|
||||||
|
|
||||||
|
mutex *deadlock.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFilteredList[T any](getList func() []T, getFilterFields func(T) []string) *FilteredList[T] {
|
||||||
|
return &FilteredList[T]{
|
||||||
|
getList: getList,
|
||||||
|
getFilterFields: getFilterFields,
|
||||||
|
mutex: &deadlock.Mutex{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilteredList[T]) GetFilter() string {
|
||||||
|
return self.filter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilteredList[T]) SetFilter(filter string) {
|
||||||
|
self.filter = filter
|
||||||
|
|
||||||
|
self.applyFilter()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilteredList[T]) ClearFilter() {
|
||||||
|
self.SetFilter("")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilteredList[T]) IsFiltering() bool {
|
||||||
|
return self.filter != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilteredList[T]) GetFilteredList() []T {
|
||||||
|
if self.filteredIndices == nil {
|
||||||
|
return self.getList()
|
||||||
|
}
|
||||||
|
return utils.ValuesAtIndices(self.getList(), self.filteredIndices)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: update to just 'Len'
|
||||||
|
func (self *FilteredList[T]) UnfilteredLen() int {
|
||||||
|
return len(self.getList())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilteredList[T]) applyFilter() {
|
||||||
|
self.mutex.Lock()
|
||||||
|
defer self.mutex.Unlock()
|
||||||
|
|
||||||
|
if self.filter == "" {
|
||||||
|
self.filteredIndices = nil
|
||||||
|
} else {
|
||||||
|
self.filteredIndices = []int{}
|
||||||
|
for i, item := range self.getList() {
|
||||||
|
for _, field := range self.getFilterFields(item) {
|
||||||
|
if self.match(field, self.filter) {
|
||||||
|
self.filteredIndices = append(self.filteredIndices, i)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilteredList[T]) match(haystack string, needle string) bool {
|
||||||
|
return utils.CaseAwareContains(haystack, needle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilteredList[T]) UnfilteredIndex(index int) int {
|
||||||
|
self.mutex.Lock()
|
||||||
|
defer self.mutex.Unlock()
|
||||||
|
|
||||||
|
if self.filteredIndices == nil {
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
// we use -1 when there are no items
|
||||||
|
if index == -1 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.filteredIndices[index]
|
||||||
|
}
|
33
pkg/gui/context/filtered_list_view_model.go
Normal file
33
pkg/gui/context/filtered_list_view_model.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package context
|
||||||
|
|
||||||
|
type FilteredListViewModel[T any] struct {
|
||||||
|
*FilteredList[T]
|
||||||
|
*ListViewModel[T]
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFilteredListViewModel[T any](getList func() []T, getFilterFields func(T) []string) *FilteredListViewModel[T] {
|
||||||
|
filteredList := NewFilteredList(getList, getFilterFields)
|
||||||
|
|
||||||
|
self := &FilteredListViewModel[T]{
|
||||||
|
FilteredList: filteredList,
|
||||||
|
}
|
||||||
|
|
||||||
|
listViewModel := NewListViewModel(filteredList.GetFilteredList)
|
||||||
|
|
||||||
|
self.ListViewModel = listViewModel
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
// used for type switch
|
||||||
|
func (self *FilteredListViewModel[T]) IsFilterableContext() {}
|
||||||
|
|
||||||
|
func (self *FilteredListViewModel[T]) ClearFilter() {
|
||||||
|
// Set the selected line index to the unfiltered index of the currently selected line,
|
||||||
|
// so that the current item is still selected after the filter is cleared.
|
||||||
|
unfilteredIndex := self.FilteredList.UnfilteredIndex(self.GetSelectedLineIdx())
|
||||||
|
|
||||||
|
self.FilteredList.ClearFilter()
|
||||||
|
|
||||||
|
self.SetSelectedLineIdx(unfilteredIndex)
|
||||||
|
}
|
@ -2,13 +2,13 @@ package context
|
|||||||
|
|
||||||
import "github.com/jesseduffield/lazygit/pkg/gui/context/traits"
|
import "github.com/jesseduffield/lazygit/pkg/gui/context/traits"
|
||||||
|
|
||||||
type BasicViewModel[T any] struct {
|
type ListViewModel[T any] struct {
|
||||||
*traits.ListCursor
|
*traits.ListCursor
|
||||||
getModel func() []T
|
getModel func() []T
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBasicViewModel[T any](getModel func() []T) *BasicViewModel[T] {
|
func NewListViewModel[T any](getModel func() []T) *ListViewModel[T] {
|
||||||
self := &BasicViewModel[T]{
|
self := &ListViewModel[T]{
|
||||||
getModel: getModel,
|
getModel: getModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,11 +17,11 @@ func NewBasicViewModel[T any](getModel func() []T) *BasicViewModel[T] {
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BasicViewModel[T]) Len() int {
|
func (self *ListViewModel[T]) Len() int {
|
||||||
return len(self.getModel())
|
return len(self.getModel())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *BasicViewModel[T]) GetSelected() T {
|
func (self *ListViewModel[T]) GetSelected() T {
|
||||||
if self.Len() == 0 {
|
if self.Len() == 0 {
|
||||||
return Zero[T]()
|
return Zero[T]()
|
||||||
}
|
}
|
||||||
@ -29,6 +29,10 @@ func (self *BasicViewModel[T]) GetSelected() T {
|
|||||||
return self.getModel()[self.GetSelectedLineIdx()]
|
return self.getModel()[self.GetSelectedLineIdx()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *ListViewModel[T]) GetItems() []T {
|
||||||
|
return self.getModel()
|
||||||
|
}
|
||||||
|
|
||||||
func Zero[T any]() T {
|
func Zero[T any]() T {
|
||||||
return *new(T)
|
return *new(T)
|
||||||
}
|
}
|
@ -13,6 +13,7 @@ import (
|
|||||||
type LocalCommitsContext struct {
|
type LocalCommitsContext struct {
|
||||||
*LocalCommitsViewModel
|
*LocalCommitsViewModel
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
|
*SearchTrait
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -57,8 +58,9 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &LocalCommitsContext{
|
ctx := &LocalCommitsContext{
|
||||||
LocalCommitsViewModel: viewModel,
|
LocalCommitsViewModel: viewModel,
|
||||||
|
SearchTrait: NewSearchTrait(c),
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
View: c.Views().Commits,
|
View: c.Views().Commits,
|
||||||
@ -73,6 +75,13 @@ func NewLocalCommitsContext(c *ContextCommon) *LocalCommitsContext {
|
|||||||
refreshViewportOnChange: true,
|
refreshViewportOnChange: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(func(selectedLineIdx int) error {
|
||||||
|
ctx.GetList().SetSelectedLineIdx(selectedLineIdx)
|
||||||
|
return ctx.HandleFocus(types.OnFocusOpts{})
|
||||||
|
}))
|
||||||
|
|
||||||
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsContext) GetSelectedItemId() string {
|
func (self *LocalCommitsContext) GetSelectedItemId() string {
|
||||||
@ -85,7 +94,7 @@ func (self *LocalCommitsContext) GetSelectedItemId() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type LocalCommitsViewModel struct {
|
type LocalCommitsViewModel struct {
|
||||||
*BasicViewModel[*models.Commit]
|
*ListViewModel[*models.Commit]
|
||||||
|
|
||||||
// If this is true we limit the amount of commits we load, for the sake of keeping things fast.
|
// If this is true we limit the amount of commits we load, for the sake of keeping things fast.
|
||||||
// If the user attempts to scroll past the end of the list, we will load more commits.
|
// If the user attempts to scroll past the end of the list, we will load more commits.
|
||||||
@ -97,7 +106,7 @@ type LocalCommitsViewModel struct {
|
|||||||
|
|
||||||
func NewLocalCommitsViewModel(getModel func() []*models.Commit, c *ContextCommon) *LocalCommitsViewModel {
|
func NewLocalCommitsViewModel(getModel func() []*models.Commit, c *ContextCommon) *LocalCommitsViewModel {
|
||||||
self := &LocalCommitsViewModel{
|
self := &LocalCommitsViewModel{
|
||||||
BasicViewModel: NewBasicViewModel(getModel),
|
ListViewModel: NewListViewModel(getModel),
|
||||||
limitCommits: true,
|
limitCommits: true,
|
||||||
showWholeGitGraph: c.UserConfig.Git.Log.ShowWholeGraph,
|
showWholeGitGraph: c.UserConfig.Git.Log.ShowWholeGraph,
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ func (self *MenuContext) GetSelectedItemId() string {
|
|||||||
type MenuViewModel struct {
|
type MenuViewModel struct {
|
||||||
c *ContextCommon
|
c *ContextCommon
|
||||||
menuItems []*types.MenuItem
|
menuItems []*types.MenuItem
|
||||||
*BasicViewModel[*types.MenuItem]
|
*FilteredListViewModel[*types.MenuItem]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMenuViewModel(c *ContextCommon) *MenuViewModel {
|
func NewMenuViewModel(c *ContextCommon) *MenuViewModel {
|
||||||
@ -65,7 +65,10 @@ func NewMenuViewModel(c *ContextCommon) *MenuViewModel {
|
|||||||
c: c,
|
c: c,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.BasicViewModel = NewBasicViewModel(func() []*types.MenuItem { return self.menuItems })
|
self.FilteredListViewModel = NewFilteredListViewModel(
|
||||||
|
func() []*types.MenuItem { return self.menuItems },
|
||||||
|
func(item *types.MenuItem) []string { return item.LabelColumns },
|
||||||
|
)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
@ -76,11 +79,12 @@ func (self *MenuViewModel) SetMenuItems(items []*types.MenuItem) {
|
|||||||
|
|
||||||
// TODO: move into presentation package
|
// TODO: move into presentation package
|
||||||
func (self *MenuViewModel) GetDisplayStrings(_startIdx int, _length int) [][]string {
|
func (self *MenuViewModel) GetDisplayStrings(_startIdx int, _length int) [][]string {
|
||||||
showKeys := slices.Some(self.menuItems, func(item *types.MenuItem) bool {
|
menuItems := self.FilteredListViewModel.GetItems()
|
||||||
|
showKeys := slices.Some(menuItems, func(item *types.MenuItem) bool {
|
||||||
return item.Key != nil
|
return item.Key != nil
|
||||||
})
|
})
|
||||||
|
|
||||||
return slices.Map(self.menuItems, func(item *types.MenuItem) []string {
|
return slices.Map(menuItems, func(item *types.MenuItem) []string {
|
||||||
displayStrings := item.LabelColumns
|
displayStrings := item.LabelColumns
|
||||||
|
|
||||||
if !showKeys {
|
if !showKeys {
|
||||||
@ -93,6 +97,7 @@ func (self *MenuViewModel) GetDisplayStrings(_startIdx int, _length int) [][]str
|
|||||||
self.c.UserConfig.Keybinding.Universal.Confirm,
|
self.c.UserConfig.Keybinding.Universal.Confirm,
|
||||||
self.c.UserConfig.Keybinding.Universal.Select,
|
self.c.UserConfig.Keybinding.Universal.Select,
|
||||||
self.c.UserConfig.Keybinding.Universal.Return,
|
self.c.UserConfig.Keybinding.Universal.Return,
|
||||||
|
self.c.UserConfig.Keybinding.Universal.StartSearch,
|
||||||
}
|
}
|
||||||
keyLabel := keybindings.LabelFromKey(item.Key)
|
keyLabel := keybindings.LabelFromKey(item.Key)
|
||||||
keyStyle := style.FgCyan
|
keyStyle := style.FgCyan
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
type PatchExplorerContext struct {
|
type PatchExplorerContext struct {
|
||||||
*SimpleContext
|
*SimpleContext
|
||||||
|
*SearchTrait
|
||||||
|
|
||||||
state *patch_exploring.State
|
state *patch_exploring.State
|
||||||
viewTrait *ViewTrait
|
viewTrait *ViewTrait
|
||||||
@ -28,7 +29,7 @@ func NewPatchExplorerContext(
|
|||||||
|
|
||||||
c *ContextCommon,
|
c *ContextCommon,
|
||||||
) *PatchExplorerContext {
|
) *PatchExplorerContext {
|
||||||
return &PatchExplorerContext{
|
ctx := &PatchExplorerContext{
|
||||||
state: nil,
|
state: nil,
|
||||||
viewTrait: NewViewTrait(view),
|
viewTrait: NewViewTrait(view),
|
||||||
c: c,
|
c: c,
|
||||||
@ -42,7 +43,18 @@ func NewPatchExplorerContext(
|
|||||||
Focusable: true,
|
Focusable: true,
|
||||||
HighlightOnFocus: true,
|
HighlightOnFocus: true,
|
||||||
})),
|
})),
|
||||||
|
SearchTrait: NewSearchTrait(c),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(
|
||||||
|
func(selectedLineIdx int) error {
|
||||||
|
ctx.GetMutex().Lock()
|
||||||
|
defer ctx.GetMutex().Unlock()
|
||||||
|
return ctx.NavigateTo(ctx.c.IsCurrentContext(ctx), selectedLineIdx)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *PatchExplorerContext) IsPatchExplorerContext() {}
|
func (self *PatchExplorerContext) IsPatchExplorerContext() {}
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ReflogCommitsContext struct {
|
type ReflogCommitsContext struct {
|
||||||
*BasicViewModel[*models.Commit]
|
*FilteredListViewModel[*models.Commit]
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,11 +19,16 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func NewReflogCommitsContext(c *ContextCommon) *ReflogCommitsContext {
|
func NewReflogCommitsContext(c *ContextCommon) *ReflogCommitsContext {
|
||||||
viewModel := NewBasicViewModel(func() []*models.Commit { return c.Model().FilteredReflogCommits })
|
viewModel := NewFilteredListViewModel(
|
||||||
|
func() []*models.Commit { return c.Model().FilteredReflogCommits },
|
||||||
|
func(commit *models.Commit) []string {
|
||||||
|
return []string{commit.ShortSha(), commit.Name}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
getDisplayStrings := func(startIdx int, length int) [][]string {
|
getDisplayStrings := func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetReflogCommitListDisplayStrings(
|
return presentation.GetReflogCommitListDisplayStrings(
|
||||||
c.Model().FilteredReflogCommits,
|
viewModel.GetItems(),
|
||||||
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
c.State().GetRepoState().GetScreenMode() != types.SCREEN_NORMAL,
|
||||||
c.Modes().CherryPicking.SelectedShaSet(),
|
c.Modes().CherryPicking.SelectedShaSet(),
|
||||||
c.Modes().Diffing.Ref,
|
c.Modes().Diffing.Ref,
|
||||||
@ -35,7 +40,7 @@ func NewReflogCommitsContext(c *ContextCommon) *ReflogCommitsContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &ReflogCommitsContext{
|
return &ReflogCommitsContext{
|
||||||
BasicViewModel: viewModel,
|
FilteredListViewModel: viewModel,
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
View: c.Views().ReflogCommits,
|
View: c.Views().ReflogCommits,
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type RemoteBranchesContext struct {
|
type RemoteBranchesContext struct {
|
||||||
*BasicViewModel[*models.RemoteBranch]
|
*FilteredListViewModel[*models.RemoteBranch]
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
*DynamicTitleBuilder
|
*DynamicTitleBuilder
|
||||||
}
|
}
|
||||||
@ -20,15 +20,20 @@ var (
|
|||||||
func NewRemoteBranchesContext(
|
func NewRemoteBranchesContext(
|
||||||
c *ContextCommon,
|
c *ContextCommon,
|
||||||
) *RemoteBranchesContext {
|
) *RemoteBranchesContext {
|
||||||
viewModel := NewBasicViewModel(func() []*models.RemoteBranch { return c.Model().RemoteBranches })
|
viewModel := NewFilteredListViewModel(
|
||||||
|
func() []*models.RemoteBranch { return c.Model().RemoteBranches },
|
||||||
|
func(remoteBranch *models.RemoteBranch) []string {
|
||||||
|
return []string{remoteBranch.Name}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
getDisplayStrings := func(startIdx int, length int) [][]string {
|
getDisplayStrings := func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetRemoteBranchListDisplayStrings(c.Model().RemoteBranches, c.Modes().Diffing.Ref)
|
return presentation.GetRemoteBranchListDisplayStrings(viewModel.GetItems(), c.Modes().Diffing.Ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &RemoteBranchesContext{
|
return &RemoteBranchesContext{
|
||||||
BasicViewModel: viewModel,
|
FilteredListViewModel: viewModel,
|
||||||
DynamicTitleBuilder: NewDynamicTitleBuilder(c.Tr.RemoteBranchesDynamicTitle),
|
DynamicTitleBuilder: NewDynamicTitleBuilder(c.Tr.RemoteBranchesDynamicTitle),
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
View: c.Views().RemoteBranches,
|
View: c.Views().RemoteBranches,
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type RemotesContext struct {
|
type RemotesContext struct {
|
||||||
*BasicViewModel[*models.Remote]
|
*FilteredListViewModel[*models.Remote]
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,14 +17,19 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func NewRemotesContext(c *ContextCommon) *RemotesContext {
|
func NewRemotesContext(c *ContextCommon) *RemotesContext {
|
||||||
viewModel := NewBasicViewModel(func() []*models.Remote { return c.Model().Remotes })
|
viewModel := NewFilteredListViewModel(
|
||||||
|
func() []*models.Remote { return c.Model().Remotes },
|
||||||
|
func(remote *models.Remote) []string {
|
||||||
|
return []string{remote.Name}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
getDisplayStrings := func(startIdx int, length int) [][]string {
|
getDisplayStrings := func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetRemoteListDisplayStrings(c.Model().Remotes, c.Modes().Diffing.Ref)
|
return presentation.GetRemoteListDisplayStrings(viewModel.GetItems(), c.Modes().Diffing.Ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &RemotesContext{
|
return &RemotesContext{
|
||||||
BasicViewModel: viewModel,
|
FilteredListViewModel: viewModel,
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
View: c.Views().Remotes,
|
View: c.Views().Remotes,
|
||||||
|
74
pkg/gui/context/search_trait.go
Normal file
74
pkg/gui/context/search_trait.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SearchTrait struct {
|
||||||
|
c *ContextCommon
|
||||||
|
|
||||||
|
searchString string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSearchTrait(c *ContextCommon) *SearchTrait {
|
||||||
|
return &SearchTrait{c: c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchTrait) GetSearchString() string {
|
||||||
|
return self.searchString
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchTrait) SetSearchString(searchString string) {
|
||||||
|
self.searchString = searchString
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchTrait) ClearSearchString() {
|
||||||
|
self.SetSearchString("")
|
||||||
|
}
|
||||||
|
|
||||||
|
// used for type switch
|
||||||
|
func (self *SearchTrait) IsSearchableContext() {}
|
||||||
|
|
||||||
|
func (self *SearchTrait) onSelectItemWrapper(innerFunc func(int) error) func(int, int, int) error {
|
||||||
|
keybindingConfig := self.c.UserConfig.Keybinding
|
||||||
|
|
||||||
|
return func(y int, index int, total int) error {
|
||||||
|
if total == 0 {
|
||||||
|
self.c.SetViewContent(
|
||||||
|
self.c.Views().Search,
|
||||||
|
fmt.Sprintf(
|
||||||
|
self.c.Tr.NoMatchesFor,
|
||||||
|
self.searchString,
|
||||||
|
theme.OptionsFgColor.Sprintf(self.c.Tr.ExitSearchMode, keybindings.Label(keybindingConfig.Universal.Return)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
self.c.SetViewContent(
|
||||||
|
self.c.Views().Search,
|
||||||
|
fmt.Sprintf(
|
||||||
|
self.c.Tr.MatchesFor,
|
||||||
|
self.searchString,
|
||||||
|
index+1,
|
||||||
|
total,
|
||||||
|
theme.OptionsFgColor.Sprintf(
|
||||||
|
self.c.Tr.SearchKeybindings,
|
||||||
|
keybindings.Label(keybindingConfig.Universal.NextMatch),
|
||||||
|
keybindings.Label(keybindingConfig.Universal.PrevMatch),
|
||||||
|
keybindings.Label(keybindingConfig.Universal.Return),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err := innerFunc(y); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchTrait) IsSearching() bool {
|
||||||
|
return self.searchString != ""
|
||||||
|
}
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type StashContext struct {
|
type StashContext struct {
|
||||||
*BasicViewModel[*models.StashEntry]
|
*FilteredListViewModel[*models.StashEntry]
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,14 +19,19 @@ var (
|
|||||||
func NewStashContext(
|
func NewStashContext(
|
||||||
c *ContextCommon,
|
c *ContextCommon,
|
||||||
) *StashContext {
|
) *StashContext {
|
||||||
viewModel := NewBasicViewModel(func() []*models.StashEntry { return c.Model().StashEntries })
|
viewModel := NewFilteredListViewModel(
|
||||||
|
func() []*models.StashEntry { return c.Model().StashEntries },
|
||||||
|
func(stashEntry *models.StashEntry) []string {
|
||||||
|
return []string{stashEntry.Name}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
getDisplayStrings := func(startIdx int, length int) [][]string {
|
getDisplayStrings := func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetStashEntryListDisplayStrings(c.Model().StashEntries, c.Modes().Diffing.Ref)
|
return presentation.GetStashEntryListDisplayStrings(viewModel.GetItems(), c.Modes().Diffing.Ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &StashContext{
|
return &StashContext{
|
||||||
BasicViewModel: viewModel,
|
FilteredListViewModel: viewModel,
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
View: c.Views().Stash,
|
View: c.Views().Stash,
|
||||||
|
@ -12,9 +12,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SubCommitsContext struct {
|
type SubCommitsContext struct {
|
||||||
|
c *ContextCommon
|
||||||
|
|
||||||
*SubCommitsViewModel
|
*SubCommitsViewModel
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
*DynamicTitleBuilder
|
*DynamicTitleBuilder
|
||||||
|
*SearchTrait
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -26,7 +29,7 @@ func NewSubCommitsContext(
|
|||||||
c *ContextCommon,
|
c *ContextCommon,
|
||||||
) *SubCommitsContext {
|
) *SubCommitsContext {
|
||||||
viewModel := &SubCommitsViewModel{
|
viewModel := &SubCommitsViewModel{
|
||||||
BasicViewModel: NewBasicViewModel(
|
ListViewModel: NewListViewModel(
|
||||||
func() []*models.Commit { return c.Model().SubCommits },
|
func() []*models.Commit { return c.Model().SubCommits },
|
||||||
),
|
),
|
||||||
ref: nil,
|
ref: nil,
|
||||||
@ -60,8 +63,10 @@ func NewSubCommitsContext(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SubCommitsContext{
|
ctx := &SubCommitsContext{
|
||||||
|
c: c,
|
||||||
SubCommitsViewModel: viewModel,
|
SubCommitsViewModel: viewModel,
|
||||||
|
SearchTrait: NewSearchTrait(c),
|
||||||
DynamicTitleBuilder: NewDynamicTitleBuilder(c.Tr.SubCommitsDynamicTitle),
|
DynamicTitleBuilder: NewDynamicTitleBuilder(c.Tr.SubCommitsDynamicTitle),
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
@ -78,12 +83,19 @@ func NewSubCommitsContext(
|
|||||||
refreshViewportOnChange: true,
|
refreshViewportOnChange: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(func(selectedLineIdx int) error {
|
||||||
|
ctx.GetList().SetSelectedLineIdx(selectedLineIdx)
|
||||||
|
return ctx.HandleFocus(types.OnFocusOpts{})
|
||||||
|
}))
|
||||||
|
|
||||||
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubCommitsViewModel struct {
|
type SubCommitsViewModel struct {
|
||||||
// name of the ref that the sub-commits are shown for
|
// name of the ref that the sub-commits are shown for
|
||||||
ref types.Ref
|
ref types.Ref
|
||||||
*BasicViewModel[*models.Commit]
|
*ListViewModel[*models.Commit]
|
||||||
|
|
||||||
limitCommits bool
|
limitCommits bool
|
||||||
}
|
}
|
||||||
|
@ -7,21 +7,26 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SubmodulesContext struct {
|
type SubmodulesContext struct {
|
||||||
*BasicViewModel[*models.SubmoduleConfig]
|
*FilteredListViewModel[*models.SubmoduleConfig]
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ types.IListContext = (*SubmodulesContext)(nil)
|
var _ types.IListContext = (*SubmodulesContext)(nil)
|
||||||
|
|
||||||
func NewSubmodulesContext(c *ContextCommon) *SubmodulesContext {
|
func NewSubmodulesContext(c *ContextCommon) *SubmodulesContext {
|
||||||
viewModel := NewBasicViewModel(func() []*models.SubmoduleConfig { return c.Model().Submodules })
|
viewModel := NewFilteredListViewModel(
|
||||||
|
func() []*models.SubmoduleConfig { return c.Model().Submodules },
|
||||||
|
func(submodule *models.SubmoduleConfig) []string {
|
||||||
|
return []string{submodule.Name}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
getDisplayStrings := func(startIdx int, length int) [][]string {
|
getDisplayStrings := func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetSubmoduleListDisplayStrings(c.Model().Submodules)
|
return presentation.GetSubmoduleListDisplayStrings(viewModel.GetItems())
|
||||||
}
|
}
|
||||||
|
|
||||||
return &SubmodulesContext{
|
return &SubmodulesContext{
|
||||||
BasicViewModel: viewModel,
|
FilteredListViewModel: viewModel,
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
View: c.Views().Submodules,
|
View: c.Views().Submodules,
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type SuggestionsContext struct {
|
type SuggestionsContext struct {
|
||||||
*BasicViewModel[*types.Suggestion]
|
*ListViewModel[*types.Suggestion]
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
|
|
||||||
State *SuggestionsContextState
|
State *SuggestionsContextState
|
||||||
@ -40,11 +40,11 @@ func NewSuggestionsContext(
|
|||||||
return presentation.GetSuggestionListDisplayStrings(state.Suggestions)
|
return presentation.GetSuggestionListDisplayStrings(state.Suggestions)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel := NewBasicViewModel(getModel)
|
viewModel := NewListViewModel(getModel)
|
||||||
|
|
||||||
return &SuggestionsContext{
|
return &SuggestionsContext{
|
||||||
State: state,
|
State: state,
|
||||||
BasicViewModel: viewModel,
|
ListViewModel: viewModel,
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
View: c.Views().Suggestions,
|
View: c.Views().Suggestions,
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type TagsContext struct {
|
type TagsContext struct {
|
||||||
*BasicViewModel[*models.Tag]
|
*FilteredListViewModel[*models.Tag]
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,14 +19,19 @@ var (
|
|||||||
func NewTagsContext(
|
func NewTagsContext(
|
||||||
c *ContextCommon,
|
c *ContextCommon,
|
||||||
) *TagsContext {
|
) *TagsContext {
|
||||||
viewModel := NewBasicViewModel(func() []*models.Tag { return c.Model().Tags })
|
viewModel := NewFilteredListViewModel(
|
||||||
|
func() []*models.Tag { return c.Model().Tags },
|
||||||
|
func(tag *models.Tag) []string {
|
||||||
|
return []string{tag.Name, tag.Message}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
getDisplayStrings := func(startIdx int, length int) [][]string {
|
getDisplayStrings := func(startIdx int, length int) [][]string {
|
||||||
return presentation.GetTagListDisplayStrings(c.Model().Tags, c.Modes().Diffing.Ref)
|
return presentation.GetTagListDisplayStrings(viewModel.GetItems(), c.Modes().Diffing.Ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &TagsContext{
|
return &TagsContext{
|
||||||
BasicViewModel: viewModel,
|
FilteredListViewModel: viewModel,
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
View: c.Views().Tags,
|
View: c.Views().Tags,
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
type WorkingTreeContext struct {
|
type WorkingTreeContext struct {
|
||||||
*filetree.FileTreeViewModel
|
*filetree.FileTreeViewModel
|
||||||
*ListContextTrait
|
*ListContextTrait
|
||||||
|
*SearchTrait
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ types.IListContext = (*WorkingTreeContext)(nil)
|
var _ types.IListContext = (*WorkingTreeContext)(nil)
|
||||||
@ -29,7 +30,8 @@ func NewWorkingTreeContext(c *ContextCommon) *WorkingTreeContext {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return &WorkingTreeContext{
|
ctx := &WorkingTreeContext{
|
||||||
|
SearchTrait: NewSearchTrait(c),
|
||||||
FileTreeViewModel: viewModel,
|
FileTreeViewModel: viewModel,
|
||||||
ListContextTrait: &ListContextTrait{
|
ListContextTrait: &ListContextTrait{
|
||||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||||
@ -44,6 +46,13 @@ func NewWorkingTreeContext(c *ContextCommon) *WorkingTreeContext {
|
|||||||
c: c,
|
c: c,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.GetView().SetOnSelectItem(ctx.SearchTrait.onSelectItemWrapper(func(selectedLineIdx int) error {
|
||||||
|
ctx.GetList().SetSelectedLineIdx(selectedLineIdx)
|
||||||
|
return ctx.HandleFocus(types.OnFocusOpts{})
|
||||||
|
}))
|
||||||
|
|
||||||
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *WorkingTreeContext) GetSelectedItemId() string {
|
func (self *WorkingTreeContext) GetSelectedItemId() string {
|
||||||
|
@ -99,6 +99,7 @@ func (gui *Gui) resetHelpersAndControllers() {
|
|||||||
modeHelper,
|
modeHelper,
|
||||||
appStatusHelper,
|
appStatusHelper,
|
||||||
),
|
),
|
||||||
|
Search: helpers.NewSearchHelper(helperCommon),
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.CustomCommandsClient = custom_commands.NewClient(
|
gui.CustomCommandsClient = custom_commands.NewClient(
|
||||||
@ -162,6 +163,16 @@ func (gui *Gui) resetHelpersAndControllers() {
|
|||||||
|
|
||||||
sideWindowControllerFactory := controllers.NewSideWindowControllerFactory(common)
|
sideWindowControllerFactory := controllers.NewSideWindowControllerFactory(common)
|
||||||
|
|
||||||
|
filterControllerFactory := controllers.NewFilterControllerFactory(common)
|
||||||
|
for _, context := range gui.c.Context().AllFilterable() {
|
||||||
|
controllers.AttachControllers(context, filterControllerFactory.Create(context))
|
||||||
|
}
|
||||||
|
|
||||||
|
searchControllerFactory := controllers.NewSearchControllerFactory(common)
|
||||||
|
for _, context := range gui.c.Context().AllSearchable() {
|
||||||
|
controllers.AttachControllers(context, searchControllerFactory.Create(context))
|
||||||
|
}
|
||||||
|
|
||||||
// allow for navigating between side window contexts
|
// allow for navigating between side window contexts
|
||||||
for _, context := range []types.Context{
|
for _, context := range []types.Context{
|
||||||
gui.State.Contexts.Status,
|
gui.State.Contexts.Status,
|
||||||
@ -323,6 +334,10 @@ func (gui *Gui) resetHelpersAndControllers() {
|
|||||||
suggestionsController,
|
suggestionsController,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
controllers.AttachControllers(gui.State.Contexts.Search,
|
||||||
|
controllers.NewSearchPromptController(common),
|
||||||
|
)
|
||||||
|
|
||||||
controllers.AttachControllers(gui.State.Contexts.Global,
|
controllers.AttachControllers(gui.State.Contexts.Global,
|
||||||
syncController,
|
syncController,
|
||||||
undoController,
|
undoController,
|
||||||
|
@ -648,7 +648,7 @@ func (self *FilesController) handleStatusFilterPressed() error {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Label: self.c.Tr.ResetCommitFilterState,
|
Label: self.c.Tr.ResetFilter,
|
||||||
OnPress: func() error {
|
OnPress: func() error {
|
||||||
return self.setStatusFiltering(filetree.DisplayAll)
|
return self.setStatusFiltering(filetree.DisplayAll)
|
||||||
},
|
},
|
||||||
@ -658,7 +658,7 @@ func (self *FilesController) handleStatusFilterPressed() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error {
|
func (self *FilesController) setStatusFiltering(filter filetree.FileTreeDisplayFilter) error {
|
||||||
self.context().FileTreeViewModel.SetFilter(filter)
|
self.context().FileTreeViewModel.SetStatusFilter(filter)
|
||||||
return self.c.PostRefreshUpdate(self.context())
|
return self.c.PostRefreshUpdate(self.context())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
48
pkg/gui/controllers/filter_controller.go
Normal file
48
pkg/gui/controllers/filter_controller.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FilterControllerFactory struct {
|
||||||
|
c *ControllerCommon
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFilterControllerFactory(c *ControllerCommon) *FilterControllerFactory {
|
||||||
|
return &FilterControllerFactory{
|
||||||
|
c: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilterControllerFactory) Create(context types.IFilterableContext) *FilterController {
|
||||||
|
return &FilterController{
|
||||||
|
baseController: baseController{},
|
||||||
|
c: self.c,
|
||||||
|
context: context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FilterController struct {
|
||||||
|
baseController
|
||||||
|
c *ControllerCommon
|
||||||
|
|
||||||
|
context types.IFilterableContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilterController) Context() types.Context {
|
||||||
|
return self.context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilterController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||||
|
return []*types.Binding{
|
||||||
|
{
|
||||||
|
Key: opts.GetKey(opts.Config.Universal.StartSearch),
|
||||||
|
Handler: self.OpenFilterPrompt,
|
||||||
|
Description: self.c.Tr.StartFilter,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FilterController) OpenFilterPrompt() error {
|
||||||
|
return self.c.Helpers().Search.OpenFilterPrompt(self.context)
|
||||||
|
}
|
@ -292,7 +292,9 @@ func (self *ConfirmationHelper) ResizePopupPanel(v *gocui.View, content string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *ConfirmationHelper) resizeMenu() {
|
func (self *ConfirmationHelper) resizeMenu() {
|
||||||
itemCount := self.c.Contexts().Menu.GetList().Len()
|
// we want the unfiltered length here so that if we're filtering we don't
|
||||||
|
// resize the window
|
||||||
|
itemCount := self.c.Contexts().Menu.UnfilteredLen()
|
||||||
offset := 3
|
offset := 3
|
||||||
panelWidth := self.getPopupPanelWidth()
|
panelWidth := self.getPopupPanelWidth()
|
||||||
x0, y0, x1, y1 := self.getPopupPanelDimensionsForContentHeight(panelWidth, itemCount+offset)
|
x0, y0, x1, y1 := self.getPopupPanelDimensionsForContentHeight(panelWidth, itemCount+offset)
|
||||||
|
@ -46,6 +46,7 @@ type Helpers struct {
|
|||||||
Mode *ModeHelper
|
Mode *ModeHelper
|
||||||
AppStatus *AppStatusHelper
|
AppStatus *AppStatusHelper
|
||||||
WindowArrangement *WindowArrangementHelper
|
WindowArrangement *WindowArrangementHelper
|
||||||
|
Search *SearchHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStubHelpers() *Helpers {
|
func NewStubHelpers() *Helpers {
|
||||||
@ -78,5 +79,6 @@ func NewStubHelpers() *Helpers {
|
|||||||
Mode: &ModeHelper{},
|
Mode: &ModeHelper{},
|
||||||
AppStatus: &AppStatusHelper{},
|
AppStatus: &AppStatusHelper{},
|
||||||
WindowArrangement: &WindowArrangementHelper{},
|
WindowArrangement: &WindowArrangementHelper{},
|
||||||
|
Search: &SearchHelper{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,10 +464,10 @@ func (self *RefreshHelper) refreshStateFiles() error {
|
|||||||
// I'd prefer to maintain as little state as possible.
|
// I'd prefer to maintain as little state as possible.
|
||||||
if conflictFileCount > 0 {
|
if conflictFileCount > 0 {
|
||||||
if fileTreeViewModel.GetFilter() == filetree.DisplayAll {
|
if fileTreeViewModel.GetFilter() == filetree.DisplayAll {
|
||||||
fileTreeViewModel.SetFilter(filetree.DisplayConflicted)
|
fileTreeViewModel.SetStatusFilter(filetree.DisplayConflicted)
|
||||||
}
|
}
|
||||||
} else if fileTreeViewModel.GetFilter() == filetree.DisplayConflicted {
|
} else if fileTreeViewModel.GetFilter() == filetree.DisplayConflicted {
|
||||||
fileTreeViewModel.SetFilter(filetree.DisplayAll)
|
fileTreeViewModel.SetStatusFilter(filetree.DisplayAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.c.Model().Files = files
|
self.c.Model().Files = files
|
||||||
|
260
pkg/gui/controllers/helpers/search_helper.go
Normal file
260
pkg/gui/controllers/helpers/search_helper.go
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NOTE: this helper supports both filtering and searching. Filtering is when
|
||||||
|
// the contents of the list are filtered, whereas searching does not actually
|
||||||
|
// change the contents of the list but instead just highlights the search.
|
||||||
|
// The general term we use to capture both searching and filtering is...
|
||||||
|
// 'searching', which is unfortunate but I can't think of a better name.
|
||||||
|
|
||||||
|
type SearchHelper struct {
|
||||||
|
c *HelperCommon
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSearchHelper(
|
||||||
|
c *HelperCommon,
|
||||||
|
) *SearchHelper {
|
||||||
|
return &SearchHelper{
|
||||||
|
c: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) OpenFilterPrompt(context types.IFilterableContext) error {
|
||||||
|
state := self.searchState()
|
||||||
|
|
||||||
|
state.Context = context
|
||||||
|
|
||||||
|
self.searchPrefixView().SetContent(self.c.Tr.FilterPrefix)
|
||||||
|
promptView := self.promptView()
|
||||||
|
promptView.ClearTextArea()
|
||||||
|
promptView.TextArea.TypeString(context.GetFilter())
|
||||||
|
promptView.RenderTextArea()
|
||||||
|
|
||||||
|
if err := self.c.PushContext(self.c.Contexts().Search); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) OpenSearchPrompt(context types.ISearchableContext) error {
|
||||||
|
state := self.searchState()
|
||||||
|
|
||||||
|
state.Context = context
|
||||||
|
searchString := context.GetSearchString()
|
||||||
|
|
||||||
|
self.searchPrefixView().SetContent(self.c.Tr.SearchPrefix)
|
||||||
|
promptView := self.promptView()
|
||||||
|
promptView.ClearTextArea()
|
||||||
|
promptView.TextArea.TypeString(searchString)
|
||||||
|
promptView.RenderTextArea()
|
||||||
|
|
||||||
|
if err := self.c.PushContext(self.c.Contexts().Search); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) DisplayFilterStatus(context types.IFilterableContext) {
|
||||||
|
state := self.searchState()
|
||||||
|
|
||||||
|
state.Context = context
|
||||||
|
searchString := context.GetFilter()
|
||||||
|
|
||||||
|
self.searchPrefixView().SetContent(self.c.Tr.FilterPrefix)
|
||||||
|
|
||||||
|
promptView := self.promptView()
|
||||||
|
keybindingConfig := self.c.UserConfig.Keybinding
|
||||||
|
promptView.SetContent(fmt.Sprintf("matches for '%s' ", searchString) + theme.OptionsFgColor.Sprintf(self.c.Tr.ExitTextFilterMode, keybindings.Label(keybindingConfig.Universal.Return)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) DisplaySearchStatus(context types.ISearchableContext) {
|
||||||
|
state := self.searchState()
|
||||||
|
|
||||||
|
state.Context = context
|
||||||
|
|
||||||
|
self.searchPrefixView().SetContent(self.c.Tr.SearchPrefix)
|
||||||
|
_ = context.GetView().SelectCurrentSearchResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) searchState() *types.SearchState {
|
||||||
|
return self.c.State().GetRepoState().GetSearchState()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) searchPrefixView() *gocui.View {
|
||||||
|
return self.c.Views().SearchPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) promptView() *gocui.View {
|
||||||
|
return self.c.Contexts().Search.GetView()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) promptContent() string {
|
||||||
|
return self.c.Contexts().Search.GetView().TextArea.GetContent()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) Confirm() error {
|
||||||
|
state := self.searchState()
|
||||||
|
if self.promptContent() == "" {
|
||||||
|
return self.CancelPrompt()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch state.SearchType() {
|
||||||
|
case types.SearchTypeFilter:
|
||||||
|
return self.ConfirmFilter()
|
||||||
|
case types.SearchTypeSearch:
|
||||||
|
return self.ConfirmSearch()
|
||||||
|
case types.SearchTypeNone:
|
||||||
|
return self.c.PopContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) ConfirmFilter() error {
|
||||||
|
// We also do this on each keypress but we do it here again just in case
|
||||||
|
state := self.searchState()
|
||||||
|
|
||||||
|
_, ok := state.Context.(types.IFilterableContext)
|
||||||
|
if !ok {
|
||||||
|
self.c.Log.Warnf("Context %s is not filterable", state.Context.GetKey())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
self.OnPromptContentChanged(self.promptContent())
|
||||||
|
|
||||||
|
return self.c.PopContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) ConfirmSearch() error {
|
||||||
|
state := self.searchState()
|
||||||
|
|
||||||
|
context, ok := state.Context.(types.ISearchableContext)
|
||||||
|
if !ok {
|
||||||
|
self.c.Log.Warnf("Context %s is searchable", state.Context.GetKey())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
searchString := self.promptContent()
|
||||||
|
context.SetSearchString(searchString)
|
||||||
|
|
||||||
|
view := context.GetView()
|
||||||
|
|
||||||
|
if err := self.c.PopContext(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := view.Search(searchString); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) CancelPrompt() error {
|
||||||
|
self.Cancel()
|
||||||
|
|
||||||
|
return self.c.PopContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) Cancel() {
|
||||||
|
state := self.searchState()
|
||||||
|
|
||||||
|
switch context := state.Context.(type) {
|
||||||
|
case types.IFilterableContext:
|
||||||
|
context.ClearFilter()
|
||||||
|
_ = self.c.PostRefreshUpdate(context)
|
||||||
|
case types.ISearchableContext:
|
||||||
|
context.ClearSearchString()
|
||||||
|
context.GetView().ClearSearch()
|
||||||
|
default:
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
self.HidePrompt()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) OnPromptContentChanged(searchString string) {
|
||||||
|
state := self.searchState()
|
||||||
|
switch context := state.Context.(type) {
|
||||||
|
case types.IFilterableContext:
|
||||||
|
context.SetSelectedLineIdx(0)
|
||||||
|
_ = context.GetView().SetOriginY(0)
|
||||||
|
context.SetFilter(searchString)
|
||||||
|
_ = self.c.PostRefreshUpdate(context)
|
||||||
|
case types.ISearchableContext:
|
||||||
|
// do nothing
|
||||||
|
default:
|
||||||
|
// do nothing (shouldn't land here)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) RenderSearchStatus(c types.Context) {
|
||||||
|
if c.GetKey() == context.SEARCH_CONTEXT_KEY {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if searchableContext, ok := c.(types.ISearchableContext); ok {
|
||||||
|
if searchableContext.IsSearching() {
|
||||||
|
self.setSearchingFrameColor()
|
||||||
|
self.DisplaySearchStatus(searchableContext)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if filterableContext, ok := c.(types.IFilterableContext); ok {
|
||||||
|
if filterableContext.IsFiltering() {
|
||||||
|
self.setSearchingFrameColor()
|
||||||
|
self.DisplayFilterStatus(filterableContext)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.HidePrompt()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) CancelSearchIfSearching(c types.Context) {
|
||||||
|
if searchableContext, ok := c.(types.ISearchableContext); ok {
|
||||||
|
view := searchableContext.GetView()
|
||||||
|
if view != nil && view.IsSearching() {
|
||||||
|
view.ClearSearch()
|
||||||
|
searchableContext.ClearSearchString()
|
||||||
|
self.Cancel()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if filterableContext, ok := c.(types.IFilterableContext); ok {
|
||||||
|
if filterableContext.IsFiltering() {
|
||||||
|
filterableContext.ClearFilter()
|
||||||
|
self.Cancel()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) HidePrompt() {
|
||||||
|
self.setNonSearchingFrameColor()
|
||||||
|
|
||||||
|
state := self.searchState()
|
||||||
|
state.Context = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) setSearchingFrameColor() {
|
||||||
|
self.c.GocuiGui().SelFgColor = theme.SearchingActiveBorderColor
|
||||||
|
self.c.GocuiGui().SelFrameColor = theme.SearchingActiveBorderColor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchHelper) setNonSearchingFrameColor() {
|
||||||
|
self.c.GocuiGui().SelFgColor = theme.ActiveBorderColor
|
||||||
|
self.c.GocuiGui().SelFrameColor = theme.ActiveBorderColor
|
||||||
|
}
|
@ -55,7 +55,7 @@ func (self *WindowArrangementHelper) GetWindowDimensions(informationStr string,
|
|||||||
self.c.Modes().Filtering.Active()
|
self.c.Modes().Filtering.Active()
|
||||||
|
|
||||||
showInfoSection := self.c.UserConfig.Gui.ShowBottomLine ||
|
showInfoSection := self.c.UserConfig.Gui.ShowBottomLine ||
|
||||||
self.c.State().GetRepoState().IsSearching() ||
|
self.c.State().GetRepoState().InSearchPrompt() ||
|
||||||
self.modeHelper.IsAnyModeActive() ||
|
self.modeHelper.IsAnyModeActive() ||
|
||||||
self.appStatusHelper.HasStatus()
|
self.appStatusHelper.HasStatus()
|
||||||
infoSectionSize := 0
|
infoSectionSize := 0
|
||||||
@ -174,11 +174,17 @@ func (self *WindowArrangementHelper) getMidSectionWeights() (int, int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *WindowArrangementHelper) infoSectionChildren(informationStr string, appStatus string) []*boxlayout.Box {
|
func (self *WindowArrangementHelper) infoSectionChildren(informationStr string, appStatus string) []*boxlayout.Box {
|
||||||
if self.c.State().GetRepoState().IsSearching() {
|
if self.c.State().GetRepoState().InSearchPrompt() {
|
||||||
|
var prefix string
|
||||||
|
if self.c.State().GetRepoState().GetSearchState().SearchType() == types.SearchTypeSearch {
|
||||||
|
prefix = self.c.Tr.SearchPrefix
|
||||||
|
} else {
|
||||||
|
prefix = self.c.Tr.FilterPrefix
|
||||||
|
}
|
||||||
return []*boxlayout.Box{
|
return []*boxlayout.Box{
|
||||||
{
|
{
|
||||||
Window: "searchPrefix",
|
Window: "searchPrefix",
|
||||||
Size: runewidth.StringWidth(self.c.Tr.SearchPrefix),
|
Size: runewidth.StringWidth(prefix),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Window: "search",
|
Window: "search",
|
||||||
|
@ -150,18 +150,7 @@ func (self *ListController) GetKeybindings(opts types.KeybindingsOpts) []*types.
|
|||||||
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Handler: self.HandleGotoTop, Description: self.c.Tr.GotoTop},
|
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoTop), Handler: self.HandleGotoTop, Description: self.c.Tr.GotoTop},
|
||||||
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Handler: self.HandleScrollLeft},
|
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollLeft), Handler: self.HandleScrollLeft},
|
||||||
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Handler: self.HandleScrollRight},
|
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.ScrollRight), Handler: self.HandleScrollRight},
|
||||||
{
|
{Tag: "navigation", Key: opts.GetKey(opts.Config.Universal.GotoBottom), Handler: self.HandleGotoBottom, Description: self.c.Tr.GotoBottom},
|
||||||
Key: opts.GetKey(opts.Config.Universal.StartSearch),
|
|
||||||
Handler: func() error { self.c.OpenSearch(); return nil },
|
|
||||||
Description: self.c.Tr.StartSearch,
|
|
||||||
Tag: "navigation",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: opts.GetKey(opts.Config.Universal.GotoBottom),
|
|
||||||
Description: self.c.Tr.GotoBottom,
|
|
||||||
Handler: self.HandleGotoBottom,
|
|
||||||
Tag: "navigation",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,9 +693,7 @@ func (self *LocalCommitsController) openSearch() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.c.OpenSearch()
|
return self.c.Helpers().Search.OpenSearchPrompt(self.context())
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) gotoBottom() error {
|
func (self *LocalCommitsController) gotoBottom() error {
|
||||||
|
@ -123,12 +123,6 @@ func (self *PatchExplorerController) GetKeybindings(opts types.KeybindingsOpts)
|
|||||||
Key: opts.GetKey(opts.Config.Universal.ScrollRight),
|
Key: opts.GetKey(opts.Config.Universal.ScrollRight),
|
||||||
Handler: self.withRenderAndFocus(self.HandleScrollRight),
|
Handler: self.withRenderAndFocus(self.HandleScrollRight),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Tag: "navigation",
|
|
||||||
Key: opts.GetKey(opts.Config.Universal.StartSearch),
|
|
||||||
Handler: func() error { self.c.OpenSearch(); return nil },
|
|
||||||
Description: self.c.Tr.StartSearch,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
Key: opts.GetKey(opts.Config.Universal.CopyToClipboard),
|
||||||
Handler: self.withLock(self.CopySelectedToClipboard),
|
Handler: self.withLock(self.CopySelectedToClipboard),
|
||||||
|
@ -50,6 +50,19 @@ func (self *QuitActions) confirmQuitDuringUpdate() error {
|
|||||||
func (self *QuitActions) Escape() error {
|
func (self *QuitActions) Escape() error {
|
||||||
currentContext := self.c.CurrentContext()
|
currentContext := self.c.CurrentContext()
|
||||||
|
|
||||||
|
switch ctx := currentContext.(type) {
|
||||||
|
case types.IFilterableContext:
|
||||||
|
if ctx.IsFiltering() {
|
||||||
|
self.c.Helpers().Search.Cancel()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case types.ISearchableContext:
|
||||||
|
if ctx.IsSearching() {
|
||||||
|
self.c.Helpers().Search.Cancel()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parentContext, hasParent := currentContext.GetParentContext()
|
parentContext, hasParent := currentContext.GetParentContext()
|
||||||
if hasParent && currentContext != nil && parentContext != nil {
|
if hasParent && currentContext != nil && parentContext != nil {
|
||||||
// TODO: think about whether this should be marked as a return rather than adding to the stack
|
// TODO: think about whether this should be marked as a return rather than adding to the stack
|
||||||
|
@ -59,11 +59,6 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts)
|
|||||||
Handler: self.checkSelected(self.setAsUpstream),
|
Handler: self.checkSelected(self.setAsUpstream),
|
||||||
Description: self.c.Tr.SetAsUpstream,
|
Description: self.c.Tr.SetAsUpstream,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
|
||||||
Handler: self.escape,
|
|
||||||
Description: self.c.Tr.ReturnToRemotesList,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||||
Handler: self.checkSelected(self.createResetMenu),
|
Handler: self.checkSelected(self.createResetMenu),
|
||||||
@ -115,10 +110,6 @@ func (self *RemoteBranchesController) checkSelected(callback func(*models.Remote
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RemoteBranchesController) escape() error {
|
|
||||||
return self.c.PushContext(self.c.Contexts().Remotes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *RemoteBranchesController) delete(selectedBranch *models.RemoteBranch) error {
|
func (self *RemoteBranchesController) delete(selectedBranch *models.RemoteBranch) error {
|
||||||
message := fmt.Sprintf("%s '%s'?", self.c.Tr.DeleteRemoteBranchMessage, selectedBranch.FullName())
|
message := fmt.Sprintf("%s '%s'?", self.c.Tr.DeleteRemoteBranchMessage, selectedBranch.FullName())
|
||||||
|
|
||||||
|
@ -104,14 +104,16 @@ func (self *RemotesController) enter(remote *models.Remote) error {
|
|||||||
if len(remote.Branches) == 0 {
|
if len(remote.Branches) == 0 {
|
||||||
newSelectedLine = -1
|
newSelectedLine = -1
|
||||||
}
|
}
|
||||||
self.c.Contexts().RemoteBranches.SetSelectedLineIdx(newSelectedLine)
|
remoteBranchesContext := self.c.Contexts().RemoteBranches
|
||||||
self.c.Contexts().RemoteBranches.SetTitleRef(remote.Name)
|
remoteBranchesContext.SetSelectedLineIdx(newSelectedLine)
|
||||||
|
remoteBranchesContext.SetTitleRef(remote.Name)
|
||||||
|
remoteBranchesContext.SetParentContext(self.Context())
|
||||||
|
|
||||||
if err := self.c.PostRefreshUpdate(self.c.Contexts().RemoteBranches); err != nil {
|
if err := self.c.PostRefreshUpdate(remoteBranchesContext); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.c.PushContext(self.c.Contexts().RemoteBranches)
|
return self.c.PushContext(remoteBranchesContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RemotesController) add() error {
|
func (self *RemotesController) add() error {
|
||||||
|
48
pkg/gui/controllers/search_controller.go
Normal file
48
pkg/gui/controllers/search_controller.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SearchControllerFactory struct {
|
||||||
|
c *ControllerCommon
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSearchControllerFactory(c *ControllerCommon) *SearchControllerFactory {
|
||||||
|
return &SearchControllerFactory{
|
||||||
|
c: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchControllerFactory) Create(context types.ISearchableContext) *SearchController {
|
||||||
|
return &SearchController{
|
||||||
|
baseController: baseController{},
|
||||||
|
c: self.c,
|
||||||
|
context: context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchController struct {
|
||||||
|
baseController
|
||||||
|
c *ControllerCommon
|
||||||
|
|
||||||
|
context types.ISearchableContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchController) Context() types.Context {
|
||||||
|
return self.context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||||
|
return []*types.Binding{
|
||||||
|
{
|
||||||
|
Key: opts.GetKey(opts.Config.Universal.StartSearch),
|
||||||
|
Handler: self.OpenSearchPrompt,
|
||||||
|
Description: self.c.Tr.StartSearch,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchController) OpenSearchPrompt() error {
|
||||||
|
return self.c.Helpers().Search.OpenSearchPrompt(self.context)
|
||||||
|
}
|
53
pkg/gui/controllers/search_prompt_controller.go
Normal file
53
pkg/gui/controllers/search_prompt_controller.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SearchPromptController struct {
|
||||||
|
baseController
|
||||||
|
c *ControllerCommon
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ types.IController = &SearchPromptController{}
|
||||||
|
|
||||||
|
func NewSearchPromptController(
|
||||||
|
common *ControllerCommon,
|
||||||
|
) *SearchPromptController {
|
||||||
|
return &SearchPromptController{
|
||||||
|
baseController: baseController{},
|
||||||
|
c: common,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchPromptController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||||
|
return []*types.Binding{
|
||||||
|
{
|
||||||
|
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: self.confirm,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: opts.GetKey(opts.Config.Universal.Return),
|
||||||
|
Modifier: gocui.ModNone,
|
||||||
|
Handler: self.cancel,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchPromptController) Context() types.Context {
|
||||||
|
return self.context()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchPromptController) context() types.Context {
|
||||||
|
return self.c.Contexts().Search
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchPromptController) confirm() error {
|
||||||
|
return self.c.Helpers().Search.Confirm()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchPromptController) cancel() error {
|
||||||
|
return self.c.Helpers().Search.CancelPrompt()
|
||||||
|
}
|
@ -83,6 +83,7 @@ func (self *SwitchToDiffFilesController) viewFiles(opts SwitchToCommitFilesConte
|
|||||||
diffFilesContext.SetCanRebase(opts.CanRebase)
|
diffFilesContext.SetCanRebase(opts.CanRebase)
|
||||||
diffFilesContext.SetParentContext(opts.Context)
|
diffFilesContext.SetParentContext(opts.Context)
|
||||||
diffFilesContext.SetWindowName(opts.Context.GetWindowName())
|
diffFilesContext.SetWindowName(opts.Context.GetWindowName())
|
||||||
|
diffFilesContext.ClearSearchString()
|
||||||
|
|
||||||
if err := self.c.Refresh(types.RefreshOptions{
|
if err := self.c.Refresh(types.RefreshOptions{
|
||||||
Scope: []types.RefreshableView{types.COMMIT_FILES},
|
Scope: []types.RefreshableView{types.COMMIT_FILES},
|
||||||
|
@ -71,12 +71,15 @@ func (self *SwitchToSubCommitsController) viewCommits() error {
|
|||||||
|
|
||||||
self.setSubCommits(commits)
|
self.setSubCommits(commits)
|
||||||
|
|
||||||
self.c.Contexts().SubCommits.SetSelectedLineIdx(0)
|
subCommitsContext := self.c.Contexts().SubCommits
|
||||||
self.c.Contexts().SubCommits.SetParentContext(self.context)
|
subCommitsContext.SetSelectedLineIdx(0)
|
||||||
self.c.Contexts().SubCommits.SetWindowName(self.context.GetWindowName())
|
subCommitsContext.SetParentContext(self.context)
|
||||||
self.c.Contexts().SubCommits.SetTitleRef(ref.Description())
|
subCommitsContext.SetWindowName(self.context.GetWindowName())
|
||||||
self.c.Contexts().SubCommits.SetRef(ref)
|
subCommitsContext.SetTitleRef(ref.Description())
|
||||||
self.c.Contexts().SubCommits.SetLimitCommits(true)
|
subCommitsContext.SetRef(ref)
|
||||||
|
subCommitsContext.SetLimitCommits(true)
|
||||||
|
subCommitsContext.ClearSearchString()
|
||||||
|
subCommitsContext.GetView().ClearSearch()
|
||||||
|
|
||||||
err = self.c.PostRefreshUpdate(self.c.Contexts().SubCommits)
|
err = self.c.PostRefreshUpdate(self.c.Contexts().SubCommits)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -89,3 +89,14 @@ func (gui *Gui) promptEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Mo
|
|||||||
|
|
||||||
return matched
|
return matched
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gui *Gui) searchEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) bool {
|
||||||
|
matched := gui.handleEditorKeypress(v.TextArea, key, ch, mod, false)
|
||||||
|
v.RenderTextArea()
|
||||||
|
|
||||||
|
searchString := v.TextArea.GetContent()
|
||||||
|
|
||||||
|
gui.helpers.Search.OnPromptContentChanged(searchString)
|
||||||
|
|
||||||
|
return matched
|
||||||
|
}
|
||||||
|
@ -34,7 +34,7 @@ type IFileTree interface {
|
|||||||
ITree[models.File]
|
ITree[models.File]
|
||||||
|
|
||||||
FilterFiles(test func(*models.File) bool) []*models.File
|
FilterFiles(test func(*models.File) bool) []*models.File
|
||||||
SetFilter(filter FileTreeDisplayFilter)
|
SetStatusFilter(filter FileTreeDisplayFilter)
|
||||||
Get(index int) *FileNode
|
Get(index int) *FileNode
|
||||||
GetFile(path string) *models.File
|
GetFile(path string) *models.File
|
||||||
GetAllItems() []*FileNode
|
GetAllItems() []*FileNode
|
||||||
@ -91,7 +91,7 @@ func (self *FileTree) FilterFiles(test func(*models.File) bool) []*models.File {
|
|||||||
return slices.Filter(self.getFiles(), test)
|
return slices.Filter(self.getFiles(), test)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileTree) SetFilter(filter FileTreeDisplayFilter) {
|
func (self *FileTree) SetStatusFilter(filter FileTreeDisplayFilter) {
|
||||||
self.filter = filter
|
self.filter = filter
|
||||||
self.SetTree()
|
self.SetTree()
|
||||||
}
|
}
|
||||||
@ -102,7 +102,7 @@ func (self *FileTree) ToggleShowTree() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileTree) Get(index int) *FileNode {
|
func (self *FileTree) Get(index int) *FileNode {
|
||||||
// need to traverse the three depth first until we get to the index.
|
// need to traverse the tree depth first until we get to the index.
|
||||||
return NewFileNode(self.tree.GetNodeAtIndex(index+1, self.collapsedPaths)) // ignoring root
|
return NewFileNode(self.tree.GetNodeAtIndex(index+1, self.collapsedPaths)) // ignoring root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,8 +126,8 @@ func (self *FileTreeViewModel) findNewSelectedIdx(prevNodes []*FileNode, currNod
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileTreeViewModel) SetFilter(filter FileTreeDisplayFilter) {
|
func (self *FileTreeViewModel) SetStatusFilter(filter FileTreeDisplayFilter) {
|
||||||
self.IFileTree.SetFilter(filter)
|
self.IFileTree.SetStatusFilter(filter)
|
||||||
self.IListCursor.SetSelectedLineIdx(0)
|
self.IListCursor.SetSelectedLineIdx(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ type GuiRepoState struct {
|
|||||||
SplitMainPanel bool
|
SplitMainPanel bool
|
||||||
LimitCommits bool
|
LimitCommits bool
|
||||||
|
|
||||||
Searching searchingState
|
SearchState *types.SearchState
|
||||||
StartupStage types.StartupStage // Allows us to not load everything at once
|
StartupStage types.StartupStage // Allows us to not load everything at once
|
||||||
|
|
||||||
ContextMgr *ContextMgr
|
ContextMgr *ContextMgr
|
||||||
@ -256,8 +256,12 @@ func (self *GuiRepoState) SetScreenMode(value types.WindowMaximisation) {
|
|||||||
self.ScreenMode = value
|
self.ScreenMode = value
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *GuiRepoState) IsSearching() bool {
|
func (self *GuiRepoState) InSearchPrompt() bool {
|
||||||
return self.Searching.isSearching
|
return self.SearchState.SearchType() != types.SearchTypeNone
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *GuiRepoState) GetSearchState() *types.SearchState {
|
||||||
|
return self.SearchState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *GuiRepoState) SetSplitMainPanel(value bool) {
|
func (self *GuiRepoState) SetSplitMainPanel(value bool) {
|
||||||
@ -268,12 +272,6 @@ func (self *GuiRepoState) GetSplitMainPanel() bool {
|
|||||||
return self.SplitMainPanel
|
return self.SplitMainPanel
|
||||||
}
|
}
|
||||||
|
|
||||||
type searchingState struct {
|
|
||||||
view *gocui.View
|
|
||||||
isSearching bool
|
|
||||||
searchString string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, reuseState bool) error {
|
func (gui *Gui) onNewRepo(startArgs appTypes.StartArgs, reuseState bool) error {
|
||||||
var err error
|
var err error
|
||||||
gui.git, err = commands.NewGitCommand(
|
gui.git, err = commands.NewGitCommand(
|
||||||
@ -358,6 +356,7 @@ func (gui *Gui) resetState(startArgs appTypes.StartArgs, reuseState bool) types.
|
|||||||
ContextMgr: NewContextMgr(gui, contextTree),
|
ContextMgr: NewContextMgr(gui, contextTree),
|
||||||
Contexts: contextTree,
|
Contexts: contextTree,
|
||||||
WindowViewNameMap: initialWindowViewNameMap(contextTree),
|
WindowViewNameMap: initialWindowViewNameMap(contextTree),
|
||||||
|
SearchState: types.NewSearchState(),
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.RepoStateMap[Repo(currentDir)] = gui.State
|
gui.RepoStateMap[Repo(currentDir)] = gui.State
|
||||||
@ -584,11 +583,12 @@ func (gui *Gui) Run(startArgs appTypes.StartArgs) error {
|
|||||||
})
|
})
|
||||||
deadlock.Opts.Disable = !gui.Debug
|
deadlock.Opts.Disable = !gui.Debug
|
||||||
|
|
||||||
gui.g.OnSearchEscape = gui.onSearchEscape
|
|
||||||
if err := gui.Config.ReloadUserConfig(); err != nil {
|
if err := gui.Config.ReloadUserConfig(); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
userConfig := gui.UserConfig
|
userConfig := gui.UserConfig
|
||||||
|
|
||||||
|
gui.g.OnSearchEscape = func() error { gui.helpers.Search.Cancel(); return nil }
|
||||||
gui.g.SearchEscapeKey = keybindings.GetKey(userConfig.Keybinding.Universal.Return)
|
gui.g.SearchEscapeKey = keybindings.GetKey(userConfig.Keybinding.Universal.Return)
|
||||||
gui.g.NextSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.NextMatch)
|
gui.g.NextSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.NextMatch)
|
||||||
gui.g.PrevSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.PrevMatch)
|
gui.g.PrevSearchMatchKey = keybindings.GetKey(userConfig.Keybinding.Universal.PrevMatch)
|
||||||
|
@ -128,10 +128,6 @@ func (self *guiCommon) Mutexes() types.Mutexes {
|
|||||||
return self.gui.Mutexes
|
return self.gui.Mutexes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *guiCommon) OpenSearch() {
|
|
||||||
_ = self.gui.handleOpenSearch(self.gui.currentViewName())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *guiCommon) GocuiGui() *gocui.Gui {
|
func (self *guiCommon) GocuiGui() *gocui.Gui {
|
||||||
return self.gui.g
|
return self.gui.g
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package gui
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -70,7 +71,8 @@ func (self *GuiDriver) Fail(message string) {
|
|||||||
self.gui.g.Close()
|
self.gui.g.Close()
|
||||||
// need to give the gui time to close
|
// need to give the gui time to close
|
||||||
time.Sleep(time.Millisecond * 100)
|
time.Sleep(time.Millisecond * 100)
|
||||||
panic(fullMessage)
|
fmt.Fprintln(os.Stderr, fullMessage)
|
||||||
|
panic("Test failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// logs to the normal place that you log to i.e. viewable with `lazygit --logs`
|
// logs to the normal place that you log to i.e. viewable with `lazygit --logs`
|
||||||
|
@ -215,18 +215,6 @@ func (self *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBi
|
|||||||
Modifier: gocui.ModNone,
|
Modifier: gocui.ModNone,
|
||||||
Handler: self.scrollUpSecondary,
|
Handler: self.scrollUpSecondary,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
ViewName: "search",
|
|
||||||
Key: opts.GetKey(opts.Config.Universal.Confirm),
|
|
||||||
Modifier: gocui.ModNone,
|
|
||||||
Handler: self.handleSearch,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ViewName: "search",
|
|
||||||
Key: opts.GetKey(opts.Config.Universal.Return),
|
|
||||||
Modifier: gocui.ModNone,
|
|
||||||
Handler: self.handleSearchEscape,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
ViewName: "confirmation",
|
ViewName: "confirmation",
|
||||||
Key: opts.GetKey(opts.Config.Universal.PrevItem),
|
Key: opts.GetKey(opts.Config.Universal.PrevItem),
|
||||||
|
@ -132,20 +132,6 @@ func (gui *Gui) layout(g *gocui.Gui) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
view.SelBgColor = theme.GocuiSelectedLineBgColor
|
view.SelBgColor = theme.GocuiSelectedLineBgColor
|
||||||
|
|
||||||
// I doubt this is expensive though it's admittedly redundant after the first render
|
|
||||||
view.SetOnSelectItem(gui.onSelectItemWrapper(listContext.OnSearchSelect))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, context := range gui.c.Context().AllPatchExplorer() {
|
|
||||||
context := context
|
|
||||||
context.GetView().SetOnSelectItem(gui.onSelectItemWrapper(
|
|
||||||
func(selectedLineIdx int) error {
|
|
||||||
context.GetMutex().Lock()
|
|
||||||
defer context.GetMutex().Unlock()
|
|
||||||
return context.NavigateTo(gui.c.IsCurrentContext(context), selectedLineIdx)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mainViewWidth, mainViewHeight := gui.Views.Main.Size()
|
mainViewWidth, mainViewHeight := gui.Views.Main.Size()
|
||||||
|
@ -46,9 +46,6 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
|
|||||||
|
|
||||||
gui.Views.Menu.Title = opts.Title
|
gui.Views.Menu.Title = opts.Title
|
||||||
gui.Views.Menu.FgColor = theme.GocuiDefaultTextColor
|
gui.Views.Menu.FgColor = theme.GocuiDefaultTextColor
|
||||||
gui.Views.Menu.SetOnSelectItem(gui.onSelectItemWrapper(func(selectedLine int) error {
|
|
||||||
return nil
|
|
||||||
}))
|
|
||||||
|
|
||||||
gui.Views.Tooltip.Wrap = true
|
gui.Views.Tooltip.Wrap = true
|
||||||
gui.Views.Tooltip.FgColor = theme.GocuiDefaultTextColor
|
gui.Views.Tooltip.FgColor = theme.GocuiDefaultTextColor
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
package gui
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/gui/keybindings"
|
|
||||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (gui *Gui) handleOpenSearch(viewName string) error {
|
|
||||||
view, err := gui.g.View(viewName)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.State.Searching.isSearching = true
|
|
||||||
gui.State.Searching.view = view
|
|
||||||
|
|
||||||
gui.Views.Search.ClearTextArea()
|
|
||||||
|
|
||||||
if err := gui.c.PushContext(gui.State.Contexts.Search); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) handleSearch() error {
|
|
||||||
gui.State.Searching.searchString = gui.Views.Search.TextArea.GetContent()
|
|
||||||
if err := gui.c.PopContext(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
view := gui.State.Searching.view
|
|
||||||
if view == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := view.Search(gui.State.Searching.searchString); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) onSelectItemWrapper(innerFunc func(int) error) func(int, int, int) error {
|
|
||||||
keybindingConfig := gui.c.UserConfig.Keybinding
|
|
||||||
|
|
||||||
return func(y int, index int, total int) error {
|
|
||||||
if total == 0 {
|
|
||||||
gui.c.SetViewContent(
|
|
||||||
gui.Views.Search,
|
|
||||||
fmt.Sprintf(
|
|
||||||
gui.Tr.NoMatchesFor,
|
|
||||||
gui.State.Searching.searchString,
|
|
||||||
theme.OptionsFgColor.Sprintf(gui.Tr.ExitSearchMode, keybindings.Label(keybindingConfig.Universal.Return)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
gui.c.SetViewContent(
|
|
||||||
gui.Views.Search,
|
|
||||||
fmt.Sprintf(
|
|
||||||
gui.Tr.MatchesFor,
|
|
||||||
gui.State.Searching.searchString,
|
|
||||||
index+1,
|
|
||||||
total,
|
|
||||||
theme.OptionsFgColor.Sprintf(
|
|
||||||
gui.Tr.SearchKeybindings,
|
|
||||||
keybindings.Label(keybindingConfig.Universal.NextMatch),
|
|
||||||
keybindings.Label(keybindingConfig.Universal.PrevMatch),
|
|
||||||
keybindings.Label(keybindingConfig.Universal.Return),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
if err := innerFunc(y); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) onSearchEscape() error {
|
|
||||||
gui.State.Searching.isSearching = false
|
|
||||||
if gui.State.Searching.view != nil {
|
|
||||||
gui.State.Searching.view.ClearSearch()
|
|
||||||
gui.State.Searching.view = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gui *Gui) handleSearchEscape() error {
|
|
||||||
if err := gui.onSearchEscape(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := gui.c.PopContext(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -68,8 +68,6 @@ type IGuiCommon interface {
|
|||||||
Context() IContextMgr
|
Context() IContextMgr
|
||||||
|
|
||||||
ActivateContext(context Context) error
|
ActivateContext(context Context) error
|
||||||
// enters search mode for the current view
|
|
||||||
OpenSearch()
|
|
||||||
|
|
||||||
GetConfig() config.AppConfigurer
|
GetConfig() config.AppConfigurer
|
||||||
GetAppState() *config.AppState
|
GetAppState() *config.AppState
|
||||||
@ -251,7 +249,8 @@ type IRepoStateAccessor interface {
|
|||||||
SetCurrentPopupOpts(*CreatePopupPanelOpts)
|
SetCurrentPopupOpts(*CreatePopupPanelOpts)
|
||||||
GetScreenMode() WindowMaximisation
|
GetScreenMode() WindowMaximisation
|
||||||
SetScreenMode(WindowMaximisation)
|
SetScreenMode(WindowMaximisation)
|
||||||
IsSearching() bool
|
InSearchPrompt() bool
|
||||||
|
GetSearchState() *SearchState
|
||||||
SetSplitMainPanel(bool)
|
SetSplitMainPanel(bool)
|
||||||
GetSplitMainPanel() bool
|
GetSplitMainPanel() bool
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,27 @@ type Context interface {
|
|||||||
HandleRenderToMain() error
|
HandleRenderToMain() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IFilterableContext interface {
|
||||||
|
Context
|
||||||
|
IListPanelState
|
||||||
|
|
||||||
|
SetFilter(string)
|
||||||
|
GetFilter() string
|
||||||
|
ClearFilter()
|
||||||
|
IsFiltering() bool
|
||||||
|
IsFilterableContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
type ISearchableContext interface {
|
||||||
|
Context
|
||||||
|
|
||||||
|
SetSearchString(string)
|
||||||
|
GetSearchString() string
|
||||||
|
ClearSearchString()
|
||||||
|
IsSearching() bool
|
||||||
|
IsSearchableContext()
|
||||||
|
}
|
||||||
|
|
||||||
type DiffableContext interface {
|
type DiffableContext interface {
|
||||||
Context
|
Context
|
||||||
|
|
||||||
@ -104,7 +125,6 @@ type IListContext interface {
|
|||||||
|
|
||||||
GetList() IList
|
GetList() IList
|
||||||
|
|
||||||
OnSearchSelect(selectedLineIdx int) error
|
|
||||||
FocusLine()
|
FocusLine()
|
||||||
IsListContext() // used for type switch
|
IsListContext() // used for type switch
|
||||||
}
|
}
|
||||||
@ -211,5 +231,7 @@ type IContextMgr interface {
|
|||||||
IsCurrent(c Context) bool
|
IsCurrent(c Context) bool
|
||||||
ForEach(func(Context))
|
ForEach(func(Context))
|
||||||
AllList() []IListContext
|
AllList() []IListContext
|
||||||
|
AllFilterable() []IFilterableContext
|
||||||
|
AllSearchable() []ISearchableContext
|
||||||
AllPatchExplorer() []IPatchExplorerContext
|
AllPatchExplorer() []IPatchExplorerContext
|
||||||
}
|
}
|
||||||
|
31
pkg/gui/types/search_state.go
Normal file
31
pkg/gui/types/search_state.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type SearchType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
SearchTypeNone SearchType = iota
|
||||||
|
// searching is where matches are highlighted but the content is not filtered down
|
||||||
|
SearchTypeSearch
|
||||||
|
// filter is where the list is filtered down to only matches
|
||||||
|
SearchTypeFilter
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: could we remove this entirely?
|
||||||
|
type SearchState struct {
|
||||||
|
Context Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSearchState() *SearchState {
|
||||||
|
return &SearchState{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *SearchState) SearchType() SearchType {
|
||||||
|
switch self.Context.(type) {
|
||||||
|
case IFilterableContext:
|
||||||
|
return SearchTypeFilter
|
||||||
|
case ISearchableContext:
|
||||||
|
return SearchTypeSearch
|
||||||
|
default:
|
||||||
|
return SearchTypeNone
|
||||||
|
}
|
||||||
|
}
|
@ -91,10 +91,16 @@ func (gui *Gui) createAllViews() error {
|
|||||||
gui.Views.Options.Frame = false
|
gui.Views.Options.Frame = false
|
||||||
|
|
||||||
gui.Views.SearchPrefix.BgColor = gocui.ColorDefault
|
gui.Views.SearchPrefix.BgColor = gocui.ColorDefault
|
||||||
gui.Views.SearchPrefix.FgColor = gocui.ColorGreen
|
gui.Views.SearchPrefix.FgColor = gocui.ColorCyan
|
||||||
gui.Views.SearchPrefix.Frame = false
|
gui.Views.SearchPrefix.Frame = false
|
||||||
gui.c.SetViewContent(gui.Views.SearchPrefix, gui.Tr.SearchPrefix)
|
gui.c.SetViewContent(gui.Views.SearchPrefix, gui.Tr.SearchPrefix)
|
||||||
|
|
||||||
|
gui.Views.Search.BgColor = gocui.ColorDefault
|
||||||
|
gui.Views.Search.FgColor = gocui.ColorCyan
|
||||||
|
gui.Views.Search.Editable = true
|
||||||
|
gui.Views.Search.Frame = false
|
||||||
|
gui.Views.Search.Editor = gocui.EditorFunc(gui.searchEditor)
|
||||||
|
|
||||||
gui.Views.Stash.Title = gui.c.Tr.StashTitle
|
gui.Views.Stash.Title = gui.c.Tr.StashTitle
|
||||||
|
|
||||||
gui.Views.Commits.Title = gui.c.Tr.CommitsTitle
|
gui.Views.Commits.Title = gui.c.Tr.CommitsTitle
|
||||||
@ -141,11 +147,6 @@ func (gui *Gui) createAllViews() error {
|
|||||||
|
|
||||||
gui.Views.Status.Title = gui.c.Tr.StatusTitle
|
gui.Views.Status.Title = gui.c.Tr.StatusTitle
|
||||||
|
|
||||||
gui.Views.Search.BgColor = gocui.ColorDefault
|
|
||||||
gui.Views.Search.FgColor = gocui.ColorGreen
|
|
||||||
gui.Views.Search.Editable = true
|
|
||||||
gui.Views.Search.Frame = false
|
|
||||||
|
|
||||||
gui.Views.AppStatus.BgColor = gocui.ColorDefault
|
gui.Views.AppStatus.BgColor = gocui.ColorDefault
|
||||||
gui.Views.AppStatus.FgColor = gocui.ColorCyan
|
gui.Views.AppStatus.FgColor = gocui.ColorCyan
|
||||||
gui.Views.AppStatus.Visible = false
|
gui.Views.AppStatus.Visible = false
|
||||||
|
@ -35,7 +35,7 @@ func dutchTranslationSet() TranslationSet {
|
|||||||
Scroll: "Scroll",
|
Scroll: "Scroll",
|
||||||
FilterStagedFiles: "Show only staged files",
|
FilterStagedFiles: "Show only staged files",
|
||||||
FilterUnstagedFiles: "Show only unstaged files",
|
FilterUnstagedFiles: "Show only unstaged files",
|
||||||
ResetCommitFilterState: "Reset commit file state filter",
|
ResetFilter: "Reset commit file state filter",
|
||||||
MergeConflictsTitle: "Merge conflicten",
|
MergeConflictsTitle: "Merge conflicten",
|
||||||
Checkout: "Uitchecken",
|
Checkout: "Uitchecken",
|
||||||
PullWait: "Pullen...",
|
PullWait: "Pullen...",
|
||||||
|
@ -54,7 +54,7 @@ type TranslationSet struct {
|
|||||||
FileFilter string
|
FileFilter string
|
||||||
FilterStagedFiles string
|
FilterStagedFiles string
|
||||||
FilterUnstagedFiles string
|
FilterUnstagedFiles string
|
||||||
ResetCommitFilterState string
|
ResetFilter string
|
||||||
MergeConflictsTitle string
|
MergeConflictsTitle string
|
||||||
Checkout string
|
Checkout string
|
||||||
NoChangedFiles string
|
NoChangedFiles string
|
||||||
@ -371,6 +371,7 @@ type TranslationSet struct {
|
|||||||
NextScreenMode string
|
NextScreenMode string
|
||||||
PrevScreenMode string
|
PrevScreenMode string
|
||||||
StartSearch string
|
StartSearch string
|
||||||
|
StartFilter string
|
||||||
Panel string
|
Panel string
|
||||||
Keybindings string
|
Keybindings string
|
||||||
KeybindingsLegend string
|
KeybindingsLegend string
|
||||||
@ -536,7 +537,9 @@ type TranslationSet struct {
|
|||||||
MatchesFor string
|
MatchesFor string
|
||||||
SearchKeybindings string
|
SearchKeybindings string
|
||||||
SearchPrefix string
|
SearchPrefix string
|
||||||
|
FilterPrefix string
|
||||||
ExitSearchMode string
|
ExitSearchMode string
|
||||||
|
ExitTextFilterMode string
|
||||||
Actions Actions
|
Actions Actions
|
||||||
Bisect Bisect
|
Bisect Bisect
|
||||||
}
|
}
|
||||||
@ -741,10 +744,10 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
Scroll: "Scroll",
|
Scroll: "Scroll",
|
||||||
MergeConflictsTitle: "Merge conflicts",
|
MergeConflictsTitle: "Merge conflicts",
|
||||||
Checkout: "Checkout",
|
Checkout: "Checkout",
|
||||||
FileFilter: "Filter files (staged/unstaged)",
|
FileFilter: "Filter files by status",
|
||||||
FilterStagedFiles: "Show only staged files",
|
FilterStagedFiles: "Show only staged files",
|
||||||
FilterUnstagedFiles: "Show only unstaged files",
|
FilterUnstagedFiles: "Show only unstaged files",
|
||||||
ResetCommitFilterState: "Reset filter",
|
ResetFilter: "Reset filter",
|
||||||
NoChangedFiles: "No changed files",
|
NoChangedFiles: "No changed files",
|
||||||
PullWait: "Pulling...",
|
PullWait: "Pulling...",
|
||||||
PushWait: "Pushing...",
|
PushWait: "Pushing...",
|
||||||
@ -1054,50 +1057,52 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
GitFlowOptions: "Show git-flow options",
|
GitFlowOptions: "Show git-flow options",
|
||||||
NotAGitFlowBranch: "This does not seem to be a git flow branch",
|
NotAGitFlowBranch: "This does not seem to be a git flow branch",
|
||||||
NewGitFlowBranchPrompt: "New {{.branchType}} name:",
|
NewGitFlowBranchPrompt: "New {{.branchType}} name:",
|
||||||
IgnoreTracked: "Ignore tracked file",
|
|
||||||
IgnoreTrackedPrompt: "Are you sure you want to ignore a tracked file?",
|
IgnoreTracked: "Ignore tracked file",
|
||||||
ExcludeTracked: "Exclude tracked file",
|
IgnoreTrackedPrompt: "Are you sure you want to ignore a tracked file?",
|
||||||
ExcludeTrackedPrompt: "Are you sure you want to exclude a tracked file?",
|
ExcludeTracked: "Exclude tracked file",
|
||||||
ViewResetToUpstreamOptions: "View upstream reset options",
|
ExcludeTrackedPrompt: "Are you sure you want to exclude a tracked file?",
|
||||||
NextScreenMode: "Next screen mode (normal/half/fullscreen)",
|
ViewResetToUpstreamOptions: "View upstream reset options",
|
||||||
PrevScreenMode: "Prev screen mode",
|
NextScreenMode: "Next screen mode (normal/half/fullscreen)",
|
||||||
StartSearch: "Start search",
|
PrevScreenMode: "Prev screen mode",
|
||||||
Panel: "Panel",
|
StartSearch: "Search the current view by text",
|
||||||
KeybindingsLegend: "Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b",
|
StartFilter: "Filter the current view by text",
|
||||||
RenameBranch: "Rename branch",
|
Panel: "Panel",
|
||||||
SetUnsetUpstream: "Set/Unset upstream",
|
KeybindingsLegend: "Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b",
|
||||||
NewBranchNamePrompt: "Enter new branch name for branch",
|
RenameBranch: "Rename branch",
|
||||||
RenameBranchWarning: "This branch is tracking a remote. This action will only rename the local branch name, not the name of the remote branch. Continue?",
|
SetUnsetUpstream: "Set/Unset upstream",
|
||||||
OpenMenu: "Open menu",
|
NewBranchNamePrompt: "Enter new branch name for branch",
|
||||||
ResetCherryPick: "Reset cherry-picked (copied) commits selection",
|
RenameBranchWarning: "This branch is tracking a remote. This action will only rename the local branch name, not the name of the remote branch. Continue?",
|
||||||
NextTab: "Next tab",
|
OpenMenu: "Open menu",
|
||||||
PrevTab: "Previous tab",
|
ResetCherryPick: "Reset cherry-picked (copied) commits selection",
|
||||||
CantUndoWhileRebasing: "Can't undo while rebasing",
|
NextTab: "Next tab",
|
||||||
CantRedoWhileRebasing: "Can't redo while rebasing",
|
PrevTab: "Previous tab",
|
||||||
MustStashWarning: "Pulling a patch out into the index requires stashing and unstashing your changes. If something goes wrong, you'll be able to access your files from the stash. Continue?",
|
CantUndoWhileRebasing: "Can't undo while rebasing",
|
||||||
MustStashTitle: "Must stash",
|
CantRedoWhileRebasing: "Can't redo while rebasing",
|
||||||
ConfirmationTitle: "Confirmation panel",
|
MustStashWarning: "Pulling a patch out into the index requires stashing and unstashing your changes. If something goes wrong, you'll be able to access your files from the stash. Continue?",
|
||||||
PrevPage: "Previous page",
|
MustStashTitle: "Must stash",
|
||||||
NextPage: "Next page",
|
ConfirmationTitle: "Confirmation panel",
|
||||||
GotoTop: "Scroll to top",
|
PrevPage: "Previous page",
|
||||||
GotoBottom: "Scroll to bottom",
|
NextPage: "Next page",
|
||||||
FilteringBy: "Filtering by",
|
GotoTop: "Scroll to top",
|
||||||
ResetInParentheses: "(Reset)",
|
GotoBottom: "Scroll to bottom",
|
||||||
OpenFilteringMenu: "View filter-by-path options",
|
FilteringBy: "Filtering by",
|
||||||
FilterBy: "Filter by",
|
ResetInParentheses: "(Reset)",
|
||||||
ExitFilterMode: "Stop filtering by path",
|
OpenFilteringMenu: "View filter-by-path options",
|
||||||
FilterPathOption: "Enter path to filter by",
|
FilterBy: "Filter by",
|
||||||
EnterFileName: "Enter path:",
|
ExitFilterMode: "Stop filtering by path",
|
||||||
FilteringMenuTitle: "Filtering",
|
FilterPathOption: "Enter path to filter by",
|
||||||
MustExitFilterModeTitle: "Command not available",
|
EnterFileName: "Enter path:",
|
||||||
MustExitFilterModePrompt: "Command not available in filtered mode. Exit filtered mode?",
|
FilteringMenuTitle: "Filtering",
|
||||||
Diff: "Diff",
|
MustExitFilterModeTitle: "Command not available",
|
||||||
EnterRefToDiff: "Enter ref to diff",
|
MustExitFilterModePrompt: "Command not available in filter-by-path mode. Exit filter-by-path mode?",
|
||||||
EnterRefName: "Enter ref:",
|
Diff: "Diff",
|
||||||
ExitDiffMode: "Exit diff mode",
|
EnterRefToDiff: "Enter ref to diff",
|
||||||
DiffingMenuTitle: "Diffing",
|
EnterRefName: "Enter ref:",
|
||||||
SwapDiff: "Reverse diff direction",
|
ExitDiffMode: "Exit diff mode",
|
||||||
OpenDiffingMenu: "Open diff menu",
|
DiffingMenuTitle: "Diffing",
|
||||||
|
SwapDiff: "Reverse diff direction",
|
||||||
|
OpenDiffingMenu: "Open diff menu",
|
||||||
// the actual view is the extras view which I intend to give more tabs in future but for now we'll only mention the command log part
|
// the actual view is the extras view which I intend to give more tabs in future but for now we'll only mention the command log part
|
||||||
OpenExtrasMenu: "Open command log menu",
|
OpenExtrasMenu: "Open command log menu",
|
||||||
ShowingGitDiff: "Showing output for:",
|
ShowingGitDiff: "Showing output for:",
|
||||||
@ -1223,9 +1228,11 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
CopyPatchToClipboard: "Copy patch to clipboard",
|
CopyPatchToClipboard: "Copy patch to clipboard",
|
||||||
NoMatchesFor: "No matches for '%s' %s",
|
NoMatchesFor: "No matches for '%s' %s",
|
||||||
ExitSearchMode: "%s: Exit search mode",
|
ExitSearchMode: "%s: Exit search mode",
|
||||||
|
ExitTextFilterMode: "%s: Exit filter mode",
|
||||||
MatchesFor: "matches for '%s' (%d of %d) %s", // lowercase because it's after other text
|
MatchesFor: "matches for '%s' (%d of %d) %s", // lowercase because it's after other text
|
||||||
SearchKeybindings: "%s: Next match, %s: Previous match, %s: Exit search mode",
|
SearchKeybindings: "%s: Next match, %s: Previous match, %s: Exit search mode",
|
||||||
SearchPrefix: "Search: ",
|
SearchPrefix: "Search: ",
|
||||||
|
FilterPrefix: "Filter: ",
|
||||||
Actions: Actions{
|
Actions: Actions{
|
||||||
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
|
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
|
||||||
CheckoutCommit: "Checkout commit",
|
CheckoutCommit: "Checkout commit",
|
||||||
|
@ -61,7 +61,7 @@ func japaneseTranslationSet() TranslationSet {
|
|||||||
FileFilter: "ファイルをフィルタ (ステージ/アンステージ)",
|
FileFilter: "ファイルをフィルタ (ステージ/アンステージ)",
|
||||||
FilterStagedFiles: "ステージされたファイルのみを表示",
|
FilterStagedFiles: "ステージされたファイルのみを表示",
|
||||||
FilterUnstagedFiles: "ステージされていないファイルのみを表示",
|
FilterUnstagedFiles: "ステージされていないファイルのみを表示",
|
||||||
ResetCommitFilterState: "フィルタをリセット",
|
ResetFilter: "フィルタをリセット",
|
||||||
// NoChangedFiles: "No changed files",
|
// NoChangedFiles: "No changed files",
|
||||||
PullWait: "Pull中...",
|
PullWait: "Pull中...",
|
||||||
PushWait: "Push中...",
|
PushWait: "Push中...",
|
||||||
|
@ -60,7 +60,7 @@ func koreanTranslationSet() TranslationSet {
|
|||||||
FileFilter: "파일을 필터하기 (Staged/unstaged)",
|
FileFilter: "파일을 필터하기 (Staged/unstaged)",
|
||||||
FilterStagedFiles: "Staged된 파일만 표시",
|
FilterStagedFiles: "Staged된 파일만 표시",
|
||||||
FilterUnstagedFiles: "Stage되지 않은 파일만 표시",
|
FilterUnstagedFiles: "Stage되지 않은 파일만 표시",
|
||||||
ResetCommitFilterState: "필터 리셋",
|
ResetFilter: "필터 리셋",
|
||||||
NoChangedFiles: "변경된 파일이 없습니다.",
|
NoChangedFiles: "변경된 파일이 없습니다.",
|
||||||
PullWait: "업데이트 중...",
|
PullWait: "업데이트 중...",
|
||||||
PushWait: "푸시 중...",
|
PushWait: "푸시 중...",
|
||||||
|
@ -31,7 +31,7 @@ func polishTranslationSet() TranslationSet {
|
|||||||
Scroll: "Przewiń",
|
Scroll: "Przewiń",
|
||||||
FilterStagedFiles: "Pokaż tylko pliki w poczekalni",
|
FilterStagedFiles: "Pokaż tylko pliki w poczekalni",
|
||||||
FilterUnstagedFiles: "Pokaż tylko pliki poza poczekalnią",
|
FilterUnstagedFiles: "Pokaż tylko pliki poza poczekalnią",
|
||||||
ResetCommitFilterState: "Resetuj filtr commitów",
|
ResetFilter: "Resetuj filtr commitów",
|
||||||
Checkout: "Przełącz",
|
Checkout: "Przełącz",
|
||||||
NoChangedFiles: "Brak zmienionych plików",
|
NoChangedFiles: "Brak zmienionych plików",
|
||||||
PullWait: "Pobieranie zmian...",
|
PullWait: "Pobieranie zmian...",
|
||||||
|
@ -79,7 +79,7 @@ func RussianTranslationSet() TranslationSet {
|
|||||||
FileFilter: "Фильтровать файлы (проиндексированные/непроиндексированные)",
|
FileFilter: "Фильтровать файлы (проиндексированные/непроиндексированные)",
|
||||||
FilterStagedFiles: "Показывать только проиндексированные файлы",
|
FilterStagedFiles: "Показывать только проиндексированные файлы",
|
||||||
FilterUnstagedFiles: "Показывать только непроиндексированные файлы",
|
FilterUnstagedFiles: "Показывать только непроиндексированные файлы",
|
||||||
ResetCommitFilterState: "Сбросить фильтр",
|
ResetFilter: "Сбросить фильтр",
|
||||||
NoChangedFiles: "Нет изменённых файлов",
|
NoChangedFiles: "Нет изменённых файлов",
|
||||||
PullWait: "Получение и слияние изменении...",
|
PullWait: "Получение и слияние изменении...",
|
||||||
PushWait: "Отправка изменении...",
|
PushWait: "Отправка изменении...",
|
||||||
|
@ -112,7 +112,7 @@ func traditionalChineseTranslationSet() TranslationSet {
|
|||||||
FileFilter: "篩選檔案 (預存/未預存)",
|
FileFilter: "篩選檔案 (預存/未預存)",
|
||||||
FilterStagedFiles: "僅顯示預存的檔案",
|
FilterStagedFiles: "僅顯示預存的檔案",
|
||||||
FilterUnstagedFiles: "僅顯示未預存的檔案",
|
FilterUnstagedFiles: "僅顯示未預存的檔案",
|
||||||
ResetCommitFilterState: "重設篩選",
|
ResetFilter: "重設篩選",
|
||||||
NoChangedFiles: "沒有變更的檔案",
|
NoChangedFiles: "沒有變更的檔案",
|
||||||
PullWait: "拉取...",
|
PullWait: "拉取...",
|
||||||
PushWait: "推送...",
|
PushWait: "推送...",
|
||||||
|
@ -10,9 +10,9 @@ type IntMatcher struct {
|
|||||||
|
|
||||||
func (self *IntMatcher) EqualsInt(target int) *IntMatcher {
|
func (self *IntMatcher) EqualsInt(target int) *IntMatcher {
|
||||||
self.appendRule(matcherRule[int]{
|
self.appendRule(matcherRule[int]{
|
||||||
name: fmt.Sprintf("equals '%d'", target),
|
name: fmt.Sprintf("equals %d", target),
|
||||||
testFn: func(value int) (bool, string) {
|
testFn: func(value int) (bool, string) {
|
||||||
return value == target, fmt.Sprintf("Expected '%d' to equal '%d'", value, target)
|
return value == target, fmt.Sprintf("Expected %d to equal %d", value, target)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -21,9 +21,9 @@ func (self *IntMatcher) EqualsInt(target int) *IntMatcher {
|
|||||||
|
|
||||||
func (self *IntMatcher) GreaterThan(target int) *IntMatcher {
|
func (self *IntMatcher) GreaterThan(target int) *IntMatcher {
|
||||||
self.appendRule(matcherRule[int]{
|
self.appendRule(matcherRule[int]{
|
||||||
name: fmt.Sprintf("greater than '%d'", target),
|
name: fmt.Sprintf("greater than %d", target),
|
||||||
testFn: func(value int) (bool, string) {
|
testFn: func(value int) (bool, string) {
|
||||||
return value > target, fmt.Sprintf("Expected '%d' to greater than '%d'", value, target)
|
return value > target, fmt.Sprintf("Expected %d to greater than %d", value, target)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -32,9 +32,9 @@ func (self *IntMatcher) GreaterThan(target int) *IntMatcher {
|
|||||||
|
|
||||||
func (self *IntMatcher) LessThan(target int) *IntMatcher {
|
func (self *IntMatcher) LessThan(target int) *IntMatcher {
|
||||||
self.appendRule(matcherRule[int]{
|
self.appendRule(matcherRule[int]{
|
||||||
name: fmt.Sprintf("less than '%d'", target),
|
name: fmt.Sprintf("less than %d", target),
|
||||||
testFn: func(value int) (bool, string) {
|
testFn: func(value int) (bool, string) {
|
||||||
return value < target, fmt.Sprintf("Expected '%d' to less than '%d'", value, target)
|
return value < target, fmt.Sprintf("Expected %d to less than %d", value, target)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -48,6 +48,18 @@ func (self *MenuDriver) TopLines(matchers ...*TextMatcher) *MenuDriver {
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *MenuDriver) Filter(text string) *MenuDriver {
|
||||||
|
self.getViewDriver().FilterOrSearch(text)
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *MenuDriver) LineCount(matcher *IntMatcher) *MenuDriver {
|
||||||
|
self.getViewDriver().LineCount(matcher)
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
func (self *MenuDriver) checkNecessaryChecksCompleted() {
|
func (self *MenuDriver) checkNecessaryChecksCompleted() {
|
||||||
if !self.hasCheckedTitle {
|
if !self.hasCheckedTitle {
|
||||||
self.t.Fail("You must check the title of a menu popup by calling Title() before calling Confirm()/Cancel().")
|
self.t.Fail("You must check the title of a menu popup by calling Title() before calling Confirm()/Cancel().")
|
||||||
|
@ -66,7 +66,7 @@ func (self *ViewDriver) Title(expected *TextMatcher) *ViewDriver {
|
|||||||
// If you only care about a subset of lines, use the ContainsLines method instead.
|
// If you only care about a subset of lines, use the ContainsLines method instead.
|
||||||
func (self *ViewDriver) Lines(matchers ...*TextMatcher) *ViewDriver {
|
func (self *ViewDriver) Lines(matchers ...*TextMatcher) *ViewDriver {
|
||||||
self.validateMatchersPassed(matchers)
|
self.validateMatchersPassed(matchers)
|
||||||
self.LineCount(len(matchers))
|
self.LineCount(EqualsInt(len(matchers)))
|
||||||
|
|
||||||
return self.assertLines(0, matchers...)
|
return self.assertLines(0, matchers...)
|
||||||
}
|
}
|
||||||
@ -470,33 +470,60 @@ func (self *ViewDriver) IsEmpty() *ViewDriver {
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *ViewDriver) LineCount(expectedCount int) *ViewDriver {
|
func (self *ViewDriver) LineCount(matcher *IntMatcher) *ViewDriver {
|
||||||
if expectedCount == 0 {
|
|
||||||
return self.IsEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
view := self.getView()
|
view := self.getView()
|
||||||
|
|
||||||
self.t.assertWithRetries(func() (bool, string) {
|
self.t.assertWithRetries(func() (bool, string) {
|
||||||
lines := view.BufferLines()
|
lineCount := self.getLineCount()
|
||||||
return len(lines) == expectedCount, fmt.Sprintf("unexpected number of lines in view '%s'. Expected %d, got %d", view.Name(), expectedCount, len(lines))
|
ok, _ := matcher.test(lineCount)
|
||||||
|
return ok, fmt.Sprintf("unexpected number of lines in view '%s'. Expected %s, got %d", view.Name(), matcher.name(), lineCount)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ViewDriver) getLineCount() int {
|
||||||
|
// can't rely entirely on view.BufferLines because it returns 1 even if there's nothing in the view
|
||||||
|
if strings.TrimSpace(self.getView().Buffer()) == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
view := self.getView()
|
||||||
|
return len(view.BufferLines())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ViewDriver) IsVisible() *ViewDriver {
|
||||||
self.t.assertWithRetries(func() (bool, string) {
|
self.t.assertWithRetries(func() (bool, string) {
|
||||||
lines := view.BufferLines()
|
return self.getView().Visible, fmt.Sprintf("%s: Expected view to be visible, but it was not", self.context)
|
||||||
|
|
||||||
// if the view has a single blank line (often the case) we want to treat that as having no lines
|
|
||||||
if len(lines) == 1 && expectedCount == 1 {
|
|
||||||
actual := strings.TrimSpace(view.Buffer())
|
|
||||||
return actual != "", fmt.Sprintf("unexpected number of lines in view '%s'. Expected 1, got 0", view.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
return len(lines) == expectedCount, fmt.Sprintf("unexpected number of lines in view '%s'. Expected %d, got %d", view.Name(), expectedCount, len(lines))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *ViewDriver) IsInvisible() *ViewDriver {
|
||||||
|
self.t.assertWithRetries(func() (bool, string) {
|
||||||
|
return !self.getView().Visible, fmt.Sprintf("%s: Expected view to be visible, but it was not", self.context)
|
||||||
|
})
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
// will filter or search depending on whether the view supports filtering/searching
|
||||||
|
func (self *ViewDriver) FilterOrSearch(text string) *ViewDriver {
|
||||||
|
self.IsFocused()
|
||||||
|
|
||||||
|
self.Press(self.t.keys.Universal.StartSearch).
|
||||||
|
Tap(func() {
|
||||||
|
self.t.ExpectSearch().
|
||||||
|
Type(text).
|
||||||
|
Confirm()
|
||||||
|
|
||||||
|
self.t.Views().Search().IsVisible().Content(Contains(fmt.Sprintf("matches for '%s'", text)))
|
||||||
|
})
|
||||||
|
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
// for when you want to make some assertion unrelated to the current view
|
// for when you want to make some assertion unrelated to the current view
|
||||||
// without breaking the method chain
|
// without breaking the method chain
|
||||||
func (self *ViewDriver) Tap(f func()) *ViewDriver {
|
func (self *ViewDriver) Tap(f func()) *ViewDriver {
|
||||||
|
@ -42,6 +42,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{
|
|||||||
Press(keys.Universal.StartSearch).
|
Press(keys.Universal.StartSearch).
|
||||||
Tap(func() {
|
Tap(func() {
|
||||||
t.ExpectSearch().
|
t.ExpectSearch().
|
||||||
|
Clear().
|
||||||
Type("o").
|
Type("o").
|
||||||
Confirm()
|
Confirm()
|
||||||
|
|
||||||
|
117
pkg/integration/tests/file/discard_all_dir_changes.go
Normal file
117
pkg/integration/tests/file/discard_all_dir_changes.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DiscardAllDirChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Discarding all changes in a directory",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
|
},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
// typically we would use more bespoke shell methods here, but I struggled to find a way to do that,
|
||||||
|
// and this is copied over from a legacy integration test which did everything in a big shell script
|
||||||
|
// so I'm just copying it across.
|
||||||
|
|
||||||
|
shell.CreateDir("dir")
|
||||||
|
|
||||||
|
// common stuff
|
||||||
|
shell.RunShellCommand(`echo test > dir/both-deleted.txt`)
|
||||||
|
shell.RunShellCommand(`git checkout -b conflict && git add dir/both-deleted.txt`)
|
||||||
|
shell.RunShellCommand(`echo bothmodded > dir/both-modded.txt && git add dir/both-modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo haha > dir/deleted-them.txt && git add dir/deleted-them.txt`)
|
||||||
|
shell.RunShellCommand(`echo haha2 > dir/deleted-us.txt && git add dir/deleted-us.txt`)
|
||||||
|
shell.RunShellCommand(`echo mod > dir/modded.txt && git add dir/modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo mod > dir/modded-staged.txt && git add dir/modded-staged.txt`)
|
||||||
|
shell.RunShellCommand(`echo del > dir/deleted.txt && git add dir/deleted.txt`)
|
||||||
|
shell.RunShellCommand(`echo del > dir/deleted-staged.txt && git add dir/deleted-staged.txt`)
|
||||||
|
shell.RunShellCommand(`echo change-delete > dir/change-delete.txt && git add dir/change-delete.txt`)
|
||||||
|
shell.RunShellCommand(`echo delete-change > dir/delete-change.txt && git add dir/delete-change.txt`)
|
||||||
|
shell.RunShellCommand(`echo double-modded > dir/double-modded.txt && git add dir/double-modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo "renamed\nhaha" > dir/renamed.txt && git add dir/renamed.txt`)
|
||||||
|
shell.RunShellCommand(`git commit -m one`)
|
||||||
|
|
||||||
|
// stuff on other branch
|
||||||
|
shell.RunShellCommand(`git branch conflict_second && git mv dir/both-deleted.txt dir/added-them-changed-us.txt`)
|
||||||
|
shell.RunShellCommand(`git commit -m "dir/both-deleted.txt renamed in dir/added-them-changed-us.txt"`)
|
||||||
|
shell.RunShellCommand(`echo blah > dir/both-added.txt && git add dir/both-added.txt`)
|
||||||
|
shell.RunShellCommand(`echo mod1 > dir/both-modded.txt && git add dir/both-modded.txt`)
|
||||||
|
shell.RunShellCommand(`rm dir/deleted-them.txt && git add dir/deleted-them.txt`)
|
||||||
|
shell.RunShellCommand(`echo modded > dir/deleted-us.txt && git add dir/deleted-us.txt`)
|
||||||
|
shell.RunShellCommand(`git commit -m "two"`)
|
||||||
|
|
||||||
|
// stuff on our branch
|
||||||
|
shell.RunShellCommand(`git checkout conflict_second`)
|
||||||
|
shell.RunShellCommand(`git mv dir/both-deleted.txt dir/changed-them-added-us.txt`)
|
||||||
|
shell.RunShellCommand(`git commit -m "both-deleted.txt renamed in dir/changed-them-added-us.txt"`)
|
||||||
|
shell.RunShellCommand(`echo mod2 > dir/both-modded.txt && git add dir/both-modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo blah2 > dir/both-added.txt && git add dir/both-added.txt`)
|
||||||
|
shell.RunShellCommand(`echo modded > dir/deleted-them.txt && git add dir/deleted-them.txt`)
|
||||||
|
shell.RunShellCommand(`rm dir/deleted-us.txt && git add dir/deleted-us.txt`)
|
||||||
|
shell.RunShellCommand(`git commit -m "three"`)
|
||||||
|
shell.RunShellCommand(`git reset --hard conflict_second`)
|
||||||
|
shell.RunCommandExpectError([]string{"git", "merge", "conflict"})
|
||||||
|
|
||||||
|
shell.RunShellCommand(`echo "new" > dir/new.txt`)
|
||||||
|
shell.RunShellCommand(`echo "new staged" > dir/new-staged.txt && git add dir/new-staged.txt`)
|
||||||
|
shell.RunShellCommand(`echo mod2 > dir/modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo mod2 > dir/modded-staged.txt && git add dir/modded-staged.txt`)
|
||||||
|
shell.RunShellCommand(`rm dir/deleted.txt`)
|
||||||
|
shell.RunShellCommand(`rm dir/deleted-staged.txt && git add dir/deleted-staged.txt`)
|
||||||
|
shell.RunShellCommand(`echo change-delete2 > dir/change-delete.txt && git add dir/change-delete.txt`)
|
||||||
|
shell.RunShellCommand(`rm dir/change-delete.txt`)
|
||||||
|
shell.RunShellCommand(`rm dir/delete-change.txt && git add dir/delete-change.txt`)
|
||||||
|
shell.RunShellCommand(`echo "changed" > dir/delete-change.txt`)
|
||||||
|
shell.RunShellCommand(`echo "change1" > dir/double-modded.txt && git add dir/double-modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo "change2" > dir/double-modded.txt`)
|
||||||
|
shell.RunShellCommand(`echo before > dir/added-changed.txt && git add dir/added-changed.txt`)
|
||||||
|
shell.RunShellCommand(`echo after > dir/added-changed.txt`)
|
||||||
|
shell.RunShellCommand(`rm dir/renamed.txt && git add dir/renamed.txt`)
|
||||||
|
shell.RunShellCommand(`echo "renamed\nhaha" > dir/renamed2.txt && git add dir/renamed2.txt`)
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Files().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains("dir").IsSelected(),
|
||||||
|
Contains("UA").Contains("added-them-changed-us.txt"),
|
||||||
|
Contains("AA").Contains("both-added.txt"),
|
||||||
|
Contains("DD").Contains("both-deleted.txt"),
|
||||||
|
Contains("UU").Contains("both-modded.txt"),
|
||||||
|
Contains("AU").Contains("changed-them-added-us.txt"),
|
||||||
|
Contains("UD").Contains("deleted-them.txt"),
|
||||||
|
Contains("DU").Contains("deleted-us.txt"),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.Remove).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("dir")).
|
||||||
|
Select(Contains("Discard all changes")).
|
||||||
|
Confirm()
|
||||||
|
}).
|
||||||
|
Tap(func() {
|
||||||
|
t.Common().ContinueOnConflictsResolved()
|
||||||
|
}).
|
||||||
|
Lines(
|
||||||
|
Contains("dir").IsSelected(),
|
||||||
|
Contains(" M").Contains("added-changed.txt"),
|
||||||
|
Contains(" D").Contains("change-delete.txt"),
|
||||||
|
Contains("??").Contains("delete-change.txt"),
|
||||||
|
Contains(" D").Contains("deleted.txt"),
|
||||||
|
Contains(" M").Contains("double-modded.txt"),
|
||||||
|
Contains(" M").Contains("modded.txt"),
|
||||||
|
Contains("??").Contains("new.txt"),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.Remove).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("dir")).
|
||||||
|
Select(Contains("Discard all changes")).
|
||||||
|
Confirm()
|
||||||
|
}).
|
||||||
|
IsEmpty()
|
||||||
|
},
|
||||||
|
})
|
56
pkg/integration/tests/file/discard_unstaged_dir_changes.go
Normal file
56
pkg/integration/tests/file/discard_unstaged_dir_changes.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DiscardUnstagedDirChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Discarding unstaged changes in a directory",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
|
},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.CreateDir("dir")
|
||||||
|
shell.CreateFileAndAdd("dir/file-one", "original content\n")
|
||||||
|
|
||||||
|
shell.Commit("first commit")
|
||||||
|
|
||||||
|
shell.UpdateFileAndAdd("dir/file-one", "original content\nnew content\n")
|
||||||
|
shell.UpdateFile("dir/file-one", "original content\nnew content\neven newer content\n")
|
||||||
|
|
||||||
|
shell.CreateDir("dir/subdir")
|
||||||
|
shell.CreateFile("dir/subdir/unstaged-file-one", "unstaged file")
|
||||||
|
shell.CreateFile("dir/unstaged-file-two", "unstaged file")
|
||||||
|
|
||||||
|
shell.CreateFile("unstaged-file-three", "unstaged file")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Files().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains("dir").IsSelected(),
|
||||||
|
Contains("subdir"),
|
||||||
|
Contains("??").Contains("unstaged-file-one"),
|
||||||
|
Contains("MM").Contains("file-one"),
|
||||||
|
Contains("??").Contains("unstaged-file-two"),
|
||||||
|
Contains("??").Contains("unstaged-file-three"),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.Remove).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("dir")).
|
||||||
|
Select(Contains("Discard unstaged changes")).
|
||||||
|
Confirm()
|
||||||
|
}).
|
||||||
|
Lines(
|
||||||
|
Contains("dir").IsSelected(),
|
||||||
|
Contains("M ").Contains("file-one"),
|
||||||
|
// this guy remains untouched because it wasn't inside the 'dir' directory
|
||||||
|
Contains("??").Contains("unstaged-file-three"),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.FileSystem().FileContent("dir/file-one", Equals("original content\nnew content\n"))
|
||||||
|
},
|
||||||
|
})
|
41
pkg/integration/tests/file/discard_unstaged_file_changes.go
Normal file
41
pkg/integration/tests/file/discard_unstaged_file_changes.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DiscardUnstagedFileChanges = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Discarding unstaged changes in a file",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {
|
||||||
|
},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.CreateFileAndAdd("file-one", "original content\n")
|
||||||
|
|
||||||
|
shell.Commit("first commit")
|
||||||
|
|
||||||
|
shell.UpdateFileAndAdd("file-one", "original content\nnew content\n")
|
||||||
|
shell.UpdateFile("file-one", "original content\nnew content\neven newer content\n")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Files().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains("MM").Contains("file-one").IsSelected(),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.Remove).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("file-one")).
|
||||||
|
Select(Contains("Discard unstaged changes")).
|
||||||
|
Confirm()
|
||||||
|
}).
|
||||||
|
Lines(
|
||||||
|
Contains("M ").Contains("file-one").IsSelected(),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.FileSystem().FileContent("file-one", Equals("original content\nnew content\n"))
|
||||||
|
},
|
||||||
|
})
|
@ -0,0 +1,84 @@
|
|||||||
|
package filter_and_search
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var FilterCommitFiles = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Basic commit file filtering by text",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: true, // skipping until we have implemented file view filtering
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.CreateDir("folder1")
|
||||||
|
shell.CreateFileAndAdd("folder1/apple-grape", "apple-grape")
|
||||||
|
shell.CreateFileAndAdd("folder1/apple-orange", "apple-orange")
|
||||||
|
shell.CreateFileAndAdd("folder1/grape-orange", "grape-orange")
|
||||||
|
shell.Commit("first commit")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Commits().
|
||||||
|
Focus().
|
||||||
|
Lines(
|
||||||
|
Contains(`first commit`).IsSelected(),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.Confirm)
|
||||||
|
|
||||||
|
t.Views().CommitFiles().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1`).IsSelected(),
|
||||||
|
Contains(`apple-grape`),
|
||||||
|
Contains(`apple-orange`),
|
||||||
|
Contains(`grape-orange`),
|
||||||
|
).
|
||||||
|
Press(keys.Files.ToggleTreeView).
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1/apple-grape`).IsSelected(),
|
||||||
|
Contains(`folder1/apple-orange`),
|
||||||
|
Contains(`folder1/grape-orange`),
|
||||||
|
).
|
||||||
|
FilterOrSearch("apple").
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1/apple-grape`).IsSelected(),
|
||||||
|
Contains(`folder1/apple-orange`),
|
||||||
|
).
|
||||||
|
Press(keys.Files.ToggleTreeView).
|
||||||
|
// filter still applies when we toggle tree view
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1`),
|
||||||
|
Contains(`apple-grape`).IsSelected(),
|
||||||
|
Contains(`apple-orange`),
|
||||||
|
).
|
||||||
|
Press(keys.Files.ToggleTreeView).
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1/apple-grape`).IsSelected(),
|
||||||
|
Contains(`folder1/apple-orange`),
|
||||||
|
).
|
||||||
|
NavigateToLine(Contains(`folder1/apple-orange`)).
|
||||||
|
Press(keys.Universal.Return).
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1/apple-grape`),
|
||||||
|
// selection is retained after escaping filter mode
|
||||||
|
Contains(`folder1/apple-orange`).IsSelected(),
|
||||||
|
Contains(`folder1/grape-orange`),
|
||||||
|
).
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsInvisible()
|
||||||
|
}).
|
||||||
|
Press(keys.Files.ToggleTreeView).
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1`),
|
||||||
|
Contains(`apple-grape`),
|
||||||
|
Contains(`apple-orange`).IsSelected(),
|
||||||
|
Contains(`grape-orange`),
|
||||||
|
).
|
||||||
|
FilterOrSearch("folder1/grape").
|
||||||
|
Lines(
|
||||||
|
// first item is always selected after filtering
|
||||||
|
Contains(`folder1`).IsSelected(),
|
||||||
|
Contains(`grape-orange`),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
76
pkg/integration/tests/filter_and_search/filter_files.go
Normal file
76
pkg/integration/tests/filter_and_search/filter_files.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package filter_and_search
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var FilterFiles = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Basic file filtering by text",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: true, // Skipping until we have implemented file view filtering
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.CreateDir("folder1")
|
||||||
|
shell.CreateFile("folder1/apple-grape", "apple-grape")
|
||||||
|
shell.CreateFile("folder1/apple-orange", "apple-orange")
|
||||||
|
shell.CreateFile("folder1/grape-orange", "grape-orange")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Files().
|
||||||
|
Focus().
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1`).IsSelected(),
|
||||||
|
Contains(`apple-grape`),
|
||||||
|
Contains(`apple-orange`),
|
||||||
|
Contains(`grape-orange`),
|
||||||
|
).
|
||||||
|
Press(keys.Files.ToggleTreeView).
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1/apple-grape`).IsSelected(),
|
||||||
|
Contains(`folder1/apple-orange`),
|
||||||
|
Contains(`folder1/grape-orange`),
|
||||||
|
).
|
||||||
|
FilterOrSearch("apple").
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1/apple-grape`).IsSelected(),
|
||||||
|
Contains(`folder1/apple-orange`),
|
||||||
|
).
|
||||||
|
Press(keys.Files.ToggleTreeView).
|
||||||
|
// filter still applies when we toggle tree view
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1`),
|
||||||
|
Contains(`apple-grape`).IsSelected(),
|
||||||
|
Contains(`apple-orange`),
|
||||||
|
).
|
||||||
|
Press(keys.Files.ToggleTreeView).
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1/apple-grape`).IsSelected(),
|
||||||
|
Contains(`folder1/apple-orange`),
|
||||||
|
).
|
||||||
|
NavigateToLine(Contains(`folder1/apple-orange`)).
|
||||||
|
Press(keys.Universal.Return).
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1/apple-grape`),
|
||||||
|
// selection is retained after escaping filter mode
|
||||||
|
Contains(`folder1/apple-orange`).IsSelected(),
|
||||||
|
Contains(`folder1/grape-orange`),
|
||||||
|
).
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsInvisible()
|
||||||
|
}).
|
||||||
|
Press(keys.Files.ToggleTreeView).
|
||||||
|
Lines(
|
||||||
|
Contains(`folder1`),
|
||||||
|
Contains(`apple-grape`),
|
||||||
|
Contains(`apple-orange`).IsSelected(),
|
||||||
|
Contains(`grape-orange`),
|
||||||
|
).
|
||||||
|
FilterOrSearch("folder1/grape").
|
||||||
|
Lines(
|
||||||
|
// first item is always selected after filtering
|
||||||
|
Contains(`folder1`).IsSelected(),
|
||||||
|
Contains(`grape-orange`),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
48
pkg/integration/tests/filter_and_search/filter_menu.go
Normal file
48
pkg/integration/tests/filter_and_search/filter_menu.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package filter_and_search
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var FilterMenu = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Filtering the keybindings menu",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.CreateFile("myfile", "myfile")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Files().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`??`).Contains(`myfile`).IsSelected(),
|
||||||
|
).
|
||||||
|
Press(keys.Universal.OptionMenu).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Keybindings")).
|
||||||
|
Filter("Toggle staged").
|
||||||
|
Lines(
|
||||||
|
// menu has filtered down to the one item that matches the filter
|
||||||
|
Contains(`Toggle staged`).IsSelected(),
|
||||||
|
).
|
||||||
|
Confirm()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Views().Files().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
// file has been staged
|
||||||
|
Contains(`A `).Contains(`myfile`).IsSelected(),
|
||||||
|
).
|
||||||
|
// Upon opening the menu again, the filter should have been reset
|
||||||
|
Press(keys.Universal.OptionMenu).
|
||||||
|
Tap(func() {
|
||||||
|
t.ExpectPopup().Menu().
|
||||||
|
Title(Equals("Keybindings")).
|
||||||
|
LineCount(GreaterThan(1))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
@ -0,0 +1,59 @@
|
|||||||
|
package filter_and_search
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var FilterRemoteBranches = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Filtering remote branches",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
shell.NewBranch("branch-apple")
|
||||||
|
shell.EmptyCommit("commit-one")
|
||||||
|
shell.NewBranch("branch-grape")
|
||||||
|
shell.NewBranch("branch-orange")
|
||||||
|
|
||||||
|
shell.CloneIntoRemote("origin")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Remotes().
|
||||||
|
Focus().
|
||||||
|
Lines(
|
||||||
|
Contains(`origin`).IsSelected(),
|
||||||
|
).
|
||||||
|
PressEnter()
|
||||||
|
|
||||||
|
t.Views().RemoteBranches().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`branch-apple`).IsSelected(),
|
||||||
|
Contains(`branch-grape`),
|
||||||
|
Contains(`branch-orange`),
|
||||||
|
).
|
||||||
|
FilterOrSearch("grape").
|
||||||
|
Lines(
|
||||||
|
Contains(`branch-grape`).IsSelected(),
|
||||||
|
).
|
||||||
|
// cancel the filter
|
||||||
|
PressEscape().
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsInvisible()
|
||||||
|
}).
|
||||||
|
Lines(
|
||||||
|
Contains(`branch-apple`),
|
||||||
|
Contains(`branch-grape`).IsSelected(),
|
||||||
|
Contains(`branch-orange`),
|
||||||
|
).
|
||||||
|
// return to remotes view
|
||||||
|
PressEscape()
|
||||||
|
|
||||||
|
t.Views().Remotes().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`origin`).IsSelected(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
151
pkg/integration/tests/filter_and_search/nested_filter.go
Normal file
151
pkg/integration/tests/filter_and_search/nested_filter.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package filter_and_search
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
var NestedFilter = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Filter in the several nested panels and verify the filters are preserved as you escape back to the surface",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
// need to create some branches, each with their own commits
|
||||||
|
shell.NewBranch("branch-gold")
|
||||||
|
shell.CreateFileAndAdd("apple", "apple")
|
||||||
|
shell.CreateFileAndAdd("orange", "orange")
|
||||||
|
shell.CreateFileAndAdd("grape", "grape")
|
||||||
|
shell.Commit("commit-knife")
|
||||||
|
|
||||||
|
shell.NewBranch("branch-silver")
|
||||||
|
shell.UpdateFileAndAdd("apple", "apple-2")
|
||||||
|
shell.UpdateFileAndAdd("orange", "orange-2")
|
||||||
|
shell.UpdateFileAndAdd("grape", "grape-2")
|
||||||
|
shell.Commit("commit-spoon")
|
||||||
|
|
||||||
|
shell.NewBranch("branch-bronze")
|
||||||
|
shell.UpdateFileAndAdd("apple", "apple-3")
|
||||||
|
shell.UpdateFileAndAdd("orange", "orange-3")
|
||||||
|
shell.UpdateFileAndAdd("grape", "grape-3")
|
||||||
|
shell.Commit("commit-fork")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Branches().
|
||||||
|
Focus().
|
||||||
|
Lines(
|
||||||
|
Contains(`branch-bronze`).IsSelected(),
|
||||||
|
Contains(`branch-silver`),
|
||||||
|
Contains(`branch-gold`),
|
||||||
|
).
|
||||||
|
FilterOrSearch("sil").
|
||||||
|
Lines(
|
||||||
|
Contains(`branch-silver`).IsSelected(),
|
||||||
|
).
|
||||||
|
PressEnter()
|
||||||
|
|
||||||
|
t.Views().SubCommits().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`commit-spoon`).IsSelected(),
|
||||||
|
Contains(`commit-knife`),
|
||||||
|
).
|
||||||
|
FilterOrSearch("knife").
|
||||||
|
Lines(
|
||||||
|
// sub-commits view searches, it doesn't filter, so we haven't filtered down the list
|
||||||
|
Contains(`commit-spoon`),
|
||||||
|
Contains(`commit-knife`).IsSelected(),
|
||||||
|
).
|
||||||
|
PressEnter()
|
||||||
|
|
||||||
|
t.Views().CommitFiles().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`apple`).IsSelected(),
|
||||||
|
Contains(`grape`),
|
||||||
|
Contains(`orange`),
|
||||||
|
).
|
||||||
|
FilterOrSearch("grape").
|
||||||
|
Lines(
|
||||||
|
Contains(`apple`),
|
||||||
|
Contains(`grape`).IsSelected(),
|
||||||
|
Contains(`orange`),
|
||||||
|
).
|
||||||
|
PressEnter()
|
||||||
|
|
||||||
|
t.Views().PatchBuilding().
|
||||||
|
IsFocused().
|
||||||
|
FilterOrSearch("newline").
|
||||||
|
SelectedLine(Contains("No newline at end of file")).
|
||||||
|
PressEscape(). // cancel search
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsInvisible()
|
||||||
|
}).
|
||||||
|
// escape to commit-files view
|
||||||
|
PressEscape()
|
||||||
|
|
||||||
|
t.Views().CommitFiles().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`apple`),
|
||||||
|
Contains(`grape`).IsSelected(),
|
||||||
|
Contains(`orange`),
|
||||||
|
).
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsVisible().Content(Contains("matches for 'grape'"))
|
||||||
|
}).
|
||||||
|
// cancel search
|
||||||
|
PressEscape().
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsInvisible()
|
||||||
|
}).
|
||||||
|
Lines(
|
||||||
|
Contains(`apple`),
|
||||||
|
Contains(`grape`).IsSelected(),
|
||||||
|
Contains(`orange`),
|
||||||
|
).
|
||||||
|
// escape to sub-commits view
|
||||||
|
PressEscape()
|
||||||
|
|
||||||
|
t.Views().SubCommits().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`commit-spoon`),
|
||||||
|
Contains(`commit-knife`).IsSelected(),
|
||||||
|
).
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsVisible().Content(Contains("matches for 'knife'"))
|
||||||
|
}).
|
||||||
|
// cancel search
|
||||||
|
PressEscape().
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsInvisible()
|
||||||
|
}).
|
||||||
|
Lines(
|
||||||
|
Contains(`commit-spoon`),
|
||||||
|
// still selected
|
||||||
|
Contains(`commit-knife`).IsSelected(),
|
||||||
|
).
|
||||||
|
// escape to branches view
|
||||||
|
PressEscape()
|
||||||
|
|
||||||
|
t.Views().Branches().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`branch-silver`).IsSelected(),
|
||||||
|
).
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsVisible().Content(Contains("matches for 'sil'"))
|
||||||
|
}).
|
||||||
|
// cancel search
|
||||||
|
PressEscape().
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsInvisible()
|
||||||
|
}).
|
||||||
|
Lines(
|
||||||
|
Contains(`branch-bronze`),
|
||||||
|
Contains(`branch-silver`).IsSelected(),
|
||||||
|
Contains(`branch-gold`),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
@ -0,0 +1,106 @@
|
|||||||
|
package filter_and_search
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/config"
|
||||||
|
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This one requires some explanation: the sub-commits and diff-file contexts are
|
||||||
|
// 'transient' in that they are spawned inside a window when you need them, but
|
||||||
|
// can be relocated elsewhere if you need them somewhere else. So for example if
|
||||||
|
// I hit enter on a branch I'll see the sub-commits view, but if I then navigate
|
||||||
|
// to the reflog context and hit enter on a reflog, the sub-commits view is moved
|
||||||
|
// to the reflog window. This is because we re-use the same view (it's a limitation
|
||||||
|
// that would be nice to remove in the future).
|
||||||
|
// Nonetheless, we need to ensure that upon moving the view, the filter is cancelled.
|
||||||
|
|
||||||
|
var NestedFilterTransient = NewIntegrationTest(NewIntegrationTestArgs{
|
||||||
|
Description: "Filter in a transient panel (sub-commits and diff-files) and ensure filter is cancelled when the panel is moved",
|
||||||
|
ExtraCmdArgs: []string{},
|
||||||
|
Skip: false,
|
||||||
|
SetupConfig: func(config *config.AppConfig) {},
|
||||||
|
SetupRepo: func(shell *Shell) {
|
||||||
|
// need to create some branches, each with their own commits
|
||||||
|
shell.NewBranch("mybranch")
|
||||||
|
shell.CreateFileAndAdd("file-one", "file-one")
|
||||||
|
shell.CreateFileAndAdd("file-two", "file-two")
|
||||||
|
shell.Commit("commit-one")
|
||||||
|
shell.EmptyCommit("commit-two")
|
||||||
|
},
|
||||||
|
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||||
|
t.Views().Branches().
|
||||||
|
Focus().
|
||||||
|
Lines(
|
||||||
|
Contains(`mybranch`).IsSelected(),
|
||||||
|
).
|
||||||
|
PressEnter()
|
||||||
|
|
||||||
|
t.Views().SubCommits().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`commit-two`).IsSelected(),
|
||||||
|
Contains(`commit-one`),
|
||||||
|
).
|
||||||
|
FilterOrSearch("one").
|
||||||
|
Lines(
|
||||||
|
Contains(`commit-two`),
|
||||||
|
Contains(`commit-one`).IsSelected(),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().ReflogCommits().
|
||||||
|
Focus().
|
||||||
|
SelectedLine(Contains("commit: commit-two")).
|
||||||
|
PressEnter()
|
||||||
|
|
||||||
|
t.Views().SubCommits().
|
||||||
|
IsFocused().
|
||||||
|
// the search on the sub-commits context has been cancelled
|
||||||
|
Lines(
|
||||||
|
Contains(`commit-two`).IsSelected(),
|
||||||
|
Contains(`commit-one`),
|
||||||
|
).
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsInvisible()
|
||||||
|
}).
|
||||||
|
NavigateToLine(Contains("commit-one")).
|
||||||
|
PressEnter()
|
||||||
|
|
||||||
|
// Now let's test the commit files context
|
||||||
|
t.Views().CommitFiles().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`file-one`).IsSelected(),
|
||||||
|
Contains(`file-two`),
|
||||||
|
).
|
||||||
|
FilterOrSearch("two").
|
||||||
|
Lines(
|
||||||
|
Contains(`file-one`),
|
||||||
|
Contains(`file-two`).IsSelected(),
|
||||||
|
)
|
||||||
|
|
||||||
|
t.Views().Branches().
|
||||||
|
Focus().
|
||||||
|
SelectedLine(Contains("mybranch")).
|
||||||
|
PressEnter()
|
||||||
|
|
||||||
|
t.Views().SubCommits().
|
||||||
|
IsFocused().
|
||||||
|
Lines(
|
||||||
|
Contains(`commit-two`).IsSelected(),
|
||||||
|
Contains(`commit-one`),
|
||||||
|
).
|
||||||
|
NavigateToLine(Contains("commit-one")).
|
||||||
|
PressEnter()
|
||||||
|
|
||||||
|
t.Views().CommitFiles().
|
||||||
|
IsFocused().
|
||||||
|
// the search on the commit-files context has been cancelled
|
||||||
|
Lines(
|
||||||
|
Contains(`file-one`).IsSelected(),
|
||||||
|
Contains(`file-two`),
|
||||||
|
).
|
||||||
|
Tap(func() {
|
||||||
|
t.Views().Search().IsInvisible()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/custom_commands"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/custom_commands"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/diff"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/diff"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/file"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/file"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/filter_and_search"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/filter_by_path"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/filter_by_path"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/interactive_rebase"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/interactive_rebase"
|
||||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/misc"
|
"github.com/jesseduffield/lazygit/pkg/integration/tests/misc"
|
||||||
@ -87,10 +88,19 @@ var tests = []*components.IntegrationTest{
|
|||||||
diff.DiffCommits,
|
diff.DiffCommits,
|
||||||
diff.IgnoreWhitespace,
|
diff.IgnoreWhitespace,
|
||||||
file.DirWithUntrackedFile,
|
file.DirWithUntrackedFile,
|
||||||
|
file.DiscardAllDirChanges,
|
||||||
file.DiscardChanges,
|
file.DiscardChanges,
|
||||||
file.DiscardStagedChanges,
|
file.DiscardStagedChanges,
|
||||||
|
file.DiscardUnstagedDirChanges,
|
||||||
|
file.DiscardUnstagedFileChanges,
|
||||||
file.Gitignore,
|
file.Gitignore,
|
||||||
file.RememberCommitMessageAfterFail,
|
file.RememberCommitMessageAfterFail,
|
||||||
|
filter_and_search.FilterCommitFiles,
|
||||||
|
filter_and_search.FilterFiles,
|
||||||
|
filter_and_search.FilterMenu,
|
||||||
|
filter_and_search.FilterRemoteBranches,
|
||||||
|
filter_and_search.NestedFilter,
|
||||||
|
filter_and_search.NestedFilterTransient,
|
||||||
filter_by_path.CliArg,
|
filter_by_path.CliArg,
|
||||||
filter_by_path.SelectFile,
|
filter_by_path.SelectFile,
|
||||||
filter_by_path.TypeFile,
|
filter_by_path.TypeFile,
|
||||||
|
@ -19,6 +19,9 @@ var (
|
|||||||
// InactiveBorderColor is the border color of the inactive active frames
|
// InactiveBorderColor is the border color of the inactive active frames
|
||||||
InactiveBorderColor gocui.Attribute
|
InactiveBorderColor gocui.Attribute
|
||||||
|
|
||||||
|
// FilteredActiveBorderColor is the border color of the active frame, when it's being searched/filtered
|
||||||
|
SearchingActiveBorderColor gocui.Attribute
|
||||||
|
|
||||||
// GocuiSelectedLineBgColor is the background color for the selected line in gocui
|
// GocuiSelectedLineBgColor is the background color for the selected line in gocui
|
||||||
GocuiSelectedLineBgColor gocui.Attribute
|
GocuiSelectedLineBgColor gocui.Attribute
|
||||||
|
|
||||||
@ -44,6 +47,7 @@ var (
|
|||||||
func UpdateTheme(themeConfig config.ThemeConfig) {
|
func UpdateTheme(themeConfig config.ThemeConfig) {
|
||||||
ActiveBorderColor = GetGocuiStyle(themeConfig.ActiveBorderColor)
|
ActiveBorderColor = GetGocuiStyle(themeConfig.ActiveBorderColor)
|
||||||
InactiveBorderColor = GetGocuiStyle(themeConfig.InactiveBorderColor)
|
InactiveBorderColor = GetGocuiStyle(themeConfig.InactiveBorderColor)
|
||||||
|
SearchingActiveBorderColor = GetGocuiStyle(themeConfig.SearchingActiveBorderColor)
|
||||||
SelectedLineBgColor = GetTextStyle(themeConfig.SelectedLineBgColor, true)
|
SelectedLineBgColor = GetTextStyle(themeConfig.SelectedLineBgColor, true)
|
||||||
SelectedRangeBgColor = GetTextStyle(themeConfig.SelectedRangeBgColor, true)
|
SelectedRangeBgColor = GetTextStyle(themeConfig.SelectedRangeBgColor, true)
|
||||||
|
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/jesseduffield/generics/slices"
|
|
||||||
"github.com/sahilm/fuzzy"
|
|
||||||
)
|
|
||||||
|
|
||||||
func FuzzySearch(needle string, haystack []string) []string {
|
|
||||||
if needle == "" {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
matches := fuzzy.Find(needle, haystack)
|
|
||||||
sort.Sort(matches)
|
|
||||||
|
|
||||||
return slices.Map(matches, func(match fuzzy.Match) string {
|
|
||||||
return match.Str
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestFuzzySearch is a function.
|
|
||||||
func TestFuzzySearch(t *testing.T) {
|
|
||||||
type scenario struct {
|
|
||||||
needle string
|
|
||||||
haystack []string
|
|
||||||
expected []string
|
|
||||||
}
|
|
||||||
|
|
||||||
scenarios := []scenario{
|
|
||||||
{
|
|
||||||
needle: "",
|
|
||||||
haystack: []string{"test"},
|
|
||||||
expected: []string{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
needle: "test",
|
|
||||||
haystack: []string{"test"},
|
|
||||||
expected: []string{"test"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
needle: "o",
|
|
||||||
haystack: []string{"a", "o", "e"},
|
|
||||||
expected: []string{"o"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
needle: "mybranch",
|
|
||||||
haystack: []string{"my_branch", "mybranch", "branch", "this is my branch"},
|
|
||||||
expected: []string{"mybranch", "my_branch", "this is my branch"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
needle: "test",
|
|
||||||
haystack: []string{"not a good match", "this 'test' is a good match", "test"},
|
|
||||||
expected: []string{"test", "this 'test' is a good match"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
needle: "test",
|
|
||||||
haystack: []string{"Test"},
|
|
||||||
expected: []string{"Test"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, s := range scenarios {
|
|
||||||
assert.EqualValues(t, s.expected, FuzzySearch(s.needle, s.haystack))
|
|
||||||
}
|
|
||||||
}
|
|
48
pkg/utils/search.go
Normal file
48
pkg/utils/search.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jesseduffield/generics/slices"
|
||||||
|
"github.com/sahilm/fuzzy"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FuzzySearch(needle string, haystack []string) []string {
|
||||||
|
if needle == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
matches := fuzzy.Find(needle, haystack)
|
||||||
|
sort.Sort(matches)
|
||||||
|
|
||||||
|
return slices.Map(matches, func(match fuzzy.Match) string {
|
||||||
|
return match.Str
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func CaseAwareContains(haystack, needle string) bool {
|
||||||
|
// if needle contains an uppercase letter, we'll do a case sensitive search
|
||||||
|
if ContainsUppercase(needle) {
|
||||||
|
return strings.Contains(haystack, needle)
|
||||||
|
}
|
||||||
|
|
||||||
|
return CaseInsensitiveContains(haystack, needle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContainsUppercase(s string) bool {
|
||||||
|
for _, r := range s {
|
||||||
|
if r >= 'A' && r <= 'Z' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func CaseInsensitiveContains(haystack, needle string) bool {
|
||||||
|
return strings.Contains(
|
||||||
|
strings.ToLower(haystack),
|
||||||
|
strings.ToLower(needle),
|
||||||
|
)
|
||||||
|
}
|
80
pkg/utils/search_test.go
Normal file
80
pkg/utils/search_test.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestFuzzySearch is a function.
|
||||||
|
func TestFuzzySearch(t *testing.T) {
|
||||||
|
type scenario struct {
|
||||||
|
needle string
|
||||||
|
haystack []string
|
||||||
|
expected []string
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []scenario{
|
||||||
|
{
|
||||||
|
needle: "",
|
||||||
|
haystack: []string{"test"},
|
||||||
|
expected: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
needle: "test",
|
||||||
|
haystack: []string{"test"},
|
||||||
|
expected: []string{"test"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
needle: "o",
|
||||||
|
haystack: []string{"a", "o", "e"},
|
||||||
|
expected: []string{"o"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
needle: "mybranch",
|
||||||
|
haystack: []string{"my_branch", "mybranch", "branch", "this is my branch"},
|
||||||
|
expected: []string{"mybranch", "my_branch", "this is my branch"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
needle: "test",
|
||||||
|
haystack: []string{"not a good match", "this 'test' is a good match", "test"},
|
||||||
|
expected: []string{"test", "this 'test' is a good match"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
needle: "test",
|
||||||
|
haystack: []string{"Test"},
|
||||||
|
expected: []string{"Test"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
assert.EqualValues(t, s.expected, FuzzySearch(s.needle, s.haystack))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCaseInsensitiveContains(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
haystack string
|
||||||
|
needle string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{"Hello, World!", "world", true}, // Case-insensitive match
|
||||||
|
{"Hello, World!", "WORLD", true}, // Case-insensitive match
|
||||||
|
{"Hello, World!", "orl", true}, // Case-insensitive match
|
||||||
|
{"Hello, World!", "o, W", true}, // Case-insensitive match
|
||||||
|
{"Hello, World!", "hello", true}, // Case-insensitive match
|
||||||
|
{"Hello, World!", "Foo", false}, // No match
|
||||||
|
{"Hello, World!", "Hello, World!!", false}, // No match
|
||||||
|
{"Hello, World!", "", true}, // Empty needle matches
|
||||||
|
{"", "Hello", false}, // Empty haystack doesn't match
|
||||||
|
{"", "", true}, // Empty strings match
|
||||||
|
{"", " ", false}, // Empty haystack, non-empty needle
|
||||||
|
{" ", "", true}, // Non-empty haystack, empty needle
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
result := CaseInsensitiveContains(testCase.haystack, testCase.needle)
|
||||||
|
assert.Equal(t, testCase.expected, result, fmt.Sprintf("Test case %d failed. Expected '%v', got '%v' for '%s' in '%s'", i, testCase.expected, result, testCase.needle, testCase.haystack))
|
||||||
|
}
|
||||||
|
}
|
@ -113,3 +113,14 @@ func MoveElement[T any](slice []T, from int, to int) []T {
|
|||||||
|
|
||||||
return newSlice
|
return newSlice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ValuesAtIndices[T any](slice []T, indices []int) []T {
|
||||||
|
result := make([]T, len(indices))
|
||||||
|
for i, index := range indices {
|
||||||
|
// gracefully handling the situation where the index is out of bounds
|
||||||
|
if index < len(slice) {
|
||||||
|
result[i] = slice[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
4
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
4
vendor/github.com/jesseduffield/gocui/view.go
generated
vendored
@ -207,6 +207,10 @@ func (v *View) gotoPreviousMatch() error {
|
|||||||
return v.SelectSearchResult(v.searcher.currentSearchIndex)
|
return v.SelectSearchResult(v.searcher.currentSearchIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *View) SelectCurrentSearchResult() error {
|
||||||
|
return v.SelectSearchResult(v.searcher.currentSearchIndex)
|
||||||
|
}
|
||||||
|
|
||||||
func (v *View) SelectSearchResult(index int) error {
|
func (v *View) SelectSearchResult(index int) error {
|
||||||
itemCount := len(v.searcher.searchPositions)
|
itemCount := len(v.searcher.searchPositions)
|
||||||
if itemCount == 0 {
|
if itemCount == 0 {
|
||||||
|
4
vendor/golang.org/x/sys/cpu/endian_little.go
generated
vendored
4
vendor/golang.org/x/sys/cpu/endian_little.go
generated
vendored
@ -2,8 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh
|
//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh || wasm
|
||||||
// +build 386 amd64 amd64p32 alpha arm arm64 loong64 mipsle mips64le mips64p32le nios2 ppc64le riscv riscv64 sh
|
// +build 386 amd64 amd64p32 alpha arm arm64 loong64 mipsle mips64le mips64p32le nios2 ppc64le riscv riscv64 sh wasm
|
||||||
|
|
||||||
package cpu
|
package cpu
|
||||||
|
|
||||||
|
2
vendor/golang.org/x/sys/unix/mkall.sh
generated
vendored
2
vendor/golang.org/x/sys/unix/mkall.sh
generated
vendored
@ -50,7 +50,7 @@ if [[ "$GOOS" = "linux" ]]; then
|
|||||||
# Use the Docker-based build system
|
# Use the Docker-based build system
|
||||||
# Files generated through docker (use $cmd so you can Ctl-C the build or run)
|
# Files generated through docker (use $cmd so you can Ctl-C the build or run)
|
||||||
$cmd docker build --tag generate:$GOOS $GOOS
|
$cmd docker build --tag generate:$GOOS $GOOS
|
||||||
$cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && /bin/pwd):/build generate:$GOOS
|
$cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && pwd):/build generate:$GOOS
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
6
vendor/golang.org/x/sys/unix/mkerrors.sh
generated
vendored
6
vendor/golang.org/x/sys/unix/mkerrors.sh
generated
vendored
@ -741,7 +741,8 @@ main(void)
|
|||||||
e = errors[i].num;
|
e = errors[i].num;
|
||||||
if(i > 0 && errors[i-1].num == e)
|
if(i > 0 && errors[i-1].num == e)
|
||||||
continue;
|
continue;
|
||||||
strcpy(buf, strerror(e));
|
strncpy(buf, strerror(e), sizeof(buf) - 1);
|
||||||
|
buf[sizeof(buf) - 1] = '\0';
|
||||||
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
|
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
|
||||||
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
|
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
|
||||||
buf[0] += a - A;
|
buf[0] += a - A;
|
||||||
@ -760,7 +761,8 @@ main(void)
|
|||||||
e = signals[i].num;
|
e = signals[i].num;
|
||||||
if(i > 0 && signals[i-1].num == e)
|
if(i > 0 && signals[i-1].num == e)
|
||||||
continue;
|
continue;
|
||||||
strcpy(buf, strsignal(e));
|
strncpy(buf, strsignal(e), sizeof(buf) - 1);
|
||||||
|
buf[sizeof(buf) - 1] = '\0';
|
||||||
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
|
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
|
||||||
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
|
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
|
||||||
buf[0] += a - A;
|
buf[0] += a - A;
|
||||||
|
30
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
30
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
@ -1699,12 +1699,23 @@ func PtracePokeUser(pid int, addr uintptr, data []byte) (count int, err error) {
|
|||||||
return ptracePoke(PTRACE_POKEUSR, PTRACE_PEEKUSR, pid, addr, data)
|
return ptracePoke(PTRACE_POKEUSR, PTRACE_PEEKUSR, pid, addr, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// elfNT_PRSTATUS is a copy of the debug/elf.NT_PRSTATUS constant so
|
||||||
|
// x/sys/unix doesn't need to depend on debug/elf and thus
|
||||||
|
// compress/zlib, debug/dwarf, and other packages.
|
||||||
|
const elfNT_PRSTATUS = 1
|
||||||
|
|
||||||
func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
|
func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
|
||||||
return ptracePtr(PTRACE_GETREGS, pid, 0, unsafe.Pointer(regsout))
|
var iov Iovec
|
||||||
|
iov.Base = (*byte)(unsafe.Pointer(regsout))
|
||||||
|
iov.SetLen(int(unsafe.Sizeof(*regsout)))
|
||||||
|
return ptracePtr(PTRACE_GETREGSET, pid, uintptr(elfNT_PRSTATUS), unsafe.Pointer(&iov))
|
||||||
}
|
}
|
||||||
|
|
||||||
func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
|
func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
|
||||||
return ptracePtr(PTRACE_SETREGS, pid, 0, unsafe.Pointer(regs))
|
var iov Iovec
|
||||||
|
iov.Base = (*byte)(unsafe.Pointer(regs))
|
||||||
|
iov.SetLen(int(unsafe.Sizeof(*regs)))
|
||||||
|
return ptracePtr(PTRACE_SETREGSET, pid, uintptr(elfNT_PRSTATUS), unsafe.Pointer(&iov))
|
||||||
}
|
}
|
||||||
|
|
||||||
func PtraceSetOptions(pid int, options int) (err error) {
|
func PtraceSetOptions(pid int, options int) (err error) {
|
||||||
@ -2420,6 +2431,21 @@ func PthreadSigmask(how int, set, oldset *Sigset_t) error {
|
|||||||
return rtSigprocmask(how, set, oldset, _C__NSIG/8)
|
return rtSigprocmask(how, set, oldset, _C__NSIG/8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sysnb getresuid(ruid *_C_int, euid *_C_int, suid *_C_int)
|
||||||
|
//sysnb getresgid(rgid *_C_int, egid *_C_int, sgid *_C_int)
|
||||||
|
|
||||||
|
func Getresuid() (ruid, euid, suid int) {
|
||||||
|
var r, e, s _C_int
|
||||||
|
getresuid(&r, &e, &s)
|
||||||
|
return int(r), int(e), int(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Getresgid() (rgid, egid, sgid int) {
|
||||||
|
var r, e, s _C_int
|
||||||
|
getresgid(&r, &e, &s)
|
||||||
|
return int(r), int(e), int(s)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unimplemented
|
* Unimplemented
|
||||||
*/
|
*/
|
||||||
|
17
vendor/golang.org/x/sys/unix/syscall_openbsd.go
generated
vendored
17
vendor/golang.org/x/sys/unix/syscall_openbsd.go
generated
vendored
@ -151,6 +151,21 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//sysnb getresuid(ruid *_C_int, euid *_C_int, suid *_C_int)
|
||||||
|
//sysnb getresgid(rgid *_C_int, egid *_C_int, sgid *_C_int)
|
||||||
|
|
||||||
|
func Getresuid() (ruid, euid, suid int) {
|
||||||
|
var r, e, s _C_int
|
||||||
|
getresuid(&r, &e, &s)
|
||||||
|
return int(r), int(e), int(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Getresgid() (rgid, egid, sgid int) {
|
||||||
|
var r, e, s _C_int
|
||||||
|
getresgid(&r, &e, &s)
|
||||||
|
return int(r), int(e), int(s)
|
||||||
|
}
|
||||||
|
|
||||||
//sys ioctl(fd int, req uint, arg uintptr) (err error)
|
//sys ioctl(fd int, req uint, arg uintptr) (err error)
|
||||||
//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
|
//sys ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) = SYS_IOCTL
|
||||||
|
|
||||||
@ -338,8 +353,6 @@ func Uname(uname *Utsname) error {
|
|||||||
// getgid
|
// getgid
|
||||||
// getitimer
|
// getitimer
|
||||||
// getlogin
|
// getlogin
|
||||||
// getresgid
|
|
||||||
// getresuid
|
|
||||||
// getthrid
|
// getthrid
|
||||||
// ktrace
|
// ktrace
|
||||||
// lfs_bmapv
|
// lfs_bmapv
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user