package cli import ( "errors" "fmt" "os" "strings" "gitea.zaclys.com/bvaudour/gob/option" "gitea.zaclys.net/bvaudour/go-calc/calc" ) type integer interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 } type CliFunc func(*Cli) option.Option[error] type WordCliFunc func(string) CliFunc func cliToCalcFunc(c *Cli, cb CliFunc) calc.CalcFunc { return func(_ *calc.Calc) option.Option[error] { return cb(c) } } func otherToCalcFunc(cb func() option.Option[error]) calc.CalcFunc { return func(_ *calc.Calc) option.Option[error] { return cb() } } func stack2Str(numbers calc.Stack) string { sl := make([]string, len(numbers)) for i, n := range numbers { sl[i] = n.String() } return strings.Join(sl, " ") } func printResult(arg any) (result option.Option[error]) { if _, e := fmt.Printf("\033[1;33m%s\033[m\n", arg); e != nil { result = option.Some(e) } return } func printError(err error) (result option.Option[error]) { if _, e := fmt.Printf("\033[1;31m%s\033[m\n", err); e != nil { result = option.Some(e) } return } func printLine(k string, arg any) (result option.Option[error]) { if _, e := fmt.Printf("\033[1;32m%s\033[m → \033[1;33m%s\033[m\n", k, arg); e != nil { result = option.Some(e) } return } func printHelp() (result option.Option[error]) { if _, e := fmt.Print(help); e != nil { result = option.Some(e) } return } func printOption(c *calc.Calc) option.Option[error] { p, f := c.Precision() t := "auto" if f { t = "fixe" } return printResult(fmt.Sprintf("%d (%s)", p, t)) } func printLast(c *calc.Calc) (err option.Option[error]) { result := c.Last() if n, ok := result.Ok(); ok { err = printResult(n) } else if e, ok := result.Err(); ok { err = option.Some(e) } return } func printStack(c *calc.Calc) (err option.Option[error]) { result := c.GetStack() if s, ok := result.Ok(); ok { err = printResult(stack2Str(s)) } else if e, ok := result.Err(); ok { err = option.Some(e) } return } func printRegistries(c *calc.Calc) (err option.Option[error]) { result := c.GetRegistries() if r, ok := result.Ok(); ok { for k, s := range r { printLine(k, stack2Str(s)) } } else if e, ok := result.Err(); ok { err = option.Some(e) } return } func printRegistry(k string) calc.CalcFunc { return func(c *calc.Calc) (err option.Option[error]) { result := c.Registry(k) if s, ok := result.Ok(); ok { err = printResult(stack2Str(s)) } else if e, ok := result.Err(); ok { err = option.Some(e) } return } } func printMacros(c *Cli) (err option.Option[error]) { result := c.c.GetMacros() if e, ok := result.Err(); ok { err = option.Some(e) } else { for k, m := range c.macros { printLine(k, m) } } return } func printMacro(k string) CliFunc { return func(c *Cli) (err option.Option[error]) { result := c.c.Macro(k) if e, ok := result.Err(); ok { err = option.Some(e) } else { err = printResult(c.macros[k]) } return } } func quit() (err option.Option[error]) { os.Exit(0) return } func execMacro(k string) calc.CalcFunc { return func(c *calc.Calc) (err option.Option[error]) { errs := c.ExecMacro(k) if len(errs) > 0 { sErrors := make([]string, len(errs)) for i, e := range errs { sErrors[i] = e.Error() } err = option.Some(errors.New(strings.Join(sErrors, "\n"))) } return } } func setPrecision(c *calc.Calc, precision option.Option[uint64], fix bool) (err option.Option[error]) { c.SetPrecision(precision, option.Some(fix)) return } func fixPrecision(fix bool) calc.CalcFunc { return func(c *calc.Calc) (err option.Option[error]) { return setPrecision(c, option.None[uint64](), fix) } } func precision[N integer](fix bool) calc.IntCalcFunc[N] { return func(args ...N) calc.CalcFunc { return func(c *calc.Calc) (err option.Option[error]) { var p option.Option[uint64] if len(args) > 0 { p = option.Some(uint64(args[0])) } return setPrecision(c, p, fix) } } } func startMacro(c *Cli) (err option.Option[error]) { if c.needMacro { return option.Some(errMacroOpen) } c.needMacro = true return } func startAlt(c *Cli) (err option.Option[error]) { if c.needAlt { return option.Some(errAltOpen) } c.needAlt = true return } func resetMacro(k string) CliFunc { return func(c *Cli) (err option.Option[error]) { if err = c.c.ResetMacro(k); !err.IsDefined() { delete(c.macros, k) } return } } func storeMacro(k string, macro string, cmd []calc.MacroElement) CliFunc { return func(c *Cli) (err option.Option[error]) { c.c.StoreMacro(k, cmd...) c.macros[k] = macro return } } func endMacro(k string) CliFunc { return func(c *Cli) (err option.Option[error]) { if !c.needMacro { return option.Some(errMacroClosed) } cb := storeMacro(k, c.strMacro(), c.cmd) c.mstate.reset() if !c.needAlt { return cb(c) } c.alt = append(c.alt, calc.MacroCommand(cliToCalcFunc(c, cb))) return } }