# frozen_string_literal: false
#
# irb/completion.rb -
# $Release Version: 0.9$
# $Revision$
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
# From Original Idea of shugo@ruby-lang.org
#
autoload :RDoc, "rdoc"
module IRB
module InputCompletor # :nodoc:
# Set of reserved words used by Ruby, you should not use these for
# constants or variables
ReservedWords = %w[
__ENCODING__ __LINE__ __FILE__
BEGIN END
alias and
begin break
case class
def defined? do
else elsif end ensure
false for
if in
module
next nil not
or
redo rescue retry return
self super
then true
undef unless until
when while
yield
]
BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
CompletionProc = proc { |input|
retrieve_completion_data(input).compact.map{ |i| i.encode(Encoding.default_external) }
}
def self.retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
case input
when /^((["'`]).*\2)\.([^.]*)$/
# String
receiver = $1
message = Regexp.quote($3)
candidates = String.instance_methods.collect{|m| m.to_s}
if doc_namespace
"String.#{message}"
else
select_message(receiver, message, candidates)
end
when /^(\/[^\/]*\/)\.([^.]*)$/
# Regexp
receiver = $1
message = Regexp.quote($2)
candidates = Regexp.instance_methods.collect{|m| m.to_s}
if doc_namespace
"Regexp.#{message}"
else
select_message(receiver, message, candidates)
end
when /^([^\]]*\])\.([^.]*)$/
# Array
receiver = $1
message = Regexp.quote($2)
candidates = Array.instance_methods.collect{|m| m.to_s}
if doc_namespace
"Array.#{message}"
else
select_message(receiver, message, candidates)
end
when /^([^\}]*\})\.([^.]*)$/
# Proc or Hash
receiver = $1
message = Regexp.quote($2)
proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
if doc_namespace
["Proc.#{message}", "Hash.#{message}"]
else
select_message(receiver, message, proc_candidates | hash_candidates)
end
when /^(:[^:.]*)$/
# Symbol
return nil if doc_namespace
sym = $1
candidates = Symbol.all_symbols.collect do |s|
":" + s.id2name.encode(Encoding.default_external)
rescue Encoding::UndefinedConversionError
# ignore
end
candidates.grep(/^#{Regexp.quote(sym)}/)
when /^::([A-Z][^:\.\(]*)$/
# Absolute Constant or class methods
receiver = $1
candidates = Object.constants.collect{|m| m.to_s}
if doc_namespace
candidates.find { |i| i == receiver }
else
candidates.grep(/^#{receiver}/).collect{|e| "::" + e}
end
when /^([A-Z].*)::([^:.]*)$/
# Constant or class methods
receiver = $1
message = Regexp.quote($2)
begin
candidates = eval("#{receiver}.constants.collect{|m| m.to_s}", bind)
candidates |= eval("#{receiver}.methods.collect{|m| m.to_s}", bind)
rescue Exception
candidates = []
end
if doc_namespace
"#{receiver}::#{message}"
else
select_message(receiver, message, candidates, "::")
end
when /^(:[^:.]+)(\.|::)([^.]*)$/
# Symbol
receiver = $1
sep = $2
message = Regexp.quote($3)
candidates = Symbol.instance_methods.collect{|m| m.to_s}
if doc_namespace
"Symbol.#{message}"
else
select_message(receiver, message, candidates, sep)
end
when /^(?