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
|
|
|
)
|
|
|
|
|
|
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 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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|