decentral1se 47045ca8f1
All checks were successful
continuous-integration/drone/push Build is passing
feat: improved deploy progress reporting
See #478
2025-03-23 09:13:36 +00:00

133 lines
2.6 KiB
Go

package compressor
import (
"bytes"
"io"
"unicode/utf8"
"github.com/muesli/ansi"
)
type Writer struct {
Forward io.Writer
ansi bool
ansiseq bytes.Buffer
lastseq bytes.Buffer
prevlastseq bytes.Buffer
resetreq bool
runeBuf []byte
compressed int
uncompressed int
}
// Bytes is shorthand for declaring a new default compressor instance,
// used to immediately compress a byte slice.
func Bytes(b []byte) []byte {
var buf bytes.Buffer
f := Writer{
Forward: &buf,
}
_, _ = f.Write(b)
_ = f.Close()
return buf.Bytes()
}
// String is shorthand for declaring a new default compressor instance,
// used to immediately compress a string.
func String(s string) string {
return string(Bytes([]byte(s)))
}
// Write is used to write content to the ANSI buffer.
func (w *Writer) Write(b []byte) (int, error) {
w.uncompressed += len(b)
for _, c := range string(b) {
if c == ansi.Marker {
// ANSI escape sequence
w.ansi = true
_, _ = w.ansiseq.WriteRune(c)
} else if w.ansi {
_, _ = w.ansiseq.WriteRune(c)
if ansi.IsTerminator(c) {
// ANSI sequence terminated
w.ansi = false
terminated := false
if bytes.HasSuffix(w.ansiseq.Bytes(), []byte("[0m")) {
// reset sequence
w.prevlastseq.Reset()
w.prevlastseq.Write(w.lastseq.Bytes())
w.lastseq.Reset()
terminated = true
w.resetreq = true
} else if c == 'm' {
// color code
_, _ = w.lastseq.Write(w.ansiseq.Bytes())
}
if !terminated {
// did we reset the sequence just to restore it again?
if bytes.Equal(w.ansiseq.Bytes(), w.prevlastseq.Bytes()) {
w.resetreq = false
w.ansiseq.Reset()
}
w.prevlastseq.Reset()
if w.resetreq {
w.ResetAnsi()
}
_, _ = w.Forward.Write(w.ansiseq.Bytes())
w.compressed += w.ansiseq.Len()
}
w.ansiseq.Reset()
}
} else {
if w.resetreq {
w.ResetAnsi()
}
_, err := w.writeRune(c)
if err != nil {
return 0, err
}
}
}
return len(b), nil
}
func (w *Writer) writeRune(r rune) (int, error) {
if w.runeBuf == nil {
w.runeBuf = make([]byte, utf8.UTFMax)
}
n := utf8.EncodeRune(w.runeBuf, r)
w.compressed += n
return w.Forward.Write(w.runeBuf[:n])
}
// Close finishes the compression operation. Always call it before trying to
// retrieve the final result.
func (w *Writer) Close() error {
if w.resetreq {
w.ResetAnsi()
}
// log.Println("Written uncompressed: ", w.uncompressed)
// log.Println("Written compressed: ", w.compressed)
return nil
}
func (w *Writer) ResetAnsi() {
w.prevlastseq.Reset()
_, _ = w.Forward.Write([]byte("\x1b[0m"))
w.resetreq = false
}