ssoroka-grepmate 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest +4 -0
- data/README +47 -0
- data/Rakefile +14 -0
- data/bin/grepmate +292 -0
- data/grepmate.gemspec +34 -0
- metadata +71 -0
data/Manifest
ADDED
data/README
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
= grepmate
|
2
|
+
|
3
|
+
Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output
|
4
|
+
|
5
|
+
== SYNOPSIS
|
6
|
+
|
7
|
+
grepmate [what_to_search_for*] [dir=dir] [exclude=exclude] [options]+
|
8
|
+
|
9
|
+
== PARAMETERS
|
10
|
+
|
11
|
+
what_to_search_for (-1 ~> what_to_search_for)
|
12
|
+
What to search for. Enclose in quotes to search for phrase.
|
13
|
+
dir=dir (-1 ~>
|
14
|
+
dir=app,config,db,lib,spec,public,vendor/plugins,test/selenium_fixtures,test/selenium)
|
15
|
+
Directories to search. Defaults to project.
|
16
|
+
exclude=exclude (-1 ~>
|
17
|
+
exclude=\.sql$,\.log$,\.tmp$,\.gz$,\.bz2$,\.tar$,\.db$,\.sqlite$,\.sqlite3$,\.csv$,\.DS_Store$,\.svn,\.git,\.CSV$,grepmate\.html$)
|
18
|
+
Exclude paths matching these patterns.
|
19
|
+
--case
|
20
|
+
Case sensitive search (exclude for case insensitive).
|
21
|
+
--no_html, -H
|
22
|
+
Turn off HTML output.
|
23
|
+
--only_rails, -R
|
24
|
+
Search Rails source, not the project. Takes precedence over dir=
|
25
|
+
--rails, -r
|
26
|
+
Search Rails source, in addition to whatever is named by dir= dir=
|
27
|
+
etc.
|
28
|
+
--gems, -g
|
29
|
+
Search all gems, in addition to whatever is named by dir= dir= etc.
|
30
|
+
--only_gems, -G
|
31
|
+
Search only gems, not the project. Takes precedence over dir=
|
32
|
+
--wait, -w
|
33
|
+
Wait between finds until TextMate is closed. Only works with
|
34
|
+
--no_html.
|
35
|
+
--count, -c
|
36
|
+
Display only the number of matches.
|
37
|
+
--help, -h
|
38
|
+
|
39
|
+
== Authors
|
40
|
+
|
41
|
+
- Steven Soroka
|
42
|
+
- Zach Holt
|
43
|
+
|
44
|
+
== To Do
|
45
|
+
|
46
|
+
- check ~/.grepmate for current rails repo to use instead of always using latest
|
47
|
+
- change output file to write to /tmp or something
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
Echoe.new('grepmate', '1.0.0') do |p|
|
6
|
+
p.description = 'Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output'
|
7
|
+
p.url = 'http://github.com/ssoroka/grepmate'
|
8
|
+
p.author = 'Steven Soroka'
|
9
|
+
p.email = 'ssoroka78@gmail.com'
|
10
|
+
p.ignore_pattern = ["tmp/*"]
|
11
|
+
p.development_dependencies = ['main']
|
12
|
+
end
|
13
|
+
|
14
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each{|f| load f }
|
data/bin/grepmate
ADDED
@@ -0,0 +1,292 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# script/grepmate brought to you by Steven Soroka and Zach Holt
|
3
|
+
# script/grepmate --help for help screen
|
4
|
+
require 'rubygems'
|
5
|
+
gem 'main', '>=2.8.0'
|
6
|
+
require 'main' # don't think this line is needed. gem should require it
|
7
|
+
|
8
|
+
|
9
|
+
def gem_path
|
10
|
+
`gem environment gemdir`.chomp
|
11
|
+
end
|
12
|
+
|
13
|
+
def gems_path
|
14
|
+
File.join(gem_path, 'gems')
|
15
|
+
end
|
16
|
+
|
17
|
+
def rails_version
|
18
|
+
`rails -v`.chomp.split(' ').last
|
19
|
+
end
|
20
|
+
|
21
|
+
def rails_path
|
22
|
+
vendor_rails = "vendor/rails"
|
23
|
+
|
24
|
+
if File.exist?(vendor_rails)
|
25
|
+
vendor_rails
|
26
|
+
else
|
27
|
+
Dir["#{gems_path}/acti*-#{rails_version}"]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Main {
|
32
|
+
option( 'case' ) {
|
33
|
+
cast :bool
|
34
|
+
description 'Case sensitive search (exclude for case insensitive).'
|
35
|
+
}
|
36
|
+
|
37
|
+
option( 'no_html', 'H' ) {
|
38
|
+
cast :bool
|
39
|
+
description 'Turn off HTML output.'
|
40
|
+
}
|
41
|
+
|
42
|
+
option( 'only_rails', 'R' ) {
|
43
|
+
cast :bool
|
44
|
+
description 'Search Rails source, not the project. Takes precedence over dir='
|
45
|
+
}
|
46
|
+
|
47
|
+
option( 'rails', 'r' ) {
|
48
|
+
cast :bool
|
49
|
+
description 'Search Rails source, in addition to whatever is named by dir= dir= etc.'
|
50
|
+
}
|
51
|
+
|
52
|
+
option('gems', 'g') {
|
53
|
+
cast :bool
|
54
|
+
description "Search all gems, in addition to whatever is named by dir= dir= etc."
|
55
|
+
}
|
56
|
+
|
57
|
+
option('only_gems', 'G') {
|
58
|
+
cast :bool
|
59
|
+
description "Search only gems, not the project. Takes precedence over dir="
|
60
|
+
}
|
61
|
+
|
62
|
+
option( 'wait', 'w' ) {
|
63
|
+
cast :bool
|
64
|
+
description 'Wait between finds until TextMate is closed. Only works with --no_html.'
|
65
|
+
}
|
66
|
+
|
67
|
+
option( 'count', 'c' ) {
|
68
|
+
cast :bool
|
69
|
+
description 'Display only the number of matches.'
|
70
|
+
}
|
71
|
+
|
72
|
+
keyword( 'dir', 'd' ) {
|
73
|
+
arity -1
|
74
|
+
default 'app', 'config', 'db', 'lib', 'spec', 'public', 'vendor/plugins', 'test/selenium_fixtures', 'test/selenium'
|
75
|
+
description 'Directories to search. Defaults to project.'
|
76
|
+
}
|
77
|
+
|
78
|
+
keyword( 'exclude' ) {
|
79
|
+
arity -1
|
80
|
+
cast { |v| Regexp.new( v ) }
|
81
|
+
default '\.sql$', '\.log$', '\.tmp$', '\.gz$', '\.bz2$', '\.tar$', '\.db$', '\.sqlite$', '\.sqlite3$', '\.csv$', '\.DS_Store$', '\.svn', '\.git', '\.CSV$', 'grepmate\.html$'
|
82
|
+
description 'Exclude paths matching these patterns.'
|
83
|
+
}
|
84
|
+
|
85
|
+
argument( 'what_to_search_for' ) {
|
86
|
+
arity -1
|
87
|
+
description "What to search for. Enclose in quotes to search for phrase."
|
88
|
+
}
|
89
|
+
|
90
|
+
|
91
|
+
def determine_directories_to_search
|
92
|
+
if @stdin.tty?
|
93
|
+
dirs = if params['only_rails'].value || params['only_gems'].value
|
94
|
+
[]
|
95
|
+
else
|
96
|
+
params['dir'].values
|
97
|
+
end
|
98
|
+
dirs += Array(rails_path) if params['only_rails'].value || params['rails'].value
|
99
|
+
dirs << gems_path if params['only_gems'].value || params['gems'].value
|
100
|
+
else
|
101
|
+
dirs = []
|
102
|
+
input = @stdin.read
|
103
|
+
|
104
|
+
input.split( "\n" ).each do |ln|
|
105
|
+
if ln =~ /^([^:]*)/ # Assume everything to the first colon is a file name
|
106
|
+
filename = File.expand_path( $1 )
|
107
|
+
if File.exist?( filename ) # But actually check that it is
|
108
|
+
dirs << filename
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
dirs.map{ |dir| File.expand_path( dir ) }.uniq
|
114
|
+
end
|
115
|
+
|
116
|
+
def determine_what_to_search_for
|
117
|
+
# funny bunny => 'funny' 'bunny'
|
118
|
+
# 'funny bunny' => 'funny bunny'
|
119
|
+
params['what_to_search_for'].values.map {|v| "\"#{v.gsub( /"/, '\\"' )}\"" }.join( " " )
|
120
|
+
end
|
121
|
+
|
122
|
+
def determine_javascript_highlight_text
|
123
|
+
# funny bunny => 'funny' 'bunny'
|
124
|
+
# 'funny bunny' => 'funny bunny'
|
125
|
+
params['what_to_search_for'].values.map {|v| "highlightSearchTerms('#{v.gsub( /'/, "\\'" ).gsub( /:/, "\\:" )}', false)" }.join( ";" )
|
126
|
+
end
|
127
|
+
|
128
|
+
def find( what_to_find, opts={} )
|
129
|
+
directories = opts[:in]
|
130
|
+
|
131
|
+
paths = `find #{directories.join(' ')}`.split( "\n" )
|
132
|
+
|
133
|
+
paths.delete_if { |path| params['exclude'].values.any?{ |exclude| path =~ exclude } }
|
134
|
+
|
135
|
+
cmd = 'grep '
|
136
|
+
cmd << '-i ' unless params['case'].value
|
137
|
+
# 3 lines of context unless we're not displaying html, or we're counting, or we're piping into another process
|
138
|
+
cmd << '-C 3 ' if !params['no_html'].value && !params['count'].value && @stdout.tty?
|
139
|
+
|
140
|
+
# paths get too large for grep to handle, so limit the number it has to deal with at once.
|
141
|
+
results = []
|
142
|
+
paths.each_slice(100) {|paths|
|
143
|
+
results += `#{cmd} -n #{what_to_find} #{paths.join(" ")}`.split( "\n" )
|
144
|
+
}
|
145
|
+
results
|
146
|
+
end
|
147
|
+
|
148
|
+
def display( results )
|
149
|
+
if results.empty?
|
150
|
+
puts "Nothing found!"
|
151
|
+
exit
|
152
|
+
elsif params['count'].value
|
153
|
+
puts "Matches: #{results.size}"
|
154
|
+
exit
|
155
|
+
end
|
156
|
+
|
157
|
+
if @stdout.tty?
|
158
|
+
if params['no_html'].value
|
159
|
+
display_textmate results
|
160
|
+
else
|
161
|
+
display_html results
|
162
|
+
end
|
163
|
+
else
|
164
|
+
puts results
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def display_textmate( results )
|
169
|
+
print "Found #{results.size} matches. "
|
170
|
+
if results.size > 20
|
171
|
+
puts "Display? [Y/n]..."
|
172
|
+
exit if $stdin.gets.chomp.downcase == 'n'
|
173
|
+
end
|
174
|
+
|
175
|
+
results.each { |f|
|
176
|
+
file, line = f.split( ':' )
|
177
|
+
system( "mate #{'-w ' if params['wait'].value}-l #{line} #{file}" )
|
178
|
+
}
|
179
|
+
end
|
180
|
+
|
181
|
+
def display_html( results )
|
182
|
+
syntax_installed = true
|
183
|
+
begin
|
184
|
+
require 'syntax/convertors/html'
|
185
|
+
rescue LoadError
|
186
|
+
syntax_installed = false
|
187
|
+
end
|
188
|
+
|
189
|
+
html = '<html><head>'
|
190
|
+
html << <<-CSS
|
191
|
+
<style type="text/css">body { background-color: #EEEEEE; } pre {
|
192
|
+
display: inline; } .ruby { font-family: Monaco; font-size: 10pt;
|
193
|
+
background-color: white } .ruby .normal {} .ruby .comment { color:
|
194
|
+
#005; font-style: italic; } .ruby .keyword { color: #A00; font-weight:
|
195
|
+
bold; } .ruby .method { color: #077; } .ruby .class { color: #074; }
|
196
|
+
.ruby .module { color: #050; } .ruby .punct { color: #447; font-weight:
|
197
|
+
bold; } .ruby .symbol { color: #099; } .ruby .string { color: #944;
|
198
|
+
background: #FFE; } .ruby .char { color: #F07; } .ruby .ident { color:
|
199
|
+
#004; } .ruby .constant { color: #07F; } .ruby .regex { color: #B66;
|
200
|
+
background: #FEF; } .ruby .number { color: #F99; } .ruby .attribute {
|
201
|
+
color: #7BB; } .ruby .global { color: #7FB; } .ruby .expr { color:
|
202
|
+
#227; } .ruby .escape { color: #277; } .ruby .highlight {
|
203
|
+
background-color: yellow; font-weight: 900; } td.lineno { text-align:
|
204
|
+
right; font-family: Monaco; font-size: 9pt; padding-right: 10px; }
|
205
|
+
td.filename { padding-top: 35px; font-family: Monaco; font-size: 14pt;
|
206
|
+
}</style>
|
207
|
+
|
208
|
+
<script type="text/javascript">
|
209
|
+
// http://www.nsftools.com/misc/SearchAndHighlight.htm
|
210
|
+
|
211
|
+
function doHighlight(bodyText,searchTerm,highlightStartTag,highlightEndTag)
|
212
|
+
{if((!highlightStartTag)||(!highlightEndTag)){highlightStartTag="<font style='color:blue; background-color:yellow;'>";highlightEndTag="</font>";}
|
213
|
+
var newText="";var i=-1;var lcSearchTerm=searchTerm.toLowerCase();var lcBodyText=bodyText.toLowerCase();while(bodyText.length>0){i=lcBodyText.indexOf(lcSearchTerm,i+1);if(i<0){newText+=bodyText;bodyText="";}else{if(bodyText.lastIndexOf(">",i)>=bodyText.lastIndexOf("<",i)){if(lcBodyText.lastIndexOf("/script>",i)>=lcBodyText.lastIndexOf("<script",i)){newText+=bodyText.substring(0,i)+highlightStartTag+bodyText.substr(i,searchTerm.length)+highlightEndTag;bodyText=bodyText.substr(i+searchTerm.length);lcBodyText=bodyText.toLowerCase();i=-1;}}}}
|
214
|
+
return newText;}
|
215
|
+
function highlightSearchTerms(searchText,treatAsPhrase,warnOnFailure,highlightStartTag,highlightEndTag)
|
216
|
+
{if(treatAsPhrase){searchArray=[searchText];}else{searchArray=searchText.split(" ");}
|
217
|
+
if(!document.body||typeof(document.body.innerHTML)=="undefined"){if(warnOnFailure){alert("Sorry, for some reason the text of this page is unavailable. Searching will not work.");}
|
218
|
+
return false;}
|
219
|
+
var bodyText=document.body.innerHTML;for(var i=0;i<searchArray.length;i++){bodyText=doHighlight(bodyText,searchArray[i],highlightStartTag,highlightEndTag);}
|
220
|
+
document.body.innerHTML=bodyText;return true;}</script></script>
|
221
|
+
CSS
|
222
|
+
|
223
|
+
html << "</head><body onLoad=\"#{determine_javascript_highlight_text}\">"
|
224
|
+
|
225
|
+
syntax_converter = ( syntax_installed ? Syntax::Convertors::HTML.for_syntax( "ruby" ) : nil )
|
226
|
+
html << '<pre>sudo gem install syntax</pre> to get syntax highlighting<br><br>' unless syntax_installed
|
227
|
+
|
228
|
+
html << '<table cellspacing="0" cellpadding="2">'
|
229
|
+
|
230
|
+
last_file = ''
|
231
|
+
separator = false
|
232
|
+
|
233
|
+
html << results.map{ |line|
|
234
|
+
if line == '--'
|
235
|
+
separator = true
|
236
|
+
''
|
237
|
+
elsif line =~ /^(.+?)-(\d+)-(.*)$/ || line =~ /^(.+?):(\d+):(.*)$/
|
238
|
+
file = $1
|
239
|
+
line = $2
|
240
|
+
context = $3
|
241
|
+
|
242
|
+
file_group = ''
|
243
|
+
|
244
|
+
if file == last_file
|
245
|
+
file_group << "<tr><td class=\"lineno\">...</td><td></td></tr>" if separator
|
246
|
+
else
|
247
|
+
parts = file.split( /\// )
|
248
|
+
path = ''
|
249
|
+
file_group << "<tr><td colspan=\"2\" class=\"filename\">"
|
250
|
+
parts.each do |part|
|
251
|
+
path << "/#{part}"
|
252
|
+
file_group << "/" unless part.equal?( parts.first )
|
253
|
+
if part.equal?( parts.last )
|
254
|
+
file_group << "<a href=\"txmt://open?url=file://#{file}\">#{part}</a>"
|
255
|
+
else
|
256
|
+
file_group << "<a href=\"file:/#{path}\">#{part}</a>"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
file_group << "</td></tr>\n"
|
260
|
+
end
|
261
|
+
|
262
|
+
separator = false
|
263
|
+
last_file = file
|
264
|
+
|
265
|
+
file_group << "<tr><td class=\"lineno\"><a href=\"txmt://open?url=file://#{file}&line=#{line}\">#{line}</a></td>"
|
266
|
+
|
267
|
+
converted = begin
|
268
|
+
syntax_converter ? syntax_converter.convert( context =~ /^(.+?)\s*$/ ? $1 : context ) : context
|
269
|
+
rescue Exception => e
|
270
|
+
"TOKENIZING ERROR: #{context} <!-- \n#{e.message}\n#{e.backtrace.join("\n")}\n -->"
|
271
|
+
end
|
272
|
+
file_group << "<td class=\"ruby\">#{ converted }</td></tr>\n"
|
273
|
+
|
274
|
+
file_group
|
275
|
+
end
|
276
|
+
}.join
|
277
|
+
|
278
|
+
html << '</table></body></html>'
|
279
|
+
|
280
|
+
File.open('grepmate.html', 'w') { |f| f.write(html) }
|
281
|
+
system("open grepmate.html")
|
282
|
+
end
|
283
|
+
|
284
|
+
def run
|
285
|
+
haystack = determine_directories_to_search
|
286
|
+
needle = determine_what_to_search_for
|
287
|
+
|
288
|
+
results = find needle, :in => haystack
|
289
|
+
|
290
|
+
display results
|
291
|
+
end
|
292
|
+
}
|
data/grepmate.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{grepmate}
|
3
|
+
s.version = "1.0.0"
|
4
|
+
|
5
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
6
|
+
s.authors = ["Steven Soroka"]
|
7
|
+
s.date = %q{2008-12-05}
|
8
|
+
s.default_executable = %q{grepmate}
|
9
|
+
s.description = %q{Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output}
|
10
|
+
s.email = %q{ssoroka78@gmail.com}
|
11
|
+
s.executables = ["grepmate"]
|
12
|
+
s.extra_rdoc_files = ["bin/grepmate", "README"]
|
13
|
+
s.files = ["bin/grepmate", "Rakefile", "README", "Manifest", "grepmate.gemspec"]
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.homepage = %q{http://github.com/ssoroka/grepmate}
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Grepmate", "--main", "README"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{grepmate}
|
19
|
+
s.rubygems_version = %q{1.2.0}
|
20
|
+
s.summary = %q{Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output}
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 2
|
25
|
+
|
26
|
+
if current_version >= 3 then
|
27
|
+
s.add_development_dependency(%q<main>, [">= 0"])
|
28
|
+
else
|
29
|
+
s.add_dependency(%q<main>, [">= 0"])
|
30
|
+
end
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<main>, [">= 0"])
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ssoroka-grepmate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Steven Soroka
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-12-05 00:00:00 -08:00
|
13
|
+
default_executable: grepmate
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: main
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
version:
|
24
|
+
description: Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output
|
25
|
+
email: ssoroka78@gmail.com
|
26
|
+
executables:
|
27
|
+
- grepmate
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- bin/grepmate
|
32
|
+
- README
|
33
|
+
files:
|
34
|
+
- bin/grepmate
|
35
|
+
- Rakefile
|
36
|
+
- README
|
37
|
+
- Manifest
|
38
|
+
- grepmate.gemspec
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://github.com/ssoroka/grepmate
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options:
|
43
|
+
- --line-numbers
|
44
|
+
- --inline-source
|
45
|
+
- --title
|
46
|
+
- Grepmate
|
47
|
+
- --main
|
48
|
+
- README
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "1.2"
|
62
|
+
version:
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project: grepmate
|
66
|
+
rubygems_version: 1.2.0
|
67
|
+
signing_key:
|
68
|
+
specification_version: 2
|
69
|
+
summary: Extremely fast search of rails projects or rails source for code, open in textmate or browser with html output
|
70
|
+
test_files: []
|
71
|
+
|