1
0
textfmt/write.go

199 lines
3.5 KiB
Go
Raw Normal View History

2025-10-14 20:46:32 +02:00
package textfmt
import (
2025-11-02 06:27:17 +01:00
"bytes"
"code.squareroundforest.org/arpio/textedit"
2025-10-14 20:46:32 +02:00
"fmt"
2025-10-23 02:55:49 +02:00
"io"
2025-10-14 20:46:32 +02:00
)
type writer interface {
write(...any)
2025-10-31 20:24:37 +01:00
flush()
2025-10-14 20:46:32 +02:00
error() error
2025-10-31 20:24:37 +01:00
setErr(err error) // TODO: remove
2025-10-14 20:46:32 +02:00
}
2025-11-02 06:27:17 +01:00
type roffWriter struct {
w io.Writer
2025-10-31 20:24:37 +01:00
err error
}
2025-11-02 06:27:17 +01:00
type mdWriter struct {
w io.Writer
err error
2025-10-31 20:24:37 +01:00
}
2025-11-02 06:27:17 +01:00
type wrapper func(io.Writer) (io.Writer, func() error)
2025-10-31 20:24:37 +01:00
2025-11-02 06:27:17 +01:00
type errorWriter struct {
out io.Writer
err error
2025-10-31 20:24:37 +01:00
}
2025-11-02 06:27:17 +01:00
func (w *errorWriter) Write(p []byte) (int, error) {
if w.err != nil {
return 0, w.err
}
2025-10-31 20:24:37 +01:00
2025-11-02 06:27:17 +01:00
var n int
n, w.err = w.out.Write(p)
return n, w.err
2025-10-31 20:24:37 +01:00
}
2025-11-02 06:27:17 +01:00
func newRoffWriter(out io.Writer, internal bool) *roffWriter {
if internal {
return &roffWriter{w: out}
}
return &roffWriter{
w: textedit.New(
out,
textedit.Replace("\u00a0", "\\~"),
),
}
2025-10-31 20:24:37 +01:00
}
2025-11-02 06:27:17 +01:00
func (w *roffWriter) write(a ...any) {
2025-10-31 20:24:37 +01:00
for _, ai := range a {
2025-11-02 06:27:17 +01:00
if w.err != nil {
return
2025-10-31 20:24:37 +01:00
}
2025-11-02 06:27:17 +01:00
if _, err := w.w.Write([]byte(fmt.Sprint(ai))); err != nil {
w.err = err
return
}
2025-10-31 20:24:37 +01:00
}
}
2025-11-02 06:27:17 +01:00
func (w *roffWriter) flush() {
if w.err != nil {
return
}
2025-10-31 20:24:37 +01:00
2025-11-02 06:27:17 +01:00
if f, ok := w.w.(interface{ Flush() error }); ok {
if err := f.Flush(); err != nil {
w.err = err
}
}
2025-10-31 20:24:37 +01:00
}
2025-11-02 06:27:17 +01:00
func (w *roffWriter) error() error {
return w.err
2025-10-31 20:24:37 +01:00
}
2025-11-02 06:27:17 +01:00
func (w *roffWriter) setErr(err error) {
w.err = err
2025-10-14 20:46:32 +02:00
}
2025-11-02 06:27:17 +01:00
func newMDWriter(out io.Writer, internal bool) *mdWriter {
if internal {
return &mdWriter{w: out}
}
2025-10-14 20:46:32 +02:00
2025-11-02 06:27:17 +01:00
return &mdWriter{
w: textedit.New(
out,
textedit.Replace("\u00a0", " "),
),
}
2025-10-28 00:47:41 +01:00
}
2025-11-02 06:27:17 +01:00
func (w *mdWriter) write(a ...any) {
2025-10-14 20:46:32 +02:00
for _, ai := range a {
if w.err != nil {
return
}
2025-11-02 06:27:17 +01:00
if _, err := w.w.Write([]byte(fmt.Sprint(ai))); err != nil {
w.err = err
return
2025-10-14 20:46:32 +02:00
}
2025-11-02 06:27:17 +01:00
}
}
func (w *mdWriter) flush() {
if w.err != nil {
return
}
2025-10-14 20:46:32 +02:00
2025-11-02 06:27:17 +01:00
if f, ok := w.w.(interface{ Flush() error }); ok {
if err := f.Flush(); err != nil {
2025-10-14 20:46:32 +02:00
w.err = err
}
}
}
2025-11-02 06:27:17 +01:00
func (w *mdWriter) error() error {
2025-10-14 20:46:32 +02:00
return w.err
}
2025-11-02 06:27:17 +01:00
func (w *mdWriter) setErr(err error) {
2025-10-14 20:46:32 +02:00
w.err = err
}
2025-11-02 06:27:17 +01:00
func writeWith(out io.Writer, w ...wrapper) (io.Writer, func() (io.Writer, error)) {
var f []func() error
ww := out
for i := len(w) - 1; i >= 0; i-- {
var fi func() error
ww, fi = w[i](ww)
f = append(f, fi)
}
2025-10-14 20:46:32 +02:00
2025-11-02 06:27:17 +01:00
return ww, func() (io.Writer, error) {
for _, fi := range f {
if err := fi(); err != nil {
return out, err
2025-10-23 02:55:38 +02:00
}
2025-10-14 20:46:32 +02:00
}
2025-11-02 06:27:17 +01:00
return out, nil
2025-10-14 20:46:32 +02:00
}
}
2025-11-02 06:27:17 +01:00
func errorHandler(out io.Writer) (io.Writer, func() error) {
ew := errorWriter{out: out}
return &ew, func() error { return ew.err }
2025-10-14 20:46:32 +02:00
}
2025-11-02 06:27:17 +01:00
func editor(e textedit.Editor) wrapper {
return func(out io.Writer) (io.Writer, func() error) {
ew := textedit.New(out, e)
return ew, func() error { return ew.Flush() }
}
2025-10-14 20:46:32 +02:00
}
2025-11-02 06:27:17 +01:00
func editString(s string, e ...wrapper) string {
var b bytes.Buffer
w, finish := writeWith(&b, e...)
w.Write([]byte(s))
finish()
return b.String()
2025-10-28 00:47:41 +01:00
}
2025-11-02 06:27:17 +01:00
func ttyNBSP() wrapper { return editor(textedit.Replace("\u00a0", " ")) }
func roffNBSP() wrapper { return editor(textedit.Replace("\u00a0", "\\~")) }
func mdNBSP() wrapper { return editor(textedit.Replace("\u00a0", " ")) }
func singleLine() wrapper { return editor(textedit.SingleLine()) }
2025-10-31 20:24:37 +01:00
2025-11-02 06:27:17 +01:00
func indent(first, rest int) wrapper {
return editor(textedit.Indent(timesn(" ", first), timesn(" ", rest)))
2025-10-28 00:47:41 +01:00
}
2025-11-02 06:27:17 +01:00
func wrap(firstWidth, restWidth int) wrapper {
return editor(textedit.Wrap(firstWidth, restWidth))
2025-10-28 00:47:41 +01:00
}
2025-11-02 06:27:17 +01:00
func wrapIndent(first, rest, firstWidth, restWidth int) wrapper {
return editor(textedit.WrapIndent(timesn(" ", first), timesn(" ", rest), firstWidth, restWidth))
}
2025-10-14 20:46:32 +02:00
2025-11-02 06:27:17 +01:00
func write(out io.Writer, a ...any) {
for _, ai := range a {
if _, err := out.Write([]byte(fmt.Sprint(ai))); err != nil {
return
2025-10-14 20:46:32 +02:00
}
}
}