mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-15 18:16:25 -04:00
Set the sort order's default from the former foldersFirst to mixed, so this is a change in behavior. I find this useful because it now matches git's order, so if you look at the diff of a commit, the TOC at the top has the same order as the file tree you see when entering the commit.
168 lines
5.1 KiB
Go
168 lines
5.1 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"reflect"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/jesseduffield/lazygit/pkg/constants"
|
|
)
|
|
|
|
func (config *UserConfig) Validate() error {
|
|
if err := validateEnum("gui.statusPanelView", config.Gui.StatusPanelView,
|
|
[]string{"dashboard", "allBranchesLog"}); err != nil {
|
|
return err
|
|
}
|
|
if err := validateEnum("gui.showDivergenceFromBaseBranch", config.Gui.ShowDivergenceFromBaseBranch,
|
|
[]string{"none", "onlyArrow", "arrowAndNumber"}); err != nil {
|
|
return err
|
|
}
|
|
if err := validateEnum("gui.fileTreeSortOrder", config.Gui.FileTreeSortOrder,
|
|
[]string{"mixed", "filesFirst", "foldersFirst"}); err != nil {
|
|
return err
|
|
}
|
|
if err := validateEnum("git.autoForwardBranches", config.Git.AutoForwardBranches,
|
|
[]string{"none", "onlyMainBranches", "allBranches"}); err != nil {
|
|
return err
|
|
}
|
|
if err := validateEnum("git.localBranchSortOrder", config.Git.LocalBranchSortOrder,
|
|
[]string{"date", "recency", "alphabetical"}); err != nil {
|
|
return err
|
|
}
|
|
if err := validateEnum("git.remoteBranchSortOrder", config.Git.RemoteBranchSortOrder,
|
|
[]string{"date", "alphabetical"}); err != nil {
|
|
return err
|
|
}
|
|
if err := validateEnum("git.log.order", config.Git.Log.Order,
|
|
[]string{"date-order", "author-date-order", "topo-order", "default"}); err != nil {
|
|
return err
|
|
}
|
|
if err := validateEnum("git.log.showGraph", config.Git.Log.ShowGraph,
|
|
[]string{"always", "never", "when-maximised"}); err != nil {
|
|
return err
|
|
}
|
|
if err := validateKeybindings(config.Keybinding); err != nil {
|
|
return err
|
|
}
|
|
if err := validateCustomCommands(config.CustomCommands); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateEnum(name string, value string, allowedValues []string) error {
|
|
if slices.Contains(allowedValues, value) {
|
|
return nil
|
|
}
|
|
allowedValuesStr := strings.Join(allowedValues, ", ")
|
|
return fmt.Errorf("Unexpected value '%s' for '%s'. Allowed values: %s", value, name, allowedValuesStr)
|
|
}
|
|
|
|
func validateKeybindingsRecurse(path string, node any) error {
|
|
value := reflect.ValueOf(node)
|
|
if value.Kind() == reflect.Struct {
|
|
for _, field := range reflect.VisibleFields(reflect.TypeOf(node)) {
|
|
var newPath string
|
|
if len(path) == 0 {
|
|
newPath = field.Name
|
|
} else {
|
|
newPath = fmt.Sprintf("%s.%s", path, field.Name)
|
|
}
|
|
if err := validateKeybindingsRecurse(newPath,
|
|
value.FieldByName(field.Name).Interface()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
} else if value.Kind() == reflect.Slice {
|
|
for i := range value.Len() {
|
|
if err := validateKeybindingsRecurse(
|
|
fmt.Sprintf("%s[%d]", path, i), value.Index(i).Interface()); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
} else if value.Kind() == reflect.String {
|
|
key := node.(string)
|
|
if !isValidKeybindingKey(key) {
|
|
return fmt.Errorf("Unrecognized key '%s' for keybinding '%s'. For permitted values see %s",
|
|
key, path, constants.Links.Docs.CustomKeybindings)
|
|
}
|
|
} else {
|
|
log.Fatalf("Unexpected type for property '%s': %s", path, value.Kind())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateKeybindings(keybindingConfig KeybindingConfig) error {
|
|
if err := validateKeybindingsRecurse("", keybindingConfig); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(keybindingConfig.Universal.JumpToBlock) != 5 {
|
|
return fmt.Errorf("keybinding.universal.jumpToBlock must have 5 elements; found %d.",
|
|
len(keybindingConfig.Universal.JumpToBlock))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func validateCustomCommandKey(key string) error {
|
|
if !isValidKeybindingKey(key) {
|
|
return fmt.Errorf("Unrecognized key '%s' for custom command. For permitted values see %s",
|
|
key, constants.Links.Docs.CustomKeybindings)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateCustomCommands(customCommands []CustomCommand) error {
|
|
for _, customCommand := range customCommands {
|
|
if err := validateCustomCommandKey(customCommand.Key); err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(customCommand.CommandMenu) > 0 {
|
|
if len(customCommand.Context) > 0 ||
|
|
len(customCommand.Command) > 0 ||
|
|
len(customCommand.Prompts) > 0 ||
|
|
len(customCommand.LoadingText) > 0 ||
|
|
len(customCommand.Output) > 0 ||
|
|
len(customCommand.OutputTitle) > 0 ||
|
|
customCommand.After != nil {
|
|
commandRef := ""
|
|
if len(customCommand.Key) > 0 {
|
|
commandRef = fmt.Sprintf(" with key '%s'", customCommand.Key)
|
|
}
|
|
return fmt.Errorf("Error with custom command%s: it is not allowed to use both commandMenu and any of the other fields except key and description.", commandRef)
|
|
}
|
|
|
|
if err := validateCustomCommands(customCommand.CommandMenu); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
for _, prompt := range customCommand.Prompts {
|
|
if err := validateCustomCommandPrompt(prompt); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := validateEnum("customCommand.output", customCommand.Output,
|
|
[]string{"", "none", "terminal", "log", "logWithPty", "popup"}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateCustomCommandPrompt(prompt CustomCommandPrompt) error {
|
|
for _, option := range prompt.Options {
|
|
if !isValidKeybindingKey(option.Key) {
|
|
return fmt.Errorf("Unrecognized key '%s' for custom command prompt option. For permitted values see %s",
|
|
option.Key, constants.Links.Docs.CustomKeybindings)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|