Merge branch 'run-format' of sloum/bombadillo into develop

This commit is contained in:
Sloom Sloum Sluom IV 2019-11-11 21:42:29 -05:00 committed by Gitea
commit c36ded496f
18 changed files with 167 additions and 172 deletions

View File

@ -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)}
}

View File

@ -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
}

View File

@ -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}
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -1,5 +0,0 @@
package cui
import (
)

View File

@ -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",
}

View File

@ -2,8 +2,8 @@ package finger
import (
"fmt"
"net"
"io/ioutil"
"net"
"time"
)

View File

@ -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"}
}

View File

@ -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)}
}

View File

@ -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 {

View File

@ -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, ""}
}

View File

@ -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
}

View File

@ -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
View File

@ -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
View File

@ -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
}

View File

@ -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
View File

@ -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
}