diff options
Diffstat (limited to 'third_party/rust/suggest/src/keyword.rs')
-rw-r--r-- | third_party/rust/suggest/src/keyword.rs | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/third_party/rust/suggest/src/keyword.rs b/third_party/rust/suggest/src/keyword.rs new file mode 100644 index 0000000000..d15688d016 --- /dev/null +++ b/third_party/rust/suggest/src/keyword.rs @@ -0,0 +1,102 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/// Given a list of keywords for a suggestion, returns a phrase that best +/// completes the user's query. This function uses two heuristics to pick the +/// best match: +/// +/// 1. Find the first keyword in the list that has at least one more word than +/// the query, then trim the keyword up to the end of that word. +/// 2. If there isn't a keyword with more words, pick the keyword that forms the +/// longest suffix of the query. This might be the query itself. +pub fn full_keyword(query: &str, keywords: &[impl AsRef<str>]) -> String { + let query_words_len = query.split_whitespace().count(); + let min_phrase_words_len = if query.ends_with(char::is_whitespace) { + // If the query ends with a space, find a keyword with at least one more + // word, so that the completed phrase can show a word after the space. + query_words_len + 1 + } else { + query_words_len + }; + keywords + .iter() + .map(AsRef::as_ref) + .filter(|phrase| phrase.starts_with(query)) + .map(|phrase| phrase.split_whitespace().collect::<Vec<_>>()) + .find(|phrase_words| phrase_words.len() > min_phrase_words_len) + .map(|phrase_words| phrase_words[..min_phrase_words_len].join(" ")) + .unwrap_or_else(|| { + keywords + .iter() + .map(AsRef::as_ref) + .filter(|phrase| phrase.starts_with(query) && query.len() < phrase.len()) + .max_by_key(|phrase| phrase.trim().len()) + .unwrap_or(query) + .to_owned() + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn keywords_with_more_words() { + assert_eq!( + full_keyword( + "moz", + &[ + "moz", + "mozi", + "mozil", + "mozill", + "mozilla", + "mozilla firefox" + ] + ), + "mozilla".to_owned(), + ); + assert_eq!( + full_keyword( + "mozilla", + &[ + "moz", + "mozi", + "mozil", + "mozill", + "mozilla", + "mozilla firefox" + ] + ), + "mozilla".to_owned(), + ); + } + + #[test] + fn keywords_with_longer_phrase() { + assert_eq!( + full_keyword("moz", &["moz", "mozi", "mozil", "mozill", "mozilla"]), + "mozilla".to_owned() + ); + assert_eq!( + full_keyword( + "mozilla f", + &["moz", "mozi", "mozil", "mozill", "mozilla firefox"] + ), + "mozilla firefox".to_owned() + ); + } + + #[test] + fn query_ends_with_space() { + assert_eq!( + full_keyword( + "mozilla ", + &["moz", "mozi", "mozil", "mozill", "mozilla firefox"] + ), + "mozilla firefox".to_owned() + ); + } +} |