From 252e7eb8d9161588c1c1e44b1f7764347e815c73 Mon Sep 17 00:00:00 2001 From: "T.v.Dein" Date: Mon, 4 Dec 2023 13:53:18 +0100 Subject: [PATCH] Feature/edit stack command (#23) * add edit feature * bump version --- command.go | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 2 +- rpn.go | 3 +- rpn.pod | 1 + 4 files changed, 104 insertions(+), 2 deletions(-) diff --git a/command.go b/command.go index d3a82d0..0a43fdb 100644 --- a/command.go +++ b/command.go @@ -18,8 +18,12 @@ along with this program. If not, see . package main import ( + "bufio" "fmt" "os" + "os/exec" + "strconv" + "strings" ) type CommandFunction func(*Calc) @@ -184,6 +188,102 @@ func (c *Calc) SetCommands() { } }, ), + + "edit": NewCommand( + "edit the stack interactively", + func(c *Calc) { + if c.stack.Len() == 0 { + fmt.Println("empty stack") + return + } + + c.stack.Backup() + + // put the stack contents into a tmp file + tmp, err := os.CreateTemp("", "stack") + if err != nil { + fmt.Println(err) + return + } + defer os.Remove(tmp.Name()) + + comment := `# add or remove numbers as you wish. +# each number must be on its own line. +# numbers must be floating point formatted. +` + _, err = tmp.WriteString(comment) + if err != nil { + fmt.Println(err) + return + } + + for _, item := range c.stack.All() { + _, err = fmt.Fprintf(tmp, "%f\n", item) + if err != nil { + fmt.Println(err) + return + } + } + + tmp.Close() + + // determine which editor to use + editor := "vi" + enveditor, present := os.LookupEnv("EDITOR") + if present { + if editor != "" { + if _, err := os.Stat(editor); err == nil { + editor = enveditor + } + } + } + + // execute editor with our tmp file containing current stack + cmd := exec.Command(editor, tmp.Name()) + + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + err = cmd.Run() + if err != nil { + fmt.Println("could not run editor command: ", err) + return + } + + // read the file back in + modified, err := os.Open(tmp.Name()) + if err != nil { + fmt.Println("Error opening file:", err) + return + } + defer modified.Close() + + // reset the stack + c.stack.Clear() + + // and put the new contents (if legit) back onto the stack + scanner := bufio.NewScanner(modified) + for scanner.Scan() { + line := strings.TrimSpace(c.Comment.ReplaceAllString(scanner.Text(), "")) + if line == "" { + continue + } + + num, err := strconv.ParseFloat(line, 64) + if err != nil { + fmt.Printf("%s is not a floating point number!\n", line) + continue + } + + c.stack.Push(num) + } + + if err := scanner.Err(); err != nil { + fmt.Println("Error reading from file:", err) + } + }, + ), } // general commands diff --git a/main.go b/main.go index b549427..3785060 100644 --- a/main.go +++ b/main.go @@ -30,7 +30,7 @@ import ( lua "github.com/yuin/gopher-lua" ) -const VERSION string = "2.0.10" +const VERSION string = "2.0.11" const Usage string = `This is rpn, a reverse polish notation calculator cli. diff --git a/rpn.go b/rpn.go index eb89625..89bebf6 100644 --- a/rpn.go +++ b/rpn.go @@ -185,7 +185,8 @@ DESCRIPTION Stack manipulation commands: clear clear the whole stack shift remove the last element of the stack reverse reverse the stack elements swap exchange the last two stack elements dup duplicate last stack item undo - undo last operation + undo last operation edit edit the stack interactively using vi or + $EDITOR Other commands: help|? show this message manual show manual quit|exit|c-d|c-c exit program diff --git a/rpn.pod b/rpn.pod index aae8858..529a107 100644 --- a/rpn.pod +++ b/rpn.pod @@ -198,6 +198,7 @@ Stack manipulation commands: swap exchange the last two stack elements dup duplicate last stack item undo undo last operation + edit edit the stack interactively using vi or $EDITOR Other commands: help|? show this message