summaryrefslogtreecommitdiff
path: root/lib/irb/completion.rb
diff options
context:
space:
mode:
authortomoya ishida <[email protected]>2023-10-12 02:08:59 +0900
committergit <[email protected]>2023-10-11 17:09:05 +0000
commit94cb5765e2e44716800cd466c64f81c048aaf95b (patch)
tree8e372dac7478a36582b9de656731361924515788 /lib/irb/completion.rb
parentb9a6fca67d97f7319b20b24427d6dc4b8290cd24 (diff)
[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
Diffstat (limited to 'lib/irb/completion.rb')
-rw-r--r--lib/irb/completion.rb174
1 files changed, 74 insertions, 100 deletions
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
index a143d1b3e1..26215f6fe1 100644
--- a/lib/irb/completion.rb
+++ b/lib/irb/completion.rb
@@ -8,55 +8,14 @@
require_relative 'ruby-lex'
module IRB
- module InputCompletor # :nodoc:
- using Module.new {
- refine ::Binding do
- def eval_methods
- ::Kernel.instance_method(:methods).bind(eval("self")).call
- end
-
- def eval_private_methods
- ::Kernel.instance_method(:private_methods).bind(eval("self")).call
- end
-
- def eval_instance_variables
- ::Kernel.instance_method(:instance_variables).bind(eval("self")).call
- end
-
- def eval_global_variables
- ::Kernel.instance_method(:global_variables).bind(eval("self")).call
- end
-
- def eval_class_constants
- ::Module.instance_method(:constants).bind(eval("self.class")).call
- end
- end
- }
-
- # Set of reserved words used by Ruby, you should not use these for
- # constants or variables
- ReservedWords = %w[
- __ENCODING__ __LINE__ __FILE__
- BEGIN END
- alias and
- begin break
- case class
- def defined? do
- else elsif end ensure
- false for
- if in
- module
- next nil not
- or
- redo rescue retry return
- self super
- then true
- undef unless until
- when while
- yield
- ]
+ class BaseCompletor # :nodoc:
+ def completion_candidates(preposing, target, postposing, bind:)
+ raise NotImplementedError
+ end
- BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
+ def doc_namespace(preposing, matched, postposing, bind:)
+ raise NotImplementedError
+ end
GEM_PATHS =
if defined?(Gem::Specification)
@@ -73,7 +32,7 @@ module IRB
[]
end.freeze
- def self.retrieve_gem_and_system_load_path
+ def retrieve_gem_and_system_load_path
candidates = (GEM_PATHS | $LOAD_PATH)
candidates.map do |p|
if p.respond_to?(:to_path)
@@ -84,8 +43,8 @@ module IRB
end.compact.sort
end
- def self.retrieve_files_to_require_from_load_path
- @@files_from_load_path ||=
+ 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|
@@ -103,13 +62,62 @@ module IRB
)
end
- def self.retrieve_files_to_require_relative_from_current_dir
- @@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
+ 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
- CompletionRequireProc = lambda { |target, preposing = nil, postposing = nil|
+ class RegexpCompletor < BaseCompletor # :nodoc:
+ using Module.new {
+ refine ::Binding do
+ def eval_methods
+ ::Kernel.instance_method(:methods).bind(eval("self")).call
+ end
+
+ def eval_private_methods
+ ::Kernel.instance_method(:private_methods).bind(eval("self")).call
+ end
+
+ def eval_instance_variables
+ ::Kernel.instance_method(:instance_variables).bind(eval("self")).call
+ end
+
+ def eval_global_variables
+ ::Kernel.instance_method(:global_variables).bind(eval("self")).call
+ end
+
+ def eval_class_constants
+ ::Module.instance_method(:constants).bind(eval("self.class")).call
+ end
+ end
+ }
+
+ # Set of reserved words used by Ruby, you should not use these for
+ # constants or variables
+ ReservedWords = %w[
+ __ENCODING__ __LINE__ __FILE__
+ BEGIN END
+ alias and
+ begin break
+ case class
+ def defined? do
+ else elsif end ensure
+ false for
+ if in
+ module
+ next nil not
+ or
+ redo rescue retry return
+ self super
+ then true
+ undef unless until
+ when while
+ yield
+ ]
+
+ def complete_require_path(target, preposing, postposing)
if target =~ /\A(['"])([^'"]+)\Z/
quote = $1
actual_target = $2
@@ -142,21 +150,21 @@ module IRB
end
end
result
- }
+ end
- CompletionProc = lambda { |target, preposing = nil, postposing = nil|
+ def completion_candidates(preposing, target, postposing, bind:)
if preposing && postposing
- result = CompletionRequireProc.(target, preposing, postposing)
- unless 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) }
+ result = complete_require_path(target, preposing, postposing)
+ return result if result
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
# 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
@@ -394,44 +402,10 @@ module IRB
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
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|
case e
when /^[a-zA-Z_]/