ssoroka-grepmate 1.0.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.
- 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
|
+
|