Skip to content

Commit

Permalink
Use RBS for indexing Core classes
Browse files Browse the repository at this point in the history
  • Loading branch information
andyw8 committed Jun 6, 2024
1 parent a3c7707 commit d2f2dfd
Show file tree
Hide file tree
Showing 9 changed files with 6,736 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ PATH
ruby-lsp (0.17.2)
language_server-protocol (~> 3.17.0)
prism (>= 0.29.0, < 0.30)
rbs
sorbet-runtime (>= 0.5.10782)

GEM
remote: https://rubygems.org/
specs:
abbrev (0.1.2)
ansi (1.5.0)
ast (2.4.2)
builder (3.2.4)
Expand Down Expand Up @@ -54,6 +56,8 @@ GEM
rbi (0.1.13)
prism (>= 0.18.0, < 1.0.0)
sorbet-runtime (>= 0.5.9204)
rbs (3.4.4)
abbrev
regexp_parser (2.9.2)
reline (0.5.0)
io-console (~> 0.5)
Expand Down
45 changes: 45 additions & 0 deletions lib/ruby_indexer/lib/ruby_indexer/index_rbs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# typed: strict
# frozen_string_literal: true

module RubyIndexer
class IndexRbs
extend T::Sig

sig { params(index: Index).void }
def initialize(index)
@index = index
end

sig { void }
def index_core_classes
loader = RBS::EnvironmentLoader.new
RBS::Environment.from_loader(loader).resolve_type_names

loader.each_signature do |source, pathname, _buffer, declarations, _directives|
process_signature(source, pathname, declarations)
end
end

private

sig { params(source: T.untyped, pathname: Pathname, declarations: T::Array[RBS::AST::Declarations::Base]).void }
def process_signature(source, pathname, declarations)
declarations.each do |declaration|
process_declaration(declaration, pathname)
end
end

sig { params(declaration: RBS::AST::Declarations::Base, pathname: Pathname).void }
def process_declaration(declaration, pathname)
return unless declaration.is_a?(RBS::AST::Declarations::Class)

nesting = [declaration.name.name.to_s]
file_path = pathname.to_s
location = RubyIndexer::Location.from_rbs_location(declaration.location)
comments = Array(declaration.comment&.string&.lines)
parent_class = nil
class_entry = Entry::Class.new(nesting, file_path, location, comments, parent_class)
@index << class_entry
end
end
end
13 changes: 13 additions & 0 deletions lib/ruby_indexer/lib/ruby_indexer/location.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ class Location
sig { returns(Integer) }
attr_reader :start_line, :end_line, :start_column, :end_column

class << self
extend T::Sig
sig { params(rbs_location: RBS::Location).returns(Location) }
def from_rbs_location(rbs_location)
new(
rbs_location.start_line,
rbs_location.end_line,
rbs_location.start_column,
rbs_location.end_column,
)
end
end

sig do
params(
start_line: Integer,
Expand Down
1 change: 1 addition & 0 deletions lib/ruby_indexer/ruby_indexer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
require "ruby_indexer/lib/ruby_indexer/configuration"
require "ruby_indexer/lib/ruby_indexer/prefix_tree"
require "ruby_indexer/lib/ruby_indexer/location"
require "ruby_indexer/lib/ruby_indexer/index_rbs"

module RubyIndexer
@configuration = T.let(Configuration.new, Configuration)
Expand Down
28 changes: 28 additions & 0 deletions lib/ruby_indexer/test/index_rbs_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# typed: true
# frozen_string_literal: true

require_relative "test_case"

module RubyIndexer
class IndexRbsTest < TestCase
def setup
@index = RubyIndexer::Index.new
IndexRbs.new(@index).index_core_classes
end

def test_index_core_classes
entries = @index["String"]
refute_nil(entries)
assert_equal(1, entries.length)
entry = entries.first
assert_match(%r{/gems/rbs-.*/core/string.rbs}, entry.file_path)
assert_equal("string.rbs", entry.file_name)

# Using fixed positions would be fragile, so let's just check some basics.
assert_operator(entry.location.start_line, :>, 0)
assert_operator(entry.location.end_line, :>, entry.location.start_line)
assert_equal(0, entry.location.start_column)
assert_operator(entry.location.end_column, :>, 0)
end
end
end
1 change: 1 addition & 0 deletions lib/ruby_lsp/internal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
require "prism"
require "prism/visitor"
require "language_server-protocol"
require "rbs"

require "ruby-lsp"
require "ruby_lsp/base_server"
Expand Down
1 change: 1 addition & 0 deletions lib/ruby_lsp/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ def shutdown

sig { params(config_hash: T::Hash[String, T.untyped]).void }
def perform_initial_indexing(config_hash)
RubyIndexer::IndexRbs.new(@global_state.index).index_core_classes
# The begin progress invocation happens during `initialize`, so that the notification is sent before we are
# stuck indexing files
RubyIndexer.configuration.apply_config(config_hash)
Expand Down
1 change: 1 addition & 0 deletions ruby-lsp.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Gem::Specification.new do |s|

s.add_dependency("language_server-protocol", "~> 3.17.0")
s.add_dependency("prism", ">= 0.29.0", "< 0.30")
s.add_dependency("rbs")
s.add_dependency("sorbet-runtime", ">= 0.5.10782")

s.required_ruby_version = ">= 3.0"
Expand Down
Loading

0 comments on commit d2f2dfd

Please sign in to comment.