module RbReadline

Constants

ABORT_CHAR

Possible definitions for history starting point specification.

ANYOTHERKEY
AUDIBLE_BELL
BAD_MODIFIER
BAD_WORD_SPEC
BFIND
BTO
CapCase
DEFAULT_BUFFER_SIZE
DEFAULT_INPUTRC
DEFAULT_MAX_KILLS
DownCase
EOF
ESC
EVENT_NOT_FOUND

Possible history errors passed to hist_error.

FFIND
FTO

Definitions used when searching the line for characters. NOTE: it is necessary that opposite directions are inverses

HISTORY_APPEND

Possible definitions for what style of writing the history file we want.

HISTORY_OVERWRITE
HISTORY_QUOTE_CHARACTERS
HISTORY_WORD_DELIMITERS
ISFUNC
ISKMAP
ISMACR
KEYMAP_SIZE
KEY_EVENT
KSEQ_DISPATCHED

A context for reading key sequences longer than a single character when

using the callback interface.
KSEQ_RECURSIVE
KSEQ_SUBSEQ
LEFT_ALT_PRESSED
LEFT_CTRL_PRESSED
MB_FIND_ANY
MB_FIND_NONZERO
MB_LEN_MAX
MULT_MATCH
NEWLINE
NO_BELL
NO_MATCH

Possible values for do_replace argument to rl_filename_quoting_function,

called by rl_complete_internal.
NO_PREV_SUBST
NUM_READONE
NUM_SAWDIGITS
NUM_SAWMINUS

Callback data for reading numeric arguments

PAGE
RB_READLINE_VERSION
READERR

Input error; can be returned by (*rl_getc_function) if readline is reading

a top-level command (RL_ISSTATE (RL_STATE_READCMD)).
RETURN
RIGHT_ALT_PRESSED
RIGHT_CTRL_PRESSED
RL_IM_DEFAULT
RL_IM_INSERT
RL_IM_OVERWRITE
RL_LIBRARY_VERSION
RL_PROMPT_END_IGNORE
RL_PROMPT_START_IGNORE

Definitions available for use by readline clients.

RL_QF_BACKSLASH
RL_QF_DOUBLE_QUOTE
RL_QF_OTHER_QUOTE
RL_QF_SINGLE_QUOTE

Possible values for the found_quote flags word used by the completion

functions.  It says what kind of (shell-like) quoting we found anywhere
in the line.
RL_READLINE_VERSION
RL_SEARCH_CSEARCH
RL_SEARCH_ISEARCH
RL_SEARCH_NSEARCH
RL_STATE_CALLBACK
RL_STATE_COMPLETING
RL_STATE_DISPATCHING
RL_STATE_DONE
RL_STATE_INITIALIZED
RL_STATE_INITIALIZING
RL_STATE_INPUTPENDING
RL_STATE_ISEARCH
RL_STATE_MACRODEF
RL_STATE_MACROINPUT
RL_STATE_METANEXT
RL_STATE_MOREINPUT
RL_STATE_MULTIKEY
RL_STATE_NONE

Possible state values for rl_readline_state

RL_STATE_NSEARCH
RL_STATE_NUMERICARG
RL_STATE_OVERWRITE
RL_STATE_READCMD
RL_STATE_SIGHANDLER
RL_STATE_TERMPREPPED
RL_STATE_TTYCSAVED
RL_STATE_UNDOING
RL_STATE_VICMDONCE
RL_STATE_VIMOTION
RUBOUT
SF_FAILED
SF_FOUND
SF_REVERSE

search flags

SINGLE_MATCH
SPACE
STD_INPUT_HANDLE
STD_OUTPUT_HANDLE
SUBST_FAILED
SYS_INPUTRC
TAB
UNDO_END
UpCase
VISIBLE_BELL
VK_LMENU
VK_MENU
VK_RMENU
VK_SHIFT
XOK

Attributes

history_base[RW]
history_length[RW]
rl_attempted_completion_function[RW]
rl_attempted_completion_over[RW]
rl_basic_quote_characters[RW]
rl_basic_word_break_characters[RW]
rl_completer_quote_characters[RW]
rl_completer_word_break_characters[RW]
rl_completion_append_character[RW]
rl_deprep_term_function[RW]
rl_event_hook[RW]
rl_filename_quote_characters[RW]
rl_instream[RW]
rl_library_version[RW]
rl_outstream[RW]
rl_point[RW]
rl_readline_name[RW]
history_base[RW]
history_length[RW]
rl_attempted_completion_function[RW]
rl_attempted_completion_over[RW]
rl_basic_quote_characters[RW]
rl_basic_word_break_characters[RW]
rl_completer_quote_characters[RW]
rl_completer_word_break_characters[RW]
rl_completion_append_character[RW]
rl_deprep_term_function[RW]
rl_event_hook[RW]
rl_filename_quote_characters[RW]
rl_instream[RW]
rl_library_version[RW]
rl_outstream[RW]
rl_point[RW]
rl_readline_name[RW]

Public Instance Methods

__rl_fix_point(x) click to toggle source

Fix up point so that it is within the line boundaries after killing

text.  If FIX_MARK_TOO is non-zero, the mark is forced within line
boundaries also.
# File lib/rbreadline.rb, line 4991
def __rl_fix_point(x)
  if (x > @rl_end)
    @rl_end
  elsif (x < 0)
    0
  else
    x
  end
