summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authortomoya ishida <tomoyapenguin@gmail.com>2024-04-04 00:50:03 +0900
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2024-04-04 17:18:47 +0900
commit8088c88d01a0c35ee4ce833fa8ab054d4cc6bc95 (patch)
tree0be6b04e61766f99951099f1296ab1cdb4d56035 /lib
parent80e31663f399a1fe106fff0fffb9e222e37a037d (diff)
[ruby/reline] Handle INT signal correctly, remove handle_cleared
because clear(C-l) is not a signal (https://github.com/ruby/reline/pull/646) https://github.com/ruby/reline/commit/3debb0ae2f
Diffstat (limited to 'lib')
-rw-r--r--lib/reline.rb35
-rw-r--r--lib/reline/ansi.rb14
-rw-r--r--lib/reline/general_io.rb1
-rw-r--r--lib/reline/line_editor.rb76
-rw-r--r--lib/reline/windows.rb2
5 files changed, 71 insertions, 57 deletions
diff --git a/lib/reline.rb b/lib/reline.rb
index b43584fc9b..f730f8af12 100644
--- a/lib/reline.rb
+++ b/lib/reline.rb
@@ -254,32 +254,35 @@ module Reline
Reline::DEFAULT_DIALOG_CONTEXT = Array.new
def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
+ unless confirm_multiline_termination
+ raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
+ end
+
Reline.update_iogate
io_gate.with_raw_input do
- unless confirm_multiline_termination
- raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
- end
inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
+ end
- whole_buffer = line_editor.whole_buffer.dup
- whole_buffer.taint if RUBY_VERSION < '2.7'
- if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
- Reline::HISTORY << whole_buffer
- end
+ whole_buffer = line_editor.whole_buffer.dup
+ whole_buffer.taint if RUBY_VERSION < '2.7'
+ if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
+ Reline::HISTORY << whole_buffer
+ end
- if line_editor.eof?
- line_editor.reset_line
- # Return nil if the input is aborted by C-d.
- nil
- else
- whole_buffer
- end
+ if line_editor.eof?
+ line_editor.reset_line
+ # Return nil if the input is aborted by C-d.
+ nil
+ else
+ whole_buffer
end
end
def readline(prompt = '', add_hist = false)
Reline.update_iogate
- inner_readline(prompt, add_hist, false)
+ io_gate.with_raw_input do
+ inner_readline(prompt, add_hist, false)
+ end
line = line_editor.line.dup
line.taint if RUBY_VERSION < '2.7'
diff --git a/lib/reline/ansi.rb b/lib/reline/ansi.rb
index 2d7c759ea2..0d7226b36f 100644
--- a/lib/reline/ansi.rb
+++ b/lib/reline/ansi.rb
@@ -151,7 +151,11 @@ class Reline::ANSI
end
def self.with_raw_input
- @@input.raw { yield }
+ if @@input.tty?
+ @@input.raw(intr: true) { yield }
+ else
+ yield
+ end
end
@@buf = []
@@ -159,11 +163,13 @@ class Reline::ANSI
unless @@buf.empty?
return @@buf.shift
end
- until c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
- timeout_second -= 0.1
+ until @@input.wait_readable(0.01)
+ timeout_second -= 0.01
return nil if timeout_second <= 0
- Reline.core.line_editor.resize
+
+ Reline.core.line_editor.handle_signal
end
+ c = @@input.getbyte
(c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
rescue Errno::EIO
# Maybe the I/O has been closed.
diff --git a/lib/reline/general_io.rb b/lib/reline/general_io.rb
index 0ac1c6c56d..d52151ad3c 100644
--- a/lib/reline/general_io.rb
+++ b/lib/reline/general_io.rb
@@ -46,6 +46,7 @@ class Reline::GeneralIO
end
c = nil
loop do
+ Reline.core.line_editor.handle_signal
result = @@input.wait_readable(0.1)
next if result.nil?
c = @@input.read(1)
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index 1fcf5e0358..c236044e41 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -138,9 +138,6 @@ class Reline::LineEditor
@screen_size = Reline::IOGate.get_screen_size
reset_variables(prompt, encoding: encoding)
@rendered_screen.base_y = Reline::IOGate.cursor_pos.y
- Reline::IOGate.set_winch_handler do
- @resized = true
- end
if ENV.key?('RELINE_ALT_SCROLLBAR')
@full_block = '::'
@upper_half_block = "''"
@@ -164,7 +161,12 @@ class Reline::LineEditor
end
end
- def resize
+ def handle_signal
+ handle_interrupted
+ handle_resized
+ end
+
+ private def handle_resized
return unless @resized
@screen_size = Reline::IOGate.get_screen_size
@@ -177,25 +179,35 @@ class Reline::LineEditor
render_differential
end
+ private def handle_interrupted
+ return unless @interrupted
+
+ @interrupted = false
+ clear_dialogs
+ scrolldown = render_differential
+ Reline::IOGate.scroll_down scrolldown
+ Reline::IOGate.move_cursor_column 0
+ @rendered_screen.lines = []
+ @rendered_screen.cursor_y = 0
+ case @old_trap
+ when 'DEFAULT', 'SYSTEM_DEFAULT'
+ raise Interrupt
+ when 'IGNORE'
+ # Do nothing
+ when 'EXIT'
+ exit
+ else
+ @old_trap.call if @old_trap.respond_to?(:call)
+ end
+ end
+
def set_signal_handlers
- @old_trap = Signal.trap('INT') {
- clear_dialogs
- scrolldown = render_differential
- Reline::IOGate.scroll_down scrolldown
- Reline::IOGate.move_cursor_column 0
- @rendered_screen.lines = []
- @rendered_screen.cursor_y = 0
- case @old_trap
- when 'DEFAULT', 'SYSTEM_DEFAULT'
- raise Interrupt
- when 'IGNORE'
- # Do nothing
- when 'EXIT'
- exit
- else
- @old_trap.call if @old_trap.respond_to?(:call)
- end
- }
+ Reline::IOGate.set_winch_handler do
+ @resized = true
+ end
+ @old_trap = Signal.trap('INT') do
+ @interrupted = true
+ end
end
def finalize
@@ -212,7 +224,6 @@ class Reline::LineEditor
@encoding = encoding
@is_multiline = false
@finished = false
- @cleared = false
@history_pointer = nil
@kill_ring ||= Reline::KillRing.new
@vi_clipboard = ''
@@ -234,6 +245,7 @@ class Reline::LineEditor
@in_pasting = false
@auto_indent_proc = nil
@dialogs = []
+ @interrupted = false
@resized = false
@cache = {}
@rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0)
@@ -541,19 +553,7 @@ class Reline::LineEditor
screen_height - wrapped_cursor_y + screen_scroll_top - @rendered_screen.base_y - 1
end
- def handle_cleared
- return unless @cleared
-
- @cleared = false
- Reline::IOGate.clear_screen
- @screen_size = Reline::IOGate.get_screen_size
- @rendered_screen.lines = []
- @rendered_screen.base_y = 0
- @rendered_screen.cursor_y = 0
- end
-
def rerender
- handle_cleared
render_differential unless @in_pasting
end
@@ -2074,7 +2074,11 @@ class Reline::LineEditor
alias_method :yank_pop, :em_yank_pop
private def ed_clear_screen(key)
- @cleared = true
+ Reline::IOGate.clear_screen
+ @screen_size = Reline::IOGate.get_screen_size
+ @rendered_screen.lines = []
+ @rendered_screen.base_y = 0
+ @rendered_screen.cursor_y = 0
end
alias_method :clear_screen, :ed_clear_screen
diff --git a/lib/reline/windows.rb b/lib/reline/windows.rb
index 28f28e15cc..ee3f73e383 100644
--- a/lib/reline/windows.rb
+++ b/lib/reline/windows.rb
@@ -259,7 +259,7 @@ class Reline::Windows
def self.check_input_event
num_of_events = 0.chr * 8
while @@output_buf.empty?
- Reline.core.line_editor.resize
+ Reline.core.line_editor.handle_signal
if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec
# prevent for background consolemode change
@@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)