module RbReadline
Constants
- ABORT_CHAR
- ANCHORED_SEARCH
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
- NON_ANCHORED_SEARCH
- 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_SEARCH
- 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
Public Instance Methods
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
# 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
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
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
# File lib/rbreadline.rb, line 5561 def _rl_any_typein() return (@push_index != @pop_index) end
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
# 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
# File lib/rbreadline.rb, line 7789 def _rl_arg_init() rl_save_prompt() @_rl_argcxt = 0 rl_setstate(RL_STATE_NUMERICARG) end
# 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
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
# 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
# File lib/rbreadline.rb, line 7636 def _rl_char_search(count, fdir, bdir) mbchar = '' mb_len = _rl_read_mbchar(mbchar, MB_LEN_MAX) if (mbchar.is_a?(Integer) && c < 0) || mbchar == 0.chr return -1 end if (count < 0) return (_rl_char_search_internal(-count, bdir, mbchar, mb_len)) else return (_rl_char_search_internal(count, fdir, mbchar, mb_len)) end end
# 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
# File lib/rbreadline.rb, line 5203 def _rl_char_value(buf,ind) buf[ind,1] end
# 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
# 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
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
# 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
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
# 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
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
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
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
# 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
# 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
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
# File lib/rbreadline.rb, line 4707 def _rl_erase_entire_line() cr() _rl_clear_to_eol(0) cr() @rl_outstream.flush end
# 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
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
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
# 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
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
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
# 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
# File lib/rbreadline.rb, line 2079 def _rl_init_eightbit() end
# File lib/rbreadline.rb, line 2598 def _rl_init_line_state() @rl_point = @rl_end = @rl_mark = 0 @rl_line_buffer = "" end
# 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
# File lib/rbreadline.rb, line 4060 def _rl_input_available IO.select([ $stdin ], nil, [ $stdin ], @_keyboard_input_timeout) end
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
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
# 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
# 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
# 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
# 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
# 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
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
# 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
# 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
# File lib/rbreadline.rb, line 8169 def _rl_make_prompt_for_search(pchar) rl_save_prompt() # We've saved the prompt, and can do anything with the various prompt # strings we need before they're restored. We want the unexpanded # portion of the prompt string after any final newline. _p = @rl_prompt ? @rl_prompt.rindex("\n") : nil if _p.nil? len = (@rl_prompt && @rl_prompt.length>0 ) ? @rl_prompt.length : 0 if (len>0) pmt = @rl_prompt.dup else pmt = '' end pmt << pchar else _p+=1 pmt = @rl_prompt[_p..-1] pmt << pchar end # will be overwritten by expand_prompt, called from rl_message @prompt_physical_chars = @saved_physical_chars + 1 pmt end
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
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
# 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
# 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
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
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
# 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
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
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
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
# 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
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
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
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
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
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
# 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
# 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
# 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
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
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
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
# File lib/rbreadline.rb, line 3883 def _rl_strip_prompt(pmt) return expand_prompt(pmt).first end
# 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
# File lib/rbreadline.rb, line 1312 def _rl_to_lower(char) char.nil? ? nil : char.chr.downcase end
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
# 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
# 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
# File lib/rbreadline.rb, line 3839 def _rl_vi_initialize_line rl_unsetstate(RL_STATE_VICMDONCE) end
# 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
# 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
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
# File lib/rbreadline.rb, line 5219 def _rl_walphabetic(c) rl_alphabetic(c) end
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
# 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
# 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 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
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 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 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
# File lib/rbreadline.rb, line 6942 def block_sigint() return if @sigint_blocked @sigint_proc = Signal.trap("INT", "IGNORE") @sigint_blocked = true end
# File lib/rbreadline.rb, line 8551 def clear_history() @the_history = nil @history_offset = @history_length = 0 end
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
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
# File lib/rbreadline.rb, line 2610 def cr_faster(new, cur) (new + 1) < (cur - new) end
# File lib/rbreadline.rb, line 2667 def ctrl_char(c) c < "\x20" end
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 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, 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
# File lib/rbreadline.rb, line 4056 def endsrch_char(c) ((ctrl_char(c) || meta_char(c) || (c) == RUBOUT) && ((c) != "\C-G")) end
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
# 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
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
# 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
# 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
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 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
# 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
# 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
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
# File lib/rbreadline.rb, line 8547 def history_is_stifled() return (@history_stifled) end
# File lib/rbreadline.rb, line 7265 def history_list() @the_history end
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
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
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
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
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
# 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
# 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 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
# File lib/rbreadline.rb, line 2703 def inv_line(line) @invisible_line[@inv_lbreaks[line] .. -1] end
# File lib/rbreadline.rb, line 2687 def inv_llen(l) (@inv_lbreaks[l+1] - @inv_lbreaks[l]) end
# 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
# File lib/rbreadline.rb, line 2671 def isprint(c) c >= "\x20" && c < "\x7f" end
# File lib/rbreadline.rb, line 2707 def m_offset(margin, offset) ((margin) == 0 ? offset : 0) end
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
# 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
# File lib/rbreadline.rb, line 2663 def meta_char(c) c > "\x7f" && c <= "\xff" end
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
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
Search non-interactively through the history list. DIR < 0 means to
search backwards through the history of previous commands; otherwise the search is for commands subsequent to the current position in the history list. PCHAR is the character to use for prompting when reading the search string; if not specified (0), it defaults to `:'.
# File lib/rbreadline.rb, line 8025 def noninc_search(dir, pchar) cxt = _rl_nsearch_init(dir, pchar) if (rl_isstate(RL_STATE_CALLBACK)) return (0) end # Read the search string. r = 0 while (true) c = _rl_search_getchar(cxt) if (c == 0.chr) break end r = _rl_nsearch_dispatch(cxt, c) if (r < 0) return 1 elsif (r == 0) break end end r = _rl_nsearch_dosearch(cxt) (r >= 0) ? _rl_nsearch_cleanup(cxt, r) : (r != 1) end
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
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
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
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
# 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
# File lib/rbreadline.rb, line 6555 def path_isdir(filename) return File.directory?(filename) end
# 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
# 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
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
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.
# File lib/rbreadline.rb, line 6584 def print_filename(to_print, full_pathname) printed_len = fnprint(to_print) if (@rl_filename_completion_desired && (@rl_visible_stats || @_rl_complete_mark_directories)) # If to_print != full_pathname, to_print is the basename of the # path passed. In this case, we try to expand the directory # name before checking for the stat character. if (to_print != full_pathname) if full_pathname.nil? || full_pathname.length==0 dn = '/' else dn = File.dirname(full_pathname) end s = File.expand_path(dn) if (@rl_directory_completion_hook) send(@rl_directory_completion_hook,s) end slen = s.length new_full_pathname = s.dup if (s[-1,1] == '/' ) slen-=1 else new_full_pathname[slen,1] = '/' end new_full_pathname[slen .. -1] = '/' + to_print if (@rl_visible_stats) extension_char = stat_char(new_full_pathname) else if (path_isdir(new_full_pathname)) extension_char = '/' end end new_full_pathname = nil else s = File.expand_path(full_pathname) if (@rl_visible_stats) extension_char = stat_char(s) else if (path_isdir(s)) extension_char = '/' end end end s = nil if (extension_char) @rl_outstream.write(extension_char) printed_len+=1 end end printed_len end
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
-
_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
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
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
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
# 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
# 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
# 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 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
# File lib/rbreadline.rb, line 6948 def release_sigint() return if !@sigint_blocked Signal.trap("INT", @sigint_proc) @sigint_blocked = false end
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 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 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
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
# 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
# File lib/rbreadline.rb, line 4811 def rl_abort(count, key) _rl_abort_internal() end
-
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
# 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
# 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
Backwards compatibility.
# File lib/rbreadline.rb, line 5187 def rl_backward(count, key) rl_backward_char(count, key) end
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
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
# File lib/rbreadline.rb, line 7781 def rl_backward_char_search (count, key) _rl_char_search(count, BFIND, FFIND) end
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
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
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
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
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
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
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
# 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
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
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
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
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
# File lib/rbreadline.rb, line 7651 def rl_char_search(count, key) _rl_char_search(count, FFIND, BFIND) end
# 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
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
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
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
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
# File lib/rbreadline.rb, line 1658 def rl_clear_signals() if Signal.list['WINCH'] trap "WINCH",@def_proc end end
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
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
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
# File lib/rbreadline.rb, line 4983 def rl_copy_text(from, to) return @rl_line_buffer[from...to] end
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
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
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
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
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
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
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
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
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
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
Display the current state of the search in the echo-area.
SEARCH_STRING contains the string that is being searched for, DIRECTION is zero for forward, or non-zero for reverse, WHERE is the history list number of the current line. If it is -1, then this line is the starting one.
# File lib/rbreadline.rb, line 7380 def rl_display_search(search_string, reverse_p, where) message = '(' if (reverse_p) message << "reverse-" end message << "i-search)`" if (search_string) message << search_string end message << "': " rl_message(message) message = nil send(@rl_redisplay_function) end
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
# 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
Lowercase the word at point.
# File lib/rbreadline.rb, line 7934 def rl_downcase_word(count, key) rl_change_case(count, DownCase) end
# 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
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
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
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
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
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
*
-
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
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
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
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
Backwards compatibility.
# File lib/rbreadline.rb, line 5137 def rl_forward(count, key) rl_forward_char(count, key) end
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
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
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
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
# File lib/rbreadline.rb, line 5022 def rl_free_undo_list() replace_history_data(-1, @rl_undo_list, nil) @rl_undo_list = nil end
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
# 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
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
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
# 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
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
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
# 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
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
# 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
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
# File lib/rbreadline.rb, line 7785 def rl_insert_completions(ignore, invoking_key) rl_complete_internal('*') end
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
# File lib/rbreadline.rb, line 1643 def rl_isstate(x) (@rl_readline_state & (x))!=0 end
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
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
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
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
# File lib/rbreadline.rb, line 3813 def rl_line_buffer @rl_line_buffer.tr(0.chr, '') end
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
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
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
# 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
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
# 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
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
Search forward through the history list for a string. If the vi-mode
code calls this, KEY will be `?'.
# File lib/rbreadline.rb, line 8051 def rl_noninc_forward_search(count, key) noninc_search(1, (key == '?') ? '?' : nil) end
Reverse search the history list for a string. If the vi-mode code
calls this, KEY will be `/'.
# File lib/rbreadline.rb, line 8057 def rl_noninc_reverse_search(count, key) noninc_search(-1, (key == '/') ? '/' : nil) end
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
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
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
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
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
# 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
# File lib/rbreadline.rb, line 5670 def rl_quoted_insert(count, key) _rl_insert_next(count) end
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
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
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
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
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
# 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
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
# 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
# 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
# File lib/rbreadline.rb, line 1654 def rl_restart_output(count, key) 0 end
# 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
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
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
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
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
# 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
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
# 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
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
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
# 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
# File lib/rbreadline.rb, line 1635 def rl_setstate(x) (@rl_readline_state |= (x)) end
# 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
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
Insert a tab character.
# File lib/rbreadline.rb, line 5675 def rl_tab_insert(count, key) _rl_insert_char(count, "\t") end
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
# 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
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
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
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
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
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
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
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
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
# File lib/rbreadline.rb, line 1639 def rl_unsetstate(x) (@rl_readline_state &= ~(x)) end
Uppercase the word at point.
# File lib/rbreadline.rb, line 7929 def rl_upcase_word(count, key) rl_change_case(count, UpCase) end
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
# 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
# File lib/rbreadline.rb, line 4815 def rl_vi_check() if (@rl_point!=0 && @rl_point == @rl_end) @rl_point-=1 end 0 end
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
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
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
# 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
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
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
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
# 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 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
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
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
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 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
# File lib/rbreadline.rb, line 1901 def tgetflag(name) `infocmp -C -r`.scan(/\w{2}/).include?(name) end
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
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
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
# File lib/rbreadline.rb, line 6173 def using_history() @history_offset = @history_length end
# File lib/rbreadline.rb, line 2691 def vis_chars(line) @visible_line[@vis_lbreaks[line] .. -1] end
# File lib/rbreadline.rb, line 2699 def vis_line(line) ((line) > @_rl_vis_botlin) ? "" : vis_chars(line) end
# File lib/rbreadline.rb, line 2683 def vis_llen(l) ((l) > @_rl_vis_botlin ? 0 : (@vis_lbreaks[l+1] - @vis_lbreaks[l])) end
# File lib/rbreadline.rb, line 2695 def vis_pos(line) @vis_lbreaks[line] || 0 end
# File lib/rbreadline.rb, line 2679 def w_offset(line, offset) ((line) == 0 ? offset : 0) end
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
# File lib/rbreadline.rb, line 2675 def whitespace(c) (c == ' ' || c == "\t") end
Private Instance Methods
# File lib/rbreadline.rb, line 8914 def no_terminal? term = ENV["TERM"] term.nil? || (term == 'dumb') || (RUBY_PLATFORM =~ /mswin|mingw/) end
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