x-1/command.go

306 lines
6.1 KiB
Go

package main
import (
"errors"
"os"
"strconv"
"strings"
)
var (
ErrInvalidArgs = errors.New("bad command arguments")
ErrUnknownCommand = errors.New("don't know that one")
)
type Command struct {
Name string
Args []string
}
func ParseCommand(line string) (*Command, error) {
line = strings.TrimSpace(line)
if line == "" {
return &Command{Name: "print"}, nil
}
cmd, rest, _ := strings.Cut(line, " ")
switch line[0] {
case 'a':
if strings.HasPrefix("about", cmd) {
return &Command{Name: "about"}, nil
}
case 'r':
if strings.HasPrefix("root", cmd) {
return &Command{Name: "root"}, nil
}
if strings.HasPrefix("reload", cmd) {
return &Command{Name: "reload"}, nil
}
case 'R':
if strings.HasPrefix("Root", cmd) {
return &Command{Name: "Root"}, nil
}
case 'b':
if strings.HasPrefix("back", cmd) {
return &Command{Name: "back"}, nil
}
case 'f':
if strings.HasPrefix("forward", cmd) {
return &Command{Name: "forward"}, nil
}
case 'n':
if strings.HasPrefix("next", cmd) {
return &Command{Name: "next"}, nil
}
case 'p':
if strings.HasPrefix("print", cmd) {
return &Command{Name: "print"}, nil
}
if strings.HasPrefix("previous", cmd) {
return &Command{Name: "previous"}, nil
}
if strings.HasPrefix("pipe", cmd) {
return &Command{
Name: "pipe",
Args: []string{rest},
}, nil
}
case 'u':
if strings.HasPrefix("up", cmd) {
return &Command{Name: "up"}, nil
}
case 'g':
if strings.HasPrefix("go", cmd) {
if rest == "" {
return nil, ErrInvalidArgs
}
return &Command{Name: "go", Args: []string{rest}}, nil
}
case 'h':
if strings.HasPrefix("help", cmd) {
return &Command{
Name: "help",
Args: []string{rest},
}, nil
}
if strings.HasPrefix("history", cmd) {
return &Command{Name: "history"}, nil
}
case '|':
return &Command{
Name: "pipe",
Args: []string{strings.TrimSpace(line[1:])},
}, nil
case 's':
if strings.HasPrefix("save", cmd) {
return &Command{
Name: "save",
Args: []string{rest},
}, nil
}
case 'l':
if strings.HasPrefix("links", cmd) {
return &Command{Name: "links"}, nil
}
case 'm':
if strings.HasPrefix("mark", cmd) {
args, err := parseMarkArgs(rest)
if err != nil {
return nil, err
}
return &Command{Name: "mark", Args: args}, nil
}
case 't':
if strings.HasPrefix("tour", cmd) {
args, err := parseTourArgs(rest)
if err != nil {
return nil, err
}
return &Command{Name: "tour", Args: args}, nil
}
case 'q':
if strings.HasPrefix("quit", cmd) {
return &Command{Name: "quit"}, nil
}
}
if rest == "" {
return &Command{Name: "go", Args: []string{cmd}}, nil
}
return nil, ErrUnknownCommand
}
func parseMarkArgs(line string) ([]string, error) {
if line == "" {
return nil, ErrInvalidArgs
}
fields := strings.Fields(line)
switch fields[0][0] {
case 'a':
if strings.HasPrefix("add", fields[0]) {
fields[0] = "add"
if len(fields) != 3 {
return nil, ErrInvalidArgs
}
return fields, nil
}
case 'g':
if strings.HasPrefix("go", fields[0]) {
fields[0] = "go"
if len(fields) != 2 {
return nil, ErrInvalidArgs
}
return fields, nil
}
case 'l':
if strings.HasPrefix("list", fields[0]) {
fields[0] = "list"
if len(fields) != 1 {
return nil, ErrInvalidArgs
}
return fields, nil
}
}
if len(fields) != 1 {
return nil, ErrInvalidArgs
}
return []string{"go", fields[0]}, nil
}
func parseTourArgs(line string) ([]string, error) {
fields := strings.Fields(line)
if len(fields) == 0 {
return []string{"next"}, nil
}
switch fields[0][0] {
case 'a':
if strings.HasPrefix("add", fields[0]) {
fields[0] = "add"
if len(fields) == 1 {
return nil, ErrInvalidArgs
}
if strings.HasPrefix("next", fields[1]) {
if len(fields) == 2 {
return nil, ErrInvalidArgs
}
fields[1] = "next"
}
return fields, nil
}
case 'c':
if strings.HasPrefix("clear", fields[0]) {
fields[0] = "clear"
if len(fields) != 1 {
return nil, ErrInvalidArgs
}
return fields, nil
}
case 'n':
if strings.HasPrefix("next", fields[0]) {
fields[0] = "next"
if len(fields) != 1 {
return nil, ErrInvalidArgs
}
return fields, nil
}
case 's':
if strings.HasPrefix("select", fields[0]) {
fields[0] = "select"
if len(fields) == 1 {
return append(fields, ""), nil
}
if len(fields) != 2 {
return nil, ErrInvalidArgs
}
return fields, nil
}
if strings.HasPrefix("show", fields[0]) {
fields[0] = "show"
if len(fields) != 1 {
return nil, ErrInvalidArgs
}
return fields, nil
}
case 'l':
if strings.HasPrefix("list", fields[0]) {
fields[0] = "list"
if len(fields) != 1 {
return nil, ErrInvalidArgs
}
return fields, nil
}
case 'p':
if strings.HasPrefix("previous", fields[0]) {
fields[0] = "previous"
if len(fields) != 1 {
return nil, ErrInvalidArgs
}
return fields, nil
}
case 'g':
if strings.HasPrefix("go", fields[0]) {
fields[0] = "go"
if len(fields) != 2 {
return nil, ErrInvalidArgs
}
if _, err := strconv.Atoi(fields[1]); err != nil {
return nil, ErrInvalidArgs
}
return fields, nil
}
}
return append([]string{"add"}, fields...), nil
}
func RunCommand(conf *Config, cmd *Command, state *BrowserState) error {
switch cmd.Name {
case "about":
return About(state)
case "root":
return Root(state, true, conf)
case "Root":
return Root(state, false, conf)
case "reload":
return Reload(state, conf)
case "back":
return Back(state)
case "forward":
return Forward(state)
case "next":
return Next(state, conf)
case "previous":
return Previous(state, conf)
case "up":
return Up(state, conf)
case "go":
return Go(state, cmd.Args[0], conf)
case "help":
return Help(state, cmd.Args[0])
case "pipe":
return Pipe(state, cmd.Args[0])
case "print":
return Print(state)
case "links":
return Links(state, conf)
case "history":
return HistoryCmd(state)
case "save":
return Save(state, cmd.Args[0], conf)
case "mark":
return Mark(state, cmd.Args, conf)
case "tour":
return TourCmd(state, cmd.Args, conf)
case "quit":
os.Exit(0)
}
return ErrUnknownCommand
}