class Rex::Ui::Text::Input::Readline

This class implements standard input using readline against standard input. It supports tab completion.

Attributes

output[RW]

The output handle to use when displaying the prompt.

prompt[RW]

The prompt that is to be displayed.

Public Class Methods

new(tab_complete_proc = nil) click to toggle source

Initializes the readline-aware Input instance for text.

# File lib/rex/ui/text/input/readline.rb, line 20
def initialize(tab_complete_proc = nil)
  if(not Object.const_defined?('Readline'))
    require 'readline'
  end

  self.extend(::Readline)

  if (tab_complete_proc)
    ::Readline.basic_word_break_characters = "\x00"
    ::Readline.completion_proc = tab_complete_proc
    @rl_saved_proc = tab_complete_proc
  end
end

Public Instance Methods

fd() click to toggle source

Returns the output pipe handle

# File lib/rex/ui/text/input/readline.rb, line 97
def fd
  $stdin
end
gets() click to toggle source

Read a line from stdin

# File lib/rex/ui/text/input/readline.rb, line 63
def gets()
  begin
    self.fd.gets()
  rescue ::Errno::EINTR
    retry
  end
end
intrinsic_shell?() click to toggle source

Indicates that this input medium as a shell builtin, no need to extend.

# File lib/rex/ui/text/input/readline.rb, line 105
def intrinsic_shell?
  true
end
pgets() click to toggle source

Stick readline into a low-priority thread so that the scheduler doesn't slow down other background threads. This is important when there are many active background jobs, such as when the user is running Karmetasploit

# File lib/rex/ui/text/input/readline.rb, line 76
def pgets()

  line = nil
  orig = Thread.current.priority

  begin
    Thread.current.priority = -20

    output.prompting
    line = readline_with_output(prompt, true)
    ::Readline::HISTORY.pop if (line and line.empty?)
  ensure
    Thread.current.priority = orig || 0
  end

  line
end
reset_tab_completion(tab_complete_proc = nil) click to toggle source

Reattach the original completion proc

# File lib/rex/ui/text/input/readline.rb, line 37
def reset_tab_completion(tab_complete_proc = nil)
  ::Readline.basic_word_break_characters = "\x00"
  ::Readline.completion_proc = tab_complete_proc || @rl_saved_proc
end
supports_readline() click to toggle source

Whether or not the input medium supports readline.

# File lib/rex/ui/text/input/readline.rb, line 45
def supports_readline
  true
end
sysread(len = 1) click to toggle source

Calls sysread on the standard input handle.

# File lib/rex/ui/text/input/readline.rb, line 52
def sysread(len = 1)
  begin
    self.fd.sysread(len)
  rescue ::Errno::EINTR
    retry
  end
end

Private Instance Methods

readline_with_output(prompt, add_history=false) click to toggle source
# File lib/rex/ui/text/input/readline.rb, line 120
def readline_with_output(prompt, add_history=false)
  # rb-readlines's Readline.readline hardcodes the input and output to $stdin and $stdout, which means setting
  # `Readline.input` or `Readline.ouput` has no effect when running `Readline.readline` with rb-readline, so need
  # to reimplement []`Readline.readline`](https://github.com/luislavena/rb-readline/blob/ce4908dae45dbcae90a6e42e3710b8c3a1f2cd64/lib/readline.rb#L36-L58)
  # for rb-readline to support setting input and output.  Output needs to be set so that colorization works for the
  # prompt on Windows.
  if defined? RbReadline
    RbReadline.rl_instream = fd
    RbReadline.rl_outstream = output

    begin
      line = RbReadline.readline(prompt)
    rescue ::Exception => exception
      RbReadline.rl_cleanup_after_signal()
      RbReadline.rl_deprep_terminal()

      raise exception
    end

    if add_history && line
      RbReadline.add_history(line)
    end

    line.try(:dup)
  else
    ::Readline.readline(prompt, true)
  end
end