Files
tablizer/vendor/github.com/glycerine/zygomys/zygo/liner.go
2024-05-14 12:10:58 +02:00

135 lines
2.7 KiB
Go

package zygo
import (
"sort"
"strings"
"github.com/glycerine/liner"
)
// filled at init time based on BuiltinFunctions
var completion_keywords = []string{`(`}
var math_funcs = []string{`* `, `** `, `+ `, `- `, `-> `, `/ `, `< `, `<= `, `== `, `> `, `>= `, `\ `}
func init() {
// fill in our auto-complete keywords
sortme := []*SymtabE{}
for f, _ := range AllBuiltinFunctions() {
sortme = append(sortme, &SymtabE{Key: f})
}
sort.Sort(SymtabSorter(sortme))
for i := range sortme {
completion_keywords = append(completion_keywords, "("+sortme[i].Key)
}
for i := range math_funcs {
completion_keywords = append(completion_keywords, "("+math_funcs[i])
}
}
type Prompter struct {
prompt string
prompter *liner.State
origMode liner.ModeApplier
rawMode liner.ModeApplier
}
// complete phrases that start with '('
func MyWordCompleter(line string, pos int) (head string, c []string, tail string) {
beg := []rune(line[:pos])
end := line[pos:]
Q("\nline = '%s' pos=%v\n", line, pos)
Q("\nbeg = '%v'\nend = '%s'\n", string(beg), end)
// find most recent paren in beg
n := len(beg)
last := n - 1
var i int
var p int = -1
outer:
for i = last; i >= 0; i-- {
Q("\nbeg[i=%v] is '%v'\n", i, string(beg[i]))
switch beg[i] {
case ' ':
break outer
case '(':
p = i
Q("\n found paren at p = %v\n", i)
break outer
}
}
Q("p=%d\n", p)
prefix := string(beg)
extendme := ""
if p == 0 {
prefix = ""
extendme = string(beg)
} else if p > 0 {
prefix = string(beg[:p])
extendme = string(beg[p:])
}
Q("prefix = '%s'\nextendme = '%s'\n", prefix, extendme)
for _, n := range completion_keywords {
if strings.HasPrefix(n, strings.ToLower(extendme)) {
Q("n='%s' has prefix = '%s'\n", n, extendme)
c = append(c, n)
}
}
return prefix, c, end
}
func NewPrompter(prompt string) *Prompter {
origMode, err := liner.TerminalMode()
if err != nil {
panic(err)
}
p := &Prompter{
prompt: prompt,
prompter: liner.NewLiner(),
origMode: origMode,
}
rawMode, err := liner.TerminalMode()
if err != nil {
panic(err)
}
p.rawMode = rawMode
p.prompter.SetCtrlCAborts(false)
p.prompter.SetWordCompleter(liner.WordCompleter(MyWordCompleter))
return p
}
func (p *Prompter) Close() {
defer p.prompter.Close()
}
func (p *Prompter) Getline(prompt *string) (line string, err error) {
applyErr := p.rawMode.ApplyMode()
if applyErr != nil {
panic(applyErr)
}
defer func() {
applyErr := p.origMode.ApplyMode()
if applyErr != nil {
panic(applyErr)
}
}()
if prompt == nil {
line, err = p.prompter.Prompt(p.prompt)
} else {
line, err = p.prompter.Prompt(*prompt)
}
if err == nil {
p.prompter.AppendHistory(line)
return line, nil
}
return "", err
}