1
0
html/wrap.go

148 lines
2.6 KiB
Go
Raw Permalink Normal View History

2025-09-11 20:50:00 +02:00
package html
import (
2025-11-01 21:23:56 +01:00
"code.squareroundforest.org/arpio/textedit"
"io"
2025-09-11 20:50:00 +02:00
"unicode"
)
2025-11-01 21:23:56 +01:00
type wrapState struct {
line, word []rune
2025-10-06 00:37:10 +02:00
inWord, inTag, inSingleQuote, inQuote bool
lastSpace, started bool
}
2025-11-01 21:23:56 +01:00
type wrapper struct {
indent *textedit.Writer
wrap *textedit.Writer
}
2025-11-01 21:23:56 +01:00
func wrapFeed(width int, s wrapState) ([]rune, wrapState) {
var ret []rune
withSpace := s.lastSpace && len(s.line) > 0
l := len(s.line) + len(s.word)
if withSpace && len(s.word) > 0 {
l++
}
2025-11-01 21:23:56 +01:00
feedLine := l > width && len(s.line) > 0
if feedLine {
2025-11-01 21:23:56 +01:00
if s.started {
ret = append(ret, '\n')
}
2025-11-01 21:23:56 +01:00
ret = append(ret, s.line...)
s.line = nil
s.started = true
}
if !feedLine && withSpace {
2025-11-01 21:23:56 +01:00
s.line = append(s.line, ' ')
}
2025-11-01 21:23:56 +01:00
s.line = append(s.line, s.word...)
s.word = nil
return ret, s
}
2025-09-11 20:50:00 +02:00
2025-11-01 21:23:56 +01:00
func wrapEdit(width int) func(rune, wrapState) ([]rune, wrapState) {
return func(r rune, s wrapState) ([]rune, wrapState) {
var ret []rune
if s.inSingleQuote {
s.inSingleQuote = r != '\''
s.word = append(s.word, r)
return ret, s
2025-09-11 20:50:00 +02:00
}
2025-11-01 21:23:56 +01:00
if s.inQuote {
s.inQuote = r != '"'
s.word = append(s.word, r)
return ret, s
2025-10-05 21:25:53 +02:00
}
2025-11-01 21:23:56 +01:00
if s.inTag {
s.inSingleQuote = r == '\''
s.inQuote = r == '"'
s.inTag = r != '>'
s.inWord = !s.inTag && !unicode.IsSpace(r)
if s.inTag || !unicode.IsSpace(r) {
s.word = append(s.word, r)
2025-10-05 20:06:39 +02:00
}
2025-11-01 21:23:56 +01:00
if !s.inTag {
ret, s = wrapFeed(width, s)
s.lastSpace = unicode.IsSpace(r)
2025-09-11 20:50:00 +02:00
}
2025-11-01 21:23:56 +01:00
return ret, s
2025-09-11 20:50:00 +02:00
}
2025-11-01 21:23:56 +01:00
if s.inWord {
s.inTag = r == '<'
s.inWord = !s.inTag && !unicode.IsSpace(r)
if !s.inWord {
ret, s = wrapFeed(width, s)
s.lastSpace = unicode.IsSpace(r)
}
2025-09-11 20:50:00 +02:00
2025-11-01 21:23:56 +01:00
if s.inWord || s.inTag {
s.word = append(s.word, r)
}
2025-09-11 20:50:00 +02:00
2025-11-01 21:23:56 +01:00
return ret, s
2025-09-11 20:50:00 +02:00
}
if unicode.IsSpace(r) {
2025-11-01 21:23:56 +01:00
s.lastSpace = true
return ret, s
2025-09-11 20:50:00 +02:00
}
2025-11-01 21:23:56 +01:00
s.word = append(s.word, r)
s.inTag = r == '<'
s.inWord = !s.inTag
return ret, s
2025-09-11 20:50:00 +02:00
}
2025-11-01 21:23:56 +01:00
}
2025-09-11 20:50:00 +02:00
2025-11-01 21:23:56 +01:00
func wrapReleaseState(width int) func(wrapState) []rune {
return func(s wrapState) []rune {
var ret []rune
if s.inTag || s.inWord {
ret, s = wrapFeed(width, s)
}
ret1, _ := wrapFeed(0, s)
return append(ret, ret1...)
}
}
2025-11-01 21:23:56 +01:00
func newWrapper(out io.Writer, width int, indent string) *wrapper {
indentWriter := newIndentWriter(out, indent)
return &wrapper{
indent: indentWriter,
wrap: textedit.New(
indentWriter,
textedit.Func(
wrapEdit(width),
wrapReleaseState(width),
),
),
2025-09-11 20:50:00 +02:00
}
2025-11-01 21:23:56 +01:00
}
2025-09-11 20:50:00 +02:00
2025-11-01 21:23:56 +01:00
func (w *wrapper) Write(p []byte) (int, error) {
return w.wrap.Write(p)
}
func (w *wrapper) Flush() error {
if err := w.wrap.Flush(); err != nil {
return err
}
2025-09-11 20:50:00 +02:00
2025-11-01 21:23:56 +01:00
if err := w.indent.Flush(); err != nil {
return err
2025-09-11 20:50:00 +02:00
}
2025-11-01 21:23:56 +01:00
return nil
2025-09-11 20:50:00 +02:00
}