-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathsearch.d
More file actions
139 lines (127 loc) · 4.18 KB
/
Copy pathsearch.d
File metadata and controls
139 lines (127 loc) · 4.18 KB
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
132
133
134
135
136
137
138
139
import iopipe.textpipe;
import iopipe.bufpipe;
import iopipe.valve;
import iopipe.refc;
import std.format;
import std.io;
auto stdout()
{
return File(1).refCounted;
}
// returns number of matches found
size_t performSearch(UTFType utfType, Dev)(Dev dev, size_t contextLines, string[] terms)
{
// repeat the input to the output. Don't transcode
alias Char = CodeUnit!utfType;
auto output = bufd!Char.push!(a => a
.encodeText!(utfType)
.outputPipe(stdout));
// output range that doesn't auto-decode
void writeOutput(const(Char)[] data)
{
if(data.length) // yes, put sometimes sends in 0 elements.
{
output.ensureElems(data.length);
output.window[0 .. data.length] = data;
output.release(data.length);
}
}
// keep N lines in context before the current line. Add one element for a
// sentinel (will always be 0)
size_t[] lineEnds = new size_t[contextLines + 1];
//size_t lineNum = 0;
size_t toPrint = 0;
size_t matches = 0;
bool printElipses = false;
auto linepipe = dev.assumeText!utfType.byLine;
while(true)
{
import std.algorithm.searching : canFind, any;
// every time we hit a match, we are going to print all the lines of
// context before, and then print all the lines of context after.
auto lstart = linepipe.window.length;
if(linepipe.extend() == 0)
break; // we are done
//++lineNum;
auto lineNum = linepipe.segments;
// check to see if we found any search terms in here
auto curLine = linepipe.window[lstart .. $];
if(terms.any!(a => curLine.canFind(a)))
{
++matches;
if(printElipses)
{
writeOutput("...\n");
printElipses = false;
}
foreach_reverse(i; 1 .. lineEnds.length)
{
if(lineEnds[i] != lineEnds[i-1])
{
formattedWrite(&writeOutput, cast(immutable(Char)[])"%s : %s", lineNum - i, linepipe.window[lineEnds[i] .. lineEnds[i - 1]]);
}
}
// print the matched line
formattedWrite(&writeOutput,cast(immutable(Char)[])"%s*: %s", lineNum, curLine);
toPrint = contextLines;
// release all data that we printed
lineEnds[] = 0;
linepipe.release(linepipe.window.length);
}
else if(toPrint > 0)
{
// keep printing lines
formattedWrite(&writeOutput, cast(immutable(Char)[])"%s : %s", lineNum, linepipe.window);
--toPrint;
// this line has been printed, so don't save it in the buffer.
linepipe.release(linepipe.window.length);
}
else if(contextLines == 0)
{
// we don't ever print context lines.
linepipe.release(linepipe.window.length);
printElipses = true;
}
else
{
// store the line ending information, but don't print anything
auto toRelease = lineEnds[$-2];
if(toRelease > 0)
{
linepipe.release(toRelease);
printElipses = true;
}
foreach_reverse(i; 1 .. lineEnds.length-1)
lineEnds[i] = lineEnds[i-1] - toRelease;
lineEnds[0] = linepipe.window.length;
}
}
return matches;
}
int main(string[] args)
{
import std.getopt;
import std.stdio : writefln, writeln, stderr;
size_t contextLines = 2;
bool useRing;
auto helpInfo = args.getopt("context", &contextLines, "ring", &useRing);
if(helpInfo.helpWanted)
{
defaultGetoptPrinter("usage", helpInfo.options);
return 1;
}
args = args[1 .. $];
if(args.length == 0)
{
stderr.writeln("Need search parameters");
return 1;
}
size_t result;
auto stdin = File(0).refCounted;
if(useRing)
result = stdin.rbufd.runWithEncoding!performSearch(contextLines, args);
else
result = stdin.bufd.runWithEncoding!performSearch(contextLines, args);
writefln("matched %s lines", result);
return 0;
}