[ruby/irb] Rename current completor to RegexpCompletor and
refactored for future extension (https://github.com/ruby/irb/pull/707) * Move completion implementation to completion/regexp_completor for future extension * Remove constant CompletionProc and PerfectMatchedProc and add a class method * Move document display logic to InputCompletor. Each completor only need to implement `completion_caididates` and `doc_namespace` * Move display_document logic to RelineInputMethod * Use RegexpCompletor directly. Not through class method of InputCompletor. * RegexpCompletor extends BaseCompletor, move back definition to completion.rb * Move display_document test to input_method test * Stop re-initialize completor on each completion phase * Store completor to ReadlineInputMethod's iver https://github.com/ruby/irb/commit/1e98521483
This commit is contained in:
parent
b9a6fca67d
commit
94cb5765e2
@ -8,7 +8,68 @@
|
|||||||
require_relative 'ruby-lex'
|
require_relative 'ruby-lex'
|
||||||
|
|
||||||
module IRB
|
module IRB
|
||||||
module InputCompletor # :nodoc:
|
class BaseCompletor # :nodoc:
|
||||||
|
def completion_candidates(preposing, target, postposing, bind:)
|
||||||
|
raise NotImplementedError
|
||||||
|
end
|
||||||
|
|
||||||
|
def doc_namespace(preposing, matched, postposing, bind:)
|
||||||
|
raise NotImplementedError
|
||||||
|
end
|
||||||
|
|
||||||
|
GEM_PATHS =
|
||||||
|
if defined?(Gem::Specification)
|
||||||
|
Gem::Specification.latest_specs(true).map { |s|
|
||||||
|
s.require_paths.map { |p|
|
||||||
|
if File.absolute_path?(p)
|
||||||
|
p
|
||||||
|
else
|
||||||
|
File.join(s.full_gem_path, p)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}.flatten
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end.freeze
|
||||||
|
|
||||||
|
def retrieve_gem_and_system_load_path
|
||||||
|
candidates = (GEM_PATHS | $LOAD_PATH)
|
||||||
|
candidates.map do |p|
|
||||||
|
if p.respond_to?(:to_path)
|
||||||
|
p.to_path
|
||||||
|
else
|
||||||
|
String(p) rescue nil
|
||||||
|
end
|
||||||
|
end.compact.sort
|
||||||
|
end
|
||||||
|
|
||||||
|
def retrieve_files_to_require_from_load_path
|
||||||
|
@files_from_load_path ||=
|
||||||
|
(
|
||||||
|
shortest = []
|
||||||
|
rest = retrieve_gem_and_system_load_path.each_with_object([]) { |path, result|
|
||||||
|
begin
|
||||||
|
names = Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: path)
|
||||||
|
rescue Errno::ENOENT
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
next if names.empty?
|
||||||
|
names.map! { |n| n.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '') }.sort!
|
||||||
|
shortest << names.shift
|
||||||
|
result.concat(names)
|
||||||
|
}
|
||||||
|
shortest.sort! | rest
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def retrieve_files_to_require_relative_from_current_dir
|
||||||
|
@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
|
||||||
|
path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class RegexpCompletor < BaseCompletor # :nodoc:
|
||||||
using Module.new {
|
using Module.new {
|
||||||
refine ::Binding do
|
refine ::Binding do
|
||||||
def eval_methods
|
def eval_methods
|
||||||
@ -56,60 +117,7 @@ module IRB
|
|||||||
yield
|
yield
|
||||||
]
|
]
|
||||||
|
|
||||||
BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
|
def complete_require_path(target, preposing, postposing)
|
||||||
|
|
||||||
GEM_PATHS =
|
|
||||||
if defined?(Gem::Specification)
|
|
||||||
Gem::Specification.latest_specs(true).map { |s|
|
|
||||||
s.require_paths.map { |p|
|
|
||||||
if File.absolute_path?(p)
|
|
||||||
p
|
|
||||||
else
|
|
||||||
File.join(s.full_gem_path, p)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}.flatten
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end.freeze
|
|
||||||
|
|
||||||
def self.retrieve_gem_and_system_load_path
|
|
||||||
candidates = (GEM_PATHS | $LOAD_PATH)
|
|
||||||
candidates.map do |p|
|
|
||||||
if p.respond_to?(:to_path)
|
|
||||||
p.to_path
|
|
||||||
else
|
|
||||||
String(p) rescue nil
|
|
||||||
end
|
|
||||||
end.compact.sort
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.retrieve_files_to_require_from_load_path
|
|
||||||
@@files_from_load_path ||=
|
|
||||||
(
|
|
||||||
shortest = []
|
|
||||||
rest = retrieve_gem_and_system_load_path.each_with_object([]) { |path, result|
|
|
||||||
begin
|
|
||||||
names = Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: path)
|
|
||||||
rescue Errno::ENOENT
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
next if names.empty?
|
|
||||||
names.map! { |n| n.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '') }.sort!
|
|
||||||
shortest << names.shift
|
|
||||||
result.concat(names)
|
|
||||||
}
|
|
||||||
shortest.sort! | rest
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.retrieve_files_to_require_relative_from_current_dir
|
|
||||||
@@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
|
|
||||||
path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
CompletionRequireProc = lambda { |target, preposing = nil, postposing = nil|
|
|
||||||
if target =~ /\A(['"])([^'"]+)\Z/
|
if target =~ /\A(['"])([^'"]+)\Z/
|
||||||
quote = $1
|
quote = $1
|
||||||
actual_target = $2
|
actual_target = $2
|
||||||
@ -142,21 +150,21 @@ module IRB
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
result
|
result
|
||||||
}
|
end
|
||||||
|
|
||||||
CompletionProc = lambda { |target, preposing = nil, postposing = nil|
|
def completion_candidates(preposing, target, postposing, bind:)
|
||||||
if preposing && postposing
|
if preposing && postposing
|
||||||
result = CompletionRequireProc.(target, preposing, postposing)
|
result = complete_require_path(target, preposing, postposing)
|
||||||
unless result
|
return result if result
|
||||||
result = retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
|
|
||||||
end
|
|
||||||
result
|
|
||||||
else
|
|
||||||
retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
|
|
||||||
end
|
end
|
||||||
}
|
retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
|
||||||
|
end
|
||||||
|
|
||||||
def self.retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
|
def doc_namespace(_preposing, matched, _postposing, bind:)
|
||||||
|
retrieve_completion_data(matched, bind: bind, doc_namespace: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def retrieve_completion_data(input, bind:, doc_namespace:)
|
||||||
case input
|
case input
|
||||||
# this regexp only matches the closing character because of irb's Reline.completer_quote_characters setting
|
# this regexp only matches the closing character because of irb's Reline.completer_quote_characters setting
|
||||||
# details are described in: https://github.com/ruby/irb/pull/523
|
# details are described in: https://github.com/ruby/irb/pull/523
|
||||||
@ -394,44 +402,10 @@ module IRB
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
PerfectMatchedProc = ->(matched, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding) {
|
|
||||||
begin
|
|
||||||
require 'rdoc'
|
|
||||||
rescue LoadError
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
RDocRIDriver ||= RDoc::RI::Driver.new
|
|
||||||
|
|
||||||
if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
|
|
||||||
IRB.__send__(:easter_egg)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
namespace = retrieve_completion_data(matched, bind: bind, doc_namespace: true)
|
|
||||||
return unless namespace
|
|
||||||
|
|
||||||
if namespace.is_a?(Array)
|
|
||||||
out = RDoc::Markup::Document.new
|
|
||||||
namespace.each do |m|
|
|
||||||
begin
|
|
||||||
RDocRIDriver.add_method(out, m)
|
|
||||||
rescue RDoc::RI::Driver::NotFoundError
|
|
||||||
end
|
|
||||||
end
|
|
||||||
RDocRIDriver.display(out)
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
RDocRIDriver.display_names([namespace])
|
|
||||||
rescue RDoc::RI::Driver::NotFoundError
|
|
||||||
end
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set of available operators in Ruby
|
# Set of available operators in Ruby
|
||||||
Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~]
|
Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~]
|
||||||
|
|
||||||
def self.select_message(receiver, message, candidates, sep = ".")
|
def select_message(receiver, message, candidates, sep = ".")
|
||||||
candidates.grep(/^#{Regexp.quote(message)}/).collect do |e|
|
candidates.grep(/^#{Regexp.quote(message)}/).collect do |e|
|
||||||
case e
|
case e
|
||||||
when /^[a-zA-Z_]/
|
when /^[a-zA-Z_]/
|
||||||
|
@ -11,6 +11,8 @@ require 'reline'
|
|||||||
|
|
||||||
module IRB
|
module IRB
|
||||||
class InputMethod
|
class InputMethod
|
||||||
|
BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
|
||||||
|
|
||||||
# The irb prompt associated with this input method
|
# The irb prompt associated with this input method
|
||||||
attr_accessor :prompt
|
attr_accessor :prompt
|
||||||
|
|
||||||
@ -179,12 +181,16 @@ module IRB
|
|||||||
super
|
super
|
||||||
|
|
||||||
@eof = false
|
@eof = false
|
||||||
|
@completor = RegexpCompletor.new
|
||||||
|
|
||||||
if Readline.respond_to?("basic_word_break_characters=")
|
if Readline.respond_to?("basic_word_break_characters=")
|
||||||
Readline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS
|
Readline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
|
||||||
end
|
end
|
||||||
Readline.completion_append_character = nil
|
Readline.completion_append_character = nil
|
||||||
Readline.completion_proc = IRB::InputCompletor::CompletionProc
|
Readline.completion_proc = ->(target) {
|
||||||
|
bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
|
||||||
|
@completor.completion_candidates('', target, '', bind: bind)
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Reads the next line from this input method.
|
# Reads the next line from this input method.
|
||||||
@ -230,11 +236,16 @@ module IRB
|
|||||||
super
|
super
|
||||||
|
|
||||||
@eof = false
|
@eof = false
|
||||||
|
@completor = RegexpCompletor.new
|
||||||
|
|
||||||
Reline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS
|
Reline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
|
||||||
Reline.completion_append_character = nil
|
Reline.completion_append_character = nil
|
||||||
Reline.completer_quote_characters = ''
|
Reline.completer_quote_characters = ''
|
||||||
Reline.completion_proc = IRB::InputCompletor::CompletionProc
|
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 =
|
Reline.output_modifier_proc =
|
||||||
if IRB.conf[:USE_COLORIZE]
|
if IRB.conf[:USE_COLORIZE]
|
||||||
proc do |output, complete: |
|
proc do |output, complete: |
|
||||||
@ -247,13 +258,13 @@ module IRB
|
|||||||
Reline::Unicode.escape_for_print(output)
|
Reline::Unicode.escape_for_print(output)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Reline.dig_perfect_match_proc = IRB::InputCompletor::PerfectMatchedProc
|
Reline.dig_perfect_match_proc = ->(matched) { display_document(matched) }
|
||||||
Reline.autocompletion = IRB.conf[:USE_AUTOCOMPLETE]
|
Reline.autocompletion = IRB.conf[:USE_AUTOCOMPLETE]
|
||||||
|
|
||||||
if IRB.conf[:USE_AUTOCOMPLETE]
|
if IRB.conf[:USE_AUTOCOMPLETE]
|
||||||
begin
|
begin
|
||||||
require 'rdoc'
|
require 'rdoc'
|
||||||
Reline.add_dialog_proc(:show_doc, SHOW_DOC_DIALOG, Reline::DEFAULT_DIALOG_CONTEXT)
|
Reline.add_dialog_proc(:show_doc, show_doc_dialog_proc, Reline::DEFAULT_DIALOG_CONTEXT)
|
||||||
rescue LoadError
|
rescue LoadError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -271,100 +282,140 @@ module IRB
|
|||||||
@auto_indent_proc = block
|
@auto_indent_proc = block
|
||||||
end
|
end
|
||||||
|
|
||||||
SHOW_DOC_DIALOG = ->() {
|
def show_doc_dialog_proc
|
||||||
dialog.trap_key = nil
|
doc_namespace = ->(matched) {
|
||||||
alt_d = [
|
preposing, _target, postposing, bind = @completion_params
|
||||||
[Reline::Key.new(nil, 0xE4, true)], # Normal Alt+d.
|
@completor.doc_namespace(preposing, matched, postposing, bind: bind)
|
||||||
[27, 100], # Normal Alt+d when convert-meta isn't used.
|
}
|
||||||
[195, 164], # The "ä" that appears when Alt+d is pressed on xterm.
|
->() {
|
||||||
[226, 136, 130] # The "∂" that appears when Alt+d in pressed on iTerm2.
|
dialog.trap_key = nil
|
||||||
]
|
alt_d = [
|
||||||
|
[Reline::Key.new(nil, 0xE4, true)], # Normal Alt+d.
|
||||||
|
[27, 100], # Normal Alt+d when convert-meta isn't used.
|
||||||
|
[195, 164], # The "ä" that appears when Alt+d is pressed on xterm.
|
||||||
|
[226, 136, 130] # The "∂" that appears when Alt+d in pressed on iTerm2.
|
||||||
|
]
|
||||||
|
|
||||||
if just_cursor_moving and completion_journey_data.nil?
|
if just_cursor_moving and completion_journey_data.nil?
|
||||||
return 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 = result[pointer]
|
|
||||||
name = IRB::InputCompletor.retrieve_completion_data(name, doc_namespace: true)
|
|
||||||
|
|
||||||
options = {}
|
|
||||||
options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
|
|
||||||
driver = RDoc::RI::Driver.new(options)
|
|
||||||
|
|
||||||
if key.match?(dialog.name)
|
|
||||||
begin
|
|
||||||
driver.display_names([name])
|
|
||||||
rescue RDoc::RI::Driver::NotFoundError
|
|
||||||
end
|
end
|
||||||
end
|
cursor_pos_to_render, result, pointer, autocomplete_dialog = context.pop(4)
|
||||||
|
return nil if result.nil? or pointer.nil? or pointer < 0
|
||||||
|
|
||||||
begin
|
name = doc_namespace.call(result[pointer])
|
||||||
name = driver.expand_name(name)
|
|
||||||
rescue RDoc::RI::Driver::NotFoundError
|
options = {}
|
||||||
return nil
|
options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
|
||||||
rescue
|
driver = RDoc::RI::Driver.new(options)
|
||||||
return nil # unknown error
|
|
||||||
end
|
if key.match?(dialog.name)
|
||||||
doc = nil
|
begin
|
||||||
used_for_class = false
|
driver.display_names([name])
|
||||||
if not name =~ /#|\./
|
rescue RDoc::RI::Driver::NotFoundError
|
||||||
found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
|
end
|
||||||
if not found.empty?
|
|
||||||
doc = driver.class_document(name, found, klasses, includes, extends)
|
|
||||||
used_for_class = true
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
unless used_for_class
|
|
||||||
doc = RDoc::Markup::Document.new
|
|
||||||
begin
|
begin
|
||||||
driver.add_method(doc, name)
|
name = driver.expand_name(name)
|
||||||
rescue RDoc::RI::Driver::NotFoundError
|
rescue RDoc::RI::Driver::NotFoundError
|
||||||
doc = nil
|
return nil
|
||||||
rescue
|
rescue
|
||||||
return nil # unknown error
|
return nil # unknown error
|
||||||
end
|
end
|
||||||
end
|
doc = nil
|
||||||
return nil if doc.nil?
|
used_for_class = false
|
||||||
width = 40
|
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
|
right_x = cursor_pos_to_render.x + autocomplete_dialog.width
|
||||||
if right_x + width > screen_width
|
if right_x + width > screen_width
|
||||||
right_width = screen_width - (right_x + 1)
|
right_width = screen_width - (right_x + 1)
|
||||||
left_x = autocomplete_dialog.column - width
|
left_x = autocomplete_dialog.column - width
|
||||||
left_x = 0 if left_x < 0
|
left_x = 0 if left_x < 0
|
||||||
left_width = width > autocomplete_dialog.column ? autocomplete_dialog.column : width
|
left_width = width > autocomplete_dialog.column ? autocomplete_dialog.column : width
|
||||||
if right_width.positive? and left_width.positive?
|
if right_width.positive? and left_width.positive?
|
||||||
if right_width >= left_width
|
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
|
width = right_width
|
||||||
x = right_x
|
x = right_x
|
||||||
else
|
elsif right_width <= 0 and left_width.positive?
|
||||||
width = left_width
|
width = left_width
|
||||||
x = left_x
|
x = left_x
|
||||||
|
else # Both are negative width.
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
elsif right_width.positive? and left_width <= 0
|
else
|
||||||
width = right_width
|
|
||||||
x = right_x
|
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
|
end
|
||||||
else
|
formatter = RDoc::Markup::ToAnsi.new
|
||||||
x = right_x
|
formatter.width = width
|
||||||
end
|
dialog.trap_key = alt_d
|
||||||
formatter = RDoc::Markup::ToAnsi.new
|
mod_key = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt"
|
||||||
formatter.width = width
|
message = "Press #{mod_key}+d to read the full document"
|
||||||
dialog.trap_key = alt_d
|
contents = [message] + doc.accept(formatter).split("\n")
|
||||||
mod_key = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt"
|
contents = contents.take(preferred_dialog_height)
|
||||||
message = "Press #{mod_key}+d to read the full document"
|
|
||||||
contents = [message] + doc.accept(formatter).split("\n")
|
|
||||||
contents = contents.take(preferred_dialog_height)
|
|
||||||
|
|
||||||
y = cursor_pos_to_render.y
|
y = cursor_pos_to_render.y
|
||||||
Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
|
Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
|
||||||
}
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def display_document(matched, driver: nil)
|
||||||
|
begin
|
||||||
|
require 'rdoc'
|
||||||
|
rescue LoadError
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
|
||||||
|
IRB.__send__(:easter_egg)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
_target, preposing, postposing, bind = @completion_params
|
||||||
|
namespace = @completor.doc_namespace(preposing, matched, postposing, bind: bind)
|
||||||
|
return unless namespace
|
||||||
|
|
||||||
|
driver ||= RDoc::RI::Driver.new
|
||||||
|
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
|
||||||
|
|
||||||
# Reads the next line from this input method.
|
# Reads the next line from this input method.
|
||||||
#
|
#
|
||||||
|
@ -8,71 +8,83 @@ module TestIRB
|
|||||||
class CompletionTest < TestCase
|
class CompletionTest < TestCase
|
||||||
def setup
|
def setup
|
||||||
# make sure require completion candidates are not cached
|
# make sure require completion candidates are not cached
|
||||||
IRB::InputCompletor.class_variable_set(:@@files_from_load_path, nil)
|
IRB::BaseCompletor.class_variable_set(:@@files_from_load_path, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
IRB.conf[:MAIN_CONTEXT] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def completion_candidates(target, bind)
|
||||||
|
IRB::RegexpCompletor.new.completion_candidates('', target, '', bind: bind)
|
||||||
|
end
|
||||||
|
|
||||||
|
def doc_namespace(target, bind)
|
||||||
|
IRB::RegexpCompletor.new.doc_namespace('', target, '', bind: bind)
|
||||||
end
|
end
|
||||||
|
|
||||||
class MethodCompletionTest < CompletionTest
|
class MethodCompletionTest < CompletionTest
|
||||||
def test_complete_string
|
def test_complete_string
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("'foo'.up", bind: binding), "'foo'.upcase")
|
assert_include(completion_candidates("'foo'.up", binding), "'foo'.upcase")
|
||||||
# completing 'foo bar'.up
|
# completing 'foo bar'.up
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("bar'.up", bind: binding), "bar'.upcase")
|
assert_include(completion_candidates("bar'.up", binding), "bar'.upcase")
|
||||||
assert_equal("String.upcase", IRB::InputCompletor.retrieve_completion_data("'foo'.upcase", bind: binding, doc_namespace: true))
|
assert_equal("String.upcase", doc_namespace("'foo'.upcase", binding))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_regexp
|
def test_complete_regexp
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("/foo/.ma", bind: binding), "/foo/.match")
|
assert_include(completion_candidates("/foo/.ma", binding), "/foo/.match")
|
||||||
# completing /foo bar/.ma
|
# completing /foo bar/.ma
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("bar/.ma", bind: binding), "bar/.match")
|
assert_include(completion_candidates("bar/.ma", binding), "bar/.match")
|
||||||
assert_equal("Regexp.match", IRB::InputCompletor.retrieve_completion_data("/foo/.match", bind: binding, doc_namespace: true))
|
assert_equal("Regexp.match", doc_namespace("/foo/.match", binding))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_array
|
def test_complete_array
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("[].an", bind: binding), "[].any?")
|
assert_include(completion_candidates("[].an", binding), "[].any?")
|
||||||
assert_equal("Array.any?", IRB::InputCompletor.retrieve_completion_data("[].any?", bind: binding, doc_namespace: true))
|
assert_equal("Array.any?", doc_namespace("[].any?", binding))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_hash_and_proc
|
def test_complete_hash_and_proc
|
||||||
# hash
|
# hash
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("{}.an", bind: binding), "{}.any?")
|
assert_include(completion_candidates("{}.an", binding), "{}.any?")
|
||||||
assert_equal(["Proc.any?", "Hash.any?"], IRB::InputCompletor.retrieve_completion_data("{}.any?", bind: binding, doc_namespace: true))
|
assert_equal(["Proc.any?", "Hash.any?"], doc_namespace("{}.any?", binding))
|
||||||
|
|
||||||
# proc
|
# proc
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("{}.bin", bind: binding), "{}.binding")
|
assert_include(completion_candidates("{}.bin", binding), "{}.binding")
|
||||||
assert_equal(["Proc.binding", "Hash.binding"], IRB::InputCompletor.retrieve_completion_data("{}.binding", bind: binding, doc_namespace: true))
|
assert_equal(["Proc.binding", "Hash.binding"], doc_namespace("{}.binding", binding))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_numeric
|
def test_complete_numeric
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("1.positi", bind: binding), "1.positive?")
|
assert_include(completion_candidates("1.positi", binding), "1.positive?")
|
||||||
assert_equal("Integer.positive?", IRB::InputCompletor.retrieve_completion_data("1.positive?", bind: binding, doc_namespace: true))
|
assert_equal("Integer.positive?", doc_namespace("1.positive?", binding))
|
||||||
|
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("1r.positi", bind: binding), "1r.positive?")
|
assert_include(completion_candidates("1r.positi", binding), "1r.positive?")
|
||||||
assert_equal("Rational.positive?", IRB::InputCompletor.retrieve_completion_data("1r.positive?", bind: binding, doc_namespace: true))
|
assert_equal("Rational.positive?", doc_namespace("1r.positive?", binding))
|
||||||
|
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("0xFFFF.positi", bind: binding), "0xFFFF.positive?")
|
assert_include(completion_candidates("0xFFFF.positi", binding), "0xFFFF.positive?")
|
||||||
assert_equal("Integer.positive?", IRB::InputCompletor.retrieve_completion_data("0xFFFF.positive?", bind: binding, doc_namespace: true))
|
assert_equal("Integer.positive?", doc_namespace("0xFFFF.positive?", binding))
|
||||||
|
|
||||||
assert_empty(IRB::InputCompletor.retrieve_completion_data("1i.positi", bind: binding))
|
assert_empty(completion_candidates("1i.positi", binding))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_symbol
|
def test_complete_symbol
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data(":foo.to_p", bind: binding), ":foo.to_proc")
|
assert_include(completion_candidates(":foo.to_p", binding), ":foo.to_proc")
|
||||||
assert_equal("Symbol.to_proc", IRB::InputCompletor.retrieve_completion_data(":foo.to_proc", bind: binding, doc_namespace: true))
|
assert_equal("Symbol.to_proc", doc_namespace(":foo.to_proc", binding))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_class
|
def test_complete_class
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("String.ne", bind: binding), "String.new")
|
assert_include(completion_candidates("String.ne", binding), "String.new")
|
||||||
assert_equal("String.new", IRB::InputCompletor.retrieve_completion_data("String.new", bind: binding, doc_namespace: true))
|
assert_equal("String.new", doc_namespace("String.new", binding))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class RequireComepletionTest < CompletionTest
|
class RequireComepletionTest < CompletionTest
|
||||||
def test_complete_require
|
def test_complete_require
|
||||||
candidates = IRB::InputCompletor::CompletionProc.("'irb", "require ", "")
|
candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'irb", "", bind: binding)
|
||||||
%w['irb/init 'irb/ruby-lex].each do |word|
|
%w['irb/init 'irb/ruby-lex].each do |word|
|
||||||
assert_include candidates, word
|
assert_include candidates, word
|
||||||
end
|
end
|
||||||
# Test cache
|
# Test cache
|
||||||
candidates = IRB::InputCompletor::CompletionProc.("'irb", "require ", "")
|
candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'irb", "", bind: binding)
|
||||||
%w['irb/init 'irb/ruby-lex].each do |word|
|
%w['irb/init 'irb/ruby-lex].each do |word|
|
||||||
assert_include candidates, word
|
assert_include candidates, word
|
||||||
end
|
end
|
||||||
@ -84,7 +96,7 @@ module TestIRB
|
|||||||
test_path = Pathname.new(temp_dir)
|
test_path = Pathname.new(temp_dir)
|
||||||
$LOAD_PATH << test_path
|
$LOAD_PATH << test_path
|
||||||
|
|
||||||
candidates = IRB::InputCompletor::CompletionProc.("'foo", "require ", "")
|
candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding)
|
||||||
assert_include candidates, "'foo"
|
assert_include candidates, "'foo"
|
||||||
ensure
|
ensure
|
||||||
$LOAD_PATH.pop if test_path
|
$LOAD_PATH.pop if test_path
|
||||||
@ -98,7 +110,7 @@ module TestIRB
|
|||||||
object.define_singleton_method(:to_s) { temp_dir }
|
object.define_singleton_method(:to_s) { temp_dir }
|
||||||
$LOAD_PATH << object
|
$LOAD_PATH << object
|
||||||
|
|
||||||
candidates = IRB::InputCompletor::CompletionProc.("'foo", "require ", "")
|
candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding)
|
||||||
assert_include candidates, "'foo"
|
assert_include candidates, "'foo"
|
||||||
ensure
|
ensure
|
||||||
$LOAD_PATH.pop if object
|
$LOAD_PATH.pop if object
|
||||||
@ -111,27 +123,27 @@ module TestIRB
|
|||||||
$LOAD_PATH << object
|
$LOAD_PATH << object
|
||||||
|
|
||||||
assert_nothing_raised do
|
assert_nothing_raised do
|
||||||
IRB::InputCompletor::CompletionProc.("'foo", "require ", "")
|
IRB::RegexpCompletor.new.completion_candidates("require ", "'foo", "", bind: binding)
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
$LOAD_PATH.pop if object
|
$LOAD_PATH.pop if object
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_require_library_name_first
|
def test_complete_require_library_name_first
|
||||||
candidates = IRB::InputCompletor::CompletionProc.("'csv", "require ", "")
|
candidates = IRB::RegexpCompletor.new.completion_candidates("require ", "'csv", "", bind: binding)
|
||||||
assert_equal "'csv", candidates.first
|
assert_equal "'csv", candidates.first
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_require_relative
|
def test_complete_require_relative
|
||||||
candidates = Dir.chdir(__dir__ + "/../..") do
|
candidates = Dir.chdir(__dir__ + "/../..") do
|
||||||
IRB::InputCompletor::CompletionProc.("'lib/irb", "require_relative ", "")
|
IRB::RegexpCompletor.new.completion_candidates("require_relative ", "'lib/irb", "", bind: binding)
|
||||||
end
|
end
|
||||||
%w['lib/irb/init 'lib/irb/ruby-lex].each do |word|
|
%w['lib/irb/init 'lib/irb/ruby-lex].each do |word|
|
||||||
assert_include candidates, word
|
assert_include candidates, word
|
||||||
end
|
end
|
||||||
# Test cache
|
# Test cache
|
||||||
candidates = Dir.chdir(__dir__ + "/../..") do
|
candidates = Dir.chdir(__dir__ + "/../..") do
|
||||||
IRB::InputCompletor::CompletionProc.("'lib/irb", "require_relative ", "")
|
IRB::RegexpCompletor.new.completion_candidates("require_relative ", "'lib/irb", "", bind: binding)
|
||||||
end
|
end
|
||||||
%w['lib/irb/init 'lib/irb/ruby-lex].each do |word|
|
%w['lib/irb/init 'lib/irb/ruby-lex].each do |word|
|
||||||
assert_include candidates, word
|
assert_include candidates, word
|
||||||
@ -160,13 +172,13 @@ module TestIRB
|
|||||||
local_variables.clear
|
local_variables.clear
|
||||||
instance_variables.clear
|
instance_variables.clear
|
||||||
|
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("str_examp", bind: binding), "str_example")
|
assert_include(completion_candidates("str_examp", binding), "str_example")
|
||||||
assert_equal("String", IRB::InputCompletor.retrieve_completion_data("str_example", bind: binding, doc_namespace: true))
|
assert_equal("String", doc_namespace("str_example", binding))
|
||||||
assert_equal("String.to_s", IRB::InputCompletor.retrieve_completion_data("str_example.to_s", bind: binding, doc_namespace: true))
|
assert_equal("String.to_s", doc_namespace("str_example.to_s", binding))
|
||||||
|
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("@str_examp", bind: binding), "@str_example")
|
assert_include(completion_candidates("@str_examp", binding), "@str_example")
|
||||||
assert_equal("String", IRB::InputCompletor.retrieve_completion_data("@str_example", bind: binding, doc_namespace: true))
|
assert_equal("String", doc_namespace("@str_example", binding))
|
||||||
assert_equal("String.to_s", IRB::InputCompletor.retrieve_completion_data("@str_example.to_s", bind: binding, doc_namespace: true))
|
assert_equal("String.to_s", doc_namespace("@str_example.to_s", binding))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_sort_variables
|
def test_complete_sort_variables
|
||||||
@ -176,7 +188,7 @@ module TestIRB
|
|||||||
xzy_1.clear
|
xzy_1.clear
|
||||||
xzy2.clear
|
xzy2.clear
|
||||||
|
|
||||||
candidates = IRB::InputCompletor.retrieve_completion_data("xz", bind: binding, doc_namespace: false)
|
candidates = completion_candidates("xz", binding)
|
||||||
assert_equal(%w[xzy xzy2 xzy_1], candidates)
|
assert_equal(%w[xzy xzy2 xzy_1], candidates)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -189,102 +201,12 @@ module TestIRB
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_constants
|
def test_complete_constants
|
||||||
assert_equal(["Foo"], IRB::InputCompletor.retrieve_completion_data("Fo", bind: binding))
|
assert_equal(["Foo"], completion_candidates("Fo", binding))
|
||||||
assert_equal(["Foo::B1", "Foo::B2", "Foo::B3"], IRB::InputCompletor.retrieve_completion_data("Foo::B", bind: binding))
|
assert_equal(["Foo::B1", "Foo::B2", "Foo::B3"], completion_candidates("Foo::B", binding))
|
||||||
assert_equal(["Foo::B1.positive?"], IRB::InputCompletor.retrieve_completion_data("Foo::B1.pos", bind: binding))
|
assert_equal(["Foo::B1.positive?"], completion_candidates("Foo::B1.pos", binding))
|
||||||
|
|
||||||
assert_equal(["::Forwardable"], IRB::InputCompletor.retrieve_completion_data("::Fo", bind: binding))
|
assert_equal(["::Forwardable"], completion_candidates("::Fo", binding))
|
||||||
assert_equal("Forwardable", IRB::InputCompletor.retrieve_completion_data("::Forwardable", bind: binding, doc_namespace: true))
|
assert_equal("Forwardable", doc_namespace("::Forwardable", binding))
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class PerfectMatchingTest < CompletionTest
|
|
||||||
def setup
|
|
||||||
# trigger PerfectMatchedProc to set up RDocRIDriver constant
|
|
||||||
IRB::InputCompletor::PerfectMatchedProc.("foo", bind: binding)
|
|
||||||
|
|
||||||
@original_use_stdout = IRB::InputCompletor::RDocRIDriver.use_stdout
|
|
||||||
# force the driver to use stdout so it doesn't start a pager and interrupt tests
|
|
||||||
IRB::InputCompletor::RDocRIDriver.use_stdout = true
|
|
||||||
end
|
|
||||||
|
|
||||||
def teardown
|
|
||||||
IRB::InputCompletor::RDocRIDriver.use_stdout = @original_use_stdout
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_perfectly_matched_namespace_triggers_document_display
|
|
||||||
omit unless has_rdoc_content?
|
|
||||||
|
|
||||||
out, err = capture_output do
|
|
||||||
IRB::InputCompletor::PerfectMatchedProc.("String", bind: binding)
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_empty(err)
|
|
||||||
|
|
||||||
assert_include(out, " S\bSt\btr\bri\bin\bng\bg")
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_perfectly_matched_multiple_namespaces_triggers_document_display
|
|
||||||
result = nil
|
|
||||||
out, err = capture_output do
|
|
||||||
result = IRB::InputCompletor::PerfectMatchedProc.("{}.nil?", bind: binding)
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_empty(err)
|
|
||||||
|
|
||||||
# check if there're rdoc contents (e.g. CI doesn't generate them)
|
|
||||||
if has_rdoc_content?
|
|
||||||
# if there's rdoc content, we can verify by checking stdout
|
|
||||||
# rdoc generates control characters for formatting method names
|
|
||||||
assert_include(out, "P\bPr\bro\boc\bc.\b.n\bni\bil\bl?\b?") # Proc.nil?
|
|
||||||
assert_include(out, "H\bHa\bas\bsh\bh.\b.n\bni\bil\bl?\b?") # Hash.nil?
|
|
||||||
else
|
|
||||||
# this is a hacky way to verify the rdoc rendering code path because CI doesn't have rdoc content
|
|
||||||
# if there are multiple namespaces to be rendered, PerfectMatchedProc renders the result with a document
|
|
||||||
# which always returns the bytes rendered, even if it's 0
|
|
||||||
assert_equal(0, result)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_not_matched_namespace_triggers_nothing
|
|
||||||
result = nil
|
|
||||||
out, err = capture_output do
|
|
||||||
result = IRB::InputCompletor::PerfectMatchedProc.("Stri", bind: binding)
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_empty(err)
|
|
||||||
assert_empty(out)
|
|
||||||
assert_nil(result)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_perfect_matching_stops_without_rdoc
|
|
||||||
result = nil
|
|
||||||
|
|
||||||
out, err = capture_output do
|
|
||||||
without_rdoc do
|
|
||||||
result = IRB::InputCompletor::PerfectMatchedProc.("String", bind: binding)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_empty(err)
|
|
||||||
assert_not_match(/from ruby core/, out)
|
|
||||||
assert_nil(result)
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_perfect_matching_handles_nil_namespace
|
|
||||||
out, err = capture_output do
|
|
||||||
# symbol literal has `nil` doc namespace so it's a good test subject
|
|
||||||
assert_nil(IRB::InputCompletor::PerfectMatchedProc.(":aiueo", bind: binding))
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_empty(err)
|
|
||||||
assert_empty(out)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def has_rdoc_content?
|
|
||||||
File.exist?(RDoc::RI::Paths::BASE)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -294,34 +216,34 @@ module TestIRB
|
|||||||
rescue
|
rescue
|
||||||
end
|
end
|
||||||
symbols += [:aiueo, :"aiu eo"]
|
symbols += [:aiueo, :"aiu eo"]
|
||||||
candidates = IRB::InputCompletor.retrieve_completion_data(":a", bind: binding)
|
candidates = completion_candidates(":a", binding)
|
||||||
assert_include(candidates, ":aiueo")
|
assert_include(candidates, ":aiueo")
|
||||||
assert_not_include(candidates, ":aiu eo")
|
assert_not_include(candidates, ":aiu eo")
|
||||||
assert_empty(IRB::InputCompletor.retrieve_completion_data(":irb_unknown_symbol_abcdefg", bind: binding))
|
assert_empty(completion_candidates(":irb_unknown_symbol_abcdefg", binding))
|
||||||
# Do not complete empty symbol for performance reason
|
# Do not complete empty symbol for performance reason
|
||||||
assert_empty(IRB::InputCompletor.retrieve_completion_data(":", bind: binding))
|
assert_empty(completion_candidates(":", binding))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_invalid_three_colons
|
def test_complete_invalid_three_colons
|
||||||
assert_empty(IRB::InputCompletor.retrieve_completion_data(":::A", bind: binding))
|
assert_empty(completion_candidates(":::A", binding))
|
||||||
assert_empty(IRB::InputCompletor.retrieve_completion_data(":::", bind: binding))
|
assert_empty(completion_candidates(":::", binding))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_absolute_constants_with_special_characters
|
def test_complete_absolute_constants_with_special_characters
|
||||||
assert_empty(IRB::InputCompletor.retrieve_completion_data("::A:", bind: binding))
|
assert_empty(completion_candidates("::A:", binding))
|
||||||
assert_empty(IRB::InputCompletor.retrieve_completion_data("::A.", bind: binding))
|
assert_empty(completion_candidates("::A.", binding))
|
||||||
assert_empty(IRB::InputCompletor.retrieve_completion_data("::A(", bind: binding))
|
assert_empty(completion_candidates("::A(", binding))
|
||||||
assert_empty(IRB::InputCompletor.retrieve_completion_data("::A)", bind: binding))
|
assert_empty(completion_candidates("::A)", binding))
|
||||||
assert_empty(IRB::InputCompletor.retrieve_completion_data("::A[", bind: binding))
|
assert_empty(completion_candidates("::A[", binding))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_complete_reserved_words
|
def test_complete_reserved_words
|
||||||
candidates = IRB::InputCompletor.retrieve_completion_data("de", bind: binding)
|
candidates = completion_candidates("de", binding)
|
||||||
%w[def defined?].each do |word|
|
%w[def defined?].each do |word|
|
||||||
assert_include candidates, word
|
assert_include candidates, word
|
||||||
end
|
end
|
||||||
|
|
||||||
candidates = IRB::InputCompletor.retrieve_completion_data("__", bind: binding)
|
candidates = completion_candidates("__", binding)
|
||||||
%w[__ENCODING__ __LINE__ __FILE__].each do |word|
|
%w[__ENCODING__ __LINE__ __FILE__].each do |word|
|
||||||
assert_include candidates, word
|
assert_include candidates, word
|
||||||
end
|
end
|
||||||
@ -342,11 +264,11 @@ module TestIRB
|
|||||||
}
|
}
|
||||||
bind = obj.instance_exec { binding }
|
bind = obj.instance_exec { binding }
|
||||||
|
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("public_hog", bind: bind), "public_hoge")
|
assert_include(completion_candidates("public_hog", bind), "public_hoge")
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("public_hoge", bind: bind, doc_namespace: true), "public_hoge")
|
assert_include(doc_namespace("public_hoge", bind), "public_hoge")
|
||||||
|
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("private_hog", bind: bind), "private_hoge")
|
assert_include(completion_candidates("private_hog", bind), "private_hoge")
|
||||||
assert_include(IRB::InputCompletor.retrieve_completion_data("private_hoge", bind: bind, doc_namespace: true), "private_hoge")
|
assert_include(doc_namespace("private_hoge", bind), "private_hoge")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
# frozen_string_literal: false
|
# frozen_string_literal: false
|
||||||
|
|
||||||
require "irb"
|
require "irb"
|
||||||
|
require "rdoc"
|
||||||
require_relative "helper"
|
require_relative "helper"
|
||||||
|
|
||||||
module TestIRB
|
module TestIRB
|
||||||
class RelineInputMethodTest < TestCase
|
class InputMethodTest < TestCase
|
||||||
def setup
|
def setup
|
||||||
@conf_backup = IRB.conf.dup
|
@conf_backup = IRB.conf.dup
|
||||||
IRB.conf[:LC_MESSAGES] = IRB::Locale.new
|
IRB.conf[:LC_MESSAGES] = IRB::Locale.new
|
||||||
@ -18,15 +18,19 @@ module TestIRB
|
|||||||
# Reset Reline configuration overrided by RelineInputMethod.
|
# Reset Reline configuration overrided by RelineInputMethod.
|
||||||
Reline.instance_variable_set(:@core, nil)
|
Reline.instance_variable_set(:@core, nil)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class RelineInputMethodTest < InputMethodTest
|
||||||
def test_initialization
|
def test_initialization
|
||||||
|
Reline.completion_proc = nil
|
||||||
|
Reline.dig_perfect_match_proc = nil
|
||||||
IRB::RelineInputMethod.new
|
IRB::RelineInputMethod.new
|
||||||
|
|
||||||
assert_nil Reline.completion_append_character
|
assert_nil Reline.completion_append_character
|
||||||
assert_equal '', Reline.completer_quote_characters
|
assert_equal '', Reline.completer_quote_characters
|
||||||
assert_equal IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS, Reline.basic_word_break_characters
|
assert_equal IRB::InputMethod::BASIC_WORD_BREAK_CHARACTERS, Reline.basic_word_break_characters
|
||||||
assert_equal IRB::InputCompletor::CompletionProc, Reline.completion_proc
|
assert_not_nil Reline.completion_proc
|
||||||
assert_equal IRB::InputCompletor::PerfectMatchedProc, Reline.dig_perfect_match_proc
|
assert_not_nil Reline.dig_perfect_match_proc
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_initialization_without_use_autocomplete
|
def test_initialization_without_use_autocomplete
|
||||||
@ -54,7 +58,7 @@ module TestIRB
|
|||||||
IRB::RelineInputMethod.new
|
IRB::RelineInputMethod.new
|
||||||
|
|
||||||
assert Reline.autocompletion
|
assert Reline.autocompletion
|
||||||
assert_equal IRB::RelineInputMethod::SHOW_DOC_DIALOG, Reline.dialog_proc(:show_doc).dialog_proc
|
assert_not_equal empty_proc, Reline.dialog_proc(:show_doc).dialog_proc
|
||||||
ensure
|
ensure
|
||||||
Reline.add_dialog_proc(:show_doc, original_show_doc_proc, Reline::DEFAULT_DIALOG_CONTEXT)
|
Reline.add_dialog_proc(:show_doc, original_show_doc_proc, Reline::DEFAULT_DIALOG_CONTEXT)
|
||||||
end
|
end
|
||||||
@ -77,5 +81,93 @@ module TestIRB
|
|||||||
Reline.add_dialog_proc(:show_doc, original_show_doc_proc, Reline::DEFAULT_DIALOG_CONTEXT)
|
Reline.add_dialog_proc(:show_doc, original_show_doc_proc, Reline::DEFAULT_DIALOG_CONTEXT)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class DisplayDocumentTest < InputMethodTest
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
@driver = RDoc::RI::Driver.new(use_stdout: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def display_document(target, bind)
|
||||||
|
input_method = IRB::RelineInputMethod.new
|
||||||
|
input_method.instance_variable_set(:@completion_params, [target, '', '', bind])
|
||||||
|
input_method.display_document(target, driver: @driver)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_perfectly_matched_namespace_triggers_document_display
|
||||||
|
omit unless has_rdoc_content?
|
||||||
|
|
||||||
|
out, err = capture_output do
|
||||||
|
display_document("String", binding)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_empty(err)
|
||||||
|
|
||||||
|
assert_include(out, " S\bSt\btr\bri\bin\bng\bg")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_perfectly_matched_multiple_namespaces_triggers_document_display
|
||||||
|
result = nil
|
||||||
|
out, err = capture_output do
|
||||||
|
result = display_document("{}.nil?", binding)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_empty(err)
|
||||||
|
|
||||||
|
# check if there're rdoc contents (e.g. CI doesn't generate them)
|
||||||
|
if has_rdoc_content?
|
||||||
|
# if there's rdoc content, we can verify by checking stdout
|
||||||
|
# rdoc generates control characters for formatting method names
|
||||||
|
assert_include(out, "P\bPr\bro\boc\bc.\b.n\bni\bil\bl?\b?") # Proc.nil?
|
||||||
|
assert_include(out, "H\bHa\bas\bsh\bh.\b.n\bni\bil\bl?\b?") # Hash.nil?
|
||||||
|
else
|
||||||
|
# this is a hacky way to verify the rdoc rendering code path because CI doesn't have rdoc content
|
||||||
|
# if there are multiple namespaces to be rendered, PerfectMatchedProc renders the result with a document
|
||||||
|
# which always returns the bytes rendered, even if it's 0
|
||||||
|
assert_equal(0, result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_not_matched_namespace_triggers_nothing
|
||||||
|
result = nil
|
||||||
|
out, err = capture_output do
|
||||||
|
result = display_document("Stri", binding)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_empty(err)
|
||||||
|
assert_empty(out)
|
||||||
|
assert_nil(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_perfect_matching_stops_without_rdoc
|
||||||
|
result = nil
|
||||||
|
|
||||||
|
out, err = capture_output do
|
||||||
|
without_rdoc do
|
||||||
|
result = display_document("String", binding)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_empty(err)
|
||||||
|
assert_not_match(/from ruby core/, out)
|
||||||
|
assert_nil(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_perfect_matching_handles_nil_namespace
|
||||||
|
out, err = capture_output do
|
||||||
|
# symbol literal has `nil` doc namespace so it's a good test subject
|
||||||
|
assert_nil(display_document(":aiueo", binding))
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_empty(err)
|
||||||
|
assert_empty(out)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def has_rdoc_content?
|
||||||
|
File.exist?(RDoc::RI::Paths::BASE)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user