summaryrefslogtreecommitdiff
path: root/lib/irb/completion.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/irb/completion.rb')
-rw-r--r--lib/irb/completion.rb76
1 files changed, 73 insertions, 3 deletions
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
index 22a1ad1d3d..d1bb82122e 100644
--- a/lib/irb/completion.rb
+++ b/lib/irb/completion.rb
@@ -7,7 +7,7 @@
# From Original Idea of shugo@ruby-lang.org
#
-autoload :RDoc, "rdoc"
+require_relative 'ruby-lex'
module IRB
module InputCompletor # :nodoc:
@@ -38,8 +38,69 @@ module IRB
BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
- CompletionProc = proc { |input|
- retrieve_completion_data(input).compact.map{ |i| i.encode(Encoding.default_external) }
+ def self.retrieve_files_to_require_from_load_path
+ @@files_from_load_path ||= $LOAD_PATH.flat_map { |path|
+ begin
+ Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: path)
+ rescue Errno::ENOENT
+ []
+ end
+ }.uniq.map { |path|
+ path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
+ }
+ end
+
+ def self.retrieve_files_to_require_relative_from_current_dir
+ @@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
+ path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
+ }
+ end
+
+ CompletionRequireProc = lambda { |target, preposing = nil, postposing = nil|
+ if target =~ /\A(['"])([^'"]+)\Z/
+ quote = $1
+ actual_target = $2
+ else
+ return nil # It's not String literal
+ end
+ tokens = RubyLex.ripper_lex_without_warning(preposing.gsub(/\s*\z/, ''))
+ tok = nil
+ tokens.reverse_each do |t|
+ unless [:on_lparen, :on_sp, :on_ignored_sp, :on_nl, :on_ignored_nl, :on_comment].include?(t.event)
+ tok = t
+ break
+ end
+ end
+ result = []
+ if tok && tok.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
+ case tok.tok
+ when 'require'
+ result = retrieve_files_to_require_from_load_path.select { |path|
+ path.start_with?(actual_target)
+ }.map { |path|
+ quote + path
+ }
+ when 'require_relative'
+ result = retrieve_files_to_require_relative_from_current_dir.select { |path|
+ path.start_with?(actual_target)
+ }.map { |path|
+ quote + path
+ }
+ end
+ end
+ result
+ }
+
+ CompletionProc = lambda { |target, preposing = nil, postposing = nil|
+ if preposing && postposing
+ result = CompletionRequireProc.(target, preposing, postposing)
+ unless result
+ result = retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
+ end
+ result
+ else
+ retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
+ end
}
def self.retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
@@ -266,13 +327,22 @@ module IRB
end
PerfectMatchedProc = ->(matched, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding) {
+ begin
+ require 'rdoc'
+ rescue LoadError
+ return
+ end
+
RDocRIDriver ||= RDoc::RI::Driver.new
+
if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
IRB.__send__(:easter_egg)
return
end
+
namespace = retrieve_completion_data(matched, bind: bind, doc_namespace: true)
return unless namespace
+
if namespace.is_a?(Array)
out = RDoc::Markup::Document.new
namespace.each do |m|