123456789_123456789_123456789_123456789_123456789_

Class: IRB::RelineInputMethod

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: IRB::StdioInputMethod
Defined in: lib/irb/input-method.rb

Constant Summary

InputMethod - Inherited

BASIC_WORD_BREAK_CHARACTERS

Class Method Summary

StdioInputMethod - Inherited

.new

Creates a new input method object.

Instance Attribute Summary

HistorySavingAbility - Included

StdioInputMethod - Inherited

#eof?

Whether the end of this input method has been reached, returns true if there is no more data to read.

#prompting?,
#readable_after_eof?

Whether this input method is still readable when there is no more data to read.

InputMethod - Inherited

#prompt

The irb prompt associated with this input method.

#prompting?,
#readable_after_eof?

Whether this input method is still readable when there is no more data to read.

#support_history_saving?

Instance Method Summary

HistorySavingAbility - Included

#load_history, #reset_history_counter, #save_history,
#ensure_history_file_writable

Returns boolean whether writing to history_file will be possible.

StdioInputMethod - Inherited

#encoding

The external encoding for standard input.

#gets

Reads the next line from this input method.

#inspect

For debug message.

#line

Returns the current line number for #io.

InputMethod - Inherited

#gets

Reads the next line from this input method.

#inspect

For debug message.

#winsize

Constructor Details

.new(completor) ⇒ RelineInputMethod

Creates a new input method object using Reline

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 254

def initialize(completor)
  IRB.__send__(:set_encoding, Reline.encoding_system_needs.name, override: false)

  super()

  @eof = false
  @completor = completor

  Reline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
  Reline.completion_append_character = nil
  Reline.completer_quote_characters = ''
  Reline.completion_proc = ->(target, preposing, postposing) {
    bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
    @completion_params = [preposing, target, postposing, bind]
    @completor.completion_candidates(preposing, target, postposing, bind: bind)
  }
  Reline.output_modifier_proc = proc do |input, complete:|
    IRB.CurrentContext.colorize_input(input, complete: complete)
  end
  Reline.dig_perfect_match_proc = ->(matched) { display_document(matched) }
  Reline.autocompletion = IRB.conf[:USE_AUTOCOMPLETE]

  if IRB.conf[:USE_AUTOCOMPLETE]
    begin
      require 'rdoc'
      Reline.add_dialog_proc(:show_doc, show_doc_dialog_proc, Reline::DEFAULT_DIALOG_CONTEXT)
    rescue LoadError
    end
  end
end

Instance Attribute Details

#eof?Boolean (readonly)

Whether the end of this input method has been reached, returns true if there is no more data to read.

See IO#eof? for more information.

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 489

def eof?
  @eof
end

#prompting?Boolean (readonly)

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 493

def prompting?
  true
end

Instance Method Details

#auto_indent(&block)

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 298

def auto_indent(&block)
  @auto_indent_proc = block
end

#check_termination(&block)

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 290

def check_termination(&block)
  @check_termination_proc = block
end

#completion_info

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 285

def completion_info
  autocomplete_message = Reline.autocompletion ? 'Autocomplete' : 'Tab Complete'
  "#{autocomplete_message}, #{@completor.inspect}"
end

#display_document(matched)

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 439

def display_document(matched)
  driver = rdoc_ri_driver
  return unless driver

  if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
    IRB.__send__(:easter_egg)
    return
  end

  namespace = retrieve_doc_namespace(matched)
  return unless namespace

  if namespace.is_a?(Array)
    out = RDoc::Markup::Document.new
    namespace.each do |m|
      begin
        driver.add_method(out, m)
      rescue RDoc::RI::Driver::NotFoundError
      end
    end
    driver.display(out)
  else
    begin
      driver.display_names([namespace])
    rescue RDoc::RI::Driver::NotFoundError
    end
  end
end

#dynamic_prompt(&block)

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 294

def dynamic_prompt(&block)
  @prompt_proc = block
end

#gets

Reads the next line from this input method.

See IO#gets for more information.

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 471

def gets
  Reline.input = @stdin
  Reline.output = @stdout
  Reline.prompt_proc = @prompt_proc
  Reline.auto_indent_proc = @auto_indent_proc if @auto_indent_proc
  if l = Reline.readmultiline(@prompt, false, &@check_termination_proc)
    Reline::HISTORY.push(l) if !l.empty?
    @line[@line_no += 1] = l + "\n"
  else
    @eof = true
    l
  end
end

#inspect

For debug message

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 498

