diff --git a/calc.go b/calc.go index 26de071..8ce89f1 100644 --- a/calc.go +++ b/calc.go @@ -20,7 +20,6 @@ package main import ( "errors" "fmt" - "os" "regexp" "strconv" "strings" @@ -47,25 +46,13 @@ type Calc struct { Funcalls Funcalls BatchFuncalls Funcalls + Commands Commands Vars map[string]float64 } // help for lua functions will be added dynamically -const Help string = `Available commands: -batch toggle batch mode (nobatch turns it off) -debug toggle debug output (nodebug turns it off) -showstack toggle show last 5 items of the stack (noshowtack turns it off) -dump display the stack contents -clear clear the whole stack -shift remove the last element of the stack -reverse reverse the stack elements -swap exchange the last two elements -vars show list of variables -history display calculation history -help|? show this message -quit|exit|c-d|c-c exit program - +const Help string = ` Operators: basic operators: + - x * / ^ (* is an alias of x) @@ -94,7 +81,7 @@ Register variables: // commands, constants and operators, defined here to feed completion // and our mode switch in Eval() dynamically const ( - Commands string = `dump reverse clear shift undo help history manual exit quit swap debug undebug nodebug batch nobatch showstack noshowstack vars` + //Commands string = `dump reverse clear shift undo help history manual exit quit swap debug undebug nodebug batch nobatch showstack noshowstack vars` Constants string = `Pi Phi Sqrt2 SqrtE SqrtPi SqrtPhi Ln2 Log2E Ln10 Log10E` ) @@ -107,7 +94,6 @@ func GetCompleteCustomFunctions() func(string) []string { completions = append(completions, luafunc) } - completions = append(completions, strings.Split(Commands, " ")...) completions = append(completions, strings.Split(Constants, " ")...) return completions @@ -126,6 +112,10 @@ func (c *Calc) GetCompleteCustomFuncalls() func(string) []string { completions = append(completions, function) } + for command := range c.Commands { + completions = append(completions, command) + } + return completions } @@ -151,6 +141,8 @@ func NewCalc() *Calc { // pre-calculate mode switching arrays c.Constants = strings.Split(Constants, " ") + c.SetCommands() + return &c } @@ -275,10 +267,19 @@ func (c *Calc) Eval(line string) { } // management commands + if _, ok := c.Commands[item]; ok { + c.Commands[item].Func(c) + continue + } + switch item { case "?": fallthrough case "help": + fmt.Println("Available commands:") + for name, command := range c.Commands { + fmt.Printf("%-20s %s\n", name, command.Help) + } fmt.Println(Help) if len(LuaFuncs) > 0 { fmt.Println("Lua functions:") @@ -286,62 +287,6 @@ func (c *Calc) Eval(line string) { fmt.Printf("%-20s %s\n", name, function.help) } } - case "dump": - c.stack.Dump() - case "debug": - c.ToggleDebug() - case "nodebug": - fallthrough - case "undebug": - c.debug = false - c.stack.debug = false - case "batch": - c.ToggleBatch() - case "nobatch": - c.batch = false - case "clear": - c.stack.Backup() - c.stack.Clear() - case "shift": - c.stack.Backup() - c.stack.Shift() - case "reverse": - c.stack.Backup() - c.stack.Reverse() - case "swap": - if c.stack.Len() < 2 { - fmt.Println("stack too small, can't swap") - } else { - c.stack.Backup() - c.stack.Swap() - } - case "undo": - c.stack.Restore() - case "history": - for _, entry := range c.history { - fmt.Println(entry) - } - case "showstack": - fallthrough - case "show": - c.ToggleShow() - case "noshowstack": - c.showstack = false - case "exit": - fallthrough - case "quit": - os.Exit(0) - case "manual": - man() - case "vars": - if len(c.Vars) > 0 { - fmt.Printf("%-20s %s\n", "VARIABLE", "VALUE") - for k, v := range c.Vars { - fmt.Printf("%-20s -> %.2f\n", k, v) - } - } else { - fmt.Println("no vars registered") - } default: fmt.Println("unknown command or operator!") diff --git a/command.go b/command.go new file mode 100644 index 0000000..078499f --- /dev/null +++ b/command.go @@ -0,0 +1,198 @@ +/* +Copyright © 2023 Thomas von Dein + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +package main + +import ( + "fmt" + "os" +) + +type CommandFunction func(*Calc) + +type Command struct { + Help string + Func CommandFunction +} + +type Commands map[string]*Command + +func NewCommand(help string, function CommandFunction) *Command { + return &Command{ + Help: help, + Func: function, + } +} + +// define all management (that is: non calculation) commands +func (c *Calc) SetCommands() { + f := Commands{ + // Toggles + "debug": NewCommand( + "toggle debugging", + func(c *Calc) { + c.ToggleDebug() + }, + ), + + "nodebug": NewCommand( + "disable debugging", + func(c *Calc) { + c.debug = false + c.stack.debug = false + }, + ), + + "batch": NewCommand( + "toggle batch mode", + func(c *Calc) { + c.ToggleBatch() + }, + ), + + "nobatch": NewCommand( + "disable batch mode", + func(c *Calc) { + c.batch = false + }, + ), + + "showstack": NewCommand( + "toggle show last 5 items of the stack", + func(c *Calc) { + c.ToggleShow() + }, + ), + + "noshowstack": NewCommand( + "disable display of the stack", + func(c *Calc) { + c.showstack = false + }, + ), + + // Display commands + "dump": NewCommand( + "display the stack contents", + func(c *Calc) { + c.stack.Dump() + }, + ), + + "history": NewCommand( + "display calculation history", + func(c *Calc) { + for _, entry := range c.history { + fmt.Println(entry) + } + }, + ), + + "vars": NewCommand( + "show list of variables", + func(c *Calc) { + if len(c.Vars) > 0 { + fmt.Printf("%-20s %s\n", "VARIABLE", "VALUE") + for k, v := range c.Vars { + fmt.Printf("%-20s -> %.2f\n", k, v) + } + } else { + fmt.Println("no vars registered") + } + }, + ), + + // stack manipulation commands + "clear": NewCommand( + "clear the whole stack", + func(c *Calc) { + c.stack.Backup() + c.stack.Clear() + }, + ), + + "shift": NewCommand( + "remove the last element of the stack", + func(c *Calc) { + c.stack.Backup() + c.stack.Shift() + }, + ), + + "reverse": NewCommand( + "reverse the stack elements", + func(c *Calc) { + c.stack.Backup() + c.stack.Reverse() + }, + ), + + "swap": NewCommand( + "exchange the last two elements", + func(c *Calc) { + if c.stack.Len() < 2 { + fmt.Println("stack too small, can't swap") + } else { + c.stack.Backup() + c.stack.Swap() + } + }, + ), + + "undo": NewCommand( + "undo last operation", + func(c *Calc) { + c.stack.Restore() + }, + ), + + "dup": NewCommand( + "duplicate last stack item", + func(c *Calc) { + item := c.stack.Last() + if len(item) == 1 { + c.stack.Backup() + c.stack.Push(item[0]) + } else { + fmt.Println("stack empty") + } + }, + ), + + // general commands + "exit": NewCommand( + "exit program", + func(c *Calc) { + os.Exit(0) + }, + ), + + "manual": NewCommand( + "show manual", + func(c *Calc) { + man() + }, + ), + } + + // aliases + f["quit"] = f["exit"] + f["undebug"] = f["nodebug"] + f["show"] = f["showstack"] + + c.Commands = f +}