end
_extract_last_quote(string, quote_char) click to toggle source
# File lib/rbreadline.rb, line 7603
def _extract_last_quote(string, quote_char)
  quote_char = Regexp.escape(quote_char)
  string =~ /(#{quote_char}(?:\\.|[^#{quote_char}])+?#{quote_char}) *$/
  $1
end
_rl_abort_internal() click to toggle source

How to abort things.

# File lib/rbreadline.rb, line 4796
def _rl_abort_internal()
  rl_ding()
  rl_clear_message()
  _rl_reset_argument()
  rl_clear_pending_input()

  rl_unsetstate(RL_STATE_MACRODEF)

  @rl_last_func = nil
  #throw :readline_top_level
  send(@rl_redisplay_function)
  @_rl_want_redisplay = false
  0
end
_rl_adjust_point(string, point) click to toggle source

adjust pointed byte and find mbstate of the point of string.

adjusted point will be point <= adjusted_point, and returns
differences of the byte(adjusted_point - point).
if point is invalied (point < 0 || more than string length),
it returns -1
# File lib/rbreadline.rb, line 8616
def _rl_adjust_point(string, point)

  length = string.length
  return -1 if (point < 0)
  return -1 if (length < point)

  pos = 0

  case @encoding
  when 'E'
    x = string.scan(/./me)
    i, len = 0, x.length
    while (pos < point && i < len)
      pos += x[i].length
      i += 1
    end
  when 'S'
    x = string.scan(/./ms)
    i, len = 0, x.length
    while (pos < point && i < len)
      pos += x[i].length
      i += 1
    end
  when 'U'
    x = string.scan(/./mu)
    i, len = 0, x.length
    while (pos < point && i < len)
      pos += x[i].length
      i += 1
    end
  when 'X'
    enc = string.encoding
    str = string.force_encoding(@encoding_name)
    len = str.length
    if point <= length / 2
      # count byte size from head
      i = 0
      while (pos < point && i < len)
        pos += str[i].bytesize
        i += 1
      end
    else
      # count byte size from tail
      pos = str.bytesize
      i = len - 1
      while (pos > point && i >= 0)
        pos -= str[i].bytesize
        i -= 1
      end
      pos += str[i + 1].bytesize if pos < point
    end
    string.force_encoding(enc)
  else
    pos = point
  end
  pos - point
end
_rl_any_typein() click to toggle source
# File lib/rbreadline.rb, line 5561
def _rl_any_typein()
  return (@push_index != @pop_index)
end
_rl_arg_dispatch(cxt, c) click to toggle source

Process C as part of the current numeric argument. Return -1 if the

argument should be aborted, 0 if we should not read any more chars, and
1 if we should continue to read chars.
# File lib/rbreadline.rb, line 7806
def _rl_arg_dispatch(cxt, c)
  key = c

  # If we see a key bound to `universal-argument' after seeing digits,
  #    it ends the argument but is otherwise ignored.
  if (@_rl_keymap[c] == :rl_universal_argument)
    if ((cxt & NUM_SAWDIGITS) == 0)
      @rl_numeric_arg *= 4
      return 1
    elsif (rl_isstate(RL_STATE_CALLBACK))
      @_rl_argcxt |= NUM_READONE
      return 0 # XXX
    else
      rl_setstate(RL_STATE_MOREINPUT)
      key = rl_read_key()
      rl_unsetstate(RL_STATE_MOREINPUT)
      rl_restore_prompt()
      rl_clear_message()
      rl_unsetstate(RL_STATE_NUMERICARG)
      if key.is_a?(Integer) && key < 0
        return -1
      end
      return (_rl_dispatch(key, @_rl_keymap))
    end
  end

  #c = (c[0].ord & ~0x80).chr
  r = c[1,1]
  if (r>='0' && r<='9')
    r = r.to_i
    @rl_numeric_arg = @rl_explicit_arg ? (@rl_numeric_arg * 10) +  r : r
    @rl_explicit_arg = 1
    @_rl_argcxt |= NUM_SAWDIGITS
  elsif (c == '-' && !@rl_explicit_arg)
    @rl_numeric_arg = 1
    @_rl_argcxt |= NUM_SAWMINUS
    @rl_arg_sign = -1
  else
    # Make M-- command equivalent to M--1 command.
    if ((@_rl_argcxt & NUM_SAWMINUS)!=0 && @rl_numeric_arg == 1 && !@rl_explicit_arg)
      @rl_explicit_arg = 1
    end
    rl_restore_prompt()
    rl_clear_message()
    rl_unsetstate(RL_STATE_NUMERICARG)

    r = _rl_dispatch(key, @_rl_keymap)
    if (rl_isstate(RL_STATE_CALLBACK))
      # At worst, this will cause an extra redisplay.  Otherwise,
      #   we have to wait until the next character comes in.
      if (!@rl_done)
        send(@rl_redisplay_function)
      end
      r = 0
    end
    return r
  end
  1
end
_rl_arg_getchar() click to toggle source
# File lib/rbreadline.rb, line 7795
def _rl_arg_getchar()
  rl_message("(arg: #{@rl_arg_sign * @rl_numeric_arg}) ")
  rl_setstate(RL_STATE_MOREINPUT)
  c = rl_read_key()
  rl_unsetstate(RL_STATE_MOREINPUT)
  c
end
_rl_arg_init() click to toggle source
# File lib/rbreadline.rb, line 7789
def _rl_arg_init()
  rl_save_prompt()
  @_rl_argcxt = 0
  rl_setstate(RL_STATE_NUMERICARG)
end
_rl_arg_overflow() click to toggle source
# File lib/rbreadline.rb, line 7866
def _rl_arg_overflow()
  if (@rl_numeric_arg > 1000000)
    @_rl_argcxt = 0
    @rl_explicit_arg = @rl_numeric_arg = 0
    rl_ding()
    rl_restore_prompt()
    rl_clear_message()
    rl_unsetstate(RL_STATE_NUMERICARG)
    return 1
  end
  0
end
_rl_backspace(count) click to toggle source

Move the cursor back.

# File lib/rbreadline.rb, line 4681
def _rl_backspace(count)
  if (@_rl_term_backspace)
    @_rl_out_stream.write(@_rl_term_backspace * count)
  else
    @_rl_out_stream.write("\b"*count)
  end
  0
end
_rl_bind_tty_special_chars(kmap) click to toggle source
# File lib/rbreadline.rb, line 6992
def _rl_bind_tty_special_chars(kmap)
  kmap[@_rl_tty_chars.t_erase] = :rl_rubout
  kmap[@_rl_tty_chars.t_kill] = :rl_unix_line_discard
  kmap[@_rl_tty_chars.t_werase] = :rl_unix_word_rubout
  kmap[@_rl_tty_chars.t_lnext] = :rl_quoted_insert
end
_rl_char_search_internal(count, dir, smbchar, len) click to toggle source
# File lib/rbreadline.rb, line 7609
def _rl_char_search_internal(count, dir, smbchar, len)
  pos = @rl_point
  inc = (dir < 0) ? -1 : 1
  while (count!=0)
    if ((dir < 0 && pos <= 0) || (dir > 0 && pos >= @rl_end))
      rl_ding()
      return -1
    end
    pos = (inc > 0) ? _rl_find_next_mbchar(@rl_line_buffer, pos, 1, MB_FIND_ANY) :
      _rl_find_prev_mbchar(@rl_line_buffer, pos, MB_FIND_ANY)
    begin
      if (_rl_is_mbchar_matched(@rl_line_buffer, pos, @rl_end, smbchar, len)!=0)
        count-=1
        if (dir < 0)
          @rl_point = (dir == BTO) ? pos+1 : pos
        else
          @rl_point = (dir == FTO) ? pos-1 : pos
        end
        break
      end
      prepos = pos
    end while ((dir < 0) ? (pos = _rl_find_prev_mbchar(@rl_line_buffer, pos, MB_FIND_ANY)) != prepos :
               (pos = _rl_find_next_mbchar(@rl_line_buffer, pos, 1, MB_FIND_ANY)) != prepos)
  end
  0
end
_rl_char_value(buf,ind) click to toggle source
# File lib/rbreadline.rb, line 5203
def _rl_char_value(buf,ind)
  buf[ind,1]
end
_rl_clean_up_for_exit() click to toggle source
# File lib/rbreadline.rb, line 1518
def _rl_clean_up_for_exit()
  if @readline_echoing_p
    _rl_move_vert(@_rl_vis_botlin)
    @_rl_vis_botlin = 0
    @rl_outstream.flush
    rl_restart_output(1, 0)
  end
end
_rl_clear_screen() click to toggle source
# File lib/rbreadline.rb, line 4672
def _rl_clear_screen()
  if (@_rl_term_clrpag)
    @rl_outstream.write(@_rl_term_clrpag)
  else
    rl_crlf()
  end
end
_rl_clear_to_eol(count) click to toggle source

Clear to the end of the line. COUNT is the minimum

number of character spaces to clear,
# File lib/rbreadline.rb, line 4649
def _rl_clear_to_eol(count)
  if (@_rl_term_clreol)
    @rl_outstream.write(@_rl_term_clreol)
  elsif (count!=0)
    space_to_eol(count)
  end
end
_rl_col_width(string,start,_end) click to toggle source
# File lib/rbreadline.rb, line 3887
def _rl_col_width(string,start,_end)
  return 0 if _end <= start

  # Find the first occurance of 0.chr, which marks the end of the string.
  # Because newlines are also in the string as 0.chrs (they are tracked
  # seperately), we need to ignore any 0.chrs that lie before _end.
  index = string[_end...string.length].index(0.chr)

  str = index ? string[0,index+_end] : string
  width = 0

  case @encoding
  when 'N'
    return (_end - start)
  when 'U'
    str[start ... _end].scan(/./mu).each {|s| width += s.unpack('U').first >= 0x1000 ? 2 : 1 }
  when 'S'
    str[start ... _end].scan(/./ms).each {|s| width += s.length }
  when 'E'
    str[start ... _end].scan(/./me).each {|s| width += s.length }
  when 'X'
    str[start ... _end].force_encoding(@encoding_name).codepoints.each {|s| width += s > 0x1000 ? 2 : 1 }
  end
  width
end
_rl_compare_chars(buf1, pos1, buf2, pos2) click to toggle source

compare the specified two characters. If the characters matched,

return true. Otherwise return false.
# File lib/rbreadline.rb, line 8736
def _rl_compare_chars(buf1, pos1, buf2, pos2)
  return false if buf1[pos1].nil? || buf2[pos2].nil?
  case @encoding
  when 'E'
    buf1[pos1..-1].scan(/./me)[0] == buf2[pos2..-1].scan(/./me)[0]
  when 'S'
    buf1[pos1..-1].scan(/./ms)[0] == buf2[pos2..-1].scan(/./ms)[0]
  when 'U'
    buf1[pos1..-1].scan(/./mu)[0] == buf2[pos2..-1].scan(/./mu)[0]
  when 'X'
    buf1[pos1..-1].force_encoding(@encoding_name)[0] == buf2[pos2..-1].force_encoding(@encoding_name)[0]
  else
    buf1[pos1] == buf2[pos2]
  end
end
_rl_control_keypad(on) click to toggle source
# File lib/rbreadline.rb, line 7029
def _rl_control_keypad(on)
  if on && @_rl_term_ks
    @_rl_out_stream.write(@_rl_term_ks)
  elsif !on && @_rl_term_ke
    @_rl_out_stream.write(@_rl_term_ke)
  end
end
_rl_copy_to_kill_ring(text, append) click to toggle source

Add TEXT to the kill ring, allocating a new kill ring slot as necessary.

This uses TEXT directly, so the caller must not free it.  If APPEND is
non-zero, and the last command was a kill, the text is appended to the
current kill ring slot, otherwise prepended.
# File lib/rbreadline.rb, line 5934
def _rl_copy_to_kill_ring(text, append)
  # First, find the slot to work with.
  if (!@_rl_last_command_was_kill)
    # Get a new slot.
    if @rl_kill_ring.nil?
      # If we don't have any defined, then make one.
      @rl_kill_ring_length = 1
      @rl_kill_ring = Array.new(@rl_kill_ring_length+1)
      @rl_kill_ring[slot = 0] = nil
    else
      # We have to add a new slot on the end, unless we have
      #   exceeded the max limit for remembering kills.
      slot = @rl_kill_ring_length
      if (slot == @rl_max_kills)
        @rl_kill_ring[0,slot] = @rl_kill_ring[1,slot]
      else
        slot = @rl_kill_ring_length += 1
      end
      @rl_kill_ring[slot-=1] = nil
    end
  else
    slot = @rl_kill_ring_length - 1
  end

  # If the last command was a kill, prepend or append.
  if (@_rl_last_command_was_kill && @rl_editing_mode != @vi_mode)
    old = @rl_kill_ring[slot]

    if (append)
      new = old + text
    else
      new = text + old
    end
    old = nil
    text = nil
    @rl_kill_ring[slot] = new
  else
    @rl_kill_ring[slot] = text
  end

  @rl_kill_index = slot
  0
end
_rl_current_display_line() click to toggle source

return the ‘current display line’ of the cursor – the number of lines to

move up to get to the first screen line of the current readline line.
# File lib/rbreadline.rb, line 5317
def _rl_current_display_line()
  # Find out whether or not there might be invisible characters in the
  #   editing buffer.
  if (@rl_display_prompt == @rl_prompt)
    nleft = @_rl_last_c_pos - @_rl_screenwidth - @rl_visible_prompt_length
  else
    nleft = @_rl_last_c_pos - @_rl_screenwidth
  end

  if (nleft > 0)
    ret = 1 + nleft / @_rl_screenwidth
  else
    ret = 0
  end

  ret
end
_rl_dispatch(key, map) click to toggle source

Do the command associated with KEY in MAP.

If the associated command is really a keymap, then read
another key, and dispatch into that map.
# File lib/rbreadline.rb, line 4361
def _rl_dispatch(key, map)
  @_rl_dispatching_keymap = map
  return _rl_dispatch_subseq(key, map, false)
end
_rl_dispatch_subseq(key, map, got_subseq) click to toggle source
# File lib/rbreadline.rb, line 4367
def _rl_dispatch_subseq(key, map, got_subseq)
  func = map[key]
  if (func)
    @rl_executing_keymap = map

    @rl_dispatching = true
    rl_setstate(RL_STATE_DISPATCHING)
    send(map[key],@rl_numeric_arg * @rl_arg_sign, key)
    rl_unsetstate(RL_STATE_DISPATCHING)
    @rl_dispatching = false
    if (@rl_pending_input == 0 && map[key] != :rl_digit_argument)
      @rl_last_func = map[key]
    end
  else
    if(map.keys.detect{|x| x =~ /^#{Regexp.escape(key)}/})
      key += _rl_subseq_getchar(key)
      return _rl_dispatch_subseq(key,map,got_subseq)
    elsif(key.length>1 && key[1].ord < 0x7f)
      _rl_abort_internal()
      return -1
    else
      @rl_dispatching = true
      rl_setstate(RL_STATE_DISPATCHING)
      send(:rl_insert,@rl_numeric_arg * @rl_arg_sign, key)
      rl_unsetstate(RL_STATE_DISPATCHING)
      @rl_dispatching = false
    end
  end
  0
end
_rl_enable_meta_key() click to toggle source
# File lib/rbreadline.rb, line 2478
def _rl_enable_meta_key()
  if(@term_has_meta && @_rl_term_mm)
    @_rl_out_stream.write(@_rl_term_mm)
  end
end
_rl_erase_at_end_of_line(l) click to toggle source

Quick redisplay hack when erasing characters at the end of the line.

# File lib/rbreadline.rb, line 5862
def _rl_erase_at_end_of_line(l)
  _rl_backspace(l)
  @rl_outstream.write(' '*l)
  _rl_backspace(l)
  @_rl_last_c_pos -= l
  @visible_line[@_rl_last_c_pos,l] = 0.chr * l
  @rl_display_fixed = true if !@rl_display_fixed
end
_rl_erase_entire_line() click to toggle source
# File lib/rbreadline.rb, line 4707
def _rl_erase_entire_line()
  cr()
  _rl_clear_to_eol(0)
  cr()
  @rl_outstream.flush
end
_rl_find_completion_word() click to toggle source
# File lib/rbreadline.rb, line 6190
def _rl_find_completion_word()
  _end = @rl_point
  found_quote = 0
  delimiter = 0.chr
  quote_char = 0.chr

  brkchars = nil
  if @rl_completion_word_break_hook
    brkchars = send(@rl_completion_word_break_hook)
  end
  if brkchars.nil?
    brkchars = @rl_completer_word_break_characters
  end
  if (@rl_completer_quote_characters)
    # We have a list of characters which can be used in pairs to
    # quote substrings for the completer.  Try to find the start
    # of an unclosed quoted substring.
    # FOUND_QUOTE is set so we know what kind of quotes we found.
    scan = 0
    pass_next = false
    while scan < _end
      if !@rl_byte_oriented
        scan = _rl_find_next_mbchar(@rl_line_buffer, scan, 1, MB_FIND_ANY)
      else
        scan += 1
      end

      if (pass_next)
        pass_next = false
        next
      end

      # Shell-like semantics for single quotes -- don't allow backslash
      #   to quote anything in single quotes, especially not the closing
      #   quote.  If you don't like this, take out the check on the value
      #   of quote_char.
      if (quote_char != "'" && @rl_line_buffer[scan,1] == "\\")
        pass_next = true
        found_quote |= RL_QF_BACKSLASH
        next
      end

      if (quote_char != 0.chr)
        # Ignore everything until the matching close quote char.
        if (@rl_line_buffer[scan,1] == quote_char)
          # Found matching close.  Abandon this substring.
          quote_char = 0.chr
          @rl_point = _end
        end

      elsif (@rl_completer_quote_characters.include?(@rl_line_buffer[scan,1]))

        # Found start of a quoted substring.
        quote_char = @rl_line_buffer[scan,1]
        @rl_point = scan + 1
        # Shell-like quoting conventions.
        if (quote_char == "'")
          found_quote |= RL_QF_SINGLE_QUOTE
        elsif (quote_char == '"')
          found_quote |= RL_QF_DOUBLE_QUOTE
        else
          found_quote |= RL_QF_OTHER_QUOTE
        end
      end
    end
  end

  if (@rl_point == _end && quote_char == 0.chr)

    # We didn't find an unclosed quoted substring upon which to do
    #   completion, so use the word break characters to find the
    #   substring on which to complete.


    while (@rl_point =  !@rl_byte_oriented ?
           _rl_find_prev_mbchar(@rl_line_buffer, @rl_point, MB_FIND_ANY):(@rl_point-1))>0

      scan = @rl_line_buffer[@rl_point,1]
      if !brkchars.include?(scan)
        next
      end
      # Call the application-specific function to tell us whether
      #   this word break character is quoted and should be skipped.
      if (@rl_char_is_quoted_p && found_quote!=0 &&
          send(@rl_char_is_quoted_p,@rl_line_buffer, @rl_point))
        next
      end

      # Convoluted code, but it avoids an n^2 algorithm with calls
      #   to char_is_quoted.
      break
    end
  end

  # If we are at an unquoted word break, then advance past it.
  scan = @rl_line_buffer[@rl_point,1]

  # If there is an application-specific function to say whether or not
  #   a character is quoted and we found a quote character, let that
  #   function decide whether or not a character is a word break, even
  #   if it is found in rl_completer_word_break_characters.  Don't bother
  #   if we're at the end of the line, though.
  if (scan != 0.chr)
    if (@rl_char_is_quoted_p)
      isbrk = (found_quote == 0 ||
               !send(@rl_char_is_quoted_p,@rl_line_buffer, @rl_point)) &&
               brkchars.include?(scan)
    else
      isbrk = brkchars.include?(scan)
    end

    if (isbrk)
      # If the character that caused the word break was a quoting
      #   character, then remember it as the delimiter.
      if (@rl_basic_quote_characters &&
          @rl_basic_quote_characters.include?(scan) &&
          (_end - @rl_point) > 1)
        delimiter = scan
      end

      # If the character isn't needed to determine something special
      #   about what kind of completion to perform, then advance past it.
      if (@rl_special_prefixes.nil? || !@rl_special_prefixes.include?(scan) )
        @rl_point+=1
      end
    end
  end

  return [quote_char,found_quote!=0,delimiter]
end
_rl_find_next_mbchar(string, seed, count, flags) click to toggle source

Find next ‘count’ characters started byte point of the specified seed.

If flags is MB_FIND_NONZERO, we look for non-zero-width multibyte
characters.
# File lib/rbreadline.rb, line 8677
def _rl_find_next_mbchar(string, seed, count, flags)
  if @encoding == 'N'
    return (seed + count)
  end
  seed = 0 if seed < 0
  return seed if count <= 0

  point = seed + _rl_adjust_point(string,seed)
  if (seed < point)
    count -= 1
  end

  str = (flags == MB_FIND_NONZERO) ? string.sub(/\x00+$/,'') : string

  case @encoding
  when 'E'
    point += str[point..-1].scan(/./me)[0,count].to_s.length
  when 'S'
    point += str[point..-1].scan(/./ms)[0,count].to_s.length
  when 'U'
    point += str[point..-1].scan(/./mu)[0,count].to_s.length
  when 'X'
    point += str[point..-1].force_encoding(@encoding_name)[0,count].bytesize
  else
    point += count
    point = str.length if point >= str.length
  end
  point
end
_rl_find_prev_mbchar(string, seed, flags) click to toggle source

Find previous character started byte point of the specified seed.

Returned point will be point <= seed.  If flags is MB_FIND_NONZERO,
we look for non-zero-width multibyte characters.
# File lib/rbreadline.rb, line 8710
def _rl_find_prev_mbchar(string, seed, flags)
  if @encoding == 'N'
    return ((seed == 0) ? seed : seed - 1)
  end

  length = string.length
  if seed < 0
    return 0
  elsif length < seed
    return length
  end

  case @encoding
  when 'E'
    string[0,seed].scan(/./me)[0..-2].to_s.length
  when 'S'
    string[0,seed].scan(/./ms)[0..-2].to_s.length
  when 'U'
    string[0,seed].scan(/./mu)[0..-2].to_s.length
  when 'X'
    string[0,seed].force_encoding(@encoding_name)[0..-2].bytesize
  end
end
_rl_fix_point(fix_mark_too) click to toggle source
# File lib/rbreadline.rb, line 5001
def _rl_fix_point(fix_mark_too)
  @rl_point = __rl_fix_point(@rl_point)
  if (fix_mark_too)
    @rl_mark = __rl_fix_point(@rl_mark)
  end
end
_rl_get_char_len(src) click to toggle source

return the number of bytes parsed from the multibyte sequence starting at src, if a non-L’0‘ wide character was recognized. It returns 0, if a L’0‘ wide character was recognized. It returns (size_t)(-1), if an invalid multibyte sequence was encountered. It returns (size_t)(-2) if it couldn’t parse a complete multibyte character.

# File lib/rbreadline.rb, line 8757
def _rl_get_char_len(src)
  return 0 if src[0,1] == 0.chr || src.length==0
  case @encoding
  when 'E'
    len = src.scan(/./me)[0].to_s.length
  when 'S'
    len = src.scan(/./ms)[0].to_s.length
  when 'U'
    len = src.scan(/./mu)[0].to_s.length
  when 'X'
    src = src.dup.force_encoding(@encoding_name)
    len = src.valid_encoding? ? src[0].bytesize : 0
  else
    len = 1
  end
  len==0 ? -2 : len
end
_rl_get_screen_size(tty, ignore_env) click to toggle source

Get readline’s idea of the screen size. TTY is a file descriptor open

to the terminal.  If IGNORE_ENV is true, we do not pay attention to the
values of $LINES and $COLUMNS.  The tests for TERM_STRING_BUFFER being
non-null serve to check whether or not we have initialized termcap.
# File lib/rbreadline.rb, line 1859
def _rl_get_screen_size(tty, ignore_env)

  if @hConsoleHandle
    csbi = Fiddle::Pointer.malloc(24)
    @GetConsoleScreenBufferInfo.Call(@hConsoleHandle,csbi)
    wc,wr = csbi[0,4].unpack('SS')
    # wr,wc, = `mode con`.scan(/\d+\n/).map{|x| x.to_i}
    @_rl_screenwidth = wc
    @_rl_screenheight = wr
  else
    wr, wc = 0
    retry_if_interrupted do
      wr, wc = `stty size`.split(' ').map { |x| x.to_i }
    end
    @_rl_screenwidth = wc
    @_rl_screenheight = wr
    if ignore_env==0 && ENV['LINES']
      @_rl_screenheight = ENV['LINES'].to_i
    end
    if ignore_env==0 && ENV['COLUMNS']
      @_rl_screenwidth = ENV['COLUMNS'].to_i
    end
  end

  # If all else fails, default to 80x24 terminal.
  if @_rl_screenwidth.nil? || @_rl_screenwidth <= 1
    @_rl_screenwidth = 80
  end
  if @_rl_screenheight.nil? || @_rl_screenheight <= 0
    @_rl_screenheight = 24
  end
  # If we're being compiled as part of bash, set the environment
  #   variables $LINES and $COLUMNS to new values.  Otherwise, just
  #   do a pair of putenv () or setenv () calls.
  sh_set_lines_and_columns(@_rl_screenheight, @_rl_screenwidth)

  if !@_rl_term_autowrap
    @_rl_screenwidth-=1
  end
  @_rl_screenchars = @_rl_screenwidth * @_rl_screenheight
end
_rl_history_set_point() click to toggle source
# File lib/rbreadline.rb, line 5495
def _rl_history_set_point ()
  @rl_point = (@_rl_history_preserve_point && @_rl_history_saved_point != -1) ?
    @_rl_history_saved_point : @rl_end
  if (@rl_point > @rl_end)
    @rl_point = @rl_end
  end
  if (@rl_editing_mode == @vi_mode && @_rl_keymap != @vi_insertion_keymap)
    @rl_point = 0
  end
  if (@rl_editing_mode == @emacs_mode)
    @rl_mark = (@rl_point == @rl_end ? 0 : @rl_end)
  end
end
_rl_init_eightbit() click to toggle source
# File lib/rbreadline.rb, line 2079
def _rl_init_eightbit()

end
_rl_init_line_state() click to toggle source
# File lib/rbreadline.rb, line 2598
def _rl_init_line_state()
  @rl_point = @rl_end = @rl_mark = 0
  @rl_line_buffer = ""
end
_rl_init_terminal_io(terminal_name) click to toggle source
# File lib/rbreadline.rb, line 1971
def _rl_init_terminal_io(terminal_name)
  term = terminal_name ? terminal_name : ENV["TERM"]
  @_rl_term_clrpag = @_rl_term_cr = @_rl_term_clreol = nil
  tty = @rl_instream ? @rl_instream.fileno : 0

  if no_terminal?
    term = "dumb"
    @_rl_bind_stty_chars = false
  end

  @term_string_buffer ||= 0.chr * 2032

  @term_buffer ||= 0.chr * 4080

  buffer = @term_string_buffer

  tgetent_ret = (term != "dumb") ? 1 : -1

  if (tgetent_ret <= 0)
    buffer = @term_buffer = @term_string_buffer = nil

    @_rl_term_autowrap = false    # used by _rl_get_screen_size

    # Allow calling application to set default height and width, using
    #rl_set_screen_size
    if (@_rl_screenwidth <= 0 || @_rl_screenheight <= 0)
      _rl_get_screen_size(tty, 0)
    end

    # Defaults.
    if (@_rl_screenwidth <= 0 || @_rl_screenheight <= 0)
      @_rl_screenwidth = 79
      @_rl_screenheight = 24
    end

    # Everything below here is used by the redisplay code (tputs).
    @_rl_screenchars = @_rl_screenwidth * @_rl_screenheight
    @_rl_term_cr = "\r"
    @_rl_term_im = @_rl_term_ei = @_rl_term_ic = @_rl_term_IC = nil
    @_rl_term_up = @_rl_term_dc = @_rl_term_DC = @_rl_visible_bell = nil
    @_rl_term_ku = @_rl_term_kd = @_rl_term_kl = @_rl_term_kr = nil
    @_rl_term_kh = @_rl_term_kH = @_rl_term_kI = @_rl_term_kD = nil
    @_rl_term_ks = @_rl_term_ke = @_rl_term_at7 = nil
    @_rl_term_mm = @_rl_term_mo = nil
    @_rl_term_ve = @_rl_term_vs = nil
    @_rl_term_forward_char = nil
    @_rl_terminal_can_insert = @term_has_meta = false

    # Reasonable defaults for tgoto().  Readline currently only uses
    #   tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we
    #   change that later...
    @_rl_term_backspace = "\b"

    return 0
  end

  get_term_capabilities(buffer)

  @_rl_term_cr ||= "\r"
  @_rl_term_autowrap = !!(tgetflag("am") && tgetflag("xn"))

  # Allow calling application to set default height and width, using
  #   rl_set_screen_size
  if (@_rl_screenwidth <= 0 || @_rl_screenheight <= 0)
    _rl_get_screen_size(tty, 0)
  end

  # Check to see if this terminal has a meta key and clear the capability
  #   variables if there is none.
  @term_has_meta = !!(tgetflag("km") || tgetflag("MT"))
  if !@term_has_meta
    @_rl_term_mm = @_rl_term_mo = nil
  end

  # Attempt to find and bind the arrow keys.  Do not override already
  #   bound keys in an overzealous attempt, however.

  bind_termcap_arrow_keys(@emacs_standard_keymap)

  bind_termcap_arrow_keys(@vi_movement_keymap)
  bind_termcap_arrow_keys(@vi_insertion_keymap)

  return 0
end
_rl_input_available() click to toggle source
# File lib/rbreadline.rb, line 4060
def _rl_input_available
  IO.select([ $stdin ], nil, [ $stdin ], @_keyboard_input_timeout)
end
_rl_insert_char(count, c) click to toggle source

Insert the character C at the current location, moving point forward.

If C introduces a multibyte sequence, we read the whole sequence and
then insert the multibyte char into the line buffer.
# File lib/rbreadline.rb, line 5580
def _rl_insert_char(count, c)
  return 0 if (count <= 0)

  incoming = ''

  if @rl_byte_oriented
    incoming << c
    incoming_length = 1
  else
    @pending_bytes << c
    if _rl_get_char_len(@pending_bytes) == -2
      return 1
    else
      incoming = @pending_bytes
      @pending_bytes = ''
      incoming_length = incoming.length
    end
  end

  if(count>1)
    string = incoming * count
    rl_insert_text(string)
    string = nil
    return 0
  end

  if @rl_byte_oriented
    # We are inserting a single character.
    #If there is pending input, then make a string of all of the
    #pending characters that are bound to rl_insert, and insert
    #them all.
    if (_rl_any_typein())
      _rl_insert_typein(c)
    else
      rl_insert_text(c)
    end
  else
    rl_insert_text(incoming)
  end

  return 0
end
_rl_insert_next(count) click to toggle source

Insert the next typed character verbatim.

# File lib/rbreadline.rb, line 5658
def _rl_insert_next(count)
  rl_setstate(RL_STATE_MOREINPUT)
  c = rl_read_key()
  rl_unsetstate(RL_STATE_MOREINPUT)

  if c.is_a?(Integer) && c < 0
    return -1
  end

  _rl_insert_char(count, c)
end
_rl_insert_typein(c) click to toggle source
# File lib/rbreadline.rb, line 5565
def _rl_insert_typein(c)
  string = c

  while ((key = rl_get_char()) && @_rl_keymap[key] == :rl_insert)
    string << key
  end
  if (key)
    _rl_unget_char(key)
  end
  rl_insert_text(string)
end
_rl_internal_char_cleanup() click to toggle source
# File lib/rbreadline.rb, line 4714
def _rl_internal_char_cleanup()
  # In vi mode, when you exit insert mode, the cursor moves back
  #   over the previous character.  We explicitly check for that here.
  if (@rl_editing_mode == @vi_mode && @_rl_keymap == @vi_movement_keymap)
    rl_vi_check()
  end

  if (@rl_num_chars_to_read!=0 && @rl_end >= @rl_num_chars_to_read)
    send(@rl_redisplay_function)
    @_rl_want_redisplay = false
    rl_newline(1, "\n")
  end

  if (!@rl_done)
    send(@rl_redisplay_function)
    @_rl_want_redisplay = false
  end

  # If the application writer has told us to erase the entire line if
  #   the only character typed was something bound to rl_newline, do so.
  if (@rl_erase_empty_line && @rl_done && @rl_last_func == :rl_newline &&
      @rl_point == 0 && @rl_end == 0)
    _rl_erase_entire_line()
  end
end
_rl_internal_pager(lines) click to toggle source
# File lib/rbreadline.rb, line 6541
def _rl_internal_pager(lines)
  @rl_outstream.write("--More--")
  @rl_outstream.flush
  i = get_y_or_n(1)
  _rl_erase_entire_line()
  if (i == 0)
    return -1
  elsif (i == 2)
    return (lines - 1)
  else
    return 0
  end
end
_rl_is_mbchar_matched(string, seed, _end, mbchar, length) click to toggle source
# File lib/rbreadline.rb, line 8822
def _rl_is_mbchar_matched(string, seed, _end, mbchar, length)
  return 0 if ((_end - seed) < length)

  for i in 0 ... length
    if (string[seed + i] != mbchar[i])
      return 0
    end
  end
  1
end
_rl_isearch_cleanup(cxt, r) click to toggle source
# File lib/rbreadline.rb, line 4347
def _rl_isearch_cleanup(cxt, r)
  if (r >= 0)
    _rl_isearch_fini(cxt)
  end
  @_rl_iscxt = nil

  rl_unsetstate(RL_STATE_ISEARCH)

  r != 0
end
_rl_isearch_dispatch(cxt, c) click to toggle source

Process just-read character C according to isearch context CXT. Return

-1 if the caller should just free the context and return, 0 if we should
break out of the loop, and 1 if we should continue to read characters.
# File lib/rbreadline.rb, line 4067
def _rl_isearch_dispatch(cxt, c)
  f = nil

  if c.is_a?(Integer) && c < 0
    cxt.sflags |= SF_FAILED
    cxt.history_pos = cxt.last_found_line
    return -1
  end

  # Translate the keys we do something with to opcodes.
  if (c && @_rl_keymap[c])
    f = @_rl_keymap[c]
    if (f == :rl_reverse_search_history)
      cxt.lastc = (cxt.sflags & SF_REVERSE)!=0 ? -1 : -2
    elsif (f == :rl_forward_search_history)
      cxt.lastc = (cxt.sflags & SF_REVERSE)!=0 ? -2 : -1
    elsif (f == :rl_rubout)
      cxt.lastc = -3
    elsif (c == "\C-G")
      cxt.lastc = -4
    elsif (c == "\C-W")  # XXX
      cxt.lastc = -5
    elsif (c == "\C-Y")  # XXX
      cxt.lastc = -6
    end
  end

  # The characters in isearch_terminators (set from the user-settable
  #   variable isearch-terminators) are used to terminate the search but
  #   not subsequently execute the character as a command.  The default
  #   value is "\033\012" (ESC and C-J).
  if (cxt.lastc.class == String && cxt.search_terminators.include?(cxt.lastc))
    # ESC still terminates the search, but if there is pending
    #input or if input arrives within 0.1 seconds (on systems
    #with select(2)) it is used as a prefix character
    #with rl_execute_next.  WATCH OUT FOR THIS!  This is intended
    #to allow the arrow keys to be used like ^F and ^B are used
    #to terminate the search and execute the movement command.
    #XXX - since _rl_input_available depends on the application-
    #settable keyboard timeout value, this could alternatively
    #use _rl_input_queued(100000)
    if (cxt.lastc == ESC && _rl_input_available())
      rl_execute_next(ESC)
    end
    return (0)
  end

  if !@rl_byte_oriented
    if (cxt.lastc.class == String && (cxt.mb.length == 1) && endsrch_char(cxt.lastc))
      # This sets rl_pending_input to c; it will be picked up the next
      #   time rl_read_key is called.
      rl_execute_next(cxt.lastc)
      return (0)
    end
  elsif (cxt.lastc.class == String && endsrch_char(cxt.lastc))
    # This sets rl_pending_input to LASTC; it will be picked up the next
    #   time rl_read_key is called.
    rl_execute_next(cxt.lastc)
    return (0)
  end

  # Now dispatch on the character.  `Opcodes' affect the search string or
  #   state.  Other characters are added to the string.
  case (cxt.lastc)

    # search again
  when -1
    if (cxt.search_string_index == 0)
      if (@last_isearch_string)
        cxt.search_string_size = 64 + @last_isearch_string_len
        cxt.search_string = @last_isearch_string.dup
        cxt.search_string_index = @last_isearch_string_len
        rl_display_search(cxt.search_string, (cxt.sflags & SF_REVERSE)!=0, -1)
      else
        return (1)
      end
    elsif (cxt.sflags & SF_REVERSE)!=0
      cxt.sline_index-=1
    elsif (cxt.sline_index != cxt.sline_len)
      cxt.sline_index+=1
    else
      rl_ding()
    end

    # switch directions
  when -2
    cxt.direction = -cxt.direction
    if (cxt.direction < 0)
      cxt.sflags |= SF_REVERSE
    else
      cxt.sflags &= ~SF_REVERSE
    end
    # delete character from search string.
  when -3  # C-H, DEL
    # This is tricky.  To do this right, we need to keep a
    # stack of search positions for the current search, with
    # sentinels marking the beginning and end.  But this will
    # do until we have a real isearch-undo.
    if (cxt.search_string_index == 0)
      rl_ding()
    else
      cxt.search_string_index -= 1
      cxt.search_string.chop!
    end
  when -4  # C-G, abort
    rl_replace_line(cxt.lines[cxt.save_line], false)
    @rl_point = cxt.save_point
    @rl_mark = cxt.save_mark
    rl_restore_prompt()
    rl_clear_message()
    return -1
  when -5  # C-W
    # skip over portion of line we already matched and yank word
    wstart = @rl_point + cxt.search_string_index
    if (wstart >= @rl_end)
      rl_ding()
    else
      # if not in a word, move to one.
      cval = _rl_char_value(@rl_line_buffer, wstart)
      if (!_rl_walphabetic(cval))
        rl_ding()
      else
        if !@rl_byte_oriented
          n = _rl_find_next_mbchar(@rl_line_buffer, wstart, 1, MB_FIND_NONZERO)
        else
          n = wstart+1
        end
        while (n < @rl_end)
          cval = _rl_char_value(@rl_line_buffer, n)
          break if !_rl_walphabetic(cval)
          if !@rl_byte_oriented
            n = _rl_find_next_mbchar(@rl_line_buffer, n, 1, MB_FIND_NONZERO)
          else
            n = n+1
          end
        end
        wlen = n - wstart + 1
        if (cxt.search_string_index + wlen + 1 >= cxt.search_string_size)
          cxt.search_string_size += wlen + 1
        end
        cxt.search_string[cxt.search_string_index..-1] = @rl_line_buffer[wstart,wlen]
        cxt.search_string_index += wlen
      end
    end

  when -6  # C-Y
    # skip over portion of line we already matched and yank rest
    wstart = @rl_point + cxt.search_string_index
    if (wstart >= @rl_end)
      rl_ding()
    else
      n = @rl_end - wstart + 1
      if (cxt.search_string_index + n + 1 >= cxt.search_string_size)
        cxt.search_string_size += n + 1
      end
      cxt.search_string[cxt.search_string_index..-1] = @rl_line_buffer[wstart,n]
    end

    # Add character to search string and continue search.
  else
    if (cxt.search_string_index + 2 >= cxt.search_string_size)
      cxt.search_string_size += 128
    end
    if !@rl_byte_oriented
      for j in 0 ... cxt.mb.length
        cxt.search_string << cxt.mb[j,1]
        cxt.search_string_index += 1
      end
    else
      cxt.search_string << c
      cxt.search_string_index += 1
    end
  end

  while (cxt.sflags &= ~(SF_FOUND|SF_FAILED))!=0
    limit = cxt.sline_len - cxt.search_string_index + 1
    # Search the current line.
    while ((cxt.sflags & SF_REVERSE)!=0 ? (cxt.sline_index >= 0) : (cxt.sline_index < limit))

      if (cxt.search_string[0,cxt.search_string_index] == cxt.sline[cxt.sline_index,cxt.search_string_index])
        cxt.sflags |= SF_FOUND
        break
      else
        cxt.sline_index += cxt.direction
      end
    end
    break if (cxt.sflags & SF_FOUND)!=0

    # Move to the next line, but skip new copies of the line
    # we just found and lines shorter than the string we're
    # searching for.
    begin
      # Move to the next line.
      cxt.history_pos += cxt.direction

      # At limit for direction?
      if ((cxt.sflags & SF_REVERSE)!=0 ? (cxt.history_pos < 0) : (cxt.history_pos == cxt.hlen))
        cxt.sflags |= SF_FAILED
        break
      end

      # We will need these later.
      cxt.sline = cxt.lines[cxt.history_pos]
      cxt.sline_len = cxt.sline.length
    end while ((cxt.prev_line_found && cxt.prev_line_found == cxt.lines[cxt.history_pos]) ||
               (cxt.search_string_index > cxt.sline_len))

    break if (cxt.sflags & SF_FAILED)!=0

    # Now set up the line for searching...
    cxt.sline_index = (cxt.sflags & SF_REVERSE)!=0 ? cxt.sline_len - cxt.search_string_index : 0
  end

  if (cxt.sflags & SF_FAILED)!=0
    # We cannot find the search string.  Ding the bell.
    rl_ding()
    cxt.history_pos = cxt.last_found_line
    return 1
  end

  # We have found the search string.  Just display it.  But don't
  #   actually move there in the history list until the user accepts
  #   the location.
  if (cxt.sflags & SF_FOUND)!=0
    cxt.prev_line_found = cxt.lines[cxt.history_pos]
    rl_replace_line(cxt.lines[cxt.history_pos], false)
    @rl_point = cxt.sline_index
    cxt.last_found_line = cxt.history_pos
    rl_display_search(cxt.search_string, (cxt.sflags & SF_REVERSE)!=0, (cxt.history_pos == cxt.save_line) ? -1 : cxt.history_pos)
  end
  1
end
_rl_isearch_fini(cxt) click to toggle source
# File lib/rbreadline.rb, line 4311
def _rl_isearch_fini(cxt)
  # First put back the original state.
  @rl_line_buffer = cxt.lines[cxt.save_line].dup
  rl_restore_prompt()

  # Save the search string for possible later use.
  @last_isearch_string = cxt.search_string
  @last_isearch_string_len = cxt.search_string_index
  cxt.search_string = nil

  if (cxt.last_found_line < cxt.save_line)
    rl_get_previous_history(cxt.save_line - cxt.last_found_line, 0)
  else
    rl_get_next_history(cxt.last_found_line - cxt.save_line, 0)
  end

  # If the string was not found, put point at the end of the last matching
  #   line.  If last_found_line == orig_line, we didn't find any matching
  #   history lines at all, so put point back in its original position.
  if (cxt.sline_index < 0)

    if (cxt.last_found_line == cxt.save_line)
      cxt.sline_index = cxt.save_point
    else
      cxt.sline_index = @rl_line_buffer.delete(0.chr).length
    end
    @rl_mark = cxt.save_mark
  end

  @rl_point = cxt.sline_index
  # Don't worry about where to put the mark here; rl_get_previous_history
  #   and rl_get_next_history take care of it.
  rl_clear_message()
end
_rl_isearch_init(direction) click to toggle source
# File lib/rbreadline.rb, line 7269
def _rl_isearch_init(direction)
  cxt = _rl_scxt_alloc(RL_SEARCH_ISEARCH, 0)
  if (direction < 0)
    cxt.sflags |= SF_REVERSE
  end

  cxt.search_terminators = @_rl_isearch_terminators ? @_rl_isearch_terminators :
    @default_isearch_terminators

  # Create an arrary of pointers to the lines that we want to search.
  hlist = history_list()
  rl_maybe_replace_line()
  i = 0
  if (hlist)
    i += 1 while(hlist[i])
  end

  # Allocate space for this many lines, +1 for the current input line,
  #   and remember those lines.
  cxt.hlen = i
  cxt.lines = []
  for i in 0 ... cxt.hlen
    cxt.lines[i] = hlist[i].line
  end

  if (@_rl_saved_line_for_history)
    cxt.lines[i] = @_rl_saved_line_for_history.line.dup
  else
    # Keep track of this so we can free it.
    cxt.allocated_line = @rl_line_buffer.dup
    cxt.lines << cxt.allocated_line
  end

  cxt.hlen+=1

  # The line where we start the search.
  cxt.history_pos = cxt.save_line

  rl_save_prompt()

  # Initialize search parameters.
  cxt.search_string_size = 128
  cxt.search_string_index = 0
  cxt.search_string = ""

  # Normalize DIRECTION into 1 or -1.
  cxt.direction = (direction >= 0) ? 1 : -1

  cxt.sline = @rl_line_buffer
  cxt.sline_len = cxt.sline.delete(0.chr).length
  cxt.sline_index = @rl_point

  @_rl_iscxt = cxt     # save globally
  cxt
end
_rl_move_cursor_relative(new, data, start=0) click to toggle source

Move the cursor from _rl_last_c_pos to NEW, which are buffer indices.

(Well, when we don't have multibyte characters, _rl_last_c_pos is a
buffer index.)
DATA is the contents of the screen line of interest; i.e., where
the movement is being done.
# File lib/rbreadline.rb, line 1532
def _rl_move_cursor_relative(new, data, start=0)
  woff = w_offset(@_rl_last_v_pos, @wrap_offset)
  cpos = @_rl_last_c_pos

  if !@rl_byte_oriented
    dpos = _rl_col_width(data, start, start+new)

    # Use NEW when comparing against the last invisible character in the
    # prompt string, since they're both buffer indices and DPOS is a desired
    # display position.
    if (new > @prompt_last_invisible)     # XXX - don't use woff here
      dpos -= woff
      # Since this will be assigned to _rl_last_c_pos at the end (more
      #   precisely, _rl_last_c_pos == dpos when this function returns),
      #   let the caller know.
      @cpos_adjusted = true
    end
  else
    dpos = new
  end
  # If we don't have to do anything, then return.
  if (cpos == dpos)
    return
  end

  if @hConsoleHandle
    csbi = Fiddle::Pointer.malloc(24)
    @GetConsoleScreenBufferInfo.Call(@hConsoleHandle,csbi)
    x,y = csbi[4,4].unpack('SS')
    x = dpos
    @SetConsoleCursorPosition.Call(@hConsoleHandle,y*65536+x)
    @_rl_last_c_pos = dpos
    return
  end

  # It may be faster to output a CR, and then move forwards instead
  #   of moving backwards.
  # i == current physical cursor position.
  if !@rl_byte_oriented
    i = @_rl_last_c_pos
  else
    i = @_rl_last_c_pos - woff
  end

  if (dpos == 0 || cr_faster(dpos, @_rl_last_c_pos) ||
      (@_rl_term_autowrap && i == @_rl_screenwidth))
    @rl_outstream.write(@_rl_term_cr)
    cpos = @_rl_last_c_pos = 0
  end

  if (cpos < dpos)
    # Move the cursor forward.  We do it by printing the command
    # to move the cursor forward if there is one, else print that
    # portion of the output buffer again.  Which is cheaper?

    # The above comment is left here for posterity.  It is faster
    # to print one character (non-control) than to print a control
    # sequence telling the terminal to move forward one character.
    # That kind of control is for people who don't know what the
    # data is underneath the cursor.

    # However, we need a handle on where the current display position is
    # in the buffer for the immediately preceding comment to be true.
    # In multibyte locales, we don't currently have that info available.
    # Without it, we don't know where the data we have to display begins
    # in the buffer and we have to go back to the beginning of the screen
    # line.  In this case, we can use the terminal sequence to move forward
    # if it's available.
    if !@rl_byte_oriented
      if (@_rl_term_forward_char)
        @rl_outstream.write(@_rl_term_forward_char * (dpos-cpos))
      else
        @rl_outstream.write(@_rl_term_cr)
        @rl_outstream.write(data[start,new])
      end
    else
      @rl_outstream.write(data[start+cpos,new-cpos])
    end
  elsif (cpos > dpos)
    _rl_backspace(cpos - dpos)
  end
  @_rl_last_c_pos = dpos
end
_rl_move_vert(to) click to toggle source

PWP: move the cursor up or down.

# File lib/rbreadline.rb, line 1618
def _rl_move_vert(to)
  if (@_rl_last_v_pos == to || to > @_rl_screenheight)
    return
  end

  if ((delta = to - @_rl_last_v_pos) > 0)
    @rl_outstream.write("\n"*delta)
    @rl_outstream.write("\r")
    @_rl_last_c_pos = 0
  else
    if(@_rl_term_up)
      @rl_outstream.write(@_rl_term_up*(-delta))
    end
  end
  @_rl_last_v_pos = to        # Now TO is here
end
_rl_nsearch_abort(cxt) click to toggle source
# File lib/rbreadline.rb, line 8228
def _rl_nsearch_abort(cxt)
  rl_maybe_unsave_line()
  rl_clear_message()
  @rl_point = cxt.save_point
  @rl_mark = cxt.save_mark
  rl_restore_prompt()
  rl_unsetstate(RL_STATE_NSEARCH)
end
_rl_nsearch_cleanup(cxt, r) click to toggle source
# File lib/rbreadline.rb, line 8221
def _rl_nsearch_cleanup(cxt, r)
  cxt = nil
  @_rl_nscxt = nil
  rl_unsetstate(RL_STATE_NSEARCH)
  r != 1
end
_rl_nsearch_dispatch(cxt, c) click to toggle source

Process just-read character C according to search context CXT. Return -1

if the caller should abort the search, 0 if we should break out of the
loop, and 1 if we should continue to read characters.
# File lib/rbreadline.rb, line 8240
def _rl_nsearch_dispatch(cxt, c)
  case (c)
  when "\C-W"
    rl_unix_word_rubout(1, c)
  when "\C-U"
    rl_unix_line_discard(1, c)
  when RETURN,NEWLINE
    return 0
  when "\C-H",RUBOUT
    if (@rl_point == 0)
      _rl_nsearch_abort(cxt)
      return -1
    end
    _rl_rubout_char(1, c)
  when "\C-C","\C-G"
    rl_ding()
    _rl_nsearch_abort(cxt)
    return -1
  else
    if !@rl_byte_oriented
      rl_insert_text(cxt.mb)
    else
      _rl_insert_char(1, c)
    end
  end

  send(@rl_redisplay_function)
  1
end
_rl_nsearch_dosearch(cxt) click to toggle source

Perform one search according to CXT, using NONINC_SEARCH_STRING. Return

-1 if the search should be aborted, any other value means to clean up
using _rl_nsearch_cleanup ().  Returns 1 if the search was successful,
0 otherwise.
# File lib/rbreadline.rb, line 8274
def _rl_nsearch_dosearch(cxt)
  @rl_mark = cxt.save_mark

  # If rl_point == 0, we want to re-use the previous search string and
  #   start from the saved history position.  If there's no previous search
  #   string, punt.
  if (@rl_point == 0)
    if @noninc_search_string.nil?
      rl_ding()
      rl_restore_prompt()
      rl_unsetstate(RL_STATE_NSEARCH)
      return -1
    end
  else
    # We want to start the search from the current history position.
    @noninc_history_pos = cxt.save_line
    @noninc_search_string = @rl_line_buffer.dup

    # If we don't want the subsequent undo list generated by the search
    #matching a history line to include the contents of the search string,
    #we need to clear rl_line_buffer here.  For now, we just clear the
    #undo list generated by reading the search string.  (If the search
    #fails, the old undo list will be restored by rl_maybe_unsave_line.)
    rl_free_undo_list()
  end

  rl_restore_prompt()
  noninc_dosearch(@noninc_search_string, cxt.direction)
end
_rl_nsearch_init(dir, pchar) click to toggle source
# File lib/rbreadline.rb, line 8195
def _rl_nsearch_init(dir, pchar)
  cxt = _rl_scxt_alloc(RL_SEARCH_NSEARCH, 0)
  if (dir < 0)
    cxt.sflags |= SF_REVERSE      # not strictly needed
  end
  cxt.direction = dir
  cxt.history_pos = cxt.save_line
  rl_maybe_save_line()
  # Clear the undo list, since reading the search string should create its
  #   own undo list, and the whole list will end up being freed when we
  #   finish reading the search string.
  @rl_undo_list = nil

  # Use the line buffer to read the search string.
  @rl_line_buffer[0,1] = 0.chr
  @rl_end = @rl_point = 0

  _p = _rl_make_prompt_for_search(pchar ? pchar : ':')
  rl_message(_p)
  _p = nil

  rl_setstate(RL_STATE_NSEARCH)
  @_rl_nscxt = cxt
  cxt
end
_rl_output_some_chars(string,start,count) click to toggle source

Write COUNT characters from STRING to the output stream.

# File lib/rbreadline.rb, line 3914
def _rl_output_some_chars(string,start,count)
  case @encoding
  when 'X'
    @_rl_out_stream.write(string[start, count].force_encoding(@encoding_name))
  else
    @_rl_out_stream.write(string[start, count])
  end
end
_rl_overwrite_char(count, c) click to toggle source

Overwrite the character at point (or next COUNT characters) with C.

If C introduces a multibyte character sequence, read the entire sequence
before starting the overwrite loop.
# File lib/rbreadline.rb, line 5626
def _rl_overwrite_char(count, c)

  # Read an entire multibyte character sequence to insert COUNT times.
  if (count > 0 && !@rl_byte_oriented)
    mbkey = ''
    _rl_read_mbstring(c, mbkey, MB_LEN_MAX)
  end
  rl_begin_undo_group()

  count.times do
    if !@rl_byte_oriented
      rl_insert_text(mbkey)
    else
      _rl_insert_char(1, c)
    end
    if (@rl_point < @rl_end)
      rl_delete(1, c)
    end
  end

  rl_end_undo_group()

  return 0
end
_rl_overwrite_rubout(count, key) click to toggle source

This is different from what vi does, so the code’s not shared. Emacs

rubout in overwrite mode has one oddity:  it replaces a control
character that's displayed as two characters (^X) with two spaces.
# File lib/rbreadline.rb, line 5810
def _rl_overwrite_rubout(count, key)
  if (@rl_point == 0)
    rl_ding()
    return 1
  end

  opoint = @rl_point

  # L == number of spaces to insert
  l = 0
  count.times do
    rl_backward_char(1, key)
    l += rl_character_len(@rl_line_buffer[@rl_point,1], @rl_point) # not exactly right
  end

  rl_begin_undo_group()

  if (count > 1 || @rl_explicit_arg)
    rl_kill_text(opoint, @rl_point)
  else
    rl_delete_text(opoint, @rl_point)
  end
  # Emacs puts point at the beginning of the sequence of spaces.
  if (@rl_point < @rl_end)
    opoint = @rl_point
    _rl_insert_char(l, ' ')
    @rl_point = opoint
  end

  rl_end_undo_group()

  0
end
_rl_read_init_file(filename, include_level) click to toggle source
# File lib/rbreadline.rb, line 2112
def _rl_read_init_file(filename, include_level)
  @current_readline_init_file = filename
  @current_readline_init_include_level = include_level

  openname = File.expand_path(filename)
  begin
    buffer = nil
    File.open(openname) do |file|
      buffer = file.read
    end
  rescue
    return -1
  end

  if (include_level == 0 && filename != @last_readline_init_file)
    @last_readline_init_file = filename.dup
  end

  @currently_reading_init_file = true

  # Loop over the lines in the file.  Lines that start with `#' are
  #   comments; all other lines are commands for readline initialization.
  @current_readline_init_lineno = 1

  buffer.each_line do |line|
    line.strip!
    next if line =~ /^#/
    next if line == ''
    rl_parse_and_bind(line)
  end

  return 0
end
_rl_read_mbchar(mbchar, size) click to toggle source

read multibyte char

# File lib/rbreadline.rb, line 8776
def _rl_read_mbchar(mbchar, size)
  mb_len = 0
  while (mb_len < size)
    rl_setstate(RL_STATE_MOREINPUT)
    c = rl_read_key()
    rl_unsetstate(RL_STATE_MOREINPUT)

    break if c.is_a?(Integer) && c < 0

    mbchar << c
    mb_len += 1
    case @encoding
    when 'E'
      break unless mbchar.scan(/./me).empty?
    when 'S'
      break unless mbchar.scan(/./ms).empty?
    when 'U'
      break unless mbchar.scan(/./mu).empty?
    when 'X'
      break if mbchar.dup.force_encoding(@encoding_name).valid_encoding?
    end
  end
  mb_len
end
_rl_read_mbstring(first, mb, mlen) click to toggle source

Read a multibyte-character string whose first character is FIRST into

the buffer MB of length MLEN.  Returns the last character read, which
may be FIRST.  Used by the search functions, among others.  Very similar
to _rl_read_mbchar.
# File lib/rbreadline.rb, line 8805
def _rl_read_mbstring(first, mb, mlen)
  c = first
  (0...mlen).each do
    mb << c
    if _rl_get_char_len(mb) == -2
      # Read more for multibyte character
      rl_setstate(RL_STATE_MOREINPUT)
      c = rl_read_key()
      break if c.is_a?(Integer) && c < 0
      rl_unsetstate(RL_STATE_MOREINPUT)
    else
      break
    end
  end
  c
end
_rl_redisplay_after_sigwinch() click to toggle source

Redisplay the current line after a SIGWINCH is received.

# File lib/rbreadline.rb, line 8853
def _rl_redisplay_after_sigwinch()
  # Clear the current line and put the cursor at column 0.  Make sure
  #   the right thing happens if we have wrapped to a new screen line.
  if @_rl_term_cr
    @rl_outstream.write(@_rl_term_cr)
    @_rl_last_c_pos = 0
    if @_rl_term_clreol
      @rl_outstream.write(@_rl_term_clreol)
    else
      space_to_eol(@_rl_screenwidth)
      @rl_outstream.write(@_rl_term_cr)
    end

    if @_rl_last_v_pos > 0
      _rl_move_vert(0)
    end
  else
    rl_crlf()
  end

  # Redraw only the last line of a multi-line prompt.
  t = @rl_display_prompt.index("\n")
  if t
    redraw_prompt(@rl_display_prompt[(t+1)..-1])
  else
    rl_forced_update_display()
  end
end
_rl_replace_text(text, start, _end) click to toggle source

Replace the contents of the line buffer between START and END with

TEXT.  The operation is undoable.  To replace the entire line in an
undoable mode, use _rl_replace_text(text, 0, rl_end)
# File lib/rbreadline.rb, line 5030
def _rl_replace_text(text, start, _end)
  rl_begin_undo_group()
  rl_delete_text(start, _end + 1)
  @rl_point = start
  n = rl_insert_text(text)
  rl_end_undo_group()
  n
end
_rl_reset_argument() click to toggle source

Create a default argument.

# File lib/rbreadline.rb, line 4017
def _rl_reset_argument()
  @rl_numeric_arg = @rl_arg_sign = 1
  @rl_explicit_arg = false
  @_rl_argcxt = 0
end
_rl_rubout_char(count, key) click to toggle source
# File lib/rbreadline.rb, line 5871
def _rl_rubout_char(count, key)
  # Duplicated code because this is called from other parts of the library.
  if (count < 0)
    return (rl_delete(-count, key))
  end
  if (@rl_point == 0)
    rl_ding()
    return -1
  end

  orig_point = @rl_point
  if (count > 1 || @rl_explicit_arg)
    rl_backward_char(count, key)
    rl_kill_text(orig_point, @rl_point)
  elsif (@rl_byte_oriented)
    c = @rl_line_buffer[@rl_point-=1,1]
    rl_delete_text(@rl_point, orig_point)
    # The erase-at-end-of-line hack is of questionable merit now.
    if (@rl_point == @rl_end && isprint(c) && @_rl_last_c_pos!=0)
      l = rl_character_len(c, @rl_point)
      _rl_erase_at_end_of_line(l)
    end
  else
    @rl_point = _rl_find_prev_mbchar(@rl_line_buffer, @rl_point, MB_FIND_NONZERO)
    rl_delete_text(@rl_point, orig_point)
  end

  0
end
_rl_scxt_alloc(type, flags) click to toggle source
# File lib/rbreadline.rb, line 7229
def _rl_scxt_alloc(type, flags)
  cxt = Struct.new(:type,:sflags,:search_string,:search_string_index,:search_string_size,:lines,:allocated_line,
                   :hlen,:hindex,:save_point,:save_mark,:save_line,:last_found_line,:prev_line_found,:save_undo_list,:history_pos,
                   :direction,:lastc,:sline,:sline_len,:sline_index,:search_terminators,:mb).new

  cxt.type = type
  cxt.sflags = flags

  cxt.search_string = nil
  cxt.search_string_size = cxt.search_string_index = 0

  cxt.lines = nil
  cxt.allocated_line = nil
  cxt.hlen = cxt.hindex = 0

  cxt.save_point = @rl_point
  cxt.save_mark = @rl_mark
  cxt.save_line = where_history()
  cxt.last_found_line = cxt.save_line
  cxt.prev_line_found = nil

  cxt.save_undo_list = nil

  cxt.history_pos = 0
  cxt.direction = 0

  cxt.lastc = 0

  cxt.sline = nil
  cxt.sline_len = cxt.sline_index = 0

  cxt.search_terminators = nil

  cxt
end
_rl_search_getchar(cxt) click to toggle source
# File lib/rbreadline.rb, line 4044
def _rl_search_getchar(cxt)
  # Read a key and decide how to proceed.
  rl_setstate(RL_STATE_MOREINPUT)
  c = cxt.lastc = rl_read_key()
  rl_unsetstate(RL_STATE_MOREINPUT)
  if !@rl_byte_oriented
    cxt.mb = ""
    c = cxt.lastc = _rl_read_mbstring(cxt.lastc, cxt.mb, MB_LEN_MAX)
  end
  c
end
_rl_set_insert_mode(im, force) click to toggle source

Function for the rest of the library to use to set insert/overwrite mode.

# File lib/rbreadline.rb, line 1449
def _rl_set_insert_mode(im, force)
  @rl_insert_mode = im
end
_rl_set_mark_at_pos(position) click to toggle source

Set the mark at POSITION.

# File lib/rbreadline.rb, line 7124
def _rl_set_mark_at_pos(position)
  return -1 if (position > @rl_end)
  @rl_mark = position
  0
end
_rl_start_using_history() click to toggle source

Set the history pointer back to the last entry in the history.

# File lib/rbreadline.rb, line 2604
def _rl_start_using_history()
  using_history()
  @_rl_saved_line_for_history = nil
end
_rl_strip_prompt(pmt) click to toggle source
# File lib/rbreadline.rb, line 3883
def _rl_strip_prompt(pmt)
  return expand_prompt(pmt).first
end
_rl_subseq_getchar(key) click to toggle source
# File lib/rbreadline.rb, line 4633
def _rl_subseq_getchar(key)
  if (key == ESC)
    rl_setstate(RL_STATE_METANEXT)
  end
  rl_setstate(RL_STATE_MOREINPUT)
  k = rl_read_key()
  rl_unsetstate(RL_STATE_MOREINPUT)
  if (key == ESC)
    rl_unsetstate(RL_STATE_METANEXT)
  end

  return k
end
_rl_to_lower(char) click to toggle source
# File lib/rbreadline.rb, line 1312
def _rl_to_lower(char)
  char.nil? ? nil : char.chr.downcase
end
_rl_unget_char(key) click to toggle source

Stuff KEY into the front of the input buffer.

Returns non-zero if successful, zero if there is
no space left in the buffer.
# File lib/rbreadline.rb, line 4621
def _rl_unget_char(key)
  if (ibuffer_space()!=0)
    @pop_index-=1
    if (@pop_index < 0)
      @pop_index = @ibuffer_len - 1
    end
    @ibuffer[@pop_index] = key
    return (1)
  end
  return (0)
end
_rl_update_final() click to toggle source
# File lib/rbreadline.rb, line 5732
def _rl_update_final()
  full_lines = false
  # If the cursor is the only thing on an otherwise-blank last line,
  #   compensate so we don't print an extra CRLF.
  if (@_rl_vis_botlin && @_rl_last_c_pos == 0 &&
      @visible_line[@vis_lbreaks[@_rl_vis_botlin],1] == 0.chr )
    @_rl_vis_botlin-=1
    full_lines = true
  end
  _rl_move_vert(@_rl_vis_botlin)
  # If we've wrapped lines, remove the final xterm line-wrap flag.
  if (full_lines && @_rl_term_autowrap && (vis_llen(@_rl_vis_botlin) == @_rl_screenwidth))
    last_line = @visible_line[@vis_lbreaks[@_rl_vis_botlin]..-1]
    @cpos_buffer_position = -1 # don't know where we are in buffer
    _rl_move_cursor_relative(@_rl_screenwidth - 1, last_line)   # XXX
    _rl_clear_to_eol(0)
    @rl_outstream.write(last_line[@_rl_screenwidth - 1,1])
  end
  @_rl_vis_botlin = 0
  rl_crlf()
  @rl_outstream.flush
  @rl_display_fixed = true if !@rl_display_fixed
end
_rl_vi_done_inserting() click to toggle source
# File lib/rbreadline.rb, line 5692
def _rl_vi_done_inserting()
  if (@_rl_vi_doing_insert)

    # The `C', `s', and `S' commands set this.
    rl_end_undo_group()
    # Now, the text between rl_undo_list->next->start and
    # rl_undo_list->next->end is what was inserted while in insert
    # mode.  It gets copied to VI_INSERT_BUFFER because it depends
    # on absolute indices into the line which may change (though they
    # probably will not).
    @_rl_vi_doing_insert = 0
    _rl_vi_save_insert(@rl_undo_list.next)
    @vi_continued_command = 1
  else
    if ((@_rl_vi_last_key_before_insert == 'i' || @_rl_vi_last_key_before_insert == 'a') && @rl_undo_list)
      _rl_vi_save_insert(@rl_undo_list)

      # XXX - Other keys probably need to be checked.
    elsif (@_rl_vi_last_key_before_insert == 'C')
      rl_end_undo_group()
    end
    while (@_rl_undo_group_level > 0)
      rl_end_undo_group()
    end
    @vi_continued_command = 0
  end
end
_rl_vi_initialize_line() click to toggle source
# File lib/rbreadline.rb, line 3839
def _rl_vi_initialize_line
  rl_unsetstate(RL_STATE_VICMDONCE)
end
_rl_vi_reset_last() click to toggle source
# File lib/rbreadline.rb, line 5725
def _rl_vi_reset_last()
  @_rl_vi_last_command = 'i'
  @_rl_vi_last_repeat = 1
  @_rl_vi_last_arg_sign = 1
  @_rl_vi_last_motion = 0
end
_rl_vi_save_insert(up) click to toggle source
# File lib/rbreadline.rb, line 5679
def _rl_vi_save_insert(up)
  if (up.nil? || up.what != UNDO_INSERT)
    if (@vi_insert_buffer_size >= 1)
      @vi_insert_buffer[0] = 0.chr
    end
    return
  end
  start = up.start
  _end = up.end
  len = _end - start + 1
  @vi_insert_buffer = @rl_line_buffer[start,len-1]
end
_rl_vi_textmod_command(c) click to toggle source

Is the command C a VI mode text modification command?

# File lib/rbreadline.rb, line 5721
def _rl_vi_textmod_command(c)
  return @vi_textmod[c]
end
_rl_walphabetic(c) click to toggle source
# File lib/rbreadline.rb, line 5219
def _rl_walphabetic(c)
  rl_alphabetic(c)
end
add_history(string) click to toggle source

Place STRING at the end of the history list. The data field

is  set to NULL.
# File lib/rbreadline.rb, line 6153
def add_history(string)
  if (@history_stifled && (@history_length == @history_max_entries))
    # If the history is stifled, and history_length is zero,
    # and it equals history_max_entries, we don't save items.
    return if (@history_length == 0)
    @the_history.shift
  else
    if @the_history.nil?
      @the_history = []
      @history_length = 1
    else
      @history_length+=1
    end
  end

  temp = alloc_history_entry(string, hist_inittime())
  @the_history[@history_length] = nil
  @the_history[@history_length - 1] = temp
end
alloc_history_entry(string, ts) click to toggle source
# File lib/rbreadline.rb, line 6133
def alloc_history_entry(string, ts)
  temp = Struct.new(:line,:data,:timestamp).new
  temp.line = string ? string.encode('UTF-8', invalid: :replace, undef: :replace, replace: '').delete(0.chr) : string
  temp.data = nil
  temp.timestamp = ts

  return temp
end
alloc_undo_entry(what, start, _end, text) click to toggle source
# File lib/rbreadline.rb, line 4930
def alloc_undo_entry(what, start, _end, text)
  temp = Struct.new(:what,:start,:end,:text,:next).new
  temp.what = what
  temp.start = start
  temp.end = _end
  temp.text = text
  temp.next = nil
  temp
end
append_to_match(text, delimiter, quote_char, nontrivial_match) click to toggle source

Append any necessary closing quote and a separator character to the just-inserted match. If the user has specified that directories should be marked by a trailing ‘/’, append one of those instead. The default trailing character is a space. Returns the number of characters appended. If NONTRIVIAL_MATCH is set, we test for a symlink (if the OS has them) and don’t add a suffix for a symlink to a directory. A nontrivial match is one that actually adds to the word being completed. The variable rl_completion_mark_symlink_dirs controls this behavior (it’s initially set to the what the user has chosen, indicated by the value of _rl_complete_mark_symlink_dirs, but may be modified by an application’s completion function).

# File lib/rbreadline.rb, line 8469
def append_to_match(text, delimiter, quote_char, nontrivial_match)
  temp_string = 0.chr * 4
  temp_string_index = 0
  if (quote_char && @rl_point>0 && !@rl_completion_suppress_quote &&
      @rl_line_buffer[@rl_point - 1,1] != quote_char)
    temp_string[temp_string_index] = quote_char
    temp_string_index += 1
  end
  if (delimiter != 0.chr)
    temp_string[temp_string_index] = delimiter
    temp_string_index += 1
  elsif (!@rl_completion_suppress_append && @rl_completion_append_character)
    temp_string[temp_string_index] = @rl_completion_append_character
    temp_string_index += 1
  end
  temp_string[temp_string_index] = 0.chr
  temp_string_index += 1

  if (@rl_filename_completion_desired)
    filename = File.expand_path(text)
    return temp_string_index unless File.exists? filename

    s = (nontrivial_match && !@rl_completion_mark_symlink_dirs) ?
      File.lstat(filename) : File.stat(filename)
    if s.directory?
      if @_rl_complete_mark_directories
        # This is clumsy.  Avoid putting in a double slash if point
        # is at the end of the line and the previous character is a
        # slash.
        if (@rl_point>0 && @rl_line_buffer[@rl_point,1] == 0.chr && @rl_line_buffer[@rl_point - 1,1] == '/' )

        elsif (@rl_line_buffer[@rl_point,1] != '/')
          rl_insert_text('/')
        end
      end
      # Don't add anything if the filename is a symlink and resolves to a
      # directory.
    elsif s.symlink? && File.stat(filename).directory?

    else
      if (@rl_point == @rl_end && temp_string_index>0)
        rl_insert_text(temp_string)
      end
    end
    filename = nil
  else
    if (@rl_point == @rl_end && temp_string_index>0)
      rl_insert_text(temp_string)
    end
  end
  temp_string_index
end
bind_arrow_keys() click to toggle source

Try and bind the common arrow key prefixes after giving termcap and

the inputrc file a chance to bind them and create `real' keymaps
for the arrow key prefix.
# File lib/rbreadline.rb, line 2540
def bind_arrow_keys()
  bind_arrow_keys_internal(@emacs_standard_keymap)
  bind_arrow_keys_internal(@vi_movement_keymap)
  bind_arrow_keys_internal(@vi_insertion_keymap)
end
bind_arrow_keys_internal(map) click to toggle source

Bind some common arrow key sequences in MAP.

# File lib/rbreadline.rb, line 2503
def bind_arrow_keys_internal(map)
  xkeymap = @_rl_keymap
  @_rl_keymap = map

  if RUBY_PLATFORM =~ /mswin|mingw/
    rl_bind_keyseq_if_unbound("\340H", :rl_get_previous_history) # Up
    rl_bind_keyseq_if_unbound("\340P", :rl_get_next_history) # Down
    rl_bind_keyseq_if_unbound("\340M", :rl_forward_char)  # Right
    rl_bind_keyseq_if_unbound("\340K", :rl_backward_char) # Left
    rl_bind_keyseq_if_unbound("\340G", :rl_beg_of_line)   # Home
    rl_bind_keyseq_if_unbound("\340O", :rl_end_of_line)   # End
    rl_bind_keyseq_if_unbound("\340s", :rl_backward_word) # Ctrl-Left
    rl_bind_keyseq_if_unbound("\340t", :rl_forward_word) # Ctrl-Right
    rl_bind_keyseq_if_unbound("\340S", :rl_delete) # Delete
    rl_bind_keyseq_if_unbound("\340R", :rl_overwrite_mode) # Insert
  else
    rl_bind_keyseq_if_unbound("\033[A", :rl_get_previous_history)
    rl_bind_keyseq_if_unbound("\033[B", :rl_get_next_history)
    rl_bind_keyseq_if_unbound("\033[C", :rl_forward_char)
    rl_bind_keyseq_if_unbound("\033[D", :rl_backward_char)
    rl_bind_keyseq_if_unbound("\033[H", :rl_beg_of_line)
    rl_bind_keyseq_if_unbound("\033[F", :rl_end_of_line)

    rl_bind_keyseq_if_unbound("\033OA", :rl_get_previous_history)
    rl_bind_keyseq_if_unbound("\033OB", :rl_get_next_history)
    rl_bind_keyseq_if_unbound("\033OC", :rl_forward_char)
    rl_bind_keyseq_if_unbound("\033OD", :rl_backward_char)
    rl_bind_keyseq_if_unbound("\033OH", :rl_beg_of_line)
    rl_bind_keyseq_if_unbound("\033OF", :rl_end_of_line)
  end

  @_rl_keymap = xkeymap
end
bind_termcap_arrow_keys(map) click to toggle source

Bind the arrow key sequences from the termcap description in MAP.

# File lib/rbreadline.rb, line 1953
def bind_termcap_arrow_keys(map)
  xkeymap = @_rl_keymap
  @_rl_keymap = map

  rl_bind_keyseq_if_unbound(@_rl_term_ku, :rl_get_previous_history)
  rl_bind_keyseq_if_unbound(@_rl_term_kd, :rl_get_next_history)
  rl_bind_keyseq_if_unbound(@_rl_term_kr, :rl_forward_char)
  rl_bind_keyseq_if_unbound(@_rl_term_kl, :rl_backward_char)

  rl_bind_keyseq_if_unbound(@_rl_term_kh, :rl_beg_of_line) # Home
  rl_bind_keyseq_if_unbound(@_rl_term_at7, :rl_end_of_line)   # End

  rl_bind_keyseq_if_unbound(@_rl_term_kD, :rl_delete)
  rl_bind_keyseq_if_unbound(@_rl_term_kI, :rl_overwrite_mode)

  @_rl_keymap = xkeymap
end
block_sigint() click to toggle source
# File lib/rbreadline.rb, line 6942
def block_sigint()
  return if @sigint_blocked
  @sigint_proc = Signal.trap("INT", "IGNORE")
  @sigint_blocked = true
end
clear_history() click to toggle source
# File lib/rbreadline.rb, line 8551
def clear_history()
  @the_history = nil
  @history_offset = @history_length = 0
end
compute_lcd_of_matches(match_list, matches, text) click to toggle source

Find the common prefix of the list of matches, and put it into

matches[0].
# File lib/rbreadline.rb, line 1318
def compute_lcd_of_matches(match_list, matches, text)
  # If only one match, just use that.  Otherwise, compare each
  #   member of the list with the next, finding out where they
  #   stop matching.
  if (matches == 1)
    match_list[0] = match_list[1]
    match_list[1] = nil
    return 1
  end

  i = 1
  low = 100000
  while(i<matches)
    if (@_rl_completion_case_fold)
      si = 0
      while((c1 = _rl_to_lower(match_list[i][si])) &&
            (c2 = _rl_to_lower(match_list[i + 1][si])))
        if !@rl_byte_oriented
          if(!_rl_compare_chars(match_list[i],si,match_list[i+1],si))
            break
          elsif ((v = _rl_get_char_len(match_list[i][si..-1])) > 1)
            si += v - 1
          end
        else
          break if (c1 != c2)
        end
        si += 1
      end
    else
      si = 0
      while((c1 = match_list[i][si]) &&
            (c2 = match_list[i + 1][si]))
        if !@rl_byte_oriented
          if(!_rl_compare_chars(match_list[i],si,match_list[i+1],si))
            break
          elsif ((v = _rl_get_char_len(match_list[i][si..-1])) > 1)
            si += v - 1
          end
        else
          break if (c1 != c2)
        end
        si += 1
      end
    end

    if (low > si)
      low = si
    end
    i += 1
  end

  # If there were multiple matches, but none matched up to even the
  #   first character, and the user typed something, use that as the
  #   value of matches[0].
  if (low == 0 && text && text.length>0 )
    match_list[0] = text.dup
  else
    # XXX - this might need changes in the presence of multibyte chars

    # If we are ignoring case, try to preserve the case of the string
    # the user typed in the face of multiple matches differing in case.
    if (@_rl_completion_case_fold)

      # We're making an assumption here:
      #  IF we're completing filenames AND
      #     the application has defined a filename dequoting function AND
      #     we found a quote character AND
      #     the application has requested filename quoting
      #  THEN
      #     we assume that TEXT was dequoted before checking against
      #     the file system and needs to be dequoted here before we
      #     check against the list of matches
      #  FI
      if (@rl_filename_completion_desired &&
          @rl_filename_dequoting_function &&
          @rl_completion_found_quote &&
          @rl_filename_quoting_desired)

        dtext = send(@rl_filename_dequoting_function,text, @rl_completion_quote_character)
        text = dtext
      end

      # sort the list to get consistent answers.
      match_list = [match_list[0]] + match_list[1..-1].sort

      si = text.length
      if (si <= low)
        for i in 1 .. matches
          if match_list[i][0,si] == text
            match_list[0] = match_list[i][0,low]
            break
          end
          # no casematch, use first entry
          if (i > matches)
            match_list[0] = match_list[1][0,low]
          end
        end
      else
        # otherwise, just use the text the user typed.
        match_list[0] = text[0,low]
      end
    else
      match_list[0] = match_list[1][0,low]
    end
  end

  return matches
end
cr() click to toggle source

Move to the start of the current line.

# File lib/rbreadline.rb, line 4700
def cr()
  if (@_rl_term_cr)
    @_rl_out_stream.write(@_rl_term_cr)
    @_rl_last_c_pos = 0
  end
end
cr_faster(new, cur) click to toggle source
# File lib/rbreadline.rb, line 2610
def cr_faster(new, cur)
  (new + 1) < (cur - new)
end
ctrl_char(c) click to toggle source
# File lib/rbreadline.rb, line 2667
def ctrl_char(c)
  c < "\x20"
end
current_history() click to toggle source

Return the history entry at the current position, as determined by

history_offset.  If there is no entry there, return a NULL pointer.
# File lib/rbreadline.rb, line 2659
def current_history()
  return ((@history_offset == @history_length) || @the_history.nil?) ? nil : @the_history[@history_offset]
end
delete_chars(count) click to toggle source

Delete COUNT characters from the display line.

# File lib/rbreadline.rb, line 8596
def delete_chars(count)
  return if (count > @_rl_screenwidth)   # XXX

  if @hConsoleHandle.nil?
    #if (@_rl_term_DC)
    #   buffer = tgoto(_rl_term_DC, count, count);
    #   @_rl_out_stream.write(buffer * count)
    #else
    if (@_rl_term_dc)
      @_rl_out_stream.write(@_rl_term_dc * count)
    end
    #end
  end
end
display_matches(matches) click to toggle source

Display MATCHES, a list of matching filenames in argv format. This handles the simple case – a single match – first. If there is more than one match, we compute the number of strings in the list and the length of the longest string, which will be needed by the display function. If the application wants to handle displaying the list of matches itself, it sets RL_COMPLETION_DISPLAY_MATCHES_HOOK to the address of a function, and we just call it. If we’re handling the display ourselves, we just call rl_display_match_list. We also check that the list of matches doesn’t exceed the user-settable threshold, and ask the user if he wants to see the list if there are more matches than RL_COMPLETION_QUERY_ITEMS.

# File lib/rbreadline.rb, line 6722
def display_matches(matches)
  # Move to the last visible line of a possibly-multiple-line command.
  _rl_move_vert(@_rl_vis_botlin)

  # Handle simple case first.  What if there is only one answer?
  if matches[1].nil?
    temp = printable_part(matches[0])
    rl_crlf()
    print_filename(temp, matches[0])
    rl_crlf()
    rl_forced_update_display()
    @rl_display_fixed = true
    return
  end

  # There is more than one answer.  Find out how many there are,
  #   and find the maximum printed length of a single entry.
  max = 0
  i = 1
  while(matches[i])
    temp = printable_part(matches[i])
    len = fnwidth(temp)

    if (len > max)
      max = len
    end
    i += 1
  end
  len = i - 1

  # If the caller has defined a display hook, then call that now.
  if (@rl_completion_display_matches_hook)
    send(@rl_completion_display_matches_hook,matches, len, max)
    return
  end

  # If there are many items, then ask the user if she really wants to
  #   see them all.
  if (@rl_completion_query_items > 0 && len >= @rl_completion_query_items)

    rl_crlf()
    @rl_outstream.write("Display all #{len} possibilities? (y or n)")
    @rl_outstream.flush
    if (get_y_or_n(false)==0)
      rl_crlf()

      rl_forced_update_display()
      @rl_display_fixed = true

      return
    end
  end

  rl_display_match_list(matches, len, max)

  rl_forced_update_display()
  @rl_display_fixed = true
end
endsrch_char(c) click to toggle source
# File lib/rbreadline.rb, line 4056
def endsrch_char(c)
  ((ctrl_char(c) || meta_char(c) || (c) == RUBOUT) && ((c) != "\C-G"))
end
expand_prompt(pmt) click to toggle source

Current implementation:

 \001 (^A) start non-visible characters
 \002 (^B) end non-visible characters
all characters except \001 and \002 (following a \001) are copied to
the returned string all characters except those between \001 and
\002 are assumed to be `visible'.
# File lib/rbreadline.rb, line 1676
def expand_prompt(pmt)
  # Short-circuit if we can.
  if (@rl_byte_oriented && pmt[RL_PROMPT_START_IGNORE].nil?)
    r = pmt.dup
    lp = r.length
    lip = 0
    niflp = 0
    vlp = lp
    return [r,lp,lip,niflp,vlp]
  end

  l = pmt.length
  ret = ''
  invfl = 0    # invisible chars in first line of prompt
  invflset = 0    # we only want to set invfl once

  igstart = 0
  rl = 0
  ignoring = false
  last = ninvis = physchars = 0
  for pi in 0 ... pmt.length
    # This code strips the invisible character string markers
    #RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE
    if (!ignoring && pmt[pi,1] == RL_PROMPT_START_IGNORE)        # XXX - check ignoring?
      ignoring = true
      igstart = pi
      next
    elsif (ignoring && pmt[pi,1] == RL_PROMPT_END_IGNORE)
      ignoring = false
      if (pi != (igstart + 1))
        last = ret.length - 1
      end
      next
    else
      if !@rl_byte_oriented
        pind = pi
        ind = _rl_find_next_mbchar(pmt, pind, 1, MB_FIND_NONZERO)
        l = ind - pind
        while (l>0)
          l-=1
          ret << pmt[pi]
          pi += 1
        end
        if (!ignoring)
          rl += ind - pind
          physchars += _rl_col_width(pmt, pind, ind)
        else
          ninvis += ind - pind
        end
        pi-=1       # compensate for later increment
      else
        ret << pmt[pi]
        if (!ignoring)
          rl+=1            # visible length byte counter
          physchars+=1
        else
          ninvis+=1        # invisible chars byte counter
        end

        if (invflset == 0 && rl >= @_rl_screenwidth)
          invfl = ninvis
          invflset = 1
        end
      end
    end
  end

  if (rl < @_rl_screenwidth)
    invfl = ninvis
  end
  lp = rl
  lip = last
  niflp = invfl
  vlp = physchars
  return [ret,lp,lip,niflp,vlp]
end
fnprint(to_print) click to toggle source
# File lib/rbreadline.rb, line 6502
def fnprint(to_print)
  printed_len = 0

  case @encoding
  when 'E'
    arr = to_print.scan(/./me)
  when 'S'
    arr = to_print.scan(/./ms)
  when 'U'
    arr = to_print.scan(/./mu)
  when 'X'
    arr = to_print.dup.force_encoding(@encoding_name).chars
  else
    arr = to_print.scan(/./m)
  end

  arr.each do |s|
    if(ctrl_char(s))
      @rl_outstream.write('^'+(s[0].ord|0x40).chr.upcase)
      printed_len += 2
    elsif s == RUBOUT
      @rl_outstream.write('^?')
      printed_len += 2
    else
      @rl_outstream.write(s)
      if @encoding=='U'
        printed_len += s.unpack('U').first >= 0x1000 ? 2 : 1
      elsif @encoding=='X'
        printed_len += s.ord >= 0x1000 ? 2 : 1
      else
        printed_len += s.length
      end
    end

  end

  printed_len
end
fnwidth(string) click to toggle source

Compute width of STRING when displayed on screen by print_filename

# File lib/rbreadline.rb, line 6672
def fnwidth(string)
  left = string.length + 1
  width = pos = 0
  while (string[pos] && string[pos,1] != 0.chr)
    if (ctrl_char(string[0,1]) || string[0,1] == RUBOUT)
      width += 2
      pos+=1
    else
      case @encoding
      when 'E'
        wc = string[pos,left-pos].scan(/./me)[0]
        bytes = wc.length
        tempwidth = wc.length
      when 'S'
        wc = string[pos,left-pos].scan(/./ms)[0]
        bytes = wc.length
        tempwidth = wc.length
      when 'U'
        wc = string[pos,left-pos].scan(/./mu)[0]
        bytes = wc.length
        tempwidth = wc.unpack('U').first >= 0x1000 ? 2 : 1
      when 'X'
        wc = string[pos,left-pos].force_encoding(@encoding_name)[0]
        bytes = wc.bytesize
        tempwidth = wc.ord >= 0x1000 ? 2 : 1
      else
        wc = string[pos,left-pos].scan(/./m)[0]
        bytes = wc.length
        tempwidth = wc.length
      end
      clen = bytes
      pos += clen
      w = tempwidth
      width += (w >= 0) ? w : 1
    end
  end
  width
end
gen_completion_matches(text, start, _end, our_func, found_quote, quote_char) click to toggle source
# File lib/rbreadline.rb, line 6321
def gen_completion_matches(text, start, _end, our_func, found_quote, quote_char)
  @rl_completion_found_quote = found_quote
  @rl_completion_quote_character = quote_char

  # If the user wants to TRY to complete, but then wants to give
  #   up and use the default completion function, they set the
  #   variable rl_attempted_completion_function.
  if (@rl_attempted_completion_function)
    matches = Readline.send(@rl_attempted_completion_function,text, start, _end)
    if (matches || @rl_attempted_completion_over)
      @rl_attempted_completion_over = false
      return (matches)
    end
  end
  # XXX -- filename dequoting moved into rl_filename_completion_function

  matches = rl_completion_matches(text, our_func)
  matches
end
get_term_capabilities(buffer) click to toggle source
# File lib/rbreadline.rb, line 1813
def get_term_capabilities(buffer)
  hash = {}
    `infocmp -C`.split(':').select{|x| x =~ /(.*)=(.*)/ and hash[$1]=$2.gsub("\\r", "\r").gsub('\\E',"\e").gsub(/\^(.)/){($1[0].ord ^ ((?a..?z).include?($1[0]) ? 0x60 : 0x40)).chr}}
    @_rl_term_at7          =     hash["@7"]
    @_rl_term_DC           =     hash["DC"]
    @_rl_term_IC           =     hash["IC"]
    @_rl_term_clreol       =     hash["ce"]
    @_rl_term_clrpag       =     hash["cl"]
    @_rl_term_cr           =     hash["cr"]
    @_rl_term_dc           =     hash["dc"]
    @_rl_term_ei           =     hash["ei"]
    @_rl_term_ic           =     hash["ic"]
    @_rl_term_im           =     hash["im"]
    @_rl_term_kD           =     hash["kD"]
    @_rl_term_kH           =     hash["kH"]
    @_rl_term_kI           =     hash["kI"]
    @_rl_term_kd           =     hash["kd"]
    @_rl_term_ke           =     hash["ke"]
    @_rl_term_kh           =     hash["kh"]
    @_rl_term_kl           =     hash["kl"]
    @_rl_term_kr           =     hash["kr"]
    @_rl_term_ks           =     hash["ks"]
    @_rl_term_ku           =     hash["ku"]
    @_rl_term_backspace    =     hash["le"]
    @_rl_term_mm           =     hash["mm"]
    @_rl_term_mo           =     hash["mo"]
    @_rl_term_forward_char =     hash["nd"]
    @_rl_term_pc           =     hash["pc"]
    @_rl_term_up           =     hash["up"]
    @_rl_visible_bell      =     hash["vb"]
    @_rl_term_vs           =     hash["vs"]
    @_rl_term_ve           =     hash["ve"]
    @tcap_initialized = true
end
get_y_or_n(for_pager) click to toggle source

The user must press “y” or “n”. Non-zero return means “y” pressed.

# File lib/rbreadline.rb, line 6645
def get_y_or_n(for_pager)
  while(true)

    rl_setstate(RL_STATE_MOREINPUT)
    c = rl_read_key()
    rl_unsetstate(RL_STATE_MOREINPUT)

    if (c == 'y' || c == 'Y' || c == ' ')
      return (1)
    end
    if (c == 'n' || c == 'N' || c == RUBOUT)
      return (0)
    end
    if (c == ABORT_CHAR || (c.is_a?(Integer) && c < 0))
      _rl_abort_internal()
    end
    if (for_pager && (c == NEWLINE || c == RETURN))
      return (2)
    end
    if (for_pager && (c == 'q' || c == 'Q'))
      return (0)
    end
    rl_ding()
  end
end
handle_parser_directive(statement) click to toggle source

Handle a parser directive. STATEMENT is the line of the directive

without any leading `$'.
# File lib/rbreadline.rb, line 2235
def handle_parser_directive(statement)

  directive,args = statement.split(' ')

  case directive.downcase
  when "if"
    parser_if(args)
    return 0
  when "endif"
    parser_endif(args)
    return 0
  when "else"
    parser_else(args)
    return 0
  when "include"
    parser_include(args)
    return 0
  end

  #_rl_init_file_error("unknown parser directive")
  return 1
end
hist_inittime() click to toggle source
# File lib/rbreadline.rb, line 6142
def hist_inittime()
  t = Time.now.to_i
  ts = "X%u" % t
  ret = ts.dup
  ret[0,1] = @history_comment_char

  ret
end
history_arg_extract(first, last, string) click to toggle source
# File lib/rbreadline.rb, line 7576
def history_arg_extract(first, last, string)
  if first != "$" || last != "$"
    fail "RbReadline.history_arg_extract called with currently unsupported args."
  end

  # Find the last index of an unescaped quote character.
  last_unescaped_quote_char = -1
  RbReadline::HISTORY_QUOTE_CHARACTERS.each_char do |quote_char|
    quote_char = Regexp.escape(quote_char)
    if index = string =~ /(?:\\.|[^#{quote_char}\\])#{quote_char} *$/
      last_unescaped_quote_char = index if index > last_unescaped_quote_char
    end
  end
  last_unescaped_quote_char += 1 # Because of the regex used above.

  # Find the last index of an unescaped word delimiter.
  delimiters = RbReadline::HISTORY_WORD_DELIMITERS.chars.to_a.map { |d| Regexp.escape(d) }
  unless last_unescaped_delimiter = string =~ /(?:\\.|[^#{delimiters.join}])+? *$/
    last_unescaped_delimiter = 0
  end

  if last_unescaped_quote_char >= last_unescaped_delimiter
    quoted_arg = _extract_last_quote(string, string[last_unescaped_quote_char,1])
  end
  quoted_arg or string[last_unescaped_delimiter...string.length]
end
history_get(offset) click to toggle source

Return the history entry which is logically at OFFSET in the history array.

OFFSET is relative to history_base.
# File lib/rbreadline.rb, line 6909
def history_get(offset)
  local_index = offset - @history_base
  return (local_index >= @history_length || local_index < 0 || @the_history.nil?) ?
    nil : @the_history[local_index]
end
history_is_stifled() click to toggle source
# File lib/rbreadline.rb, line 8547
def history_is_stifled()
  return (@history_stifled)
end
history_list() click to toggle source
# File lib/rbreadline.rb, line 7265
def history_list()
  @the_history
end
history_search_pos(string, dir, pos) click to toggle source

Search for STRING in the history list. DIR is < 0 for searching

backwards.  POS is an absolute index into the history list at
which point to begin searching.
# File lib/rbreadline.rb, line 8097
def history_search_pos(string, dir, pos)
  old = where_history()
  history_set_pos(pos)
  if (history_search(string, dir) == -1)
    history_set_pos(old)
    return (-1)
  end
  ret = where_history()
  history_set_pos(old)
  ret
end
history_search_prefix(string, direction) click to toggle source

Do an anchored search for string through the history in DIRECTION.

# File lib/rbreadline.rb, line 8090
def history_search_prefix (string, direction)
  history_search_internal(string, direction, ANCHORED_SEARCH)
end
history_set_pos(pos) click to toggle source

Make the current history item be the one at POS, an absolute index.

Returns zero if POS is out of range, else non-zero.
# File lib/rbreadline.rb, line 8081
def history_set_pos(pos)
  if (pos > @history_length || pos < 0 || @the_history.nil?)
    return (0)
  end
  @history_offset = pos
  1
end
ibuffer_space() click to toggle source

Return the amount of space available in the buffer for stuffing

characters.
# File lib/rbreadline.rb, line 4593
def ibuffer_space()
  if (@pop_index > @push_index)
    return (@pop_index - @push_index - 1)
  else
    return (@ibuffer_len - (@push_index - @pop_index))
  end
end
init_line_structures(minsize) click to toggle source

Initialize the VISIBLE_LINE and INVISIBLE_LINE arrays, and their associated

arrays of line break markers.  MINSIZE is the minimum size of VISIBLE_LINE
and INVISIBLE_LINE; if it is greater than LINE_SIZE, LINE_SIZE is
increased.  If the lines have already been allocated, this ensures that
they can hold at least MINSIZE characters.
# File lib/rbreadline.rb, line 2631
def init_line_structures(minsize)
  if @invisible_line.nil? # initialize it
    if (@line_size < minsize)
      @line_size = minsize
    end
    @visible_line = 0.chr * @line_size
    @invisible_line = 0.chr * @line_size # 1.chr
  elsif (@line_size < minsize)  # ensure it can hold MINSIZE chars
    @line_size *= 2
    if (@line_size < minsize)
      @line_size = minsize
    end
    @visible_line << 0.chr * (@line_size - @visible_line.length)
    @invisible_line << 1.chr * (@line_size - @invisible_line.length)
  end
  @visible_line[minsize,@line_size-minsize] = 0.chr * (@line_size-minsize)
  @invisible_line[minsize,@line_size-minsize] = 1.chr * (@line_size-minsize)

  if @vis_lbreaks.nil?
    @inv_lbreaks = []
    @vis_lbreaks = []
    @_rl_wrapped_line = []
    @inv_lbreaks[0] = @vis_lbreaks[0] = 0
  end
end
insert_all_matches(matches, point, qc) click to toggle source
# File lib/rbreadline.rb, line 6389
def insert_all_matches(matches, point, qc)
  rl_begin_undo_group()
  # remove any opening quote character; make_quoted_replacement will add
  #   it back.
  if (qc && qc.length>0 && point>0 && @rl_line_buffer[point - 1,1] == qc)
    point-=1
  end
  rl_delete_text(point, @rl_point)
  @rl_point = point
  if (matches[1])
    i = 1
    while(matches[i])
      rp = make_quoted_replacement(matches[i], SINGLE_MATCH, qc)
      rl_insert_text(rp)
      rl_insert_text(" ")
      if (rp != matches[i])
        rp = nil
      end
      i += 1
    end
  else
    rp = make_quoted_replacement(matches[0], SINGLE_MATCH, qc)
    rl_insert_text(rp)
    rl_insert_text(" ")
    if (rp != matches[0])
      rp = nil
    end
  end
  rl_end_undo_group()
end
insert_match(match, start, mtype, qc) click to toggle source
# File lib/rbreadline.rb, line 6461
def insert_match(match, start, mtype, qc)
  oqc = qc
  replacement = make_quoted_replacement(match, mtype, qc)

  # Now insert the match.
  if (replacement)
    # Don't double an opening quote character.
    if (qc && qc.length>0 && start!=0 && @rl_line_buffer[start - 1,1] == qc &&
        replacement[0,1] == qc)
      start-=1
      # If make_quoted_replacement changed the quoting character, remove
      # the opening quote and insert the (fully-quoted) replacement.
    elsif (qc && (qc != oqc) && start!=0 && @rl_line_buffer[start - 1,1] == oqc &&
           replacement[0,1] != oqc)
      start-=1
    end
    _rl_replace_text(replacement, start, @rl_point - 1)
    if (replacement != match)
      replacement = nil
    end
  end
end
insert_some_chars(string, count, col) click to toggle source

Insert COUNT characters from STRING to the output stream at column COL.

# File lib/rbreadline.rb, line 8557
def insert_some_chars(string, count, col)
  if @hConsoleHandle
    _rl_output_some_chars(string,0,count)
  else
    # DEBUGGING
    if (@rl_byte_oriented)
      if (count != col)
        $stderr.write("readline: debug: insert_some_chars: count (#{count}) != col (#{col})\n");
      end
    end
    # If IC is defined, then we do not have to "enter" insert mode.
    #if (@_rl_term_IC)
    #   buffer = tgoto(@_rl_term_IC, 0, col)
    #   @_rl_out_stream.write(buffer)
    #   _rl_output_some_chars(string,0,count)
    #else
    # If we have to turn on insert-mode, then do so.
    if (@_rl_term_im)
      @_rl_out_stream.write(@_rl_term_im)
    end
    # If there is a special command for inserting characters, then
    # use that first to open up the space.
    if (@_rl_term_ic)
      @_rl_out_stream.write(@_rl_term_ic * count)
    end

    # Print the text.
    _rl_output_some_chars(string,0, count)

    # If there is a string to turn off insert mode, we had best use
    # it now.
    if (@_rl_term_ei)
      @_rl_out_stream.write(@_rl_term_ei)
    end
    #end
  end
end
inv_line(line) click to toggle source
# File lib/rbreadline.rb, line 2703
def inv_line(line)
  @invisible_line[@inv_lbreaks[line] .. -1]
end
inv_llen(l) click to toggle source
# File lib/rbreadline.rb, line 2687
def inv_llen(l)
  (@inv_lbreaks[l+1] - @inv_lbreaks[l])
end
isascii(c) click to toggle source
# File lib/rbreadline.rb, line 8015
def isascii(c)
  int_val = c[0].to_i # 1.8 + 1.9 compat.
  return (int_val < 128 && int_val > 0)
end
isprint(c) click to toggle source
# File lib/rbreadline.rb, line 2671
def isprint(c)
  c >= "\x20" && c < "\x7f"
end
m_offset(margin, offset) click to toggle source
# File lib/rbreadline.rb, line 2707
def m_offset(margin, offset)
  ((margin) == 0 ? offset : 0)
end
make_history_line_current(entry) click to toggle source

Make the data from the history entry ENTRY be the contents of the

current line.  This doesn't do anything with rl_point; the caller
must set it.
# File lib/rbreadline.rb, line 8064
def make_history_line_current(entry)
  _rl_replace_text(entry.line, 0, @rl_end)
  _rl_fix_point(1)
  if (@rl_editing_mode == @vi_mode)
    # POSIX.2 says that the `U' command doesn't affect the copy of any
    #   command lines to the edit line.  We're going to implement that by
    #   making the undo list start after the matching line is copied to the
    #   current editing buffer.
    rl_free_undo_list()
  end
  if (@_rl_saved_line_for_history)
    @_rl_saved_line_for_history = nil
  end
end
make_quoted_replacement(match, mtype, qc) click to toggle source
# File lib/rbreadline.rb, line 6420
def make_quoted_replacement(match, mtype, qc)
  # If we are doing completion on quoted substrings, and any matches
  #   contain any of the completer_word_break_characters, then auto-
  #   matically prepend the substring with a quote character (just pick
  #   the first one from the list of such) if it does not already begin
  #   with a quote string.  FIXME: Need to remove any such automatically
  #   inserted quote character when it no longer is necessary, such as
  #   if we change the string we are completing on and the new set of
  #   matches don't require a quoted substring.
  replacement = match

  should_quote = match && @rl_completer_quote_characters &&
    @rl_filename_completion_desired &&
    @rl_filename_quoting_desired

  if (should_quote)
    should_quote = should_quote && (qc.nil? || qc == 0.chr ||
                                    (@rl_completer_quote_characters &&
                                     @rl_completer_quote_characters.include?(qc)))
  end

  if (should_quote)

    # If there is a single match, see if we need to quote it.
    #   This also checks whether the common prefix of several
    # matches needs to be quoted.
    should_quote = @rl_filename_quote_characters ?
      !!match[@rl_filename_quote_characters] :
      false

    do_replace = should_quote ? mtype : NO_MATCH
    # Quote the replacement, since we found an embedded
    # word break character in a potential match.
    if (do_replace != NO_MATCH && @rl_filename_quoting_function)
      replacement = send(@rl_filename_quoting_function,match, do_replace, qc)
    end
  end
  replacement
end
meta_char(c) click to toggle source
# File lib/rbreadline.rb, line 2663
def meta_char(c)
  c > "\x7f" && c <= "\xff"
end
next_history() click to toggle source

Move history_offset forward to the next history entry, and return

a pointer to that entry.  If there is no next entry then return a
NULL pointer.
# File lib/rbreadline.rb, line 5445
def next_history()
  (@history_offset == @history_length) ? nil : @the_history[@history_offset+=1]
end
noninc_dosearch(string, dir) click to toggle source

Search for a line in the history containing STRING. If DIR is < 0, the

search is backwards through previous entries, else through subsequent
entries.  Returns 1 if the search was successful, 0 otherwise.
# File lib/rbreadline.rb, line 8138
def noninc_dosearch(string, dir)
  if (string.nil? || string == '' || @noninc_history_pos < 0)
    rl_ding()
    return 0
  end

  pos = noninc_search_from_pos(string, @noninc_history_pos + dir, dir)
  if (pos == -1)
    # Search failed, current history position unchanged.
    rl_maybe_unsave_line()
    rl_clear_message()
    @rl_point = 0
    rl_ding()
    return 0
  end

  @noninc_history_pos = pos

  oldpos = where_history()
  history_set_pos(@noninc_history_pos)
  entry = current_history()
  if (@rl_editing_mode != @vi_mode)
    history_set_pos(oldpos)
  end
  make_history_line_current(entry)
  @rl_point = 0
  @rl_mark = @rl_end
  rl_clear_message()
  1
end
noninc_search_from_pos(string, pos, dir) click to toggle source

Search the history list for STRING starting at absolute history position

POS.  If STRING begins with `^', the search must match STRING at the
beginning of a history line, otherwise a full substring match is performed
for STRING.  DIR < 0 means to search backwards through the history list,
DIR >= 0 means to search forward.
# File lib/rbreadline.rb, line 8114
def noninc_search_from_pos(string, pos, dir)
  return 1 if (pos < 0)

  old = where_history()
  return -1 if (history_set_pos(pos) == 0)

  rl_setstate(RL_STATE_SEARCH)
  if (string[0,1] == '^')
    ret = history_search_prefix(string + 1, dir)
  else
    ret = history_search(string, dir)
  end
  rl_unsetstate(RL_STATE_SEARCH)

  if (ret != -1)
    ret = where_history()
  end
  history_set_pos(old)
  ret
end
parser_else(args) click to toggle source

Invert the current parser state if there is anything on the stack.

# File lib/rbreadline.rb, line 2191
def parser_else(args)
  if @if_stack.empty?
    #_rl_init_file_error ("$else found without matching $if")
    return 0
  end

  # Check the previous (n) levels of the stack to make sure that
  #   we haven't previously turned off parsing.
  return 0 if @if_stack.detect {|x| x }

  # Invert the state of parsing if at top level.
  @_rl_parsing_conditionalized_out = !@_rl_parsing_conditionalized_out
  return 0
end
parser_endif(args) click to toggle source

Terminate a conditional, popping the value of

_rl_parsing_conditionalized_out from the stack.
# File lib/rbreadline.rb, line 2208
def parser_endif(args)
  if (@if_stack.length>0)
    @_rl_parsing_conditionalized_out = @if_stack.pop
  else
    #_rl_init_file_error ("$endif without matching $if")
  end
  0
end
parser_if(args) click to toggle source

Push _rl_parsing_conditionalized_out, and set parser state based

on ARGS.
# File lib/rbreadline.rb, line 2148
def parser_if(args)
  # Push parser state.
  @if_stack << @_rl_parsing_conditionalized_out

  # If parsing is turned off, then nothing can turn it back on except
  #   for finding the matching endif.  In that case, return right now.
  if @_rl_parsing_conditionalized_out
    return 0
  end

  args.downcase!
  # Handle "$if term=foo" and "$if mode=emacs" constructs.  If this
  #   isn't term=foo, or mode=emacs, then check to see if the first
  #   word in ARGS is the same as the value stored in rl_readline_name.
  if (@rl_terminal_name && args =~ /^term=/)
    # Terminals like "aaa-60" are equivalent to "aaa".
    tname = @rl_terminal_name.downcase.gsub(/-.*$/,'')

    # Test the `long' and `short' forms of the terminal name so that
    #if someone has a `sun-cmd' and does not want to have bindings
    #that will be executed if the terminal is a `sun', they can put
    #`$if term=sun-cmd' into their .inputrc.
    @_rl_parsing_conditionalized_out = (args[5..-1] != tname && args[5..-1] != @rl_terminal_name.downcase)
  elsif args =~ /^mode=/
    if args[5..-1] == "emacs"
      mode = @emacs_mode
    elsif args[5..-1] == "vi"
      mode = @vi_mode
    else
      mode = @no_mode
    end
  @_rl_parsing_conditionalized_out = (mode != @rl_editing_mode)
  # Check to see if the first word in ARGS is the same as the
  #   value stored in rl_readline_name.
  elsif (args == @rl_readline_name)
    @_rl_parsing_conditionalized_out = false
  else
    @_rl_parsing_conditionalized_out = true
  end
  return 0
end
parser_include(args) click to toggle source
# File lib/rbreadline.rb, line 2217
def parser_include(args)
  return 0 if (@_rl_parsing_conditionalized_out)

  old_init_file = @current_readline_init_file
  old_line_number = @current_readline_init_lineno
  old_include_level = @current_readline_init_include_level

  r = _rl_read_init_file(args, old_include_level + 1)

  @current_readline_init_file = old_init_file
  @current_readline_init_lineno = old_line_number
  @current_readline_init_include_level = old_include_level

  return r
end
path_isdir(filename) click to toggle source
# File lib/rbreadline.rb, line 6555
def path_isdir(filename)
  return File.directory?(filename)
end
postprocess_matches(matchesp, matching_filenames) click to toggle source
# File lib/rbreadline.rb, line 6353
def postprocess_matches(matchesp, matching_filenames)
  matches = matchesp

  return 0 if matches.nil?

  # It seems to me that in all the cases we handle we would like
  #   to ignore duplicate possiblilities.  Scan for the text to
  #   insert being identical to the other completions.
  if (@rl_ignore_completion_duplicates)
    remove_duplicate_matches(matches)
  end

  # If we are matching filenames, then here is our chance to
  #   do clever processing by re-examining the list.  Call the
  #   ignore function with the array as a parameter.  It can
  #   munge the array, deleting matches as it desires.
  if (@rl_ignore_some_completions_function && matching_filenames)
    nmatch = matches.length
    send(@rl_ignore_some_completions_function,matches)
    if (matches.nil? || matches[0].nil?)
      matches = nil
      return 0
    else
      # If we removed some matches, recompute the common prefix.
      i = matches.length
      if (i > 1 && i < nmatch)
        t = matches[0]
        compute_lcd_of_matches(matches, i - 1, t)
      end
    end
  end

  matchesp = matches
  1
end
prepare_terminal_settings(meta_flag) click to toggle source
# File lib/rbreadline.rb, line 6999
def prepare_terminal_settings(meta_flag)
  retry_if_interrupted do
    @readline_echoing_p = (`stty -a`.scan(/-*echo\b/).first == 'echo')
  end

  # First, the basic settings to put us into character-at-a-time, no-echo
  #   input mode.
  setting = " -echo -icrnl cbreak"

  # If this terminal doesn't care how the 8th bit is used, then we can
  #   use it for the meta-key.  If only one of even or odd parity is
  #  specified, then the terminal is using parity, and we cannot.
  retry_if_interrupted do
    if (`stty -a`.scan(/-parenb\b/).first == '-parenb')
      setting << " pass8"
    end
  end

  setting << " -ixoff"

  rl_bind_key(@_rl_tty_chars.t_start, :rl_restart_output) unless @_rl_tty_chars.t_start.nil?
  @_rl_eof_char = @_rl_tty_chars.t_eof

  #setting << " -isig"

  retry_if_interrupted do
    `stty #{setting}`
  end
end
previous_history() click to toggle source

Back up history_offset to the previous history entry, and return

a pointer to that entry.  If there is no previous entry then return
a NULL pointer.
# File lib/rbreadline.rb, line 5438
def previous_history()
  @history_offset!=0 ? @the_history[@history_offset-=1] : nil
end
print_filename(to_print, full_pathname) click to toggle source

Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we

are using it, check for and output a single character for `special'
filenames.  Return the number of characters we output.
printable_part(pathname) click to toggle source

Return the portion of PATHNAME that should be output when listing

possible completions.  If we are hacking filename completion, we
are only interested in the basename, the portion following the
final slash.  Otherwise, we return what we were passed.  Since
printing empty strings is not very informative, if we're doing
filename completion, and the basename is the empty string, we look
for the previous slash and return the portion following that.  If
there's no previous slash, we just return what we were passed.
# File lib/rbreadline.rb, line 6492
def printable_part(pathname)
  if (!@rl_filename_completion_desired)  # don't need to do anything
    return (pathname)
  end

  temp = pathname.rindex('/')
  return pathname if temp.nil?
  File.basename(pathname)
end
prompt_ending_index() click to toggle source
  • _rl_last_c_pos is an absolute cursor position in multibyte locales and a

    buffer index in others.  This macro is used when deciding whether the
    current cursor position is in the middle of a prompt string containing
    invisible characters.
# File lib/rbreadline.rb, line 2618
def prompt_ending_index()
  if !@rl_byte_oriented
    @prompt_physical_chars
  else
    (@prompt_last_invisible+1)
  end
end
readline_default_bindings() click to toggle source

If this system allows us to look at the values of the regular

input editing characters, then bind them to their readline
equivalents, iff the characters are not bound to keymaps.
# File lib/rbreadline.rb, line 2073
def readline_default_bindings()
  if @_rl_bind_stty_chars
    rl_tty_set_default_bindings(@_rl_keymap)
  end
end
readline_initialize_everything() click to toggle source

Initialize the entire state of the world.

# File lib/rbreadline.rb, line 2547
def readline_initialize_everything()
  # Set up input and output if they are not already set up.
  @rl_instream ||= $stdin

  @rl_outstream ||= $stdout

  # Bind _rl_in_stream and _rl_out_stream immediately.  These values
  #   may change, but they may also be used before readline_internal ()
  #   is called.
  @_rl_in_stream = @rl_instream
  @_rl_out_stream = @rl_outstream

  # Allocate data structures.
  @rl_line_buffer = ""

  # Initialize the terminal interface.
  @rl_terminal_name ||= ENV["TERM"]
  _rl_init_terminal_io(@rl_terminal_name)

  # Bind tty characters to readline functions.
  readline_default_bindings()

  # Decide whether we should automatically go into eight-bit mode.
  _rl_init_eightbit()

  # Read in the init file.
  rl_read_init_file(nil)

  # XXX
  if (@_rl_horizontal_scroll_mode && @_rl_term_autowrap)
    @_rl_screenwidth -= 1
    @_rl_screenchars -= @_rl_screenheight
  end

  # Override the effect of any `set keymap' assignments in the
  #   inputrc file.
  rl_set_keymap_from_edit_mode()

  # Try to bind a common arrow key prefix, if not already bound.
  bind_arrow_keys()

  # Enable the meta key, if this terminal has one.
  if @_rl_enable_meta
    _rl_enable_meta_key()
  end

  # If the completion parser's default word break characters haven't
  #   been set yet, then do so now.
  @rl_completer_word_break_characters ||= @rl_basic_word_break_characters
end
readline_internal() click to toggle source

Read a line of input from the global rl_instream, doing output on

the global rl_outstream.
If rl_prompt is non-null, then that is our prompt.
# File lib/rbreadline.rb, line 4851
def readline_internal()
  readline_internal_setup()
  eof = readline_internal_charloop()
  readline_internal_teardown(eof)
end
readline_internal_charloop() click to toggle source
# File lib/rbreadline.rb, line 4740
def readline_internal_charloop()
  lastc = -1
  eof_found = false

  while (!@rl_done)
    lk = @_rl_last_command_was_kill

    #  send(rl_redisplay_function)
    #  @_rl_want_redisplay = false

    if (@rl_pending_input == 0)
      # Then initialize the argument and number of keys read.
      _rl_reset_argument()
      @rl_key_sequence_length = 0
    end

    rl_setstate(RL_STATE_READCMD)
    c = rl_read_key()
    rl_unsetstate(RL_STATE_READCMD)
    # look at input.c:rl_getc() for the circumstances under which this will
    #be returned; punt immediately on read error without converting it to
    #a newline.
    if (c == READERR)
      eof_found = true
      break
    end

    # EOF typed to a non-blank line is a <NL>.
    if (c == EOF && @rl_end!=0)
      c = NEWLINE
    end

    # The character _rl_eof_char typed to blank line, and not as the
    #previous character is interpreted as EOF.
    if (((c == @_rl_eof_char && lastc != c) || c == EOF) && @rl_end==0)
      eof_found = true
      break
    end
    lastc = c
    if _rl_dispatch(c, @_rl_keymap)== -1
      next
    end

    # If there was no change in _rl_last_command_was_kill, then no kill
    #has taken place.  Note that if input is pending we are reading
    #a prefix command, so nothing has changed yet.
    if (@rl_pending_input == 0 && lk == @_rl_last_command_was_kill)
      @_rl_last_command_was_kill = false
    end
    _rl_internal_char_cleanup()
  end

  eof_found
end
readline_internal_setup() click to toggle source
# File lib/rbreadline.rb, line 3982
def readline_internal_setup()
  @_rl_in_stream = @rl_instream
  @_rl_out_stream = @rl_outstream

  if (@rl_startup_hook)
    send(@rl_startup_hook)
  end

  # If we're not echoing, we still want to at least print a prompt, because
  #   rl_redisplay will not do it for us.  If the calling application has a
  #   custom redisplay function, though, let that function handle it.
  if (!@readline_echoing_p && @rl_redisplay_function == :rl_redisplay)
    if (@rl_prompt && !@rl_already_prompted)
      nprompt = _rl_strip_prompt(@rl_prompt)
      @_rl_out_stream.write(nprompt)
      @_rl_out_stream.flush
    end
  else
    if (@rl_prompt && @rl_already_prompted)
      rl_on_new_line_with_prompt()
    else
      rl_on_new_line()
    end
    send(@rl_redisplay_function)
  end

  if (@rl_editing_mode == @vi_mode)
    rl_vi_insertion_mode(1, 'i')
  end
  if (@rl_pre_input_hook)
    send(@rl_pre_input_hook)
  end
end
readline_internal_teardown(eof) click to toggle source
# File lib/rbreadline.rb, line 4822
def readline_internal_teardown(eof)
  # Restore the original of this history line, iff the line that we
  #   are editing was originally in the history, AND the line has changed.
  entry = current_history()

  if (entry && @rl_undo_list)
    temp = @rl_line_buffer.delete(0.chr).dup
    rl_revert_line(1, 0)
    entry = replace_history_entry(where_history(), @rl_line_buffer, nil)
    entry = nil

    @rl_line_buffer = temp+0.chr
    temp = nil
  end

  # At any rate, it is highly likely that this line has an undo list.  Get
  #   rid of it now.
  if (@rl_undo_list)
    rl_free_undo_list()
  end
  # Restore normal cursor, if available.
  _rl_set_insert_mode(RL_IM_INSERT, 0)

  (eof ? nil : @rl_line_buffer.delete(0.chr))
end
redraw_prompt(t) click to toggle source

Redraw the last line of a multi-line prompt that may possibly contain terminal escape sequences. Called with the cursor at column 0 of the line to draw the prompt on.

# File lib/rbreadline.rb, line 8836
def redraw_prompt(t)
  oldp = @rl_display_prompt
  rl_save_prompt()

  @rl_display_prompt = t
  @local_prompt,@prompt_visible_length,@prompt_last_invisible,@prompt_invis_chars_first_line,@prompt_physical_chars =
    expand_prompt(t)
  @local_prompt_prefix = nil
  @local_prompt_len = @local_prompt ? @local_prompt.length : 0

  rl_forced_update_display()

  @rl_display_prompt = oldp
  rl_restore_prompt()
end
release_sigint() click to toggle source
# File lib/rbreadline.rb, line 6948
def release_sigint()
  return if !@sigint_blocked
  Signal.trap("INT", @sigint_proc)
  @sigint_blocked = false
end
remove_duplicate_matches(matches) click to toggle source

Filter out duplicates in MATCHES. This frees up the strings in

MATCHES.
# File lib/rbreadline.rb, line 6343
def remove_duplicate_matches(matches)
  # Sort the items.
  # Sort the array without matches[0], since we need it to
  #   stay in place no matter what.
  if matches.length>0
    matches[1..-2] = matches[1..-2].sort.uniq
  end
  matches
end
remove_history(which) click to toggle source

Remove history element WHICH from the history. The removed

element is returned to you so you can free the line, data,
and containing structure.
# File lib/rbreadline.rb, line 6932
def remove_history(which)
  if (which < 0 || which >= @history_length || @history_length ==  0 || @the_history.nil?)
    return nil
  end
  return_value = @the_history[which]
  @the_history.delete_at(which)
  @history_length-=1
  return_value
end
replace_history_data(which,old, new) click to toggle source

Replace the DATA in the specified history entries, replacing OLD with

NEW.  WHICH says which one(s) to replace:  WHICH == -1 means to replace
all of the history entries where entry->data == OLD; WHICH == -2 means
to replace the `newest' history entry where entry->data == OLD; and
WHICH >= 0 means to replace that particular history entry's data, as
long as it matches OLD.
# File lib/rbreadline.rb, line 5058
def replace_history_data(which,old, new)
  new = new.dup if new
  if (which < -2 || which >= @history_length || @history_length == 0 || @the_history.nil?)
    return
  end
  if (which >= 0)
    entry = @the_history[which]
    if (entry && entry.data == old)
      entry.data = new
    end
    return
  end

  last = -1
  for i in 0 ... @history_length
    entry = @the_history[i]
    if entry.nil?
      next
    end
    if (entry.data == old)
      last = i
      if (which == -1)
        entry.data = new
      end
    end
  end
  if (which == -2 && last >= 0)
    entry = @the_history[last]
    entry.data = new  # XXX - we don't check entry->old
  end
end
replace_history_entry(which, line, data) click to toggle source

Make the history entry at WHICH have LINE and DATA. This returns

the old entry so you can dispose of the data.  In the case of an
invalid WHICH, a NULL pointer is returned.
# File lib/rbreadline.rb, line 5412
def replace_history_entry (which, line, data)
  if (which < 0 || which >= @history_length)
    return nil
  end
  temp = Struct.new(:line,:timestamp,:data).new
  old_value = @the_history[which]
  temp.line = line.delete(0.chr)
  temp.data = data
  temp.timestamp = old_value.timestamp.dup
  @the_history[which] = temp
  old_value
end
retry_if_interrupted() { |block| ... } click to toggle source
# File lib/rbreadline.rb, line 6954
def retry_if_interrupted(&block)
  tries = 0
  begin
    yield block
  rescue Errno::EINTR
    tries += 1
    retry if tries <= 10
  end
end
rl_abort(count, key) click to toggle source
# File lib/rbreadline.rb, line 4811
def rl_abort(count, key)
  _rl_abort_internal()
end
rl_add_undo(what, start, _end, text) click to toggle source
  • Remember how to undo something. Concatenate some undos if that

    seems right.
# File lib/rbreadline.rb, line 4942
def rl_add_undo(what, start, _end, text)
  temp = alloc_undo_entry(what, start, _end, text)
  temp.next = @rl_undo_list
  @rl_undo_list = temp
end
rl_alphabetic(c) click to toggle source
# File lib/rbreadline.rb, line 5210
def rl_alphabetic(c)
  if c =~ /\w/
    return true
  end

  return !!(@_rl_allow_pathname_alphabetic_chars &&
            @pathname_alphabetic_chars[c])
end
rl_arrow_keys(count, c) click to toggle source
# File lib/rbreadline.rb, line 5541
def rl_arrow_keys(count, c)
  rl_setstate(RL_STATE_MOREINPUT)
  ch = rl_read_key()
  rl_unsetstate(RL_STATE_MOREINPUT)

  case (ch.upcase)
  when 'A'
    rl_get_previous_history(count, ch)
  when 'B'
    rl_get_next_history(count, ch)
  when 'C'
    rl_forward_byte(count, ch)
  when 'D'
    rl_backward_byte(count, ch)
  else
    rl_ding()
  end
  0
end
rl_backward(count, key) click to toggle source

Backwards compatibility.

# File lib/rbreadline.rb, line 5187
def rl_backward(count, key)
  rl_backward_char(count, key)
end
rl_backward_byte(count, key) click to toggle source

Move backward COUNT bytes.

# File lib/rbreadline.rb, line 5142
def rl_backward_byte(count, key)
  if (count < 0)
    return (rl_forward_byte(-count, key))
  end
  if (count > 0)
    if (@rl_point < count)
      @rl_point = 0
      rl_ding()
    else
      @rl_point -= count
    end
  end

  if (@rl_point < 0)
    @rl_point = 0
  end
  0
end
rl_backward_char(count, key) click to toggle source

Move backward COUNT characters.

# File lib/rbreadline.rb, line 5162
def rl_backward_char(count, key)
  if @rl_byte_oriented
    return (rl_backward_byte(count, key))
  end
  if (count < 0)
    return (rl_forward_char(-count, key))
  end

  if (count > 0)
    point = @rl_point
    while (count > 0 && point > 0)
      point = _rl_find_prev_mbchar(@rl_line_buffer, point, MB_FIND_NONZERO)
      count-=1
    end
    if (count > 0)
      @rl_point = 0
      rl_ding()
    else
      @rl_point = point
    end
  end
  0
end
rl_backward_kill_line(direction, ignore) click to toggle source

Kill backwards to the start of the line. If DIRECTION is negative, kill

forwards to the line end instead.
# File lib/rbreadline.rb, line 7156
def rl_backward_kill_line(direction, ignore)
  if (direction < 0)
    return (rl_kill_line(1, ignore))
  else
    if (@rl_point==0)
      rl_ding()
    else
      orig_point = @rl_point
      rl_beg_of_line(1, ignore)
      if (@rl_point != orig_point)
        rl_kill_text(orig_point, @rl_point)
      end
      if (@rl_editing_mode == @emacs_mode)
        @rl_mark = @rl_point
      end
    end
  end
  0
end
rl_backward_kill_word(count, ignore) click to toggle source

Rubout the word before point, placing it on the kill ring.

# File lib/rbreadline.rb, line 7750
def rl_backward_kill_word(count, ignore)
  if (count < 0)
    return (rl_kill_word(-count, ignore))
  else
    orig_point = @rl_point
    rl_backward_word(count, ignore)
    if (@rl_point != orig_point)
      rl_kill_text(orig_point, @rl_point)
    end
    if (@rl_editing_mode == @emacs_mode)
      @rl_mark = @rl_point
    end
  end
  0
end
rl_backward_word(count, key) click to toggle source

Move backward a word. We do what Emacs does. Handles multibyte chars.

# File lib/rbreadline.rb, line 5279
def rl_backward_word(count, key)
  if (count < 0)
    return (rl_forward_word(-count, key))
  end
  while (count>0)
    return 0 if (@rl_point == 0)

    # Like rl_forward_word (), except that we look at the characters
    # just before point.
    _p =  !@rl_byte_oriented ? _rl_find_prev_mbchar(@rl_line_buffer, @rl_point, MB_FIND_NONZERO):(@rl_point-1)
    c = _rl_char_value(@rl_line_buffer, _p)
    if (!_rl_walphabetic(c))
      @rl_point = _p
      while (@rl_point > 0)
        _p = !@rl_byte_oriented ? _rl_find_prev_mbchar(@rl_line_buffer, @rl_point, MB_FIND_NONZERO):(@rl_point-1)
        c = _rl_char_value(@rl_line_buffer, _p)
        if (_rl_walphabetic(c))
          break
        end
        @rl_point = _p
      end
    end
    while (@rl_point>0)
      _p = !@rl_byte_oriented ? _rl_find_prev_mbchar(@rl_line_buffer, @rl_point, MB_FIND_NONZERO):(@rl_point-1)
      c = _rl_char_value(@rl_line_buffer, _p)
      if (!_rl_walphabetic(c))
        break
      else
        @rl_point = _p
      end
    end
    count -= 1
  end
  0
end
rl_beg_of_line(count, key) click to toggle source

Move to the beginning of the line.

# File lib/rbreadline.rb, line 5192
def rl_beg_of_line(count, key)
  @rl_point = 0
  0
end
rl_begin_undo_group() click to toggle source

Begin a group. Subsequent undos are undone as an atomic operation.

# File lib/rbreadline.rb, line 5009
def rl_begin_undo_group()
  rl_add_undo(UNDO_BEGIN, 0, 0, nil)
  @_rl_undo_group_level+=1
  0
end
rl_beginning_of_history(count, key) click to toggle source

Meta-< goes to the start of the history.

# File lib/rbreadline.rb, line 7916
def rl_beginning_of_history(count, key)
  rl_get_previous_history(1 + where_history(), key)
end
rl_bind_key(key, function) click to toggle source

Bind KEY to FUNCTION. Returns non-zero if KEY is out of range.

# File lib/rbreadline.rb, line 2441
def rl_bind_key(key, function)
  @_rl_keymap[rl_translate_keyseq(key)] = function
  @rl_binding_keymap = @_rl_keymap
  0
end
rl_bind_keyseq_if_unbound(keyseq, default_func) click to toggle source
# File lib/rbreadline.rb, line 1948
def rl_bind_keyseq_if_unbound(keyseq, default_func)
  rl_bind_keyseq_if_unbound_in_map(keyseq, default_func, @_rl_keymap)
end
rl_bind_keyseq_if_unbound_in_map(keyseq, default_func, kmap) click to toggle source

Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right

now, this is always used to attempt to bind the arrow keys, hence the
check for rl_vi_movement_mode.
# File lib/rbreadline.rb, line 1936
def rl_bind_keyseq_if_unbound_in_map(keyseq, default_func, kmap)
  if (keyseq)
    func = rl_function_of_keyseq(keyseq, kmap, nil)
    if (func.nil? || func == :rl_vi_movement_mode)
      return (rl_bind_keyseq_in_map(keyseq, default_func, kmap))
    else
      return 1
    end
  end
  0
end
rl_bind_keyseq_in_map(keyseq, function, map) click to toggle source

Bind the key sequence represented by the string KEYSEQ to

FUNCTION.  This makes new keymaps as necessary.  The initial
place to do bindings is in MAP.
# File lib/rbreadline.rb, line 1928
def rl_bind_keyseq_in_map(keyseq, function, map)
  rl_generic_bind(ISFUNC, keyseq, function, map)
end
rl_capitalize_word(count, key) click to toggle source

Upcase the first letter, downcase the rest.

# File lib/rbreadline.rb, line 7939
def rl_capitalize_word(count, key)
  rl_change_case(count, CapCase)
end
rl_change_case(count, op) click to toggle source

The meaty function.

Change the case of COUNT words, performing OP on them.
OP is one of UpCase, DownCase, or CapCase.
If a negative argument is given, leave point where it started,
otherwise, leave it where it moves to.
# File lib/rbreadline.rb, line 7964
def rl_change_case(count, op)
  start = @rl_point
  rl_forward_word(count, 0)
  _end = @rl_point

  if (op != UpCase && op != DownCase && op != CapCase)
    rl_ding()
    return -1
  end

  if (count < 0)
    start,_end = _end,start
  end

  # We are going to modify some text, so let's prepare to undo it.
  rl_modifying(start, _end)

  inword = false
  while (start < _end)
    c = _rl_char_value(@rl_line_buffer, start)
    #  This assumes that the upper and lower case versions are the same width.
    if !@rl_byte_oriented
      _next = _rl_find_next_mbchar(@rl_line_buffer, start, 1, MB_FIND_NONZERO)
    else
      _next = start + 1
    end

    if (!_rl_walphabetic(c))
      inword = false
      start = _next
      next
    end

    if (op == CapCase)
      nop = inword ? DownCase : UpCase
      inword = true
    else
      nop = op
    end
    if (isascii(c))
      nc = (nop == UpCase) ? c.upcase : c.downcase
      @rl_line_buffer[start] = nc
    end

    start = _next
  end

  @rl_point = _end
  0
end
rl_character_len(c, pos) click to toggle source
# File lib/rbreadline.rb, line 5793
def rl_character_len(c, pos)
  if (meta_char(c))
    return ((!@_rl_output_meta_chars) ? 4 : 1)
  end
  if (c == "\t")
    return (((pos | 7) + 1) - pos)
  end
  if (ctrl_char(c) || c == RUBOUT)
    return (2)
  end

  return ((isprint(c)) ? 1 : 2)
end
rl_cleanup_after_signal() click to toggle source

Clean up the terminal and readline state after catching a signal, before

resending it to the calling application.
# File lib/rbreadline.rb, line 1509
def rl_cleanup_after_signal()
  _rl_clean_up_for_exit()
  if (@rl_deprep_term_function)
    send(@rl_deprep_term_function)
  end
  rl_clear_pending_input()
  rl_clear_signals()
end
rl_clear_message() click to toggle source

How to clear things from the “echo-area”.

# File lib/rbreadline.rb, line 4301
def rl_clear_message()
  @rl_display_prompt = @rl_prompt
  if (@msg_saved_prompt)
    rl_restore_prompt()
    @msg_saved_prompt = nil
  end
  send(@rl_redisplay_function)
  0
end
rl_clear_pending_input() click to toggle source

Clear any pending input pushed with rl_execute_next()

# File lib/rbreadline.rb, line 1648
def rl_clear_pending_input()
  @rl_pending_input = 0
  rl_unsetstate(RL_STATE_INPUTPENDING)
  0
end
rl_clear_screen(count, key) click to toggle source

C-l typed to a line without quoting clears the screen, and then reprints

the prompt and the current input line.  Given a numeric arg, redraw only
the current line.
# File lib/rbreadline.rb, line 5365
def rl_clear_screen(count, key)
  if (@rl_explicit_arg)
    rl_refresh_line(count, key)
    return 0
  end

  _rl_clear_screen()      # calls termcap function to clear screen
  rl_forced_update_display()
  @rl_display_fixed = true
  0
end
rl_clear_signals() click to toggle source
# File lib/rbreadline.rb, line 1658
def rl_clear_signals()
  if Signal.list['WINCH']
    trap "WINCH",@def_proc
  end
end
rl_complete(ignore, invoking_key) click to toggle source

Complete the word at or before point. You have supplied the function

that does the initial simple matching selection algorithm (see
rl_completion_matches ()).  The default is to do filename completion.
# File lib/rbreadline.rb, line 6893
def rl_complete(ignore, invoking_key)
  if (@rl_inhibit_completion)
    return (_rl_insert_char(ignore, invoking_key))
  elsif (@rl_last_func == :rl_complete && !@completion_changed_buffer)
    return (rl_complete_internal('?'))
  elsif (@_rl_complete_show_all)
    return (rl_complete_internal('!'))
  elsif (@_rl_complete_show_unmodified)
    return (rl_complete_internal('@'))
  else
    return (rl_complete_internal(TAB))
  end
end
rl_complete_internal(what_to_do) click to toggle source

Complete the word at or before point.

WHAT_TO_DO says what to do with the completion.
`?' means list the possible completions.
TAB means do standard completion.
`*' means insert all of the possible completions.
`!' means to do standard completion, and list all possible completions if
there is more than one.
`@' means to do standard completion, and list all possible completions if
there is more than one and partial completion is not possible.
# File lib/rbreadline.rb, line 6790
def rl_complete_internal(what_to_do)
  rl_setstate(RL_STATE_COMPLETING)
  set_completion_defaults(what_to_do)

  saved_line_buffer = @rl_line_buffer ? @rl_line_buffer.delete(0.chr) : nil
  our_func = @rl_completion_entry_function ?
    @rl_completion_entry_function : :rl_filename_completion_function
  # We now look backwards for the start of a filename/variable word.
  _end = @rl_point
  found_quote = false
  delimiter = 0.chr
  quote_char = 0.chr

  if (@rl_point!=0)
    # This (possibly) changes rl_point.  If it returns a non-zero char,
    #   we know we have an open quote.
    quote_char,found_quote,delimiter = _rl_find_completion_word()
  end

  start = @rl_point
  @rl_point = _end

  text = rl_copy_text(start, _end)
  matches = gen_completion_matches(text, start, _end, our_func, found_quote, quote_char)
  # nontrivial_lcd is set if the common prefix adds something to the word
  #   being completed.
  nontrivial_lcd = !!(matches && text != matches[0])
  text = nil
  if matches.nil?
    rl_ding()
    saved_line_buffer = nil
    @completion_changed_buffer = false
    rl_unsetstate(RL_STATE_COMPLETING)
    return 0
  end

  # If we are matching filenames, the attempted completion function will
  #   have set rl_filename_completion_desired to a non-zero value.  The basic
  #   rl_filename_completion_function does this.
  i = @rl_filename_completion_desired
  if (postprocess_matches(matches, i) == 0)
    rl_ding()
    saved_line_buffer = nil
    @completion_changed_buffer = false
    rl_unsetstate(RL_STATE_COMPLETING)
    return 0
  end

  case (what_to_do)

  when TAB,'!','@'
    # Insert the first match with proper quoting.
    if (matches[0])
      insert_match(matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, quote_char)
    end
  # If there are more matches, ring the bell to indicate.
  # If we are in vi mode, Posix.2 says to not ring the bell.
  # If the `show-all-if-ambiguous' variable is set, display
  # all the matches immediately.  Otherwise, if this was the
  # only match, and we are hacking files, check the file to
  # see if it was a directory.  If so, and the `mark-directories'
  # variable is set, add a '/' to the name.  If not, and we
  # are at the end of the line, then add a space.
  if (matches[1])
    if (what_to_do == '!')
      display_matches(matches)
    elsif (what_to_do == '@')
      if (!nontrivial_lcd)
        display_matches(matches)
      end
    elsif (@rl_editing_mode != @vi_mode)
      rl_ding()   # There are other matches remaining.
    end
  else
    append_to_match(matches[0], delimiter, quote_char, nontrivial_lcd)
  end
  when '*'
    insert_all_matches(matches, start, quote_char)
  when '?'
    display_matches(matches)
  else
    $stderr.write("\r\nreadline: bad value #{what_to_do} for what_to_do in rl_complete\n")
    rl_ding()
    saved_line_buffer = nil
    rl_unsetstate(RL_STATE_COMPLETING)
    return 1
  end

  matches = nil

  # Check to see if the line has changed through all of this manipulation.
  if (saved_line_buffer)
    @completion_changed_buffer = @rl_line_buffer.delete(0.chr) != saved_line_buffer
    saved_line_buffer = nil
  end

  rl_unsetstate(RL_STATE_COMPLETING)
  0
end
rl_completion_matches(text, entry_function) click to toggle source

Return an array of (char *) which is a list of completions for TEXT.

If there are no completions, return a NULL pointer.
The first entry in the returned array is the substitution for TEXT.
The remaining entries are the possible completions.
The array is terminated with a NULL pointer.

ENTRY_FUNCTION is a function of two args, and returns a (char *).
  The first argument is TEXT.
  The second is a state argument it should be zero on the first call, and
  non-zero on subsequent calls.  It returns a NULL pointer to the caller
  when there are no more matches.
# File lib/rbreadline.rb, line 1293
def rl_completion_matches(text, entry_function)
  matches = 0
  match_list = []
  match_list[1] = nil
  while (string = send(entry_function, text, matches))
    match_list[matches+=1] = string
    match_list[matches+1] = nil
  end

  # If there were any matches, then look through them finding out the
  # lowest common denominator.  That then becomes match_list[0].
  if (matches!=0)
    compute_lcd_of_matches(match_list, matches, text)
  else                # There were no matches.
    match_list = nil
  end
  return (match_list)
end
rl_copy_text(from, to) click to toggle source
# File lib/rbreadline.rb, line 4983
def rl_copy_text(from, to)
  return @rl_line_buffer[from...to]
end
rl_crlf() click to toggle source

Move to the start of the next line.

# File lib/rbreadline.rb, line 4691
def rl_crlf()
  if (@_rl_term_cr)
    @_rl_out_stream.write(@_rl_term_cr)
  end
  @_rl_out_stream.write("\n")
  return 0
end
rl_delete(count, key) click to toggle source

Delete the character under the cursor. Given a numeric argument,

kill that many characters instead.
# File lib/rbreadline.rb, line 5903
def rl_delete(count, key)
  if (count < 0)
    return (_rl_rubout_char(-count, key))
  end
  if (@rl_point == @rl_end)
    rl_ding()
    return -1
  end

  if (count > 1 || @rl_explicit_arg)
    xpoint = @rl_point
    rl_forward_byte(count, key)

    rl_kill_text(xpoint, @rl_point)
    @rl_point = xpoint
  else
    if !@rl_byte_oriented
      xpoint =_rl_find_next_mbchar(@rl_line_buffer, @rl_point, 1, MB_FIND_NONZERO)
    else
      xpoint = @rl_point + 1
    end

    rl_delete_text(@rl_point, xpoint)
  end
  0
end
rl_delete_horizontal_space(count, ignore) click to toggle source

Delete all spaces and tabs around point.

# File lib/rbreadline.rb, line 6075
def rl_delete_horizontal_space(count, ignore)
  start = @rl_point

  while (@rl_point!=0 && whitespace(@rl_line_buffer[@rl_point - 1]))
    @rl_point-=1
  end
  start = @rl_point
  while (@rl_point < @rl_end && whitespace(@rl_line_buffer[@rl_point]))
    @rl_point+=1
  end
  if (start != @rl_point)
    rl_delete_text(start, @rl_point)
    @rl_point = start
  end
  if (@rl_point < 0)
    @rl_point = 0
  end
  0
end
rl_delete_or_show_completions(count, key) click to toggle source

Like the tcsh editing function delete-char-or-list. The eof character

is caught before this is invoked, so this really does the same thing as
delete-char-or-list-or-eof, as long as it's bound to the eof character.
# File lib/rbreadline.rb, line 6103
def rl_delete_or_show_completions(count, key)
  if (@rl_end != 0 && @rl_point == @rl_end)
    return (rl_possible_completions(count, key))
  else
    return (rl_delete(count, key))
  end
end
rl_delete_text(from, to) click to toggle source

Delete the string between FROM and TO. FROM is inclusive, TO is not.

Returns the number of characters deleted.
# File lib/rbreadline.rb, line 4951
def rl_delete_text(from, to)

  # Fix it if the caller is confused.
  if (from > to)
    from,to = to,from
  end

  # fix boundaries
  if (to > @rl_end)
    to = @rl_end
    if (from > to)
      from = to
    end
  end
  if (from < 0)
    from = 0
  end
  text = rl_copy_text(from, to)
  diff = to - from
  @rl_line_buffer[from...to] = ''
  @rl_line_buffer << 0.chr * diff
  # Remember how to undo this delete.
  if (!@_rl_doing_an_undo)
    rl_add_undo(UNDO_DELETE, from, to, text)
  else
    text = nil
  end
  @rl_end -= diff
  @rl_line_buffer[@rl_end,1] = 0.chr
  return (diff)
end
rl_deprep_terminal() click to toggle source

Restore the terminal’s normal settings and modes.

# File lib/rbreadline.rb, line 7099
def rl_deprep_terminal()
  return if ENV["TERM"].nil?
  return if (!@terminal_prepped)

  # Try to keep this function from being interrupted.
  block_sigint()

  if (@_rl_enable_keypad)
    _rl_control_keypad(false)
  end

  @rl_outstream.flush

  # restore terminal setting
  retry_if_interrupted do
    `stty #{@otio}`
  end

  @terminal_prepped = false
  rl_unsetstate(RL_STATE_TERMPREPPED)

  release_sigint()
end
rl_digit_argument(ignore, key) click to toggle source

Start a numeric argument with initial value KEY

# File lib/rbreadline.rb, line 7896
def rl_digit_argument(ignore, key)
  _rl_arg_init()
  if (rl_isstate(RL_STATE_CALLBACK))
    _rl_arg_dispatch(@_rl_argcxt, key)
    rl_message("(arg: #{@rl_arg_sign * @rl_numeric_arg}) ")
    return 0
  else
    rl_execute_next(key)
    return (rl_digit_loop())
  end
end
rl_digit_loop() click to toggle source

Handle C-u style numeric args, as well as M–, and M-digits.

# File lib/rbreadline.rb, line 7880
def rl_digit_loop()
  while (true)
    return 1 if _rl_arg_overflow()!=0
    c = _rl_arg_getchar()
    if (c >= "\xFE")
      _rl_abort_internal()
      return -1
    end
    r = _rl_arg_dispatch(@_rl_argcxt, c)
    break if (r <= 0 || !rl_isstate(RL_STATE_NUMERICARG))
  end

  return r
end
rl_ding() click to toggle source

Ring the terminal bell.

# File lib/rbreadline.rb, line 4024
def rl_ding()
  if @MessageBeep
    @MessageBeep.Call(0)
  elsif @readline_echoing_p
    if @_rl_bell_preference == VISIBLE_BELL
      if (@_rl_visible_bell)
        @_rl_out_stream.write(@_rl_visible_bell.chr)
      else
        $stderr.write("\007")
        $stderr.flush
      end
    elsif @_rl_bell_preference == AUDIBLE_BELL
      $stderr.write("\007")
      $stderr.flush
    end
    return 0
  end
  return -1
end
rl_display_match_list(matches, len, max) click to toggle source

A convenience function for displaying a list of strings in

columnar format on readline's output stream.  MATCHES is the list
of strings, in argv format, LEN is the number of strings in MATCHES,
and MAX is the length of the longest string in MATCHES.
# File lib/rbreadline.rb, line 8383
def rl_display_match_list(matches, len, max)
  # How many items of MAX length can we fit in the screen window?
  max += 2
  limit = @_rl_screenwidth / max
  if (limit != 1 && (limit * max == @_rl_screenwidth))
    limit-=1
  end
  # Avoid a possible floating exception.  If max > _rl_screenwidth,
  #   limit will be 0 and a divide-by-zero fault will result.
  if (limit == 0)
    limit = 1
  end
  # How many iterations of the printing loop?
  count = (len + (limit - 1)) / limit

  # Watch out for special case.  If LEN is less than LIMIT, then
  #   just do the inner printing loop.
  #     0 < len <= limit  implies  count = 1.

  # Sort the items if they are not already sorted.
  if (!@rl_ignore_completion_duplicates)
    matches[1,len] = matches[1,len].sort
  end
  rl_crlf()

  lines = 0
  if (!@_rl_print_completions_horizontally)
    # Print the sorted items, up-and-down alphabetically, like ls.
    for i in 1 .. count
      l = i
      for j in 0 ... limit
        if (l > len || matches[l].nil?)
          break
        else
          temp = printable_part(matches[l])
          printed_len = print_filename(temp, matches[l])

          if (j + 1 < limit)
            @rl_outstream.write(' '*(max - printed_len))
          end
        end
        l += count
      end
      rl_crlf()
      lines+=1
      if (@_rl_page_completions && lines >= (@_rl_screenheight - 1) && i < count)
        lines = _rl_internal_pager(lines)
        return if (lines < 0)
      end
    end
  else
    # Print the sorted items, across alphabetically, like ls -x.
    i = 1
    while(matches[i])
      temp = printable_part(matches[i])
      printed_len = print_filename(temp, matches[i])
      # Have we reached the end of this line?
      if (matches[i+1])
        if ((limit > 1) && (i % limit) == 0)
          rl_crlf()
          lines+=1
          if (@_rl_page_completions && lines >= @_rl_screenheight - 1)
            lines = _rl_internal_pager(lines)
            return if (lines < 0)
          end
        else
          @rl_outstream.write(' '*(max - printed_len))
        end
      end
      i += 1
    end
    rl_crlf()
  end
end
rl_do_lowercase_version(ignore1, ignore2) click to toggle source

What to do for some uppercase characters, like meta characters,

and some characters appearing in emacs_ctlx_keymap.  This function
is just a stub, you bind keys to it and the code in _rl_dispatch ()
is special cased.
# File lib/rbreadline.rb, line 5789
def rl_do_lowercase_version(ignore1, ignore2)
  0
end
rl_do_undo() click to toggle source
# File lib/rbreadline.rb, line 7661
def rl_do_undo()
  start = _end = waiting_for_begin = 0
  begin
    return 0 if @rl_undo_list.nil?

    @_rl_doing_an_undo = true
    rl_setstate(RL_STATE_UNDOING)

    # To better support vi-mode, a start or end value of -1 means
    # rl_point, and a value of -2 means rl_end.
    if (@rl_undo_list.what == UNDO_DELETE || @rl_undo_list.what == UNDO_INSERT)
      start = trans(@rl_undo_list.start)
      _end = trans(@rl_undo_list.end)
    end

    case (@rl_undo_list.what)
      # Undoing deletes means inserting some text.
    when UNDO_DELETE
      @rl_point = start
      rl_insert_text(@rl_undo_list.text)
      @rl_undo_list.text = nil

      # Undoing inserts means deleting some text.
    when UNDO_INSERT
      rl_delete_text(start, _end)
      @rl_point = start
      # Undoing an END means undoing everything 'til we get to a BEGIN.
    when UNDO_END
      waiting_for_begin+=1
      # Undoing a BEGIN means that we are done with this group.
    when UNDO_BEGIN
      if (waiting_for_begin!=0)
        waiting_for_begin-=1
      else
        rl_ding()
      end
    end

    @_rl_doing_an_undo = false
    rl_unsetstate(RL_STATE_UNDOING)

    release = @rl_undo_list
    @rl_undo_list = @rl_undo_list.next
    replace_history_data(-1, release, @rl_undo_list)
    release = nil
  end while (waiting_for_begin!=0)

  1
end
rl_downcase_word(count, key) click to toggle source

Lowercase the word at point.

# File lib/rbreadline.rb, line 7934
def rl_downcase_word(count, key)
  rl_change_case(count, DownCase)
end
rl_emacs_editing_mode(count, key) click to toggle source
# File lib/rbreadline.rb, line 1441
def rl_emacs_editing_mode(count, key)
  @rl_editing_mode = @emacs_mode
  _rl_set_insert_mode(RL_IM_INSERT, 1) # emacs mode default is insert mode
  @_rl_keymap = @emacs_standard_keymap
  0
end
rl_end_of_history(count, key) click to toggle source

Meta-> goes to the end of the history. (The current line).

# File lib/rbreadline.rb, line 7921
def rl_end_of_history(count, key)
  rl_maybe_replace_line()
  using_history()
  rl_maybe_unsave_line()
  0
end
rl_end_of_line(count, key) click to toggle source

Move to the end of the line.

# File lib/rbreadline.rb, line 5198
def rl_end_of_line(count, key)
  @rl_point = @rl_end
  0
end
rl_end_undo_group() click to toggle source

End an undo group started with rl_begin_undo_group ().

# File lib/rbreadline.rb, line 5016
def rl_end_undo_group()
  rl_add_undo(UNDO_END, 0, 0, nil)
  @_rl_undo_group_level-=1
  0
end
rl_exchange_point_and_mark(count, key) click to toggle source

Exchange the position of mark and point.

# File lib/rbreadline.rb, line 8366
def rl_exchange_point_and_mark(count, key)
  if (@rl_mark > @rl_end)
    @rl_mark = -1
  end
  if (@rl_mark == -1)
    rl_ding()
    return -1
  else
    @rl_point, @rl_mark = @rl_mark, @rl_point
  end
  0
end
rl_execute_next(c) click to toggle source

Make C be the next command to be executed.

# File lib/rbreadline.rb, line 7909
def rl_execute_next(c)
  @rl_pending_input = c
  rl_setstate(RL_STATE_INPUTPENDING)
  0
end
rl_expand_prompt(prompt) click to toggle source

*

  • Expand the prompt string into the various display components, if

  • necessary.

*

  • local_prompt = expanded last line of string in rl_display_prompt

  • (portion after the final newline)

  • local_prompt_prefix = portion before last newline of rl_display_prompt,

  • expanded via expand_prompt

  • prompt_visible_length = number of visible characters in local_prompt

  • prompt_prefix_length = number of visible characters in local_prompt_prefix

*

  • This function is called once per call to readline(). It may also be

  • called arbitrarily to expand the primary prompt.

*

  • The return value is the number of visible characters on the last line

  • of the (possibly multi-line) prompt.

*

# File lib/rbreadline.rb, line 1771
def rl_expand_prompt(prompt)
  @local_prompt = @local_prompt_prefix = nil
  @local_prompt_len = 0
  @prompt_last_invisible = @prompt_invis_chars_first_line = 0
  @prompt_visible_length = @prompt_physical_chars = 0

  if (prompt.nil? || prompt == '')
    return (0)
  end

  pi = prompt.rindex("\n")
  if pi.nil?
    # The prompt is only one logical line, though it might wrap.
    @local_prompt,@prompt_visible_length,@prompt_last_invisible,@prompt_invis_chars_first_line,@prompt_physical_chars = expand_prompt(prompt)
    @local_prompt_prefix = nil
    @local_prompt_len = @local_prompt ? @local_prompt.length : 0
    return (@prompt_visible_length)
  else
    # The prompt spans multiple lines.
    pi += 1 if prompt.length!=pi+1
    t = pi
    @local_prompt,@prompt_visible_length,@prompt_last_invisible,@prompt_invis_chars_first_line,@prompt_physical_chars = expand_prompt(prompt[pi..-1])
    c = prompt[t]
    prompt[t] = 0.chr
    # The portion of the prompt string up to and including the
    #final newline is now null-terminated.
    @local_prompt_prefix,@prompt_prefix_length,_,_, = expand_prompt(prompt)
    prompt[t] = c
    @local_prompt_len = @local_prompt ? @local_prompt.length : 0
    return (@prompt_prefix_length)
  end
end
rl_extend_line_buffer(len) click to toggle source

Increase the size of RL_LINE_BUFFER until it has enough space to hold

LEN characters.
# File lib/rbreadline.rb, line 4887
def rl_extend_line_buffer(len)
  while (len >= @rl_line_buffer.length)
    @rl_line_buffer << 0.chr * DEFAULT_BUFFER_SIZE
  end
  @the_line = @rl_line_buffer
end
rl_filename_completion_function(text, state) click to toggle source

Okay, now we write the entry_function for filename completion. In the general case. Note that completion in the shell is a little different because of all the pathnames that must be followed when looking up the completion for a command.

# File lib/rbreadline.rb, line 1119
def rl_filename_completion_function(text, state)
  # If we don't have any state, then do some initialization.
  if (state == 0)
    # If we were interrupted before closing the directory or reading
    #all of its contents, close it.
    if(@directory)
      @directory.close
      @directory = nil
    end

    text.delete!(0.chr)
    if text.length == 0
      @dirname = "."
      @filename = ""
    elsif text.rindex(File::SEPARATOR) == text.length-1
      @dirname = text
      @filename = ""
    else
      @dirname, @filename = File.split(text)

      # This preserves the "./" when the user types "./dirname<tab>".
      if @dirname == "." && text[0,2] == ".#{File::SEPARATOR}"
        @dirname += File::SEPARATOR
      end
    end

    # We aren't done yet.  We also support the "~user" syntax.

    # Save the version of the directory that the user typed.
    @users_dirname = @dirname.dup

    if (@dirname[0,1] == '~')
      @dirname = File.expand_path(@dirname)
    end

    # The directory completion hook should perform any necessary
    #   dequoting.
    if (@rl_directory_completion_hook && send(rl_directory_completion_hook,@dirname))
      @users_dirname = @dirname.dup
    elsif (@rl_completion_found_quote && @rl_filename_dequoting_function)
      # delete single and double quotes
      temp = send(@rl_filename_dequoting_function, @users_dirname, @rl_completion_quote_character)
      @users_dirname = temp
      @dirname = @users_dirname.dup
    end

    begin
      @directory = Dir.new(@dirname)
    rescue Errno::ENOENT, Errno::ENOTDIR, Errno::EACCES
    end

    # Now dequote a non-null filename.
    if (@filename && @filename.length>0 && @rl_completion_found_quote && @rl_filename_dequoting_function)
      # delete single and double quotes
      temp = send(@rl_filename_dequoting_function, @filename, @rl_completion_quote_character)
      @filename = temp
    end

    @filename_len = @filename.length
    @rl_filename_completion_desired = true
  end

  # At this point we should entertain the possibility of hacking wildcarded
  #   filenames, like /usr/man/man<WILD>/te<TAB>.  If the directory name
  #   contains globbing characters, then build an array of directories, and
  #   then map over that list while completing.
  # *** UNIMPLEMENTED ***

  # Now that we have some state, we can read the directory.
  entry = nil
  while(@directory && (entry = @directory.read))
    d_name = entry
    # Special case for no filename.  If the user has disabled the
    #   `match-hidden-files' variable, skip filenames beginning with `.'.
    #All other entries except "." and ".." match.
    if (@filename_len == 0)
      next if (!@_rl_match_hidden_files && d_name[0,1] == '.')
      break if (d_name != '.' && d_name != '..')
    else
      # Otherwise, if these match up to the length of filename, then
      #   it is a match.

      if (@_rl_completion_case_fold)
        break if d_name =~ /^#{Regexp.escape(@filename)}/i
      else
        break if d_name =~ /^#{Regexp.escape(@filename)}/
      end
    end
  end

  if entry.nil?
    if @directory
      @directory.close
      @directory = nil
    end
    @dirname = nil
    @filename = nil
    @users_dirname = nil

    return nil
  else
    if (@dirname != '.')
      if (@rl_complete_with_tilde_expansion && @users_dirname[0,1] == "~")
        temp = @dirname
        if(temp[-1,1] != File::SEPARATOR)
          temp += File::SEPARATOR
        end
      else
        temp = @users_dirname
        if(temp[-1,1] != File::SEPARATOR)
          temp += File::SEPARATOR
        end
      end
      temp += entry
    else
      temp = entry.dup
    end
    return (temp)
  end
end
rl_forced_update_display() click to toggle source

Actually update the display, period.

# File lib/rbreadline.rb, line 5336
def rl_forced_update_display()
  if (@visible_line)
    @visible_line.gsub!(/[^\x00]/,0.chr)
  end
  rl_on_new_line()
  @forced_display=true if !@forced_display
  send(@rl_redisplay_function)
  0
end
rl_forward(count, key) click to toggle source

Backwards compatibility.

# File lib/rbreadline.rb, line 5137
def rl_forward(count, key)
  rl_forward_char(count, key)
end
rl_forward_byte(count, key) click to toggle source

Move forward COUNT bytes.

# File lib/rbreadline.rb, line 5091
def rl_forward_byte(count, key)
  if (count < 0)
    return (rl_backward_byte(-count, key))
  end
  if (count > 0)
    _end = @rl_point + count
    lend = @rl_end > 0 ? @rl_end - ((@rl_editing_mode == @vi_mode)?1:0) : @rl_end
    if (_end > lend)
      @rl_point = lend
      rl_ding()
    else
      @rl_point = _end
    end
  end

  if (@rl_end < 0)
    @rl_end = 0
  end
  return 0
end
rl_forward_char(count, key) click to toggle source

Move forward COUNT characters.

# File lib/rbreadline.rb, line 5113
def rl_forward_char(count, key)
  if @rl_byte_oriented
    return (rl_forward_byte(count, key))
  end
  if (count < 0)
    return (rl_backward_char(-count, key))
  end
  if (count > 0)
    point = _rl_find_next_mbchar(@rl_line_buffer, @rl_point, count, MB_FIND_NONZERO)
    if (@rl_end <= point && @rl_editing_mode == @vi_mode)
      point = _rl_find_prev_mbchar(@rl_line_buffer, @rl_end, MB_FIND_NONZERO)
    end
    if (@rl_point == point)
      rl_ding()
    end
    @rl_point = point
    if (@rl_end < 0)
      @rl_end = 0
    end
  end
  0
end
rl_forward_search_history(sign, key) click to toggle source

Search forwards through the history looking for a string which is typed

interactively.  Start with the current line.
# File lib/rbreadline.rb, line 7194
def rl_forward_search_history(sign, key)
  rl_search_history(sign, key)
end
rl_forward_word(count, key) click to toggle source

Move forward a word. We do what Emacs does. Handles multibyte chars.

# File lib/rbreadline.rb, line 5224
def rl_forward_word(count, key)
  if (count < 0)
    return (rl_backward_word(-count, key))
  end

  while (count>0)
    return 0 if (@rl_point == @rl_end)

    # If we are not in a word, move forward until we are in one.
    # Then, move forward until we hit a non-alphabetic character.
    c = _rl_char_value(@rl_line_buffer, @rl_point)

    if (!_rl_walphabetic(c))
      if !@rl_byte_oriented
        @rl_point = _rl_find_next_mbchar(@rl_line_buffer, @rl_point, 1, MB_FIND_NONZERO)
      else
        @rl_point += 1
      end
      while (@rl_point < @rl_end)
        c = _rl_char_value(@rl_line_buffer, @rl_point)
        if (_rl_walphabetic(c))
          break
        end
        if !@rl_byte_oriented
          @rl_point = _rl_find_next_mbchar(@rl_line_buffer, @rl_point, 1, MB_FIND_NONZERO)
        else
          @rl_point += 1
        end
      end
    end

    return 0 if (@rl_point == @rl_end)

    if !@rl_byte_oriented
      @rl_point = _rl_find_next_mbchar(@rl_line_buffer, @rl_point, 1, MB_FIND_NONZERO)
    else
      @rl_point += 1
    end
    while (@rl_point < @rl_end)
      c = _rl_char_value(@rl_line_buffer, @rl_point)
      if (!_rl_walphabetic(c))
        break
      end
      if !@rl_byte_oriented
        @rl_point = _rl_find_next_mbchar(@rl_line_buffer, @rl_point, 1, MB_FIND_NONZERO)
      else
        @rl_point += 1
      end
    end
    count -= 1
  end
  0
end
rl_free_undo_list() click to toggle source
# File lib/rbreadline.rb, line 5022
def rl_free_undo_list()
  replace_history_data(-1, @rl_undo_list, nil)
  @rl_undo_list = nil
end
rl_function_of_keyseq(keyseq, map, type) click to toggle source

Return the function (or macro) definition which would be invoked via

KEYSEQ if executed in MAP.  If MAP is NULL, then the current keymap is
used.  TYPE, if non-NULL, is a pointer to an int which will receive the
type of the object pointed to.  One of ISFUNC (function), ISKMAP (keymap),
or ISMACR (macro).
# File lib/rbreadline.rb, line 1910
def rl_function_of_keyseq(keyseq, map, type)
  map ||= @_rl_keymap
  map[keyseq]
end
rl_gather_tyi() click to toggle source
# File lib/rbreadline.rb, line 4512
def rl_gather_tyi()
  chars_avail = @kbhit.Call
  return 0 if(chars_avail<=0)
  k = send(@rl_getc_function,@rl_instream)
  rl_stuff_char(k)
  return 1
end
rl_generic_bind(type, keyseq, data, map) click to toggle source

Bind the key sequence represented by the string KEYSEQ to

the arbitrary pointer DATA.  TYPE says what kind of data is
pointed to by DATA, right now this can be a function (ISFUNC),
a macro (ISMACR), or a keymap (ISKMAP).  This makes new keymaps
as necessary.  The initial place to do bindings is in MAP.
# File lib/rbreadline.rb, line 1920
def rl_generic_bind(type, keyseq, data, map)
  map[keyseq] = data
  0
end
rl_get_char() click to toggle source

Get a key from the buffer of characters to be read.

Return the key in KEY.
Result is KEY if there was a key, or 0 if there wasn't.
# File lib/rbreadline.rb, line 4604
def rl_get_char()
  if (@push_index == @pop_index)
    return nil
  end
  key = @ibuffer[@pop_index]
  @pop_index += 1

  if (@pop_index >= @ibuffer_len)
    @pop_index = 0
  end

  return key
end
rl_get_keymap_name_from_edit_mode() click to toggle source
# File lib/rbreadline.rb, line 2492
def rl_get_keymap_name_from_edit_mode()
  if (@rl_editing_mode == @emacs_mode)
    "emacs"
  elsif (@rl_editing_mode == @vi_mode)
    "vi"
  else
    "none"
  end
end
rl_get_next_history(count, key) click to toggle source

Move down to the next history line.

# File lib/rbreadline.rb, line 5510
def rl_get_next_history(count, key)
  if (count < 0)
    return (rl_get_previous_history(-count, key))
  end
  if (count == 0)
    return 0
  end
  rl_maybe_replace_line()

  # either not saved by rl_newline or at end of line, so set appropriately.
  if (@_rl_history_saved_point == -1 && (@rl_point!=0 || @rl_end!=0))
    @_rl_history_saved_point = (@rl_point == @rl_end) ? -1 : @rl_point
  end
  temp = nil
  while (count>0)
    temp = next_history()
    if temp.nil?
      break
    end
    count -= 1
  end

  if temp.nil?
    rl_maybe_unsave_line()
  else
    rl_replace_from_history(temp, 0)
    _rl_history_set_point()
  end
  0
end
rl_get_previous_history(count, key) click to toggle source

Get the previous item out of our interactive history, making it the current

line.  If there is no previous history, just ding.
# File lib/rbreadline.rb, line 5451
def rl_get_previous_history(count, key)
  if (count < 0)
    return (rl_get_next_history(-count, key))
  end
  if (count == 0)
    return 0
  end
  # either not saved by rl_newline or at end of line, so set appropriately.
  if (@_rl_history_saved_point == -1 && (@rl_point!=0 || @rl_end!=0))
    @_rl_history_saved_point = (@rl_point == @rl_end) ? -1 : @rl_point
  end

  # If we don't have a line saved, then save this one.
  rl_maybe_save_line()

  # If the current line has changed, save the changes.
  rl_maybe_replace_line()

  temp = old_temp = nil
  while (count>0)
    temp = previous_history()
    if temp.nil?
      break
    end
    old_temp = temp
    count -= 1
  end

  # If there was a large argument, and we moved back to the start of the
  #   history, that is not an error.  So use the last value found.
  if (temp.nil? && old_temp)
    temp = old_temp
  end

  if temp.nil?
    rl_ding()
  else
    rl_replace_from_history(temp, 0)
    _rl_history_set_point()
  end

  0
end
rl_getc(stream) click to toggle source
# File lib/rbreadline.rb, line 4492
def rl_getc(stream)
  while (@kbhit.Call == 0)
    # If there is no input, yield the processor for other threads
    sleep(@_keyboard_input_timeout)
  end
  c = @getch.Call
  alt = (@GetKeyState.call(VK_LMENU) & 0x80) != 0
  if c==0 || c==0xE0
    while (@kbhit.Call == 0)
      # If there is no input, yield the processor for other threads
      sleep(@_keyboard_input_timeout)
    end
    r = c.chr + @getch.Call.chr
  else
    r = c.chr
  end
  r = "\e"+r if alt
  r
end
rl_initialize() click to toggle source

Initialize readline (and terminal if not already).

# File lib/rbreadline.rb, line 3844
def rl_initialize()
  # If we have never been called before, initialize the
  #   terminal and data structures.
  if (!@rl_initialized)
    rl_setstate(RL_STATE_INITIALIZING)
    readline_initialize_everything()
    rl_unsetstate(RL_STATE_INITIALIZING)
    @rl_initialized = true
    rl_setstate(RL_STATE_INITIALIZED)
  end

  # Initalize the current line information.
  _rl_init_line_state()

  # We aren't done yet.  We haven't even gotten started yet!
  @rl_done = false
  rl_unsetstate(RL_STATE_DONE)

  # Tell the history routines what is going on.
  _rl_start_using_history()

  # Make the display buffer match the state of the line.
  rl_reset_line_state()

  # No such function typed yet.
  @rl_last_func = nil

  # Parsing of key-bindings begins in an enabled state.
  @_rl_parsing_conditionalized_out = 0

  if (@rl_editing_mode == @vi_mode)
    _rl_vi_initialize_line()
  end
  # Each line starts in insert mode (the default).
  _rl_set_insert_mode(RL_IM_DEFAULT, 1)

  return 0
end
rl_insert(count, c) click to toggle source
# File lib/rbreadline.rb, line 5651
def rl_insert(count, c)
  ((@rl_insert_mode == RL_IM_INSERT) ? _rl_insert_char(count, c) :
   _rl_overwrite_char(count, c))
end
rl_insert_comment(count, key) click to toggle source

Turn the current line into a comment in shell history.

A K*rn shell style function.
# File lib/rbreadline.rb, line 6113
def rl_insert_comment(count, key)
  rl_beg_of_line(1, key)
  @rl_comment_text = @_rl_comment_begin ? @_rl_comment_begin : '#'

  if (!@rl_explicit_arg)
    rl_insert_text(@rl_comment_text)
  else
    @rl_comment_len = @rl_comment_text.length
    if @rl_comment_text[0,@rl_comment_len] == @rl_line_buffer[0,@rl_comment_len]
      rl_delete_text(@rl_point, @rl_point + @rl_comment_len)
    else
      rl_insert_text(@rl_comment_text)
    end
  end

  send(@rl_redisplay_function)
  rl_newline(1, "\n")
  0
end
rl_insert_completions(ignore, invoking_key) click to toggle source
# File lib/rbreadline.rb, line 7785
def rl_insert_completions(ignore, invoking_key)
  rl_complete_internal('*')
end
rl_insert_text(string) click to toggle source

Insert a string of text into the line at point. This is the only

way that you should do insertion.  _rl_insert_char () calls this
function.  Returns the number of characters inserted.
# File lib/rbreadline.rb, line 4897
def rl_insert_text(string)
  string.delete!(0.chr)
  l = string.length
  return 0 if (l == 0)

  if (@rl_end + l >= @rl_line_buffer.length)
    rl_extend_line_buffer(@rl_end + l)
  end
  @rl_line_buffer[@rl_point,0] = string

  # Remember how to undo this if we aren't undoing something.
  if (!@_rl_doing_an_undo)
    # If possible and desirable, concatenate the undos.
    if ((l == 1) &&
        @rl_undo_list &&
        (@rl_undo_list.what == UNDO_INSERT) &&
        (@rl_undo_list.end == @rl_point) &&
        (@rl_undo_list.end - @rl_undo_list.start < 20))
      @rl_undo_list.end+=1
    else
      rl_add_undo(UNDO_INSERT, @rl_point, @rl_point + l, nil)
    end
  end
  @rl_point += l
  @rl_end += l
  if @rl_line_buffer.length <= @rl_end
    @rl_line_buffer << 0.chr * (@rl_end - @rl_line_buffer.length + 1)
  else
    @rl_line_buffer[@rl_end] = "\0"
  end
  l
end
rl_isstate(x) click to toggle source
# File lib/rbreadline.rb, line 1643
def rl_isstate(x)
  (@rl_readline_state & (x))!=0
end
rl_kill_full_line(count, ignore) click to toggle source

Kill the whole line, no matter where point is.

# File lib/rbreadline.rb, line 7177
def rl_kill_full_line(count, ignore)
  rl_begin_undo_group()
  @rl_point = 0
  rl_kill_text(@rl_point, @rl_end)
  @rl_mark = 0
  rl_end_undo_group()
  0
end
rl_kill_line(direction, ignore) click to toggle source

Kill from here to the end of the line. If DIRECTION is negative, kill

back to the line start instead.
# File lib/rbreadline.rb, line 7137
def rl_kill_line (direction, ignore)
  if (direction < 0)
    return (rl_backward_kill_line(1, ignore))
  else
    orig_point = @rl_point
    rl_end_of_line(1, ignore)
    if (orig_point != @rl_point)
      rl_kill_text(orig_point, @rl_point)
    end
    @rl_point = orig_point
    if (@rl_editing_mode == @emacs_mode)
      @rl_mark = @rl_point
    end
  end
  0
end
rl_kill_text(from, to) click to toggle source

The way to kill something. This appends or prepends to the last

kill, if the last command was a kill command.  if FROM is less
than TO, then the text is appended, otherwise prepended.  If the
last command was not a kill command, then a new slot is made for
this kill.
# File lib/rbreadline.rb, line 5983
def rl_kill_text(from, to)
  # Is there anything to kill?
  if (from == to)
    @_rl_last_command_was_kill = true if !@_rl_last_command_was_kill
    return 0
  end
  text = rl_copy_text(from, to)

  # Delete the copied text from the line.
  rl_delete_text(from, to)
  _rl_copy_to_kill_ring(text, from < to)
  @_rl_last_command_was_kill = true if !@_rl_last_command_was_kill
  0
end
rl_kill_word(count, key) click to toggle source

Delete the word at point, saving the text in the kill ring.

# File lib/rbreadline.rb, line 7730
def rl_kill_word(count, key)
  if (count < 0)
    return (rl_backward_kill_word(-count, key))
  else
    orig_point = @rl_point
    rl_forward_word(count, key)

    if (@rl_point != orig_point)
      rl_kill_text(orig_point, @rl_point)
    end

    @rl_point = orig_point
    if (@rl_editing_mode == @emacs_mode)
      @rl_mark = @rl_point
    end
  end
  0
end
rl_line_buffer() click to toggle source
# File lib/rbreadline.rb, line 3813
def rl_line_buffer
  @rl_line_buffer.tr(0.chr, '')
end
rl_maybe_replace_line() click to toggle source

Perhaps put back the current line if it has changed.

# File lib/rbreadline.rb, line 5426
def rl_maybe_replace_line()
  temp = current_history()
  # If the current line has changed, save the changes.
  if (temp && temp.data != @rl_undo_list)
    temp = replace_history_entry(where_history(), @rl_line_buffer, @rl_undo_list)
  end
  0
end
rl_maybe_save_line() click to toggle source

Save the current line in _rl_saved_line_for_history.

# File lib/rbreadline.rb, line 5393
def rl_maybe_save_line()
  if @_rl_saved_line_for_history.nil?
    @_rl_saved_line_for_history = Struct.new(:line,:timestamp,:data).new
    @_rl_saved_line_for_history.line = @rl_line_buffer.dup
    @_rl_saved_line_for_history.timestamp = nil
    @_rl_saved_line_for_history.data = @rl_undo_list
  end
  0
end
rl_maybe_unsave_line() click to toggle source

Restore the _rl_saved_line_for_history if there is one.

# File lib/rbreadline.rb, line 5378
def rl_maybe_unsave_line()
  if (@_rl_saved_line_for_history)
    # Can't call with `1' because rl_undo_list might point to an undo
    # list from a history entry, as in rl_replace_from_history() below.
    rl_replace_line(@_rl_saved_line_for_history.line, false)
    @rl_undo_list = @_rl_saved_line_for_history.data
    @_rl_saved_line_for_history = nil
    @rl_point = @rl_end  # rl_replace_line sets rl_end
  else
    rl_ding()
  end
  0
end
rl_message(msg_buf) click to toggle source
# File lib/rbreadline.rb, line 7361
def rl_message(msg_buf)
  @rl_display_prompt = msg_buf
  if @saved_local_prompt.nil?
    rl_save_prompt()
    @msg_saved_prompt = true
  end
  @local_prompt,@prompt_visible_length,@prompt_last_invisible,@prompt_invis_chars_first_line,@prompt_physical_chars =
    expand_prompt(msg_buf)
  @local_prompt_prefix = nil
  @local_prompt_len = @local_prompt ? @local_prompt.length : 0
  send(@rl_redisplay_function)
  0
end
rl_modifying(start, _end) click to toggle source

Save an undo entry for the text from START to END.

# File lib/rbreadline.rb, line 7944
def rl_modifying(start, _end)
  if (start > _end)
    start,_end = _end,start
  end

  if (start != _end)
    temp = rl_copy_text(start, _end)
    rl_begin_undo_group()
    rl_add_undo(UNDO_DELETE, start, _end, temp)
    rl_add_undo(UNDO_INSERT, start, _end, nil)
    rl_end_undo_group()
  end
  0
end
rl_named_function(name) click to toggle source
# File lib/rbreadline.rb, line 2344
def rl_named_function(name)
  case name
  when "accept-line"
    return :rl_newline
  when "arrow-key-prefix"
    return :rl_arrow_keys
  when "backward-delete-char"
    return :rl_rubout
  when "character-search"
    return :rl_char_search
  when  "character-search-backward"
    return :rl_backward_char_search
  when "copy-region-as-kill"
    return :rl_copy_region_to_kill
  when "delete-char"
    return :rl_delete
  when "delete-char-or-list"
    return :rl_delete_or_show_completions
  when "forward-backward-delete-char"
    return :rl_rubout_or_delete
  when "kill-whole-line"
    return :rl_kill_full_line
  when "next-history"
    return :rl_get_next_history
  when "non-incremental-forward-search-history"
    return :rl_noninc_forward_search
  when "non-incremental-reverse-search-history"
    return :rl_noninc_reverse_search
  when "non-incremental-forward-search-history-again"
    return :rl_noninc_forward_search_again
  when "non-incremental-reverse-search-history-again"
    return :rl_noninc_reverse_search_again
  when "redraw-current-line"
    return :rl_refresh_line
  when "previous-history"
    return :rl_get_previous_history
  when "self-insert"
    return :rl_insert
  when "undo"
    return :rl_undo_command
  when "beginning-of-line"
    return :rl_beg_of_line
  else
    if name =~ /^[-a-z]+$/
      method = ('rl_' + name.gsub('-', '_')).to_sym
      return method if respond_to?(method)
    end
  end
  nil
end
rl_newline(count, key) click to toggle source

What to do when a NEWLINE is pressed. We accept the whole line.

KEY is the key that invoked this command.  I guess it could have
meaning in the future.
# File lib/rbreadline.rb, line 5760
def rl_newline(count, key)
  @rl_done = true

  if (@_rl_history_preserve_point)
    @_rl_history_saved_point = (@rl_point == @rl_end) ? 1 : @rl_point
  end
  rl_setstate(RL_STATE_DONE)

  if (@rl_editing_mode == @vi_mode)
    _rl_vi_done_inserting()
    if (_rl_vi_textmod_command(@_rl_vi_last_command).nil?)   # XXX
      _rl_vi_reset_last()
    end
  end
  # If we've been asked to erase empty lines, suppress the final update,
  #   since _rl_update_final calls rl_crlf().
  if (@rl_erase_empty_line && @rl_point == 0 && @rl_end == 0)
    return 0
  end
  if @readline_echoing_p
    _rl_update_final()
  end
  0
end
rl_on_new_line() click to toggle source

Tell the update routines that we have moved onto a new (empty) line.

# File lib/rbreadline.rb, line 3818
def rl_on_new_line()
  if (@visible_line)
    @visible_line[0,1] = 0.chr
  end
  @_rl_last_c_pos = @_rl_last_v_pos = 0
  @_rl_vis_botlin = @last_lmargin = 0
  if (@vis_lbreaks)
    @vis_lbreaks[0] = @vis_lbreaks[1] = 0
  end
  @visible_wrap_offset = 0
  0
end
rl_on_new_line_with_prompt() click to toggle source

Tell the update routines that we have moved onto a new line with the

prompt already displayed.  Code originally from the version of readline
distributed with CLISP.  rl_expand_prompt must have already been called
(explicitly or implicitly).  This still doesn't work exactly right.
# File lib/rbreadline.rb, line 3927
def rl_on_new_line_with_prompt()
  # Initialize visible_line and invisible_line to ensure that they can hold
  #   the already-displayed prompt.
  prompt_size = @rl_prompt.length + 1
  init_line_structures(prompt_size)

  # Make sure the line structures hold the already-displayed prompt for
  #   redisplay.
  lprompt = @local_prompt ? @local_prompt : @rl_prompt
  @visible_line[0,lprompt.length] = lprompt
  @invisible_line[0,lprompt.length] = lprompt

  # If the prompt contains newlines, take the last tail.
  prompt_last_line = rl_prompt.rindex("\n")
  if prompt_last_line.nil?
    prompt_last_line = @rl_prompt
  else
    prompt_last_line = @rl_prompt[prompt_last_line..-1]
  end
  l = prompt_last_line.length
  if !@rl_byte_oriented
    @_rl_last_c_pos = _rl_col_width(prompt_last_line, 0, l)
  else
    @_rl_last_c_pos = l
  end

  # Dissect prompt_last_line into screen lines. Note that here we have
  #   to use the real screenwidth. Readline's notion of screenwidth might be
  #   one less, see terminal.c.
  real_screenwidth = @_rl_screenwidth + (@_rl_term_autowrap ? 0 : 1)
  @_rl_last_v_pos = l / real_screenwidth
  # If the prompt length is a multiple of real_screenwidth, we don't know
  #   whether the cursor is at the end of the last line, or already at the
  #   beginning of the next line. Output a newline just to be safe.
  if (l > 0 && (l % real_screenwidth) == 0)
    _rl_output_some_chars("\n",0,1)
  end
  @last_lmargin = 0

  newlines = 0
  i = 0
  while (i <= l)
    @_rl_vis_botlin = newlines
    @vis_lbreaks[newlines] = i
    newlines += 1
    i += real_screenwidth
  end
  @vis_lbreaks[newlines] = l
  @visible_wrap_offset = 0

  @rl_display_prompt = @rl_prompt  # XXX - make sure it's set

  return 0
end
rl_overwrite_mode(count, key) click to toggle source

Toggle overwrite mode. A positive explicit argument selects overwrite

mode.  A negative or zero explicit argument selects insert mode.
# File lib/rbreadline.rb, line 1455
def rl_overwrite_mode(count, key)
  if (!@rl_explicit_arg)
    _rl_set_insert_mode(@rl_insert_mode ^ 1, 0)
  elsif (count > 0)
    _rl_set_insert_mode(RL_IM_OVERWRITE, 0)
  else
    _rl_set_insert_mode(RL_IM_INSERT, 0)
  end
  0
end
rl_parse_and_bind(string) click to toggle source

Read the binding command from STRING and perform it.

A key binding command looks like: Keyname: function-name\0,
a variable binding command looks like: set variable value.
A new-style keybinding looks like "\C-x\C-x": exchange-point-and-mark.
# File lib/rbreadline.rb, line 2451
def rl_parse_and_bind(string)

  # If this is a parser directive, act on it.
  if (string[0,1] == "$")
    handle_parser_directive(string[1..-1])
    return 0
  end

  # If we aren't supposed to be parsing right now, then we're done.
  return 0 if @_rl_parsing_conditionalized_out

  if string =~ /^set/i
    _,var,value = string.downcase.split(' ')
    rl_variable_bind(var, value)
    return 0
  end

  if string =~ /"(.*)"\s*:\s*(.*)$/
    key, funname = $1, $2
    func = rl_named_function(funname)
    rl_bind_key(key, func) if func
  end

  0
end
rl_possible_completions(ignore, invoking_key) click to toggle source

List the possible completions. See description of rl_complete ().

# File lib/rbreadline.rb, line 6096
def rl_possible_completions(ignore, invoking_key)
  rl_complete_internal('?')
end
rl_prep_terminal(meta_flag) click to toggle source
# File lib/rbreadline.rb, line 7051
def rl_prep_terminal(meta_flag)
  if no_terminal?
    @readline_echoing_p = true
    return
  end

  return if (@terminal_prepped)

  # Try to keep this function from being INTerrupted.
  block_sigint()

  if (@_rl_bind_stty_chars)
    # If editing in vi mode, make sure we restore the bindings in the
    # insertion keymap no matter what keymap we ended up in.
    if (@rl_editing_mode == @vi_mode)
      rl_tty_unset_default_bindings(@vi_insertion_keymap)
    else
      rl_tty_unset_default_bindings(@_rl_keymap)
    end
  end

  save_tty_chars()

  rl_setstate(RL_STATE_TTYCSAVED)
  if (@_rl_bind_stty_chars)

    # If editing in vi mode, make sure we set the bindings in the
    # insertion keymap no matter what keymap we ended up in.
    if (@rl_editing_mode == @vi_mode)
      _rl_bind_tty_special_chars(@vi_insertion_keymap)
    else
      _rl_bind_tty_special_chars(@_rl_keymap)
    end
  end

  prepare_terminal_settings(meta_flag)

  if (@_rl_enable_keypad)
    _rl_control_keypad(true)
  end
  @rl_outstream.flush
  @terminal_prepped = true
  rl_setstate(RL_STATE_TERMPREPPED)

  release_sigint()
end
rl_quoted_insert(count, key) click to toggle source
# File lib/rbreadline.rb, line 5670
def rl_quoted_insert(count, key)
  _rl_insert_next(count)
end
rl_re_read_init_file(count, ignore) click to toggle source

Re-read the current keybindings file.

# File lib/rbreadline.rb, line 8359
def rl_re_read_init_file(count, ignore)
  r = rl_read_init_file(nil)
  rl_set_keymap_from_edit_mode()
  r
end
rl_read_init_file(filename) click to toggle source

Do key bindings from a file. If FILENAME is NULL it defaults

to the first non-null filename from this list:
  1. the filename used for the previous call
  2. the value of the shell variable `INPUTRC'
  3. ~/.inputrc
  4. /etc/inputrc
If the file existed and could be opened and read, 0 is returned,
otherwise errno is returned.
# File lib/rbreadline.rb, line 2092
def rl_read_init_file(filename)
  # Default the filename.
  filename ||= @last_readline_init_file
  filename ||= ENV["INPUTRC"]
  if (filename.nil? || filename == '')
    filename = DEFAULT_INPUTRC
    # Try to read DEFAULT_INPUTRC; fall back to SYS_INPUTRC on failure
    if (_rl_read_init_file(filename, 0) == 0)
      return 0
    end
    filename = SYS_INPUTRC
  end

  if RUBY_PLATFORM =~ /mswin|mingw/
    return 0 if (_rl_read_init_file(filename, 0) == 0)
    filename = "~/_inputrc"
  end
  return (_rl_read_init_file(filename, 0))
end
rl_read_key() click to toggle source

Read a key, including pending input.

# File lib/rbreadline.rb, line 4558
def rl_read_key()
  @rl_key_sequence_length+=1

  if (@rl_pending_input!=0)
    c = @rl_pending_input
    rl_clear_pending_input()
  else
    # If the user has an event function, then call it periodically.
    if (@rl_event_hook)
      while (@rl_event_hook && (c=rl_get_char()).nil?)

        send(@rl_event_hook)
        if (@rl_done)     # XXX - experimental
          return ("\n")
        end
        if (rl_gather_tyi() < 0)   # XXX - EIO
          @rl_done = true
          return ("\n")
        end
      end

    else

      if (c=rl_get_char()).nil?
        c = send(@rl_getc_function,@rl_instream)
      end
    end
  end

  return (c)
end
rl_redisplay() click to toggle source

Basic redisplay algorithm.

# File lib/rbreadline.rb, line 3172
def rl_redisplay()
  return if !@readline_echoing_p

  _rl_wrapped_multicolumn = 0

  @rl_display_prompt ||= ""

  if (@invisible_line.nil? || @vis_lbreaks.nil?)
    init_line_structures(0)
    rl_on_new_line()
  end

  # Draw the line into the buffer.
  @cpos_buffer_position = -1

  line = @invisible_line
  out = inv_botlin = 0

  # Mark the line as modified or not.  We only do this for history
  #   lines.
  modmark = 0
  if (@_rl_mark_modified_lines && current_history() && @rl_undo_list)
    line[out,1] = '*'
    out += 1
    line[out,1] = 0.chr
    modmark = 1
  end

  # If someone thought that the redisplay was handled, but the currently
  #   visible line has a different modification state than the one about
  #   to become visible, then correct the caller's misconception.
  if (@visible_line[0,1] != @invisible_line[0,1])
    @rl_display_fixed = false
  end

  # If the prompt to be displayed is the `primary' readline prompt (the
  #   one passed to readline()), use the values we have already expanded.
  #   If not, use what's already in rl_display_prompt.  WRAP_OFFSET is the
  #   number of non-visible characters in the prompt string.
  if (@rl_display_prompt == @rl_prompt || @local_prompt)

    if (@local_prompt_prefix && @forced_display)
      _rl_output_some_chars(@local_prompt_prefix,0,@local_prompt_prefix.length)
    end
    if (@local_prompt_len > 0)

      temp = @local_prompt_len + out + 2
      if (temp >= @line_size)
        @line_size = (temp + 1024) - (temp % 1024)
        if @visible_line.length >= @line_size
          @visible_line = @visible_line[0,@line_size]
        else
          @visible_line += 0.chr * (@line_size-@visible_line.length)
        end

        if @invisible_line.length >= @line_size
          @invisible_line = @invisible_line[0,@line_size]
        else
          @invisible_line += 0.chr * (@line_size-@invisible_line.length)
        end
        if @encoding=='X'
          @visible_line.force_encoding('ASCII-8BIT')
          @invisible_line.force_encoding('ASCII-8BIT')
        end
        line = @invisible_line
      end
      line[out,@local_prompt_len] = @local_prompt
      out += @local_prompt_len
    end
    line[out,1] = 0.chr
    @wrap_offset = @local_prompt_len - @prompt_visible_length
  else
    prompt_this_line = @rl_display_prompt.rindex("\n")
    if prompt_this_line.nil?
      prompt_this_line = 0
    else
      prompt_this_line+=1

      pmtlen = prompt_this_line # temp var
      if (@forced_display)
        _rl_output_some_chars(@rl_display_prompt,0,pmtlen)
        # Make sure we are at column zero even after a newline,
        #regardless of the state of terminal output processing.
        if (pmtlen < 2 || @rl_display_prompt[prompt_this_line-2,1] != "\r")
          cr()
        end
      end
    end

    @prompt_physical_chars = pmtlen = @rl_display_prompt.length - prompt_this_line
    temp = pmtlen + out + 2
    if (temp >= @line_size)
      @line_size = (temp + 1024) - (temp % 1024)
      if @visible_line.length >= @line_size
        @visible_line = @visible_line[0,@line_size]
      else
        @visible_line += 0.chr * (@line_size-@visible_line.length)
      end

      if @invisible_line.length >= @line_size
        @invisible_line = @invisible_line[0,@line_size]
      else
        @invisible_line += 0.chr * (@line_size-@invisible_line.length)
      end
      if @encoding=='X'
        @visible_line.force_encoding('ASCII-8BIT')
        @invisible_line.force_encoding('ASCII-8BIT')
      end

      line = @invisible_line
    end
    line[out,pmtlen] = @rl_display_prompt[prompt_this_line,pmtlen]
    out += pmtlen
    line[out,1] = 0.chr
    @wrap_offset = @prompt_invis_chars_first_line = 0
  end
  # inv_lbreaks[i] is where line i starts in the buffer.
  @inv_lbreaks[newlines = 0] = 0
  lpos = @prompt_physical_chars + modmark

  @_rl_wrapped_line = Array.new(@visible_line.length,0)
  num = 0

  # prompt_invis_chars_first_line is the number of invisible characters in
  #   the first physical line of the prompt.
  #  wrap_offset - prompt_invis_chars_first_line is the number of invis
  #   chars on the second line.

  # what if lpos is already >= _rl_screenwidth before we start drawing the
  #   contents of the command line?
  while (lpos >= @_rl_screenwidth)
    # fix from Darin Johnson <darin@acuson.com> for prompt string with
    #   invisible characters that is longer than the screen width.  The
    #   prompt_invis_chars_first_line variable could be made into an array
    #   saying how many invisible characters there are per line, but that's
    #   probably too much work for the benefit gained.  How many people have
    #   prompts that exceed two physical lines?
    #   Additional logic fix from Edward Catmur <ed@catmur.co.uk>
    if (!@rl_byte_oriented)
      n0 = num
      temp = @local_prompt_len
      while (num < temp)
        z = _rl_col_width(@local_prompt, n0, num)
        if (z > @_rl_screenwidth)
          num = _rl_find_prev_mbchar(@local_prompt, num, MB_FIND_ANY)
          break
        elsif (z == @_rl_screenwidth)
          break
        end
        num+=1
      end
      temp = num
    else
      temp = ((newlines + 1) * @_rl_screenwidth)
    end

    # Now account for invisible characters in the current line.
    temp += (@local_prompt_prefix.nil? ? ((newlines == 0) ? @prompt_invis_chars_first_line :
                                          ((newlines == 1) ? @wrap_offset : 0)) :
                                          ((newlines == 0) ? @wrap_offset : 0))

    @inv_lbreaks[newlines+=1] = temp
    if !@rl_byte_oriented
      lpos -= _rl_col_width(@local_prompt, n0, num)
    else
      lpos -= @_rl_screenwidth
    end
  end
  @prompt_last_screen_line = newlines

  # Draw the rest of the line (after the prompt) into invisible_line, keeping
  #   track of where the cursor is (cpos_buffer_position), the number of the line containing
  #   the cursor (lb_linenum), the last line number (inv_botlin).
  #   It maintains an array of line breaks for display (inv_lbreaks).
  #   This handles expanding tabs for display and displaying meta characters.
  lb_linenum = 0
  _in = 0
  if !@rl_byte_oriented && @rl_end>0
    case @encoding
    when 'E'
      wc = @rl_line_buffer[0,@rl_end].scan(/./me)[0]
      wc_bytes = wc ? wc.length : 1
    when 'S'
      wc = @rl_line_buffer[0,@rl_end].scan(/./ms)[0]
      wc_bytes = wc ? wc.length : 1
    when 'U'
      wc = @rl_line_buffer[0,@rl_end].scan(/./mu)[0]
      wc_bytes = wc ? wc.length : 1
    when 'X'
      wc = @rl_line_buffer[0,@rl_end].force_encoding(@encoding_name)[0]
      wc_bytes = wc ? wc.bytesize : 1
    end
  else
    wc_bytes = 1
  end

  while(_in < @rl_end)

    c = @rl_line_buffer[_in,1]
    if(c == 0.chr)
      @rl_end = _in
      break
    end
    if (!@rl_byte_oriented)
      case @encoding
      when 'U'
        wc_width = wc && wc.unpack('U').first >= 0x1000 ? 2 : 1
      when 'X'
        wc_width = wc && wc.ord > 0x1000 ? 2 : 1
      else
        wc_width = wc ? wc.length : 1
      end
    end
    if (out + 8 >= @line_size)    # XXX - 8 for \t
      @line_size *= 2
      if @visible_line.length>=@line_size
        @visible_line = @visible_line[0,@line_size]
      else
        @visible_line += 0.chr * (@line_size-@visible_line.length)
      end
      if @invisible_line.length>=@line_size
        @invisible_line = @invisible_line[0,@line_size]
      else
        @invisible_line += 0.chr * (@line_size-@invisible_line.length)
      end
      line = @invisible_line
    end

    if (_in == @rl_point)
      @cpos_buffer_position = out
      lb_linenum = newlines
    end
    if (false && meta_char(c))
      if (!@_rl_output_meta_chars && false)
        line[out,4] = "\\%03o" % c.ord

        if (lpos + 4 >= @_rl_screenwidth)
          temp = @_rl_screenwidth - lpos
          @inv_lbreaks[newlines+=1] = out + temp
          lpos = 4 - temp
        else
          lpos += 4
        end
        out += 4
      else
        line[out,1] = c
        out += 1
        lpos+=1
        if (lpos >= @_rl_screenwidth)
          @inv_lbreaks[newlines+=1] = out
          @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
          lpos = 0
        end
      end

    elsif (c == "\t")

      newout = out + 8 - lpos % 8
      temp = newout - out
      if (lpos + temp >= @_rl_screenwidth)
        temp2 = @_rl_screenwidth - lpos
        @inv_lbreaks[newlines+=1] = out + temp2
        lpos = temp - temp2
        while (out < newout)
          line[out,1] = ' '
          out += 1
        end

      else

        while (out < newout)
          line[out,1] = ' '
          out += 1
        end
        lpos += temp
      end

    elsif (c == "\n" && !@_rl_horizontal_scroll_mode && @_rl_term_up)
      line[out,1] = 0.chr # XXX - sentinel
      out += 1
      @inv_lbreaks[newlines+=1] = out
      lpos = 0
    elsif (ctrl_char(c) || c == RUBOUT)
      line[out,1] = '^'
      out += 1
      lpos+=1
      if (lpos >= @_rl_screenwidth)
        @inv_lbreaks[newlines+=1] = out
        @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
        lpos = 0
      end
      # NOTE: c[0].ord works identically on both 1.8 and 1.9
      line[out,1] = ctrl_char(c) ? (c[0].ord|0x40).chr.upcase : '?'
      out += 1
      lpos+=1
      if (lpos >= @_rl_screenwidth)
        @inv_lbreaks[newlines+=1] = out
        @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
        lpos = 0
      end
    else

      if (!@rl_byte_oriented)
        _rl_wrapped_multicolumn = 0
        if (@_rl_screenwidth < lpos + wc_width)
          for i in lpos ... @_rl_screenwidth
            # The space will be removed in update_line()
            line[out,1] = ' '
            out += 1
            _rl_wrapped_multicolumn+=1
            lpos+=1
            if (lpos >= @_rl_screenwidth)
              @inv_lbreaks[newlines+=1] = out
              @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
              lpos = 0
            end
          end
        end
        if (_in == @rl_point)
          @cpos_buffer_position = out
          lb_linenum = newlines
        end
        line[out,wc_bytes] = @rl_line_buffer[_in,wc_bytes]
        out += wc_bytes
        for i in 0 ... wc_width
          lpos+=1
          if (lpos >= @_rl_screenwidth)
            @inv_lbreaks[newlines+=1] = out
            @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
            lpos = 0
          end
        end
      else
        line[out,1] = c
        out += 1
        lpos+=1
        if (lpos >= @_rl_screenwidth)
          @inv_lbreaks[newlines+=1] = out
          @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
          lpos = 0
        end
      end

    end

    if (!@rl_byte_oriented)
      _in += wc_bytes
      case @encoding
      when 'E'
        wc = @rl_line_buffer[_in,@rl_end - _in].scan(/./me)[0]
        wc_bytes = wc ? wc.length : 1
      when 'S'
        wc = @rl_line_buffer[_in,@rl_end - _in].scan(/./ms)[0]
        wc_bytes = wc ? wc.length : 1
      when 'U'
        wc = @rl_line_buffer[_in,@rl_end - _in].scan(/./mu)[0]
        wc_bytes = wc ? wc.length : 1
      when 'X'
        wc = @rl_line_buffer[_in,@rl_end - _in].force_encoding(@encoding_name)[0]
        wc_bytes = wc ? wc.bytesize : 1
      end

    else
      _in+=1
    end
  end

  line[out,1] = 0.chr

  if (@cpos_buffer_position < 0)
    @cpos_buffer_position = out
    lb_linenum = newlines
  end

  inv_botlin = newlines
  @inv_lbreaks[newlines+1] = out
  cursor_linenum = lb_linenum

  # CPOS_BUFFER_POSITION == position in buffer where cursor should be placed.
  #   CURSOR_LINENUM == line number where the cursor should be placed.

  # PWP: now is when things get a bit hairy.  The visible and invisible
  #   line buffers are really multiple lines, which would wrap every
  #   (screenwidth - 1) characters.  Go through each in turn, finding
  #   the changed region and updating it.  The line order is top to bottom.

  # If we can move the cursor up and down, then use multiple lines,
  #   otherwise, let long lines display in a single terminal line, and
  #   horizontally scroll it.

  if (!@_rl_horizontal_scroll_mode && @_rl_term_up)
    if (!@rl_display_fixed || @forced_display)
      @forced_display = false
      # If we have more than a screenful of material to display, then
      #   only display a screenful.  We should display the last screen,
      #   not the first.
      if (out >= @_rl_screenchars)
        if (!@rl_byte_oriented)
          out = _rl_find_prev_mbchar(line, @_rl_screenchars, MB_FIND_ANY)
        else
          out = @_rl_screenchars - 1
        end
      end

      # The first line is at character position 0 in the buffer.  The
      #   second and subsequent lines start at inv_lbreaks[N], offset by
      #   OFFSET (which has already been calculated above).

      # For each line in the buffer, do the updating display.
      linenum = 0
      while linenum <= inv_botlin
        # This can lead us astray if we execute a program that changes
        #the locale from a non-multibyte to a multibyte one.
        o_cpos = @_rl_last_c_pos
        @cpos_adjusted = false
        update_line(@visible_line,vis_pos(linenum), inv_line(linenum), linenum,
                    vis_llen(linenum), inv_llen(linenum), inv_botlin)

        if (linenum == 0 && !@rl_byte_oriented &&
            !@cpos_adjusted &&
            @_rl_last_c_pos != o_cpos &&
            @_rl_last_c_pos > @wrap_offset &&
            o_cpos < @prompt_last_invisible)
          @_rl_last_c_pos -= @wrap_offset
        end

        # If this is the line with the prompt, we might need to
        # compensate for invisible characters in the new line. Do
        # this only if there is not more than one new line (which
        # implies that we completely overwrite the old visible line)
        # and the new line is shorter than the old.  Make sure we are
        # at the end of the new line before clearing.
        if (linenum == 0 &&
            inv_botlin == 0 && @_rl_last_c_pos == out &&
            (@wrap_offset > @visible_wrap_offset) &&
            (@_rl_last_c_pos < @visible_first_line_len))
          if !@rl_byte_oriented
            nleft = @_rl_screenwidth - @_rl_last_c_pos
          else
            nleft = @_rl_screenwidth + @wrap_offset - @_rl_last_c_pos
          end
          if (nleft!=0)
            _rl_clear_to_eol(nleft)
          end
        end

        # Since the new first line is now visible, save its length.
        if (linenum == 0)
          @visible_first_line_len = (inv_botlin > 0) ? @inv_lbreaks[1] : out - @wrap_offset
        end

        linenum += 1
      end

      # We may have deleted some lines.  If so, clear the left over
      #   blank ones at the bottom out.
      if (@_rl_vis_botlin > inv_botlin)
        while(linenum <= @_rl_vis_botlin)
          tt = vis_chars(linenum)
          _rl_move_vert(linenum)
          _rl_move_cursor_relative(0, tt)
          _rl_clear_to_eol((linenum == @_rl_vis_botlin) ? tt.length : @_rl_screenwidth)
          linenum += 1
        end
      end
      @_rl_vis_botlin = inv_botlin

      # CHANGED_SCREEN_LINE is set to 1 if we have moved to a
      #   different screen line during this redisplay.
      changed_screen_line = @_rl_last_v_pos != cursor_linenum
      if (changed_screen_line)
        _rl_move_vert(cursor_linenum)
        # If we moved up to the line with the prompt using _rl_term_up,
        # the physical cursor position on the screen stays the same,
        # but the buffer position needs to be adjusted to account
        # for invisible characters.
        if (@rl_byte_oriented && cursor_linenum == 0 && @wrap_offset!=0)
          @_rl_last_c_pos += @wrap_offset
        end
      end
      # We have to reprint the prompt if it contains invisible
      #   characters, since it's not generally OK to just reprint
      #   the characters from the current cursor position.  But we
      #   only need to reprint it if the cursor is before the last
      #   invisible character in the prompt string.
      nleft = @prompt_visible_length + @wrap_offset
      if (cursor_linenum == 0 && @wrap_offset > 0 && @_rl_last_c_pos > 0 &&
          @_rl_last_c_pos < prompt_ending_index() && @local_prompt)
        if (@_rl_term_cr)
          @rl_outstream.write(@_rl_term_cr)
        end
        _rl_output_some_chars(@local_prompt,0,nleft)
        if !@rl_byte_oriented
          @_rl_last_c_pos = _rl_col_width(@local_prompt, 0, nleft) - @wrap_offset
        else
          @_rl_last_c_pos = nleft
        end
      end

      # Where on that line?  And where does that line start
      #   in the buffer?
      pos = @inv_lbreaks[cursor_linenum]
      # nleft == number of characters in the line buffer between the
      #   start of the line and the desired cursor position.
      nleft = @cpos_buffer_position - pos

      # NLEFT is now a number of characters in a buffer.  When in a
      #   multibyte locale, however, _rl_last_c_pos is an absolute cursor
      #   position that doesn't take invisible characters in the prompt
      #   into account.  We use a fudge factor to compensate.

      # Since _rl_backspace() doesn't know about invisible characters in the
      #   prompt, and there's no good way to tell it, we compensate for
      #   those characters here and call _rl_backspace() directly.

      if (@wrap_offset!=0 && cursor_linenum == 0 && nleft < @_rl_last_c_pos)
        # TX == new physical cursor position in multibyte locale.
        if !@rl_byte_oriented
          tx = _rl_col_width(@visible_line, pos, pos+nleft) - @visible_wrap_offset
        else
          tx = nleft
        end
        if tx >= 0 && @_rl_last_c_pos > tx
          _rl_backspace(@_rl_last_c_pos - tx) # XXX
          @_rl_last_c_pos = tx
        end
      end
      # We need to note that in a multibyte locale we are dealing with
      #   _rl_last_c_pos as an absolute cursor position, but moving to a
      #   point specified by a buffer position (NLEFT) that doesn't take
      #   invisible characters into account.
      if !@rl_byte_oriented
        _rl_move_cursor_relative(nleft, @invisible_line,pos)
      elsif (nleft != @_rl_last_c_pos)
        _rl_move_cursor_relative(nleft, @invisible_line,pos)
      end
    end

  else           # Do horizontal scrolling.

    # Always at top line.
    @_rl_last_v_pos = 0

    # Compute where in the buffer the displayed line should start.  This
    # will be LMARGIN.

    # The number of characters that will be displayed before the cursor.
    ndisp = @cpos_buffer_position - @wrap_offset
    nleft  = @prompt_visible_length + @wrap_offset
    # Where the new cursor position will be on the screen.  This can be
    # longer than SCREENWIDTH; if it is, lmargin will be adjusted.
    phys_c_pos = @cpos_buffer_position - (@last_lmargin!=0 ? @last_lmargin : @wrap_offset)
    t = @_rl_screenwidth / 3

    # If the number of characters had already exceeded the screenwidth,
    #last_lmargin will be > 0.

    # If the number of characters to be displayed is more than the screen
    # width, compute the starting offset so that the cursor is about
    # two-thirds of the way across the screen.
    if (phys_c_pos > @_rl_screenwidth - 2)
      lmargin = @cpos_buffer_position - (2 * t)
      if (lmargin < 0)
        lmargin = 0
      end
      # If the left margin would be in the middle of a prompt with
      #   invisible characters, don't display the prompt at all.
      if (@wrap_offset!=0 && lmargin > 0 && lmargin < nleft)
        lmargin = nleft
      end
    elsif (ndisp < @_rl_screenwidth - 2)      # XXX - was -1
      lmargin = 0
    elsif (phys_c_pos < 1)
      # If we are moving back towards the beginning of the line and
      #   the last margin is no longer correct, compute a new one.
      lmargin = ((@cpos_buffer_position - 1) / t) * t # XXX
      if (@wrap_offset!=0 && lmargin > 0 && lmargin < nleft)
        lmargin = nleft
      end
    else
      lmargin = @last_lmargin
    end

    # If the first character on the screen isn't the first character
    #in the display line, indicate this with a special character.
    if (lmargin > 0)
      line[lmargin,1] = '<'
    end

    # If SCREENWIDTH characters starting at LMARGIN do not encompass
    # the whole line, indicate that with a special character at the
    # right edge of the screen.  If LMARGIN is 0, we need to take the
    # wrap offset into account.
    t = lmargin + m_offset(lmargin, @wrap_offset) + @_rl_screenwidth
    if (t < out)
      line[t - 1,1] = '>'
    end
    if (!@rl_display_fixed || @forced_display || lmargin != @last_lmargin)

      @forced_display = false
      update_line(@visible_line,@last_lmargin,@invisible_line[lmargin..-1],
                  0,
                  @_rl_screenwidth + @visible_wrap_offset,
                  @_rl_screenwidth + (lmargin ? 0 : @wrap_offset),
                  0)
      # If the visible new line is shorter than the old, but the number
      #   of invisible characters is greater, and we are at the end of
      #   the new line, we need to clear to eol.
      t = @_rl_last_c_pos - m_offset(lmargin, @wrap_offset)
      if ((m_offset(lmargin, @wrap_offset) > @visible_wrap_offset) &&
          (@_rl_last_c_pos == out) &&
          t < @visible_first_line_len)

        nleft = @_rl_screenwidth - t
        _rl_clear_to_eol(nleft)
      end
      @visible_first_line_len = out - lmargin - m_offset(lmargin, @wrap_offset)
      if (@visible_first_line_len > @_rl_screenwidth)
        @visible_first_line_len = @_rl_screenwidth
      end
      _rl_move_cursor_relative(@cpos_buffer_position - lmargin, @invisible_line ,lmargin)
      @last_lmargin = lmargin
    end
  end
  @rl_outstream.flush

  # Swap visible and non-visible lines.
  @visible_line,@invisible_line = @invisible_line,@visible_line
  @vis_lbreaks,@inv_lbreaks = @inv_lbreaks,@vis_lbreaks

  @rl_display_fixed = false
  # If we are displaying on a single line, and last_lmargin is > 0, we
  #   are not displaying any invisible characters, so set visible_wrap_offset
  #   to 0.
  if (@_rl_horizontal_scroll_mode && @last_lmargin!=0)
    @visible_wrap_offset = 0
  else
    @visible_wrap_offset = @wrap_offset
  end
end
rl_refresh_line(ignore1, ignore2) click to toggle source

Clear the current line. Numeric argument to C-l does this.

# File lib/rbreadline.rb, line 5348
def rl_refresh_line(ignore1, ignore2)
  curr_line = _rl_current_display_line()

  _rl_move_vert(curr_line)
  _rl_move_cursor_relative(0, @rl_line_buffer)   # XXX is this right

  _rl_clear_to_eol(0)     # arg of 0 means to not use spaces

  rl_forced_update_display()
  @rl_display_fixed = true

  0
end
rl_replace_from_history(entry, flags) click to toggle source
# File lib/rbreadline.rb, line 6915
def rl_replace_from_history(entry, flags)
  # Can't call with `1' because rl_undo_list might point to an undo list
  #   from a history entry, just like we're setting up here.
  rl_replace_line(entry.line, false)
  @rl_undo_list = entry.data
  @rl_point = @rl_end
  @rl_mark = 0

  if (@rl_editing_mode == @vi_mode)
    @rl_point = 0
    @rl_mark = @rl_end
  end
end
rl_replace_line(text, clear_undo) click to toggle source

Replace the current line buffer contents with TEXT. If CLEAR_UNDO is

non-zero, we free the current undo list.
# File lib/rbreadline.rb, line 5041
def rl_replace_line(text, clear_undo)
  len = text.delete(0.chr).length
  @rl_line_buffer = text.dup + 0.chr
  @rl_end = len
  if (clear_undo)
    rl_free_undo_list()
  end
  _rl_fix_point(true)
end
rl_reset_line_state() click to toggle source
# File lib/rbreadline.rb, line 3831
def rl_reset_line_state()
  rl_on_new_line()

  @rl_display_prompt = @rl_prompt ? @rl_prompt : ""
  @forced_display = true
  0
end
rl_resize_terminal() click to toggle source
# File lib/rbreadline.rb, line 8882
def rl_resize_terminal()
  if @readline_echoing_p
    _rl_get_screen_size(@rl_instream.fileno, 1)
    if @rl_redisplay_function != :rl_redisplay
      rl_forced_update_display()
    else
      _rl_redisplay_after_sigwinch()
    end
  end
end
rl_restart_output(count, key) click to toggle source
# File lib/rbreadline.rb, line 1654
def rl_restart_output(count, key)
  0
end
rl_restore_prompt() click to toggle source
# File lib/rbreadline.rb, line 7341
def rl_restore_prompt()
  @local_prompt = nil
  @local_prompt_prefix = nil

  @local_prompt = @saved_local_prompt
  @local_prompt_prefix = @saved_local_prefix
  @local_prompt_len = @saved_local_length
  @prompt_prefix_length = @saved_prefix_length
  @prompt_last_invisible = @saved_last_invisible
  @prompt_visible_length = @saved_visible_length
  @prompt_invis_chars_first_line = @saved_invis_chars_first_line
  @prompt_physical_chars = @saved_physical_chars

  # can test saved_local_prompt to see if prompt info has been saved.
  @saved_local_prompt = @saved_local_prefix = nil
  @saved_local_length = 0
  @saved_last_invisible = @saved_visible_length = @saved_prefix_length = 0
  @saved_invis_chars_first_line = @saved_physical_chars = 0
end
rl_reverse_search_history(sign, key) click to toggle source

Search backwards through the history looking for a string which is typed

interactively.  Start with the current line.
# File lib/rbreadline.rb, line 7188
def rl_reverse_search_history(sign, key)
  rl_search_history(-sign, key)
end
rl_revert_line(count, key) click to toggle source

Revert the current line to its previous state.

# File lib/rbreadline.rb, line 7767
def rl_revert_line(count, key)
  if @rl_undo_list.nil?
    rl_ding()
  else
    while (@rl_undo_list)
      rl_do_undo()
    end
    if (@rl_editing_mode == @vi_mode)
      @rl_point = @rl_mark = 0      # rl_end should be set correctly
    end
  end
  0
end
rl_rubout(count, key) click to toggle source

Rubout the character behind point.

# File lib/rbreadline.rb, line 5845
def rl_rubout(count, key)
  if (count < 0)
    return (rl_delete(-count, key))
  end
  if (@rl_point==0)
    rl_ding()
    return -1
  end

  if (@rl_insert_mode == RL_IM_OVERWRITE)
    return (_rl_overwrite_rubout(count, key))
  end
  _rl_rubout_char(count, key)
end
rl_rubout_or_delete(count, key) click to toggle source

Delete the character under the cursor, unless the insertion

point is at the end of the line, in which case the character
behind the cursor is deleted.  COUNT is obeyed and may be used
to delete forward or backward that many characters.
# File lib/rbreadline.rb, line 6066
def rl_rubout_or_delete(count, key)
  if (@rl_end != 0 && @rl_point == @rl_end)
    return (_rl_rubout_char(count, key))
  else
    return (rl_delete(count, key))
  end
end
rl_save_prompt() click to toggle source
# File lib/rbreadline.rb, line 7325
def rl_save_prompt()
  @saved_local_prompt = @local_prompt
  @saved_local_prefix = @local_prompt_prefix
  @saved_prefix_length = @prompt_prefix_length
  @saved_local_length = @local_prompt_len
  @saved_last_invisible = @prompt_last_invisible
  @saved_visible_length = @prompt_visible_length
  @saved_invis_chars_first_line = @prompt_invis_chars_first_line
  @saved_physical_chars = @prompt_physical_chars

  @local_prompt = @local_prompt_prefix = nil
  @local_prompt_len = 0
  @prompt_last_invisible = @prompt_visible_length = @prompt_prefix_length = 0
  @prompt_invis_chars_first_line = @prompt_physical_chars = 0
end
rl_search_history(direction, invoking_key) click to toggle source

Search through the history looking for an interactively typed string.

This is analogous to i-search.  We start the search in the current line.
DIRECTION is which direction to search; >= 0 means forward, < 0 means
backwards.
# File lib/rbreadline.rb, line 7202
def rl_search_history(direction, invoking_key)
  rl_setstate(RL_STATE_ISEARCH)
  cxt = _rl_isearch_init(direction)

  rl_display_search(cxt.search_string, (cxt.sflags & SF_REVERSE)!=0, -1)

  # If we are using the callback interface, all we do is set up here and
  #    return.  The key is that we leave RL_STATE_ISEARCH set.
  if (rl_isstate(RL_STATE_CALLBACK))
    return (0)
  end

  r = -1
  while(true)
    _rl_search_getchar(cxt)
    # We might want to handle EOF here (c == 0)
    r = _rl_isearch_dispatch(cxt, cxt.lastc)
    break if (r <= 0)
  end

  # The searching is over.  The user may have found the string that she
  #   was looking for, or else she may have exited a failing search.  If
  #   LINE_INDEX is -1, then that shows that the string searched for was
  #   not found.  We use this to determine where to place rl_point.
  _rl_isearch_cleanup(cxt, r)
end
rl_set_keymap_from_edit_mode() click to toggle source
# File lib/rbreadline.rb, line 2484
def rl_set_keymap_from_edit_mode()
  if (@rl_editing_mode == @emacs_mode)
    @_rl_keymap = @emacs_standard_keymap
  elsif (@rl_editing_mode == @vi_mode)
    @_rl_keymap = @vi_insertion_keymap
  end
end
rl_set_mark(count, key) click to toggle source

A bindable command to set the mark.

# File lib/rbreadline.rb, line 7131
def rl_set_mark(count, key)
  _rl_set_mark_at_pos(@rl_explicit_arg ? count : @rl_point)
end
rl_set_prompt(prompt) click to toggle source

Set up the prompt and expand it. Called from readline() and

rl_callback_handler_install ().
# File lib/rbreadline.rb, line 1806
def rl_set_prompt(prompt)
  @rl_prompt = prompt ? prompt.dup : nil
  @rl_display_prompt = @rl_prompt ? @rl_prompt : ""
  @rl_visible_prompt_length = rl_expand_prompt(@rl_prompt)
  0
end
rl_set_signals() click to toggle source
# File lib/rbreadline.rb, line 1664
def rl_set_signals()
  if Signal.list['WINCH']
    @def_proc = trap "WINCH",Proc.new{rl_sigwinch_handler(0)}
  end
end
rl_setstate(x) click to toggle source
# File lib/rbreadline.rb, line 1635
def rl_setstate(x)
  (@rl_readline_state |= (x))
end
rl_sigwinch_handler(sig) click to toggle source
# File lib/rbreadline.rb, line 8893
def rl_sigwinch_handler(sig)
  rl_setstate(RL_STATE_SIGHANDLER)
  rl_resize_terminal()
  rl_unsetstate(RL_STATE_SIGHANDLER)
end
rl_stuff_char(key) click to toggle source

Add KEY to the buffer of characters to be read. Returns 1 if the

character was stuffed correctly; 0 otherwise.
# File lib/rbreadline.rb, line 4400
def rl_stuff_char(key)
  return 0 if (ibuffer_space() == 0)

  if (key == EOF)
    key = NEWLINE
    @rl_pending_input = EOF
    rl_setstate(RL_STATE_INPUTPENDING)
  end
  @ibuffer[@push_index] = key
  @push_index += 1
  if (@push_index >= @ibuffer_len)
    @push_index = 0
  end

  return 1
end
rl_tab_insert(count, key) click to toggle source

Insert a tab character.

# File lib/rbreadline.rb, line 5675
def rl_tab_insert(count, key)
  _rl_insert_char(count, "\t")
end
rl_tilde_expand(ignore, key) click to toggle source

A function for simple tilde expansion.

# File lib/rbreadline.rb, line 1468
def rl_tilde_expand(ignore, key)
  _end = @rl_point
  start = _end - 1

  if (@rl_point == @rl_end && @rl_line_buffer[@rl_point,1] == '~' )
    homedir = File.expand_path("~")
    _rl_replace_text(homedir, start, _end)
    return (0)
  elsif (@rl_line_buffer[start,1] != '~')
    while(!whitespace(@rl_line_buffer[start,1]) && start >= 0)
      start -= 1
    end
    start+=1
  end

  _end = start
  begin
    _end+=1
  end while(!whitespace(@rl_line_buffer[_end,1]) && _end < @rl_end)

  if (whitespace(@rl_line_buffer[_end,1]) || _end >= @rl_end)
    _end-=1
  end

  # If the first character of the current word is a tilde, perform
  #tilde expansion and insert the result.  If not a tilde, do
  #   nothing.
  if (@rl_line_buffer[start,1] == '~')

    len = _end - start + 1
    temp = @rl_line_buffer[start,len]
    homedir = File.expand_path(temp)
    temp = nil

    _rl_replace_text(homedir, start, _end)
  end
  0
end
rl_translate_keyseq(seq) click to toggle source
# File lib/rbreadline.rb, line 2395
def rl_translate_keyseq(seq)
  require 'strscan'

  ss = StringScanner.new(seq)
  new_seq = ''

  until ss.eos?
    char = ss.getch
    next new_seq << char unless char == '\\'

    char = ss.getch
    new_seq << case char
               when 'a'
                 "\007"
               when 'b'
                 "\b"
               when 'd'
                 RUBOUT
               when 'e'
                 ESC
               when 'f'
                 "\f"
               when 'n'
                 NEWLINE
               when 'r'
                 RETURN
               when 't'
                 TAB
               when 'v'
                 0x0B
               when '\\'
                 '\\'
               when 'x'
                 ss.scan(/\d\d/).to_i(16).chr
               when '0'..'7'
                 ss.pos -= 1
                 ss.scan(/\d\d\d/).to_i(8).chr
               else
                 char
               end
  end

  new_seq
end
rl_transpose_chars(count, key) click to toggle source

Transpose the characters at point. If point is at the end of the line,

then transpose the characters before point.
# File lib/rbreadline.rb, line 7399
def rl_transpose_chars(count, key)
  return 0 if (count == 0)

  if (@rl_point==0 || @rl_end < 2)
    rl_ding()
    return -1
  end

  rl_begin_undo_group()

  if (@rl_point == @rl_end)
    if !@rl_byte_oriented
      @rl_point = _rl_find_prev_mbchar(@rl_line_buffer, @rl_point, MB_FIND_NONZERO)
    else
      @rl_point -= 1
    end
    count = 1
  end

  prev_point = @rl_point
  if !@rl_byte_oriented
    @rl_point = _rl_find_prev_mbchar(@rl_line_buffer, @rl_point, MB_FIND_NONZERO)
  else
    @rl_point -= 1
  end

  char_length = prev_point - @rl_point
  dummy = @rl_line_buffer[@rl_point,char_length]

  rl_delete_text(@rl_point, @rl_point + char_length)

  @rl_point += count
  _rl_fix_point(0)
  rl_insert_text(dummy)
  rl_end_undo_group()
  dummy = nil
  0
end
rl_transpose_words(count, key) click to toggle source

Transpose the words at point. If point is at the end of the line,

transpose the two words before point.
# File lib/rbreadline.rb, line 8306
def rl_transpose_words(count, key)
  orig_point = @rl_point

  return if (count==0)

  # Find the two words.
  rl_forward_word(count, key)
  w2_end = @rl_point
  rl_backward_word(1, key)
  w2_beg = @rl_point
  rl_backward_word(count, key)
  w1_beg = @rl_point
  rl_forward_word(1, key)
  w1_end = @rl_point

  # Do some check to make sure that there really are two words.
  if ((w1_beg == w2_beg) || (w2_beg < w1_end))
    rl_ding()
    @rl_point = orig_point
    return -1
  end

  # Get the text of the words.
  word1 = rl_copy_text(w1_beg, w1_end)
  word2 = rl_copy_text(w2_beg, w2_end)

  # We are about to do many insertions and deletions.  Remember them
  #   as one operation.
  rl_begin_undo_group()

  # Do the stuff at word2 first, so that we don't have to worry
  #   about word1 moving.
  @rl_point = w2_beg
  rl_delete_text(w2_beg, w2_end)
  rl_insert_text(word1)

  @rl_point = w1_beg
  rl_delete_text(w1_beg, w1_end)
  rl_insert_text(word2)

  # This is exactly correct since the text before this point has not
  #   changed in length.
  @rl_point = w2_end

  # I think that does it.
  rl_end_undo_group()
  word1 = nil
  word2 = nil

  0
end
rl_tty_set_default_bindings(kmap) click to toggle source

New public way to set the system default editing chars to their readline

equivalents.
# File lib/rbreadline.rb, line 2058
def rl_tty_set_default_bindings(kmap)
  h = {}
  retry_if_interrupted do
    h = Hash[*`stty -a`.scan(/(\w+) = ([^;]+);/).flatten]
  end
  h.each {|k,v| v.gsub!(/\^(.)/){($1[0].ord ^ ((?a..?z).include?($1[0]) ? 0x60 : 0x40)).chr}}
  kmap[h['erase']] = :rl_rubout
  kmap[h['kill']] = :rl_unix_line_discard
  kmap[h['werase']] = :rl_unix_word_rubout
  kmap[h['lnext']] = :rl_quoted_insert
end
rl_tty_unset_default_bindings(kmap) click to toggle source

Rebind all of the tty special chars that readline worries about back

to self-insert.  Call this before saving the current terminal special
chars with save_tty_chars().  This only works on POSIX termios or termio
systems.
# File lib/rbreadline.rb, line 7041
def rl_tty_unset_default_bindings(kmap)
  # Don't bother before we've saved the tty special chars at least once.
  return if (!rl_isstate(RL_STATE_TTYCSAVED))

  kmap[@_rl_tty_chars.t_erase] = :rl_insert
  kmap[@_rl_tty_chars.t_kill] = :rl_insert
  kmap[@_rl_tty_chars.t_lnext] = :rl_insert
  kmap[@_rl_tty_chars.t_werase] = :rl_insert
end
rl_undo_command(count, key) click to toggle source

Do some undoing of things that were done.

# File lib/rbreadline.rb, line 7714
def rl_undo_command(count, key)
  if (count < 0)
    return 0 # Nothing to do.
  end
  while (count>0)
    if (rl_do_undo())
      count-=1
    else
      rl_ding()
      break
    end
  end
  0
end
rl_unix_filename_rubout(count, key) click to toggle source

This deletes one filename component in a Unix pathname. That is, it

deletes backward to directory separator (`/') or whitespace.
# File lib/rbreadline.rb, line 6030
def rl_unix_filename_rubout(count, key)
  if (@rl_point == 0)
    rl_ding()
  else
    orig_point = @rl_point
    if (count <= 0)
      count = 1
    end

    while (count>0)

      c = @rl_line_buffer[@rl_point - 1,1]
      while (@rl_point>0 && (whitespace(c) || c == '/'))
        @rl_point-=1
        c = @rl_line_buffer[@rl_point - 1,1]
      end

      while (@rl_point>0 && !whitespace(c) && c != '/')
        @rl_point-=1
        c = @rl_line_buffer[@rl_point - 1,1]
      end
      count -= 1
    end

    rl_kill_text(orig_point, @rl_point)
    if (@rl_editing_mode == @emacs_mode)
      @rl_mark = @rl_point
    end
  end
  0
end
rl_unix_line_discard(count, key) click to toggle source

Here is C-u doing what Unix does. You don’t have to use these key-bindings. We have a choice of killing the entire line, or killing from where we are to the start of the line. We choose the latter, because if you are a Unix weenie, then you haven’t backspaced into the line at all, and if you aren’t, then you know what you are doing.

# File lib/rbreadline.rb, line 7444
def rl_unix_line_discard(count, key)
  if (@rl_point == 0)
    rl_ding()
  else
    rl_kill_text(@rl_point, 0)
    @rl_point = 0
    if (@rl_editing_mode == @emacs_mode)
      @rl_mark = @rl_point
    end
  end
  0
end
rl_unix_word_rubout(count, key) click to toggle source

This does what C-w does in Unix. We can’t prevent people from

using behaviour that they expect.
# File lib/rbreadline.rb, line 6000
def rl_unix_word_rubout(count, key)
  if (@rl_point == 0)
    rl_ding()
  else
    orig_point = @rl_point
    if (count <= 0)
      count = 1
    end

    while (count>0)
      while (@rl_point>0 && whitespace(@rl_line_buffer[@rl_point - 1,1]))
        @rl_point-=1
      end

      while (@rl_point>0 && !whitespace(@rl_line_buffer[@rl_point - 1,1]))
        @rl_point-=1
      end
      count -= 1
    end

    rl_kill_text(orig_point, @rl_point)
    if (@rl_editing_mode == @emacs_mode)
      @rl_mark = @rl_point
    end
  end
  0
end
rl_unsetstate(x) click to toggle source
# File lib/rbreadline.rb, line 1639
def rl_unsetstate(x)
  (@rl_readline_state &= ~(x))
end
rl_upcase_word(count, key) click to toggle source

Uppercase the word at point.

# File lib/rbreadline.rb, line 7929
def rl_upcase_word(count, key)
  rl_change_case(count, UpCase)
end
rl_username_completion_function(text, state) click to toggle source

A completion function for usernames.

TEXT contains a partial username preceded by a random
character (usually `~').
# File lib/rbreadline.rb, line 1243
def rl_username_completion_function(text, state)
  return nil if RUBY_PLATFORM =~ /mswin|mingw/

    if (state == 0)
      first_char = text[0,1]
      first_char_loc = (first_char == '~' ? 1 : 0)

      username = text[first_char_loc..-1]
      namelen = username.length
      Etc.setpwent()
    end

  while (entry = Etc.getpwent())
    # Null usernames should result in all users as possible completions.
    break if (namelen == 0 || entry.name =~ /^#{username}/ )
  end

  if entry.nil?
    Etc.endpwent()
    return nil
  else
    value = text.dup
    value[first_char_loc..-1] = entry.name

    if (first_char == '~')
      @rl_filename_completion_desired = true
    end

    return (value)
  end
end
rl_variable_bind(name,value) click to toggle source
# File lib/rbreadline.rb, line 2259
def rl_variable_bind(name,value)
  case name
  when "bind-tty-special-chars"
    @_rl_bind_stty_chars = value.nil? || value=='1' || value == 'on'
  when "blink-matching-paren"
    @rl_blink_matching_paren = value.nil? || value=='1' || value == 'on'
  when "byte-oriented"
    @rl_byte_oriented = value.nil? || value=='1' || value == 'on'
  when "completion-ignore-case"
    @_rl_completion_case_fold = value.nil? || value=='1' || value == 'on'
  when "convert-meta"
    @_rl_convert_meta_chars_to_ascii = value.nil? || value=='1' || value == 'on'
  when "disable-completion"
    @rl_inhibit_completion = value.nil? || value=='1' || value == 'on'
  when "enable-keypad"
    @_rl_enable_keypad = value.nil? || value=='1' || value == 'on'
  when "expand-tilde"
    @rl_complete_with_tilde_expansion = value.nil? || value=='1' || value == 'on'
  when "history-preserve-point"
    @_rl_history_preserve_point = value.nil? || value=='1' || value == 'on'
  when "horizontal-scroll-mode"
    @_rl_horizontal_scroll_mode = value.nil? || value=='1' || value == 'on'
  when "input-meta"
    @_rl_meta_flag = value.nil? || value=='1' || value == 'on'
  when "mark-directories"
    @_rl_complete_mark_directories = value.nil? || value=='1' || value == 'on'
  when "mark-modified-lines"
    @_rl_mark_modified_lines = value.nil? || value=='1' || value == 'on'
  when "mark-symlinked-directories"
    @_rl_complete_mark_symlink_dirs = value.nil? || value=='1' || value == 'on'
  when "match-hidden-files"
    @_rl_match_hidden_files = value.nil? || value=='1' || value == 'on'
  when "meta-flag"
    @_rl_meta_flag = value.nil? || value=='1' || value == 'on'
  when "output-meta"
    @_rl_output_meta_chars = value.nil? || value=='1' || value == 'on'
  when "page-completions"
    @_rl_page_completions = value.nil? || value=='1' || value == 'on'
  when "prefer-visible-bell"
    @_rl_prefer_visible_bell = value.nil? || value=='1' || value == 'on'
  when "print-completions-horizontally"
    @_rl_print_completions_horizontally = value.nil? || value=='1' || value == 'on'
  when "show-all-if-ambiguous"
    @_rl_complete_show_all = value.nil? || value=='1' || value == 'on'
  when "show-all-if-unmodified"
    @_rl_complete_show_unmodified = value.nil? || value=='1' || value == 'on'
  when "visible-stats"
    @rl_visible_stats = value.nil? || value=='1' || value == 'on'
  when "bell-style"
    case value
    when "none","off"
      @_rl_bell_preference = NO_BELL
    when "audible", "on"
      @_rl_bell_preference = AUDIBLE_BELL
    when "visible"
      @_rl_bell_preference = VISIBLE_BELL
    else
      @_rl_bell_preference = AUDIBLE_BELL
    end
  when "comment-begin"
    @_rl_comment_begin = value.dup
  when "completion-query-items"
    @rl_completion_query_items = value.to_i
  when "editing-mode"
    case value
    when "vi"
      # This is a NOOP until the rest of Vi-mode is working.
    when "emacs"
      @_rl_keymap = @emacs_standard_keymap
      @rl_editing_mode = @emacs_mode
    end
  when "isearch-terminators"
    @_rl_isearch_terminators = instance_eval(value)
  when "keymap"
    case value
    when "emacs","emacs-standard","emacs-meta","emacs-ctlx"
      @_rl_keymap = @emacs_standard_keymap
    when "vi","vi-move","vi-command"
      # This is a NOOP until the rest of Vi-mode is working.
    when "vi-insert"
      # This is a NOOP until the rest of Vi-mode is working.
    end
  end
end
rl_vi_check() click to toggle source
# File lib/rbreadline.rb, line 4815
def rl_vi_check()
  if (@rl_point!=0 && @rl_point == @rl_end)
    @rl_point-=1
  end
  0
end
rl_vi_editing_mode(count, key) click to toggle source

This is a NOOP until the rest of Vi-mode is working.

# File lib/rbreadline.rb, line 1429
def rl_vi_editing_mode(count, key)
  0
end
rl_vi_insertion_mode(count, key) click to toggle source

Switching from one mode to the other really just involves

switching keymaps.
# File lib/rbreadline.rb, line 1435
def rl_vi_insertion_mode(count, key)
  @_rl_keymap = @vi_insertion_keymap
  @_rl_vi_last_key_before_insert = key
  0
end
rl_yank(count, ignore) click to toggle source

Yank back the last killed text. This ignores arguments.

# File lib/rbreadline.rb, line 7458
def rl_yank(count, ignore)
  if @rl_kill_ring.nil?
    _rl_abort_internal()
    return -1
  end
  _rl_set_mark_at_pos(@rl_point)
  rl_insert_text(@rl_kill_ring[@rl_kill_index])
  0
end
rl_yank_last_arg(count, key) click to toggle source
# File lib/rbreadline.rb, line 7548
def rl_yank_last_arg(count, key)
  if (@rl_last_func != :rl_yank_last_arg)
    @history_skip = 0
    @explicit_arg_p = @rl_explicit_arg
    @count_passed = count
    @direction = 1
  else
    if (@undo_needed)
      rl_do_undo()
    end
    if (count < 1)
      @direction = -@direction
    end
    @history_skip += @direction
    if (@history_skip < 0)
      @history_skip = 0
    end
  end

  if (@explicit_arg_p)
    retval = rl_yank_nth_arg_internal(@count_passed, key, @history_skip)
  else
    retval = rl_yank_nth_arg_internal('$', key, @history_skip)
  end
  @undo_needed = retval == 0
  retval
end
rl_yank_nth_arg(count, ignore) click to toggle source

Yank the COUNTth argument from the previous history line.

# File lib/rbreadline.rb, line 7535
def rl_yank_nth_arg(count, ignore)
  rl_yank_nth_arg_internal(count, ignore, 0)
end
rl_yank_nth_arg_internal(count, ignore, history_skip) click to toggle source

Yank the COUNTh argument from the previous history line, skipping

HISTORY_SKIP lines before looking for the `previous line'.
# File lib/rbreadline.rb, line 7498
def rl_yank_nth_arg_internal(count, ignore, history_skip)
  pos = where_history()
  if (history_skip>0)
    history_skip.times { previous_history() }
  end
  entry = previous_history()
  history_set_pos(pos)
  if entry.nil?
    rl_ding()
    return -1
  end

  arg = history_arg_extract(count, count, entry.line)
  if (arg.nil? || arg=='')
    rl_ding()
    arg = nil
    return -1
  end

  rl_begin_undo_group()

  _rl_set_mark_at_pos(@rl_point)

  # Vi mode always inserts a space before yanking the argument, and it
  #   inserts it right *after* rl_point.
  if (@rl_editing_mode == @vi_mode)
    rl_vi_append_mode(1, ignore)
    rl_insert_text(" ")
  end

  rl_insert_text(arg)
  arg = nil
  rl_end_undo_group()
  return 0
end
rl_yank_pop(count, key) click to toggle source

If the last command was yank, or yank_pop, and the text just

before point is identical to the current kill item, then
delete that text from the line, rotate the index down, and
yank back some other text.
# File lib/rbreadline.rb, line 7472
def rl_yank_pop(count, key)
  if (((@rl_last_func != :rl_yank_pop) && (@rl_last_func != :rl_yank)) ||
      @rl_kill_ring.nil?)
    _rl_abort_internal()
    return -1
  end

  l = @rl_kill_ring[@rl_kill_index].length
  n = @rl_point - l
  if (n >= 0 && @rl_line_buffer[n,l] == @rl_kill_ring[@rl_kill_index][0,l])
    rl_delete_text(n, @rl_point)
    @rl_point = n
    @rl_kill_index-=1
    if (@rl_kill_index < 0)
      @rl_kill_index = @rl_kill_ring_length - 1
    end
    rl_yank(1, 0)
    return 0
  else
    _rl_abort_internal()
    return -1
  end
end
save_tty_chars() click to toggle source
# File lib/rbreadline.rb, line 6964
def save_tty_chars()
  @_rl_last_tty_chars = @_rl_tty_chars
  h = {}
  retry_if_interrupted do
    h = Hash[*`stty -a`.scan(/(\w+) = ([^;]+);/).flatten]
  end
  h.each {|k,v| v.gsub!(/\^(.)/){($1[0].ord ^ ((?a..?z).include?($1[0]) ? 0x60 : 0x40)).chr}}
  @_rl_tty_chars.t_erase = h['erase']
  @_rl_tty_chars.t_kill = h['kill']
  @_rl_tty_chars.t_intr = h['intr']
  @_rl_tty_chars.t_quit = h['quit']
  @_rl_tty_chars.t_start = h['start']
  @_rl_tty_chars.t_stop = h['stop']
  @_rl_tty_chars.t_eof = h['eof']
  @_rl_tty_chars.t_eol = "\n"
  @_rl_tty_chars.t_eol2 = h['eol2']
  @_rl_tty_chars.t_susp = h['susp']
  @_rl_tty_chars.t_dsusp = h['dsusp']
  @_rl_tty_chars.t_reprint = h['rprnt']
  @_rl_tty_chars.t_flush = h['flush']
  @_rl_tty_chars.t_werase = h['werase']
  @_rl_tty_chars.t_lnext = h['lnext']
  @_rl_tty_chars.t_status = -1
  retry_if_interrupted do
    @otio = `stty -g`
  end
end
set_completion_defaults(what_to_do) click to toggle source

Set default values for readline word completion. These are the variables

that application completion functions can change or inspect.
# File lib/rbreadline.rb, line 6179
def set_completion_defaults(what_to_do)
  # Only the completion entry function can change these.
  @rl_filename_completion_desired = false
  @rl_filename_quoting_desired = true
  @rl_completion_type = what_to_do
  @rl_completion_suppress_append = @rl_completion_suppress_quote = false

  # The completion entry function may optionally change this.
  @rl_completion_mark_symlink_dirs = @_rl_complete_mark_symlink_dirs
end
sh_set_lines_and_columns(lines, cols) click to toggle source

Set the environment variables LINES and COLUMNS to lines and cols,

respectively.
# File lib/rbreadline.rb, line 1850
def sh_set_lines_and_columns(lines, cols)
  ENV["LINES"] = lines.to_s
  ENV["COLUMNS"] = cols.to_s
end
space_to_eol(count) click to toggle source

Clear to the end of the line using spaces. COUNT is the minimum

number of character spaces to clear,
# File lib/rbreadline.rb, line 4659
def space_to_eol(count)
  if @hConsoleHandle
    csbi = Fiddle::Pointer.malloc(24)
    @GetConsoleScreenBufferInfo.Call(@hConsoleHandle,csbi)
    cursor_pos = csbi[4,4].unpack('L').first
    written = Fiddle::Pointer.malloc(4)
    @FillConsoleOutputCharacter.Call(@hConsoleHandle,0x20,count,cursor_pos,written)
  else
    @rl_outstream.write(' ' * count)
  end
  @_rl_last_c_pos += count
end
stat_char(filename) click to toggle source

Return the character which best describes FILENAME.

`@' for symbolic links
`/' for directories
`*' for executables
`=' for sockets
`|' for FIFOs
`%' for character special devices
`#' for block special devices
# File lib/rbreadline.rb, line 6567
def stat_char(filename)
  return nil if !File.exists?(filename)

  return '/' if File.directory?(filename)
  return '%' if File.chardev?(filename)
  return '#' if File.blockdev?(filename)
  return '@' if File.symlink?(filename)
  return '=' if File.socket?(filename)
  return '|' if File.pipe?(filename)
  return '*' if File.executable?(filename)
  nil
end
stifle_history(max) click to toggle source

Stifle the history list, remembering only MAX number of lines.

# File lib/rbreadline.rb, line 8523
def stifle_history(max)
  max = 0 if (max < 0)

  if (@history_length > max)
    @the_history.slice!(0,(@history_length - max))
    @history_length = max
  end

  @history_stifled = true
  @max_input_history = @history_max_entries = max
end
tgetflag(name) click to toggle source
# File lib/rbreadline.rb, line 1901
def tgetflag(name)
    `infocmp -C -r`.scan(/\w{2}/).include?(name)
end
trans(i) click to toggle source

Undo the next thing in the list. Return 0 if there

is nothing to undo, or non-zero if there was.
# File lib/rbreadline.rb, line 7657
def trans(i)
  ((i) == -1 ? @rl_point : ((i) == -2 ? @rl_end : (i)))
end
unstifle_history() click to toggle source

Stop stifling the history. This returns the previous maximum

number of history entries.  The value is positive if the history
was stifled,  negative if it wasn't.
# File lib/rbreadline.rb, line 8538
def unstifle_history()
  if (@history_stifled)
    @history_stifled = false
    return (@history_max_entries)
  else
    return (-@history_max_entries)
  end
end
update_line(old, ostart, new, current_line, omax, nmax, inv_botlin) click to toggle source

PWP: update_line() is based on finding the middle difference of each

 line on the screen; vis:

           /old first difference
/beginning of line   |        /old last same       /old EOL
v          v         v         v

old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as new: eddie> Oh, my little buggy says to me, as lurgid as

^          ^   ^           ^
\beginning of line   |  \new last same    \new end of line
           \new first difference

 All are character pointers for the sake of speed.  Special cases for
 no differences, as well as for end of line additions must be handled.

 Could be made even smarter, but this works well enough
# File lib/rbreadline.rb, line 2728
def update_line(old, ostart, new, current_line, omax, nmax, inv_botlin)
  # If we're at the right edge of a terminal that supports xn, we're
  #   ready to wrap around, so do so.  This fixes problems with knowing
  #   the exact cursor position and cut-and-paste with certain terminal
  #   emulators.  In this calculation, TEMP is the physical screen
  #   position of the cursor.
  if @encoding == 'X'
    old.force_encoding('ASCII-8BIT')
    new.force_encoding('ASCII-8BIT')
  end

  if !@rl_byte_oriented
    temp = @_rl_last_c_pos
  else
    temp = @_rl_last_c_pos - w_offset(@_rl_last_v_pos, @visible_wrap_offset)
  end
  if (temp == @_rl_screenwidth && @_rl_term_autowrap && !@_rl_horizontal_scroll_mode &&
      @_rl_last_v_pos == current_line - 1)

    if (!@rl_byte_oriented)
      # This fixes only double-column characters, but if the wrapped
      #   character comsumes more than three columns, spaces will be
      #   inserted in the string buffer.
      if (@_rl_wrapped_line[current_line] > 0)
        _rl_clear_to_eol(@_rl_wrapped_line[current_line])
      end

      if new[0,1] != 0.chr
        case @encoding
        when 'E'
          wc = new.scan(/./me)[0]
          ret = wc.length
          tempwidth = wc.length
        when 'S'
          wc = new.scan(/./ms)[0]
          ret = wc.length
          tempwidth = wc.length
        when 'U'
          wc = new.scan(/./mu)[0]
          ret = wc.length
          tempwidth = wc.unpack('U').first >= 0x1000 ? 2 : 1
        when 'X'
          wc = new[0..-1].force_encoding(@encoding_name)[0]
          ret = wc.bytesize
          tempwidth = wc.ord >= 0x1000 ? 2 : 1
        else
          ret = 1
          tempwidth = 1
        end
      else
        tempwidth = 0
      end

      if (tempwidth > 0)
        bytes = ret
        @rl_outstream.write(new[0,bytes])
        @_rl_last_c_pos = tempwidth
        @_rl_last_v_pos+=1

        if old[ostart,1] != 0.chr
          case @encoding
          when 'E'
            wc = old[ostart..-1].scan(/./me)[0]
            ret = wc.length
          when 'S'
            wc = old[ostart..-1].scan(/./ms)[0]
            ret = wc.length
          when 'U'
            wc = old[ostart..-1].scan(/./mu)[0]
            ret = wc.length
          when 'X'
            wc = old[ostart..-1].force_encoding(@encoding_name)[0]
            ret = wc.bytesize
          end
        else
          ret = 0
        end
        if (ret != 0 && bytes != 0)
          if ret != bytes
            len = old[ostart..-1].index(0.chr,ret)
            old[ostart+bytes,len-ret] = old[ostart+ret,len-ret]
          end
          old[ostart,bytes] = new[0,bytes]
        end
      else
        @rl_outstream.write(' ')
        @_rl_last_c_pos = 1
        @_rl_last_v_pos+=1
        if (old[ostart,1] != 0.chr && new[0,1] != 0.chr)
          old[ostart,1] = new[0,1]
        end
      end

    else
      if (new[0,1] != 0.chr)
        @rl_outstream.write(new[0,1])
      else
        @rl_outstream.write(' ')
      end
      @_rl_last_c_pos = 1
      @_rl_last_v_pos+=1
      if (old[ostart,1] != 0.chr && new[0,1] != 0.chr)
        old[ostart,1] = new[0,1]
      end
    end
  end

  # Find first difference.
  if (!@rl_byte_oriented)
    # See if the old line is a subset of the new line, so that the
    # only change is adding characters.
    temp = (omax < nmax) ? omax : nmax
    if old[ostart,temp]==new[0,temp]
      ofd = temp
      nfd = temp
    else
      if (omax == nmax && new[0,omax]==old[ostart,omax])
        ofd = omax
        nfd = nmax
      else
        new_offset = 0
        old_offset = ostart
        ofd = 0
        nfd = 0
        while(ofd < omax && old[ostart+ofd,1] != 0.chr &&
              _rl_compare_chars(old, old_offset, new, new_offset))

          old_offset = _rl_find_next_mbchar(old, old_offset, 1, MB_FIND_ANY)
          new_offset = _rl_find_next_mbchar(new, new_offset, 1, MB_FIND_ANY)
          ofd = old_offset - ostart
          nfd = new_offset
        end
      end
    end
  else
    ofd = 0
    nfd = 0
    while(ofd < omax && old[ostart+ofd,1] != 0.chr && old[ostart+ofd,1] == new[nfd,1])
      ofd += 1
      nfd += 1
    end
  end


  # Move to the end of the screen line.  ND and OD are used to keep track
  #   of the distance between ne and new and oe and old, respectively, to
  #   move a subtraction out of each loop.
  oe = old.index(0.chr,ostart+ofd) - ostart
  if oe.nil? || oe>omax
    oe = omax
  end

  ne = new.index(0.chr,nfd)
  if ne.nil? || ne>omax
    ne = nmax
  end

  # If no difference, continue to next line.
  if (ofd == oe && nfd == ne)
    return
  end


  wsatend = true       # flag for trailing whitespace

  if (!@rl_byte_oriented)

    ols = _rl_find_prev_mbchar(old, ostart+oe, MB_FIND_ANY) - ostart
    nls = _rl_find_prev_mbchar(new, ne, MB_FIND_ANY)
    while ((ols > ofd) && (nls > nfd))

      if (!_rl_compare_chars(old, ostart+ols, new, nls))
        break
      end
      if (old[ostart+ols,1] == " ")
        wsatend = false
      end

      ols = _rl_find_prev_mbchar(old, ols+ostart, MB_FIND_ANY) - ostart
      nls = _rl_find_prev_mbchar(new, nls, MB_FIND_ANY)
    end
  else
    ols = oe - 1         # find last same
    nls = ne - 1
    while ((ols > ofd) && (nls > nfd) && old[ostart+ols,1] == new[nls,1])
      if (old[ostart+ols,1] != " ")
        wsatend = false
      end
      ols-=1
      nls-=1
    end
  end

  if (wsatend)
    ols = oe
    nls = ne
  elsif (!_rl_compare_chars(old, ostart+ols, new, nls))
    if (old[ostart+ols,1] != 0.chr)         # don't step past the NUL
      if !@rl_byte_oriented
        ols = _rl_find_next_mbchar(old, ostart+ols, 1, MB_FIND_ANY) - ostart
      else
        ols+=1
      end
    end
    if (new[nls,1] != 0.chr )
      if !@rl_byte_oriented
        nls = _rl_find_next_mbchar(new, nls, 1, MB_FIND_ANY)
      else
        nls+=1
      end
    end
  end

  # count of invisible characters in the current invisible line.
  current_invis_chars = w_offset(current_line, @wrap_offset)
  if (@_rl_last_v_pos != current_line)
    _rl_move_vert(current_line)
    if (@rl_byte_oriented && current_line == 0 && @visible_wrap_offset!=0)
      @_rl_last_c_pos += @visible_wrap_offset
    end
  end

  # If this is the first line and there are invisible characters in the
  #   prompt string, and the prompt string has not changed, and the current
  #   cursor position is before the last invisible character in the prompt,
  #   and the index of the character to move to is past the end of the prompt
  #   string, then redraw the entire prompt string.  We can only do this
  #   reliably if the terminal supports a `cr' capability.

  #  This is not an efficiency hack -- there is a problem with redrawing
  #  portions of the prompt string if they contain terminal escape
  #  sequences (like drawing the `unbold' sequence without a corresponding
  #  `bold') that manifests itself on certain terminals.

  lendiff = @local_prompt_len

  if (current_line == 0 && !@_rl_horizontal_scroll_mode &&
      @_rl_term_cr && lendiff > @prompt_visible_length && @_rl_last_c_pos > 0 &&
      ofd >= lendiff && @_rl_last_c_pos < prompt_ending_index())
    @rl_outstream.write(@_rl_term_cr)
    _rl_output_some_chars(@local_prompt,0,lendiff)
    if !@rl_byte_oriented
      # We take wrap_offset into account here so we can pass correct
      #   information to _rl_move_cursor_relative.
      @_rl_last_c_pos = _rl_col_width(@local_prompt, 0, lendiff) - @wrap_offset
      @cpos_adjusted = true
    else
      @_rl_last_c_pos = lendiff
    end
  end

  o_cpos = @_rl_last_c_pos

  # When this function returns, _rl_last_c_pos is correct, and an absolute
  #   cursor postion in multibyte mode, but a buffer index when not in a
  #   multibyte locale.
  _rl_move_cursor_relative(ofd, old, ostart)

  # We need to indicate that the cursor position is correct in the presence
  # of invisible characters in the prompt string.  Let's see if setting this
  # when we make sure we're at the end of the drawn prompt string works.
  if (current_line == 0 && !@rl_byte_oriented &&
      (@_rl_last_c_pos > 0 || o_cpos > 0) &&
      @_rl_last_c_pos == @prompt_physical_chars)
    @cpos_adjusted = true
  end

  # if (len (new) > len (old))
  #   lendiff == difference in buffer
  #   col_lendiff == difference on screen
  #   When not using multibyte characters, these are equal
  lendiff = (nls - nfd) - (ols - ofd)
  if !@rl_byte_oriented
    col_lendiff = _rl_col_width(new, nfd, nls) - _rl_col_width(old, ostart+ofd, ostart+ols)
  else
    col_lendiff = lendiff
  end

  # If we are changing the number of invisible characters in a line, and
  #   the spot of first difference is before the end of the invisible chars,
  #   lendiff needs to be adjusted.
  if (current_line == 0 && !@_rl_horizontal_scroll_mode &&
      current_invis_chars != @visible_wrap_offset)
    if !@rl_byte_oriented
      lendiff += @visible_wrap_offset - current_invis_chars
      col_lendiff += @visible_wrap_offset - current_invis_chars
    else
      lendiff += @visible_wrap_offset - current_invis_chars
      col_lendiff = lendiff
    end
  end

  # Insert (diff (len (old), len (new)) ch.
  temp = ne - nfd
  if !@rl_byte_oriented
    col_temp = _rl_col_width(new,nfd,ne)
  else
    col_temp = temp
  end
  if (col_lendiff > 0) # XXX - was lendiff

    # Non-zero if we're increasing the number of lines.
    gl = current_line >= @_rl_vis_botlin && inv_botlin > @_rl_vis_botlin

    # If col_lendiff is > 0, implying that the new string takes up more
    # screen real estate than the old, but lendiff is < 0, meaning that it
    # takes fewer bytes, we need to just output the characters starting from
    # the first difference.  These will overwrite what is on the display, so
    # there's no reason to do a smart update.  This can really only happen in
    # a multibyte environment.
    if lendiff < 0
      _rl_output_some_chars(new, nfd, temp)
      @_rl_last_c_pos += _rl_col_width(new, nfd, nfd+temp)

      # If nfd begins before any invisible characters in the prompt, adjust
      # _rl_last_c_pos to account for wrap_offset and set cpos_adjusted to
      # let the caller know.
      if current_line == 0 && @wrap_offset && nfd <= @prompt_last_invisible
        @_rl_last_c_pos -= @wrap_offset
        @cpos_adjusted = true
      end
      return
    # Sometimes it is cheaper to print the characters rather than
    # use the terminal's capabilities.  If we're growing the number
    # of lines, make sure we actually cause the new line to wrap
    # around on auto-wrapping terminals.
    elsif (@_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || @_rl_term_IC) && (!@_rl_term_autowrap || !gl))

      # If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and
      #   _rl_horizontal_scroll_mode == 1, inserting the characters with
      #   _rl_term_IC or _rl_term_ic will screw up the screen because of the
      #   invisible characters.  We need to just draw them.
      if (old[ostart+ols,1] != 0.chr && (!@_rl_horizontal_scroll_mode || @_rl_last_c_pos > 0 ||
                                         lendiff <= @prompt_visible_length || current_invis_chars==0))

        insert_some_chars(new[nfd..-1], lendiff, col_lendiff)
        @_rl_last_c_pos += col_lendiff
      elsif ((@rl_byte_oriented) && old[ostart+ols,1] == 0.chr && lendiff > 0)
        # At the end of a line the characters do not have to
        # be "inserted".  They can just be placed on the screen.
        # However, this screws up the rest of this block, which
        # assumes you've done the insert because you can.
        _rl_output_some_chars(new,nfd, lendiff)
        @_rl_last_c_pos += col_lendiff
      else
        _rl_output_some_chars(new,nfd, temp)
        @_rl_last_c_pos += col_temp
        # If nfd begins before any invisible characters in the prompt, adjust
        # _rl_last_c_pos to account for wrap_offset and set cpos_adjusted to
        # let the caller know.
        if current_line == 0 && @wrap_offset && nfd <= @prompt_last_invisible
          @_rl_last_c_pos -= @wrap_offset
          @cpos_adjusted = true
        end
        return
      end
      # Copy (new) chars to screen from first diff to last match.
      temp = nls - nfd
      if ((temp - lendiff) > 0)
        _rl_output_some_chars(new,(nfd + lendiff),temp - lendiff)
        # XXX -- this bears closer inspection.  Fixes a redisplay bug
        # reported against bash-3.0-alpha by Andreas Schwab involving
        # multibyte characters and prompt strings with invisible
        # characters, but was previously disabled.
        @_rl_last_c_pos += _rl_col_width(new,nfd+lendiff, nfd+lendiff+temp-col_lendiff)
      end
    else
      # cannot insert chars, write to EOL
      _rl_output_some_chars(new,nfd, temp)
      @_rl_last_c_pos += col_temp
      # If we're in a multibyte locale and were before the last invisible
      #   char in the current line (which implies we just output some invisible
      #   characters) we need to adjust _rl_last_c_pos, since it represents
      #   a physical character position.
    end
  else           # Delete characters from line.
    # If possible and inexpensive to use terminal deletion, then do so.
    if (@_rl_term_dc && (2 * col_temp) >= -col_lendiff)

      # If all we're doing is erasing the invisible characters in the
      #   prompt string, don't bother.  It screws up the assumptions
      #   about what's on the screen.
      if (@_rl_horizontal_scroll_mode && @_rl_last_c_pos == 0 &&
          -lendiff == @visible_wrap_offset)
        col_lendiff = 0
      end

      if (col_lendiff!=0)
        delete_chars(-col_lendiff) # delete (diff) characters
      end

      # Copy (new) chars to screen from first diff to last match
      temp = nls - nfd
      if (temp > 0)
        # If nfd begins at the prompt, or before the invisible characters in
        # the prompt, we need to adjust _rl_last_c_pos in a multibyte locale
        # to account for the wrap offset and set cpos_adjusted accordingly.
        _rl_output_some_chars(new,nfd, temp)
        if !@rl_byte_oriented
          @_rl_last_c_pos += _rl_col_width(new,nfd,nfd+temp)
          if current_line == 0 && @wrap_offset && nfd <= @prompt_last_invisible
            @_rl_last_c_pos -= @wrap_offset
            @cpos_adjusted = true
          end
        else
          @_rl_last_c_pos += temp
        end
      end

      # Otherwise, print over the existing material.
    else
      if (temp > 0)
        # If nfd begins at the prompt, or before the invisible characters in
        # the prompt, we need to adjust _rl_last_c_pos in a multibyte locale
        # to account for the wrap offset and set cpos_adjusted accordingly.
        _rl_output_some_chars(new,nfd, temp)
        @_rl_last_c_pos += col_temp      # XXX
        if !@rl_byte_oriented
          if current_line == 0 && @wrap_offset && nfd <= @prompt_last_invisible
            @_rl_last_c_pos -= @wrap_offset
            @cpos_adjusted = true
          end
        end
      end

      lendiff = (oe) - (ne)
      if !@rl_byte_oriented
        col_lendiff = _rl_col_width(old, ostart, ostart+oe) - _rl_col_width(new, 0, ne)
      else
        col_lendiff = lendiff
      end

      if (col_lendiff!=0)
        if (@_rl_term_autowrap && current_line < inv_botlin)
          space_to_eol(col_lendiff)
        else
          _rl_clear_to_eol(col_lendiff)
        end
      end
    end
  end
end
using_history() click to toggle source
# File lib/rbreadline.rb, line 6173
def using_history()
  @history_offset = @history_length
end
vis_chars(line) click to toggle source
# File lib/rbreadline.rb, line 2691
def vis_chars(line)
  @visible_line[@vis_lbreaks[line] .. -1]
end
vis_line(line) click to toggle source
# File lib/rbreadline.rb, line 2699
def vis_line(line)
  ((line) > @_rl_vis_botlin) ? "" : vis_chars(line)
end
vis_llen(l) click to toggle source
# File lib/rbreadline.rb, line 2683
def vis_llen(l)
  ((l) > @_rl_vis_botlin ? 0 : (@vis_lbreaks[l+1] - @vis_lbreaks[l]))
end
vis_pos(line) click to toggle source
# File lib/rbreadline.rb, line 2695
def vis_pos(line)
  @vis_lbreaks[line] || 0
end
w_offset(line, offset) click to toggle source
# File lib/rbreadline.rb, line 2679
def w_offset(line, offset)
  ((line) == 0 ? offset : 0)
end
where_history() click to toggle source

Returns the magic number which says what history element we are

looking at now.  In this implementation, it returns history_offset.
# File lib/rbreadline.rb, line 5405
def where_history()
  @history_offset
end
whitespace(c) click to toggle source
# File lib/rbreadline.rb, line 2675
def whitespace(c)
  (c == ' ' || c == "\t")
end

Private Instance Methods

no_terminal?() click to toggle source
# File lib/rbreadline.rb, line 8914
def no_terminal?
  term = ENV["TERM"]
  term.nil? || (term == 'dumb') || (RUBY_PLATFORM =~ /mswin|mingw/)
end
readline(prompt) click to toggle source

Read a line of input. Prompt with PROMPT. An empty PROMPT means

none.  A return value of NULL means that EOF was encountered.
# File lib/rbreadline.rb, line 4859
def readline(prompt)
  # If we are at EOF return a NULL string.
  if (@rl_pending_input == EOF)
    rl_clear_pending_input()
    return nil
  end

  rl_set_prompt(prompt)

  rl_initialize()
  @readline_echoing_p = true
  if (@rl_prep_term_function)
    send(@rl_prep_term_function,@_rl_meta_flag)
  end
  rl_set_signals()

  value = readline_internal()
  if(@rl_deprep_term_function)
    send(@rl_deprep_term_function)
  end

  rl_clear_signals()

  value
end