ssoroka-grepmate 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/Manifest +4 -0
  2. data/README +47 -0
  3. data/Rakefile +14 -0
  4. data/bin/grepmate +292 -0
  5. data/grepmate.gemspec +34 -0
  6. metadata +71 -0
data/Manifest ADDED
@@ -0,0 +1,4 @@
1
+ bin/grepmate
2
+ Rakefile
3
+ README
4
+ Manifest
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
+