-
Notifications
You must be signed in to change notification settings - Fork 1
/
builtin.go
117 lines (97 loc) · 2.7 KB
/
builtin.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package main
import (
"context"
"fmt"
"os"
"strings"
"github.com/charmbracelet/lipgloss"
"github.com/shafreeck/cortana"
"github.com/shafreeck/guru/tui"
)
// the builtin commands
type CommandListener interface {
OnCommand(args []string) // args[0] is the command name
}
type BuiltinCommand struct {
*cortana.Cortana
completes *Completion
listeners map[CommandListener]struct{}
text string
}
func (c *BuiltinCommand) Launch(args []string) string {
cmd := c.SearchCommand(args)
if cmd == nil {
usage := lipgloss.NewStyle().Foreground(
lipgloss.AdaptiveColor{Dark: "#79b3ec", Light: "#1d73c9"}).
Render(c.UsageString())
fmt.Fprint(tui.Stdout, usage)
return ""
}
cmd.Proc()
text := c.text
c.text = "" // clear the state
for l := range builtins.listeners {
l.OnCommand(args)
}
return text
}
func (c *BuiltinCommand) AddListener(l CommandListener) {
c.listeners[l] = struct{}{}
}
func (c *BuiltinCommand) RemoveListener(l CommandListener) {
delete(c.listeners, l)
}
// Parse the args and set usgae if meet --help/-h
func (c *BuiltinCommand) Parse(v interface{}) (usage bool) {
c.Cortana.Parse(v, cortana.OnUsage(func(usageString string) {
c.Usage()
usage = true
}))
return
}
type BuiltinCommandFunc func() string
func (c *BuiltinCommand) AddCommand(path string, cmd BuiltinCommandFunc,
breif string, complete ...CompleteCommand) {
c.Cortana.AddCommand(path, builtin(cmd), breif)
if len(complete) == 0 {
c.completes.AddCommand(path, func(s []rune, pos int) ([][]rune, int) { return nil, 0 })
return
}
c.completes.AddCommand(path, complete[0])
}
func (c *BuiltinCommand) Alias(name, definition string) {
c.Cortana.Alias(name, definition)
c.completes.Alias(name, definition)
}
func builtin(f func() string) func() {
return func() {
builtins.text = f()
}
}
var builtins = BuiltinCommand{Cortana: cortana.New(cortana.ExitOnError(false)),
completes: completes, listeners: make(map[CommandListener]struct{})}
func init() {
// add commands
builtins.AddCommand(":exit", exit, "exit guru")
builtins.AddCommand(":read", read, "read from stdin with a textarea")
builtins.AddCommand(":help", func() string {
return builtins.Launch(nil) // launch none commonds, so it print usage and return ""
}, "help for commands")
// add aliases
builtins.Alias(":quit", ":exit")
// add completion handler for system commands
completes.AddCommand("$", sysCommandComplete)
}
func exit() string {
os.Exit(0)
return ""
}
func read() string {
opts := struct {
Prompt []string `cortana:"prompt"`
}{}
builtins.Parse(&opts)
// no error in this model
text, _ := tui.Display[tui.Model[string], string](context.Background(), tui.NewTextAreaModel())
return strings.Join(opts.Prompt, " ") + "\n" + text
}