mirror of
https://github.com/makew0rld/amfora.git
synced 2024-12-04 14:46:29 -05:00
🚧 Initial work
This commit is contained in:
parent
4514f8b8c0
commit
8e7300726d
@ -34,13 +34,14 @@ func aboutInit(version, commit, builtBy string) {
|
||||
}
|
||||
|
||||
func createAboutPage(url string, content string) structs.Page {
|
||||
renderContent, links := renderer.RenderGemini(content, textWidth(), false)
|
||||
renderContent, links, maxPreCols := renderer.RenderGemini(content, textWidth(), false)
|
||||
return structs.Page{
|
||||
Raw: content,
|
||||
Content: renderContent,
|
||||
Links: links,
|
||||
URL: url,
|
||||
Width: -1, // Force reformatting on first display
|
||||
Mediatype: structs.TextGemini,
|
||||
Raw: content,
|
||||
Content: renderContent,
|
||||
MaxPreCols: maxPreCols,
|
||||
Links: links,
|
||||
URL: url,
|
||||
TermWidth: -1, // Force reformatting on first display
|
||||
Mediatype: structs.TextGemini,
|
||||
}
|
||||
}
|
||||
|
@ -132,14 +132,15 @@ 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(), false)
|
||||
content, links, maxPreCols := renderer.RenderGemini(bkmkPageRaw, textWidth(), false)
|
||||
page := structs.Page{
|
||||
Raw: bkmkPageRaw,
|
||||
Content: content,
|
||||
Links: links,
|
||||
URL: "about:bookmarks",
|
||||
Width: termW,
|
||||
Mediatype: structs.TextGemini,
|
||||
Raw: bkmkPageRaw,
|
||||
Content: content,
|
||||
MaxPreCols: maxPreCols,
|
||||
Links: links,
|
||||
URL: "about:bookmarks",
|
||||
TermWidth: termW,
|
||||
Mediatype: structs.TextGemini,
|
||||
}
|
||||
setPage(t, &page)
|
||||
t.applyBottomBar()
|
||||
|
@ -72,7 +72,11 @@ func Init(version, commit, builtBy string) {
|
||||
reformatMu.Lock() // Only allow one reformat job at a time
|
||||
for i := range tabs {
|
||||
// Overwrite all tabs with a new, differently sized, left margin
|
||||
browser.AddTab(strconv.Itoa(i), makeTabLabel(strconv.Itoa(i+1)), makeContentLayout(tabs[i].view))
|
||||
browser.AddTab(
|
||||
strconv.Itoa(i),
|
||||
makeTabLabel(strconv.Itoa(i+1)),
|
||||
makeContentLayout(tabs[i].view, leftMargin()),
|
||||
)
|
||||
if tabs[i] == t {
|
||||
// Reformat page ASAP, in the middle of loop
|
||||
reformatPageAndSetView(t, t.page)
|
||||
@ -129,8 +133,6 @@ func Init(version, commit, builtBy string) {
|
||||
bottomBar.SetDoneFunc(func(key tcell.Key) {
|
||||
tab := curTab
|
||||
|
||||
tabs[tab].saveScroll()
|
||||
|
||||
// Reset func to set the bottomBar back to what it was before
|
||||
// Use for errors.
|
||||
reset := func() {
|
||||
@ -247,14 +249,15 @@ func Init(version, commit, builtBy string) {
|
||||
// Render the default new tab content ONCE and store it for later
|
||||
// This code is repeated in Reload()
|
||||
newTabContent := getNewTabContent()
|
||||
renderedNewTabContent, newTabLinks := renderer.RenderGemini(newTabContent, textWidth(), false)
|
||||
renderedNewTabContent, newTabLinks, maxPreCols := renderer.RenderGemini(newTabContent, textWidth(), false)
|
||||
newTabPage = structs.Page{
|
||||
Raw: newTabContent,
|
||||
Content: renderedNewTabContent,
|
||||
Links: newTabLinks,
|
||||
URL: "about:newtab",
|
||||
Width: -1, // Force reformatting on first display
|
||||
Mediatype: structs.TextGemini,
|
||||
Raw: newTabContent,
|
||||
Content: renderedNewTabContent,
|
||||
MaxPreCols: maxPreCols,
|
||||
Links: newTabLinks,
|
||||
URL: "about:newtab",
|
||||
TermWidth: -1, // Force reformatting on first display
|
||||
Mediatype: structs.TextGemini,
|
||||
}
|
||||
|
||||
modalInit()
|
||||
@ -432,7 +435,6 @@ func NewTab() {
|
||||
tabs[curTab].view.Highlight("")
|
||||
// Save bottomBar state
|
||||
tabs[curTab].saveBottomBar()
|
||||
tabs[curTab].saveScroll()
|
||||
}
|
||||
|
||||
curTab = NumTabs()
|
||||
@ -443,7 +445,11 @@ func NewTab() {
|
||||
tabs[curTab].addToHistory("about:newtab")
|
||||
tabs[curTab].history.pos = 0 // Manually set as first page
|
||||
|
||||
browser.AddTab(strconv.Itoa(curTab), makeTabLabel(strconv.Itoa(curTab+1)), makeContentLayout(tabs[curTab].view))
|
||||
browser.AddTab(
|
||||
strconv.Itoa(curTab),
|
||||
makeTabLabel(strconv.Itoa(curTab+1)),
|
||||
makeContentLayout(tabs[curTab].view, leftMargin()),
|
||||
)
|
||||
browser.SetCurrentTab(strconv.Itoa(curTab))
|
||||
App.SetFocus(tabs[curTab].view)
|
||||
|
||||
@ -506,7 +512,6 @@ func SwitchTab(tab int) {
|
||||
if curTab > -1 {
|
||||
// Save bottomBar state
|
||||
tabs[curTab].saveBottomBar()
|
||||
tabs[curTab].saveScroll()
|
||||
}
|
||||
|
||||
curTab = tab % NumTabs()
|
||||
@ -527,14 +532,15 @@ func Reload() {
|
||||
// Re-render new tab, similar to Init()
|
||||
newTabContent := getNewTabContent()
|
||||
tmpTermW := termW
|
||||
renderedNewTabContent, newTabLinks := renderer.RenderGemini(newTabContent, textWidth(), false)
|
||||
renderedNewTabContent, newTabLinks, maxPreCols := renderer.RenderGemini(newTabContent, textWidth(), false)
|
||||
newTabPage = structs.Page{
|
||||
Raw: newTabContent,
|
||||
Content: renderedNewTabContent,
|
||||
Links: newTabLinks,
|
||||
URL: "about:newtab",
|
||||
Width: tmpTermW,
|
||||
Mediatype: structs.TextGemini,
|
||||
Raw: newTabContent,
|
||||
Content: renderedNewTabContent,
|
||||
MaxPreCols: maxPreCols,
|
||||
Links: newTabLinks,
|
||||
URL: "about:newtab",
|
||||
TermWidth: tmpTermW,
|
||||
Mediatype: structs.TextGemini,
|
||||
}
|
||||
temp := newTabPage // Copy
|
||||
setPage(tabs[curTab], &temp)
|
||||
|
@ -59,23 +59,25 @@ func handleFile(u string) (*structs.Page, bool) {
|
||||
}
|
||||
|
||||
if mimetype == "text/gemini" {
|
||||
rendered, links := renderer.RenderGemini(string(content), textWidth(), false)
|
||||
rendered, links, maxPreCols := renderer.RenderGemini(string(content), textWidth(), false)
|
||||
page = &structs.Page{
|
||||
Mediatype: structs.TextGemini,
|
||||
URL: u,
|
||||
Raw: string(content),
|
||||
Content: rendered,
|
||||
Links: links,
|
||||
Width: termW,
|
||||
Mediatype: structs.TextGemini,
|
||||
URL: u,
|
||||
Raw: string(content),
|
||||
Content: rendered,
|
||||
MaxPreCols: maxPreCols,
|
||||
Links: links,
|
||||
TermWidth: termW,
|
||||
}
|
||||
} else {
|
||||
page = &structs.Page{
|
||||
Mediatype: structs.TextPlain,
|
||||
URL: u,
|
||||
Raw: string(content),
|
||||
Content: renderer.RenderPlainText(string(content)),
|
||||
Links: []string{},
|
||||
Width: termW,
|
||||
Mediatype: structs.TextPlain,
|
||||
URL: u,
|
||||
Raw: string(content),
|
||||
Content: renderer.RenderPlainText(string(content)),
|
||||
MaxPreCols: -1,
|
||||
Links: []string{},
|
||||
TermWidth: termW,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -107,14 +109,15 @@ func createDirectoryListing(u string) (*structs.Page, bool) {
|
||||
content += fmt.Sprintf("=> %s%s %s%s\n", f.Name(), separator, f.Name(), separator)
|
||||
}
|
||||
|
||||
rendered, links := renderer.RenderGemini(content, textWidth(), false)
|
||||
rendered, links, maxPreCols := renderer.RenderGemini(content, textWidth(), false)
|
||||
page = &structs.Page{
|
||||
Mediatype: structs.TextGemini,
|
||||
URL: u,
|
||||
Raw: content,
|
||||
Content: rendered,
|
||||
Links: links,
|
||||
Width: termW,
|
||||
Mediatype: structs.TextGemini,
|
||||
URL: u,
|
||||
Raw: content,
|
||||
Content: rendered,
|
||||
MaxPreCols: maxPreCols,
|
||||
Links: links,
|
||||
TermWidth: termW,
|
||||
}
|
||||
return page, true
|
||||
}
|
||||
|
@ -337,7 +337,7 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) {
|
||||
return ret("", false)
|
||||
}
|
||||
|
||||
page.Width = termW
|
||||
page.TermWidth = termW
|
||||
|
||||
if !client.HasClientCert(parsed.Host) {
|
||||
// Don't cache pages with client certs
|
||||
|
@ -24,7 +24,6 @@ func followLink(t *tab, prev, next string) {
|
||||
}
|
||||
|
||||
if t.hasContent() {
|
||||
t.saveScroll() // Likely called later on, it's here just in case
|
||||
nextURL, err := resolveRelLink(t, prev, next)
|
||||
if err != nil {
|
||||
Error("URL Error", err.Error())
|
||||
@ -48,7 +47,7 @@ func followLink(t *tab, prev, next string) {
|
||||
// It will not waste resources if the passed page is already fitted to the current terminal width, and can be
|
||||
// called safely even when the page might be already formatted properly.
|
||||
func reformatPage(p *structs.Page) {
|
||||
if p.Width == termW {
|
||||
if p.TermWidth == termW {
|
||||
// No changes to make
|
||||
return
|
||||
}
|
||||
@ -65,7 +64,7 @@ func reformatPage(p *structs.Page) {
|
||||
strings.HasPrefix(p.URL, "file") {
|
||||
proxied = false
|
||||
}
|
||||
rendered, _ = renderer.RenderGemini(p.Raw, textWidth(), proxied)
|
||||
rendered, _, _ = renderer.RenderGemini(p.Raw, textWidth(), proxied)
|
||||
case structs.TextPlain:
|
||||
rendered = renderer.RenderPlainText(p.Raw)
|
||||
case structs.TextAnsi:
|
||||
@ -75,17 +74,16 @@ func reformatPage(p *structs.Page) {
|
||||
return
|
||||
}
|
||||
p.Content = rendered
|
||||
p.Width = termW
|
||||
p.TermWidth = termW
|
||||
}
|
||||
|
||||
// reformatPageAndSetView is for reformatting a page that is already being displayed.
|
||||
// setPage should be used when a page is being loaded for the first time.
|
||||
func reformatPageAndSetView(t *tab, p *structs.Page) {
|
||||
if p.Width == termW {
|
||||
if p.TermWidth == termW {
|
||||
// No changes to make
|
||||
return
|
||||
}
|
||||
t.saveScroll()
|
||||
reformatPage(p)
|
||||
t.view.SetText(p.Content)
|
||||
t.applyScroll() // Go back to where you were, roughly
|
||||
@ -101,8 +99,6 @@ func setPage(t *tab, p *structs.Page) {
|
||||
return
|
||||
}
|
||||
|
||||
t.saveScroll() // Save the scroll of the previous page
|
||||
|
||||
// Make sure the page content is fitted to the terminal every time it's displayed
|
||||
reformatPage(p)
|
||||
|
||||
@ -112,10 +108,13 @@ func setPage(t *tab, p *structs.Page) {
|
||||
t.view.SetText(p.Content)
|
||||
t.view.Highlight("") // Turn off highlights, other funcs may restore if necessary
|
||||
t.view.ScrollToBeginning()
|
||||
|
||||
// Set tab number in case a favicon from before overwrote it
|
||||
// Reset page left margin
|
||||
tabNum := tabNumber(t)
|
||||
browser.SetTabLabel(strconv.Itoa(tabNum), makeTabLabel(strconv.Itoa(tabNum+1)))
|
||||
browser.AddTab(
|
||||
strconv.Itoa(tabNum),
|
||||
makeTabLabel(strconv.Itoa(tabNum+1)),
|
||||
makeContentLayout(t.view, leftMargin()),
|
||||
)
|
||||
App.Draw()
|
||||
|
||||
// Setup display
|
||||
|
@ -149,14 +149,15 @@ func Subscriptions(t *tab, u string) string {
|
||||
}
|
||||
}
|
||||
|
||||
content, links := renderer.RenderGemini(rawPage, textWidth(), false)
|
||||
content, links, maxPreCols := renderer.RenderGemini(rawPage, textWidth(), false)
|
||||
page := structs.Page{
|
||||
Raw: rawPage,
|
||||
Content: content,
|
||||
Links: links,
|
||||
URL: u,
|
||||
Width: termW,
|
||||
Mediatype: structs.TextGemini,
|
||||
Raw: rawPage,
|
||||
Content: content,
|
||||
MaxPreCols: maxPreCols,
|
||||
Links: links,
|
||||
URL: u,
|
||||
TermWidth: termW,
|
||||
Mediatype: structs.TextGemini,
|
||||
}
|
||||
go cache.AddPage(&page)
|
||||
setPage(t, &page)
|
||||
@ -191,14 +192,15 @@ func ManageSubscriptions(t *tab, u string) {
|
||||
)
|
||||
}
|
||||
|
||||
content, links := renderer.RenderGemini(rawPage, textWidth(), false)
|
||||
content, links, maxPreCols := renderer.RenderGemini(rawPage, textWidth(), false)
|
||||
page := structs.Page{
|
||||
Raw: rawPage,
|
||||
Content: content,
|
||||
Links: links,
|
||||
URL: "about:manage-subscriptions",
|
||||
Width: termW,
|
||||
Mediatype: structs.TextGemini,
|
||||
Raw: rawPage,
|
||||
Content: content,
|
||||
MaxPreCols: maxPreCols,
|
||||
Links: links,
|
||||
URL: "about:manage-subscriptions",
|
||||
TermWidth: termW,
|
||||
Mediatype: structs.TextGemini,
|
||||
}
|
||||
go cache.AddPage(&page)
|
||||
setPage(t, &page)
|
||||
|
@ -121,6 +121,58 @@ func makeNewTab() *tab {
|
||||
tabs[tab].page.SelectedID = strconv.Itoa(index)
|
||||
}
|
||||
})
|
||||
t.view.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||
// Capture left/right scrolling and change the left margin size accordingly
|
||||
// See #197
|
||||
// Up/down scrolling is saved in this func to keep them in sync, but the keys
|
||||
// are passed and no extra behaviour happens.
|
||||
|
||||
key := event.Key()
|
||||
mod := event.Modifiers()
|
||||
ru := event.Rune()
|
||||
|
||||
oldCol := t.page.Column
|
||||
|
||||
if (key == tcell.KeyRight && mod == tcell.ModNone) ||
|
||||
(key == tcell.KeyRune && mod == tcell.ModNone && ru == 'l') {
|
||||
// Scrolling to the right
|
||||
// TODO check if already scrolled to the end
|
||||
t.page.Column++
|
||||
} else if (key == tcell.KeyLeft && mod == tcell.ModNone) ||
|
||||
(key == tcell.KeyRune && mod == tcell.ModNone && ru == 'h') {
|
||||
// Scrolling to the left
|
||||
if t.page.Column == 0 {
|
||||
// Can't scroll to the left anymore
|
||||
return nil
|
||||
}
|
||||
t.page.Column--
|
||||
} else if (key == tcell.KeyUp && mod == tcell.ModNone) ||
|
||||
(key == tcell.KeyRune && mod == tcell.ModNone && ru == 'k') {
|
||||
// Scrolling up
|
||||
if t.page.Row > 0 {
|
||||
t.page.Row--
|
||||
}
|
||||
return event
|
||||
} else if (key == tcell.KeyDown && mod == tcell.ModNone) ||
|
||||
(key == tcell.KeyRune && mod == tcell.ModNone && ru == 'j') {
|
||||
// Scrolling down
|
||||
// TODO need to check for max vertical scroll before doing this
|
||||
return event
|
||||
} else {
|
||||
// Some other key, stop processing it
|
||||
return event
|
||||
}
|
||||
|
||||
if t.page.MaxPreCols <= termW && t.page.MaxPreCols > -1 {
|
||||
// No scrolling is actually necessary
|
||||
t.page.Column = oldCol // Reset
|
||||
return nil // Ignore keys
|
||||
}
|
||||
|
||||
t.applyHorizontalScroll()
|
||||
App.Draw()
|
||||
return nil
|
||||
})
|
||||
|
||||
return &t
|
||||
}
|
||||
@ -167,19 +219,39 @@ func (t *tab) hasContent() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// saveScroll saves where in the page the user was.
|
||||
// It should be used whenever moving from one page to another.
|
||||
func (t *tab) saveScroll() {
|
||||
// It will also be saved in the cache because the cache uses the same pointer
|
||||
row, col := t.view.GetScrollOffset()
|
||||
t.page.Row = row
|
||||
t.page.Column = col
|
||||
// applyHorizontalScroll handles horizontal scroll logic including left margin resizing,
|
||||
// see #197 for details. Use applyScroll instead.
|
||||
//
|
||||
// In certain cases it will still use and apply the saved Row.
|
||||
func (t *tab) applyHorizontalScroll() {
|
||||
i := tabNumber(t)
|
||||
if i == -1 {
|
||||
// Tab is not actually being used and should not be (re)added to the browser
|
||||
return
|
||||
}
|
||||
if t.page.Column >= leftMargin() {
|
||||
// Scrolled to the right far enough that no left margin is needed
|
||||
browser.AddTab(
|
||||
strconv.Itoa(i),
|
||||
makeTabLabel(strconv.Itoa(i+1)),
|
||||
makeContentLayout(t.view, 0),
|
||||
)
|
||||
t.view.ScrollTo(t.page.Row, t.page.Column-leftMargin())
|
||||
} else {
|
||||
// Left margin is still needed, but is not necessarily at the right size by default
|
||||
browser.AddTab(
|
||||
strconv.Itoa(i),
|
||||
makeTabLabel(strconv.Itoa(i+1)),
|
||||
makeContentLayout(t.view, leftMargin()-t.page.Column),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// applyScroll applies the saved scroll values to the page and tab.
|
||||
// It should only be used when going backward and forward.
|
||||
func (t *tab) applyScroll() {
|
||||
t.view.ScrollTo(t.page.Row, t.page.Column)
|
||||
t.view.ScrollTo(t.page.Row, 0)
|
||||
t.applyHorizontalScroll()
|
||||
}
|
||||
|
||||
// saveBottomBar saves the current bottomBar values in the tab.
|
||||
|
@ -14,13 +14,15 @@ import (
|
||||
// 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, as well as a single empty
|
||||
// along with the provided left margin, as well as a single empty
|
||||
// line at the top, for a top margin.
|
||||
func makeContentLayout(tv *cview.TextView) *cview.Flex {
|
||||
func makeContentLayout(tv *cview.TextView, leftMargin int) *cview.Flex {
|
||||
// Create horizontal flex with the left margin as an empty space
|
||||
horiz := cview.NewFlex()
|
||||
horiz.SetDirection(cview.FlexColumn)
|
||||
horiz.AddItem(nil, leftMargin(), 0, false)
|
||||
if leftMargin > 0 {
|
||||
horiz.AddItem(nil, leftMargin, 0, false)
|
||||
}
|
||||
horiz.AddItem(tv, 0, 1, true)
|
||||
|
||||
// Create a vertical flex with the other one and a top margin
|
||||
|
1
go.mod
1
go.mod
@ -8,6 +8,7 @@ require (
|
||||
github.com/gdamore/tcell/v2 v2.1.1-0.20210125004847-19e17097d8fe
|
||||
github.com/google/go-cmp v0.5.0 // indirect
|
||||
github.com/makeworld-the-better-one/go-gemini v0.11.0
|
||||
github.com/mattn/go-runewidth v0.0.10
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/mapstructure v1.3.1 // indirect
|
||||
github.com/mmcdole/gofeed v1.1.0
|
||||
|
@ -118,13 +118,14 @@ func MakePage(url string, res *gemini.Response, width int, proxied bool) (*struc
|
||||
}
|
||||
|
||||
if mediatype == "text/gemini" {
|
||||
rendered, links := RenderGemini(utfText, width, proxied)
|
||||
rendered, links, maxPreCols := RenderGemini(utfText, width, proxied)
|
||||
return &structs.Page{
|
||||
Mediatype: structs.TextGemini,
|
||||
RawMediatype: mediatype,
|
||||
URL: url,
|
||||
Raw: utfText,
|
||||
Content: rendered,
|
||||
MaxPreCols: maxPreCols,
|
||||
Links: links,
|
||||
MadeAt: time.Now(),
|
||||
}, nil
|
||||
@ -137,6 +138,7 @@ func MakePage(url string, res *gemini.Response, width int, proxied bool) (*struc
|
||||
URL: url,
|
||||
Raw: utfText,
|
||||
Content: RenderANSI(utfText),
|
||||
MaxPreCols: -1,
|
||||
Links: []string{},
|
||||
MadeAt: time.Now(),
|
||||
}, nil
|
||||
@ -149,6 +151,7 @@ func MakePage(url string, res *gemini.Response, width int, proxied bool) (*struc
|
||||
URL: url,
|
||||
Raw: utfText,
|
||||
Content: RenderPlainText(utfText),
|
||||
MaxPreCols: -1,
|
||||
Links: []string{},
|
||||
MadeAt: time.Now(),
|
||||
}, nil
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/makeworld-the-better-one/amfora/config"
|
||||
"github.com/mattn/go-runewidth"
|
||||
"github.com/spf13/viper"
|
||||
"gitlab.com/tslocum/cview"
|
||||
)
|
||||
@ -267,19 +268,19 @@ func convertRegularGemini(s string, numLinks, width int, proxied bool) (string,
|
||||
}
|
||||
|
||||
// RenderGemini converts text/gemini into a cview displayable format.
|
||||
// It also returns a slice of link URLs.
|
||||
// It also returns a slice of link URLs, and the Page.MaxPreCols value.
|
||||
//
|
||||
// width is the number of columns to wrap to.
|
||||
// leftMargin is the number of blank spaces to prepend to each line.
|
||||
//
|
||||
// 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 int, proxied bool) (string, []string) {
|
||||
func RenderGemini(s string, width int, proxied bool) (string, []string, int) {
|
||||
s = cview.Escape(s)
|
||||
|
||||
lines := strings.Split(s, "\n")
|
||||
|
||||
links := make([]string, 0)
|
||||
maxPreCols := 0
|
||||
|
||||
// Process and wrap non preformatted lines
|
||||
rendered := "" // Final result
|
||||
@ -288,6 +289,11 @@ func RenderGemini(s string, width int, proxied bool) (string, []string) {
|
||||
|
||||
// processPre is for rendering preformatted blocks
|
||||
processPre := func() {
|
||||
lineWidth := runewidth.StringWidth(buf)
|
||||
if lineWidth > maxPreCols {
|
||||
maxPreCols = lineWidth
|
||||
}
|
||||
|
||||
// Support ANSI color codes in preformatted blocks - see #59
|
||||
if viper.GetBool("a-general.color") && viper.GetBool("a-general.ansi") {
|
||||
buf = cview.TranslateANSI(buf)
|
||||
@ -348,5 +354,5 @@ func RenderGemini(s string, width int, proxied bool) (string, []string) {
|
||||
processRegular()
|
||||
}
|
||||
|
||||
return rendered, links
|
||||
return rendered, links, maxPreCols
|
||||
}
|
||||
|
@ -25,10 +25,11 @@ type Page struct {
|
||||
RawMediatype string // The actual mediatype sent by the server
|
||||
Raw string // The raw response, as received over the network
|
||||
Content string // The processed content, NOT raw. Uses cview color tags. It will also have a left margin.
|
||||
MaxPreCols int // The amount of the terminal columns the longest preformatted line in Raw takes up, used for #197. -1 means infinite length lines, AKA always allow scrolling.
|
||||
Links []string // URLs, for each region in the content.
|
||||
Row int // Scroll position
|
||||
Column int // ditto
|
||||
Width int // The terminal width when the Content was set, to know when reformatting should happen.
|
||||
Row int // Vertical scroll position
|
||||
Column int // Horizontal scroll position - does not map exactly to a cview.TextView because it includes left margin size changes, see #197
|
||||
TermWidth int // The terminal width when the Content was set, to know when reformatting should happen.
|
||||
Selected string // The current text or link selected
|
||||
SelectedID string // The cview region ID for the selected text/link
|
||||
Mode PageMode
|
||||
|
Loading…
Reference in New Issue
Block a user