handle input types
* spartan prompts * gemini [sensitive]input responses * gopher search servers
This commit is contained in:
parent
1c96ee6e4c
commit
684539c70d
122
actions.go
122
actions.go
|
@ -14,6 +14,8 @@ import (
|
|||
"syscall"
|
||||
|
||||
"tildegit.org/tjp/sliderule"
|
||||
"tildegit.org/tjp/sliderule/gemini"
|
||||
"tildegit.org/tjp/sliderule/gopher"
|
||||
)
|
||||
|
||||
var client sliderule.Client
|
||||
|
@ -103,10 +105,66 @@ func Reload(state *BrowserState, conf *Config) error {
|
|||
return ErrMustBeOnAPage
|
||||
}
|
||||
|
||||
urlStr, _ := gopherURL(state.Url)
|
||||
response, err := client.Fetch(urlStr)
|
||||
if err != nil {
|
||||
return err
|
||||
urlStr, itemType := gopherURL(state.Url)
|
||||
if itemType == gopher.SearchType && state.Url.RawQuery == "" {
|
||||
state.Readline.SetPrompt("query: ")
|
||||
line, err := state.Readline.Readline()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
state.Url.RawQuery = url.QueryEscape(strings.TrimRight(line, "\n"))
|
||||
urlStr, _ = gopherURL(state.Url)
|
||||
}
|
||||
|
||||
var response *sliderule.Response
|
||||
var err error
|
||||
if state.Url.Scheme == "spartan" && state.Url.Fragment == "prompt" {
|
||||
input, err := externalMessage()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body := io.LimitReader(bytes.NewBuffer(input), int64(len(input)))
|
||||
|
||||
state.Url.Fragment = ""
|
||||
response, err = client.Upload(state.Url.String(), body)
|
||||
state.Url.Fragment = "prompt"
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
response, err = client.Fetch(urlStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if state.Url.Scheme == "gemini" {
|
||||
switch response.Status {
|
||||
case gemini.StatusInput:
|
||||
state.Readline.SetPrompt("input: ")
|
||||
line, err := state.Readline.Readline()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
state.Url.RawQuery = url.QueryEscape(strings.TrimRight(line, "\n"))
|
||||
response, err = client.Fetch(state.Url.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case gemini.StatusSensitiveInput:
|
||||
line, err := state.Readline.ReadPassword("password: ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
state.Url.RawQuery = url.QueryEscape(strings.TrimRight(string(line), "\n"))
|
||||
response, err = client.Fetch(state.Url.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.DocType = docType(state.Url, response)
|
||||
|
@ -123,6 +181,59 @@ func Reload(state *BrowserState, conf *Config) error {
|
|||
return print(state)
|
||||
}
|
||||
|
||||
func externalMessage() ([]byte, error) {
|
||||
tmpf, err := os.CreateTemp("", "*")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = os.Remove(tmpf.Name()) }()
|
||||
|
||||
prompt := []byte("# enter input below (this line will be ignored)\n")
|
||||
|
||||
err = (func() error {
|
||||
defer func() { _ = tmpf.Close() }()
|
||||
|
||||
if _, err := tmpf.Write(prompt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
editor := os.Getenv("EDITOR")
|
||||
if editor == "" {
|
||||
editor = "vi"
|
||||
}
|
||||
editor, err = exec.LookPath(editor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd := exec.Command(editor, tmpf.Name())
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmpf, err = os.Open(tmpf.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = tmpf.Close() }()
|
||||
|
||||
buf, err := io.ReadAll(tmpf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bytes.TrimPrefix(buf, prompt), nil
|
||||
}
|
||||
|
||||
func back(state *BrowserState) error {
|
||||
if state.Back == nil {
|
||||
return ErrNoPreviousHistory
|
||||
|
@ -287,6 +398,9 @@ func parseURL(str string, state *BrowserState, defaultScheme string) (*url.URL,
|
|||
return nil, -1, ErrInvalidNumericLink
|
||||
}
|
||||
u = state.Links[i].Target
|
||||
if state.Links[i].Prompt {
|
||||
u.Fragment = "prompt"
|
||||
}
|
||||
} else {
|
||||
i = -1
|
||||
u, err = url.Parse(str)
|
||||
|
|
28
handlers.go
28
handlers.go
|
@ -12,12 +12,13 @@ import (
|
|||
"tildegit.org/tjp/sliderule/gemini/gemtext"
|
||||
"tildegit.org/tjp/sliderule/gopher"
|
||||
"tildegit.org/tjp/sliderule/gopher/gophermap"
|
||||
"tildegit.org/tjp/sliderule/spartan"
|
||||
)
|
||||
|
||||
func docType(u *url.URL, response *sliderule.Response) string {
|
||||
_, gopherType := gopherURL(u)
|
||||
switch gopherType {
|
||||
case gopher.MenuType:
|
||||
case gopher.MenuType, gopher.SearchType:
|
||||
return "text/x-gophermap"
|
||||
case gopher.TextFileType, gopher.ErrorType, gopher.InfoMessageType:
|
||||
return "text/plain"
|
||||
|
@ -49,18 +50,26 @@ func docType(u *url.URL, response *sliderule.Response) string {
|
|||
return "application/xml"
|
||||
}
|
||||
|
||||
if u.Scheme == "gemini" {
|
||||
if response.Status == gemini.StatusSuccess {
|
||||
mtype, _, err := mime.ParseMediaType(response.Meta.(string))
|
||||
if err == nil {
|
||||
return mtype
|
||||
}
|
||||
if metaIsMediaType(u, response) {
|
||||
mtype, _, err := mime.ParseMediaType(response.Meta.(string))
|
||||
if err == nil {
|
||||
return mtype
|
||||
}
|
||||
}
|
||||
|
||||
return "text/plain"
|
||||
}
|
||||
|
||||
func metaIsMediaType(u *url.URL, response *sliderule.Response) bool {
|
||||
if u.Scheme == "gemini" && response.Status == gemini.StatusSuccess {
|
||||
return true
|
||||
}
|
||||
if u.Scheme == "spartan" && response.Status == spartan.StatusSuccess {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func parseDoc(doctype string, body []byte, conf *Config) (string, []Link, error) {
|
||||
switch doctype {
|
||||
case "text/x-gophermap":
|
||||
|
@ -114,7 +123,11 @@ func parseGemtextDoc(body []byte, softWrap int) (string, []Link, error) {
|
|||
|
||||
i := 0
|
||||
for _, item := range gemdoc {
|
||||
isPrompt := false
|
||||
switch item.Type() {
|
||||
case gemtext.LineTypePrompt:
|
||||
isPrompt = true
|
||||
fallthrough
|
||||
case gemtext.LineTypeLink:
|
||||
ll := item.(gemtext.LinkLine)
|
||||
u, err := url.Parse(ll.URL())
|
||||
|
@ -124,6 +137,7 @@ func parseGemtextDoc(body []byte, softWrap int) (string, []Link, error) {
|
|||
l = append(l, Link{
|
||||
Text: ll.Label(),
|
||||
Target: u,
|
||||
Prompt: isPrompt,
|
||||
})
|
||||
label := ll.Label()
|
||||
if len(label) == 0 {
|
||||
|
|
1
main.go
1
main.go
|
@ -42,6 +42,7 @@ func main() {
|
|||
state.Readline = rl
|
||||
|
||||
for {
|
||||
rl.SetPrompt(Prompt)
|
||||
line, err := rl.Readline()
|
||||
if err == io.EOF {
|
||||
break
|
||||
|
|
Loading…
Reference in New Issue