mirror of
https://github.com/makeworld-the-better-one/amfora.git
synced 2024-09-11 14:55:51 +03:00
🔀 Merge branch 'master' into feeds
This commit is contained in:
commit
0f5458c730
26
.github/workflows/goreleaser.yml
vendored
Normal file
26
.github/workflows/goreleaser.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
name: goreleaser
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.15
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: 0.x
|
||||
args: release --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,7 +1,8 @@
|
||||
# Binaries
|
||||
amfora
|
||||
amfora-*
|
||||
build/
|
||||
build
|
||||
dist
|
||||
|
||||
# Recording
|
||||
rec.yml
|
||||
|
@ -41,3 +41,6 @@ linters-settings:
|
||||
gocritic:
|
||||
disabled-checks:
|
||||
- ifElseChain
|
||||
goconst:
|
||||
# minimal length of string constant, 3 by default
|
||||
min-len: 5
|
||||
|
59
.goreleaser.yml
Normal file
59
.goreleaser.yml
Normal file
@ -0,0 +1,59 @@
|
||||
project_name: amfora
|
||||
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- go mod download
|
||||
- go generate ./...
|
||||
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
- freebsd
|
||||
- netbsd
|
||||
- openbsd
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
- arm64
|
||||
- arm
|
||||
goarm:
|
||||
- 6
|
||||
- 7
|
||||
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: 386
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
- goos: freebsd
|
||||
goarch: arm64
|
||||
- goos: netbsd
|
||||
goarch: arm
|
||||
- goos: netbsd
|
||||
goarch: arm64
|
||||
- goos: openbsd
|
||||
goarch: arm
|
||||
- goos: openbsd
|
||||
goarch: arm64
|
||||
|
||||
archives:
|
||||
- format: binary
|
||||
|
||||
replacements:
|
||||
darwin: macOS
|
||||
386: 32-bit
|
||||
amd64: 64-bit
|
||||
|
||||
milestones:
|
||||
- close: true
|
||||
|
||||
changelog:
|
||||
skip: true
|
17
CHANGELOG.md
17
CHANGELOG.md
@ -4,25 +4,30 @@ All notable changes to this project will be documented in this file.
|
||||
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]
|
||||
|
||||
|
||||
## [v1.5.0] - 2020-09-01
|
||||
### Added
|
||||
- **Proxy support** - see the `[proxies]` section in the config (#66, #80)
|
||||
- **Emoji favicons** can now be seen if `emoji_favicons` is enabled in the config (#62)
|
||||
- **Proxy support** - specify a proxy in the config for all requests to go through it (#66)
|
||||
- The `shift_numbers` key in the config was added, so that non US keyboard users can navigate tabs (#64)
|
||||
- `shift_numbers` key in the config was added, so that non US keyboard users can navigate tabs (#64)
|
||||
- <kbd>F1</kbd> and <kbd>F2</kbd> keys for navigating to the previous and next tabs (#64)
|
||||
- Resolving any relative path (starting with a `.`) in the bottom bar is supported, not just `..` (#71)
|
||||
- Set programs in config to open other schemes like `gopher://` or `magnet:` (#74)
|
||||
- Resolving any relative path (starts with a `.`) in the bottom bar is supported, not just `..` (#71)
|
||||
- You can now set external programs in the config to open other schemes, like `gopher://` or `magnet:` (#74)
|
||||
- Auto-redirecting can be enabled - redirect within Gemini up to 5 times automatically (#75)
|
||||
- Help page now documents paging keys (#78)
|
||||
- The new tab page can be customized by creating a gemtext file called `newtab.gmi` in the config directory (#67, #83)
|
||||
|
||||
### Changed
|
||||
- Update to [go-gemini](https://github.com/makeworld-the-better-one/go-gemini) v0.8.4
|
||||
|
||||
### Fixed
|
||||
- Two digit (and higher) link texts are now in line with one digit ones (#60)
|
||||
- Race condition when reloading pages, could have caused the cache to still be used
|
||||
- Race condition when reloading pages that could have caused the cache to still be used
|
||||
- Prevent panic (crash) when the server sends an error with an empty meta string (#73)
|
||||
- URLs with with colon-only schemes (like `mailto:`) are properly recognized
|
||||
- You can no longer navigate through the history when the help page is open (#55, #78)
|
||||
|
||||
|
||||
## [1.4.0] - 2020-07-28
|
||||
|
27
README.md
27
README.md
@ -61,12 +61,14 @@ This section is for programmers who want to install from source. Make sure you'r
|
||||
|
||||
Install latest release:
|
||||
```
|
||||
GO111MODULE=on go get github.com/makeworld-the-better-one/amfora
|
||||
go env -w GO111MODULE=on
|
||||
go get github.com/makeworld-the-better-one/amfora
|
||||
```
|
||||
|
||||
Install latest commit:
|
||||
```
|
||||
GO111MODULE=on go get github.com/makeworld-the-better-one/amfora@master
|
||||
go env -w GO111MODULE=on
|
||||
go get github.com/makeworld-the-better-one/amfora@master
|
||||
```
|
||||
|
||||
## Usage
|
||||
@ -95,15 +97,14 @@ Features in *italics* are in the master branch, but not in the latest release.
|
||||
- [x] Bookmarks
|
||||
- [x] Download pages and arbitrary data
|
||||
- [x] Theming
|
||||
- [x] *Emoji favicons*
|
||||
- [x] Emoji favicons
|
||||
- See `gemini://mozz.us/files/rfc_gemini_favicon.gmi` for details
|
||||
- [x] *Proxying*
|
||||
- All requests can optionally be sent through another server
|
||||
- A gemini proxy server implementation currently does not exist, but Amfora will support it when it does!
|
||||
- Disabled by default, enable in config
|
||||
- [x] Proxying
|
||||
- Schemes like Gopher or HTTP can be proxied through a Gemini server
|
||||
- [x] *Subscribe to RSS and Atom feeds and display them*
|
||||
- Subscribing to page changes, similar to how Spacewalk works, is also supported
|
||||
- [ ] Support Markdown rendering
|
||||
- [ ] Search in pages with <kbd>Ctrl-F</kbd>
|
||||
- Subscribing to page changes, similar to how Spacewalk works, will also be supported
|
||||
- [ ] Stream support
|
||||
- [ ] Full client certificate UX within the client
|
||||
- Create transient and permanent certs within the client, per domain
|
||||
- Manage and browse them
|
||||
@ -118,6 +119,14 @@ The config file is written in the intuitive [TOML](https://github.com/toml-lang/
|
||||
|
||||
On Windows, the file is in `%APPDATA%\amfora\config.toml`, which usually expands to `C:\Users\<username>\AppData\Roaming\amfora\config.toml`.
|
||||
|
||||
## Known Bugs
|
||||
|
||||
- Pasting on Windows is truncated, the full paste content won't be added. ([#43](https://github.com/makeworld-the-better-one/amfora/issues/43))
|
||||
- ANSI codes aren't displaying properly ([#59](https://github.com/makeworld-the-better-one/amfora/issues/59))
|
||||
|
||||
You can also check out [all the issues with the bug label](https://github.com/makeworld-the-better-one/amfora/issues?q=is%3Aopen+is%3Aissue+label%3Abug).
|
||||
|
||||
|
||||
## Libraries
|
||||
Amfora ❤️ open source!
|
||||
|
||||
|
10
amfora.go
10
amfora.go
@ -9,7 +9,11 @@ import (
|
||||
"github.com/makeworld-the-better-one/amfora/feeds"
|
||||
)
|
||||
|
||||
var version = "1.5.0-unreleased"
|
||||
var (
|
||||
version = "1.5.0"
|
||||
commit = "unknown"
|
||||
builtBy = "unknown"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// err := logger.Init()
|
||||
@ -19,7 +23,9 @@ func main() {
|
||||
|
||||
if len(os.Args) > 1 {
|
||||
if os.Args[1] == "--version" || os.Args[1] == "-v" {
|
||||
fmt.Println("amfora v" + version)
|
||||
fmt.Println("Amfora", version)
|
||||
fmt.Println("Commit:", commit)
|
||||
fmt.Println("Built by:", builtBy)
|
||||
return
|
||||
}
|
||||
if os.Args[1] == "--help" || os.Args[1] == "-h" {
|
||||
|
@ -2,31 +2,43 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/url"
|
||||
|
||||
"github.com/makeworld-the-better-one/go-gemini"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// Fetch returns response data and an error.
|
||||
// The error text is human friendly and should be displayed.
|
||||
func Fetch(u string) (*gemini.Response, error) {
|
||||
var res *gemini.Response
|
||||
var err error
|
||||
|
||||
if viper.GetString("a-general.proxy") == "" {
|
||||
res, err = gemini.Fetch(u)
|
||||
} else {
|
||||
res, err = gemini.FetchWithHost(viper.GetString("a-general.proxy"), u)
|
||||
}
|
||||
res, err := gemini.Fetch(u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parsed, _ := url.Parse(u)
|
||||
|
||||
ok := handleTofu(parsed.Hostname(), parsed.Port(), res.Cert)
|
||||
if !ok {
|
||||
return res, ErrTofu
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
// FetchWithProxy is the same as Fetch, but uses a proxy.
|
||||
func FetchWithProxy(proxyHostname, proxyPort, u string) (*gemini.Response, error) {
|
||||
res, err := gemini.FetchWithHost(net.JoinHostPort(proxyHostname, proxyPort), u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Only associate the returned cert with the proxy
|
||||
ok := handleTofu(proxyHostname, proxyPort, res.Cert)
|
||||
if !ok {
|
||||
return res, ErrTofu
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
@ -22,6 +22,9 @@ var amforaAppData string // Where amfora files are stored on Windows - cached he
|
||||
var configDir string
|
||||
var configPath string
|
||||
|
||||
var NewTabPath string
|
||||
var CustomNewTab bool
|
||||
|
||||
var TofuStore = viper.New()
|
||||
var tofuDBDir string
|
||||
var tofuDBPath string
|
||||
@ -74,6 +77,13 @@ func Init() error {
|
||||
}
|
||||
configPath = filepath.Join(configDir, "config.toml")
|
||||
|
||||
// Search for a custom new tab
|
||||
NewTabPath = filepath.Join(configDir, "newtab.gmi")
|
||||
CustomNewTab = false
|
||||
if _, err := os.Stat(NewTabPath); err == nil {
|
||||
CustomNewTab = true
|
||||
}
|
||||
|
||||
// Store TOFU db directory and file paths
|
||||
if runtime.GOOS == "windows" {
|
||||
// Windows just stores it in APPDATA along with other stuff
|
||||
|
@ -21,8 +21,8 @@ home = "gemini://gemini.circumlunar.space"
|
||||
# If set to false, a prompt will be shown before following redirects.
|
||||
auto_redirect = false
|
||||
|
||||
# What command to run to open a HTTP URL. Set to "default" to try to guess the browser,
|
||||
# or set to "off" to not open HTTP URLs.
|
||||
# What command to run to open a HTTP(S) URL. Set to "default" to try to guess the browser,
|
||||
# or set to "off" to not open HTTP(S) URLs.
|
||||
# If a command is set, than the URL will be added (in quotes) to the end of the command.
|
||||
# A space will be prepended if necessary.
|
||||
http = "default"
|
||||
@ -55,12 +55,6 @@ page_max_time = 10
|
||||
# Whether to replace tab numbers with emoji favicons, which are cached.
|
||||
emoji_favicons = false
|
||||
|
||||
# Proxy server, through which all requests would be sent.
|
||||
# String should be a host: a domain/IP with an optional port. Port 1965 is assumed otherwise.
|
||||
# The proxy server needs to be a Gemini server that supports proxying.
|
||||
# By default it is empty, which disables the proxy.
|
||||
proxy = ""
|
||||
|
||||
|
||||
[keybindings]
|
||||
# In the future there will be more settings here.
|
||||
@ -74,10 +68,13 @@ shift_numbers = "!@#$%^&*()"
|
||||
# Allows setting the commands to run for various URL schemes.
|
||||
# E.g. to open FTP URLs with FileZilla set the following key:
|
||||
# ftp = "filezilla"
|
||||
# You can set any scheme to "off" to disable handling it.
|
||||
# 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
|
||||
# Use the http setting in the "a-general" section above.
|
||||
#
|
||||
# NOTE: These settings are override by the ones in the proxies section.
|
||||
|
||||
# This is a special key that defines the handler for all URL schemes for which
|
||||
# no handler is defined.
|
||||
@ -93,6 +90,20 @@ max_size = 0 # Size in bytes
|
||||
max_pages = 30 # The maximum number of pages the cache will store
|
||||
|
||||
|
||||
[proxies]
|
||||
# Allows setting a Gemini proxy for different schemes.
|
||||
# The settings are similar to the url-handlers section above.
|
||||
# E.g. to open a gopher page by connecting to a Gemini proxy server:
|
||||
# gopher = "example.com:123"
|
||||
#
|
||||
# Port 1965 is assumed if no port is specified.
|
||||
#
|
||||
# NOTE: These settings override any external handlers specified in
|
||||
# the url-handlers section.
|
||||
#
|
||||
# Note that HTTP and HTTPS are treated as separate protocols here.
|
||||
|
||||
|
||||
[theme]
|
||||
# This section is for changing the COLORS used in Amfora.
|
||||
# These colors only apply if 'color' is enabled above.
|
||||
|
@ -18,8 +18,8 @@ home = "gemini://gemini.circumlunar.space"
|
||||
# If set to false, a prompt will be shown before following redirects.
|
||||
auto_redirect = false
|
||||
|
||||
# What command to run to open a HTTP URL. Set to "default" to try to guess the browser,
|
||||
# or set to "off" to not open HTTP URLs.
|
||||
# What command to run to open a HTTP(S) URL. Set to "default" to try to guess the browser,
|
||||
# or set to "off" to not open HTTP(S) URLs.
|
||||
# If a command is set, than the URL will be added (in quotes) to the end of the command.
|
||||
# A space will be prepended if necessary.
|
||||
http = "default"
|
||||
@ -52,12 +52,6 @@ page_max_time = 10
|
||||
# Whether to replace tab numbers with emoji favicons, which are cached.
|
||||
emoji_favicons = false
|
||||
|
||||
# Proxy server, through which all requests would be sent.
|
||||
# String should be a host: a domain/IP with an optional port. Port 1965 is assumed otherwise.
|
||||
# The proxy server needs to be a Gemini server that supports proxying.
|
||||
# By default it is empty, which disables the proxy.
|
||||
proxy = ""
|
||||
|
||||
|
||||
[keybindings]
|
||||
# In the future there will be more settings here.
|
||||
@ -71,10 +65,13 @@ shift_numbers = "!@#$%^&*()"
|
||||
# Allows setting the commands to run for various URL schemes.
|
||||
# E.g. to open FTP URLs with FileZilla set the following key:
|
||||
# ftp = "filezilla"
|
||||
# You can set any scheme to "off" to disable handling it.
|
||||
# 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
|
||||
# Use the http setting in the "a-general" section above.
|
||||
#
|
||||
# NOTE: These settings are override by the ones in the proxies section.
|
||||
|
||||
# This is a special key that defines the handler for all URL schemes for which
|
||||
# no handler is defined.
|
||||
@ -90,6 +87,20 @@ max_size = 0 # Size in bytes
|
||||
max_pages = 30 # The maximum number of pages the cache will store
|
||||
|
||||
|
||||
[proxies]
|
||||
# Allows setting a Gemini proxy for different schemes.
|
||||
# The settings are similar to the url-handlers section above.
|
||||
# E.g. to open a gopher page by connecting to a Gemini proxy server:
|
||||
# gopher = "example.com:123"
|
||||
#
|
||||
# Port 1965 is assumed if no port is specified.
|
||||
#
|
||||
# NOTE: These settings override any external handlers specified in
|
||||
# the url-handlers section.
|
||||
#
|
||||
# Note that HTTP and HTTPS are treated as separate protocols here.
|
||||
|
||||
|
||||
[theme]
|
||||
# This section is for changing the COLORS used in Amfora.
|
||||
# These colors only apply if 'color' is enabled above.
|
||||
|
@ -116,7 +116,7 @@ func Bookmarks(t *tab) {
|
||||
bkmkPageRaw += fmt.Sprintf("=> %s %s\r\n", keys[i], m[keys[i]])
|
||||
}
|
||||
// Render and display
|
||||
content, links := renderer.RenderGemini(bkmkPageRaw, textWidth(), leftMargin())
|
||||
content, links := renderer.RenderGemini(bkmkPageRaw, textWidth(), leftMargin(), false)
|
||||
page := structs.Page{
|
||||
Raw: bkmkPageRaw,
|
||||
Content: content,
|
||||
|
@ -51,8 +51,6 @@ var tabRow = cview.NewTextView().
|
||||
var layout = cview.NewFlex().
|
||||
SetDirection(cview.FlexRow)
|
||||
|
||||
var renderedNewTabContent string
|
||||
var newTabLinks []string
|
||||
var newTabPage structs.Page
|
||||
|
||||
var App = cview.NewApplication().
|
||||
@ -202,7 +200,8 @@ func Init() {
|
||||
})
|
||||
|
||||
// Render the default new tab content ONCE and store it for later
|
||||
renderedNewTabContent, newTabLinks = renderer.RenderGemini(newTabContent, textWidth(), leftMargin())
|
||||
newTabContent := getNewTabContent()
|
||||
renderedNewTabContent, newTabLinks := renderer.RenderGemini(newTabContent, textWidth(), leftMargin(), false)
|
||||
newTabPage = structs.Page{
|
||||
Raw: newTabContent,
|
||||
Content: renderedNewTabContent,
|
||||
@ -232,6 +231,11 @@ func Init() {
|
||||
// It's focused on a modal right now, nothing should interrupt
|
||||
return event
|
||||
}
|
||||
_, ok = App.GetFocus().(*cview.Table)
|
||||
if ok {
|
||||
// It's focused on help right now
|
||||
return event
|
||||
}
|
||||
|
||||
if tabs[curTab].mode == tabModeDone {
|
||||
// All the keys and operations that can only work while NOT loading
|
||||
@ -514,6 +518,24 @@ func SwitchTab(tab int) {
|
||||
}
|
||||
|
||||
func Reload() {
|
||||
if tabs[curTab].page.URL == "about:newtab" && config.CustomNewTab {
|
||||
// Re-render new tab, similar to Init()
|
||||
newTabContent := getNewTabContent()
|
||||
tmpTermW := termW
|
||||
renderedNewTabContent, newTabLinks := renderer.RenderGemini(newTabContent, textWidth(), leftMargin(), false)
|
||||
newTabPage = structs.Page{
|
||||
Raw: newTabContent,
|
||||
Content: renderedNewTabContent,
|
||||
Links: newTabLinks,
|
||||
URL: "about:newtab",
|
||||
Width: tmpTermW,
|
||||
Mediatype: structs.TextGemini,
|
||||
}
|
||||
temp := newTabPage // Copy
|
||||
setPage(tabs[curTab], &temp)
|
||||
return
|
||||
}
|
||||
|
||||
if !tabs[curTab].hasContent() {
|
||||
return
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ func Feeds(t *tab) {
|
||||
feedPageRaw += fmt.Sprintf("=>%s %s - %s\n", entry.URL, entry.Author, entry.Title)
|
||||
}
|
||||
|
||||
content, links := renderer.RenderGemini(feedPageRaw, textWidth(), leftMargin())
|
||||
content, links := renderer.RenderGemini(feedPageRaw, textWidth(), leftMargin(), false)
|
||||
page := structs.Page{
|
||||
Raw: feedPageRaw,
|
||||
Content: content,
|
||||
|
@ -12,12 +12,14 @@ var helpCells = strings.TrimSpace(`
|
||||
?|Bring up this help. You can scroll!
|
||||
Esc|Leave the help
|
||||
Arrow keys, h/j/k/l|Scroll and move a page.
|
||||
PgUp, u|Go up a page in document
|
||||
PgDn, d|Go down a page in document
|
||||
g|Go to top of document
|
||||
G|Go to bottom of document
|
||||
Tab|Navigate to the next item in a popup.
|
||||
Shift-Tab|Navigate to the previous item in a popup.
|
||||
b, Alt-Left|Go back in the history
|
||||
f, Alt-Right|Go forward in the history
|
||||
g|Go to top of document
|
||||
G|Go to bottom of document
|
||||
spacebar|Open bar at the bottom - type a URL, link number, search term.
|
||||
|You can also type two dots (..) to go up a directory in the URL.
|
||||
|Typing new:N will open link number N in a new tab
|
||||
@ -60,7 +62,7 @@ func Help() {
|
||||
func helpInit() {
|
||||
// Populate help table
|
||||
helpTable.SetDoneFunc(func(key tcell.Key) {
|
||||
if key == tcell.KeyEsc {
|
||||
if key == tcell.KeyEsc || key == tcell.KeyEnter {
|
||||
tabPages.SwitchToPage(strconv.Itoa(curTab))
|
||||
App.SetFocus(tabs[curTab].view)
|
||||
App.Draw()
|
||||
|
@ -1,12 +1,20 @@
|
||||
//nolint
|
||||
package display
|
||||
|
||||
var newTabContent = `# New Tab
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/makeworld-the-better-one/amfora/config"
|
||||
)
|
||||
|
||||
//nolint
|
||||
var defaultNewTabContent = `# New Tab
|
||||
|
||||
You've opened a new tab. Use the bar at the bottom to browse around. You can start typing in it by pressing the space key.
|
||||
|
||||
Press the ? key at any time to bring up the help, and see other keybindings. Most are what you expect.
|
||||
|
||||
You can customize this page by creating a gemtext file called newtab.gmi, in Amfora's configuration folder.
|
||||
|
||||
Happy browsing!
|
||||
|
||||
=> about:bookmarks Bookmarks
|
||||
@ -14,3 +22,12 @@ Happy browsing!
|
||||
=> //gemini.circumlunar.space Project Gemini
|
||||
=> https://github.com/makeworld-the-better-one/amfora Amfora homepage [HTTPS]
|
||||
`
|
||||
|
||||
// Read the new tab content from a file if it exists or fallback to a default page.
|
||||
func getNewTabContent() string {
|
||||
data, err := ioutil.ReadFile(config.NewTabPath)
|
||||
if err == nil {
|
||||
return string(data)
|
||||
}
|
||||
return defaultNewTabContent
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/url"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
@ -77,7 +78,11 @@ func reformatPage(p *structs.Page) {
|
||||
switch p.Mediatype {
|
||||
case structs.TextGemini:
|
||||
// Links are not recorded because they won't change
|
||||
rendered, _ = renderer.RenderGemini(p.Raw, textWidth(), leftMargin())
|
||||
proxied := true
|
||||
if strings.HasPrefix(p.URL, "gemini") || strings.HasPrefix(p.URL, "about") {
|
||||
proxied = false
|
||||
}
|
||||
rendered, _ = renderer.RenderGemini(p.Raw, textWidth(), leftMargin(), proxied)
|
||||
case structs.TextPlain:
|
||||
rendered = renderer.RenderPlainText(p.Raw, leftMargin())
|
||||
case structs.TextAnsi:
|
||||
@ -167,6 +172,7 @@ func handleHTTP(u string, showInfo bool) {
|
||||
func handleOther(u string) {
|
||||
// The URL should have a scheme due to a previous call to normalizeURL
|
||||
parsed, _ := url.Parse(u)
|
||||
|
||||
// Search for a handler for the URL scheme
|
||||
handler := strings.TrimSpace(viper.GetString("url-handlers." + parsed.Scheme))
|
||||
if len(handler) == 0 {
|
||||
@ -330,15 +336,36 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
|
||||
return ret("", false)
|
||||
}
|
||||
|
||||
proxy := strings.TrimSpace(viper.GetString("proxies." + parsed.Scheme))
|
||||
usingProxy := false
|
||||
|
||||
proxyHostname, proxyPort, err := net.SplitHostPort(proxy)
|
||||
if err != nil {
|
||||
// Error likely means there's no port in the host
|
||||
proxyHostname = proxy
|
||||
proxyPort = "1965"
|
||||
}
|
||||
|
||||
if strings.HasPrefix(u, "http") {
|
||||
handleHTTP(u, true)
|
||||
return ret("", false)
|
||||
if proxy == "" || proxy == "off" {
|
||||
// No proxy available
|
||||
handleHTTP(u, true)
|
||||
return ret("", false)
|
||||
}
|
||||
usingProxy = true
|
||||
}
|
||||
if !strings.HasPrefix(u, "gemini") {
|
||||
handleOther(u)
|
||||
return ret("", false)
|
||||
|
||||
if !strings.HasPrefix(u, "http") && !strings.HasPrefix(u, "gemini") {
|
||||
// Not a Gemini URL
|
||||
if proxy == "" || proxy == "off" {
|
||||
// No proxy available
|
||||
handleOther(u)
|
||||
return ret("", false)
|
||||
}
|
||||
usingProxy = true
|
||||
}
|
||||
// Gemini URL
|
||||
|
||||
// Gemini URL, or one with a Gemini proxy available
|
||||
|
||||
// Load page from cache if possible
|
||||
page, ok := cache.GetPage(u)
|
||||
@ -352,7 +379,12 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
|
||||
t.mode = tabModeLoading
|
||||
App.Draw()
|
||||
|
||||
res, err := client.Fetch(u)
|
||||
var res *gemini.Response
|
||||
if usingProxy {
|
||||
res, err = client.FetchWithProxy(proxyHostname, proxyPort, u)
|
||||
} else {
|
||||
res, err = client.Fetch(u)
|
||||
}
|
||||
|
||||
// Loading may have taken a while, make sure tab is still valid
|
||||
if !isValidTab(t) {
|
||||
@ -360,20 +392,32 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
|
||||
}
|
||||
|
||||
if errors.Is(err, client.ErrTofu) {
|
||||
if Tofu(parsed.Host, client.GetExpiry(parsed.Hostname(), parsed.Port())) {
|
||||
// They want to continue anyway
|
||||
client.ResetTofuEntry(parsed.Hostname(), parsed.Port(), res.Cert)
|
||||
// Response can be used further down, no need to reload
|
||||
if usingProxy {
|
||||
// They are using a proxy
|
||||
if Tofu(proxy, client.GetExpiry(proxyHostname, proxyPort)) {
|
||||
// They want to continue anyway
|
||||
client.ResetTofuEntry(proxyHostname, proxyPort, res.Cert)
|
||||
// Response can be used further down, no need to reload
|
||||
} else {
|
||||
// They don't want to continue
|
||||
return ret("", false)
|
||||
}
|
||||
} else {
|
||||
// They don't want to continue
|
||||
return ret("", false)
|
||||
if Tofu(parsed.Host, client.GetExpiry(parsed.Hostname(), parsed.Port())) {
|
||||
// They want to continue anyway
|
||||
client.ResetTofuEntry(parsed.Hostname(), parsed.Port(), res.Cert)
|
||||
// Response can be used further down, no need to reload
|
||||
} else {
|
||||
// They don't want to continue
|
||||
return ret("", false)
|
||||
}
|
||||
}
|
||||
} else if err != nil {
|
||||
Error("URL Fetch Error", err.Error())
|
||||
return ret("", false)
|
||||
}
|
||||
if renderer.CanDisplay(res) {
|
||||
page, err := renderer.MakePage(u, res, textWidth(), leftMargin())
|
||||
page, err := renderer.MakePage(u, res, textWidth(), leftMargin(), usingProxy)
|
||||
// Rendering may have taken a while, make sure tab is still valid
|
||||
if !isValidTab(t) {
|
||||
return ret("", false)
|
||||
|
@ -57,7 +57,7 @@ func CanDisplay(res *gemini.Response) bool {
|
||||
|
||||
// MakePage creates a formatted, rendered Page from the given network response and params.
|
||||
// You must set the Page.Width value yourself.
|
||||
func MakePage(url string, res *gemini.Response, width, leftMargin int) (*structs.Page, error) {
|
||||
func MakePage(url string, res *gemini.Response, width, leftMargin int, proxied bool) (*structs.Page, error) {
|
||||
if !CanDisplay(res) {
|
||||
return nil, ErrCantDisplay
|
||||
}
|
||||
@ -102,7 +102,7 @@ func MakePage(url string, res *gemini.Response, width, leftMargin int) (*structs
|
||||
}
|
||||
|
||||
if mediatype == "text/gemini" {
|
||||
rendered, links := RenderGemini(utfText, width, leftMargin)
|
||||
rendered, links := RenderGemini(utfText, width, leftMargin, proxied)
|
||||
return &structs.Page{
|
||||
Mediatype: structs.TextGemini,
|
||||
URL: url,
|
||||
|
@ -87,13 +87,17 @@ func tagLines(s, start, end string) string {
|
||||
|
||||
// convertRegularGemini converts non-preformatted blocks of text/gemini
|
||||
// into a cview-compatible format.
|
||||
// Since this only works on non-preformatted blocks, RenderGemini
|
||||
// should always be used instead.
|
||||
//
|
||||
// It also returns a slice of link URLs.
|
||||
// numLinks is the number of links that exist so far.
|
||||
// width is the number of columns to wrap to.
|
||||
//
|
||||
// Since this only works on non-preformatted blocks, RenderGemini
|
||||
// should always be used instead.
|
||||
func convertRegularGemini(s string, numLinks, width int) (string, []string) {
|
||||
//
|
||||
// proxied is whether the request is through the gemini:// scheme.
|
||||
// If it's not a gemini:// page, set this to true.
|
||||
func convertRegularGemini(s string, numLinks, width int, proxied bool) (string, []string) {
|
||||
links := make([]string, 0)
|
||||
lines := strings.Split(s, "\n")
|
||||
wrappedLines := make([]string, 0) // Final result
|
||||
@ -175,7 +179,8 @@ func convertRegularGemini(s string, numLinks, width int) (string, []string) {
|
||||
|
||||
if viper.GetBool("a-general.color") {
|
||||
pU, err := urlPkg.Parse(url)
|
||||
if err == nil && (pU.Scheme == "" || pU.Scheme == "gemini" || pU.Scheme == "about") {
|
||||
if !proxied && err == nil &&
|
||||
(pU.Scheme == "" || pU.Scheme == "gemini" || pU.Scheme == "about") {
|
||||
// A gemini link
|
||||
// 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
|
||||
@ -267,7 +272,10 @@ func convertRegularGemini(s string, numLinks, width int) (string, []string) {
|
||||
//
|
||||
// width is the number of columns to wrap to.
|
||||
// leftMargin is the number of blank spaces to prepend to each line.
|
||||
func RenderGemini(s string, width, leftMargin int) (string, []string) {
|
||||
//
|
||||
// proxied is whether the request is through the gemini:// scheme.
|
||||
// If it's not a gemini:// page, set this to true.
|
||||
func RenderGemini(s string, width, leftMargin int, proxied bool) (string, []string) {
|
||||
s = cview.Escape(s)
|
||||
if viper.GetBool("a-general.color") {
|
||||
s = cview.TranslateANSI(s)
|
||||
@ -292,7 +300,7 @@ func RenderGemini(s string, width, leftMargin int) (string, []string) {
|
||||
)
|
||||
} else {
|
||||
// Not preformatted, regular text
|
||||
ren, lks := convertRegularGemini(buf, len(links), width)
|
||||
ren, lks := convertRegularGemini(buf, len(links), width, proxied)
|
||||
links = append(links, lks...)
|
||||
rendered += ren
|
||||
}
|
||||
@ -310,7 +318,7 @@ func RenderGemini(s string, width, leftMargin int) (string, []string) {
|
||||
} else {
|
||||
// Not preformatted, regular text
|
||||
// Same code as in the loop above
|
||||
ren, lks := convertRegularGemini(buf, len(links), width)
|
||||
ren, lks := convertRegularGemini(buf, len(links), width, proxied)
|
||||
links = append(links, lks...)
|
||||
rendered += ren
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user