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
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/peterh/liner"
|
||||
)
|
||||
|
||||
type libraryFiles []string
|
||||
@ -20,10 +22,41 @@ func (l *libraryFiles) Set(value string) error {
|
||||
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() {
|
||||
// flag setup
|
||||
var libs libraryFiles
|
||||
flag.Var(&libs, "l", "propser library file (may be repeated)")
|
||||
debug := flag.Bool("debug", false, "output debugging information")
|
||||
flag.Parse()
|
||||
|
||||
// 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")
|
||||
|
||||
// read loop
|
||||
for {
|
||||
if c.Flags["Immediate"] {
|
||||
fmt.Print("> ")
|
||||
} else {
|
||||
fmt.Print(" ")
|
||||
p := "> "
|
||||
if !c.Flags["Immediate"] {
|
||||
p = " "
|
||||
}
|
||||
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
// read line
|
||||
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())
|
||||
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) {
|
||||
fmt.Printf("bye\n")
|
||||
os.Exit(0)
|
||||
break
|
||||
} else if err != nil {
|
||||
fmt.Printf("error in evaluation: %v\n", err)
|
||||
} else if c.Flags["Immediate"] {
|
||||
|
Loading…
Reference in New Issue
Block a user