Skip to content

Commit

Permalink
Stop re-initialize completor on each completion phase
Browse files Browse the repository at this point in the history
  • Loading branch information
tompng committed Oct 10, 2023
1 parent 43302ae commit f618538
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 48 deletions.
41 changes: 15 additions & 26 deletions lib/irb/completion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,11 @@

module IRB
class BaseCompletor # :nodoc:
def initialize(target, preposing = nil, postposing = nil)
def completion_candidates(preposing, target, postposing, bind:)
raise NotImplementedError
end

def completion_candidates
raise NotImplementedError
end

def doc_namespace(matched)
def doc_namespace(preposing, matched, postposing, bind:)
raise NotImplementedError
end

Expand All @@ -36,7 +32,7 @@ def doc_namespace(matched)
[]
end.freeze

def self.retrieve_gem_and_system_load_path
def retrieve_gem_and_system_load_path
candidates = (GEM_PATHS | $LOAD_PATH)
candidates.map do |p|
if p.respond_to?(:to_path)
Expand All @@ -47,8 +43,8 @@ def self.retrieve_gem_and_system_load_path
end.compact.sort
end

def self.retrieve_files_to_require_from_load_path
@@files_from_load_path ||=
def retrieve_files_to_require_from_load_path
@files_from_load_path ||=
(
shortest = []
rest = retrieve_gem_and_system_load_path.each_with_object([]) { |path, result|
Expand All @@ -66,8 +62,8 @@ def self.retrieve_files_to_require_from_load_path
)
end

def self.retrieve_files_to_require_relative_from_current_dir
@@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
def 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
Expand Down Expand Up @@ -140,13 +136,13 @@ def complete_require_path(target, preposing, postposing)
if tok && tok.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
case tok.tok
when 'require'
result = BaseCompletor.retrieve_files_to_require_from_load_path.select { |path|
result = retrieve_files_to_require_from_load_path.select { |path|
path.start_with?(actual_target)
}.map { |path|
quote + path
}
when 'require_relative'
result = BaseCompletor.retrieve_files_to_require_relative_from_current_dir.select { |path|
result = retrieve_files_to_require_relative_from_current_dir.select { |path|
path.start_with?(actual_target)
}.map { |path|
quote + path
Expand All @@ -156,23 +152,16 @@ def complete_require_path(target, preposing, postposing)
result
end

def initialize(target, preposing, postposing, bind:)
@target = target
@preposing = preposing
@postposing = postposing
@binding = bind
end

def completion_candidates
if @preposing && @postposing
result = complete_require_path(@target, @preposing, @postposing)
def completion_candidates(preposing, target, postposing, bind:)
if preposing && postposing
result = complete_require_path(target, preposing, postposing)
return result if result
end
retrieve_completion_data(@target, bind: @binding, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
end

def doc_namespace(target)
retrieve_completion_data(target, bind: @binding, doc_namespace: true)
def doc_namespace(_preposing, matched, _postposing, bind:)
retrieve_completion_data(matched, bind: bind, doc_namespace: true)
end

def retrieve_completion_data(input, bind:, doc_namespace:)
Expand Down
18 changes: 11 additions & 7 deletions lib/irb/input-method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def initialize
Readline.completion_append_character = nil
Readline.completion_proc = ->(target) {
bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
RegexpCompletor.new(target, '', '', bind: bind).completion_candidates
RegexpCompletor.new.completion_candidates('', target, '', bind: bind)
}
end

Expand Down Expand Up @@ -235,14 +235,15 @@ def initialize
super

@eof = false
@completor = RegexpCompletor.new

Reline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
Reline.completion_append_character = nil
Reline.completer_quote_characters = ''
Reline.completion_proc = ->(target, preposing, postposing) {
bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
@completor = RegexpCompletor.new(target, preposing, postposing, bind: bind)
@completor.completion_candidates
@completion_params = [preposing, target, postposing, bind]
@completor.completion_candidates(preposing, target, postposing, bind: bind)
}
Reline.output_modifier_proc =
if IRB.conf[:USE_COLORIZE]
Expand Down Expand Up @@ -281,7 +282,10 @@ def auto_indent(&block)
end

def show_doc_dialog_proc
get_current_completor = -> { @completor }
doc_namespace = ->(matched) {
preposing, _target, postposing, bind = @completion_params
@completor.doc_namespace(preposing, matched, postposing, bind: bind)
}
->() {
dialog.trap_key = nil
alt_d = [
Expand All @@ -297,8 +301,7 @@ def show_doc_dialog_proc
cursor_pos_to_render, result, pointer, autocomplete_dialog = context.pop(4)
return nil if result.nil? or pointer.nil? or pointer < 0

completor = get_current_completor.call
name = completor.doc_namespace(result[pointer])
name = doc_namespace.call(result[pointer])

options = {}
options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
Expand Down Expand Up @@ -391,7 +394,8 @@ def display_document(matched, driver: nil)
return
end

namespace = @completor.doc_namespace(matched)
_target, preposing, postposing, bind = @completion_params
namespace = @completor.doc_namespace(preposing, matched, postposing, bind: bind)
return unless namespace

driver ||= RDoc::RI::Driver.new
Expand Down
22 changes: 10 additions & 12 deletions test/irb/test_completion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,11 @@ def teardown
end

def completion_candidates(target, bind)
completor = IRB::RegexpCompletor.new(target, '', '', bind: bind)
completor.completion_candidates
IRB::RegexpCompletor.new.completion_candidates('', target, '', bind: bind)
end

def doc_namespace(target, bind)
completor = IRB::RegexpCompletor.new(target, '', '', bind: bind)
completor.doc_namespace(target)
IRB::RegexpCompletor.new.doc_namespace('', target, '', bind: bind)
end

class MethodCompletionTest < CompletionTest
Expand Down Expand Up @@ -81,12 +79,12 @@ def test_complete_class

class RequireComepletionTest < CompletionTest
def test_complete_require
candidates = IRB::RegexpCompletor.new("'irb", "require ", "", bind: binding).completion_candidates
candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'irb", "", bind: binding)
%w['irb/init 'irb/ruby-lex].each do |word|
assert_include candidates, word
end
# Test cache
candidates = IRB::RegexpCompletor.new("'irb", "require ", "", bind: binding).completion_candidates
candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'irb", "", bind: binding)
%w['irb/init 'irb/ruby-lex].each do |word|
assert_include candidates, word
end
Expand All @@ -98,7 +96,7 @@ def test_complete_require_with_pathname_in_load_path
test_path = Pathname.new(temp_dir)
$LOAD_PATH << test_path

candidates = IRB::RegexpCompletor.new("'foo", "require ", "", bind: binding).completion_candidates
candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding)
assert_include candidates, "'foo"
ensure
$LOAD_PATH.pop if test_path
Expand All @@ -112,7 +110,7 @@ def test_complete_require_with_string_convertable_in_load_path
object.define_singleton_method(:to_s) { temp_dir }
$LOAD_PATH << object

candidates = IRB::RegexpCompletor.new("'foo", "require ", "", bind: binding).completion_candidates
candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding)
assert_include candidates, "'foo"
ensure
$LOAD_PATH.pop if object
Expand All @@ -125,27 +123,27 @@ def object.to_s; raise; end
$LOAD_PATH << object

assert_nothing_raised do
IRB::RegexpCompletor.new("'foo", "require ", "", bind: binding).completion_candidates
IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding)
end
ensure
$LOAD_PATH.pop if object
end

def test_complete_require_library_name_first
candidates = IRB::RegexpCompletor.new("'csv", "require ", "", bind: binding).completion_candidates
candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'csv", "", bind: binding)
assert_equal "'csv", candidates.first
end

def test_complete_require_relative
candidates = Dir.chdir(__dir__ + "/../..") do
IRB::RegexpCompletor.new("'lib/irb", "require_relative ", "", bind: binding).completion_candidates
IRB::RegexpCompletor.new.completion_candidates("require_relative ", "'lib/irb", "", bind: binding)
end
%w['lib/irb/init 'lib/irb/ruby-lex].each do |word|
assert_include candidates, word
end
# Test cache
candidates = Dir.chdir(__dir__ + "/../..") do
IRB::RegexpCompletor.new("'lib/irb", "require_relative ", "", bind: binding).completion_candidates
IRB::RegexpCompletor.new.completion_candidates("require_relative ", "'lib/irb", "", bind: binding)
end
%w['lib/irb/init 'lib/irb/ruby-lex].each do |word|
assert_include candidates, word
Expand Down
4 changes: 1 addition & 3 deletions test/irb/test_input_method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,8 @@ def setup
end

def display_document(target, bind)
completor = IRB::RegexpCompletor.new(target, '', '', bind: bind)
input_method = IRB::RelineInputMethod.new
# @completor needs to be initialized before calling display_document
input_method.instance_variable_set(:@completor, completor)
input_method.instance_variable_set(:@completion_params, [target, '', '', bind])
input_method.display_document(target, driver: @driver)
end

Expand Down

0 comments on commit f618538

Please sign in to comment.