Skip to content

Commit

Permalink
Merge pull request #212 from aycabta/complete-require-and-require_rel…
Browse files Browse the repository at this point in the history
…ative

Complete require and require_relative
  • Loading branch information
aycabta authored Mar 24, 2021
2 parents f7f876a + 1c61178 commit f2c1d7c
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 2 deletions.
58 changes: 56 additions & 2 deletions lib/irb/completion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

autoload :RDoc, "rdoc"

require_relative 'ruby-lex'

module IRB
module InputCompletor # :nodoc:

Expand Down Expand Up @@ -38,8 +40,60 @@ def defined? do

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)
Expand Down
1 change: 1 addition & 0 deletions lib/irb/input-method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ def initialize
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]
Expand Down
14 changes: 14 additions & 0 deletions test/irb/test_completion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,19 @@ def test_complete_predicate?
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

0 comments on commit f2c1d7c

Please sign in to comment.