Cleans up some display issues
This commit is contained in:
parent
19f210f243
commit
db1cf75d2e
|
@ -50,6 +50,7 @@ func (b *Bookmarks) ToggleOpen() {
|
||||||
b.IsFocused = true
|
b.IsFocused = true
|
||||||
} else {
|
} else {
|
||||||
b.IsFocused = false
|
b.IsFocused = false
|
||||||
|
cui.Clear("screen")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
183
client.go
183
client.go
|
@ -3,7 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
// "os/user"
|
// "os/user"
|
||||||
|
@ -73,7 +72,8 @@ func (c *client) GetSize() {
|
||||||
if h != c.Height || w != c.Width {
|
if h != c.Height || w != c.Width {
|
||||||
c.Height = h
|
c.Height = h
|
||||||
c.Width = w
|
c.Width = w
|
||||||
c.Scroll(0)
|
c.SetPercentRead()
|
||||||
|
c.Draw()
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
@ -86,7 +86,7 @@ func (c *client) Draw() {
|
||||||
screen.WriteString("\033[0m")
|
screen.WriteString("\033[0m")
|
||||||
screen.WriteString(c.TopBar.Render(c.Width, c.Options["theme"]))
|
screen.WriteString(c.TopBar.Render(c.Width, c.Options["theme"]))
|
||||||
screen.WriteString("\n")
|
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" {
|
if c.Options["theme"] == "inverse" {
|
||||||
screen.WriteString("\033[7m")
|
screen.WriteString("\033[7m")
|
||||||
}
|
}
|
||||||
|
@ -122,11 +122,11 @@ func (c *client) Draw() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < c.Height - 3; i++ {
|
for i := 0; i < c.Height - 3; i++ {
|
||||||
if i < len(pageContent) - 1 {
|
if i < len(pageContent) {
|
||||||
screen.WriteString(fmt.Sprintf("%-*.*s", c.Width, c.Width, pageContent[i]))
|
screen.WriteString(fmt.Sprintf("%-*.*s", c.Width - 1, c.Width - 1, pageContent[i]))
|
||||||
screen.WriteString("\n")
|
screen.WriteString("\n")
|
||||||
} else {
|
} else {
|
||||||
screen.WriteString(fmt.Sprintf("%*.*s", c.Width, c.Width, " "))
|
screen.WriteString(fmt.Sprintf("%-*.*s", c.Width, c.Width, " "))
|
||||||
screen.WriteString("\n")
|
screen.WriteString("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,6 +301,28 @@ func (c *client) doCommand(action string, values []string) {
|
||||||
c.displayConfigValue(values[0])
|
c.displayConfigValue(values[0])
|
||||||
case "SEARCH":
|
case "SEARCH":
|
||||||
c.search(strings.Join(values, " "))
|
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:
|
default:
|
||||||
c.SetMessage(fmt.Sprintf("Unknown action %q", action), true)
|
c.SetMessage(fmt.Sprintf("Unknown action %q", action), true)
|
||||||
c.DrawMessage()
|
c.DrawMessage()
|
||||||
|
@ -340,28 +362,15 @@ func (c *client) doCommandAs(action string, values []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case "WRITE", "W":
|
case "WRITE", "W":
|
||||||
// TODO figure out how best to handle file
|
u, err := MakeUrl(values[0])
|
||||||
// writing... it will depend on request model
|
if err != nil {
|
||||||
// using fetch would be best
|
c.SetMessage(err.Error(), true)
|
||||||
// - - - - - - - - - - - - - - - - - - - - -
|
c.DrawMessage()
|
||||||
// var data []byte
|
return
|
||||||
// if values[0] == "." {
|
}
|
||||||
// d, err := c.getCurrentPageRawData()
|
fileName := strings.Join(values[1:], "-")
|
||||||
// if err != nil {
|
fileName = strings.Trim(fileName, " \t\r\n\a\f\v")
|
||||||
// c.SetMessage(err.Error(), true)
|
c.saveFile(u, fileName)
|
||||||
// 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()
|
|
||||||
|
|
||||||
case "SET", "S":
|
case "SET", "S":
|
||||||
if _, ok := c.Options[values[0]]; ok {
|
if _, ok := c.Options[values[0]]; ok {
|
||||||
|
@ -424,8 +433,10 @@ func (c *client) doLinkCommandAs(action, target string, values []string) {
|
||||||
c.Draw()
|
c.Draw()
|
||||||
}
|
}
|
||||||
case "WRITE", "W":
|
case "WRITE", "W":
|
||||||
// TODO get file writing working in some semblance of universal way
|
out := make([]string, 0, len(values) + 1)
|
||||||
// return saveFile(links[num-1], strings.Join(values, " "))
|
out = append(out, links[num])
|
||||||
|
out = append(out, values...)
|
||||||
|
c.doCommandAs(action, out)
|
||||||
default:
|
default:
|
||||||
c.SetMessage(fmt.Sprintf("Unknown command structure"), true)
|
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
|
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) {
|
||||||
savePath := c.Options["savelocation"] + name
|
var file []byte
|
||||||
err := ioutil.WriteFile(savePath, data, 0644)
|
var err error
|
||||||
if err != nil {
|
switch u.Scheme {
|
||||||
return "", err
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
return savePath, nil
|
if err != nil {
|
||||||
|
c.SetMessage(err.Error(), true)
|
||||||
|
c.DrawMessage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
savePath := c.Options["savelocation"] + name
|
||||||
|
err = ioutil.WriteFile(savePath, file, 0644)
|
||||||
|
if err != nil {
|
||||||
|
c.SetMessage("Error writing file to disk", true)
|
||||||
|
c.DrawMessage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SetMessage(fmt.Sprintf("File saved to: %s", savePath), false)
|
||||||
|
c.DrawMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) doLinkCommand(action, target string) {
|
func (c *client) doLinkCommand(action, target string) {
|
||||||
|
@ -503,6 +535,30 @@ func (c *client) doLinkCommand(action, target string) {
|
||||||
link := links[num]
|
link := links[num]
|
||||||
c.SetMessage(fmt.Sprintf("[%d] %s", num + 1, link), false)
|
c.SetMessage(fmt.Sprintf("[%d] %s", num + 1, link), false)
|
||||||
c.DrawMessage()
|
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:
|
default:
|
||||||
c.SetMessage(fmt.Sprintf("Action %q does not exist for target %q", action, target), true)
|
c.SetMessage(fmt.Sprintf("Action %q does not exist for target %q", action, target), true)
|
||||||
c.DrawMessage()
|
c.DrawMessage()
|
||||||
|
@ -576,7 +632,6 @@ func (c *client) Scroll(amount int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.BookMarks.Position = newScrollPosition
|
c.BookMarks.Position = newScrollPosition
|
||||||
c.Draw()
|
|
||||||
} else {
|
} else {
|
||||||
var percentRead int
|
var percentRead int
|
||||||
page := c.PageState.History[c.PageState.Position]
|
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)
|
percentRead = int(float32(newScrollPosition + c.Height - 3) / float32(len(page.WrappedContent)) * 100.0)
|
||||||
}
|
}
|
||||||
c.FootBar.SetPercentRead(percentRead)
|
c.FootBar.SetPercentRead(percentRead)
|
||||||
c.Draw()
|
|
||||||
}
|
}
|
||||||
|
c.Draw()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) SetPercentRead() {
|
func (c *client) SetPercentRead() {
|
||||||
|
@ -731,9 +786,9 @@ func (c *client) Visit(url string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pg := MakePage(u, content, links)
|
pg := MakePage(u, content, links)
|
||||||
pg.WrapContent(c.Width)
|
pg.WrapContent(c.Width - 1)
|
||||||
c.PageState.Add(pg)
|
c.PageState.Add(pg)
|
||||||
c.Scroll(0) // to update percent read
|
c.SetPercentRead()
|
||||||
c.ClearMessage()
|
c.ClearMessage()
|
||||||
c.SetHeaderUrl()
|
c.SetHeaderUrl()
|
||||||
c.Draw()
|
c.Draw()
|
||||||
|
@ -748,9 +803,9 @@ func (c *client) Visit(url string) {
|
||||||
case 2:
|
case 2:
|
||||||
if capsule.MimeMaj == "text" {
|
if capsule.MimeMaj == "text" {
|
||||||
pg := MakePage(u, capsule.Content, capsule.Links)
|
pg := MakePage(u, capsule.Content, capsule.Links)
|
||||||
pg.WrapContent(c.Width)
|
pg.WrapContent(c.Width - 1)
|
||||||
c.PageState.Add(pg)
|
c.PageState.Add(pg)
|
||||||
c.Scroll(0)
|
c.SetPercentRead()
|
||||||
c.ClearMessage()
|
c.ClearMessage()
|
||||||
c.SetHeaderUrl()
|
c.SetHeaderUrl()
|
||||||
c.Draw()
|
c.Draw()
|
||||||
|
@ -808,51 +863,7 @@ func (c *client) Visit(url string) {
|
||||||
//--------------------------------------------------\\
|
//--------------------------------------------------\\
|
||||||
|
|
||||||
func MakeClient(name string) *client {
|
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()}
|
c := client{0, 0, defaultOptions, "", false, MakePages(), MakeBookmarks(), MakeHeadbar(name), MakeFootbar()}
|
||||||
return &c
|
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
28
defaults.go
|
@ -19,31 +19,3 @@ var defaultOptions = map[string]string{
|
||||||
"theme": "normal", // "normal", "inverted"
|
"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",
|
|
||||||
}
|
|
||||||
|
|
|
@ -56,6 +56,53 @@ func Retrieve(host, port, resource string) (string, error) {
|
||||||
return string(result), nil
|
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) {
|
func Visit(host, port, resource string) (Capsule, error) {
|
||||||
capsule := MakeCapsule()
|
capsule := MakeCapsule()
|
||||||
rawResp, err := Retrieve(host, port, resource)
|
rawResp, err := Retrieve(host, port, resource)
|
||||||
|
|
2
main.go
2
main.go
|
@ -106,7 +106,7 @@ func main() {
|
||||||
}
|
}
|
||||||
args := flag.Args()
|
args := flag.Args()
|
||||||
|
|
||||||
cui.Tput("rmam") // turn off line wrapping
|
cui.Tput("rmam") // turn off line wrapping
|
||||||
cui.Tput("smcup") // use alternate screen
|
cui.Tput("smcup") // use alternate screen
|
||||||
defer cui.Exit()
|
defer cui.Exit()
|
||||||
err := initClient()
|
err := initClient()
|
||||||
|
|
Loading…
Reference in New Issue