class Reline::LineEditor

Constants

CompletionJourneyData
DIALOG_DEFAULT_HEIGHT
MINIMUM_SCROLLBAR_HEIGHT
PROMPT_LIST_CACHE_TIMEOUT
VI_MOTIONS

Attributes

auto_indent_proc[RW]
byte_pointer[R]
completion_append_character[RW]
completion_proc[RW]
confirm_multiline_termination_proc[RW]
dig_perfect_match_proc[RW]
line[R]

TODO: undo TODO: Use “private alias_method” idiom after drop Ruby 2.5.

output[W]
output_modifier_proc[RW]
pre_input_hook[RW]
prompt_proc[RW]

Public Class Methods

new(config, encoding) click to toggle source
# File reline/line_editor.rb, line 57
def initialize(config, encoding)
  @config = config
  @completion_append_character = ''
  reset_variables(encoding: encoding)
end

Public Instance Methods

add_dialog_proc(name, p, context = nil) click to toggle source
# File reline/line_editor.rb, line 639
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
backward_char(key, arg: 1)
Alias for: ed_prev_char
backward_delete_char(key, arg: 1)
Alias for: em_delete_prev_char
backward_kill_word(key)
Alias for: ed_delete_prev_word
backward_word(key)
Alias for: ed_prev_word
beginning_of_line(key)
Alias for: ed_move_to_beg
byte_pointer=(val) click to toggle source
# File reline/line_editor.rb, line 1842
def byte_pointer=(val)
  @byte_pointer = val
  str = @line.byteslice(0, @byte_pointer)
  @cursor = calculate_width(str)
  @cursor_max = calculate_width(@line)
end
call_completion_proc() click to toggle source
# File reline/line_editor.rb, line 1613
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
call_completion_proc_with_checking_args(pre, target, post) click to toggle source
# File reline/line_editor.rb, line 1621
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
capitalize_word(key)
Alias for: em_capitol_case
clear_screen(key)
Alias for: ed_clear_screen
confirm_multiline_termination() click to toggle source
# File reline/line_editor.rb, line 1760
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
delete_char(key)
Alias for: em_delete
delete_char_or_list(key)
Alias for: em_delete_or_list
delete_text(start = nil, length = nil) click to toggle source
# File reline/line_editor.rb, line 1782
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
downcase_word(key)
Alias for: em_lower_case
ed_digit(key)
Alias for: ed_insert
editing_mode() click to toggle source
# File reline/line_editor.rb, line 1229
def editing_mode
  @config.editing_mode
end
end_of_line(key)
Alias for: ed_move_to_end
eof?() click to toggle source
# File reline/line_editor.rb, line 252
def eof?
  @eof
end
exchange_point_and_mark(key)
Alias for: em_exchange_mark
finalize() click to toggle source
# File reline/line_editor.rb, line 248
def finalize
  Signal.trap('INT', @old_trap)
end
finish() click to toggle source
# File reline/line_editor.rb, line 1868
def finish
  @finished = true
  @rerender_all = true
  @config.reset
end
finished?() click to toggle source
# File reline/line_editor.rb, line 1864
def finished?
  @finished
end
forward_char(key, arg: 1)
Alias for: ed_next_char
forward_search_history(key)
Alias for: vi_search_next
forward_word(key)
Alias for: em_next_word
history_search_backward(key, arg: 1)
history_search_forward(key, arg: 1)
input_key(key) click to toggle source
# File reline/line_editor.rb, line 1538
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? and @line
    process_auto_indent
  end
end
insert_text(text) click to toggle source
# File reline/line_editor.rb, line 1770
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
io_gate() click to toggle source
# File reline/line_editor.rb, line 63
def io_gate
  Reline::IOGate
end
just_move_cursor() click to toggle source
# File reline/line_editor.rb, line 935
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
  @cursor, @cursor_max, _, @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 + @cursor) - 1
  calculate_scroll_partial_screen(@highest_in_all, new_first_line_started_from + new_started_from)
  @previous_line_index = nil
  @line = @buffer_of_lines[@line_index]
  if @rerender_all
    rerender_all_lines
    @rerender_all = false
    true
  else
    @first_line_started_from = new_first_line_started_from
    @started_from = new_started_from
    move_cursor_down(first_line_diff + @started_from)
    Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
    false
  end
