Feature #14787 ยป show_doc_when_completion.patch
| lib/irb/completion.rb | ||
|---|---|---|
| # | ||
| require "readline" | ||
| require "rdoc" | ||
| module IRB | ||
|   module InputCompletor # :nodoc: | ||
|     RDocRIDriver = RDoc::RI::Driver.new | ||
|     # Set of reserved words used by Ruby, you should not use these for | ||
|     # constants or variables | ||
| ... | ... | |
|     ] | ||
|     CompletionProc = proc { |input| | ||
|       bind = IRB.conf[:MAIN_CONTEXT].workspace.binding | ||
|       workspace = IRB.conf[:MAIN_CONTEXT].workspace | ||
|       if workspace.completion_data[:prev] == input | ||
|         workspace.completion_data[:repeat_count] += 1 | ||
|       else | ||
|         workspace.completion_data[:repeat_count] = 0 | ||
|       end | ||
|       workspace.completion_data[:prev] = input | ||
|       candidates = complement(input) | ||
|       if workspace.completion_data[:display_name] | ||
|         display_name = workspace.completion_data[:display_name] | ||
|         workspace.completion_data[:display_name] = nil | ||
|         begin | ||
|           RDocRIDriver.display_name(display_name) | ||
|         rescue RDoc::RI::Driver::NotFoundError | ||
|           candidates | ||
|         else | ||
|           [] | ||
|         end | ||
|       else | ||
|         candidates | ||
|       end | ||
|     } | ||
|     def self.check_display_name(candidates, on_input, receiver = nil) | ||
|       ws = IRB.conf[:MAIN_CONTEXT].workspace | ||
|       if ws.completion_data[:repeat_count] > 1 and candidates.find{|m| m == on_input} | ||
|         if block_given? | ||
|           ws.completion_data[:display_name] = yield | ||
|         else | ||
|           ws.completion_data[:display_name] = receiver ? "#{receiver}##{on_input}" : on_input | ||
|         end | ||
|       end | ||
|       candidates | ||
|     end | ||
|     def self.complement(input) | ||
|       bind = IRB.conf[:MAIN_CONTEXT].workspace.binding | ||
|       case input | ||
|       when /^((["'`]).*\2)\.([^.]*)$/ | ||
|         # String | ||
|         receiver = $1 | ||
|         on_input = $3 | ||
|         message = Regexp.quote($3) | ||
|         candidates = String.instance_methods.collect{|m| m.to_s} | ||
|         select_message(receiver, message, candidates) | ||
|         candidates = select_message(receiver, message, candidates) | ||
|         check_display_name(candidates, input) do | ||
|           "String##{on_input}" | ||
|         end | ||
|       when /^(\/[^\/]*\/)\.([^.]*)$/ | ||
|         # Regexp | ||
|         receiver = $1 | ||
|         on_input = $2 | ||
|         message = Regexp.quote($2) | ||
|         candidates = Regexp.instance_methods.collect{|m| m.to_s} | ||
|         select_message(receiver, message, candidates) | ||
|         candidates = select_message(receiver, message, candidates) | ||
|         check_display_name(candidates, input) do | ||
|           "Regexp##{on_input}" | ||
|         end | ||
|       when /^([^\]]*\])\.([^.]*)$/ | ||
|         # Array | ||
|         receiver = $1 | ||
|         on_input = $2 | ||
|         message = Regexp.quote($2) | ||
|         candidates = Array.instance_methods.collect{|m| m.to_s} | ||
|         select_message(receiver, message, candidates) | ||
|         candidates = select_message(receiver, message, candidates) | ||
|         check_display_name(candidates, input) do | ||
|           "Array##{on_input}" | ||
|         end | ||
|       when /^([^\}]*\})\.([^.]*)$/ | ||
|         # Proc or Hash | ||
|         receiver = $1 | ||
|         on_input = $2 | ||
|         message = Regexp.quote($2) | ||
|         candidates = Proc.instance_methods.collect{|m| m.to_s} | ||
|         candidates |= Hash.instance_methods.collect{|m| m.to_s} | ||
|         select_message(receiver, message, candidates) | ||
|         candidates = select_message(receiver, message, candidates) | ||
|         check_display_name(candidates, input) do | ||
|           if Proc.instance_methods.find{|m| m.to_s == on_input} | ||
|             "Proc##{on_input}" | ||
|           elsif Hash.instance_methods.find{|m| m.to_s == on_input} | ||
|             "Hash##{on_input}" | ||
|           end | ||
|         end | ||
|       when /^(:[^:.]*)$/ | ||
|         # Symbol | ||
| ... | ... | |
|         # Absolute Constant or class methods | ||
|         receiver = $1 | ||
|         candidates = Object.constants.collect{|m| m.to_s} | ||
|         candidates.grep(/^#{receiver}/).collect{|e| "::" + e} | ||
|         candidates = candidates.grep(/^#{receiver}/).collect{|e| "::" + e} | ||
|         check_display_name(candidates, input) do | ||
|           receiver | ||
|         end | ||
|       when /^([A-Z].*)::([^:.]*)$/ | ||
|         # Constant or class methods | ||
|         receiver = $1 | ||
|         on_input = $2 | ||
|         message = Regexp.quote($2) | ||
|         begin | ||
|           candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind) | ||
| ... | ... | |
|         rescue Exception | ||
|           candidates = [] | ||
|         end | ||
|         select_message(receiver, message, candidates, "::") | ||
|         candidates = select_message(receiver, message, candidates, "::") | ||
|         check_display_name(candidates, input) do | ||
|           input | ||
|         end | ||
|       when /^(:[^:.]+)(\.|::)([^.]*)$/ | ||
|         # Symbol | ||
|         receiver = $1 | ||
|         sep = $2 | ||
|         on_input = $3 | ||
|         message = Regexp.quote($3) | ||
|         candidates = Symbol.instance_methods.collect{|m| m.to_s} | ||
|         select_message(receiver, message, candidates, sep) | ||
|         candidates = select_message(receiver, message, candidates, sep) | ||
|         check_display_name(candidates, on_input, "Symbol") | ||
|       when /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)(\.|::)([^.]*)$/ | ||
|         # Numeric | ||
|         receiver = $1 | ||
|         sep = $5 | ||
|         on_input = $6 | ||
|         message = Regexp.quote($6) | ||
|         begin | ||
| ... | ... | |
|         rescue Exception | ||
|           candidates = [] | ||
|         end | ||
|         select_message(receiver, message, candidates, sep) | ||
|         candidates = select_message(receiver, message, candidates, sep) | ||
|         check_display_name(candidates, input) do | ||
|           rec = eval(receiver, bind) | ||
|           "#{rec.class.name}##{on_input}" | ||
|         end | ||
|       when /^(-?0x[0-9a-fA-F_]+)(\.|::)([^.]*)$/ | ||
|         # Numeric(0xFFFF) | ||
|         receiver = $1 | ||
|         sep = $2 | ||
|         on_input = $3 | ||
|         message = Regexp.quote($3) | ||
|         begin | ||
| ... | ... | |
|         rescue Exception | ||
|           candidates = [] | ||
|         end | ||
|         select_message(receiver, message, candidates, sep) | ||
|         candidates = select_message(receiver, message, candidates, sep) | ||
|         check_display_name(candidates, input) do | ||
|           rec = eval(receiver, bind) | ||
|           display_name = "#{rec.class.name}##{on_input}" | ||
|         end | ||
|       when /^(\$[^.]*)$/ | ||
|         # global var | ||
| ... | ... | |
|         # variable.func or func.func | ||
|         receiver = $1 | ||
|         sep = $2 | ||
|         on_input = $3 | ||
|         message = Regexp.quote($3) | ||
|         gv = eval("global_variables", bind).collect{|m| m.to_s} | ||
| ... | ... | |
|               candidates = rec.constants.collect{|m| m.to_s} | ||
|             end | ||
|             candidates |= rec.methods.collect{|m| m.to_s} | ||
|             check_display_name(candidates, on_input) do | ||
|               if sep == "::" or rec.kind_of?(Module) | ||
|                 "#{rec.name}::#{on_input}" | ||
|               else | ||
|                 "#{rec.class.name}##{on_input}" | ||
|               end | ||
|             end | ||
|           rescue Exception | ||
|             candidates = [] | ||
|           end | ||
| ... | ... | |
|           } | ||
|           candidates.sort! | ||
|           candidates.uniq! | ||
|           check_display_name(candidates, on_input) do | ||
|             "#{sep}#{on_input}" | ||
|           end | ||
|         end | ||
|         select_message(receiver, message, candidates, sep) | ||
| ... | ... | |
|         # unknown(maybe String) | ||
|         receiver = "" | ||
|         on_input = $1 | ||
|         message = Regexp.quote($1) | ||
|         candidates = String.instance_methods(true).collect{|m| m.to_s} | ||
|         select_message(receiver, message, candidates) | ||
|         candidates = select_message(receiver, message, candidates) | ||
|         check_display_name(candidates, on_input, "String") | ||
|       else | ||
|         candidates = eval("methods | private_methods | local_variables | instance_variables | self.class.constants", bind).collect{|m| m.to_s} | ||
|         (candidates|ReservedWords).grep(/^#{Regexp.quote(input)}/) | ||
|         candidates = (candidates | ReservedWords).grep(/^#{Regexp.quote(input)}/) | ||
|         check_display_name(candidates, input) do | ||
|           "Kernel##{input}" | ||
|         end | ||
|       end | ||
|     } | ||
|     end | ||
|     # Set of available operators in Ruby | ||
|     Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~] | ||
| lib/irb/workspace.rb | ||
|---|---|---|
|           end | ||
|         end | ||
|       end | ||
|       @completion_data = {} | ||
|       @binding.local_variable_set(:_, nil) | ||
|     end | ||
| ... | ... | |
|     # <code>IRB.conf[:__MAIN__]</code> | ||
|     attr_reader :main | ||
|     # Data for showing document in completion | ||
|     attr_accessor :completion_data | ||
|     # Evaluate the given +statements+ within the  context of this workspace. | ||
|     def evaluate(context, statements, file = __FILE__, line = __LINE__) | ||
|       eval(statements, @binding, file, line) | ||