/IronPython_Main/External.LCA_RESTRICTED/Languages/Ruby/redist-libs/ruby/site_ruby/1.9.1/rbreadline.rb
Ruby | 8664 lines | 6081 code | 1132 blank | 1451 comment | 1492 complexity | 1b86031473b7980d86552309ca944a1e MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
- # rbreadline.rb -- a general facility for reading lines of input
- # with emacs style editing and completion.
-
- #
- # Inspired by GNU Readline, translation to Ruby
- # Copyright (C) 2009 by Park Heesob phasis@gmail.com
- #
-
- class Fixnum
- def ord; self; end
- end
-
- module RbReadline
- require 'etc'
-
- RL_LIBRARY_VERSION = "5.2"
- RL_READLINE_VERSION = 0x0502
- RB_READLINE_VERSION = "0.2.0"
-
- EOF = "\xFF"
- ESC = "\C-["
- PAGE = "\C-L"
- SPACE = "\x20"
- RETURN = "\C-M"
- ABORT_CHAR = "\C-G"
- TAB = "\t"
- RUBOUT = "x7f"
- NEWLINE = "\n"
-
- DEFAULT_BUFFER_SIZE = 256
- DEFAULT_MAX_KILLS = 10
-
- MB_FIND_NONZERO = 1
- MB_FIND_ANY = 0
- MB_LEN_MAX = 4
-
- DEFAULT_INPUTRC = "~/.inputrc"
- SYS_INPUTRC = "/etc/inputrc"
-
- UpCase = 1
- DownCase = 2
- CapCase = 3
-
- # Possible history errors passed to hist_error.
- EVENT_NOT_FOUND = 0
- BAD_WORD_SPEC = 1
- SUBST_FAILED = 2
- BAD_MODIFIER = 3
- NO_PREV_SUBST = 4
-
- # Possible definitions for history starting point specification.
- ANCHORED_SEARCH = 1
- NON_ANCHORED_SEARCH = 0
-
- # Possible definitions for what style of writing the history file we want.
- HISTORY_APPEND = 0
- HISTORY_OVERWRITE = 1
-
- # Input error; can be returned by (*rl_getc_function) if readline is reading
- # a top-level command (RL_ISSTATE (RL_STATE_READCMD)).
- READERR = 0xFE.chr
-
- # Definitions available for use by readline clients.
- RL_PROMPT_START_IGNORE = 1.chr
- RL_PROMPT_END_IGNORE = 2.chr
-
- # Possible values for do_replace argument to rl_filename_quoting_function,
- # called by rl_complete_internal.
- NO_MATCH = 0
- SINGLE_MATCH = 1
- MULT_MATCH = 2
-
- # Callback data for reading numeric arguments
- NUM_SAWMINUS = 0x01
- NUM_SAWDIGITS = 0x02
- NUM_READONE = 0x04
-
- # A context for reading key sequences longer than a single character when
- # using the callback interface.
- KSEQ_DISPATCHED = 0x01
- KSEQ_SUBSEQ = 0x02
- KSEQ_RECURSIVE = 0x04
-
- # Possible state values for rl_readline_state
- RL_STATE_NONE = 0x000000 # no state before first call
-
- RL_STATE_INITIALIZING = 0x000001 # initializing
- RL_STATE_INITIALIZED = 0x000002 # initialization done
- RL_STATE_TERMPREPPED = 0x000004 # terminal is prepped
- RL_STATE_READCMD = 0x000008 # reading a command key
- RL_STATE_METANEXT = 0x000010 # reading input after ESC
- RL_STATE_DISPATCHING = 0x000020 # dispatching to a command
- RL_STATE_MOREINPUT = 0x000040 # reading more input in a command function
- RL_STATE_ISEARCH = 0x000080 # doing incremental search
- RL_STATE_NSEARCH = 0x000100 # doing non-inc search
- RL_STATE_SEARCH = 0x000200 # doing a history search
- RL_STATE_NUMERICARG = 0x000400 # reading numeric argument
- RL_STATE_MACROINPUT = 0x000800 # getting input from a macro
- RL_STATE_MACRODEF = 0x001000 # defining keyboard macro
- RL_STATE_OVERWRITE = 0x002000 # overwrite mode
- RL_STATE_COMPLETING = 0x004000 # doing completion
- RL_STATE_SIGHANDLER = 0x008000 # in readline sighandler
- RL_STATE_UNDOING = 0x010000 # doing an undo
- RL_STATE_INPUTPENDING = 0x020000 # rl_execute_next called
- RL_STATE_TTYCSAVED = 0x040000 # tty special chars saved
- RL_STATE_CALLBACK = 0x080000 # using the callback interface
- RL_STATE_VIMOTION = 0x100000 # reading vi motion arg
- RL_STATE_MULTIKEY = 0x200000 # reading multiple-key command
- RL_STATE_VICMDONCE = 0x400000 # entered vi command mode at least once
-
- RL_STATE_DONE = 0x800000 # done accepted line
-
- NO_BELL = 0
- AUDIBLE_BELL = 1
- VISIBLE_BELL = 2
- # The actions that undo knows how to undo. Notice that UNDO_DELETE means
- # to insert some text, and UNDO_INSERT means to delete some text. I.e.,
- # the code tells undo what to undo, not how to undo it.
- UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END = 0,1,2,3
-
- # Definitions used when searching the line for characters.
- # NOTE: it is necessary that opposite directions are inverses
- FTO = 1 # forward to
- BTO = -1 # backward to
- FFIND = 2 # forward find
- BFIND = -2 # backward find
-
- # 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_QF_SINGLE_QUOTE = 0x01
- RL_QF_DOUBLE_QUOTE = 0x02
- RL_QF_BACKSLASH = 0x04
- RL_QF_OTHER_QUOTE = 0x08
-
- KEYMAP_SIZE = 257
- ANYOTHERKEY = KEYMAP_SIZE-1
-
- @hConsoleHandle = nil
- @MessageBeep = nil
-
- RL_IM_INSERT = 1
- RL_IM_OVERWRITE = 0
- RL_IM_DEFAULT = RL_IM_INSERT
- @no_mode = -1
- @vi_mode = 0
- @emacs_mode = 1
- ISFUNC = 0
- ISKMAP = 1
- ISMACR = 2
-
- HISTORY_WORD_DELIMITERS = " \t\n;&()|<>"
- HISTORY_QUOTE_CHARACTERS = "\"'`"
-
- RL_SEARCH_ISEARCH = 0x01 # incremental search
- RL_SEARCH_NSEARCH = 0x02 # non-incremental search
- RL_SEARCH_CSEARCH = 0x04 # intra-line char search
-
- # search flags
- SF_REVERSE = 0x01
- SF_FOUND = 0x02
- SF_FAILED = 0x04
-
- @slashify_in_quotes = "\\`\"$"
-
- @sigint_proc = nil
- @sigint_blocked = false
-
- @rl_prep_term_function = :rl_prep_terminal
- @rl_deprep_term_function = :rl_deprep_terminal
-
- @_rl_history_saved_point = -1
-
- @rl_max_kills = DEFAULT_MAX_KILLS
- @rl_kill_ring = nil
- @rl_kill_index = 0
- @rl_kill_ring_length = 0
-
- @pending_bytes = ''
- @stored_count = 0
-
- @_rl_isearch_terminators = nil
- @_rl_iscxt = nil
- @last_isearch_string = nil
- @last_isearch_string_len = 0
- @default_isearch_terminators = "\033\012"
- @_rl_history_preserve_point = false
- @terminal_prepped = false
- @otio = nil
-
- @msg_saved_prompt = false
-
- @_rl_nscxt = nil
- @noninc_search_string = nil
- @noninc_history_pos = 0
- @prev_line_found = nil
-
- rl_history_search_len = 0
- rl_history_search_pos = 0
- history_search_string = nil
- history_string_size = 0
-
- @_rl_tty_chars = Struct.new(:t_eol,:t_eol2,:t_erase,:t_werase,:t_kill,:t_reprint,:t_intr,:t_eof,
- :t_quit,:t_susp,:t_dsusp,:t_start,:t_stop,:t_lnext,:t_flush,:t_status).new
- @_rl_last_tty_chars = nil
-
- # Variables exported by this file.
- # The character that represents the start of a history expansion
- # request. This is usually `!'.
- @history_expansion_char = ?!
-
- # The character that invokes word substitution if found at the start of
- # a line. This is usually `^'.
- @history_subst_char = ?^
-
- # During tokenization, if this character is seen as the first character
- # of a word, then it, and all subsequent characters upto a newline are
- # ignored. For a Bourne shell, this should be '#'. Bash special cases
- # the interactive comment character to not be a comment delimiter.
- @history_comment_char = ?\0
-
- # The list of characters which inhibit the expansion of text if found
- # immediately following history_expansion_char.
- @history_no_expand_chars = " \t\n\r="
-
- # If set to a non-zero value, single quotes inhibit history expansion.
- # The default is 0.
- @history_quotes_inhibit_expansion = 0
-
- # Used to split words by history_tokenize_internal.
- @history_word_delimiters = HISTORY_WORD_DELIMITERS
-
- # If set, this points to a function that is called to verify that a
- # particular history expansion should be performed.
- @history_inhibit_expansion_function = nil
-
- @rl_event_hook = nil
- # The visible cursor position. If you print some text, adjust this.
- # NOTE: _rl_last_c_pos is used as a buffer index when not in a locale
- # supporting multibyte characters, and an absolute cursor position when
- # in such a locale. This is an artifact of the donated multibyte support.
- # Care must be taken when modifying its value.
- @_rl_last_c_pos = 0
- @_rl_last_v_pos = 0
-
- @cpos_adjusted = false
- @cpos_buffer_position = 0
-
- # Number of lines currently on screen minus 1.
- @_rl_vis_botlin = 0
-
- # Variables used only in this file.
- # The last left edge of text that was displayed. This is used when
- # doing horizontal scrolling. It shifts in thirds of a screenwidth.
- @last_lmargin = 0
-
- # The line display buffers. One is the line currently displayed on
- # the screen. The other is the line about to be displayed.
- @visible_line = nil
- @invisible_line = nil
-
- # A buffer for `modeline' messages.
- @msg_buf = 0.chr * 128
-
- # Non-zero forces the redisplay even if we thought it was unnecessary.
- @forced_display = false
-
- # Default and initial buffer size. Can grow.
- @line_size = 1024
-
- # Variables to keep track of the expanded prompt string, which may
- # include invisible characters.
-
- @local_prompt = nil
- @local_prompt_prefix = nil
- @local_prompt_len = 0
- @prompt_visible_length = 0
- @prompt_prefix_length = 0
-
- # The number of invisible characters in the line currently being
- # displayed on the screen.
- @visible_wrap_offset = 0
-
- # The number of invisible characters in the prompt string. Static so it
- # can be shared between rl_redisplay and update_line
- @wrap_offset = 0
-
- @prompt_last_invisible = 0
-
- # The length (buffer offset) of the first line of the last (possibly
- # multi-line) buffer displayed on the screen.
- @visible_first_line_len = 0
-
- # Number of invisible characters on the first physical line of the prompt.
- # Only valid when the number of physical characters in the prompt exceeds
- # (or is equal to) _rl_screenwidth.
- @prompt_invis_chars_first_line = 0
-
- @prompt_last_screen_line = 0
-
- @prompt_physical_chars = 0
-
- # Variables to save and restore prompt and display information.
-
- # These are getting numerous enough that it's time to create a struct.
-
- @saved_local_prompt = nil
- @saved_local_prefix = nil
- @saved_last_invisible = 0
- @saved_visible_length = 0
- @saved_prefix_length = 0
- @saved_local_length = 0
- @saved_invis_chars_first_line = 0
- @saved_physical_chars = 0
-
- @inv_lbreaks = nil
- @vis_lbreaks = nil
- @_rl_wrapped_line = nil
-
- @term_buffer = nil
- @term_string_buffer = nil
-
- @tcap_initialized = false
-
- # While we are editing the history, this is the saved
- # version of the original line.
- @_rl_saved_line_for_history = nil
-
- # An array of HIST_ENTRY. This is where we store the history.
- @the_history = nil
- @history_base = 1
-
- # Non-zero means that we have enforced a limit on the amount of
- # history that we save.
- @history_stifled = false
-
- # If HISTORY_STIFLED is non-zero, then this is the maximum number of
- # entries to remember.
- @history_max_entries = 0
- @max_input_history = 0 # backwards compatibility
-
- # The current location of the interactive history pointer. Just makes
- # life easier for outside callers.
- @history_offset = 0
-
- # The number of strings currently stored in the history list.
- @history_length = 0
-
- @_rl_vi_last_command = 'i' # default `.' puts you in insert mode
-
- # Non-zero means enter insertion mode.
- @_rl_vi_doing_insert = 0
-
- # Command keys which do movement for xxx_to commands.
- @vi_motion = " hl^$0ftFT;,%wbeWBE|"
-
- # Keymap used for vi replace characters. Created dynamically since
- # rarely used.
- @vi_replace_map = nil
-
- # The number of characters inserted in the last replace operation.
- @vi_replace_count = 0
-
- # If non-zero, we have text inserted after a c[motion] command that put
- # us implicitly into insert mode. Some people want this text to be
- # attached to the command so that it is `redoable' with `.'.
- @vi_continued_command = false
- @vi_insert_buffer = nil
- @vi_insert_buffer_size = 0
-
- @_rl_vi_last_repeat = 1
- @_rl_vi_last_arg_sign = 1
- @_rl_vi_last_motion = 0
- @_rl_vi_last_search_char = 0
- @_rl_vi_last_replacement = 0
-
- @_rl_vi_last_key_before_insert = 0
-
- @vi_redoing = 0
-
- # Text modification commands. These are the `redoable' commands.
- @vi_textmod = "_*\\AaIiCcDdPpYyRrSsXx~"
-
- # Arrays for the saved marks.
- @vi_mark_chars = Array.new(26,-1)
-
- @emacs_standard_keymap = {
- "\C-@" => :rl_set_mark ,
- "\C-a" => :rl_beg_of_line ,
- "\C-b" => :rl_backward_char ,
- "\C-d" => :rl_delete ,
- "\C-e" => :rl_end_of_line ,
- "\C-f" => :rl_forward_char ,
- "\C-g" => :rl_abort ,
- "\C-h" => :rl_rubout ,
- "\C-i" => :rl_complete ,
- "\C-j" => :rl_newline ,
- "\C-k" => :rl_kill_line ,
- "\C-l" => :rl_clear_screen ,
- "\C-m" => :rl_newline ,
- "\C-n" => :rl_get_next_history ,
- "\C-p" => :rl_get_previous_history ,
- "\C-q" => :rl_quoted_insert ,
- "\C-r" => :rl_reverse_search_history ,
- "\C-s" => :rl_forward_search_history ,
- "\C-t" => :rl_transpose_chars ,
- "\C-u" => :rl_unix_line_discard ,
- "\C-v" => :rl_quoted_insert ,
- "\C-w" => :rl_unix_word_rubout ,
- "\C-y" => :rl_yank ,
- "\C-]" => :rl_char_search ,
- "\C-_" => :rl_undo_command ,
- "\x7F" => :rl_rubout ,
- "\e\C-g" => :rl_abort ,
- "\e\C-h" => :rl_backward_kill_word ,
- "\e\C-i" => :rl_tab_insert ,
- "\e\C-j" => :rl_vi_editing_mode ,
- "\e\C-m" => :rl_vi_editing_mode ,
- "\e\C-r" => :rl_revert_line ,
- "\e\C-y" => :rl_yank_nth_arg ,
- "\e\C-[" => :rl_complete ,
- "\e\C-]" => :rl_backward_char_search ,
- "\e " => :rl_set_mark ,
- "\e#" => :rl_insert_comment ,
- "\e&" => :rl_tilde_expand ,
- "\e*" => :rl_insert_completions ,
- "\e-" => :rl_digit_argument ,
- "\e." => :rl_yank_last_arg ,
- "\e0" => :rl_digit_argument ,
- "\e1" => :rl_digit_argument ,
- "\e2" => :rl_digit_argument ,
- "\e3" => :rl_digit_argument ,
- "\e4" => :rl_digit_argument ,
- "\e5" => :rl_digit_argument ,
- "\e6" => :rl_digit_argument ,
- "\e7" => :rl_digit_argument ,
- "\e8" => :rl_digit_argument ,
- "\e9" => :rl_digit_argument ,
- "\e<" => :rl_beginning_of_history ,
- "\e=" => :rl_possible_completions ,
- "\e>" => :rl_end_of_history ,
- "\e?" => :rl_possible_completions ,
- "\eB" => :rl_backward_word ,
- "\eC" => :rl_capitalize_word ,
- "\eD" => :rl_kill_word ,
- "\eF" => :rl_forward_word ,
- "\eL" => :rl_downcase_word ,
- "\eN" => :rl_noninc_forward_search ,
- "\eP" => :rl_noninc_reverse_search ,
- "\eR" => :rl_revert_line ,
- "\eT" => :rl_transpose_words ,
- "\eU" => :rl_upcase_word ,
- "\eY" => :rl_yank_pop ,
- "\e\\" => :rl_delete_horizontal_space ,
- "\e_" => :rl_yank_last_arg ,
- "\eb" => :rl_backward_word ,
- "\ec" => :rl_capitalize_word ,
- "\ed" => :rl_kill_word ,
- "\ef" => :rl_forward_word ,
- "\el" => :rl_downcase_word ,
- "\en" => :rl_noninc_forward_search ,
- "\ep" => :rl_noninc_reverse_search ,
- "\er" => :rl_revert_line ,
- "\et" => :rl_transpose_words ,
- "\eu" => :rl_upcase_word ,
- "\ey" => :rl_yank_pop ,
- "\e~" => :rl_tilde_expand ,
- "\377" => :rl_backward_kill_word ,
-
- "\C-x\C-g" => :rl_abort ,
- "\C-x\C-r" => :rl_re_read_init_file ,
- "\C-x\C-u" => :rl_undo_command ,
- "\C-x\C-x" => :rl_exchange_point_and_mark ,
- "\C-x(" => :rl_start_kbd_macro ,
- "\C-x)" => :rl_end_kbd_macro ,
- "\C-xE" => :rl_call_last_kbd_macro ,
- "\C-xe" => :rl_call_last_kbd_macro ,
- "\C-x\x7F" => :rl_backward_kill_line
- }
-
- @vi_movement_keymap = {
- "\C-d" => :rl_vi_eof_maybe ,
- "\C-e" => :rl_emacs_editing_mode ,
- "\C-g" => :rl_abort ,
- "\C-h" => :rl_backward_char ,
- "\C-j" => :rl_newline ,
- "\C-k" => :rl_kill_line ,
- "\C-l" => :rl_clear_screen ,
- "\C-m" => :rl_newline ,
- "\C-n" => :rl_get_next_history ,
- "\C-p" => :rl_get_previous_history ,
- "\C-q" => :rl_quoted_insert ,
- "\C-r" => :rl_reverse_search_history ,
- "\C-s" => :rl_forward_search_history ,
- "\C-t" => :rl_transpose_chars ,
- "\C-u" => :rl_unix_line_discard ,
- "\C-v" => :rl_quoted_insert ,
- "\C-w" => :rl_unix_word_rubout ,
- "\C-y" => :rl_yank ,
- "\C-_" => :rl_vi_undo ,
- " " => :rl_forward_char ,
- "#" => :rl_insert_comment ,
- "$" => :rl_end_of_line ,
- "%" => :rl_vi_match ,
- "&" => :rl_vi_tilde_expand ,
- "*" => :rl_vi_complete ,
- "+" => :rl_get_next_history ,
- "," => :rl_vi_char_search ,
- "-" => :rl_get_previous_history ,
- "." => :rl_vi_redo ,
- "/" => :rl_vi_search ,
- "0" => :rl_beg_of_line ,
- "1" => :rl_vi_arg_digit ,
- "2" => :rl_vi_arg_digit ,
- "3" => :rl_vi_arg_digit ,
- "4" => :rl_vi_arg_digit ,
- "5" => :rl_vi_arg_digit ,
- "6" => :rl_vi_arg_digit ,
- "7" => :rl_vi_arg_digit ,
- "8" => :rl_vi_arg_digit ,
- "9" => :rl_vi_arg_digit ,
- "" => :rl_vi_char_search ,
- "=" => :rl_vi_complete ,
- "?" => :rl_vi_search ,
- "A" => :rl_vi_append_eol ,
- "B" => :rl_vi_prev_word ,
- "C" => :rl_vi_change_to ,
- "D" => :rl_vi_delete_to ,
- "E" => :rl_vi_end_word ,
- "F" => :rl_vi_char_search ,
- "G" => :rl_vi_fetch_history ,
- "I" => :rl_vi_insert_beg ,
- "N" => :rl_vi_search_again ,
- "P" => :rl_vi_put ,
- "R" => :rl_vi_replace ,
- "S" => :rl_vi_subst ,
- "T" => :rl_vi_char_search ,
- "U" => :rl_revert_line ,
- "W" => :rl_vi_next_word ,
- "X" => :rl_vi_rubout ,
- "Y" => :rl_vi_yank_to ,
- "\\" => :rl_vi_complete ,
- "^" => :rl_vi_first_print ,
- "_" => :rl_vi_yank_arg ,
- "`" => :rl_vi_goto_mark ,
- "a" => :rl_vi_append_mode ,
- "b" => :rl_vi_prev_word ,
- "c" => :rl_vi_change_to ,
- "d" => :rl_vi_delete_to ,
- "e" => :rl_vi_end_word ,
- "f" => :rl_vi_char_search ,
- "h" => :rl_backward_char ,
- "i" => :rl_vi_insertion_mode ,
- "j" => :rl_get_next_history ,
- "k" => :rl_get_previous_history ,
- "l" => :rl_forward_char ,
- "m" => :rl_vi_set_mark ,
- "n" => :rl_vi_search_again ,
- "p" => :rl_vi_put ,
- "r" => :rl_vi_change_char ,
- "s" => :rl_vi_subst ,
- "t" => :rl_vi_char_search ,
- "u" => :rl_vi_undo ,
- "w" => :rl_vi_next_word ,
- "x" => :rl_vi_delete ,
- "y" => :rl_vi_yank_to ,
- "|" => :rl_vi_column ,
- "~" => :rl_vi_change_case
- }
-
- @vi_insertion_keymap = {
- "\C-a" => :rl_insert ,
- "\C-b" => :rl_insert ,
- "\C-c" => :rl_insert ,
- "\C-d" => :rl_vi_eof_maybe ,
- "\C-e" => :rl_insert ,
- "\C-f" => :rl_insert ,
- "\C-g" => :rl_insert ,
- "\C-h" => :rl_rubout ,
- "\C-i" => :rl_complete ,
- "\C-j" => :rl_newline ,
- "\C-k" => :rl_insert ,
- "\C-l" => :rl_insert ,
- "\C-m" => :rl_newline ,
- "\C-n" => :rl_insert ,
- "\C-o" => :rl_insert ,
- "\C-p" => :rl_insert ,
- "\C-q" => :rl_insert ,
- "\C-r" => :rl_reverse_search_history ,
- "\C-s" => :rl_forward_search_history ,
- "\C-t" => :rl_transpose_chars ,
- "\C-u" => :rl_unix_line_discard ,
- "\C-v" => :rl_quoted_insert ,
- "\C-w" => :rl_unix_word_rubout ,
- "\C-x" => :rl_insert ,
- "\C-y" => :rl_yank ,
- "\C-z" => :rl_insert ,
- "\C-[" => :rl_vi_movement_mode ,
- "\C-\\" => :rl_insert ,
- "\C-]" => :rl_insert ,
- "\C-^" => :rl_insert ,
- "\C-_" => :rl_vi_undo ,
- "\x7F" => :rl_rubout
- }
-
- @rl_library_version = RL_LIBRARY_VERSION
-
- @rl_readline_version = RL_READLINE_VERSION
-
- @rl_readline_name = "other"
-
- @rl_getc_function = :rl_getc
-
- # Non-zero tells rl_delete_text and rl_insert_text to not add to
- # the undo list.
- @_rl_doing_an_undo = false
-
- # How many unclosed undo groups we currently have.
- @_rl_undo_group_level = 0
-
- # The current undo list for THE_LINE.
- @rl_undo_list = nil
-
- # Application-specific redisplay function.
- @rl_redisplay_function = :rl_redisplay
-
- # Global variables declared here.
- # What YOU turn on when you have handled all redisplay yourself.
- @rl_display_fixed = false
-
- @_rl_suppress_redisplay = 0
- @_rl_want_redisplay = false
-
- # The stuff that gets printed out before the actual text of the line.
- # This is usually pointing to rl_prompt.
- @rl_display_prompt = nil
-
- # True if this is `real' readline as opposed to some stub substitute.
- @rl_gnu_readline_p = true
-
- for i in 32 .. 255
- @emacs_standard_keymap[i.chr] = :rl_insert unless @emacs_standard_keymap[i.chr]
- @vi_insertion_keymap[i.chr] = :rl_insert unless @vi_insertion_keymap[i.chr]
- end
- # A pointer to the keymap that is currently in use.
- # By default, it is the standard emacs keymap.
- @_rl_keymap = @emacs_standard_keymap
-
-
- # The current style of editing.
- @rl_editing_mode = @emacs_mode
-
- # The current insert mode: input (the default) or overwrite
- @rl_insert_mode = RL_IM_DEFAULT
-
- # Non-zero if we called this function from _rl_dispatch(). It's present
- # so functions can find out whether they were called from a key binding
- # or directly from an application.
- @rl_dispatching = false
-
- # Non-zero if the previous command was a kill command.
- @_rl_last_command_was_kill = false
-
- # The current value of the numeric argument specified by the user.
- @rl_numeric_arg = 1
-
- # Non-zero if an argument was typed.
- @rl_explicit_arg = false
-
- # Temporary value used while generating the argument.
- @rl_arg_sign = 1
-
- # Non-zero means we have been called at least once before.
- @rl_initialized = false
-
- # Flags word encapsulating the current readline state.
- @rl_readline_state = RL_STATE_NONE
-
- # The current offset in the current input line.
- @rl_point = 0
-
- # Mark in the current input line.
- @rl_mark = 0
-
- # Length of the current input line.
- @rl_end = 0
-
- # Make this non-zero to return the current input_line.
- @rl_done = false
-
- # The last function executed by readline.
- @rl_last_func = nil
-
- # Top level environment for readline_internal ().
- @readline_top_level = nil
-
- # The streams we interact with.
- @_rl_in_stream = nil
- @_rl_out_stream = nil
-
- # The names of the streams that we do input and output to.
- @rl_instream = nil
- @rl_outstream = nil
-
- @pop_index = 0
- @push_index = 0
- @ibuffer = 0.chr * 512
- @ibuffer_len = @ibuffer.length - 1
-
-
- # Non-zero means echo characters as they are read. Defaults to no echo
- # set to 1 if there is a controlling terminal, we can get its attributes,
- # and the attributes include `echo'. Look at rltty.c:prepare_terminal_settings
- # for the code that sets it.
- @readline_echoing_p = false
-
- # Current prompt.
- @rl_prompt = nil
- @rl_visible_prompt_length = 0
-
- # Set to non-zero by calling application if it has already printed rl_prompt
- # and does not want readline to do it the first time.
- @rl_already_prompted = false
-
- # The number of characters read in order to type this complete command.
- @rl_key_sequence_length = 0
-
- # If non-zero, then this is the address of a function to call just
- # before readline_internal_setup () prints the first prompt.
- @rl_startup_hook = nil
-
- # If non-zero, this is the address of a function to call just before
- # readline_internal_setup () returns and readline_internal starts
- # reading input characters.
- @rl_pre_input_hook = nil
-
- # The character that can generate an EOF. Really read from
- # the terminal driver... just defaulted here.
- @_rl_eof_char = "\cD"
-
- # Non-zero makes this the next keystroke to read.
- @rl_pending_input = 0
-
- # Pointer to a useful terminal name.
- @rl_terminal_name = nil
-
- # Non-zero means to always use horizontal scrolling in line display.
- @_rl_horizontal_scroll_mode = false
-
- # Non-zero means to display an asterisk at the starts of history lines
- # which have been modified.
- @_rl_mark_modified_lines = false
-
- # The style of `bell' notification preferred. This can be set to NO_BELL,
- # AUDIBLE_BELL, or VISIBLE_BELL.
- @_rl_bell_preference = AUDIBLE_BELL
-
- # String inserted into the line by rl_insert_comment ().
- @_rl_comment_begin = nil
-
- # Keymap holding the function currently being executed.
- @rl_executing_keymap = nil
-
- # Keymap we're currently using to dispatch.
- @_rl_dispatching_keymap = nil
-
- # Non-zero means to erase entire line, including prompt, on empty input lines.
- @rl_erase_empty_line = false
-
- # Non-zero means to read only this many characters rather than up to a
- # character bound to accept-line.
- @rl_num_chars_to_read = 0
-
- # Line buffer and maintenence.
- @rl_line_buffer = nil
-
- # Key sequence `contexts'
- @_rl_kscxt = nil
-
- # Non-zero means do not parse any lines other than comments and
- # parser directives.
- @_rl_parsing_conditionalized_out = false
-
- # Non-zero means to convert characters with the meta bit set to
- # escape-prefixed characters so we can indirect through
- # emacs_meta_keymap or vi_escape_keymap.
- @_rl_convert_meta_chars_to_ascii = true
-
- # Non-zero means to output characters with the meta bit set directly
- # rather than as a meta-prefixed escape sequence.
- @_rl_output_meta_chars = false
-
- # Non-zero means to look at the termios special characters and bind
- # them to equivalent readline functions at startup.
- @_rl_bind_stty_chars = true
-
- @rl_completion_display_matches_hook = nil
-
- XOK = 1
-
- @_rl_term_clreol = nil
- @_rl_term_clrpag = nil
- @_rl_term_cr = nil
- @_rl_term_backspace = nil
- @_rl_term_goto = nil
- @_rl_term_pc = nil
-
- # Non-zero if we determine that the terminal can do character insertion.
- @_rl_terminal_can_insert = false
-
- # How to insert characters.
- @_rl_term_im = nil
- @_rl_term_ei = nil
- @_rl_term_ic = nil
- @_rl_term_ip = nil
- @_rl_term_IC = nil
-
- # How to delete characters.
- @_rl_term_dc = nil
- @_rl_term_DC = nil
-
- @_rl_term_forward_char = nil
-
- # How to go up a line.
- @_rl_term_up = nil
-
- # A visible bell; char if the terminal can be made to flash the screen.
- @_rl_visible_bell = nil
-
- # Non-zero means the terminal can auto-wrap lines.
- @_rl_term_autowrap = true
-
- # Non-zero means that this terminal has a meta key.
- @term_has_meta = 0
-
- # The sequences to write to turn on and off the meta key, if this
- # terminal has one.
- @_rl_term_mm = nil
- @_rl_term_mo = nil
-
- # The key sequences output by the arrow keys, if this terminal has any.
- @_rl_term_ku = nil
- @_rl_term_kd = nil
- @_rl_term_kr = nil
- @_rl_term_kl = nil
-
- # How to initialize and reset the arrow keys, if this terminal has any.
- @_rl_term_ks = nil
- @_rl_term_ke = nil
-
- # The key sequences sent by the Home and End keys, if any.
- @_rl_term_kh = nil
- @_rl_term_kH = nil
- @_rl_term_at7 = nil
-
- # Delete key
- @_rl_term_kD = nil
-
- # Insert key
- @_rl_term_kI = nil
-
- # Cursor control
- @_rl_term_vs = nil # very visible
- @_rl_term_ve = nil # normal
-
- # Variables that hold the screen dimensions, used by the display code.
- @_rl_screenwidth = @_rl_screenheight = @_rl_screenchars = 0
-
- # Non-zero means the user wants to enable the keypad.
- @_rl_enable_keypad = false
-
- # Non-zero means the user wants to enable a meta key.
- @_rl_enable_meta = true
-
- # ****************************************************************
- #
- # Completion matching, from readline's point of view.
- #
- # ****************************************************************
-
- # Variables known only to the readline library.
-
- # If non-zero, non-unique completions always show the list of matches.
- @_rl_complete_show_all = false
-
- # If non-zero, non-unique completions show the list of matches, unless it
- # is not possible to do partial completion and modify the line.
- @_rl_complete_show_unmodified = false
-
- # If non-zero, completed directory names have a slash appended.
- @_rl_complete_mark_directories = true
-
- # If non-zero, the symlinked directory completion behavior introduced in
- # readline-4.2a is disabled, and symlinks that point to directories have
- # a slash appended (subject to the value of _rl_complete_mark_directories).
- # This is user-settable via the mark-symlinked-directories variable.
- @_rl_complete_mark_symlink_dirs = false
-
- # If non-zero, completions are printed horizontally in alphabetical order,
- # like `ls -x'.
- @_rl_print_completions_horizontally = false
-
- @_rl_completion_case_fold = false
-
- # If non-zero, don't match hidden files (filenames beginning with a `.' on
- # Unix) when doing filename completion.
- @_rl_match_hidden_files = true
-
- # Global variables available to applications using readline.
-
- # Non-zero means add an additional character to each filename displayed
- # during listing completion iff rl_filename_completion_desired which helps
- # to indicate the type of file being listed.
- @rl_visible_stats = false
-
- # If non-zero, then this is the address of a function to call when
- # completing on a directory name. The function is called with
- # the address of a string (the current directory name) as an arg.
- @rl_directory_completion_hook = nil
-
- @rl_directory_rewrite_hook = nil
-
- # Non-zero means readline completion functions perform tilde expansion.
- @rl_complete_with_tilde_expansion = false
-
- # Pointer to the generator function for completion_matches ().
- # NULL means to use rl_filename_completion_function (), the default filename
- # completer.
- @rl_completion_entry_function = nil
-
- # Pointer to alternative function to create matches.
- # Function is called with TEXT, START, and END.
- # START and END are indices in RL_LINE_BUFFER saying what the boundaries
- # of TEXT are.
- # If this function exists and returns NULL then call the value of
- # rl_completion_entry_function to try to match, otherwise use the
- # array of strings returned.
- @rl_attempted_completion_function = nil
-
- # Non-zero means to suppress normal filename completion after the
- # user-specified completion function has been called.
- @rl_attempted_completion_over = false
-
- # Set to a character indicating the type of completion being performed
- # by rl_complete_internal, available for use by application completion
- # functions.
- @rl_completion_type = 0
-
- # Up to this many items will be displayed in response to a
- # possible-completions call. After that, we ask the user if
- # she is sure she wants to see them all. A negative value means
- # don't ask.
- @rl_completion_query_items = 100
-
- @_rl_page_completions = 1
-
- # The basic list of characters that signal a break between words for the
- # completer routine. The contents of this variable is what breaks words
- # in the shell, i.e. " \t\n\"\\'`@$><="
- @rl_basic_word_break_characters = " \t\n\"\\'`@$><=|&{(" # })
-
- # List of basic quoting characters.
- @rl_basic_quote_characters = "\"'"
-
- # The list of characters that signal a break between words for
- # rl_complete_internal. The default list is the contents of
- # rl_basic_word_break_characters.
- @rl_completer_word_break_characters = nil
-
- # Hook function to allow an application to set the completion word
- # break characters before readline breaks up the line. Allows
- # position-dependent word break characters.
- @rl_completion_word_break_hook = nil
-
- # List of characters which can be used to quote a substring of the line.
- # Completion occurs on the entire substring, and within the substring
- # rl_completer_word_break_characters are treated as any other character,
- # unless they also appear within this list.
- @rl_completer_quote_characters = nil
-
- # List of characters that should be quoted in filenames by the completer.
- @rl_filename_quote_characters = nil
-
- # List of characters that are word break characters, but should be left
- # in TEXT when it is passed to the completion function. The shell uses
- # this to help determine what kind of completing to do.
- @rl_special_prefixes = nil
-
- # If non-zero, then disallow duplicates in the matches.
- @rl_ignore_completion_duplicates = true
-
- # Non-zero means that the results of the matches are to be treated
- # as filenames. This is ALWAYS zero on entry, and can only be changed
- # within a completion entry finder function.
- @rl_filename_completion_desired = false
-
- # Non-zero means that the results of the matches are to be quoted using
- # double quotes (or an application-specific quoting mechanism) if the
- # filename contains any characters in rl_filename_quote_chars. This is
- # ALWAYS non-zero on entry, and can only be changed within a completion
- # entry finder function.
- @rl_filename_quoting_desired = true
-
- # This function, if defined, is called by the completer when real
- # filename completion is done, after all the matching names have been
- # generated. It is passed a (char**) known as matches in the code below.
- # It consists of a NULL-terminated array of pointers to potential
- # matching strings. The 1st element (matches[0]) is the maximal
- # substring that is common to all matches. This function can re-arrange
- # the list of matches as required, but all elements of the array must be
- # free()'d if they are deleted. The main intent of this function is
- # to implement FIGNORE a la SunOS csh.
- @rl_ignore_some_completions_function = nil
-
- # Set to a function to quote a filename in an application-specific fashion.
- # Called with the text to quote, the type of match found (single or multiple)
- # and a pointer to the quoting character to be used, which the function can
- # reset if desired.
- #rl_filename_quoting_function = rl_quote_filename
-
- # Function to call to remove quoting characters from a filename. Called
- # before completion is attempted, so the embedded quotes do not interfere
- # with matching names in the file system. Readline doesn't do anything
- # with this it's set only by applications.
- @rl_filename_dequoting_function = nil
-
- # Function to call to decide whether or not a word break character is
- # quoted. If a character is quoted, it does not break words for the
- # completer.
- @rl_char_is_quoted_p = nil
-
- # If non-zero, the completion functions don't append anything except a
- # possible closing quote. This is set to 0 by rl_complete_internal and
- # may be changed by an application-specific completion function.
- @rl_completion_suppress_append = false
-
- # Character appended to completed words when at the end of the line. The
- # default is a space.
- @rl_completion_append_character = ' '
-
- # If non-zero, the completion functions don't append any closing quote.
- # This is set to 0 by rl_complete_internal and may be changed by an
- # application-specific completion function.
- @rl_completion_suppress_quote = false
-
- # Set to any quote character readline thinks it finds before any application
- # completion function is called.
- @rl_completion_quote_character = 0
-
- # Set to a non-zero value if readline found quoting anywhere in the word to
- # be completed set before any application completion function is called.
- @rl_completion_found_quote = false
-
- # If non-zero, a slash will be appended to completed filenames that are
- # symbolic links to directory names, subject to the value of the
- # mark-directories variable (which is user-settable). This exists so
- # that application completion functions can override the user's preference
- # (set via the mark-symlinked-directories variable) if appropriate.
- # It's set to the value of _rl_complete_mark_symlink_dirs in
- # rl_complete_internal before any application-specific completion
- # function is called, so without that function doing anything, the user's
- # preferences are honored.
- @rl_completion_mark_symlink_dirs = false
-
- # If non-zero, inhibit completion (temporarily).
- @rl_inhibit_completion = false
-
- # Variables local to this file.
-
- # Local variable states what happened during the last completion attempt.
- @completion_changed_buffer = nil
-
- # Non-zero means treat 0200 bit in terminal input as Meta bit.
- @_rl_meta_flag = false
-
- # Stack of previous values of parsing_conditionalized_out.
- @if_stack = []
- @if_stack_depth = 0
-
-
- # The last key bindings file read.
- @last_readline_init_file = nil
-
- # The file we're currently reading key bindings from.
- @current_readline_init_file = nil
- @current_readline_init_include_level = 0
- @current_readline_init_lineno = 0
-
- ENV["HOME"] ||= ENV["HOMEDRIVE"]+ENV["HOMEPATH"]
-
- @directory = nil
- @filename = nil
- @dirname = nil
- @users_dirname = nil
- @filename_len = 0
-
- attr_accessor :rl_attempted_completion_function,:rl_deprep_term_function,
- :rl_event_hook,:rl_attempted_completion_over,:rl_basic_quote_characters,
- :rl_basic_word_break_characters,:rl_completer_quote_characters,
- :rl_completer_word_break_characters,:rl_completion_append_character,
- :rl_filename_quote_characters,:rl_instream,:rl_library_version,:rl_outstream,
- :rl_readline_name,:history_length,:history_base
-
- module_function
- # 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.
- 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)
- @filename = text.dup
- if text.length == 0
- text = "."
- end
- @dirname = File.dirname(text)
- # 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] == ?~)
- @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
- end
-
- @directory = Dir.new(@dirname)
-
- # 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)
- if (!@_rl_match_hidden_files && d_name[0]==?.)
- next
- end
- if (d_name != '.' && d_name != '..')
- break
- end
- 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] == ?~)
- temp = @dirname
- if(temp[-1] != ?/)
- temp += '/'
- end
- else
- temp = @users_dirname
- if(temp[-1] != ?/)
- temp += '/'
- end
- end
- temp += entry
- else
- temp = entry.dup
- end
- return (temp)
- end
- end
-
- # A completion function for usernames.
- # TEXT contains a partial username preceded by a random
- # character (usually `~').
- def rl_username_completion_function(text, state)
- return nil if RUBY_PLATFORM =~ /mswin|mingw/
-
- if (state == 0)
- first_char = text[0]
- first_char_loc = (text[0] == ?~ ? 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
-
- #*************************************************************
- #
- # Application-callable completion match generator functions
- #
- #*************************************************************
-
- # 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.
- #
- def rl_completion_matches(text, entry_function)
- matches = 0
- match_list_size = 10
- 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
-
- def _rl_to_lower(char)
- char.nil? ? nil : char.chr.downcase
- end
-
- # Find the common prefix of the list of matches, and put it into
- # matches[0].
- 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
-
-
- def rl_vi_editing_mode(count, key)
- _rl_set_insert_mode(RL_IM_INSERT, 1) # vi mode ignores insert mode
- @rl_editing_mode = @vi_mode
- rl_vi_insertion_mode(1, key)
- 0
- end
-
- # Switching from one mode to the other really just involves
- # switching keymaps.
- def rl_vi_insertion_mode(count, key)
- @_rl_keymap = @vi_insertion_keymap
- @_rl_vi_last_key_before_insert = key
- 0
- end
-
- 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
-
- # Function for the rest of the library to use to set insert/overwrite mode.
- def _rl_set_insert_mode(im, force)
- @rl_insert_mode = im
- end
-
- # Toggle overwrite mode. A positive explicit argument selects overwrite
- # mode. A negative or zero explicit argument selects insert mode.
- 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
-
-
- # A function for simple tilde expansion.
- def rl_tilde_expand(ignore, key)
- _end = @rl_point
- start = _end - 1
-
- if (@rl_point == @rl_end && @rl_line_buffer[@rl_point] == ?~ )
- homedir = File.expand_path("~")
- _rl_replace_text(homedir, start, _end)
- return (0)
- elsif (@rl_line_buffer[start] != ?~)
- 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] == ?~)
-
- 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
-
- # Clean up the terminal and readline state after catching a signal, before
- # resending it to the calling application.
- 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
-
- 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
-
- # 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.
- 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)
-
- if (dpos > @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 = 0.chr * 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.
- 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
-
- def rl_setstate(x)
- (@rl_readline_state |= (x))
- end
-
- def rl_unsetstate(x)
- (@rl_readline_state &= ~(x))
- end
-
- def rl_isstate(x)
- (@rl_readline_state & (x))!=0
- end
-
- # Clear any pending input pushed with rl_execute_next()
- def rl_clear_pending_input()
- @rl_pending_input = 0
- rl_unsetstate(RL_STATE_INPUTPENDING)
- 0
- end
-
- def rl_restart_output(count, key)
- 0
- end
-
- def rl_clear_signals()
- if Signal.list['WINCH']
- trap "WINCH",@def_proc
- end
- end
-
- def rl_set_signals()
- if Signal.list['WINCH']
- @def_proc = trap "WINCH",Proc.new{rl_sigwinch_handler(0)}
- end
- 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'.
- 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
-
-
- #*
- #* 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.
- #*
- 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_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,_,@prompt_invis_chars_first_line, = expand_prompt(prompt)
- prompt[t] = c
- @local_prompt_len = @local_prompt ? @local_prompt.length : 0
- return (@prompt_prefix_length)
- end
- end
-
- # Set up the prompt and expand it. Called from readline() and
- # rl_callback_handler_install ().
- 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
-
- def get_term_capabilities(buffer)
- hash = {}
- `infocmp -C`.split(':').select{|x| x =~ /(.*)=(.*)/ and hash[$1]=$2.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
-
- # Set the environment variables LINES and COLUMNS to lines and cols,
- # respectively.
- def sh_set_lines_and_columns(lines, cols)
- ENV["LINES"] = lines.to_s
- ENV["COLUMNS"] = cols.to_s
- 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.
- def _rl_get_screen_size(tty, ignore_env)
-
- if @hConsoleHandle
- csbi = 0.chr * 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 = `stty size`.split(' ').map{|x| x.to_i}
- @_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
-
- def tgetflag(name)
- `infocmp -C -r`.scan(/\w{2}/).include?(name)
- 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).
- def rl_function_of_keyseq(keyseq, map, type)
- map ||= @_rl_keymap
- map[keyseq]
- 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.
- def rl_generic_bind(type, keyseq, data, map)
- map[keyseq] = data
- 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.
- def rl_bind_keyseq_in_map(keyseq, function, map)
- rl_generic_bind(ISFUNC, keyseq, function, map)
- 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.
- 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
-
- def rl_bind_keyseq_if_unbound(keyseq, default_func)
- rl_bind_keyseq_if_unbound_in_map(keyseq, default_func, @_rl_keymap)
- end
-
- # Bind the arrow key sequences from the termcap description in MAP.
- 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
-
- 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
-
- # "An application program can assume that the terminal can do
- # character insertion if *any one of* the capabilities `IC',
- # `im', `ic' or `ip' is provided." But we can't do anything if
- # only `ip' is provided, so...
- @_rl_terminal_can_insert = !!(@_rl_term_IC || @_rl_term_im || @_rl_term_ic)
-
- # 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
-
- # New public way to set the system default editing chars to their readline
- # equivalents.
- def rl_tty_set_default_bindings(kmap)
- h = Hash[*`stty -a`.scan(/(\w+) = ([^;]+);/).flatten]
- 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
-
- # 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.
- def readline_default_bindings()
- if @_rl_bind_stty_chars
- rl_tty_set_default_bindings(@_rl_keymap)
- end
- end
-
- def _rl_init_eightbit()
-
- 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.
- 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
-
- 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 = File.open(openname).read
- 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
-
- # Push _rl_parsing_conditionalized_out, and set parser state based
- # on ARGS.
- 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
-
- # Invert the current parser state if there is anything on the stack.
- 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.
- 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
-
- 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
-
- # Handle a parser directive. STATEMENT is the line of the directive
- # without any leading `$'.
- 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
-
-
- 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"
- @_rl_keymap = @vi_insertion_keymap
- @rl_editing_mode = @vi_mode
- 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"
- @_rl_keymap = @vi_movement_keymap
- when "vi-insert"
- @_rl_keymap = @vi_insertion_keymap
- end
- end
- end
-
- 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 "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 "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]+$/
- return ('rl_'+name.gsub('-','_')).to_sym
- end
- end
- nil
- end
-
- # Bind KEY to FUNCTION. Returns non-zero if KEY is out of range.
- def rl_bind_key(key, function)
- @_rl_keymap[key] = function
- @rl_binding_keymap = @_rl_keymap
- 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.
- def rl_parse_and_bind(string)
-
- # If this is a parser directive, act on it.
- if (string[0] == ?$)
- 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
-
- key,funname = string.split(/\s*:\s*/)
- key = instance_eval(key)
- rl_bind_key(key, rl_named_function(funname))
-
- 0
- end
-
-
- def _rl_enable_meta_key()
- if(@term_has_meta && @_rl_term_mm)
- @_rl_out_stream.write(@_rl_term_mm)
- end
- end
-
- 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
-
- 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
-
- # Bind some common arrow key sequences in MAP.
- 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
-
- # 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.
- 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
-
- # Initialize the entire state of the world.
- 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 ||= 0.chr * DEFAULT_BUFFER_SIZE
-
- # 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
-
- def _rl_init_line_state()
- @rl_point = @rl_end = @rl_mark = 0
- @rl_line_buffer = 0.chr * @rl_line_buffer.length
- end
-
- # Set the history pointer back to the last entry in the history.
- def _rl_start_using_history()
- using_history()
- @_rl_saved_line_for_history = nil
- end
-
-
- def cr_faster(new, cur)
- (new + 1) < (cur - new)
- 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.
- def prompt_ending_index()
- if !@rl_byte_oriented
- @prompt_physical_chars
- else
- (@prompt_last_invisible+1)
- 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.
- 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
-
- # Return the history entry at the current position, as determined by
- # history_offset. If there is no entry there, return a NULL pointer.
- def current_history()
- return ((@history_offset == @history_length) || @the_history.nil?) ?
- nil : @the_history[@history_offset]
- end
-
- def meta_char(c)
- c > "\x7f" && c <= "\xff"
- end
-
- def ctrl_char(c)
- c < "\x20"
- end
-
- def isprint(c)
- c >= "\x20" && c < "\x7f"
- end
-
- def whitespace(c)
- (c == ' ' || c == "\t")
- end
-
- def w_offset(line, offset)
- ((line) == 0 ? offset : 0)
- end
-
- def vis_llen(l)
- ((l) > @_rl_vis_botlin ? 0 : (@vis_lbreaks[l+1] - @vis_lbreaks[l]))
- end
-
- def inv_llen(l)
- (@inv_lbreaks[l+1] - @inv_lbreaks[l])
- end
-
- def vis_chars(line)
- @visible_line[@vis_lbreaks[line] .. -1]
- end
-
- def vis_pos(line)
- @vis_lbreaks[line]
- end
-
- def vis_line(line)
- ((line) > @_rl_vis_botlin) ? "" : vis_chars(line)
- end
-
- def inv_line(line)
- @invisible_line[@inv_lbreaks[line] .. -1]
- end
-
- def m_offset(margin, offset)
- ((margin) == 0 ? offset : 0)
- 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
- 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] != ?\0
- 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] != ?\0
- 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] != ?\0 && new[0] != ?\0)
- old[ostart] = new[0]
- end
- end
-
- else
- if (new[0] != ?\0)
- @rl_outstream.write(new[0,1])
- else
- @rl_outstream.write(' ')
- end
- @_rl_last_c_pos = 1
- @_rl_last_v_pos+=1
- if (old[ostart]!= ?\0 && new[0] != ?\0)
- old[ostart] = new[0]
- 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.
- if (index = old.index(0.chr)) && omax+ostart>index
- omax = index - ostart
- end
- if (index = new.index(0.chr)) && nmax>index
- nmax = index
- end
-
- 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] != ?\0 &&
- _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] != ?\0 && old[ostart+ofd] == new[nfd])
- 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] == ?\x20)
- 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] == new[nls])
- if (old[ostart+ols] != ?\x20 )
- 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] != ?\0) # 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] != ?\0 )
- 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
-
- # 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)
-
- if (current_line == 0 && !@rl_byte_oriented && @_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
- # 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.
- if (@_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] != ?\0 && (!@_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] == ?\0 && 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
- # We have horizontal scrolling and we are not inserting at
- # the end. We have invisible characters in this line. This
- # is a dumb update.
- _rl_output_some_chars(new,nfd, temp)
- @_rl_last_c_pos += col_temp
- 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)
- _rl_output_some_chars(new,nfd, temp)
- @_rl_last_c_pos += _rl_col_width(new,nfd,nfd+temp)
- end
-
- # Otherwise, print over the existing material.
- else
- if (temp > 0)
- _rl_output_some_chars(new,nfd, temp)
- @_rl_last_c_pos += col_temp # XXX
- 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
-
- # Basic redisplay algorithm.
- 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] = '*'
- out += 1
- line[out] = 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] != @invisible_line[0])
- @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] = 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] != ?\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] = 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 (lb_botlin and 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] = 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] = ' '
- out += 1
- end
-
- else
-
- while (out < newout)
- line[out] = ' '
- out += 1
- end
- lpos += temp
- end
-
- elsif (c == "\n" && !@_rl_horizontal_scroll_mode && @_rl_term_up)
- line[out] = 0.chr # XXX - sentinel
- out += 1
- @inv_lbreaks[newlines+=1] = out
- lpos = 0
- elsif (ctrl_char(c) || c == RUBOUT)
- line[out] = '^'
- out += 1
- lpos+=1
- if (lpos >= @_rl_screenwidth)
- @inv_lbreaks[newlines+=1] = out
- @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
- lpos = 0
- end
- line[out] = 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] = ' '
- 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] = 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] = 0.chr
-
- if (@cpos_buffer_position < 0)
- @cpos_buffer_position = out
- lb_linenum = newlines
- end
-
- inv_botlin = lb_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.
- for linenum in 0 .. 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
- 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 (@_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] = '<'
- 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] = '>'
- 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
-
- # Tell the update routines that we have moved onto a new (empty) line.
- def rl_on_new_line()
- if (@visible_line)
- @visible_line[0] = 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
-
- def rl_reset_line_state()
- rl_on_new_line()
-
- @rl_display_prompt = @rl_prompt ? @rl_prompt : ""
- @forced_display = true
- 0
- end
-
- def _rl_vi_initialize_line
- rl_unsetstate(RL_STATE_VICMDONCE)
- end
-
- # Initialize readline (and terminal if not already).
- 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
-
- def _rl_strip_prompt(pmt)
- return expand_prompt(pmt).first
- end
-
- def _rl_col_width(string,start,_end)
- return 0 if _end <= start
-
- index = string.index(0.chr)
- str = index ? string[0,index] : 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
-
- # Write COUNT characters from STRING to the output stream.
- def _rl_output_some_chars(string,start,count)
- @_rl_out_stream.write(string[start,count])
- 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.
- 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
-
- 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
-
- # Create a default argument.
- def _rl_reset_argument()
- @rl_numeric_arg = @rl_arg_sign = 1
- @rl_explicit_arg = false
- @_rl_argcxt = 0
- end
-
- # Ring the terminal bell.
- 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
-
- 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
-
- def endsrch_char(c)
- ((ctrl_char(c) || meta_char(c) || (c) == RUBOUT) && ((c) != "\C-G"))
- 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.
- def _rl_isearch_dispatch(cxt, c)
- f = nil
-
- # 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.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[cxt.search_string_index-=1] = 0.chr
- 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
-
- # How to clear things from the "echo-area".
- 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
-
- 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
-
-
- def _rl_isearch_cleanup(cxt, r)
- if (r >= 0)
- _rl_isearch_fini(cxt)
- end
- ctx = nil
- @_rl_iscxt = nil
-
- rl_unsetstate(RL_STATE_ISEARCH)
-
- r != 0
- 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.
- def _rl_dispatch(key, map)
- @_rl_dispatching_keymap = map
- return _rl_dispatch_subseq(key, map, false)
- end
-
-
- 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] < ?\x7F)
- _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
-
- # Add KEY to the buffer of characters to be read. Returns 1 if the
- # character was stuffed correctly; 0 otherwise.
- 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
-
- begin
- # Cygwin will look like Windows, but we want to treat it like a Posix OS:
- raise LoadError, "Cygwin is a Posix OS." if RUBY_PLATFORM =~ /\bcygwin\b/i
- raise LoadError, "Not Windows" if RUBY_PLATFORM !~ /mswin|mingw/
-
- if RUBY_VERSION < '1.9.1' or defined?(IRONRUBY_VERSION)
- require 'Win32API'
- else
- require 'dl'
- class Win32API
- DLL = {}
- TYPEMAP = {"0" => DL::TYPE_VOID, "S" => DL::TYPE_VOIDP, "I" => DL::TYPE_LONG}
-
- def initialize(dllname, func, import, export = "0")
- @proto = [import].join.tr("VPpNnLlIi", "0SSI").sub(/^(.)0*$/, '\1')
- handle = DLL[dllname] ||= DL.dlopen(dllname)
- @func = DL::CFunc.new(handle[func], TYPEMAP[export.tr("VPpNnLlIi", "0SSI")], func)
- end
-
- def call(*args)
- import = @proto.split("")
- args.each_with_index do |x, i|
- args[i], = [x == 0 ? nil : x].pack("p").unpack("l!*") if import[i] == "S"
- args[i], = [x].pack("I").unpack("i") if import[i] == "I"
- end
- ret, = @func.call(args)
- return ret || 0
- end
-
- alias Call call
- end
- end
-
- STD_OUTPUT_HANDLE = -11
- STD_INPUT_HANDLE = -10
- KEY_EVENT = 1
- VK_SHIFT = 0x10
- VK_MENU = 0x12
- VK_LMENU = 0xA4
- VK_RMENU = 0xA5
-
- LEFT_CTRL_PRESSED = 0x0008
- RIGHT_CTRL_PRESSED = 0x0004
- LEFT_ALT_PRESSED = 0x0002
- RIGHT_ALT_PRESSED = 0x0001
-
- @getch = Win32API.new("msvcrt", "_getch", [], 'I')
- @kbhit = Win32API.new("msvcrt", "_kbhit", [], 'I')
- @GetStdHandle = Win32API.new("kernel32","GetStdHandle",['L'],'L')
- @SetConsoleCursorPosition = Win32API.new("kernel32","SetConsoleCursorPosition",['L','L'],'L')
- @GetConsoleScreenBufferInfo = Win32API.new("kernel32","GetConsoleScreenBufferInfo",['L','P'],'L')
- @FillConsoleOutputCharacter = Win32API.new("kernel32","FillConsoleOutputCharacter",['L','L','L','L','P'],'L')
- @ReadConsoleInput = Win32API.new( "kernel32", "ReadConsoleInput", ['L', 'P', 'L', 'P'], 'L' )
- @MessageBeep = Win32API.new("user32","MessageBeep",['L'],'L')
- @GetKeyboardState = Win32API.new("user32","GetKeyboardState",['P'],'L')
- @GetKeyState = Win32API.new("user32","GetKeyState",['L'],'L')
- @hConsoleHandle = @GetStdHandle.Call(STD_OUTPUT_HANDLE)
- @hConsoleInput = @GetStdHandle.Call(STD_INPUT_HANDLE)
- @pending_count = 0
- @pending_key = nil
-
- begin
- case `chcp`.scan(/\d+$/).first.to_i
- when 936,949,950,51932,51936,50225
- @encoding = "E"
- when 932,50220,50221,20222
- @encoding = "S"
- when 65001
- @encoding = "U"
- else
- @encoding = "N"
- end
- rescue
- @encoding = "N"
- end
-
- def rl_getc(stream)
- c = @getch.Call
- alt = (@GetKeyState.call(VK_LMENU) & 0x80) != 0
- if c==0 || c==0xE0
- r = c.chr + @getch.Call.chr
- else
- r = c.chr
- end
- r = "\e"+r if alt
- r
- end
-
- 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
-
- rescue LoadError # If we're not on Windows try...
-
- if ENV["LANG"] =~ /\.UTF-8/
- @encoding = "U"
- elsif ENV["LANG"] =~ /\.EUC/
- @encoding = "E"
- elsif ENV["LANG"] =~ /\.SHIFT/
- @encoding = "S"
- else
- @encoding = "N"
- end
-
- def rl_getc(stream)
- begin
- c = stream.read(1)
- rescue Errno::EINTR
- c = rl_getc(stream)
- end
- return c ? c : EOF
- end
-
- def rl_gather_tyi()
- chars_avail = 0
- result = select([@rl_instream],nil,nil,0.1)
- return 0 if result.nil?
- k = send(@rl_getc_function,@rl_instream)
- rl_stuff_char(k)
- return 1
- end
- end
-
- if defined? ''.getbyte
- @encoding = "X" # ruby 1.9.x or greater
- @encoding_name = Encoding.default_external.to_s
- end
-
- @rl_byte_oriented = @encoding == "N"
-
- # Read a key, including pending input.
- 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
-
-
- # Return the amount of space available in the buffer for stuffing
- # characters.
- def ibuffer_space()
- if (@pop_index > @push_index)
- return (@pop_index - @push_index - 1)
- else
- return (@ibuffer_len - (@push_index - @pop_index))
- end
- 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.
- 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
-
- # Stuff KEY into the *front* of the input buffer.
- # Returns non-zero if successful, zero if there is
- # no space left in the buffer.
- 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
-
- 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
-
- # Clear to the end of the line. COUNT is the minimum
- # number of character spaces to clear,
- 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
-
- # Clear to the end of the line using spaces. COUNT is the minimum
- # number of character spaces to clear,
- def space_to_eol(count)
- if @hConsoleHandle
- csbi = 0.chr * 24
- @GetConsoleScreenBufferInfo.Call(@hConsoleHandle,csbi)
- cursor_pos = csbi[4,4].unpack('L').first
- written = 0.chr * 4
- @FillConsoleOutputCharacter.Call(@hConsoleHandle,0x20,count,cursor_pos,written)
- else
- @rl_outstream.write(' ' * count)
- end
- @_rl_last_c_pos += count
- end
-
- def _rl_clear_screen()
- if (@_rl_term_clrpag)
- @rl_outstream.write(@_rl_tirberm_clrpag)
- else
- rl_crlf()
- end
- end
-
- # Move the cursor back.
- 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
-
- # Move to the start of the next line.
- def rl_crlf()
- if (@_rl_term_cr)
- @_rl_out_stream.write(@_rl_term_cr)
- end
- @_rl_out_stream.write("\n")
- return 0
- end
-
- # Move to the start of the current line.
- def cr()
- if (@_rl_term_cr)
- @_rl_out_stream.write(@_rl_term_cr)
- @_rl_last_c_pos = 0
- end
- end
-
- def _rl_erase_entire_line()
- cr()
- _rl_clear_to_eol(0)
- cr()
- @rl_outstream.flush
- end
-
- 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
-
- 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
-
- # How to abort things.
- 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
-
- def rl_abort(count, key)
- _rl_abort_internal()
- end
-
- def rl_vi_check()
- if (@rl_point!=0 && @rl_point == @rl_end)
- @rl_point-=1
- end
- 0
- end
-
- 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
-
- # 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.
- def readline_internal()
- readline_internal_setup()
- eof = readline_internal_charloop()
- readline_internal_teardown(eof)
- end
-
- # Read a line of input. Prompt with PROMPT. An empty PROMPT means
- # none. A return value of NULL means that EOF was encountered.
- 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
-
- # Increase the size of RL_LINE_BUFFER until it has enough space to hold
- # LEN characters.
- 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
-
- # 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.
- 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
-
- 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
-
- #* Remember how to undo something. Concatenate some undos if that
- # seems right.
- 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
-
-
- # Delete the string between FROM and TO. FROM is inclusive, TO is not.
- # Returns the number of characters deleted.
- 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] = 0.chr
- return (diff)
- end
-
- def rl_copy_text(from, to)
- return @rl_line_buffer[from...to]
- end
-
- # 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.
-
- def __rl_fix_point(x)
- if (x > @rl_end)
- @rl_end
- elsif (x < 0)
- 0
- else
- x
- end
- end
-
- 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
-
- # Begin a group. Subsequent undos are undone as an atomic operation.
- def rl_begin_undo_group()
- rl_add_undo(UNDO_BEGIN, 0, 0, nil)
- @_rl_undo_group_level+=1
- 0
- end
-
- # End an undo group started with rl_begin_undo_group ().
- def rl_end_undo_group()
- rl_add_undo(UNDO_END, 0, 0, nil)
- @_rl_undo_group_level-=1
- 0
- end
-
- def rl_free_undo_list()
- replace_history_data(-1, @rl_undo_list, nil)
- @rl_undo_list = nil
- 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)
- 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
-
- # Replace the current line buffer contents with TEXT. If CLEAR_UNDO is
- # non-zero, we free the current undo list.
- 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
-
-
- # 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.
- 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
-
- # Move forward COUNT bytes.
- 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.
- 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
-
- # Backwards compatibility.
- def rl_forward(count, key)
- rl_forward_char(count, key)
- end
-
- # Move backward COUNT bytes.
- 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.
- 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
-
- # Backwards compatibility.
- def rl_backward(count, key)
- rl_backward_char(count, key)
- end
-
- # Move to the beginning of the line.
- def rl_beg_of_line(count, key)
- @rl_point = 0
- 0
- end
-
- # Move to the end of the line.
- def rl_end_of_line(count, key)
- @rl_point = @rl_end
- 0
- end
-
- def _rl_char_value(buf,ind)
- buf[ind,1]
- end
-
- @_rl_allow_pathname_alphabetic_chars = false
- @pathname_alphabetic_chars = '/-_=~.#$'
-
- def rl_alphabetic(c)
- if c =~ /\w/
- return true
- end
-
- return !!(@_rl_allow_pathname_alphabetic_chars &&
- @pathname_alphabetic_chars[c])
- end
-
- def _rl_walphabetic(c)
- rl_alphabetic(c)
- end
-
- # Move forward a word. We do what Emacs does. Handles multibyte chars.
- 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
-
- # Move backward a word. We do what Emacs does. Handles multibyte chars.
- 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
-
- # 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.
- 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
-
- # Actually update the display, period.
- 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
-
-
- # Clear the current line. Numeric argument to C-l does this.
- 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
-
- # 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.
- 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
-
- # Restore the _rl_saved_line_for_history if there is one.
- 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
-
- # Save the current line in _rl_saved_line_for_history.
- 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
-
- # Returns the magic number which says what history element we are
- # looking at now. In this implementation, it returns history_offset.
- def where_history()
- @history_offset
- 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.
- 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
-
- # Perhaps put back the current line if it has changed.
- 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
-
- # 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.
- def previous_history()
- @history_offset!=0 ? @the_history[@history_offset-=1] : nil
- 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.
- def next_history()
- (@history_offset == @history_length) ? nil : @the_history[@history_offset+=1]
- end
-
- # Get the previous item out of our interactive history, making it the current
- # line. If there is no previous history, just ding.
- 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
-
- 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
-
- # Move down to the next history line.
- 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
-
- 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
-
- def _rl_any_typein()
- return (@push_index != @pop_index)
- end
-
- 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
-
- # 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.
- 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
-
- # 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.
- def _rl_overwrite_char(count, c)
-
- # Read an entire multibyte character sequence to insert COUNT times.
- if (count > 0 && !@rl_byte_oriented)
- mbkey = ''
- k = _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
-
- def rl_insert(count, c)
- ((@rl_insert_mode == RL_IM_INSERT) ? _rl_insert_char(count, c) :
- _rl_overwrite_char(count, c))
- end
-
-
- # Insert the next typed character verbatim.
- def _rl_insert_next(count)
- rl_setstate(RL_STATE_MOREINPUT)
- c = rl_read_key()
- rl_unsetstate(RL_STATE_MOREINPUT)
-
- _rl_insert_char(count, c)
- end
-
- def rl_quoted_insert(count, key)
- _rl_insert_next(count)
- end
-
- # Insert a tab character.
- def rl_tab_insert(count, key)
- _rl_insert_char(count, "\t")
- end
-
- 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
-
- 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
-
- # Is the command C a VI mode text modification command?
- def _rl_vi_textmod_command(c)
- return @vi_textmod[c]
- end
-
- 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
-
- 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]] == ?\0 )
- @_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
-
-
- # 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.
- 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
-
- # 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.
- def rl_do_lowercase_version(ignore1, ignore2)
- 0
- end
-
- 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
-
- # 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.
- 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
-
- # Rubout the character behind point.
- 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
-
-
- # Quick redisplay hack when erasing characters at the end of the line.
- 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
-
- 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
-
- # Delete the character under the cursor. Given a numeric argument,
- # kill that many characters instead.
- 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
-
- # 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.
- 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
-
- # 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.
- 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
-
- # This does what C-w does in Unix. We can't prevent people from
- # using behaviour that they expect.
- 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
-
- # This deletes one filename component in a Unix pathname. That is, it
- # deletes backward to directory separator (`/') or whitespace.
- 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
-
- # 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.
- 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
-
- # Delete all spaces and tabs around point.
- 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
-
- # List the possible completions. See description of rl_complete ().
- def rl_possible_completions(ignore, invoking_key)
- rl_complete_internal('?')
- 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.
- 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
-
- # Turn the current line into a comment in shell history.
- # A K*rn shell style function.
- 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
-
- def alloc_history_entry(string, ts)
- temp = Struct.new(:line,:data,:timestamp).new
- temp.line = string ? string.delete(0.chr) : string
- temp.data = nil
- temp.timestamp = ts
-
- return temp
- end
-
- def hist_inittime()
- t = Time.now.to_i
- ts = "X%u" % t
- ret = ts.dup
- ret[0] = @history_comment_char
-
- ret
- end
-
- # Place STRING at the end of the history list. The data field
- # is set to NULL.
- 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
-
- def using_history()
- @history_offset = @history_length
- end
-
- # Set default values for readline word completion. These are the variables
- # that application completion functions can change or inspect.
- 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
-
- 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 (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] == ?\\)
- 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
- if !@rl_byte_oriented
- scan = _rl_find_next_mbchar(@rl_line_buffer, scan, 1, MB_FIND_ANY)
- else
- scan += 1
- 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
-
- 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
-
- # Filter out duplicates in MATCHES. This frees up the strings in
- # MATCHES.
- 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
-
- 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
-
- 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
-
- 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
-
-
- 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
-
- # 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.
- 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
-
- 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
-
- def _rl_internal_pager(lines)
- @rl_outstream.puts "--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
-
- def path_isdir(filename)
- return File.directory?(filename)
- 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
- 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
-
-
- # 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.
- def print_filename(to_print, full_pathname)
- extension_char = 0.chr
- 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
- tlen = to_print.length
- new_full_pathname = s.dup
- if (s[-1] == ?/ )
- slen-=1
- else
- new_full_pathname[slen] = ?/
- 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
-
- # The user must press "y" or "n". Non-zero return means "y" pressed.
- 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)
- _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
-
- # Compute width of STRING when displayed on screen by print_filename
- def fnwidth(string)
- left = string.length + 1
- width = pos = 0
- while (string[pos] && string[pos] != ?\0)
- 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
-
- # 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.
- 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
-
- # 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.
- 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
-
- # 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.
- 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
-
- # Return the history entry which is logically at OFFSET in the history array.
- # OFFSET is relative to history_base.
- 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
-
- 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
-
- # Remove history element WHICH from the history. The removed
- # element is returned to you so you can free the line, data,
- # and containing structure.
- 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
-
- def block_sigint()
- return if @sigint_blocked
- #@sigint_proc = Signal.trap("INT","IGNORE")
- @sigint_blocked = true
- end
-
- def release_sigint()
- return if !@sigint_blocked
- #Signal.trap("INT",@sigint_proc)
- @sigint_blocked = false
- end
-
- def save_tty_chars()
- @_rl_last_tty_chars = @_rl_tty_chars
- h = Hash[*`stty -a`.scan(/(\w+) = ([^;]+);/).flatten]
- 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
- @otio = `stty -g`
- end
-
- 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
-
- def prepare_terminal_settings(meta_flag)
- @readline_echoing_p = (`stty -a`.scan(/-*echo\b/).first == 'echo')
-
- # 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.
- if (`stty -a`.scan(/-parenb\b/).first == '-parenb')
- setting << " pass8"
- end
-
- setting << " -ixoff"
-
- rl_bind_key(@_rl_tty_chars.t_start, :rl_restart_output)
- @_rl_eof_char = @_rl_tty_chars.t_eof
-
- #setting << " -isig"
-
- `stty #{setting}`
- end
-
- 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
-
- # 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.
- 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
-
- 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
-
- # Restore the terminal's normal settings and modes.
- 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
- `stty #{@otio}`
-
- @terminal_prepped = false
- rl_unsetstate(RL_STATE_TERMPREPPED)
-
- release_sigint()
- end
-
- # Set the mark at POSITION.
- def _rl_set_mark_at_pos(position)
- return -1 if (position > @rl_end)
- @rl_mark = position
- 0
- end
-
- # A bindable command to set the mark.
- def rl_set_mark(count, key)
- _rl_set_mark_at_pos(@rl_explicit_arg ? count : @rl_point)
- end
-
- # Kill from here to the end of the line. If DIRECTION is negative, kill
- # back to the line start instead.
- 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
-
- # Kill backwards to the start of the line. If DIRECTION is negative, kill
- # forwards to the line end instead.
- 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
-
- # Kill the whole line, no matter where point is.
- 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
-
- # Search backwards through the history looking for a string which is typed
- # interactively. Start with the current line.
- def rl_reverse_search_history(sign, key)
- rl_search_history(-sign, key)
- end
-
- # Search forwards through the history looking for a string which is typed
- # interactively. Start with the current line.
- def rl_forward_search_history(sign, key)
- rl_search_history(sign, key)
- 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.
- 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)
- c = _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
-
- 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).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
-
- def history_list()
- @the_history
- end
-
- 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 = Array.new(cxt.hlen+1)
- 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[i] = 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 = 0.chr * cxt.search_string_size
-
- # 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
-
- 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
-
- 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
-
- 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
-
- # 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.
- 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
-
- # Transpose the characters at point. If point is at the end of the line,
- # then transpose the characters before point.
- 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
-
- # 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.
- 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
-
- # Yank back the last killed text. This ignores arguments.
- 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
-
- # 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.
- 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
-
- # Yank the COUNTh argument from the previous history line, skipping
- # HISTORY_SKIP lines before looking for the `previous line'.
- def rl_yank_nth_arg_internal(count, ignore, history_skip)
- pos = where_history()
- if (history_skip>0)
- history_skip.times { entry = 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
-
- # Yank the COUNTth argument from the previous history line.
- def rl_yank_nth_arg(count, ignore)
- rl_yank_nth_arg_internal(count, ignore, 0)
- end
-
- # Yank the last argument from the previous history line. This `knows'
- # how rl_yank_nth_arg treats a count of `$'. With an argument, this
- # behaves the same as rl_yank_nth_arg.
- @history_skip = 0
- @explicit_arg_p = false
- @count_passed = 1
- @direction = 1
- @undo_needed = false
-
- 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
-
- 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
-
- def _rl_char_search(count, fdir, bdir)
- mbchar = ''
- mb_len = _rl_read_mbchar(mbchar, MB_LEN_MAX)
-
- 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
-
- def rl_char_search(count, key)
- _rl_char_search(count, FFIND, BFIND)
- end
-
- # Undo the next thing in the list. Return 0 if there
- # is nothing to undo, or non-zero if there was.
- def trans(i)
- ((i) == -1 ? @rl_point : ((i) == -2 ? @rl_end : (i)))
- end
-
- 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
-
-
-
- # Do some undoing of things that were done.
- 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
-
- # Delete the word at point, saving the text in the kill ring.
- 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
-
- # Rubout the word before point, placing it on the kill ring.
- 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
-
- # Revert the current line to its previous state.
- 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
-
- def rl_backward_char_search (count, key)
- _rl_char_search(count, BFIND, FFIND)
- end
-
- def rl_insert_completions(ignore, invoking_key)
- rl_complete_internal('*')
- end
-
- def _rl_arg_init()
- rl_save_prompt()
- @_rl_argcxt = 0
- rl_setstate(RL_STATE_NUMERICARG)
- end
-
- 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
-
- # 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.
- 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)
- 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
-
- 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
-
- # Handle C-u style numeric args, as well as M--, and M-digits.
- 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
-
- # Start a numeric argument with initial value KEY
- 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
-
- # Make C be the next command to be executed.
- def rl_execute_next(c)
- @rl_pending_input = c
- rl_setstate(RL_STATE_INPUTPENDING)
- 0
- end
-
- # Meta-< goes to the start of the history.
- def rl_beginning_of_history(count, key)
- rl_get_previous_history(1 + where_history(), key)
- end
-
- # Meta-> goes to the end of the history. (The current line).
- def rl_end_of_history(count, key)
- rl_maybe_replace_line()
- using_history()
- rl_maybe_unsave_line()
- 0
- end
-
- # Uppercase the word at point.
- def rl_upcase_word(count, key)
- rl_change_case(count, UpCase)
- end
-
- # Lowercase the word at point.
- def rl_downcase_word(count, key)
- rl_change_case(count, DownCase)
- end
-
- # Upcase the first letter, downcase the rest.
- def rl_capitalize_word(count, key)
- rl_change_case(count, CapCase)
- end
-
- # Save an undo entry for the text from START to END.
- 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
-
- # 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.
- 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
-
- def isascii(c)
- int_val = c[0].to_i # 1.8 + 1.9 compat.
- return (int_val < 128 && int_val > 0)
- 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 `:'.
- 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 forward through the history list for a string. If the vi-mode
- # code calls this, KEY will be `?'.
- 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 `/'.
- def rl_noninc_reverse_search(count, key)
- noninc_search(-1, (key == '/') ? '/' : nil)
- 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.
- def make_history_line_current(entry)
- _rl_replace_text(entry.line, 0, @rl_end)
- _rl_fix_point(1)
- if (@rl_editing_mode == @vi_mode)
- # POSIX.2 says that the `U' command doesn't affect the copy of any
- # command lines to the edit line. We're going to implement that by
- # making the undo list start after the matching line is copied to the
- # current editing buffer.
- rl_free_undo_list()
- end
- if (@_rl_saved_line_for_history)
- @_rl_saved_line_for_history = nil
- end
- end
-
- # Make the current history item be the one at POS, an absolute index.
- # Returns zero if POS is out of range, else non-zero.
- def history_set_pos(pos)
- if (pos > @history_length || pos < 0 || @the_history.nil?)
- return (0)
- end
- @history_offset = pos
- 1
- end
-
- # Do an anchored search for string through the history in DIRECTION.
- def history_search_prefix (string, direction)
- history_search_internal(string, direction, ANCHORED_SEARCH)
- 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.
- 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
-
- # 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.
- 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
-
- # 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.
- 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
-
- 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
-
- 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] = 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
-
- def _rl_nsearch_cleanup(cxt, r)
- cxt = nil
- @_rl_nscxt = nil
- rl_unsetstate(RL_STATE_NSEARCH)
- r != 1
- end
-
- 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
-
- # 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.
- def _rl_nsearch_dispatch(cxt, c)
- case (c)
- when "\C-W"
- rl_unix_word_rubout(1, c)
- when "\C-W"
- 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.
- 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
-
- # Transpose the words at point. If point is at the end of the line,
- # transpose the two words before point.
- 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
-
- # Re-read the current keybindings file.
- def rl_re_read_init_file(count, ignore)
- r = rl_read_init_file(nil)
- rl_set_keymap_from_edit_mode()
- r
- end
-
- # Exchange the position of mark and point.
- 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
-
- # 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.
- 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
-
- # 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).
- 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)
- 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] == ?\0 && @rl_line_buffer[@rl_point - 1] == ?/ )
-
- elsif (@rl_line_buffer[@rl_point] != ?/ )
- 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
-
- # Stifle the history list, remembering only MAX number of lines.
- 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
-
- # 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.
- def unstifle_history()
- if (@history_stifled)
- @history_stifled = false
- return (@history_max_entries)
- else
- return (-@history_max_entries)
- end
- end
-
- def history_is_stifled()
- return (@history_stifled)
- end
-
- def clear_history()
- @the_history = nil
- @history_offset = @history_length = 0
- end
-
- # Insert COUNT characters from STRING to the output stream at column COL.
- 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
-
- # Delete COUNT characters from the display line.
- 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
-
- # 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
- 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'
- pos = string.scan(/./me).inject(0){|r,x| r<point ? r += x.length : r }
- when 'S'
- pos = string.scan(/./ms).inject(0){|r,x| r<point ? r += x.length : r }
- when 'U'
- pos = string.scan(/./mu).inject(0){|r,x| r<point ? r += x.length : r }
- when 'X'
- pos = string.dup.force_encoding(@encoding_name).chars.inject(0){|r,x| r<point ? r += x.bytesize : r }
- else
- pos = point
- end
- pos - point
- 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.
- 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
-
- case @encoding
- when 'E'
- point += string[point..-1].scan(/./me)[0,count].to_s.length
- when 'S'
- point += string[point..-1].scan(/./ms)[0,count].to_s.length
- when 'U'
- point += string[point..-1].scan(/./mu)[0,count].to_s.length
- when 'X'
- point += string[point..-1].force_encoding(@encoding_name)[0,count].bytesize
- else
- point += count
- end
- if flags == MB_FIND_NONZERO
- point = string.length if point>=string.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.
- 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
-
- # compare the specified two characters. If the characters matched,
- # return true. Otherwise return false.
- 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
-
- # 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.
- def _rl_get_char_len(src)
- return 0 if src[0] == ?\0 || 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
-
- # read multibyte char
- def _rl_read_mbchar(mbchar, size)
- mb_len = 0
- while (mb_len < size)
- rl_setstate(RL_STATE_MOREINPUT)
- mbchar << rl_read_key()
- mb_len += 1
- rl_unsetstate(RL_STATE_MOREINPUT)
- 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.
- def _rl_read_mbstring(first, mb, mlen)
- c = first
- for i in 0 ... mlen
- mb << c
- if _rl_get_char_len(mb) == -2
- # Read more for multibyte character
- rl_setstate(RL_STATE_MOREINPUT)
- c = rl_read_key()
- rl_unsetstate(RL_STATE_MOREINPUT)
- else
- break
- end
- end
- c
- end
-
- 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
-
- # 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.
- 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
-
- # Redisplay the current line after a SIGWINCH is received.
- 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
-
- 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
-
- def rl_sigwinch_handler(sig)
- rl_setstate(RL_STATE_SIGHANDLER)
- rl_resize_terminal()
- rl_unsetstate(RL_STATE_SIGHANDLER)
- end
-
-
-
- module_function :rl_attempted_completion_function,:rl_deprep_term_function,
- :rl_event_hook,:rl_attempted_completion_over,:rl_basic_quote_characters,
- :rl_basic_word_break_characters,:rl_completer_quote_characters,
- :rl_completer_word_break_characters,:rl_completion_append_character,
- :rl_filename_quote_characters,:rl_instream,:rl_library_version,:rl_outstream,
- :rl_readline_name,
- :rl_attempted_completion_function=,:rl_deprep_term_function=,
- :rl_event_hook=,:rl_attempted_completion_over=,:rl_basic_quote_characters=,
- :rl_basic_word_break_characters=,:rl_completer_quote_characters=,
- :rl_completer_word_break_characters=,:rl_completion_append_character=,
- :rl_filename_quote_characters=,:rl_instream=,:rl_library_version=,:rl_outstream=,
- :rl_readline_name=,:history_length,:history_base
-
- def no_terminal?
- term = ENV["TERM"]
- term.nil? || (term == 'dumb') || (term == 'cygwin' && RUBY_PLATFORM =~ /mswin|mingw/)
- end
- private :no_terminal?
-
- end