mirror of
https://github.com/makew0rld/amfora.git
synced 2024-12-04 14:46:29 -05:00
Replace left margin spaces with an empty primitive
This commit introduced flashing issues in the tab row when reformatting, and even can panic in certain reformatting situations. These bugs have been logged in the inital comment of the PR.
This commit is contained in:
parent
4dff2b0119
commit
90654cd2cf
@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- More reliable start, no more flash of unindented text, or text that stays unindented (#107)
|
- More reliable start, no more flash of unindented text, or text that stays unindented (#107)
|
||||||
- Pages with ANSI resets don't use the terminal's default text and background colors (#107)
|
- Pages with ANSI resets don't use the terminal's default text and background colors (#107)
|
||||||
- ANSI documents don't leak color into the left margin (#107)
|
- ANSI documents don't leak color into the left margin (#107)
|
||||||
|
- Rendering very long documents is now ~96% faster, excluding gemtext parsing (#107)
|
||||||
|
|
||||||
|
|
||||||
## [1.7.2] - 2020-12-21
|
## [1.7.2] - 2020-12-21
|
||||||
|
3
NOTES.md
3
NOTES.md
@ -4,9 +4,6 @@
|
|||||||
- URL for each tab should not be stored as a string - in the current code there's lots of reparsing the URL
|
- URL for each tab should not be stored as a string - in the current code there's lots of reparsing the URL
|
||||||
|
|
||||||
## Upstream Bugs
|
## Upstream Bugs
|
||||||
- Text background not reset on ANSI pages
|
|
||||||
- Filed [issue 25](https://gitlab.com/tslocum/cview/-/issues/25)
|
|
||||||
- Add some bold back into modal text after this is fixed
|
|
||||||
- Bookmark keys aren't deleted, just set to `""`
|
- Bookmark keys aren't deleted, just set to `""`
|
||||||
- Waiting on [this viper PR](https://github.com/spf13/viper/pull/519) to be merged
|
- Waiting on [this viper PR](https://github.com/spf13/viper/pull/519) to be merged
|
||||||
- Help table cells aren't dynamically wrapped
|
- Help table cells aren't dynamically wrapped
|
||||||
|
@ -124,7 +124,7 @@ func Bookmarks(t *tab) {
|
|||||||
bkmkPageRaw += fmt.Sprintf("=> %s %s\r\n", keys[i], m[keys[i]])
|
bkmkPageRaw += fmt.Sprintf("=> %s %s\r\n", keys[i], m[keys[i]])
|
||||||
}
|
}
|
||||||
// Render and display
|
// Render and display
|
||||||
content, links := renderer.RenderGemini(bkmkPageRaw, textWidth(), leftMargin(), false)
|
content, links := renderer.RenderGemini(bkmkPageRaw, textWidth(), false)
|
||||||
page := structs.Page{
|
page := structs.Page{
|
||||||
Raw: bkmkPageRaw,
|
Raw: bkmkPageRaw,
|
||||||
Content: content,
|
Content: content,
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
"github.com/makeworld-the-better-one/amfora/cache"
|
"github.com/makeworld-the-better-one/amfora/cache"
|
||||||
@ -52,6 +53,9 @@ var layout = cview.NewFlex()
|
|||||||
var newTabPage structs.Page
|
var newTabPage structs.Page
|
||||||
var versionPage structs.Page
|
var versionPage structs.Page
|
||||||
|
|
||||||
|
// Global mutex for changing the size of the left margin on all tabs.
|
||||||
|
var reformatMu = sync.Mutex{}
|
||||||
|
|
||||||
var App = cview.NewApplication()
|
var App = cview.NewApplication()
|
||||||
|
|
||||||
func Init(version, commit, builtBy string) {
|
func Init(version, commit, builtBy string) {
|
||||||
@ -59,7 +63,7 @@ func Init(version, commit, builtBy string) {
|
|||||||
"# Amfora Version Info\n\nAmfora: %s\nCommit: %s\nBuilt by: %s",
|
"# Amfora Version Info\n\nAmfora: %s\nCommit: %s\nBuilt by: %s",
|
||||||
version, commit, builtBy,
|
version, commit, builtBy,
|
||||||
)
|
)
|
||||||
renderVersionContent, versionLinks := renderer.RenderGemini(versionContent, textWidth(), leftMargin(), false)
|
renderVersionContent, versionLinks := renderer.RenderGemini(versionContent, textWidth(), false)
|
||||||
versionPage = structs.Page{
|
versionPage = structs.Page{
|
||||||
Raw: versionContent,
|
Raw: versionContent,
|
||||||
Content: renderVersionContent,
|
Content: renderVersionContent,
|
||||||
@ -78,10 +82,22 @@ func Init(version, commit, builtBy string) {
|
|||||||
|
|
||||||
// Make sure the current tab content is reformatted when the terminal size changes
|
// Make sure the current tab content is reformatted when the terminal size changes
|
||||||
go func(t *tab) {
|
go func(t *tab) {
|
||||||
|
reformatMu.Lock()
|
||||||
|
// Lock the app to prevent screen updates until this is done, because calling
|
||||||
|
// browser.AddTab updates the display
|
||||||
|
for i := range tabs {
|
||||||
|
// Overwrite tabs with a new, differently sized, left margin
|
||||||
|
browser.AddTab(strconv.Itoa(i), makeTabLabel(strconv.Itoa(i+1)), makeContentLayout(tabs[i].view))
|
||||||
|
if tabs[i] == t {
|
||||||
|
// Reformat page ASAP, in the middle of loop
|
||||||
|
// TODO The per-tab mutext is unecessary if the global one is used
|
||||||
t.reformatMu.Lock() // Only one reformat job per tab
|
t.reformatMu.Lock() // Only one reformat job per tab
|
||||||
defer t.reformatMu.Unlock()
|
|
||||||
// Use the current tab, but don't affect other tabs if the user switches tabs
|
|
||||||
reformatPageAndSetView(t, t.page)
|
reformatPageAndSetView(t, t.page)
|
||||||
|
t.reformatMu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
App.Draw()
|
||||||
|
reformatMu.Unlock()
|
||||||
}(tabs[curTab])
|
}(tabs[curTab])
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -240,7 +256,7 @@ func Init(version, commit, builtBy string) {
|
|||||||
// Render the default new tab content ONCE and store it for later
|
// Render the default new tab content ONCE and store it for later
|
||||||
// This code is repeated in Reload()
|
// This code is repeated in Reload()
|
||||||
newTabContent := getNewTabContent()
|
newTabContent := getNewTabContent()
|
||||||
renderedNewTabContent, newTabLinks := renderer.RenderGemini(newTabContent, textWidth(), leftMargin(), false)
|
renderedNewTabContent, newTabLinks := renderer.RenderGemini(newTabContent, textWidth(), false)
|
||||||
newTabPage = structs.Page{
|
newTabPage = structs.Page{
|
||||||
Raw: newTabContent,
|
Raw: newTabContent,
|
||||||
Content: renderedNewTabContent,
|
Content: renderedNewTabContent,
|
||||||
@ -436,7 +452,7 @@ func NewTab() {
|
|||||||
tabs[curTab].addToHistory("about:newtab")
|
tabs[curTab].addToHistory("about:newtab")
|
||||||
tabs[curTab].history.pos = 0 // Manually set as first page
|
tabs[curTab].history.pos = 0 // Manually set as first page
|
||||||
|
|
||||||
browser.AddTab(strconv.Itoa(curTab), makeTabLabel(strconv.Itoa(curTab+1)), tabs[curTab].view)
|
browser.AddTab(strconv.Itoa(curTab), makeTabLabel(strconv.Itoa(curTab+1)), makeContentLayout(tabs[curTab].view))
|
||||||
browser.SetCurrentTab(strconv.Itoa(curTab))
|
browser.SetCurrentTab(strconv.Itoa(curTab))
|
||||||
App.SetFocus(tabs[curTab].view)
|
App.SetFocus(tabs[curTab].view)
|
||||||
|
|
||||||
@ -520,7 +536,7 @@ func Reload() {
|
|||||||
// Re-render new tab, similar to Init()
|
// Re-render new tab, similar to Init()
|
||||||
newTabContent := getNewTabContent()
|
newTabContent := getNewTabContent()
|
||||||
tmpTermW := termW
|
tmpTermW := termW
|
||||||
renderedNewTabContent, newTabLinks := renderer.RenderGemini(newTabContent, textWidth(), leftMargin(), false)
|
renderedNewTabContent, newTabLinks := renderer.RenderGemini(newTabContent, textWidth(), false)
|
||||||
newTabPage = structs.Page{
|
newTabPage = structs.Page{
|
||||||
Raw: newTabContent,
|
Raw: newTabContent,
|
||||||
Content: renderedNewTabContent,
|
Content: renderedNewTabContent,
|
||||||
|
@ -59,7 +59,7 @@ func handleFile(u string) (*structs.Page, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if mimetype == "text/gemini" {
|
if mimetype == "text/gemini" {
|
||||||
rendered, links := renderer.RenderGemini(string(content), textWidth(), leftMargin(), false)
|
rendered, links := renderer.RenderGemini(string(content), textWidth(), false)
|
||||||
page = &structs.Page{
|
page = &structs.Page{
|
||||||
Mediatype: structs.TextGemini,
|
Mediatype: structs.TextGemini,
|
||||||
URL: u,
|
URL: u,
|
||||||
@ -73,7 +73,7 @@ func handleFile(u string) (*structs.Page, bool) {
|
|||||||
Mediatype: structs.TextPlain,
|
Mediatype: structs.TextPlain,
|
||||||
URL: u,
|
URL: u,
|
||||||
Raw: string(content),
|
Raw: string(content),
|
||||||
Content: renderer.RenderPlainText(string(content), leftMargin()),
|
Content: renderer.RenderPlainText(string(content)),
|
||||||
Links: []string{},
|
Links: []string{},
|
||||||
Width: termW,
|
Width: termW,
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ func createDirectoryListing(u string) (*structs.Page, bool) {
|
|||||||
content += fmt.Sprintf("=> %s%s %s%s\n", f.Name(), separator, f.Name(), separator)
|
content += fmt.Sprintf("=> %s%s %s%s\n", f.Name(), separator, f.Name(), separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
rendered, links := renderer.RenderGemini(content, textWidth(), leftMargin(), false)
|
rendered, links := renderer.RenderGemini(content, textWidth(), false)
|
||||||
page = &structs.Page{
|
page = &structs.Page{
|
||||||
Mediatype: structs.TextGemini,
|
Mediatype: structs.TextGemini,
|
||||||
URL: u,
|
URL: u,
|
||||||
|
@ -373,7 +373,7 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
|
|||||||
res.Body = rr.NewRestartReader(res.Body)
|
res.Body = rr.NewRestartReader(res.Body)
|
||||||
|
|
||||||
if renderer.CanDisplay(res) {
|
if renderer.CanDisplay(res) {
|
||||||
page, err := renderer.MakePage(u, res, textWidth(), leftMargin(), usingProxy)
|
page, err := renderer.MakePage(u, res, textWidth(), usingProxy)
|
||||||
// Rendering may have taken a while, make sure tab is still valid
|
// Rendering may have taken a while, make sure tab is still valid
|
||||||
if !isValidTab(t) {
|
if !isValidTab(t) {
|
||||||
return ret("", false)
|
return ret("", false)
|
||||||
|
@ -65,11 +65,11 @@ func reformatPage(p *structs.Page) {
|
|||||||
strings.HasPrefix(p.URL, "file") {
|
strings.HasPrefix(p.URL, "file") {
|
||||||
proxied = false
|
proxied = false
|
||||||
}
|
}
|
||||||
rendered, _ = renderer.RenderGemini(p.Raw, textWidth(), leftMargin(), proxied)
|
rendered, _ = renderer.RenderGemini(p.Raw, textWidth(), proxied)
|
||||||
case structs.TextPlain:
|
case structs.TextPlain:
|
||||||
rendered = renderer.RenderPlainText(p.Raw, leftMargin())
|
rendered = renderer.RenderPlainText(p.Raw)
|
||||||
case structs.TextAnsi:
|
case structs.TextAnsi:
|
||||||
rendered = renderer.RenderANSI(p.Raw, leftMargin())
|
rendered = renderer.RenderANSI(p.Raw)
|
||||||
default:
|
default:
|
||||||
// Rendering this type is not implemented
|
// Rendering this type is not implemented
|
||||||
return
|
return
|
||||||
@ -89,6 +89,8 @@ func reformatPageAndSetView(t *tab, p *structs.Page) {
|
|||||||
reformatPage(p)
|
reformatPage(p)
|
||||||
t.view.SetText(p.Content)
|
t.view.SetText(p.Content)
|
||||||
t.applyScroll() // Go back to where you were, roughly
|
t.applyScroll() // Go back to where you were, roughly
|
||||||
|
|
||||||
|
App.Draw()
|
||||||
}
|
}
|
||||||
|
|
||||||
// setPage displays a Page on the passed tab number.
|
// setPage displays a Page on the passed tab number.
|
||||||
|
@ -149,7 +149,7 @@ func Subscriptions(t *tab, u string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
content, links := renderer.RenderGemini(rawPage, textWidth(), leftMargin(), false)
|
content, links := renderer.RenderGemini(rawPage, textWidth(), false)
|
||||||
page := structs.Page{
|
page := structs.Page{
|
||||||
Raw: rawPage,
|
Raw: rawPage,
|
||||||
Content: content,
|
Content: content,
|
||||||
@ -191,7 +191,7 @@ func ManageSubscriptions(t *tab, u string) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
content, links := renderer.RenderGemini(rawPage, textWidth(), leftMargin(), false)
|
content, links := renderer.RenderGemini(rawPage, textWidth(), false)
|
||||||
page := structs.Page{
|
page := structs.Page{
|
||||||
Raw: rawPage,
|
Raw: rawPage,
|
||||||
Content: content,
|
Content: content,
|
||||||
|
@ -13,6 +13,17 @@ import (
|
|||||||
|
|
||||||
// This file contains funcs that are small, self-contained utilities.
|
// This file contains funcs that are small, self-contained utilities.
|
||||||
|
|
||||||
|
// makeContentLayout returns a flex that contains the given TextView
|
||||||
|
// along with the current correct left margin.
|
||||||
|
func makeContentLayout(tv *cview.TextView) *cview.Flex {
|
||||||
|
// Create horizontal flex with the left margin as an empty space
|
||||||
|
flex := cview.NewFlex()
|
||||||
|
flex.SetDirection(cview.FlexColumn)
|
||||||
|
flex.AddItem(nil, leftMargin(), 0, false)
|
||||||
|
flex.AddItem(tv, 0, 1, true)
|
||||||
|
return flex
|
||||||
|
}
|
||||||
|
|
||||||
// makeTabLabel takes a string and adds spacing to it, making it
|
// makeTabLabel takes a string and adds spacing to it, making it
|
||||||
// suitable for display as a tab label.
|
// suitable for display as a tab label.
|
||||||
func makeTabLabel(s string) string {
|
func makeTabLabel(s string) string {
|
||||||
|
@ -58,7 +58,7 @@ func CanDisplay(res *gemini.Response) bool {
|
|||||||
|
|
||||||
// MakePage creates a formatted, rendered Page from the given network response and params.
|
// MakePage creates a formatted, rendered Page from the given network response and params.
|
||||||
// You must set the Page.Width value yourself.
|
// You must set the Page.Width value yourself.
|
||||||
func MakePage(url string, res *gemini.Response, width, leftMargin int, proxied bool) (*structs.Page, error) {
|
func MakePage(url string, res *gemini.Response, width int, proxied bool) (*structs.Page, error) {
|
||||||
if !CanDisplay(res) {
|
if !CanDisplay(res) {
|
||||||
return nil, ErrCantDisplay
|
return nil, ErrCantDisplay
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ func MakePage(url string, res *gemini.Response, width, leftMargin int, proxied b
|
|||||||
}
|
}
|
||||||
|
|
||||||
if mediatype == "text/gemini" {
|
if mediatype == "text/gemini" {
|
||||||
rendered, links := RenderGemini(utfText, width, leftMargin, proxied)
|
rendered, links := RenderGemini(utfText, width, proxied)
|
||||||
return &structs.Page{
|
return &structs.Page{
|
||||||
Mediatype: structs.TextGemini,
|
Mediatype: structs.TextGemini,
|
||||||
RawMediatype: mediatype,
|
RawMediatype: mediatype,
|
||||||
@ -119,7 +119,7 @@ func MakePage(url string, res *gemini.Response, width, leftMargin int, proxied b
|
|||||||
RawMediatype: mediatype,
|
RawMediatype: mediatype,
|
||||||
URL: url,
|
URL: url,
|
||||||
Raw: utfText,
|
Raw: utfText,
|
||||||
Content: RenderANSI(utfText, leftMargin),
|
Content: RenderANSI(utfText),
|
||||||
Links: []string{},
|
Links: []string{},
|
||||||
MadeAt: time.Now(),
|
MadeAt: time.Now(),
|
||||||
}, nil
|
}, nil
|
||||||
@ -131,7 +131,7 @@ func MakePage(url string, res *gemini.Response, width, leftMargin int, proxied b
|
|||||||
RawMediatype: mediatype,
|
RawMediatype: mediatype,
|
||||||
URL: url,
|
URL: url,
|
||||||
Raw: utfText,
|
Raw: utfText,
|
||||||
Content: RenderPlainText(utfText, leftMargin),
|
Content: RenderPlainText(utfText),
|
||||||
Links: []string{},
|
Links: []string{},
|
||||||
MadeAt: time.Now(),
|
MadeAt: time.Now(),
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -21,7 +21,7 @@ var ansiRegex = regexp.MustCompile(`\x1b\[[0-9;]*m`)
|
|||||||
|
|
||||||
// RenderANSI renders plain text pages containing ANSI codes.
|
// RenderANSI renders plain text pages containing ANSI codes.
|
||||||
// Practically, it is used for the text/x-ansi.
|
// Practically, it is used for the text/x-ansi.
|
||||||
func RenderANSI(s string, leftMargin int) string {
|
func RenderANSI(s string) string {
|
||||||
s = cview.Escape(s)
|
s = cview.Escape(s)
|
||||||
if viper.GetBool("a-general.color") && viper.GetBool("a-general.ansi") {
|
if viper.GetBool("a-general.color") && viper.GetBool("a-general.ansi") {
|
||||||
s = cview.TranslateANSI(s)
|
s = cview.TranslateANSI(s)
|
||||||
@ -33,24 +33,15 @@ func RenderANSI(s string, leftMargin int) string {
|
|||||||
} else {
|
} else {
|
||||||
s = ansiRegex.ReplaceAllString(s, "")
|
s = ansiRegex.ReplaceAllString(s, "")
|
||||||
}
|
}
|
||||||
var shifted string
|
return s
|
||||||
lines := strings.Split(s, "\n")
|
|
||||||
for i := range lines {
|
|
||||||
shifted += fmt.Sprintf("[-:%s]", config.GetColorString("bg")) + strings.Repeat(" ", leftMargin) + lines[i] + "\n"
|
|
||||||
}
|
|
||||||
return shifted
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderPlainText should be used to format plain text pages.
|
// RenderPlainText should be used to format plain text pages.
|
||||||
func RenderPlainText(s string, leftMargin int) string {
|
func RenderPlainText(s string) string {
|
||||||
var shifted string
|
// It used to add a left margin, now this is done elsewhere.
|
||||||
lines := strings.Split(cview.Escape(s), "\n")
|
// The function is kept for convenience and in case rendering
|
||||||
for i := range lines {
|
// is needed in the future.
|
||||||
shifted += strings.Repeat(" ", leftMargin) +
|
return s
|
||||||
"[" + config.GetColorString("regular_text") + "]" + lines[i] + "[-]" +
|
|
||||||
"\n"
|
|
||||||
}
|
|
||||||
return shifted
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrapLine wraps a line to the provided width, and adds the provided prefix and suffix to each wrapped line.
|
// wrapLine wraps a line to the provided width, and adds the provided prefix and suffix to each wrapped line.
|
||||||
@ -283,7 +274,7 @@ func convertRegularGemini(s string, numLinks, width int, proxied bool) (string,
|
|||||||
//
|
//
|
||||||
// proxied is whether the request is through the gemini:// scheme.
|
// proxied is whether the request is through the gemini:// scheme.
|
||||||
// If it's not a gemini:// page, set this to true.
|
// If it's not a gemini:// page, set this to true.
|
||||||
func RenderGemini(s string, width, leftMargin int, proxied bool) (string, []string) {
|
func RenderGemini(s string, width int, proxied bool) (string, []string) {
|
||||||
s = cview.Escape(s)
|
s = cview.Escape(s)
|
||||||
|
|
||||||
lines := strings.Split(s, "\n")
|
lines := strings.Split(s, "\n")
|
||||||
@ -357,13 +348,5 @@ func RenderGemini(s string, width, leftMargin int, proxied bool) (string, []stri
|
|||||||
processRegular()
|
processRegular()
|
||||||
}
|
}
|
||||||
|
|
||||||
if leftMargin > 0 {
|
|
||||||
renLines := strings.Split(rendered, "\n")
|
|
||||||
for i := range renLines {
|
|
||||||
renLines[i] = strings.Repeat(" ", leftMargin) + renLines[i]
|
|
||||||
}
|
|
||||||
return strings.Join(renLines, "\n"), links
|
|
||||||
}
|
|
||||||
|
|
||||||
return rendered, links
|
return rendered, links
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user