prak 1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/History.txt +27 -0
- data/Manifest.txt +12 -0
- data/README.txt +70 -0
- data/Rakefile +17 -0
- data/bin/prak +7 -0
- data/lib/prak.rb +9 -0
- data/lib/prak/bootstrap.rb +22 -0
- data/lib/prak/command_line.rb +292 -0
- data/lib/prak/compile_match_file.rb +145 -0
- data/lib/prak/file.rb +142 -0
- data/lib/prak/search.rb +36 -0
- data/prak.gemspec +19 -0
- metadata +85 -0
data/.gemtest
ADDED
File without changes
|
data/History.txt
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
== 1.0 / 2009-09-27
|
3
|
+
|
4
|
+
* MinGW is a valid Windows platform type.
|
5
|
+
* Can use ~bang and ~ques in a regex and they will be turned into ! and ?
|
6
|
+
This is to get around bash.
|
7
|
+
* Added -k negative file match option (Contributed by Juozas Gaigalas')
|
8
|
+
* Added .cc and .hpp to the C++ file types
|
9
|
+
* Added Vala file types
|
10
|
+
* 20% faster on average
|
11
|
+
* Moved to Github
|
12
|
+
|
13
|
+
== 0.9 / 2008-02-03
|
14
|
+
|
15
|
+
* Added .rake to ruby files
|
16
|
+
* Colouring works on Win32 if win32console gem is installed.
|
17
|
+
* Checks that file is readable by the current user.
|
18
|
+
* Ignores socket files.
|
19
|
+
* Added .erb and .haml to Ruby filetypes.
|
20
|
+
* Added search at end-of/start-of line options
|
21
|
+
* Fixed searching up the directory tree when passed '.'
|
22
|
+
|
23
|
+
== 0.8.0 / 2007-10-30
|
24
|
+
|
25
|
+
* Initial release.
|
26
|
+
|
27
|
+
|
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
prak
|
2
|
+
|
3
|
+
Original by:
|
4
|
+
http://rubyforge.org/projects/rak
|
5
|
+
Daniel Lucraft (http://danlucraft.com/blog/)
|
6
|
+
|
7
|
+
Modifications by Sven Winkler
|
8
|
+
|
9
|
+
== DESCRIPTION:
|
10
|
+
|
11
|
+
Replacement for grep. Recursively scans directories to match a given
|
12
|
+
Ruby regular expression. Prints highlighted results.
|
13
|
+
|
14
|
+
Based on the Perl tool 'ack' by Andy Lester.
|
15
|
+
|
16
|
+
Examples with similar grep:
|
17
|
+
|
18
|
+
$ prak pattern
|
19
|
+
$ grep pattern $(find . | grep -v .svn)
|
20
|
+
|
21
|
+
$ prak --ruby pattern
|
22
|
+
$ grep pattern $(find . -name '*.rb' | grep -v .svn)
|
23
|
+
|
24
|
+
== FEATURES/PROBLEMS:
|
25
|
+
|
26
|
+
* Ruby regular expression syntax (uses oniguruma gem if installed).
|
27
|
+
* Highlighted output.
|
28
|
+
* Automatically recurses down the current directory or any given
|
29
|
+
directories.
|
30
|
+
* Skips version control directories, backups like '~' and '#' and your
|
31
|
+
* ruby project's pkg directory.
|
32
|
+
* Allows inclusion and exclusion of files based on types.
|
33
|
+
* Many options similar to grep.
|
34
|
+
|
35
|
+
== SYNOPSIS:
|
36
|
+
|
37
|
+
See 'prak --help' for usage information.
|
38
|
+
|
39
|
+
== REQUIREMENTS:
|
40
|
+
|
41
|
+
* Ruby
|
42
|
+
|
43
|
+
== INSTALL:
|
44
|
+
|
45
|
+
* gem install prak
|
46
|
+
|
47
|
+
== LICENSE:
|
48
|
+
|
49
|
+
(The MIT License)
|
50
|
+
|
51
|
+
Original copyright (c) 2007 Daniel Lucraft
|
52
|
+
|
53
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
54
|
+
a copy of this software and associated documentation files (the
|
55
|
+
'Software'), to deal in the Software without restriction, including
|
56
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
57
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
58
|
+
permit persons to whom the Software is furnished to do so, subject to
|
59
|
+
the following conditions:
|
60
|
+
|
61
|
+
The above copyright notice and this permission notice shall be
|
62
|
+
included in all copies or substantial portions of the Software.
|
63
|
+
|
64
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
65
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
66
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
67
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
68
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
69
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
70
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'hoe'
|
4
|
+
|
5
|
+
$:.unshift 'lib'
|
6
|
+
|
7
|
+
require 'prak'
|
8
|
+
|
9
|
+
Hoe.spec('prak') do |p|
|
10
|
+
p.author = 'Sven Winkler'
|
11
|
+
p.email = 'sven@q-logix.de'
|
12
|
+
p.version = Prak::VERSION
|
13
|
+
p.summary = 'A grep replacement in Ruby, type "$prak pattern".'
|
14
|
+
p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
15
|
+
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
|
16
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
17
|
+
end
|
data/bin/prak
ADDED
data/lib/prak.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'getoptlong'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'oniguruma'
|
5
|
+
require 'inline'
|
6
|
+
$use_onig = true
|
7
|
+
rescue LoadError
|
8
|
+
$use_onig = false
|
9
|
+
end
|
10
|
+
|
11
|
+
class String
|
12
|
+
def expand_tabs(shift=0)
|
13
|
+
expanded = dup
|
14
|
+
1 while expanded.sub!(/\t+/){ " "*($&.size*8 - ($`.size+shift)%8) }
|
15
|
+
expanded
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
@@ -0,0 +1,292 @@
|
|
1
|
+
class Prak
|
2
|
+
|
3
|
+
FILE_COLOUR = "\033[1;31m"
|
4
|
+
MATCH_COLOUR = "\033[1;37m\033[41m"
|
5
|
+
CLEAR_COLOURS = "\033[0m"
|
6
|
+
|
7
|
+
FILE_TYPES = {
|
8
|
+
:asm => %w( .s .S ),
|
9
|
+
:cc => %w( .c .h .xs ),
|
10
|
+
:coffee => %w( .coffee.js .coffee ),
|
11
|
+
:cpp => %w( .cpp .cc .m .h .hpp .C .H ),
|
12
|
+
:csharp => %w( .cs ),
|
13
|
+
:css => %w( .css .sass .scss .less ),
|
14
|
+
:elisp => %w( .el ),
|
15
|
+
:haskell => %w( .hs .lhs ),
|
16
|
+
:hh => %w( .h ),
|
17
|
+
:html => %w( .htm .html .shtml ),
|
18
|
+
:image => %w( .bmp .gif .jpg .jpeg .png .psd ),
|
19
|
+
:lisp => %w( .lisp ),
|
20
|
+
:java => %w( .java properties ),
|
21
|
+
:js => %w( .js ),
|
22
|
+
:jsp => %w( .jsp .jspx .jhtm .jhtml ),
|
23
|
+
:make => %w( Makefile ),
|
24
|
+
:mason => %w( .mas .mhtml .mpl .mtxt ),
|
25
|
+
:ocaml => %w( .ml .mli ),
|
26
|
+
:parrot => %w( .pir .pasm .pmc .ops .pod .pg .tg ),
|
27
|
+
:perl => %w( .pl .pm .pod .t ),
|
28
|
+
:php => %w( .php .phpt .php3 .php4 .php5 ),
|
29
|
+
:prolog => %w( .pl .ecl ),
|
30
|
+
:python => %w( .py ),
|
31
|
+
:ruby => %w( .rb .rhtml .rjs .rxml Rakefile .rake .erb .haml .slim),
|
32
|
+
:scheme => %w( .scm ),
|
33
|
+
:shell => %w( .sh .bash .csh .ksh .zsh ),
|
34
|
+
:sql => %w( .sql .ctl ),
|
35
|
+
:tcl => %w( .tcl ),
|
36
|
+
:tex => %w( .tex .cls .sty ),
|
37
|
+
:text => %w( .txt .text ),
|
38
|
+
:tt => %w( .tt .tt2 .ttml ),
|
39
|
+
:vala => %w( .vala .vapi ),
|
40
|
+
:vb => %w( .bas .cls .frm .ctl .vb .resx ),
|
41
|
+
:vim => %w( .vim ),
|
42
|
+
:yaml => %w( .yaml .yml ),
|
43
|
+
:xml => %w( .xml .dtd .xslt )
|
44
|
+
}
|
45
|
+
|
46
|
+
VC_DIRS = %w(blib CVS _darcs .git .pc RCS SCCS .svn pkg)
|
47
|
+
|
48
|
+
class << self
|
49
|
+
attr_reader :opt
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.unknown_type(type)
|
53
|
+
puts "rak: Unknown --type \"#{type}\""
|
54
|
+
puts "rak: See rak --help types"
|
55
|
+
exit
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.parse_command_line_options options = {}
|
59
|
+
|
60
|
+
@opt = options
|
61
|
+
|
62
|
+
# file types
|
63
|
+
opt[:includes] = []
|
64
|
+
opt[:excludes] = []
|
65
|
+
|
66
|
+
FILE_TYPES.each do |type, exts|
|
67
|
+
if ARGV.delete('--'+type.to_s)
|
68
|
+
exts.each do |ext|
|
69
|
+
opt[:includes] << ext
|
70
|
+
end
|
71
|
+
end
|
72
|
+
if ARGV.delete('--no'+type.to_s)
|
73
|
+
exts.each do |ext|
|
74
|
+
opt[:excludes] << ext
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
opts = GetoptLong.new(
|
80
|
+
[ '--help', GetoptLong::OPTIONAL_ARGUMENT ],
|
81
|
+
[ '--max-count', '-m', GetoptLong::REQUIRED_ARGUMENT ],
|
82
|
+
[ '--files', '-f', GetoptLong::NO_ARGUMENT ],
|
83
|
+
[ '--output', GetoptLong::REQUIRED_ARGUMENT ],
|
84
|
+
[ '--version', GetoptLong::NO_ARGUMENT ],
|
85
|
+
[ '-c', '--count', GetoptLong::NO_ARGUMENT ],
|
86
|
+
[ '-h', '--no-filename', GetoptLong::NO_ARGUMENT ],
|
87
|
+
[ '-i', '--ignore-case', GetoptLong::NO_ARGUMENT ],
|
88
|
+
[ '-v', '--invert-match', GetoptLong::NO_ARGUMENT ],
|
89
|
+
[ '-n', GetoptLong::NO_ARGUMENT ],
|
90
|
+
[ '-Q', '--literal', GetoptLong::NO_ARGUMENT ],
|
91
|
+
[ '-o', GetoptLong::NO_ARGUMENT ],
|
92
|
+
[ '-w', '--word-regexp', GetoptLong::NO_ARGUMENT ],
|
93
|
+
[ '--group', GetoptLong::NO_ARGUMENT ],
|
94
|
+
[ '--nogroup', GetoptLong::NO_ARGUMENT ],
|
95
|
+
[ '-l', '--files-with-matches', GetoptLong::NO_ARGUMENT ],
|
96
|
+
[ '-L', '--files-without-matches', GetoptLong::NO_ARGUMENT ],
|
97
|
+
[ '--passthru', GetoptLong::NO_ARGUMENT ],
|
98
|
+
[ '-H', '--with-filename', GetoptLong::NO_ARGUMENT ],
|
99
|
+
[ '--colour', GetoptLong::NO_ARGUMENT ],
|
100
|
+
[ '--nocolour', GetoptLong::NO_ARGUMENT ],
|
101
|
+
[ '--color', GetoptLong::NO_ARGUMENT ],
|
102
|
+
[ '--nocolor', GetoptLong::NO_ARGUMENT ],
|
103
|
+
[ '-a', '--all', GetoptLong::NO_ARGUMENT ],
|
104
|
+
[ '--type', GetoptLong::REQUIRED_ARGUMENT ],
|
105
|
+
[ '--sort-files', GetoptLong::NO_ARGUMENT ],
|
106
|
+
[ '--follow', GetoptLong::NO_ARGUMENT ],
|
107
|
+
[ '--nofollow', GetoptLong::NO_ARGUMENT ],
|
108
|
+
[ '--after-context', '-A', GetoptLong::REQUIRED_ARGUMENT ],
|
109
|
+
[ '--before-context', '-B', GetoptLong::REQUIRED_ARGUMENT ],
|
110
|
+
[ '--context', '-C', GetoptLong::OPTIONAL_ARGUMENT ],
|
111
|
+
[ '-g', GetoptLong::REQUIRED_ARGUMENT ],
|
112
|
+
[ '-k', GetoptLong::REQUIRED_ARGUMENT ],
|
113
|
+
[ '-x', '--line-regexp', GetoptLong::NO_ARGUMENT ],
|
114
|
+
[ '-s', '--line-start', GetoptLong::NO_ARGUMENT ],
|
115
|
+
[ '-e', '--line-end', GetoptLong::NO_ARGUMENT ],
|
116
|
+
[ '-E', '--encoding', GetoptLong::REQUIRED_ARGUMENT ],
|
117
|
+
)
|
118
|
+
|
119
|
+
self.standard_options
|
120
|
+
|
121
|
+
# if redirected (RAK_TEST allows us to redirect in testing and still
|
122
|
+
# get the non-redirected defaults).
|
123
|
+
unless STDOUT.isatty or ENV['RAK_TEST'] == "true"
|
124
|
+
opt[:colour] = false
|
125
|
+
opt[:print_file_each_line] = true
|
126
|
+
opt[:print_filename] = false
|
127
|
+
opt[:print_line_number] = false
|
128
|
+
end
|
129
|
+
|
130
|
+
begin
|
131
|
+
opts.each do |option, arg|
|
132
|
+
case option
|
133
|
+
when '--help'
|
134
|
+
if arg == ""
|
135
|
+
# TODO: USAGE_HELP
|
136
|
+
puts USAGE_HELP
|
137
|
+
elsif arg == "types" or arg == "type"
|
138
|
+
puts TYPES_HELP
|
139
|
+
end
|
140
|
+
exit
|
141
|
+
when '--max-count'
|
142
|
+
opt[:max_count] = arg.to_i
|
143
|
+
when '--files'
|
144
|
+
opt[:only_print_filelist] = true
|
145
|
+
when '--output'
|
146
|
+
opt[:print_filename] = false
|
147
|
+
opt[:print_line_number] = false
|
148
|
+
opt[:print_output] = arg
|
149
|
+
opt[:print_highlighted] = false
|
150
|
+
when '--version'
|
151
|
+
puts VERSION_INFO
|
152
|
+
exit
|
153
|
+
when '-c'
|
154
|
+
opt[:print_num_matches] = true
|
155
|
+
opt[:print_filename] = false
|
156
|
+
opt[:print_line_number] = false
|
157
|
+
opt[:print_highlighted] = false
|
158
|
+
when '-h'
|
159
|
+
opt[:print_filename] = false
|
160
|
+
opt[:print_line_number] = false
|
161
|
+
opt[:print_file_each_line] = false
|
162
|
+
when '-i'
|
163
|
+
opt[:ignore_case] = true
|
164
|
+
when '-v'
|
165
|
+
opt[:invert_match] = true
|
166
|
+
when '-n'
|
167
|
+
opt[:descend] = false
|
168
|
+
when '-Q'
|
169
|
+
opt[:literal] = true
|
170
|
+
when '-o'
|
171
|
+
opt[:print_match] = true
|
172
|
+
opt[:print_filename] = false
|
173
|
+
opt[:print_line_number] = false
|
174
|
+
opt[:print_highlighted] = false
|
175
|
+
when '-w'
|
176
|
+
opt[:match_whole_words] = true
|
177
|
+
when '--group'
|
178
|
+
opt[:print_filename] = true
|
179
|
+
opt[:print_file_each_line] = false
|
180
|
+
when '--nogroup'
|
181
|
+
opt[:print_file_each_line] = true
|
182
|
+
opt[:print_filename] = false
|
183
|
+
opt[:print_line_number] = false
|
184
|
+
when '-l'
|
185
|
+
opt[:print_filename] = false
|
186
|
+
opt[:print_line_number] = false
|
187
|
+
opt[:print_highlighted] = false
|
188
|
+
opt[:print_file_if_match] = true
|
189
|
+
when '-L'
|
190
|
+
opt[:print_filename] = false
|
191
|
+
opt[:print_line_number] = false
|
192
|
+
opt[:print_highlighted] = false
|
193
|
+
opt[:print_file_if_no_match] = true
|
194
|
+
when '--passthru'
|
195
|
+
opt[:print_entire_line_if_no_match] = true
|
196
|
+
when '-H'
|
197
|
+
opt[:print_filename] = true
|
198
|
+
opt[:print_line_number] = true
|
199
|
+
when '--nocolour', '--nocolor'
|
200
|
+
opt[:colour] = false
|
201
|
+
when '--colour', '--color'
|
202
|
+
opt[:colour] = true
|
203
|
+
when '-a'
|
204
|
+
opt[:all_files] = true
|
205
|
+
when '--type'
|
206
|
+
if arg[0..1] == "no"
|
207
|
+
type = arg[2..-1]
|
208
|
+
arr = opt[:excludes]
|
209
|
+
else
|
210
|
+
type = arg
|
211
|
+
arr = opt[:includes]
|
212
|
+
end
|
213
|
+
exts = FILE_TYPES[type.intern]
|
214
|
+
unknown_type(type) unless exts
|
215
|
+
exts.each do |ext|
|
216
|
+
arr << ext
|
217
|
+
end
|
218
|
+
when '--sort-files'
|
219
|
+
opt[:sort_files] = true
|
220
|
+
when '--follow'
|
221
|
+
opt[:follow_symlinks] = true
|
222
|
+
when '--nofollow'
|
223
|
+
opt[:follow_symlinks] = false
|
224
|
+
when '--after-context'
|
225
|
+
opt[:use_context] = true
|
226
|
+
opt[:after_context] = arg.to_i
|
227
|
+
when '--before-context'
|
228
|
+
opt[:use_context] = true
|
229
|
+
opt[:before_context] = arg.to_i
|
230
|
+
when '--context'
|
231
|
+
opt[:use_context] = true
|
232
|
+
if arg == ""
|
233
|
+
val = 2
|
234
|
+
else
|
235
|
+
val = arg.to_i
|
236
|
+
end
|
237
|
+
opt[:before_context] = val
|
238
|
+
opt[:after_context] = val
|
239
|
+
when '-g'
|
240
|
+
opt[:filename_regex] = compile_regexp(arg)
|
241
|
+
when '-k'
|
242
|
+
opt[:neg_filename_regex] = compile_regexp(arg)
|
243
|
+
when '-x'
|
244
|
+
opt[:match_whole_lines] = true
|
245
|
+
when '-s'
|
246
|
+
opt[:match_line_starts] = true
|
247
|
+
when '-e'
|
248
|
+
opt[:match_line_ends] = true
|
249
|
+
end
|
250
|
+
end
|
251
|
+
rescue GetoptLong::InvalidOption => ex
|
252
|
+
puts "rak: see rak --help for usage."
|
253
|
+
exit
|
254
|
+
rescue SystemExit
|
255
|
+
exit
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def self.standard_options
|
260
|
+
opt[:max_count] = nil
|
261
|
+
opt[:only_print_filelist] = false
|
262
|
+
opt[:print_filename] = true
|
263
|
+
opt[:print_line_number] = true
|
264
|
+
opt[:print_output] = nil
|
265
|
+
opt[:print_highlighted] = true
|
266
|
+
opt[:print_num_matches] = false
|
267
|
+
opt[:ignore_case] = false
|
268
|
+
opt[:invert_match] = false
|
269
|
+
opt[:descend] = true
|
270
|
+
opt[:literal] = false
|
271
|
+
opt[:print_match] = false
|
272
|
+
opt[:match_whole_words] = false
|
273
|
+
opt[:match_whole_lines] = false
|
274
|
+
opt[:match_line_starts] = false
|
275
|
+
opt[:match_line_ends] = false
|
276
|
+
opt[:print_file_each_line] = false
|
277
|
+
opt[:print_file_if_match] = false
|
278
|
+
opt[:print_file_if_no_match] = false
|
279
|
+
opt[:print_entire_line_if_no_match] = false
|
280
|
+
opt[:colour] = true
|
281
|
+
opt[:all_files] = false
|
282
|
+
opt[:sort_files] = false
|
283
|
+
opt[:follow_symlinks] = false
|
284
|
+
opt[:after_context] = 0
|
285
|
+
opt[:before_context] = 0
|
286
|
+
opt[:collect_context] = false
|
287
|
+
opt[:filename_regex] = nil
|
288
|
+
opt[:neg_filename_regex] = nil
|
289
|
+
opt[:standard_encoding] = "UTF-8"
|
290
|
+
end
|
291
|
+
|
292
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
class Prak
|
2
|
+
def self.compile_match_file
|
3
|
+
c = []
|
4
|
+
c << %{def match_file(re, fn, file_separator) }
|
5
|
+
c << %{ displayed_filename = false }
|
6
|
+
c << %{ count = 0 }
|
7
|
+
c << %{ i = 0 }
|
8
|
+
c << %{ matches = [] }
|
9
|
+
c << %{ print_num = 0 }
|
10
|
+
|
11
|
+
if opt[:before_context] > 0
|
12
|
+
c << %{ before_context = [] }
|
13
|
+
c << %{ before_context_size = opt[:before_context] }
|
14
|
+
end
|
15
|
+
c << %{ if fn.is_a? String }
|
16
|
+
c << %{ f = File.open(fn, "r", :encoding => opt[:standard_encoding]) }
|
17
|
+
c << %{ elsif fn.is_a? IO }
|
18
|
+
c << %{ f = fn }
|
19
|
+
c << %{ end }
|
20
|
+
|
21
|
+
c << %{ f.each_line do |line| }
|
22
|
+
c << %{ line = line.force_encoding("BINARY") unless line.valid_encoding? }
|
23
|
+
c << %{ i += 1 }
|
24
|
+
if opt[:print_output]
|
25
|
+
c << %{ line.scan(re){ matches << eval(opt[:print_output]) } }
|
26
|
+
else
|
27
|
+
c << %{ line.scan(re){ matches << $~ } }
|
28
|
+
end
|
29
|
+
if opt[:print_match]
|
30
|
+
c << %{ matches.each{|md| puts md.to_s } }
|
31
|
+
end
|
32
|
+
c << %{ count += matches.size }
|
33
|
+
if opt[:invert_match]
|
34
|
+
if opt[:print_filename]
|
35
|
+
c << %{ unless displayed_filename }
|
36
|
+
c << %{ print file_separator }
|
37
|
+
c << %{ file_separator.replace("\\n") }
|
38
|
+
c << %{ puts FILE_COLOUR + fn + CLEAR_COLOURS }
|
39
|
+
c << %{ displayed_filename = true }
|
40
|
+
c << %{ end }
|
41
|
+
end
|
42
|
+
c << %{ if matches.empty? }
|
43
|
+
if opt[:print_highlighted]
|
44
|
+
if opt[:print_line_number]
|
45
|
+
c << %{ print "\#{i.to_s.rjust(4) }|" }
|
46
|
+
end
|
47
|
+
c << %{ puts "\#{line.expand_tabs }" }
|
48
|
+
end
|
49
|
+
c << %{ end }
|
50
|
+
c << %{ matches.clear }
|
51
|
+
else
|
52
|
+
c << %{ if matches.empty? }
|
53
|
+
if opt[:print_entire_line_if_no_match]
|
54
|
+
c << %{ puts line }
|
55
|
+
end
|
56
|
+
if opt[:use_context]
|
57
|
+
if opt[:before_context] > 0
|
58
|
+
c << %{ if print_num == 0 }
|
59
|
+
c << %{ before_context << [i, line] }
|
60
|
+
c << %{ if before_context.length > before_context_size }
|
61
|
+
c << %{ before_context.shift }
|
62
|
+
c << %{ end }
|
63
|
+
c << %{ end }
|
64
|
+
end
|
65
|
+
c << %{ if print_num > 0 }
|
66
|
+
c << %{ print_num -= 1 }
|
67
|
+
if opt[:print_highlighted]
|
68
|
+
if opt[:print_line_number]
|
69
|
+
c << %{ print "\#{i.to_s.rjust(4) }|" }
|
70
|
+
end
|
71
|
+
c << %{ puts "\#{line.expand_tabs }" }
|
72
|
+
c << %{ end }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
c << %{ else }
|
76
|
+
c << %{ print_num = opt[:after_context] }
|
77
|
+
if opt[:print_filename]
|
78
|
+
c << %{ unless displayed_filename }
|
79
|
+
c << %{ print file_separator }
|
80
|
+
c << %{ file_separator.replace("\\n") }
|
81
|
+
c << %{ puts FILE_COLOUR + fn + CLEAR_COLOURS }
|
82
|
+
c << %{ displayed_filename = true }
|
83
|
+
c << %{ end }
|
84
|
+
end
|
85
|
+
if opt[:before_context] > 0
|
86
|
+
c << %{ before_context.each do |before_i, before_line| }
|
87
|
+
if opt[:print_line_number]
|
88
|
+
c << %{ print "\#{before_i.to_s.rjust(4) }|" }
|
89
|
+
end
|
90
|
+
c << %{ puts before_line.expand_tabs }
|
91
|
+
c << %{ end }
|
92
|
+
c << %{ before_context = [] }
|
93
|
+
end
|
94
|
+
if opt[:print_output]
|
95
|
+
c << %{ matches.each {|m| puts m } }
|
96
|
+
end
|
97
|
+
if opt[:print_highlighted]
|
98
|
+
if opt[:print_line_number]
|
99
|
+
c << %{ prefix = "\#{i.to_s.rjust(4) }|" }
|
100
|
+
else
|
101
|
+
if opt[:print_file_each_line]
|
102
|
+
c << %{ fn_str = (fn.is_a?(String) ? FILE_COLOUR + fn + CLEAR_COLOURS + ":" : "") }
|
103
|
+
c << %{ prefix = fn_str + "\#{i.to_s }:" }
|
104
|
+
else
|
105
|
+
c << %{ prefix = "" }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
c << %{ print_highlighted(prefix, line, matches) }
|
109
|
+
end
|
110
|
+
c << %{ end }
|
111
|
+
if opt[:max_count]
|
112
|
+
c << %{ if count >= opt[:max_count] }
|
113
|
+
c << %{ break }
|
114
|
+
c << %{ end }
|
115
|
+
end
|
116
|
+
c << %{ matches.clear }
|
117
|
+
end
|
118
|
+
c << %{ end }
|
119
|
+
c << %{ f.close if f === File }
|
120
|
+
if opt[:print_num_matches]
|
121
|
+
if opt[:invert_match]
|
122
|
+
c << %{ puts "\#{fn }:\#{i-count }" }
|
123
|
+
else
|
124
|
+
c << %{ if count > 0 }
|
125
|
+
c << %{ puts "\#{fn }:\#{count }" }
|
126
|
+
c << %{ end }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
if opt[:print_file_if_match]
|
130
|
+
c << %{ if count > 0 }
|
131
|
+
c << %{ puts fn }
|
132
|
+
c << %{ end }
|
133
|
+
end
|
134
|
+
|
135
|
+
if opt[:print_file_if_no_match]
|
136
|
+
c << %{ if count == 0 }
|
137
|
+
c << %{ puts fn }
|
138
|
+
c << %{ end }
|
139
|
+
end
|
140
|
+
c << %{end }
|
141
|
+
|
142
|
+
Prak.instance_eval c.join("\n")
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
data/lib/prak/file.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
class Prak
|
2
|
+
|
3
|
+
def self.file_relevant?(fn)
|
4
|
+
# These don't change at this point
|
5
|
+
@types_rx ||= extension_regexp(FILE_TYPES.values.flatten)
|
6
|
+
@includes_rx ||= extension_regexp(opt[:includes])
|
7
|
+
@excludes_rx ||= extension_regexp(opt[:excludes])
|
8
|
+
|
9
|
+
ext = File.basename(fn)
|
10
|
+
ext = shebang_matches(fn) unless ext =~ @types_rx
|
11
|
+
|
12
|
+
return false if !opt[:all_files] and !ext or fn =~ /[~#]\z/
|
13
|
+
return false if @includes_rx and (ext||"") !~ @includes_rx
|
14
|
+
return false if @excludes_rx and (ext||"") =~ @excludes_rx
|
15
|
+
return false if opt[:filename_regex] and fn !~ opt[:filename_regex]
|
16
|
+
return false if opt[:neg_filename_regex] and fn =~ opt[:neg_filename_regex]
|
17
|
+
return true
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.find_all_files(path, &blk)
|
21
|
+
return if File.socket?(path)
|
22
|
+
return unless File.readable?(path)
|
23
|
+
|
24
|
+
if File.file?(path)
|
25
|
+
return unless file_relevant?(path)
|
26
|
+
yield(path.sub(/\A\.\/+/, "").gsub(/\/+/, "/"))
|
27
|
+
elsif File.directory?(path)
|
28
|
+
Dir["#{path}/*"].each do |fn|
|
29
|
+
next if VC_DIRS.any?{|vc| vc == File.basename(fn)}
|
30
|
+
next if File.directory?(fn) and not opt[:descend]
|
31
|
+
next if File.symlink?(fn) and not opt[:follow_symlinks]
|
32
|
+
find_all_files(fn, &blk)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# It's really asking for Pathname...
|
38
|
+
def self.each_file(todo, &blk)
|
39
|
+
if todo.empty?
|
40
|
+
if STDIN.isatty
|
41
|
+
todo = ["."]
|
42
|
+
else
|
43
|
+
opt[:print_filename] = false
|
44
|
+
yield(STDIN)
|
45
|
+
return
|
46
|
+
end
|
47
|
+
elsif todo.size == 1 and File.file?(todo[0])
|
48
|
+
opt[:print_filename] = false
|
49
|
+
end
|
50
|
+
|
51
|
+
if opt[:sort_files]
|
52
|
+
sortme = []
|
53
|
+
todo.each do |item|
|
54
|
+
find_all_files(item) do |fn|
|
55
|
+
sortme << fn
|
56
|
+
end
|
57
|
+
end
|
58
|
+
sortme.sort_by{|fn|fn.downcase}.each(&blk)
|
59
|
+
else
|
60
|
+
todo.each do |item|
|
61
|
+
find_all_files(item, &blk)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.print_highlighted(prefix, line, matches)
|
67
|
+
print prefix
|
68
|
+
matches = matches.map{|md| md.offset(0)}
|
69
|
+
cuts = [0, matches, line.size].flatten
|
70
|
+
column = 0
|
71
|
+
0.upto(cuts.size-2) do |i|
|
72
|
+
part = line[cuts[i]...cuts[i+1]]
|
73
|
+
part = part.expand_tabs(column)
|
74
|
+
column += part.size
|
75
|
+
print MATCH_COLOUR if i%2 == 1
|
76
|
+
print part
|
77
|
+
print CLEAR_COLOURS if i%2 == 1
|
78
|
+
end
|
79
|
+
print "\n" unless line[-1,1] == "\n"
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.compile_regexp(str)
|
83
|
+
if $use_onig
|
84
|
+
Oniguruma::ORegexp.new(str)
|
85
|
+
else
|
86
|
+
Regexp.new(str)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.extension_regexp(extensions)
|
91
|
+
return nil if extensions.empty?
|
92
|
+
Regexp.compile('(?:' + extensions.map{|x| Regexp.escape(x)}.join("|") + ')\z')
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.shebang_matches(fn)
|
96
|
+
begin
|
97
|
+
line = File.open(fn, :encoding => opt[:standard_encoding]).readline
|
98
|
+
if line =~ /^#!/
|
99
|
+
if line =~ /\b(ruby|perl|php|python|make)[0-9.]*\b/i
|
100
|
+
FILE_TYPES[$1.downcase.intern].first
|
101
|
+
elsif line =~ /\b(sh|bash|csh|ksh|zsh)\b/
|
102
|
+
".sh"
|
103
|
+
else
|
104
|
+
".other"
|
105
|
+
end
|
106
|
+
elsif line =~ /^<\?xml\b/
|
107
|
+
".xml"
|
108
|
+
else
|
109
|
+
false
|
110
|
+
end
|
111
|
+
rescue
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.compile_pattern(str)
|
117
|
+
if opt[:literal]
|
118
|
+
str = Regexp.quote(str)
|
119
|
+
end
|
120
|
+
if opt[:match_whole_words]
|
121
|
+
str = "\\b(?:" + str + ")\\b"
|
122
|
+
end
|
123
|
+
if opt[:match_whole_lines]
|
124
|
+
str = "^(?:" + str + ")$"
|
125
|
+
end
|
126
|
+
if opt[:match_line_starts]
|
127
|
+
str = "^(?:" + str + ")"
|
128
|
+
end
|
129
|
+
if opt[:match_line_ends]
|
130
|
+
str = "(?:" + str + ")$"
|
131
|
+
end
|
132
|
+
str = str.gsub("~bang", "!").gsub("~ques", "?")
|
133
|
+
if $use_onig
|
134
|
+
flags = opt[:ignore_case] ? Oniguruma::OPTION_IGNORECASE : nil
|
135
|
+
Oniguruma::ORegexp.new(str, :options => flags)
|
136
|
+
else
|
137
|
+
flags = opt[:ignore_case] ? Regexp::IGNORECASE : nil
|
138
|
+
Regexp.new(str, flags)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
data/lib/prak/search.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
class Prak
|
2
|
+
|
3
|
+
def self.search
|
4
|
+
|
5
|
+
parse_command_line_options
|
6
|
+
|
7
|
+
unless opt[:colour]
|
8
|
+
FILE_COLOUR.replace ""
|
9
|
+
CLEAR_COLOURS.replace ""
|
10
|
+
MATCH_COLOUR.replace ""
|
11
|
+
end
|
12
|
+
|
13
|
+
if opt[:only_print_filelist]
|
14
|
+
each_file(ARGV) do |fn|
|
15
|
+
puts fn
|
16
|
+
end
|
17
|
+
elsif ARGV.empty?
|
18
|
+
# TODO USAGE_HELP
|
19
|
+
puts USAGE_HELP
|
20
|
+
exit
|
21
|
+
else
|
22
|
+
re = compile_pattern(ARGV.shift)
|
23
|
+
compiled = false
|
24
|
+
file_separator = ""
|
25
|
+
each_file(ARGV) do |fn|
|
26
|
+
# each_file might turn off printing file name, but only before first yield
|
27
|
+
unless compiled
|
28
|
+
compile_match_file
|
29
|
+
compiled = true
|
30
|
+
end
|
31
|
+
match_file(re, fn, file_separator)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/prak.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
Gem::Specification.spec do |s|
|
3
|
+
s.name = %q{prak}
|
4
|
+
s.version = "2.0"
|
5
|
+
|
6
|
+
s.authors = ["Daniel Lucraft"]
|
7
|
+
s.date = %q{2008-02-03}
|
8
|
+
s.default_executable = %q{prak}
|
9
|
+
s.description = %q{Based on the Perl tool 'ack' by Andy Lester. Examples with similar grep: $ prak pattern $ grep pattern $(find . | grep -v .svn) $ prak --ruby pattern $ grep pattern $(find . -name '*.rb' | grep -v .svn) == FEATURES/PROBLEMS: * Ruby regular expression syntax (uses oniguruma gem if installed). * Highlighted output. * Automatically recurses down the current directory or any given directories. * Skips version control directories, backups like '~' and '#' and your * ruby project's pkg directory. * Allows inclusion and exclusion of files based on types. * Many options similar to grep.}
|
10
|
+
s.email = %q{dan@fluentradical.com}
|
11
|
+
s.executables = ["prak"]
|
12
|
+
s.files = FileList["{lib,spec,bin,doc}/**/*"]
|
13
|
+
s.homepage = %q{http://github.com/sven-q/prak.git}
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
s.rubygems_version = %q{1.3.0}
|
16
|
+
s.summary = %q{A grep replacement in Ruby, type "prak pattern".}
|
17
|
+
s.required_ruby_version = '>= 1.9.2'
|
18
|
+
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: prak
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.1'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sven Winkler
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-08-23 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: hoe
|
16
|
+
requirement: &2153032040 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.12'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2153032040
|
25
|
+
description: ! 'Modifications by Sven Winkler
|
26
|
+
|
27
|
+
|
28
|
+
== DESCRIPTION:
|
29
|
+
|
30
|
+
|
31
|
+
Replacement for grep. Recursively scans directories to match a given
|
32
|
+
|
33
|
+
Ruby regular expression. Prints highlighted results.
|
34
|
+
|
35
|
+
|
36
|
+
Based on the Perl tool ''ack'' by Andy Lester.'
|
37
|
+
email: sven@q-logix.de
|
38
|
+
executables:
|
39
|
+
- prak
|
40
|
+
extensions: []
|
41
|
+
extra_rdoc_files:
|
42
|
+
- History.txt
|
43
|
+
- Manifest.txt
|
44
|
+
- README.txt
|
45
|
+
files:
|
46
|
+
- History.txt
|
47
|
+
- Manifest.txt
|
48
|
+
- README.txt
|
49
|
+
- Rakefile
|
50
|
+
- bin/prak
|
51
|
+
- lib/prak.rb
|
52
|
+
- lib/prak/bootstrap.rb
|
53
|
+
- lib/prak/command_line.rb
|
54
|
+
- lib/prak/compile_match_file.rb
|
55
|
+
- lib/prak/file.rb
|
56
|
+
- lib/prak/search.rb
|
57
|
+
- prak.gemspec
|
58
|
+
- .gemtest
|
59
|
+
homepage:
|
60
|
+
licenses: []
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- --main
|
64
|
+
- README.txt
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ! '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubyforge_project: prak
|
81
|
+
rubygems_version: 1.8.6
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: A grep replacement in Ruby, type "$prak pattern".
|
85
|
+
test_files: []
|