star/bed/cmdline/parse.go
2025-04-26 19:33:14 +08:00

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):])
}