diff options
Diffstat (limited to 'actions.go')
| -rw-r--r-- | actions.go | 148 |
1 files changed, 95 insertions, 53 deletions
@@ -32,13 +32,22 @@ var ( ErrCantMoveRelative = errors.New("next/previous only work after navigating to a link on a page") ErrAlreadyAtTop = errors.New("already at the site root") ErrInvalidNumericLink = errors.New("no link with that number") - ErrInvalidLink = errors.New("that doesn't look like a valid URL") ErrSaveNeedsFilename = errors.New("save requires a filename argument") ErrInvalidMarkArgs = errors.New("mark what?") ErrInvalidTourArgs = errors.New("tour what?") ErrOnlyTextGemini = errors.New("that is only supported for text/gemini pages") ) +func ErrInvalidLink(invalidURL string) error { + return invalidLinkErr(invalidURL) +} + +type invalidLinkErr string + +func (ie invalidLinkErr) Error() string { + return fmt.Sprintf("that doesn't look like a valid URL: %s", string(ie)) +} + func About(_ *BrowserState) error { _, err := fmt.Println(` ... @@ -73,13 +82,13 @@ It was written by TJP and released to the public domain. return err } -func Navigate(state *BrowserState, target *url.URL, navIndex int, conf *Config) error { +func Navigate(state *BrowserState, target *url.URL, navIndex int) error { if state.Url == nil || target.String() != state.Url.String() { pushHistory(state, target, navIndex) } state.Modal = nil - return Reload(state, conf) + return Reload(state) } func pushHistory(state *BrowserState, target *url.URL, navIndex int) { @@ -91,6 +100,25 @@ func pushHistory(state *BrowserState, target *url.URL, navIndex int) { NavIndex: navIndex, } hist.Forward = state.History + + purgeOldHistory(state) +} + +func purgeOldHistory(state *BrowserState) { + if state.Depth <= state.SavedHistoryDepth { + return + } + + d := state.SavedHistoryDepth + h := state.History + for d > 0 { + h = h.Back + d -= 1 + } + + h.Body = nil + h.Formatted = "" + h.Links = nil } func gopherURL(u *url.URL) (string, sliderule.Status) { @@ -103,7 +131,7 @@ func gopherURL(u *url.URL) (string, sliderule.Status) { return clone.String(), sliderule.Status(itemType) } -func Reload(state *BrowserState, conf *Config) error { +func Reload(state *BrowserState) error { if state.Url == nil { return ErrMustBeOnAPage } @@ -144,9 +172,9 @@ func Reload(state *BrowserState, conf *Config) error { } } + if state.Url.Scheme == "gemini" { outer: - for { - if state.Url.Scheme == "gemini" { + for { switch response.Status { case gemini.StatusInput: state.Readline.SetPrompt(response.Meta.(string) + " ") @@ -178,23 +206,33 @@ outer: default: return fmt.Errorf("gemini response %s: %s", gemini.StatusName(response.Status), response.Meta.(string)) } - } else { - break } } state.DocType = docType(state.Url, response) + state.Url = returnedURL(state.Url, response) state.Body, err = io.ReadAll(response.Body) if err != nil { return err } - state.Formatted, state.Links, err = parseDoc(state.DocType, state.Body, conf) + state.Formatted, state.Links, err = parseDoc(state.DocType, state.Body, state.Config) if err != nil { return err } - return HandleResource(state, conf) + return HandleResource(state) +} + +func returnedURL(requested *url.URL, response *sliderule.Response) *url.URL { + _, gopherType := gopherURL(requested) + if gopherType == 0 { + return response.Request.URL + } + + u := *response.Request.URL + u.Path = "/" + string([]byte{byte(gopherType)}) + u.Path + return &u } func requestCtx(timeout time.Duration) (context.Context, context.CancelFunc) { @@ -206,7 +244,7 @@ func requestCtx(timeout time.Duration) (context.Context, context.CancelFunc) { } func fetch(state *BrowserState, u string, tlsConf *tls.Config) (*sliderule.Response, error) { - ctx, cancel := requestCtx(state.Timeout) + ctx, cancel := requestCtx(state.Timeout.Duration) defer cancel() tlsConf.ClientSessionCache = nil @@ -229,7 +267,7 @@ func fetch(state *BrowserState, u string, tlsConf *tls.Config) (*sliderule.Respo return nil, err } - ctx, cancel = requestCtx(state.Timeout) + ctx, cancel = requestCtx(state.Timeout.Duration) defer cancel() return sliderule.NewClient(tlsConf).Fetch(ctx, u) } else if err != nil { @@ -239,7 +277,7 @@ func fetch(state *BrowserState, u string, tlsConf *tls.Config) (*sliderule.Respo } func upload(state *BrowserState, u string, body io.Reader, tlsConf *tls.Config) (*sliderule.Response, error) { - ctx, cancel := requestCtx(state.Timeout) + ctx, cancel := requestCtx(state.Timeout.Duration) defer cancel() tlsConf.ClientSessionCache = nil @@ -261,7 +299,7 @@ func upload(state *BrowserState, u string, body io.Reader, tlsConf *tls.Config) return nil, err } - ctx, cancel = requestCtx(state.Timeout) + ctx, cancel = requestCtx(state.Timeout.Duration) defer cancel() return sliderule.NewClient(tlsConf).Upload(ctx, u, body) } else if err != nil { @@ -327,21 +365,25 @@ func back(state *BrowserState) error { if state.Back == nil { return ErrNoPreviousHistory } - state.History = state.Back state.Modal = nil + state.History = state.Back + + if state.Body == nil { + return Reload(state) + } return nil } -func Back(state *BrowserState, conf *Config, num int) error { +func Back(state *BrowserState, num int) error { for i := 0; i < num; i += 1 { if err := back(state); err != nil { return err } } - return HandleResource(state, conf) + return HandleResource(state) } -func Forward(state *BrowserState, conf *Config, num int) error { +func Forward(state *BrowserState, num int) error { for i := 0; i < num; i += 1 { if state.Forward == nil { return ErrNoNextHistory @@ -350,10 +392,10 @@ func Forward(state *BrowserState, conf *Config, num int) error { } state.Modal = nil - return HandleResource(state, conf) + return HandleResource(state) } -func Next(state *BrowserState, conf *Config) error { +func Next(state *BrowserState) error { switch state.NavIndex { case -1: return ErrCantMoveRelative @@ -369,10 +411,10 @@ func Next(state *BrowserState, conf *Config) error { u := state.Url.ResolveReference(state.Links[index].Target) - return Navigate(state, u, index, conf) + return Navigate(state, u, index) } -func Previous(state *BrowserState, conf *Config) error { +func Previous(state *BrowserState) error { switch state.NavIndex { case -1: return ErrCantMoveRelative @@ -388,10 +430,10 @@ func Previous(state *BrowserState, conf *Config) error { u := state.Url.ResolveReference(state.Links[index].Target) - return Navigate(state, u, index, conf) + return Navigate(state, u, index) } -func Root(state *BrowserState, tilde bool, conf *Config) error { +func Root(state *BrowserState, tilde bool) error { if state.Url == nil { return ErrMustBeOnAPage } @@ -411,10 +453,10 @@ func Root(state *BrowserState, tilde bool, conf *Config) error { u.Path = base } - return Navigate(state, &u, -1, conf) + return Navigate(state, &u, -1) } -func Up(state *BrowserState, conf *Config) error { +func Up(state *BrowserState) error { if state.Url == nil { return ErrMustBeOnAPage } @@ -429,16 +471,16 @@ func Up(state *BrowserState, conf *Config) error { u.RawQuery = "" u.Fragment = "" - return Navigate(state, &u, -1, conf) + return Navigate(state, &u, -1) } -func Go(state *BrowserState, dest string, conf *Config) error { - u, idx, err := parseURL(dest, state, conf.DefaultScheme) +func Go(state *BrowserState, dest string) error { + u, idx, err := parseURL(dest, state, state.DefaultScheme) if err != nil { return err } - return Navigate(state, u, idx, conf) + return Navigate(state, u, idx) } func parseURL(str string, state *BrowserState, defaultScheme string) (*url.URL, int, error) { @@ -458,7 +500,7 @@ func parseURL(str string, state *BrowserState, defaultScheme string) (*url.URL, } else if strings.HasPrefix(str, "t:") { i, err := strconv.Atoi(str[2:]) if err != nil { - return nil, -1, ErrInvalidLink + return nil, -1, ErrInvalidLink(str) } if i < 0 || i >= len(state.CurrentTour.Links) { @@ -468,10 +510,10 @@ func parseURL(str string, state *BrowserState, defaultScheme string) (*url.URL, } else if strings.HasPrefix(str, "t[") { idx := strings.IndexByte(str, ']') if idx < 0 || idx >= len(str)-2 || str[idx+1] != ':' { - return nil, -1, ErrInvalidLink + return nil, -1, ErrInvalidLink(str) } if i, err := strconv.Atoi(str[idx+2:]); err != nil { - return nil, -1, ErrInvalidLink + return nil, -1, ErrInvalidLink(str) } else { _, tour, err := findTour(state, str[2:idx]) if err != nil { @@ -499,7 +541,7 @@ func parseURL(str string, state *BrowserState, defaultScheme string) (*url.URL, i = -1 u, err = url.Parse(str) if err != nil { - return nil, -1, ErrInvalidLink + return nil, -1, ErrInvalidLink(str) } if u.Scheme == "" { u.Scheme = defaultScheme @@ -510,7 +552,7 @@ func parseURL(str string, state *BrowserState, defaultScheme string) (*url.URL, } if u.Hostname() == "" { - return nil, -1, ErrInvalidLink + return nil, -1, ErrInvalidLink(u.String()) } return u, i, nil @@ -563,12 +605,12 @@ func Print(state *BrowserState) error { return print(state) } -func HandleResource(state *BrowserState, conf *Config) error { +func HandleResource(state *BrowserState) error { if state.Modal != nil { return Print(state) } - if handler, ok := conf.Handlers[state.DocType]; ok { + if handler, ok := state.Handlers[state.DocType]; ok { return Pipe(state, handler) } @@ -577,10 +619,10 @@ func HandleResource(state *BrowserState, conf *Config) error { return print(state) } - return Save(state, path.Base(state.Url.Path), conf) + return Save(state, path.Base(state.Url.Path)) } -func Outline(state *BrowserState, conf *Config) error { +func Outline(state *BrowserState) error { if state.Body == nil { return ErrMustBeOnAPage } @@ -604,7 +646,7 @@ func Outline(state *BrowserState, conf *Config) error { } } - formatted, _, err := parseGemtextDoc(b.Bytes(), conf.SoftWrap) + formatted, _, err := parseGemtextDoc(b.Bytes(), state.SoftWrap) if err != nil { return err } @@ -617,7 +659,7 @@ func Outline(state *BrowserState, conf *Config) error { return Print(state) } -func Links(state *BrowserState, conf *Config) error { +func Links(state *BrowserState) error { if state.Links == nil { return ErrMustBeOnAPage } @@ -626,7 +668,7 @@ func Links(state *BrowserState, conf *Config) error { for _, link := range state.Links { fmt.Fprintf(buf, "=> %s %s\n", link.Target.String(), link.Text) } - formatted, _, err := parseDoc("text/gemini", buf.Bytes(), conf) + formatted, _, err := parseDoc("text/gemini", buf.Bytes(), state.Config) if err != nil { return err } @@ -666,7 +708,7 @@ func HistoryCmd(state *BrowserState) error { return Print(state) } -func Save(state *BrowserState, filename string, conf *Config) error { +func Save(state *BrowserState, filename string) error { if state.Body == nil { return ErrMustBeOnAPage } @@ -674,7 +716,7 @@ func Save(state *BrowserState, filename string, conf *Config) error { return ErrSaveNeedsFilename } - p := filepath.Join(conf.DownloadFolder, filename) + p := filepath.Join(state.DownloadFolder, filename) _, err := os.Stat(p) pbase := p i := 1 @@ -691,12 +733,12 @@ func Save(state *BrowserState, filename string, conf *Config) error { return Print(state) } -func Mark(state *BrowserState, args []string, conf *Config) error { +func Mark(state *BrowserState, args []string) error { switch args[0] { case "add": - return MarkAdd(state, conf, args[1], args[2]) + return MarkAdd(state, args[1], args[2]) case "go": - return MarkGo(state, conf, args[1]) + return MarkGo(state, args[1]) case "list": return MarkList(state) case "delete": @@ -706,27 +748,27 @@ func Mark(state *BrowserState, args []string, conf *Config) error { return ErrInvalidMarkArgs } -func TourCmd(state *BrowserState, args []string, conf *Config) error { +func TourCmd(state *BrowserState, args []string) error { switch args[0] { case "add": if args[1] == "next" { - return TourAddNext(state, conf, args[2:]) + return TourAddNext(state, args[2:]) } - return TourAdd(state, conf, args[1:]) + return TourAdd(state, args[1:]) case "show": return TourShow(state) case "select": return TourSelect(state, args[1]) case "next": - return TourNext(state, conf) + return TourNext(state) case "previous": - return TourPrevious(state, conf) + return TourPrevious(state) case "clear": return TourClear(state) case "list": return TourList(state) case "go": - return TourGo(state, conf, args[1]) + return TourGo(state, args[1]) } return ErrInvalidTourArgs |
