mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-08-24 02:24:25 -05:00
Convert keybinding fields to Keybinding
Until now every keybinding config field was a plain string. That meant a user
couldn't ask for two keys to invoke a command — the config silently accepted
only one form.
Convert every string-typed field across all 13 KeybindingXxxConfig structs to
Keybinding so the union type extends to every command. Defaults wrap their
single-key value in Keybinding{...} so the generated Config.md still renders one
scalar key per binding.
The alt fields keep their separate Binding registrations for now: this commit
does not yet introduce the merge mechanism that folds them into the main field —
that comes in a follow-up. Consumers previously calling opts.GetKeys on a string
field now call opts.GetKeys on the Keybinding, or take .String() / Keys[0] where
a single value is needed.
Adds a Keybinding.String helper for rendering, schema-generator work that
inlines the Keybinding union into each consuming property, and a unit test
covering the user-facing scalar/sequence YAML forms for quit.
This commit is contained in:
@@ -591,7 +591,10 @@ notARepository: prompt
|
||||
# view the output of the subprocess before returning to Lazygit.
|
||||
promptToReturnFromSubprocess: true
|
||||
|
||||
# Keybindings
|
||||
# Keybindings.
|
||||
# Each binding can be a single key or a list of keys; see
|
||||
# https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md
|
||||
# for the syntax.
|
||||
keybinding:
|
||||
universal:
|
||||
quit: q
|
||||
|
||||
@@ -50,7 +50,7 @@ Custom command keybindings will appear alongside inbuilt keybindings when you vi
|
||||
For a given custom command, here are the allowed fields:
|
||||
| _field_ | _description_ | required |
|
||||
|-----------------|----------------------|-|
|
||||
| key | The key to trigger the command. Use a single letter or one of the values from [here](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md). Custom commands without a key specified can be triggered by selecting them from the keybindings (`?`) menu | no |
|
||||
| key | The key to trigger the command. Use a single key or list of keys, as described in [Custom_Keybindings.md](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md). Custom commands without a key specified can be triggered by selecting them from the keybindings (`?`) menu | no |
|
||||
| command | The command to run (using Go template syntax for placeholder values) | yes |
|
||||
| context | The context in which to listen for the key (see [below](#contexts)) | yes |
|
||||
| prompts | A list of prompts that will request user input before running the final command | no |
|
||||
@@ -193,7 +193,7 @@ The permitted option fields are:
|
||||
| name | The first part of the label | no |
|
||||
| description | The second part of the label | no |
|
||||
| value | the value that will be used in the command | yes |
|
||||
| key | Keybinding to invoke this menu option without needing to navigate to it. Can be a single letter or one of the values from [here](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md) | no |
|
||||
| key | Keybinding to invoke this menu option without needing to navigate to it. Use a single key or list of keys, as described in [Custom_Keybindings.md](https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md) | no |
|
||||
|
||||
If an option has no name the value will be displayed to the user in place of the name, so you're allowed to only include the value like so:
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ A keybinding is one of:
|
||||
- A special key name in angle brackets, e.g. `<enter>`, `<f1>`, `<up>`.
|
||||
- A key with modifiers in angle brackets, e.g. `<ctrl+c>`, `<ctrl+shift+up>`.
|
||||
- The literal string `<disabled>` to disable a binding.
|
||||
- A list of any of the above, to bind multiple keys to the same action:
|
||||
`quit: [q, <ctrl+c>]`.
|
||||
|
||||
### Modifiers
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package config
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/karimkhaleel/jsonschema"
|
||||
"github.com/samber/lo"
|
||||
@@ -67,6 +68,12 @@ func (k Keybinding) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal([]string(k))
|
||||
}
|
||||
|
||||
// String renders the keybinding as a human-readable label, joining
|
||||
// alternates with " or " for use in help text.
|
||||
func (k Keybinding) String() string {
|
||||
return strings.Join(k, " or ")
|
||||
}
|
||||
|
||||
// JSONSchema lets the schema generator describe this type as a union of a
|
||||
// string and an array of strings instead of just an array.
|
||||
func (Keybinding) JSONSchema() *jsonschema.Schema {
|
||||
|
||||
@@ -149,3 +149,34 @@ func TestKeybindingYAMLRoundTrip(t *testing.T) {
|
||||
assert.Equal(t, original, decoded)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeybindingConfigYAMLAcceptsBothForms(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
name string
|
||||
yaml string
|
||||
expected Keybinding
|
||||
}{
|
||||
{
|
||||
name: "scalar form",
|
||||
yaml: "quit: q\n",
|
||||
expected: Keybinding{"q"},
|
||||
},
|
||||
{
|
||||
name: "sequence form",
|
||||
yaml: "quit: [q, <esc>]\n",
|
||||
expected: Keybinding{"q", "<esc>"},
|
||||
},
|
||||
{
|
||||
name: "block sequence form",
|
||||
yaml: "quit:\n - q\n - <esc>\n",
|
||||
expected: Keybinding{"q", "<esc>"},
|
||||
},
|
||||
}
|
||||
for _, s := range scenarios {
|
||||
t.Run(s.name, func(t *testing.T) {
|
||||
var cfg KeybindingUniversalConfig
|
||||
assert.NoError(t, yaml.Unmarshal([]byte(s.yaml), &cfg))
|
||||
assert.Equal(t, s.expected, cfg.Quit)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,10 +206,9 @@ func GetValidatedKeyBindingKey(label string) gocui.Key {
|
||||
return key
|
||||
}
|
||||
|
||||
func GetValidatedKeyBindingKeys(label string) []gocui.Key {
|
||||
k := GetValidatedKeyBindingKey(label)
|
||||
if !k.IsSet() {
|
||||
return nil
|
||||
}
|
||||
return []gocui.Key{k}
|
||||
func GetValidatedKeyBindingKeys(labels Keybinding) []gocui.Key {
|
||||
return lo.FilterMap(labels, func(label string, _ int) (gocui.Key, bool) {
|
||||
k := GetValidatedKeyBindingKey(label)
|
||||
return k, k.IsSet()
|
||||
})
|
||||
}
|
||||
|
||||
+327
-326
@@ -36,7 +36,8 @@ type UserConfig struct {
|
||||
NotARepository string `yaml:"notARepository" jsonschema:"enum=prompt,enum=create,enum=skip,enum=quit"`
|
||||
// If true, display a confirmation when subprocess terminates. This allows you to view the output of the subprocess before returning to Lazygit.
|
||||
PromptToReturnFromSubprocess bool `yaml:"promptToReturnFromSubprocess"`
|
||||
// Keybindings
|
||||
// Keybindings.
|
||||
// Each binding can be a single key or a list of keys; see https://github.com/jesseduffield/lazygit/blob/master/docs/keybindings/Custom_Keybindings.md for the syntax.
|
||||
Keybinding KeybindingConfig `yaml:"keybinding"`
|
||||
}
|
||||
|
||||
@@ -422,202 +423,202 @@ type KeybindingConfig struct {
|
||||
|
||||
// damn looks like we have some inconsistencies here with -alt and -alt1
|
||||
type KeybindingUniversalConfig struct {
|
||||
Quit string `yaml:"quit"`
|
||||
QuitAlt1 string `yaml:"quit-alt1"`
|
||||
SuspendApp string `yaml:"suspendApp"`
|
||||
Return string `yaml:"return"`
|
||||
QuitWithoutChangingDirectory string `yaml:"quitWithoutChangingDirectory"`
|
||||
TogglePanel string `yaml:"togglePanel"`
|
||||
PrevItem string `yaml:"prevItem"`
|
||||
NextItem string `yaml:"nextItem"`
|
||||
PrevItemAlt string `yaml:"prevItem-alt"`
|
||||
NextItemAlt string `yaml:"nextItem-alt"`
|
||||
PrevPage string `yaml:"prevPage"`
|
||||
NextPage string `yaml:"nextPage"`
|
||||
ScrollLeft string `yaml:"scrollLeft"`
|
||||
ScrollRight string `yaml:"scrollRight"`
|
||||
GotoTop string `yaml:"gotoTop"`
|
||||
GotoBottom string `yaml:"gotoBottom"`
|
||||
GotoTopAlt string `yaml:"gotoTop-alt"`
|
||||
GotoBottomAlt string `yaml:"gotoBottom-alt"`
|
||||
ToggleRangeSelect string `yaml:"toggleRangeSelect"`
|
||||
RangeSelectDown string `yaml:"rangeSelectDown"`
|
||||
RangeSelectUp string `yaml:"rangeSelectUp"`
|
||||
PrevBlock string `yaml:"prevBlock"`
|
||||
NextBlock string `yaml:"nextBlock"`
|
||||
PrevBlockAlt string `yaml:"prevBlock-alt"`
|
||||
NextBlockAlt string `yaml:"nextBlock-alt"`
|
||||
NextBlockAlt2 string `yaml:"nextBlock-alt2"`
|
||||
PrevBlockAlt2 string `yaml:"prevBlock-alt2"`
|
||||
JumpToBlock []string `yaml:"jumpToBlock"`
|
||||
FocusMainView string `yaml:"focusMainView"`
|
||||
NextMatch string `yaml:"nextMatch"`
|
||||
PrevMatch string `yaml:"prevMatch"`
|
||||
StartSearch string `yaml:"startSearch"`
|
||||
MoveWordLeft string `yaml:"moveWordLeft"` // <alt+left> on Mac
|
||||
MoveWordRight string `yaml:"moveWordRight"` // <alt+right> on Mac
|
||||
BackspaceWord string `yaml:"backspaceWord"` // <alt+backspace> on Mac
|
||||
ForwardDeleteWord string `yaml:"forwardDeleteWord"` // <alt+delete> on Mac
|
||||
OptionMenu string `yaml:"optionMenu"`
|
||||
Select string `yaml:"select"`
|
||||
GoInto string `yaml:"goInto"`
|
||||
Confirm string `yaml:"confirm"`
|
||||
ConfirmMenu string `yaml:"confirmMenu"`
|
||||
ConfirmSuggestion string `yaml:"confirmSuggestion"`
|
||||
ConfirmInEditor string `yaml:"confirmInEditor"` // <meta+enter> on Mac
|
||||
ConfirmInEditorAlt string `yaml:"confirmInEditor-alt"`
|
||||
Remove string `yaml:"remove"`
|
||||
New string `yaml:"new"`
|
||||
Edit string `yaml:"edit"`
|
||||
OpenFile string `yaml:"openFile"`
|
||||
ScrollUpMain string `yaml:"scrollUpMain"`
|
||||
ScrollDownMain string `yaml:"scrollDownMain"`
|
||||
ScrollUpMainAlt1 string `yaml:"scrollUpMain-alt1"`
|
||||
ScrollDownMainAlt1 string `yaml:"scrollDownMain-alt1"`
|
||||
ScrollUpMainAlt2 string `yaml:"scrollUpMain-alt2"`
|
||||
ScrollDownMainAlt2 string `yaml:"scrollDownMain-alt2"`
|
||||
ExecuteShellCommand string `yaml:"executeShellCommand"`
|
||||
CreateRebaseOptionsMenu string `yaml:"createRebaseOptionsMenu"`
|
||||
Push string `yaml:"pushFiles"` // 'Files' appended for legacy reasons
|
||||
Pull string `yaml:"pullFiles"` // 'Files' appended for legacy reasons
|
||||
Refresh string `yaml:"refresh"`
|
||||
CreatePatchOptionsMenu string `yaml:"createPatchOptionsMenu"`
|
||||
NextTab string `yaml:"nextTab"`
|
||||
PrevTab string `yaml:"prevTab"`
|
||||
NextScreenMode string `yaml:"nextScreenMode"`
|
||||
PrevScreenMode string `yaml:"prevScreenMode"`
|
||||
CyclePagers string `yaml:"cyclePagers"`
|
||||
Undo string `yaml:"undo"`
|
||||
Redo string `yaml:"redo"`
|
||||
FilteringMenu string `yaml:"filteringMenu"`
|
||||
DiffingMenu string `yaml:"diffingMenu"`
|
||||
DiffingMenuAlt string `yaml:"diffingMenu-alt"`
|
||||
CopyToClipboard string `yaml:"copyToClipboard"`
|
||||
OpenRecentRepos string `yaml:"openRecentRepos"`
|
||||
SubmitEditorText string `yaml:"submitEditorText"`
|
||||
ExtrasMenu string `yaml:"extrasMenu"`
|
||||
ToggleWhitespaceInDiffView string `yaml:"toggleWhitespaceInDiffView"`
|
||||
IncreaseContextInDiffView string `yaml:"increaseContextInDiffView"`
|
||||
DecreaseContextInDiffView string `yaml:"decreaseContextInDiffView"`
|
||||
IncreaseRenameSimilarityThreshold string `yaml:"increaseRenameSimilarityThreshold"`
|
||||
DecreaseRenameSimilarityThreshold string `yaml:"decreaseRenameSimilarityThreshold"`
|
||||
OpenDiffTool string `yaml:"openDiffTool"`
|
||||
Quit Keybinding `yaml:"quit"`
|
||||
QuitAlt1 Keybinding `yaml:"quit-alt1"`
|
||||
SuspendApp Keybinding `yaml:"suspendApp"`
|
||||
Return Keybinding `yaml:"return"`
|
||||
QuitWithoutChangingDirectory Keybinding `yaml:"quitWithoutChangingDirectory"`
|
||||
TogglePanel Keybinding `yaml:"togglePanel"`
|
||||
PrevItem Keybinding `yaml:"prevItem"`
|
||||
NextItem Keybinding `yaml:"nextItem"`
|
||||
PrevItemAlt Keybinding `yaml:"prevItem-alt"`
|
||||
NextItemAlt Keybinding `yaml:"nextItem-alt"`
|
||||
PrevPage Keybinding `yaml:"prevPage"`
|
||||
NextPage Keybinding `yaml:"nextPage"`
|
||||
ScrollLeft Keybinding `yaml:"scrollLeft"`
|
||||
ScrollRight Keybinding `yaml:"scrollRight"`
|
||||
GotoTop Keybinding `yaml:"gotoTop"`
|
||||
GotoBottom Keybinding `yaml:"gotoBottom"`
|
||||
GotoTopAlt Keybinding `yaml:"gotoTop-alt"`
|
||||
GotoBottomAlt Keybinding `yaml:"gotoBottom-alt"`
|
||||
ToggleRangeSelect Keybinding `yaml:"toggleRangeSelect"`
|
||||
RangeSelectDown Keybinding `yaml:"rangeSelectDown"`
|
||||
RangeSelectUp Keybinding `yaml:"rangeSelectUp"`
|
||||
PrevBlock Keybinding `yaml:"prevBlock"`
|
||||
NextBlock Keybinding `yaml:"nextBlock"`
|
||||
PrevBlockAlt Keybinding `yaml:"prevBlock-alt"`
|
||||
NextBlockAlt Keybinding `yaml:"nextBlock-alt"`
|
||||
NextBlockAlt2 Keybinding `yaml:"nextBlock-alt2"`
|
||||
PrevBlockAlt2 Keybinding `yaml:"prevBlock-alt2"`
|
||||
JumpToBlock []string `yaml:"jumpToBlock"`
|
||||
FocusMainView Keybinding `yaml:"focusMainView"`
|
||||
NextMatch Keybinding `yaml:"nextMatch"`
|
||||
PrevMatch Keybinding `yaml:"prevMatch"`
|
||||
StartSearch Keybinding `yaml:"startSearch"`
|
||||
MoveWordLeft Keybinding `yaml:"moveWordLeft"` // <alt+left> on Mac
|
||||
MoveWordRight Keybinding `yaml:"moveWordRight"` // <alt+right> on Mac
|
||||
BackspaceWord Keybinding `yaml:"backspaceWord"` // <alt+backspace> on Mac
|
||||
ForwardDeleteWord Keybinding `yaml:"forwardDeleteWord"` // <alt+delete> on Mac
|
||||
OptionMenu Keybinding `yaml:"optionMenu"`
|
||||
Select Keybinding `yaml:"select"`
|
||||
GoInto Keybinding `yaml:"goInto"`
|
||||
Confirm Keybinding `yaml:"confirm"`
|
||||
ConfirmMenu Keybinding `yaml:"confirmMenu"`
|
||||
ConfirmSuggestion Keybinding `yaml:"confirmSuggestion"`
|
||||
ConfirmInEditor Keybinding `yaml:"confirmInEditor"` // <meta+enter> on Mac
|
||||
ConfirmInEditorAlt Keybinding `yaml:"confirmInEditor-alt"`
|
||||
Remove Keybinding `yaml:"remove"`
|
||||
New Keybinding `yaml:"new"`
|
||||
Edit Keybinding `yaml:"edit"`
|
||||
OpenFile Keybinding `yaml:"openFile"`
|
||||
ScrollUpMain Keybinding `yaml:"scrollUpMain"`
|
||||
ScrollDownMain Keybinding `yaml:"scrollDownMain"`
|
||||
ScrollUpMainAlt1 Keybinding `yaml:"scrollUpMain-alt1"`
|
||||
ScrollDownMainAlt1 Keybinding `yaml:"scrollDownMain-alt1"`
|
||||
ScrollUpMainAlt2 Keybinding `yaml:"scrollUpMain-alt2"`
|
||||
ScrollDownMainAlt2 Keybinding `yaml:"scrollDownMain-alt2"`
|
||||
ExecuteShellCommand Keybinding `yaml:"executeShellCommand"`
|
||||
CreateRebaseOptionsMenu Keybinding `yaml:"createRebaseOptionsMenu"`
|
||||
Push Keybinding `yaml:"pushFiles"` // 'Files' appended for legacy reasons
|
||||
Pull Keybinding `yaml:"pullFiles"` // 'Files' appended for legacy reasons
|
||||
Refresh Keybinding `yaml:"refresh"`
|
||||
CreatePatchOptionsMenu Keybinding `yaml:"createPatchOptionsMenu"`
|
||||
NextTab Keybinding `yaml:"nextTab"`
|
||||
PrevTab Keybinding `yaml:"prevTab"`
|
||||
NextScreenMode Keybinding `yaml:"nextScreenMode"`
|
||||
PrevScreenMode Keybinding `yaml:"prevScreenMode"`
|
||||
CyclePagers Keybinding `yaml:"cyclePagers"`
|
||||
Undo Keybinding `yaml:"undo"`
|
||||
Redo Keybinding `yaml:"redo"`
|
||||
FilteringMenu Keybinding `yaml:"filteringMenu"`
|
||||
DiffingMenu Keybinding `yaml:"diffingMenu"`
|
||||
DiffingMenuAlt Keybinding `yaml:"diffingMenu-alt"`
|
||||
CopyToClipboard Keybinding `yaml:"copyToClipboard"`
|
||||
OpenRecentRepos Keybinding `yaml:"openRecentRepos"`
|
||||
SubmitEditorText Keybinding `yaml:"submitEditorText"`
|
||||
ExtrasMenu Keybinding `yaml:"extrasMenu"`
|
||||
ToggleWhitespaceInDiffView Keybinding `yaml:"toggleWhitespaceInDiffView"`
|
||||
IncreaseContextInDiffView Keybinding `yaml:"increaseContextInDiffView"`
|
||||
DecreaseContextInDiffView Keybinding `yaml:"decreaseContextInDiffView"`
|
||||
IncreaseRenameSimilarityThreshold Keybinding `yaml:"increaseRenameSimilarityThreshold"`
|
||||
DecreaseRenameSimilarityThreshold Keybinding `yaml:"decreaseRenameSimilarityThreshold"`
|
||||
OpenDiffTool Keybinding `yaml:"openDiffTool"`
|
||||
}
|
||||
|
||||
type KeybindingStatusConfig struct {
|
||||
CheckForUpdate string `yaml:"checkForUpdate"`
|
||||
RecentRepos string `yaml:"recentRepos"`
|
||||
AllBranchesLogGraph string `yaml:"allBranchesLogGraph"`
|
||||
AllBranchesLogGraphReverse string `yaml:"allBranchesLogGraphReverse"`
|
||||
CheckForUpdate Keybinding `yaml:"checkForUpdate"`
|
||||
RecentRepos Keybinding `yaml:"recentRepos"`
|
||||
AllBranchesLogGraph Keybinding `yaml:"allBranchesLogGraph"`
|
||||
AllBranchesLogGraphReverse Keybinding `yaml:"allBranchesLogGraphReverse"`
|
||||
}
|
||||
|
||||
type KeybindingFilesConfig struct {
|
||||
CommitChanges string `yaml:"commitChanges"`
|
||||
CommitChangesWithoutHook string `yaml:"commitChangesWithoutHook"`
|
||||
AmendLastCommit string `yaml:"amendLastCommit"`
|
||||
CommitChangesWithEditor string `yaml:"commitChangesWithEditor"`
|
||||
FindBaseCommitForFixup string `yaml:"findBaseCommitForFixup"`
|
||||
ConfirmDiscard string `yaml:"confirmDiscard"`
|
||||
IgnoreFile string `yaml:"ignoreFile"`
|
||||
RefreshFiles string `yaml:"refreshFiles"`
|
||||
StashAllChanges string `yaml:"stashAllChanges"`
|
||||
ViewStashOptions string `yaml:"viewStashOptions"`
|
||||
ToggleStagedAll string `yaml:"toggleStagedAll"`
|
||||
ViewResetOptions string `yaml:"viewResetOptions"`
|
||||
Fetch string `yaml:"fetch"`
|
||||
ToggleTreeView string `yaml:"toggleTreeView"`
|
||||
OpenMergeOptions string `yaml:"openMergeOptions"`
|
||||
OpenStatusFilter string `yaml:"openStatusFilter"`
|
||||
CopyFileInfoToClipboard string `yaml:"copyFileInfoToClipboard"`
|
||||
CollapseAll string `yaml:"collapseAll"`
|
||||
ExpandAll string `yaml:"expandAll"`
|
||||
CommitChanges Keybinding `yaml:"commitChanges"`
|
||||
CommitChangesWithoutHook Keybinding `yaml:"commitChangesWithoutHook"`
|
||||
AmendLastCommit Keybinding `yaml:"amendLastCommit"`
|
||||
CommitChangesWithEditor Keybinding `yaml:"commitChangesWithEditor"`
|
||||
FindBaseCommitForFixup Keybinding `yaml:"findBaseCommitForFixup"`
|
||||
ConfirmDiscard Keybinding `yaml:"confirmDiscard"`
|
||||
IgnoreFile Keybinding `yaml:"ignoreFile"`
|
||||
RefreshFiles Keybinding `yaml:"refreshFiles"`
|
||||
StashAllChanges Keybinding `yaml:"stashAllChanges"`
|
||||
ViewStashOptions Keybinding `yaml:"viewStashOptions"`
|
||||
ToggleStagedAll Keybinding `yaml:"toggleStagedAll"`
|
||||
ViewResetOptions Keybinding `yaml:"viewResetOptions"`
|
||||
Fetch Keybinding `yaml:"fetch"`
|
||||
ToggleTreeView Keybinding `yaml:"toggleTreeView"`
|
||||
OpenMergeOptions Keybinding `yaml:"openMergeOptions"`
|
||||
OpenStatusFilter Keybinding `yaml:"openStatusFilter"`
|
||||
CopyFileInfoToClipboard Keybinding `yaml:"copyFileInfoToClipboard"`
|
||||
CollapseAll Keybinding `yaml:"collapseAll"`
|
||||
ExpandAll Keybinding `yaml:"expandAll"`
|
||||
}
|
||||
|
||||
type KeybindingBranchesConfig struct {
|
||||
CreatePullRequest string `yaml:"createPullRequest"`
|
||||
ViewPullRequestOptions string `yaml:"viewPullRequestOptions"`
|
||||
OpenPullRequestInBrowser string `yaml:"openPullRequestInBrowser"`
|
||||
CopyPullRequestURL string `yaml:"copyPullRequestURL"`
|
||||
CheckoutBranchByName string `yaml:"checkoutBranchByName"`
|
||||
ForceCheckoutBranch string `yaml:"forceCheckoutBranch"`
|
||||
CheckoutPreviousBranch string `yaml:"checkoutPreviousBranch"`
|
||||
RebaseBranch string `yaml:"rebaseBranch"`
|
||||
RenameBranch string `yaml:"renameBranch"`
|
||||
MergeIntoCurrentBranch string `yaml:"mergeIntoCurrentBranch"`
|
||||
MoveCommitsToNewBranch string `yaml:"moveCommitsToNewBranch"`
|
||||
ViewGitFlowOptions string `yaml:"viewGitFlowOptions"`
|
||||
FastForward string `yaml:"fastForward"`
|
||||
CreateTag string `yaml:"createTag"`
|
||||
PushTag string `yaml:"pushTag"`
|
||||
SetUpstream string `yaml:"setUpstream"`
|
||||
FetchRemote string `yaml:"fetchRemote"`
|
||||
AddForkRemote string `yaml:"addForkRemote"`
|
||||
SortOrder string `yaml:"sortOrder"`
|
||||
CreatePullRequest Keybinding `yaml:"createPullRequest"`
|
||||
ViewPullRequestOptions Keybinding `yaml:"viewPullRequestOptions"`
|
||||
OpenPullRequestInBrowser Keybinding `yaml:"openPullRequestInBrowser"`
|
||||
CopyPullRequestURL Keybinding `yaml:"copyPullRequestURL"`
|
||||
CheckoutBranchByName Keybinding `yaml:"checkoutBranchByName"`
|
||||
ForceCheckoutBranch Keybinding `yaml:"forceCheckoutBranch"`
|
||||
CheckoutPreviousBranch Keybinding `yaml:"checkoutPreviousBranch"`
|
||||
RebaseBranch Keybinding `yaml:"rebaseBranch"`
|
||||
RenameBranch Keybinding `yaml:"renameBranch"`
|
||||
MergeIntoCurrentBranch Keybinding `yaml:"mergeIntoCurrentBranch"`
|
||||
MoveCommitsToNewBranch Keybinding `yaml:"moveCommitsToNewBranch"`
|
||||
ViewGitFlowOptions Keybinding `yaml:"viewGitFlowOptions"`
|
||||
FastForward Keybinding `yaml:"fastForward"`
|
||||
CreateTag Keybinding `yaml:"createTag"`
|
||||
PushTag Keybinding `yaml:"pushTag"`
|
||||
SetUpstream Keybinding `yaml:"setUpstream"`
|
||||
FetchRemote Keybinding `yaml:"fetchRemote"`
|
||||
AddForkRemote Keybinding `yaml:"addForkRemote"`
|
||||
SortOrder Keybinding `yaml:"sortOrder"`
|
||||
}
|
||||
|
||||
type KeybindingWorktreesConfig struct {
|
||||
ViewWorktreeOptions string `yaml:"viewWorktreeOptions"`
|
||||
ViewWorktreeOptions Keybinding `yaml:"viewWorktreeOptions"`
|
||||
}
|
||||
|
||||
type KeybindingCommitsConfig struct {
|
||||
SquashDown string `yaml:"squashDown"`
|
||||
RenameCommit string `yaml:"renameCommit"`
|
||||
RenameCommitWithEditor string `yaml:"renameCommitWithEditor"`
|
||||
ViewResetOptions string `yaml:"viewResetOptions"`
|
||||
MarkCommitAsFixup string `yaml:"markCommitAsFixup"`
|
||||
SetFixupMessage string `yaml:"setFixupMessage"`
|
||||
CreateFixupCommit string `yaml:"createFixupCommit"`
|
||||
SquashAboveCommits string `yaml:"squashAboveCommits"`
|
||||
MoveDownCommit string `yaml:"moveDownCommit"`
|
||||
MoveUpCommit string `yaml:"moveUpCommit"`
|
||||
AmendToCommit string `yaml:"amendToCommit"`
|
||||
ResetCommitAuthor string `yaml:"resetCommitAuthor"`
|
||||
PickCommit string `yaml:"pickCommit"`
|
||||
RevertCommit string `yaml:"revertCommit"`
|
||||
CherryPickCopy string `yaml:"cherryPickCopy"`
|
||||
PasteCommits string `yaml:"pasteCommits"`
|
||||
MarkCommitAsBaseForRebase string `yaml:"markCommitAsBaseForRebase"`
|
||||
CreateTag string `yaml:"tagCommit"`
|
||||
CheckoutCommit string `yaml:"checkoutCommit"`
|
||||
ResetCherryPick string `yaml:"resetCherryPick"`
|
||||
CopyCommitAttributeToClipboard string `yaml:"copyCommitAttributeToClipboard"`
|
||||
OpenLogMenu string `yaml:"openLogMenu"`
|
||||
OpenInBrowser string `yaml:"openInBrowser"`
|
||||
OpenPullRequestInBrowser string `yaml:"openPullRequestInBrowser"`
|
||||
ViewBisectOptions string `yaml:"viewBisectOptions"`
|
||||
StartInteractiveRebase string `yaml:"startInteractiveRebase"`
|
||||
SelectCommitsOfCurrentBranch string `yaml:"selectCommitsOfCurrentBranch"`
|
||||
SquashDown Keybinding `yaml:"squashDown"`
|
||||
RenameCommit Keybinding `yaml:"renameCommit"`
|
||||
RenameCommitWithEditor Keybinding `yaml:"renameCommitWithEditor"`
|
||||
ViewResetOptions Keybinding `yaml:"viewResetOptions"`
|
||||
MarkCommitAsFixup Keybinding `yaml:"markCommitAsFixup"`
|
||||
SetFixupMessage Keybinding `yaml:"setFixupMessage"`
|
||||
CreateFixupCommit Keybinding `yaml:"createFixupCommit"`
|
||||
SquashAboveCommits Keybinding `yaml:"squashAboveCommits"`
|
||||
MoveDownCommit Keybinding `yaml:"moveDownCommit"`
|
||||
MoveUpCommit Keybinding `yaml:"moveUpCommit"`
|
||||
AmendToCommit Keybinding `yaml:"amendToCommit"`
|
||||
ResetCommitAuthor Keybinding `yaml:"resetCommitAuthor"`
|
||||
PickCommit Keybinding `yaml:"pickCommit"`
|
||||
RevertCommit Keybinding `yaml:"revertCommit"`
|
||||
CherryPickCopy Keybinding `yaml:"cherryPickCopy"`
|
||||
PasteCommits Keybinding `yaml:"pasteCommits"`
|
||||
MarkCommitAsBaseForRebase Keybinding `yaml:"markCommitAsBaseForRebase"`
|
||||
CreateTag Keybinding `yaml:"tagCommit"`
|
||||
CheckoutCommit Keybinding `yaml:"checkoutCommit"`
|
||||
ResetCherryPick Keybinding `yaml:"resetCherryPick"`
|
||||
CopyCommitAttributeToClipboard Keybinding `yaml:"copyCommitAttributeToClipboard"`
|
||||
OpenLogMenu Keybinding `yaml:"openLogMenu"`
|
||||
OpenInBrowser Keybinding `yaml:"openInBrowser"`
|
||||
OpenPullRequestInBrowser Keybinding `yaml:"openPullRequestInBrowser"`
|
||||
ViewBisectOptions Keybinding `yaml:"viewBisectOptions"`
|
||||
StartInteractiveRebase Keybinding `yaml:"startInteractiveRebase"`
|
||||
SelectCommitsOfCurrentBranch Keybinding `yaml:"selectCommitsOfCurrentBranch"`
|
||||
}
|
||||
|
||||
type KeybindingAmendAttributeConfig struct {
|
||||
ResetAuthor string `yaml:"resetAuthor"`
|
||||
SetAuthor string `yaml:"setAuthor"`
|
||||
AddCoAuthor string `yaml:"addCoAuthor"`
|
||||
ResetAuthor Keybinding `yaml:"resetAuthor"`
|
||||
SetAuthor Keybinding `yaml:"setAuthor"`
|
||||
AddCoAuthor Keybinding `yaml:"addCoAuthor"`
|
||||
}
|
||||
|
||||
type KeybindingStashConfig struct {
|
||||
PopStash string `yaml:"popStash"`
|
||||
RenameStash string `yaml:"renameStash"`
|
||||
PopStash Keybinding `yaml:"popStash"`
|
||||
RenameStash Keybinding `yaml:"renameStash"`
|
||||
}
|
||||
|
||||
type KeybindingCommitFilesConfig struct {
|
||||
CheckoutCommitFile string `yaml:"checkoutCommitFile"`
|
||||
CheckoutCommitFile Keybinding `yaml:"checkoutCommitFile"`
|
||||
}
|
||||
|
||||
type KeybindingMainConfig struct {
|
||||
ToggleSelectHunk string `yaml:"toggleSelectHunk"`
|
||||
PickBothHunks string `yaml:"pickBothHunks"`
|
||||
EditSelectHunk string `yaml:"editSelectHunk"`
|
||||
ToggleSelectHunk Keybinding `yaml:"toggleSelectHunk"`
|
||||
PickBothHunks Keybinding `yaml:"pickBothHunks"`
|
||||
EditSelectHunk Keybinding `yaml:"editSelectHunk"`
|
||||
}
|
||||
|
||||
type KeybindingSubmodulesConfig struct {
|
||||
Init string `yaml:"init"`
|
||||
Update string `yaml:"update"`
|
||||
BulkMenu string `yaml:"bulkMenu"`
|
||||
Init Keybinding `yaml:"init"`
|
||||
Update Keybinding `yaml:"update"`
|
||||
BulkMenu Keybinding `yaml:"bulkMenu"`
|
||||
}
|
||||
|
||||
type KeybindingCommitMessageConfig struct {
|
||||
CommitMenu string `yaml:"commitMenu"`
|
||||
CommitMenu Keybinding `yaml:"commitMenu"`
|
||||
}
|
||||
|
||||
// OSConfig contains config on the level of the os
|
||||
@@ -904,191 +905,191 @@ func GetDefaultConfigForPlatform(platform string) *UserConfig {
|
||||
PromptToReturnFromSubprocess: true,
|
||||
Keybinding: KeybindingConfig{
|
||||
Universal: KeybindingUniversalConfig{
|
||||
Quit: "q",
|
||||
QuitAlt1: "<ctrl+c>",
|
||||
SuspendApp: "<ctrl+z>",
|
||||
Return: "<esc>",
|
||||
QuitWithoutChangingDirectory: "Q",
|
||||
TogglePanel: "<tab>",
|
||||
PrevItem: "<up>",
|
||||
NextItem: "<down>",
|
||||
PrevItemAlt: "k",
|
||||
NextItemAlt: "j",
|
||||
PrevPage: ",",
|
||||
NextPage: ".",
|
||||
ScrollLeft: "H",
|
||||
ScrollRight: "L",
|
||||
GotoTop: "<",
|
||||
GotoBottom: ">",
|
||||
GotoTopAlt: "<home>",
|
||||
GotoBottomAlt: "<end>",
|
||||
ToggleRangeSelect: "v",
|
||||
RangeSelectDown: "<shift+down>",
|
||||
RangeSelectUp: "<shift+up>",
|
||||
PrevBlock: "<left>",
|
||||
NextBlock: "<right>",
|
||||
PrevBlockAlt: "h",
|
||||
NextBlockAlt: "l",
|
||||
PrevBlockAlt2: "<backtab>",
|
||||
NextBlockAlt2: "<tab>",
|
||||
Quit: Keybinding{"q"},
|
||||
QuitAlt1: Keybinding{"<ctrl+c>"},
|
||||
SuspendApp: Keybinding{"<ctrl+z>"},
|
||||
Return: Keybinding{"<esc>"},
|
||||
QuitWithoutChangingDirectory: Keybinding{"Q"},
|
||||
TogglePanel: Keybinding{"<tab>"},
|
||||
PrevItem: Keybinding{"<up>"},
|
||||
NextItem: Keybinding{"<down>"},
|
||||
PrevItemAlt: Keybinding{"k"},
|
||||
NextItemAlt: Keybinding{"j"},
|
||||
PrevPage: Keybinding{","},
|
||||
NextPage: Keybinding{"."},
|
||||
ScrollLeft: Keybinding{"H"},
|
||||
ScrollRight: Keybinding{"L"},
|
||||
GotoTop: Keybinding{"<"},
|
||||
GotoBottom: Keybinding{">"},
|
||||
GotoTopAlt: Keybinding{"<home>"},
|
||||
GotoBottomAlt: Keybinding{"<end>"},
|
||||
ToggleRangeSelect: Keybinding{"v"},
|
||||
RangeSelectDown: Keybinding{"<shift+down>"},
|
||||
RangeSelectUp: Keybinding{"<shift+up>"},
|
||||
PrevBlock: Keybinding{"<left>"},
|
||||
NextBlock: Keybinding{"<right>"},
|
||||
PrevBlockAlt: Keybinding{"h"},
|
||||
NextBlockAlt: Keybinding{"l"},
|
||||
PrevBlockAlt2: Keybinding{"<backtab>"},
|
||||
NextBlockAlt2: Keybinding{"<tab>"},
|
||||
JumpToBlock: []string{"1", "2", "3", "4", "5"},
|
||||
FocusMainView: "0",
|
||||
NextMatch: "n",
|
||||
PrevMatch: "N",
|
||||
StartSearch: "/",
|
||||
MoveWordLeft: platformKeyBinding(platform, map[string]string{"darwin": "<alt+left>"}, "<ctrl+left>"),
|
||||
MoveWordRight: platformKeyBinding(platform, map[string]string{"darwin": "<alt+right>"}, "<ctrl+right>"),
|
||||
BackspaceWord: platformKeyBinding(platform, map[string]string{"darwin": "<alt+backspace>"}, "<ctrl+backspace>"),
|
||||
ForwardDeleteWord: platformKeyBinding(platform, map[string]string{"darwin": "<alt+delete>"}, "<ctrl+delete>"),
|
||||
OptionMenu: "?",
|
||||
Select: "<space>",
|
||||
GoInto: "<enter>",
|
||||
Confirm: "<enter>",
|
||||
ConfirmMenu: "<enter>",
|
||||
ConfirmSuggestion: "<enter>",
|
||||
ConfirmInEditor: platformKeyBinding(platform, map[string]string{"darwin": "<meta+enter>"}, "<ctrl+enter>"),
|
||||
ConfirmInEditorAlt: "<ctrl+s>",
|
||||
Remove: "d",
|
||||
New: "n",
|
||||
Edit: "e",
|
||||
OpenFile: "o",
|
||||
OpenRecentRepos: "<ctrl+r>",
|
||||
ScrollUpMain: "<pgup>",
|
||||
ScrollDownMain: "<pgdown>",
|
||||
ScrollUpMainAlt1: "K",
|
||||
ScrollDownMainAlt1: "J",
|
||||
ScrollUpMainAlt2: "<ctrl+u>",
|
||||
ScrollDownMainAlt2: "<ctrl+d>",
|
||||
ExecuteShellCommand: ":",
|
||||
CreateRebaseOptionsMenu: "m",
|
||||
Push: "P",
|
||||
Pull: "p",
|
||||
Refresh: "R",
|
||||
CreatePatchOptionsMenu: "<ctrl+p>",
|
||||
NextTab: "]",
|
||||
PrevTab: "[",
|
||||
NextScreenMode: "+",
|
||||
PrevScreenMode: "_",
|
||||
CyclePagers: "|",
|
||||
Undo: "z",
|
||||
Redo: "Z",
|
||||
FilteringMenu: "<ctrl+s>",
|
||||
DiffingMenu: "W",
|
||||
DiffingMenuAlt: "<ctrl+e>",
|
||||
CopyToClipboard: "<ctrl+o>",
|
||||
SubmitEditorText: "<enter>",
|
||||
ExtrasMenu: "@",
|
||||
ToggleWhitespaceInDiffView: "<ctrl+w>",
|
||||
IncreaseContextInDiffView: "}",
|
||||
DecreaseContextInDiffView: "{",
|
||||
IncreaseRenameSimilarityThreshold: ")",
|
||||
DecreaseRenameSimilarityThreshold: "(",
|
||||
OpenDiffTool: "<ctrl+t>",
|
||||
FocusMainView: Keybinding{"0"},
|
||||
NextMatch: Keybinding{"n"},
|
||||
PrevMatch: Keybinding{"N"},
|
||||
StartSearch: Keybinding{"/"},
|
||||
MoveWordLeft: Keybinding{platformKeyBinding(platform, map[string]string{"darwin": "<alt+left>"}, "<ctrl+left>")},
|
||||
MoveWordRight: Keybinding{platformKeyBinding(platform, map[string]string{"darwin": "<alt+right>"}, "<ctrl+right>")},
|
||||
BackspaceWord: Keybinding{platformKeyBinding(platform, map[string]string{"darwin": "<alt+backspace>"}, "<ctrl+backspace>")},
|
||||
ForwardDeleteWord: Keybinding{platformKeyBinding(platform, map[string]string{"darwin": "<alt+delete>"}, "<ctrl+delete>")},
|
||||
OptionMenu: Keybinding{"?"},
|
||||
Select: Keybinding{"<space>"},
|
||||
GoInto: Keybinding{"<enter>"},
|
||||
Confirm: Keybinding{"<enter>"},
|
||||
ConfirmMenu: Keybinding{"<enter>"},
|
||||
ConfirmSuggestion: Keybinding{"<enter>"},
|
||||
ConfirmInEditor: Keybinding{platformKeyBinding(platform, map[string]string{"darwin": "<meta+enter>"}, "<ctrl+enter>")},
|
||||
ConfirmInEditorAlt: Keybinding{"<ctrl+s>"},
|
||||
Remove: Keybinding{"d"},
|
||||
New: Keybinding{"n"},
|
||||
Edit: Keybinding{"e"},
|
||||
OpenFile: Keybinding{"o"},
|
||||
OpenRecentRepos: Keybinding{"<ctrl+r>"},
|
||||
ScrollUpMain: Keybinding{"<pgup>"},
|
||||
ScrollDownMain: Keybinding{"<pgdown>"},
|
||||
ScrollUpMainAlt1: Keybinding{"K"},
|
||||
ScrollDownMainAlt1: Keybinding{"J"},
|
||||
ScrollUpMainAlt2: Keybinding{"<ctrl+u>"},
|
||||
ScrollDownMainAlt2: Keybinding{"<ctrl+d>"},
|
||||
ExecuteShellCommand: Keybinding{":"},
|
||||
CreateRebaseOptionsMenu: Keybinding{"m"},
|
||||
Push: Keybinding{"P"},
|
||||
Pull: Keybinding{"p"},
|
||||
Refresh: Keybinding{"R"},
|
||||
CreatePatchOptionsMenu: Keybinding{"<ctrl+p>"},
|
||||
NextTab: Keybinding{"]"},
|
||||
PrevTab: Keybinding{"["},
|
||||
NextScreenMode: Keybinding{"+"},
|
||||
PrevScreenMode: Keybinding{"_"},
|
||||
CyclePagers: Keybinding{"|"},
|
||||
Undo: Keybinding{"z"},
|
||||
Redo: Keybinding{"Z"},
|
||||
FilteringMenu: Keybinding{"<ctrl+s>"},
|
||||
DiffingMenu: Keybinding{"W"},
|
||||
DiffingMenuAlt: Keybinding{"<ctrl+e>"},
|
||||
CopyToClipboard: Keybinding{"<ctrl+o>"},
|
||||
SubmitEditorText: Keybinding{"<enter>"},
|
||||
ExtrasMenu: Keybinding{"@"},
|
||||
ToggleWhitespaceInDiffView: Keybinding{"<ctrl+w>"},
|
||||
IncreaseContextInDiffView: Keybinding{"}"},
|
||||
DecreaseContextInDiffView: Keybinding{"{"},
|
||||
IncreaseRenameSimilarityThreshold: Keybinding{")"},
|
||||
DecreaseRenameSimilarityThreshold: Keybinding{"("},
|
||||
OpenDiffTool: Keybinding{"<ctrl+t>"},
|
||||
},
|
||||
Status: KeybindingStatusConfig{
|
||||
CheckForUpdate: "u",
|
||||
RecentRepos: "<enter>",
|
||||
AllBranchesLogGraph: "a",
|
||||
AllBranchesLogGraphReverse: "A",
|
||||
CheckForUpdate: Keybinding{"u"},
|
||||
RecentRepos: Keybinding{"<enter>"},
|
||||
AllBranchesLogGraph: Keybinding{"a"},
|
||||
AllBranchesLogGraphReverse: Keybinding{"A"},
|
||||
},
|
||||
Files: KeybindingFilesConfig{
|
||||
CommitChanges: "c",
|
||||
CommitChangesWithoutHook: "w",
|
||||
AmendLastCommit: "A",
|
||||
CommitChangesWithEditor: "C",
|
||||
FindBaseCommitForFixup: "<ctrl+f>",
|
||||
IgnoreFile: "i",
|
||||
RefreshFiles: "r",
|
||||
StashAllChanges: "s",
|
||||
ViewStashOptions: "S",
|
||||
ToggleStagedAll: "a",
|
||||
ViewResetOptions: "D",
|
||||
Fetch: "f",
|
||||
ToggleTreeView: "`",
|
||||
OpenMergeOptions: "M",
|
||||
OpenStatusFilter: "<ctrl+b>",
|
||||
ConfirmDiscard: "x",
|
||||
CopyFileInfoToClipboard: "y",
|
||||
CollapseAll: "-",
|
||||
ExpandAll: "=",
|
||||
CommitChanges: Keybinding{"c"},
|
||||
CommitChangesWithoutHook: Keybinding{"w"},
|
||||
AmendLastCommit: Keybinding{"A"},
|
||||
CommitChangesWithEditor: Keybinding{"C"},
|
||||
FindBaseCommitForFixup: Keybinding{"<ctrl+f>"},
|
||||
IgnoreFile: Keybinding{"i"},
|
||||
RefreshFiles: Keybinding{"r"},
|
||||
StashAllChanges: Keybinding{"s"},
|
||||
ViewStashOptions: Keybinding{"S"},
|
||||
ToggleStagedAll: Keybinding{"a"},
|
||||
ViewResetOptions: Keybinding{"D"},
|
||||
Fetch: Keybinding{"f"},
|
||||
ToggleTreeView: Keybinding{"`"},
|
||||
OpenMergeOptions: Keybinding{"M"},
|
||||
OpenStatusFilter: Keybinding{"<ctrl+b>"},
|
||||
ConfirmDiscard: Keybinding{"x"},
|
||||
CopyFileInfoToClipboard: Keybinding{"y"},
|
||||
CollapseAll: Keybinding{"-"},
|
||||
ExpandAll: Keybinding{"="},
|
||||
},
|
||||
Branches: KeybindingBranchesConfig{
|
||||
CopyPullRequestURL: "<ctrl+y>",
|
||||
CreatePullRequest: "o",
|
||||
ViewPullRequestOptions: "O",
|
||||
OpenPullRequestInBrowser: "G",
|
||||
CheckoutBranchByName: "c",
|
||||
ForceCheckoutBranch: "F",
|
||||
CheckoutPreviousBranch: "-",
|
||||
RebaseBranch: "r",
|
||||
RenameBranch: "R",
|
||||
MergeIntoCurrentBranch: "M",
|
||||
MoveCommitsToNewBranch: "N",
|
||||
ViewGitFlowOptions: "i",
|
||||
FastForward: "f",
|
||||
CreateTag: "T",
|
||||
PushTag: "P",
|
||||
SetUpstream: "u",
|
||||
FetchRemote: "f",
|
||||
AddForkRemote: "F",
|
||||
SortOrder: "s",
|
||||
CopyPullRequestURL: Keybinding{"<ctrl+y>"},
|
||||
CreatePullRequest: Keybinding{"o"},
|
||||
ViewPullRequestOptions: Keybinding{"O"},
|
||||
OpenPullRequestInBrowser: Keybinding{"G"},
|
||||
CheckoutBranchByName: Keybinding{"c"},
|
||||
ForceCheckoutBranch: Keybinding{"F"},
|
||||
CheckoutPreviousBranch: Keybinding{"-"},
|
||||
RebaseBranch: Keybinding{"r"},
|
||||
RenameBranch: Keybinding{"R"},
|
||||
MergeIntoCurrentBranch: Keybinding{"M"},
|
||||
MoveCommitsToNewBranch: Keybinding{"N"},
|
||||
ViewGitFlowOptions: Keybinding{"i"},
|
||||
FastForward: Keybinding{"f"},
|
||||
CreateTag: Keybinding{"T"},
|
||||
PushTag: Keybinding{"P"},
|
||||
SetUpstream: Keybinding{"u"},
|
||||
FetchRemote: Keybinding{"f"},
|
||||
AddForkRemote: Keybinding{"F"},
|
||||
SortOrder: Keybinding{"s"},
|
||||
},
|
||||
Worktrees: KeybindingWorktreesConfig{
|
||||
ViewWorktreeOptions: "w",
|
||||
ViewWorktreeOptions: Keybinding{"w"},
|
||||
},
|
||||
Commits: KeybindingCommitsConfig{
|
||||
SquashDown: "s",
|
||||
RenameCommit: "r",
|
||||
RenameCommitWithEditor: "R",
|
||||
ViewResetOptions: "g",
|
||||
MarkCommitAsFixup: "f",
|
||||
SetFixupMessage: "c",
|
||||
CreateFixupCommit: "F",
|
||||
SquashAboveCommits: "S",
|
||||
MoveDownCommit: "<ctrl+j>",
|
||||
MoveUpCommit: "<ctrl+k>",
|
||||
AmendToCommit: "A",
|
||||
ResetCommitAuthor: "a",
|
||||
PickCommit: "p",
|
||||
RevertCommit: "t",
|
||||
CherryPickCopy: "C",
|
||||
PasteCommits: "V",
|
||||
MarkCommitAsBaseForRebase: "B",
|
||||
CreateTag: "T",
|
||||
CheckoutCommit: "<space>",
|
||||
ResetCherryPick: "<ctrl+r>",
|
||||
CopyCommitAttributeToClipboard: "y",
|
||||
OpenLogMenu: "<ctrl+l>",
|
||||
OpenInBrowser: "o",
|
||||
OpenPullRequestInBrowser: "G",
|
||||
ViewBisectOptions: "b",
|
||||
StartInteractiveRebase: "i",
|
||||
SelectCommitsOfCurrentBranch: "*",
|
||||
SquashDown: Keybinding{"s"},
|
||||
RenameCommit: Keybinding{"r"},
|
||||
RenameCommitWithEditor: Keybinding{"R"},
|
||||
ViewResetOptions: Keybinding{"g"},
|
||||
MarkCommitAsFixup: Keybinding{"f"},
|
||||
SetFixupMessage: Keybinding{"c"},
|
||||
CreateFixupCommit: Keybinding{"F"},
|
||||
SquashAboveCommits: Keybinding{"S"},
|
||||
MoveDownCommit: Keybinding{"<ctrl+j>"},
|
||||
MoveUpCommit: Keybinding{"<ctrl+k>"},
|
||||
AmendToCommit: Keybinding{"A"},
|
||||
ResetCommitAuthor: Keybinding{"a"},
|
||||
PickCommit: Keybinding{"p"},
|
||||
RevertCommit: Keybinding{"t"},
|
||||
CherryPickCopy: Keybinding{"C"},
|
||||
PasteCommits: Keybinding{"V"},
|
||||
MarkCommitAsBaseForRebase: Keybinding{"B"},
|
||||
CreateTag: Keybinding{"T"},
|
||||
CheckoutCommit: Keybinding{"<space>"},
|
||||
ResetCherryPick: Keybinding{"<ctrl+r>"},
|
||||
CopyCommitAttributeToClipboard: Keybinding{"y"},
|
||||
OpenLogMenu: Keybinding{"<ctrl+l>"},
|
||||
OpenInBrowser: Keybinding{"o"},
|
||||
OpenPullRequestInBrowser: Keybinding{"G"},
|
||||
ViewBisectOptions: Keybinding{"b"},
|
||||
StartInteractiveRebase: Keybinding{"i"},
|
||||
SelectCommitsOfCurrentBranch: Keybinding{"*"},
|
||||
},
|
||||
AmendAttribute: KeybindingAmendAttributeConfig{
|
||||
ResetAuthor: "a",
|
||||
SetAuthor: "A",
|
||||
AddCoAuthor: "c",
|
||||
ResetAuthor: Keybinding{"a"},
|
||||
SetAuthor: Keybinding{"A"},
|
||||
AddCoAuthor: Keybinding{"c"},
|
||||
},
|
||||
Stash: KeybindingStashConfig{
|
||||
PopStash: "g",
|
||||
RenameStash: "r",
|
||||
PopStash: Keybinding{"g"},
|
||||
RenameStash: Keybinding{"r"},
|
||||
},
|
||||
CommitFiles: KeybindingCommitFilesConfig{
|
||||
CheckoutCommitFile: "c",
|
||||
CheckoutCommitFile: Keybinding{"c"},
|
||||
},
|
||||
Main: KeybindingMainConfig{
|
||||
ToggleSelectHunk: "a",
|
||||
PickBothHunks: "b",
|
||||
EditSelectHunk: "E",
|
||||
ToggleSelectHunk: Keybinding{"a"},
|
||||
PickBothHunks: Keybinding{"b"},
|
||||
EditSelectHunk: Keybinding{"E"},
|
||||
},
|
||||
Submodules: KeybindingSubmodulesConfig{
|
||||
Init: "i",
|
||||
Update: "u",
|
||||
BulkMenu: "b",
|
||||
Init: Keybinding{"i"},
|
||||
Update: Keybinding{"u"},
|
||||
BulkMenu: Keybinding{"b"},
|
||||
},
|
||||
CommitMessage: KeybindingCommitMessageConfig{
|
||||
CommitMenu: "<ctrl+o>",
|
||||
CommitMenu: Keybinding{"<ctrl+o>"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ func TestUserConfigValidate_enums(t *testing.T) {
|
||||
{
|
||||
name: "Keybindings",
|
||||
setup: func(config *UserConfig, value string) {
|
||||
config.Keybinding.Universal.Quit = value
|
||||
config.Keybinding.Universal.Quit = Keybinding{value}
|
||||
},
|
||||
testCases: []testCase{
|
||||
{value: "", valid: true},
|
||||
|
||||
+10
-8
@@ -4,6 +4,8 @@
|
||||
|
||||
package gocui
|
||||
|
||||
import "github.com/samber/lo"
|
||||
|
||||
// Editor interface must be satisfied by gocui editors.
|
||||
type Editor interface {
|
||||
Edit(v *View, key Key) bool
|
||||
@@ -23,19 +25,19 @@ func (f EditorFunc) Edit(v *View, key Key) bool {
|
||||
var DefaultEditor Editor = EditorFunc(SimpleEditor)
|
||||
|
||||
var (
|
||||
moveWordLeftKeybinding = NewKey(KeyArrowLeft, "", ModCtrl)
|
||||
moveWordRightKeybinding = NewKey(KeyArrowRight, "", ModCtrl)
|
||||
backspaceWordKeybinding = NewKey(KeyBackspace, "", ModCtrl)
|
||||
forwardDeleteWordKeybinding = NewKey(KeyDelete, "", ModCtrl)
|
||||
moveWordLeftKeybinding = []Key{NewKey(KeyArrowLeft, "", ModCtrl)}
|
||||
moveWordRightKeybinding = []Key{NewKey(KeyArrowRight, "", ModCtrl)}
|
||||
backspaceWordKeybinding = []Key{NewKey(KeyBackspace, "", ModCtrl)}
|
||||
forwardDeleteWordKeybinding = []Key{NewKey(KeyDelete, "", ModCtrl)}
|
||||
)
|
||||
|
||||
// SimpleEditor is used as the default gocui editor.
|
||||
func SimpleEditor(v *View, key Key) bool {
|
||||
switch {
|
||||
case key.Equals(backspaceWordKeybinding),
|
||||
case lo.SomeBy(backspaceWordKeybinding, func(k Key) bool { return key.Equals(k) }),
|
||||
key.Equals(NewKeyStrMod("w", ModCtrl)):
|
||||
v.TextArea.BackSpaceWord()
|
||||
case key.Equals(forwardDeleteWordKeybinding),
|
||||
case lo.SomeBy(forwardDeleteWordKeybinding, func(k Key) bool { return key.Equals(k) }),
|
||||
key.Equals(NewKeyStrMod("d", ModAlt)):
|
||||
v.TextArea.ForwardDeleteWord()
|
||||
case key.Equals(NewKeyName(KeyBackspace)),
|
||||
@@ -49,13 +51,13 @@ func SimpleEditor(v *View, key Key) bool {
|
||||
case key.Equals(NewKeyName(KeyArrowUp)):
|
||||
v.TextArea.MoveCursorUp()
|
||||
case key.Equals(NewKeyStrMod("b", ModAlt)),
|
||||
key.Equals(moveWordLeftKeybinding):
|
||||
lo.SomeBy(moveWordLeftKeybinding, func(k Key) bool { return key.Equals(k) }):
|
||||
v.TextArea.MoveLeftWord()
|
||||
case key.Equals(NewKeyName(KeyArrowLeft)),
|
||||
key.Equals(NewKeyStrMod("b", ModCtrl)):
|
||||
v.TextArea.MoveCursorLeft()
|
||||
case key.Equals(NewKeyStrMod("f", ModAlt)),
|
||||
key.Equals(moveWordRightKeybinding):
|
||||
lo.SomeBy(moveWordRightKeybinding, func(k Key) bool { return key.Equals(k) }):
|
||||
v.TextArea.MoveRightWord()
|
||||
case key.Equals(NewKeyName(KeyArrowRight)),
|
||||
key.Equals(NewKeyStrMod("f", ModCtrl)):
|
||||
|
||||
+10
-10
@@ -178,9 +178,9 @@ type Gui struct {
|
||||
|
||||
OnSearchEscape func() error
|
||||
|
||||
SearchEscapeKey Key
|
||||
NextSearchMatchKey Key
|
||||
PrevSearchMatchKey Key
|
||||
SearchEscapeKeys []Key
|
||||
NextSearchMatchKeys []Key
|
||||
PrevSearchMatchKeys []Key
|
||||
|
||||
ErrorHandler func(error) error
|
||||
|
||||
@@ -256,9 +256,9 @@ func NewGui(opts NewGuiOpts) (*Gui, error) {
|
||||
g.SupportOverlaps = opts.SupportOverlaps
|
||||
|
||||
// default keys for when searching strings in a view
|
||||
g.SearchEscapeKey = NewKeyName(KeyEsc)
|
||||
g.NextSearchMatchKey = NewKeyRune('n')
|
||||
g.PrevSearchMatchKey = NewKeyRune('N')
|
||||
g.SearchEscapeKeys = []Key{NewKeyName(KeyEsc)}
|
||||
g.NextSearchMatchKeys = []Key{NewKeyRune('n')}
|
||||
g.PrevSearchMatchKeys = []Key{NewKeyRune('N')}
|
||||
|
||||
g.playRecording = opts.PlayRecording
|
||||
|
||||
@@ -1525,11 +1525,11 @@ func (g *Gui) execKeybindings(v *View, ev *GocuiEvent) error {
|
||||
|
||||
// if we're searching, and we've hit n/N/Esc, we ignore the default keybinding
|
||||
if v != nil && v.IsSearching() {
|
||||
if ev.Key.Equals(g.NextSearchMatchKey) {
|
||||
if lo.SomeBy(g.NextSearchMatchKeys, func(k Key) bool { return ev.Key.Equals(k) }) {
|
||||
return v.gotoNextMatch()
|
||||
} else if ev.Key.Equals(g.PrevSearchMatchKey) {
|
||||
} else if lo.SomeBy(g.PrevSearchMatchKeys, func(k Key) bool { return ev.Key.Equals(k) }) {
|
||||
return v.gotoPreviousMatch()
|
||||
} else if ev.Key.Equals(g.SearchEscapeKey) {
|
||||
} else if lo.SomeBy(g.SearchEscapeKeys, func(k Key) bool { return ev.Key.Equals(k) }) {
|
||||
v.searcher.clearSearch()
|
||||
if g.OnSearchEscape != nil {
|
||||
if err := g.OnSearchEscape(); err != nil {
|
||||
@@ -1669,7 +1669,7 @@ func (g *Gui) Snapshot() string {
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func (g *Gui) SetEditKeybindings(moveWordLeft, moveWordRight, backspaceWord, forwardDeleteWord Key) {
|
||||
func (g *Gui) SetEditKeybindings(moveWordLeft, moveWordRight, backspaceWord, forwardDeleteWord []Key) {
|
||||
moveWordLeftKeybinding = moveWordLeft
|
||||
moveWordRightKeybinding = moveWordRight
|
||||
backspaceWordKeybinding = backspaceWord
|
||||
|
||||
@@ -166,8 +166,8 @@ func (self *CommitMessageContext) SetPanelState(
|
||||
|
||||
self.c.Views().CommitDescription.Subtitle = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionSubTitle,
|
||||
map[string]string{
|
||||
"togglePanelKeyBinding": self.c.UserConfig().Keybinding.Universal.TogglePanel,
|
||||
"commitMenuKeybinding": self.c.UserConfig().Keybinding.CommitMessage.CommitMenu,
|
||||
"togglePanelKeyBinding": self.c.UserConfig().Keybinding.Universal.TogglePanel.String(),
|
||||
"commitMenuKeybinding": self.c.UserConfig().Keybinding.CommitMessage.CommitMenu.String(),
|
||||
})
|
||||
|
||||
self.c.Views().CommitDescription.Visible = true
|
||||
|
||||
@@ -105,8 +105,8 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
Description: self.c.Tr.CherryPickCopy,
|
||||
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.CherryPickCopyTooltip,
|
||||
map[string]string{
|
||||
"paste": opts.Config.Commits.PasteCommits,
|
||||
"escape": opts.Config.Universal.Return,
|
||||
"paste": opts.Config.Commits.PasteCommits.String(),
|
||||
"escape": opts.Config.Universal.Return.String(),
|
||||
},
|
||||
),
|
||||
DisplayOnScreen: true,
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
type CommitDescriptionController struct {
|
||||
@@ -67,22 +68,24 @@ func (self *CommitDescriptionController) GetMouseKeybindings(opts types.Keybindi
|
||||
func (self *CommitDescriptionController) GetOnFocus() func(types.OnFocusOpts) {
|
||||
return func(types.OnFocusOpts) {
|
||||
footer := ""
|
||||
if self.c.UserConfig().Keybinding.Universal.ConfirmInEditor != "<disabled>" || self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt != "<disabled>" {
|
||||
if self.c.UserConfig().Keybinding.Universal.ConfirmInEditor == "<disabled>" {
|
||||
mainDisabled := len(self.c.UserConfig().Keybinding.Universal.ConfirmInEditor) > 0
|
||||
altDisabled := len(self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt) > 0
|
||||
if !mainDisabled || !altDisabled {
|
||||
if mainDisabled {
|
||||
footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooter,
|
||||
map[string]string{
|
||||
"confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt,
|
||||
"confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt.String(),
|
||||
})
|
||||
} else if self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt == "<disabled>" {
|
||||
} else if altDisabled {
|
||||
footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooter,
|
||||
map[string]string{
|
||||
"confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor,
|
||||
"confirmInEditorKeybinding": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor.String(),
|
||||
})
|
||||
} else {
|
||||
footer = utils.ResolvePlaceholderString(self.c.Tr.CommitDescriptionFooterTwoBindings,
|
||||
map[string]string{
|
||||
"confirmInEditorKeybinding1": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor,
|
||||
"confirmInEditorKeybinding2": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt,
|
||||
"confirmInEditorKeybinding1": self.c.UserConfig().Keybinding.Universal.ConfirmInEditor.String(),
|
||||
"confirmInEditorKeybinding2": self.c.UserConfig().Keybinding.Universal.ConfirmInEditorAlt.String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -112,7 +115,7 @@ func (self *CommitDescriptionController) handleTogglePanel() error {
|
||||
// ctrl key or fn key, which is unlikely to occur in pasted text. And if
|
||||
// they mapped some *other* command to "<tab>", then we're totally out of
|
||||
// luck.
|
||||
if self.c.GocuiGui().IsPasting && self.c.UserConfig().Keybinding.Universal.TogglePanel == "<tab>" {
|
||||
if self.c.GocuiGui().IsPasting && lo.Contains(self.c.UserConfig().Keybinding.Universal.TogglePanel, "<tab>") {
|
||||
// Handling tabs in pasted commit messages is not optimal, but hopefully
|
||||
// good enough for now. We simply insert 4 spaces without worrying about
|
||||
// column alignment. This works well enough for leading indentation,
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/controllers/helpers"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
type CommitMessageController struct {
|
||||
@@ -123,7 +124,7 @@ func (self *CommitMessageController) handleTogglePanel() error {
|
||||
// ctrl key or fn key, which is unlikely to occur in pasted text. And if
|
||||
// they mapped some *other* command to "<tab>", then we're totally out of
|
||||
// luck.
|
||||
if self.c.GocuiGui().IsPasting && self.c.UserConfig().Keybinding.Universal.TogglePanel == "<tab>" {
|
||||
if self.c.GocuiGui().IsPasting && lo.Contains(self.c.UserConfig().Keybinding.Universal.TogglePanel, "<tab>") {
|
||||
// It is unlikely that a pasted commit message contains a tab in the
|
||||
// subject line, so it shouldn't matter too much how we handle it.
|
||||
// Simply insert 4 spaces instead; all that matters is that we don't
|
||||
@@ -183,7 +184,7 @@ func (self *CommitMessageController) confirm() error {
|
||||
// to some ctrl key or fn key, which is unlikely to occur in pasted text.
|
||||
// And if they mapped some *other* command to "<enter>", then we're totally
|
||||
// out of luck.
|
||||
if self.c.GocuiGui().IsPasting && self.c.UserConfig().Keybinding.Universal.SubmitEditorText == "<enter>" {
|
||||
if self.c.GocuiGui().IsPasting && lo.Contains(self.c.UserConfig().Keybinding.Universal.SubmitEditorText, "<enter>") {
|
||||
return self.switchToCommitDescription()
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ func (self *TagsHelper) OpenCreateTagPrompt(ref string, onCreate func()) error {
|
||||
self.c.Tr.ForceTagPrompt,
|
||||
map[string]string{
|
||||
"tagName": tagName,
|
||||
"cancelKey": self.c.UserConfig().Keybinding.Universal.Return,
|
||||
"confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm,
|
||||
"cancelKey": self.c.UserConfig().Keybinding.Universal.Return.String(),
|
||||
"confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm.String(),
|
||||
},
|
||||
)
|
||||
force := self.c.Git().Tag.HasTag(tagName)
|
||||
|
||||
@@ -3,6 +3,7 @@ package controllers
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
@@ -39,7 +40,7 @@ func (self *JumpToSideWindowController) GetKeybindings(opts types.KeybindingsOpt
|
||||
return &types.Binding{
|
||||
ViewName: "",
|
||||
// by default the keys are 1, 2, 3, etc
|
||||
Keys: opts.GetKeys(opts.Config.Universal.JumpToBlock[index]),
|
||||
Keys: opts.GetKeys(config.Keybinding{opts.Config.Universal.JumpToBlock[index]}),
|
||||
Handler: opts.Guards.NoPopupPanel(self.goToSideWindow(window)),
|
||||
}
|
||||
})
|
||||
|
||||
@@ -141,7 +141,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
GetDisabledReason: self.require(self.notMidRebase(self.c.Tr.AlreadyRebasing), self.canFindCommitForQuickStart),
|
||||
Description: self.c.Tr.QuickStartInteractiveRebase,
|
||||
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.QuickStartInteractiveRebaseTooltip, map[string]string{
|
||||
"editKey": editCommitKey,
|
||||
"editKey": editCommitKey.String(),
|
||||
}),
|
||||
},
|
||||
{
|
||||
@@ -161,7 +161,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
||||
Tooltip: utils.ResolvePlaceholderString(
|
||||
self.c.Tr.CreateFixupCommitTooltip,
|
||||
map[string]string{
|
||||
"squashAbove": opts.Config.Commits.SquashAboveCommits,
|
||||
"squashAbove": opts.Config.Commits.SquashAboveCommits.String(),
|
||||
},
|
||||
),
|
||||
},
|
||||
@@ -679,7 +679,7 @@ func (self *LocalCommitsController) findCommitForQuickStartInteractiveRebase() (
|
||||
|
||||
if !ok || index == 0 {
|
||||
errorMsg := utils.ResolvePlaceholderString(self.c.Tr.CannotQuickStartInteractiveRebase, map[string]string{
|
||||
"editKey": self.c.UserConfig().Keybinding.Universal.Edit,
|
||||
"editKey": self.c.UserConfig().Keybinding.Universal.Edit.String(),
|
||||
})
|
||||
|
||||
return nil, errors.New(errorMsg)
|
||||
|
||||
@@ -44,7 +44,7 @@ func (self *SubmodulesController) GetKeybindings(opts types.KeybindingsOpts) []*
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Description: self.c.Tr.Enter,
|
||||
Tooltip: utils.ResolvePlaceholderString(self.c.Tr.EnterSubmoduleTooltip,
|
||||
map[string]string{"escape": opts.Config.Universal.Return}),
|
||||
map[string]string{"escape": opts.Config.Universal.Return.String()}),
|
||||
DisplayOnScreen: true,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -256,8 +256,8 @@ func (self *SyncController) forcePushPrompt() string {
|
||||
return utils.ResolvePlaceholderString(
|
||||
self.c.Tr.ForcePushPrompt,
|
||||
map[string]string{
|
||||
"cancelKey": self.c.UserConfig().Keybinding.Universal.Return,
|
||||
"confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm,
|
||||
"cancelKey": self.c.UserConfig().Keybinding.Universal.Return.String(),
|
||||
"confirmKey": self.c.UserConfig().Keybinding.Universal.Confirm.String(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
+8
-8
@@ -472,15 +472,15 @@ func (gui *Gui) onUserConfigLoaded() error {
|
||||
gui.setColorScheme()
|
||||
gui.configureViewProperties()
|
||||
|
||||
gui.g.SearchEscapeKey = config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.Return)
|
||||
gui.g.NextSearchMatchKey = config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.NextMatch)
|
||||
gui.g.PrevSearchMatchKey = config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.PrevMatch)
|
||||
gui.g.SearchEscapeKeys = config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.Return)
|
||||
gui.g.NextSearchMatchKeys = config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.NextMatch)
|
||||
gui.g.PrevSearchMatchKeys = config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.PrevMatch)
|
||||
|
||||
gui.g.SetEditKeybindings(
|
||||
config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.MoveWordLeft),
|
||||
config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.MoveWordRight),
|
||||
config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.BackspaceWord),
|
||||
config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.ForwardDeleteWord),
|
||||
config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.MoveWordLeft),
|
||||
config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.MoveWordRight),
|
||||
config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.BackspaceWord),
|
||||
config.GetValidatedKeyBindingKeys(userConfig.Keybinding.Universal.ForwardDeleteWord),
|
||||
)
|
||||
|
||||
gui.g.ShowListFooter = userConfig.Gui.ShowListFooter
|
||||
@@ -1089,7 +1089,7 @@ func (gui *Gui) showIntroPopupMessage() {
|
||||
introMessage := utils.ResolvePlaceholderString(
|
||||
gui.c.Tr.IntroPopupMessage,
|
||||
map[string]string{
|
||||
"confirmationKey": gui.c.UserConfig().Keybinding.Universal.Confirm,
|
||||
"confirmationKey": gui.c.UserConfig().Keybinding.Universal.Confirm.String(),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -28,10 +28,10 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
|
||||
maxColumnSize := 1
|
||||
|
||||
essentialKeys := []gocui.Key{
|
||||
config.GetValidatedKeyBindingKey(gui.c.UserConfig().Keybinding.Universal.ConfirmMenu),
|
||||
config.GetValidatedKeyBindingKey(gui.c.UserConfig().Keybinding.Universal.Return),
|
||||
config.GetValidatedKeyBindingKey(gui.c.UserConfig().Keybinding.Universal.PrevItem),
|
||||
config.GetValidatedKeyBindingKey(gui.c.UserConfig().Keybinding.Universal.NextItem),
|
||||
config.GetValidatedKeyBindingKeys(gui.c.UserConfig().Keybinding.Universal.ConfirmMenu)[0],
|
||||
config.GetValidatedKeyBindingKeys(gui.c.UserConfig().Keybinding.Universal.Return)[0],
|
||||
config.GetValidatedKeyBindingKeys(gui.c.UserConfig().Keybinding.Universal.PrevItem)[0],
|
||||
config.GetValidatedKeyBindingKeys(gui.c.UserConfig().Keybinding.Universal.NextItem)[0],
|
||||
}
|
||||
|
||||
for _, item := range opts.Items {
|
||||
|
||||
@@ -70,7 +70,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
||||
if currentContext.GetKey() == context.LOCAL_COMMITS_CONTEXT_KEY {
|
||||
if self.c.Modes().CherryPicking.Active() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: self.c.KeybindingsOpts().Config.Commits.PasteCommits,
|
||||
key: self.c.KeybindingsOpts().Config.Commits.PasteCommits.String(),
|
||||
description: self.c.Tr.PasteCommits,
|
||||
style: style.FgCyan,
|
||||
})
|
||||
@@ -78,7 +78,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
||||
|
||||
if self.c.Model().BisectInfo.Started() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: self.c.KeybindingsOpts().Config.Commits.ViewBisectOptions,
|
||||
key: self.c.KeybindingsOpts().Config.Commits.ViewBisectOptions.String(),
|
||||
description: self.c.Tr.ViewBisectOptions,
|
||||
style: style.FgGreen,
|
||||
})
|
||||
@@ -88,7 +88,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
||||
// Mode-specific global keybindings
|
||||
if state := self.c.Model().WorkingTreeStateAtLastCommitRefresh; state.Any() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: self.c.KeybindingsOpts().Config.Universal.CreateRebaseOptionsMenu,
|
||||
key: self.c.KeybindingsOpts().Config.Universal.CreateRebaseOptionsMenu.String(),
|
||||
description: state.OptionsMapTitle(self.c.Tr),
|
||||
style: style.FgYellow,
|
||||
})
|
||||
@@ -96,7 +96,7 @@ func (self *OptionsMapMgr) renderContextOptionsMap() {
|
||||
|
||||
if self.c.Git().Patch.PatchBuilder.Active() {
|
||||
optionsMap = utils.Prepend(optionsMap, bindingInfo{
|
||||
key: self.c.KeybindingsOpts().Config.Universal.CreatePatchOptionsMenu,
|
||||
key: self.c.KeybindingsOpts().Config.Universal.CreatePatchOptionsMenu.String(),
|
||||
description: self.c.Tr.ViewPatchOptions,
|
||||
style: style.FgYellow,
|
||||
})
|
||||
|
||||
@@ -239,7 +239,7 @@ type OnFocusLostOpts struct {
|
||||
type ContextKey string
|
||||
|
||||
type KeybindingsOpts struct {
|
||||
GetKeys func(key string) []gocui.Key
|
||||
GetKeys func(keys config.Keybinding) []gocui.Key
|
||||
Config config.KeybindingConfig
|
||||
Guards KeybindingGuards
|
||||
}
|
||||
|
||||
+1
-1
@@ -236,7 +236,7 @@ func (gui *Gui) configureViewProperties() {
|
||||
|
||||
gui.Views.Stash.TitlePrefix = jumpLabels[4]
|
||||
|
||||
gui.Views.Main.TitlePrefix = keyToTitlePrefix(gui.c.UserConfig().Keybinding.Universal.FocusMainView)
|
||||
gui.Views.Main.TitlePrefix = keyToTitlePrefix(gui.c.UserConfig().Keybinding.Universal.FocusMainView[0])
|
||||
} else {
|
||||
gui.Views.Status.TitlePrefix = ""
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ func (self *CommitDescriptionPanelDriver) GoToBeginning() *CommitDescriptionPane
|
||||
}
|
||||
|
||||
func (self *CommitDescriptionPanelDriver) AddCoAuthor(author string) *CommitDescriptionPanelDriver {
|
||||
self.t.press(self.t.keys.CommitMessage.CommitMenu)
|
||||
self.t.press(self.t.keys.CommitMessage.CommitMenu[0])
|
||||
self.t.ExpectPopup().Menu().Title(Equals("Commit Menu")).
|
||||
Select(Contains("Add co-author")).
|
||||
Confirm()
|
||||
|
||||
@@ -73,6 +73,6 @@ func (self *CommitMessagePanelDriver) SelectNextMessage() *CommitMessagePanelDri
|
||||
}
|
||||
|
||||
func (self *CommitMessagePanelDriver) OpenCommitMenu() *CommitMessagePanelDriver {
|
||||
self.t.press(self.t.keys.CommitMessage.CommitMenu)
|
||||
self.t.press(self.t.keys.CommitMessage.CommitMenu[0])
|
||||
return self
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func (self *PromptDriver) SuggestionTopLines(matchers ...*TextMatcher) *PromptDr
|
||||
}
|
||||
|
||||
func (self *PromptDriver) ConfirmFirstSuggestion() {
|
||||
self.t.press(self.t.keys.Universal.TogglePanel)
|
||||
self.t.press(self.t.keys.Universal.TogglePanel[0])
|
||||
self.t.Views().Suggestions().
|
||||
IsFocused().
|
||||
SelectedLineIdx(0).
|
||||
@@ -76,7 +76,7 @@ func (self *PromptDriver) ConfirmFirstSuggestion() {
|
||||
}
|
||||
|
||||
func (self *PromptDriver) ConfirmSuggestion(matcher *TextMatcher) {
|
||||
self.t.press(self.t.keys.Universal.TogglePanel)
|
||||
self.t.press(self.t.keys.Universal.TogglePanel[0])
|
||||
self.t.Views().Suggestions().
|
||||
IsFocused().
|
||||
NavigateToLine(matcher).
|
||||
@@ -84,19 +84,19 @@ func (self *PromptDriver) ConfirmSuggestion(matcher *TextMatcher) {
|
||||
}
|
||||
|
||||
func (self *PromptDriver) DeleteSuggestion(matcher *TextMatcher) *PromptDriver {
|
||||
self.t.press(self.t.keys.Universal.TogglePanel)
|
||||
self.t.press(self.t.keys.Universal.TogglePanel[0])
|
||||
self.t.Views().Suggestions().
|
||||
IsFocused().
|
||||
NavigateToLine(matcher)
|
||||
self.t.press(self.t.keys.Universal.Remove)
|
||||
self.t.press(self.t.keys.Universal.Remove[0])
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *PromptDriver) EditSuggestion(matcher *TextMatcher) *PromptDriver {
|
||||
self.t.press(self.t.keys.Universal.TogglePanel)
|
||||
self.t.press(self.t.keys.Universal.TogglePanel[0])
|
||||
self.t.Views().Suggestions().
|
||||
IsFocused().
|
||||
NavigateToLine(matcher)
|
||||
self.t.press(self.t.keys.Universal.Edit)
|
||||
self.t.press(self.t.keys.Universal.Edit[0])
|
||||
return self
|
||||
}
|
||||
|
||||
@@ -52,8 +52,8 @@ func (self *TestDriver) click(x, y int) {
|
||||
// Should only be used in specific cases where you're doing something weird!
|
||||
// E.g. invoking a global keybinding from within a popup.
|
||||
// You probably shouldn't use this function, and should instead go through a view like t.Views().Commit().Focus().Press(...)
|
||||
func (self *TestDriver) GlobalPress(keyStr string) {
|
||||
self.press(keyStr)
|
||||
func (self *TestDriver) GlobalPress(key config.Keybinding) {
|
||||
self.press(key[0])
|
||||
}
|
||||
|
||||
func (self *TestDriver) typeContent(content string) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
@@ -376,11 +377,11 @@ func (self *ViewDriver) Focus() *ViewDriver {
|
||||
currentViewTabIndex := lo.IndexOf(window.viewNames, currentViewName)
|
||||
if tabIndex > currentViewTabIndex {
|
||||
for range tabIndex - currentViewTabIndex {
|
||||
self.t.press(self.t.keys.Universal.NextTab)
|
||||
self.t.press(self.t.keys.Universal.NextTab[0])
|
||||
}
|
||||
} else if tabIndex < currentViewTabIndex {
|
||||
for range currentViewTabIndex - tabIndex {
|
||||
self.t.press(self.t.keys.Universal.PrevTab)
|
||||
self.t.press(self.t.keys.Universal.PrevTab[0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,10 +408,10 @@ func (self *ViewDriver) IsFocused() *ViewDriver {
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *ViewDriver) Press(keyStr string) *ViewDriver {
|
||||
func (self *ViewDriver) Press(key config.Keybinding) *ViewDriver {
|
||||
self.IsFocused()
|
||||
|
||||
self.t.press(keyStr)
|
||||
self.t.press(key[0])
|
||||
|
||||
return self
|
||||
}
|
||||
@@ -423,10 +424,10 @@ func (self *ViewDriver) Delay() *ViewDriver {
|
||||
|
||||
// for use when typing or navigating, because in demos we want that to happen
|
||||
// faster
|
||||
func (self *ViewDriver) PressFast(keyStr string) *ViewDriver {
|
||||
func (self *ViewDriver) PressFast(key config.Keybinding) *ViewDriver {
|
||||
self.IsFocused()
|
||||
|
||||
self.t.pressFast(keyStr)
|
||||
self.t.pressFast(key[0])
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("two").IsSelected(),
|
||||
Contains("one"),
|
||||
).
|
||||
Press("n").
|
||||
Press(config.Keybinding{"n"}).
|
||||
Tap(func() {
|
||||
t.Views().Search().IsVisible().Content(Contains("matches for 'o' (3 of 3)"))
|
||||
}).
|
||||
@@ -68,7 +68,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("two"),
|
||||
Contains("one").IsSelected(),
|
||||
).
|
||||
Press("n").
|
||||
Press(config.Keybinding{"n"}).
|
||||
Tap(func() {
|
||||
t.Views().Search().IsVisible().Content(Contains("matches for 'o' (1 of 3)"))
|
||||
}).
|
||||
@@ -78,7 +78,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("two"),
|
||||
Contains("one"),
|
||||
).
|
||||
Press("n").
|
||||
Press(config.Keybinding{"n"}).
|
||||
Tap(func() {
|
||||
t.Views().Search().IsVisible().Content(Contains("matches for 'o' (2 of 3)"))
|
||||
}).
|
||||
@@ -88,7 +88,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("two").IsSelected(),
|
||||
Contains("one"),
|
||||
).
|
||||
Press("N").
|
||||
Press(config.Keybinding{"N"}).
|
||||
Tap(func() {
|
||||
t.Views().Search().IsVisible().Content(Contains("matches for 'o' (1 of 3)"))
|
||||
}).
|
||||
@@ -98,7 +98,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("two"),
|
||||
Contains("one"),
|
||||
).
|
||||
Press("N").
|
||||
Press(config.Keybinding{"N"}).
|
||||
Tap(func() {
|
||||
t.Views().Search().IsVisible().Content(Contains("matches for 'o' (3 of 3)"))
|
||||
}).
|
||||
@@ -112,7 +112,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Tap(func() {
|
||||
t.Views().Search().IsVisible().Content(Contains("matches for 'o' (1 of 3)"))
|
||||
}).
|
||||
Press("N").
|
||||
Press(config.Keybinding{"N"}).
|
||||
Tap(func() {
|
||||
t.Views().Search().IsVisible().Content(Contains("matches for 'o' (1 of 3)"))
|
||||
}).
|
||||
@@ -146,7 +146,7 @@ var Search = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("two"),
|
||||
Contains("one"),
|
||||
).
|
||||
Press("n").
|
||||
Press(config.Keybinding{"n"}).
|
||||
Tap(func() {
|
||||
t.Views().Search().IsVisible().Content(Contains("matches for 't' (1 of 2)"))
|
||||
}).
|
||||
|
||||
@@ -48,13 +48,13 @@ customCommands:
|
||||
).Confirm()
|
||||
t.Views().Status().Content(Contains("other → master"))
|
||||
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("../other/file.txt", Equals("global X"))
|
||||
|
||||
t.GlobalPress("Y")
|
||||
t.GlobalPress(config.Keybinding{"Y"})
|
||||
t.FileSystem().FileContent("../other/file.txt", Equals("local Y"))
|
||||
|
||||
t.GlobalPress("Z")
|
||||
t.GlobalPress(config.Keybinding{"Z"})
|
||||
t.FileSystem().FileContent("../other/file.txt", Equals("local Z"))
|
||||
},
|
||||
})
|
||||
|
||||
@@ -29,7 +29,7 @@ var AccessCommitProperties = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Lines(
|
||||
Contains("my change").IsSelected(),
|
||||
).
|
||||
Press("X")
|
||||
Press(config.Keybinding{"X"})
|
||||
|
||||
hash := t.Git().GetCommitHash("HEAD")
|
||||
t.FileSystem().FileContent("file.txt", Equals(fmt.Sprintf("my change\n%s\n%s", hash, hash)))
|
||||
|
||||
@@ -25,7 +25,7 @@ var BasicCommand = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsEmpty().
|
||||
IsFocused().
|
||||
Press("a").
|
||||
Press(config.Keybinding{"a"}).
|
||||
Lines(
|
||||
Contains("myfile"),
|
||||
)
|
||||
|
||||
@@ -35,7 +35,7 @@ var CheckForConflicts = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("second-change-branch"),
|
||||
).
|
||||
NavigateToLine(Contains("second-change-branch")).
|
||||
Press("m")
|
||||
Press(config.Keybinding{"m"})
|
||||
|
||||
t.Common().AcknowledgeConflicts()
|
||||
},
|
||||
|
||||
@@ -55,7 +55,7 @@ var ConditionalPromptFalseString = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Menu().Title(Equals("Pick one")).Select(Contains("foo")).Confirm()
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ var ConditionalPromptFalseValue = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Prompt().Title(Equals("Enter a word")).Type("false").Confirm()
|
||||
|
||||
|
||||
@@ -52,12 +52,12 @@ var ConditionalPrompts = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// Test 1: Select "first" via key — conditional prompt should be skipped
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Choose an option"))
|
||||
|
||||
t.Views().Menu().Press("1")
|
||||
t.Views().Menu().Press(config.Keybinding{"1"})
|
||||
|
||||
// Detail prompt should be skipped, file should be created directly
|
||||
t.Views().Files().
|
||||
@@ -75,12 +75,12 @@ var ConditionalPrompts = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsEmpty().
|
||||
IsFocused().
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Choose an option"))
|
||||
|
||||
t.Views().Menu().Press("H")
|
||||
t.Views().Menu().Press(config.Keybinding{"H"})
|
||||
|
||||
// Detail prompt should appear because Choice == "SECOND"
|
||||
t.ExpectPopup().Prompt().Title(Equals("Enter detail for second option")).Type("extra").Confirm()
|
||||
|
||||
@@ -39,7 +39,7 @@ var CustomCommandsSubmenu = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
IsEmpty().
|
||||
Press("x").
|
||||
Press(config.Keybinding{"x"}).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("My Custom Commands")).
|
||||
@@ -55,7 +55,7 @@ var CustomCommandsSubmenu = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Press("x").
|
||||
Press(config.Keybinding{"x"}).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("My Custom Commands")).
|
||||
@@ -63,7 +63,7 @@ var CustomCommandsSubmenu = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("1 touch myfile-global"),
|
||||
Contains("3 touch myfile-commits"),
|
||||
)
|
||||
t.GlobalPress("3")
|
||||
t.GlobalPress(config.Keybinding{"3"})
|
||||
})
|
||||
|
||||
t.Views().Files().
|
||||
|
||||
+5
-5
@@ -43,13 +43,13 @@ var CustomCommandsSubmenuWithSpecialKeybindings = NewIntegrationTest(NewIntegrat
|
||||
},
|
||||
},
|
||||
}
|
||||
cfg.GetUserConfig().Keybinding.Universal.ConfirmMenu = "y"
|
||||
cfg.GetUserConfig().Keybinding.Universal.ConfirmMenu = config.Keybinding{"y"}
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
IsEmpty().
|
||||
Press("x").
|
||||
Press(config.Keybinding{"x"}).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("My Custom Commands")).
|
||||
@@ -59,14 +59,14 @@ var CustomCommandsSubmenuWithSpecialKeybindings = NewIntegrationTest(NewIntegrat
|
||||
Contains(" echo y"),
|
||||
Contains(" echo down"),
|
||||
)
|
||||
t.GlobalPress("j")
|
||||
t.GlobalPress(config.Keybinding{"j"})
|
||||
t.ExpectPopup().Alert().Title(Equals("echo j")).Content(Equals("j")).Confirm()
|
||||
}).
|
||||
Press("x").
|
||||
Press(config.Keybinding{"x"}).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("My Custom Commands"))
|
||||
t.GlobalPress("H")
|
||||
t.GlobalPress(config.Keybinding{"H"})
|
||||
t.ExpectPopup().Alert().Title(Equals("echo H")).Content(Equals("H")).Confirm()
|
||||
})
|
||||
},
|
||||
|
||||
@@ -59,7 +59,7 @@ var FormPrompts = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsEmpty().
|
||||
IsFocused().
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Prompt().Title(Equals("Enter a file name")).Type("my file").Confirm()
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ var GlobalContext = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// commits
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Press("X")
|
||||
Press(config.Keybinding{"X"})
|
||||
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
@@ -37,7 +37,7 @@ var GlobalContext = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// branches
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Press("X")
|
||||
Press(config.Keybinding{"X"})
|
||||
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
@@ -49,7 +49,7 @@ var GlobalContext = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// files
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
Press("X")
|
||||
Press(config.Keybinding{"X"})
|
||||
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
|
||||
@@ -48,7 +48,7 @@ var MenuFromCommand = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Menu().Title(Equals("Choose commit message")).Select(Contains("bar")).Confirm()
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ var MenuFromCommandsOutput = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("Which git command do you want to run?")).
|
||||
|
||||
@@ -51,14 +51,14 @@ var MenuPromptWithKeys = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Menu().
|
||||
Title(Equals("Choose an option"))
|
||||
|
||||
// 'H' is normally a navigation key (ScrollLeft), so this tests that menu item
|
||||
// keybindings have proper precedence over non-essential navigation keys
|
||||
t.Views().Menu().Press("H")
|
||||
t.Views().Menu().Press(config.Keybinding{"H"})
|
||||
|
||||
t.FileSystem().FileContent("result.txt", Equals("SECOND\n"))
|
||||
},
|
||||
|
||||
@@ -25,7 +25,7 @@ var MultipleContexts = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// commits
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Press("X")
|
||||
Press(config.Keybinding{"X"})
|
||||
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
@@ -37,7 +37,7 @@ var MultipleContexts = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// branches
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Press("X")
|
||||
Press(config.Keybinding{"X"})
|
||||
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
@@ -46,7 +46,7 @@ var MultipleContexts = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
// files
|
||||
t.Views().ReflogCommits().
|
||||
Focus().
|
||||
Press("X")
|
||||
Press(config.Keybinding{"X"})
|
||||
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
|
||||
@@ -57,7 +57,7 @@ var MultiplePrompts = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
IsEmpty().
|
||||
IsFocused().
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Prompt().Title(Equals("Enter a file name")).Type("myfile").Confirm()
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ var RunCommand = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("Enter a branch name")).
|
||||
|
||||
@@ -34,34 +34,34 @@ var SelectedCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
NavigateToLine(Contains("commit 03"))
|
||||
|
||||
// SubCommits
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("commit 03"))
|
||||
|
||||
t.Views().SubCommits().PressEnter()
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("commit 03"))
|
||||
|
||||
// ReflogCommits
|
||||
t.Views().ReflogCommits().Focus()
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("commit: commit 02"))
|
||||
|
||||
t.Views().ReflogCommits().PressEnter()
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("commit: commit 02"))
|
||||
|
||||
// LocalCommits
|
||||
t.Views().Commits().Focus()
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("commit 01"))
|
||||
|
||||
t.Views().Commits().PressEnter()
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("commit 01"))
|
||||
|
||||
// None of these
|
||||
t.Views().Files().Focus()
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("commit 01"))
|
||||
},
|
||||
})
|
||||
|
||||
@@ -29,13 +29,13 @@ var SelectedCommitRange = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("commit 01"),
|
||||
)
|
||||
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("commit 03\n"))
|
||||
|
||||
t.Views().Commits().Focus().
|
||||
Press(keys.Universal.RangeSelectDown)
|
||||
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("commit 03\ncommit 02\n"))
|
||||
},
|
||||
})
|
||||
|
||||
@@ -29,7 +29,7 @@ var SelectedPath = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Files().
|
||||
Focus().
|
||||
NavigateToLine(Contains("file2"))
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("folder2/file2"))
|
||||
|
||||
t.Views().Commits().
|
||||
@@ -38,7 +38,7 @@ var SelectedPath = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().CommitFiles().
|
||||
IsFocused().
|
||||
NavigateToLine(Contains("file1"))
|
||||
t.GlobalPress("X")
|
||||
t.GlobalPress(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("folder1/file1"))
|
||||
},
|
||||
})
|
||||
|
||||
@@ -40,13 +40,13 @@ var SelectedSubmodule = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("submodule").IsSelected(),
|
||||
)
|
||||
|
||||
t.Views().Submodules().Press("X")
|
||||
t.Views().Submodules().Press(config.Keybinding{"X"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("path/submodule"))
|
||||
|
||||
t.Views().Submodules().Press("U")
|
||||
t.Views().Submodules().Press(config.Keybinding{"U"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("../submodule"))
|
||||
|
||||
t.Views().Submodules().Press("N")
|
||||
t.Views().Submodules().Press(config.Keybinding{"N"})
|
||||
t.FileSystem().FileContent("file.txt", Equals("submodule"))
|
||||
},
|
||||
})
|
||||
|
||||
@@ -37,7 +37,7 @@ var ShowOutputInPanel = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Lines(
|
||||
Contains("my change").IsSelected(),
|
||||
).
|
||||
Press("X")
|
||||
Press(config.Keybinding{"X"})
|
||||
|
||||
t.ExpectPopup().Alert().
|
||||
// Uses cmd string as title if no outputTitle is provided
|
||||
@@ -46,7 +46,7 @@ var ShowOutputInPanel = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Confirm()
|
||||
|
||||
t.Views().Commits().
|
||||
Press("Y")
|
||||
Press(config.Keybinding{"Y"})
|
||||
|
||||
hash := t.Git().GetCommitHash("HEAD")
|
||||
t.ExpectPopup().Alert().
|
||||
|
||||
@@ -49,7 +49,7 @@ var SuggestionsCommand = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("branch-three"),
|
||||
Contains("branch-two"),
|
||||
).
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("Enter a branch name")).
|
||||
|
||||
@@ -49,7 +49,7 @@ var SuggestionsPreset = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("branch-three"),
|
||||
Contains("branch-two"),
|
||||
).
|
||||
Press("a")
|
||||
Press(config.Keybinding{"a"})
|
||||
|
||||
t.ExpectPopup().Prompt().
|
||||
Title(Equals("Enter a branch name")).
|
||||
|
||||
@@ -63,7 +63,7 @@ var CustomCommand = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Wait(500).
|
||||
Press("a").
|
||||
Press(config.Keybinding{"a"}).
|
||||
Tap(func() {
|
||||
t.Wait(500)
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ var FilterMenuWithNoKeybindings = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Filtering the keybindings menu so that only entries without keybinding are left",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
config.GetUserConfig().Keybinding.Universal.ToggleWhitespaceInDiffView = "<disabled>"
|
||||
SetupConfig: func(cfg *config.AppConfig) {
|
||||
cfg.GetUserConfig().Keybinding.Universal.ToggleWhitespaceInDiffView = nil
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
},
|
||||
|
||||
@@ -26,7 +26,7 @@ var ShowExecTodos = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Press("X").
|
||||
Press(config.Keybinding{"X"}).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Alert().Title(Equals("Error")).Content(Contains("Rebasing (2/4)Executing: false")).Confirm()
|
||||
}).
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var DisabledKeybindings = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Confirms you can disable keybindings by setting them to <disabled>",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
config.GetUserConfig().Keybinding.Universal.PrevItem = "<disabled>"
|
||||
config.GetUserConfig().Keybinding.Universal.NextItem = "<disabled>"
|
||||
config.GetUserConfig().Keybinding.Universal.NextTab = "<up>"
|
||||
config.GetUserConfig().Keybinding.Universal.PrevTab = "<down>"
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Press("<up>")
|
||||
|
||||
t.Views().Worktrees().IsFocused()
|
||||
},
|
||||
})
|
||||
@@ -44,7 +44,7 @@ var Enter = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
assertInSubmodule()
|
||||
|
||||
t.Views().Files().IsFocused().
|
||||
Press("e").
|
||||
Press(config.Keybinding{"e"}).
|
||||
Tap(func() {
|
||||
t.Views().Commits().Content(Contains("empty commit"))
|
||||
}).
|
||||
|
||||
@@ -46,7 +46,7 @@ var Reset = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
assertInSubmodule()
|
||||
|
||||
t.Views().Files().IsFocused().
|
||||
Press("e").
|
||||
Press(config.Keybinding{"e"}).
|
||||
Tap(func() {
|
||||
t.Views().Commits().Content(Contains("empty commit"))
|
||||
t.Views().Files().Content(Contains("my_file"))
|
||||
|
||||
@@ -334,7 +334,6 @@ var tests = []*components.IntegrationTest{
|
||||
misc.ConfirmOnQuit,
|
||||
misc.CopyConfirmationMessageToClipboard,
|
||||
misc.CopyToClipboard,
|
||||
misc.DisabledKeybindings,
|
||||
misc.InitialOpen,
|
||||
misc.RecentReposOnLaunch,
|
||||
patch_building.Apply,
|
||||
|
||||
@@ -15,9 +15,9 @@ var DisableSwitchTabWithPanelJumpKeys = NewIntegrationTest(NewIntegrationTestArg
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Status().Focus().
|
||||
Press(keys.Universal.JumpToBlock[1])
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[1]})
|
||||
t.Views().Files().IsFocused().
|
||||
Press(keys.Universal.JumpToBlock[1])
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[1]})
|
||||
|
||||
// Despite jumping to an already focused panel,
|
||||
// the tab should not change from the base files view
|
||||
|
||||
@@ -16,19 +16,19 @@ var SwitchTabWithPanelJumpKeys = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Worktrees().Focus().
|
||||
Press(keys.Universal.JumpToBlock[2])
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[2]})
|
||||
|
||||
t.Views().Branches().IsFocused().
|
||||
Press(keys.Universal.JumpToBlock[2])
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[2]})
|
||||
|
||||
t.Views().Remotes().IsFocused().
|
||||
Press(keys.Universal.JumpToBlock[2])
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[2]})
|
||||
|
||||
t.Views().Tags().IsFocused().
|
||||
Press(keys.Universal.JumpToBlock[2])
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[2]})
|
||||
|
||||
t.Views().Branches().IsFocused().
|
||||
Press(keys.Universal.JumpToBlock[1])
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[1]})
|
||||
|
||||
// When jumping to a panel from a different one, keep its current tab:
|
||||
t.Views().Worktrees().IsFocused()
|
||||
|
||||
@@ -32,7 +32,7 @@ var CustomCommand = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Contains("linked-worktree"),
|
||||
).
|
||||
NavigateToLine(Contains("linked-worktree")).
|
||||
Press("d").
|
||||
Press(config.Keybinding{"d"}).
|
||||
Lines(
|
||||
Contains("(main worktree)"),
|
||||
)
|
||||
|
||||
@@ -58,6 +58,7 @@ func customReflect(v *config.UserConfig) *jsonschema.Schema {
|
||||
}
|
||||
filterOutDevComments(r)
|
||||
schema := r.Reflect(v)
|
||||
inlineKeybindingRefs(schema)
|
||||
defaultConfig := config.GetDefaultConfig()
|
||||
userConfigSchema := schema.Definitions["UserConfig"]
|
||||
|
||||
@@ -77,6 +78,57 @@ func customReflect(v *config.UserConfig) *jsonschema.Schema {
|
||||
return schema
|
||||
}
|
||||
|
||||
// inlineKeybindingRefs replaces every `$ref: #/$defs/Keybinding` in the
|
||||
// schema with the inlined oneOf union, then drops the Keybinding definition.
|
||||
//
|
||||
// The schema generator stores types that implement JSONSchema() as shared
|
||||
// definitions and uses $ref to point at them. That works for most types
|
||||
// (where every reference logically points at the same data), but for
|
||||
// Keybinding fields each property carries its own description and default,
|
||||
// and writing those onto the shared definition would clobber siblings.
|
||||
// Inlining sidesteps the issue.
|
||||
func inlineKeybindingRefs(schema *jsonschema.Schema) {
|
||||
const ref = "#/$defs/Keybinding"
|
||||
keybindingDef, ok := schema.Definitions["Keybinding"]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
inline := func(s *jsonschema.Schema) {
|
||||
desc := s.Description
|
||||
*s = *keybindingDef
|
||||
s.Description = desc
|
||||
}
|
||||
var visit func(s *jsonschema.Schema)
|
||||
visit = func(s *jsonschema.Schema) {
|
||||
if s == nil {
|
||||
return
|
||||
}
|
||||
if s.Properties != nil {
|
||||
for pair := s.Properties.Oldest(); pair != nil; pair = pair.Next() {
|
||||
if pair.Value.Ref == ref {
|
||||
inline(pair.Value)
|
||||
} else {
|
||||
visit(pair.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
if s.Items != nil {
|
||||
if s.Items.Ref == ref {
|
||||
inline(s.Items)
|
||||
} else {
|
||||
visit(s.Items)
|
||||
}
|
||||
}
|
||||
if s.AdditionalProperties != nil {
|
||||
visit(s.AdditionalProperties)
|
||||
}
|
||||
}
|
||||
for _, def := range schema.Definitions {
|
||||
visit(def)
|
||||
}
|
||||
delete(schema.Definitions, "Keybinding")
|
||||
}
|
||||
|
||||
func filterOutDevComments(r *jsonschema.Reflector) {
|
||||
for k, v := range r.CommentMap {
|
||||
commentLines := strings.Split(v, "\n")
|
||||
|
||||
+1784
-164
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user