# encoding: US-ASCII # # readline.rb -- GNU Readline module # Copyright (C) 1997-2001 Shugo Maeda # # Ruby translation by Park Heesob phasis@gmail.com module Readline require 'rbreadline' include RbReadline @completion_proc = nil @completion_case_fold = false # Begins an interactive terminal process using +prompt+ as the command # prompt that users see when they type commands. The method returns the # line entered whenever a carriage return is encountered. # # If an +add_history+ argument is provided, commands entered by users are # stored in a history buffer that can be recalled for later use. # # Note that this method depends on $stdin and $stdout both being open. # Because this is meant as an interactive console interface, they should # generally not be redirected. # # If you would like to add non-visible characters to the the prompt (for # example to add colors) you must prepend the character \001 (^A) before # each sequence of non-visible characters and add the character \002 (^B) # after, otherwise line wrapping may not work properly. # # Example: # # loop{ Readline.readline('> ') } # def readline(prompt = "", add_history = nil) if $stdin.closed? raise IOError, "stdin closed" end RbReadline.rl_instream = $stdin RbReadline.rl_outstream = $stdout begin buff = RbReadline.readline(prompt) rescue Exception => e buff = nil RbReadline.rl_cleanup_after_signal() RbReadline.rl_deprep_terminal() raise e end if add_history && buff RbReadline.add_history(buff) end return buff ? buff.dup : nil end # Sets the input stream (an IO object) for readline interaction. The # default is $stdin. # def self.input=(input) RbReadline.rl_instream = input end # Sets the output stream (an IO object) for readline interaction. The # default is $stdout. # def self.output=(output) RbReadline.rl_outstream = output end # Returns current line buffer # def self.line_buffer RbReadline.rl_line_buffer end # Sets the auto-completion procedure (i.e. tab auto-complete). # # The +proc+ argument is typically a Proc object. It must respond to # .call, take a single String argument and return an Array of # candidates for completion. # # Example: # # list = ['search', 'next', 'clear'] # Readline.completion_proc = proc{ |s| list.grep( /^#{Regexp.escape(s)}/) } # def self.completion_proc=(proc) unless proc.respond_to? :call raise ArgumentError,"argument must respond to `call'" end @completion_proc = proc end # Returns the current auto-completion procedure. # def self.completion_proc() @completion_proc end # Sets whether or not the completion proc should ignore case sensitivity. # The default is false, i.e. completion procs are case sensitive. # def self.completion_case_fold=(bool) @completion_case_fold = bool end # Returns whether or not the completion proc is case sensitive. The # default is false, i.e. completion procs are case sensitive. # def self.completion_case_fold() @completion_case_fold end # Returns nil if no matches are found or an array of strings: # # [0] is the replacement for text # [1..n] the possible matches # [n+1] nil # # The possible matches should not include [0]. # # If this method sets RbReadline.rl_attempted_completion_over to true, # then the default completion function will not be called when this # function returns nil. def self.readline_attempted_completion_function(text,start,_end) proc = @completion_proc return nil if proc.nil? RbReadline.rl_attempted_completion_over = true case_fold = @completion_case_fold ary = proc.call(text) if ary.class != Array ary = Array(ary) else ary.compact! end matches = ary.length return nil if (matches == 0) result = Array.new(matches+2) for i in 0 ... matches result[i+1] = ary[i].dup end result[matches+1] = nil if(matches==1) result[0] = result[1].dup result[1] = nil else i = 1 low = 100000 while (i < matches) if (case_fold) si = 0 while ((c1 = result[i][si,1].downcase) && (c2 = result[i + 1][si,1].downcase)) break if (c1 != c2) si += 1 end else si = 0 while ((c1 = result[i][si,1]) && (c2 = result[i + 1][si,1])) break if (c1 != c2) si += 1 end end if (low > si) low = si end i+=1 end result[0] = result[1][0,low] end result end # Sets vi editing mode. # def self.vi_editing_mode() RbReadline.rl_vi_editing_mode(1,0) nil end # Sets emacs editing mode # def self.emacs_editing_mode() RbReadline.rl_emacs_editing_mode(1,0) nil end # Sets the character that is automatically appended after the # Readline.completion_proc method is called. # # If +char+ is nil or empty, then a null character is used. # def self.completion_append_character=(char) if char.nil? RbReadline.rl_completion_append_character = ?\0 elsif char.length==0 RbReadline.rl_completion_append_character = ?\0 else RbReadline.rl_completion_append_character = char[0].chr end end # Returns the character that is automatically appended after the # Readline.completion_proc method is called. # def self.completion_append_character() if RbReadline.rl_completion_append_character == ?\0 return nil end return RbReadline.rl_completion_append_character end # Sets the character string that signal a break between words for the # completion proc. # def self.basic_word_break_characters=(str) RbReadline.rl_basic_word_break_characters = str.dup end # Returns the character string that signal a break between words for the # completion proc. The default is " \t\n\"\\'`@$><=|&{(". # def self.basic_word_break_characters() if RbReadline.rl_basic_word_break_characters.nil? nil else RbReadline.rl_basic_word_break_characters.dup end end # Sets the character string that signal the start or end of a word for # the completion proc. # def self.completer_word_break_characters=(str) RbReadline.rl_completer_word_break_characters = str.dup end # Returns the character string that signal the start or end of a word for # the completion proc. # def self.completer_word_break_characters() if RbReadline.rl_completer_word_break_characters.nil? nil else RbReadline.rl_completer_word_break_characters.dup end end # Sets the list of quote characters that can cause a word break. # def self.basic_quote_characters=(str) RbReadline.rl_basic_quote_characters = str.dup end # Returns the list of quote characters that can cause a word break. # The default is "'\"" (single and double quote characters). # def self.basic_quote_characters() if RbReadline.rl_basic_quote_characters.nil? nil else RbReadline.rl_basic_quote_characters.dup end end # Sets the list of characters that can be used to quote a substring of # the line, i.e. a group of characters within quotes. # def self.completer_quote_characters=(str) RbReadline.rl_completer_quote_characters = str.dup end # Returns the list of characters that can be used to quote a substring # of the line, i.e. a group of characters inside quotes. # def self.completer_quote_characters() if RbReadline.rl_completer_quote_characters.nil? nil else RbReadline.rl_completer_quote_characters.dup end end # Sets the character string of one or more characters that indicate quotes # for the filename completion of user input. # def self.filename_quote_characters=(str) RbReadline.rl_filename_quote_characters = str.dup end # Returns the character string used to indicate quotes for the filename # completion of user input. # def self.filename_quote_characters() if RbReadline.rl_filename_quote_characters.nil? nil else RbReadline.rl_filename_quote_characters.dup end end # Returns the current offset in the current input line. # def self.point() RbReadline.rl_point end # The History class encapsulates a history of all commands entered by # users at the prompt, providing an interface for inspection and retrieval # of all commands. class History extend Enumerable # The History class, stringified in all caps. #-- # Why? # def self.to_s "HISTORY" end # Returns the command that was entered at the specified +index+ # in the history buffer. # # Raises an IndexError if the entry is nil. # def self.[](index) if index < 0 index += RbReadline.history_length end entry = RbReadline.history_get(RbReadline.history_base+index) if entry.nil? raise IndexError,"invalid index" end entry.line.dup end # Sets the command +str+ at the given index in the history buffer. # # You can only replace an existing entry. Attempting to create a new # entry will result in an IndexError. # def self.[]=(index,str) if index<0 index += RbReadline.history_length end entry = RbReadline.replace_history_entry(index,str,nil) if entry.nil? raise IndexError,"invalid index" end str end # Synonym for Readline.add_history. # def self.<<(str) RbReadline.add_history(str) end # Pushes a list of +args+ onto the history buffer. # def self.push(*args) args.each do |str| RbReadline.add_history(str) end end # Internal function that removes the item at +index+ from the history # buffer, performing necessary duplication in the process. #-- # TODO: mark private? # def self.rb_remove_history(index) entry = RbReadline.remove_history(index) if (entry) val = entry.line.dup entry = nil return val end nil end # Removes and returns the last element from the history buffer. # def self.pop() if RbReadline.history_length>0 rb_remove_history(RbReadline.history_length-1) else nil end end # Removes and returns the first element from the history buffer. # def self.shift() if RbReadline.history_length>0 rb_remove_history(0) else nil end end # Iterates over each entry in the history buffer. # def self.each() for i in 0 ... RbReadline.history_length entry = RbReadline.history_get(RbReadline.history_base + i) break if entry.nil? yield entry.line.dup end self end # Returns the length of the history buffer. # def self.length() RbReadline.history_length end # Synonym for Readline.length. # def self.size() RbReadline.history_length end # Returns a bolean value indicating whether or not the history buffer # is empty. # def self.empty?() RbReadline.history_length == 0 end # Deletes an entry from the histoyr buffer at the specified +index+. # def self.delete_at(index) if index < 0 i += RbReadline.history_length end if index < 0 || index > RbReadline.history_length - 1 raise IndexError, "invalid index" end rb_remove_history(index) end end HISTORY = History unless const_defined? :HISTORY # The Fcomp class provided to encapsulate typical filename completion # procedure. You will not typically use this directly, but will instead # use the Readline::FILENAME_COMPLETION_PROC. # class Fcomp def self.call(str) matches = RbReadline.rl_completion_matches(str, :rl_filename_completion_function) if (matches) result = [] i = 0 while(matches[i]) result << matches[i].dup matches[i] = nil i += 1 end matches = nil if (result.length >= 2) result.shift end else result = nil end return result end end FILENAME_COMPLETION_PROC = Fcomp unless const_defined? :FILENAME_COMPLETION_PROC # The Ucomp class provided to encapsulate typical filename completion # procedure. You will not typically use this directly, but will instead # use the Readline::USERNAME_COMPLETION_PROC. # # Note that this feature currently only works on Unix systems since it # ultimately uses the Etc module to iterate over a list of users. # class Ucomp def self.call(str) matches = RbReadline.rl_completion_matches(str, :rl_username_completion_function) if (matches) result = [] i = 0 while(matches[i]) result << matches[i].dup matches[i] = nil i += 1 end matches = nil if (result.length >= 2) result.shift end else result = nil end return result end end USERNAME_COMPLETION_PROC = Ucomp unless const_defined? :USERNAME_COMPLETION_PROC RbReadline.rl_readline_name = "Ruby" RbReadline.using_history() VERSION = RbReadline.rl_library_version unless const_defined? :VERSION module_function :readline RbReadline.rl_attempted_completion_function = :readline_attempted_completion_function end