summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authortomoya ishida <[email protected]>2024-10-02 02:01:31 +0900
committergit <[email protected]>2024-10-01 17:01:38 +0000
commite320da60976f6818c8667afb98fe88142c3073d2 (patch)
tree3b056188af6c69387799b656a1e6aebf972255d2 /lib
parentec230ac6432ea89f1ee53d82a62337d4883dc83a (diff)
[ruby/reline] Fix Reline crash with invalid encoding history
(https://github.com/ruby/reline/pull/751) https://github.com/ruby/reline/commit/e9d4b37e34
Diffstat (limited to 'lib')
-rw-r--r--lib/reline/history.rb6
-rw-r--r--lib/reline/line_editor.rb2
-rw-r--r--lib/reline/unicode.rb16
3 files changed, 20 insertions, 4 deletions
diff --git a/lib/reline/history.rb b/lib/reline/history.rb
index 3f3b65fea6..47c68ba774 100644
--- a/lib/reline/history.rb
+++ b/lib/reline/history.rb
@@ -19,7 +19,7 @@ class Reline::History < Array
def []=(index, val)
index = check_index(index)
- super(index, String.new(val, encoding: Reline.encoding_system_needs))
+ super(index, Reline::Unicode.safe_encode(val, Reline.encoding_system_needs))
end
def concat(*val)
@@ -45,7 +45,7 @@ class Reline::History < Array
end
end
super(*(val.map{ |v|
- String.new(v, encoding: Reline.encoding_system_needs)
+ Reline::Unicode.safe_encode(v, Reline.encoding_system_needs)
}))
end
@@ -56,7 +56,7 @@ class Reline::History < Array
if @config.history_size.positive?
shift if size + 1 > @config.history_size
end
- super(String.new(val, encoding: Reline.encoding_system_needs))
+ super(Reline::Unicode.safe_encode(val, Reline.encoding_system_needs))
end
private def check_index(index)
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index c71a5f79ee..56dc235c03 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -1325,7 +1325,7 @@ class Reline::LineEditor
save_old_buffer
pre = @buffer_of_lines[@line_index].byteslice(0, @byte_pointer)
post = @buffer_of_lines[@line_index].byteslice(@byte_pointer..)
- lines = (pre + text.gsub(/\r\n?/, "\n") + post).split("\n", -1)
+ lines = (pre + Reline::Unicode.safe_encode(text, @encoding).gsub(/\r\n?/, "\n") + post).split("\n", -1)
lines << '' if lines.empty?
@buffer_of_lines[@line_index, 1] = lines
@line_index += lines.size - 1
diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb
index ef239d5e9e..0ec815aeea 100644
--- a/lib/reline/unicode.rb
+++ b/lib/reline/unicode.rb
@@ -54,6 +54,22 @@ class Reline::Unicode
}.join
end
+ def self.safe_encode(str, encoding)
+ # Reline only supports utf-8 convertible string.
+ converted = str.encode(encoding, invalid: :replace, undef: :replace)
+ return converted if str.encoding == Encoding::UTF_8 || converted.encoding == Encoding::UTF_8 || converted.ascii_only?
+
+ # This code is essentially doing the same thing as
+ # `str.encode(utf8, **replace_options).encode(encoding, **replace_options)`
+ # but also avoids unneccesary irreversible encoding conversion.
+ converted.gsub(/\X/) do |c|
+ c.encode(Encoding::UTF_8)
+ c
+ rescue Encoding::UndefinedConversionError
+ '?'
+ end
+ end
+
require 'reline/unicode/east_asian_width'
def self.get_mbchar_width(mbchar)