diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d558b1..51d529c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Wrapped list items are indented to stay behind the bullet (#35) - Certificate expiry date is stored when the cert IDs match (#39) - What link was selected is remembered as you browse through history +- Render ANSI codes in `text/x-ansi` pages, or text pages that end with `.ans` ### Changed - Pages are rewrapped dynamically, whenever the terminal size changes (#33) diff --git a/display/private.go b/display/private.go index 7fcb934..0359386 100644 --- a/display/private.go +++ b/display/private.go @@ -127,6 +127,8 @@ func reformatPage(p *structs.Page) { rendered, _ = renderer.RenderGemini(p.Raw, textWidth(), leftMargin()) } else if p.Mediatype == structs.TextPlain { rendered = renderer.RenderPlainText(p.Raw, leftMargin()) + } else if p.Mediatype == structs.TextAnsi { + rendered = renderer.RenderANSI(p.Raw, leftMargin()) } else { // Rendering this type is not implemented return diff --git a/renderer/page.go b/renderer/page.go index a528562..ea5ee74 100644 --- a/renderer/page.go +++ b/renderer/page.go @@ -109,14 +109,25 @@ func MakePage(url string, res *gemini.Response, width, leftMargin int) (*structs Links: links, }, nil } else if strings.HasPrefix(mediatype, "text/") { - // Treated as plaintext - return &structs.Page{ - Mediatype: structs.TextPlain, - Url: url, - Raw: utfText, - Content: RenderPlainText(utfText, leftMargin), - Links: []string{}, - }, nil + if mediatype == "text/x-ansi" || strings.HasSuffix(url, ".ans") { + // ANSI + return &structs.Page{ + Mediatype: structs.TextAnsi, + Url: url, + Raw: utfText, + Content: RenderANSI(utfText, leftMargin), + Links: []string{}, + }, nil + } else { + // Treated as plaintext + return &structs.Page{ + Mediatype: structs.TextPlain, + Url: url, + Raw: utfText, + Content: RenderPlainText(utfText, leftMargin), + Links: []string{}, + }, nil + } } return nil, errors.New("displayable mediatype is not handled in the code, implementation error") diff --git a/renderer/renderer.go b/renderer/renderer.go index 04a6c30..8e12918 100644 --- a/renderer/renderer.go +++ b/renderer/renderer.go @@ -13,6 +13,21 @@ import ( "gitlab.com/tslocum/cview" ) +// RenderANSI renders plain text pages containing ANSI codes. +// Practically, it is used for the text/x-ansi. +func RenderANSI(s string, leftMargin int) string { + s = cview.Escape(s) + if viper.GetBool("a-general.color") { + s = cview.TranslateANSI(s) + } + var shifted string + lines := strings.Split(s, "\n") + for i := range lines { + shifted += strings.Repeat(" ", leftMargin) + lines[i] + "\n" + } + return shifted +} + // RenderPlainText should be used to format plain text pages. func RenderPlainText(s string, leftMargin int) string { var shifted string diff --git a/structs/structs.go b/structs/structs.go index 426081b..dcd629b 100644 --- a/structs/structs.go +++ b/structs/structs.go @@ -5,6 +5,7 @@ type Mediatype string const ( TextGemini Mediatype = "text/gemini" TextPlain Mediatype = "text/plain" + TextAnsi Mediatype = "text/x-ansi" ) type PageMode int