diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e07554..8d4592c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `ansi` config setting, to disable ANSI colors in pages (#79, #86) - Edit current URL with e (#87) +- If `emoji_favicons` is enabled, new bookmarks will have the domain's favicon prepended (#69, #90) +- The `BROWSER` env var is now also checked when opening web links on Unix (#93) ### Changed - Disabling the `color` config setting also disables ANSI colors in pages (#79, #86) +- Updated [go-isemoji](https://github.com/makeworld-the-better-one/go-isemoji) to v1.1.0 to support Emoji 13.1 for favicons +- The web browser code doesn't check for Xorg anymore, just display variables (#93) +- Bookmarks can be made to non-gemini URLs (#94) + +### Fixed +- XDG user dir file is parsed instead of looking for XDG env vars (#97, #100) ## [v1.5.0] - 2020-09-01 diff --git a/Makefile b/Makefile index 8df09ad..3738545 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ GITV != git describe --tags GITC != git rev-parse --verify HEAD -SRC != find -type f -name '*.go' ! -name '*_test.go' -TEST != find -type f -name '*_test.go' +SRC != find . -type f -name '*.go' ! -name '*_test.go' +TEST != find . -type f -name '*_test.go' PREFIX ?= /usr/local VERSION ?= $(GITV) diff --git a/README.md b/README.md index 12c265a..5c27aff 100644 --- a/README.md +++ b/README.md @@ -61,22 +61,35 @@ brew upgrade amfora ``` ### From Source -This section is for programmers who want to install from source. Make sure you're using Go 1.13 at least, as earlier versions will fail to build. +This section is for advanced users who want to install the latest (possibly unstable) version of Amfora. -The recommended way of installing Amfora fom source is using the Makefile. +**Requirements:** +- Go 1.13 or later +- GNU Make -On Windows, you need install make, which can be done with [Chocolatey](https://chocolatey.org/install): `choco install make`. Please note the Makefile does not intend to support Windows, and so there may be issues. +Please note the Makefile does not intend to support Windows, and so there may be issues. ```shell git clone https://github.com/makeworld-the-better-one/amfora cd amfora # git checkout v1.2.3 # Optionally pin to a specific version instead of the latest commit -make +make # Might be gmake on macOS sudo make install # If you want to install the binary for all users ``` Because you installed with the Makefile, running `amfora -v` will tell you exactly what commit the binary was built from. +MacOS users can also use [Homebrew](https://brew.sh/) to install the latest commit of Amfora: + +``` +brew tap makeworld-the-better-one/tap +brew install --HEAD amfora +``` +You can update it with: +``` +brew upgrade --fetch-HEAD amfora +``` + ## Usage Just call `amfora` or `amfora ` on the terminal. On Windows it might be `amfora.exe` instead. diff --git a/config/config.go b/config/config.go index 128affc..01746c7 100644 --- a/config/config.go +++ b/config/config.go @@ -14,6 +14,8 @@ import ( "github.com/gdamore/tcell" "github.com/makeworld-the-better-one/amfora/cache" homedir "github.com/mitchellh/go-homedir" + "github.com/rkoesters/xdg/basedir" + "github.com/rkoesters/xdg/userdirs" "github.com/spf13/viper" "gitlab.com/tslocum/cview" ) @@ -67,12 +69,11 @@ func Init() error { configDir = amforaAppData } else { // Unix / POSIX system - xdg_config, ok := os.LookupEnv("XDG_CONFIG_HOME") - if ok && strings.TrimSpace(xdg_config) != "" { - configDir = filepath.Join(xdg_config, "amfora") - } else { + if basedir.ConfigHome == "" { // Default to ~/.config/amfora configDir = filepath.Join(home, ".config", "amfora") + } else { + configDir = filepath.Join(basedir.ConfigHome, "amfora") } } configPath = filepath.Join(configDir, "config.toml") @@ -90,12 +91,11 @@ func Init() error { tofuDBDir = amforaAppData } else { // XDG cache dir on POSIX systems - xdg_cache, ok := os.LookupEnv("XDG_CACHE_HOME") - if ok && strings.TrimSpace(xdg_cache) != "" { - tofuDBDir = filepath.Join(xdg_cache, "amfora") - } else { + if basedir.CacheHome == "" { // Default to ~/.cache/amfora tofuDBDir = filepath.Join(home, ".cache", "amfora") + } else { + tofuDBDir = filepath.Join(basedir.CacheHome, "amfora") } } tofuDBPath = filepath.Join(tofuDBDir, "tofu.toml") @@ -106,12 +106,11 @@ func Init() error { bkmkDir = amforaAppData } else { // XDG data dir on POSIX systems - xdg_data, ok := os.LookupEnv("XDG_DATA_HOME") - if ok && strings.TrimSpace(xdg_data) != "" { - bkmkDir = filepath.Join(xdg_data, "amfora") - } else { + if basedir.DataHome == "" { // Default to ~/.local/share/amfora bkmkDir = filepath.Join(home, ".local", "share", "amfora") + } else { + bkmkDir = filepath.Join(basedir.DataHome, "amfora") } } bkmkPath = filepath.Join(bkmkDir, "bookmarks.toml") @@ -181,7 +180,11 @@ func Init() error { if viper.GetString("a-general.downloads") == "" { // Find default Downloads dir // This seems to work for all OSes? - DownloadsDir = filepath.Join(home, "Downloads") + if userdirs.Download == "" { + DownloadsDir = filepath.Join(home, "Downloads") + } else { + DownloadsDir = userdirs.Download + } // Create it just in case err = os.MkdirAll(DownloadsDir, 0755) if err != nil { diff --git a/display/bookmarks.go b/display/bookmarks.go index 7dd6ca9..017c19d 100644 --- a/display/bookmarks.go +++ b/display/bookmarks.go @@ -3,7 +3,6 @@ package display import ( "fmt" "strconv" - "strings" "github.com/gdamore/tcell" "github.com/makeworld-the-better-one/amfora/bookmarks" @@ -71,7 +70,7 @@ func bkmkInit() { // It also accepts a bool indicating whether this page already has a bookmark. // It returns the bookmark name and the bookmark action: // 1, 0, -1 for add/update, cancel, and remove -func openBkmkModal(name string, exists bool) (string, int) { +func openBkmkModal(name string, exists bool, favicon string) (string, int) { // Basically a copy of Input() // Reset buttons before input field, to make sure the input is in focus @@ -86,6 +85,9 @@ func openBkmkModal(name string, exists bool) (string, int) { // Remove and re-add input field - to clear the old text bkmkModal.GetForm().Clear(false) + if favicon != "" && !exists { + name = favicon + " " + name + } bkmkModalText = "" bkmkModal.GetForm().AddInputField("Name: ", name, 0, nil, func(text string) { @@ -133,20 +135,22 @@ func Bookmarks(t *tab) { // It is the high-level way of doing it. It should be called in a goroutine. // It can also be called to edit an existing bookmark. func addBookmark() { - if !strings.HasPrefix(tabs[curTab].page.URL, "gemini://") { - // Can't make bookmarks for other kinds of URLs + t := tabs[curTab] + p := t.page + + if !t.hasContent() { + // It's an about: page, or a malformed one return } - - name, exists := bookmarks.Get(tabs[curTab].page.URL) + name, exists := bookmarks.Get(p.URL) // Open a bookmark modal with the current name of the bookmark, if it exists - newName, action := openBkmkModal(name, exists) + newName, action := openBkmkModal(name, exists, p.Favicon) switch action { case 1: // Add/change the bookmark - bookmarks.Set(tabs[curTab].page.URL, newName) + bookmarks.Set(p.URL, newName) case -1: - bookmarks.Remove(tabs[curTab].page.URL) + bookmarks.Remove(p.URL) } // Other case is action = 0, meaning "Cancel", so nothing needs to happen } diff --git a/go.mod b/go.mod index 2f77ed8..bc129f0 100644 --- a/go.mod +++ b/go.mod @@ -8,12 +8,13 @@ require ( github.com/gdamore/tcell v1.3.1-0.20200608133353-cb1e5d6fa606 github.com/google/go-cmp v0.5.0 // indirect github.com/makeworld-the-better-one/go-gemini v0.8.4 - github.com/makeworld-the-better-one/go-isemoji v1.0.0 + github.com/makeworld-the-better-one/go-isemoji v1.1.0 github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.3.1 // indirect github.com/mmcdole/gofeed v1.0.0 github.com/pelletier/go-toml v1.8.0 // indirect + github.com/rkoesters/xdg v0.0.0-20181125232953-edd15b846f9b github.com/spf13/afero v1.2.2 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect diff --git a/go.sum b/go.sum index 129a600..d8f5d5d 100644 --- a/go.sum +++ b/go.sum @@ -132,8 +132,8 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/makeworld-the-better-one/go-gemini v0.8.4 h1:ntsQ9HnlJCmC9PDqXp/f1SCALjBMwh69BbT4BhFRFaw= github.com/makeworld-the-better-one/go-gemini v0.8.4/go.mod h1:P7/FbZ+IEIbA/d+A0Y3w2GNgD8SA2AcNv7aDGJbaWG4= -github.com/makeworld-the-better-one/go-isemoji v1.0.0 h1:W3O4+qwtXeT8PUDzcQ1UjxiupQWgc/oJHpqwrllx3xM= -github.com/makeworld-the-better-one/go-isemoji v1.0.0/go.mod h1:FBjkPl9rr0G4vlZCc+Mr+QcnOfGCTbGWYW8/1sp06I0= +github.com/makeworld-the-better-one/go-isemoji v1.1.0 h1:wZBHOKB5zAIgaU2vaWnXFDDhatebB8TySrNVxjVV84g= +github.com/makeworld-the-better-one/go-isemoji v1.1.0/go.mod h1:FBjkPl9rr0G4vlZCc+Mr+QcnOfGCTbGWYW8/1sp06I0= github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f h1:YEUlTs5gb35UlBLTgqrub9axWTYB3d7/8TxrkJDZpRI= github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f/go.mod h1:X6sxWNi9PBgQybpR4fpXPVD5fm7svLqZTQ5DJuERIoM= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -186,6 +186,8 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rkoesters/xdg v0.0.0-20181125232953-edd15b846f9b h1:8NiY6v9/IlFU8osj1L7kqzRbrG6e3izRQQjGze1Q1R0= +github.com/rkoesters/xdg v0.0.0-20181125232953-edd15b846f9b/go.mod h1:T1HolqzmdHnJIH6p7A9LDuvYGQgEHx9ijX3vKgDKU60= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= diff --git a/webbrowser/open_browser_darwin.go b/webbrowser/open_browser_darwin.go index e9992b7..44c522e 100644 --- a/webbrowser/open_browser_darwin.go +++ b/webbrowser/open_browser_darwin.go @@ -4,6 +4,7 @@ package webbrowser import "os/exec" +// Open opens `url` in default system browser. func Open(url string) (string, error) { err := exec.Command("open", url).Start() if err != nil { diff --git a/webbrowser/open_browser_other.go b/webbrowser/open_browser_other.go index 706953f..9501034 100644 --- a/webbrowser/open_browser_other.go +++ b/webbrowser/open_browser_other.go @@ -4,6 +4,7 @@ package webbrowser import "fmt" +// Open opens `url` in default system browser, but not on this OS. func Open(url string) (string, error) { return "", fmt.Errorf("unsupported OS for default HTTP handling. Set a command in the config") } diff --git a/webbrowser/open_browser_unix.go b/webbrowser/open_browser_unix.go index 99ecbb5..4d265be 100644 --- a/webbrowser/open_browser_unix.go +++ b/webbrowser/open_browser_unix.go @@ -9,27 +9,40 @@ import ( "os/exec" ) -// OpenInBrowser checks for the presence of a display server -// and environment variables indicating a gui is present. If found -// then xdg-open is called on a url to open said url in the default -// gui web browser for the system +// Open opens `url` in default system browser. It tries to do so in two +// ways (xdg-open and $BROWSER). It only works if there is a display +// server working. +// +// bouncepaw: I tried to support TTYs as well. The idea was to open +// a browser in foreground and return back to amfora after the browser +// is closed. While all browsers I tested opened correctly (w3m, lynx), +// I couldn't make it restore amfora correctly. The screen always ended +// up distorted. None of my stunts with altscreen buffers helped. func Open(url string) (string, error) { - disp := os.Getenv("DISPLAY") - wayland := os.Getenv("WAYLAND_DISPLAY") - _, err := exec.LookPath("Xorg") - if disp == "" && wayland == "" && err != nil { - return "", fmt.Errorf("no gui is available") + var ( + // In prev versions there was also Xorg executable checked for. + // I don't see any reason to check for it. + xorgDisplay = os.Getenv("DISPLAY") + waylandDisplay = os.Getenv("WAYLAND_DISPLAY") + xdgOpenPath, xdgOpenNotFoundErr = exec.LookPath("xdg-open") + envBrowser = os.Getenv("BROWSER") + ) + switch { + case xorgDisplay == "" && waylandDisplay == "": + return "", fmt.Errorf("no display server was found") + 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 { + return "", err + } + return "Opened in system default web browser", nil + case envBrowser != "": + if err := exec.Command(envBrowser, url).Start(); err != nil { + return "", err + } + return "Opened in system default web browser", nil + default: + return "", fmt.Errorf("could not determine system browser") } - - _, err = exec.LookPath("xdg-open") - if err != nil { - return "", fmt.Errorf("xdg-open command not found, cannot open in web browser") - } - // Use start rather than run or output in order - // to release the process and not block - err = exec.Command("xdg-open", url).Start() - if err != nil { - return "", err - } - return "Opened in system default web browser", nil } diff --git a/webbrowser/open_browser_windows.go b/webbrowser/open_browser_windows.go index 61b4bb4..66b8c46 100644 --- a/webbrowser/open_browser_windows.go +++ b/webbrowser/open_browser_windows.go @@ -5,6 +5,7 @@ package webbrowser 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() if err != nil {