rcodetools 0.4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +18 -0
- data/README +34 -0
- data/README.emacs +54 -0
- data/README.method_analysis +13 -0
- data/README.vim +84 -0
- data/README.xmpfilter +202 -0
- data/Rakefile +123 -0
- data/Rakefile.method_analysis +30 -0
- data/THANKS +6 -0
- data/bin/rct-complete +37 -0
- data/bin/rct-doc +50 -0
- data/bin/rct-meth-args +392 -0
- data/bin/xmpfilter +75 -0
- data/icicles-rcodetools.el +31 -0
- data/lib/method_analyzer.rb +107 -0
- data/lib/rcodetools/completion.rb +282 -0
- data/lib/rcodetools/doc.rb +176 -0
- data/lib/rcodetools/options.rb +83 -0
- data/lib/rcodetools/xmpfilter.rb +208 -0
- data/lib/rcodetools/xmptestunitfilter.rb +197 -0
- data/rcodetools.el +162 -0
- data/rcodetools.vim +118 -0
- data/setup.rb +1585 -0
- data/test/data/add_markers-input.rb +2 -0
- data/test/data/add_markers-output.rb +2 -0
- data/test/data/bindings-input.rb +26 -0
- data/test/data/bindings-output.rb +31 -0
- data/test/data/completion-input.rb +1 -0
- data/test/data/completion-output.rb +2 -0
- data/test/data/completion_emacs-input.rb +1 -0
- data/test/data/completion_emacs-output.rb +5 -0
- data/test/data/completion_emacs_icicles-input.rb +1 -0
- data/test/data/completion_emacs_icicles-output.rb +5 -0
- data/test/data/doc-input.rb +1 -0
- data/test/data/doc-output.rb +1 -0
- data/test/data/method_analyzer-data.rb +33 -0
- data/test/data/method_args.data.rb +106 -0
- data/test/data/no_warnings-input.rb +3 -0
- data/test/data/no_warnings-output.rb +4 -0
- data/test/data/refe-input.rb +1 -0
- data/test/data/refe-output.rb +1 -0
- data/test/data/ri-input.rb +1 -0
- data/test/data/ri-output.rb +1 -0
- data/test/data/ri_emacs-input.rb +1 -0
- data/test/data/ri_emacs-output.rb +1 -0
- data/test/data/ri_vim-input.rb +1 -0
- data/test/data/ri_vim-output.rb +1 -0
- data/test/data/rspec-input.rb +48 -0
- data/test/data/rspec-output.rb +52 -0
- data/test/data/rspec_poetry-input.rb +48 -0
- data/test/data/rspec_poetry-output.rb +52 -0
- data/test/data/simple_annotation-input.rb +8 -0
- data/test/data/simple_annotation-output.rb +8 -0
- data/test/data/unit_test-input.rb +50 -0
- data/test/data/unit_test-output.rb +52 -0
- data/test/data/unit_test_poetry-input.rb +50 -0
- data/test/data/unit_test_poetry-output.rb +52 -0
- data/test/test_completion.rb +467 -0
- data/test/test_doc.rb +403 -0
- data/test/test_functional.rb +18 -0
- data/test/test_method_analyzer.rb +99 -0
- data/test/test_method_args.rb +134 -0
- data/test/test_run.rb +41 -0
- data/test/test_xmpfilter.rb +36 -0
- data/test/test_xmptestunitfilter.rb +84 -0
- metadata +139 -0
data/bin/xmpfilter
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
#! /home/batsman/usr//bin/ruby
|
2
|
+
require 'rcodetools/xmpfilter'
|
3
|
+
require 'rcodetools/options'
|
4
|
+
|
5
|
+
options = DEFAULT_OPTIONS
|
6
|
+
rails_settings = false
|
7
|
+
klass = XMPFilter
|
8
|
+
|
9
|
+
opts = OptionParser.new do |opts|
|
10
|
+
opts.extend OptionHandler
|
11
|
+
opts.set_banner
|
12
|
+
|
13
|
+
opts.separator ""
|
14
|
+
opts.separator "Modes:"
|
15
|
+
opts.on("-a", "--annotations", "Annotate code (default)") do
|
16
|
+
klass = XMPFilter
|
17
|
+
end
|
18
|
+
opts.on("-u", "--unittest", "Complete Test::Unit assertions.") do
|
19
|
+
require 'rcodetools/xmptestunitfilter'
|
20
|
+
klass = XMPTestUnitFilter
|
21
|
+
end
|
22
|
+
opts.on("-s", "--spec", "Complete RSpec expectations.") do
|
23
|
+
require 'rcodetools/xmptestunitfilter'
|
24
|
+
klass = XMPRSpecFilter
|
25
|
+
options[:interpreter] = "spec"
|
26
|
+
end
|
27
|
+
opts.on("-m", "--markers", "Add # => markers.") do
|
28
|
+
klass = XMPAddMarkers
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.handle_interpreter options
|
32
|
+
|
33
|
+
opts.separator ""
|
34
|
+
opts.separator "Specific options:"
|
35
|
+
opts.on("-l N", "--min-line-length N", Integer, "Align markers to N spaces.") do |min_codeline_size|
|
36
|
+
options[:min_codeline_size] = min_codeline_size
|
37
|
+
end
|
38
|
+
opts.on("--rails", "Setting appropriate for Rails.",
|
39
|
+
"(no warnings, find working directory,",
|
40
|
+
" Test::Unit assertions)") do
|
41
|
+
require 'rcodetools/xmptestunitfilter'
|
42
|
+
options[:warnings] = false
|
43
|
+
klass = XMPTestUnitFilter
|
44
|
+
rails_settings = true
|
45
|
+
end
|
46
|
+
opts.on("--[no-]poetry", "Whether to use extra parentheses.",
|
47
|
+
"(default: use them)") do |poetry_p|
|
48
|
+
options[:use_parentheses] = !poetry_p
|
49
|
+
end
|
50
|
+
opts.on("--[no-]warnings", "Whether to add warnings (# !>).",
|
51
|
+
"(default: enabled)") {|warnings_p| options[:warnings] = warnings_p }
|
52
|
+
opts.on("-q", "--quiet", "Supress standard output.") do
|
53
|
+
options[:output_stdout] = false
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.handle_misc options
|
57
|
+
end
|
58
|
+
|
59
|
+
set_extra_opts options
|
60
|
+
opts.parse!(ARGV)
|
61
|
+
|
62
|
+
if rails_settings && !options[:wd]
|
63
|
+
if File.exist? ARGF.path
|
64
|
+
options[:wd] = File.dirname(ARGF.path)
|
65
|
+
elsif File.exist? "test/unit"
|
66
|
+
options[:wd] = "test/unit"
|
67
|
+
elsif File.exist? "unit"
|
68
|
+
options[:wd] = "unit"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
targetcode = ARGF.read
|
72
|
+
Dir.chdir options[:wd] if options[:wd]
|
73
|
+
|
74
|
+
# Do the job. dispatched by klass.
|
75
|
+
puts klass.run(targetcode, options)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
;;; icicles-rcodetools.el -- accurate completion with icicles
|
2
|
+
|
3
|
+
;;; Copyright (c) 2006 rubikitch <rubikitch@ruby-lang.org>
|
4
|
+
;;;
|
5
|
+
;;; Use and distribution subject to the terms of the Ruby license.
|
6
|
+
|
7
|
+
(require 'icicles)
|
8
|
+
(require 'rcodetools)
|
9
|
+
|
10
|
+
(setq rct-complete-symbol-function 'rct-complete-symbol--icicles)
|
11
|
+
(icicle-define-command rct-complete-symbol--icicles
|
12
|
+
"Perform ruby method and class completion on the text around point with icicles.
|
13
|
+
C-M-RET shows RI documentation on each candidate.
|
14
|
+
See also `rct-interactive'."
|
15
|
+
|
16
|
+
(lambda (result)
|
17
|
+
(save-excursion
|
18
|
+
(search-backward pattern)
|
19
|
+
(setq beg (point)))
|
20
|
+
(delete-region beg end)
|
21
|
+
(insert result)) ;/function
|
22
|
+
"rct-complete: " ;prompt
|
23
|
+
rct-method-completion-table
|
24
|
+
nil t pattern nil nil nil
|
25
|
+
((end (point)) beg
|
26
|
+
pattern klass
|
27
|
+
(icicle-candidate-help-fn
|
28
|
+
(lambda (result) (ri result klass)))) ;bindings
|
29
|
+
(rct-exec-and-eval rct-complete-command-name "--completion-emacs-icicles"))
|
30
|
+
|
31
|
+
(provide 'icicles-rcodetools)
|
@@ -0,0 +1,107 @@
|
|
1
|
+
class Module
|
2
|
+
remove_method :attr_reader
|
3
|
+
def attr_reader(*names)
|
4
|
+
names.each do |name|
|
5
|
+
module_eval "def #{name}() @#{name} end"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
remove_method :attr_writer
|
9
|
+
def attr_writer(*names)
|
10
|
+
names.each do |name|
|
11
|
+
module_eval "def #{name}=(x) @#{name}=x end"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
remove_method :attr_accessor
|
15
|
+
def attr_accessor(*names)
|
16
|
+
attr_reader(*names)
|
17
|
+
attr_writer(*names)
|
18
|
+
end
|
19
|
+
remove_method :attr
|
20
|
+
def attr(name, writer=false)
|
21
|
+
attr_reader name
|
22
|
+
attr_writer name if writer
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
module MethodAnalyzer
|
28
|
+
@@methods = Hash.new{ |h,k| h[k] = Hash.new{ |h,k| h[k] = []} }
|
29
|
+
@@whereis = []
|
30
|
+
@@expand_path = Hash.new{ |h,k| h[k] = File.expand_path(k)}
|
31
|
+
|
32
|
+
def self.trace_func(event, file, line, id, binding, klass, *rest)
|
33
|
+
return if file == __FILE__
|
34
|
+
return if (event != 'call' and event != 'c-call')
|
35
|
+
return if klass == Class and id == :inherited
|
36
|
+
return if klass == Module and id == :method_added
|
37
|
+
return if klass == Kernel and id == :singleton_method_added
|
38
|
+
saved_crit = Thread.critical
|
39
|
+
Thread.critical = true
|
40
|
+
|
41
|
+
the_self = eval("self",binding)
|
42
|
+
flag = Class === the_self ? "." : "#"
|
43
|
+
#klass = klass == Kernel ? Object : klass
|
44
|
+
fullname = "#{klass}#{flag}#{id}"
|
45
|
+
file.replace @@expand_path[file]
|
46
|
+
if event == 'call'
|
47
|
+
@@whereis << [file, line, fullname] if file !~ /\(eval\)$/
|
48
|
+
file, line, rest = caller(4)[0].split(/:/)
|
49
|
+
file.replace @@expand_path[file] # DRY
|
50
|
+
p caller(0) if $DEBUG
|
51
|
+
line = line.to_i
|
52
|
+
end
|
53
|
+
@@methods[file][line] << fullname if event =~ /call/
|
54
|
+
|
55
|
+
Thread.critical = saved_crit
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.at_exit__output_marshal
|
59
|
+
at_exit do
|
60
|
+
set_trace_func nil
|
61
|
+
dbfile = "method_analysis"
|
62
|
+
old = Marshal.load(File.read(dbfile)) rescue {}
|
63
|
+
open(dbfile, "wb") do |io|
|
64
|
+
# Because Marshal.dump cannot handle hashes with default_proc
|
65
|
+
@@methods.default = nil
|
66
|
+
@@methods.each_value{ |v| v.default=nil; v.each_value{ |vv| vv.uniq! } }
|
67
|
+
Marshal.dump(@@methods.merge(old), io)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def self.at_exit__output_text
|
74
|
+
at_exit do
|
75
|
+
set_trace_func nil
|
76
|
+
puts "method fullnames"
|
77
|
+
@@methods.sort.each do |file, lines|
|
78
|
+
lines.sort.each do |line, methods|
|
79
|
+
printf "%s:%s:%s\n", file, line, methods.uniq.join(" ")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
puts
|
84
|
+
puts "method definitions"
|
85
|
+
@@whereis.sort.uniq.each do |file, line, fullname |
|
86
|
+
printf "%s:%s:%s\n", file, line, fullname
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.set_at_exit
|
93
|
+
case ENV['METHOD_ANALYZER_FORMAT']
|
94
|
+
when 'marshal'
|
95
|
+
at_exit__output_marshal
|
96
|
+
else
|
97
|
+
at_exit__output_text
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
set_at_exit
|
102
|
+
set_trace_func method(:trace_func).to_proc
|
103
|
+
end
|
104
|
+
|
105
|
+
if __FILE__ == $0
|
106
|
+
load "./test/data/method_analyzer-data.rb"
|
107
|
+
end
|
@@ -0,0 +1,282 @@
|
|
1
|
+
require 'rcodetools/xmpfilter'
|
2
|
+
require 'enumerator'
|
3
|
+
# Common routines for XMPCompletionFilter/XMPDocFilter
|
4
|
+
module ProcessParticularLine
|
5
|
+
def fill_literal!(expr)
|
6
|
+
[ "\"", "'", "`" ].each do |q|
|
7
|
+
expr.gsub!(/#{q}(.+)#{q}/){ '"' + "x"*$1.length + '"' }
|
8
|
+
end
|
9
|
+
expr.gsub!(/(%([wWqQxrs])?(\W))(.+?)\3/){
|
10
|
+
percent = $2 == 'x' ? '%'+$3 : $1 # avoid executing shell command
|
11
|
+
percent + "x"*$4.length + $3
|
12
|
+
}
|
13
|
+
[ %w[( )], %w[{ }], %w![ ]!, %w[< >] ].each do |b,e|
|
14
|
+
rb, re = [b,e].map{ |x| Regexp.quote(x)}
|
15
|
+
expr.gsub!(/(%([wWqQxrs])?(#{rb}))(.+)#{re}/){
|
16
|
+
percent = $2 == 'x' ? '%'+$3 : $1 # avoid executing shell command
|
17
|
+
percent + "x"*$4.length + e
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module ExpressionExtension
|
23
|
+
attr_accessor :eval_string
|
24
|
+
attr_accessor :meth
|
25
|
+
end
|
26
|
+
OPERATOR_CHARS = '\|^&<>=~\+\-\*\/%\['
|
27
|
+
def set_expr_and_postfix!(expr, column, ®exp)
|
28
|
+
expr.extend ExpressionExtension
|
29
|
+
|
30
|
+
@postfix = ""
|
31
|
+
expr_orig = expr.clone
|
32
|
+
column ||= expr.length
|
33
|
+
last_char = expr[column-1]
|
34
|
+
expr.replace expr[ regexp[column] ]
|
35
|
+
debugprint "expr_orig=#{expr_orig}", "expr(sliced)=#{expr}"
|
36
|
+
right_stripped = Regexp.last_match.post_match
|
37
|
+
_handle_do_end right_stripped
|
38
|
+
aref_or_aset = aref_or_aset? right_stripped, last_char
|
39
|
+
debugprint "aref_or_aset=#{aref_or_aset.inspect}"
|
40
|
+
set_last_word! expr, aref_or_aset
|
41
|
+
fill_literal! expr_orig
|
42
|
+
_handle_brackets expr_orig, expr
|
43
|
+
expr << aref_or_aset if aref_or_aset
|
44
|
+
_handle_keywords expr_orig, column
|
45
|
+
debugprint "expr(processed)=#{expr}"
|
46
|
+
expr
|
47
|
+
end
|
48
|
+
|
49
|
+
def _handle_do_end(right_stripped)
|
50
|
+
right_stripped << "\n"
|
51
|
+
n_do = right_stripped.scan(/[\s\)]do\s/).length
|
52
|
+
n_end = right_stripped.scan(/\bend\b/).length
|
53
|
+
@postfix = ";begin" * (n_do - n_end)
|
54
|
+
end
|
55
|
+
|
56
|
+
def _handle_brackets(expr_orig, expr)
|
57
|
+
[ %w[{ }], %w[( )], %w![ ]! ].each do |left, right|
|
58
|
+
n_left = expr_orig.count(left) - expr.count(left)
|
59
|
+
n_right = expr_orig.count(right) - expr.count(right)
|
60
|
+
n = n_left - n_right
|
61
|
+
@postfix << ";#{left}" * n if n >= 0
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def _handle_keywords(expr_orig, column)
|
66
|
+
%w[if unless while until for].each do |keyw|
|
67
|
+
pos = expr_orig.index(/\b#{keyw}\b/)
|
68
|
+
@postfix << ";begin" if pos and pos < column # if * xxx
|
69
|
+
|
70
|
+
pos = expr_orig.index(/;\s*#{keyw}\b/)
|
71
|
+
@postfix << ";begin" if pos and column < pos # * ; if xxx
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def aref_or_aset?(right_stripped, last_char)
|
76
|
+
if last_char == ?[
|
77
|
+
case right_stripped
|
78
|
+
when /\]\s*=/: "[]="
|
79
|
+
when /\]/: "[]"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def set_last_word!(expr, aref_or_aset=nil)
|
85
|
+
debugprint "expr(before set_last_word)=#{expr}"
|
86
|
+
if aref_or_aset
|
87
|
+
opchars = ""
|
88
|
+
else
|
89
|
+
opchars = expr.slice!(/\s*[#{OPERATOR_CHARS}]+$/)
|
90
|
+
debugprint "expr(strip opchars)=#{expr}"
|
91
|
+
end
|
92
|
+
|
93
|
+
expr.replace(if expr =~ /[\"\'\`]$/ # String operations
|
94
|
+
"''"
|
95
|
+
else
|
96
|
+
fill_literal! expr
|
97
|
+
phrase = current_phrase(expr)
|
98
|
+
if aref_or_aset
|
99
|
+
expr.eval_string = expr[0..-2]
|
100
|
+
expr.meth = aref_or_aset
|
101
|
+
elsif phrase.match( /^(.+)\.(.*)$/ )
|
102
|
+
expr.eval_string, expr.meth = $1, $2
|
103
|
+
elsif opchars != ''
|
104
|
+
expr
|
105
|
+
end
|
106
|
+
debugprint "expr.eval_string=#{expr.eval_string}", "expr.meth=#{expr.meth}"
|
107
|
+
phrase
|
108
|
+
end << (opchars || '')) # ` font-lock hack
|
109
|
+
debugprint "expr(after set_last_word)=#{expr}"
|
110
|
+
end
|
111
|
+
|
112
|
+
def current_phrase(expr)
|
113
|
+
paren_level = 0
|
114
|
+
start = 0
|
115
|
+
(expr.length-1).downto(0) do |i|
|
116
|
+
c = expr[i,1]
|
117
|
+
if c =~ /[\)\}\]]/
|
118
|
+
paren_level += 1
|
119
|
+
next
|
120
|
+
end
|
121
|
+
if paren_level > 0
|
122
|
+
next if c =~ /[, ]/
|
123
|
+
else
|
124
|
+
break (start = i+1) if c =~ /[ ,\(\{\[]/
|
125
|
+
end
|
126
|
+
if c =~ /[\(\{\[]/
|
127
|
+
paren_level -= 1
|
128
|
+
break (start = i+1) if paren_level < 0
|
129
|
+
end
|
130
|
+
end
|
131
|
+
expr[start..-1]
|
132
|
+
end
|
133
|
+
|
134
|
+
def add_BEGIN
|
135
|
+
<<XXX
|
136
|
+
BEGIN {
|
137
|
+
class Object
|
138
|
+
def method_missing(meth, *args, &block)
|
139
|
+
# ignore NoMethodError
|
140
|
+
end
|
141
|
+
end
|
142
|
+
}
|
143
|
+
XXX
|
144
|
+
end
|
145
|
+
|
146
|
+
class RuntimeDataError < RuntimeError; end
|
147
|
+
class NewCodeError < Exception; end
|
148
|
+
def runtime_data_with_class(code, lineno, column=nil)
|
149
|
+
newcode = code.to_a.enum_with_index.map{|line, i|
|
150
|
+
i+1==lineno ? prepare_line(line.chomp, column) : line
|
151
|
+
}.join
|
152
|
+
newcode << add_BEGIN if @ignore_NoMethodError
|
153
|
+
debugprint "newcode", newcode, "-"*80
|
154
|
+
stdout, stderr = execute(newcode)
|
155
|
+
output = stderr.readlines
|
156
|
+
debugprint "stdout", output, "-"*80
|
157
|
+
output = output.reject{|x| /^-:[0-9]+: warning/.match(x)}
|
158
|
+
runtime_data = extract_data(output)
|
159
|
+
if exception = /^-:[0-9]+:.*/m.match(output.join)
|
160
|
+
raise NewCodeError, exception[0].chomp
|
161
|
+
end
|
162
|
+
begin
|
163
|
+
dat = runtime_data.results[1][0]
|
164
|
+
[dat[0], dat[1..-1].to_s]
|
165
|
+
rescue
|
166
|
+
raise RuntimeDataError, runtime_data.inspect
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def runtime_data(code, lineno, column=nil)
|
171
|
+
runtime_data_with_class(code, lineno, column)[1]
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
# Nearly 100% accurate completion for any editors!!
|
177
|
+
# by rubikitch <rubikitch@ruby-lang.org>
|
178
|
+
class XMPCompletionFilter < XMPFilter
|
179
|
+
include ProcessParticularLine
|
180
|
+
|
181
|
+
# String completion begins with this.
|
182
|
+
attr :prefix
|
183
|
+
|
184
|
+
def self.run(code, opts)
|
185
|
+
new(opts).completion_code(code, opts[:lineno], opts[:column])
|
186
|
+
end
|
187
|
+
|
188
|
+
def prepare_line(expr, column)
|
189
|
+
set_expr_and_postfix!(expr, column){|c| /^.{#{c}}/ }
|
190
|
+
@prefix = expr
|
191
|
+
case expr
|
192
|
+
when /^\$\w+$/ # global variable
|
193
|
+
__prepare_line 'global_variables'
|
194
|
+
when /^@@\w+$/ # class variable
|
195
|
+
__prepare_line 'Module === self ? class_variables : self.class.class_variables'
|
196
|
+
when /^@\w+$/ # instance variable
|
197
|
+
__prepare_line 'instance_variables'
|
198
|
+
when /^([A-Z].*)::(.*)$/ # nested constants / class methods
|
199
|
+
@prefix = $2
|
200
|
+
__prepare_line "#$1.constants | #$1.methods(true)"
|
201
|
+
when /^[A-Z]\w*$/ # normal constants
|
202
|
+
__prepare_line 'Module.constants'
|
203
|
+
when /^::(.+)::(.*)$/ # toplevel nested constants
|
204
|
+
@prefix = $2
|
205
|
+
__prepare_line "::#$1.constants | ::#$1.methods"
|
206
|
+
when /^::(.*)/ # toplevel constant
|
207
|
+
@prefix = $1
|
208
|
+
__prepare_line 'Object.constants'
|
209
|
+
when /^(:[^:.]*)$/ # symbol
|
210
|
+
__prepare_line 'Symbol.all_symbols.map{|s| ":" + s.id2name}'
|
211
|
+
when /\.([^.]*)$/ # method call
|
212
|
+
@prefix = $1
|
213
|
+
__prepare_line "(#{Regexp.last_match.pre_match}).methods(true)"
|
214
|
+
else # bare words
|
215
|
+
__prepare_line "methods | private_methods | local_variables | self.class.constants"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def __prepare_line(all_completion_expr)
|
220
|
+
v = "#{VAR}"
|
221
|
+
idx = 1
|
222
|
+
oneline_ize(<<EOC)
|
223
|
+
#{v} = (#{all_completion_expr}).grep(/^#{Regexp.quote(@prefix)}/)
|
224
|
+
$stderr.puts("#{MARKER}[#{idx}] => " + #{v}.class.to_s + " " + #{v}.join(" ")) || #{v}
|
225
|
+
exit
|
226
|
+
EOC
|
227
|
+
end
|
228
|
+
|
229
|
+
# Array of completion candidates.
|
230
|
+
def candidates(code, lineno, column=nil)
|
231
|
+
methods = runtime_data(code, lineno, column) rescue ""
|
232
|
+
methods.split.sort
|
233
|
+
end
|
234
|
+
|
235
|
+
# Completion code for editors.
|
236
|
+
def completion_code(code, lineno, column=nil)
|
237
|
+
candidates(code, lineno, column).join("\n")
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
class XMPCompletionEmacsFilter < XMPCompletionFilter
|
242
|
+
def completion_code(code, lineno, column=nil)
|
243
|
+
elisp = "(progn\n"
|
244
|
+
elisp << "(setq rct-method-completion-table '("
|
245
|
+
begin
|
246
|
+
candidates(code, lineno, column).each do |meth|
|
247
|
+
elisp << format('("%s") ', meth)
|
248
|
+
end
|
249
|
+
rescue Exception => err
|
250
|
+
return %Q[(error "#{err.message}")]
|
251
|
+
end
|
252
|
+
elisp << "))\n"
|
253
|
+
elisp << %Q[(setq pattern "#{prefix}")\n]
|
254
|
+
elisp << %Q[(try-completion pattern rct-method-completion-table nil)\n]
|
255
|
+
elisp << ")" # /progn
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
class XMPCompletionEmacsIciclesFilter < XMPCompletionFilter
|
260
|
+
def candidates(code, lineno, column=nil)
|
261
|
+
klass, methods = runtime_data_with_class(code, lineno, column) rescue ["", ""]
|
262
|
+
@klass = klass
|
263
|
+
methods.split.sort
|
264
|
+
end
|
265
|
+
|
266
|
+
def completion_code(code, lineno, column=nil)
|
267
|
+
elisp = "(progn\n"
|
268
|
+
elisp << "(setq rct-method-completion-table '("
|
269
|
+
begin
|
270
|
+
candidates(code, lineno, column).each do |meth|
|
271
|
+
elisp << format('("%s") ', meth)
|
272
|
+
end
|
273
|
+
rescue Exception => err
|
274
|
+
return %Q[(error "#{err.message}")]
|
275
|
+
end
|
276
|
+
elisp << "))\n"
|
277
|
+
elisp << %Q[(setq pattern "#{prefix}")\n]
|
278
|
+
elisp << %Q[(setq klass "#{@klass}")\n]
|
279
|
+
elisp << ")" # /progn
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|