Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions lib/irb/completion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,14 @@ def completion_candidates(preposing, target, _postposing, bind:)

return commands unless result

commands | result.completion_candidates.map { target + _1 }
encoded_candidates = result.completion_candidates.filter_map do |i|
encoded = i.encode(Encoding.default_external)
target + encoded
rescue Encoding::UndefinedConversionError
# If the string cannot be converted, we just ignore it
nil
end
commands | encoded_candidates
end

def doc_namespace(preposing, matched, _postposing, bind:)
Expand Down Expand Up @@ -194,7 +201,12 @@ def completion_candidates(preposing, target, postposing, bind:)
# It doesn't make sense to propose commands with other preposing
commands = [] unless preposing.empty?

completion_data = retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
completion_data = retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.filter_map do |i|
i.encode(Encoding.default_external)
rescue Encoding::UndefinedConversionError
Comment on lines +205 to +206

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add this encode and rescue to IRB::TypeCompletor#completion_candidates?
It is the default completor when RUBY_VERSION >= '3.4'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied the same fix to IRB::TypeCompletor#completion_candidates.
4897ccf

# If the string cannot be converted, we just ignore it
nil
end
commands | completion_data
end

Expand Down
30 changes: 30 additions & 0 deletions test/irb/test_completion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -314,4 +314,34 @@ def test_retrieve_completion_data
assert_equal(IRB::InputCompletor.retrieve_completion_data('a.abs', bind: bind, doc_namespace: true), 'Integer.abs')
end
end

class InvalidEncodingMethodTest < TestCase
def test_regexp_completor_handles_encoding_errors_gracefully
if RUBY_ENGINE == 'truffleruby'
omit "TruffleRuby does not support invalid encoding methods."
end

invalid_method_name = "b\xff".force_encoding(Encoding::ASCII_8BIT)

test_obj = Object.new
test_obj.define_singleton_method(invalid_method_name) {}
test_bind = test_obj.instance_eval { binding }

original_encoding = Encoding.default_external

begin
Encoding.default_external = Encoding::UTF_8

completor = IRB::RegexpCompletor.new

assert_nothing_raised do
result = completor.completion_candidates('', 'b', '', bind: test_bind)
assert_include(result, 'block_given?')
assert_not_include(result, nil)
end
ensure
Encoding.default_external = original_encoding
end
end
end
end
22 changes: 22 additions & 0 deletions test/irb/test_type_completor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,28 @@ 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

def test_type_completor_handles_encoding_errors_gracefully
invalid_method_name = "b\xff".dup.force_encoding(Encoding::ASCII_8BIT)

test_obj = Object.new
test_obj.define_singleton_method(invalid_method_name) {}
test_bind = test_obj.instance_eval { binding }

original_encoding = Encoding.default_external

begin
Encoding.default_external = Encoding::UTF_8

assert_nothing_raised do
result = @completor.completion_candidates('', 'b', '', bind: test_bind)
assert_include(result, 'block_given?')
assert_not_include(result, nil)
end
ensure
Encoding.default_external = original_encoding
end
end
end

class TypeCompletorIntegrationTest < IntegrationTestCase
Expand Down