diff options
Diffstat (limited to 'lib/reline')
-rw-r--r-- | lib/reline/ansi.rb | 2 | ||||
-rw-r--r-- | lib/reline/config.rb | 17 | ||||
-rw-r--r-- | lib/reline/key_actor/emacs.rb | 4 | ||||
-rw-r--r-- | lib/reline/line_editor.rb | 74 | ||||
-rw-r--r-- | lib/reline/version.rb | 2 |
5 files changed, 82 insertions, 17 deletions
diff --git a/lib/reline/ansi.rb b/lib/reline/ansi.rb index 45a475a787..fa9feb2630 100644 --- a/lib/reline/ansi.rb +++ b/lib/reline/ansi.rb @@ -235,7 +235,7 @@ class Reline::ANSI s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i] return s if s[0] > 0 && s[1] > 0 [24, 80] - rescue Errno::ENOTTY + rescue Errno::ENOTTY, Errno::ENODEV [24, 80] end diff --git a/lib/reline/config.rb b/lib/reline/config.rb index d44c2675ab..62c6d105b3 100644 --- a/lib/reline/config.rb +++ b/lib/reline/config.rb @@ -182,9 +182,10 @@ class Reline::Config next if if_stack.any? { |_no, skip| skip } case line - when /^set +([^ ]+) +([^ ]+)/i - var, value = $1.downcase, $2 - bind_variable(var, value) + when /^set +([^ ]+) +(.+)/i + # value ignores everything after a space, raw_value does not. + var, value, raw_value = $1.downcase, $2.partition(' ').first, $2 + bind_variable(var, value, raw_value) next when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o key, func_name = $1, $2 @@ -234,7 +235,7 @@ class Reline::Config end end - def bind_variable(name, value) + def bind_variable(name, value, raw_value) case name when 'history-size' begin @@ -259,7 +260,7 @@ class Reline::Config when 'completion-query-items' @completion_query_items = value.to_i when 'isearch-terminators' - @isearch_terminators = retrieve_string(value) + @isearch_terminators = retrieve_string(raw_value) when 'editing-mode' case value when 'emacs' @@ -301,11 +302,11 @@ class Reline::Config @show_mode_in_prompt = false end when 'vi-cmd-mode-string' - @vi_cmd_mode_string = retrieve_string(value) + @vi_cmd_mode_string = retrieve_string(raw_value) when 'vi-ins-mode-string' - @vi_ins_mode_string = retrieve_string(value) + @vi_ins_mode_string = retrieve_string(raw_value) when 'emacs-mode-string' - @emacs_mode_string = retrieve_string(value) + @emacs_mode_string = retrieve_string(raw_value) when *VARIABLE_NAMES then variable_name = :"@#{name.tr(?-, ?_)}" instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on') diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb index 9c797ba43e..d7354520b0 100644 --- a/lib/reline/key_actor/emacs.rb +++ b/lib/reline/key_actor/emacs.rb @@ -63,7 +63,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base # 30 ^^ :ed_unassigned, # 31 ^_ - :ed_unassigned, + :undo, # 32 SPACE :ed_insert, # 33 ! @@ -319,7 +319,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base # 158 M-^^ :ed_unassigned, # 159 M-^_ - :ed_unassigned, + :redo, # 160 M-SPACE :em_set_mark, # 161 M-! diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb index 4c76932c10..8f6421fb10 100644 --- a/lib/reline/line_editor.rb +++ b/lib/reline/line_editor.rb @@ -4,7 +4,6 @@ require 'reline/unicode' require 'tempfile' class Reline::LineEditor - # TODO: undo # TODO: Use "private alias_method" idiom after drop Ruby 2.5. attr_reader :byte_pointer attr_accessor :confirm_multiline_termination_proc @@ -251,6 +250,9 @@ class Reline::LineEditor @resized = false @cache = {} @rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0) + @input_lines = [[[""], 0, 0]] + @input_lines_position = 0 + @undoing = false reset_line end @@ -948,7 +950,8 @@ class Reline::LineEditor unless @waiting_proc byte_pointer_diff = @byte_pointer - old_byte_pointer @byte_pointer = old_byte_pointer - send(@vi_waiting_operator, byte_pointer_diff) + method_obj = method(@vi_waiting_operator) + wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff) cleanup_waiting end else @@ -1009,7 +1012,8 @@ class Reline::LineEditor if @vi_waiting_operator byte_pointer_diff = @byte_pointer - old_byte_pointer @byte_pointer = old_byte_pointer - send(@vi_waiting_operator, byte_pointer_diff) + method_obj = method(@vi_waiting_operator) + wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff) cleanup_waiting end @kill_ring.process @@ -1106,6 +1110,7 @@ class Reline::LineEditor end def input_key(key) + save_old_buffer @config.reset_oneshot_key_bindings @dialogs.each do |dialog| if key.char.instance_of?(Symbol) and key.char == dialog.name @@ -1120,7 +1125,6 @@ class Reline::LineEditor finish return end - old_lines = @buffer_of_lines.dup @first_char = false @completion_occurs = false @@ -1134,12 +1138,15 @@ class Reline::LineEditor @completion_journey_state = nil end + push_input_lines unless @undoing + @undoing = false + if @in_pasting clear_dialogs return end - modified = old_lines != @buffer_of_lines + modified = @old_buffer_of_lines != @buffer_of_lines if !@completion_occurs && modified && !@config.disable_completion && @config.autocompletion # Auto complete starts only when edited process_insert(force: true) @@ -1148,6 +1155,29 @@ class Reline::LineEditor modified end + def save_old_buffer + @old_buffer_of_lines = @buffer_of_lines.dup + end + + def push_input_lines + if @old_buffer_of_lines == @buffer_of_lines + @input_lines[@input_lines_position] = [@buffer_of_lines.dup, @byte_pointer, @line_index] + else + @input_lines = @input_lines[0..@input_lines_position] + @input_lines_position += 1 + @input_lines.push([@buffer_of_lines.dup, @byte_pointer, @line_index]) + end + trim_input_lines + end + + MAX_INPUT_LINES = 100 + def trim_input_lines + if @input_lines.size > MAX_INPUT_LINES + @input_lines.shift + @input_lines_position -= 1 + end + end + def scroll_into_view _wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position if wrapped_cursor_y < screen_scroll_top @@ -1224,6 +1254,18 @@ class Reline::LineEditor process_auto_indent end + def set_current_lines(lines, byte_pointer = nil, line_index = 0) + cursor = current_byte_pointer_cursor + @buffer_of_lines = lines + @line_index = line_index + if byte_pointer + @byte_pointer = byte_pointer + else + calculate_nearest_cursor(cursor) + end + process_auto_indent + end + def retrieve_completion_block(set_completion_quote_character = false) if Reline.completer_word_break_characters.empty? word_break_regexp = nil @@ -1306,6 +1348,7 @@ class Reline::LineEditor end def insert_pasted_text(text) + 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) @@ -1313,6 +1356,7 @@ class Reline::LineEditor @buffer_of_lines[@line_index, 1] = lines @line_index += lines.size - 1 @byte_pointer = @buffer_of_lines[@line_index].bytesize - post.bytesize + push_input_lines end def insert_text(text) @@ -2487,4 +2531,24 @@ class Reline::LineEditor private def vi_editing_mode(key) @config.editing_mode = :vi_insert end + + private def undo(_key) + @undoing = true + + return if @input_lines_position <= 0 + + @input_lines_position -= 1 + target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position] + set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y) + end + + private def redo(_key) + @undoing = true + + return if @input_lines_position >= @input_lines.size - 1 + + @input_lines_position += 1 + target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position] + set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y) + end end diff --git a/lib/reline/version.rb b/lib/reline/version.rb index ef7d617a45..46613a5952 100644 --- a/lib/reline/version.rb +++ b/lib/reline/version.rb @@ -1,3 +1,3 @@ module Reline - VERSION = '0.5.6' + VERSION = '0.5.7' end |