2.1.0 Release - Merge branch 'develop' of sloum/bombadillo into master

This commit is contained in:
Sloom Sloum Sluom IV 2020-01-04 14:37:05 -05:00 committed by Gitea
commit b4e077869f
10 changed files with 281 additions and 74 deletions

View File

@ -1 +1 @@
v2.0.0
2.1.0

View File

@ -4,8 +4,7 @@
.SH SYNOPSIS
.nf
.fam C
\fBbombadillo\fP [\fIurl\fP]
\fBbombadillo\fP [\fBOPTION\fP]
\fBbombadillo\fP [\fIoptions\fP] [\fIurl\fP]
.fam T
.fi
.SH DESCRIPTION
@ -15,12 +14,16 @@
.SH OPTIONS
.TP
.B
\fB-v\fP
Display version information and exit.
\fB-h\fP
Display usage help and exit. Provides a list of all command line options with a short description and exits.
.TP
.B
\fB-h\fP
Usage help. Displays all command line options with a short description.
\fB-t\fP
Set the window title to 'Bombadillo'. Can be used in a GUI environment, however not all terminals support this feature.
.TP
.B
\fB-v\fP
Display version information and exit.
.SH PROTOCOL SUPPORT
All of the below protocols are supported. With the exception of gopher, the protocol name must be present as the scheme component of a url in the form of \fI[protocol]://[the rest of the url]\fP.
.TP
@ -38,7 +41,7 @@ Basic support is provided for the finger protocol. The format is: \fIfinger://[[
.TP
.B
local
Local is similar to the \fIfile\fP protocol used in web browsers or the like, with a smaller set of features. Users can use the local scheme to view files on their local system. Directories are supported as viewable text object as well as any files. Wildcards and globbing are not supported. Using \fI~\fP to represent a user's home directory, as well as relative paths, are supported.
Local is similar to the \fIfile\fP protocol used in web browsers or the like, with a smaller set of features. Users can use the local scheme to view files on their local system. Directories are supported as viewable text object as well as any files. Wildcards and globbing are not supported. Using \fI~\fP to represent a user's home directory, as well as relative paths, are supported. The \fIcolor\fP theme has no effect on this protocol and all terminal escape sequences will be rendered to the screen literally.
.TP
.B
telnet
@ -88,6 +91,13 @@ k
Scroll up a single line.
.TP
.B
n
Jump to next found text item.
.TP
.B
Jump to previous found text item.
.TP
.B
q
Quit \fBbombadillo\fP.
.TP
@ -100,6 +110,10 @@ u
Scroll up an amount corresponding to 75% of your terminal window height in the current document.
.TP
.B
/
Search for text within current document. / followed by a text query will highlight and allow navigation of found text. / with an empty query will clear the current query.
.TP
.B
<tab>
Toggle the scroll focus between the bookmarks panel and the document panel. Only has an effect if the bookmarks panel is open.
.TP
@ -150,7 +164,7 @@ check [setting name]
Displays the current value for a given configuration setting. \fIc\fP can be used instead of the full \fIcheck\fP.
.TP
.B
delete [bookmark id]]
delete [bookmark id]
Deletes the bookmark matching the bookmark id. \fId\fP can be used instead of the full \fIdelete\fP.
.TP
.B
@ -186,7 +200,7 @@ search [keywords\.\.\.]
Submits a search to the search engine set by the \fIsearchengine\fP setting, with the query being the provided keyword(s).
.TP
.B
set [setting name]
set [setting name] [value]
Sets the value for a given configuration setting. \fIs\fP can be used instead of the full \fIset\fP.
.TP
.B
@ -210,6 +224,10 @@ configlocation
The path to the directory that the \fI.bombadillo.ini\fP configuration file is stored in. This is a \fBread only\fP setting and cannot be changed with the \fIset\fP command, but it can be read with the \fIcheck\fP command.
.TP
.B
defaultscheme
The scheme that should be used when no scheme is present in a given URL. \fIgopher\fP, \fIgemini\fP, \fIhttp\fP, and \fIhttps\fP are valid values.
.TP
.B
homeurl
The url that \fBbombadillo\fP navigates to when the program loads or when the \fIhome\fP or \fIh\fP LINE COMMAND is issued. This should be a valid url. If a scheme/protocol is not included, gopher will be assumed.
.TP
@ -227,7 +245,7 @@ Tells the browser what command to use to start a telnet session. Should be a val
.TP
.B
theme
Can toggle between visual modes. Valid values are \fInormal\fP and \fIinverse\fP. When set to inverse, the terminal color mode is inverted.
Can toggle between visual modes. Valid values are \fInormal\fP, \fIcolor\fP, and \fIinverse\fP. When set to inverse, the normal mode colors are inverted. Both normal and inverse modes filter out terminal escape sequences. When set to color, Bombadillo will render terminal escape sequences representing colors when it finds them in documents.
.TP
.B
tlscertificate

