Commit 4532db9b authored by Miles Whittaker's avatar Miles Whittaker Committed by Miles Whittaker
Browse files

Started golang port of ruby hilighter gem

parents
hl
tags
!cmd/hl
This diff is collapsed.
GITLAB = hl "gitlab.com/mjwhitta/hilighter"
LOCAL = hl "hilighter"
all: build unlocal
build: local fmt
@go build ./cmd/hl
clean: unlocal fmt
@rm -f hl
clena: clean
fmt:
@go fmt . ./cmd/hl
gen:
@./scripts/generate_go_funcs
local:
@find cmd -type f -exec sed -i 's#$(GITLAB)#$(LOCAL)#' {} +
@rm -f go.mod go.sum
unlocal:
@find cmd -type f -exec sed -i 's#$(LOCAL)#$(GITLAB)#' {} +
@git checkout go.mod go.sum
# Hilighter
## What is this?
This go package provides color methods for strings. It also provides a
method for wrapping strings that accounts for color escape codes.
## How to install
```
$ go get -u gitlab.com/mjwhitta/hilighter/cmd/hl
```
## Usage
In a terminal you can do things like the following:
```
$ cat some_file | hl green on_blue
$ cat some_file | hl rainbow on_white dim
$ cat some_file | hl rainbow on_rainbow
$ hl rainbow on_rainbow <some_file
$ echo "Hex color codes!" | hl ffffff on_ff0000
$ cat some_file | hl wrap
$ cat some_file | hl wrap_64
```
In golang you can do things like the following:
```
package main
import (
"fmt"
hl "gitlab.com/mjwhitta/hilighter"
)
func main() {
// Example 1 (single color)
var greenStr = hl.Green("1. Hello, %s!\n", "world")
fmt.Print(greenStr)
// or
hl.PrintGreen("1. Hello, %s!\n", "world")
// or
hl.PrintlnGreen("1. Hello, world!")
// Example 2 (multiple colors)
var multiColored = hl.Hilights(
[]string{"white", "on_green"},
"2. Hello, %s!\n",
"world",
)
fmt.Print(multiColored)
// or
multiColored = hl.Hilights(
[]string{"white", "on_green"},
"2. Hello, world!",
)
fmt.Println(multiColored)
// or
hl.PrintHilights(
[]string{"white", "on_green"},
"2. Hello, %s!\n",
"world",
)
// or
hl.PrintlnHilights(
[]string{"white", "on_green"},
"2. Hello, world!",
)
// Example 3 (8-bit)
var eightBit = hl.Color002("3. 8-bit color codes!")
fmt.Println(eightBit)
// or
hl.PrintlnColor002("3. 8-bit color codes!")
// Example 4 (text wrapping)
var long_var = "4."
var word = "hilight"
for i := 0; i < 32; i++ {
long_var += " " + word
}
var wrapped = hl.Wrap(80, hl.Hilight("green", long_var))
fmt.Println(wrapped)
// or
hl.PrintWrap(80, hl.Green("%s\n", long_var))
// or
hl.PrintlnWrap(80, hl.Green(long_var))
}
```
The following colors are supported:
Foreground | Background
---------- | ----------
black | on_black
red | on_red
green | on_green
yellow | on_yellow
blue | on_blue
magenta | on_magenta
cyan | on_cyan
white | on_white
light_black | on_light_black
light_red | on_light_red
light_green | on_light_green
light_yellow | on_light_yellow
light_blue | on_light_blue
light_magenta | on_light_magenta
light_cyan | on_light_cyan
light_white | on_light_white
default | on_default
color000 to color255 | on_color000 to on_color255
000000 to ffffff | on_000000 to on_ffffff
The following modes are supported:
On | Off | Description
--- | --- | -----------
normal | | Same as default
reset | | Same as default
bold | no_bold | Turn on/off bold
dim | no_dim | Turn on/off dim. Not widely supported
faint | no_faint | Same as dim
italic | no_italic | Turn on/off italics. Sometimes treated as inverse. Not widely supported.
underline | no_underline | Turn on/off underline
blink | no_blink | Turn on/off blink. Less than 150/min.
blink_slow | no_blink_slow | Same as blink
blink_rapid | no_blink_rapid | Same as blink. 150+/min. Not widely supported.
inverse | no_inverse | Reverse foreground/background
negative | no_negative | Same as inverse
swap | no_swap | Same as inverse
conceal | no_conceal | Turn on/off conceal. Useful for passwords. Not widely supported.
hide | no_hide | Same as conceal
crossed_out | no_crossed_out | Characters legible, but marked for deletion. Not widely supported.
strikethrough | no_strikethrough | Same as CrossedOut
[fraktur] | no_fraktur | Hardly ever supported
[fraktur]: https://en.wikipedia.org/wiki/Fraktur
## Links
- [Source](https://gitlab.com/mjwhitta/hilighter)
- [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code)
## TODO
- Better README
This diff is collapsed.
// This file is autogenerated. Do not modify directly.
package hilighter
func Reset(str string, args ...interface{}) string {
return modify("reset", str, args...)
}
func Normal(str string, args ...interface{}) string {
return modify("normal", str, args...)
}
func Bold(str string, args ...interface{}) string {
return modify("bold", str, args...)
}
func NoBold(str string, args ...interface{}) string {
return modify("no_bold", str, args...)
}
func Dim(str string, args ...interface{}) string {
return modify("dim", str, args...)
}
func NoDim(str string, args ...interface{}) string {
return modify("no_dim", str, args...)
}
func Faint(str string, args ...interface{}) string {
return modify("faint", str, args...)
}
func NoFaint(str string, args ...interface{}) string {
return modify("no_faint", str, args...)
}
func Italic(str string, args ...interface{}) string {
return modify("italic", str, args...)
}
func NoItalic(str string, args ...interface{}) string {
return modify("no_italic", str, args...)
}
func Underline(str string, args ...interface{}) string {
return modify("underline", str, args...)
}
func NoUnderline(str string, args ...interface{}) string {
return modify("no_underline", str, args...)
}
func Blink(str string, args ...interface{}) string {
return modify("blink", str, args...)
}
func NoBlink(str string, args ...interface{}) string {
return modify("no_blink", str, args...)
}
func BlinkSlow(str string, args ...interface{}) string {
return modify("blink_slow", str, args...)
}
func NoBlinkSlow(str string, args ...interface{}) string {
return modify("no_blink_slow", str, args...)
}
func BlinkRapid(str string, args ...interface{}) string {
return modify("blink_rapid", str, args...)
}
func NoBlinkRapid(str string, args ...interface{}) string {
return modify("no_blink_rapid", str, args...)
}
func Inverse(str string, args ...interface{}) string {
return modify("inverse", str, args...)
}
func NoInverse(str string, args ...interface{}) string {
return modify("no_inverse", str, args...)
}
func Negative(str string, args ...interface{}) string {
return modify("negative", str, args...)
}
func NoNegative(str string, args ...interface{}) string {
return modify("no_negative", str, args...)
}
func Swap(str string, args ...interface{}) string {
return modify("swap", str, args...)
}
func NoSwap(str string, args ...interface{}) string {
return modify("no_swap", str, args...)
}
func Hide(str string, args ...interface{}) string {
return modify("hide", str, args...)
}
func NoHide(str string, args ...interface{}) string {
return modify("no_hide", str, args...)
}
func Conceal(str string, args ...interface{}) string {
return modify("conceal", str, args...)
}
func NoConceal(str string, args ...interface{}) string {
return modify("no_conceal", str, args...)
}
func CrossedOut(str string, args ...interface{}) string {
return modify("crossed_out", str, args...)
}
func NoCrossedOut(str string, args ...interface{}) string {
return modify("no_crossed_out", str, args...)
}
func Strikethrough(str string, args ...interface{}) string {
return modify("strikethrough", str, args...)
}
func NoStrikethrough(str string, args ...interface{}) string {
return modify("no_strikethrough", str, args...)
}
func Fraktur(str string, args ...interface{}) string {
return modify("fraktur", str, args...)
}
func NoFraktur(str string, args ...interface{}) string {
return modify("no_fraktur", str, args...)
}
package main
import (
"bufio"
"fmt"
"os"
"strings"
"gitlab.com/mjwhitta/cli"
hl "gitlab.com/mjwhitta/hilighter"
)
// Helpers begin
func err(msg string) { fmt.Println(hl.Red("[!] %s", msg)) }
func errx(status int, msg string) {
err(msg)
os.Exit(status)
}
func good(msg string) { fmt.Println(hl.Green("[+] %s", msg)) }
func info(msg string) { fmt.Println(hl.White("[*] %s", msg)) }
func subinfo(msg string) { fmt.Println(hl.Cyan("[=] %s", msg)) }
func warn(msg string) { fmt.Println(hl.Yellow("[-] %s", msg)) }
// Helpers end
var nocolor bool
var sample bool
var table bool
var version bool
func init() {
// Configure cli package
cli.Align = true
cli.Authors = []string{"Miles Whittaker <mj@whitta.dev>"}
cli.Banner = fmt.Sprintf(
"%s [OPTIONS] [color1]... [colorN]",
os.Args[0],
)
cli.BugEmail = "hilighter.bugs@whitta.dev"
cli.ExitStatus = strings.Join(
[]string{
"Normally the exit status is 0. In the event of invalid",
"or missing arguments, the exit status will be non-zero.",
},
" ",
)
cli.Info = strings.Join(
[]string{
"Hilights the text from stdin using the methods passed",
"on the CLI.",
},
" ",
)
cli.Title = "Hilighter"
// Parse cli flags
cli.Flag(&nocolor, "no-color", false, "Disable colorized output.")
cli.Flag(
&sample,
"s",
"sample",
false,
"Show sample foreground/background colors.",
)
cli.Flag(&table, "t", "table", false, "Show the color table.")
cli.Flag(&version, "V", "version", false, "Show version.")
cli.Parse()
// Validate cli flags
if (!sample && !table && !version && (cli.NArg() == 0)) ||
((sample || table || version) && (cli.NArg() != 0)) {
cli.Usage(1)
}
}
func main() {
hl.Disable = nocolor
defer func() {
if r := recover(); r != nil {
err(r.(error).Error())
}
}()
if sample {
hl.Sample()
} else if table {
hl.Table()
} else if version {
fmt.Printf("Version: %s\n", hl.Version)
} else {
var line string
var scanner = bufio.NewScanner(os.Stdin)
// Read line by line
for scanner.Scan() {
line = scanner.Text()
// Apply all specified color codes
for i := range cli.Args() {
line = hl.Hilight(cli.Arg(i), line)
}
// Print the result
fmt.Println(line)
}
if scanner.Err() != nil {
errx(1, scanner.Err().Error())
}
}
}
package hilighter
import "fmt"
var Colors = map[string]string{
"black": "30",
"red": "31",
"green": "32",
"yellow": "33",
"blue": "34",
"magenta": "35",
"cyan": "36",
"white": "37",
"light_black": "90",
"light_red": "91",
"light_green": "92",
"light_yellow": "93",
"light_blue": "94",
"light_magenta": "95",
"light_cyan": "96",
"light_white": "97",
"on_black": "40",
"on_red": "41",
"on_green": "42",
"on_yellow": "43",
"on_blue": "44",
"on_magenta": "45",
"on_cyan": "46",
"on_white": "47",
"on_light_black": "100",
"on_light_red": "101",
"on_light_green": "102",
"on_light_yellow": "103",
"on_light_blue": "104",
"on_light_magenta": "105",
"on_light_cyan": "106",
"on_light_white": "107",
"default": "39",
"on_default": "49",
}
var Modes = map[string]string{
"reset": "0",
"normal": "0",
"bold": "1",
"dim": "2",
"faint": "2",
"italic": "3",
"underline": "4",
"blink": "5",
"blink_slow": "5",
"blink_rapid": "6",
"inverse": "7",
"negative": "7",
"swap": "7",
"hide": "8",
"conceal": "8",
"crossed_out": "9",
"strikethrough": "9",
"fraktur": "20",
"no_bold": "21",
"no_dim": "22",
"no_faint": "22",
"no_italic": "23",
"no_fraktur": "23",
"no_underline": "24",
"no_blink": "25",
"no_blink_slow": "25",
"no_blink_rapid": "26",
"no_inverse": "27",
"no_negative": "27",
"no_swap": "27",
"no_hide": "28",
"no_conceal": "28",
"no_crossed_out": "29",
"no_strikethrough": "29",
}
func init() {
// Add all 8-bit colors, fg and bg
for i := 0; i < 256; i++ {
var key = fmt.Sprintf("color_%03d", i)
var val = fmt.Sprintf("38;5;%03d", i)
Colors[key] = val
key = fmt.Sprintf("on_color_%03d", i)
val = fmt.Sprintf("48;5;%03d", i)
Colors[key] = val
}
}
package hilighter
import (
"fmt"
"strings"
)
func bgColor(code string, str string, args ...interface{}) string {
// Strip all other bg color codes and don't extend bg color over
// newlines
str = newline.ReplaceAllString(
plainBg(str, args...),
"\x1b["+Colors["on_default"]+"m\n\x1b["+Colors[code]+"m",
)
// Wrap whole thing with specified color code
var colorized = "\x1b[" + Colors[code] + "m" + str +
"\x1b[" + Colors["on_default"] + "m"
// Remove color codes, if the line only contains color codes
colorized = onlyCodes.ReplaceAllString(colorized, "")
return colorized
}
func colorize(clr string, str string, args ...interface{}) string {
if Disable {
// Return the string w/o any color codes
return Plain(str, args...)
}
// Call the appropriate function
if strings.HasPrefix(clr, "on_") {
return bgColor(clr, str, args...)
} else {
return fgColor(clr, str, args...)
}
}
func fgColor(code string, str string, args ...interface{}) string {
// Strip all other fg color codes and don't extend fg color over
// newlines
str = newline.ReplaceAllString(
plainFg(str, args...),
"\x1b["+Colors["default"]+"m\n\x1b["+Colors[code]+"m",
)
// Wrap whole thing with specified color code
var colorized = "\x1b[" + Colors[code] + "m" + str +
"\x1b[" + Colors["default"] + "m"
// Remove color codes, if the line only contains color codes
colorized = onlyCodes.ReplaceAllString(colorized, "")
return colorized
}
func OnRainbow(str string, args ...interface{}) string {
if Disable {
// Return the string w/o any color codes
return Plain(str, args...)
}
// Strip all other bg color codes and split on newline
var lines = strings.Split(plainBg(str, args...), "\n")
var out []string
// Loop thru lines and apply bg color codes
for i := range lines {
var matches = iterate.FindAllString(lines[i], -1)
for idx, char := range matches {
// TODO rainbow
fmt.Printf("%d -> %s\x1b[0m\n", idx, char)
}
// FIXME remove
out = append(out, lines[i])
}