package main import ( "bytes" "errors" "fmt" "sort" "strings" ) var ( ErrInvalidURL = errors.New("that's not a valid URL") ErrNotAMark = errors.New("that's not a known mark name") ) func MarkAdd(state *BrowserState, name, target string) error { u, _, err := parseURL(target, state, state.DefaultScheme) if err != nil { return ErrInvalidURL } state.Marks[name] = u.String() if err := saveMarks(state.Marks); err != nil { return err } state.Modal = []byte(fmt.Sprintf("Saved mark %s to %s\n", name, u.String())) return Print(state) } func MarkGo(state *BrowserState, name string) error { _, target, err := findMark(state, name) if err != nil { return err } return Go(state, target) } func MarkList(state *BrowserState) error { names := make([]string, 0, len(state.Marks)) for name := range state.Marks { names = append(names, name) } sort.Strings(names) buf := &bytes.Buffer{} for _, name := range names { _, err := fmt.Fprintf(buf, "%s: %s\n", name, state.Marks[name]) if err != nil { return err } } state.Modal = buf.Bytes() if len(state.Modal) == 0 { state.Modal = []byte("(no marks)\n") } return Print(state) } func MarkDelete(state *BrowserState, name string) error { name, _, err := findMark(state, name) if err != nil { return err } delete(state.Marks, name) if err := saveMarks(state.Marks); err != nil { return err } state.Modal = []byte(fmt.Sprintf("Deleted mark %s\n", name)) return Print(state) } func findMark(state *BrowserState, prefix string) (string, string, error) { found := 0 fullname := "" value := "" for name, target := range state.Marks { if strings.HasPrefix(name, prefix) { found += 1 value = target fullname = name } } switch found { case 0: return "", "", ErrNotAMark case 1: return fullname, value, nil default: return "", "", fmt.Errorf("too ambiguous - found %d matching marks", found) } }