x-1/tour.go

226 lines
4.9 KiB
Go
Raw Normal View History

2024-01-03 19:17:37 +00:00
package main
import (
"bytes"
"errors"
"fmt"
"net/url"
"slices"
"strconv"
"strings"
)
var (
ErrEndOfTour = errors.New("you've hit the end of the tour")
ErrStartOfTour = errors.New("you're at the start of the tour")
ErrInvalidTourPos = errors.New("that's not a valid tour link")
)
type Tour struct {
Index int
Links []*url.URL
}
func parseURLs(state *BrowserState, defaultScheme, str string) ([]*url.URL, error) {
urls := []*url.URL{}
if str == "*" {
for _, link := range state.Links {
urls = append(urls, state.Url.ResolveReference(link.Target))
}
return urls, nil
}
if i := strings.IndexByte(str, '-'); i > 0 {
start, e1 := strconv.Atoi(str[:i])
end, e2 := strconv.Atoi(str[i+1:])
if e1 == nil && e2 == nil && end >= start && start >= 0 && start < len(state.Links) && end < len(state.Links) {
for _, link := range state.Links[start : end+1] {
urls = append(urls, state.Url.ResolveReference(link.Target))
}
return urls, nil
}
}
u, _, err := parseURL(str, state, defaultScheme)
if err != nil {
return nil, err
}
return []*url.URL{u}, nil
}
2024-01-17 15:55:42 +00:00
func TourAdd(state *BrowserState, targets []string) error {
2024-01-03 19:17:37 +00:00
newurls := []*url.URL{}
for _, target := range targets {
2024-01-17 15:55:42 +00:00
urls, err := parseURLs(state, state.DefaultScheme, target)
2024-01-03 19:17:37 +00:00
if err != nil {
return err
}
newurls = append(newurls, urls...)
}
state.CurrentTour.Links = append(state.CurrentTour.Links, newurls...)
if state.CurrentTour != &state.DefaultTour {
return saveTours(state.NamedTours)
}
2024-01-11 01:03:32 +00:00
state.Modal = []byte(fmt.Sprintf("Added %d urls to the tour\n", len(newurls)))
return Print(state)
2024-01-03 19:17:37 +00:00
}
2024-01-17 15:55:42 +00:00
func TourAddNext(state *BrowserState, targets []string) error {
2024-01-03 19:17:37 +00:00
newurls := []*url.URL{}
for _, target := range targets {
2024-01-17 15:55:42 +00:00
urls, err := parseURLs(state, state.DefaultScheme, target)
2024-01-03 19:17:37 +00:00
if err != nil {
return err
}
newurls = append(newurls, urls...)
}
state.CurrentTour.Links = slices.Insert(
state.CurrentTour.Links,
state.CurrentTour.Index,
newurls...,
)
if state.CurrentTour != &state.DefaultTour {
return saveTours(state.NamedTours)
}
2024-01-11 01:03:32 +00:00
state.Modal = []byte(fmt.Sprintf("Added %d urls to go next on the tour\n", len(newurls)))
return Print(state)
2024-01-03 19:17:37 +00:00
}
func TourShow(state *BrowserState) error {
tour := state.CurrentTour
buf := &bytes.Buffer{}
for i, link := range tour.Links {
mark := ""
if i == tour.Index-1 {
mark = "* "
}
if _, err := fmt.Fprintf(buf, "%s%d %s\n", mark, i, link.String()); err != nil {
return err
}
}
state.Modal = buf.Bytes()
if len(state.Modal) == 0 {
state.Modal = []byte("(empty)\n")
}
return Print(state)
}
2024-01-17 15:55:42 +00:00
func TourNext(state *BrowserState) error {
2024-01-03 19:17:37 +00:00
tour := state.CurrentTour
if tour.Index >= len(tour.Links) || len(tour.Links) == 0 {
return ErrEndOfTour
}
page := tour.Links[tour.Index]
tour.Index += 1
2024-01-17 15:55:42 +00:00
return Navigate(state, page, -1)
2024-01-03 19:17:37 +00:00
}
2024-01-17 15:55:42 +00:00
func TourPrevious(state *BrowserState) error {
2024-01-03 19:17:37 +00:00
tour := state.CurrentTour
if tour.Index <= 0 {
return ErrStartOfTour
}
tour.Index -= 1
if tour.Index <= 0 {
return ErrStartOfTour
}
page := tour.Links[tour.Index-1]
2024-01-17 15:55:42 +00:00
return Navigate(state, page, -1)
2024-01-03 19:17:37 +00:00
}
func TourClear(state *BrowserState) error {
state.CurrentTour.Index = 0
state.CurrentTour.Links = nil
if state.CurrentTour != &state.DefaultTour {
return saveTours(state.NamedTours)
}
2024-01-11 01:03:32 +00:00
state.Modal = []byte("Tour is cleared\n")
return Print(state)
2024-01-03 19:17:37 +00:00
}
func TourList(state *BrowserState) error {
buf := &bytes.Buffer{}
mark := ""
if state.CurrentTour == &state.DefaultTour {
mark = "* "
}
if _, err := fmt.Fprintf(buf, "%s(default): %d links\n", mark, len(state.DefaultTour.Links)); err != nil {
return err
}
for name, tour := range state.NamedTours {
mark = ""
if tour == state.CurrentTour {
mark = "* "
}
if _, err := fmt.Fprintf(buf, "%s%s: %d links\n", mark, name, len(tour.Links)); err != nil {
return err
}
}
state.Modal = buf.Bytes()
return Print(state)
}
2024-01-17 15:55:42 +00:00
func TourGo(state *BrowserState, pos string) error {
2024-01-03 19:17:37 +00:00
tour := state.CurrentTour
i, _ := strconv.Atoi(pos)
if i < 0 || i >= len(tour.Links) {
return ErrInvalidTourPos
}
tour.Index = i + 1
2024-01-17 15:55:42 +00:00
return Navigate(state, tour.Links[i], -1)
2024-01-03 19:17:37 +00:00
}
func TourSelect(state *BrowserState, name string) error {
2024-01-11 01:03:32 +00:00
tourName, tour, err := findTour(state, name)
if err != nil {
return err
2024-01-03 19:17:37 +00:00
}
2024-01-11 01:03:32 +00:00
state.CurrentTour = tour
state.Modal = []byte(fmt.Sprintf("Tour %s is now active\n", tourName))
return Print(state)
2024-01-03 19:17:37 +00:00
}
2024-01-11 01:03:32 +00:00
func findTour(state *BrowserState, prefix string) (string, *Tour, error) {
2024-01-03 19:17:37 +00:00
if prefix == "" {
2024-03-31 15:15:21 +00:00
return "(default)", &state.DefaultTour, nil
2024-01-03 19:17:37 +00:00
}
found := 0
var value *Tour
2024-01-11 01:03:32 +00:00
var tourName string
2024-01-03 19:17:37 +00:00
for name, tour := range state.NamedTours {
if strings.HasPrefix(name, prefix) {
found += 1
value = tour
2024-01-11 01:03:32 +00:00
tourName = name
2024-01-03 19:17:37 +00:00
}
}
switch found {
case 0:
tour := &Tour{}
state.NamedTours[prefix] = tour
2024-03-31 15:15:21 +00:00
return prefix, tour, nil
2024-01-03 19:17:37 +00:00
case 1:
2024-01-11 01:03:32 +00:00
return tourName, value, nil
2024-01-03 19:17:37 +00:00
default:
2024-01-11 01:03:32 +00:00
return "", nil, fmt.Errorf("too ambiguous - found %d matching tours", found)
2024-01-03 19:17:37 +00:00
}
}