View File

@ -5,6 +5,6 @@ GenericName=Non-Web Browser
Comment=View gopher, gemini, finger, telnet, http(s) sites over the internet
Terminal=true
Categories=Network;WebBrowser;ConsoleOnly;
Exec=bombadillo %U
Exec=bombadillo -t %u
Icon=bombadillo-icon
MimeType=x-scheme-handler/gopher;x-scheme-handler/gemini;x-scheme-handler/finger;

165
client.go
View File

@ -47,8 +47,7 @@ func (c *client) GetSizeOnce() {
cmd.Stdin = os.Stdin
out, err := cmd.Output()
if err != nil {
fmt.Println("Fatal error: Unable to retrieve terminal size")
os.Exit(5)
cui.Exit(5, "Fatal error: Unable to retrieve terminal size")
}
var h, w int
_, _ = fmt.Sscan(string(out), &h, &w)
@ -66,8 +65,7 @@ func (c *client) GetSize() {
cmd.Stdin = os.Stdin
out, err := cmd.Output()
if err != nil {
fmt.Println("Fatal error: Unable to retrieve terminal size")
os.Exit(5)
cui.Exit(5, "Fatal error: Unable to retrieve terminal size")
}
var h, w int
_, _ = fmt.Sscan(string(out), &h, &w)
@ -88,10 +86,12 @@ 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-1)
pageContent := c.PageState.Render(c.Height, c.Width-1, (c.Options["theme"] == "color"))
var re *regexp.Regexp
if c.Options["theme"] == "inverse" {
screen.WriteString("\033[7m")
}
re = regexp.MustCompile(`\033\[(?:\d*;?)+[A-Za-z]`)
if c.BookMarks.IsOpen {
bm := c.BookMarks.Render(c.Width, c.Height)
bmWidth := len([]rune(bm[0]))
@ -99,7 +99,14 @@ func (c *client) Draw() {
if c.Width > bmWidth {
contentWidth := c.Width - bmWidth
if i < len(pageContent) {
screen.WriteString(fmt.Sprintf("%-*.*s", contentWidth, contentWidth, pageContent[i]))
extra := 0
if c.Options["theme"] == "color" {
escapes := re.FindAllString(pageContent[i], -1)
for _, esc := range escapes {
extra += len(esc)
}
}
screen.WriteString(fmt.Sprintf("%-*.*s", contentWidth+extra, contentWidth+extra, pageContent[i]))
} else {
screen.WriteString(fmt.Sprintf("%-*.*s", contentWidth, contentWidth, " "))
}
@ -112,6 +119,9 @@ func (c *client) Draw() {
screen.WriteString("\033[2m")
}
if c.Options["theme"] == "color" {
screen.WriteString("\033[0m")
}
screen.WriteString(bm[i])
if c.Options["theme"] == "inverse" && !c.BookMarks.IsFocused {
@ -125,7 +135,12 @@ func (c *client) Draw() {
} else {
for i := 0; i < c.Height-3; i++ {
if i < len(pageContent) {
screen.WriteString(fmt.Sprintf("%-*.*s", c.Width, c.Width, pageContent[i]))
extra := 0
escapes := re.FindAllString(pageContent[i], -1)
for _, esc := range escapes {
extra += len(esc)
}
screen.WriteString(fmt.Sprintf("%-*.*s", c.Width+extra, c.Width+extra, pageContent[i]))
screen.WriteString("\n")
} else {
screen.WriteString(fmt.Sprintf("%-*.*s", c.Width, c.Width, " "))
@ -157,7 +172,7 @@ func (c *client) TakeControlInput() {
c.Scroll(-1)
case 'q', 'Q':
// quit bombadillo
cui.Exit()
cui.Exit(0, "")
case 'g':
// scroll to top
c.ClearMessage()
@ -217,14 +232,53 @@ func (c *client) TakeControlInput() {
// Toggle bookmark browser focus on/off
c.BookMarks.ToggleFocused()
c.Draw()
case 'n':
// Next search item
c.ClearMessage()
err := c.NextSearchItem(1)
if err != nil {
c.SetMessage(err.Error(), false)
c.DrawMessage()
}
case 'N':
// Previous search item
c.ClearMessage()
err := c.NextSearchItem(-1)
if err != nil {
c.SetMessage(err.Error(), false)
c.DrawMessage()
}
case '/':
// Search for text
c.ClearMessage()
c.ClearMessageLine()
if c.Options["theme"] == "normal" || c.Options["theme"] == "color" {
fmt.Printf("\033[7m%*.*s\r", c.Width, c.Width, "")
}
entry, err := cui.GetLine("/")
c.ClearMessageLine()
if err != nil {
c.SetMessage(err.Error(), true)
c.DrawMessage()
break
}
err = c.find(entry)
if err != nil {
c.SetMessage(err.Error(), true)
c.DrawMessage()
}
err = c.NextSearchItem(0)
if err != nil {
c.Draw()
}
case ':', ' ':
// Process a command
c.ClearMessage()
c.ClearMessageLine()
if c.Options["theme"] == "normal" {
if c.Options["theme"] == "normal" || c.Options["theme"] == "color" {
fmt.Printf("\033[7m%*.*s\r", c.Width, c.Width, "")
}
entry, err := cui.GetLine()
entry, err := cui.GetLine(": ")
c.ClearMessageLine()
if err != nil {
c.SetMessage(err.Error(), true)
@ -278,7 +332,7 @@ func (c *client) simpleCommand(action string) {
action = strings.ToUpper(action)
switch action {
case "Q", "QUIT":
cui.Exit()
cui.Exit(0, "")
case "H", "HOME":
if c.Options["homeurl"] != "unset" {
go c.Visit(c.Options["homeurl"])
@ -622,11 +676,11 @@ func (c *client) search(query, url, question string) {
if query == "" {
c.ClearMessage()
c.ClearMessageLine()
if c.Options["theme"] == "normal" {
if c.Options["theme"] == "normal" || c.Options["theme"] == "color" {
fmt.Printf("\033[7m%*.*s\r", c.Width, c.Width, "")
}
fmt.Print(question)
entry, err = cui.GetLine()
entry, err = cui.GetLine("? ")
c.ClearMessageLine()
if err != nil {
c.SetMessage(err.Error(), true)
@ -728,9 +782,13 @@ func (c *client) ReloadPage() error {
return fmt.Errorf("There is no page to reload")
}
url := c.PageState.History[c.PageState.Position].Location.Full
err := c.PageState.NavigateHistory(-1)
if err != nil {
return err
if c.PageState.Position == 0 {
c.PageState.Position--
} else {
err := c.PageState.NavigateHistory(-1)
if err != nil {
return err
}
}
length := c.PageState.Length
c.Visit(url)
@ -771,7 +829,7 @@ func (c *client) DrawMessage() {
func (c *client) RenderMessage() string {
leadIn, leadOut := "", ""
if c.Options["theme"] == "normal" {
if c.Options["theme"] == "normal" || c.Options["theme"] == "color" {
leadIn = "\033[7m"
leadOut = "\033[0m"
}
@ -780,7 +838,7 @@ func (c *client) RenderMessage() string {
leadIn = "\033[31;1m"
leadOut = "\033[0m"
if c.Options["theme"] == "normal" {
if c.Options["theme"] == "normal" || c.Options["theme"] == "color" {
leadIn = "\033[41;1;7m"
}
}
@ -889,7 +947,7 @@ func (c *client) handleGopher(u Url) {
return
}
pg := MakePage(u, content, links)
pg.WrapContent(c.Width - 1)
pg.WrapContent(c.Width-1, (c.Options["theme"] == "color"))
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
@ -912,7 +970,7 @@ func (c *client) handleGemini(u Url) {
case 2:
if capsule.MimeMaj == "text" {
pg := MakePage(u, capsule.Content, capsule.Links)
pg.WrapContent(c.Width - 1)
pg.WrapContent(c.Width-1, (c.Options["theme"] == "color"))
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
@ -960,7 +1018,7 @@ func (c *client) handleLocal(u Url) {
return
}
pg := MakePage(u, content, links)
pg.WrapContent(c.Width - 1)
pg.WrapContent(c.Width-1, (c.Options["theme"] == "color"))
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
@ -976,7 +1034,7 @@ func (c *client) handleFinger(u Url) {
return
}
pg := MakePage(u, content, []string{})
pg.WrapContent(c.Width - 1)
pg.WrapContent(c.Width-1, (c.Options["theme"] == "color"))
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
@ -996,7 +1054,7 @@ func (c *client) handleWeb(u Url) {
return
}
pg := MakePage(u, page.Content, page.Links)
pg.WrapContent(c.Width - 1)
pg.WrapContent(c.Width-1, (c.Options["theme"] == "color"))
c.PageState.Add(pg)
c.SetPercentRead()
c.ClearMessage()
@ -1029,6 +1087,67 @@ func (c *client) handleWeb(u Url) {
}
}
func (c *client) find(s string) error {
c.PageState.History[c.PageState.Position].SearchTerm = s
c.PageState.History[c.PageState.Position].FindText()
if s == "" {
return nil
}
if len(c.PageState.History[c.PageState.Position].FoundLinkLines) == 0 {
return fmt.Errorf("No text matching %q was found", s)
}
return nil
}
func (c *client) NextSearchItem(dir int) error {
page := c.PageState.History[c.PageState.Position]
if len(page.FoundLinkLines) == 0 {
return fmt.Errorf("The search is over before it has begun")
}
c.PageState.History[c.PageState.Position].SearchIndex += dir
page.SearchIndex += dir
if page.SearchIndex < 0 {
c.PageState.History[c.PageState.Position].SearchIndex = 0
page.SearchIndex = 0
}
if page.SearchIndex >= len(page.FoundLinkLines) {
c.PageState.History[c.PageState.Position].SearchIndex = len(page.FoundLinkLines) - 1
return fmt.Errorf("The search path goes no further")
} else if page.SearchIndex < 0 {
c.PageState.History[c.PageState.Position].SearchIndex = 0
return fmt.Errorf("You are at the beginning of the search path")
}
diff := page.FoundLinkLines[page.SearchIndex] - page.ScrollPosition
c.ScrollForSearch(diff)
c.Draw()
return nil
}
func (c *client) ScrollForSearch(amount int) {
var percentRead int
page := c.PageState.History[c.PageState.Position]
bottom := len(page.WrappedContent) - c.Height + 3 // 3 for the three bars: top, msg, bottom
newScrollPosition := page.ScrollPosition + amount
if newScrollPosition < 0 {
newScrollPosition = 0
} else if newScrollPosition > bottom {
newScrollPosition = bottom
}
c.PageState.History[c.PageState.Position].ScrollPosition = newScrollPosition
if len(page.WrappedContent) < c.Height-3 {
percentRead = 100
} else {
percentRead = int(float32(newScrollPosition+c.Height-3) / float32(len(page.WrappedContent)) * 100.0)
}
c.FootBar.SetPercentRead(percentRead)
c.Draw()
}
//------------------------------------------------\\
// + + + F U N C T I O N S + + + \\
//--------------------------------------------------\\

View File

@ -44,9 +44,13 @@ func moveCursorToward(dir string, amount int) {
}
// Exit performs cleanup operations before exiting the application
func Exit() {
func Exit(exitCode int, msg string) {
CleanupTerm()
os.Exit(0)
if msg != "" {
fmt.Print(msg, "\n")
}
fmt.Print("\033[23;0t") // Restore window title from terminal stack
os.Exit(exitCode)
}
// InitTerm sets the terminal modes appropriate for Bombadillo
@ -93,11 +97,11 @@ func Getch() rune {
return char
}
func GetLine() (string, error) {
func GetLine(prefix string) (string, error) {
SetLineMode()
reader := bufio.NewReader(os.Stdin)
fmt.Print(": ")
fmt.Print(prefix)
text, err := reader.ReadString('\n')
if err != nil {
return "", err

View File

@ -50,7 +50,8 @@ var defaultOptions = map[string]string{
"searchengine": "gopher://gopher.floodgap.com:70/7/v2/vs",
"telnetcommand": "telnet",
"configlocation": xdgConfigPath(),
"theme": "normal", // "normal", "inverted"
"defaultscheme": "gopher", // "gopher", "gemini", "http", "https"
"theme": "normal", // "normal", "inverted", "color"
"tlscertificate": "",
"tlskey": "",
"webmode": "none", // "none", "gui", "lynx", "w3m", "elinks"

57
main.go
View File

@ -47,10 +47,6 @@ func saveConfig() error {
opts.WriteString("\n[SETTINGS]\n")
for k, v := range bombadillo.Options {
if k == "theme" && v != "normal" && v != "inverse" {
v = "normal"
bombadillo.Options["theme"] = "normal"
}
opts.WriteString(k)
opts.WriteRune('=')
opts.WriteString(v)
@ -66,8 +62,9 @@ func saveConfig() error {
func validateOpt(opt, val string) bool {
var validOpts = map[string][]string{
"webmode": []string{"none", "gui", "lynx", "w3m", "elinks"},
"theme": []string{"normal", "inverse"},
"webmode": []string{"none", "gui", "lynx", "w3m", "elinks"},
"theme": []string{"normal", "inverse", "color"},
"defaultscheme": []string{"gopher", "gemini", "http", "https"},
}
opt = strings.ToLower(opt)
@ -86,19 +83,27 @@ func validateOpt(opt, val string) bool {
func lowerCaseOpt(opt, val string) string {
switch opt {
case "webmode", "theme":
case "webmode", "theme", "defaultscheme":
return strings.ToLower(val)
default:
return val
}
}
func loadConfig() error {
file, err := os.Open(bombadillo.Options["configlocation"] + "/.bombadillo.ini")
func loadConfig() {
err := os.MkdirAll(bombadillo.Options["configlocation"], 0755)
if err != nil {
exitMsg := fmt.Sprintf("Error creating 'configlocation' directory: %s", err.Error())
cui.Exit(3, exitMsg)
}
fp := filepath.Join(bombadillo.Options["configlocation"], ".bombadillo.ini")
file, err := os.Open(fp)
if err != nil {
err = saveConfig()
if err != nil {
return err
exitMsg := fmt.Sprintf("Error writing config file during bootup: %s", err.Error())
cui.Exit(4, exitMsg)
}
}
@ -108,11 +113,7 @@ func loadConfig() error {
for _, v := range settings.Settings {
lowerkey := strings.ToLower(v.Key)
if lowerkey == "configlocation" {
// The config defaults to the home folder.
// Users cannot really edit this value. But
// a compile time override is available.
// It is still stored in the ini and as a part
// of the options map.
// Read only
continue
}
@ -132,17 +133,14 @@ func loadConfig() error {
for _, v := range settings.Certs {
bombadillo.Certs.Add(v.Key, v.Value)
}
return nil
}
func initClient() error {
func initClient() {
bombadillo = MakeClient(" ((( Bombadillo ))) ")
err := loadConfig()
loadConfig()
if bombadillo.Options["tlscertificate"] != "" && bombadillo.Options["tlskey"] != "" {
bombadillo.Certs.LoadCertificate(bombadillo.Options["tlscertificate"], bombadillo.Options["tlskey"])
}
return err
}
// In the event of specific signals, ensure the display is shown correctly.
@ -159,7 +157,7 @@ func handleSignals(c <-chan os.Signal) {
cui.InitTerm()
bombadillo.Draw()
case syscall.SIGINT:
cui.Exit()
cui.Exit(130, "")
}
}
}
@ -168,10 +166,10 @@ func handleSignals(c <-chan os.Signal) {
func printHelp() {
art := `Bombadillo - a non-web browser
Syntax: bombadillo [url]
bombadillo [options...]
Syntax: bombadillo [options] [url]
Examples: bombadillo gopher://bombadillo.colorfield.space
bombadillo -t
bombadillo -v
Options:
@ -182,6 +180,7 @@ Options:
func main() {
getVersion := flag.Bool("v", false, "Display version information and exit")
addTitleToXWindow := flag.Bool("t", false, "Set the window title to 'Bombadillo'. Can be used in a GUI environment, however not all terminals support this feature.")
flag.Usage = printHelp
flag.Parse()
if *getVersion {
@ -191,13 +190,15 @@ func main() {
args := flag.Args()
cui.InitTerm()
defer cui.Exit()
err := initClient()
if err != nil {
// if we can't initialize we should bail out
panic(err)
if *addTitleToXWindow {
fmt.Print("\033[22;0t") // Store window title on terminal stack
fmt.Print("\033]0;Bombadillo\007") // Update window title
}
defer cui.Exit(0, "")
initClient()
// watch for signals, send them to be handled
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGTSTP, syscall.SIGCONT, syscall.SIGINT)

69
page.go
View File

@ -1,6 +1,7 @@
package main
import (
"fmt"
"strings"
)
@ -17,6 +18,9 @@ type Page struct {
Links []string
Location Url
ScrollPosition int
FoundLinkLines []int
SearchTerm string
SearchIndex int
}
//------------------------------------------------\\
@ -47,15 +51,23 @@ func (p *Page) ScrollPositionRange(termHeight int) (int, int) {
// width and updates the WrappedContent
// of the Page struct width a string slice
// of the wrapped data
func (p *Page) WrapContent(width int) {
func (p *Page) WrapContent(width int, color bool) {
counter := 0
var content strings.Builder
var esc strings.Builder
escape := false
content.Grow(len(p.RawContent))
for _, ch := range []rune(p.RawContent) {
if escape {
if color {
esc.WriteRune(ch)
}
if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') {
escape = false
if ch == 'm' {
content.WriteString(esc.String())
esc.Reset()
}
}
continue
}
@ -74,10 +86,20 @@ func (p *Page) WrapContent(width int) {
// Get rid of control characters we dont want
continue
} else if ch == 27 {
if p.Location.Scheme == "local" {
if counter+4 >= width {
content.WriteRune('\n')
}
content.WriteString("\\033")
continue
}
escape = true
if color {
esc.WriteRune(ch)
}
continue
} else {
if counter < width {
if counter <= width {
content.WriteRune(ch)
counter++
} else {
@ -94,6 +116,47 @@ func (p *Page) WrapContent(width int) {
}
p.WrappedContent = strings.Split(content.String(), "\n")
p.HighlightFoundText()
}
func (p *Page) HighlightFoundText() {
if p.SearchTerm == "" {
return
}
for i, ln := range p.WrappedContent {
found := strings.Index(ln, p.SearchTerm)
if found < 0 {
continue
}
format := "\033[7m%s\033[27m"
if bombadillo.Options["theme"] == "inverse" {
format = "\033[27m%s\033[7m"
}
ln = strings.ReplaceAll(ln, p.SearchTerm, fmt.Sprintf(format, p.SearchTerm))
p.WrappedContent[i] = ln
}
}
func (p *Page) FindText() {
p.FoundLinkLines = make([]int, 0, 10)
s := p.SearchTerm
p.SearchIndex = 0
if s == "" {
return
}
format := "\033[7m%s\033[27m"
if bombadillo.Options["theme"] == "inverse" {
format = "\033[27m%s\033[7m"
}
for i, ln := range p.WrappedContent {
found := strings.Index(ln, s)
if found < 0 {
continue
}
ln = strings.ReplaceAll(ln, s, fmt.Sprintf(format, s))
p.WrappedContent[i] = ln
p.FoundLinkLines = append(p.FoundLinkLines, i)
}
}
//------------------------------------------------\\
@ -102,6 +165,6 @@ func (p *Page) WrapContent(width int) {
// 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}
p := Page{make([]string, 0), content, links, url, 0, make([]int, 0), "", 0}
return p
}

View File

@ -60,13 +60,13 @@ func (p *Pages) Add(pg Page) {
// 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 {
func (p *Pages) Render(termHeight, termWidth int, color bool) []string {
if p.Length < 1 {
return make([]string, 0)
}
pos := p.History[p.Position].ScrollPosition
prev := len(p.History[p.Position].WrappedContent)
p.History[p.Position].WrapContent(termWidth)
p.History[p.Position].WrapContent(termWidth, color)
now := len(p.History[p.Position].WrappedContent)
if prev > now {
diff := prev - now

3
url.go
View File

@ -44,6 +44,7 @@ func MakeUrl(u string) (Url, error) {
if len(u) < 1 {
return Url{}, fmt.Errorf("Invalid url, unable to parse")
}
if strings.HasPrefix(u, "finger://") {
return parseFinger(u)
}
@ -103,7 +104,7 @@ func MakeUrl(u string) (Url, error) {
out.Scheme = strings.ToLower(out.Scheme)
if out.Scheme == "" {
out.Scheme = "gopher"
out.Scheme = bombadillo.Options["defaultscheme"]
}
if out.Scheme == "gopher" && out.Port == "" {