Skip to content

Commit a9a5123

Browse files
committed
Remove fuzzy logic from lib search command
1 parent 5704138 commit a9a5123

File tree

2 files changed

+37
-59
lines changed

2 files changed

+37
-59
lines changed

commands/lib/search.go

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ import (
2222

2323
"github.com/arduino/arduino-cli/arduino/libraries/librariesindex"
2424
"github.com/arduino/arduino-cli/arduino/libraries/librariesmanager"
25+
"github.com/arduino/arduino-cli/arduino/utils"
2526
"github.com/arduino/arduino-cli/commands"
2627
rpc "github.com/arduino/arduino-cli/rpc/commands"
27-
"github.com/lithammer/fuzzysearch/fuzzy"
2828
semver "go.bug.st/relaxed-semver"
2929
)
3030

@@ -43,44 +43,33 @@ func searchLibrary(req *rpc.LibrarySearchReq, lm *librariesmanager.LibrariesMana
4343
res := []*rpc.SearchedLibrary{}
4444
status := rpc.LibrarySearchStatus_success
4545

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))
46+
searchArgs := strings.Split(strings.Trim(query, " "), " ")
47+
48+
match := func(toTest []string) (bool, error) {
49+
if len(searchArgs) == 0 {
50+
return true, nil
5051
}
51-
return &rpc.LibrarySearchResp{Libraries: res, Status: status}, nil
52-
}
5352

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
53+
for _, t := range toTest {
54+
matches, err := utils.Match(t, searchArgs)
55+
if err != nil {
56+
return false, err
57+
}
58+
if matches {
59+
return matches, nil
60+
}
61+
}
62+
return false, nil
6063
}
6164

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)
7265
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-
}
81-
}
66+
toTest := []string{lib.Name, lib.Latest.Paragraph, lib.Latest.Sentence}
67+
if ok, err := match(toTest); err != nil {
68+
return nil, err
69+
} else if !ok {
70+
continue
8271
}
83-
nextLib:
72+
res = append(res, indexLibraryToRPCSearchLibrary(lib))
8473
}
8574

8675
return &rpc.LibrarySearchResp{Libraries: res, Status: status}, nil

test/test_lib.py

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ def test_lib_ops_caseinsensitive(run_command):
414414

415415

416416
def test_search(run_command):
417-
assert run_command("lib update-index")
417+
assert run_command("update")
418418

419419
result = run_command("lib search --names")
420420
assert result.ok
@@ -433,29 +433,6 @@ def test_search(run_command):
433433
result = run_command("lib search --names")
434434
assert result.ok
435435

436-
# Search for a specific target
437-
result = run_command("lib search --names ArduinoJson --format json")
438-
assert result.ok
439-
libs_json = json.loads(result.stdout)
440-
assert len(libs_json.get("libraries")) >= 1
441-
442-
443-
def test_search_paragraph(run_command):
444-
"""
445-
Search for a string that's only present in the `paragraph` field
446-
within the index file.
447-
"""
448-
assert run_command("lib update-index")
449-
result = run_command('lib search "A simple and efficient JSON library" --names --format json')
450-
assert result.ok
451-
data = json.loads(result.stdout)
452-
libraries = [l["name"] for l in data["libraries"]]
453-
assert "ArduinoJson" in libraries
454-
455-
456-
def test_lib_search_fuzzy(run_command):
457-
run_command("update")
458-
459436
def run_search(search_args, expected_libraries):
460437
res = run_command(f"lib search --names --format json {search_args}")
461438
assert res.ok
@@ -468,7 +445,6 @@ def run_search(search_args, expected_libraries):
468445
run_search("Arduino mkr iot carrier", ["Arduino_MKRIoTCarrier"])
469446
run_search("mkr iot carrier", ["Arduino_MKRIoTCarrier"])
470447
run_search("mkriotcarrier", ["Arduino_MKRIoTCarrier"])
471-
run_search("Arduinomkriotcarrier", ["Arduino_MKRIoTCarrier"])
472448

473449
run_search(
474450
"dht",
@@ -481,10 +457,23 @@ def run_search(search_args, expected_libraries):
481457
run_search("sensor dht", [])
482458

483459
run_search("arduino json", ["ArduinoJson", "Arduino_JSON"])
484-
run_search("arduinojson", ["ArduinoJson", "Arduino_JSON"])
460+
run_search("arduinojson", ["ArduinoJson"])
485461
run_search("json", ["ArduinoJson", "Arduino_JSON"])
486462

487463

464+
def test_search_paragraph(run_command):
465+
"""
466+
Search for a string that's only present in the `paragraph` field
467+
within the index file.
468+
"""
469+
assert run_command("lib update-index")
470+
result = run_command('lib search "A simple and efficient JSON library" --names --format json')
471+
assert result.ok
472+
data = json.loads(result.stdout)
473+
libraries = [l["name"] for l in data["libraries"]]
474+
assert "ArduinoJson" in libraries
475+
476+
488477
def test_lib_list_with_updatable_flag(run_command):
489478
# Init the environment explicitly
490479
run_command("lib update-index")

0 commit comments

Comments
 (0)