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 270

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 525

def eof?
  @eof
end

#prompting?Boolean (readonly)

[ GitHub ]

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

def prompting?
  true
end

Instance Method Details

#auto_indent(&block)

[ GitHub ]

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

def auto_indent(&block)
  @auto_indent_proc = block
end

#check_termination(&block)

[ GitHub ]

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

def check_termination(&block)
  @check_termination_proc = block
end

#command_doc_dialog_contents(command_name, width)

[ GitHub ]

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

def command_doc_dialog_contents(command_name, width)
  command_class = IRB::Command.load_command(command_name)
  return unless command_class

  [PRESS_ALT_D_TO_READ_FULL_DOC, ""] + command_class.doc_dialog_content(command_name, width)
end

#completion_info

[ GitHub ]

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

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

#dialog_doc_position(cursor_pos_to_render, autocomplete_dialog, screen_width)

[ GitHub ]

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

def dialog_doc_position(cursor_pos_to_render, autocomplete_dialog, screen_width)
  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? && 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? && left_width <= 0
      width = right_width
      x = right_x
    elsif right_width <= 0 && left_width.positive?
      width = left_width
      x = left_x
    else
      return nil
    end
  else
    x = right_x
  end
  [x, width]
end

#display_document(matched)

[ GitHub ]

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

def display_document(matched)
  target = retrieve_document_target(matched)
  return unless target

  case target
  when CommandDocument
    command_class = IRB::Command.load_command(target.name)
    if command_class
      content = command_class.help_message || command_class.description
      Pager.page(retain_content: true) do |io|
        io.puts content
      end
    end
  when MethodDocument
    driver = rdoc_ri_driver
    return unless driver

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

    if target.names.length > 1
      out = RDoc::Markup::Document.new
      target.names.each do |m|
        begin
          driver.add_method(out, m)
        rescue RDoc::RI::Driver::NotFoundError
        end
      end
      driver.display(out)
    else
      begin
        driver.display_names([target.name])
      rescue RDoc::RI::Driver::NotFoundError
      end
    end
  end
end

#dynamic_prompt(&block)

[ GitHub ]

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

def dynamic_prompt(&block)
  @prompt_proc = block
end

#easter_egg_dialog_contents

[ GitHub ]

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

def easter_egg_dialog_contents
  type = STDOUT.external_encoding == Encoding::UTF_8 ? :unicode : :ascii
  lines = IRB.send(:, type).split("\n")
  lines[0][0, PRESS_ALT_D_TO_SEE_MORE.size] = PRESS_ALT_D_TO_SEE_MORE
  lines
end

#gets

Reads the next line from this input method.

See IO#gets for more information.

[ GitHub ]

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

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? && l != Reline::HISTORY.to_a.last
    @line[@line_no += 1] = l + "\n"
  else
    @eof = true
    l
  end
end

#inspect

For debug message

[ GitHub ]

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

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_dialog_contents(name, width)

[ GitHub ]

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

def rdoc_dialog_contents(name, width)
  driver = rdoc_ri_driver
  return unless driver

  name = driver.expand_name(name)

  doc = if name =~ /#|\./
    d = RDoc::Markup::Document.new
    driver.add_method(d, name)
    d
  else
    found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
    if found.empty?
      d = RDoc::Markup::Document.new
      driver.add_method(d, name)
      d
    else
      driver.class_document(name, found, klasses, includes, extends)
    end
  end

  formatter = RDoc::Markup::ToAnsi.new
  formatter.width = width
  [PRESS_ALT_D_TO_READ_FULL_DOC] + doc.accept(formatter).split("\n")
rescue RDoc::RI::Driver::NotFoundError
end

#rdoc_ri_driver

[ GitHub ]

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

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_document_target(matched)

[ GitHub ]

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

def retrieve_document_target(matched)
  preposing, _target, postposing, bind = @completion_params
  result = @completor.doc_namespace(preposing, matched, postposing, bind: bind)
  case result
  when DocumentTarget, nil
    result
  when Array
    MethodDocument.new(*result)
  when String
    MethodDocument.new(result)
  end
end

#show_doc_dialog_proc

[ GitHub ]

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

def show_doc_dialog_proc
  input_method = self # self is changed in the lambda below.
  ->() {
    dialog.trap_key = nil

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

    matched_text = result[pointer]
    show_easter_egg = matched_text&.match?(/\ARubyVM/) && !ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
    target = show_easter_egg ? nil : input_method.retrieve_document_target(matched_text)

    x, width = input_method.dialog_doc_position(cursor_pos_to_render, autocomplete_dialog, screen_width)
    return nil unless x

    dialog.trap_key = ALT_D_SEQUENCES

    if key.match?(dialog.name)
      begin
        print "\e[?1049h"
        input_method.display_document(matched_text)
      ensure
        print "\e[?1049l"
      end
    end

    contents = case target
    when CommandDocument
      input_method.command_doc_dialog_contents(target.name, width)
    when MethodDocument
      input_method.rdoc_dialog_contents(target.name, width)
    else
      if show_easter_egg
        input_method.easter_egg_dialog_contents
      end
    end
    return nil unless contents

    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