From 646872d52d198cf7cc6c487d0c99c6053bf0d15b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Janko=20Marohni=C4=87?= Date: Sat, 25 Oct 2025 13:24:04 +0200 Subject: [PATCH] Filter out indexed entries before fuzzy searching We're doing extra work fuzzy matching across the whole index, even though only a subset of entries are considered valid results. We can filter out dependency/private entries *before* fuzzy matching, which should speed things up, assuming that fuzzy matching is more expensive than filtering. --- lib/ruby_indexer/lib/ruby_indexer/index.rb | 8 ++++-- lib/ruby_lsp/requests/workspace_symbol.rb | 32 ++++++++++++++-------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/lib/ruby_indexer/lib/ruby_indexer/index.rb b/lib/ruby_indexer/lib/ruby_indexer/index.rb index bc36927534..e5abc07c5b 100644 --- a/lib/ruby_indexer/lib/ruby_indexer/index.rb +++ b/lib/ruby_indexer/lib/ruby_indexer/index.rb @@ -195,12 +195,13 @@ def prefix_search(query, nesting = nil) end # Fuzzy searches index entries based on Jaro-Winkler similarity. If no query is provided, all entries are returned - #: (String? query) -> Array[Entry] - def fuzzy_search(query) + #: (String? query) ?{ (Entry) -> bool? } -> Array[Entry] + def fuzzy_search(query, &condition) unless query entries = @entries.filter_map do |_name, entries| next if entries.first.is_a?(Entry::SingletonClass) + entries = entries.select(&condition) if condition entries end @@ -212,6 +213,9 @@ def fuzzy_search(query) results = @entries.filter_map do |name, entries| next if entries.first.is_a?(Entry::SingletonClass) + entries = entries.select(&condition) if condition + next if entries.empty? + similarity = DidYouMean::JaroWinkler.distance(name.gsub("::", "").downcase, normalized_query) [entries, -similarity] if similarity > ENTRY_SIMILARITY_THRESHOLD end diff --git a/lib/ruby_lsp/requests/workspace_symbol.rb b/lib/ruby_lsp/requests/workspace_symbol.rb index 1abde2337c..f41be04957 100644 --- a/lib/ruby_lsp/requests/workspace_symbol.rb +++ b/lib/ruby_lsp/requests/workspace_symbol.rb @@ -20,17 +20,7 @@ def initialize(global_state, query) # @override #: -> Array[Interface::WorkspaceSymbol] def perform - @index.fuzzy_search(@query).filter_map do |entry| - uri = entry.uri - file_path = uri.full_path - - # We only show symbols declared in the workspace - in_dependencies = file_path && !not_in_dependencies?(file_path) - next if in_dependencies - - # We should never show private symbols when searching the entire workspace - next if entry.private? - + fuzzy_search.filter_map do |entry| kind = kind_for_entry(entry) loc = entry.location @@ -44,7 +34,7 @@ def perform container_name: container.join("::"), kind: kind, location: Interface::Location.new( - uri: uri.to_s, + uri: entry.uri.to_s, range: Interface::Range.new( start: Interface::Position.new(line: loc.start_line - 1, character: loc.start_column), end: Interface::Position.new(line: loc.end_line - 1, character: loc.end_column), @@ -53,6 +43,24 @@ def perform ) end end + + private + + #: -> Array[RubyIndexer::Entry] + def fuzzy_search + @index.fuzzy_search(@query) do |entry| + file_path = entry.uri.full_path + + # We only show symbols declared in the workspace + in_dependencies = file_path && !not_in_dependencies?(file_path) + next if in_dependencies + + # We should never show private symbols when searching the entire workspace + next if entry.private? + + true + end + end end end end