1
0
mirror of https://github.com/makew0rld/amfora.git synced 2024-12-04 14:46:29 -05:00

ANSI and plain renderers done but untested, gemtext started

This commit is contained in:
makeworld 2021-03-01 19:05:26 -05:00
parent 8f216f569b
commit d2d5846b0e
3 changed files with 163 additions and 2 deletions

71
render/gemtext.go Normal file
View File

@ -0,0 +1,71 @@
package render
import (
"bufio"
"io"
)
// Renderer for gemtext. Other Renderers are in renderer.go.
type GemtextRenderer struct {
r *io.PipeReader
w *io.PipeWriter
// scanner is used to process line by line.
scanner *bufio.Scanner
// scanWriter is used to send data to the scanner, which reads out of the other
// end of the pipe.
scanWriter *io.PipeWriter
// lineEnd holds the rest of line when the Read call cuts off the line being returned.
lineEnd []byte
links chan string
// numLinks is the number of links that exist so far.
numLinks int
// width is the number of columns to wrap to.
width int
// proxied is whether the request is through the gemini:// scheme.
proxied bool
// pre indicates whether the renderer is currently in a preformatted block
// or not.
pre bool
}
// NewGemtextRenderer.
//
// width is the number of columns to wrap to.
//
// proxied is whether the request is through the gemini:// scheme.
// If it's not a gemini:// page, set this to true.
func NewGemtextRenderer(width int, proxied bool) *GemtextRenderer {
pr, pw := io.Pipe()
scanReader, scanWriter := io.Pipe()
scanner := bufio.NewScanner(scanReader)
links := make(chan string, 10)
return &GemtextRenderer{
r: pr,
w: pw,
scanner: scanner,
scanWriter: scanWriter,
lineEnd: make([]byte, 0),
links: links,
numLinks: 0,
width: width,
proxied: proxied,
pre: false,
}
}
func (r *GemtextRenderer) Links() <-chan string {
return r.links
}
func (r *GemtextRenderer) Write(p []byte) (n int, err error) {
// Just write to the scanner, all logic is in Read()
return r.scanWriter.Write(p)
}

View File

@ -41,7 +41,7 @@ func RenderPlainText(s string) string {
// It used to add a left margin, now this is done elsewhere.
// The function is kept for convenience and in case rendering
// is needed in the future.
return s
return cview.Escape(s)
}
// wrapLine wraps a line to the provided width, and adds the provided prefix and suffix to each wrapped line.
@ -270,7 +270,6 @@ func convertRegularGemini(s string, numLinks, width int, proxied bool) (string,
// It also returns a slice of link URLs.
//
// 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.

91
render/renderer.go Normal file
View File

@ -0,0 +1,91 @@
package render
import (
"bytes"
"fmt"
"io"
"github.com/makeworld-the-better-one/amfora/config"
"github.com/spf13/viper"
"gitlab.com/tslocum/cview"
)
// Renderer renderers network bytes into something that can be displayed on a
// cview.TextView.
type Renderer interface {
io.ReadWriter
// Links returns a channel that yields Link URLs as they are parsed.
// It is buffered. The channel might be closed to indicate links are supported
// for this renderer.
Links() <-chan string
}
type PlaintextRenderer struct {
*io.PipeReader
w *io.PipeWriter
}
func NewPlaintextRenderer() *PlaintextRenderer {
pr, pw := io.Pipe()
return &PlaintextRenderer{pr, pw}
}
func (r *PlaintextRenderer) Write(p []byte) (n int, err error) {
// TODO: The escaping will fail if the Write bytes end in the middle of a tag
// How can this be avoided by users of this func?
return r.w.Write(cview.EscapeBytes(p))
}
func (r *PlaintextRenderer) Links() <-chan string {
ch := make(chan string)
close(ch)
return ch
}
type ANSIRenderer struct {
*io.PipeReader
pw *io.PipeWriter
ansiWriter io.Writer // cview.ANSIWriter
buf bytes.Buffer
}
func NewANSIRenderer() *ANSIRenderer {
pr, pw := io.Pipe()
var ansiWriter io.Writer = nil // When ANSI is disabled
var buf bytes.Buffer
if viper.GetBool("a-general.color") && viper.GetBool("a-general.ansi") {
// ANSI enabled
ansiWriter = cview.ANSIWriter(&buf)
}
return &ANSIRenderer{pr, pw, ansiWriter, buf}
}
func (r *ANSIRenderer) Write(p []byte) (n int, err error) {
if r.ansiWriter == nil {
// ANSI disabled
return r.pw.Write(ansiRegex.ReplaceAll(p, []byte{}))
}
// ANSI enabled
r.buf.Reset()
r.ansiWriter.Write(p) // Shouldn't error because everything it writes to are all bytes.Buffer
return r.pw.Write(
// The ANSIWriter injects tags like [-:-:-]
// but this will reset the background to use the user's terminal color.
// These tags need to be replaced with resets that use the theme color.
bytes.ReplaceAll(
r.buf.Bytes(),
[]byte("[-:-:-]"),
[]byte(fmt.Sprintf("[-:%s:-]", config.GetColorString("bg"))),
),
)
}
func (r *ANSIRenderer) Links() <-chan string {
ch := make(chan string)
close(ch)
return ch
}