From f740ce6cf935e651a5b02f3ef7ad1f39008aedff Mon Sep 17 00:00:00 2001 From: makeworld Date: Thu, 19 Nov 2020 00:07:56 -0500 Subject: [PATCH 01/10] =?UTF-8?q?=F0=9F=92=84=20Switch=20pre.=20text=20col?= =?UTF-8?q?or=20to=20yellow=20-=20less=20passive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- config/theme.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4547b95..bc9d33e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Changed - Updated [go-gemini](https://github.com/makeworld-the-better-one/go-gemini) to v0.9.1 to support CN-only wildcard certs -- Preformatted text is now grey by default +- Preformatted text is now light yellow by default ## [1.6.0] - 2020-11-04 diff --git a/config/theme.go b/config/theme.go index a7177b6..3552c1d 100644 --- a/config/theme.go +++ b/config/theme.go @@ -58,7 +58,7 @@ var theme = map[string]tcell.Color{ "link_number": tcell.ColorSilver, "regular_text": tcell.ColorWhite, "quote_text": tcell.ColorWhite, - "preformatted_text": tcell.ColorGrey, + "preformatted_text": tcell.Color229, // xterm:Wheat1, #ffffaf "list_text": tcell.ColorWhite, } From 780cf4113792928d425b96f2ae24a6c68ad5118e Mon Sep 17 00:00:00 2001 From: makeworld Date: Thu, 19 Nov 2020 00:34:02 -0500 Subject: [PATCH 02/10] =?UTF-8?q?=F0=9F=93=9D=20Document=20user=20themes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + contrib/themes/README.md | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 contrib/themes/README.md diff --git a/README.md b/README.md index 4d626a2..e6c2628 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ Features in *italics* are in the master branch, but not in the latest release. - [x] Bookmarks - [x] Download pages and arbitrary data - [x] Theming + - Check out the [user contributed themes](https://github.com/makeworld-the-better-one/amfora/tree/master/contrib/themes)! - [x] Emoji favicons - See `gemini://mozz.us/files/rfc_gemini_favicon.gmi` for details - Disabled by default, enable in config diff --git a/contrib/themes/README.md b/contrib/themes/README.md new file mode 100644 index 0000000..76d7aae --- /dev/null +++ b/contrib/themes/README.md @@ -0,0 +1,13 @@ +# User Contributed Themes + +You can use these themes by replacing the `[theme]` section of your config with their contents. + +## Nord + +Contributed by **[@lokesh-krishna](https://github.com/lokesh-krishna)**. + +![screenshot of the nord theme](https://user-images.githubusercontent.com/20235646/99020443-a93a1980-2584-11eb-8028-0b95cfcf0fc6.png) + +## Yours? + +Contribute your own theme by opening a PR. \ No newline at end of file From ed7de1d05e26b7013d675722d2750e80d49ff6cd Mon Sep 17 00:00:00 2001 From: makeworld Date: Thu, 19 Nov 2020 00:37:34 -0500 Subject: [PATCH 03/10] =?UTF-8?q?=F0=9F=93=9D=20Themes=20need=20truecolor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/themes/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/themes/README.md b/contrib/themes/README.md index 76d7aae..49704b6 100644 --- a/contrib/themes/README.md +++ b/contrib/themes/README.md @@ -1,6 +1,6 @@ # User Contributed Themes -You can use these themes by replacing the `[theme]` section of your config with their contents. +You can use these themes by replacing the `[theme]` section of your config with their contents. Some themes won't display properly on terminals that do not have truecolor support. ## Nord @@ -10,4 +10,4 @@ Contributed by **[@lokesh-krishna](https://github.com/lokesh-krishna)**. ## Yours? -Contribute your own theme by opening a PR. \ No newline at end of file +Contribute your own theme by opening a PR. From 73bd0717532daa079040d8f155e649414782b42b Mon Sep 17 00:00:00 2001 From: makeworld Date: Thu, 19 Nov 2020 20:49:16 -0500 Subject: [PATCH 04/10] =?UTF-8?q?=F0=9F=94=A7=20Use=20single=20quotes=20fo?= =?UTF-8?q?r=20commands=20and=20paths=20in=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ config/default.go | 28 ++++++++++++++++------------ default-config.toml | 28 ++++++++++++++++------------ 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc9d33e..97df23e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated [go-gemini](https://github.com/makeworld-the-better-one/go-gemini) to v0.9.1 to support CN-only wildcard certs - Preformatted text is now light yellow by default +### Fixed +- Single quotes are used in the default config for commands and paths so that Windows paths with backslashes will be parsed correctly + ## [1.6.0] - 2020-11-04 ### Added diff --git a/config/default.go b/config/default.go index 6329539..d1c5c98 100644 --- a/config/default.go +++ b/config/default.go @@ -28,14 +28,15 @@ auto_redirect = false # # The best to define a command is using a string array. # Examples: -# http = ["firefox"] -# http = ["custom-browser", "--flag", "--option=2"] -# http = ["/path/with spaces/in it/firefox"] +# http = ['firefox'] +# http = ['custom-browser', '--flag', '--option=2'] +# http = ['/path/with spaces/in it/firefox'] # -# Using just a string will also work, but it is deprecated, -# and will degrade if you use paths with spaces. +# Note the use of single quotes, so that backslashes will not be escaped. +# Using just a string will also work, but it is deprecated, and will degrade if +# you use paths with spaces. -http = "default" +http = 'default' # Any URL that will accept a query string can be put here search = "gemini://gus.guru/search" @@ -58,7 +59,8 @@ max_width = 100 # 'downloads' is the path to a downloads folder. # An empty value means the code will find the default downloads folder for your system. # If the path does not exist it will be created. -downloads = "" +# Note the use of single quotes, so that backslashes will not be escaped. +downloads = '' # Max size for displayable content in bytes - after that size a download window pops up page_max_size = 2097152 # 2 MiB @@ -71,16 +73,17 @@ emoji_favicons = false [auth] # Authentication settings +# Note the use of single quotes for values, so that backslashes will not be escaped. [auth.certs] # Client certificates # Set domain name equal to path to client cert -# "example.com" = "mycert.crt" +# "example.com" = 'mycert.crt' [auth.keys] # Client certificate keys # Set domain name equal to path to key for the client cert above -# "example.com" = "mycert.key" +# "example.com" = 'mycert.key' [keybindings] @@ -94,18 +97,19 @@ shift_numbers = "!@#$%^&*()" [url-handlers] # Allows setting the commands to run for various URL schemes. # E.g. to open FTP URLs with FileZilla set the following key: -# ftp = "filezilla" +# ftp = 'filezilla' # You can set any scheme to "off" or "" to disable handling it, or # just leave the key unset. # # DO NOT use this for setting the HTTP command. # Use the http setting in the "a-general" section above. # -# NOTE: These settings are override by the ones in the proxies section. +# NOTE: These settings are overrided by the ones in the proxies section. +# Note the use of single quotes, so that backslashes will not be escaped. # This is a special key that defines the handler for all URL schemes for which # no handler is defined. -other = "off" +other = 'off' [cache] diff --git a/default-config.toml b/default-config.toml index 9ac0d21..b9ec3d3 100644 --- a/default-config.toml +++ b/default-config.toml @@ -25,14 +25,15 @@ auto_redirect = false # # The best to define a command is using a string array. # Examples: -# http = ["firefox"] -# http = ["custom-browser", "--flag", "--option=2"] -# http = ["/path/with spaces/in it/firefox"] +# http = ['firefox'] +# http = ['custom-browser', '--flag', '--option=2'] +# http = ['/path/with spaces/in it/firefox'] # -# Using just a string will also work, but it is deprecated, -# and will degrade if you use paths with spaces. +# Note the use of single quotes, so that backslashes will not be escaped. +# Using just a string will also work, but it is deprecated, and will degrade if +# you use paths with spaces. -http = "default" +http = 'default' # Any URL that will accept a query string can be put here search = "gemini://gus.guru/search" @@ -55,7 +56,8 @@ max_width = 100 # 'downloads' is the path to a downloads folder. # An empty value means the code will find the default downloads folder for your system. # If the path does not exist it will be created. -downloads = "" +# Note the use of single quotes, so that backslashes will not be escaped. +downloads = '' # Max size for displayable content in bytes - after that size a download window pops up page_max_size = 2097152 # 2 MiB @@ -68,16 +70,17 @@ emoji_favicons = false [auth] # Authentication settings +# Note the use of single quotes for values, so that backslashes will not be escaped. [auth.certs] # Client certificates # Set domain name equal to path to client cert -# "example.com" = "mycert.crt" +# "example.com" = 'mycert.crt' [auth.keys] # Client certificate keys # Set domain name equal to path to key for the client cert above -# "example.com" = "mycert.key" +# "example.com" = 'mycert.key' [keybindings] @@ -91,18 +94,19 @@ shift_numbers = "!@#$%^&*()" [url-handlers] # Allows setting the commands to run for various URL schemes. # E.g. to open FTP URLs with FileZilla set the following key: -# ftp = "filezilla" +# ftp = 'filezilla' # You can set any scheme to "off" or "" to disable handling it, or # just leave the key unset. # # DO NOT use this for setting the HTTP command. # Use the http setting in the "a-general" section above. # -# NOTE: These settings are override by the ones in the proxies section. +# NOTE: These settings are overrided by the ones in the proxies section. +# Note the use of single quotes, so that backslashes will not be escaped. # This is a special key that defines the handler for all URL schemes for which # no handler is defined. -other = "off" +other = 'off' [cache] From 4b78a13140a7fb6e54f4f6aa9516bfa848e87816 Mon Sep 17 00:00:00 2001 From: makeworld Date: Sat, 21 Nov 2020 12:45:54 -0500 Subject: [PATCH 05/10] =?UTF-8?q?=F0=9F=9A=B8=20Support=20numpad=20enter?= =?UTF-8?q?=20key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ THANKS.md | 3 ++- display/display.go | 2 +- display/help.go | 2 +- display/tab.go | 4 ++-- display/util.go | 3 +++ 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97df23e..b0f10e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Support numpad enter key (#123) + ### Changed - Updated [go-gemini](https://github.com/makeworld-the-better-one/go-gemini) to v0.9.1 to support CN-only wildcard certs - Preformatted text is now light yellow by default diff --git a/THANKS.md b/THANKS.md index 0e093f4..bfe147c 100644 --- a/THANKS.md +++ b/THANKS.md @@ -10,4 +10,5 @@ Thank you to the following contributors, who have helped make Amfora great. FOSS - Timur Ismagilov (@bouncepaw) - Matt Caroll (@ohiolab) - Patryk Niedźwiedziński (@pniedzwiedzinski) -- Trevor Slocum (@tsclocum) \ No newline at end of file +- Trevor Slocum (@tsclocum) +- Cole Helbling (@cole-h) diff --git a/display/display.go b/display/display.go index d2b6921..4ccb5e4 100644 --- a/display/display.go +++ b/display/display.go @@ -115,7 +115,7 @@ func Init() { //nolint:exhaustive switch key { - case tcell.KeyEnter: + case tcell.KeyEnter, KeyNumpadEnter: // Figure out whether it's a URL, link number, or search // And send out a request diff --git a/display/help.go b/display/help.go index 1391a07..224adf2 100644 --- a/display/help.go +++ b/display/help.go @@ -63,7 +63,7 @@ func Help() { func helpInit() { // Populate help table helpTable.SetDoneFunc(func(key tcell.Key) { - if key == tcell.KeyEsc || key == tcell.KeyEnter { + if key == tcell.KeyEsc || key == tcell.KeyEnter || key == KeyNumpadEnter { tabPages.SwitchToPage(strconv.Itoa(curTab)) App.SetFocus(tabs[curTab].view) App.Draw() diff --git a/display/tab.go b/display/tab.go index f192720..28d1d6c 100644 --- a/display/tab.go +++ b/display/tab.go @@ -76,7 +76,7 @@ func makeNewTab() *tab { currentSelection := tabs[tab].view.GetHighlights() numSelections := len(tabs[tab].page.Links) - if key == tcell.KeyEnter && len(currentSelection) > 0 { + if (key == tcell.KeyEnter || key == KeyNumpadEnter) && len(currentSelection) > 0 { // A link is selected and enter was pressed: "click" it and load the page it's for bottomBar.SetLabel("") linkN, _ := strconv.Atoi(currentSelection[0]) @@ -85,7 +85,7 @@ func makeNewTab() *tab { followLink(tabs[tab], tabs[tab].page.URL, tabs[tab].page.Links[linkN]) return } - if len(currentSelection) == 0 && (key == tcell.KeyEnter || key == tcell.KeyTab) { + if len(currentSelection) == 0 && (key == tcell.KeyEnter || key == KeyNumpadEnter || key == tcell.KeyTab) { // They've started link highlighting tabs[tab].page.Mode = structs.ModeLinkSelect diff --git a/display/util.go b/display/util.go index 4ea8e91..3de9b16 100644 --- a/display/util.go +++ b/display/util.go @@ -5,12 +5,15 @@ import ( "net/url" "strings" + "github.com/gdamore/tcell" "github.com/spf13/viper" "gitlab.com/tslocum/cview" ) // This file contains funcs that are small, self-contained utilities. +const KeyNumpadEnter = tcell.KeyCtrlJ + // escapeMeta santizes a META string for use within a cview modal. func escapeMeta(meta string) string { return cview.Escape(strings.ReplaceAll(meta, "\n", "")) From a04c281ae0c292f59cc81ee5c54afb82e1ac4d5c Mon Sep 17 00:00:00 2001 From: makeworld Date: Sat, 21 Nov 2020 19:35:17 -0500 Subject: [PATCH 06/10] =?UTF-8?q?=E2=8F=AA=20Revert=20"=F0=9F=9A=B8=20Supp?= =?UTF-8?q?ort=20numpad=20enter=20key"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 4b78a13140a7fb6e54f4f6aa9516bfa848e87816. See #123 for more info on why this was reverted. --- CHANGELOG.md | 3 --- THANKS.md | 3 +-- display/display.go | 2 +- display/help.go | 2 +- display/tab.go | 4 ++-- display/util.go | 3 --- 6 files changed, 5 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0f10e2..97df23e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -### Added -- Support numpad enter key (#123) - ### Changed - Updated [go-gemini](https://github.com/makeworld-the-better-one/go-gemini) to v0.9.1 to support CN-only wildcard certs - Preformatted text is now light yellow by default diff --git a/THANKS.md b/THANKS.md index bfe147c..0e093f4 100644 --- a/THANKS.md +++ b/THANKS.md @@ -10,5 +10,4 @@ Thank you to the following contributors, who have helped make Amfora great. FOSS - Timur Ismagilov (@bouncepaw) - Matt Caroll (@ohiolab) - Patryk Niedźwiedziński (@pniedzwiedzinski) -- Trevor Slocum (@tsclocum) -- Cole Helbling (@cole-h) +- Trevor Slocum (@tsclocum) \ No newline at end of file diff --git a/display/display.go b/display/display.go index 4ccb5e4..d2b6921 100644 --- a/display/display.go +++ b/display/display.go @@ -115,7 +115,7 @@ func Init() { //nolint:exhaustive switch key { - case tcell.KeyEnter, KeyNumpadEnter: + case tcell.KeyEnter: // Figure out whether it's a URL, link number, or search // And send out a request diff --git a/display/help.go b/display/help.go index 224adf2..1391a07 100644 --- a/display/help.go +++ b/display/help.go @@ -63,7 +63,7 @@ func Help() { func helpInit() { // Populate help table helpTable.SetDoneFunc(func(key tcell.Key) { - if key == tcell.KeyEsc || key == tcell.KeyEnter || key == KeyNumpadEnter { + if key == tcell.KeyEsc || key == tcell.KeyEnter { tabPages.SwitchToPage(strconv.Itoa(curTab)) App.SetFocus(tabs[curTab].view) App.Draw() diff --git a/display/tab.go b/display/tab.go index 28d1d6c..f192720 100644 --- a/display/tab.go +++ b/display/tab.go @@ -76,7 +76,7 @@ func makeNewTab() *tab { currentSelection := tabs[tab].view.GetHighlights() numSelections := len(tabs[tab].page.Links) - if (key == tcell.KeyEnter || key == KeyNumpadEnter) && len(currentSelection) > 0 { + if key == tcell.KeyEnter && len(currentSelection) > 0 { // A link is selected and enter was pressed: "click" it and load the page it's for bottomBar.SetLabel("") linkN, _ := strconv.Atoi(currentSelection[0]) @@ -85,7 +85,7 @@ func makeNewTab() *tab { followLink(tabs[tab], tabs[tab].page.URL, tabs[tab].page.Links[linkN]) return } - if len(currentSelection) == 0 && (key == tcell.KeyEnter || key == KeyNumpadEnter || key == tcell.KeyTab) { + if len(currentSelection) == 0 && (key == tcell.KeyEnter || key == tcell.KeyTab) { // They've started link highlighting tabs[tab].page.Mode = structs.ModeLinkSelect diff --git a/display/util.go b/display/util.go index 3de9b16..4ea8e91 100644 --- a/display/util.go +++ b/display/util.go @@ -5,15 +5,12 @@ import ( "net/url" "strings" - "github.com/gdamore/tcell" "github.com/spf13/viper" "gitlab.com/tslocum/cview" ) // This file contains funcs that are small, self-contained utilities. -const KeyNumpadEnter = tcell.KeyCtrlJ - // escapeMeta santizes a META string for use within a cview modal. func escapeMeta(meta string) string { return cview.Escape(strings.ReplaceAll(meta, "\n", "")) From 51fd32e1ea88914de4de07219df479bf400b79ab Mon Sep 17 00:00:00 2001 From: Mattias Jadelius <212982+jedthehumanoid@users.noreply.github.com> Date: Sun, 22 Nov 2020 22:25:20 +0100 Subject: [PATCH 07/10] fix for #103: Simple handling of local (file://) urls (#117) Co-authored-by: Mattias Jadelius --- display/file.go | 116 +++++++++++++++++++++++++++++++++++++++++++++ display/private.go | 15 +++++- 2 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 display/file.go diff --git a/display/file.go b/display/file.go new file mode 100644 index 0000000..51a660c --- /dev/null +++ b/display/file.go @@ -0,0 +1,116 @@ +package display + +import ( + "fmt" + "io/ioutil" + "mime" + "net/url" + "os" + "path/filepath" + "strings" + + "github.com/makeworld-the-better-one/amfora/renderer" + "github.com/makeworld-the-better-one/amfora/structs" + "github.com/spf13/viper" +) + +// handleFile handles urls using file:// protocol +func handleFile(u string) (*structs.Page, bool) { + page := &structs.Page{} + + uri, err := url.ParseRequestURI(u) + if err != nil { + Error("File Error", "Cannot parse URI: "+err.Error()) + return page, false + } + fi, err := os.Stat(uri.Path) + if err != nil { + Error("File Error", "Cannot open local file: "+err.Error()) + return page, false + } + + switch mode := fi.Mode(); { + case mode.IsDir(): + return createDirectoryListing(u) + case mode.IsRegular(): + if fi.Size() > viper.GetInt64("a-general.page_max_size") { + Error("File Error", "Cannot open local file, exceeds page max size") + return page, false + } + + mimetype := mime.TypeByExtension(filepath.Ext(uri.Path)) + if strings.HasSuffix(u, ".gmi") || strings.HasSuffix(u, ".gemini") { + mimetype = "text/gemini" + } + + if !strings.HasPrefix(mimetype, "text/") { + Error("File Error", "Cannot open file, not recognized as text.") + return page, false + } + + content, err := ioutil.ReadFile(uri.Path) + if err != nil { + Error("File Error", "Cannot open local file: "+err.Error()) + return page, false + } + + if mimetype == "text/gemini" { + rendered, links := renderer.RenderGemini(string(content), textWidth(), leftMargin(), false) + page = &structs.Page{ + Mediatype: structs.TextGemini, + URL: u, + Raw: string(content), + Content: rendered, + Links: links, + Width: termW, + } + } else { + page = &structs.Page{ + Mediatype: structs.TextPlain, + URL: u, + Raw: string(content), + Content: renderer.RenderPlainText(string(content), leftMargin()), + Links: []string{}, + Width: termW, + } + } + } + return page, true +} + +// createDirectoryListing creates a text/gemini page for a directory +// that lists all the files as links. +func createDirectoryListing(u string) (*structs.Page, bool) { + page := &structs.Page{} + + uri, err := url.ParseRequestURI(u) + if err != nil { + Error("Directory Error", "Cannot parse URI: "+err.Error()) + } + + files, err := ioutil.ReadDir(uri.Path) + if err != nil { + Error("Directory error", "Cannot open local directory: "+err.Error()) + return page, false + } + content := "Index of " + uri.Path + "\n" + content += "=> ../ ../\n" + for _, f := range files { + separator := "" + if f.IsDir() { + separator = "/" + } + content += fmt.Sprintf("=> %s%s %s%s\n", f.Name(), separator, f.Name(), separator) + } + + rendered, links := renderer.RenderGemini(content, textWidth(), leftMargin(), false) + page = &structs.Page{ + Mediatype: structs.TextGemini, + URL: u, + Raw: content, + Content: rendered, + Links: links, + Width: termW, + } + return page, true +} diff --git a/display/private.go b/display/private.go index 8686fd7..67b54cf 100644 --- a/display/private.go +++ b/display/private.go @@ -78,7 +78,9 @@ func reformatPage(p *structs.Page) { case structs.TextGemini: // Links are not recorded because they won't change proxied := true - if strings.HasPrefix(p.URL, "gemini") || strings.HasPrefix(p.URL, "about") { + if strings.HasPrefix(p.URL, "gemini") || + strings.HasPrefix(p.URL, "about") || + strings.HasPrefix(p.URL, "file") { proxied = false } rendered, _ = renderer.RenderGemini(p.Raw, textWidth(), leftMargin(), proxied) @@ -370,7 +372,16 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) { usingProxy = true } - if !strings.HasPrefix(u, "http") && !strings.HasPrefix(u, "gemini") { + if strings.HasPrefix(u, "file") { + page, ok := handleFile(u) + if !ok { + return ret("", false) + } + setPage(t, page) + return ret(u, true) + } + + if !strings.HasPrefix(u, "http") && !strings.HasPrefix(u, "gemini") && !strings.HasPrefix(u, "file") { // Not a Gemini URL if proxy == "" || proxy == "off" { // No proxy available From 9eebbb54e7d7b207afeb5ce10cb1efcbfee356d1 Mon Sep 17 00:00:00 2001 From: makeworld Date: Sun, 22 Nov 2020 16:27:34 -0500 Subject: [PATCH 08/10] =?UTF-8?q?=F0=9F=93=9D=20Doc=20for=20#117?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ THANKS.md | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97df23e..a3d27f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Opening local files with `file://` URIs (#103, #117) + ### Changed - Updated [go-gemini](https://github.com/makeworld-the-better-one/go-gemini) to v0.9.1 to support CN-only wildcard certs - Preformatted text is now light yellow by default diff --git a/THANKS.md b/THANKS.md index 0e093f4..e5ba5b9 100644 --- a/THANKS.md +++ b/THANKS.md @@ -10,4 +10,5 @@ Thank you to the following contributors, who have helped make Amfora great. FOSS - Timur Ismagilov (@bouncepaw) - Matt Caroll (@ohiolab) - Patryk Niedźwiedziński (@pniedzwiedzinski) -- Trevor Slocum (@tsclocum) \ No newline at end of file +- Trevor Slocum (@tsclocum) +- Mattias Jadelius (@jedthehumanoid) From 8cc240bb4e4426cfe0700990091086e4c9392c63 Mon Sep 17 00:00:00 2001 From: makeworld Date: Mon, 23 Nov 2020 13:19:05 -0500 Subject: [PATCH 09/10] =?UTF-8?q?=F0=9F=92=84=20Add=20dracula=20theme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contrib/themes/README.md | 13 +++++ contrib/themes/dracula.toml | 103 ++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 contrib/themes/dracula.toml diff --git a/contrib/themes/README.md b/contrib/themes/README.md index 49704b6..ad0d10d 100644 --- a/contrib/themes/README.md +++ b/contrib/themes/README.md @@ -8,6 +8,19 @@ Contributed by **[@lokesh-krishna](https://github.com/lokesh-krishna)**. ![screenshot of the nord theme](https://user-images.githubusercontent.com/20235646/99020443-a93a1980-2584-11eb-8028-0b95cfcf0fc6.png) +## Dracula + +Contributed by **[@crdpa](https://github.com/crdpa)**. + +![screenshot of dracula theme](https://user-images.githubusercontent.com/61637474/99983229-5b928d80-2d8a-11eb-8e5c-e5681bb274c5.png) + +
+More screenshots + +![screenshot of dracula theme](https://user-images.githubusercontent.com/61637474/99983237-5e8d7e00-2d8a-11eb-8e22-3a3459ae560a.png) +![screenshot of dracula theme](https://user-images.githubusercontent.com/61637474/99983210-53d2e900-2d8a-11eb-9ab7-12dc10c2933a.png) +
+ ## Yours? Contribute your own theme by opening a PR. diff --git a/contrib/themes/dracula.toml b/contrib/themes/dracula.toml new file mode 100644 index 0000000..3be9b62 --- /dev/null +++ b/contrib/themes/dracula.toml @@ -0,0 +1,103 @@ +[theme] +# This section is for changing the COLORS used in Amfora. +# These colors only apply if 'color' is enabled above. +# Colors can be set using a W3C color name, or a hex value such as "#ffffff". + +# Note that not all colors will work on terminals that do not have truecolor support. +# If you want to stick to the standard 16 or 256 colors, you can get +# a list of those here: https://jonasjacek.github.io/colors/ +# DO NOT use the names from that site, just the hex codes. + +# Definitions: +# bg = background +# fg = foreground +# dl = download +# btn = button +# hdg = heading +# bkmk = bookmark +# modal = a popup window/box in the middle of the screen + +# EXAMPLES: +# hdg_1 = "green" +# hdg_2 = "#5f0000" + +# Available keys to set: + +# bg: background for pages, tab row, app in general +# tab_num: The number/highlight of the tabs at the top +# tab_divider: The color of the divider character between tab numbers: | +# bottombar_label: The color of the prompt that appears when you press space +# bottombar_text: The color of the text you type +# bottombar_bg + +bg = "#282a36" +fg = "#f8f8f2" +tab_num = "#50fa7b" +tab_divider = "#f8f8f2" +bottombar_bg = "#282a36" +bottombar_text = "#f8f8f2" +bottombar_label = "#9aedfe" + +# hdg_1 +# hdg_2 +# hdg_3 +# amfora_link: A link that Amfora supports viewing. For now this is only gemini:// +# foreign_link: HTTP(S), Gopher, etc +# link_number: The silver number that appears to the left of a link +# regular_text: Normal gemini text, and plaintext documents +# quote_text +# preformatted_text +# list_text + +hdg_1 = "#5af78e" +hdg_2 = "#9aedfe" +hdg_3 = "#caa9fa" +amfora_link = "#f4f99d" +foreign_link = "#d4d989" +link_number = "#ff5555" +regular_text = "#f8f8f2" +quote_text = "#E6E6E6" +preformatted_text = "#f8f8f2" +list_text = "#f8f8f2" + +# btn_bg: The bg color for all modal buttons +# btn_text: The text color for all modal buttons + +btn_bg = "#bfbfbf" +btn_text = "#4d4d4d" + +dl_choice_modal_bg = "#282a36" +dl_choice_modal_text = "#f8f8f2" +dl_modal_bg = "#282a36" +dl_modal_text = "#f8f8f2" +info_modal_bg = "#282a36" +info_modal_text = "#f8f8f2" +error_modal_bg = "#282a36" +error_modal_text = "#ff5555" +yesno_modal_bg = "#282a36" +yesno_modal_text = "#f1fa8c" +tofu_modal_bg = "#282a36" +tofu_modal_text = "#f8f8f2" + +# input_modal_bg +# input_modal_text +# input_modal_field_bg: The bg of the input field, where you type the text +# input_modal_field_text: The color of the text you type + +input_modal_bg = "#282a36" +input_modal_text = "#f8f8f2" +input_modal_field_bg = "#4d4d4d" +input_modal_field_text ="#f8f8f2" + +# bkmk_modal_bg +# bkmk_modal_text +# bkmk_modal_label +# bkmk_modal_field_bg +# bkmk_modal_field_text + +bkmk_modal_bg = "#282a36" +bkmk_modal_text = "#f8f8f2" +bkmk_modal_label = "#f8f8f2" +bkmk_modal_field_bg = "#000000" +bkmk_modal_field_text = "#f8f8f2" + From c53c36a4d0bd487dab339b65faa185582f4b26c0 Mon Sep 17 00:00:00 2001 From: makeworld Date: Mon, 23 Nov 2020 21:09:48 -0500 Subject: [PATCH 10/10] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20=20go-gemini=20v0.9.?= =?UTF-8?q?3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Timeout when header takes too long, downloading uses proxies if appropriate --- CHANGELOG.md | 5 ++++- amfora.go | 3 +++ client/client.go | 54 +++++++++++++++++++++++++++++++++++++--------- display/private.go | 23 ++++++++++++++------ go.mod | 2 +- go.sum | 4 ++-- renderer/page.go | 9 ++------ 7 files changed, 73 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3d27f1..9a607f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Opening local files with `file://` URIs (#103, #117) ### Changed -- Updated [go-gemini](https://github.com/makeworld-the-better-one/go-gemini) to v0.9.1 to support CN-only wildcard certs +- Updated [go-gemini](https://github.com/makeworld-the-better-one/go-gemini) to v0.9.3 + - Supports CN-only wildcard certs + - Time out when header takes too long - Preformatted text is now light yellow by default ### Fixed - Single quotes are used in the default config for commands and paths so that Windows paths with backslashes will be parsed correctly +- Downloading now uses proxies when appropriate ## [1.6.0] - 2020-11-04 diff --git a/amfora.go b/amfora.go index 8c58a73..46c6643 100644 --- a/amfora.go +++ b/amfora.go @@ -4,6 +4,7 @@ import ( "fmt" "os" + "github.com/makeworld-the-better-one/amfora/client" "github.com/makeworld-the-better-one/amfora/config" "github.com/makeworld-the-better-one/amfora/display" ) @@ -43,6 +44,8 @@ func main() { os.Exit(1) } + client.Init() + display.Init() display.NewTab() display.NewTab() // Open extra tab and close it to fully initialize the app and wrapping diff --git a/client/client.go b/client/client.go index 2ec65d5..c7eee10 100644 --- a/client/client.go +++ b/client/client.go @@ -5,13 +5,29 @@ import ( "io/ioutil" "net" "net/url" + "time" "github.com/makeworld-the-better-one/go-gemini" "github.com/mitchellh/go-homedir" "github.com/spf13/viper" ) -var certCache = make(map[string][][]byte) +var ( + certCache = make(map[string][][]byte) + fetchClient *gemini.Client + dlClient *gemini.Client // For downloading +) + +func Init() { + fetchClient = &gemini.Client{ + ConnectTimeout: 10 * time.Second, // Default is 15 + ReadTimeout: time.Duration(viper.GetInt("a-general.page_max_time")) * time.Second, + } + dlClient = &gemini.Client{ + ConnectTimeout: 10 * time.Second, // Default is 15 + // No read timeout, download can take as long as it needs + } +} func clientCert(host string) ([]byte, []byte) { if cert := certCache[host]; cert != nil { @@ -53,18 +69,16 @@ func HasClientCert(host string) bool { return cert != nil } -// Fetch returns response data and an error. -// The error text is human friendly and should be displayed. -func Fetch(u string) (*gemini.Response, error) { +func fetch(u string, c *gemini.Client) (*gemini.Response, error) { parsed, _ := url.Parse(u) cert, key := clientCert(parsed.Host) var res *gemini.Response var err error if cert != nil { - res, err = gemini.FetchWithCert(u, cert, key) + res, err = c.FetchWithCert(u, cert, key) } else { - res, err = gemini.Fetch(u) + res, err = c.Fetch(u) } if err != nil { return nil, err @@ -78,17 +92,27 @@ func Fetch(u string) (*gemini.Response, error) { return res, err } -// FetchWithProxy is the same as Fetch, but uses a proxy. -func FetchWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, error) { +// Fetch returns response data and an error. +// The error text is human friendly and should be displayed. +func Fetch(u string) (*gemini.Response, error) { + return fetch(u, fetchClient) +} + +// Download is the same as Fetch but with no read timeout. +func Download(u string) (*gemini.Response, error) { + return fetch(u, dlClient) +} + +func fetchWithProxy(proxyHostname, proxyPort, u string, c *gemini.Client) (*gemini.Response, error) { parsed, _ := url.Parse(u) cert, key := clientCert(parsed.Host) var res *gemini.Response var err error if cert != nil { - res, err = gemini.FetchWithHostAndCert(net.JoinHostPort(proxyHostname, proxyPort), u, cert, key) + res, err = c.FetchWithHostAndCert(net.JoinHostPort(proxyHostname, proxyPort), u, cert, key) } else { - res, err = gemini.FetchWithHost(net.JoinHostPort(proxyHostname, proxyPort), u) + res, err = c.FetchWithHost(net.JoinHostPort(proxyHostname, proxyPort), u) } if err != nil { return nil, err @@ -102,3 +126,13 @@ func FetchWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, error return res, nil } + +// FetchWithProxy is the same as Fetch, but uses a proxy. +func FetchWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, error) { + return fetchWithProxy(proxyHostname, proxyPort, u, fetchClient) +} + +// DownloadWithProxy is the same as FetchWithProxy but with no read timeout. +func DownloadWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, error) { + return fetchWithProxy(proxyHostname, proxyPort, u, dlClient) +} diff --git a/display/private.go b/display/private.go index 67b54cf..771aa48 100644 --- a/display/private.go +++ b/display/private.go @@ -452,24 +452,35 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) { return ret("", false) } + var res2 *gemini.Response + var dlErr error + if errors.Is(err, renderer.ErrTooLarge) { // Make new request for downloading purposes - res, clientErr := client.Fetch(u) - if clientErr != nil && !errors.Is(clientErr, client.ErrTofu) { + if usingProxy { + res2, dlErr = client.DownloadWithProxy(proxyHostname, proxyPort, u) + } else { + res2, dlErr = client.Download(u) + } + if dlErr != nil && !errors.Is(dlErr, client.ErrTofu) { Error("URL Fetch Error", err.Error()) return ret("", false) } - go dlChoice("That page is too large. What would you like to do?", u, res) + go dlChoice("That page is too large. What would you like to do?", u, res2) return ret("", false) } if errors.Is(err, renderer.ErrTimedOut) { // Make new request for downloading purposes - res, clientErr := client.Fetch(u) - if clientErr != nil && !errors.Is(clientErr, client.ErrTofu) { + if usingProxy { + res2, dlErr = client.DownloadWithProxy(proxyHostname, proxyPort, u) + } else { + res2, dlErr = client.Download(u) + } + if dlErr != nil && !errors.Is(dlErr, client.ErrTofu) { Error("URL Fetch Error", err.Error()) return ret("", false) } - go dlChoice("Loading that page timed out. What would you like to do?", u, res) + go dlChoice("Loading that page timed out. What would you like to do?", u, res2) return ret("", false) } if err != nil { diff --git a/go.mod b/go.mod index e633377..4fe7054 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/fsnotify/fsnotify v1.4.9 // indirect 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.9.1 + github.com/makeworld-the-better-one/go-gemini v0.9.3 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 diff --git a/go.sum b/go.sum index 1bf7e3f..d536110 100644 --- a/go.sum +++ b/go.sum @@ -125,8 +125,8 @@ github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tW github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/makeworld-the-better-one/go-gemini v0.9.1 h1:/Vc6Y4Y1aOi4lZIBA1wDe+4N2xAI8EQ0CIjip2NUQkk= -github.com/makeworld-the-better-one/go-gemini v0.9.1/go.mod h1:P7/FbZ+IEIbA/d+A0Y3w2GNgD8SA2AcNv7aDGJbaWG4= +github.com/makeworld-the-better-one/go-gemini v0.9.3 h1:vpJc1u4LYpEI5h7GcOE2zSfOmpE9gQzt0vEayp/ilWc= +github.com/makeworld-the-better-one/go-gemini v0.9.3/go.mod h1:P7/FbZ+IEIbA/d+A0Y3w2GNgD8SA2AcNv7aDGJbaWG4= 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= diff --git a/renderer/page.go b/renderer/page.go index d7afb80..0bcd72a 100644 --- a/renderer/page.go +++ b/renderer/page.go @@ -5,8 +5,8 @@ import ( "errors" "io" "mime" + "os" "strings" - "time" "github.com/makeworld-the-better-one/amfora/structs" "github.com/makeworld-the-better-one/go-gemini" @@ -63,18 +63,13 @@ func MakePage(url string, res *gemini.Response, width, leftMargin int, proxied b } buf := new(bytes.Buffer) - go func() { - time.Sleep(time.Duration(viper.GetInt("a-general.page_max_time")) * time.Second) - res.Body.Close() - }() - _, err := io.CopyN(buf, res.Body, viper.GetInt64("a-general.page_max_size")+1) res.Body.Close() if err == nil { // Content was larger than max size return nil, ErrTooLarge } else if err != io.EOF { - if strings.HasSuffix(err.Error(), "use of closed network connection") { + if errors.Is(err, os.ErrDeadlineExceeded) { // Timed out return nil, ErrTimedOut }