glark 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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