end
kill_line(key)
Alias for: ed_kill_line
kill_whole_line(key)
Alias for: em_kill_line
kill_word(key)
Alias for: em_delete_next_word
multiline_off() click to toggle source
# File reline/line_editor.rb, line 318
def multiline_off
  @is_multiline = false
end
multiline_on() click to toggle source
# File reline/line_editor.rb, line 314
def multiline_on
  @is_multiline = true
end
next_history(key, arg: 1)
Alias for: ed_next_history
previous_history(key, arg: 1)
Alias for: ed_prev_history
quoted_insert(str, arg: 1)
Alias for: ed_quoted_insert
rerender() click to toggle source
# File reline/line_editor.rb, line 426
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)
  cursor_column = (prompt_width + @cursor) % @screen_size.last
  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
    new_lines = whole_lines
    prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
    modify_lines(new_lines).each_with_index do |line, index|
      @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\r\n"
      Reline::IOGate.erase_after_cursor
    end
    @output.flush
    clear_dialog(cursor_column)
    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_trap_key(cursor_column)
    rerender_added_newline(prompt, prompt_width, prompt_list)
    @add_newline_to_end_of_buffer = false
  else
    if @just_cursor_moving and not @rerender_all
      clear_dialog_with_trap_key(cursor_column)
      rendered = just_move_cursor
      @just_cursor_moving = false
      return
    elsif @previous_line_index or new_highest_in_this != @highest_in_this
      clear_dialog_with_trap_key(cursor_column)
      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.
      new_lines = whole_lines
      line = modify_lines(new_lines)[@line_index]
      clear_dialog(cursor_column)
      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(cursor_column)
    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
rerender_all() click to toggle source
# File reline/line_editor.rb, line 420
def rerender_all
  @rerender_all = true
  process_insert(force: true)
  rerender
end
reset(prompt = '', encoding:) click to toggle source
# File reline/line_editor.rb, line 154
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
reset_line() click to toggle source
# File reline/line_editor.rb, line 296
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
reset_variables(prompt = '', encoding:) click to toggle source
# File reline/line_editor.rb, line 256
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 = []
  @previous_rendered_dialog_y = 0
  @last_key = nil
  @resized = false
  reset_line
end
resize() click to toggle source
# File reline/line_editor.rb, line 185
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
retrieve_completion_block(set_completion_quote_character = false) click to toggle source
# File reline/line_editor.rb, line 1682
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
    lines = whole_lines
    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
reverse_search_history(key)
Alias for: vi_search_prev
self_insert(key)
Alias for: ed_insert
set_mark(key)
Alias for: em_set_mark
set_pasting_state(in_pasting) click to toggle source
# File reline/line_editor.rb, line 67
def set_pasting_state(in_pasting)
  @in_pasting = in_pasting
end
set_signal_handlers() click to toggle source
# File reline/line_editor.rb, line 225
def set_signal_handlers
  @old_trap = Signal.trap('INT') {
    clear_dialog(0)
    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
  }
end
simplified_rendering?() click to toggle source
# File reline/line_editor.rb, line 71
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
transpose_chars(key)
Alias for: ed_transpose_chars
transpose_words(key)
Alias for: ed_transpose_words
unix_line_discard(key)
Alias for: vi_kill_line_prev
unix_word_rubout(key)
Alias for: em_kill_region
upcase_word(key)
Alias for: em_upper_case
vi_end_of_transmission(key)
Alias for: vi_list_or_eof
vi_eof_maybe(key)
Alias for: vi_list_or_eof
vi_movement_mode(key)
Alias for: vi_command_mode
whole_buffer() click to toggle source
# File reline/line_editor.rb, line 1856
def whole_buffer
  if @buffer_of_lines.size == 1 and @line.nil?
    nil
  else
    whole_lines.join("\n")
  end
