bloopletech-rtags 0.99.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +55 -0
- data/README +8 -0
- data/RELEASENOTES +43 -0
- data/TODO +40 -0
- data/bin/rtags +861 -0
- metadata +54 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
rtags is copyrighted free software.
|
2
|
+
|
3
|
+
You can redistribute it and/or modify it under either the terms of the GPL
|
4
|
+
(see COPYING.txt file), or the conditions below:
|
5
|
+
|
6
|
+
1. You may make and give away verbatim copies of the source form of the
|
7
|
+
software without restriction, provided that you duplicate all of the
|
8
|
+
original copyright notices and associated disclaimers.
|
9
|
+
|
10
|
+
2. You may modify your copy of the software in any way, provided that
|
11
|
+
you do at least ONE of the following:
|
12
|
+
|
13
|
+
a) place your modifications in the Public Domain or otherwise
|
14
|
+
make them Freely Available, such as by posting said
|
15
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
16
|
+
the author to include your modifications in the software.
|
17
|
+
|
18
|
+
b) use the modified software only within your corporation or
|
19
|
+
organization.
|
20
|
+
|
21
|
+
c) rename any non-standard executables so the names do not conflict
|
22
|
+
with standard executables, which must also be provided.
|
23
|
+
|
24
|
+
d) make other distribution arrangements with the author.
|
25
|
+
|
26
|
+
3. You may distribute the software in object code or executable
|
27
|
+
form, provided that you do at least ONE of the following:
|
28
|
+
|
29
|
+
a) distribute the executables and library files of the software,
|
30
|
+
together with instructions (in the manual page or equivalent)
|
31
|
+
on where to get the original distribution.
|
32
|
+
|
33
|
+
b) accompany the distribution with the machine-readable source of
|
34
|
+
the software.
|
35
|
+
|
36
|
+
c) give non-standard executables non-standard names, with
|
37
|
+
instructions on where to get the original software distribution.
|
38
|
+
|
39
|
+
d) make other distribution arrangements with the author.
|
40
|
+
|
41
|
+
4. You may modify and include the part of the software into any other
|
42
|
+
software (possibly commercial). But some files in the distribution
|
43
|
+
are not written by the author, so that they are not under this terms.
|
44
|
+
|
45
|
+
5. The scripts and library files supplied as input to or produced as
|
46
|
+
output from the software do not automatically fall under the
|
47
|
+
copyright of the software, but belong to whomever generated them,
|
48
|
+
and may be sold commercially, and may be aggregated with this
|
49
|
+
software.
|
50
|
+
|
51
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
52
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
53
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
54
|
+
PURPOSE.
|
55
|
+
|
data/README
ADDED
data/RELEASENOTES
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
rtags.rb -
|
2
|
+
|
3
|
+
Release Version: 0.96 (April 2006) by Pjotr Prins
|
4
|
+
Improved filtering on repository files (skip _darcs, CVS, .SVN)
|
5
|
+
Test for hash bang Ruby - if no .rb extension
|
6
|
+
|
7
|
+
Release Version: 0.95 (December 2006) by Pjotr Prins
|
8
|
+
Added -R/--recurse switch by Chetan Patil
|
9
|
+
Added regression tests for recursion
|
10
|
+
|
11
|
+
Release Version: 0.94 (December 2006) by Pjotr Prins
|
12
|
+
Added support for ClassName.new tags - which point to the
|
13
|
+
Class def initialize methods
|
14
|
+
|
15
|
+
Release Version: 0.93 (August 2006) by Pjotr Prins
|
16
|
+
Fixed bug where multiple lines were written to tags file - which
|
17
|
+
broke them for vi
|
18
|
+
Fixed infinite loop for specific cases
|
19
|
+
Added -a switch (append mode)
|
20
|
+
Turned warnings off by default (-w switch)
|
21
|
+
Included RELEASENOTES in gem
|
22
|
+
More regression testing (-a, tags, TAGS)
|
23
|
+
Run regression test before making a release
|
24
|
+
|
25
|
+
Release Version: 0.92 (August 2006) by Pjotr Prins
|
26
|
+
Added catching of parse errors
|
27
|
+
Fixed exit on 'alias' token error (`parse_alias': undefined method `name')
|
28
|
+
Added support for command line arguments with optparse
|
29
|
+
Added debug switches (--debug, --debug_tokens)
|
30
|
+
Print to stderr on debug
|
31
|
+
Added support for alternate tags filename (-f switch)
|
32
|
+
Added --quiet switch
|
33
|
+
Added regression files to ./test
|
34
|
+
|
35
|
+
Release Version: 0.91 (July 2006) by Pjotr Prins
|
36
|
+
First independent public release on RubyForge
|
37
|
+
Depends on irb 0.9
|
38
|
+
Wrote install.sh and gem packaging
|
39
|
+
|
40
|
+
Release Version: 0.9 (2002/07/09) by Keiju ISHITSUKA
|
41
|
+
Released as part of irb source tree
|
42
|
+
|
43
|
+
|
data/TODO
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
TODO
|
2
|
+
|
3
|
+
For version 1.0:
|
4
|
+
|
5
|
+
- Recognise 'alias :name' tokens
|
6
|
+
- include the argument list and an end of line $ pattern (at least the
|
7
|
+
first opening parenthesis should be included in the pattern)
|
8
|
+
- indicate whether the entry is a c(lass), a m(odule), or a f (method)
|
9
|
+
like ctags
|
10
|
+
|
11
|
+
Later:
|
12
|
+
|
13
|
+
- Add switch for not following symlinks
|
14
|
+
- Fix class Foo::Bar to show as such in the TAGS file
|
15
|
+
- Find modules with double colon notation like "BIO::MODULE::IO"
|
16
|
+
- Cache class names so classes can be found that lack an initialize
|
17
|
+
method
|
18
|
+
- Provide - command line switch, allowing for
|
19
|
+
find . -name '*.rb' -print | rtags -
|
20
|
+
|
21
|
+
MUSINGS
|
22
|
+
|
23
|
+
Apart from adding the - switch at some point in the future it would
|
24
|
+
be neat to have smarter tags. For one, if a class has not initialize
|
25
|
+
method we would like to jump to the class definition on
|
26
|
+
Classname.new. If we were to store the tags we find in memory
|
27
|
+
(instead of just writing them out, as is the current behaviour) it
|
28
|
+
would be trivial to implement.
|
29
|
+
|
30
|
+
Also some tokens (alias) and multilines are not handled correctly.
|
31
|
+
|
32
|
+
Try:
|
33
|
+
|
34
|
+
cd ./test ruby ../bin/rtags -R
|
35
|
+
|
36
|
+
and you get
|
37
|
+
|
38
|
+
Warn: parse error in <./data/report.rb> in line 170, pos 4
|
39
|
+
|
40
|
+
which is an unrecognised alias.
|
data/bin/rtags
ADDED
@@ -0,0 +1,861 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# rtags is a Ruby replacement for ctags - allowing for name navigation in
|
4
|
+
# source code using vim, emacs and others.
|
5
|
+
#
|
6
|
+
# by Keiju ISHITSUKA and Pjotr Prins
|
7
|
+
#
|
8
|
+
# LICENSE: RUBY LICENSE - see file LICENSE.TXT
|
9
|
+
# INSTALL: see file README
|
10
|
+
# RELEASE NOTES: see file RELEASENOTES
|
11
|
+
|
12
|
+
RTAGS_VERSION='0.99.1 (January 2013)'
|
13
|
+
|
14
|
+
require 'optparse'
|
15
|
+
require 'ostruct'
|
16
|
+
|
17
|
+
usage = <<USAGE
|
18
|
+
|
19
|
+
rtags #{RTAGS_VERSION} (Ruby tags) by Keiju ISHITSUKA
|
20
|
+
improvements by Pjotr Prins, Chetan Patil, Gaizka Villane, Brenton Fletcher
|
21
|
+
|
22
|
+
A Ruby tool for using Ruby tags rendering more tags than
|
23
|
+
other tools for use with vim or emacs
|
24
|
+
|
25
|
+
For info see http://rtags.rubyforge.org/
|
26
|
+
|
27
|
+
usage:
|
28
|
+
|
29
|
+
rtags [--vi] [-R] filenames
|
30
|
+
rtags --help
|
31
|
+
|
32
|
+
by default creates an emacs tags file. With the --vi switch
|
33
|
+
a vim tags file is created instead.
|
34
|
+
|
35
|
+
USAGE
|
36
|
+
|
37
|
+
|
38
|
+
$options = OpenStruct.new()
|
39
|
+
$options.warning_level = 0
|
40
|
+
$options.recurse = false
|
41
|
+
|
42
|
+
OptionParser.new do |opts|
|
43
|
+
opts.on_tail("-h", "--help", "Print this message") do
|
44
|
+
print(usage)
|
45
|
+
print(opts)
|
46
|
+
print <<EXAMPLE
|
47
|
+
|
48
|
+
Examples:
|
49
|
+
|
50
|
+
rtags *.rb
|
51
|
+
rtags -x *.rb
|
52
|
+
rtags -R <path>
|
53
|
+
rtags --vi -f vim_tags *.rb
|
54
|
+
rtags `find ~/src/ -name *.rb|grep -v _darcs`
|
55
|
+
|
56
|
+
EXAMPLE
|
57
|
+
exit()
|
58
|
+
end
|
59
|
+
|
60
|
+
opts.on("-f tagfile", String, "Output to tagfile") do |s|
|
61
|
+
$options.tagfile = s
|
62
|
+
end
|
63
|
+
opts.on("-a", "append mode") do
|
64
|
+
$options.tagfile_mode = 'a'
|
65
|
+
end
|
66
|
+
opts.on("-w level", Integer, "Warning level (default 0)") do |w|
|
67
|
+
$options.warning_level = w
|
68
|
+
end
|
69
|
+
opts.on("--vi", "Use vi type tags (default is emacs)") do
|
70
|
+
$options.vi = true
|
71
|
+
end
|
72
|
+
opts.on("-x", "Print cross reference file to stdout") do
|
73
|
+
$options.xref = true
|
74
|
+
end
|
75
|
+
opts.on("-b", "When using -x, only print base name. E.g., print only 'method' and not '::Module::Class#method'") do
|
76
|
+
$options.xref_only_base = true
|
77
|
+
end
|
78
|
+
opts.on("-B", "When using -x, only print absolute name. E.g., print only '::Module::Class#method' and not 'method'. Inverse of -b") do
|
79
|
+
$options.xref_only_abs = true
|
80
|
+
end
|
81
|
+
opts.on("--quiet", "Quiet mode") do
|
82
|
+
$options.quiet = true
|
83
|
+
end
|
84
|
+
opts.on("--debug", "Debug output to stderr") do
|
85
|
+
$options.debug = true
|
86
|
+
end
|
87
|
+
opts.on("--debug_tokens", "Debug token information to stdout") do
|
88
|
+
$options.debug_tokens = true
|
89
|
+
end
|
90
|
+
opts.on("-R", "--recurse", "Recurse path for .rb files (default '.')") do
|
91
|
+
$options.recurse = true
|
92
|
+
end
|
93
|
+
opts.on("-L file", String, "Read from file a list of file names for which tags should be generated.") do |f|
|
94
|
+
$options.files_in_list = f
|
95
|
+
end
|
96
|
+
end.parse!(ARGV)
|
97
|
+
|
98
|
+
if $options.tagfile == nil
|
99
|
+
if $options.vi
|
100
|
+
$options.tagfile = 'tags'
|
101
|
+
else
|
102
|
+
$options.tagfile = 'TAGS'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
$options.tagfile_mode = 'w' if $options.tagfile_mode == nil
|
106
|
+
$options.warning_level = -1 if $options.quiet
|
107
|
+
if $options.recurse and ARGV.size == 0
|
108
|
+
ARGV.push '.'
|
109
|
+
end
|
110
|
+
|
111
|
+
print "\nrtags.rb #{RTAGS_VERSION} writing to file '#{$options.tagfile}'\n" if (!$options.quiet && !$options.xref)
|
112
|
+
|
113
|
+
require "e2mmap"
|
114
|
+
require "tracer"
|
115
|
+
|
116
|
+
require "irb/ruby-lex"
|
117
|
+
require "irb/ruby-token"
|
118
|
+
|
119
|
+
class RubyLex
|
120
|
+
def identify_string_dvar
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
require "stringio"
|
125
|
+
|
126
|
+
module RTAGS
|
127
|
+
@RCS_ID='-rtags.rb 0.95 -'
|
128
|
+
|
129
|
+
class RTToken
|
130
|
+
def initialize(readed, context, name, token)
|
131
|
+
@readed = readed
|
132
|
+
@context = context
|
133
|
+
@name = name
|
134
|
+
@token = token
|
135
|
+
end
|
136
|
+
attr :readed
|
137
|
+
attr :context
|
138
|
+
attr :name
|
139
|
+
attr :token
|
140
|
+
|
141
|
+
def line_no
|
142
|
+
@token.line_no
|
143
|
+
end
|
144
|
+
|
145
|
+
def seek
|
146
|
+
@token.seek
|
147
|
+
end
|
148
|
+
|
149
|
+
def to_s
|
150
|
+
"#{def_name} #{abs_name} in #{token.inspect}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
class RTModule < RTToken
|
155
|
+
def abs_name
|
156
|
+
(context || "") + "::" + name
|
157
|
+
end
|
158
|
+
|
159
|
+
def def_name
|
160
|
+
"module"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class RTClass < RTModule
|
165
|
+
def abs_name
|
166
|
+
(context || "") + "::" + name
|
167
|
+
end
|
168
|
+
|
169
|
+
def def_name
|
170
|
+
"class"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
class RTSingleClass < RTClass
|
175
|
+
def abs_name
|
176
|
+
(context || "") + "<<" + name
|
177
|
+
end
|
178
|
+
|
179
|
+
def def_name
|
180
|
+
"class"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
class RTMethod < RTToken
|
185
|
+
def abs_name
|
186
|
+
(context || "") + "#" + name
|
187
|
+
end
|
188
|
+
|
189
|
+
def def_name
|
190
|
+
"method"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
class RTAlias < RTMethod
|
195
|
+
def def_name
|
196
|
+
"alias"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
class RTAttr < RTMethod
|
201
|
+
def def_name
|
202
|
+
"attr"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
class RTClassCall < RTMethod
|
207
|
+
def abs_name
|
208
|
+
(context || "") + "!" + (token.name == name ? name : "#{token.name}(#{name})")
|
209
|
+
end
|
210
|
+
|
211
|
+
def def_name
|
212
|
+
"class call"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
class RTSingleMethod < RTToken
|
217
|
+
def abs_name
|
218
|
+
(context || "") + "." + name
|
219
|
+
end
|
220
|
+
|
221
|
+
def def_name
|
222
|
+
"class method"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
class RTSingleAlias < RTSingleMethod
|
227
|
+
def def_name
|
228
|
+
"alias"
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
class RTSingleAttr < RTSingleMethod
|
233
|
+
def def_name
|
234
|
+
"attr"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
class RTSingleClassCall < RTSingleMethod
|
239
|
+
def abs_name
|
240
|
+
(context || "") + ":" + (token.name == name ? name : "#{token.name}(#{name})")
|
241
|
+
end
|
242
|
+
|
243
|
+
def def_name
|
244
|
+
"class call"
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
class Parser
|
249
|
+
include RubyToken
|
250
|
+
|
251
|
+
def initialize(file_name)
|
252
|
+
@size = 0
|
253
|
+
@input_file_name = file_name
|
254
|
+
@scanner = RubyLex.new
|
255
|
+
@scanner.exception_on_syntax_error = false
|
256
|
+
# @scanner.skip_space = true
|
257
|
+
# @scanner.readed_auto_clean_up = true
|
258
|
+
#parse_statements
|
259
|
+
end
|
260
|
+
|
261
|
+
# display warnings on stderr, depending on the set warning_level
|
262
|
+
|
263
|
+
def warn s,level=0,token=nil,extra=nil
|
264
|
+
if level <= $options.warning_level
|
265
|
+
$stderr.print "\nWarn: #{s} in <#{@input_file_name}> "
|
266
|
+
if token
|
267
|
+
$stderr.print "in line #{token.line_no}, pos #{token.char_no}"
|
268
|
+
# $stderr.print "by name <#{token.name}>" if token and token.name
|
269
|
+
$stderr.print "\n"
|
270
|
+
end
|
271
|
+
if $options.debug
|
272
|
+
$stderr.print "Token=",token.inspect,"\n" if token
|
273
|
+
$stderr.print extra if extra
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# Scan +@input_file_name+ for tags and yields each tag
|
279
|
+
|
280
|
+
def scan(&block)
|
281
|
+
print "\nParsing #{@input_file_name}..." if (!$options.quiet && !$options.xref)
|
282
|
+
|
283
|
+
input = StringIO.new(File.read(@input_file_name) + "\n")
|
284
|
+
@tokens = []
|
285
|
+
@unget_readed = []
|
286
|
+
@readed = []
|
287
|
+
@scanner.set_input(input)
|
288
|
+
parse_statements(&block)
|
289
|
+
end
|
290
|
+
|
291
|
+
# get the next token - fetching it from the temporary +@tokens+
|
292
|
+
# stack if it is not empty
|
293
|
+
|
294
|
+
def get_tk
|
295
|
+
if @tokens.empty?
|
296
|
+
tk = @scanner.token
|
297
|
+
@readed.push @scanner.get_readed
|
298
|
+
$stderr.print tk.inspect if $options.debug_tokens
|
299
|
+
tk
|
300
|
+
else
|
301
|
+
@readed.push @unget_readed.shift
|
302
|
+
tk = @tokens.shift
|
303
|
+
$stderr.print tk.inspect if $options.debug_tokens
|
304
|
+
tk
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
# lookahead returning the next token without popping it
|
309
|
+
def peek_tk
|
310
|
+
unget_tk(tk = get_tk)
|
311
|
+
tk
|
312
|
+
end
|
313
|
+
|
314
|
+
# push the token +tk+ back onto the stack
|
315
|
+
def unget_tk(tk)
|
316
|
+
@tokens.unshift tk
|
317
|
+
@unget_readed.unshift @readed.pop
|
318
|
+
end
|
319
|
+
|
320
|
+
def skip_tkspace(skip_nl = true)
|
321
|
+
tokens = []
|
322
|
+
while ((tk = get_tk).kind_of?(TkSPACE) ||
|
323
|
+
(skip_nl && tk.kind_of?(TkNL)))
|
324
|
+
tokens.push tk
|
325
|
+
end
|
326
|
+
unget_tk(tk)
|
327
|
+
tokens
|
328
|
+
end
|
329
|
+
|
330
|
+
# returns the actual token string as it was read and
|
331
|
+
# sets the read buffer to zero length
|
332
|
+
def get_tkreaded
|
333
|
+
readed = @readed.join("")
|
334
|
+
@readed = []
|
335
|
+
readed
|
336
|
+
end
|
337
|
+
|
338
|
+
NORMAL = "::"
|
339
|
+
SINGLE = "<<"
|
340
|
+
|
341
|
+
# The 'grunt' method splits a line into tokens and invokes the
|
342
|
+
# basic parsers for class, module, method etc.
|
343
|
+
|
344
|
+
def parse_statements(context = nil, single = NORMAL, &block)
|
345
|
+
begin
|
346
|
+
last_seekpos = -1
|
347
|
+
nest = 1
|
348
|
+
symbeg = false
|
349
|
+
|
350
|
+
while (tk = get_tk)
|
351
|
+
case tk
|
352
|
+
when TkCLASS
|
353
|
+
parse_class(context, single, tk, &block)
|
354
|
+
when TkMODULE
|
355
|
+
parse_module(context, single, tk, &block)
|
356
|
+
when TkDEF
|
357
|
+
nest += 1
|
358
|
+
parse_method(context, single, tk, &block)
|
359
|
+
when TkALIAS
|
360
|
+
parse_alias(context, single, tk, &block)
|
361
|
+
when TkCASE,
|
362
|
+
TkDO,
|
363
|
+
TkFOR,
|
364
|
+
TkIF,
|
365
|
+
TkUNLESS,
|
366
|
+
TkUNTIL,
|
367
|
+
TkWHILE,
|
368
|
+
TkBEGIN
|
369
|
+
nest += 1
|
370
|
+
when TkSYMBEG
|
371
|
+
symbeg = true
|
372
|
+
when TkIDENTIFIER
|
373
|
+
parse_identifier(context, single, nest, symbeg, tk, &block)
|
374
|
+
symbeg = false
|
375
|
+
when TkEND
|
376
|
+
return if (nest -= 1) == 0
|
377
|
+
end
|
378
|
+
begin
|
379
|
+
get_tkreaded
|
380
|
+
skip_tkspace(false) # don't skip newlines
|
381
|
+
# prevent endless loop (tokenizer does not always behave
|
382
|
+
# at eof)
|
383
|
+
tmp_tk = tk
|
384
|
+
seekpos = tmp_tk.seek if tmp_tk and tmp_tk.seek
|
385
|
+
if last_seekpos == seekpos
|
386
|
+
warn('bailing out early',0,tk)
|
387
|
+
return
|
388
|
+
end
|
389
|
+
last_seekpos = seekpos
|
390
|
+
end while peek_tk == TkNL
|
391
|
+
# p [@input_file_name, peek_tk]
|
392
|
+
end
|
393
|
+
rescue
|
394
|
+
warn('parse error',0,tk,"#{$!.message}:\n#{$!.backtrace.join("\n")}")
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
# Get the full name of the constant including namespaces
|
399
|
+
def parse_full_constant_name(name_token)
|
400
|
+
name = name_token.name
|
401
|
+
if peek_tk.kind_of? TkCOLON2
|
402
|
+
get_tk # skip the ::
|
403
|
+
namespaced_name_token = get_tk
|
404
|
+
rest = parse_full_constant_name(namespaced_name_token)
|
405
|
+
name += '::' + rest unless rest.nil?
|
406
|
+
end
|
407
|
+
|
408
|
+
name
|
409
|
+
end
|
410
|
+
|
411
|
+
def parse_class(context, single, tk, &block)
|
412
|
+
skip_tkspace
|
413
|
+
case name_t = get_tk
|
414
|
+
when TkCONSTANT
|
415
|
+
name = parse_full_constant_name(name_t)
|
416
|
+
if single == SINGLE
|
417
|
+
yield RTSingleClass.new(get_tkreaded, context, name, tk)
|
418
|
+
else
|
419
|
+
yield RTClass.new(get_tkreaded, context, name, tk)
|
420
|
+
end
|
421
|
+
parse_statements((context || "") + single + name, &block)
|
422
|
+
|
423
|
+
when TkLSHFT
|
424
|
+
skip_tkspace
|
425
|
+
case (name_t2 = get_tk)
|
426
|
+
when TkSELF
|
427
|
+
parse_statements(context, SINGLE, &block)
|
428
|
+
when TkCONSTANT, TkIVAR
|
429
|
+
# yield RTSingleClass.new(get_tkreaded, context, name_t2.name, tk)
|
430
|
+
parse_statements((context || "") + "::" + name_t2.name,
|
431
|
+
SINGLE,
|
432
|
+
&block)
|
433
|
+
else
|
434
|
+
warn('unrecognised token',1,name_t2)
|
435
|
+
end
|
436
|
+
else
|
437
|
+
warn('unrecognised token',1,name_t2)
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def parse_module(context, single, tk, &block)
|
442
|
+
skip_tkspace
|
443
|
+
name = get_tk.name
|
444
|
+
yield RTModule.new(get_tkreaded, context, name, tk)
|
445
|
+
parse_statements((context||"") + single + name, &block)
|
446
|
+
end
|
447
|
+
|
448
|
+
def parse_method(context, single, tk, &block)
|
449
|
+
skip_tkspace
|
450
|
+
name_t = get_tk
|
451
|
+
back_tk = skip_tkspace
|
452
|
+
|
453
|
+
if (dot = get_tk).kind_of?(TkDOT)
|
454
|
+
# tricky tech. Not sure when this gets reached - probably
|
455
|
+
# 'static' definitions as part of modules
|
456
|
+
@scanner.instance_eval{@lex_state = EXPR_FNAME}
|
457
|
+
skip_tkspace
|
458
|
+
name_t2 = get_tk
|
459
|
+
case name_t
|
460
|
+
when TkSELF
|
461
|
+
name = name_t2.name
|
462
|
+
when TkId
|
463
|
+
if context and
|
464
|
+
context =~ /^#{name_t.name}$/ || context =~ /::#{name_t.name}$/
|
465
|
+
name = name_t2.name
|
466
|
+
else
|
467
|
+
context = (context || "") + "::" + name_t.name
|
468
|
+
name = name_t2.name
|
469
|
+
end
|
470
|
+
else
|
471
|
+
warn('unrecognised token',1,name_t2)
|
472
|
+
#break
|
473
|
+
end
|
474
|
+
yield RTSingleMethod.new(get_tkreaded, context, name, tk)
|
475
|
+
|
476
|
+
else
|
477
|
+
unget_tk dot
|
478
|
+
back_tk.reverse_each do |tk|
|
479
|
+
unget_tk tk
|
480
|
+
end
|
481
|
+
name = name_t.name
|
482
|
+
# ---- if the method is an initialize make sure the class
|
483
|
+
# initiation (with Class.new) points to the tag
|
484
|
+
if name=='initialize'
|
485
|
+
name = 'new'
|
486
|
+
if context and context =~ /::(\S+)$/
|
487
|
+
name = $1+'.new'
|
488
|
+
end
|
489
|
+
end
|
490
|
+
if single == SINGLE
|
491
|
+
yield RTSingleMethod.new(get_tkreaded, context, name, tk)
|
492
|
+
else
|
493
|
+
yield RTMethod.new(get_tkreaded, context, name, tk)
|
494
|
+
end
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
def parse_alias(context, single, tk, &block)
|
499
|
+
skip_tkspace
|
500
|
+
if (token = get_tk).is_a? TkSYMBEG
|
501
|
+
# Name is in next token
|
502
|
+
token = get_tk
|
503
|
+
end
|
504
|
+
|
505
|
+
name = token.name
|
506
|
+
if context
|
507
|
+
if single == SINGLE
|
508
|
+
yield RTSingleAlias.new(get_tkreaded, context, name, tk)
|
509
|
+
else
|
510
|
+
yield RTAlias.new(get_tkreaded, context, name, tk)
|
511
|
+
end
|
512
|
+
else
|
513
|
+
if single == SINGLE
|
514
|
+
yield RTSingleAlias.new(get_tkreaded, "main", name, tk)
|
515
|
+
else
|
516
|
+
yield RTAlias.new(get_tkreaded, nil, name, tk)
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
def parse_attr(context, single, tk, &block)
|
522
|
+
args = parse_symbol_arg(1)
|
523
|
+
if args.size > 0
|
524
|
+
name = args[0]
|
525
|
+
if context
|
526
|
+
if single == SINGLE
|
527
|
+
yield RTSingleAttr.new(get_tkreaded, context, name, tk)
|
528
|
+
else
|
529
|
+
yield RTAttr.new(get_tkreaded, context, name, tk)
|
530
|
+
end
|
531
|
+
else
|
532
|
+
if single == SINGLE
|
533
|
+
yield RTSingleAttr.new(get_tkreaded, "main", name, tk)
|
534
|
+
else
|
535
|
+
yield RTAttr.new(get_tkreaded, nil, name, tk)
|
536
|
+
end
|
537
|
+
end
|
538
|
+
else
|
539
|
+
warn('token not recognized - next attr arg size == zero',1)
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
def parse_attr_accessor(context, single, tk, &block)
|
544
|
+
args = parse_symbol_arg
|
545
|
+
readed = get_tkreaded
|
546
|
+
for name in args
|
547
|
+
if context
|
548
|
+
if single == SINGLE
|
549
|
+
yield RTSingleAttr.new(readed, context, name, tk)
|
550
|
+
else
|
551
|
+
yield RTAttr.new(readed, context, name, tk)
|
552
|
+
end
|
553
|
+
else
|
554
|
+
if single == SINGLE
|
555
|
+
yield RTSingleAttr.new(readed, "main", name, tk)
|
556
|
+
else
|
557
|
+
yield RTAttr.new(readed, nil, name, tk)
|
558
|
+
end
|
559
|
+
end
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
KNOWN_CLASS_METHOD_CALLS = %w(belongs_to has_one has_many has_and_belongs_to_many after_create after_destroy after_find after_initialize after_save after_update after_validation around_create around_destroy around_save around_update before_create before_destroy before_save before_update before_validation)
|
564
|
+
|
565
|
+
def parse_known_class_method_calls(context, single, tk, &block)
|
566
|
+
args = parse_symbol_arg
|
567
|
+
readed = get_tkreaded
|
568
|
+
(args.empty? ? [tk.name] : args).each do |name|
|
569
|
+
if context
|
570
|
+
if single == SINGLE
|
571
|
+
yield RTSingleClassCall.new(readed, context, name, tk)
|
572
|
+
else
|
573
|
+
yield RTClassCall.new(readed, context, name, tk)
|
574
|
+
end
|
575
|
+
else
|
576
|
+
if single == SINGLE
|
577
|
+
yield RTSingleClassCall.new(readed, "main", name, tk)
|
578
|
+
else
|
579
|
+
yield RTClassCall.new(readed, nil, name, tk)
|
580
|
+
end
|
581
|
+
end
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
def parse_identifier(context, single, nest, symbeg, tk, &block)
|
586
|
+
case tk.name
|
587
|
+
when "attr"
|
588
|
+
parse_attr(context, single, tk, &block)
|
589
|
+
when /^attr_(reader|writer|accessor)$/
|
590
|
+
parse_attr_accessor(context, single, tk, &block)
|
591
|
+
else
|
592
|
+
if !context.nil? && nest == 1 && !symbeg
|
593
|
+
parse_known_class_method_calls(context, single, tk, &block)
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
|
599
|
+
|
600
|
+
def parse_symbol_arg(no = nil)
|
601
|
+
args = []
|
602
|
+
skip_tkspace
|
603
|
+
case (tk = get_tk)
|
604
|
+
when TkLPAREN
|
605
|
+
loop do
|
606
|
+
skip_tkspace
|
607
|
+
if tk1 = parse_symbol_in_arg
|
608
|
+
args.push tk1
|
609
|
+
break if no and args.size >= no
|
610
|
+
end
|
611
|
+
|
612
|
+
skip_tkspace
|
613
|
+
case tk2 = get_tk
|
614
|
+
when TkRPAREN
|
615
|
+
break
|
616
|
+
when TkCOMMA
|
617
|
+
else
|
618
|
+
warn('token not recognized in funargs',1,tk)
|
619
|
+
break
|
620
|
+
end
|
621
|
+
end
|
622
|
+
else
|
623
|
+
unget_tk tk
|
624
|
+
|
625
|
+
loop do
|
626
|
+
skip_tkspace(false)
|
627
|
+
case (tk1 = get_tk)
|
628
|
+
when TkCOMMA
|
629
|
+
when TkDO, TkNL
|
630
|
+
unget_tk tk1
|
631
|
+
break
|
632
|
+
else
|
633
|
+
skip_tkspace
|
634
|
+
unget_tk tk1
|
635
|
+
if tk = parse_symbol_in_arg
|
636
|
+
args.push tk
|
637
|
+
break if no and args.size >= no
|
638
|
+
else
|
639
|
+
warn('token not recognized in funargs',1,tk1)
|
640
|
+
|
641
|
+
unless args.empty?
|
642
|
+
while (tk2 = get_tk) && !tk2.is_a?(TkNL) && !tk2.is_a?(TkDO)
|
643
|
+
end
|
644
|
+
unget_tk tk2
|
645
|
+
return args
|
646
|
+
end
|
647
|
+
return args
|
648
|
+
end
|
649
|
+
end
|
650
|
+
end
|
651
|
+
end
|
652
|
+
args
|
653
|
+
end
|
654
|
+
|
655
|
+
def parse_symbol_in_arg
|
656
|
+
case (tk = get_tk)
|
657
|
+
when TkSYMBEG
|
658
|
+
case (tk1 = get_tk)
|
659
|
+
when TkIDENTIFIER
|
660
|
+
tokens = skip_tkspace(false)
|
661
|
+
if (tk2 = get_tk).is_a?(TkASSIGN)
|
662
|
+
unget_tk tk2
|
663
|
+
tokens.each { |tk3| unget_tk tk3 }
|
664
|
+
unget_tk tk1
|
665
|
+
unget_tk tk
|
666
|
+
warn('token not recognized; next ',1,tk)
|
667
|
+
nil
|
668
|
+
else
|
669
|
+
tokens.each { |tk3| unget_tk tk3 }
|
670
|
+
tk1.name
|
671
|
+
end
|
672
|
+
when TkCONSTANT, TkFID
|
673
|
+
tk1.name
|
674
|
+
else
|
675
|
+
unget_tk tk1
|
676
|
+
warn('token not recognized; next SYMBEG ',1,tk1)
|
677
|
+
nil
|
678
|
+
end
|
679
|
+
when TkSTRING
|
680
|
+
eval @readed[-1]
|
681
|
+
else
|
682
|
+
unget_tk tk
|
683
|
+
warn('token not recognized; next SYMBEG and STRING ',1,tk) if $options.debug
|
684
|
+
nil
|
685
|
+
end
|
686
|
+
end
|
687
|
+
end
|
688
|
+
|
689
|
+
module Filter
|
690
|
+
|
691
|
+
# Test for boring repository directories that should be skipped
|
692
|
+
def Filter::skipdir name
|
693
|
+
if name =~ /\/(\.svn|\.hg|_darcs|CVS|\.git)/
|
694
|
+
print "\nSkipping boring directory #{name}"
|
695
|
+
return true
|
696
|
+
end
|
697
|
+
false
|
698
|
+
end
|
699
|
+
|
700
|
+
# Test whether this is a Ruby file
|
701
|
+
def Filter::skipfile name
|
702
|
+
if name =~ /.rb$/i
|
703
|
+
return false
|
704
|
+
end
|
705
|
+
# OK - test for magic hash bang
|
706
|
+
firstline = File.new(name, :encoding => "BINARY").gets
|
707
|
+
return false if firstline =~ /^#\!/ and firstline =~ /ruby/i
|
708
|
+
true
|
709
|
+
end
|
710
|
+
|
711
|
+
end
|
712
|
+
|
713
|
+
class TAGS
|
714
|
+
def initialize(files)
|
715
|
+
if $options.recurse
|
716
|
+
@files = []
|
717
|
+
recurse = lambda do |fname|
|
718
|
+
if File.directory? fname and not Filter::skipdir(fname)
|
719
|
+
Dir.entries(fname).select {|f| f !~ /^\.(?:\.|\w+)?$/ }.map {|f| fname+'/'+f }.each(&recurse)
|
720
|
+
else
|
721
|
+
# is a file
|
722
|
+
if File.file?(fname) and not Filter::skipfile(fname)
|
723
|
+
# @files.push(fname) if fname =~ /.rb$/i
|
724
|
+
@files.push(fname)
|
725
|
+
end
|
726
|
+
end
|
727
|
+
end
|
728
|
+
files.each(&recurse)
|
729
|
+
else
|
730
|
+
@files = files
|
731
|
+
end
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
class EMACS_TAGS < TAGS
|
736
|
+
# Create the tags file in emacs mode
|
737
|
+
def shipout
|
738
|
+
open($options.tagfile, $options.tagfile_mode) do |out|
|
739
|
+
@output = out
|
740
|
+
@files.each do |fn|
|
741
|
+
if File.directory? fn
|
742
|
+
puts "\nWarning: #{fn} is a directory - SKIPPING. Specify --recurse option to recurse into directories.\n"
|
743
|
+
next
|
744
|
+
end
|
745
|
+
output = []
|
746
|
+
size = 0
|
747
|
+
|
748
|
+
$stderr.printf "--\n-- parse file: %s\n", fn if $options.debug
|
749
|
+
parser = Parser.new(fn)
|
750
|
+
parser.scan do |tk|
|
751
|
+
$stderr.print tk, "\n" if $options.debug
|
752
|
+
line = tk.readed.split(/\n/)[0]
|
753
|
+
item = sprintf("%s\C-?%s\C-A%d,%s\n",
|
754
|
+
line,
|
755
|
+
tk.abs_name,
|
756
|
+
tk.line_no,
|
757
|
+
tk.seek)
|
758
|
+
output.push item
|
759
|
+
size += item.size
|
760
|
+
end
|
761
|
+
@output.print "\C-L\n#{fn},#{size}\n"
|
762
|
+
@output.print output.join
|
763
|
+
end
|
764
|
+
end
|
765
|
+
end
|
766
|
+
end
|
767
|
+
|
768
|
+
class VI_TAGS < TAGS
|
769
|
+
# Create the tags file in vi(m) mode
|
770
|
+
def shipout
|
771
|
+
output = []
|
772
|
+
@files.each do |fn|
|
773
|
+
if File.directory? fn
|
774
|
+
puts "\nWarning: #{fn} is a directory - SKIPPING. Specify --recurse option to recurse into directories.\n"
|
775
|
+
next
|
776
|
+
end
|
777
|
+
|
778
|
+
$stderr.printf "--\n-- parse file: %s\n", fn if $options.debug
|
779
|
+
parser = Parser.new(fn)
|
780
|
+
parser.scan do |tk|
|
781
|
+
$stderr.print tk, "\n" if $options.debug
|
782
|
+
line = tk.readed.split(/\n/)[0]
|
783
|
+
output.push sprintf("%s\t%s\t/^%s/\n",
|
784
|
+
tk.name,
|
785
|
+
fn,
|
786
|
+
line)
|
787
|
+
output.push sprintf("%s\t%s\t/^%s/\n",
|
788
|
+
tk.abs_name,
|
789
|
+
fn,
|
790
|
+
line)
|
791
|
+
end
|
792
|
+
end
|
793
|
+
# sort entries
|
794
|
+
open($options.tagfile, $options.tagfile_mode) do |out|
|
795
|
+
out << output.sort!.join
|
796
|
+
end
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
800
|
+
class XREF_TAGS < TAGS
|
801
|
+
# Print cross ref file (like ctags -x)
|
802
|
+
def shipout
|
803
|
+
output = []
|
804
|
+
@files.each do |fn|
|
805
|
+
if File.directory? fn
|
806
|
+
puts "\nWarning: #{fn} is a directory - SKIPPING. Specify --recurse option to recurse into directories.\n"
|
807
|
+
next
|
808
|
+
end
|
809
|
+
|
810
|
+
size = 0
|
811
|
+
|
812
|
+
$stderr.printf "--\n-- parse file: %s\n", fn if $options.debug
|
813
|
+
parser = Parser.new(fn)
|
814
|
+
parser.scan do |tk|
|
815
|
+
$stderr.print tk, "\n" if $options.debug
|
816
|
+
line = tk.readed.split(/\n/)[0]
|
817
|
+
unless $options.xref_only_abs
|
818
|
+
output.push sprintf("%-16s %-10s %4d %-16s %s\n",
|
819
|
+
tk.name.gsub(/^::/, "").gsub(" ", "_"),
|
820
|
+
tk.def_name,
|
821
|
+
tk.line_no,
|
822
|
+
fn,
|
823
|
+
line)
|
824
|
+
end
|
825
|
+
|
826
|
+
unless $options.xref_only_base
|
827
|
+
output.push sprintf("%-16s %-10s %4d %-16s %s\n",
|
828
|
+
tk.abs_name.gsub(/^::/, "").gsub(" ", "_"),
|
829
|
+
tk.def_name,
|
830
|
+
tk.line_no,
|
831
|
+
fn,
|
832
|
+
line)
|
833
|
+
end
|
834
|
+
end
|
835
|
+
end
|
836
|
+
puts output.join
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
|
841
|
+
end
|
842
|
+
|
843
|
+
if (!$options.files_in_list && ARGV.size == 0) or ARGV[0] == '--help'
|
844
|
+
ARGV.shift
|
845
|
+
print usage
|
846
|
+
exit 1
|
847
|
+
end
|
848
|
+
|
849
|
+
files = ARGV
|
850
|
+
files += File.readlines($options.files_in_list).map { |f| f.chomp } if $options.files_in_list
|
851
|
+
|
852
|
+
if $options.vi
|
853
|
+
tags = RTAGS::VI_TAGS.new(files)
|
854
|
+
elsif $options.xref
|
855
|
+
tags = RTAGS::XREF_TAGS.new(files)
|
856
|
+
else
|
857
|
+
tags = RTAGS::EMACS_TAGS.new(files)
|
858
|
+
end
|
859
|
+
tags.shipout
|
860
|
+
print "\n" if !$options.xref
|
861
|
+
$stderr.print "\nEnd - tagfile generated\n" if (!$options.quiet && !$options.xref)
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bloopletech-rtags
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.99.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Pjotr Prins, Keiju Ishitsuka
|
9
|
+
autorequire: irb
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-23 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: This is the original commit of the rtags source code as written by Keiju
|
15
|
+
ISHITSUKA as part of the irb project. Now irb has moved into the main Ruby source
|
16
|
+
tree rtags has become an independent project
|
17
|
+
email: pjotr.public02@thebird.nl
|
18
|
+
executables:
|
19
|
+
- rtags
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- RELEASENOTES
|
24
|
+
- TODO
|
25
|
+
- README
|
26
|
+
- LICENSE.txt
|
27
|
+
- bin/rtags
|
28
|
+
homepage: http://rtags.rubyforge.org
|
29
|
+
licenses: []
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 1.8.1
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project: rtags
|
48
|
+
rubygems_version: 1.8.24
|
49
|
+
signing_key:
|
50
|
+
specification_version: 3
|
51
|
+
summary: rtags is a Ruby replacement for ctags - allowing for name navigation in source
|
52
|
+
code using vim, emacs and others
|
53
|
+
test_files: []
|
54
|
+
has_rdoc: false
|