Skip to content

Commit

Permalink
Migrate PathCompletion to use the index
Browse files Browse the repository at this point in the history
  • Loading branch information
vinistock committed Aug 29, 2023
1 parent f5a7b43 commit cf58198
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 16 deletions.
14 changes: 14 additions & 0 deletions lib/ruby_indexer/lib/ruby_indexer/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ def initialize
# "/my/project/bar.rb" => [#<Entry::Class>],
# }
@files_to_entries = T.let({}, T::Hash[String, T::Array[Entry]])

# Holds all require paths for every indexed item so that we can provide autocomplete for requires
@require_paths_tree = T.let(PrefixTree.new([]), PrefixTree)
end

sig { params(indexable: Indexable).void }
Expand All @@ -40,6 +43,9 @@ def delete(indexable)
end

@files_to_entries.delete(indexable.full_path)

require_path = indexable.require_path
@require_paths_tree.delete(require_path) if require_path
end

sig { params(entry: Entry).void }
Expand All @@ -53,6 +59,11 @@ def [](fully_qualified_name)
@entries[fully_qualified_name.delete_prefix("::")]
end

sig { params(query: String).returns(T::Array[String]) }
def search_require_paths(query)
@require_paths_tree.search(query)
end

# Fuzzy searches index entries based on Jaro-Winkler similarity. If no query is provided, all entries are returned
sig { params(query: T.nilable(String)).returns(T::Array[Entry]) }
def fuzzy_search(query)
Expand Down Expand Up @@ -95,6 +106,9 @@ def index_single(indexable, source = nil)
content = source || File.read(indexable.full_path)
visitor = IndexVisitor.new(self, YARP.parse(content), indexable.full_path)
visitor.run

require_path = indexable.require_path
@require_paths_tree.insert(require_path) if require_path
rescue Errno::EISDIR
# If `path` is a directory, just ignore it and continue indexing
end
Expand Down
13 changes: 13 additions & 0 deletions lib/ruby_indexer/test/index_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,18 @@ def test_index_single_ignores_directories
ensure
FileUtils.rm_r("lib/this_is_a_dir.rb")
end

def test_searching_for_require_paths
@index.index_single(Indexable.new("/fake", "/fake/path/foo.rb"), <<~RUBY)
class Foo
end
RUBY
@index.index_single(Indexable.new("/fake", "/fake/path/other_foo.rb"), <<~RUBY)
class Foo
end
RUBY

assert_equal(["path/foo", "path/other_foo"], @index.search_require_paths("path"))
end
end
end
19 changes: 5 additions & 14 deletions lib/ruby_lsp/requests/path_completion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,24 @@ class PathCompletion < Listener
sig { override.returns(ResponseType) }
attr_reader :response

sig { params(emitter: EventEmitter, message_queue: Thread::Queue).void }
def initialize(emitter, message_queue)
super
sig { params(index: RubyIndexer::Index, emitter: EventEmitter, message_queue: Thread::Queue).void }
def initialize(index, emitter, message_queue)
super(emitter, message_queue)
@response = T.let([], ResponseType)
@tree = T.let(RubyIndexer::PrefixTree.new(collect_load_path_files), RubyIndexer::PrefixTree)
@index = index

emitter.register(self, :on_tstring_content)
end

sig { params(node: SyntaxTree::TStringContent).void }
def on_tstring_content(node)
@tree.search(node.value).sort.each do |path|
@index.search_require_paths(node.value).sort!.each do |path|
@response << build_completion(path, node)
end
end

private

sig { returns(T::Array[String]) }
def collect_load_path_files
$LOAD_PATH.flat_map do |p|
Dir.glob("**/*.rb", base: p)
end.map! do |result|
result.delete_suffix!(".rb")
end
end

sig { params(label: String, node: SyntaxTree::TStringContent).returns(Interface::CompletionItem) }
def build_completion(label, node)
Interface::CompletionItem.new(
Expand Down
10 changes: 8 additions & 2 deletions test/requests/path_completion_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def setup
@message_queue = Thread::Queue.new
@uri = URI("file:///fake.rb")
@store = RubyLsp::Store.new
@executor = RubyLsp::Executor.new(@store, @message_queue)
end

def teardown
Expand All @@ -31,7 +32,6 @@ def test_completion_command
}

result = with_file_structure do
@store = RubyLsp::Store.new
@store.set(uri: @uri, source: document.source, version: 1)
run_request(
method: "textDocument/completion",
Expand Down Expand Up @@ -196,7 +196,6 @@ def test_completion_is_not_triggered_if_argument_is_not_a_string
private

def run_request(method:, params: {})
@executor = RubyLsp::Executor.new(@store, @message_queue)
result = @executor.execute({ method: method, params: params })
error = result.error
raise error if error
Expand Down Expand Up @@ -228,6 +227,13 @@ def with_file_structure(&block)
tmpdir + "/foo/support/quux.rb",
])

index = @executor.instance_variable_get(:@index)
indexables = Dir.glob(File.join(tmpdir, "**", "*.rb")).map! do |path|
RubyIndexer::Indexable.new(tmpdir, path)
end

index.index_all(indexables: indexables)

return block.call
ensure
$LOAD_PATH.delete(tmpdir)
Expand Down

0 comments on commit cf58198

Please sign in to comment.