The minimum Jaro-Winkler similarity score for an entry to be considered a match for a given fuzzy search query
Public Class Methods
new()
# File lib/ruby_indexer/lib/ruby_indexer/index.rb, line 14definitialize# Holds all entries in the index using the following format:# {# "Foo" => [#<Entry::Class>, #<Entry::Class>],# "Foo::Bar" => [#<Entry::Class>],# }@entries = T.let({}, T::Hash[String, T::Array[Entry]])
# Holds all entries in the index using a prefix tree for searching based on prefixes to provide autocompletion@entries_tree = T.let(PrefixTree[T::Array[Entry]].new, PrefixTree[T::Array[Entry]])
# Holds references to where entries where discovered so that we can easily delete them# {# "/my/project/foo.rb" => [#<Entry::Class>, #<Entry::Class>],# "/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[IndexablePath].new, PrefixTree[IndexablePath])
end
Public Instance Methods
<<(entry)
# File lib/ruby_indexer/lib/ruby_indexer/index.rb, line 65def<<(entry)
name = entry.name
(@entries[name] ||= []) <<entry
(@files_to_entries[entry.file_path] ||= []) <<entry@entries_tree.insert(name, T.must(@entries[name]))
end
[](fully_qualified_name)
# File lib/ruby_indexer/lib/ruby_indexer/index.rb, line 74def[](fully_qualified_name)
@entries[fully_qualified_name.delete_prefix("::")]
end
delete(indexable)
# File lib/ruby_indexer/lib/ruby_indexer/index.rb, line 37defdelete(indexable)
# For each constant discovered in `path`, delete the associated entry from the index. If there are no entries# left, delete the constant from the index.@files_to_entries[indexable.full_path]&.eachdo|entry|name = entry.nameentries = @entries[name]
nextunlessentries# Delete the specific entry from the list for this nameentries.delete(entry)
# If all entries were deleted, then remove the name from the hash and from the prefix tree. Otherwise, update# the prefix tree with the current entriesifentries.empty?@entries.delete(name)
@entries_tree.delete(name)
else@entries_tree.insert(name, entries)
endend@files_to_entries.delete(indexable.full_path)
require_path = indexable.require_path@require_paths_tree.delete(require_path) ifrequire_pathend
follow_aliased_namespace(name)
# File lib/ruby_indexer/lib/ruby_indexer/index.rb, line 210deffollow_aliased_namespace(name)
returnnameif@entries[name]
parts = name.split("::")
real_parts = []
(parts.length-1).downto(0).eachdo|i|current_name = T.must(parts[0..i]).join("::")
entry = @entries[current_name]&.firstcaseentrywhenEntry::Aliastarget = entry.targetreturnfollow_aliased_namespace("#{target}::#{real_parts.join("::")}")
whenEntry::UnresolvedAliasresolved = resolve_alias(entry)
ifresolved.is_a?(Entry::UnresolvedAlias)
raiseUnresolvableAliasError, "The constant #{resolved.name} is an alias to a non existing constant"endtarget = resolved.targetreturnfollow_aliased_namespace("#{target}::#{real_parts.join("::")}")
elsereal_parts.unshift(T.must(parts[i]))
endendreal_parts.join("::")
end
# File lib/ruby_indexer/lib/ruby_indexer/index.rb, line 171defindex_all(indexable_paths:RubyIndexer.configuration.indexables, &block)
# Calculate how many paths are worth 1% of progressprogress_step = (indexable_paths.length/100.0).ceilindexable_paths.each_with_indexdo|path, index|ifblock&&index%progress_step==0progress = (index/progress_step) +1breakunlessblock.call(progress)
endindex_single(path)
endend
index_single(indexable_path, source = nil)
# File lib/ruby_indexer/lib/ruby_indexer/index.rb, line 186defindex_single(indexable_path, source = nil)
content = source||File.read(indexable_path.full_path)
result = Prism.parse(content)
collector = Collector.new(self, result, indexable_path.full_path)
collector.collect(result.value)
require_path = indexable_path.require_path@require_paths_tree.insert(require_path, indexable_path) ifrequire_pathrescueErrno::EISDIR, Errno::ENOENT# If `path` is a directory, just ignore it and continue indexing. If the file doesn't exist, then we also ignore# itend
# File lib/ruby_indexer/lib/ruby_indexer/index.rb, line 135defresolve(name, nesting)
ifname.start_with?("::")
name = name.delete_prefix("::")
results = @entries[name] ||@entries[follow_aliased_namespace(name)]
returnresults&.map { |e|e.is_a?(Entry::UnresolvedAlias) ?resolve_alias(e) :e }
endnesting.length.downto(0).eachdo|i|namespace = T.must(nesting[0...i]).join("::")
full_name = namespace.empty??name:"#{namespace}::#{name}"# If we find an entry with `full_name` directly, then we can already return it, even if it contains aliases -# because the user might be trying to jump to the alias definition.## However, if we don't find it, then we need to search for possible aliases in the namespace. For example, in# the LSP itself we alias `RubyLsp::Interface` to `LanguageServer::Protocol::Interface`, which means doing# `RubyLsp::Interface::Location` is allowed. For these cases, we need some way to realize that the# `RubyLsp::Interface` part is an alias, that has to be resolvedentries = @entries[full_name] ||@entries[follow_aliased_namespace(full_name)]
returnentries.map { |e|e.is_a?(Entry::UnresolvedAlias) ?resolve_alias(e) :e } ifentriesendnilrescueUnresolvableAliasErrornilend
resolve_method(method_name, receiver_name)
# File lib/ruby_indexer/lib/ruby_indexer/index.rb, line 244defresolve_method(method_name, receiver_name)
method_entries = self[method_name]
owner_entries = self[receiver_name]
returnunlessowner_entries&&method_entriesowner_name = T.must(owner_entries.first).nameT.cast(
method_entries.grep(Entry::Member).selectdo|entry|T.cast(entry, Entry::Member).owner&.name==owner_nameend,
T::Array[Entry::Member],
)
end
search_require_paths(query)
# File lib/ruby_indexer/lib/ruby_indexer/index.rb, line 79defsearch_require_paths(query)
@require_paths_tree.search(query)
end