diff options
Diffstat (limited to 'lib/reline.rb')
-rw-r--r-- | lib/reline.rb | 103 |
1 files changed, 37 insertions, 66 deletions
diff --git a/lib/reline.rb b/lib/reline.rb index f0060f5c9c..6bae469894 100644 --- a/lib/reline.rb +++ b/lib/reline.rb @@ -7,6 +7,7 @@ require 'reline/key_stroke' require 'reline/line_editor' require 'reline/history' require 'reline/terminfo' +require 'reline/io' require 'reline/face' require 'rbconfig' @@ -18,20 +19,10 @@ module Reline class ConfigEncodingConversionError < StandardError; end Key = Struct.new(:char, :combined_char, :with_meta) do - def match?(other) - case other - when Reline::Key - (other.char.nil? or char.nil? or char == other.char) and - (other.combined_char.nil? or combined_char.nil? or combined_char == other.combined_char) and - (other.with_meta.nil? or with_meta.nil? or with_meta == other.with_meta) - when Integer, Symbol - (combined_char and combined_char == other) or - (combined_char.nil? and char and char == other) - else - false - end + # For dialog_proc `key.match?(dialog.name)` + def match?(sym) + combined_char.is_a?(Symbol) && combined_char == sym end - alias_method :==, :match? end CursorPos = Struct.new(:x, :y) DialogRenderInfo = Struct.new( @@ -225,17 +216,20 @@ module Reline journey_data = completion_journey_data return unless journey_data - target = journey_data.list[journey_data.pointer] + target = journey_data.list.first + completed = journey_data.list[journey_data.pointer] result = journey_data.list.drop(1) pointer = journey_data.pointer - 1 - return if target.empty? || (result == [target] && pointer < 0) + return if completed.empty? || (result == [completed] && pointer < 0) target_width = Reline::Unicode.calculate_width(target) - x = cursor_pos.x - target_width - if x < 0 - x = screen_width + x + completed_width = Reline::Unicode.calculate_width(completed) + if cursor_pos.x <= completed_width - target_width + # When target is rendered on the line above cursor position + x = screen_width - completed_width y = -1 else + x = [cursor_pos.x - completed_width, 0].max y = 0 end cursor_pos_to_render = Reline::CursorPos.new(x, y) @@ -260,7 +254,6 @@ module Reline raise ArgumentError.new('#readmultiline needs block to confirm multiline termination') end - Reline.update_iogate io_gate.with_raw_input do inner_readline(prompt, add_hist, true, &confirm_multiline_termination) end @@ -283,7 +276,6 @@ module Reline def readline(prompt = '', add_hist = false) @mutex.synchronize do - Reline.update_iogate io_gate.with_raw_input do inner_readline(prompt, add_hist, false) end @@ -309,6 +301,10 @@ module Reline $stderr.sync = true $stderr.puts "Reline is used by #{Process.pid}" end + unless config.test_mode or config.loaded? + config.read + io_gate.set_default_key_bindings(config) + end otio = io_gate.prep may_req_ambiguous_char_width @@ -329,18 +325,12 @@ module Reline line_editor.auto_indent_proc = auto_indent_proc line_editor.dig_perfect_match_proc = dig_perfect_match_proc pre_input_hook&.call - unless Reline::IOGate == Reline::GeneralIO + unless Reline::IOGate.dumb? @dialog_proc_list.each_pair do |name_sym, d| line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context) end end - unless config.test_mode - config.read - config.reset_default_key_bindings - io_gate.set_default_key_bindings(config) - end - line_editor.print_nomultiline_prompt(prompt) line_editor.update_dialogs line_editor.rerender @@ -350,7 +340,15 @@ module Reline loop do read_io(config.keyseq_timeout) { |inputs| line_editor.set_pasting_state(io_gate.in_pasting?) - inputs.each { |key| line_editor.update(key) } + inputs.each do |key| + if key.char == :bracketed_paste_start + text = io_gate.read_bracketed_paste + line_editor.insert_pasted_text(text) + line_editor.scroll_into_view + else + line_editor.update(key) + end + end } if line_editor.finished? line_editor.render_finished @@ -390,9 +388,8 @@ module Reline end case result when :matched - expanded = key_stroke.expand(buffer).map{ |expanded_c| - Reline::Key.new(expanded_c, expanded_c, false) - } + expanded, rest_bytes = key_stroke.expand(buffer) + rest_bytes.reverse_each { |c| io_gate.ungetc(c) } block.(expanded) break when :matching @@ -406,9 +403,8 @@ module Reline if buffer.size == 1 and c == "\e".ord read_escaped_key(keyseq_timeout, c, block) else - expanded = buffer.map{ |expanded_c| - Reline::Key.new(expanded_c, expanded_c, false) - } + expanded, rest_bytes = key_stroke.expand(buffer) + rest_bytes.reverse_each { |c| io_gate.ungetc(c) } block.(expanded) end break @@ -432,9 +428,8 @@ module Reline return :next when :matched buffer << succ_c - expanded = key_stroke.expand(buffer).map{ |expanded_c| - Reline::Key.new(expanded_c, expanded_c, false) - } + expanded, rest_bytes = key_stroke.expand(buffer) + rest_bytes.reverse_each { |c| io_gate.ungetc(c) } block.(expanded) return :break end @@ -464,7 +459,7 @@ module Reline end private def may_req_ambiguous_char_width - @ambiguous_width = 2 if io_gate == Reline::GeneralIO or !STDOUT.tty? + @ambiguous_width = 2 if io_gate.dumb? || !STDIN.tty? || !STDOUT.tty? return if defined? @ambiguous_width io_gate.move_cursor_column(0) begin @@ -558,37 +553,13 @@ module Reline def self.line_editor core.line_editor end +end - def self.update_iogate - return if core.config.test_mode - # Need to change IOGate when `$stdout.tty?` change from false to true by `$stdout.reopen` - # Example: rails/spring boot the application in non-tty, then run console in tty. - if ENV['TERM'] != 'dumb' && core.io_gate == Reline::GeneralIO && $stdout.tty? - require 'reline/ansi' - remove_const(:IOGate) - const_set(:IOGate, Reline::ANSI) - end - end -end +Reline::IOGate = Reline::IO.decide_io_gate -require 'reline/general_io' -io = Reline::GeneralIO -unless ENV['TERM'] == 'dumb' - case RbConfig::CONFIG['host_os'] - when /mswin|msys|mingw|cygwin|bccwin|wince|emc/ - require 'reline/windows' - tty = (io = Reline::Windows).msys_tty? - else - tty = $stdout.tty? - end -end -Reline::IOGate = if tty - require 'reline/ansi' - Reline::ANSI -else - io -end +# Deprecated +Reline::GeneralIO = Reline::Dumb.new Reline::Face.load_initial_configs |