From 471251cc6aaa7093a16a120fd128f6bc526a5886 Mon Sep 17 00:00:00 2001 From: Valentin Kiselev Date: Mon, 9 Oct 2023 10:23:46 +0300 Subject: [PATCH] fix: correctly sort alphanumeric commands (#562) --- internal/lefthook/run/runner.go | 46 ++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/internal/lefthook/run/runner.go b/internal/lefthook/run/runner.go index 37e42c1f..6a8024ee 100644 --- a/internal/lefthook/run/runner.go +++ b/internal/lefthook/run/runner.go @@ -11,9 +11,11 @@ import ( "regexp" "slices" "sort" + "strconv" "strings" "sync" "sync/atomic" + "unicode" "github.com/charmbracelet/lipgloss" "github.com/spf13/afero" @@ -330,7 +332,7 @@ func (r *Runner) runCommands(ctx context.Context) { } } - sort.Strings(commands) + sortAlnum(commands) interactiveCommands := make([]string, 0) var wg sync.WaitGroup @@ -529,3 +531,45 @@ func (r *Runner) logExecute(name string, err error, out io.Reader) { log.Infof("%s", err) } } + +// sortAlnum sorts the command names by preceding numbers if they occur. +// If the command names starts with letter the command name will be sorted alphabetically. +// +// []string{"1_command", "10command", "3 command", "command5"} // -> 1_command, 3 command, 10command, command5 +func sortAlnum(strs []string) { + sort.SliceStable(strs, func(i, j int) bool { + numEnds := -1 + for idx, ch := range strs[i] { + if unicode.IsDigit(ch) { + numEnds = idx + } else { + break + } + } + if numEnds == -1 { + return strs[i] < strs[j] + } + numI, err := strconv.Atoi(strs[i][:numEnds+1]) + if err != nil { + return strs[i] < strs[j] + } + + numEnds = -1 + for idx, ch := range strs[j] { + if unicode.IsDigit(ch) { + numEnds = idx + } else { + break + } + } + if numEnds == -1 { + return true + } + numJ, err := strconv.Atoi(strs[j][:numEnds+1]) + if err != nil { + return true + } + + return numI < numJ + }) +}