Skip to content

Commit 3ac178b

Browse files
committed
Add fuzzy search to board listall command
1 parent 9b5dd01 commit 3ac178b

File tree

2 files changed

+56
-10
lines changed

2 files changed

+56
-10
lines changed

commands/board/listall.go

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,32 @@ import (
2222

2323
"github.com/arduino/arduino-cli/commands"
2424
rpc "github.com/arduino/arduino-cli/rpc/commands"
25+
"github.com/lithammer/fuzzysearch/fuzzy"
2526
)
2627

28+
// maximumSearchDistance is the maximum Levenshtein distance accepted when using fuzzy search.
29+
// This value is completely arbitrary and picked randomly.
30+
const maximumSearchDistance = 20
31+
2732
// ListAll FIXMEDOC
2833
func ListAll(ctx context.Context, req *rpc.BoardListAllReq) (*rpc.BoardListAllResp, error) {
2934
pm := commands.GetPackageManager(req.GetInstance().GetId())
3035
if pm == nil {
3136
return nil, errors.New("invalid instance")
3237
}
3338

34-
args := req.GetSearchArgs()
35-
match := func(name string) bool {
36-
if len(args) == 0 {
39+
searchArgs := strings.Join(req.SearchArgs, " ")
40+
41+
match := func(toTest []string) bool {
42+
if len(searchArgs) == 0 {
3743
return true
3844
}
39-
name = strings.ToLower(name)
40-
for _, term := range args {
41-
if !strings.Contains(name, strings.ToLower(term)) {
42-
return false
45+
for _, rank := range fuzzy.RankFindNormalizedFold(searchArgs, toTest) {
46+
if rank.Distance < maximumSearchDistance {
47+
return true
4348
}
4449
}
45-
return true
50+
return false
4651
}
4752

4853
list := &rpc.BoardListAllResp{Boards: []*rpc.BoardListItem{}}
@@ -75,13 +80,26 @@ func ListAll(ctx context.Context, req *rpc.BoardListAllReq) (*rpc.BoardListAllRe
7580
ManuallyInstalled: platform.ManuallyInstalled,
7681
}
7782

83+
toTest := []string{
84+
platform.String(),
85+
platform.Name,
86+
platform.Architecture,
87+
targetPackage.Name,
88+
targetPackage.Maintainer,
89+
}
90+
7891
for _, board := range installedPlatformRelease.Boards {
79-
if !match(board.Name()) {
92+
if !req.GetIncludeHiddenBoards() && board.IsHidden() {
8093
continue
8194
}
82-
if !req.GetIncludeHiddenBoards() && board.IsHidden() {
95+
96+
toTest := toTest
97+
toTest = append(toTest, strings.Split(board.Name(), " ")...)
98+
toTest = append(toTest, board.FQBN())
99+
if !match(toTest) {
83100
continue
84101
}
102+
85103
list.Boards = append(list.Boards, &rpc.BoardListItem{
86104
Name: board.Name(),
87105
FQBN: board.FQBN(),

test/test_board.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,34 @@ def test_board_listall_with_manually_installed_platform(run_command, data_dir):
455455
assert "Arduino SAMD (32-bits ARM Cortex-M0+) Boards" == platform["Name"]
456456

457457

458+
def test_board_listall_fuzzy_search(run_command, data_dir):
459+
assert run_command("update")
460+
461+
# Install from platform manager
462+
assert run_command("core install arduino:avr@1.8.3")
463+
464+
# Manually installs a core in sketchbooks hardware folder
465+
git_url = "https://github.com/arduino/ArduinoCore-samd.git"
466+
repo_dir = Path(data_dir, "hardware", "arduino-beta-development", "samd")
467+
assert Repo.clone_from(git_url, repo_dir, multi_options=["-b 1.8.11"])
468+
469+
res = run_command("board listall --format json samd")
470+
assert res.ok
471+
data = json.loads(res.stdout)
472+
boards = {b["FQBN"]: b for b in data["boards"]}
473+
assert len(boards) == 17
474+
assert "arduino-beta-development:samd:mkr1000" in boards
475+
assert "arduino:avr:uno" not in boards
476+
477+
res = run_command("board listall --format json avr")
478+
assert res.ok
479+
data = json.loads(res.stdout)
480+
boards = {b["FQBN"]: b for b in data["boards"]}
481+
assert len(boards) == 26
482+
assert "arduino:avr:uno" in boards
483+
assert "arduino-beta-development:samd:mkr1000" not in boards
484+
485+
458486
def test_board_details(run_command):
459487
run_command("core update-index")
460488
# Download samd core pinned to 1.8.6

0 commit comments

Comments
 (0)