gob/shell/console/prompt.go

153 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 dentier.
func PromptInt(sp PromptFunc) ParsedPromptFunc[int] {
return ParsedPrompt(sp, singleConv[int])
}
// PromptUint transforme un prompt en prompt dentier 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 nest 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 dentiers.
func PromptSliceInt(sp PromptFunc, t ...scanner.Tokenizer) ParsedPromptFunc[[]int] {
return MultiplePrompt(sp, singleConv[int], t...)
}
// PromptSliceUint transform un prompt en prompt de slice dentiers 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...)
}