diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb index 0fdb85ab4..26215f6fe 100644 --- a/lib/irb/completion.rb +++ b/lib/irb/completion.rb @@ -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 @@ -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) @@ -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| @@ -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 @@ -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 @@ -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:) diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb index 07605ca5d..af2b4994f 100644 --- a/lib/irb/input-method.rb +++ b/lib/irb/input-method.rb @@ -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 @@ -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] @@ -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 = [ @@ -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? @@ -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 diff --git a/test/irb/test_completion.rb b/test/irb/test_completion.rb index ad3ef3acf..2ef893826 100644 --- a/test/irb/test_completion.rb +++ b/test/irb/test_completion.rb @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/test/irb/test_input_method.rb b/test/irb/test_input_method.rb index 73d3fafa3..2d8cfadcf 100644 --- a/test/irb/test_input_method.rb +++ b/test/irb/test_input_method.rb @@ -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