forked from jthebault/hound
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ack.go
114 lines (92 loc) · 2.14 KB
/
ack.go
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
package client
import (
"ansi"
"bytes"
"fmt"
"hound/config"
"os"
"regexp"
)
type ackPresenter struct {
f *os.File
}
func hiliteMatches(c *ansi.Colorer, p *regexp.Regexp, line string) string {
// find the indexes for all matches
idxs := p.FindAllStringIndex(line, -1)
var buf bytes.Buffer
beg := 0
for _, idx := range idxs {
// for each match add the contents before the match ...
buf.WriteString(line[beg:idx[0]])
// and the highlighted version of the match
buf.WriteString(c.FgBg(line[idx[0]:idx[1]],
ansi.Black,
ansi.Bold,
ansi.Yellow,
ansi.Intense))
beg = idx[1]
}
buf.WriteString(line[beg:])
return buf.String()
}
func lineNumber(c *ansi.Colorer, buf *bytes.Buffer, n int, hasMatch bool) string {
defer buf.Reset()
s := fmt.Sprintf("%d", n)
buf.WriteString(c.Fg(s, ansi.Yellow, ansi.Bold))
if hasMatch {
buf.WriteByte(':')
} else {
buf.WriteByte('-')
}
for i := len(s); i < 6; i++ {
buf.WriteByte(' ')
}
return buf.String()
}
func (p *ackPresenter) Present(
re *regexp.Regexp,
ctx int,
repos map[string]*config.Repo,
res *Response) error {
c := ansi.NewFor(p.f)
buf := bytes.NewBuffer(make([]byte, 0, 20))
for repo, resp := range res.Results {
if _, err := fmt.Fprintf(p.f, "%s\n",
c.Fg(repoNameFor(repos, repo), ansi.Red, ansi.Bold)); err != nil {
return err
}
for _, file := range resp.Matches {
if _, err := fmt.Fprintf(p.f, "%s\n",
c.Fg(file.Filename, ansi.Green, ansi.Bold)); err != nil {
return err
}
blocks := coalesceMatches(file.Matches)
for _, block := range blocks {
for i, n := 0, len(block.Lines); i < n; i++ {
line := block.Lines[i]
hasMatch := block.Matches[i]
if hasMatch {
line = hiliteMatches(c, re, line)
}
if _, err := fmt.Fprintf(p.f, "%s%s\n",
lineNumber(c, buf, block.Start+i, hasMatch),
line); err != nil {
return err
}
}
if ctx > 0 {
if _, err := fmt.Fprintln(p.f, "--"); err != nil {
return err
}
}
}
if _, err := fmt.Fprintln(p.f); err != nil {
return err
}
}
}
return nil
}
func NewAckPresenter(w *os.File) Presenter {
return &ackPresenter{w}
}