1
0
textfmt/write.go
2025-10-31 20:24:37 +01:00

234 lines
3.3 KiB
Go

package textfmt
import (
"fmt"
"io"
"slices"
"strings"
)
type writer interface {
write(...any)
flush()
error() error
setErr(err error) // TODO: remove
}
type textWriter struct {
err error
out io.Writer
}
type editor struct {
out writer
pending []rune
replace map[string]string
}
func (w *textWriter) write(a ...any) {
if w.err != nil {
return
}
for _, ai := range a {
if _, err := w.out.Write([]byte(fmt.Sprint(ai))); err != nil {
w.err = err
return
}
}
}
func (w *textWriter) flush() {}
func (w *textWriter) error() error {
return w.err
}
func (e *textWriter) setErr(err error) {
}
func (e *editor) write(a ...any) {
for _, ai := range a {
s := fmt.Sprint(ai)
r := []rune(s)
for key, replacement := range e.replace {
rk := []rune(key)
if len(e.pending) >= len(rk) {
continue
}
if !slices.Equal(e.pending, rk[:len(e.pending)]) {
continue
}
if len(r) < len(rk)-len(e.pending) {
if slices.Equal(r, rk[len(e.pending):len(e.pending)+len(r)]) {
e.pending = append(e.pending, r...)
r = nil
break
}
continue
}
if slices.Equal(r[:len(rk)-len(e.pending)], rk[len(e.pending):]) {
r = []rune(replacement)
e.pending = nil
break
}
}
e.out.write(string(r))
}
}
func (e *editor) flush() {
e.out.write(string(e.pending))
e.out.flush()
}
func (e *editor) error() error {
return e.out.error()
}
func (e *editor) setErr(err error) {
}
// --
type ttyWriter struct {
w io.Writer
internal bool
err error
}
type roffWriter struct {
w io.Writer
internal bool
err error
}
type mdWriter struct {
w io.Writer
internal bool
err error
}
func (w *ttyWriter) write(a ...any) {
for _, ai := range a {
if w.err != nil {
return
}
s := fmt.Sprint(ai)
r := []rune(s)
if !w.internal {
for i := range r {
if r[i] == '\u00a0' {
r[i] = ' '
}
}
}
if _, err := w.w.Write([]byte(string(r))); err != nil {
w.err = err
}
}
}
func (w *ttyWriter) flush() {}
func (w *ttyWriter) error() error {
return w.err
}
func (w *ttyWriter) setErr(err error) {
w.err = err
}
func (w *roffWriter) write(a ...any) {
for _, ai := range a {
if w.err != nil {
return
}
var rr []rune
s := fmt.Sprint(ai)
r := []rune(s)
if w.internal {
rr = r
} else {
for i := range r {
if r[i] == '\u00a0' {
rr = append(rr, []rune("\\~")...)
continue
}
rr = append(rr, r[i])
}
}
if _, err := w.w.Write([]byte(string(rr))); err != nil {
w.err = err
}
}
}
func (w *roffWriter) flush() {}
func (w *roffWriter) error() error {
return w.err
}
func (w *roffWriter) setErr(err error) {
w.err = err
}
func (w *mdWriter) write(a ...any) {
for _, ai := range a {
if w.err != nil {
return
}
s := fmt.Sprint(ai)
r := []rune(s)
if !w.internal {
for i := range r {
if r[i] == '\u00a0' {
r[i] = ' '
}
}
}
s = string(r)
_, w.err = w.w.Write([]byte(s))
}
}
func (w *mdWriter) flush() {}
func (w *mdWriter) error() error {
return w.err
}
func (w *mdWriter) setErr(err error) {
w.err = err
}
func writeLines(w writer, txt string, indentFirst, indentRest int) {
lines := strings.Split(txt, "\n")
for i, l := range lines {
if i > 0 {
w.write("\n")
}
indent := indentFirst
if i > 0 {
indent = indentRest
}
w.write(timesn(" ", indent))
w.write(l)
}
}