mirror of
https://github.com/makew0rld/amfora.git
synced 2024-06-01 18:31:08 +00:00
Merge branch 'master' into commands
This commit is contained in:
commit
96add16a83
|
@ -8,6 +8,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Added
|
||||
- Syntax highlighting for preformatted text blocks with alt text (#252, #263, [wiki page](https://github.com/makeworld-the-better-one/amfora/wiki/Source-Code-Highlighting))
|
||||
|
||||
### Changed
|
||||
- Center text automatically, removing `left_margin` from the config (#233)
|
||||
- `max_width` defaults to 80 columns instead of 100 (#233)
|
||||
|
||||
### Fixed
|
||||
- Modal can't be closed when opening non-gemini text URLs from the commandline (#283, #284)
|
||||
- External programs started by Amfora remain as zombie processes (#219)
|
||||
- Prevent link lines (and other types) from being wider than the `max_width` setting (#280)
|
||||
|
||||
|
||||
## [1.9.2] - 2021-12-10
|
||||
### Fixed
|
||||
|
|
|
@ -142,8 +142,8 @@ Features in *italics* are in the master branch, but not in the latest release.
|
|||
- So is subscribing to a page, to know when it changes
|
||||
- [x] Open non-text files in another application
|
||||
- [x] Ability to stream content instead of downloading it first
|
||||
- [x] Highlighting of preformatted code blocks that list a language in the alt text
|
||||
- [x] Run custom commands using the current or selected URL as an argument
|
||||
- [x] *Highlighting of preformatted code blocks that list a language in the alt text*
|
||||
- [x] *Run custom commands using the current or selected URL as an argument*
|
||||
- [ ] Stream support
|
||||
- [ ] Table of contents for pages
|
||||
- [ ] Search in pages with <kbd>Ctrl-F</kbd>
|
||||
|
|
|
@ -200,8 +200,7 @@ func Init() error {
|
|||
viper.SetDefault("a-general.highlight_style", "monokai")
|
||||
viper.SetDefault("a-general.bullets", true)
|
||||
viper.SetDefault("a-general.show_link", false)
|
||||
viper.SetDefault("a-general.left_margin", 0.15)
|
||||
viper.SetDefault("a-general.max_width", 100)
|
||||
viper.SetDefault("a-general.max_width", 80)
|
||||
viper.SetDefault("a-general.downloads", "")
|
||||
viper.SetDefault("a-general.temp_downloads", "")
|
||||
viper.SetDefault("a-general.page_max_size", 2097152)
|
||||
|
|
|
@ -70,11 +70,8 @@ bullets = true
|
|||
# Whether to show link after link text
|
||||
show_link = false
|
||||
|
||||
# A number from 0 to 1, indicating what percentage of the terminal width the left margin should take up.
|
||||
left_margin = 0.15
|
||||
|
||||
# The max number of columns to wrap a page's text to. Preformatted blocks are not wrapped.
|
||||
max_width = 100
|
||||
max_width = 80
|
||||
|
||||
# 'downloads' is the path to a downloads folder.
|
||||
# An empty value means the code will find the default downloads folder for your system.
|
||||
|
|
|
@ -67,11 +67,8 @@ bullets = true
|
|||
# Whether to show link after link text
|
||||
show_link = false
|
||||
|
||||
# A number from 0 to 1, indicating what percentage of the terminal width the left margin should take up.
|
||||
left_margin = 0.15
|
||||
|
||||
# The max number of columns to wrap a page's text to. Preformatted blocks are not wrapped.
|
||||
max_width = 100
|
||||
max_width = 80
|
||||
|
||||
# 'downloads' is the path to a downloads folder.
|
||||
# An empty value means the code will find the default downloads folder for your system.
|
||||
|
|
|
@ -241,7 +241,7 @@ func Init(version, commit, builtBy string) {
|
|||
}
|
||||
if i <= len(tabs[tab].page.Links) && i > 0 {
|
||||
// It's a valid link number
|
||||
followLink(tabs[tab], tabs[tab].page.URL, tabs[tab].page.Links[i-1])
|
||||
go followLink(tabs[tab], tabs[tab].page.URL, tabs[tab].page.Links[i-1])
|
||||
return
|
||||
}
|
||||
// Invalid link number, don't do anything
|
||||
|
|
|
@ -191,6 +191,8 @@ func open(u string, resp *gemini.Response) {
|
|||
Error("File Opening Error", "Error executing custom command: "+err.Error())
|
||||
return
|
||||
}
|
||||
//nolint:errcheck
|
||||
go proc.Wait() // Prevent zombies, see #219
|
||||
Info("Opened with " + cmd[0])
|
||||
return
|
||||
}
|
||||
|
@ -214,11 +216,14 @@ func open(u string, resp *gemini.Response) {
|
|||
Info("Opened in default system viewer")
|
||||
} else {
|
||||
cmd := mediaHandler.Cmd
|
||||
err := exec.Command(cmd[0], append(cmd[1:], path)...).Start()
|
||||
proc := exec.Command(cmd[0], append(cmd[1:], path)...)
|
||||
err := proc.Start()
|
||||
if err != nil {
|
||||
Error("File Opening Error", "Error executing custom command: "+err.Error())
|
||||
return
|
||||
}
|
||||
//nolint:errcheck
|
||||
go proc.Wait() // Prevent zombies, see #219
|
||||
Info("Opened with " + cmd[0])
|
||||
}
|
||||
App.Draw()
|
||||
|
|
|
@ -48,16 +48,19 @@ func handleHTTP(u string, showInfo bool) bool {
|
|||
}
|
||||
|
||||
// Custom command
|
||||
var err error
|
||||
var proc *exec.Cmd
|
||||
if len(config.HTTPCommand) > 1 {
|
||||
err = exec.Command(config.HTTPCommand[0], append(config.HTTPCommand[1:], u)...).Start()
|
||||
proc = exec.Command(config.HTTPCommand[0], append(config.HTTPCommand[1:], u)...)
|
||||
} else {
|
||||
err = exec.Command(config.HTTPCommand[0], u).Start()
|
||||
proc = exec.Command(config.HTTPCommand[0], u)
|
||||
}
|
||||
err := proc.Start()
|
||||
if err != nil {
|
||||
Error("HTTP Error", "Error executing custom browser command: "+err.Error())
|
||||
return false
|
||||
}
|
||||
//nolint:errcheck
|
||||
go proc.Wait() // Prevent zombies, see #219
|
||||
Info("Opened with: " + config.HTTPCommand[0])
|
||||
|
||||
App.Draw()
|
||||
|
@ -104,15 +107,18 @@ func handleOther(u string) {
|
|||
|
||||
// Custom application command
|
||||
|
||||
var err error
|
||||
var proc *exec.Cmd
|
||||
if len(handler) > 1 {
|
||||
err = exec.Command(handler[0], append(handler[1:], u)...).Start()
|
||||
proc = exec.Command(handler[0], append(handler[1:], u)...)
|
||||
} else {
|
||||
err = exec.Command(handler[0], u).Start()
|
||||
proc = exec.Command(handler[0], u)
|
||||
}
|
||||
err := proc.Start()
|
||||
if err != nil {
|
||||
Error("URL Error", "Error executing custom command: "+err.Error())
|
||||
}
|
||||
//nolint:errcheck
|
||||
go proc.Wait() // Prevent zombies, see #219
|
||||
Info("Opened with: " + handler[0])
|
||||
App.Draw()
|
||||
}
|
||||
|
@ -352,7 +358,7 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
|
|||
// Disable read timeout and go back to start
|
||||
res.SetReadTimeout(0) //nolint: errcheck
|
||||
res.Body.(*rr.RestartReader).Restart()
|
||||
go dlChoice("That page is too large. What would you like to do?", u, res)
|
||||
dlChoice("That page is too large. What would you like to do?", u, res)
|
||||
return ret("", false)
|
||||
}
|
||||
if errors.Is(err, renderer.ErrTimedOut) {
|
||||
|
@ -360,7 +366,7 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
|
|||
// Disable read timeout and go back to start
|
||||
res.SetReadTimeout(0) //nolint: errcheck
|
||||
res.Body.(*rr.RestartReader).Restart()
|
||||
go dlChoice("Loading that page timed out. What would you like to do?", u, res)
|
||||
dlChoice("Loading that page timed out. What would you like to do?", u, res)
|
||||
return ret("", false)
|
||||
}
|
||||
if err != nil {
|
||||
|
@ -493,7 +499,7 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
|
|||
// Disable read timeout and go back to start
|
||||
res.SetReadTimeout(0) //nolint: errcheck
|
||||
res.Body.(*rr.RestartReader).Restart()
|
||||
go dlChoice("That file could not be displayed. What would you like to do?", u, res)
|
||||
dlChoice("That file could not be displayed. What would you like to do?", u, res)
|
||||
}
|
||||
}()
|
||||
return ret("", false)
|
||||
|
@ -503,6 +509,6 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
|
|||
// Disable read timeout and go back to start
|
||||
res.SetReadTimeout(0) //nolint: errcheck
|
||||
res.Body.(*rr.RestartReader).Restart()
|
||||
go dlChoice("That file could not be displayed. What would you like to do?", u, res)
|
||||
dlChoice("That file could not be displayed. What would you like to do?", u, res)
|
||||
return ret("", false)
|
||||
}
|
||||
|
|
|
@ -16,24 +16,21 @@ import (
|
|||
// The bookmark modal is in bookmarks.go
|
||||
|
||||
var infoModal = cview.NewModal()
|
||||
|
||||
var errorModal = cview.NewModal()
|
||||
var errorModalDone = make(chan struct{})
|
||||
|
||||
var inputModal = cview.NewModal()
|
||||
var inputCh = make(chan string)
|
||||
var inputModalText string // The current text of the input field in the modal
|
||||
|
||||
var yesNoModal = cview.NewModal()
|
||||
|
||||
// Channel to receive yesNo answer on
|
||||
var inputCh = make(chan string)
|
||||
var yesNoCh = make(chan bool)
|
||||
|
||||
var inputModalText string // The current text of the input field in the modal
|
||||
|
||||
// Internal channel used to know when a modal has been dismissed
|
||||
var modalDone = make(chan struct{})
|
||||
|
||||
func modalInit() {
|
||||
infoModal.AddButtons([]string{"Ok"})
|
||||
|
||||
errorModal.AddButtons([]string{"Ok"})
|
||||
|
||||
yesNoModal.AddButtons([]string{"Yes", "No"})
|
||||
|
||||
panels.AddPanel(PanelInfoModal, infoModal, false, false)
|
||||
|
@ -145,6 +142,7 @@ func modalInit() {
|
|||
panels.HidePanel(PanelInfoModal)
|
||||
App.SetFocus(tabs[curTab].view)
|
||||
App.Draw()
|
||||
modalDone <- struct{}{}
|
||||
})
|
||||
|
||||
errorModal.SetBorder(true)
|
||||
|
@ -153,7 +151,7 @@ func modalInit() {
|
|||
panels.HidePanel(PanelErrorModal)
|
||||
App.SetFocus(tabs[curTab].view)
|
||||
App.Draw()
|
||||
errorModalDone <- struct{}{}
|
||||
modalDone <- struct{}{}
|
||||
})
|
||||
|
||||
inputModal.SetBorder(true)
|
||||
|
@ -183,7 +181,7 @@ func modalInit() {
|
|||
dlInit()
|
||||
}
|
||||
|
||||
// Error displays an error on the screen in a modal.
|
||||
// Error displays an error on the screen in a modal, and blocks until dismissed by the user.
|
||||
func Error(title, text string) {
|
||||
if text == "" {
|
||||
text = "No additional information."
|
||||
|
@ -203,19 +201,21 @@ func Error(title, text string) {
|
|||
App.SetFocus(errorModal)
|
||||
App.Draw()
|
||||
|
||||
<-errorModalDone
|
||||
<-modalDone
|
||||
}
|
||||
|
||||
// Info displays some info on the screen in a modal.
|
||||
// Info displays some info on the screen in a modal, and blocks until dismissed by the user.
|
||||
func Info(s string) {
|
||||
infoModal.SetText(s)
|
||||
panels.ShowPanel(PanelInfoModal)
|
||||
panels.SendToFront(PanelInfoModal)
|
||||
App.SetFocus(infoModal)
|
||||
App.Draw()
|
||||
|
||||
<-modalDone
|
||||
}
|
||||
|
||||
// Input pulls up a modal that asks for input, and returns the user's input.
|
||||
// Input pulls up a modal that asks for input, waits for that input, and returns it.
|
||||
// It returns an bool indicating if the user chose to send input or not.
|
||||
func Input(prompt string, sensitive bool) (string, bool) {
|
||||
// Remove elements and re-add them - to clear input text and keep input in focus
|
||||
|
@ -257,7 +257,7 @@ func Input(prompt string, sensitive bool) (string, bool) {
|
|||
return resp, true
|
||||
}
|
||||
|
||||
// YesNo displays a modal asking a yes-or-no question.
|
||||
// YesNo displays a modal asking a yes-or-no question, waits for an answer, then returns it as a bool.
|
||||
func YesNo(prompt string) bool {
|
||||
if viper.GetBool("a-general.color") {
|
||||
m := yesNoModal
|
||||
|
@ -289,7 +289,7 @@ func YesNo(prompt string) bool {
|
|||
}
|
||||
|
||||
// Tofu displays the TOFU warning modal.
|
||||
// It returns a bool indicating whether the user wants to continue.
|
||||
// It blocks then returns a bool indicating whether the user wants to continue.
|
||||
func Tofu(host string, expiry time.Time) bool {
|
||||
// Reuses yesNoModal, with error color
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package display
|
||||
|
||||
// This file contains the functions that aren't part of the public API.
|
||||
// The funcs are for network and displaying.
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
@ -9,17 +12,20 @@ import (
|
|||
"github.com/makeworld-the-better-one/amfora/structs"
|
||||
)
|
||||
|
||||
// This file contains the functions that aren't part of the public API.
|
||||
// The funcs are for network and displaying.
|
||||
|
||||
// followLink should be used when the user "clicks" a link on a page.
|
||||
// Not when a URL is opened on a new tab for the first time.
|
||||
// It will handle setting the bottomBar.
|
||||
// followLink should be used when the user "clicks" a link on a page,
|
||||
// but not when a URL is opened on a new tab for the first time.
|
||||
//
|
||||
// It will handle updating the bottomBar.
|
||||
//
|
||||
// It should be called with the `go` keyword to spawn a new goroutine if
|
||||
// it would otherwise block the UI loop, such as when called from an input
|
||||
// handler.
|
||||
//
|
||||
// It blocks until navigation is finished, and we've completed any user
|
||||
// interaction related to loading the URL (such as info, error modals)
|
||||
func followLink(t *tab, prev, next string) {
|
||||
if strings.HasPrefix(next, "about:") {
|
||||
if final, ok := handleAbout(t, next); ok {
|
||||
t.addToHistory(final)
|
||||
}
|
||||
goURL(t, next)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -29,7 +35,7 @@ func followLink(t *tab, prev, next string) {
|
|||
Error("URL Error", err.Error())
|
||||
return
|
||||
}
|
||||
go goURL(t, nextURL)
|
||||
goURL(t, nextURL)
|
||||
return
|
||||
}
|
||||
// No content on current tab, so the "prev" URL is not valid.
|
||||
|
@ -39,7 +45,7 @@ func followLink(t *tab, prev, next string) {
|
|||
Error("URL Error", "Link URL could not be parsed")
|
||||
return
|
||||
}
|
||||
go goURL(t, next)
|
||||
goURL(t, next)
|
||||
}
|
||||
|
||||
// reformatPage will take the raw page content and reformat it according to the current terminal dimensions.
|
||||
|
|
|
@ -86,7 +86,7 @@ func makeNewTab() *tab {
|
|||
linkN, _ := strconv.Atoi(currentSelection[0])
|
||||
tabs[tab].page.Selected = tabs[tab].page.Links[linkN]
|
||||
tabs[tab].page.SelectedID = currentSelection[0]
|
||||
followLink(tabs[tab], tabs[tab].page.URL, tabs[tab].page.Links[linkN])
|
||||
go followLink(tabs[tab], tabs[tab].page.URL, tabs[tab].page.Links[linkN])
|
||||
return
|
||||
}
|
||||
if len(currentSelection) == 0 && (key == tcell.KeyEnter || key == tcell.KeyTab) {
|
||||
|
@ -156,12 +156,12 @@ func makeNewTab() *tab {
|
|||
if t.hasContent() {
|
||||
savePath, err := downloadPage(t.page)
|
||||
if err != nil {
|
||||
Error("Download Error", fmt.Sprintf("Error saving page content: %v", err))
|
||||
go Error("Download Error", fmt.Sprintf("Error saving page content: %v", err))
|
||||
} else {
|
||||
Info(fmt.Sprintf("Page content saved to %s. ", savePath))
|
||||
go Info(fmt.Sprintf("Page content saved to %s. ", savePath))
|
||||
}
|
||||
} else {
|
||||
Info("The current page has no content, so it couldn't be downloaded.")
|
||||
go Info("The current page has no content, so it couldn't be downloaded.")
|
||||
}
|
||||
return nil
|
||||
case config.CmdBack:
|
||||
|
@ -178,7 +178,7 @@ func makeNewTab() *tab {
|
|||
currentURL := tabs[curTab].page.URL
|
||||
err := clipboard.WriteAll(currentURL)
|
||||
if err != nil {
|
||||
Error("Copy Error", err.Error())
|
||||
go Error("Copy Error", err.Error())
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
|
@ -193,14 +193,14 @@ func makeNewTab() *tab {
|
|||
if err != nil {
|
||||
err := clipboard.WriteAll(selectedURL)
|
||||
if err != nil {
|
||||
Error("Copy Error", err.Error())
|
||||
go Error("Copy Error", err.Error())
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
err = clipboard.WriteAll(copiedURL.String())
|
||||
if err != nil {
|
||||
Error("Copy Error", err.Error())
|
||||
go Error("Copy Error", err.Error())
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
|
@ -209,7 +209,7 @@ func makeNewTab() *tab {
|
|||
if cmd >= config.CmdLink1 && cmd <= config.CmdLink0 {
|
||||
if int(cmd) <= len(t.page.Links) {
|
||||
// It's a valid link number
|
||||
followLink(&t, t.page.URL, t.page.Links[cmd-1])
|
||||
go followLink(&t, t.page.URL, t.page.Links[cmd-1])
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,4 +29,5 @@ Thank you to the following contributors, who have helped make Amfora great. FOSS
|
|||
* Michael McDonagh (@m-mcdonagh)
|
||||
* mooff (@awfulcooking)
|
||||
* Josias (@justjosias)
|
||||
* mntn (@mntn-xyz)
|
||||
`)
|
||||
|
|
|
@ -63,7 +63,14 @@ func isValidTab(t *tab) bool {
|
|||
}
|
||||
|
||||
func leftMargin() int {
|
||||
return int(float64(termW) * viper.GetFloat64("a-general.left_margin"))
|
||||
// Return the left margin size that centers the text, assuming it's the max width
|
||||
// https://github.com/makeworld-the-better-one/amfora/issues/233
|
||||
|
||||
lm := (termW - viper.GetInt("a-general.max_width")) / 2
|
||||
if lm < 0 {
|
||||
return 0
|
||||
}
|
||||
return lm
|
||||
}
|
||||
|
||||
func textWidth() int {
|
||||
|
@ -73,13 +80,11 @@ func textWidth() int {
|
|||
return viper.GetInt("a-general.max_width")
|
||||
}
|
||||
|
||||
rightMargin := leftMargin()
|
||||
if leftMargin() > 10 {
|
||||
// 10 is the max right margin
|
||||
rightMargin = 10
|
||||
}
|
||||
// Subtract left and right margin from total width to get text width
|
||||
// Left and right margin are equal because text is automatically centered, see:
|
||||
// https://github.com/makeworld-the-better-one/amfora/issues/233
|
||||
|
||||
max := termW - leftMargin() - rightMargin
|
||||
max := termW - leftMargin()*2
|
||||
if max < viper.GetInt("a-general.max_width") {
|
||||
return max
|
||||
}
|
||||
|
|
|
@ -58,6 +58,10 @@ func RenderPlainText(s string) string {
|
|||
//
|
||||
// Set includeFirst to true if the prefix and suffix should be applied to the first wrapped line as well
|
||||
func wrapLine(line string, width int, prefix, suffix string, includeFirst bool) []string {
|
||||
if width < 1 {
|
||||
width = 1
|
||||
}
|
||||
|
||||
// Anonymous function to allow recovery from potential WordWrap panic
|
||||
var ret []string
|
||||
func() {
|
||||
|
@ -196,7 +200,7 @@ func convertRegularGemini(s string, numLinks, width int, proxied bool) (string,
|
|||
// Add the link text in blue (in a region), and a gray link number to the left of it
|
||||
// Those are the default colors, anyway
|
||||
|
||||
wrappedLink = wrapLine(linkText, width,
|
||||
wrappedLink = wrapLine(linkText, width-indent,
|
||||
strings.Repeat(" ", indent)+
|
||||
`["`+strconv.Itoa(num-1)+`"][`+config.GetColorString("amfora_link")+`]`,
|
||||
`[-][""]`,
|
||||
|
@ -211,8 +215,8 @@ func convertRegularGemini(s string, numLinks, width int, proxied bool) (string,
|
|||
} else {
|
||||
// No color
|
||||
|
||||
wrappedLink = wrapLine(linkText, width,
|
||||
strings.Repeat(" ", len(strconv.Itoa(num))+4)+ // +4 for spaces and brackets
|
||||
wrappedLink = wrapLine(linkText, width-indent,
|
||||
strings.Repeat(" ", indent)+ // +4 for spaces and brackets
|
||||
`["`+strconv.Itoa(num-1)+`"]`,
|
||||
`[""]`,
|
||||
false, // Don't indent the first line, it's the one with link number
|
||||
|
@ -228,7 +232,7 @@ func convertRegularGemini(s string, numLinks, width int, proxied bool) (string,
|
|||
if viper.GetBool("a-general.color") {
|
||||
// Color
|
||||
|
||||
wrappedLink = wrapLine(linkText, width,
|
||||
wrappedLink = wrapLine(linkText, width-indent,
|
||||
strings.Repeat(" ", indent)+
|
||||
`["`+strconv.Itoa(num-1)+`"]`+linkTag,
|
||||
`[-::-][""]`,
|
||||
|
@ -242,7 +246,7 @@ func convertRegularGemini(s string, numLinks, width int, proxied bool) (string,
|
|||
} else {
|
||||
// No color
|
||||
|
||||
wrappedLink = wrapLine(linkText, width,
|
||||
wrappedLink = wrapLine(linkText, width-indent,
|
||||
strings.Repeat(" ", indent)+
|
||||
`["`+strconv.Itoa(num-1)+`"]`,
|
||||
`[::-][""]`,
|
||||
|
@ -261,7 +265,8 @@ func convertRegularGemini(s string, numLinks, width int, proxied bool) (string,
|
|||
} else if strings.HasPrefix(lines[i], "* ") {
|
||||
if viper.GetBool("a-general.bullets") {
|
||||
// Wrap list item, and indent wrapped lines past the bullet
|
||||
wrappedItem := wrapLine(lines[i][1:], width,
|
||||
wrappedItem := wrapLine(lines[i][1:],
|
||||
width-4, // Subtract the 4 indent spaces
|
||||
fmt.Sprintf(" [%s]", config.GetColorString("list_text")),
|
||||
"[-]", false)
|
||||
// Add bullet
|
||||
|
@ -269,7 +274,8 @@ func convertRegularGemini(s string, numLinks, width int, proxied bool) (string,
|
|||
wrappedItem[0] + "[-]"
|
||||
wrappedLines = append(wrappedLines, wrappedItem...)
|
||||
} else {
|
||||
wrappedItem := wrapLine(lines[i][1:], width,
|
||||
wrappedItem := wrapLine(lines[i][1:],
|
||||
width-4, // Subtract the 4 indent spaces
|
||||
fmt.Sprintf(" [%s]", config.GetColorString("list_text")),
|
||||
"[-]", false)
|
||||
// Add "*"
|
||||
|
@ -290,7 +296,9 @@ func convertRegularGemini(s string, numLinks, width int, proxied bool) (string,
|
|||
lines[i] = strings.TrimPrefix(lines[i], ">")
|
||||
lines[i] = strings.TrimPrefix(lines[i], " ")
|
||||
wrappedLines = append(wrappedLines,
|
||||
wrapLine(lines[i], width, fmt.Sprintf("[%s::i]> ", config.GetColorString("quote_text")),
|
||||
wrapLine(lines[i],
|
||||
width-2, // Subtract 2 for width of prefix string
|
||||
fmt.Sprintf("[%s::i]> ", config.GetColorString("quote_text")),
|
||||
"[-::-]", true)...,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -7,9 +7,12 @@ import "os/exec"
|
|||
|
||||
// Open opens `path` in default system viewer.
|
||||
func Open(path string) (string, error) {
|
||||
err := exec.Command("open", path).Start()
|
||||
proc := exec.Command("open", path)
|
||||
err := proc.Start()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
//nolint:errcheck
|
||||
go proc.Wait() // Prevent zombies, see #219
|
||||
return "Opened in default system viewer", nil
|
||||
}
|
||||
|
|
|
@ -25,9 +25,12 @@ func Open(path string) (string, error) {
|
|||
case xdgOpenNotFoundErr == nil:
|
||||
// Use start rather than run or output in order
|
||||
// to make application run in background.
|
||||
if err := exec.Command(xdgOpenPath, path).Start(); err != nil {
|
||||
proc := exec.Command(xdgOpenPath, path)
|
||||
if err := proc.Start(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
//nolint:errcheck
|
||||
go proc.Wait() // Prevent zombies, see #219
|
||||
return "Opened in default system viewer", nil
|
||||
default:
|
||||
return "", fmt.Errorf("could not determine default system viewer. " +
|
||||
|
|
|
@ -8,9 +8,12 @@ import "os/exec"
|
|||
|
||||
// Open opens `path` in default system vierwer.
|
||||
func Open(path string) (string, error) {
|
||||
err := exec.Command("rundll32", "url.dll,FileProtocolHandler", path).Start()
|
||||
proc := exec.Command("rundll32", "url.dll,FileProtocolHandler", path)
|
||||
err := proc.Start()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
//nolint:errcheck
|
||||
go proc.Wait() // Prevent zombies, see #219
|
||||
return "Opened in default system viewer", nil
|
||||
}
|
||||
|
|
|
@ -7,9 +7,12 @@ import "os/exec"
|
|||
|
||||
// Open opens `url` in default system browser.
|
||||
func Open(url string) (string, error) {
|
||||
err := exec.Command("open", url).Start()
|
||||
proc := exec.Command("open", url)
|
||||
err := proc.Start()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
//nolint:errcheck
|
||||
go proc.Wait() // Prevent zombies, see #219
|
||||
return "Opened in system default web browser", nil
|
||||
}
|
||||
|
|
|
@ -34,14 +34,20 @@ func Open(url string) (string, error) {
|
|||
case xdgOpenNotFoundErr == nil: // Prefer xdg-open over $BROWSER
|
||||
// Use start rather than run or output in order
|
||||
// to make browser running in background.
|
||||
if err := exec.Command(xdgOpenPath, url).Start(); err != nil {
|
||||
proc := exec.Command(xdgOpenPath, url)
|
||||
if err := proc.Start(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
//nolint:errcheck
|
||||
go proc.Wait() // Prevent zombies, see #219
|
||||
return "Opened in system default web browser", nil
|
||||
case envBrowser != "":
|
||||
if err := exec.Command(envBrowser, url).Start(); err != nil {
|
||||
proc := exec.Command(envBrowser, url)
|
||||
if err := proc.Start(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
//nolint:errcheck
|
||||
go proc.Wait() // Prevent zombies, see #219
|
||||
return "Opened in system default web browser", nil
|
||||
default:
|
||||
return "", fmt.Errorf("could not determine system browser")
|
||||
|
|
|
@ -8,9 +8,12 @@ import "os/exec"
|
|||
|
||||
// Open opens `url` in default system browser.
|
||||
func Open(url string) (string, error) {
|
||||
err := exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
|
||||
proc := exec.Command("rundll32", "url.dll,FileProtocolHandler", url)
|
||||
err := proc.Start()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
//nolint:errcheck
|
||||
go proc.Wait() // Prevent zombies, see #219
|
||||
return "Opened in system default web browser", nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user