bloopletech-rtags 0.99.1
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/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
|