Browse Source

Cleans up some display issues

pull/40/head
sloumdrone 2 years ago
parent
commit
db1cf75d2e
  1. 1
      bookmarks.go
  2. 179
      client.go
  3. 28
      defaults.go
  4. 47
      gemini/gemini.go
  5. 2
      main.go

1
bookmarks.go

@ -50,6 +50,7 @@ func (b *Bookmarks) ToggleOpen() {
b.IsFocused = true
} else {
b.IsFocused = false
cui.Clear("screen")
}
}

179
client.go

@ -3,7 +3,6 @@ package main
import (
"fmt"
"io/ioutil"
"net"
"os"
"os/exec"
// "os/user"
@ -73,7 +72,8 @@ func (c *client) GetSize() {
if h != c.Height || w != c.Width {
c.Height = h
c.Width = w
c.Scroll(0)
c.SetPercentRead()
c.Draw()
}
time.Sleep(500 * time.Millisecond)
@ -86,7 +86,7 @@ func (c *client) Draw() {
screen.WriteString("\033[0m")
screen.WriteString(c.TopBar.Render(c.Width, c.Options["theme"]))
screen.WriteString("\n")
pageContent := c.PageState.Render(c.Height, c.Width)
pageContent := c.PageState.Render(c.Height, c.Width - 1)
if c.Options["theme"] == "inverse" {
screen.WriteString("\033[7m")
}
@ -122,11 +122,11 @@ func (c *client) Draw() {
}
} else {
for i := 0; i < c.Height - 3; i++ {
if i < len(pageContent) - 1 {
screen.WriteString(fmt.Sprintf("%-*.*s", c.Width, c.Width, pageContent[i]))
if i < len(pageContent) {
screen.WriteString(fmt.Sprintf("%-*.*s", c.Width - 1, c.Width - 1, pageContent[i]))
screen.WriteString("\n")
} else {
screen.WriteString(fmt.Sprintf("%*.*s", c.Width, c.Width, " "))
screen.WriteString(fmt.Sprintf("%-*.*s", c.Width, c.Width, " "))
screen.WriteString("\n")
}
}
@ -301,6 +301,28 @@ func (c *client) doCommand(action string, values []string) {
c.displayConfigValue(values[0])
case "SEARCH":
c.search(strings.Join(values, " "))
case "WRITE", "W":
if values[0] == "." {
values[0] = c.PageState.History[c.PageState.Position].Location.Full
}
u, err := MakeUrl(values[0])
if err != nil {
c.SetMessage(err.Error(), true)
c.DrawMessage()
return
}
fns := strings.Split(u.Resource, "/")
var fn string
if len(fns) > 0 {
fn = strings.Trim(fns[len(fns) - 1], "\t\r\n \a\f\v")
} else {
fn = "index"
}
if fn == "" {
fn = "index"
}
c.saveFile(u, fn)
default:
c.SetMessage(fmt.Sprintf("Unknown action %q", action), true)
c.DrawMessage()
@ -340,28 +362,15 @@ func (c *client) doCommandAs(action string, values []string) {
}
case "WRITE", "W":
// TODO figure out how best to handle file
// writing... it will depend on request model
// using fetch would be best
// - - - - - - - - - - - - - - - - - - - - -
// var data []byte
// if values[0] == "." {
// d, err := c.getCurrentPageRawData()
// if err != nil {
// c.SetMessage(err.Error(), true)
// c.DrawMessage()
// return
// }
// data = []byte(d)
// }
// fp, err := c.saveFile(data, strings.Join(values[1:], " "))
// if err != nil {
// c.SetMessage(err.Error(), true)
// c.DrawMessage()
// return
// }
// c.SetMessage(fmt.Sprintf("File saved to: %s", fp), false)
// c.DrawMessage()
u, err := MakeUrl(values[0])
if err != nil {
c.SetMessage(err.Error(), true)
c.DrawMessage()
return
}
fileName := strings.Join(values[1:], "-")
fileName = strings.Trim(fileName, " \t\r\n\a\f\v")
c.saveFile(u, fileName)
case "SET", "S":
if _, ok := c.Options[values[0]]; ok {
@ -424,8 +433,10 @@ func (c *client) doLinkCommandAs(action, target string, values []string) {
c.Draw()
}
case "WRITE", "W":
// TODO get file writing working in some semblance of universal way
// return saveFile(links[num-1], strings.Join(values, " "))
out := make([]string, 0, len(values) + 1)
out = append(out, links[num])
out = append(out, values...)
c.doCommandAs(action, out)
default:
c.SetMessage(fmt.Sprintf("Unknown command structure"), true)
}
@ -446,14 +457,35 @@ func (c *client) getCurrentPageRawData() (string, error) {
return c.PageState.History[c.PageState.Position].RawContent, nil
}
func (c *client) saveFile(data []byte, name string) (string, error) {
func (c *client) saveFile(u Url, name string) {
var file []byte
var err error
switch u.Scheme {
case "gopher":
file, err = gopher.Retrieve(u.Host, u.Port, u.Resource)
case "gemini":
file, err = gemini.Fetch(u.Host, u.Port, u.Resource)
default:
c.SetMessage(fmt.Sprintf("Saving files over %s is not supported", u.Scheme), true)
c.DrawMessage()
return
}
if err != nil {
c.SetMessage(err.Error(), true)
c.DrawMessage()
return
}
savePath := c.Options["savelocation"] + name
err := ioutil.WriteFile(savePath, data, 0644)
err = ioutil.WriteFile(savePath, file, 0644)
if err != nil {
return "", err
c.SetMessage("Error writing file to disk", true)
c.DrawMessage()
return
}
return savePath, nil
c.SetMessage(fmt.Sprintf("File saved to: %s", savePath), false)
c.DrawMessage()
}
func (c *client) doLinkCommand(action, target string) {
@ -503,6 +535,30 @@ func (c *client) doLinkCommand(action, target string) {
link := links[num]
c.SetMessage(fmt.Sprintf("[%d] %s", num + 1, link), false)
c.DrawMessage()
case "WRITE", "W":
links := c.PageState.History[c.PageState.Position].Links
if len(links) < num || num < 1 {
c.SetMessage("Invalid link ID", true)
c.DrawMessage()
return
}
u, err := MakeUrl(links[num-1])
if err != nil {
c.SetMessage(err.Error(), true)
c.DrawMessage()
return
}
fns := strings.Split(u.Resource, "/")
var fn string
if len(fns) > 0 {
fn = strings.Trim(fns[len(fns) - 1], "\t\r\n \a\f\v")
} else {
fn = "index"
}
if fn == "" {
fn = "index"
}
c.saveFile(u, fn)
default:
c.SetMessage(fmt.Sprintf("Action %q does not exist for target %q", action, target), true)
c.DrawMessage()
@ -576,7 +632,6 @@ func (c *client) Scroll(amount int) {
}
c.BookMarks.Position = newScrollPosition
c.Draw()
} else {
var percentRead int
page := c.PageState.History[c.PageState.Position]
@ -609,8 +664,8 @@ func (c *client) Scroll(amount int) {
percentRead = int(float32(newScrollPosition + c.Height - 3) / float32(len(page.WrappedContent)) * 100.0)
}
c.FootBar.SetPercentRead(percentRead)
c.Draw()
}
c.Draw()
}
func (c *client) SetPercentRead() {
@ -731,9 +786,9 @@ func (c *client) Visit(url string) {
return
}
pg := MakePage(u, content, links)
pg.WrapContent(c.Width)
pg.WrapContent(c.Width - 1)
c.PageState.Add(pg)
c.Scroll(0) // to update percent read
c.SetPercentRead()
c.ClearMessage()
c.SetHeaderUrl()
c.Draw()
@ -748,9 +803,9 @@ func (c *client) Visit(url string) {
case 2:
if capsule.MimeMaj == "text" {
pg := MakePage(u, capsule.Content, capsule.Links)
pg.WrapContent(c.Width)
pg.WrapContent(c.Width - 1)
c.PageState.Add(pg)
c.Scroll(0)
c.SetPercentRead()
c.ClearMessage()
c.SetHeaderUrl()
c.Draw()
@ -808,51 +863,7 @@ func (c *client) Visit(url string) {
//--------------------------------------------------\\
func MakeClient(name string) *client {
// var userinfo, _ = user.Current()
// var options = map[string]string{
// "homeurl": "gopher://colorfield.space:70/1/bombadillo-info",
// "savelocation": userinfo.HomeDir,
// "searchengine": "gopher://gopher.floodgap.com:70/7/v2/vs",
// "openhttp": "false",
// "httpbrowser": "lynx",
// "configlocation": userinfo.HomeDir,
// }
c := client{0, 0, defaultOptions, "", false, MakePages(), MakeBookmarks(), MakeHeadbar(name), MakeFootbar()}
return &c
}
// Retrieve a byte slice of raw response dataa
// from a url string
func Fetch(url string) ([]byte, error) {
u, err := MakeUrl(url)
if err != nil {
return []byte(""), err
}
timeOut := time.Duration(5) * time.Second
if u.Host == "" || u.Port == "" {
return []byte(""), fmt.Errorf("Incomplete request url")
}
addr := u.Host + ":" + u.Port
conn, err := net.DialTimeout("tcp", addr, timeOut)
if err != nil {
return []byte(""), err
}
send := u.Resource + "\n"
_, err = conn.Write([]byte(send))
if err != nil {
return []byte(""), err
}
result, err := ioutil.ReadAll(conn)
if err != nil {
return []byte(""), err
}
return result, err
}

28
defaults.go

@ -19,31 +19,3 @@ var defaultOptions = map[string]string{
"theme": "normal", // "normal", "inverted"
}
// TODO decide whether or not to institute a color theme
// system. Preliminary testing implies it should be very
// doable.
var theme = map[string]string{
"topbar_title_bg": "",
"topbar_link_fg": "",
"body_bg": "237",
"body_fg": "",
"bookmarks_bg": "",
"bookmarks_fg": "",
"command_bg": "",
"message_fg": "",
"error_fg": "",
"bottombar_bg": "",
"bottombar_fg": "",
//
// text style options
//
"topbar_title_style": "bold",
"topbar_link_style": "plain",
"body_style": "plain",
"bookmark_body_style": "plain",
"bookmark_border_style": "plain",
"message_style": "italic",
"error_style": "bold",
"command_style": "plain",
"bottom_bar_style": "plain",
}

47
gemini/gemini.go

@ -56,6 +56,53 @@ func Retrieve(host, port, resource string) (string, error) {
return string(result), nil
}
func Fetch(host, port, resource string) ([]byte, error) {
rawResp, err := Retrieve(host, port, resource)
if err != nil {
return make([]byte, 0), err
}
resp := strings.SplitN(rawResp, "\r\n", 2)
if len(resp) != 2 {
if err != nil {
return make([]byte, 0), fmt.Errorf("Invalid response from server")
}
}
header := strings.SplitN(resp[0], " ", 2)
if len([]rune(header[0])) != 2 {
header = strings.SplitN(resp[0], "\t", 2)
if len([]rune(header[0])) != 2 {
return make([]byte,0), fmt.Errorf("Invalid response format from server")
}
}
// Get status code single digit form
status, err := strconv.Atoi(string(header[0][0]))
if err != nil {
return make([]byte, 0), fmt.Errorf("Invalid status response from server")
}
if status != 2 {
switch status {
case 1:
return make([]byte, 0), fmt.Errorf("[1] Queries cannot be saved.")
case 3:
return make([]byte, 0), fmt.Errorf("[3] Redirects cannot be saved.")
case 4:
return make([]byte, 0), fmt.Errorf("[4] Temporary Failure.")
case 5:
return make([]byte, 0), fmt.Errorf("[5] Permanent Failure.")
case 6:
return make([]byte, 0), fmt.Errorf("[6] Client Certificate Required (Not supported by Bombadillo)")
default:
return make([]byte, 0), fmt.Errorf("Invalid response status from server")
}
}
return []byte(resp[1]), nil
}
func Visit(host, port, resource string) (Capsule, error) {
capsule := MakeCapsule()
rawResp, err := Retrieve(host, port, resource)

2
main.go

@ -106,7 +106,7 @@ func main() {
}
args := flag.Args()
cui.Tput("rmam") // turn off line wrapping
cui.Tput("rmam") // turn off line wrapping
cui.Tput("smcup") // use alternate screen
defer cui.Exit()
err := initClient()

Loading…
Cancel
Save