lib/ruby_indexer/lib/ruby_indexer/index.rb in ruby-lsp-0.8.1 vs lib/ruby_indexer/lib/ruby_indexer/index.rb in ruby-lsp-0.9.0

- old
+ new

@@ -3,10 +3,13 @@ module RubyIndexer class Index extend T::Sig + # The minimum Jaro-Winkler similarity score for an entry to be considered a match for a given fuzzy search query + ENTRY_SIMILARITY_THRESHOLD = 0.7 + sig { void } def initialize # Holds all entries in the index using the following format: # { # "Foo" => [#<Entry::Class>, #<Entry::Class>], @@ -48,10 +51,25 @@ sig { params(fully_qualified_name: String).returns(T.nilable(T::Array[Entry])) } def [](fully_qualified_name) @entries[fully_qualified_name.delete_prefix("::")] 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) + return @entries.flat_map { |_name, entries| entries } unless query + + normalized_query = query.gsub("::", "").downcase + + results = @entries.filter_map do |name, entries| + similarity = DidYouMean::JaroWinkler.distance(name.gsub("::", "").downcase, normalized_query) + [entries, -similarity] if similarity > ENTRY_SIMILARITY_THRESHOLD + end + results.sort_by!(&:last) + results.flat_map(&:first) + end + # Try to find the entry based on the nesting from the most specific to the least specific. For example, if we have # the nesting as ["Foo", "Bar"] and the name as "Baz", we will try to find it in this order: # 1. Foo::Bar::Baz # 2. Foo::Baz # 3. Baz @@ -75,10 +93,12 @@ sig { params(path: String, source: T.nilable(String)).void } def index_single(path, source = nil) content = source || File.read(path) visitor = IndexVisitor.new(self, YARP.parse(content), path) visitor.run + rescue Errno::EISDIR + # If `path` is a directory, just ignore it and continue indexing end class Entry extend T::Sig @@ -98,9 +118,14 @@ def initialize(name, file_path, location, comments) @name = name @file_path = file_path @location = location @comments = comments + end + + sig { returns(String) } + def file_name + File.basename(@file_path) end class Namespace < Entry sig { returns(String) } def short_name