end
whole_lines() click to toggle source
# File reline/line_editor.rb, line 1849
def whole_lines
  index = @previous_line_index || @line_index
  temp_lines = @buffer_of_lines.dup
  temp_lines[index] = @line
  temp_lines
end
wrap_method_call(method_symbol, method_obj, key, with_operator = false) click to toggle source
# File reline/line_editor.rb, line 1421
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
yank(key)
Alias for: em_yank
yank_pop(key)
Alias for: em_yank_pop

Private Instance Methods

argumentable?(method_obj) click to toggle source
# File reline/line_editor.rb, line 1411
        def argumentable?(method_obj)
  method_obj and method_obj.parameters.any? { |param| param[0] == :key and param[1] == :arg }
end
byteinsert(str, byte_pointer, other) click to toggle source
# File reline/line_editor.rb, line 1880
        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
byteslice!(str, byte_pointer, size) click to toggle source
# File reline/line_editor.rb, line 1874
        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
calculate_height_by_lines(lines, prompt) click to toggle source
# File reline/line_editor.rb, line 322
        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
calculate_height_by_width(width) click to toggle source
# File reline/line_editor.rb, line 340
        def calculate_height_by_width(width)
  width.div(@screen_size.last) + 1
end
calculate_nearest_cursor(line_to_calc = @line, cursor = @cursor, started_from = @started_from, byte_pointer = @byte_pointer, update = true) click to toggle source
# File reline/line_editor.rb, line 378
        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
calculate_scroll_partial_screen(highest_in_all, cursor_y) click to toggle source
# File reline/line_editor.rb, line 878
        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
calculate_width(str, allow_escape_code = false) click to toggle source
# File reline/line_editor.rb, line 1887
        def calculate_width(str, allow_escape_code = false)
  Reline::Unicode.calculate_width(str, allow_escape_code)
end
check_mode_string() click to toggle source
# File reline/line_editor.rb, line 81
        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
check_multiline_prompt(buffer, force_recalc: false) click to toggle source
# File reline/line_editor.rb, line 101
        def check_multiline_prompt(buffer, force_recalc: false)
  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? && !force_recalc
    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
clear_dialog(cursor_column) click to toggle source
# File reline/line_editor.rb, line 862
        def clear_dialog(cursor_column)
  changes = @dialogs.map do |dialog|
    old_dialog = dialog.dup
    dialog.contents = nil
    [old_dialog, dialog]
  end
  render_dialog_changes(changes, cursor_column)
end
clear_dialog_with_trap_key(cursor_column) click to toggle source
# File reline/line_editor.rb, line 871
        def clear_dialog_with_trap_key(cursor_column)
  clear_dialog(cursor_column)
  @dialogs.each do |dialog|
    dialog.trap_key = nil
  end
end
clear_screen_buffer(prompt, prompt_list, prompt_width) click to toggle source
# File reline/line_editor.rb, line 1208
        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
complete(list, just_show_list = false) click to toggle source
# File reline/line_editor.rb, line 1283
        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).split("\n")[@line_index] || String.new(encoding: @encoding)
      line_to_pointer = (preposing + completed + completion_append_character.to_s).split("\n").last || String.new(encoding: @encoding)
      @cursor_max = calculate_width(@line)
      @cursor = calculate_width(line_to_pointer)
      @byte_pointer = line_to_pointer.bytesize
    end
  end
end
complete_internal_proc(list, is_menu) click to toggle source
# File reline/line_editor.rb, line 1237
        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
copy_for_vi(text) click to toggle source
# File reline/line_editor.rb, line 2804
        def copy_for_vi(text)
  if @config.editing_mode_is?(:vi_insert) or @config.editing_mode_is?(:vi_command)
    @vi_clipboard = text
  end
end
dialog_range(dialog, dialog_y) click to toggle source
# File reline/line_editor.rb, line 671
        def dialog_range(dialog, dialog_y)
  x_range = dialog.column...dialog.column + dialog.width
  y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size
  [x_range, y_range]
end
ed_argument_digit(key) click to toggle source
# File reline/line_editor.rb, line 3103
        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
ed_clear_screen(key) click to toggle source
# File reline/line_editor.rb, line 2668
        def ed_clear_screen(key)
  @cleared = true
