Release 2.3.3 to master #204
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
bombadillo
|
bombadillo
|
||||||
*.asciinema
|
*.asciinema
|
||||||
|
*.swp
|
||||||
|
|
|
@ -25,10 +25,10 @@ Changes are implemented to the default branch when:
|
||||||
|
|
||||||
### Process for introducing a new change
|
### Process for introducing a new change
|
||||||
|
|
||||||
Please refer to our [notes on contributing](README.md#contributing) to get an understanding of how new changes are initiated, the type of changes accepted and the review process.
|
Before you begin, please refer to our [notes on contributing](README.md#contributing) to get an understanding of how new changes are initiated, the type of changes accepted and the review process.
|
||||||
|
|
||||||
1. Create a new feature branch based on the **develop** branch.
|
1. Create a new feature branch based on the **develop** branch.
|
||||||
1. Raise a pull request (PR) targeting the **develop** branch.
|
1. Raise a pull request (PR) targeting the current release branch (confirm this in the issue comments before proceeding).
|
||||||
1. The PR is reviewed.
|
1. The PR is reviewed.
|
||||||
1. If the PR is approved, it is merged.
|
1. If the PR is approved, it is merged.
|
||||||
1. The version number is incremented, along with any other release activity.
|
1. The version number is incremented, along with any other release activity.
|
||||||
|
|
65
client.go
65
client.go
|
@ -344,23 +344,26 @@ func (c *client) simpleCommand(action string) {
|
||||||
case "SEARCH":
|
case "SEARCH":
|
||||||
c.search("", "", "?")
|
c.search("", "", "?")
|
||||||
case "HELP", "?":
|
case "HELP", "?":
|
||||||
go c.Visit(helplocation)
|
c.Visit(helplocation)
|
||||||
default:
|
default:
|
||||||
c.SetMessage(fmt.Sprintf("Unknown action %q", action), true)
|
c.SetMessage(syntaxErrorMessage(action), true)
|
||||||
c.DrawMessage()
|
c.DrawMessage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) doCommand(action string, values []string) {
|
func (c *client) doCommand(action string, values []string) {
|
||||||
if length := len(values); length != 1 {
|
|
||||||
c.SetMessage(fmt.Sprintf("Expected 1 argument, received %d", len(values)), true)
|
|
||||||
c.DrawMessage()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case "CHECK", "C":
|
case "C", "CHECK":
|
||||||
c.displayConfigValue(values[0])
|
c.displayConfigValue(values[0])
|
||||||
|
c.DrawMessage()
|
||||||
|
case "HELP", "?":
|
||||||
|
if val, ok := ERRS[values[0]]; ok {
|
||||||
|
c.SetMessage("Usage: " + val, false)
|
||||||
|
} else {
|
||||||
|
msg := fmt.Sprintf("%q is not a valid command; help syntax: %s", values[0], ERRS[action])
|
||||||
|
c.SetMessage(msg, false)
|
||||||
|
}
|
||||||
|
c.DrawMessage()
|
||||||
case "PURGE", "P":
|
case "PURGE", "P":
|
||||||
err := c.Certs.Purge(values[0])
|
err := c.Certs.Purge(values[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -405,24 +408,22 @@ func (c *client) doCommand(action string, values []string) {
|
||||||
c.saveFile(u, fn)
|
c.saveFile(u, fn)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
c.SetMessage(fmt.Sprintf("Unknown action %q", action), true)
|
c.SetMessage(syntaxErrorMessage(action), true)
|
||||||
c.DrawMessage()
|
c.DrawMessage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) doCommandAs(action string, values []string) {
|
func (c *client) doCommandAs(action string, values []string) {
|
||||||
if len(values) < 2 {
|
|
||||||
c.SetMessage(fmt.Sprintf("Expected 2+ arguments, received %d", len(values)), true)
|
|
||||||
c.DrawMessage()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if values[0] == "." {
|
|
||||||
values[0] = c.PageState.History[c.PageState.Position].Location.Full
|
|
||||||
}
|
|
||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
case "ADD", "A":
|
case "ADD", "A":
|
||||||
|
if len(values) < 2 {
|
||||||
|
c.SetMessage(syntaxErrorMessage(action), true)
|
||||||
|
c.DrawMessage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if values[0] == "." {
|
||||||
|
values[0] = c.PageState.History[c.PageState.Position].Location.Full
|
||||||
|
}
|
||||||
msg, err := c.BookMarks.Add(values)
|
msg, err := c.BookMarks.Add(values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.SetMessage(err.Error(), true)
|
c.SetMessage(err.Error(), true)
|
||||||
|
@ -441,8 +442,18 @@ func (c *client) doCommandAs(action string, values []string) {
|
||||||
c.Draw()
|
c.Draw()
|
||||||
}
|
}
|
||||||
case "SEARCH":
|
case "SEARCH":
|
||||||
|
if len(values) < 2 {
|
||||||
|
c.SetMessage(syntaxErrorMessage(action), true)
|
||||||
|
c.DrawMessage()
|
||||||
|
return
|
||||||
|
}
|
||||||
c.search(strings.Join(values, " "), "", "")
|
c.search(strings.Join(values, " "), "", "")
|
||||||
case "SET", "S":
|
case "SET", "S":
|
||||||
|
if len(values) < 2 {
|
||||||
|
c.SetMessage(syntaxErrorMessage(action), true)
|
||||||
|
c.DrawMessage()
|
||||||
|
return
|
||||||
|
}
|
||||||
if _, ok := c.Options[values[0]]; ok {
|
if _, ok := c.Options[values[0]]; ok {
|
||||||
val := strings.Join(values[1:], " ")
|
val := strings.Join(values[1:], " ")
|
||||||
if !validateOpt(values[0], val) {
|
if !validateOpt(values[0], val) {
|
||||||
|
@ -473,7 +484,7 @@ func (c *client) doCommandAs(action string, values []string) {
|
||||||
c.SetMessage(fmt.Sprintf("Unable to set %s, it does not exist", values[0]), true)
|
c.SetMessage(fmt.Sprintf("Unable to set %s, it does not exist", values[0]), true)
|
||||||
c.DrawMessage()
|
c.DrawMessage()
|
||||||
default:
|
default:
|
||||||
c.SetMessage(fmt.Sprintf("Unknown command structure"), true)
|
c.SetMessage(syntaxErrorMessage(action), true)
|
||||||
c.DrawMessage()
|
c.DrawMessage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -523,7 +534,7 @@ func (c *client) doLinkCommandAs(action, target string, values []string) {
|
||||||
out = append(out, values...)
|
out = append(out, values...)
|
||||||
c.doCommandAs(action, out)
|
c.doCommandAs(action, out)
|
||||||
default:
|
default:
|
||||||
c.SetMessage(fmt.Sprintf("Unknown command structure"), true)
|
c.SetMessage(syntaxErrorMessage(action), true)
|
||||||
c.DrawMessage()
|
c.DrawMessage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -655,7 +666,7 @@ func (c *client) doLinkCommand(action, target string) {
|
||||||
}
|
}
|
||||||
c.saveFile(u, fn)
|
c.saveFile(u, fn)
|
||||||
default:
|
default:
|
||||||
c.SetMessage("Unknown command structure", true)
|
c.SetMessage(syntaxErrorMessage(action), true)
|
||||||
c.DrawMessage()
|
c.DrawMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -977,6 +988,7 @@ func (c *client) handleGemini(u Url) {
|
||||||
case 2:
|
case 2:
|
||||||
// Success
|
// Success
|
||||||
if capsule.MimeMaj == "text" || (c.Options["showimages"] == "true" && capsule.MimeMaj == "image") {
|
if capsule.MimeMaj == "text" || (c.Options["showimages"] == "true" && capsule.MimeMaj == "image") {
|
||||||
|
u.Mime = capsule.MimeMin
|
||||||
pg := MakePage(u, capsule.Content, capsule.Links)
|
pg := MakePage(u, capsule.Content, capsule.Links)
|
||||||
pg.FileType = capsule.MimeMaj
|
pg.FileType = capsule.MimeMaj
|
||||||
pg.WrapContent(c.Width-1, (c.Options["theme"] == "color"))
|
pg.WrapContent(c.Width-1, (c.Options["theme"] == "color"))
|
||||||
|
@ -1203,6 +1215,13 @@ func findAvailableFileName(fpath, fname string) (string, error) {
|
||||||
return savePath, nil
|
return savePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func syntaxErrorMessage(action string) string {
|
||||||
|
if val, ok := ERRS[action]; ok {
|
||||||
|
return fmt.Sprintf("Incorrect syntax. Try: %s", val)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Unknown command %q", action)
|
||||||
|
}
|
||||||
|
|
||||||
func updateTimeouts(timeoutString string) error {
|
func updateTimeouts(timeoutString string) error {
|
||||||
sec, err := strconv.Atoi(timeoutString)
|
sec, err := strconv.Atoi(timeoutString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -94,10 +94,10 @@ func (p *Parser) parseAction() (*Command, error) {
|
||||||
case Value:
|
case Value:
|
||||||
cm.Target = t.val
|
cm.Target = t.val
|
||||||
cm.Type = DOLINK
|
cm.Type = DOLINK
|
||||||
case Word:
|
case Word, Action:
|
||||||
cm.Value = append(cm.Value, t.val)
|
cm.Value = append(cm.Value, t.val)
|
||||||
cm.Type = DO
|
cm.Type = DO
|
||||||
case Action, Whitespace:
|
case Whitespace:
|
||||||
return nil, fmt.Errorf("Found %q (%d), expected value", t.val, t.kind)
|
return nil, fmt.Errorf("Found %q (%d), expected value", t.val, t.kind)
|
||||||
}
|
}
|
||||||
t = p.scan()
|
t = p.scan()
|
||||||
|
|
|
@ -102,6 +102,7 @@ func Getch() rune {
|
||||||
|
|
||||||
func GetLine(prefix string) (string, error) {
|
func GetLine(prefix string) (string, error) {
|
||||||
termios.SetLineMode()
|
termios.SetLineMode()
|
||||||
|
defer termios.SetCharMode()
|
||||||
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
fmt.Print(prefix)
|
fmt.Print(prefix)
|
||||||
|
@ -110,7 +111,6 @@ func GetLine(prefix string) (string, error) {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
termios.SetCharMode()
|
|
||||||
return text[:len(text)-1], nil
|
return text[:len(text)-1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -361,6 +361,7 @@ func parseGemini(b, currentUrl string) (string, []string) {
|
||||||
links := make([]string, 0, 10)
|
links := make([]string, 0, 10)
|
||||||
|
|
||||||
inPreBlock := false
|
inPreBlock := false
|
||||||
|
spacer := " "
|
||||||
|
|
||||||
outputIndex := 0
|
outputIndex := 0
|
||||||
for i, ln := range splitContent {
|
for i, ln := range splitContent {
|
||||||
|
@ -371,7 +372,7 @@ func parseGemini(b, currentUrl string) (string, []string) {
|
||||||
alt := strings.TrimSpace(ln)
|
alt := strings.TrimSpace(ln)
|
||||||
if len(alt) > 3 {
|
if len(alt) > 3 {
|
||||||
alt = strings.TrimSpace(alt[3:])
|
alt = strings.TrimSpace(alt[3:])
|
||||||
splitContent[outputIndex] = fmt.Sprintf("[ %s ]", alt)
|
splitContent[outputIndex] = fmt.Sprintf("%s[ALT][ %s ]", spacer, alt)
|
||||||
outputIndex++
|
outputIndex++
|
||||||
}
|
}
|
||||||
} else if isPreBlockDeclaration {
|
} else if isPreBlockDeclaration {
|
||||||
|
@ -401,7 +402,12 @@ func parseGemini(b, currentUrl string) (string, []string) {
|
||||||
if inPreBlock && (BlockBehavior == "alt" || BlockBehavior == "neither") {
|
if inPreBlock && (BlockBehavior == "alt" || BlockBehavior == "neither") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
splitContent[outputIndex] = ln
|
var leader, tail string = "", ""
|
||||||
|
if len(ln) > 0 && ln[0] == '#' {
|
||||||
|
leader = "\033[1m"
|
||||||
|
tail = "\033[0m"
|
||||||
|
}
|
||||||
|
splitContent[outputIndex] = fmt.Sprintf("%s%s%s%s", spacer, leader, ln, tail)
|
||||||
outputIndex++
|
outputIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,8 @@ func parseMap(text string) (string, []string) {
|
||||||
} else {
|
} else {
|
||||||
link := buildLink(line[2], line[3], string(line[0][0]), line[1])
|
link := buildLink(line[2], line[3], string(line[0][0]), line[1])
|
||||||
links = append(links, link)
|
links = append(links, link)
|
||||||
linktext := fmt.Sprintf("(%s) %2d %s", getType(string(line[0][0])), len(links), title)
|
linkNum := fmt.Sprintf("[%d]",len(links))
|
||||||
|
linktext := fmt.Sprintf("%s %5s %s", getType(string(line[0][0])), linkNum, title)
|
||||||
splitContent[i] = linktext
|
splitContent[i] = linktext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
28
help.go
Normal file
28
help.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
// ERRS maps commands to their syntax error message
|
||||||
|
var ERRS = map[string]string{
|
||||||
|
"A": "`a [target] [name...]`",
|
||||||
|
"ADD": "`add [target] [name...]`",
|
||||||
|
"D": "`d [bookmark-id]`",
|
||||||
|
"DELETE": "`delete [bookmark-id]`",
|
||||||
|
"B": "`b [[bookmark-id]]`",
|
||||||
|
"BOOKMARKS": "`bookmarks [[bookmark-id]]`",
|
||||||
|
"C": "`c [link_id]` or `c [setting]`",
|
||||||
|
"CHECK": "`check [link_id]` or `check [setting]`",
|
||||||
|
"H": "`h`",
|
||||||
|
"HOME": "`home`",
|
||||||
|
"P": "`p [host]`",
|
||||||
|
"PURGE": "`purge [host]`",
|
||||||
|
"Q": "`q`",
|
||||||
|
"QUIT": "`quit`",
|
||||||
|
"R": "`r`",
|
||||||
|
"RELOAD": "`reload`",
|
||||||
|
"SEARCH": "`search [[keyword(s)...]]`",
|
||||||
|
"S": "`s [setting] [value]`",
|
||||||
|
"SET": "`set [setting] [value]`",
|
||||||
|
"W": "`w [target]`",
|
||||||
|
"WRITE": "`write [target]`",
|
||||||
|
"?": "`? [[command]]`",
|
||||||
|
"HELP": "`help [[command]]`",
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ func Visit(webmode, url string, width int) (Page, error) {
|
||||||
return Page{}, fmt.Errorf("Invalid webmode setting")
|
return Page{}, fmt.Errorf("Invalid webmode setting")
|
||||||
}
|
}
|
||||||
c, err := exec.Command(webmode, "-dump", w, fmt.Sprintf("%d", width), url).Output()
|
c, err := exec.Command(webmode, "-dump", w, fmt.Sprintf("%d", width), url).Output()
|
||||||
if err != nil {
|
if err != nil && c == nil {
|
||||||
return Page{}, err
|
return Page{}, err
|
||||||
}
|
}
|
||||||
return parseLinks(string(c)), nil
|
return parseLinks(string(c)), nil
|
||||||
|
|
14
page.go
14
page.go
|
@ -72,11 +72,17 @@ func (p *Page) WrapContent(width int, color bool) {
|
||||||
}
|
}
|
||||||
width = min(width, 100)
|
width = min(width, 100)
|
||||||
counter := 0
|
counter := 0
|
||||||
spacer := " "
|
spacer := ""
|
||||||
var content strings.Builder
|
var content strings.Builder
|
||||||
var esc strings.Builder
|
var esc strings.Builder
|
||||||
escape := false
|
escape := false
|
||||||
content.Grow(len(p.RawContent))
|
content.Grow(len(p.RawContent))
|
||||||
|
|
||||||
|
if p.Location.Mime == "1" { // gopher document
|
||||||
|
spacer = " "
|
||||||
|
} else if strings.HasSuffix(p.Location.Mime, "gemini") { //gemini document
|
||||||
|
spacer = " "
|
||||||
|
}
|
||||||
for _, ch := range []rune(p.RawContent) {
|
for _, ch := range []rune(p.RawContent) {
|
||||||
if escape {
|
if escape {
|
||||||
if color {
|
if color {
|
||||||
|
@ -125,10 +131,8 @@ func (p *Page) WrapContent(width int, color bool) {
|
||||||
} else {
|
} else {
|
||||||
content.WriteRune('\n')
|
content.WriteRune('\n')
|
||||||
counter = 0
|
counter = 0
|
||||||
if p.Location.Mime == "1" {
|
content.WriteString(spacer)
|
||||||
content.WriteString(spacer)
|
counter += len(spacer)
|
||||||
counter += len(spacer)
|
|
||||||
}
|
|
||||||
content.WriteRune(ch)
|
content.WriteRune(ch)
|
||||||
counter++
|
counter++
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user