x-1/command.go

429 lines
8.7 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: "default"}, 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) {
fields := strings.Fields(rest)
switch len(fields) {
case 0:
return &Command{Name: "back"}, nil
case 1:
if _, err := strconv.Atoi(fields[0]); err != nil {
return nil, ErrInvalidArgs
}
return &Command{Name: "back", Args: fields}, nil
default:
return nil, ErrInvalidArgs
}
}
case 'f':
if strings.HasPrefix("forward", cmd) {
fields := strings.Fields(rest)
switch len(fields) {
case 0:
return &Command{Name: "forward"}, nil
case 1:
if _, err := strconv.Atoi(fields[0]); err != nil {
return nil, ErrInvalidArgs
}
return &Command{Name: "forward", Args: fields}, nil
default:
return nil, ErrInvalidArgs
}
}
case 'i':
if strings.HasPrefix("identity", cmd) {
args, err := parseIdentityArgs(rest)
if err != nil {
return nil, err
}
return &Command{Name: "identity", Args: args}, nil
}
case 'n':
if strings.HasPrefix("next", cmd) {
return &Command{Name: "next"}, nil
}
case 'o':
if strings.HasPrefix("outline", cmd) {
return &Command{Name: "outline"}, 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 '?':
return &Command{Name: "help", Args: []string{""}}, 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) {
fields := strings.Fields(line)
if len(fields) == 0 {
return []string{"list"}, nil
}
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
}
case 'd':
if strings.HasPrefix("delete", fields[0]) {
fields[0] = "delete"
if len(fields) != 2 {
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 parseIdentityArgs(line string) ([]string, error) {
fields := strings.Fields(line)
if len(fields) == 0 {
return []string{"list"}, nil
}
switch fields[0][0] {
case 'c':
if strings.HasPrefix("create", fields[0]) {
fields[0] = "create"
if len(fields) != 2 {
return nil, ErrInvalidArgs
}
return fields, nil
}
case 'l':
if strings.HasPrefix("list", fields[0]) {
if len(fields) != 1 {
return nil, ErrInvalidArgs
}
return []string{"list"}, nil
}
case 'd':
if strings.HasPrefix("delete", fields[0]) {
fields[0] = "delete"
if len(fields) != 2 {
return nil, ErrInvalidArgs
}
return fields, nil
}
case 'u':
if strings.HasPrefix("use", fields[0]) {
fields[0] = "use"
if len(fields) != 4 {
return nil, ErrInvalidArgs
}
switch fields[2][0] {
case 'd':
if !strings.HasPrefix("domain", fields[2]) {
return nil, ErrInvalidArgs
}
fields[2] = "domain"
case 'f':
if !strings.HasPrefix("folder", fields[2]) {
return nil, ErrInvalidArgs
}
fields[2] = "folder"
case 'p':
if !strings.HasPrefix("page", fields[2]) {
return nil, ErrInvalidArgs
}
fields[2] = "page"
default:
return nil, ErrInvalidArgs
}
return fields, nil
}
}
return nil, ErrInvalidArgs
}
func RunCommand(cmd *Command, state *BrowserState) error {
switch cmd.Name {
case "about":
return About(state)
case "root":
return Root(state, true)
case "Root":
return Root(state, false)
case "reload":
return Reload(state)
case "back":
num := 1
if len(cmd.Args) == 1 {
num, _ = strconv.Atoi(cmd.Args[0])
}
return Back(state, num)
case "forward":
num := 1
if len(cmd.Args) == 1 {
num, _ = strconv.Atoi(cmd.Args[0])
}
return Forward(state, num)
case "next":
return Next(state)
case "previous":
return Previous(state)
case "up":
return Up(state)
case "go":
return Go(state, cmd.Args[0])
case "help":
return Help(state, cmd.Args[0])
case "outline":
return Outline(state)
case "pipe":
return Pipe(state, cmd.Args[0])
case "default":
return HandleResource(state)
case "print":
return Print(state)
case "links":
return Links(state)
case "history":
return HistoryCmd(state)
case "save":
return Save(state, cmd.Args[0])
case "mark":
return Mark(state, cmd.Args)
case "tour":
return TourCmd(state, cmd.Args)
case "identity":
return IdentityCmd(state, cmd.Args)
case "quit":
os.Exit(0)
}
return ErrUnknownCommand
}