Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type based completion using Prism and RBS #708

Merged
merged 21 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
93ca339
Add completor using prism and rbs
tompng Oct 13, 2023
3662af2
Add TypeCompletion test
tompng Oct 16, 2023
7ea69a9
Switchable completors: RegexpCompletor and TypeCompletion::Completor
tompng Oct 13, 2023
87deeda
Add completion info to irb_info
tompng Oct 16, 2023
a749c5e
Complete reserved words
tompng Oct 18, 2023
6c59ff4
Fix [*] (*) {**} and prism's change of KeywordParameterNode
tompng Nov 2, 2023
9dede7b
Fix require, frozen_string_literal
tompng Nov 4, 2023
977b13f
Drop prism<=0.16.0 support
tompng Nov 4, 2023
2960a14
Add Completor.last_completion_error for debug report
tompng Nov 4, 2023
71dd503
Retrieve `self` and `Module.nesting` in more safe way
tompng Nov 4, 2023
63693d3
Support BasicObject
tompng Nov 4, 2023
8a0fb2e
Handle lvar and ivar get exception correctly
tompng Nov 4, 2023
635ad5b
Skip ivar reference test of non-self object in ruby < 3.2
tompng Nov 4, 2023
95f5031
BaseScope to RootScope, move method objects constant under Methods
tompng Nov 4, 2023
09b8346
Remove unused Splat struct
tompng Nov 4, 2023
12efb40
Drop deeply nested array/hash type calculation from actual object. No…
tompng Nov 4, 2023
a41c769
Refactor loading rbs in test, change preload_in_thread not to cache T…
tompng Nov 4, 2023
e9d649b
Use new option added in prism 0.17.1 to parse code with localvars
tompng Nov 5, 2023
124f80f
Add Prism version check and warn when :type completor cannot be enabled
tompng Nov 5, 2023
0aa23f1
build_type_completor should skip truffleruby (because endless method …
tompng Nov 6, 2023
dffc27c
Merge branch 'master' into yarp_rbs_completor
tompng Nov 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ gem "rake"
gem "test-unit"
gem "test-unit-ruby-core"
gem "debug", github: "ruby/debug"
if RUBY_VERSION >= "3.0.0"
gem "rbs"
gem "prism"
end
4 changes: 2 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ Rake::TestTask.new(:test) do |t|
t.libs << "test" << "test/lib"
t.libs << "lib"
t.ruby_opts << "-rhelper"
t.test_files = FileList["test/irb/test_*.rb"]
t.test_files = FileList["test/irb/test_*.rb", "test/irb/type_completion/test_*.rb"]
end

# To make sure they have been correctly setup for Ruby CI.
desc "Run each irb test file in isolation."
task :test_in_isolation do
failed = false

FileList["test/irb/test_*.rb"].each do |test_file|
FileList["test/irb/test_*.rb", "test/irb/type_completion/test_*.rb"].each do |test_file|
ENV["TEST"] = test_file
begin
Rake::Task["test"].execute
Expand Down
4 changes: 4 additions & 0 deletions lib/irb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@
#
# IRB.conf[:USE_AUTOCOMPLETE] = false
#
# To enable enhanced completion using type information, add the following to your +.irbrc+:
#
# IRB.conf[:COMPLETOR] = :type
#
# === History
#
# By default, irb will store the last 1000 commands you used in
Expand Down
1 change: 1 addition & 0 deletions lib/irb/cmd/irb_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def execute
str = "Ruby version: #{RUBY_VERSION}\n"
str += "IRB version: #{IRB.version}\n"
str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
str += "Completion: #{IRB.CurrentContext.io.respond_to?(:completion_info) ? IRB.CurrentContext.io.completion_info : 'off'}\n"
str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
Expand Down
49 changes: 27 additions & 22 deletions lib/irb/completion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,30 @@

module IRB
class BaseCompletor # :nodoc:

# 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 completion_candidates(preposing, target, postposing, bind:)
raise NotImplementedError
end
Expand Down Expand Up @@ -94,28 +118,9 @@ def eval_class_constants
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 inspect
'RegexpCompletor'
end

def complete_require_path(target, preposing, postposing)
if target =~ /\A(['"])([^'"]+)\Z/
Expand Down
19 changes: 17 additions & 2 deletions lib/irb/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ def initialize(irb, workspace = nil, input_method = nil)
when nil
if STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
# Both of multiline mode and singleline mode aren't specified.
@io = RelineInputMethod.new
@io = RelineInputMethod.new(build_completor)
else
@io = nil
end
when false
@io = nil
when true
@io = RelineInputMethod.new
@io = RelineInputMethod.new(build_completor)
end
unless @io
case use_singleline?
Expand Down Expand Up @@ -149,6 +149,21 @@ def initialize(irb, workspace = nil, input_method = nil)
@command_aliases = IRB.conf[:COMMAND_ALIASES]
end

private def build_completor
# Valid values are :regexp and :type
if IRB.conf[:COMPLETOR] == :type && RUBY_VERSION >= '3.0.0'
begin
require 'prism'
tompng marked this conversation as resolved.
Show resolved Hide resolved
require 'irb/type_completion/completor'
TypeCompletion::Types.preload_in_thread
return TypeCompletion::Completor.new
rescue LoadError
end
end
# Fallback to RegexpCompletor
RegexpCompletor.new
end

def save_history=(val)
IRB.conf[:SAVE_HISTORY] = val
end
Expand Down
1 change: 1 addition & 0 deletions lib/irb/init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def IRB.init_config(ap_path)
@CONF[:USE_SINGLELINE] = false unless defined?(ReadlineInputMethod)
@CONF[:USE_COLORIZE] = (nc = ENV['NO_COLOR']).nil? || nc.empty?
@CONF[:USE_AUTOCOMPLETE] = ENV.fetch("IRB_USE_AUTOCOMPLETE", "true") != "false"
@CONF[:COMPLETOR] = :regexp
@CONF[:INSPECT_MODE] = true
@CONF[:USE_TRACER] = false
@CONF[:USE_LOADER] = false
Expand Down
15 changes: 12 additions & 3 deletions lib/irb/input-method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ def initialize
}
end

def completion_info
'RegexpCompletor'
end

# Reads the next line from this input method.
#
# See IO#gets for more information.
Expand Down Expand Up @@ -230,13 +234,13 @@ class RelineInputMethod < StdioInputMethod
HISTORY = Reline::HISTORY
include HistorySavingAbility
# Creates a new input method object using Reline
def initialize
def initialize(completor)
IRB.__send__(:set_encoding, Reline.encoding_system_needs.name, override: false)

super
super()

@eof = false
@completor = RegexpCompletor.new
@completor = completor

Reline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
Reline.completion_append_character = nil
Expand Down Expand Up @@ -270,6 +274,11 @@ def initialize
end
end

def completion_info
autocomplete_message = IRB.conf[:USE_AUTOCOMPLETE] ? 'Autocomplete' : 'Tab Complete'
tompng marked this conversation as resolved.
Show resolved Hide resolved
"#{autocomplete_message}, #{@completor.inspect}"
end

def check_termination(&block)
@check_termination_proc = block
end
Expand Down
Loading