fixes
This commit is contained in:
parent
b173ca9cb2
commit
dfebc9013b
62
actions.go
62
actions.go
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -14,6 +15,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"tildegit.org/tjp/sliderule"
|
"tildegit.org/tjp/sliderule"
|
||||||
"tildegit.org/tjp/sliderule/gemini"
|
"tildegit.org/tjp/sliderule/gemini"
|
||||||
|
@ -72,22 +74,25 @@ It was written by TJP and released to the public domain.
|
||||||
}
|
}
|
||||||
|
|
||||||
func Navigate(state *BrowserState, target *url.URL, navIndex int, conf *Config) error {
|
func Navigate(state *BrowserState, target *url.URL, navIndex int, conf *Config) error {
|
||||||
hist := state.History
|
if state.Url == nil || target.String() != state.Url.String() {
|
||||||
|
pushHistory(state, target, navIndex)
|
||||||
if hist.Url == nil || target.String() != hist.Url.String() {
|
|
||||||
state.History = &History{
|
|
||||||
Url: target,
|
|
||||||
Depth: hist.Depth + 1,
|
|
||||||
Back: hist,
|
|
||||||
NavIndex: navIndex,
|
|
||||||
}
|
|
||||||
hist.Forward = state.History
|
|
||||||
}
|
}
|
||||||
state.Modal = nil
|
state.Modal = nil
|
||||||
|
|
||||||
return Reload(state, conf)
|
return Reload(state, conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pushHistory(state *BrowserState, target *url.URL, navIndex int) {
|
||||||
|
hist := state.History
|
||||||
|
state.History = &History{
|
||||||
|
Url: target,
|
||||||
|
Depth: hist.Depth + 1,
|
||||||
|
Back: hist,
|
||||||
|
NavIndex: navIndex,
|
||||||
|
}
|
||||||
|
hist.Forward = state.History
|
||||||
|
}
|
||||||
|
|
||||||
func gopherURL(u *url.URL) (string, sliderule.Status) {
|
func gopherURL(u *url.URL) (string, sliderule.Status) {
|
||||||
if u.Scheme != "gopher" || len(u.Path) < 2 || !strings.HasPrefix(u.Path, "/") {
|
if u.Scheme != "gopher" || len(u.Path) < 2 || !strings.HasPrefix(u.Path, "/") {
|
||||||
return u.String(), 0
|
return u.String(), 0
|
||||||
|
@ -173,6 +178,8 @@ outer:
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("gemini response %s: %s", gemini.StatusName(response.Status), response.Meta.(string))
|
return fmt.Errorf("gemini response %s: %s", gemini.StatusName(response.Status), response.Meta.(string))
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,10 +197,22 @@ outer:
|
||||||
return HandleResource(state, conf)
|
return HandleResource(state, conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func requestCtx(timeout time.Duration) (context.Context, context.CancelFunc) {
|
||||||
|
ctx := context.Background()
|
||||||
|
if timeout > 0 {
|
||||||
|
return context.WithTimeout(ctx, timeout)
|
||||||
|
}
|
||||||
|
return ctx, func() {}
|
||||||
|
}
|
||||||
|
|
||||||
func fetch(state *BrowserState, u string, tlsConf *tls.Config) (*sliderule.Response, error) {
|
func fetch(state *BrowserState, u string, tlsConf *tls.Config) (*sliderule.Response, error) {
|
||||||
|
ctx, cancel := requestCtx(state.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
tlsConf.ClientSessionCache = nil
|
tlsConf.ClientSessionCache = nil
|
||||||
response, err := sliderule.NewClient(tlsConf).Fetch(u)
|
response, err := sliderule.NewClient(tlsConf).Fetch(ctx, u)
|
||||||
var tofuErr *TOFUViolation
|
var tofuErr *TOFUViolation
|
||||||
|
|
||||||
if errors.As(err, &tofuErr) {
|
if errors.As(err, &tofuErr) {
|
||||||
writeError(err.Error())
|
writeError(err.Error())
|
||||||
state.Readline.SetPrompt("Trust new certificate instead (y/n)? [n] ")
|
state.Readline.SetPrompt("Trust new certificate instead (y/n)? [n] ")
|
||||||
|
@ -210,7 +229,9 @@ func fetch(state *BrowserState, u string, tlsConf *tls.Config) (*sliderule.Respo
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return sliderule.NewClient(tlsConf).Fetch(u)
|
ctx, cancel = requestCtx(state.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
return sliderule.NewClient(tlsConf).Fetch(ctx, u)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -218,8 +239,11 @@ 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) {
|
func upload(state *BrowserState, u string, body io.Reader, tlsConf *tls.Config) (*sliderule.Response, error) {
|
||||||
|
ctx, cancel := requestCtx(state.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
tlsConf.ClientSessionCache = nil
|
tlsConf.ClientSessionCache = nil
|
||||||
response, err := sliderule.NewClient(tlsConf).Upload(u, body)
|
response, err := sliderule.NewClient(tlsConf).Upload(ctx, u, body)
|
||||||
var tofuErr *TOFUViolation
|
var tofuErr *TOFUViolation
|
||||||
if errors.As(err, &tofuErr) {
|
if errors.As(err, &tofuErr) {
|
||||||
writeError(err.Error())
|
writeError(err.Error())
|
||||||
|
@ -237,7 +261,9 @@ func upload(state *BrowserState, u string, body io.Reader, tlsConf *tls.Config)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return sliderule.NewClient(tlsConf).Upload(u, body)
|
ctx, cancel = requestCtx(state.Timeout)
|
||||||
|
defer cancel()
|
||||||
|
return sliderule.NewClient(tlsConf).Upload(ctx, u, body)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -306,16 +332,16 @@ func back(state *BrowserState) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Back(state *BrowserState, num int) error {
|
func Back(state *BrowserState, conf *Config, num int) error {
|
||||||
for i := 0; i < num; i += 1 {
|
for i := 0; i < num; i += 1 {
|
||||||
if err := back(state); err != nil {
|
if err := back(state); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return print(state)
|
return HandleResource(state, conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Forward(state *BrowserState, num int) error {
|
func Forward(state *BrowserState, conf *Config, num int) error {
|
||||||
for i := 0; i < num; i += 1 {
|
for i := 0; i < num; i += 1 {
|
||||||
if state.Forward == nil {
|
if state.Forward == nil {
|
||||||
return ErrNoNextHistory
|
return ErrNoNextHistory
|
||||||
|
@ -324,7 +350,7 @@ func Forward(state *BrowserState, num int) error {
|
||||||
}
|
}
|
||||||
state.Modal = nil
|
state.Modal = nil
|
||||||
|
|
||||||
return print(state)
|
return HandleResource(state, conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Next(state *BrowserState, conf *Config) error {
|
func Next(state *BrowserState, conf *Config) error {
|
||||||
|
|
|
@ -383,13 +383,13 @@ func RunCommand(conf *Config, cmd *Command, state *BrowserState) error {
|
||||||
if len(cmd.Args) == 1 {
|
if len(cmd.Args) == 1 {
|
||||||
num, _ = strconv.Atoi(cmd.Args[0])
|
num, _ = strconv.Atoi(cmd.Args[0])
|
||||||
}
|
}
|
||||||
return Back(state, num)
|
return Back(state, conf, num)
|
||||||
case "forward":
|
case "forward":
|
||||||
num := 1
|
num := 1
|
||||||
if len(cmd.Args) == 1 {
|
if len(cmd.Args) == 1 {
|
||||||
num, _ = strconv.Atoi(cmd.Args[0])
|
num, _ = strconv.Atoi(cmd.Args[0])
|
||||||
}
|
}
|
||||||
return Forward(state, num)
|
return Forward(state, conf, num)
|
||||||
case "next":
|
case "next":
|
||||||
return Next(state, conf)
|
return Next(state, conf)
|
||||||
case "previous":
|
case "previous":
|
||||||
|
|
25
files.go
25
files.go
|
@ -11,17 +11,19 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConfigMain struct {
|
type ConfigMain struct {
|
||||||
DefaultScheme string `toml:"default_scheme"`
|
DefaultScheme string `toml:"default_scheme"`
|
||||||
SoftWrap int `toml:"soft_wrap"`
|
SoftWrap int `toml:"soft_wrap"`
|
||||||
DownloadFolder string `toml:"download_folder"`
|
DownloadFolder string `toml:"download_folder"`
|
||||||
VimKeys bool `toml:"vim_keys"`
|
VimKeys bool `toml:"vim_keys"`
|
||||||
Quiet bool `toml:"quiet"`
|
Quiet bool `toml:"quiet"`
|
||||||
Pager string `toml:"pager"`
|
Pager string `toml:"pager"`
|
||||||
|
Timeout duration `toml:"duration"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -30,6 +32,14 @@ type Config struct {
|
||||||
Handlers map[string]string `toml:"handlers"`
|
Handlers map[string]string `toml:"handlers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type duration struct{ time.Duration }
|
||||||
|
|
||||||
|
func (d *duration) UnmarshalText(text []byte) error {
|
||||||
|
var err error
|
||||||
|
d.Duration, err = time.ParseDuration(string(text))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func getConfig() (*Config, error) {
|
func getConfig() (*Config, error) {
|
||||||
home := os.Getenv("HOME")
|
home := os.Getenv("HOME")
|
||||||
path := os.Getenv("XDG_CONFIG_HOME")
|
path := os.Getenv("XDG_CONFIG_HOME")
|
||||||
|
@ -50,6 +60,9 @@ func getConfig() (*Config, error) {
|
||||||
DownloadFolder: home,
|
DownloadFolder: home,
|
||||||
Quiet: false,
|
Quiet: false,
|
||||||
Pager: "auto",
|
Pager: "auto",
|
||||||
|
Timeout: duration{
|
||||||
|
time.Duration(10 * time.Second),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Handlers: map[string]string{},
|
Handlers: map[string]string{},
|
||||||
}
|
}
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -5,7 +5,7 @@ go 1.21.0
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.3.2
|
github.com/BurntSushi/toml v1.3.2
|
||||||
github.com/chzyer/readline v1.5.1
|
github.com/chzyer/readline v1.5.1
|
||||||
tildegit.org/tjp/sliderule v1.6.2-0.20240110181009-de1490808fa6
|
tildegit.org/tjp/sliderule v1.6.2-0.20240115025310-751f423f11bf
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -20,5 +20,5 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40W
|
||||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
tildegit.org/tjp/sliderule v1.6.2-0.20240110181009-de1490808fa6 h1:nVGF/L3NI+dqmlEdagFFjZZabPMPOocr1zVW1qBfGVg=
|
tildegit.org/tjp/sliderule v1.6.2-0.20240115025310-751f423f11bf h1:p0MqM4m/LcgLjRH24OOV+oNOu/8+alABAdI6kLantvE=
|
||||||
tildegit.org/tjp/sliderule v1.6.2-0.20240110181009-de1490808fa6/go.mod h1:opdo8E25iS9X9pNismM8U7pCH8XO0PdRIIhdADn8Uik=
|
tildegit.org/tjp/sliderule v1.6.2-0.20240115025310-751f423f11bf/go.mod h1:opdo8E25iS9X9pNismM8U7pCH8XO0PdRIIhdADn8Uik=
|
||||||
|
|
9
help.go
9
help.go
|
@ -64,7 +64,8 @@ Consult "help COMMAND" for more information on any single command.
|
||||||
`[1:],
|
`[1:],
|
||||||
|
|
||||||
"cli": `
|
"cli": `
|
||||||
x-1 [-c COMMANDS] [URL]
|
x-1 -h
|
||||||
|
x-1 [-q] [-c COMMANDS] [URL]
|
||||||
-----------------------
|
-----------------------
|
||||||
With no arguments or flags, x-1 will just display the prompt and begin
|
With no arguments or flags, x-1 will just display the prompt and begin
|
||||||
executing your commands. Use the "help" command to begin exploring this
|
executing your commands. Use the "help" command to begin exploring this
|
||||||
|
@ -75,6 +76,9 @@ provided by separating them with a semi-colon ';') and then exit. In
|
||||||
this mode it also forces quiet mode, in which it doesn't automatically
|
this mode it also forces quiet mode, in which it doesn't automatically
|
||||||
print loaded pages.
|
print loaded pages.
|
||||||
|
|
||||||
|
The -q flag will force quiet mode, overriding "quiet" in the
|
||||||
|
configuration file.
|
||||||
|
|
||||||
With a URL argument, it will begin an interactive prompt session by
|
With a URL argument, it will begin an interactive prompt session by
|
||||||
loading the requested url.
|
loading the requested url.
|
||||||
`[1:],
|
`[1:],
|
||||||
|
@ -122,6 +126,9 @@ The section "[main]" contains general configuration options:
|
||||||
will pipe every page printed through less(1), "never" will not, and
|
will pipe every page printed through less(1), "never" will not, and
|
||||||
"auto" will pipe it through "less -F", which skips the pager when
|
"auto" will pipe it through "less -F", which skips the pager when
|
||||||
the output fits on a single screen anyway.
|
the output fits on a single screen anyway.
|
||||||
|
* timeout (string): Maximum time to wait trying to make a connection
|
||||||
|
to the host. Should be in the form with a unit suffix, like "15s" or
|
||||||
|
"500ms". The default is "10s".
|
||||||
|
|
||||||
`[1:],
|
`[1:],
|
||||||
|
|
||||||
|
|
5
main.go
5
main.go
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
var cmdMode = flag.String("c", "", "")
|
var cmdMode = flag.String("c", "", "")
|
||||||
var helpMode = flag.Bool("h", false, "")
|
var helpMode = flag.Bool("h", false, "")
|
||||||
|
var quietMode = flag.Bool("q", false, "")
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
conf, err := getConfig()
|
conf, err := getConfig()
|
||||||
|
@ -62,6 +63,10 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *quietMode {
|
||||||
|
state.Quiet = true
|
||||||
|
}
|
||||||
|
|
||||||
rl, err := readline.New(Prompt)
|
rl, err := readline.New(Prompt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|
11
state.go
11
state.go
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/chzyer/readline"
|
"github.com/chzyer/readline"
|
||||||
)
|
)
|
||||||
|
@ -19,8 +20,9 @@ type BrowserState struct {
|
||||||
DefaultTour Tour
|
DefaultTour Tour
|
||||||
CurrentTour *Tour
|
CurrentTour *Tour
|
||||||
|
|
||||||
Quiet bool
|
Quiet bool
|
||||||
Pager string
|
Pager string
|
||||||
|
Timeout time.Duration
|
||||||
|
|
||||||
Readline *readline.Instance
|
Readline *readline.Instance
|
||||||
}
|
}
|
||||||
|
@ -58,8 +60,9 @@ func NewBrowserState(conf *Config) *BrowserState {
|
||||||
NavIndex: -1,
|
NavIndex: -1,
|
||||||
},
|
},
|
||||||
|
|
||||||
Quiet: conf.Quiet,
|
Quiet: conf.Quiet,
|
||||||
Pager: conf.Pager,
|
Pager: conf.Pager,
|
||||||
|
Timeout: conf.Timeout.Duration,
|
||||||
}
|
}
|
||||||
state.CurrentTour = &state.DefaultTour
|
state.CurrentTour = &state.DefaultTour
|
||||||
return state
|
return state
|
||||||
|
|
Loading…
Reference in New Issue