Skip to content

Commit

Permalink
Use Pin::Search to query workspace symbols (#560)
Browse files Browse the repository at this point in the history
  • Loading branch information
castwide committed Jun 12, 2022
1 parent fb891ef commit 0906cca
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 13 deletions.
7 changes: 4 additions & 3 deletions lib/solargraph/api_map.rb
Original file line number Diff line number Diff line change
Expand Up @@ -383,9 +383,10 @@ def document path
# @param query [String]
# @return [Array<Pin::Base>]
def query_symbols query
result = []
source_map_hash.each_value { |s| result.concat s.query_symbols(query) }
result
Pin::Search.new(
source_map_hash.values.flat_map(&:document_symbols),
query
).results
end

# @param location [Solargraph::Location]
Expand Down
1 change: 1 addition & 0 deletions lib/solargraph/pin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module Pin
autoload :DuckMethod, 'solargraph/pin/duck_method'
autoload :Singleton, 'solargraph/pin/singleton'
autoload :KeywordParam, 'solargraph/pin/keyword_param'
autoload :Search, 'solargraph/pin/search'

ROOT_PIN = Pin::Namespace.new(type: :class, name: '', closure: nil)
end
Expand Down
61 changes: 61 additions & 0 deletions lib/solargraph/pin/search.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# frozen_string_literal: true

require 'jaro_winkler'

module Solargraph
module Pin
class Search
class Result
# @return [Float]
attr_reader :match

# @return [Pin::Base]
attr_reader :pin

def initialize match, pin
@match = match
@pin = pin
end
end

# @param pins [Array<Pin::Base>]
# @param query [String]
def initialize pins, query
@pins = pins
@query = query
end

# @return [Array<Pin::Base>]
def results
@results ||= do_query
end

private

# @return [Array<Pin::Base>]
def do_query
return @pins if @query.nil? || @query.empty?
@pins.map do |pin|
match = [fuzzy_string_match(pin.path, @query), fuzzy_string_match(pin.name, @query)].max
Result.new(match, pin) if match > 0.6
end
.compact
.sort do |a, b|
if a.match == b.match
a.pin.path <=> b.pin.path
else
b.match <=> a.match
end
end
.map(&:pin)
end

# @param str1 [String]
# @param str2 [String]
# @return [Float]
def fuzzy_string_match str1, str2
JaroWinkler.distance(str1, str2)
end
end
end
end
11 changes: 1 addition & 10 deletions lib/solargraph/source_map.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# frozen_string_literal: true

require 'jaro_winkler'
require 'yard'
require 'yard-solargraph'
require 'set'
Expand Down Expand Up @@ -76,8 +75,7 @@ def document_symbols
# @param query [String]
# @return [Array<Pin::Base>]
def query_symbols query
return document_symbols if query && query.empty?
document_symbols.select{ |pin| fuzzy_string_match(pin.path, query) || fuzzy_string_match(pin.name, query) }
Pin::Search.new(document_symbols, query).results
end

# @param position [Position]
Expand Down Expand Up @@ -178,12 +176,5 @@ def _locate_pin line, character, *klasses
# Assuming the root pin is always valid
found || pins.first
end

# @param str1 [String]
# @param str2 [String]
# @return [Boolean]
def fuzzy_string_match str1, str2
JaroWinkler.distance(str1, str2) > 0.6
end
end
end
34 changes: 34 additions & 0 deletions spec/pin/search_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
describe Solargraph::Pin::Search do
it 'returns ordered matches on paths' do
example_class = Solargraph::Pin::Namespace.new(name: 'Example')
pins = [
example_class,
Solargraph::Pin::Method.new(name: 'foobar', closure: example_class),
Solargraph::Pin::Method.new(name: 'foo_bar', closure: example_class)
]
search = Solargraph::Pin::Search.new(pins, 'example')
expect(search.results.map(&:path)).to eq(['Example'])
end

it 'returns ordered matches on names' do
example_class = Solargraph::Pin::Namespace.new(name: 'Example')
pins = [
example_class,
Solargraph::Pin::Method.new(name: 'foobar', closure: example_class),
Solargraph::Pin::Method.new(name: 'foo_bar', closure: example_class)
]
search = Solargraph::Pin::Search.new(pins, 'foobar')
expect(search.results.map(&:path)).to eq(['Example.foobar', 'Example.foo_bar'])
end

it 'filters insufficient matches' do
example_class = Solargraph::Pin::Namespace.new(name: 'Example')
pins = [
example_class,
Solargraph::Pin::Method.new(name: 'foobar', closure: example_class),
Solargraph::Pin::Method.new(name: 'bazquz', closure: example_class)
]
search = Solargraph::Pin::Search.new(pins, 'foobar')
expect(search.results.map(&:path)).to eq(['Example.foobar'])
end
end

0 comments on commit 0906cca

Please sign in to comment.