From b77172870192dcc2cb6df016f4186469c1d6286f Mon Sep 17 00:00:00 2001 From: Galin Bajlekov <117099775+galin-enso@users.noreply.github.com> Date: Fri, 17 Feb 2023 00:21:37 +0100 Subject: [PATCH] Improve searching of component browser entries (#5645) Closes #5102 This PR improves searching entries in the component browser. Now the searcher input is also matched to the code that a component would generate, and the best match of the two is used for filtering and sorting the components in the component browser. https://user-images.githubusercontent.com/117099775/219328904-c7a067d5-4998-4ee5-8475-d4974cd7bff5.mp4 #### Entry name formatting Additionally, the component entry's displayed name format is changed to show the method's name first, followed by the type name in parentheses. This formatting fits better in the narrow columns of the component browser. --- CHANGELOG.md | 4 +++ app/gui/src/controller/searcher/component.rs | 32 +++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e8d25edd50..a60a7916e6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -92,6 +92,9 @@ - [Added restoring of last project snapshot on shortcut.][4050] - [Added contextual suggestions to argument dropdowns][4072]. Dropdowns will now contain suggestions which are based on evaluated data. +- [Improved component browser entry filtering and sorting][5645]. The component + browser will now provide suggestions matching either the component's label or + the corresponding code. #### EnsoGL (rendering engine) @@ -473,6 +476,7 @@ [4120]: https://github.com/enso-org/enso/pull/4120 [4050]: https://github.com/enso-org/enso/pull/4050 [4072]: https://github.com/enso-org/enso/pull/4072 +[5645]: https://github.com/enso-org/enso/pull/5645 [5646]: https://github.com/enso-org/enso/pull/5646 #### Enso Compiler diff --git a/app/gui/src/controller/searcher/component.rs b/app/gui/src/controller/searcher/component.rs index b85b66cb1d0..7803da92509 100644 --- a/app/gui/src/controller/searcher/component.rs +++ b/app/gui/src/controller/searcher/component.rs @@ -152,12 +152,36 @@ impl Component { /// /// It should be called each time the filtering pattern changes. pub fn update_matching_info(&self, pattern: impl Str) { + // Match the input pattern to the component label. let label = self.label(); - let matches = fuzzly::matches(&label, pattern.as_ref()); - let subsequence = matches.and_option_from(|| { + let label_matches = fuzzly::matches(&label, pattern.as_ref()); + let label_subsequence = label_matches.and_option_from(|| { let metric = fuzzly::metric::default(); - fuzzly::find_best_subsequence(label, pattern, metric) + fuzzly::find_best_subsequence(label, pattern.as_ref(), metric) }); + + // Match the input pattern to the code to be inserted. + let code = match &self.data { + Data::FromDatabase { entry, .. } => entry.code_to_insert(true).to_string(), + Data::Virtual { snippet } => snippet.code.to_string(), + }; + let code_matches = fuzzly::matches(&code, pattern.as_ref()); + let code_subsequence = code_matches.and_option_from(|| { + let metric = fuzzly::metric::default(); + fuzzly::find_best_subsequence(code, pattern.as_ref(), metric) + }); + + // Pick the best match score of the two, use only the character indices matching the label. + let subsequence = match (label_subsequence, code_subsequence) { + (Some(label), Some(code)) => { + let score = label.score.max(code.score); + Some(fuzzly::Subsequence { score, ..label }) + } + (None, Some(code)) => Some(fuzzly::Subsequence { indices: Vec::new(), ..code }), + (Some(label), None) => Some(label), + (None, None) => None, + }; + *self.match_info.borrow_mut() = match subsequence { Some(subsequence) => MatchInfo::Matches { subsequence }, None => MatchInfo::DoesNotMatch, @@ -192,7 +216,7 @@ impl Display for Component { let self_type_not_here = self_type_ref.filter(|t| *t != &entry.defined_in); if let Some(self_type) = self_type_not_here { let self_name = self_type.name().from_case(Case::Snake).to_case(Case::Title); - write!(f, "{self_name} {entry_name}") + write!(f, "{entry_name} ({self_name})") } else { write!(f, "{entry_name}") }