package console import ( "fmt" "strings" "gitea.zaclys.com/bvaudour/gob/convert" . "gitea.zaclys.com/bvaudour/gob/option" "gitea.zaclys.com/bvaudour/gob/shell/scanner" ) // PromptFunc est une fonction qui affiche une invite de commande et retourne la saisie brute. type PromptFunc func(string) Result[string] // ParsedPromptFunc est une fonction qui affiche une invite de commande et retourne la saisie parsée. type ParsedPromptFunc[T any] func(string) Result[T] // ConvFunc est une fonction qui convertit une chaîne de caractère en un type donné. type ConvFunc[T any] func(string) Result[T] // PromptOf transforme un prompter en fonction promptable. func PromptOf(p Prompter) PromptFunc { return p.Prompt } func singleConv[T any](s string) Result[T] { var value T if !convert.Convert(s, &value) { return Err[T](fmt.Errorf("Failed to convert %s", s)) } return Ok(value) } func boolConv(s string) (out Result[bool]) { s = strings.ToLower(s) switch s { case "oui", "o", "yes", "y", "1", "true", "t", "on": out = Ok(true) case "non", "n", "no", "0", "false", "f", "off": out = Ok(false) default: out = Err[bool](fmt.Errorf("%s: not a boolean", s)) } return } func strConv(s string) Result[string] { return Ok(s) } // ParsedPrompt transforme un prompt en prompt de donnée parsée. func ParsedPrompt[T any](sp PromptFunc, conv ConvFunc[T]) ParsedPromptFunc[T] { return func(p string) (out Result[T]) { sout := sp(p) if v, ok := sout.Ok(); ok { out = conv(v) } else if err, ok := sout.Err(); ok { out = Err[T](err) } return } } // PromptInt transforme un prompt en prompt d’entier. func PromptInt(sp PromptFunc) ParsedPromptFunc[int] { return ParsedPrompt(sp, singleConv[int]) } // PromptUint transforme un prompt en prompt d’entier non signé. func PromptUint(sp PromptFunc) ParsedPromptFunc[uint] { return ParsedPrompt(sp, singleConv[uint]) } // PromptFloat transforme un prompt en prompt de nombre décimal. func PromptFloat(sp PromptFunc) ParsedPromptFunc[float64] { return ParsedPrompt(sp, singleConv[float64]) } // PromptBool transforme un prompt en prompt de booléen. // // Valeurs autorisée : // - true : O(ui), Y(es), t(rue), 1, on // - false : N(on), f(alse), 0, off // La valeur est insensible à la casse. func PromptBool(sp PromptFunc) ParsedPromptFunc[bool] { return ParsedPrompt(sp, boolConv) } // MultiplePrompt transforme un prompt en prompt de valeurs multiples. // Si aucun tokenizer n’est fourni, il considère la chaîne globale // comme des mots séparés par des blancs. func MultiplePrompt[T any]( sp PromptFunc, conv ConvFunc[T], t ...scanner.Tokenizer, ) ParsedPromptFunc[[]T] { return func(p string) (out Result[[]T]) { sout := sp(p) if line, ok := sout.Ok(); ok { var tk scanner.Tokenizer if len(t) > 0 { tk = t[0] } else { tk = scanner.NewTokenizer(false, false) } sc := scanner.NewScanner(strings.NewReader(line), tk) var tmp []T for sc.Scan() { elem := conv(sc.Text()) if v, ok := elem.Ok(); ok { tmp = append(tmp, v) } else if err, ok := elem.Err(); ok { return Err[[]T](err) } } out = Ok(tmp) } else if err, ok := sout.Err(); ok { out = Err[[]T](err) } return } } // PromptSlice transform un prompt en prompt de slice de strings. func PromptSlice(sp PromptFunc, t ...scanner.Tokenizer) ParsedPromptFunc[[]string] { return MultiplePrompt(sp, strConv, t...) } // PromptSliceInt transform un prompt en prompt de slice d’entiers. func PromptSliceInt(sp PromptFunc, t ...scanner.Tokenizer) ParsedPromptFunc[[]int] { return MultiplePrompt(sp, singleConv[int], t...) } // PromptSliceUint transform un prompt en prompt de slice d’entiers non signés. func PromptSliceUint(sp PromptFunc, t ...scanner.Tokenizer) ParsedPromptFunc[[]uint] { return MultiplePrompt(sp, singleConv[uint], t...) } // PromptSliceFloat transform un prompt en prompt de slice de décimaux. func PromptSliceFloat(sp PromptFunc, t ...scanner.Tokenizer) ParsedPromptFunc[[]float64] { return MultiplePrompt(sp, singleConv[float64], t...) } // PromptSliceBool transform un prompt en prompt de slice de booléens. func PromptSliceBool(sp PromptFunc, t ...scanner.Tokenizer) ParsedPromptFunc[[]bool] { return MultiplePrompt(sp, boolConv, t...) }