glark 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,266 @@
1
+ #!/usr/bin/ruby -w
2
+ #!ruby -w
3
+ # vim: set filetype=ruby : set sw=2
4
+
5
+ # Glark output.
6
+
7
+ require 'English'
8
+
9
+ require 'rubygems'
10
+ require 'riel'
11
+
12
+ require 'glark/options'
13
+ require 'glark/input'
14
+
15
+ class Results
16
+ include Loggable
17
+
18
+ end
19
+
20
+ class OutputFormat < Results
21
+
22
+ attr_reader :formatted, :infile, :show_file_name, :has_context
23
+
24
+ def initialize(infile, show_file_names)
25
+ @infile = infile
26
+ @show_file_name = show_file_names
27
+ @formatted = []
28
+ @has_context = false
29
+
30
+ opts = GlarkOptions.instance
31
+
32
+ @label = opts.label
33
+ @out = opts.out
34
+ @show_break = opts.show_break
35
+ @show_line_numbers = opts.show_line_numbers
36
+ end
37
+
38
+ # Prints the line, which is assumed to be 0-indexed, and is thus adjusted by
39
+ # one.
40
+ def print_line_number(lnum)
41
+ @out.printf "%5d ", lnum + 1
42
+ end
43
+
44
+ # prints the line, and adjusts for the fact that in our world, lines are
45
+ # 0-indexed, whereas they are displayed as if 1-indexed.
46
+ def print_line(lnum, ch = nil)
47
+ log { "lnum #{lnum}, ch: '#{ch}'" }
48
+ begin
49
+ lnums = @infile.get_range(lnum)
50
+ log { "lnums(#{lnum}): #{lnums}" }
51
+ if lnums
52
+ lnums.each do |ln|
53
+ if show_line_numbers
54
+ print_line_number(ln)
55
+ if ch && has_context
56
+ @out.printf "%s ", ch
57
+ end
58
+ end
59
+ line = @formatted[ln] || @infile.get_line(ln)
60
+ @out.puts line
61
+ end
62
+ end
63
+ rescue => e
64
+ # puts e
65
+ # puts e.backtrace
66
+ end
67
+ end
68
+
69
+ def write_matches(matching, from, to)
70
+ if @infile.count
71
+ write_count(matching)
72
+ elsif matching
73
+ firstline = from ? from : 0
74
+ lastline = to ? to : @infile.get_lines.length - 1
75
+
76
+ (firstline .. lastline).each do |ln|
77
+ if @infile.stati[ln]
78
+ unless @infile.stati[ln] == InputFile::WRITTEN
79
+ if firstline > 0 && !@infile.stati[ln - 1] && has_context && @show_break
80
+ @out.puts " ---"
81
+ end
82
+
83
+ print_line(ln, @infile.stati[ln])
84
+
85
+ @infile.stati[ln] = InputFile::WRITTEN
86
+ end
87
+ end
88
+
89
+ end
90
+ else
91
+ firstline = from ? from : 0
92
+ lastline = to ? to : @infile.get_lines.length - 1
93
+ (firstline .. lastline).each do |ln|
94
+ if @infile.stati[ln] != InputFile::WRITTEN && @infile.stati[ln] != ":"
95
+ log { "printing #{ln}" }
96
+ print_line(ln)
97
+ @infile.stati[ln] = InputFile::WRITTEN
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ def write_all
104
+ (0 ... @infile.get_lines.length).each do |ln|
105
+ print_line(ln)
106
+ end
107
+ end
108
+
109
+ def get_line_to_print(lnum)
110
+ formatted[lnum] || infile.get_line(lnum)
111
+ end
112
+
113
+ def show_line_numbers
114
+ @show_line_numbers
115
+ end
116
+
117
+ end
118
+
119
+
120
+ # -------------------------------------------------------
121
+ # Glark output format
122
+ # -------------------------------------------------------
123
+
124
+ class GlarkOutputFormat < OutputFormat
125
+
126
+ def initialize(infile, show_file_names)
127
+ super
128
+
129
+ opts = GlarkOptions.instance
130
+
131
+ @has_context = opts.after != 0 || opts.before != 0
132
+ @file_header_shown = false
133
+ if @highlight = opts.highlight
134
+ @fname_highlighter = opts.file_highlight
135
+ end
136
+ @lnum_highlighter = opts.line_number_highlight
137
+ end
138
+
139
+ # prints the line, and adjusts for the fact that in our world, lines are
140
+ # 0-indexed, whereas they are displayed as if 1-indexed.
141
+ def print_line(lnum, ch = nil)
142
+ log { "lnum #{lnum}, ch: '#{ch}'" }
143
+ begin
144
+ lnums = @infile.get_range(lnum)
145
+ log { "lnums(#{lnum}): #{lnums}" }
146
+ if lnums
147
+ log { "printing" }
148
+ lnums.each do |ln|
149
+ println(ln, ch)
150
+ end
151
+ end
152
+ rescue => e
153
+ # puts e
154
+ # puts e.backtrace
155
+ end
156
+ end
157
+
158
+ def show_file_header
159
+ if show_file_name && !@file_header_shown
160
+ fname = @label || @infile.fname
161
+ fname = @fname_highlighter.highlight(fname) if @highlight
162
+
163
+ @out.puts fname
164
+ end
165
+ @file_header_shown = true
166
+ end
167
+
168
+ def print_line_number(lnum)
169
+ if @lnum_highlighter
170
+ lnumstr = (lnum + 1).to_s
171
+ pad = " " * ([5 - lnumstr.length, 0].max)
172
+ @out.print pad + " " + @lnum_highlighter.highlight(lnumstr) + " "
173
+ else
174
+ super
175
+ end
176
+ end
177
+
178
+ def write_count(matching = true)
179
+ ct = matching ? @infile.count : @infile.get_lines.size - @infile.count
180
+ @out.puts " " + ct.to_s
181
+ end
182
+
183
+ def write_matches(matching, from = nil, to = nil)
184
+ show_file_header
185
+ super(matching, from, to)
186
+ end
187
+
188
+ def write_all
189
+ show_file_header
190
+ super
191
+ end
192
+
193
+ def println(ln, ch)
194
+ if show_line_numbers
195
+ print_line_number(ln)
196
+ end
197
+
198
+ if ch && has_context
199
+ @out.printf "%s ", ch
200
+ end
201
+
202
+ line = get_line_to_print(ln)
203
+ log { "line: #{line}" }
204
+
205
+ @out.puts line
206
+ end
207
+
208
+ end
209
+
210
+
211
+ class GlarkMatchList < GlarkOutputFormat
212
+ attr_reader :matches
213
+
214
+ def initialize(infile, show_file_names)
215
+ super
216
+ @matches = Array.new
217
+ end
218
+
219
+ def write_matches(matching, from, to)
220
+ stack "matching: #{matching}"
221
+ from.upto(to) do |line|
222
+ @matches[line] = true
223
+ end
224
+ log { "matches: #{@matches}" }
225
+ end
226
+
227
+ end
228
+
229
+
230
+ # -------------------------------------------------------
231
+ # Grep output format
232
+ # -------------------------------------------------------
233
+
234
+ # This matches grep, mostly. It is for running within emacs, thus,
235
+ # it does not support context or highlighting.
236
+ class GrepOutputFormat < OutputFormat
237
+
238
+ def write_count(matching = true)
239
+ print_file_name
240
+ ct = matching ? @infile.count : @infile.get_lines.length - @infile.count
241
+ puts ct
242
+ end
243
+
244
+ # prints the line, and adjusts for the fact that in our world, lines are
245
+ # 0-indexed, whereas they are displayed as if 1-indexed.
246
+ def print_line(lnum, ch = nil)
247
+ ln = get_line_to_print(lnum)
248
+
249
+ if ln
250
+ print_file_name
251
+ if show_line_numbers
252
+ printf "%d: ", lnum + 1
253
+ end
254
+
255
+ print ln
256
+ end
257
+ end
258
+
259
+ def print_file_name
260
+ if show_file_name
261
+ fname = @label || @infile.fname
262
+ print @infile.fname, ":"
263
+ end
264
+ end
265
+
266
+ end
@@ -0,0 +1,317 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'pathname'
5
+
6
+ testdir = Pathname.new(__FILE__).expand_path.dirname.to_s
7
+ $:.unshift testdir
8
+
9
+ require 'testcase'
10
+ require 'stringio'
11
+
12
+ class TC_Glark < GlarkTestCase
13
+
14
+ def do_search_test(exprargs, contents, expected)
15
+ opts = GlarkOptions.instance
16
+
17
+ # Egads, Ruby is fun. Converting a maybe-array into a definite one:
18
+ args = [ exprargs ].flatten
19
+
20
+ expr = ExpressionFactory.new.make_expression(args)
21
+
22
+ outfname = infname = nil
23
+
24
+ begin
25
+ outfname = create_file do |outfile|
26
+ opts.out = outfile
27
+ infname = write_file(contents)
28
+
29
+ files = [ infname ]
30
+ glark = Glark.new(expr, files)
31
+ glark.search(infname)
32
+ end
33
+
34
+ do_file_test(outfname, expected)
35
+ ensure
36
+ [ outfname, infname ].each do |fname|
37
+ if fname && File.exists?(fname)
38
+ File.delete(fname)
39
+ end
40
+ end
41
+ GlarkOptions.instance.reset
42
+ end
43
+ end
44
+
45
+ def test_match_invert
46
+ contents = [
47
+ "ABC",
48
+ "DEF",
49
+ "GHI",
50
+ "JKL",
51
+ "MNO",
52
+ "PQR",
53
+ "STU",
54
+ ]
55
+
56
+ exprstr = "K"
57
+
58
+ expected = contents.collect_with_index do |line, idx|
59
+ if !line.index(exprstr)
60
+ sprintf("%5d %s", idx + 1, line)
61
+ end
62
+ end.compact
63
+
64
+ Log.verbose = false
65
+
66
+ opts = GlarkOptions.instance
67
+ opts.invert_match = true
68
+ opts.verbose = false
69
+ Log.verbose = false
70
+
71
+ do_search_test(exprstr, contents, expected)
72
+ end
73
+
74
+ def do_match_test(contents, patterns, regexp, exprargs)
75
+ defcolors = Text::ANSIHighlighter::DEFAULT_COLORS
76
+
77
+ patdata = patterns.collect_with_index do |pat, pidx|
78
+ color = Text::ANSIHighlighter.make(defcolors[pidx % defcolors.length])
79
+ [ pat, color ]
80
+ end
81
+
82
+ expected = contents.collect_with_index do |line, li|
83
+ if line.index(regexp)
84
+ ln = line.dup
85
+ patdata.each do |pat|
86
+ ln.gsub!(pat[0]) { pat[1].highlight(pat[0]) }
87
+ end
88
+ sprintf("%5d %s", li + 1, ln)
89
+ else
90
+ nil
91
+ end
92
+ end.compact
93
+
94
+ # Log.verbose = false
95
+
96
+ opts = GlarkOptions.instance
97
+ opts.verbose = Log.verbose = false
98
+
99
+ do_search_test(exprargs, contents, expected)
100
+ end
101
+
102
+ def test_match_plain_old_match
103
+ contents = [
104
+ "ABC",
105
+ "DEF",
106
+ "GHI",
107
+ "JKL",
108
+ "MNO",
109
+ "PQR",
110
+ "STU",
111
+ ]
112
+
113
+ do_match_test(contents, %w{K}, %r{K}, "K")
114
+ do_match_test(contents, %w{A}, %r{A}, "A")
115
+ end
116
+
117
+ def test_match_regexp_or
118
+ contents = [
119
+ "ABC",
120
+ "DEF",
121
+ "GHI",
122
+ "JKL",
123
+ "MNO",
124
+ "PQR",
125
+ "STU",
126
+ ]
127
+
128
+ do_match_test(contents, %w{K N}, %r{(K)|(N)}, '(K)|(N)')
129
+ end
130
+
131
+ def do_test_match_alteration
132
+ patternsets = [
133
+ %w{ nul },
134
+ %w{ oo ae z },
135
+ %w{ zoo },
136
+ %w{ zeff },
137
+ ]
138
+
139
+ contents = [
140
+ "zaffres",
141
+ "zoaea",
142
+ "zoaea's",
143
+ "zoea",
144
+ "zoeas",
145
+ "zonulae",
146
+ "zooea",
147
+ "zooeae",
148
+ "zooeal",
149
+ "zooeas",
150
+ "zooecia",
151
+ "zooecium",
152
+ "zoogloeae",
153
+ "zoogloeal",
154
+ "zoogloeas",
155
+ "zygaenid",
156
+ ]
157
+
158
+ patternsets.each do |patterns|
159
+ regexp = Regexp.new(patterns.collect { |x| "(#{x})" }.join('|'))
160
+ exprargs = yield patterns
161
+
162
+ do_match_test(contents, patterns, regexp, exprargs)
163
+ end
164
+ end
165
+
166
+ def test_match_multicolor_alt_regexp
167
+ do_test_match_alteration do |patterns|
168
+ patterns.collect { |x| "(#{x})" }.join('|')
169
+ end
170
+ end
171
+
172
+ def test_match_multicolor_or_expression
173
+ do_test_match_alteration do |patterns|
174
+ exprargs = [ patterns[-1] ]
175
+ patterns.reverse[1 .. -1].each do |pat|
176
+ exprargs.insert(0, "--or", pat)
177
+ end
178
+ exprargs
179
+ end
180
+ end
181
+
182
+ def do_test_match_and_expression(contents, matches, patterns, exprargs)
183
+ regexp = Regexp.new(patterns.collect { |x| "(#{x})" }.join('|'))
184
+
185
+ defcolors = Text::ANSIHighlighter::DEFAULT_COLORS
186
+
187
+ patdata = patterns.collect_with_index do |pat, pidx|
188
+ color = Text::ANSIHighlighter.make(defcolors[pidx % defcolors.length])
189
+ [ pat, color ]
190
+ end
191
+
192
+ expected = contents.collect_with_index do |line, li|
193
+ if matches.include?(line)
194
+ ln = line.dup
195
+ patdata.each do |pat|
196
+ ln.gsub!(pat[0]) { pat[1].highlight(pat[0]) }
197
+ end
198
+ sprintf("%5d %s", li + 1, ln)
199
+ else
200
+ nil
201
+ end
202
+ end.compact
203
+
204
+ if false
205
+ for line in expected
206
+ $stderr.puts line
207
+ end
208
+ end
209
+
210
+ Log.verbose = false
211
+ opts = GlarkOptions.instance
212
+ opts.verbose = Log.verbose = false
213
+
214
+ do_search_test(exprargs, contents, expected)
215
+ end
216
+
217
+ def test_match_and_expression_2_lines_apart
218
+ contents = [
219
+ "zaffres",
220
+ "zoaea",
221
+ "zoaea's",
222
+ "zoea",
223
+ "zoeas",
224
+ "zonulae",
225
+ "zooea",
226
+ "zooeae",
227
+ "zooeal",
228
+ "zooeas",
229
+ "zooecia",
230
+ "zooecium",
231
+ "zoogloeae",
232
+ "zoogloeal",
233
+ "zoogloeas",
234
+ "zygaenid",
235
+ ]
236
+
237
+ # 'ea', 'ec' within 2 lines of each other:
238
+ matches = [
239
+ "zooeal",
240
+ "zooeas",
241
+ "zooecia",
242
+ "zooecium",
243
+ "zoogloeae",
244
+ "zoogloeal",
245
+ ]
246
+
247
+ patterns = %w{ ea ec }
248
+
249
+ exprargs = [ "--and", "2" ] | patterns
250
+
251
+ do_test_match_and_expression(contents, matches, patterns, exprargs)
252
+ end
253
+
254
+ def test_match_and_expression_3_lines_apart
255
+ contents = [
256
+ "zaffres",
257
+ "zoaea",
258
+ "zoaea's",
259
+ "zoea",
260
+ "zoeas",
261
+ "zonulae",
262
+ "zooea",
263
+ "zooeae",
264
+ "zooeal",
265
+ "zooeas",
266
+ "zooecia",
267
+ "zooecium",
268
+ "zoogloeae",
269
+ "zoogloeal",
270
+ "zoogloeas",
271
+ "zygaenid",
272
+ ]
273
+
274
+ matches = [
275
+ "zoaea's",
276
+ "zoea",
277
+ "zoeas",
278
+ "zonulae",
279
+ ]
280
+
281
+ patterns = %w{ aea ula }
282
+
283
+ exprargs = [ "--and", "3" ] | patterns
284
+
285
+ do_test_match_and_expression(contents, matches, patterns, exprargs)
286
+ end
287
+
288
+ def test_match_and_expression_entire_file
289
+ contents = [
290
+ "zaffres",
291
+ "zoaea",
292
+ "zoaea's",
293
+ "zoea",
294
+ "zoeas",
295
+ "zonulae",
296
+ "zooea",
297
+ "zooeae",
298
+ "zooeal",
299
+ "zooeas",
300
+ "zooecia",
301
+ "zooecium",
302
+ "zoogloeae",
303
+ "zoogloeal",
304
+ "zoogloeas",
305
+ "zygaenid",
306
+ ]
307
+
308
+ matches = contents
309
+
310
+ patterns = %w{ aff yga }
311
+
312
+ exprargs = [ "--and", "-1" ] | patterns
313
+
314
+ do_test_match_and_expression(contents, matches, patterns, exprargs)
315
+ end
316
+
317
+ end