Create new type and remove un-used code
Create Release & Upload Assets / Upload Assets To Gitea w/ goreleaser (push) Failing after 11s
Create Release & Upload Assets / Upload Assets To Gitea w/ goreleaser (push) Failing after 11s
This commit is contained in:
+196
@@ -0,0 +1,196 @@
|
||||
package tml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Parser is used to parse a TML string into an output string containing ANSI escape codes
|
||||
type Parser struct {
|
||||
writer io.Writer
|
||||
IncludeLeadingResets bool
|
||||
IncludeTrailingResets bool
|
||||
state parserState
|
||||
}
|
||||
|
||||
type parserState struct {
|
||||
fg string
|
||||
bg string
|
||||
attrs attrs
|
||||
}
|
||||
|
||||
type attrs uint8
|
||||
|
||||
const (
|
||||
bold uint8 = 1 << iota
|
||||
dim
|
||||
underline
|
||||
blink
|
||||
reverse
|
||||
hidden
|
||||
italic
|
||||
strikethrough
|
||||
)
|
||||
|
||||
var resetAll = "\x1b[0m"
|
||||
var resetFg = "\x1b[39m"
|
||||
var resetBg = "\x1b[49m"
|
||||
|
||||
var attrMap = map[uint8]string{
|
||||
bold: "\x1b[1m",
|
||||
dim: "\x1b[2m",
|
||||
italic: "\x1b[3m",
|
||||
underline: "\x1b[4m",
|
||||
blink: "\x1b[5m",
|
||||
reverse: "\x1b[7m",
|
||||
hidden: "\x1b[8m",
|
||||
strikethrough: "\x1b[9m",
|
||||
}
|
||||
|
||||
func (s *parserState) setFg(esc string) string {
|
||||
if s.fg == esc {
|
||||
return ""
|
||||
}
|
||||
s.fg = esc
|
||||
return esc
|
||||
}
|
||||
|
||||
func (s *parserState) setBg(esc string) string {
|
||||
if s.bg == esc {
|
||||
return ""
|
||||
}
|
||||
s.bg = esc
|
||||
return esc
|
||||
}
|
||||
|
||||
func (s *parserState) setAttr(attr int8) string {
|
||||
|
||||
output := ""
|
||||
|
||||
if attr < 0 {
|
||||
output = resetAll + s.fg + s.bg
|
||||
}
|
||||
|
||||
s.attrs = attrs(uint8(s.attrs) + uint8(attr))
|
||||
|
||||
for attr, esc := range attrMap {
|
||||
if uint8(s.attrs)&attr > 0 {
|
||||
output += esc
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
// NewParser creates a new parser that writes to w
|
||||
func NewParser(w io.Writer) *Parser {
|
||||
return &Parser{
|
||||
writer: w,
|
||||
IncludeLeadingResets: true,
|
||||
IncludeTrailingResets: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) handleTag(name string) bool {
|
||||
|
||||
if strings.HasPrefix(name, "/") {
|
||||
name = name[1:]
|
||||
if _, isFg := fgTags[name]; isFg {
|
||||
if !disableFormatting {
|
||||
p.writer.Write([]byte(p.state.setFg(resetFg)))
|
||||
}
|
||||
return true
|
||||
} else if _, isBg := bgTags[name]; isBg {
|
||||
if !disableFormatting {
|
||||
p.writer.Write([]byte(p.state.setBg(resetBg)))
|
||||
}
|
||||
return true
|
||||
} else if attr, isAttr := attrTags[name]; isAttr {
|
||||
if !disableFormatting {
|
||||
p.writer.Write([]byte(p.state.setAttr(-int8(attr))))
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if esc, ok := fgTags[name]; ok {
|
||||
if !disableFormatting {
|
||||
p.writer.Write([]byte(p.state.setFg(esc)))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if esc, ok := bgTags[name]; ok {
|
||||
if !disableFormatting {
|
||||
p.writer.Write([]byte(p.state.setBg(esc)))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if attr, ok := attrTags[name]; ok {
|
||||
if !disableFormatting {
|
||||
p.writer.Write([]byte(p.state.setAttr(int8(attr))))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Parse takes input from the reader and converts any provided tags to the relevant ANSI escape codes for output to parser's writer.
|
||||
func (p *Parser) Parse(reader io.Reader) error {
|
||||
|
||||
formattingLock.RLock()
|
||||
defer formattingLock.RUnlock()
|
||||
|
||||
buffer := make([]byte, 1024)
|
||||
|
||||
if p.IncludeLeadingResets && !disableFormatting {
|
||||
if _, err := p.writer.Write([]byte(resetAll)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var inTag bool
|
||||
var tagName string
|
||||
|
||||
for {
|
||||
n, err := reader.Read(buffer)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
for _, r := range string(buffer[:n]) {
|
||||
|
||||
if inTag {
|
||||
if r == '>' {
|
||||
if !p.handleTag(tagName) {
|
||||
p.writer.Write([]byte(fmt.Sprintf("<%s>", tagName)))
|
||||
}
|
||||
tagName = ""
|
||||
inTag = false
|
||||
continue
|
||||
}
|
||||
tagName = fmt.Sprintf("%s%c", tagName, r)
|
||||
continue
|
||||
}
|
||||
|
||||
if r == '<' {
|
||||
inTag = true
|
||||
continue
|
||||
}
|
||||
|
||||
p.writer.Write([]byte(string([]rune{r})))
|
||||
}
|
||||
}
|
||||
|
||||
if p.IncludeTrailingResets && !disableFormatting {
|
||||
p.writer.Write([]byte(resetAll))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user