@@ -24,12 +24,10 @@ import (
2424 "github.com/arduino/arduino-cli/arduino/libraries/librariesmanager"
2525 "github.com/arduino/arduino-cli/commands"
2626 rpc "github.com/arduino/arduino-cli/rpc/commands"
27- "github.com/imjasonmiller/godice "
27+ "github.com/lithammer/fuzzysearch/fuzzy "
2828 semver "go.bug.st/relaxed-semver"
2929)
3030
31- var similarityThreshold = 0.7
32-
3331// LibrarySearch FIXMEDOC
3432func LibrarySearch (ctx context.Context , req * rpc.LibrarySearchReq ) (* rpc.LibrarySearchResp , error ) {
3533 lm := commands .GetLibraryManager (req .GetInstance ().GetId ())
@@ -41,45 +39,70 @@ func LibrarySearch(ctx context.Context, req *rpc.LibrarySearchReq) (*rpc.Library
4139}
4240
4341func searchLibrary (req * rpc.LibrarySearchReq , lm * librariesmanager.LibrariesManager ) (* rpc.LibrarySearchResp , error ) {
42+ query := req .GetQuery ()
4443 res := []* rpc.SearchedLibrary {}
4544 status := rpc .LibrarySearchStatus_success
4645
47- for _ , lib := range lm .Index .Libraries {
48- qry := strings .ToLower (req .GetQuery ())
49- if strings .Contains (strings .ToLower (lib .Name ), qry ) ||
50- strings .Contains (strings .ToLower (lib .Latest .Paragraph ), qry ) ||
51- strings .Contains (strings .ToLower (lib .Latest .Sentence ), qry ) {
52- releases := map [string ]* rpc.LibraryRelease {}
53- for str , rel := range lib .Releases {
54- releases [str ] = GetLibraryParameters (rel )
55- }
56- latest := GetLibraryParameters (lib .Latest )
57-
58- searchedLib := & rpc.SearchedLibrary {
59- Name : lib .Name ,
60- Releases : releases ,
61- Latest : latest ,
62- }
63- res = append (res , searchedLib )
46+ // If the query is empty all libraries are returned
47+ if strings .Trim (query , " " ) == "" {
48+ for _ , lib := range lm .Index .Libraries {
49+ res = append (res , indexLibraryToRPCSearchLibrary (lib ))
6450 }
51+ return & rpc.LibrarySearchResp {Libraries : res , Status : status }, nil
6552 }
6653
67- if len (res ) == 0 {
68- status = rpc .LibrarySearchStatus_failed
69- for _ , lib := range lm .Index .Libraries {
70- if godice .CompareString (req .GetQuery (), lib .Name ) > similarityThreshold {
71- res = append (res , & rpc.SearchedLibrary {
72- Name : lib .Name ,
73- })
54+ // maximumSearchDistance is the maximum Levenshtein distance accepted when using fuzzy search.
55+ // This value is completely arbitrary and picked randomly.
56+ maximumSearchDistance := 150
57+ // Use a lower distance for shorter query or the user might be flooded with unrelated results
58+ if len (query ) <= 4 {
59+ maximumSearchDistance = 40
60+ }
61+
62+ // Removes some chars from query strings to enhance results
63+ cleanQuery := strings .Map (func (r rune ) rune {
64+ switch r {
65+ case '_' :
66+ case '-' :
67+ case ' ' :
68+ return - 1
69+ }
70+ return r
71+ }, query )
72+ for _ , lib := range lm .Index .Libraries {
73+ // Use both uncleaned and cleaned query
74+ for _ , q := range []string {query , cleanQuery } {
75+ toTest := []string {lib .Name , lib .Latest .Paragraph , lib .Latest .Sentence }
76+ for _ , rank := range fuzzy .RankFindNormalizedFold (q , toTest ) {
77+ if rank .Distance < maximumSearchDistance {
78+ res = append (res , indexLibraryToRPCSearchLibrary (lib ))
79+ goto nextLib
80+ }
7481 }
7582 }
83+ nextLib:
7684 }
7785
7886 return & rpc.LibrarySearchResp {Libraries : res , Status : status }, nil
7987}
8088
81- // GetLibraryParameters FIXMEDOC
82- func GetLibraryParameters (rel * librariesindex.Release ) * rpc.LibraryRelease {
89+ // indexLibraryToRPCSearchLibrary converts a librariindex.Library to rpc.SearchLibrary
90+ func indexLibraryToRPCSearchLibrary (lib * librariesindex.Library ) * rpc.SearchedLibrary {
91+ releases := map [string ]* rpc.LibraryRelease {}
92+ for str , rel := range lib .Releases {
93+ releases [str ] = getLibraryParameters (rel )
94+ }
95+ latest := getLibraryParameters (lib .Latest )
96+
97+ return & rpc.SearchedLibrary {
98+ Name : lib .Name ,
99+ Releases : releases ,
100+ Latest : latest ,
101+ }
102+ }
103+
104+ // getLibraryParameters FIXMEDOC
105+ func getLibraryParameters (rel * librariesindex.Release ) * rpc.LibraryRelease {
83106 return & rpc.LibraryRelease {
84107 Author : rel .Author ,
85108 Version : rel .Version .String (),
0 commit comments