mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-06-20 01:19:23 +02:00
Convert JumpToBlock to a list of multi-key bindings
JumpToBlock is special: each of its 5 elements is the binding for one side window (status / files / branches / commits / stash), not an alternate for a single command. Change the field from []string to []Keybinding so each window slot can have alternates of its own. The schema becomes "an array of 5 keybindings, each itself a string or array of strings", which falls out cleanly from how the Keybinding type inlines into the generated schema. Existing configs (a flat array of 5 strings) keep validating because each element is unmarshalled through Keybinding's scalar-or-sequence decoder.
This commit is contained in:
@@ -180,3 +180,18 @@ func TestKeybindingConfigYAMLAcceptsBothForms(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJumpToBlockYAMLAcceptsMixedForms(t *testing.T) {
|
||||
yamlInput := `
|
||||
jumpToBlock:
|
||||
- "1"
|
||||
- ["2", "@"]
|
||||
- "3"
|
||||
- "4"
|
||||
- "5"
|
||||
`
|
||||
var cfg KeybindingUniversalConfig
|
||||
assert.NoError(t, yaml.Unmarshal([]byte(yamlInput), &cfg))
|
||||
expected := []Keybinding{{"1"}, {"2", "@"}, {"3"}, {"4"}, {"5"}}
|
||||
assert.Equal(t, expected, cfg.JumpToBlock)
|
||||
}
|
||||
|
||||
+81
-81
@@ -423,86 +423,86 @@ type KeybindingConfig struct {
|
||||
|
||||
// damn looks like we have some inconsistencies here with -alt and -alt1
|
||||
type KeybindingUniversalConfig struct {
|
||||
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"`
|
||||
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 []Keybinding `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 {
|
||||
@@ -932,7 +932,7 @@ func GetDefaultConfigForPlatform(platform string) *UserConfig {
|
||||
NextBlockAlt: Keybinding{"l"},
|
||||
PrevBlockAlt2: Keybinding{"<backtab>"},
|
||||
NextBlockAlt2: Keybinding{"<tab>"},
|
||||
JumpToBlock: []string{"1", "2", "3", "4", "5"},
|
||||
JumpToBlock: []Keybinding{{"1"}, {"2"}, {"3"}, {"4"}, {"5"}},
|
||||
FocusMainView: Keybinding{"0"},
|
||||
NextMatch: Keybinding{"n"},
|
||||
PrevMatch: Keybinding{"N"},
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -127,7 +128,10 @@ func TestUserConfigValidate_enums(t *testing.T) {
|
||||
{
|
||||
name: "JumpToBlock keybinding",
|
||||
setup: func(config *UserConfig, value string) {
|
||||
config.Keybinding.Universal.JumpToBlock = strings.Split(value, ",")
|
||||
labels := strings.Split(value, ",")
|
||||
config.Keybinding.Universal.JumpToBlock = lo.Map(labels, func(label string, _ int) Keybinding {
|
||||
return Keybinding{label}
|
||||
})
|
||||
},
|
||||
testCases: []testCase{
|
||||
{value: "", valid: false},
|
||||
|
||||
@@ -3,7 +3,6 @@ package controllers
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
@@ -40,7 +39,7 @@ func (self *JumpToSideWindowController) GetKeybindings(opts types.KeybindingsOpt
|
||||
return &types.Binding{
|
||||
ViewName: "",
|
||||
// by default the keys are 1, 2, 3, etc
|
||||
Keys: opts.GetKeys(config.Keybinding{opts.Config.Universal.JumpToBlock[index]}),
|
||||
Keys: opts.GetKeys(opts.Config.Universal.JumpToBlock[index]),
|
||||
Handler: opts.Guards.NoPopupPanel(self.goToSideWindow(window)),
|
||||
}
|
||||
})
|
||||
|
||||
+6
-5
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
"github.com/jesseduffield/lazygit/pkg/gocui"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
@@ -210,14 +211,14 @@ func (gui *Gui) configureViewProperties() {
|
||||
gui.Views.CommitDescription.TextArea.AutoWrapWidth = gui.c.UserConfig().Git.Commit.AutoWrapWidth
|
||||
|
||||
if gui.c.UserConfig().Gui.ShowPanelJumps {
|
||||
keyToTitlePrefix := func(key string) string {
|
||||
if key == "<disabled>" {
|
||||
keyToTitlePrefix := func(binding config.Keybinding) string {
|
||||
if len(binding) == 0 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("[%s]", key)
|
||||
return fmt.Sprintf("[%s]", binding[0])
|
||||
}
|
||||
jumpBindings := gui.c.UserConfig().Keybinding.Universal.JumpToBlock
|
||||
jumpLabels := lo.Map(jumpBindings, func(binding string, _ int) string {
|
||||
jumpLabels := lo.Map(jumpBindings, func(binding config.Keybinding, _ int) string {
|
||||
return keyToTitlePrefix(binding)
|
||||
})
|
||||
|
||||
@@ -236,7 +237,7 @@ func (gui *Gui) configureViewProperties() {
|
||||
|
||||
gui.Views.Stash.TitlePrefix = jumpLabels[4]
|
||||
|
||||
gui.Views.Main.TitlePrefix = keyToTitlePrefix(gui.c.UserConfig().Keybinding.Universal.FocusMainView[0])
|
||||
gui.Views.Main.TitlePrefix = keyToTitlePrefix(gui.c.UserConfig().Keybinding.Universal.FocusMainView)
|
||||
} else {
|
||||
gui.Views.Status.TitlePrefix = ""
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ func (self *ViewDriver) Focus() *ViewDriver {
|
||||
if lo.Contains(window.viewNames, viewName) {
|
||||
tabIndex := lo.IndexOf(window.viewNames, viewName)
|
||||
// jump to the desired window
|
||||
self.t.press(self.t.keys.Universal.JumpToBlock[windowIndex])
|
||||
self.t.press(self.t.keys.Universal.JumpToBlock[windowIndex][0])
|
||||
|
||||
// assert we're in the window before continuing
|
||||
self.t.assertWithRetries(func() (bool, string) {
|
||||
|
||||
@@ -15,9 +15,9 @@ var DisableSwitchTabWithPanelJumpKeys = NewIntegrationTest(NewIntegrationTestArg
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Status().Focus().
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[1]})
|
||||
Press(keys.Universal.JumpToBlock[1])
|
||||
t.Views().Files().IsFocused().
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[1]})
|
||||
Press(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(config.Keybinding{keys.Universal.JumpToBlock[2]})
|
||||
Press(keys.Universal.JumpToBlock[2])
|
||||
|
||||
t.Views().Branches().IsFocused().
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[2]})
|
||||
Press(keys.Universal.JumpToBlock[2])
|
||||
|
||||
t.Views().Remotes().IsFocused().
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[2]})
|
||||
Press(keys.Universal.JumpToBlock[2])
|
||||
|
||||
t.Views().Tags().IsFocused().
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[2]})
|
||||
Press(keys.Universal.JumpToBlock[2])
|
||||
|
||||
t.Views().Branches().IsFocused().
|
||||
Press(config.Keybinding{keys.Universal.JumpToBlock[1]})
|
||||
Press(keys.Universal.JumpToBlock[1])
|
||||
|
||||
// When jumping to a panel from a different one, keep its current tab:
|
||||
t.Views().Worktrees().IsFocused()
|
||||
|
||||
@@ -2473,7 +2473,17 @@
|
||||
},
|
||||
"jumpToBlock": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "array",
|
||||
"default": [
|
||||
|
||||
Reference in New Issue
Block a user