mirror of
https://github.com/makeworld-the-better-one/amfora.git
synced 2024-09-11 14:55:51 +03:00
parent
199d122990
commit
cfe58cb5f3
14
CHANGELOG.md
14
CHANGELOG.md
@ -6,12 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
- Support over 55 charsets (#3)
|
- **Bookmarks** (#10)
|
||||||
- Add titles to error modals
|
- **Support over 55 charsets** (#3)
|
||||||
|
- **Search using the bottom bar**
|
||||||
|
- Add titles to all modals
|
||||||
- Store ports in TOFU database (#7)
|
- Store ports in TOFU database (#7)
|
||||||
- Search from bottom bar
|
- Search from bottom bar
|
||||||
- Wrapping based on terminal width (#1)
|
- Wrapping based on terminal width (#1)
|
||||||
- `left_margin` config option
|
- `left_margin` config option (#1)
|
||||||
- Right margin for text (#1)
|
- Right margin for text (#1)
|
||||||
- Desktop entry file
|
- Desktop entry file
|
||||||
- Option to continue anyway when cert doesn't match TOFU database
|
- Option to continue anyway when cert doesn't match TOFU database
|
||||||
@ -21,7 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Changed
|
### Changed
|
||||||
- Connection timeout is 15 seconds (was 5s)
|
- Connection timeout is 15 seconds (was 5s)
|
||||||
- Hash `SubjectPublicKeyInfo` for TOFU instead (#7)
|
- Hash `SubjectPublicKeyInfo` for TOFU instead (#7)
|
||||||
- `wrap_width` config option became `max_width`
|
- `wrap_width` config option became `max_width` (#1)
|
||||||
|
- Make the help table look better
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- Opening multiple URLs from the command line (threading issues)
|
- Opening multiple URLs from the command line (threading issues)
|
||||||
@ -30,7 +33,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Reset bottom bar on error / invalid URL
|
- Reset bottom bar on error / invalid URL
|
||||||
- Side scrolling doesn't cut off text on the left side (#1)
|
- Side scrolling doesn't cut off text on the left side (#1)
|
||||||
- Mark status code 21 as invalid
|
- Mark status code 21 as invalid
|
||||||
- You can't type on the bottom bar as it's loading
|
- Bottom bar is not in focus after clicking Enter
|
||||||
|
- Badly formed links on pages can no longer crash the browser
|
||||||
|
|
||||||
|
|
||||||
## [1.0.0] - 2020-06-18
|
## [1.0.0] - 2020-06-18
|
||||||
|
@ -49,8 +49,8 @@ Features in *italics* are in the master branch, but not in the latest release.
|
|||||||
- [x] Basic forward/backward history, for each tab
|
- [x] Basic forward/backward history, for each tab
|
||||||
- [x] Input (Status Code 10 & 11)
|
- [x] Input (Status Code 10 & 11)
|
||||||
- [x] *Multiple charset support (over 55)*
|
- [x] *Multiple charset support (over 55)*
|
||||||
- [x] *Built-in search using GUS*
|
- [x] *Built-in search (uses GUS by default)*
|
||||||
- [ ] Bookmarks
|
- [x] *Bookmarks*
|
||||||
- [ ] Search in pages with <kbd>Ctrl-F</kbd>
|
- [ ] Search in pages with <kbd>Ctrl-F</kbd>
|
||||||
- [ ] Download pages and arbitrary data
|
- [ ] Download pages and arbitrary data
|
||||||
- [ ] Emoji favicons
|
- [ ] Emoji favicons
|
||||||
|
60
bookmarks/bookmarks.go
Normal file
60
bookmarks/bookmarks.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package bookmarks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base32"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/makeworld-the-better-one/amfora/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var bkmkStore = config.BkmkStore
|
||||||
|
|
||||||
|
// bkmkKey returns the viper key for the given bookmark URL.
|
||||||
|
// Note that URLs are the keys, NOT the bookmark name.
|
||||||
|
func bkmkKey(url string) string {
|
||||||
|
// Keys are base32 encoded URLs to prevent any bad chars like periods from being used
|
||||||
|
return "bookmarks." + base32.StdEncoding.EncodeToString([]byte(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Set(url, name string) {
|
||||||
|
bkmkStore.Set(bkmkKey(url), name)
|
||||||
|
bkmkStore.WriteConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the NAME of the bookmark, given the URL.
|
||||||
|
// It also returns a bool indicating whether it exists.
|
||||||
|
func Get(url string) (string, bool) {
|
||||||
|
name := bkmkStore.GetString(bkmkKey(url))
|
||||||
|
return name, name != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func Remove(url string) {
|
||||||
|
// XXX: Viper can't actually delete keys, which means the bookmarks file might get clouded
|
||||||
|
// with non-entries over time.
|
||||||
|
bkmkStore.Set(bkmkKey(url), "")
|
||||||
|
bkmkStore.WriteConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
// All returns all the bookmarks in a map of URLs to names.
|
||||||
|
func All() map[string]string {
|
||||||
|
ret := make(map[string]string)
|
||||||
|
|
||||||
|
bkmksMap, ok := bkmkStore.AllSettings()["bookmarks"].(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
// No bookmarks stored yet, return empty map
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
for b32Url, name := range bkmksMap {
|
||||||
|
if n, ok := name.(string); n == "" || !ok {
|
||||||
|
// name is not a string, or it's empty - ignore
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
url, err := base32.StdEncoding.DecodeString(strings.ToUpper(b32Url))
|
||||||
|
if err != nil {
|
||||||
|
// This would only happen if a user messed around with the bookmarks file
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret[string(url)] = name.(string)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
5
cache/cache.go
vendored
5
cache/cache.go
vendored
@ -4,6 +4,7 @@ package cache
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/makeworld-the-better-one/amfora/structs"
|
"github.com/makeworld-the-better-one/amfora/structs"
|
||||||
@ -47,8 +48,8 @@ func removeUrl(url string) {
|
|||||||
// If your page is larger than the max cache size, the provided page
|
// If your page is larger than the max cache size, the provided page
|
||||||
// will silently not be added to the cache.
|
// will silently not be added to the cache.
|
||||||
func Add(p *structs.Page) {
|
func Add(p *structs.Page) {
|
||||||
if p.Url == "" {
|
if p.Url == "" || strings.HasPrefix(p.Url, "about:") {
|
||||||
// Just in case, don't waste cache on new tab page
|
// Just in case, these pages shouldn't be cached
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Never cache pages with query strings, to reduce unexpected behaviour
|
// Never cache pages with query strings, to reduce unexpected behaviour
|
||||||
|
@ -19,12 +19,17 @@ var TofuStore = viper.New()
|
|||||||
var tofuDBDir string
|
var tofuDBDir string
|
||||||
var tofuDBPath string
|
var tofuDBPath string
|
||||||
|
|
||||||
|
// Bookmarks
|
||||||
|
var BkmkStore = viper.New()
|
||||||
|
var bkmkDir string
|
||||||
|
var bkmkPath string
|
||||||
|
|
||||||
func Init() error {
|
func Init() error {
|
||||||
home, err := homedir.Dir()
|
home, err := homedir.Dir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
// Cache AppData path
|
// Store AppData path
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
appdata, ok := os.LookupEnv("APPDATA")
|
appdata, ok := os.LookupEnv("APPDATA")
|
||||||
if ok {
|
if ok {
|
||||||
@ -33,7 +38,8 @@ func Init() error {
|
|||||||
amforaAppData = filepath.Join(home, filepath.FromSlash("AppData/Roaming/amfora/"))
|
amforaAppData = filepath.Join(home, filepath.FromSlash("AppData/Roaming/amfora/"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Cache config directory and file paths
|
|
||||||
|
// Store config directory and file paths
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
configDir = amforaAppData
|
configDir = amforaAppData
|
||||||
} else {
|
} else {
|
||||||
@ -48,7 +54,7 @@ func Init() error {
|
|||||||
}
|
}
|
||||||
configPath = filepath.Join(configDir, "config.toml")
|
configPath = filepath.Join(configDir, "config.toml")
|
||||||
|
|
||||||
// Cache TOFU db directory and file paths
|
// Store TOFU db directory and file paths
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
// Windows just stores it in APPDATA along with other stuff
|
// Windows just stores it in APPDATA along with other stuff
|
||||||
tofuDBDir = amforaAppData
|
tofuDBDir = amforaAppData
|
||||||
@ -64,6 +70,25 @@ func Init() error {
|
|||||||
}
|
}
|
||||||
tofuDBPath = filepath.Join(tofuDBDir, "tofu.toml")
|
tofuDBPath = filepath.Join(tofuDBDir, "tofu.toml")
|
||||||
|
|
||||||
|
// Store bookmarks dir and path
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// Windows just keeps it in APPDATA along with other Amfora files
|
||||||
|
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 {
|
||||||
|
// Default to ~/.local/share/amfora
|
||||||
|
bkmkDir = filepath.Join(home, ".local", "share", "amfora")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bkmkPath = filepath.Join(bkmkDir, "bookmarks.toml")
|
||||||
|
|
||||||
|
// Create necessary files and folders
|
||||||
|
|
||||||
|
// Config
|
||||||
err = os.MkdirAll(configDir, 0755)
|
err = os.MkdirAll(configDir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -78,12 +103,20 @@ func Init() error {
|
|||||||
}
|
}
|
||||||
f.Close()
|
f.Close()
|
||||||
}
|
}
|
||||||
|
// TOFU
|
||||||
err = os.MkdirAll(tofuDBDir, 0755)
|
err = os.MkdirAll(tofuDBDir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
os.OpenFile(tofuDBPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
|
os.OpenFile(tofuDBPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
|
||||||
|
// Bookmarks
|
||||||
|
err = os.MkdirAll(bkmkDir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
os.OpenFile(bkmkPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
|
||||||
|
|
||||||
|
// Setup vipers
|
||||||
|
|
||||||
TofuStore.SetConfigFile(tofuDBPath)
|
TofuStore.SetConfigFile(tofuDBPath)
|
||||||
TofuStore.SetConfigType("toml")
|
TofuStore.SetConfigType("toml")
|
||||||
@ -92,6 +125,18 @@ func Init() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BkmkStore.SetConfigFile(bkmkPath)
|
||||||
|
BkmkStore.SetConfigType("toml")
|
||||||
|
err = BkmkStore.ReadInConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
BkmkStore.Set("DO NOT TOUCH", true)
|
||||||
|
err = BkmkStore.WriteConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
viper.SetDefault("a-general.home", "gemini.circumlunar.space")
|
viper.SetDefault("a-general.home", "gemini.circumlunar.space")
|
||||||
viper.SetDefault("a-general.http", "default")
|
viper.SetDefault("a-general.http", "default")
|
||||||
viper.SetDefault("a-general.search", "gus.guru/search")
|
viper.SetDefault("a-general.search", "gus.guru/search")
|
||||||
|
@ -9,7 +9,7 @@ var defaultConf = []byte(`# This is the default config file.
|
|||||||
# gemini://example.com
|
# gemini://example.com
|
||||||
# //example.com
|
# //example.com
|
||||||
# example.com
|
# example.com
|
||||||
# example.com:1901
|
# example.com:123
|
||||||
|
|
||||||
[a-general]
|
[a-general]
|
||||||
home = "gemini://gemini.circumlunar.space"
|
home = "gemini://gemini.circumlunar.space"
|
||||||
@ -23,16 +23,10 @@ http = "default"
|
|||||||
search = "gemini://gus.guru/search" # Any URL that will accept a query string can be put here
|
search = "gemini://gus.guru/search" # Any URL that will accept a query string can be put here
|
||||||
color = true # Whether colors will be used in the terminal
|
color = true # Whether colors will be used in the terminal
|
||||||
bullets = true # Whether to replace list asterisks with unicode bullets
|
bullets = true # Whether to replace list asterisks with unicode bullets
|
||||||
|
|
||||||
# A number from 0 to 1, indicating what percentage of the terminal width the left margin should take up.
|
# A number from 0 to 1, indicating what percentage of the terminal width the left margin should take up.
|
||||||
left_margin = 0.15
|
left_margin = 0.15
|
||||||
max_width = 100 # The max number of columns to wrap a page's text to. Preformatted blocks are not wrapped.
|
max_width = 100 # The max number of columns to wrap a page's text to. Preformatted blocks are not wrapped.
|
||||||
|
|
||||||
[bookmarks]
|
|
||||||
# Make sure to quote the key names if you edit this part yourself
|
|
||||||
# Example:
|
|
||||||
# "CAPCOM" = "gemini://gemini.circumlunar.space/capcom/"
|
|
||||||
|
|
||||||
# Options for page cache - which is only for text/gemini pages
|
# Options for page cache - which is only for text/gemini pages
|
||||||
# Increase the cache size to speed up browsing at the expense of memory
|
# Increase the cache size to speed up browsing at the expense of memory
|
||||||
[cache]
|
[cache]
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# gemini://example.com
|
# gemini://example.com
|
||||||
# //example.com
|
# //example.com
|
||||||
# example.com
|
# example.com
|
||||||
# example.com:1901
|
# example.com:123
|
||||||
|
|
||||||
[a-general]
|
[a-general]
|
||||||
home = "gemini://gemini.circumlunar.space"
|
home = "gemini://gemini.circumlunar.space"
|
||||||
@ -20,16 +20,10 @@ http = "default"
|
|||||||
search = "gemini://gus.guru/search" # Any URL that will accept a query string can be put here
|
search = "gemini://gus.guru/search" # Any URL that will accept a query string can be put here
|
||||||
color = true # Whether colors will be used in the terminal
|
color = true # Whether colors will be used in the terminal
|
||||||
bullets = true # Whether to replace list asterisks with unicode bullets
|
bullets = true # Whether to replace list asterisks with unicode bullets
|
||||||
|
|
||||||
# A number from 0 to 1, indicating what percentage of the terminal width the left margin should take up.
|
# A number from 0 to 1, indicating what percentage of the terminal width the left margin should take up.
|
||||||
left_margin = 0.15
|
left_margin = 0.15
|
||||||
max_width = 100 # The max number of columns to wrap a page's text to. Preformatted blocks are not wrapped.
|
max_width = 100 # The max number of columns to wrap a page's text to. Preformatted blocks are not wrapped.
|
||||||
|
|
||||||
[bookmarks]
|
|
||||||
# Make sure to quote the key names if you edit this part yourself
|
|
||||||
# Example:
|
|
||||||
# "CAPCOM" = "gemini://gemini.circumlunar.space/capcom/"
|
|
||||||
|
|
||||||
# Options for page cache - which is only for text/gemini pages
|
# Options for page cache - which is only for text/gemini pages
|
||||||
# Increase the cache size to speed up browsing at the expense of memory
|
# Increase the cache size to speed up browsing at the expense of memory
|
||||||
[cache]
|
[cache]
|
||||||
|
120
display/bookmarks.go
Normal file
120
display/bookmarks.go
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
package display
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/makeworld-the-better-one/amfora/renderer"
|
||||||
|
"github.com/makeworld-the-better-one/amfora/structs"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell"
|
||||||
|
"github.com/makeworld-the-better-one/amfora/bookmarks"
|
||||||
|
"gitlab.com/tslocum/cview"
|
||||||
|
)
|
||||||
|
|
||||||
|
// For adding and removing bookmarks, basically a clone of the input modal.
|
||||||
|
var bkmkModal = cview.NewModal().
|
||||||
|
SetBackgroundColor(tcell.ColorTeal).
|
||||||
|
SetButtonBackgroundColor(tcell.ColorNavy).
|
||||||
|
SetButtonTextColor(tcell.ColorWhite).
|
||||||
|
SetTextColor(tcell.ColorWhite)
|
||||||
|
|
||||||
|
// bkmkCh is for the user action
|
||||||
|
var bkmkCh = make(chan int) // 1, 0, -1 for add/update, cancel, and remove
|
||||||
|
var bkmkModalText string // The current text of the input field in the modal
|
||||||
|
|
||||||
|
func bkmkInit() {
|
||||||
|
bkmkModal.SetBorder(true)
|
||||||
|
bkmkModal.SetBorderColor(tcell.ColorWhite)
|
||||||
|
bkmkModal.SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
||||||
|
switch buttonLabel {
|
||||||
|
case "Add":
|
||||||
|
bkmkCh <- 1
|
||||||
|
case "Change":
|
||||||
|
bkmkCh <- 1
|
||||||
|
case "Remove":
|
||||||
|
bkmkCh <- -1
|
||||||
|
case "Cancel":
|
||||||
|
bkmkCh <- 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//tabPages.SwitchToPage(strconv.Itoa(curTab)) - handled in bkmk()
|
||||||
|
})
|
||||||
|
bkmkModal.GetFrame().SetTitleColor(tcell.ColorWhite)
|
||||||
|
bkmkModal.GetFrame().SetTitleAlign(cview.AlignCenter)
|
||||||
|
bkmkModal.GetFrame().SetTitle(" Add Bookmark ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bkmk displays the "Add a bookmark" modal.
|
||||||
|
// It accepts the default value for the bookmark name that will be displayed, but can be changed by the user.
|
||||||
|
// 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) {
|
||||||
|
// Basically a copy of Input()
|
||||||
|
|
||||||
|
// Remove and re-add input field - to clear the old text
|
||||||
|
if bkmkModal.GetForm().GetFormItemCount() > 0 {
|
||||||
|
bkmkModal.GetForm().RemoveFormItem(0)
|
||||||
|
}
|
||||||
|
bkmkModalText = ""
|
||||||
|
bkmkModal.GetForm().AddInputField("Name: ", name, 0, nil,
|
||||||
|
func(text string) {
|
||||||
|
// Store for use later
|
||||||
|
bkmkModalText = text
|
||||||
|
})
|
||||||
|
|
||||||
|
bkmkModal.ClearButtons()
|
||||||
|
if exists {
|
||||||
|
bkmkModal.SetText("Change or remove the bookmark for the current page?")
|
||||||
|
bkmkModal.AddButtons([]string{"Change", "Remove", "Cancel"})
|
||||||
|
} else {
|
||||||
|
bkmkModal.SetText("Create a bookmark for the current page?")
|
||||||
|
bkmkModal.AddButtons([]string{"Add", "Cancel"})
|
||||||
|
}
|
||||||
|
tabPages.ShowPage("bkmk")
|
||||||
|
tabPages.SendToFront("bkmk")
|
||||||
|
App.SetFocus(bkmkModal)
|
||||||
|
App.Draw()
|
||||||
|
|
||||||
|
action := <-bkmkCh
|
||||||
|
tabPages.SwitchToPage(strconv.Itoa(curTab))
|
||||||
|
|
||||||
|
return bkmkModalText, action
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bookmarks displays the bookmarks page on the current tab.
|
||||||
|
func Bookmarks() {
|
||||||
|
// Gather bookmarks
|
||||||
|
rawContent := "# Bookmarks\r\n\r\n"
|
||||||
|
for url, name := range bookmarks.All() {
|
||||||
|
rawContent += fmt.Sprintf("=> %s %s\r\n", url, name)
|
||||||
|
}
|
||||||
|
// Render and display
|
||||||
|
content, links := renderer.RenderGemini(rawContent, textWidth())
|
||||||
|
page := structs.Page{Content: content, Links: links, Url: "about:bookmarks"}
|
||||||
|
setPage(&page)
|
||||||
|
}
|
||||||
|
|
||||||
|
// addBookmark goes through the process of adding a bookmark for the current page.
|
||||||
|
// 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(tabMap[curTab].Url, "gemini://") {
|
||||||
|
// Can't make bookmarks for other kinds of URLs
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
name, exists := bookmarks.Get(tabMap[curTab].Url)
|
||||||
|
// Open a bookmark modal with the current name of the bookmark, if it exists
|
||||||
|
newName, action := openBkmkModal(name, exists)
|
||||||
|
switch action {
|
||||||
|
case 1:
|
||||||
|
// Add/change the bookmark
|
||||||
|
bookmarks.Set(tabMap[curTab].Url, newName)
|
||||||
|
case -1:
|
||||||
|
bookmarks.Remove(tabMap[curTab].Url)
|
||||||
|
}
|
||||||
|
// Other case is action = 0, meaning "Cancel", so nothing needs to happen
|
||||||
|
}
|
@ -5,13 +5,11 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
|
|
||||||
"github.com/makeworld-the-better-one/amfora/renderer"
|
|
||||||
|
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
"github.com/makeworld-the-better-one/amfora/cache"
|
"github.com/makeworld-the-better-one/amfora/cache"
|
||||||
|
"github.com/makeworld-the-better-one/amfora/renderer"
|
||||||
"github.com/makeworld-the-better-one/amfora/structs"
|
"github.com/makeworld-the-better-one/amfora/structs"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"gitlab.com/tslocum/cview"
|
"gitlab.com/tslocum/cview"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,24 +26,13 @@ var bottomBar = cview.NewInputField().
|
|||||||
SetFieldTextColor(tcell.ColorBlack).
|
SetFieldTextColor(tcell.ColorBlack).
|
||||||
SetLabelColor(tcell.ColorGreen)
|
SetLabelColor(tcell.ColorGreen)
|
||||||
|
|
||||||
var helpTable = cview.NewTable().
|
|
||||||
SetSelectable(false, false).
|
|
||||||
SetFixed(1, 2).
|
|
||||||
SetBorders(true).
|
|
||||||
SetBordersColor(tcell.ColorGray)
|
|
||||||
|
|
||||||
// Viewer for the tab primitives
|
// Viewer for the tab primitives
|
||||||
// Pages are named as strings of tab numbers - so the textview for the first tab
|
// Pages are named as strings of tab numbers - so the textview for the first tab
|
||||||
// is held in the page named "0".
|
// is held in the page named "0".
|
||||||
// The only pages that don't confine to this scheme named after the modals above,
|
// The only pages that don't confine to this scheme are those named after modals,
|
||||||
// which is used to draw modals on top the current tab.
|
// which are used to draw modals on top the current tab.
|
||||||
// Ex: "info", "error", "input", "yesno"
|
// Ex: "info", "error", "input", "yesno"
|
||||||
var tabPages = cview.NewPages().
|
var tabPages = cview.NewPages()
|
||||||
AddPage("help", helpTable, true, false).
|
|
||||||
AddPage("info", infoModal, false, false).
|
|
||||||
AddPage("error", errorModal, false, false).
|
|
||||||
AddPage("input", inputModal, false, false).
|
|
||||||
AddPage("yesno", yesNoModal, false, false)
|
|
||||||
|
|
||||||
// The tabs at the top with titles
|
// The tabs at the top with titles
|
||||||
var tabRow = cview.NewTextView().
|
var tabRow = cview.NewTextView().
|
||||||
@ -116,15 +103,17 @@ func Init() {
|
|||||||
if c == 0 {
|
if c == 0 {
|
||||||
tableCell = cview.NewTableCell(cells[cell]).
|
tableCell = cview.NewTableCell(cells[cell]).
|
||||||
SetAttributes(tcell.AttrBold).
|
SetAttributes(tcell.AttrBold).
|
||||||
SetExpansion(1)
|
SetExpansion(1).
|
||||||
|
SetAlign(cview.AlignCenter)
|
||||||
} else {
|
} else {
|
||||||
tableCell = cview.NewTableCell(cells[cell]).
|
tableCell = cview.NewTableCell(" " + cells[cell]).
|
||||||
SetExpansion(2)
|
SetExpansion(2)
|
||||||
}
|
}
|
||||||
helpTable.SetCell(r, c, tableCell)
|
helpTable.SetCell(r, c, tableCell)
|
||||||
cell++
|
cell++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tabPages.AddPage("help", helpTable, true, false)
|
||||||
|
|
||||||
bottomBar.SetBackgroundColor(tcell.ColorWhite)
|
bottomBar.SetBackgroundColor(tcell.ColorWhite)
|
||||||
bottomBar.SetDoneFunc(func(key tcell.Key) {
|
bottomBar.SetDoneFunc(func(key tcell.Key) {
|
||||||
@ -147,7 +136,7 @@ func Init() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// It's a full URL or search term
|
// It's a full URL or search term
|
||||||
// Detect if it's a search or URL
|
// Detect if it's a search or URL
|
||||||
if strings.Contains(query, " ") || (!strings.Contains(query, "//") && !strings.Contains(query, ".")) {
|
if strings.Contains(query, " ") || (!strings.Contains(query, "//") && !strings.Contains(query, ".") && !strings.HasPrefix(query, "about:")) {
|
||||||
URL(viper.GetString("a-general.search") + "?" + pathEscape(query))
|
URL(viper.GetString("a-general.search") + "?" + pathEscape(query))
|
||||||
} else {
|
} else {
|
||||||
// Full URL
|
// Full URL
|
||||||
@ -178,7 +167,7 @@ func Init() {
|
|||||||
|
|
||||||
// Render the default new tab content ONCE and store it for later
|
// Render the default new tab content ONCE and store it for later
|
||||||
renderedNewTabContent, newTabLinks = renderer.RenderGemini(newTabContent, textWidth())
|
renderedNewTabContent, newTabLinks = renderer.RenderGemini(newTabContent, textWidth())
|
||||||
newTabPage = structs.Page{Content: renderedNewTabContent, Links: newTabLinks}
|
newTabPage = structs.Page{Content: renderedNewTabContent, Links: newTabLinks, Url: "about:newtab"}
|
||||||
|
|
||||||
modalInit()
|
modalInit()
|
||||||
|
|
||||||
@ -212,6 +201,13 @@ func Init() {
|
|||||||
case tcell.KeyCtrlQ:
|
case tcell.KeyCtrlQ:
|
||||||
Stop()
|
Stop()
|
||||||
return nil
|
return nil
|
||||||
|
case tcell.KeyCtrlB:
|
||||||
|
Bookmarks()
|
||||||
|
addToHist("about:bookmarks")
|
||||||
|
return nil
|
||||||
|
case tcell.KeyCtrlD:
|
||||||
|
go addBookmark()
|
||||||
|
return nil
|
||||||
case tcell.KeyRune:
|
case tcell.KeyRune:
|
||||||
// Regular key was sent
|
// Regular key was sent
|
||||||
switch string(event.Rune()) {
|
switch string(event.Rune()) {
|
||||||
@ -422,6 +418,22 @@ func Reload() {
|
|||||||
// URL loads and handles the provided URL for the current tab.
|
// URL loads and handles the provided URL for the current tab.
|
||||||
// It should be an absolute URL.
|
// It should be an absolute URL.
|
||||||
func URL(u string) {
|
func URL(u string) {
|
||||||
|
// Some code is copied in followLink()
|
||||||
|
|
||||||
|
if u == "about:bookmarks" {
|
||||||
|
Bookmarks()
|
||||||
|
addToHist("about:bookmarks")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if u == "about:newtab" {
|
||||||
|
setPage(&newTabPage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(u, "about:") {
|
||||||
|
Error("Error", "Not a valid 'about:' URL.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
final, displayed := handleURL(u)
|
final, displayed := handleURL(u)
|
||||||
if displayed {
|
if displayed {
|
||||||
@ -433,10 +445,3 @@ func URL(u string) {
|
|||||||
func NumTabs() int {
|
func NumTabs() int {
|
||||||
return len(tabViews)
|
return len(tabViews)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Help displays the help and keybindings.
|
|
||||||
func Help() {
|
|
||||||
helpTable.ScrollToBeginning()
|
|
||||||
tabPages.SwitchToPage("help")
|
|
||||||
App.Draw()
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
package display
|
package display
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell"
|
||||||
|
"gitlab.com/tslocum/cview"
|
||||||
|
)
|
||||||
|
|
||||||
var helpCells = strings.TrimSpace(`
|
var helpCells = strings.TrimSpace(`
|
||||||
?|Bring up this help.
|
?|Bring up this help.
|
||||||
@ -8,17 +13,32 @@ Esc|Leave the help
|
|||||||
Arrow keys, h/j/k/l|Scroll and move a page.
|
Arrow keys, h/j/k/l|Scroll and move a page.
|
||||||
Tab|Navigate to the next item in a popup.
|
Tab|Navigate to the next item in a popup.
|
||||||
Shift-Tab|Navigate to the previous item in a popup.
|
Shift-Tab|Navigate to the previous item in a popup.
|
||||||
Ctrl-H|Go home
|
|
||||||
Ctrl-T|New tab
|
|
||||||
Ctrl-W|Close tab. For now, only the right-most tab can be closed.
|
|
||||||
b|Go back a page
|
b|Go back a page
|
||||||
f|Go forward a page
|
f|Go forward a page
|
||||||
g|Go to top of document
|
g|Go to top of document
|
||||||
G|Go to bottom of document
|
G|Go to bottom of document
|
||||||
spacebar|Open bar at the bottom - type a URL or link number
|
spacebar|Open bar at the bottom - type a URL or link number
|
||||||
Enter|On a page this will start link highlighting. Press Tab and Shift-Tab to pick different links. Press enter again to go to one.
|
Enter|On a page this will start link highlighting. Press Tab and Shift-Tab to pick different links. Press enter again to go to one.
|
||||||
Ctrl-R, R|Reload a page. This also clears the cache.
|
|
||||||
q, Ctrl-Q|Quit
|
|
||||||
Shift-NUMBER|Go to a specific tab.
|
Shift-NUMBER|Go to a specific tab.
|
||||||
Shift-0, )|Go to the last tab.
|
Shift-0, )|Go to the last tab.
|
||||||
|
Ctrl-H|Go home
|
||||||
|
Ctrl-T|New tab
|
||||||
|
Ctrl-W|Close tab. For now, only the right-most tab can be closed.
|
||||||
|
Ctrl-R, R|Reload a page, discarding the cached version.
|
||||||
|
Ctrl-B|View bookmarks
|
||||||
|
Ctrl-D|Add, change, or remove a bookmark for the current page.
|
||||||
|
q, Ctrl-Q|Quit
|
||||||
`)
|
`)
|
||||||
|
|
||||||
|
var helpTable = cview.NewTable().
|
||||||
|
SetSelectable(false, false).
|
||||||
|
SetFixed(1, 2).
|
||||||
|
SetBorders(true).
|
||||||
|
SetBordersColor(tcell.ColorGray)
|
||||||
|
|
||||||
|
// Help displays the help and keybindings.
|
||||||
|
func Help() {
|
||||||
|
helpTable.ScrollToBeginning()
|
||||||
|
tabPages.SwitchToPage("help")
|
||||||
|
App.Draw()
|
||||||
|
}
|
||||||
|
@ -9,7 +9,8 @@ import (
|
|||||||
"gitlab.com/tslocum/cview"
|
"gitlab.com/tslocum/cview"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file contains code for all the popups / modals used in the display
|
// This file contains code for the popups / modals used in the display.
|
||||||
|
// The bookmark modal is in bookmarks.go
|
||||||
|
|
||||||
var infoModal = cview.NewModal().
|
var infoModal = cview.NewModal().
|
||||||
SetBackgroundColor(tcell.ColorGray).
|
SetBackgroundColor(tcell.ColorGray).
|
||||||
@ -45,20 +46,30 @@ var yesNoModal = cview.NewModal().
|
|||||||
var yesNoCh = make(chan bool)
|
var yesNoCh = make(chan bool)
|
||||||
|
|
||||||
func modalInit() {
|
func modalInit() {
|
||||||
|
tabPages.AddPage("info", infoModal, false, false).
|
||||||
|
AddPage("error", errorModal, false, false).
|
||||||
|
AddPage("input", inputModal, false, false).
|
||||||
|
AddPage("yesno", yesNoModal, false, false).
|
||||||
|
AddPage("bkmk", bkmkModal, false, false)
|
||||||
|
|
||||||
// Modal functions that can't be added up above, because they return the wrong type
|
// Modal functions that can't be added up above, because they return the wrong type
|
||||||
|
|
||||||
infoModal.SetBorder(true)
|
infoModal.SetBorder(true)
|
||||||
infoModal.SetBorderColor(tcell.ColorWhite)
|
infoModal.SetBorderColor(tcell.ColorWhite)
|
||||||
infoModal.SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
infoModal.SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
||||||
tabPages.SwitchToPage(strconv.Itoa(curTab))
|
tabPages.SwitchToPage(strconv.Itoa(curTab))
|
||||||
})
|
})
|
||||||
|
infoModal.GetFrame().SetTitleColor(tcell.ColorWhite)
|
||||||
|
infoModal.GetFrame().SetTitleAlign(cview.AlignCenter)
|
||||||
|
infoModal.GetFrame().SetTitle(" Info ")
|
||||||
|
|
||||||
errorModal.SetBorder(true)
|
errorModal.SetBorder(true)
|
||||||
errorModal.SetBorderColor(tcell.ColorWhite)
|
errorModal.SetBorderColor(tcell.ColorWhite)
|
||||||
errorModal.GetFrame().SetTitleColor(tcell.ColorWhite)
|
|
||||||
errorModal.GetFrame().SetTitleAlign(cview.AlignCenter)
|
|
||||||
errorModal.SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
errorModal.SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
||||||
tabPages.SwitchToPage(strconv.Itoa(curTab))
|
tabPages.SwitchToPage(strconv.Itoa(curTab))
|
||||||
})
|
})
|
||||||
|
errorModal.GetFrame().SetTitleColor(tcell.ColorWhite)
|
||||||
|
errorModal.GetFrame().SetTitleAlign(cview.AlignCenter)
|
||||||
|
|
||||||
inputModal.SetBorder(true)
|
inputModal.SetBorder(true)
|
||||||
inputModal.SetBorderColor(tcell.ColorWhite)
|
inputModal.SetBorderColor(tcell.ColorWhite)
|
||||||
@ -72,6 +83,9 @@ func modalInit() {
|
|||||||
|
|
||||||
//tabPages.SwitchToPage(strconv.Itoa(curTab)) - handled in Input()
|
//tabPages.SwitchToPage(strconv.Itoa(curTab)) - handled in Input()
|
||||||
})
|
})
|
||||||
|
inputModal.GetFrame().SetTitleColor(tcell.ColorWhite)
|
||||||
|
inputModal.GetFrame().SetTitleAlign(cview.AlignCenter)
|
||||||
|
inputModal.GetFrame().SetTitle(" Input ")
|
||||||
|
|
||||||
yesNoModal.SetBorder(true)
|
yesNoModal.SetBorder(true)
|
||||||
yesNoModal.SetBorderColor(tcell.ColorWhite)
|
yesNoModal.SetBorderColor(tcell.ColorWhite)
|
||||||
@ -84,6 +98,10 @@ func modalInit() {
|
|||||||
|
|
||||||
//tabPages.SwitchToPage(strconv.Itoa(curTab)) - Handled in YesNo()
|
//tabPages.SwitchToPage(strconv.Itoa(curTab)) - Handled in YesNo()
|
||||||
})
|
})
|
||||||
|
yesNoModal.GetFrame().SetTitleColor(tcell.ColorWhite)
|
||||||
|
yesNoModal.GetFrame().SetTitleAlign(cview.AlignCenter)
|
||||||
|
|
||||||
|
bkmkInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error displays an error on the screen in a modal.
|
// Error displays an error on the screen in a modal.
|
||||||
@ -157,7 +175,7 @@ func YesNo(prompt string) bool {
|
|||||||
// Tofu displays the TOFU warning modal.
|
// Tofu displays the TOFU warning modal.
|
||||||
// It returns a bool indicating whether the user wants to continue.
|
// It returns a bool indicating whether the user wants to continue.
|
||||||
func Tofu(host string) bool {
|
func Tofu(host string) bool {
|
||||||
// Reuses yesno modal, with error colour
|
// Reuses yesNoModal, with error colour
|
||||||
|
|
||||||
yesNoModal.SetBackgroundColor(tcell.ColorMaroon)
|
yesNoModal.SetBackgroundColor(tcell.ColorMaroon)
|
||||||
yesNoModal.SetText(
|
yesNoModal.SetText(
|
||||||
|
@ -8,6 +8,8 @@ Press the ? key at any time to bring up the help, and see other keybindings. Mos
|
|||||||
|
|
||||||
Happy browsing!
|
Happy browsing!
|
||||||
|
|
||||||
=> //gemini.circumlunar.space Gemini homepage
|
=> about:bookmarks Bookmarks
|
||||||
|
|
||||||
|
=> //gemini.circumlunar.space Project Gemini
|
||||||
=> https://github.com/makeworld-the-better-one/amfora Amfora homepage [HTTPS]
|
=> https://github.com/makeworld-the-better-one/amfora Amfora homepage [HTTPS]
|
||||||
`
|
`
|
||||||
|
@ -61,6 +61,10 @@ func tabHasContent() bool {
|
|||||||
// Likely the default content page
|
// Likely the default content page
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(tabMap[curTab].Url, "about:") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
_, ok := tabMap[curTab]
|
_, ok := tabMap[curTab]
|
||||||
return ok // If there's a page, return true
|
return ok // If there's a page, return true
|
||||||
}
|
}
|
||||||
@ -84,16 +88,44 @@ func applyScroll() {
|
|||||||
// followLink should be used when the user "clicks" a link on a page.
|
// 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.
|
// Not when a URL is opened on a new tab for the first time.
|
||||||
func followLink(prev, next string) {
|
func followLink(prev, next string) {
|
||||||
saveScroll() // Likely called later on anyway, here just in case
|
|
||||||
prevParsed, _ := url.Parse(prev)
|
// Copied from URL()
|
||||||
nextParsed, err := url.Parse(next)
|
if next == "about:bookmarks" {
|
||||||
|
Bookmarks()
|
||||||
|
addToHist("about:bookmarks")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(next, "about:") {
|
||||||
|
Error("Error", "Not a valid 'about:' URL for linking")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tabHasContent() {
|
||||||
|
saveScroll() // Likely called later on anyway, here just in case
|
||||||
|
prevParsed, _ := url.Parse(prev)
|
||||||
|
nextParsed, err := url.Parse(next)
|
||||||
|
if err != nil {
|
||||||
|
Error("URL Error", "Link URL could not be parsed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nextURL := prevParsed.ResolveReference(nextParsed).String()
|
||||||
|
go func() {
|
||||||
|
final, displayed := handleURL(nextURL)
|
||||||
|
if displayed {
|
||||||
|
addToHist(final)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// No content on current tab, so the "prev" URL is not valid.
|
||||||
|
// An example is the about:newtab page
|
||||||
|
_, err := url.Parse(next)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error("URL Error", "Link URL could not be parsed")
|
Error("URL Error", "Link URL could not be parsed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
nextURL := prevParsed.ResolveReference(nextParsed).String()
|
|
||||||
go func() {
|
go func() {
|
||||||
final, displayed := handleURL(nextURL)
|
final, displayed := handleURL(next)
|
||||||
if displayed {
|
if displayed {
|
||||||
addToHist(final)
|
addToHist(final)
|
||||||
}
|
}
|
||||||
@ -112,15 +144,9 @@ func addLeftMargin(text string) string {
|
|||||||
func setPage(p *structs.Page) {
|
func setPage(p *structs.Page) {
|
||||||
saveScroll() // Save the scroll of the previous page
|
saveScroll() // Save the scroll of the previous page
|
||||||
|
|
||||||
if !p.Displayable {
|
|
||||||
// Add margin to page based on terminal width
|
|
||||||
p.Content = addLeftMargin(p.Content)
|
|
||||||
p.Displayable = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change page on screen
|
// Change page on screen
|
||||||
tabMap[curTab] = p
|
tabMap[curTab] = p
|
||||||
tabViews[curTab].SetText(p.Content)
|
tabViews[curTab].SetText(addLeftMargin(p.Content))
|
||||||
tabViews[curTab].Highlight("") // Turn off highlights
|
tabViews[curTab].Highlight("") // Turn off highlights
|
||||||
tabViews[curTab].ScrollToBeginning()
|
tabViews[curTab].ScrollToBeginning()
|
||||||
|
|
||||||
@ -144,12 +170,14 @@ func handleURL(u string) (string, bool) {
|
|||||||
|
|
||||||
App.SetFocus(tabViews[curTab])
|
App.SetFocus(tabViews[curTab])
|
||||||
|
|
||||||
//logger.Log.Printf("Sent: %s", u)
|
// To allow linking to the bookmarks page, and history browsing
|
||||||
|
if u == "about:bookmarks" {
|
||||||
|
Bookmarks()
|
||||||
|
return "about:bookmarks", true
|
||||||
|
}
|
||||||
|
|
||||||
u = normalizeURL(u)
|
u = normalizeURL(u)
|
||||||
|
|
||||||
//logger.Log.Printf("Normalized: %s", u)
|
|
||||||
|
|
||||||
parsed, err := url.Parse(u)
|
parsed, err := url.Parse(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Error("URL Error", err.Error())
|
Error("URL Error", err.Error())
|
||||||
|
16
go.sum
16
go.sum
@ -32,20 +32,17 @@ github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
|
|||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||||
github.com/gdamore/tcell v1.3.0 h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM=
|
|
||||||
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
|
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
|
||||||
github.com/gdamore/tcell v1.3.1-0.20200608133353-cb1e5d6fa606 h1:Y00kKKKYVyn7InlCMRcnZbwcjHFIsgkjU0Bn1F5re4o=
|
github.com/gdamore/tcell v1.3.1-0.20200608133353-cb1e5d6fa606 h1:Y00kKKKYVyn7InlCMRcnZbwcjHFIsgkjU0Bn1F5re4o=
|
||||||
github.com/gdamore/tcell v1.3.1-0.20200608133353-cb1e5d6fa606/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0=
|
github.com/gdamore/tcell v1.3.1-0.20200608133353-cb1e5d6fa606/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0=
|
||||||
@ -143,7 +140,6 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI
|
|||||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA=
|
github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA=
|
||||||
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
@ -152,7 +148,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
|
|||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw=
|
github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw=
|
||||||
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
|
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
|
||||||
@ -183,25 +178,20 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK
|
|||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
|
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
|
||||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
@ -279,7 +269,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -288,7 +277,6 @@ golang.org/x/sys v0.0.0-20200610111108-226ff32320da h1:bGb80FudwxpeucJUjPYJXuJ8H
|
|||||||
golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@ -334,23 +322,19 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi
|
|||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
|
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
|
||||||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200603094226-e3079894b1e8 h1:jL/vaozO53FMfZLySWM+4nulF3gQEC6q5jH90LPomDo=
|
gopkg.in/yaml.v3 v3.0.0-20200603094226-e3079894b1e8 h1:jL/vaozO53FMfZLySWM+4nulF3gQEC6q5jH90LPomDo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200603094226-e3079894b1e8/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200603094226-e3079894b1e8/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@ -71,7 +71,8 @@ func convertRegularGemini(s string, numLinks int, width int) (string, []string)
|
|||||||
links = append(links, url)
|
links = append(links, url)
|
||||||
|
|
||||||
if viper.GetBool("a-general.color") {
|
if viper.GetBool("a-general.color") {
|
||||||
if pU, _ := urlPkg.Parse(url); pU.Scheme == "" || pU.Scheme == "gemini" {
|
pU, err := urlPkg.Parse(url)
|
||||||
|
if err == nil && (pU.Scheme == "" || pU.Scheme == "gemini" || pU.Scheme == "about") {
|
||||||
// A gemini link
|
// A gemini link
|
||||||
// Add the link text in blue (in a region), and a gray link number to the left of it
|
// Add the link text in blue (in a region), and a gray link number to the left of it
|
||||||
lines[i] = `[silver::b][` + strconv.Itoa(numLinks+len(links)) + "[]" + "[-::-] " +
|
lines[i] = `[silver::b][` + strconv.Itoa(numLinks+len(links)) + "[]" + "[-::-] " +
|
||||||
|
@ -2,12 +2,12 @@ package structs
|
|||||||
|
|
||||||
// Page is for storing UTF-8 text/gemini pages, as well as text/plain pages.
|
// Page is for storing UTF-8 text/gemini pages, as well as text/plain pages.
|
||||||
type Page struct {
|
type Page struct {
|
||||||
Url string
|
Url string
|
||||||
Content string // The processed content, NOT raw. Uses cview colour tags. All link/link texts must have region tags.
|
Content string // The processed content, NOT raw. Uses cview colour tags. All link/link texts must have region tags.
|
||||||
Links []string // URLs, for each region in the content.
|
Links []string // URLs, for each region in the content.
|
||||||
Row int // Scroll position
|
Row int // Scroll position
|
||||||
Column int // ditto
|
Column int // ditto
|
||||||
Displayable bool // Set to true once the content has been modified to display nicely on the screen - margins added
|
//Displayable bool // Set to true once the content has been modified to display nicely on the screen - margins added
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns an approx. size of a Page in bytes.
|
// Size returns an approx. size of a Page in bytes.
|
||||||
|
Loading…
Reference in New Issue
Block a user