summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortjp <tjp@ctrl-c.club>2024-01-04 12:47:06 -0700
committertjp <tjp@ctrl-c.club>2024-01-04 12:47:06 -0700
commit684539c70d4b5dfac56e840f46d8dd08821e93d6 (patch)
tree3f6f7e49964879367a511dbb5b568fb1b0ee9c42
parent1c96ee6e4c2268f69091aba9b7b3ed0f8515207f (diff)
handle input types
* spartan prompts * gemini [sensitive]input responses * gopher search servers
-rw-r--r--actions.go122
-rw-r--r--handlers.go28
-rw-r--r--main.go1
-rw-r--r--state.go1
4 files changed, 141 insertions, 11 deletions
diff --git a/actions.go b/actions.go
index 065b673..6e5c7dd 100644
--- a/actions.go
+++ b/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)
diff --git a/handlers.go b/handlers.go
index e68c5f5..b4ce3f2 100644
--- a/handlers.go
+++ b/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 {
diff --git a/main.go b/main.go
index 2e88ce6..97cce21 100644
--- a/main.go
+++ b/main.go
@@ -42,6 +42,7 @@ func main() {
state.Readline = rl
for {
+ rl.SetPrompt(Prompt)
line, err := rl.Readline()
if err == io.EOF {
break
diff --git a/state.go b/state.go
index 141fafb..feeff53 100644
--- a/state.go
+++ b/state.go
@@ -45,6 +45,7 @@ type History struct {
type Link struct {
Text string
Target *url.URL
+ Prompt bool
}
func NewBrowserState() *BrowserState {