mirror of
https://github.com/makew0rld/amfora.git
synced 2024-12-04 14:46:29 -05:00
Gemtext renderer too now
This commit is contained in:
parent
74971e51e5
commit
c1ecbf71b9
1
NOTES.md
1
NOTES.md
@ -1,7 +1,6 @@
|
|||||||
# Notes
|
# Notes
|
||||||
|
|
||||||
## Stream (#9)
|
## Stream (#9)
|
||||||
- Refactor renderers to work with `Write`, maybe drop `ReadFrom` entirely
|
|
||||||
- Then make handlers and stuff part of `tab`
|
- Then make handlers and stuff part of `tab`
|
||||||
- Go through process of loading a page from the very beginning and line up all the parts
|
- Go through process of loading a page from the very beginning and line up all the parts
|
||||||
- Also handle non-network pages like `about:` pages, where `Raw` already exists and just needs to be rendered
|
- Also handle non-network pages like `about:` pages, where `Raw` already exists and just needs to be rendered
|
||||||
|
@ -18,8 +18,10 @@ import (
|
|||||||
type GemtextRenderer struct {
|
type GemtextRenderer struct {
|
||||||
// Buffers and I/O
|
// Buffers and I/O
|
||||||
|
|
||||||
r *io.PipeReader
|
readOut *io.PipeReader
|
||||||
w *io.PipeWriter
|
readIn *io.PipeWriter
|
||||||
|
writeIn *io.PipeWriter
|
||||||
|
writeOut *io.PipeReader
|
||||||
links chan string
|
links chan string
|
||||||
|
|
||||||
// Configurable options
|
// Configurable options
|
||||||
@ -79,7 +81,8 @@ func wrapLine(line string, width int, prefix, suffix string, includeFirst bool)
|
|||||||
// 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 NewGemtextRenderer(width int, proxied bool) *GemtextRenderer {
|
func NewGemtextRenderer(width int, proxied bool) *GemtextRenderer {
|
||||||
pr, pw := io.Pipe()
|
pr1, pw1 := io.Pipe()
|
||||||
|
pr2, pw2 := io.Pipe()
|
||||||
|
|
||||||
ansiEnabled := false
|
ansiEnabled := false
|
||||||
if viper.GetBool("a-general.color") && viper.GetBool("a-general.ansi") {
|
if viper.GetBool("a-general.color") && viper.GetBool("a-general.ansi") {
|
||||||
@ -90,15 +93,53 @@ func NewGemtextRenderer(width int, proxied bool) *GemtextRenderer {
|
|||||||
colorEnabled = true
|
colorEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return &GemtextRenderer{
|
ren := GemtextRenderer{
|
||||||
r: pr,
|
readOut: pr1,
|
||||||
w: pw,
|
readIn: pw1,
|
||||||
|
writeIn: pw2,
|
||||||
|
writeOut: pr2,
|
||||||
links: make(chan string, 10),
|
links: make(chan string, 10),
|
||||||
width: width,
|
width: width,
|
||||||
proxied: proxied,
|
proxied: proxied,
|
||||||
ansiEnabled: ansiEnabled,
|
ansiEnabled: ansiEnabled,
|
||||||
colorEnabled: colorEnabled,
|
colorEnabled: colorEnabled,
|
||||||
}
|
}
|
||||||
|
go ren.handler()
|
||||||
|
return &ren
|
||||||
|
}
|
||||||
|
|
||||||
|
// handler is supposed to run in a goroutine as soon as the renderer is created.
|
||||||
|
// It handles the buffering and parsing in the background.
|
||||||
|
func (ren *GemtextRenderer) handler() {
|
||||||
|
// Go through lines, render, and write each line
|
||||||
|
|
||||||
|
// Splits on lines and drops terminators, unlike the other renderers
|
||||||
|
scanner := bufio.NewScanner(ren.writeOut)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
|
||||||
|
// Process the one possibly invisible line
|
||||||
|
if strings.HasPrefix(line, "```") {
|
||||||
|
ren.pre = !ren.pre
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render line and write it
|
||||||
|
|
||||||
|
//nolint:errcheck
|
||||||
|
ren.readIn.Write([]byte(ren.renderLine(line)))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything has been read, no more links
|
||||||
|
close(ren.links)
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
// Close the ends this func touches, shouldn't matter really
|
||||||
|
ren.writeOut.CloseWithError(err)
|
||||||
|
ren.readIn.CloseWithError(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderLine handles all lines except preformatted markings. The input line
|
// renderLine handles all lines except preformatted markings. The input line
|
||||||
@ -310,48 +351,19 @@ func (ren *GemtextRenderer) renderLine(line string) string {
|
|||||||
return strings.Join(wrappedLines, "\n") + "\n"
|
return strings.Join(wrappedLines, "\n") + "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ren *GemtextRenderer) ReadFrom(r io.Reader) (int64, error) {
|
|
||||||
// Go through lines, render, and write each line
|
|
||||||
|
|
||||||
var n int64
|
|
||||||
scanner := bufio.NewScanner(r)
|
|
||||||
scanner.Split(ScanLines)
|
|
||||||
|
|
||||||
for scanner.Scan() {
|
|
||||||
n += int64(len(scanner.Bytes()))
|
|
||||||
line := scanner.Text()
|
|
||||||
|
|
||||||
// Process the one possibly invisible line
|
|
||||||
if strings.HasPrefix(line, "```") {
|
|
||||||
ren.pre = !ren.pre
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render line and write it
|
|
||||||
|
|
||||||
//nolint:errcheck
|
|
||||||
ren.w.Write([]byte(
|
|
||||||
ren.renderLine(strings.TrimRight(line, "\r\n")),
|
|
||||||
))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everything has been read, no more links
|
|
||||||
close(ren.links)
|
|
||||||
|
|
||||||
return n, scanner.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write will panic, use ReadFrom instead.
|
|
||||||
func (ren *GemtextRenderer) Write(p []byte) (n int, err error) {
|
func (ren *GemtextRenderer) Write(p []byte) (n int, err error) {
|
||||||
// This renderer is line based, and so it can't process arbitrary bytes.
|
return ren.writeIn.Write(p)
|
||||||
// One solution would be to handle rendering on the other end of the pipe,
|
|
||||||
// the Read call, but it's simpler to just implement ReadFrom.
|
|
||||||
panic("func Write not allowed for GemtextRenderer")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ren *GemtextRenderer) Read(p []byte) (n int, err error) {
|
func (ren *GemtextRenderer) Read(p []byte) (n int, err error) {
|
||||||
return ren.r.Read(p)
|
return ren.readOut.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ren *GemtextRenderer) Close() error {
|
||||||
|
// Close user-facing ends of the pipes. Shouldn't matter which ends though
|
||||||
|
ren.writeIn.Close()
|
||||||
|
ren.readOut.Close()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ren *GemtextRenderer) Links() <-chan string {
|
func (ren *GemtextRenderer) Links() <-chan string {
|
||||||
|
@ -16,7 +16,8 @@ import (
|
|||||||
// cview.TextView.
|
// cview.TextView.
|
||||||
//
|
//
|
||||||
// Calling Close when all writing is done is not a no-op, it will stop the the
|
// Calling Close when all writing is done is not a no-op, it will stop the the
|
||||||
// goroutine that runs for each Renderer.
|
// goroutine that runs for each Renderer, and will also allow the Links channel
|
||||||
|
// to be closed. Close should be called once all the data has been copied
|
||||||
//
|
//
|
||||||
// Write calls may block if the Lines channel buffer is full.
|
// Write calls may block if the Lines channel buffer is full.
|
||||||
type Renderer interface {
|
type Renderer interface {
|
||||||
|
Loading…
Reference in New Issue
Block a user