429 lines
8.7 KiB
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
|
|
}
|