1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
package main
import (
"bufio"
"flag"
"fmt"
"os"
"regexp"
"strings"
)
func init() {
highlightColor = red
flag.Var((*colorFlag)(&highlightColor), "c", fmt.Sprintf("highlight `color` %s", colorsChoices))
background = defaultColor
flag.Var((*colorFlag)(&background), "bg", fmt.Sprintf("background `color` default|%s", colorsChoices))
}
var (
highlightColor ansiColor
background ansiColor
)
//go:generate stringer -type=ansiColor -linecomment
type ansiColor int
const (
black ansiColor = iota
red
green
yellow
blue
magenta
cyan
white
defaultColor ansiColor = 9 // default
)
var colorsChoices = func() string {
nColors := white - black + 1
colors := make([]string, nColors)
for i := range nColors {
colors[i] = (black + i).String()
}
return strings.Join(colors, "|")
}()
func (c ansiColor) Foreground() int {
return 30 + int(c)
}
func (c ansiColor) Background() int {
return 40 + int(c)
}
type colorFlag int
func (c *colorFlag) Set(val string) error {
var ac ansiColor
switch strings.ToLower(val) {
case "default":
ac = defaultColor
case "black":
ac = black
case "red":
ac = red
case "green":
ac = green
case "yellow":
ac = yellow
case "blue":
ac = blue
case "magenta":
ac = magenta
case "cyan":
ac = cyan
case "white":
ac = white
default:
return fmt.Errorf("unknown color %q (valid choices: %s)", val, colorsChoices)
}
*c = colorFlag(ac)
return nil
}
func (c *colorFlag) String() string {
return ansiColor(*c).String()
}
func run() error {
args := flag.Args()
if len(args) == 0 {
fmt.Fprintf(os.Stderr, "missing regexp to highlight\n")
flag.Usage()
}
if len(args) > 2 {
fmt.Fprintf(os.Stderr, "too many positional arguments\n")
flag.Usage()
}
highlightRE, err := regexp.CompilePOSIX(args[0])
if err != nil {
return fmt.Errorf("invalid highlight regexp: %s", err)
}
foregroundColor := highlightColor.Foreground()
backgroundColor := background.Background()
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
loc := highlightRE.FindStringIndex(line)
if loc == nil {
fmt.Printf("%s\n", line)
continue
}
startIdx, endIdx := loc[0], loc[1]
fmt.Printf("%s\033[%d;%dm%s\033[39;49m%s\n", line[:startIdx], foregroundColor, backgroundColor, line[startIdx:endIdx], line[endIdx:])
}
return scanner.Err()
}
func main() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: hi [OPTIONS] REGEXP\n")
flag.PrintDefaults()
os.Exit(2)
}
flag.Parse()
if err := run(); err != nil {
fmt.Fprintf(os.Stderr, "hi: %s\n", err)
os.Exit(1)
}
}
|