color support
This commit is contained in:
parent
06648c9177
commit
9bd2401fd9
36
color.go
Normal file
36
color.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/fatih/color"
|
||||||
|
|
||||||
|
var colorCache = map[string]*color.Color{}
|
||||||
|
|
||||||
|
func makeColor(name string) (c *color.Color) {
|
||||||
|
// caching
|
||||||
|
if c, ok := colorCache[name]; ok {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
defer func() { colorCache[name] = c }()
|
||||||
|
|
||||||
|
switch name {
|
||||||
|
case "black":
|
||||||
|
return color.New(color.FgBlack)
|
||||||
|
case "red":
|
||||||
|
return color.New(color.FgRed)
|
||||||
|
case "green":
|
||||||
|
return color.New(color.FgGreen)
|
||||||
|
case "yellow":
|
||||||
|
return color.New(color.FgYellow)
|
||||||
|
case "blue":
|
||||||
|
return color.New(color.FgBlue)
|
||||||
|
case "magenta":
|
||||||
|
return color.New(color.FgMagenta)
|
||||||
|
case "cyan":
|
||||||
|
return color.New(color.FgCyan)
|
||||||
|
case "white":
|
||||||
|
return color.New(color.FgWhite)
|
||||||
|
case "":
|
||||||
|
return color.New()
|
||||||
|
default:
|
||||||
|
panic("unknown color name. valid color names: black, red, green, yellow, blue, magenta, cyan, white")
|
||||||
|
}
|
||||||
|
}
|
7
go.mod
7
go.mod
@ -1,3 +1,10 @@
|
|||||||
module git.tordarus.net/Tordarus/format
|
module git.tordarus.net/Tordarus/format
|
||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/fatih/color v1.13.0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e // indirect
|
||||||
|
)
|
||||||
|
14
go.sum
Normal file
14
go.sum
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||||
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
|
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||||
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e h1:w36l2Uw3dRan1K3TyXriXvY+6T56GNmlKGcqiQUJDfM=
|
||||||
|
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
106
main.go
106
main.go
@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -46,7 +45,7 @@ var (
|
|||||||
// it may be useful to have a boolean flag for this behavior
|
// it may be useful to have a boolean flag for this behavior
|
||||||
lineParseAmount = flag.Int("n", 1, "amount of lines to feed into input pattern")
|
lineParseAmount = flag.Int("n", 1, "amount of lines to feed into input pattern")
|
||||||
|
|
||||||
replacePattern = regexp.MustCompile(`\{(\d+)(?::(.*?))?(?::(.*?))?\}`)
|
replacePattern = regexp.MustCompile(`\{(\d+)(?::(.*?))?(?::(.*?))?(?::(.*?))?\}`)
|
||||||
|
|
||||||
numMutationPattern = regexp.MustCompile(`([+\-*/])(\d+|\((\d+)\))`)
|
numMutationPattern = regexp.MustCompile(`([+\-*/])(\d+|\((\d+)\))`)
|
||||||
)
|
)
|
||||||
@ -123,7 +122,8 @@ func replaceVars(format string, vars ...string) string {
|
|||||||
for _, replacement := range replacements {
|
for _, replacement := range replacements {
|
||||||
rplStr := replacement[0]
|
rplStr := replacement[0]
|
||||||
varIndex, _ := strconv.Atoi(replacement[1])
|
varIndex, _ := strconv.Atoi(replacement[1])
|
||||||
rplFmt := replacement[2]
|
rplColor := makeColor(replacement[2])
|
||||||
|
rplFmt := replacement[3]
|
||||||
|
|
||||||
// default format if not specified by user
|
// default format if not specified by user
|
||||||
if rplFmt == "" {
|
if rplFmt == "" {
|
||||||
@ -132,106 +132,16 @@ func replaceVars(format string, vars ...string) string {
|
|||||||
|
|
||||||
if strings.HasSuffix(rplFmt, "d") { // replace integers
|
if strings.HasSuffix(rplFmt, "d") { // replace integers
|
||||||
value, _ := strconv.ParseInt(vars[varIndex], 10, 64)
|
value, _ := strconv.ParseInt(vars[varIndex], 10, 64)
|
||||||
mutate := numMut2func[int64](replacement[3])
|
mutate := numMut2func[int64](replacement[4])
|
||||||
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, mutate(value, vars)), 1)
|
format = strings.Replace(format, rplStr, rplColor.Sprintf(rplFmt, mutate(value, vars)), 1)
|
||||||
} else if strings.HasSuffix(rplFmt, "f") || strings.HasSuffix(rplFmt, "g") { // replace floats
|
} else if strings.HasSuffix(rplFmt, "f") || strings.HasSuffix(rplFmt, "g") { // replace floats
|
||||||
value, _ := strconv.ParseFloat(vars[varIndex], 64)
|
value, _ := strconv.ParseFloat(vars[varIndex], 64)
|
||||||
mutate := numMut2func[float64](replacement[3])
|
mutate := numMut2func[float64](replacement[4])
|
||||||
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, mutate(value, vars)), 1)
|
format = strings.Replace(format, rplStr, rplColor.Sprintf(rplFmt, mutate(value, vars)), 1)
|
||||||
} else { // replace strings
|
} else { // replace strings
|
||||||
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, vars[varIndex]), 1)
|
format = strings.Replace(format, rplStr, rplColor.Sprintf(rplFmt, vars[varIndex]), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return format
|
return format
|
||||||
}
|
}
|
||||||
|
|
||||||
var numMutatorCache = map[string]interface{}{}
|
|
||||||
|
|
||||||
func numMut2func[T int64 | float64](mutation string) (f func(value T, vars []string) T) {
|
|
||||||
if mutation == "" {
|
|
||||||
return func(value T, vars []string) T { return value }
|
|
||||||
}
|
|
||||||
|
|
||||||
// caching
|
|
||||||
if v, ok := numMutatorCache[mutation]; ok {
|
|
||||||
return v.(func(value T, vars []string) T)
|
|
||||||
}
|
|
||||||
defer func() { numMutatorCache[mutation] = f }()
|
|
||||||
|
|
||||||
matches := numMutationPattern.FindAllStringSubmatch(mutation, -1)
|
|
||||||
mutators := make([]NumMutator, 0, len(matches))
|
|
||||||
var err error
|
|
||||||
for _, match := range matches {
|
|
||||||
mut := NumMutator{Op: NewNumOperatorFromString(match[1])}
|
|
||||||
if match[3] == "" {
|
|
||||||
mut.Value, err = strconv.Atoi(match[2])
|
|
||||||
mut.Var = false
|
|
||||||
if err != nil {
|
|
||||||
panic("invalid number in number mutator: " + match[2])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mut.Var = true
|
|
||||||
mut.Value, err = strconv.Atoi(match[3])
|
|
||||||
if err != nil {
|
|
||||||
panic("invalid back reference group in number mutator: " + match[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutators = append(mutators, mut)
|
|
||||||
}
|
|
||||||
|
|
||||||
numberParser := number_parser[T]()
|
|
||||||
|
|
||||||
return func(value T, vars []string) T {
|
|
||||||
for _, mutator := range mutators {
|
|
||||||
var otherValue T
|
|
||||||
if mutator.Var {
|
|
||||||
other := numberParser(vars[mutator.Value])
|
|
||||||
otherValue = T(other)
|
|
||||||
} else {
|
|
||||||
otherValue = T(mutator.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch mutator.Op {
|
|
||||||
case NumOperatorAdd:
|
|
||||||
value += otherValue
|
|
||||||
case NumOperatorSub:
|
|
||||||
value -= otherValue
|
|
||||||
case NumOperatorMul:
|
|
||||||
value *= otherValue
|
|
||||||
case NumOperatorDiv:
|
|
||||||
value /= otherValue
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func number_parser[T int64 | float64]() func(str string) T {
|
|
||||||
typeOfT := reflect.TypeOf(new(T)).Elem()
|
|
||||||
typeOfInt64 := reflect.TypeOf(new(int64)).Elem()
|
|
||||||
typeOfFloat64 := reflect.TypeOf(new(float64)).Elem()
|
|
||||||
|
|
||||||
if typeOfT == typeOfInt64 {
|
|
||||||
return func(str string) T {
|
|
||||||
num, err := strconv.Atoi(str)
|
|
||||||
if err != nil {
|
|
||||||
panic("expected integer but found " + str)
|
|
||||||
}
|
|
||||||
return T(num)
|
|
||||||
}
|
|
||||||
} else if typeOfT == typeOfFloat64 {
|
|
||||||
return func(str string) T {
|
|
||||||
num, err := strconv.ParseFloat(str, 64)
|
|
||||||
if err != nil {
|
|
||||||
panic("expected float but found " + str)
|
|
||||||
}
|
|
||||||
return T(num)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
panic("invalid number type")
|
|
||||||
}
|
|
||||||
|
94
mutator.go
94
mutator.go
@ -1,5 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
type NumMutator struct {
|
type NumMutator struct {
|
||||||
Op NumOperator
|
Op NumOperator
|
||||||
Var bool
|
Var bool
|
||||||
@ -29,3 +34,92 @@ func NewNumOperatorFromString(str string) NumOperator {
|
|||||||
panic("invalid number operator: " + str)
|
panic("invalid number operator: " + str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var numMutatorCache = map[string]interface{}{}
|
||||||
|
|
||||||
|
func numMut2func[T int64 | float64](mutation string) (f func(value T, vars []string) T) {
|
||||||
|
if mutation == "" {
|
||||||
|
return func(value T, vars []string) T { return value }
|
||||||
|
}
|
||||||
|
|
||||||
|
// caching
|
||||||
|
if v, ok := numMutatorCache[mutation]; ok {
|
||||||
|
return v.(func(value T, vars []string) T)
|
||||||
|
}
|
||||||
|
defer func() { numMutatorCache[mutation] = f }()
|
||||||
|
|
||||||
|
matches := numMutationPattern.FindAllStringSubmatch(mutation, -1)
|
||||||
|
mutators := make([]NumMutator, 0, len(matches))
|
||||||
|
var err error
|
||||||
|
for _, match := range matches {
|
||||||
|
mut := NumMutator{Op: NewNumOperatorFromString(match[1])}
|
||||||
|
if match[3] == "" {
|
||||||
|
mut.Value, err = strconv.Atoi(match[2])
|
||||||
|
mut.Var = false
|
||||||
|
if err != nil {
|
||||||
|
panic("invalid number in number mutator: " + match[2])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mut.Var = true
|
||||||
|
mut.Value, err = strconv.Atoi(match[3])
|
||||||
|
if err != nil {
|
||||||
|
panic("invalid back reference group in number mutator: " + match[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutators = append(mutators, mut)
|
||||||
|
}
|
||||||
|
|
||||||
|
numberParser := number_parser[T]()
|
||||||
|
|
||||||
|
return func(value T, vars []string) T {
|
||||||
|
for _, mutator := range mutators {
|
||||||
|
var otherValue T
|
||||||
|
if mutator.Var {
|
||||||
|
other := numberParser(vars[mutator.Value])
|
||||||
|
otherValue = T(other)
|
||||||
|
} else {
|
||||||
|
otherValue = T(mutator.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch mutator.Op {
|
||||||
|
case NumOperatorAdd:
|
||||||
|
value += otherValue
|
||||||
|
case NumOperatorSub:
|
||||||
|
value -= otherValue
|
||||||
|
case NumOperatorMul:
|
||||||
|
value *= otherValue
|
||||||
|
case NumOperatorDiv:
|
||||||
|
value /= otherValue
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func number_parser[T int64 | float64]() func(str string) T {
|
||||||
|
typeOfT := reflect.TypeOf(new(T)).Elem()
|
||||||
|
typeOfInt64 := reflect.TypeOf(new(int64)).Elem()
|
||||||
|
typeOfFloat64 := reflect.TypeOf(new(float64)).Elem()
|
||||||
|
|
||||||
|
if typeOfT == typeOfInt64 {
|
||||||
|
return func(str string) T {
|
||||||
|
num, err := strconv.Atoi(str)
|
||||||
|
if err != nil {
|
||||||
|
panic("expected integer but found " + str)
|
||||||
|
}
|
||||||
|
return T(num)
|
||||||
|
}
|
||||||
|
} else if typeOfT == typeOfFloat64 {
|
||||||
|
return func(str string) T {
|
||||||
|
num, err := strconv.ParseFloat(str, 64)
|
||||||
|
if err != nil {
|
||||||
|
panic("expected float but found " + str)
|
||||||
|
}
|
||||||
|
return T(num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("invalid number type")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user