56 lines
1.3 KiB
Go
56 lines
1.3 KiB
Go
package cmdline
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"b612.me/apps/b612/bed/event"
|
|
)
|
|
|
|
func parse(src string) (cmd command, r *event.Range,
|
|
bang bool, name, prefix, arg string, err error) {
|
|
prefix, arg = cutPrefixFunc(src, func(r rune) bool {
|
|
return unicode.IsSpace(r) || r == ':'
|
|
})
|
|
if arg == "" {
|
|
return
|
|
}
|
|
r, arg = event.ParseRange(arg)
|
|
name, arg = cutPrefixFunc(arg, func(r rune) bool {
|
|
return !unicode.IsSpace(r)
|
|
})
|
|
name, bang = strings.CutSuffix(name, "!")
|
|
prefix = src[:len(src)-len(arg)]
|
|
if name == "" {
|
|
// To jump by byte offset, name should not be "go[to]".
|
|
cmd = command{name: "goto", eventType: event.CursorGoto}
|
|
return
|
|
}
|
|
for _, cmd = range commands {
|
|
if matchCommand(cmd.name, name) {
|
|
arg = strings.TrimLeftFunc(arg, unicode.IsSpace)
|
|
prefix = src[:len(src)-len(arg)]
|
|
return
|
|
}
|
|
}
|
|
cmd, err = command{}, errors.New("unknown command: "+name)
|
|
return
|
|
}
|
|
|
|
func cutPrefixFunc(src string, f func(rune) bool) (string, string) {
|
|
for i, r := range src {
|
|
if !f(r) {
|
|
return src[:i], src[i:]
|
|
}
|
|
}
|
|
return src, ""
|
|
}
|
|
|
|
func matchCommand(cmd, name string) bool {
|
|
prefix, rest, _ := strings.Cut(cmd, "[")
|
|
abbr, _, _ := strings.Cut(rest, "]")
|
|
return strings.HasPrefix(name, prefix) &&
|
|
strings.HasPrefix(abbr, name[len(prefix):])
|
|
}
|