summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraycabta <aycabta@gmail.com>2021-03-24 14:55:05 +0900
committergit <svn-admin@ruby-lang.org>2021-03-24 15:11:41 +0900
commit0927756e58c7d68517a1468f2327ce50989ff3f2 (patch)
treedeb83d6f2ca40f4b0052092f9e066321d5781ee2
parent0259ee600857729d289959ddf5973c25159209b2 (diff)
[ruby/irb] Complete require and require_relative
https://github.com/ruby/irb/commit/1c61178b4c
-rw-r--r--lib/irb/completion.rb58
-rw-r--r--lib/irb/input-method.rb1
-rw-r--r--test/irb/test_completion.rb14
3 files changed, 71 insertions, 2 deletions
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
index 22a1ad1d3d..0385142a3c 100644
--- a/lib/irb/completion.rb
+++ b/lib/irb/completion.rb
@@ -9,6 +9,8 @@
autoload :RDoc, "rdoc"
+require_relative 'ruby-lex'
+
module IRB
module InputCompletor # :nodoc:
@@ -38,8 +40,60 @@ module IRB
BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
- CompletionProc = proc { |input|
- retrieve_completion_data(input).compact.map{ |i| i.encode(Encoding.default_external) }
+ 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
+ if tok && tok.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
+ case tok.tok
+ when 'require'
+ result = $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/, '')
+ }.select { |path|
+ path.start_with?(actual_target)
+ }.map { |path|
+ quote + path
+ }
+ when 'require_relative'
+ result = Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
+ path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
+ }.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)
diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb
index e223672985..1854567a2d 100644
--- a/lib/irb/input-method.rb
+++ b/lib/irb/input-method.rb
@@ -280,6 +280,7 @@ module IRB
Reline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS
end
Reline.completion_append_character = nil
+ Reline.completer_quote_characters = ''
Reline.completion_proc = IRB::InputCompletor::CompletionProc
Reline.output_modifier_proc =
if IRB.conf[:USE_COLORIZE]
diff --git a/test/irb/test_completion.rb b/test/irb/test_completion.rb
index 984453d059..de043c7088 100644
--- a/test/irb/test_completion.rb
+++ b/test/irb/test_completion.rb
@@ -55,5 +55,19 @@ module TestIRB
namespace = IRB::InputCompletor.retrieve_completion_data("1.positive?", bind: binding, doc_namespace: true)
assert_equal "Integer.positive?", namespace
end
+
+ def test_complete_require
+ candidates = IRB::InputCompletor::CompletionProc.("'irb", "require ", "")
+ %w['irb/init 'irb/ruby-lex].each do |word|
+ assert_include candidates, word
+ end
+ end
+
+ def test_complete_require_relative
+ candidates = IRB::InputCompletor::CompletionProc.("'lib/irb", "require_relative ", "")
+ %w['lib/irb/init 'lib/irb/ruby-lex].each do |word|
+ assert_include candidates, word
+ end
+ end
end
end