def inspect
  config = Reline::Config.new
  str = "RelineInputMethod with Reline #{Reline::VERSION}"
  inputrc_path = File.expand_path(config.inputrc_path)
  str += " and #{inputrc_path}" if File.exist?(inputrc_path)
  str
end

#rdoc_ri_driver

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 307

def rdoc_ri_driver
  return @rdoc_ri_driver if defined?(@rdoc_ri_driver)

  begin
    require 'rdoc'
  rescue LoadError
    @rdoc_ri_driver = nil
  else
    options = {}
    options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
    @rdoc_ri_driver = RDoc::RI::Driver.new(options)
  end
end

#retrieve_doc_namespace(matched)

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 302

def retrieve_doc_namespace(matched)
  preposing, _target, postposing, bind = @completion_params
  @completor.doc_namespace(preposing, matched, postposing, bind: bind)
end

#show_doc_dialog_proc

[ GitHub ]

  
# File 'lib/irb/input-method.rb', line 321

def show_doc_dialog_proc
  input_method = self # self is changed in the lambda below.
  ->() {
    dialog.trap_key = nil
    alt_d = [
      [27, 100], # Normal Alt+d when convert-meta isn't used.
      # When option/alt is not configured as a meta key in terminal emulator,
      # option/alt + d will send a unicode character depend on OS keyboard setting.
      [195, 164], # "ä" in somewhere (FIXME: environment information is unknown).
      [226, 136, 130] # "∂" Alt+d on Mac keyboard.
    ]

    if just_cursor_moving and completion_journey_data.nil?
      return nil
    end
    cursor_pos_to_render, result, pointer, autocomplete_dialog = context.pop(4)
    return nil if result.nil? or pointer.nil? or pointer < 0

    name = input_method.retrieve_doc_namespace(result[pointer])
    # Use first one because document dialog does not support multiple namespaces.
    name = name.first if name.is_a?(Array)

    show_easter_egg = name&.match?(/\ARubyVM/) && !ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']

    driver = input_method.rdoc_ri_driver

    if key.match?(dialog.name)
      if show_easter_egg
        IRB.__send__(:easter_egg)
      else
        # RDoc::RI::Driver#display_names uses pager command internally.
        # Some pager command like `more` doesn't use alternate screen
        # so we need to turn on and off alternate screen manually.
        begin
          print "\e[?1049h"
          driver.display_names([name])
        rescue RDoc::RI::Driver::NotFoundError
        ensure
          print "\e[?1049l"
        end
      end
    end

    begin
      name = driver.expand_name(name)
    rescue RDoc::RI::Driver::NotFoundError
      return nil
    rescue
      return nil # unknown error
    end
    doc = nil
    used_for_class = false
    if not name =~ /#|\./
      found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
      if not found.empty?
        doc = driver.class_document(name, found, klasses, includes, extends)
        used_for_class = true
      end
    end
    unless used_for_class
      doc = RDoc::Markup::Document.new
      begin
        driver.add_method(doc, name)
      rescue RDoc::RI::Driver::NotFoundError
        doc = nil
      rescue
        return nil # unknown error
      end
    end
    return nil if doc.nil?
    width = 40

    right_x = cursor_pos_to_render.x + autocomplete_dialog.width
    if right_x + width > screen_width
      right_width = screen_width - (right_x + 1)
      left_x = autocomplete_dialog.column - width
      left_x = 0 if left_x < 0
      left_width = width > autocomplete_dialog.column ? autocomplete_dialog.column : width
      if right_width.positive? and left_width.positive?
        if right_width >= left_width
          width = right_width
          x = right_x
        else
          width = left_width
          x = left_x
        end
      elsif right_width.positive? and left_width <= 0
        width = right_width
        x = right_x
      elsif right_width <= 0 and left_width.positive?
        width = left_width
        x = left_x
      else # Both are negative width.
        return nil
      end
    else
      x = right_x
    end
    formatter = RDoc::Markup::ToAnsi.new
    formatter.width = width
    dialog.trap_key = alt_d
    mod_key = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt"
    if show_easter_egg
      type = STDOUT.external_encoding == Encoding::UTF_8 ? :unicode : :ascii
      contents = IRB.send(:, type).split("\n")
      message = "Press #{mod_key}+d to see more"
      contents[0][0, message.size] = message
    else
      message = "Press #{mod_key}+d to read the full document"
      contents = [message] + doc.accept(formatter).split("\n")
    end
    contents = contents.take(preferred_dialog_height)

    y = cursor_pos_to_render.y
    Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
  }
end