-
Notifications
You must be signed in to change notification settings - Fork 141
/
line_grep.go
112 lines (101 loc) · 2.66 KB
/
line_grep.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
package the_platinum_searcher
import (
"bufio"
"io"
"os"
)
type lineGrep struct {
printer printer
before int
after int
column bool
}
func newLineGrep(printer printer, opts Option) lineGrep {
return lineGrep{
printer: printer,
before: opts.OutputOption.Before,
after: opts.OutputOption.After,
column: opts.OutputOption.Column,
}
}
func (g lineGrep) enableContext() bool {
return g.before > 0 || g.after > 0
}
type matchFunc func(b []byte) bool
type countFunc func(b []byte) int
func (g lineGrep) grepEachLines(f *os.File, encoding int, matchFn matchFunc, countFn countFunc) {
f.Seek(0, 0)
match := match{path: f.Name()}
var reader io.Reader
if r := newDecodeReader(f, encoding); r != nil {
// decode file from shift-jis or euc-jp.
reader = r
} else {
reader = f
}
lineNum := 1
matchState := newMatchState()
afterCount := 0
beforeMatches := make([]line, 0, g.before)
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
if matched := matchFn(scanner.Bytes()); matched || g.enableContext() {
if g.enableContext() {
// print match and context lines.
matchState = matchState.transition(matched)
if matchState.isBefore() {
// store before line.
beforeMatches = g.storeBeforeMatch(beforeMatches, lineNum, scanner.Text(), matched)
} else if matchState.isAfter() {
if g.after > 0 {
// append after line.
match.add(lineNum, 0, scanner.Text(), matched)
afterCount++
} else if g.before > 0 && g.after == 0 {
beforeMatches = g.storeBeforeMatch(beforeMatches, lineNum, scanner.Text(), matched)
}
if afterCount >= g.after {
// reset to before match
matchState = matchState.reset()
afterCount = 0
}
} else if matchState.isMatching() {
// append and reset before lines.
match.lines = append(match.lines, beforeMatches...)
beforeMatches = make([]line, 0, g.before)
// append match line.
column := 0
if g.column {
column = countFn(scanner.Bytes())
}
match.add(lineNum, column, scanner.Text(), matched)
// reset after count.
afterCount = 0
}
} else if matched {
// print only match line.
column := 0
if g.column {
column = countFn(scanner.Bytes())
}
match.add(lineNum, column, scanner.Text(), matched)
}
}
lineNum++
}
g.printer.print(match)
}
func (g lineGrep) storeBeforeMatch(beforeMatches []line, lineNum int, text string, matched bool) []line {
if g.before == 0 {
return beforeMatches
}
if len(beforeMatches) >= g.before {
beforeMatches = beforeMatches[1:]
}
return append(beforeMatches, line{
num: lineNum,
column: 0,
text: text,
matched: matched,
})
}