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:
Generated
+2
@@ -0,0 +1,2 @@
|
||||
bin
|
||||
.vscode
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
|
||||
default: build
|
||||
|
||||
build: test
|
||||
mkdir -p bin
|
||||
go build ./tml/ -o bin/tml
|
||||
|
||||
build-travis: test
|
||||
mkdir -p bin/linux-amd64/tml
|
||||
mkdir -p bin/darwin-amd64/tml
|
||||
GOOS=linux GOARCH=amd64 go build -o bin/linux-amd64/tml -ldflags "-X github.com/liamg/tml/version.Version=${TRAVIS_TAG}" ./tml
|
||||
GOOS=darwin GOARCH=amd64 go build -o bin/darwin-amd64/tml -ldflags "-X github.com/liamg/tml/version.Version=${TRAVIS_TAG}" ./tml
|
||||
|
||||
test:
|
||||
go vet ./...
|
||||
go test -v ./...
|
||||
|
||||
.PHONY: build test
|
||||
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
# tml - Terminal Markup Language
|
||||
|
||||
[](https://travis-ci.org/liamg/tml)
|
||||
[](https://godoc.org/github.com/liamg/tml)
|
||||
|
||||
A Go module (and standalone binary) to make the output of coloured/formatted text in the terminal easier and more readable.
|
||||
|
||||
You can use it in your Go programs, and bash etc. too.
|
||||
|
||||

|
||||
|
||||
## Usage in Go
|
||||
|
||||
The output of coloured/formatted text is easy using the following syntax:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/liamg/tml"
|
||||
|
||||
func main() {
|
||||
tml.Printf("<red>this text is <bold>red</bold></red> and the following is <green>%s</green>\n", "not red")
|
||||
}
|
||||
```
|
||||
|
||||
## Usage in Bash
|
||||
|
||||
First, install tml:
|
||||
|
||||
Install Go and run the following command.
|
||||
|
||||
```
|
||||
# For Go 1.16+
|
||||
# Make sure that `$GOPATH/bin` is in your `$PATH`, because that's where this gets installed
|
||||
|
||||
go install github.com/liamg/tml/tml@latest
|
||||
|
||||
# For Go <1.16
|
||||
|
||||
go get -u github.com/liamg/tml/tml
|
||||
```
|
||||
|
||||
Then you can simply pipe text containing tags to tml:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
echo "<red>this text is <bold>red</bold></red> and the following is <green>not red</green>" | tml
|
||||
```
|
||||
|
||||
## Format
|
||||
|
||||
Each tag is enclosed in angle brackets, much like HTML.
|
||||
|
||||
You can nest tags as deeply as you like.
|
||||
|
||||
It's not required to close tags you've opened, though it can make for easier reading.
|
||||
|
||||
### Available Tags
|
||||
|
||||
#### Foreground Colours
|
||||
|
||||
- `<red>`
|
||||
- `<green>`
|
||||
- `<yellow>`
|
||||
- `<blue>`
|
||||
- `<magenta>`
|
||||
- `<cyan>`
|
||||
- `<lightgrey>`
|
||||
- `<darkgrey>`
|
||||
- `<black>`
|
||||
- `<white>`
|
||||
- `<lightred>`
|
||||
- `<lightgreen>`
|
||||
- `<lightyellow>`
|
||||
- `<lightblue>`
|
||||
- `<lightmagenta>`
|
||||
- `<lightcyan>`
|
||||
|
||||
#### Background Colours
|
||||
|
||||
- `<bg-red>`
|
||||
- `<bg-green>`
|
||||
- `<bg-yellow>`
|
||||
- `<bg-blue>`
|
||||
- `<bg-magenta>`
|
||||
- `<bg-cyan>`
|
||||
- `<bg-lightgrey>`
|
||||
- `<bg-darkgrey>`
|
||||
- `<bg-black>`
|
||||
- `<bg-white>`
|
||||
- `<bg-lightred>`
|
||||
- `<bg-lightgreen>`
|
||||
- `<bg-lightyellow>`
|
||||
- `<bg-lightblue>`
|
||||
- `<bg-lightmagenta>`
|
||||
- `<bg-lightcyan>`
|
||||
|
||||
#### Attributes
|
||||
|
||||
- `<bold>`
|
||||
- `<dim>`
|
||||
- `<italic>`
|
||||
- `<underline>`
|
||||
- `<blink>`
|
||||
- `<reverse>`
|
||||
- `<hidden>`
|
||||
- `<strikethrough>`
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package tml
|
||||
|
||||
import "sync"
|
||||
|
||||
var disableFormatting bool
|
||||
var formattingLock sync.RWMutex
|
||||
|
||||
func DisableFormatting() {
|
||||
formattingLock.Lock()
|
||||
defer formattingLock.Unlock()
|
||||
disableFormatting = true
|
||||
}
|
||||
|
||||
func EnableFormatting() {
|
||||
formattingLock.Lock()
|
||||
defer formattingLock.Unlock()
|
||||
disableFormatting = false
|
||||
}
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
+6
@@ -0,0 +1,6 @@
|
||||
package tml
|
||||
|
||||
// NewLine prints a new line to the terminal with no content
|
||||
func NewLine() {
|
||||
Println("")
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package tml
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// Parse converts the input string (containing TML tags) into a string containing ANSI escape code sequences for output to the terminal.
|
||||
func Parse(input string) (string, error) {
|
||||
output := bytes.NewBufferString("")
|
||||
if err := NewParser(output).Parse(strings.NewReader(input)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return output.String(), nil
|
||||
}
|
||||
+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
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package tml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Printf works like fmt.Printf, but adds the option of using tags to apply colour or text formatting to the written text. For example "<red>some red text</red>".
|
||||
// A full list of tags is available here: https://github.com/liamg/tml
|
||||
func Printf(input string, a ...interface{}) error {
|
||||
return Fprintf(os.Stdout, input, a...)
|
||||
}
|
||||
|
||||
func Fprintf(w io.Writer, input string, a ...interface{}) error {
|
||||
format, err := Parse(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = fmt.Fprintf(w, format, a...)
|
||||
return err
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package tml
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Println works like fmt.Println, but adds the option of using tags to apply colour or text formatting to the written text. For example "<red>some red text</red>".
|
||||
// A full list of tags is available here: https://github.com/liamg/tml
|
||||
func Println(input string) {
|
||||
Fprintln(os.Stdout, input)
|
||||
}
|
||||
|
||||
func Fprintln(w io.Writer, input string) {
|
||||
Fprintf(w, "%s\n", input)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package tml
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Sprintf works like fmt.Sprintf, but adds the option of using tags to apply colour or text formatting to the written text. For example "<red>some red text</red>".
|
||||
// A full list of tags is available here: https://github.com/liamg/tml
|
||||
func Sprintf(input string, a ...interface{}) string {
|
||||
// parsing cannot fail as the reader/writer are simply for local strings
|
||||
format, _ := Parse(input)
|
||||
return fmt.Sprintf(format, a...)
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package tml
|
||||
|
||||
var fgTags = map[string]string{
|
||||
"red": "\x1b[31m",
|
||||
"green": "\x1b[32m",
|
||||
"yellow": "\x1b[33m",
|
||||
"blue": "\x1b[34m",
|
||||
"magenta": "\x1b[35m",
|
||||
"cyan": "\x1b[36m",
|
||||
"lightgrey": "\x1b[37m",
|
||||
"darkgrey": "\x1b[90m",
|
||||
"black": "\x1b[30m",
|
||||
"lightred": "\x1b[91m",
|
||||
"lightgreen": "\x1b[92m",
|
||||
"lightyellow": "\x1b[93m",
|
||||
"lightblue": "\x1b[94m",
|
||||
"lightmagenta": "\x1b[95m",
|
||||
"lightcyan": "\x1b[96m",
|
||||
"white": "\x1b[97m",
|
||||
}
|
||||
|
||||
var bgTags = map[string]string{
|
||||
"bg-red": "\x1b[41m",
|
||||
"bg-green": "\x1b[42m",
|
||||
"bg-yellow": "\x1b[43m",
|
||||
"bg-blue": "\x1b[44m",
|
||||
"bg-magenta": "\x1b[45m",
|
||||
"bg-cyan": "\x1b[46m",
|
||||
"bg-lightgrey": "\x1b[47m",
|
||||
"bg-darkgrey": "\x1b[40m",
|
||||
"bg-black": "\x1b[40m",
|
||||
"bg-lightred": "\x1b[101m",
|
||||
"bg-lightgreen": "\x1b[102m",
|
||||
"bg-lightyellow": "\x1b[103m",
|
||||
"bg-lightblue": "\x1b[104m",
|
||||
"bg-lightmagenta": "\x1b[105m",
|
||||
"bg-lightcyan": "\x1b[106m",
|
||||
"bg-white": "\x1b[107m",
|
||||
}
|
||||
|
||||
var attrTags = map[string]uint8{
|
||||
"bold": bold,
|
||||
"dim": dim,
|
||||
"italic": italic,
|
||||
"underline": underline,
|
||||
"blink": blink,
|
||||
"reverse": reverse,
|
||||
"hidden": hidden,
|
||||
"strikethrough": strikethrough,
|
||||
}
|
||||
Reference in New Issue
Block a user