forked from toolshed/abra
93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
package cellbuf
|
|
|
|
import (
|
|
"io"
|
|
|
|
"github.com/charmbracelet/x/ansi"
|
|
)
|
|
|
|
// PenWriter is a writer that writes to a buffer and keeps track of the current
|
|
// pen style and link state for the purpose of wrapping with newlines.
|
|
type PenWriter struct {
|
|
w io.Writer
|
|
p *ansi.Parser
|
|
style Style
|
|
link Link
|
|
}
|
|
|
|
// NewPenWriter returns a new PenWriter.
|
|
func NewPenWriter(w io.Writer) *PenWriter {
|
|
pw := &PenWriter{w: w}
|
|
pw.p = ansi.GetParser()
|
|
handleCsi := func(cmd ansi.Cmd, params ansi.Params) {
|
|
if cmd == 'm' {
|
|
ReadStyle(params, &pw.style)
|
|
}
|
|
}
|
|
handleOsc := func(cmd int, data []byte) {
|
|
if cmd == 8 {
|
|
ReadLink(data, &pw.link)
|
|
}
|
|
}
|
|
pw.p.SetHandler(ansi.Handler{
|
|
HandleCsi: handleCsi,
|
|
HandleOsc: handleOsc,
|
|
})
|
|
return pw
|
|
}
|
|
|
|
// Style returns the current pen style.
|
|
func (w *PenWriter) Style() Style {
|
|
return w.style
|
|
}
|
|
|
|
// Link returns the current pen link.
|
|
func (w *PenWriter) Link() Link {
|
|
return w.link
|
|
}
|
|
|
|
// Write writes to the buffer.
|
|
func (w *PenWriter) Write(p []byte) (int, error) {
|
|
for i := range p {
|
|
b := p[i]
|
|
w.p.Advance(b)
|
|
if b == '\n' {
|
|
if !w.style.Empty() {
|
|
_, _ = w.w.Write([]byte(ansi.ResetStyle))
|
|
}
|
|
if !w.link.Empty() {
|
|
_, _ = w.w.Write([]byte(ansi.ResetHyperlink()))
|
|
}
|
|
}
|
|
|
|
_, _ = w.w.Write([]byte{b})
|
|
if b == '\n' {
|
|
if !w.link.Empty() {
|
|
_, _ = w.w.Write([]byte(ansi.SetHyperlink(w.link.URL, w.link.Params)))
|
|
}
|
|
if !w.style.Empty() {
|
|
_, _ = w.w.Write([]byte(w.style.Sequence()))
|
|
}
|
|
}
|
|
}
|
|
|
|
return len(p), nil
|
|
}
|
|
|
|
// Close closes the writer, resets the style and link if necessary, and releases
|
|
// its parser. Calling it is performance critical, but forgetting it does not
|
|
// cause safety issues or leaks.
|
|
func (w *PenWriter) Close() error {
|
|
if !w.style.Empty() {
|
|
_, _ = w.w.Write([]byte(ansi.ResetStyle))
|
|
}
|
|
if !w.link.Empty() {
|
|
_, _ = w.w.Write([]byte(ansi.ResetHyperlink()))
|
|
}
|
|
if w.p != nil {
|
|
ansi.PutParser(w.p)
|
|
w.p = nil
|
|
}
|
|
return nil
|
|
}
|