From 5dcc93e8cc67b22e5493fedb7fbb0c59cd1689df Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 3 May 2026 14:14:23 +0200 Subject: [PATCH] Validate that gui.spinner.frames must all have the same width The spinner looks weird if they don't. While we're at it, validate that frames must not be empty, which would have crashed with a division by zero. --- pkg/config/user_config_validation.go | 19 ++++++++++++++ pkg/config/user_config_validation_test.go | 30 +++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/pkg/config/user_config_validation.go b/pkg/config/user_config_validation.go index 23215eab6..7eeab32dd 100644 --- a/pkg/config/user_config_validation.go +++ b/pkg/config/user_config_validation.go @@ -1,6 +1,7 @@ package config import ( + "errors" "fmt" "log" "reflect" @@ -8,6 +9,8 @@ import ( "strings" "github.com/jesseduffield/lazygit/pkg/constants" + "github.com/jesseduffield/lazygit/pkg/utils" + "github.com/samber/lo" ) func (config *UserConfig) Validate() error { @@ -49,6 +52,22 @@ func (config *UserConfig) Validate() error { if err := validateCustomCommands(config.CustomCommands); err != nil { return err } + if err := validateSpinner(config.Gui.Spinner); err != nil { + return err + } + return nil +} + +func validateSpinner(spinner SpinnerConfig) error { + if len(spinner.Frames) == 0 { + return errors.New("gui.spinner.frames must not be empty.") + } + firstWidth := utils.StringWidth(spinner.Frames[0]) + if lo.SomeBy(spinner.Frames, func(frame string) bool { + return utils.StringWidth(frame) != firstWidth + }) { + return errors.New("All gui.spinner.frames entries must have the same width.") + } return nil } diff --git a/pkg/config/user_config_validation_test.go b/pkg/config/user_config_validation_test.go index 7fbfd00d4..a2841684d 100644 --- a/pkg/config/user_config_validation_test.go +++ b/pkg/config/user_config_validation_test.go @@ -289,3 +289,33 @@ func TestUserConfigValidate_enums(t *testing.T) { }) } } + +func TestUserConfigValidate_spinnerFrames(t *testing.T) { + scenarios := []struct { + name string + frames []string + valid bool + }{ + {name: "empty", frames: []string{}, valid: false}, + {name: "single frame", frames: []string{"|"}, valid: true}, + {name: "all same width", frames: []string{"|", "/", "-", "\\"}, valid: true}, + {name: "all same width, multi-char", frames: []string{". ", ".. ", "..."}, valid: true}, + {name: "all same width, wide runes", frames: []string{"⠋", "⠙", "⠹"}, valid: true}, + {name: "differing widths", frames: []string{"|", "//"}, valid: false}, + {name: "first differs from rest", frames: []string{"||", "/", "-"}, valid: false}, + } + + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + config := GetDefaultConfig() + config.Gui.Spinner.Frames = s.frames + err := config.Validate() + + if s.valid { + assert.NoError(t, err) + } else { + assert.Error(t, err) + } + }) + } +}