add a nice readline experience (with history!)
This commit is contained in:
parent
b7c7e02697
commit
8e33e13ffc
2
go.mod
2
go.mod
@ -1,3 +1,5 @@
|
|||||||
module git.yetaga.in/alazyreader/prosper
|
module git.yetaga.in/alazyreader/prosper
|
||||||
|
|
||||||
go 1.15
|
go 1.15
|
||||||
|
|
||||||
|
require github.com/peterh/liner v1.2.1
|
||||||
|
4
go.sum
Normal file
4
go.sum
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
|
||||||
|
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/peterh/liner v1.2.1 h1:O4BlKaq/LWu6VRWmol4ByWfzx6MfXc5Op5HETyIy5yg=
|
||||||
|
github.com/peterh/liner v1.2.1/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
|
88
main.go
88
main.go
@ -1,12 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/peterh/liner"
|
||||||
)
|
)
|
||||||
|
|
||||||
type libraryFiles []string
|
type libraryFiles []string
|
||||||
@ -20,10 +22,41 @@ func (l *libraryFiles) Set(value string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func historyFn() string {
|
||||||
|
dataHome := os.Getenv("XDG_DATA_HOME")
|
||||||
|
home := os.Getenv("HOME")
|
||||||
|
if dataHome == "" {
|
||||||
|
dataHome = filepath.Join(home, ".local/share/")
|
||||||
|
}
|
||||||
|
prosperDir := filepath.Join(dataHome, "prosper")
|
||||||
|
os.MkdirAll(prosperDir, 0755)
|
||||||
|
return filepath.Join(prosperDir, ".history")
|
||||||
|
}
|
||||||
|
|
||||||
|
func completer(d Dictionary) liner.Completer {
|
||||||
|
return func(line string) []string {
|
||||||
|
candidates := []string{}
|
||||||
|
words := strings.Split(line, " ")
|
||||||
|
for w := range d {
|
||||||
|
if strings.HasPrefix(w, words[len(words)-1]) {
|
||||||
|
// must reconstruct the _full_ line to return for the completer
|
||||||
|
pref := strings.Join(words[:len(words)-1], " ")
|
||||||
|
if len(pref) != 0 {
|
||||||
|
candidates = append(candidates, pref+" "+w)
|
||||||
|
} else {
|
||||||
|
candidates = append(candidates, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return candidates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// flag setup
|
// flag setup
|
||||||
var libs libraryFiles
|
var libs libraryFiles
|
||||||
flag.Var(&libs, "l", "propser library file (may be repeated)")
|
flag.Var(&libs, "l", "propser library file (may be repeated)")
|
||||||
|
debug := flag.Bool("debug", false, "output debugging information")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// create main context
|
// create main context
|
||||||
@ -64,27 +97,60 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
// set up liner
|
||||||
|
line := liner.NewLiner()
|
||||||
|
line.SetCtrlCAborts(true)
|
||||||
|
line.SetCompleter(completer(dict))
|
||||||
|
|
||||||
|
historyFile := historyFn()
|
||||||
|
|
||||||
|
if f, err := os.Open(historyFile); err == nil {
|
||||||
|
_, err := line.ReadHistory(f)
|
||||||
|
if err != nil && *debug {
|
||||||
|
fmt.Printf("error reading line history: %v", err)
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if f, err := os.Create(historyFile); err != nil {
|
||||||
|
if *debug {
|
||||||
|
fmt.Printf("Error writing history file: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
line.WriteHistory(f)
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
line.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Welcome banner
|
||||||
fmt.Print("prosper\n")
|
fmt.Print("prosper\n")
|
||||||
|
|
||||||
// read loop
|
// read loop
|
||||||
for {
|
for {
|
||||||
if c.Flags["Immediate"] {
|
p := "> "
|
||||||
fmt.Print("> ")
|
if !c.Flags["Immediate"] {
|
||||||
} else {
|
p = " "
|
||||||
fmt.Print(" ")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
line, err := reader.ReadString('\n')
|
// read line
|
||||||
if err != nil {
|
l, err := line.Prompt(p)
|
||||||
|
if err == liner.ErrPromptAborted {
|
||||||
|
fmt.Println("ctrl-C caught (try BYE)")
|
||||||
|
continue
|
||||||
|
} else if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
line = strings.TrimSpace(line)
|
|
||||||
err = c.Eval(line + " ") // append a space to make sure we always close out our parse loop
|
// parse line
|
||||||
|
l = strings.TrimSpace(l)
|
||||||
|
line.AppendHistory(l)
|
||||||
|
err = c.Eval(l + " ") // append a space to make sure we always close out our parse loop
|
||||||
if errors.Is(err, ErrExit) {
|
if errors.Is(err, ErrExit) {
|
||||||
fmt.Printf("bye\n")
|
fmt.Printf("bye\n")
|
||||||
os.Exit(0)
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
fmt.Printf("error in evaluation: %v\n", err)
|
fmt.Printf("error in evaluation: %v\n", err)
|
||||||
} else if c.Flags["Immediate"] {
|
} else if c.Flags["Immediate"] {
|
||||||
|
Loading…
Reference in New Issue
Block a user