end
Also aliased as: clear_screen
ed_delete_next_char(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 3015
        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
ed_delete_prev_char(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2933
        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
ed_delete_prev_word(key) click to toggle source
# File reline/line_editor.rb, line 2701
        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
Also aliased as: backward_kill_word
ed_insert(key) click to toggle source
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, call ed-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 reline/line_editor.rb, line 1944
        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
Also aliased as: ed_digit, self_insert
ed_kill_line(key) click to toggle source
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 reline/line_editor.rb, line 2551
        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
Also aliased as: kill_line
ed_move_to_beg(key) click to toggle source
# File reline/line_editor.rb, line 2057
        def ed_move_to_beg(key)
  @byte_pointer = @cursor = 0
end
Also aliased as: beginning_of_line
ed_move_to_end(key) click to toggle source
# File reline/line_editor.rb, line 2062
        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
Also aliased as: end_of_line
ed_newline(key) click to toggle source
# File reline/line_editor.rb, line 2490
        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
ed_next_char(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2013
        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
Also aliased as: forward_char
ed_next_history(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2442
        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
Also aliased as: next_history
ed_prev_char(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2033
        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
Also aliased as: backward_char
ed_prev_history(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2391
        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
Also aliased as: previous_history
ed_prev_word(key) click to toggle source
# File reline/line_editor.rb, line 2682
        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
Also aliased as: backward_word
ed_quoted_insert(str, arg: 1) click to toggle source
# File reline/line_editor.rb, line 1997
        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
Also aliased as: quoted_insert
ed_search_next_history(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2339
        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
Also aliased as: history_search_forward
ed_search_prev_history(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2292
        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
Also aliased as: history_search_backward
ed_transpose_chars(key) click to toggle source
# File reline/line_editor.rb, line 2713
        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
Also aliased as: transpose_chars
ed_transpose_words(key) click to toggle source
# File reline/line_editor.rb, line 2733
        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
Also aliased as: transpose_words
ed_unassigned(key) click to toggle source
Editline

ed-unassigned This editor command always results in an error.

GNU Readline

There is no corresponding macro.

# File reline/line_editor.rb, line 1914
def ed_unassigned(key) end
em_capitol_case(key) click to toggle source
# File reline/line_editor.rb, line 2748
        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
Also aliased as: capitalize_word
em_delete(key) click to toggle source
# File reline/line_editor.rb, line 2600
        def em_delete(key)
  if @line.empty? and (not @is_multiline or @buffer_of_lines.size == 1) and key == "\C-d".ord
    @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
Also aliased as: delete_char
em_delete_next_word(key) click to toggle source
# File reline/line_editor.rb, line 2691
        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
Also aliased as: kill_word
em_delete_or_list(key) click to toggle source
# File reline/line_editor.rb, line 2627
        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
Also aliased as: delete_char_or_list
em_delete_prev_char(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2523
        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
Also aliased as: backward_delete_char
em_exchange_mark(key) click to toggle source
# File reline/line_editor.rb, line 3287
        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
Also aliased as: exchange_point_and_mark
em_kill_line(key) click to toggle source
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 reline/line_editor.rb, line 2589
        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
Also aliased as: kill_whole_line
em_kill_region(key) click to toggle source
# File reline/line_editor.rb, line 2792
        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
Also aliased as: unix_word_rubout
em_lower_case(key) click to toggle source
# File reline/line_editor.rb, line 2760
        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
Also aliased as: downcase_word
em_meta_next(key) click to toggle source
# File reline/line_editor.rb, line 3298
        def em_meta_next(key)
end
em_next_word(key) click to toggle source
# File reline/line_editor.rb, line 2673
        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
Also aliased as: forward_word
em_set_mark(key) click to toggle source
# File reline/line_editor.rb, line 3282
        def em_set_mark(key)
  @mark_pointer = [@byte_pointer, @line_index]
end
Also aliased as: set_mark
em_upper_case(key) click to toggle source
# File reline/line_editor.rb, line 2776
        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
Also aliased as: upcase_word
em_yank(key) click to toggle source
# File reline/line_editor.rb, line 2639
        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
Also aliased as: yank
em_yank_pop(key) click to toggle source
# File reline/line_editor.rb, line 2651
        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
Also aliased as: yank_pop
generate_searcher() click to toggle source
# File reline/line_editor.rb, line 2077
        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
inclusive?(method_obj) click to toggle source
# File reline/line_editor.rb, line 1415
        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
incremental_search_history(key) click to toggle source
# File reline/line_editor.rb, line 2195
        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
insert_new_line(cursor_line, next_line) click to toggle source
# File reline/line_editor.rb, line 332
        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
key_delete(key) click to toggle source
# File reline/line_editor.rb, line 1891
        def key_delete(key)
  if @config.editing_mode_is?(:vi_insert)
    ed_delete_next_char(key)
  elsif @config.editing_mode_is?(:emacs)
    em_delete(key)
  end
end
key_newline(key) click to toggle source
# File reline/line_editor.rb, line 1899
        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
menu(target, list) click to toggle source
modify_lines(before, force_recalc: false) click to toggle source
# File reline/line_editor.rb, line 1185
        def modify_lines(before, force_recalc: false)
  return before if !force_recalc && (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
move_completed_list(list, direction) click to toggle source
# File reline/line_editor.rb, line 1327
        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
move_cursor_down(val) click to toggle source
# File reline/line_editor.rb, line 368
        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
move_cursor_up(val) click to toggle source
# File reline/line_editor.rb, line 359
        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
normal_char(key) click to toggle source
# File reline/line_editor.rb, line 1498
        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
      if @config.editing_mode_is?(:vi_command, :vi_insert)
        # split ESC + key in vi mode
        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)
      end
    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
padding_space_with_escape_sequences(str, width) click to toggle source
# File reline/line_editor.rb, line 658
        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
process_auto_indent() click to toggle source
# File reline/line_editor.rb, line 1643
        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
    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[@line_index - 1].bytesize + 1), false)
    if result
      new_indent = result
    end
    if new_indent&.>= 0
      @line = ' ' * new_indent + @line.lstrip
    end
  end
  new_lines = whole_lines
  new_indent = @auto_indent_proc.(new_lines, @line_index, @byte_pointer, @check_new_auto_indent)
  if new_indent&.>= 0
    md = new_lines[@line_index].match(/\A */)
    prev_indent = md[0].count(' ')
    if @check_new_auto_indent
      line = @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip
      @cursor = new_indent
      @cursor_max = calculate_width(line)
      @byte_pointer = new_indent
    else
      @line = ' ' * new_indent + @line.lstrip
      @cursor += new_indent - prev_indent
      @cursor_max = calculate_width(@line)
      @byte_pointer += new_indent - prev_indent
    end
  end
  @check_new_auto_indent = false
end
process_insert(force: false) click to toggle source
# File reline/line_editor.rb, line 1916
        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
process_key(key, method_symbol) click to toggle source
# File reline/line_editor.rb, line 1441
        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
range_subtract(base_ranges, subtract_ranges) click to toggle source
# File reline/line_editor.rb, line 665
        def range_subtract(base_ranges, subtract_ranges)
  indices = base_ranges.flat_map(&:to_a).uniq.sort - subtract_ranges.flat_map(&:to_a)
  chunks = indices.chunk_while { |a, b| a + 1 == b }
  chunks.map { |a| a.first...a.last + 1 }
end
render_dialog(cursor_column) click to toggle source
# File reline/line_editor.rb, line 649
        def render_dialog(cursor_column)
  changes = @dialogs.map do |dialog|
    old_dialog = dialog.dup
    update_each_dialog(dialog, cursor_column)
    [old_dialog, dialog]
  end
  render_dialog_changes(changes, cursor_column)
end
render_dialog_changes(changes, cursor_column) click to toggle source
# File reline/line_editor.rb, line 677
        def render_dialog_changes(changes, cursor_column)
  # Collect x-coordinate range and content of previous and current dialogs for each line
  old_dialog_ranges = {}
  new_dialog_ranges = {}
  new_dialog_contents = {}
  changes.each do |old_dialog, new_dialog|
    if old_dialog.contents
      x_range, y_range = dialog_range(old_dialog, @previous_rendered_dialog_y)
      y_range.each do |y|
        (old_dialog_ranges[y] ||= []) << x_range
      end
    end
    if new_dialog.contents
      x_range, y_range = dialog_range(new_dialog, @first_line_started_from + @started_from)
      y_range.each do |y|
        (new_dialog_ranges[y] ||= []) << x_range
        (new_dialog_contents[y] ||= []) << [x_range, new_dialog.contents[y - y_range.begin]]
      end
    end
  end
  return if old_dialog_ranges.empty? && new_dialog_ranges.empty?

  # Calculate x-coordinate ranges to restore text that was hidden behind dialogs for each line
  ranges_to_restore = {}
  subtract_cache = {}
  old_dialog_ranges.each do |y, old_x_ranges|
    new_x_ranges = new_dialog_ranges[y] || []
    ranges = subtract_cache[[old_x_ranges, new_x_ranges]] ||= range_subtract(old_x_ranges, new_x_ranges)
    ranges_to_restore[y] = ranges if ranges.any?
  end

  # Create visual_lines for restoring text hidden behind dialogs
  if ranges_to_restore.any?
    lines = whole_lines
    prompt, _prompt_width, prompt_list = check_multiline_prompt(lines, force_recalc: true)
    modified_lines = modify_lines(lines, force_recalc: true)
    visual_lines = []
    modified_lines.each_with_index { |l, i|
      pr = prompt_list ? prompt_list[i] : prompt
      vl, = split_by_width(pr + l, @screen_size.last)
      vl.compact!
      visual_lines.concat(vl)
    }
  end

  # Clear and rerender all dialogs line by line
  Reline::IOGate.hide_cursor
  ymin, ymax = (ranges_to_restore.keys + new_dialog_ranges.keys).minmax
  scroll_partial_screen = @scroll_partial_screen || 0
  screen_y_range = scroll_partial_screen..(scroll_partial_screen + @screen_height - 1)
  ymin = ymin.clamp(screen_y_range.begin, screen_y_range.end)
  ymax = ymax.clamp(screen_y_range.begin, screen_y_range.end)
  dialog_y = @first_line_started_from + @started_from
  cursor_y = dialog_y
  if @highest_in_all <= ymax
    scroll_down(ymax - cursor_y)
    move_cursor_up(ymax - cursor_y)
  end
  (ymin..ymax).each do |y|
    move_cursor_down(y - cursor_y)
    cursor_y = y
    new_x_ranges = new_dialog_ranges[y]
    restore_ranges = ranges_to_restore[y]
    # Restore text that was hidden behind dialogs
    if restore_ranges
      line = visual_lines[y] || ''
      restore_ranges.each do |range|
        col = range.begin
        width = range.end - range.begin
        s = padding_space_with_escape_sequences(Reline::Unicode.take_range(line, col, width), width)
        Reline::IOGate.move_cursor_column(col)
        @output.write "\e[0m#{s}\e[0m"
      end
      max_column = [calculate_width(line, true), new_x_ranges&.map(&:end)&.max || 0].max
      if max_column < restore_ranges.map(&:end).max
        Reline::IOGate.move_cursor_column(max_column)
        Reline::IOGate.erase_after_cursor
      end
    end
    # Render dialog contents
    new_dialog_contents[y]&.each do |x_range, content|
      Reline::IOGate.move_cursor_column(x_range.begin)
      @output.write "\e[0m#{content}\e[0m"
    end
  end
  move_cursor_up(cursor_y - dialog_y)
  Reline::IOGate.move_cursor_column(cursor_column)
  Reline::IOGate.show_cursor

  @previous_rendered_dialog_y = dialog_y
end
render_partial(prompt, prompt_width, line_to_render, this_started_from, with_control: true) click to toggle source
# File reline/line_editor.rb, line 1088
        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
render_whole_lines(lines, prompt, prompt_width) click to toggle source
# File reline/line_editor.rb, line 1062
        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
rerender_added_newline(prompt, prompt_width, prompt_list) click to toggle source
# File reline/line_editor.rb, line 911
        def rerender_added_newline(prompt, prompt_width, prompt_list)
  @buffer_of_lines[@previous_line_index] = @line
  @line = @buffer_of_lines[@line_index]
  @previous_line_index = nil
  if @in_pasting
    scroll_down(1)
  else
    lines = whole_lines
    prev_line_prompt = @prompt_proc ? prompt_list[@line_index - 1] : prompt
    prev_line_prompt_width = @prompt_proc ? calculate_width(prev_line_prompt, true) : prompt_width
    prev_line = modify_lines(lines)[@line_index - 1]
    move_cursor_up(@started_from)
    render_partial(prev_line_prompt, prev_line_prompt_width, prev_line, @first_line_started_from + @started_from, with_control: false)
    scroll_down(1)
    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
end
rerender_all_lines() click to toggle source
# File reline/line_editor.rb, line 1007
        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
rerender_changed_current_line() click to toggle source
# File reline/line_editor.rb, line 963
        def rerender_changed_current_line
  new_lines = whole_lines
  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
run_for_operators(key, method_symbol, &block) click to toggle source
# File reline/line_editor.rb, line 1373
        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
scroll_down(val) click to toggle source
# File reline/line_editor.rb, line 348
        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
search_next_char(key, arg, need_prev_char: false, inclusive: false) click to toggle source
# File reline/line_editor.rb, line 3171
        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
search_prev_char(key, arg, need_next_char = false) click to toggle source
# File reline/line_editor.rb, line 3228
        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
show_menu() click to toggle source
# File reline/line_editor.rb, line 1195
        def show_menu
  scroll_down(@highest_in_all - @first_line_started_from)
  @rerender_all = true
  @menu_info.list.sort!.each do |item|
    Reline::IOGate.move_cursor_column(0)
    @output.write item
    @output.flush
    scroll_down(1)
  end
  scroll_down(@highest_in_all - 1)
  move_cursor_up(@highest_in_all - 1 - @first_line_started_from)
end
split_by_width(str, max_width) click to toggle source
# File reline/line_editor.rb, line 344
        def split_by_width(str, max_width)
  Reline::Unicode.split_by_width(str, max_width, @encoding)
end
update_each_dialog(dialog, cursor_column) click to toggle source
# File reline/line_editor.rb, line 769
        def update_each_dialog(dialog, cursor_column)
  if @in_pasting
    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.contents = nil
    dialog.trap_key = nil
    return
  end
  contents = dialog_render_info.contents
  pointer = dialog.pointer
  if dialog_render_info.width
    dialog.width = dialog_render_info.width
  else
    dialog.width = contents.map { |l| calculate_width(l, true) }.max
  end
  height = dialog_render_info.height || DIALOG_DEFAULT_HEIGHT
  height = contents.size if contents.size < height
  if 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
    else
      dialog.scroll_top = 0
    end
    contents = contents[dialog.scroll_top, 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 * ((contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
    bar_height = MINIMUM_SCROLLBAR_HEIGHT if bar_height < MINIMUM_SCROLLBAR_HEIGHT
    scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
  else
    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 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
    dialog.vertical_offset = dialog_render_info.pos.y + 1
  end
  if dialog.column < 0
    dialog.column = 0
    dialog.width = @screen_size.last
  end
  dialog.contents = contents.map.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 - (scrollbar_pos.nil? ? 0 : @block_elem_width)
    str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
    colored_content = "\e[#{bg_color}m\e[#{fg_color}m#{str}"
    if scrollbar_pos
      color_seq = "\e[37m"
      if scrollbar_pos <= (i * 2) and (i * 2 + 1) < (scrollbar_pos + bar_height)
        colored_content + color_seq + @full_block
      elsif scrollbar_pos <= (i * 2) and (i * 2) < (scrollbar_pos + bar_height)
        colored_content + color_seq + @upper_half_block
      elsif scrollbar_pos <= (i * 2 + 1) and (i * 2) < (scrollbar_pos + bar_height)
        colored_content + color_seq + @lower_half_block
      else
        colored_content + color_seq + ' ' * @block_elem_width
      end
    else
      colored_content
    end
  end
end
vi_add(key) click to toggle source
# File reline/line_editor.rb, line 2814
        def vi_add(key)
  @config.editing_mode = :vi_insert
  ed_next_char(key)
end
vi_add_at_eol(key) click to toggle source
# File reline/line_editor.rb, line 2928
        def vi_add_at_eol(key)
  ed_move_to_end(key)
  @config.editing_mode = :vi_insert
end
vi_change_meta(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2954
        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
vi_command_mode(key) click to toggle source
# File reline/line_editor.rb, line 2819
        def vi_command_mode(key)
  ed_prev_char(key)
  @config.editing_mode = :vi_command
end
Also aliased as: vi_movement_mode
vi_delete_meta(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2972
        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
vi_delete_prev_char(key) click to toggle source
# File reline/line_editor.rb, line 2903
        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
vi_end_big_word(key, arg: 1, inclusive: false) click to toggle source
# File reline/line_editor.rb, line 2884
        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
vi_end_word(key, arg: 1, inclusive: false) click to toggle source
# File reline/line_editor.rb, line 2845
        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
vi_first_print(key) click to toggle source
# File reline/line_editor.rb, line 2053
        def vi_first_print(key)
  @byte_pointer, @cursor = Reline::Unicode.vi_first_print(@line)
end
vi_histedit(key) click to toggle source
# File reline/line_editor.rb, line 3057
        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
vi_insert(key) click to toggle source
# File reline/line_editor.rb, line 2810
        def vi_insert(key)
  @config.editing_mode = :vi_insert
end
vi_insert_at_bol(key) click to toggle source
# File reline/line_editor.rb, line 2923
        def vi_insert_at_bol(key)
  ed_move_to_beg(key)
  @config.editing_mode = :vi_insert
end
vi_join_lines(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 3268
        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
vi_kill_line_prev(key) click to toggle source
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 reline/line_editor.rb, line 2574
        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
Also aliased as: unix_line_discard
vi_list_or_eof(key) click to toggle source
# File reline/line_editor.rb, line 2999
        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
vi_next_big_word(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2864
        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
vi_next_char(key, arg: 1, inclusive: false) click to toggle source
# File reline/line_editor.rb, line 3163
        def vi_next_char(key, arg: 1, inclusive: false)
  @waiting_proc = ->(key_for_proc) { search_next_char(key_for_proc, arg, inclusive: inclusive) }
end
vi_next_word(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2825
        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
vi_paste_next(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 3091
        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
vi_paste_prev(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 3079
        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
vi_prev_big_word(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2874
        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
vi_prev_char(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 3220
        def vi_prev_char(key, arg: 1)
  @waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg) }
end
vi_prev_word(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2835
        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
vi_replace_char(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 3135
        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
vi_search_next(key) click to toggle source
# File reline/line_editor.rb, line 2287
        def vi_search_next(key)
  incremental_search_history(key)
end
Also aliased as: forward_search_history
vi_search_prev(key) click to toggle source
# File reline/line_editor.rb, line 2282
        def vi_search_prev(key)
  incremental_search_history(key)
end
Also aliased as: reverse_search_history
vi_to_column(key, arg: 0) click to toggle source
# File reline/line_editor.rb, line 3120
        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
vi_to_history_line(key) click to toggle source
# File reline/line_editor.rb, line 3034
        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
vi_to_next_char(key, arg: 1, inclusive: false) click to toggle source
# File reline/line_editor.rb, line 3167
        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
vi_to_prev_char(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 3224
        def vi_to_prev_char(key, arg: 1)
  @waiting_proc = ->(key_for_proc) { search_prev_char(key_for_proc, arg, true) }
end
vi_yank(key, arg: 1) click to toggle source
# File reline/line_editor.rb, line 2987
        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
vi_zero(key) click to toggle source
# File reline/line_editor.rb, line 2949
        def vi_zero(key)
  @byte_pointer = 0
  @cursor = 0
end