diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb index af3b69eb2..e69eae1de 100644 --- a/lib/irb/completion.rb +++ b/lib/irb/completion.rb @@ -86,6 +86,11 @@ def retrieve_files_to_require_from_load_path ) end + def command_completions(preposing, target) + return [] unless preposing && preposing.match?(/\A\s*\z/) + IRB::ExtendCommandBundle.command_names.select { _1.start_with?(target) } + end + 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/, '') @@ -103,9 +108,10 @@ def inspect end def completion_candidates(preposing, target, _postposing, bind:) + commands = command_completions(preposing, target) result = ReplTypeCompletor.analyze(preposing + target, binding: bind, filename: @context.irb_path) - return [] unless result - result.completion_candidates.map { target + _1 } + return commands unless result + commands | result.completion_candidates.map { target + _1 } end def doc_namespace(preposing, matched, _postposing, bind:) @@ -177,11 +183,12 @@ def complete_require_path(target, preposing, postposing) end def completion_candidates(preposing, target, postposing, bind:) + commands = command_completions(preposing, target) if preposing && postposing result = complete_require_path(target, preposing, postposing) return result if result end - retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) } + commands | retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) } end def doc_namespace(_preposing, matched, _postposing, bind:) diff --git a/test/irb/test_completion.rb b/test/irb/test_completion.rb index 0625c9697..831b030bf 100644 --- a/test/irb/test_completion.rb +++ b/test/irb/test_completion.rb @@ -14,6 +14,13 @@ def doc_namespace(target, bind) IRB::RegexpCompletor.new.doc_namespace('', target, '', bind: bind) end + class CommandCompletionTest < CompletionTest + def test_command_completion + assert_include(IRB::RegexpCompletor.new.completion_candidates(' ', 'show_s', '', bind: binding), 'show_source') + assert_not_include(IRB::RegexpCompletor.new.completion_candidates(';', 'show_s', '', bind: binding), 'show_source') + end + end + class MethodCompletionTest < CompletionTest def test_complete_string assert_include(completion_candidates("'foo'.up", binding), "'foo'.upcase") diff --git a/test/irb/test_type_completor.rb b/test/irb/test_type_completor.rb index cf4fc12c9..1ab231fab 100644 --- a/test/irb/test_type_completor.rb +++ b/test/irb/test_type_completor.rb @@ -9,6 +9,8 @@ return end +require 'irb/context' +require 'irb/extend-command' require 'irb/completion' require 'tempfile' require_relative './helper' @@ -54,6 +56,11 @@ def test_empty_completion assert_equal [], candidates assert_doc_namespace('(', ')', nil) end + + def test_command_completion + assert_include(@completor.completion_candidates(' ', 'show_s', '', bind: binding), 'show_source') + assert_not_include(@completor.completion_candidates(';', 'show_s', '', bind: binding), 'show_source') + end end class TypeCompletorIntegrationTest < IntegrationTestCase