forked from sloum/bombadillo
Merge branch 'run-format' of sloum/bombadillo into develop
This commit is contained in:
commit
c36ded496f
38
bookmarks.go
38
bookmarks.go
|
@ -11,19 +11,23 @@ import (
|
|||
// + + + T Y P E S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// Bookmarks represents the contents of the bookmarks
|
||||
// bar, as well as its visibility, focus, and scroll
|
||||
// state.
|
||||
type Bookmarks struct {
|
||||
IsOpen bool
|
||||
IsOpen bool
|
||||
IsFocused bool
|
||||
Position int
|
||||
Length int
|
||||
Titles []string
|
||||
Links []string
|
||||
Position int
|
||||
Length int
|
||||
Titles []string
|
||||
Links []string
|
||||
}
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + R E C E I V E R S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// Add a bookmark to the bookmarks struct
|
||||
func (b *Bookmarks) Add(v []string) (string, error) {
|
||||
if len(v) < 2 {
|
||||
return "", fmt.Errorf("Received %d arguments, expected 2+", len(v))
|
||||
|
@ -34,6 +38,7 @@ func (b *Bookmarks) Add(v []string) (string, error) {
|
|||
return "Bookmark added successfully", nil
|
||||
}
|
||||
|
||||
// Delete a bookmark from the bookmarks struct
|
||||
func (b *Bookmarks) Delete(i int) (string, error) {
|
||||
if i < len(b.Titles) && len(b.Titles) == len(b.Links) {
|
||||
b.Titles = append(b.Titles[:i], b.Titles[i+1:]...)
|
||||
|
@ -44,6 +49,7 @@ func (b *Bookmarks) Delete(i int) (string, error) {
|
|||
return "", fmt.Errorf("Bookmark %d does not exist", i)
|
||||
}
|
||||
|
||||
// ToggleOpen toggles visibility state of the bookmarks bar
|
||||
func (b *Bookmarks) ToggleOpen() {
|
||||
b.IsOpen = !b.IsOpen
|
||||
if b.IsOpen {
|
||||
|
@ -53,12 +59,15 @@ func (b *Bookmarks) ToggleOpen() {
|
|||
}
|
||||
}
|
||||
|
||||
// ToggleFocused toggles the focal state of the bookmarks bar
|
||||
func (b *Bookmarks) ToggleFocused() {
|
||||
if b.IsOpen {
|
||||
b.IsFocused = !b.IsFocused
|
||||
}
|
||||
}
|
||||
|
||||
// IniDump returns a string representing the current bookmarks
|
||||
// in the format that .bombadillo.ini uses
|
||||
func (b Bookmarks) IniDump() string {
|
||||
if len(b.Titles) < 1 {
|
||||
return ""
|
||||
|
@ -73,7 +82,7 @@ func (b Bookmarks) IniDump() string {
|
|||
return out
|
||||
}
|
||||
|
||||
// Get a list, including link nums, of bookmarks
|
||||
// List returns a list, including link nums, of bookmarks
|
||||
// as a string slice
|
||||
func (b Bookmarks) List() []string {
|
||||
var out []string
|
||||
|
@ -83,13 +92,15 @@ func (b Bookmarks) List() []string {
|
|||
return out
|
||||
}
|
||||
|
||||
// Render returns a string slice with the contents of each
|
||||
// visual row of the bookmark bar.
|
||||
func (b Bookmarks) Render(termwidth, termheight int) []string {
|
||||
width := 40
|
||||
termheight -= 3
|
||||
var walll, wallr, floor, ceil, tr, tl, br, bl string
|
||||
if termwidth < 40 {
|
||||
width = termwidth
|
||||
}
|
||||
}
|
||||
if b.IsFocused {
|
||||
walll = cui.Shapes["awalll"]
|
||||
wallr = cui.Shapes["awallr"]
|
||||
|
@ -115,11 +126,11 @@ func (b Bookmarks) Render(termwidth, termheight int) []string {
|
|||
top := fmt.Sprintf("%s%s%s", tl, strings.Repeat(ceil, contentWidth), tr)
|
||||
out = append(out, top)
|
||||
marks := b.List()
|
||||
for i := 0; i < termheight - 2; i++ {
|
||||
if i + b.Position >= len(b.Titles) {
|
||||
for i := 0; i < termheight-2; i++ {
|
||||
if i+b.Position >= len(b.Titles) {
|
||||
out = append(out, fmt.Sprintf("%s%-*.*s%s", walll, contentWidth, contentWidth, "", wallr))
|
||||
} else {
|
||||
out = append(out, fmt.Sprintf("%s%-*.*s%s", walll, contentWidth, contentWidth, marks[i + b.Position], wallr))
|
||||
out = append(out, fmt.Sprintf("%s%-*.*s%s", walll, contentWidth, contentWidth, marks[i+b.Position], wallr))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,16 +139,11 @@ func (b Bookmarks) Render(termwidth, termheight int) []string {
|
|||
return out
|
||||
}
|
||||
|
||||
// TODO handle scrolling of the bookmarks list
|
||||
// either here with a scroll up/down or in the client
|
||||
// code for scroll
|
||||
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + F U N C T I O N S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// MakeBookmarks creates a Bookmark struct with default values
|
||||
func MakeBookmarks() Bookmarks {
|
||||
return Bookmarks{false, false, 0, 0, make([]string, 0), make([]string, 0)}
|
||||
}
|
||||
|
||||
|
|
42
client.go
42
client.go
|
@ -51,7 +51,7 @@ func (c *client) GetSizeOnce() {
|
|||
os.Exit(5)
|
||||
}
|
||||
var h, w int
|
||||
fmt.Sscan(string(out), &h, &w)
|
||||
_, _ = fmt.Sscan(string(out), &h, &w)
|
||||
c.Height = h
|
||||
c.Width = w
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ func (c *client) GetSize() {
|
|||
os.Exit(5)
|
||||
}
|
||||
var h, w int
|
||||
fmt.Sscan(string(out), &h, &w)
|
||||
_, _ = fmt.Sscan(string(out), &h, &w)
|
||||
if h != c.Height || w != c.Width {
|
||||
c.Height = h
|
||||
c.Width = w
|
||||
|
@ -268,7 +268,7 @@ func (c *client) routeCommandInput(com *cmdparse.Command) error {
|
|||
case cmdparse.DOLINKAS:
|
||||
c.doLinkCommandAs(com.Action, com.Target, com.Value)
|
||||
default:
|
||||
return fmt.Errorf("Unknown command entry!")
|
||||
return fmt.Errorf("Unknown command entry")
|
||||
}
|
||||
|
||||
return err
|
||||
|
@ -385,10 +385,9 @@ func (c *client) doCommandAs(action string, values []string) {
|
|||
c.SetMessage(err.Error(), true)
|
||||
c.DrawMessage()
|
||||
return
|
||||
} else {
|
||||
c.SetMessage(msg, false)
|
||||
c.DrawMessage()
|
||||
}
|
||||
c.SetMessage(msg, false)
|
||||
c.DrawMessage()
|
||||
|
||||
err = saveConfig()
|
||||
if err != nil {
|
||||
|
@ -437,7 +436,7 @@ func (c *client) doLinkCommandAs(action, target string, values []string) {
|
|||
return
|
||||
}
|
||||
|
||||
num -= 1
|
||||
num--
|
||||
|
||||
links := c.PageState.History[c.PageState.Position].Links
|
||||
if num >= len(links) || num < 0 {
|
||||
|
@ -456,10 +455,9 @@ func (c *client) doLinkCommandAs(action, target string, values []string) {
|
|||
c.SetMessage(err.Error(), true)
|
||||
c.DrawMessage()
|
||||
return
|
||||
} else {
|
||||
c.SetMessage(msg, false)
|
||||
c.DrawMessage()
|
||||
}
|
||||
c.SetMessage(msg, false)
|
||||
c.DrawMessage()
|
||||
|
||||
err = saveConfig()
|
||||
if err != nil {
|
||||
|
@ -564,10 +562,9 @@ func (c *client) doLinkCommand(action, target string) {
|
|||
c.SetMessage(err.Error(), true)
|
||||
c.DrawMessage()
|
||||
return
|
||||
} else {
|
||||
c.SetMessage(msg, false)
|
||||
c.DrawMessage()
|
||||
}
|
||||
c.SetMessage(msg, false)
|
||||
c.DrawMessage()
|
||||
|
||||
err = saveConfig()
|
||||
if err != nil {
|
||||
|
@ -585,7 +582,7 @@ func (c *client) doLinkCommand(action, target string) {
|
|||
}
|
||||
c.Visit(c.BookMarks.Links[num])
|
||||
case "CHECK", "C":
|
||||
num -= 1
|
||||
num--
|
||||
|
||||
links := c.PageState.History[c.PageState.Position].Links
|
||||
if num >= len(links) || num < 0 {
|
||||
|
@ -877,8 +874,7 @@ func (c *client) Visit(url string) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// +++ Begin Protocol Handlers +++
|
||||
// +++ Begin Protocol Handlers +++
|
||||
|
||||
func (c *client) handleGopher(u Url) {
|
||||
if u.DownloadOnly {
|
||||
|
@ -1022,15 +1018,15 @@ func (c *client) handleWeb(u Url) {
|
|||
c.SetMessage("The file is non-text: writing to disk...", false)
|
||||
c.DrawMessage()
|
||||
var fn string
|
||||
if i := strings.LastIndex(u.Full, "/"); i > 0 && i + 1 < len(u.Full) {
|
||||
fn = u.Full[i + 1:]
|
||||
if i := strings.LastIndex(u.Full, "/"); i > 0 && i+1 < len(u.Full) {
|
||||
fn = u.Full[i+1:]
|
||||
} else {
|
||||
fn = "bombadillo.download"
|
||||
}
|
||||
c.saveFile(u, fn)
|
||||
}
|
||||
|
||||
// Open in default web browser if available
|
||||
// Open in default web browser if available
|
||||
} else {
|
||||
if strings.ToUpper(c.Options["terminalonly"]) == "TRUE" {
|
||||
c.SetMessage("'terminalonly' is set to true and 'lynxmode' is not enabled, cannot open web link", false)
|
||||
|
@ -1049,11 +1045,12 @@ func (c *client) handleWeb(u Url) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + F U N C T I O N S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// MakeClient returns a client struct and names the client after
|
||||
// the string that is passed in
|
||||
func MakeClient(name string) *client {
|
||||
c := client{0, 0, defaultOptions, "", false, MakePages(), MakeBookmarks(), MakeHeadbar(name), MakeFootbar(), gemini.MakeTofuDigest()}
|
||||
return &c
|
||||
|
@ -1061,12 +1058,12 @@ func MakeClient(name string) *client {
|
|||
|
||||
func findAvailableFileName(fpath, fname string) (string, error) {
|
||||
savePath := filepath.Join(fpath, fname)
|
||||
_, fileErr := os.Stat(savePath)
|
||||
_, fileErr := os.Stat(savePath)
|
||||
|
||||
for suffix := 1; fileErr == nil; suffix++ {
|
||||
fn := fmt.Sprintf("%s.%d", fname, suffix)
|
||||
savePath = filepath.Join(fpath, fn)
|
||||
_, fileErr = os.Stat(savePath)
|
||||
_, fileErr = os.Stat(savePath)
|
||||
|
||||
if !os.IsNotExist(fileErr) && fileErr != nil {
|
||||
return savePath, fileErr
|
||||
|
@ -1075,4 +1072,3 @@ func findAvailableFileName(fpath, fname string) (string, error) {
|
|||
|
||||
return savePath, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -68,10 +68,10 @@ func (s *scanner) scanText() Token {
|
|||
|
||||
capInput := strings.ToUpper(buf.String())
|
||||
switch capInput {
|
||||
case "D", "DELETE", "A", "ADD","W", "WRITE",
|
||||
case "D", "DELETE", "A", "ADD", "W", "WRITE",
|
||||
"S", "SET", "R", "RELOAD", "SEARCH",
|
||||
"Q", "QUIT", "B", "BOOKMARKS", "H",
|
||||
"HOME", "?", "HELP", "C", "CHECK",
|
||||
"HOME", "?", "HELP", "C", "CHECK",
|
||||
"P", "PURGE":
|
||||
return Token{Action, capInput}
|
||||
}
|
||||
|
|
|
@ -21,11 +21,11 @@ type Parser struct {
|
|||
|
||||
type Config struct {
|
||||
// Bookmarks gopher.Bookmarks
|
||||
Bookmarks struct {
|
||||
Titles, Links []string
|
||||
Bookmarks struct {
|
||||
Titles, Links []string
|
||||
}
|
||||
Settings []KeyValue
|
||||
Certs []KeyValue
|
||||
Settings []KeyValue
|
||||
Certs []KeyValue
|
||||
}
|
||||
|
||||
type KeyValue struct {
|
||||
|
|
13
cui/cui.go
13
cui/cui.go
|
@ -26,19 +26,6 @@ var Shapes = map[string]string{
|
|||
"abr": "▟",
|
||||
}
|
||||
|
||||
func drawShape(shape string) {
|
||||
if val, ok := Shapes[shape]; ok {
|
||||
fmt.Printf("%s", val)
|
||||
} else {
|
||||
fmt.Print("x")
|
||||
}
|
||||
}
|
||||
|
||||
func moveThenDrawShape(r, c int, s string) {
|
||||
MoveCursorTo(r, c)
|
||||
drawShape(s)
|
||||
}
|
||||
|
||||
func MoveCursorTo(row, col int) {
|
||||
fmt.Printf("\033[%d;%dH", row, col)
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
package cui
|
||||
|
||||
import (
|
||||
)
|
||||
|
29
defaults.go
29
defaults.go
|
@ -12,21 +12,20 @@ var defaultOptions = map[string]string{
|
|||
// Edit these values before compile to have different default values
|
||||
// ... though they can always be edited from within bombadillo as well
|
||||
// it just may take more time/work.
|
||||
//
|
||||
// To change the default location for the config you can enter
|
||||
// any valid path as a string, if you want an absolute, or
|
||||
// concatenate with the main default: `userinfo.HomeDir` like so:
|
||||
// "configlocation": userinfo.HomeDir + "/config/"
|
||||
"homeurl": "gopher://bombadillo.colorfield.space:70/1/user-guide.map",
|
||||
"savelocation": userinfo.HomeDir,
|
||||
"searchengine": "gopher://gopher.floodgap.com:70/7/v2/vs",
|
||||
"openhttp": "false",
|
||||
"telnetcommand": "telnet",
|
||||
//
|
||||
// To change the default location for the config you can enter
|
||||
// any valid path as a string, if you want an absolute, or
|
||||
// concatenate with the main default: `userinfo.HomeDir` like so:
|
||||
// "configlocation": userinfo.HomeDir + "/config/"
|
||||
"homeurl": "gopher://bombadillo.colorfield.space:70/1/user-guide.map",
|
||||
"savelocation": userinfo.HomeDir,
|
||||
"searchengine": "gopher://gopher.floodgap.com:70/7/v2/vs",
|
||||
"openhttp": "false",
|
||||
"telnetcommand": "telnet",
|
||||
"configlocation": userinfo.HomeDir,
|
||||
"theme": "normal", // "normal", "inverted"
|
||||
"terminalonly": "true",
|
||||
"theme": "normal", // "normal", "inverted"
|
||||
"terminalonly": "true",
|
||||
"tlscertificate": "",
|
||||
"tlskey": "",
|
||||
"lynxmode": "false",
|
||||
"tlskey": "",
|
||||
"lynxmode": "false",
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ package finger
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
19
footbar.go
19
footbar.go
|
@ -5,21 +5,23 @@ import (
|
|||
"strconv"
|
||||
)
|
||||
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + T Y P E S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// Footbar deals with the values present in the
|
||||
// client's footbar
|
||||
type Footbar struct {
|
||||
PercentRead string
|
||||
PageType string
|
||||
PageType string
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + R E C E I V E R S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// SetPercentRead sets the percentage of the current
|
||||
// document the user has read
|
||||
func (f *Footbar) SetPercentRead(p int) {
|
||||
if p > 100 {
|
||||
p = 100
|
||||
|
@ -29,25 +31,28 @@ func (f *Footbar) SetPercentRead(p int) {
|
|||
f.PercentRead = strconv.Itoa(p) + "%"
|
||||
}
|
||||
|
||||
// SetPageType sets the current page's type
|
||||
// NOTE: This is not currently in use
|
||||
func (f *Footbar) SetPageType(t string) {
|
||||
f.PageType = t
|
||||
}
|
||||
|
||||
// Render returns a string representing the visual display
|
||||
// of the bookmarks bar
|
||||
func (f *Footbar) Render(termWidth, position int, theme string) string {
|
||||
pre := fmt.Sprintf("HST: (%2.2d) - - - %4s Read ", position + 1, f.PercentRead)
|
||||
pre := fmt.Sprintf("HST: (%2.2d) - - - %4s Read ", position+1, f.PercentRead)
|
||||
out := "\033[0m%*.*s "
|
||||
if theme == "inverse" {
|
||||
out = "\033[7m%*.*s \033[0m"
|
||||
}
|
||||
return fmt.Sprintf(out, termWidth - 1, termWidth - 1, pre)
|
||||
return fmt.Sprintf(out, termWidth-1, termWidth-1, pre)
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + F U N C T I O N S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// MakeFootbar returns a footbar with default values
|
||||
func MakeFootbar() Footbar {
|
||||
return Footbar{"---", "N/A"}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,22 +11,19 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
|
||||
type Capsule struct {
|
||||
MimeMaj string
|
||||
MimeMaj string
|
||||
MimeMin string
|
||||
Status int
|
||||
Content string
|
||||
Status int
|
||||
Content string
|
||||
Links []string
|
||||
}
|
||||
|
||||
|
||||
type TofuDigest struct {
|
||||
certs map[string]string
|
||||
ClientCert tls.Certificate
|
||||
certs map[string]string
|
||||
ClientCert tls.Certificate
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + R E C E I V E R S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
@ -107,17 +104,17 @@ func (t *TofuDigest) newCert(host string, cState *tls.ConnectionState) error {
|
|||
reasons.WriteString("; ")
|
||||
}
|
||||
if now.Before(cert.NotBefore) {
|
||||
reasons.WriteString(fmt.Sprintf("Cert [%d] is not valid yet", index + 1))
|
||||
reasons.WriteString(fmt.Sprintf("Cert [%d] is not valid yet", index+1))
|
||||
continue
|
||||
}
|
||||
|
||||
if now.After(cert.NotAfter) {
|
||||
reasons.WriteString(fmt.Sprintf("Cert [%d] is expired", index + 1))
|
||||
reasons.WriteString(fmt.Sprintf("Cert [%d] is expired", index+1))
|
||||
continue
|
||||
}
|
||||
|
||||
if err := cert.VerifyHostname(host); err != nil {
|
||||
reasons.WriteString(fmt.Sprintf("Cert [%d] hostname does not match", index + 1))
|
||||
reasons.WriteString(fmt.Sprintf("Cert [%d] hostname does not match", index+1))
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -143,8 +140,6 @@ func (t *TofuDigest) IniDump() string {
|
|||
return out.String()
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + F U N C T I O N S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
@ -157,7 +152,7 @@ func Retrieve(host, port, resource string, td *TofuDigest) (string, error) {
|
|||
addr := host + ":" + port
|
||||
|
||||
conf := &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
|
@ -183,7 +178,7 @@ func Retrieve(host, port, resource string, td *TofuDigest) (string, error) {
|
|||
|
||||
if td.Exists(host) {
|
||||
// See if we have a matching cert
|
||||
err := td.Match(host, &connState)
|
||||
err := td.Match(host, &connState)
|
||||
if err != nil && err.Error() != "EXP" {
|
||||
// If there is no match and it isnt because of an expiration
|
||||
// just return the error
|
||||
|
@ -223,21 +218,21 @@ func Fetch(host, port, resource string, td *TofuDigest) ([]byte, error) {
|
|||
rawResp, err := Retrieve(host, port, resource, td)
|
||||
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")
|
||||
}
|
||||
}
|
||||
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]))
|
||||
|
@ -271,24 +266,24 @@ func Visit(host, port, resource string, td *TofuDigest) (Capsule, error) {
|
|||
rawResp, err := Retrieve(host, port, resource, td)
|
||||
if err != nil {
|
||||
return capsule, err
|
||||
}
|
||||
}
|
||||
|
||||
resp := strings.SplitN(rawResp, "\r\n", 2)
|
||||
if len(resp) != 2 {
|
||||
if err != nil {
|
||||
return capsule, 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 capsule, fmt.Errorf("Invalid response format from server")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body := resp[1]
|
||||
|
||||
|
||||
// Get status code single digit form
|
||||
capsule.Status, err = strconv.Atoi(string(header[0][0]))
|
||||
if err != nil {
|
||||
|
@ -351,7 +346,7 @@ func parseGemini(b, rootUrl, currentUrl string) (string, []string) {
|
|||
subLn := strings.Trim(ln[2:], "\r\n\t \a")
|
||||
splitPoint := strings.IndexAny(subLn, " \t")
|
||||
|
||||
if splitPoint < 0 || len([]rune(subLn)) - 1 <= splitPoint {
|
||||
if splitPoint < 0 || len([]rune(subLn))-1 <= splitPoint {
|
||||
link = subLn
|
||||
decorator = subLn
|
||||
} else {
|
||||
|
@ -359,7 +354,7 @@ func parseGemini(b, rootUrl, currentUrl string) (string, []string) {
|
|||
decorator = strings.Trim(subLn[splitPoint:], "\t\n\r \a")
|
||||
}
|
||||
|
||||
if strings.Index(link, "://") < 0 {
|
||||
if strings.Index(link, "://") < 0 {
|
||||
link = handleRelativeUrl(link, rootUrl, currentUrl)
|
||||
}
|
||||
|
||||
|
@ -385,7 +380,7 @@ func handleRelativeUrl(u, root, current string) string {
|
|||
return fmt.Sprintf("%s/%s", root, u)
|
||||
}
|
||||
|
||||
current = current[:ind + 1]
|
||||
current = current[:ind+1]
|
||||
return fmt.Sprintf("%s%s", current, u)
|
||||
}
|
||||
|
||||
|
@ -398,7 +393,6 @@ func hashCert(cert []byte) string {
|
|||
return fmt.Sprintf("%s", string(bytes.Join(hex, []byte(":"))))
|
||||
}
|
||||
|
||||
|
||||
func MakeCapsule() Capsule {
|
||||
return Capsule{"", "", 0, "", make([]string, 0, 5)}
|
||||
}
|
||||
|
|
|
@ -83,8 +83,8 @@ func Visit(gophertype, host, port, resource string) (string, []string, error) {
|
|||
resp, err := Retrieve(host, port, resource)
|
||||
if err != nil {
|
||||
return "", []string{}, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
text := string(resp)
|
||||
links := []string{}
|
||||
|
||||
|
@ -92,7 +92,6 @@ func Visit(gophertype, host, port, resource string) (string, []string, error) {
|
|||
return text, []string{}, nil
|
||||
}
|
||||
|
||||
|
||||
if gophertype == "1" {
|
||||
text, links = parseMap(text)
|
||||
}
|
||||
|
@ -116,7 +115,7 @@ func isWebLink(resource string) (string, bool) {
|
|||
return "", false
|
||||
}
|
||||
|
||||
func parseMap(text string) (string, []string) {
|
||||
func parseMap(text string) (string, []string) {
|
||||
splitContent := strings.Split(text, "\n")
|
||||
links := make([]string, 0, 10)
|
||||
|
||||
|
@ -135,7 +134,7 @@ func parseMap(text string) (string, []string) {
|
|||
} else {
|
||||
title = ""
|
||||
}
|
||||
|
||||
|
||||
if len(line) > 1 && len(line[0]) > 0 && string(line[0][0]) == "i" {
|
||||
splitContent[i] = " " + string(title)
|
||||
} else if len(line) >= 4 {
|
||||
|
|
13
headbar.go
13
headbar.go
|
@ -8,31 +8,32 @@ import (
|
|||
// + + + T Y P E S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// Headbar represents the contents of the top bar of
|
||||
// the client and contains the client name and the
|
||||
// current URL
|
||||
type Headbar struct {
|
||||
title string
|
||||
url string
|
||||
url string
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + R E C E I V E R S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// Render returns a string with the contents of theHeadbar
|
||||
func (h *Headbar) Render(width int, theme string) string {
|
||||
maxMsgWidth := width - len([]rune(h.title)) - 2
|
||||
if theme == "inverse" {
|
||||
return fmt.Sprintf("\033[7m%s▟\033[27m %-*.*s\033[0m", h.title, maxMsgWidth, maxMsgWidth, h.url)
|
||||
} else {
|
||||
return fmt.Sprintf("%s▟\033[7m %-*.*s\033[0m", h.title, maxMsgWidth, maxMsgWidth, h.url)
|
||||
}
|
||||
return fmt.Sprintf("%s▟\033[7m %-*.*s\033[0m", h.title, maxMsgWidth, maxMsgWidth, h.url)
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + F U N C T I O N S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// MakeHeadbar returns a Headbar with default values
|
||||
func MakeHeadbar(title string) Headbar {
|
||||
return Headbar{title, ""}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ func IsTextFile(url string) bool {
|
|||
}
|
||||
|
||||
// If we made it here, there is no content-type header.
|
||||
// So in the event of the unknown, lets render to the
|
||||
// So in the event of the unknown, lets render to the
|
||||
// screen. This will allow redirects to get rendered
|
||||
// as well.
|
||||
return true
|
||||
|
@ -89,4 +89,3 @@ func Fetch(url string) ([]byte, error) {
|
|||
|
||||
return bodyBytes, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ func Open(address string) (string, error) {
|
|||
}
|
||||
defer file.Close()
|
||||
|
||||
|
||||
if pathIsDir(address) {
|
||||
fileList, err := file.Readdirnames(0)
|
||||
if err != nil {
|
||||
|
@ -40,21 +39,20 @@ func Open(address string) (string, error) {
|
|||
return string(bytes), nil
|
||||
}
|
||||
|
||||
|
||||
func pathExists(p string) bool {
|
||||
exists := true
|
||||
|
||||
if _, err := os.Stat(p); os.IsNotExist(err) {
|
||||
exists = false
|
||||
}
|
||||
if _, err := os.Stat(p); os.IsNotExist(err) {
|
||||
exists = false
|
||||
}
|
||||
|
||||
return exists
|
||||
return exists
|
||||
}
|
||||
|
||||
func pathIsDir(p string) bool {
|
||||
info, err := os.Stat(p)
|
||||
info, err := os.Stat(p)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return info.IsDir()
|
||||
}
|
||||
|
|
11
main.go
11
main.go
|
@ -82,9 +82,8 @@ func validateOpt(opt, val string) bool {
|
|||
}
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func lowerCaseOpt(opt, val string) string {
|
||||
|
@ -107,7 +106,7 @@ func loadConfig() error {
|
|||
|
||||
confparser := config.NewParser(file)
|
||||
settings, _ = confparser.Parse()
|
||||
file.Close()
|
||||
_ = file.Close()
|
||||
for _, v := range settings.Settings {
|
||||
lowerkey := strings.ToLower(v.Key)
|
||||
if lowerkey == "configlocation" {
|
||||
|
@ -129,7 +128,7 @@ func loadConfig() error {
|
|||
}
|
||||
|
||||
for i, v := range settings.Bookmarks.Titles {
|
||||
bombadillo.BookMarks.Add([]string{v, settings.Bookmarks.Links[i]})
|
||||
_, _ = bombadillo.BookMarks.Add([]string{v, settings.Bookmarks.Links[i]})
|
||||
}
|
||||
|
||||
for _, v := range settings.Certs {
|
||||
|
@ -157,7 +156,7 @@ func handleSignals(c <-chan os.Signal) {
|
|||
switch <-c {
|
||||
case syscall.SIGTSTP:
|
||||
cui.CleanupTerm()
|
||||
syscall.Kill(syscall.Getpid(), syscall.SIGSTOP)
|
||||
_ = syscall.Kill(syscall.Getpid(), syscall.SIGSTOP)
|
||||
case syscall.SIGCONT:
|
||||
cui.InitTerm()
|
||||
bombadillo.Draw()
|
||||
|
@ -179,7 +178,7 @@ Examples: bombadillo gopher://bombadillo.colorfield.space
|
|||
|
||||
Options:
|
||||
`
|
||||
fmt.Fprint(os.Stdout, art)
|
||||
_, _ = fmt.Fprint(os.Stdout, art)
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
|
|
21
page.go
21
page.go
|
@ -8,11 +8,14 @@ import (
|
|||
// + + + T Y P E S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// Page represents a visited URL's contents; including
|
||||
// the raw content, wrapped content, link slice, URL,
|
||||
// and the current scroll position
|
||||
type Page struct {
|
||||
WrappedContent []string
|
||||
RawContent string
|
||||
Links []string
|
||||
Location Url
|
||||
RawContent string
|
||||
Links []string
|
||||
Location Url
|
||||
ScrollPosition int
|
||||
}
|
||||
|
||||
|
@ -20,9 +23,11 @@ type Page struct {
|
|||
// + + + R E C E I V E R S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// ScrollPositionRange may not be in actual usage....
|
||||
// TODO: find where this is being used
|
||||
func (p *Page) ScrollPositionRange(termHeight int) (int, int) {
|
||||
termHeight -= 3
|
||||
if len(p.WrappedContent) - p.ScrollPosition < termHeight {
|
||||
if len(p.WrappedContent)-p.ScrollPosition < termHeight {
|
||||
p.ScrollPosition = len(p.WrappedContent) - termHeight
|
||||
}
|
||||
if p.ScrollPosition < 0 {
|
||||
|
@ -38,7 +43,7 @@ func (p *Page) ScrollPositionRange(termHeight int) (int, int) {
|
|||
return p.ScrollPosition, end
|
||||
}
|
||||
|
||||
// Performs a hard wrap to the requested
|
||||
// WrapContent performs a hard wrap to the requested
|
||||
// width and updates the WrappedContent
|
||||
// of the Page struct width a string slice
|
||||
// of the wrapped data
|
||||
|
@ -51,7 +56,7 @@ func (p *Page) WrapContent(width int) {
|
|||
content.WriteRune(ch)
|
||||
counter = 0
|
||||
} else if ch == '\t' {
|
||||
if counter + 4 < width {
|
||||
if counter+4 < width {
|
||||
content.WriteString(" ")
|
||||
counter += 4
|
||||
} else {
|
||||
|
@ -69,7 +74,7 @@ func (p *Page) WrapContent(width int) {
|
|||
content.WriteRune('\n')
|
||||
counter = 0
|
||||
if p.Location.Mime == "1" {
|
||||
spacer := " "
|
||||
spacer := " "
|
||||
content.WriteString(spacer)
|
||||
counter += len(spacer)
|
||||
}
|
||||
|
@ -85,8 +90,8 @@ func (p *Page) WrapContent(width int) {
|
|||
// + + + F U N C T I O N S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// MakePage returns a Page struct with default values
|
||||
func MakePage(url Url, content string, links []string) Page {
|
||||
p := Page{make([]string, 0), content, links, url, 0}
|
||||
return p
|
||||
}
|
||||
|
||||
|
|
33
pages.go
33
pages.go
|
@ -8,22 +8,28 @@ import (
|
|||
// + + + T Y P E S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// Pages is a struct that represents the history of the client.
|
||||
// It functions as a container for the pages (history array) and
|
||||
// tracks the current history length and location.
|
||||
type Pages struct {
|
||||
Position int
|
||||
Length int
|
||||
History [20]Page
|
||||
Length int
|
||||
History [20]Page
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + R E C E I V E R S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// NavigateHistory takes a positive or negative integer
|
||||
// and updates the current history position. Checks are done
|
||||
// to make sure that the position moved to is a valid history
|
||||
// location. Returns an error or nil.
|
||||
func (p *Pages) NavigateHistory(qty int) error {
|
||||
newPosition := p.Position + qty
|
||||
if newPosition < 0 {
|
||||
return fmt.Errorf("You are already at the beginning of history")
|
||||
} else if newPosition > p.Length - 1 {
|
||||
} else if newPosition > p.Length-1 {
|
||||
return fmt.Errorf("Your way is blocked by void, there is nothing forward")
|
||||
}
|
||||
|
||||
|
@ -31,23 +37,29 @@ func (p *Pages) NavigateHistory(qty int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Add gets passed a Page, which gets added to the history
|
||||
// arrayr. Add also updates the current length and position
|
||||
// of the Pages struct to which it belongs. Add also shifts
|
||||
// off array items if necessary.
|
||||
func (p *Pages) Add(pg Page) {
|
||||
if p.Position == p.Length - 1 && p.Length < len(p.History) {
|
||||
if p.Position == p.Length-1 && p.Length < len(p.History) {
|
||||
p.History[p.Length] = pg
|
||||
p.Length++
|
||||
p.Position++
|
||||
} else if p.Position == p.Length - 1 && p.Length == 20 {
|
||||
} else if p.Position == p.Length-1 && p.Length == 20 {
|
||||
for x := 1; x < len(p.History); x++ {
|
||||
p.History[x-1] = p.History[x]
|
||||
}
|
||||
p.History[len(p.History)-1] = pg
|
||||
} else {
|
||||
p.Position += 1
|
||||
p.Position++
|
||||
p.Length = p.Position + 1
|
||||
p.History[p.Position] = pg
|
||||
}
|
||||
}
|
||||
|
||||
// Render wraps the content for the current page and returns
|
||||
// the page content as a string slice
|
||||
func (p *Pages) Render(termHeight, termWidth int) []string {
|
||||
if p.Length < 1 {
|
||||
return make([]string, 0)
|
||||
|
@ -62,12 +74,12 @@ func (p *Pages) Render(termHeight, termWidth int) []string {
|
|||
} else if prev < now {
|
||||
diff := now - prev
|
||||
pos = pos + diff
|
||||
if pos > now - termHeight {
|
||||
if pos > now-termHeight {
|
||||
pos = now - termHeight
|
||||
}
|
||||
}
|
||||
|
||||
if pos < 0 || now < termHeight - 3 {
|
||||
if pos < 0 || now < termHeight-3 {
|
||||
pos = 0
|
||||
}
|
||||
|
||||
|
@ -80,8 +92,7 @@ func (p *Pages) Render(termHeight, termWidth int) []string {
|
|||
// + + + F U N C T I O N S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// MakePages returns a Pages struct with default values
|
||||
func MakePages() Pages {
|
||||
return Pages{-1, 0, [20]Page{}}
|
||||
}
|
||||
|
||||
|
||||
|
|
23
url.go
23
url.go
|
@ -12,13 +12,18 @@ import (
|
|||
// + + + T Y P E S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
// Url is a struct representing the different pieces
|
||||
// of a url. This custom struct is used rather than the
|
||||
// built-in url library so-as to support gopher URLs, as
|
||||
// well as track mime-type and renderability (can the
|
||||
// response to the url be rendered as text in the client).
|
||||
type Url struct {
|
||||
Scheme string
|
||||
Host string
|
||||
Port string
|
||||
Resource string
|
||||
Full string
|
||||
Mime string
|
||||
Scheme string
|
||||
Host string
|
||||
Port string
|
||||
Resource string
|
||||
Full string
|
||||
Mime string
|
||||
DownloadOnly bool
|
||||
}
|
||||
|
||||
|
@ -28,12 +33,10 @@ type Url struct {
|
|||
|
||||
// There are currently no receivers for the Url struct
|
||||
|
||||
|
||||
//------------------------------------------------\\
|
||||
// + + + F U N C T I O N S + + + \\
|
||||
//--------------------------------------------------\\
|
||||
|
||||
|
||||
// MakeUrl is a Url constructor that takes in a string
|
||||
// representation of a url and returns a Url struct and
|
||||
// an error (or nil).
|
||||
|
@ -152,7 +155,7 @@ func parseFinger(u string) (Url, error) {
|
|||
if len(userPlusAddress) > 1 {
|
||||
out.Resource = userPlusAddress[0]
|
||||
u = userPlusAddress[1]
|
||||
}
|
||||
}
|
||||
hostPort := strings.Split(u, ":")
|
||||
if len(hostPort) < 2 {
|
||||
out.Port = "79"
|
||||
|
@ -167,5 +170,3 @@ func parseFinger(u string) (Url, error) {
|
|||
out.Full = fmt.Sprintf("%s://%s%s:%s", out.Scheme, resource, out.Host, out.Port)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue