class Reline::LineEditor
Constants
- CompletionJourneyData
- DIALOG_DEFAULT_HEIGHT
- MenuInfo
- PROMPT_LIST_CACHE_TIMEOUT
- VI_MOTIONS
Attributes
TODO: undo TODO: Use “private alias_method” idiom after drop Ruby 2.5.
Public Class Methods
# File lib/reline/line_editor.rb, line 56 def initialize(config, encoding) @config = config @completion_append_character = '' reset_variables(encoding: encoding) end
Public Instance Methods
# File lib/reline/line_editor.rb, line 641 def add_dialog_proc(name, p, context = nil) dialog = Dialog.new(name, @config, DialogProcScope.new(self, @config, p, context)) if index = @dialogs.find_index { |d| d.name == name } @dialogs[index] = dialog else @dialogs << dialog end end
# File lib/reline/line_editor.rb, line 1903 def byte_pointer=(val) @byte_pointer = val str = @line.byteslice(0, @byte_pointer) @cursor = calculate_width(str) @cursor_max = calculate_width(@line) end
# File lib/reline/line_editor.rb, line 1667 def call_completion_proc result = retrieve_completion_block(true) pre, target, post = result result = call_completion_proc_with_checking_args(pre, target, post) Reline.core.instance_variable_set(:@completion_quote_character, nil) result end
# File lib/reline/line_editor.rb, line 1675 def call_completion_proc_with_checking_args(pre, target, post) if @completion_proc and target argnum = @completion_proc.parameters.inject(0) { |result, item| case item.first when :req, :opt result + 1 when :rest break 3 end } case argnum when 1 result = @completion_proc.(target) when 2 result = @completion_proc.(target, pre) when 3..Float::INFINITY result = @completion_proc.(target, pre, post) end end result end
# File lib/reline/line_editor.rb, line 1821 def confirm_multiline_termination temp_buffer = @buffer_of_lines.dup if @previous_line_index and @line_index == (@buffer_of_lines.size - 1) temp_buffer[@previous_line_index] = @line else temp_buffer[@line_index] = @line end @confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n") end
# File lib/reline/line_editor.rb, line 1843 def delete_text(start = nil, length = nil) if start.nil? and length.nil? if @is_multiline if @buffer_of_lines.size == 1 @line&.clear @byte_pointer = 0 @cursor = 0 @cursor_max = 0 elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0 @buffer_of_lines.pop @line_index -= 1 @line = @buffer_of_lines[@line_index] @byte_pointer = 0 @cursor = 0 @cursor_max = calculate_width(@line) elsif @line_index < (@buffer_of_lines.size - 1) @buffer_of_lines.delete_at(@line_index) @line = @buffer_of_lines[@line_index] @byte_pointer = 0 @cursor = 0 @cursor_max = calculate_width(@line) end else @line&.clear @byte_pointer = 0 @cursor = 0 @cursor_max = 0 end elsif not start.nil? and not length.nil? if @line before = @line.byteslice(0, start) after = @line.byteslice(start + length, @line.bytesize) @line = before + after @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize str = @line.byteslice(0, @byte_pointer) @cursor = calculate_width(str) @cursor_max = calculate_width(@line) end elsif start.is_a?(Range) range = start first = range.first last = range.last last = @line.bytesize - 1 if last > @line.bytesize last += @line.bytesize if last < 0 first += @line.bytesize if first < 0 range = range.exclude_end? ? first...last : first..last @line = @line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(@encoding) @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize str = @line.byteslice(0, @byte_pointer) @cursor = calculate_width(str) @cursor_max = calculate_width(@line) else @line = @line.byteslice(0, start) @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize str = @line.byteslice(0, @byte_pointer) @cursor = calculate_width(str) @cursor_max = calculate_width(@line) end end
# File lib/reline/line_editor.rb, line 1285 def editing_mode @config.editing_mode end
# File lib/reline/line_editor.rb, line 258 def eof? @eof end
# File lib/reline/line_editor.rb, line 250 def finalize Signal.trap('INT', @old_trap) begin Signal.trap('TSTP', @old_tstp_trap) rescue ArgumentError end end
# File lib/reline/line_editor.rb, line 1932 def finish @finished = true @rerender_all = true @config.reset end
# File lib/reline/line_editor.rb, line 1928 def finished? @finished end
# File lib/reline/line_editor.rb, line 1592 def input_key(key) @last_key = key @config.reset_oneshot_key_bindings @dialogs.each do |dialog| if key.char.instance_of?(Symbol) and key.char == dialog.name return end end @just_cursor_moving = nil if key.char.nil? if @first_char @line = nil end finish return end old_line = @line.dup @first_char = false completion_occurs = false if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord unless @config.disable_completion result = call_completion_proc if result.is_a?(Array) completion_occurs = true process_insert if @config.autocompletion move_completed_list(result, :down) else complete(result) end end end elsif @config.editing_mode_is?(:emacs, :vi_insert) and key.char == :completion_journey_up if not @config.disable_completion and @config.autocompletion result = call_completion_proc if result.is_a?(Array) completion_occurs = true process_insert move_completed_list(result, :up) end end elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char) unless @config.disable_completion result = call_completion_proc if result.is_a?(Array) completion_occurs = true process_insert move_completed_list(result, "\C-p".ord == key.char ? :up : :down) end end elsif Symbol === key.char and respond_to?(key.char, true) process_key(key.char, key.char) else normal_char(key) end unless completion_occurs @completion_state = CompletionState::NORMAL @completion_journey_data = nil end if not @in_pasting and @just_cursor_moving.nil? if @previous_line_index and @buffer_of_lines[@previous_line_index] == @line @just_cursor_moving = true elsif @previous_line_index.nil? and @buffer_of_lines[@line_index] == @line and old_line == @line @just_cursor_moving = true else @just_cursor_moving = false end else @just_cursor_moving = false end if @is_multiline and @auto_indent_proc and not simplified_rendering? process_auto_indent end end
# File lib/reline/line_editor.rb, line 1831 def insert_text(text) width = calculate_width(text) if @cursor == @cursor_max @line += text else @line = byteinsert(@line, @byte_pointer, text) end @byte_pointer += text.bytesize @cursor += width @cursor_max += width end
# File lib/reline/line_editor.rb, line 983 def just_move_cursor prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines) move_cursor_up(@started_from) new_first_line_started_from = if @line_index.zero? 0 else calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt) end first_line_diff = new_first_line_started_from - @first_line_started_from new_cursor, new_cursor_max, new_started_from, new_byte_pointer = calculate_nearest_cursor(@buffer_of_lines[@line_index], @cursor, @started_from, @byte_pointer, false) new_started_from = calculate_height_by_width(prompt_width + new_cursor) - 1 calculate_scroll_partial_screen(@highest_in_all, new_first_line_started_from + new_started_from) @previous_line_index = nil if @rerender_all @line = @buffer_of_lines[@line_index] rerender_all_lines @rerender_all = false true else @line = @buffer_of_lines[@line_index] @first_line_started_from = new_first_line_started_from @started_from = new_started_from @cursor = new_cursor @cursor_max = new_cursor_max @byte_pointer = new_byte_pointer move_cursor_down(first_line_diff + @started_from) Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) false end end
# File lib/reline/line_editor.rb, line 323 def multiline_off @is_multiline = false end
# File lib/reline/line_editor.rb, line 319 def multiline_on @is_multiline = true end
# File lib/reline/line_editor.rb, line 431 def rerender return if @line.nil? if @menu_info scroll_down(@highest_in_all - @first_line_started_from) @rerender_all = true end if @menu_info show_menu @menu_info = nil end prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines) if @cleared clear_screen_buffer(prompt, prompt_list, prompt_width) @cleared = false return end if @is_multiline and finished? and @scroll_partial_screen # Re-output all code higher than the screen when finished. Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen) Reline::IOGate.move_cursor_column(0) @scroll_partial_screen = nil prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines) if @previous_line_index new_lines = whole_lines(index: @previous_line_index, line: @line) else new_lines = whole_lines end modify_lines(new_lines).each_with_index do |line, index| @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\n" Reline::IOGate.erase_after_cursor end @output.flush clear_dialog return end new_highest_in_this = calculate_height_by_width(prompt_width + calculate_width(@line.nil? ? '' : @line)) rendered = false if @add_newline_to_end_of_buffer clear_dialog_with_content rerender_added_newline(prompt, prompt_width) @add_newline_to_end_of_buffer = false else if @just_cursor_moving and not @rerender_all clear_dialog_with_content rendered = just_move_cursor @just_cursor_moving = false return elsif @previous_line_index or new_highest_in_this != @highest_in_this clear_dialog_with_content rerender_changed_current_line @previous_line_index = nil rendered = true elsif @rerender_all rerender_all_lines @rerender_all = false rendered = true else end end if @is_multiline if finished? # Always rerender on finish because output_modifier_proc may return a different output. if @previous_line_index new_lines = whole_lines(index: @previous_line_index, line: @line) else new_lines = whole_lines end line = modify_lines(new_lines)[@line_index] clear_dialog prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines) render_partial(prompt, prompt_width, line, @first_line_started_from) move_cursor_down(@highest_in_all - (@first_line_started_from + @highest_in_this - 1) - 1) scroll_down(1) Reline::IOGate.move_cursor_column(0) Reline::IOGate.erase_after_cursor else if not rendered and not @in_pasting line = modify_lines(whole_lines)[@line_index] prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines) render_partial(prompt, prompt_width, line, @first_line_started_from) end render_dialog((prompt_width + @cursor) % @screen_size.last) end @buffer_of_lines[@line_index] = @line @rest_height = 0 if @scroll_partial_screen else line = modify_lines(whole_lines)[@line_index] render_partial(prompt, prompt_width, line, 0) if finished? scroll_down(1) Reline::IOGate.move_cursor_column(0) Reline::IOGate.erase_after_cursor end end end
# File lib/reline/line_editor.rb, line 425 def rerender_all @rerender_all = true process_insert(force: true) rerender end
# File lib/reline/line_editor.rb, line 149 def reset(prompt = '', encoding:) @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y @screen_size = Reline::IOGate.get_screen_size @screen_height = @screen_size.first reset_variables(prompt, encoding: encoding) Reline::IOGate.set_winch_handler do @resized = true end if ENV.key?('RELINE_ALT_SCROLLBAR') @full_block = '::' @upper_half_block = "''" @lower_half_block = '..' @block_elem_width = 2 elsif Reline::IOGate.win? @full_block = '█' @upper_half_block = '▀' @lower_half_block = '▄' @block_elem_width = 1 elsif @encoding == Encoding::UTF_8 @full_block = '█' @upper_half_block = '▀' @lower_half_block = '▄' @block_elem_width = Reline::Unicode.calculate_width('█') else @full_block = '::' @upper_half_block = "''" @lower_half_block = '..' @block_elem_width = 2 end end
# File lib/reline/line_editor.rb, line 301 def reset_line @cursor = 0 @cursor_max = 0 @byte_pointer = 0 @buffer_of_lines = [String.new(encoding: @encoding)] @line_index = 0 @previous_line_index = nil @line = @buffer_of_lines[0] @first_line_started_from = 0 @move_up = 0 @started_from = 0 @highest_in_this = 1 @highest_in_all = 1 @line_backup_in_history = nil @multibyte_buffer = String.new(encoding: 'ASCII-8BIT') @check_new_auto_indent = false end
# File lib/reline/line_editor.rb, line 262 def reset_variables(prompt = '', encoding:) @prompt = prompt.gsub("\n", "\\n") @mark_pointer = nil @encoding = encoding @is_multiline = false @finished = false @cleared = false @rerender_all = false @history_pointer = nil @kill_ring ||= Reline::KillRing.new @vi_clipboard = '' @vi_arg = nil @waiting_proc = nil @waiting_operator_proc = nil @waiting_operator_vi_arg = nil @completion_journey_data = nil @completion_state = CompletionState::NORMAL @perfect_matched = nil @menu_info = nil @first_prompt = true @searching_prompt = nil @first_char = true @add_newline_to_end_of_buffer = false @just_cursor_moving = nil @cached_prompt_list = nil @prompt_cache_time = nil @eof = false @continuous_insertion_buffer = String.new(encoding: @encoding) @scroll_partial_screen = nil @prev_mode_string = nil @drop_terminate_spaces = false @in_pasting = false @auto_indent_proc = nil @dialogs = [] @last_key = nil @resized = false reset_line end
# File lib/reline/line_editor.rb, line 180 def resize return unless @resized @resized = false @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y old_screen_size = @screen_size @screen_size = Reline::IOGate.get_screen_size @screen_height = @screen_size.first if old_screen_size.last < @screen_size.last # columns increase @rerender_all = true rerender else back = 0 new_buffer = whole_lines prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer) new_buffer.each_with_index do |line, index| prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc width = prompt_width + calculate_width(line) height = calculate_height_by_width(width) back += height end @highest_in_all = back @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max) @first_line_started_from = if @line_index.zero? 0 else calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt) end if @prompt_proc prompt = prompt_list[@line_index] prompt_width = calculate_width(prompt, true) end calculate_nearest_cursor @started_from = calculate_height_by_width(prompt_width + @cursor) - 1 Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max) @rerender_all = true end end
# File lib/reline/line_editor.rb, line 1739 def retrieve_completion_block(set_completion_quote_character = false) if Reline.completer_word_break_characters.empty? word_break_regexp = nil else word_break_regexp = /\A[#{Regexp.escape(Reline.completer_word_break_characters)}]/ end if Reline.completer_quote_characters.empty? quote_characters_regexp = nil else quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/ end before = @line.byteslice(0, @byte_pointer) rest = nil break_pointer = nil quote = nil closing_quote = nil escaped_quote = nil i = 0 while i < @byte_pointer do slice = @line.byteslice(i, @byte_pointer - i) unless slice.valid_encoding? i += 1 next end if quote and slice.start_with?(closing_quote) quote = nil i += 1 rest = nil elsif quote and slice.start_with?(escaped_quote) # skip i += 2 elsif quote_characters_regexp and slice =~ quote_characters_regexp # find new " rest = $' quote = $& closing_quote = /(?!\\)#{Regexp.escape(quote)}/ escaped_quote = /\\#{Regexp.escape(quote)}/ i += 1 break_pointer = i - 1 elsif word_break_regexp and not quote and slice =~ word_break_regexp rest = $' i += 1 before = @line.byteslice(i, @byte_pointer - i) break_pointer = i else i += 1 end end postposing = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer) if rest preposing = @line.byteslice(0, break_pointer) target = rest if set_completion_quote_character and quote Reline.core.instance_variable_set(:@completion_quote_character, quote) if postposing !~ /(?!\\)#{Regexp.escape(quote)}/ # closing quote insert_text(quote) end end else preposing = '' if break_pointer preposing = @line.byteslice(0, break_pointer) else preposing = '' end target = before end if @is_multiline if @previous_line_index lines = whole_lines(index: @previous_line_index, line: @line) else lines = whole_lines end if @line_index > 0 preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing end if (lines.size - 1) > @line_index postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n") end end [preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)] end
# File lib/reline/line_editor.rb, line 62 def set_pasting_state(in_pasting) @in_pasting = in_pasting end
# File lib/reline/line_editor.rb, line 220 def set_signal_handlers @old_trap = Signal.trap('INT') { clear_dialog if @scroll_partial_screen move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1) else move_cursor_down(@highest_in_all - @line_index - 1) end Reline::IOGate.move_cursor_column(0) scroll_down(1) 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 } begin @old_tstp_trap = Signal.trap('TSTP') { Reline::IOGate.ungetc("\C-z".ord) @old_tstp_trap.call if @old_tstp_trap.respond_to?(:call) } rescue ArgumentError end end
# File lib/reline/line_editor.rb, line 66 def simplified_rendering? if finished? false elsif @just_cursor_moving and not @rerender_all true else not @rerender_all and not finished? and @in_pasting end end
# File lib/reline/line_editor.rb, line 1916 def whole_buffer if @buffer_of_lines.size == 1 and @line.nil? nil else if @previous_line_index whole_lines(index: @previous_line_index, line: @line).join("\n") else whole_lines.join("\n") end end end
# File lib/reline/line_editor.rb, line 1910 def whole_lines(index: @line_index, line: @line) temp_lines = @buffer_of_lines.dup temp_lines[index] = line temp_lines end
# File lib/reline/line_editor.rb, line 1477 def wrap_method_call(method_symbol, method_obj, key, with_operator = false) if @config.editing_mode_is?(:emacs, :vi_insert) and @waiting_proc.nil? and @waiting_operator_proc.nil? not_insertion = method_symbol != :ed_insert process_insert(force: not_insertion) end if @vi_arg and argumentable?(method_obj) if with_operator and inclusive?(method_obj) method_obj.(key, arg: @vi_arg, inclusive: true) else method_obj.(key, arg: @vi_arg) end else if with_operator and inclusive?(method_obj) method_obj.(key, inclusive: true) else method_obj.(key) end end end
Private Instance Methods
# File lib/reline/line_editor.rb, line 1467 def argumentable?(method_obj) method_obj and method_obj.parameters.any? { |param| param[0] == :key and param[1] == :arg } end
# File lib/reline/line_editor.rb, line 1944 def byteinsert(str, byte_pointer, other) new_str = str.byteslice(0, byte_pointer) new_str << other new_str << str.byteslice(byte_pointer, str.bytesize) new_str end
# File lib/reline/line_editor.rb, line 1938 def byteslice!(str, byte_pointer, size) new_str = str.byteslice(0, byte_pointer) new_str << str.byteslice(byte_pointer + size, str.bytesize) [new_str, str.byteslice(byte_pointer, size)] end
# File lib/reline/line_editor.rb, line 327 def calculate_height_by_lines(lines, prompt) result = 0 prompt_list = prompt.is_a?(Array) ? prompt : nil lines.each_with_index { |line, i| prompt = prompt_list[i] if prompt_list and prompt_list[i] result += calculate_height_by_width(calculate_width(prompt, true) + calculate_width(line)) } result end
# File lib/reline/line_editor.rb, line 345 def calculate_height_by_width(width) width.div(@screen_size.last) + 1 end
# File lib/reline/line_editor.rb, line 383 def calculate_nearest_cursor(line_to_calc = @line, cursor = @cursor, started_from = @started_from, byte_pointer = @byte_pointer, update = true) new_cursor_max = calculate_width(line_to_calc) new_cursor = 0 new_byte_pointer = 0 height = 1 max_width = @screen_size.last if @config.editing_mode_is?(:vi_command) last_byte_size = Reline::Unicode.get_prev_mbchar_size(line_to_calc, line_to_calc.bytesize) if last_byte_size > 0 last_mbchar = line_to_calc.byteslice(line_to_calc.bytesize - last_byte_size, last_byte_size) last_width = Reline::Unicode.get_mbchar_width(last_mbchar) end_of_line_cursor = new_cursor_max - last_width else end_of_line_cursor = new_cursor_max end else end_of_line_cursor = new_cursor_max end line_to_calc.grapheme_clusters.each do |gc| mbchar = gc.encode(Encoding::UTF_8) mbchar_width = Reline::Unicode.get_mbchar_width(mbchar) now = new_cursor + mbchar_width if now > end_of_line_cursor or now > cursor break end new_cursor += mbchar_width if new_cursor > max_width * height height += 1 end new_byte_pointer += gc.bytesize end new_started_from = height - 1 if update @cursor = new_cursor @cursor_max = new_cursor_max @started_from = new_started_from @byte_pointer = new_byte_pointer else [new_cursor, new_cursor_max, new_started_from, new_byte_pointer] end end
# File lib/reline/line_editor.rb, line 934 def calculate_scroll_partial_screen(highest_in_all, cursor_y) if @screen_height < highest_in_all old_scroll_partial_screen = @scroll_partial_screen if cursor_y == 0 @scroll_partial_screen = 0 elsif cursor_y == (highest_in_all - 1) @scroll_partial_screen = highest_in_all - @screen_height else if @scroll_partial_screen if cursor_y <= @scroll_partial_screen @scroll_partial_screen = cursor_y elsif (@scroll_partial_screen + @screen_height - 1) < cursor_y @scroll_partial_screen = cursor_y - (@screen_height - 1) end else if cursor_y > (@screen_height - 1) @scroll_partial_screen = cursor_y - (@screen_height - 1) else @scroll_partial_screen = 0 end end end if @scroll_partial_screen != old_scroll_partial_screen @rerender_all = true end else if @scroll_partial_screen @rerender_all = true end @scroll_partial_screen = nil end end
# File lib/reline/line_editor.rb, line 1951 def calculate_width(str, allow_escape_code = false) Reline::Unicode.calculate_width(str, allow_escape_code) end
# File lib/reline/line_editor.rb, line 76 def check_mode_string mode_string = nil if @config.show_mode_in_prompt if @config.editing_mode_is?(:vi_command) mode_string = @config.vi_cmd_mode_string elsif @config.editing_mode_is?(:vi_insert) mode_string = @config.vi_ins_mode_string elsif @config.editing_mode_is?(:emacs) mode_string = @config.emacs_mode_string else mode_string = '?' end end if mode_string != @prev_mode_string @rerender_all = true end @prev_mode_string = mode_string mode_string end
# File lib/reline/line_editor.rb, line 96 def check_multiline_prompt(buffer) if @vi_arg prompt = "(arg: #{@vi_arg}) " @rerender_all = true elsif @searching_prompt prompt = @searching_prompt @rerender_all = true else prompt = @prompt end if simplified_rendering? mode_string = check_mode_string prompt = mode_string + prompt if mode_string return [prompt, calculate_width(prompt, true), [prompt] * buffer.size] end if @prompt_proc use_cached_prompt_list = false if @cached_prompt_list if @just_cursor_moving use_cached_prompt_list = true elsif Time.now.to_f < (@prompt_cache_time + PROMPT_LIST_CACHE_TIMEOUT) and buffer.size == @cached_prompt_list.size use_cached_prompt_list = true end end use_cached_prompt_list = false if @rerender_all if use_cached_prompt_list prompt_list = @cached_prompt_list else prompt_list = @cached_prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") } @prompt_cache_time = Time.now.to_f end prompt_list.map!{ prompt } if @vi_arg or @searching_prompt prompt_list = [prompt] if prompt_list.empty? mode_string = check_mode_string prompt_list = prompt_list.map{ |pr| mode_string + pr } if mode_string prompt = prompt_list[@line_index] prompt = prompt_list[0] if prompt.nil? prompt = prompt_list.last if prompt.nil? if buffer.size > prompt_list.size (buffer.size - prompt_list.size).times do prompt_list << prompt_list.last end end prompt_width = calculate_width(prompt, true) [prompt, prompt_width, prompt_list] else mode_string = check_mode_string prompt = mode_string + prompt if mode_string prompt_width = calculate_width(prompt, true) [prompt, prompt_width, nil] end end
# File lib/reline/line_editor.rb, line 882 def clear_dialog @dialogs.each do |dialog| clear_each_dialog(dialog) end end
# File lib/reline/line_editor.rb, line 888 def clear_dialog_with_content @dialogs.each do |dialog| clear_each_dialog(dialog) dialog.contents = nil dialog.trap_key = nil end end
# File lib/reline/line_editor.rb, line 896 def clear_each_dialog(dialog) dialog.trap_key = nil return unless dialog.contents prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines]) visual_lines = [] visual_lines_under_dialog = [] visual_start = nil dialog.lines_backup[:lines].each_with_index { |l, i| pr = prompt_list ? prompt_list[i] : prompt vl, _ = split_by_width(pr + l, @screen_size.last) vl.compact! if i == dialog.lines_backup[:line_index] visual_start = visual_lines.size + dialog.lines_backup[:started_from] + dialog.vertical_offset end visual_lines.concat(vl) } visual_lines_under_dialog = visual_lines[visual_start, dialog.contents.size] visual_lines_under_dialog = [] if visual_lines_under_dialog.nil? Reline::IOGate.hide_cursor move_cursor_down(dialog.vertical_offset) dialog_vertical_size = dialog.contents.size dialog_vertical_size.times do |i| if i < visual_lines_under_dialog.size Reline::IOGate.move_cursor_column(dialog.column) str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width) str = padding_space_with_escape_sequences(str, dialog.width) @output.write "\e[0m#{str}\e[0m" else Reline::IOGate.move_cursor_column(dialog.column) @output.write "\e[0m#{' ' * dialog.width}\e[0m" end move_cursor_down(1) if i < (dialog_vertical_size - 1) end move_cursor_up(dialog_vertical_size - 1 + dialog.vertical_offset) Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) Reline::IOGate.show_cursor end
# File lib/reline/line_editor.rb, line 1264 def clear_screen_buffer(prompt, prompt_list, prompt_width) Reline::IOGate.clear_screen back = 0 modify_lines(whole_lines).each_with_index do |line, index| if @prompt_proc pr = prompt_list[index] height = render_partial(pr, calculate_width(pr), line, back, with_control: false) else height = render_partial(prompt, prompt_width, line, back, with_control: false) end if index < (@buffer_of_lines.size - 1) move_cursor_down(1) back += height end end move_cursor_up(back) move_cursor_down(@first_line_started_from + @started_from) @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) end
# File lib/reline/line_editor.rb, line 1339 def complete(list, just_show_list = false) case @completion_state when CompletionState::NORMAL, CompletionState::JOURNEY @completion_state = CompletionState::COMPLETION when CompletionState::PERFECT_MATCH @dig_perfect_match_proc&.(@perfect_matched) end if just_show_list is_menu = true elsif @completion_state == CompletionState::MENU is_menu = true elsif @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH is_menu = true else is_menu = false end result = complete_internal_proc(list, is_menu) if @completion_state == CompletionState::MENU_WITH_PERFECT_MATCH @completion_state = CompletionState::PERFECT_MATCH end return if result.nil? target, preposing, completed, postposing = result return if completed.nil? if target <= completed and (@completion_state == CompletionState::COMPLETION) if list.include?(completed) if list.one? @completion_state = CompletionState::PERFECT_MATCH else @completion_state = CompletionState::MENU_WITH_PERFECT_MATCH end @perfect_matched = completed else @completion_state = CompletionState::MENU end if not just_show_list and target < completed @line = preposing + completed + completion_append_character.to_s + postposing line_to_pointer = preposing + completed + completion_append_character.to_s @cursor_max = calculate_width(@line) @cursor = calculate_width(line_to_pointer) @byte_pointer = line_to_pointer.bytesize end end end
# File lib/reline/line_editor.rb, line 1293 def complete_internal_proc(list, is_menu) preposing, target, postposing = retrieve_completion_block list = list.select { |i| if i and not Encoding.compatible?(target.encoding, i.encoding) raise Encoding::CompatibilityError, "#{target.encoding.name} is not compatible with #{i.encoding.name}" end if @config.completion_ignore_case i&.downcase&.start_with?(target.downcase) else i&.start_with?(target) end }.uniq if is_menu menu(target, list) return nil end completed = list.inject { |memo, item| begin memo_mbchars = memo.unicode_normalize.grapheme_clusters item_mbchars = item.unicode_normalize.grapheme_clusters rescue Encoding::CompatibilityError memo_mbchars = memo.grapheme_clusters item_mbchars = item.grapheme_clusters end size = [memo_mbchars.size, item_mbchars.size].min result = '' size.times do |i| if @config.completion_ignore_case if memo_mbchars[i].casecmp?(item_mbchars[i]) result << memo_mbchars[i] else break end else if memo_mbchars[i] == item_mbchars[i] result << memo_mbchars[i] else break end end end result } [target, preposing, completed, postposing] end
# File lib/reline/line_editor.rb, line 2864 def copy_for_vi(text) if @config.editing_mode_is?(:vi_insert) or @config.editing_mode_is?(:vi_command) @vi_clipboard = text end end
# File lib/reline/line_editor.rb, line 3163 def ed_argument_digit(key) if @vi_arg.nil? if key.chr.to_i.zero? if key.anybits?(0b10000000) unescaped_key = key ^ 0b10000000 unless unescaped_key.chr.to_i.zero? @vi_arg = unescaped_key.chr.to_i end end else @vi_arg = key.chr.to_i end else @vi_arg = @vi_arg * 10 + key.chr.to_i end end
# File lib/reline/line_editor.rb, line 2730 def ed_clear_screen(key) @cleared = true end
# File lib/reline/line_editor.rb, line 3075 def ed_delete_next_char(key, arg: 1) byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer) unless @line.empty? || byte_size == 0 @line, mbchar = byteslice!(@line, @byte_pointer, byte_size) copy_for_vi(mbchar) width = Reline::Unicode.get_mbchar_width(mbchar) @cursor_max -= width if @cursor > 0 and @cursor >= @cursor_max byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer) mbchar = @line.byteslice(@byte_pointer - byte_size, byte_size) width = Reline::Unicode.get_mbchar_width(mbchar) @byte_pointer -= byte_size @cursor -= width end end arg -= 1 ed_delete_next_char(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 2993 def ed_delete_prev_char(key, arg: 1) deleted = '' arg.times do if @cursor > 0 byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer) @byte_pointer -= byte_size @line, mbchar = byteslice!(@line, @byte_pointer, byte_size) deleted.prepend(mbchar) width = Reline::Unicode.get_mbchar_width(mbchar) @cursor -= width @cursor_max -= width end end copy_for_vi(deleted) end
# File lib/reline/line_editor.rb, line 2762 def ed_delete_prev_word(key) if @byte_pointer > 0 byte_size, width = Reline::Unicode.em_backward_word(@line, @byte_pointer) @line, word = byteslice!(@line, @byte_pointer - byte_size, byte_size) @kill_ring.append(word, true) @byte_pointer -= byte_size @cursor -= width @cursor_max -= width end end
- Editline
-
ed-insert
(vi input: almost all; emacs: printable characters) In insert mode, insert the input character left of the cursor position. In replace mode, overwrite the character at the cursor and move the cursor to the right by one character position. Accept an argument to do this repeatedly. It is an error if the input character is the NUL character (Ctrl-@
). Failure to enlarge the edit buffer also results in an error. - Editline
-
ed-digit
(emacs: 0 to 9) If in argument input mode, append the input digit to the argument being read. Otherwise, called-insert
. It is an error if the input character is not a digit or if the existing argument is already greater than a million. - GNU
Readline
-
self-insert
(a, b, A, 1, !, …) Insert yourself.
# File lib/reline/line_editor.rb, line 2006 def ed_insert(key) str = nil width = nil bytesize = nil if key.instance_of?(String) begin key.encode(Encoding::UTF_8) rescue Encoding::UndefinedConversionError return end str = key bytesize = key.bytesize else begin key.chr.encode(Encoding::UTF_8) rescue Encoding::UndefinedConversionError return end str = key.chr bytesize = 1 end if @in_pasting @continuous_insertion_buffer << str return elsif not @continuous_insertion_buffer.empty? process_insert end width = Reline::Unicode.get_mbchar_width(str) if @cursor == @cursor_max @line += str else @line = byteinsert(@line, @byte_pointer, str) end last_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer) @byte_pointer += bytesize last_mbchar = @line.byteslice((@byte_pointer - bytesize - last_byte_size), last_byte_size) combined_char = last_mbchar + str if last_byte_size != 0 and combined_char.grapheme_clusters.size == 1 # combined char last_mbchar_width = Reline::Unicode.get_mbchar_width(last_mbchar) combined_char_width = Reline::Unicode.get_mbchar_width(combined_char) if combined_char_width > last_mbchar_width width = combined_char_width - last_mbchar_width else width = 0 end end @cursor += width @cursor_max += width end
- Editline
-
ed-kill-line
(vi command:D
,Ctrl-K
; emacs:Ctrl-K
,Ctrl-U
) + Kill from the cursor to the end of the line. - GNU
Readline
-
kill-line
(C-k
) Kill the text from point to the end of the line. With a negative numeric argument, kill backward from the cursor to the beginning of the current line.
# File lib/reline/line_editor.rb, line 2613 def ed_kill_line(key) if @line.bytesize > @byte_pointer @line, deleted = byteslice!(@line, @byte_pointer, @line.bytesize - @byte_pointer) @byte_pointer = @line.bytesize @cursor = @cursor_max = calculate_width(@line) @kill_ring.append(deleted) elsif @is_multiline and @byte_pointer == @line.bytesize and @buffer_of_lines.size > @line_index + 1 @cursor = calculate_width(@line) @byte_pointer = @line.bytesize @line += @buffer_of_lines.delete_at(@line_index + 1) @cursor_max = calculate_width(@line) @buffer_of_lines[@line_index] = @line @rerender_all = true @rest_height += 1 end end
# File lib/reline/line_editor.rb, line 2119 def ed_move_to_beg(key) @byte_pointer = @cursor = 0 end
# File lib/reline/line_editor.rb, line 2124 def ed_move_to_end(key) @byte_pointer = 0 @cursor = 0 byte_size = 0 while @byte_pointer < @line.bytesize byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer) if byte_size > 0 mbchar = @line.byteslice(@byte_pointer, byte_size) @cursor += Reline::Unicode.get_mbchar_width(mbchar) end @byte_pointer += byte_size end end
# File lib/reline/line_editor.rb, line 2552 def ed_newline(key) process_insert(force: true) if @is_multiline if @config.editing_mode_is?(:vi_command) if @line_index < (@buffer_of_lines.size - 1) ed_next_history(key) # means cursor down else # should check confirm_multiline_termination to finish? finish end else if @line_index == (@buffer_of_lines.size - 1) if confirm_multiline_termination finish else key_newline(key) end else # should check confirm_multiline_termination to finish? @previous_line_index = @line_index @line_index = @buffer_of_lines.size - 1 finish end end else if @history_pointer Reline::HISTORY[@history_pointer] = @line @history_pointer = nil end finish end end
# File lib/reline/line_editor.rb, line 2075 def ed_next_char(key, arg: 1) byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer) if (@byte_pointer < @line.bytesize) mbchar = @line.byteslice(@byte_pointer, byte_size) width = Reline::Unicode.get_mbchar_width(mbchar) @cursor += width if width @byte_pointer += byte_size elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == @line.bytesize and @line_index < @buffer_of_lines.size - 1 next_line = @buffer_of_lines[@line_index + 1] @cursor = 0 @byte_pointer = 0 @cursor_max = calculate_width(next_line) @previous_line_index = @line_index @line_index += 1 end arg -= 1 ed_next_char(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 2504 def ed_next_history(key, arg: 1) if @is_multiline and @line_index < (@buffer_of_lines.size - 1) @previous_line_index = @line_index @line_index += 1 return end if @history_pointer.nil? return elsif @history_pointer == (Reline::HISTORY.size - 1) if @is_multiline @history_pointer = nil @buffer_of_lines = @line_backup_in_history.split("\n") @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty? @line_index = 0 @line = @buffer_of_lines.first @rerender_all = true else @history_pointer = nil @line = @line_backup_in_history end else if @is_multiline Reline::HISTORY[@history_pointer] = whole_buffer @history_pointer += 1 @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n") @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty? @line_index = 0 @line = @buffer_of_lines.first @rerender_all = true else Reline::HISTORY[@history_pointer] = @line @history_pointer += 1 @line = Reline::HISTORY[@history_pointer] end end @line = '' unless @line if @config.editing_mode_is?(:emacs, :vi_insert) @cursor_max = @cursor = calculate_width(@line) @byte_pointer = @line.bytesize elsif @config.editing_mode_is?(:vi_command) @byte_pointer = @cursor = 0 @cursor_max = calculate_width(@line) end arg -= 1 ed_next_history(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 2095 def ed_prev_char(key, arg: 1) if @cursor > 0 byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer) @byte_pointer -= byte_size mbchar = @line.byteslice(@byte_pointer, byte_size) width = Reline::Unicode.get_mbchar_width(mbchar) @cursor -= width elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0 prev_line = @buffer_of_lines[@line_index - 1] @cursor = calculate_width(prev_line) @byte_pointer = prev_line.bytesize @cursor_max = calculate_width(prev_line) @previous_line_index = @line_index @line_index -= 1 end arg -= 1 ed_prev_char(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 2453 def ed_prev_history(key, arg: 1) if @is_multiline and @line_index > 0 @previous_line_index = @line_index @line_index -= 1 return end if Reline::HISTORY.empty? return end if @history_pointer.nil? @history_pointer = Reline::HISTORY.size - 1 if @is_multiline @line_backup_in_history = whole_buffer @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n") @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty? @line_index = @buffer_of_lines.size - 1 @line = @buffer_of_lines.last @rerender_all = true else @line_backup_in_history = @line @line = Reline::HISTORY[@history_pointer] end elsif @history_pointer.zero? return else if @is_multiline Reline::HISTORY[@history_pointer] = whole_buffer @history_pointer -= 1 @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n") @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty? @line_index = @buffer_of_lines.size - 1 @line = @buffer_of_lines.last @rerender_all = true else Reline::HISTORY[@history_pointer] = @line @history_pointer -= 1 @line = Reline::HISTORY[@history_pointer] end end if @config.editing_mode_is?(:emacs, :vi_insert) @cursor_max = @cursor = calculate_width(@line) @byte_pointer = @line.bytesize elsif @config.editing_mode_is?(:vi_command) @byte_pointer = @cursor = 0 @cursor_max = calculate_width(@line) end arg -= 1 ed_prev_history(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 2744 def ed_prev_word(key) if @byte_pointer > 0 byte_size, width = Reline::Unicode.em_backward_word(@line, @byte_pointer) @byte_pointer -= byte_size @cursor -= width end end
# File lib/reline/line_editor.rb, line 2059 def ed_quoted_insert(str, arg: 1) @waiting_proc = proc { |key| arg.times do if key == "\C-j".ord or key == "\C-m".ord key_newline(key) elsif key == 0 # Ignore NUL. else ed_insert(key) end end @waiting_proc = nil } end
# File lib/reline/line_editor.rb, line 2401 def ed_search_next_history(key, arg: 1) substr = @line.slice(0, @byte_pointer) if @history_pointer.nil? return elsif @history_pointer == (Reline::HISTORY.size - 1) and not substr.empty? return end history = Reline::HISTORY.slice((@history_pointer + 1)..-1) h_pointer = nil line_no = nil if @is_multiline h_pointer = history.index { |h| h.split("\n").each_with_index { |l, i| if l.start_with?(substr) line_no = i break end } not line_no.nil? } else h_pointer = history.index { |l| l.start_with?(substr) } end h_pointer += @history_pointer + 1 if h_pointer and @history_pointer return if h_pointer.nil? and not substr.empty? @history_pointer = h_pointer if @is_multiline if @history_pointer.nil? and substr.empty? @buffer_of_lines = [] @line_index = 0 else @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n") @line_index = line_no end @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty? @line = @buffer_of_lines[@line_index] @rerender_all = true else if @history_pointer.nil? and substr.empty? @line = '' else @line = Reline::HISTORY[@history_pointer] end end @cursor_max = calculate_width(@line) arg -= 1 ed_search_next_history(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 2354 def ed_search_prev_history(key, arg: 1) history = nil h_pointer = nil line_no = nil substr = @line.slice(0, @byte_pointer) if @history_pointer.nil? return if not @line.empty? and substr.empty? history = Reline::HISTORY elsif @history_pointer.zero? history = nil h_pointer = nil else history = Reline::HISTORY.slice(0, @history_pointer) end return if history.nil? if @is_multiline h_pointer = history.rindex { |h| h.split("\n").each_with_index { |l, i| if l.start_with?(substr) line_no = i break end } not line_no.nil? } else h_pointer = history.rindex { |l| l.start_with?(substr) } end return if h_pointer.nil? @history_pointer = h_pointer if @is_multiline @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n") @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty? @line_index = line_no @line = @buffer_of_lines[@line_index] @rerender_all = true else @line = Reline::HISTORY[@history_pointer] end @cursor_max = calculate_width(@line) arg -= 1 ed_search_prev_history(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 2773 def ed_transpose_chars(key) if @byte_pointer > 0 if @cursor_max > @cursor byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer) mbchar = @line.byteslice(@byte_pointer, byte_size) width = Reline::Unicode.get_mbchar_width(mbchar) @cursor += width @byte_pointer += byte_size end back1_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer) if (@byte_pointer - back1_byte_size) > 0 back2_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer - back1_byte_size) back2_pointer = @byte_pointer - back1_byte_size - back2_byte_size @line, back2_mbchar = byteslice!(@line, back2_pointer, back2_byte_size) @line = byteinsert(@line, @byte_pointer - back2_byte_size, back2_mbchar) end end end
# File lib/reline/line_editor.rb, line 2793 def ed_transpose_words(key) left_word_start, middle_start, right_word_start, after_start = Reline::Unicode.ed_transpose_words(@line, @byte_pointer) before = @line.byteslice(0, left_word_start) left_word = @line.byteslice(left_word_start, middle_start - left_word_start) middle = @line.byteslice(middle_start, right_word_start - middle_start) right_word = @line.byteslice(right_word_start, after_start - right_word_start) after = @line.byteslice(after_start, @line.bytesize - after_start) return if left_word.empty? or right_word.empty? @line = before + right_word + middle + left_word + after from_head_to_left_word = before + right_word + middle + left_word @byte_pointer = from_head_to_left_word.bytesize @cursor = calculate_width(from_head_to_left_word) end
- Editline
-
ed-unassigned
This editor command always results in an error. - GNU
Readline
-
There is no corresponding macro.
# File lib/reline/line_editor.rb, line 1976 def ed_unassigned(key) end
# File lib/reline/line_editor.rb, line 2808 def em_capitol_case(key) if @line.bytesize > @byte_pointer byte_size, _, new_str = Reline::Unicode.em_forward_word_with_capitalization(@line, @byte_pointer) before = @line.byteslice(0, @byte_pointer) after = @line.byteslice((@byte_pointer + byte_size)..-1) @line = before + new_str + after @byte_pointer += new_str.bytesize @cursor += calculate_width(new_str) end end
# File lib/reline/line_editor.rb, line 2662 def em_delete(key) if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1) @line = nil if @buffer_of_lines.size > 1 scroll_down(@highest_in_all - @first_line_started_from) end Reline::IOGate.move_cursor_column(0) @eof = true finish elsif @byte_pointer < @line.bytesize splitted_last = @line.byteslice(@byte_pointer, @line.bytesize) mbchar = splitted_last.grapheme_clusters.first width = Reline::Unicode.get_mbchar_width(mbchar) @cursor_max -= width @line, = byteslice!(@line, @byte_pointer, mbchar.bytesize) elsif @is_multiline and @byte_pointer == @line.bytesize and @buffer_of_lines.size > @line_index + 1 @cursor = calculate_width(@line) @byte_pointer = @line.bytesize @line += @buffer_of_lines.delete_at(@line_index + 1) @cursor_max = calculate_width(@line) @buffer_of_lines[@line_index] = @line @rerender_all = true @rest_height += 1 end end
# File lib/reline/line_editor.rb, line 2753 def em_delete_next_word(key) if @line.bytesize > @byte_pointer byte_size, width = Reline::Unicode.em_forward_word(@line, @byte_pointer) @line, word = byteslice!(@line, @byte_pointer, byte_size) @kill_ring.append(word) @cursor_max -= width end end
# File lib/reline/line_editor.rb, line 2689 def em_delete_or_list(key) if @line.empty? or @byte_pointer < @line.bytesize em_delete(key) else # show completed list result = call_completion_proc if result.is_a?(Array) complete(result, true) end end end
# File lib/reline/line_editor.rb, line 2585 def em_delete_prev_char(key, arg: 1) if @is_multiline and @cursor == 0 and @line_index > 0 @buffer_of_lines[@line_index] = @line @cursor = calculate_width(@buffer_of_lines[@line_index - 1]) @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index) @line_index -= 1 @line = @buffer_of_lines[@line_index] @cursor_max = calculate_width(@line) @rerender_all = true elsif @cursor > 0 byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer) @byte_pointer -= byte_size @line, mbchar = byteslice!(@line, @byte_pointer, byte_size) width = Reline::Unicode.get_mbchar_width(mbchar) @cursor -= width @cursor_max -= width end arg -= 1 em_delete_prev_char(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 3347 def em_exchange_mark(key) return unless @mark_pointer new_pointer = [@byte_pointer, @line_index] @previous_line_index = @line_index @byte_pointer, @line_index = @mark_pointer @cursor = calculate_width(@line.byteslice(0, @byte_pointer)) @cursor_max = calculate_width(@line) @mark_pointer = new_pointer end
- Editline
-
em-kill-line
(not bound) Delete the entire contents of the edit buffer and save it to the cut buffer.vi-kill-line-prev
- GNU
Readline
-
kill-whole-line
(not bound) Kill all characters on the current line, no matter where point is.
# File lib/reline/line_editor.rb, line 2651 def em_kill_line(key) if @line.size > 0 @kill_ring.append(@line.dup, true) @line.clear @byte_pointer = 0 @cursor_max = 0 @cursor = 0 end end
# File lib/reline/line_editor.rb, line 2852 def em_kill_region(key) if @byte_pointer > 0 byte_size, width = Reline::Unicode.em_big_backward_word(@line, @byte_pointer) @line, deleted = byteslice!(@line, @byte_pointer - byte_size, byte_size) @byte_pointer -= byte_size @cursor -= width @cursor_max -= width @kill_ring.append(deleted, true) end end
# File lib/reline/line_editor.rb, line 2820 def em_lower_case(key) if @line.bytesize > @byte_pointer byte_size, = Reline::Unicode.em_forward_word(@line, @byte_pointer) part = @line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar| mbchar =~ /[A-Z]/ ? mbchar.downcase : mbchar }.join rest = @line.byteslice((@byte_pointer + byte_size)..-1) @line = @line.byteslice(0, @byte_pointer) + part @byte_pointer = @line.bytesize @cursor = calculate_width(@line) @cursor_max = @cursor + calculate_width(rest) @line += rest end end
# File lib/reline/line_editor.rb, line 2735 def em_next_word(key) if @line.bytesize > @byte_pointer byte_size, width = Reline::Unicode.em_forward_word(@line, @byte_pointer) @byte_pointer += byte_size @cursor += width end end
# File lib/reline/line_editor.rb, line 3342 def em_set_mark(key) @mark_pointer = [@byte_pointer, @line_index] end
# File lib/reline/line_editor.rb, line 2836 def em_upper_case(key) if @line.bytesize > @byte_pointer byte_size, = Reline::Unicode.em_forward_word(@line, @byte_pointer) part = @line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar| mbchar =~ /[a-z]/ ? mbchar.upcase : mbchar }.join rest = @line.byteslice((@byte_pointer + byte_size)..-1) @line = @line.byteslice(0, @byte_pointer) + part @byte_pointer = @line.bytesize @cursor = calculate_width(@line) @cursor_max = @cursor + calculate_width(rest) @line += rest end end
# File lib/reline/line_editor.rb, line 2701 def em_yank(key) yanked = @kill_ring.yank if yanked @line = byteinsert(@line, @byte_pointer, yanked) yanked_width = calculate_width(yanked) @cursor += yanked_width @cursor_max += yanked_width @byte_pointer += yanked.bytesize end end
# File lib/reline/line_editor.rb, line 2713 def em_yank_pop(key) yanked, prev_yank = @kill_ring.yank_pop if yanked prev_yank_width = calculate_width(prev_yank) @cursor -= prev_yank_width @cursor_max -= prev_yank_width @byte_pointer -= prev_yank.bytesize @line, = byteslice!(@line, @byte_pointer, prev_yank.bytesize) @line = byteinsert(@line, @byte_pointer, yanked) yanked_width = calculate_width(yanked) @cursor += yanked_width @cursor_max += yanked_width @byte_pointer += yanked.bytesize end end
# File lib/reline/line_editor.rb, line 2139 def generate_searcher Fiber.new do |first_key| prev_search_key = first_key search_word = String.new(encoding: @encoding) multibyte_buf = String.new(encoding: 'ASCII-8BIT') last_hit = nil case first_key when "\C-r".ord prompt_name = 'reverse-i-search' when "\C-s".ord prompt_name = 'i-search' end loop do key = Fiber.yield(search_word) search_again = false case key when -1 # determined Reline.last_incremental_search = search_word break when "\C-h".ord, "\C-?".ord grapheme_clusters = search_word.grapheme_clusters if grapheme_clusters.size > 0 grapheme_clusters.pop search_word = grapheme_clusters.join end when "\C-r".ord, "\C-s".ord search_again = true if prev_search_key == key prev_search_key = key else multibyte_buf << key if multibyte_buf.dup.force_encoding(@encoding).valid_encoding? search_word << multibyte_buf.dup.force_encoding(@encoding) multibyte_buf.clear end end hit = nil if not search_word.empty? and @line_backup_in_history&.include?(search_word) @history_pointer = nil hit = @line_backup_in_history else if search_again if search_word.empty? and Reline.last_incremental_search search_word = Reline.last_incremental_search end if @history_pointer case prev_search_key when "\C-r".ord history_pointer_base = 0 history = Reline::HISTORY[0..(@history_pointer - 1)] when "\C-s".ord history_pointer_base = @history_pointer + 1 history = Reline::HISTORY[(@history_pointer + 1)..-1] end else history_pointer_base = 0 history = Reline::HISTORY end elsif @history_pointer case prev_search_key when "\C-r".ord history_pointer_base = 0 history = Reline::HISTORY[0..@history_pointer] when "\C-s".ord history_pointer_base = @history_pointer history = Reline::HISTORY[@history_pointer..-1] end else history_pointer_base = 0 history = Reline::HISTORY end case prev_search_key when "\C-r".ord hit_index = history.rindex { |item| item.include?(search_word) } when "\C-s".ord hit_index = history.index { |item| item.include?(search_word) } end if hit_index @history_pointer = history_pointer_base + hit_index hit = Reline::HISTORY[@history_pointer] end end case prev_search_key when "\C-r".ord prompt_name = 'reverse-i-search' when "\C-s".ord prompt_name = 'i-search' end if hit if @is_multiline @buffer_of_lines = hit.split("\n") @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty? @line_index = @buffer_of_lines.size - 1 @line = @buffer_of_lines.last @byte_pointer = @line.bytesize @cursor = @cursor_max = calculate_width(@line) @rerender_all = true @searching_prompt = "(%s)`%s'" % [prompt_name, search_word] else @line = hit @searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit] end last_hit = hit else if @is_multiline @rerender_all = true @searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word] else @searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit] end end end end end
# File lib/reline/line_editor.rb, line 1471 def inclusive?(method_obj) # If a motion method with the keyword argument "inclusive" follows the # operator, it must contain the character at the cursor position. method_obj and method_obj.parameters.any? { |param| param[0] == :key and param[1] == :inclusive } end
# File lib/reline/line_editor.rb, line 2257 def incremental_search_history(key) unless @history_pointer if @is_multiline @line_backup_in_history = whole_buffer else @line_backup_in_history = @line end end searcher = generate_searcher searcher.resume(key) @searching_prompt = "(reverse-i-search)`': " termination_keys = ["\C-j".ord] termination_keys.concat(@config.isearch_terminators&.chars&.map(&:ord)) if @config.isearch_terminators @waiting_proc = ->(k) { case k when *termination_keys if @history_pointer buffer = Reline::HISTORY[@history_pointer] else buffer = @line_backup_in_history end if @is_multiline @buffer_of_lines = buffer.split("\n") @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty? @line_index = @buffer_of_lines.size - 1 @line = @buffer_of_lines.last @rerender_all = true else @line = buffer end @searching_prompt = nil @waiting_proc = nil @cursor_max = calculate_width(@line) @cursor = @byte_pointer = 0 @rerender_all = true @cached_prompt_list = nil searcher.resume(-1) when "\C-g".ord if @is_multiline @buffer_of_lines = @line_backup_in_history.split("\n") @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty? @line_index = @buffer_of_lines.size - 1 @line = @buffer_of_lines.last @rerender_all = true else @line = @line_backup_in_history end @history_pointer = nil @searching_prompt = nil @waiting_proc = nil @line_backup_in_history = nil @cursor_max = calculate_width(@line) @cursor = @byte_pointer = 0 @rerender_all = true else chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT) if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord searcher.resume(k) else if @history_pointer line = Reline::HISTORY[@history_pointer] else line = @line_backup_in_history end if @is_multiline @line_backup_in_history = whole_buffer @buffer_of_lines = line.split("\n") @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty? @line_index = @buffer_of_lines.size - 1 @line = @buffer_of_lines.last @rerender_all = true else @line_backup_in_history = @line @line = line end @searching_prompt = nil @waiting_proc = nil @cursor_max = calculate_width(@line) @cursor = @byte_pointer = 0 @rerender_all = true @cached_prompt_list = nil searcher.resume(-1) end end } end
# File lib/reline/line_editor.rb, line 337 def insert_new_line(cursor_line, next_line) @line = cursor_line @buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding: @encoding)) @previous_line_index = @line_index @line_index += 1 @just_cursor_moving = false end
# File lib/reline/line_editor.rb, line 1955 def key_delete(key) if @config.editing_mode_is?(:vi_insert, :emacs) ed_delete_next_char(key) end end
# File lib/reline/line_editor.rb, line 1961 def key_newline(key) if @is_multiline if (@buffer_of_lines.size - 1) == @line_index and @line.bytesize == @byte_pointer @add_newline_to_end_of_buffer = true end next_line = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer) cursor_line = @line.byteslice(0, @byte_pointer) insert_new_line(cursor_line, next_line) @cursor = 0 @check_new_auto_indent = true unless @in_pasting end end
# File lib/reline/line_editor.rb, line 1241 def modify_lines(before) return before if before.nil? || before.empty? || simplified_rendering? if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: finished?) after.lines("\n").map { |l| l.chomp('') } else before end end
# File lib/reline/line_editor.rb, line 1383 def move_completed_list(list, direction) case @completion_state when CompletionState::NORMAL, CompletionState::COMPLETION, CompletionState::MENU, CompletionState::MENU_WITH_PERFECT_MATCH @completion_state = CompletionState::JOURNEY result = retrieve_completion_block return if result.nil? preposing, target, postposing = result @completion_journey_data = CompletionJourneyData.new( preposing, postposing, [target] + list.select{ |item| item.start_with?(target) }, 0) if @completion_journey_data.list.size == 1 @completion_journey_data.pointer = 0 else case direction when :up @completion_journey_data.pointer = @completion_journey_data.list.size - 1 when :down @completion_journey_data.pointer = 1 end end @completion_state = CompletionState::JOURNEY else case direction when :up @completion_journey_data.pointer -= 1 if @completion_journey_data.pointer < 0 @completion_journey_data.pointer = @completion_journey_data.list.size - 1 end when :down @completion_journey_data.pointer += 1 if @completion_journey_data.pointer >= @completion_journey_data.list.size @completion_journey_data.pointer = 0 end end end completed = @completion_journey_data.list[@completion_journey_data.pointer] new_line = (@completion_journey_data.preposing + completed + @completion_journey_data.postposing).split("\n")[@line_index] @line = new_line.nil? ? String.new(encoding: @encoding) : new_line line_to_pointer = (@completion_journey_data.preposing + completed).split("\n").last line_to_pointer = String.new(encoding: @encoding) if line_to_pointer.nil? @cursor_max = calculate_width(@line) @cursor = calculate_width(line_to_pointer) @byte_pointer = line_to_pointer.bytesize end
# File lib/reline/line_editor.rb, line 373 def move_cursor_down(val) if val > 0 Reline::IOGate.move_cursor_down(val) @rest_height -= val @rest_height = 0 if @rest_height < 0 elsif val < 0 move_cursor_up(-val) end end
# File lib/reline/line_editor.rb, line 364 def move_cursor_up(val) if val > 0 Reline::IOGate.move_cursor_up(val) @rest_height += val elsif val < 0 move_cursor_down(-val) end end
# File lib/reline/line_editor.rb, line 1554 def normal_char(key) method_symbol = method_obj = nil if key.combined_char.is_a?(Symbol) process_key(key.combined_char, key.combined_char) return end @multibyte_buffer << key.combined_char if @multibyte_buffer.size > 1 if @multibyte_buffer.dup.force_encoding(@encoding).valid_encoding? process_key(@multibyte_buffer.dup.force_encoding(@encoding), nil) @multibyte_buffer.clear else # invalid return end else # single byte return if key.char >= 128 # maybe, first byte of multi byte method_symbol = @config.editing_mode.get_method(key.combined_char) if key.with_meta and method_symbol == :ed_unassigned # split ESC + key method_symbol = @config.editing_mode.get_method("\e".ord) process_key("\e".ord, method_symbol) method_symbol = @config.editing_mode.get_method(key.char) process_key(key.char, method_symbol) else process_key(key.combined_char, method_symbol) end @multibyte_buffer.clear end if @config.editing_mode_is?(:vi_command) and @cursor > 0 and @cursor == @cursor_max byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer) @byte_pointer -= byte_size mbchar = @line.byteslice(@byte_pointer, byte_size) width = Reline::Unicode.get_mbchar_width(mbchar) @cursor -= width end end
# File lib/reline/line_editor.rb, line 657 def padding_space_with_escape_sequences(str, width) padding_width = width - calculate_width(str, true) # padding_width should be only positive value. But macOS and Alacritty returns negative value. padding_width = 0 if padding_width < 0 str + (' ' * padding_width) end
# File lib/reline/line_editor.rb, line 1697 def process_auto_indent return if not @check_new_auto_indent and @previous_line_index # move cursor up or down if @check_new_auto_indent and @previous_line_index and @previous_line_index > 0 and @line_index > @previous_line_index # Fix indent of a line when a newline is inserted to the next new_lines = whole_lines(index: @previous_line_index, line: @line) new_indent = @auto_indent_proc.(new_lines[0..-3].push(''), @line_index - 1, 0, true) md = @line.match(/\A */) prev_indent = md[0].count(' ') @line = ' ' * new_indent + @line.lstrip new_indent = nil result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, (new_lines[-2].size + 1), false) if result new_indent = result end if new_indent&.>= 0 @line = ' ' * new_indent + @line.lstrip end end if @previous_line_index new_lines = whole_lines(index: @previous_line_index, line: @line) else new_lines = whole_lines end new_indent = @auto_indent_proc.(new_lines, @line_index, @byte_pointer, @check_new_auto_indent) new_indent = @cursor_max if new_indent&.> @cursor_max if new_indent&.>= 0 md = new_lines[@line_index].match(/\A */) prev_indent = md[0].count(' ') if @check_new_auto_indent @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip @cursor = new_indent @byte_pointer = new_indent else @line = ' ' * new_indent + @line.lstrip @cursor += new_indent - prev_indent @byte_pointer += new_indent - prev_indent end end @check_new_auto_indent = false end
# File lib/reline/line_editor.rb, line 1978 def process_insert(force: false) return if @continuous_insertion_buffer.empty? or (@in_pasting and not force) width = Reline::Unicode.calculate_width(@continuous_insertion_buffer) bytesize = @continuous_insertion_buffer.bytesize if @cursor == @cursor_max @line += @continuous_insertion_buffer else @line = byteinsert(@line, @byte_pointer, @continuous_insertion_buffer) end @byte_pointer += bytesize @cursor += width @cursor_max += width @continuous_insertion_buffer.clear end
# File lib/reline/line_editor.rb, line 1497 def process_key(key, method_symbol) if method_symbol and respond_to?(method_symbol, true) method_obj = method(method_symbol) else method_obj = nil end if method_symbol and key.is_a?(Symbol) if @vi_arg and argumentable?(method_obj) run_for_operators(key, method_symbol) do |with_operator| wrap_method_call(method_symbol, method_obj, key, with_operator) end else wrap_method_call(method_symbol, method_obj, key) if method_obj end @kill_ring.process if @vi_arg @rerender_al = true @vi_arg = nil end elsif @vi_arg if key.chr =~ /[0-9]/ ed_argument_digit(key) else if argumentable?(method_obj) run_for_operators(key, method_symbol) do |with_operator| wrap_method_call(method_symbol, method_obj, key, with_operator) end elsif @waiting_proc @waiting_proc.(key) elsif method_obj wrap_method_call(method_symbol, method_obj, key) else ed_insert(key) unless @config.editing_mode_is?(:vi_command) end @kill_ring.process if @vi_arg @rerender_all = true @vi_arg = nil end end elsif @waiting_proc @waiting_proc.(key) @kill_ring.process elsif method_obj if method_symbol == :ed_argument_digit wrap_method_call(method_symbol, method_obj, key) else run_for_operators(key, method_symbol) do |with_operator| wrap_method_call(method_symbol, method_obj, key, with_operator) end end @kill_ring.process else ed_insert(key) unless @config.editing_mode_is?(:vi_command) end end
# File lib/reline/line_editor.rb, line 651 def render_dialog(cursor_column) @dialogs.each do |dialog| render_each_dialog(dialog, cursor_column) end end
# File lib/reline/line_editor.rb, line 664 def render_each_dialog(dialog, cursor_column) if @in_pasting clear_each_dialog(dialog) dialog.contents = nil dialog.trap_key = nil return end dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from) dialog_render_info = dialog.call(@last_key) if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty? dialog.lines_backup = { lines: modify_lines(whole_lines), line_index: @line_index, first_line_started_from: @first_line_started_from, started_from: @started_from, byte_pointer: @byte_pointer } clear_each_dialog(dialog) dialog.contents = nil dialog.trap_key = nil return end old_dialog = dialog.clone dialog.contents = dialog_render_info.contents pointer = dialog.pointer if dialog_render_info.width dialog.width = dialog_render_info.width else dialog.width = dialog.contents.map { |l| calculate_width(l, true) }.max end height = dialog_render_info.height || DIALOG_DEFAULT_HEIGHT height = dialog.contents.size if dialog.contents.size < height if dialog.contents.size > height if dialog.pointer if dialog.pointer < 0 dialog.scroll_top = 0 elsif (dialog.pointer - dialog.scroll_top) >= (height - 1) dialog.scroll_top = dialog.pointer - (height - 1) elsif (dialog.pointer - dialog.scroll_top) < 0 dialog.scroll_top = dialog.pointer end pointer = dialog.pointer - dialog.scroll_top end dialog.contents = dialog.contents[dialog.scroll_top, height] end if dialog.contents and dialog.scroll_top >= dialog.contents.size dialog.scroll_top = dialog.contents.size - height end if dialog_render_info.scrollbar and dialog_render_info.contents.size > height bar_max_height = height * 2 moving_distance = (dialog_render_info.contents.size - height) * 2 position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance) bar_height = (bar_max_height * ((dialog.contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i dialog.scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i else dialog.scrollbar_pos = nil end upper_space = @first_line_started_from - @started_from dialog.column = dialog_render_info.pos.x dialog.width += @block_elem_width if dialog.scrollbar_pos diff = (dialog.column + dialog.width) - (@screen_size.last) if diff > 0 dialog.column -= diff end if (@rest_height - dialog_render_info.pos.y) >= height dialog.vertical_offset = dialog_render_info.pos.y + 1 elsif upper_space >= height dialog.vertical_offset = dialog_render_info.pos.y - height else if (@rest_height - dialog_render_info.pos.y) < height scroll_down(height + dialog_render_info.pos.y) move_cursor_up(height + dialog_render_info.pos.y) end dialog.vertical_offset = dialog_render_info.pos.y + 1 end Reline::IOGate.hide_cursor if dialog.column < 0 dialog.column = 0 dialog.width = @screen_size.last end reset_dialog(dialog, old_dialog) move_cursor_down(dialog.vertical_offset) Reline::IOGate.move_cursor_column(dialog.column) dialog.contents.each_with_index do |item, i| if i == pointer fg_color = dialog_render_info.pointer_fg_color bg_color = dialog_render_info.pointer_bg_color else fg_color = dialog_render_info.fg_color bg_color = dialog_render_info.bg_color end str_width = dialog.width - (dialog.scrollbar_pos.nil? ? 0 : @block_elem_width) str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width) @output.write "\e[#{bg_color}m\e[#{fg_color}m#{str}" if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column) @output.write "\e[37m" if dialog.scrollbar_pos <= (i * 2) and (i * 2 + 1) < (dialog.scrollbar_pos + bar_height) @output.write @full_block elsif dialog.scrollbar_pos <= (i * 2) and (i * 2) < (dialog.scrollbar_pos + bar_height) @output.write @upper_half_block elsif dialog.scrollbar_pos <= (i * 2 + 1) and (i * 2) < (dialog.scrollbar_pos + bar_height) @output.write @lower_half_block else @output.write ' ' * @block_elem_width end end @output.write "\e[0m" Reline::IOGate.move_cursor_column(dialog.column) move_cursor_down(1) if i < (dialog.contents.size - 1) end Reline::IOGate.move_cursor_column(cursor_column) move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1) Reline::IOGate.show_cursor dialog.lines_backup = { lines: modify_lines(whole_lines), line_index: @line_index, first_line_started_from: @first_line_started_from, started_from: @started_from, byte_pointer: @byte_pointer } end
# File lib/reline/line_editor.rb, line 1144 def render_partial(prompt, prompt_width, line_to_render, this_started_from, with_control: true) visual_lines, height = split_by_width(line_to_render.nil? ? prompt : prompt + line_to_render, @screen_size.last) cursor_up_from_last_line = 0 if @scroll_partial_screen last_visual_line = this_started_from + (height - 1) last_screen_line = @scroll_partial_screen + (@screen_height - 1) if (@scroll_partial_screen - this_started_from) >= height # Render nothing because this line is before the screen. visual_lines = [] elsif this_started_from > last_screen_line # Render nothing because this line is after the screen. visual_lines = [] else deleted_lines_before_screen = [] if @scroll_partial_screen > this_started_from and last_visual_line >= @scroll_partial_screen # A part of visual lines are before the screen. deleted_lines_before_screen = visual_lines.shift((@scroll_partial_screen - this_started_from) * 2) deleted_lines_before_screen.compact! end if this_started_from <= last_screen_line and last_screen_line < last_visual_line # A part of visual lines are after the screen. visual_lines.pop((last_visual_line - last_screen_line) * 2) end move_cursor_up(deleted_lines_before_screen.size - @started_from) cursor_up_from_last_line = @started_from - deleted_lines_before_screen.size end end if with_control if height > @highest_in_this diff = height - @highest_in_this scroll_down(diff) @highest_in_all += diff @highest_in_this = height move_cursor_up(diff) elsif height < @highest_in_this diff = @highest_in_this - height @highest_in_all -= diff @highest_in_this = height end move_cursor_up(@started_from) @started_from = calculate_height_by_width(prompt_width + @cursor) - 1 cursor_up_from_last_line = height - 1 - @started_from end if Reline::Unicode::CSI_REGEXP.match?(prompt + line_to_render) @output.write "\e[0m" # clear character decorations end visual_lines.each_with_index do |line, index| Reline::IOGate.move_cursor_column(0) if line.nil? if calculate_width(visual_lines[index - 1], true) == Reline::IOGate.get_screen_size.last # reaches the end of line if Reline::IOGate.win? and Reline::IOGate.win_legacy_console? # A newline is automatically inserted if a character is rendered at # eol on command prompt. else # When the cursor is at the end of the line and erases characters # after the cursor, some terminals delete the character at the # cursor position. move_cursor_down(1) Reline::IOGate.move_cursor_column(0) end else Reline::IOGate.erase_after_cursor move_cursor_down(1) Reline::IOGate.move_cursor_column(0) end next end @output.write line if Reline::IOGate.win? and Reline::IOGate.win_legacy_console? and calculate_width(line, true) == Reline::IOGate.get_screen_size.last # A newline is automatically inserted if a character is rendered at eol on command prompt. @rest_height -= 1 if @rest_height > 0 end @output.flush if @first_prompt @first_prompt = false @pre_input_hook&.call end end unless visual_lines.empty? Reline::IOGate.erase_after_cursor Reline::IOGate.move_cursor_column(0) end if with_control # Just after rendring, so the cursor is on the last line. if finished? Reline::IOGate.move_cursor_column(0) else # Moves up from bottom of lines to the cursor position. move_cursor_up(cursor_up_from_last_line) # This logic is buggy if a fullwidth char is wrapped because there is only one halfwidth at end of a line. Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) end end height end
# File lib/reline/line_editor.rb, line 1118 def render_whole_lines(lines, prompt, prompt_width) rendered_height = 0 modify_lines(lines).each_with_index do |line, index| if prompt.is_a?(Array) line_prompt = prompt[index] prompt_width = calculate_width(line_prompt, true) else line_prompt = prompt end height = render_partial(line_prompt, prompt_width, line, rendered_height, with_control: false) if index < (lines.size - 1) if @scroll_partial_screen if (@scroll_partial_screen - height) < rendered_height and (@scroll_partial_screen + @screen_height - 1) >= (rendered_height + height) move_cursor_down(1) end else scroll_down(1) end rendered_height += height else rendered_height += height - 1 end end rendered_height end
# File lib/reline/line_editor.rb, line 967 def rerender_added_newline(prompt, prompt_width) scroll_down(1) @buffer_of_lines[@previous_line_index] = @line @line = @buffer_of_lines[@line_index] unless @in_pasting render_partial(prompt, prompt_width, @line, @first_line_started_from + @started_from + 1, with_control: false) end @cursor = @cursor_max = calculate_width(@line) @byte_pointer = @line.bytesize @highest_in_all += @highest_in_this @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max) @first_line_started_from += @started_from + 1 @started_from = calculate_height_by_width(prompt_width + @cursor) - 1 @previous_line_index = nil end
# File lib/reline/line_editor.rb, line 1063 def rerender_all_lines move_cursor_up(@first_line_started_from + @started_from) Reline::IOGate.move_cursor_column(0) back = 0 new_buffer = whole_lines prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer) new_buffer.each_with_index do |line, index| prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc width = prompt_width + calculate_width(line) height = calculate_height_by_width(width) back += height end old_highest_in_all = @highest_in_all if @line_index.zero? new_first_line_started_from = 0 else new_first_line_started_from = calculate_height_by_lines(new_buffer[0..(@line_index - 1)], prompt_list || prompt) end new_started_from = calculate_height_by_width(prompt_width + @cursor) - 1 calculate_scroll_partial_screen(back, new_first_line_started_from + new_started_from) if @scroll_partial_screen move_cursor_up(@first_line_started_from + @started_from) scroll_down(@screen_height - 1) move_cursor_up(@screen_height) Reline::IOGate.move_cursor_column(0) elsif back > old_highest_in_all scroll_down(back - 1) move_cursor_up(back - 1) elsif back < old_highest_in_all scroll_down(back) Reline::IOGate.erase_after_cursor (old_highest_in_all - back - 1).times do scroll_down(1) Reline::IOGate.erase_after_cursor end move_cursor_up(old_highest_in_all - 1) end render_whole_lines(new_buffer, prompt_list || prompt, prompt_width) if @prompt_proc prompt = prompt_list[@line_index] prompt_width = calculate_width(prompt, true) end @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max) @highest_in_all = back @first_line_started_from = new_first_line_started_from @started_from = new_started_from if @scroll_partial_screen Reline::IOGate.move_cursor_up(@screen_height - (@first_line_started_from + @started_from - @scroll_partial_screen) - 1) Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) else move_cursor_down(@first_line_started_from + @started_from - back + 1) Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) end end
# File lib/reline/line_editor.rb, line 1015 def rerender_changed_current_line if @previous_line_index new_lines = whole_lines(index: @previous_line_index, line: @line) else new_lines = whole_lines end prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines) all_height = calculate_height_by_lines(new_lines, prompt_list || prompt) diff = all_height - @highest_in_all move_cursor_down(@highest_in_all - @first_line_started_from - @started_from - 1) if diff > 0 scroll_down(diff) move_cursor_up(all_height - 1) elsif diff < 0 (-diff).times do Reline::IOGate.move_cursor_column(0) Reline::IOGate.erase_after_cursor move_cursor_up(1) end move_cursor_up(all_height - 1) else move_cursor_up(all_height - 1) end @highest_in_all = all_height back = render_whole_lines(new_lines, prompt_list || prompt, prompt_width) move_cursor_up(back) if @previous_line_index @buffer_of_lines[@previous_line_index] = @line @line = @buffer_of_lines[@line_index] end @first_line_started_from = if @line_index.zero? 0 else calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt) end if @prompt_proc prompt = prompt_list[@line_index] prompt_width = calculate_width(prompt, true) end move_cursor_down(@first_line_started_from) calculate_nearest_cursor @started_from = calculate_height_by_width(prompt_width + @cursor) - 1 move_cursor_down(@started_from) Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max) end
# File lib/reline/line_editor.rb, line 786 def reset_dialog(dialog, old_dialog) return if dialog.lines_backup.nil? or old_dialog.contents.nil? prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines]) visual_lines = [] visual_start = nil dialog.lines_backup[:lines].each_with_index { |l, i| pr = prompt_list ? prompt_list[i] : prompt vl, _ = split_by_width(pr + l, @screen_size.last) vl.compact! if i == dialog.lines_backup[:line_index] visual_start = visual_lines.size + dialog.lines_backup[:started_from] end visual_lines.concat(vl) } old_y = dialog.lines_backup[:first_line_started_from] + dialog.lines_backup[:started_from] y = @first_line_started_from + @started_from y_diff = y - old_y if (old_y + old_dialog.vertical_offset) < (y + dialog.vertical_offset) # rerender top move_cursor_down(old_dialog.vertical_offset - y_diff) start = visual_start + old_dialog.vertical_offset line_num = dialog.vertical_offset - old_dialog.vertical_offset line_num.times do |i| Reline::IOGate.move_cursor_column(old_dialog.column) if visual_lines[start + i].nil? s = ' ' * old_dialog.width else s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width) s = padding_space_with_escape_sequences(s, old_dialog.width) end @output.write "\e[0m#{s}\e[0m" move_cursor_down(1) if i < (line_num - 1) end move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff) end if (old_y + old_dialog.vertical_offset + old_dialog.contents.size) > (y + dialog.vertical_offset + dialog.contents.size) # rerender bottom move_cursor_down(dialog.vertical_offset + dialog.contents.size - y_diff) start = visual_start + dialog.vertical_offset + dialog.contents.size line_num = (old_dialog.vertical_offset + old_dialog.contents.size) - (dialog.vertical_offset + dialog.contents.size) line_num.times do |i| Reline::IOGate.move_cursor_column(old_dialog.column) if visual_lines[start + i].nil? s = ' ' * old_dialog.width else s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width) s = padding_space_with_escape_sequences(s, old_dialog.width) end @output.write "\e[0m#{s}\e[0m" move_cursor_down(1) if i < (line_num - 1) end move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff) end if old_dialog.column < dialog.column # rerender left move_cursor_down(old_dialog.vertical_offset - y_diff) width = dialog.column - old_dialog.column start = visual_start + old_dialog.vertical_offset line_num = old_dialog.contents.size line_num.times do |i| Reline::IOGate.move_cursor_column(old_dialog.column) if visual_lines[start + i].nil? s = ' ' * width else s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width) s = padding_space_with_escape_sequences(s, dialog.width) end @output.write "\e[0m#{s}\e[0m" move_cursor_down(1) if i < (line_num - 1) end move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff) end if (old_dialog.column + old_dialog.width) > (dialog.column + dialog.width) # rerender right move_cursor_down(old_dialog.vertical_offset + y_diff) width = (old_dialog.column + old_dialog.width) - (dialog.column + dialog.width) start = visual_start + old_dialog.vertical_offset line_num = old_dialog.contents.size line_num.times do |i| Reline::IOGate.move_cursor_column(old_dialog.column + dialog.width) if visual_lines[start + i].nil? s = ' ' * width else s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column + dialog.width, width) rerender_width = old_dialog.width - dialog.width s = padding_space_with_escape_sequences(s, rerender_width) end Reline::IOGate.move_cursor_column(dialog.column + dialog.width) @output.write "\e[0m#{s}\e[0m" move_cursor_down(1) if i < (line_num - 1) end move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff) end Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last) end
# File lib/reline/line_editor.rb, line 1429 def run_for_operators(key, method_symbol, &block) if @waiting_operator_proc if VI_MOTIONS.include?(method_symbol) old_cursor, old_byte_pointer = @cursor, @byte_pointer @vi_arg = @waiting_operator_vi_arg if @waiting_operator_vi_arg&.> 1 block.(true) unless @waiting_proc cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer @cursor, @byte_pointer = old_cursor, old_byte_pointer @waiting_operator_proc.(cursor_diff, byte_pointer_diff) else old_waiting_proc = @waiting_proc old_waiting_operator_proc = @waiting_operator_proc current_waiting_operator_proc = @waiting_operator_proc @waiting_proc = proc { |k| old_cursor, old_byte_pointer = @cursor, @byte_pointer old_waiting_proc.(k) cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer @cursor, @byte_pointer = old_cursor, old_byte_pointer current_waiting_operator_proc.(cursor_diff, byte_pointer_diff) @waiting_operator_proc = old_waiting_operator_proc } end else # Ignores operator when not motion is given. block.(false) end @waiting_operator_proc = nil @waiting_operator_vi_arg = nil if @vi_arg @rerender_all = true @vi_arg = nil end else block.(false) end end
# File lib/reline/line_editor.rb, line 353 def scroll_down(val) if val <= @rest_height Reline::IOGate.move_cursor_down(val) @rest_height -= val else Reline::IOGate.move_cursor_down(@rest_height) Reline::IOGate.scroll_down(val - @rest_height) @rest_height = 0 end end
# File lib/reline/line_editor.rb, line 3231 def search_next_char(key, arg, need_prev_char: false, inclusive: false) if key.instance_of?(String) inputed_char = key else inputed_char = key.chr end prev_total = nil total = nil found = false @line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar| # total has [byte_size, cursor] unless total # skip cursor point width = Reline::Unicode.get_mbchar_width(mbchar) total = [mbchar.bytesize, width] else if inputed_char == mbchar arg -= 1 if arg.zero? found = true break end end width = Reline::Unicode.get_mbchar_width(mbchar) prev_total = total total = [total.first + mbchar.bytesize, total.last + width] end end if not need_prev_char and found and total byte_size, width = total @byte_pointer += byte_size @cursor += width elsif need_prev_char and found and prev_total byte_size, width = prev_total @byte_pointer += byte_size @cursor += width end if inclusive byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer) if byte_size > 0 c = @line.byteslice(@byte_pointer, byte_size) width = Reline::Unicode.get_mbchar_width(c) @byte_pointer += byte_size @cursor += width end end @waiting_proc = nil end
# File lib/reline/line_editor.rb, line 3288 def search_prev_char(key, arg, need_next_char = false) if key.instance_of?(String) inputed_char = key else inputed_char = key.chr end prev_total = nil total = nil found = false @line.byteslice(0..@byte_pointer).grapheme_clusters.reverse_each do |mbchar| # total has [byte_size, cursor] unless total # skip cursor point width = Reline::Unicode.get_mbchar_width(mbchar) total = [mbchar.bytesize, width] else if inputed_char == mbchar arg -= 1 if arg.zero? found = true break end end width = Reline::Unicode.get_mbchar_width(mbchar) prev_total = total total = [total.first + mbchar.bytesize, total.last + width] end end if not need_next_char and found and total byte_size, width = total @byte_pointer -= byte_size @cursor -= width elsif need_next_char and found and prev_total byte_size, width = prev_total @byte_pointer -= byte_size @cursor -= width end @waiting_proc = nil end
# File lib/reline/line_editor.rb, line 349 def split_by_width(str, max_width) Reline::Unicode.split_by_width(str, max_width, @encoding) end
# File lib/reline/line_editor.rb, line 2874 def vi_add(key) @config.editing_mode = :vi_insert ed_next_char(key) end
# File lib/reline/line_editor.rb, line 2988 def vi_add_at_eol(key) ed_move_to_end(key) @config.editing_mode = :vi_insert end
# File lib/reline/line_editor.rb, line 3014 def vi_change_meta(key, arg: 1) @drop_terminate_spaces = true @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff| if byte_pointer_diff > 0 @line, cut = byteslice!(@line, @byte_pointer, byte_pointer_diff) elsif byte_pointer_diff < 0 @line, cut = byteslice!(@line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff) end copy_for_vi(cut) @cursor += cursor_diff if cursor_diff < 0 @cursor_max -= cursor_diff.abs @byte_pointer += byte_pointer_diff if byte_pointer_diff < 0 @config.editing_mode = :vi_insert @drop_terminate_spaces = false } @waiting_operator_vi_arg = arg end
# File lib/reline/line_editor.rb, line 2879 def vi_command_mode(key) ed_prev_char(key) @config.editing_mode = :vi_command end
# File lib/reline/line_editor.rb, line 3032 def vi_delete_meta(key, arg: 1) @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff| if byte_pointer_diff > 0 @line, cut = byteslice!(@line, @byte_pointer, byte_pointer_diff) elsif byte_pointer_diff < 0 @line, cut = byteslice!(@line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff) end copy_for_vi(cut) @cursor += cursor_diff if cursor_diff < 0 @cursor_max -= cursor_diff.abs @byte_pointer += byte_pointer_diff if byte_pointer_diff < 0 } @waiting_operator_vi_arg = arg end
# File lib/reline/line_editor.rb, line 2963 def vi_delete_prev_char(key) if @is_multiline and @cursor == 0 and @line_index > 0 @buffer_of_lines[@line_index] = @line @cursor = calculate_width(@buffer_of_lines[@line_index - 1]) @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index) @line_index -= 1 @line = @buffer_of_lines[@line_index] @cursor_max = calculate_width(@line) @rerender_all = true elsif @cursor > 0 byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer) @byte_pointer -= byte_size @line, mbchar = byteslice!(@line, @byte_pointer, byte_size) width = Reline::Unicode.get_mbchar_width(mbchar) @cursor -= width @cursor_max -= width end end
# File lib/reline/line_editor.rb, line 2944 def vi_end_big_word(key, arg: 1, inclusive: false) if @line.bytesize > @byte_pointer byte_size, width = Reline::Unicode.vi_big_forward_end_word(@line, @byte_pointer) @byte_pointer += byte_size @cursor += width end arg -= 1 if inclusive and arg.zero? byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer) if byte_size > 0 c = @line.byteslice(@byte_pointer, byte_size) width = Reline::Unicode.get_mbchar_width(c) @byte_pointer += byte_size @cursor += width end end vi_end_big_word(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 2905 def vi_end_word(key, arg: 1, inclusive: false) if @line.bytesize > @byte_pointer byte_size, width = Reline::Unicode.vi_forward_end_word(@line, @byte_pointer) @byte_pointer += byte_size @cursor += width end arg -= 1 if inclusive and arg.zero? byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer) if byte_size > 0 c = @line.byteslice(@byte_pointer, byte_size) width = Reline::Unicode.get_mbchar_width(c) @byte_pointer += byte_size @cursor += width end end vi_end_word(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 2115 def vi_first_print(key) @byte_pointer, @cursor = Reline::Unicode.vi_first_print(@line) end
# File lib/reline/line_editor.rb, line 3117 def vi_histedit(key) path = Tempfile.open { |fp| if @is_multiline fp.write whole_lines.join("\n") else fp.write @line end fp.path } system("#{ENV['EDITOR']} #{path}") if @is_multiline @buffer_of_lines = File.read(path).split("\n") @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty? @line_index = 0 @line = @buffer_of_lines[@line_index] @rerender_all = true else @line = File.read(path) end finish end
# File lib/reline/line_editor.rb, line 2870 def vi_insert(key) @config.editing_mode = :vi_insert end
# File lib/reline/line_editor.rb, line 2983 def vi_insert_at_bol(key) ed_move_to_beg(key) @config.editing_mode = :vi_insert end
# File lib/reline/line_editor.rb, line 3328 def vi_join_lines(key, arg: 1) if @is_multiline and @buffer_of_lines.size > @line_index + 1 @cursor = calculate_width(@line) @byte_pointer = @line.bytesize @line += ' ' + @buffer_of_lines.delete_at(@line_index + 1).lstrip @cursor_max = calculate_width(@line) @buffer_of_lines[@line_index] = @line @rerender_all = true @rest_height += 1 end arg -= 1 vi_join_lines(key, arg: arg) if arg > 0 end
- Editline
-
vi-kill-line-prev
(vi:Ctrl-U
) Delete the string from the beginning of the edit buffer to the cursor and save it to the cut buffer. - GNU
Readline
-
unix-line-discard
(C-u
) Kill backward from the cursor to the beginning of the current line.
# File lib/reline/line_editor.rb, line 2636 def vi_kill_line_prev(key) if @byte_pointer > 0 @line, deleted = byteslice!(@line, 0, @byte_pointer) @byte_pointer = 0 @kill_ring.append(deleted, true) @cursor_max = calculate_width(@line) @cursor = 0 end end
# File lib/reline/line_editor.rb, line 3059 def vi_list_or_eof(key) if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1) @line = nil if @buffer_of_lines.size > 1 scroll_down(@highest_in_all - @first_line_started_from) end Reline::IOGate.move_cursor_column(0) @eof = true finish else ed_newline(key) end end
# File lib/reline/line_editor.rb, line 2924 def vi_next_big_word(key, arg: 1) if @line.bytesize > @byte_pointer byte_size, width = Reline::Unicode.vi_big_forward_word(@line, @byte_pointer) @byte_pointer += byte_size @cursor += width end arg -= 1 vi_next_big_word(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 3223 def vi_next_char(key, arg: 1, inclusive: false) @waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg, inclusive: inclusive) } end
# File lib/reline/line_editor.rb, line 2885 def vi_next_word(key, arg: 1) if @line.bytesize > @byte_pointer byte_size, width = Reline::Unicode.vi_forward_word(@line, @byte_pointer, @drop_terminate_spaces) @byte_pointer += byte_size @cursor += width end arg -= 1 vi_next_word(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 3151 def vi_paste_next(key, arg: 1) if @vi_clipboard.size > 0 byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer) @line = byteinsert(@line, @byte_pointer + byte_size, @vi_clipboard) @cursor_max += calculate_width(@vi_clipboard) @cursor += calculate_width(@vi_clipboard) @byte_pointer += @vi_clipboard.bytesize end arg -= 1 vi_paste_next(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 3139 def vi_paste_prev(key, arg: 1) if @vi_clipboard.size > 0 @line = byteinsert(@line, @byte_pointer, @vi_clipboard) @cursor_max += calculate_width(@vi_clipboard) cursor_point = @vi_clipboard.grapheme_clusters[0..-2].join @cursor += calculate_width(cursor_point) @byte_pointer += cursor_point.bytesize end arg -= 1 vi_paste_prev(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 2934 def vi_prev_big_word(key, arg: 1) if @byte_pointer > 0 byte_size, width = Reline::Unicode.vi_big_backward_word(@line, @byte_pointer) @byte_pointer -= byte_size @cursor -= width end arg -= 1 vi_prev_big_word(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 3280 def vi_prev_char(key, arg: 1) @waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg) } end
# File lib/reline/line_editor.rb, line 2895 def vi_prev_word(key, arg: 1) if @byte_pointer > 0 byte_size, width = Reline::Unicode.vi_backward_word(@line, @byte_pointer) @byte_pointer -= byte_size @cursor -= width end arg -= 1 vi_prev_word(key, arg: arg) if arg > 0 end
# File lib/reline/line_editor.rb, line 3195 def vi_replace_char(key, arg: 1) @waiting_proc = ->(k) { if arg == 1 byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer) before = @line.byteslice(0, @byte_pointer) remaining_point = @byte_pointer + byte_size after = @line.byteslice(remaining_point, @line.bytesize - remaining_point) @line = before + k.chr + after @cursor_max = calculate_width(@line) @waiting_proc = nil elsif arg > 1 byte_size = 0 arg.times do byte_size += Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer + byte_size) end before = @line.byteslice(0, @byte_pointer) remaining_point = @byte_pointer + byte_size after = @line.byteslice(remaining_point, @line.bytesize - remaining_point) replaced = k.chr * arg @line = before + replaced + after @byte_pointer += replaced.bytesize @cursor += calculate_width(replaced) @cursor_max = calculate_width(@line) @waiting_proc = nil end } end
# File lib/reline/line_editor.rb, line 2349 def vi_search_next(key) incremental_search_history(key) end
# File lib/reline/line_editor.rb, line 2344 def vi_search_prev(key) incremental_search_history(key) end
# File lib/reline/line_editor.rb, line 3180 def vi_to_column(key, arg: 0) @byte_pointer, @cursor = @line.grapheme_clusters.inject([0, 0]) { |total, gc| # total has [byte_size, cursor] mbchar_width = Reline::Unicode.get_mbchar_width(gc) if (total.last + mbchar_width) >= arg break total elsif (total.last + mbchar_width) >= @cursor_max break total else total = [total.first + gc.bytesize, total.last + mbchar_width] total end } end
# File lib/reline/line_editor.rb, line 3094 def vi_to_history_line(key) if Reline::HISTORY.empty? return end if @history_pointer.nil? @history_pointer = 0 @line_backup_in_history = @line @line = Reline::HISTORY[@history_pointer] @cursor_max = calculate_width(@line) @cursor = 0 @byte_pointer = 0 elsif @history_pointer.zero? return else Reline::HISTORY[@history_pointer] = @line @history_pointer = 0 @line = Reline::HISTORY[@history_pointer] @cursor_max = calculate_width(@line) @cursor = 0 @byte_pointer = 0 end end
# File lib/reline/line_editor.rb, line 3227 def vi_to_next_char(key, arg: 1, inclusive: false) @waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg, need_prev_char: true, inclusive: inclusive) } end
# File lib/reline/line_editor.rb, line 3284 def vi_to_prev_char(key, arg: 1) @waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg, true) } end
# File lib/reline/line_editor.rb, line 3047 def vi_yank(key, arg: 1) @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff| if byte_pointer_diff > 0 cut = @line.byteslice(@byte_pointer, byte_pointer_diff) elsif byte_pointer_diff < 0 cut = @line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff) end copy_for_vi(cut) } @waiting_operator_vi_arg = arg end
# File lib/reline/line_editor.rb, line 3009 def vi_zero(key) @byte_pointer = 0 @cursor = 0 end