From f1bcb6b99deb25a0a5dc3054c2be6312516dfa37 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Sat, 7 Dec 2024 01:09:03 -0800 Subject: [PATCH] wip emoji: Recognize word-aligned matches in ranking; TODO test --- lib/model/emoji.dart | 55 +++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/lib/model/emoji.dart b/lib/model/emoji.dart index 7aea5ff8e7..0cd03a0b61 100644 --- a/lib/model/emoji.dart +++ b/lib/model/emoji.dart @@ -331,7 +331,12 @@ enum EmojiMatchQuality { /// The query matches a prefix of the emoji name, but not the whole name. prefix, - /// The query matches somewhere in the emoji name, but not at the start. + /// The query matches starting at the start of a word in the emoji name, + /// but not the start of the whole name. + wordAligned, + + /// The query matches somewhere in the emoji name, + /// but not at the start of any word. other; /// The best possible quality of match. @@ -385,10 +390,8 @@ class EmojiAutocompleteView extends AutocompleteView false, }; return switch (matchQuality) { - EmojiMatchQuality.exact => 0, - EmojiMatchQuality.prefix => isPopular ? 1 : isCustomEmoji ? 3 : 4, - // TODO word-boundary vs. not - EmojiMatchQuality.other => isPopular ? 2 : isCustomEmoji ? 5 : 6, + EmojiMatchQuality.exact => 0, + EmojiMatchQuality.prefix => isPopular ? 1 : isCustomEmoji ? 3 : 5, + EmojiMatchQuality.wordAligned => isPopular ? 2 : isCustomEmoji ? 4 : 6, + EmojiMatchQuality.other => isCustomEmoji ? 7 : 8, }; } /// The number of possible values returned by [_rankResult]. - static const _numResultRanks = 7; + static const _numResultRanks = 9; static bool _isPopularEmoji(EmojiCandidate candidate) { return candidate.emojiType == ReactionType.unicodeEmoji @@ -473,29 +476,23 @@ class EmojiAutocompleteQuery extends ComposeAutocompleteQuery { } EmojiMatchQuality? _matchName(String emojiName) { + // Compare query_matches_string_in_order in Zulip web:shared/src/typeahead.ts . // TODO(#1067) this assumes emojiName is already lower-case (and no diacritics) - if (emojiName == _adjusted) return EmojiMatchQuality.exact; - if (emojiName.startsWith(_adjusted)) return EmojiMatchQuality.prefix; - if (_nameMatches(emojiName)) return EmojiMatchQuality.other; - return null; - } - - // Compare query_matches_string_in_order in Zulip web:shared/src/typeahead.ts . - bool _nameMatches(String emojiName) { - const String separator = '_'; - - if (!_adjusted.contains(separator)) { + if (emojiName == _adjusted) return EmojiMatchQuality.exact; + if (emojiName.startsWith(_adjusted)) return EmojiMatchQuality.prefix; + const String sep = '_'; + if (emojiName.contains(sep + _adjusted)) return EmojiMatchQuality.wordAligned; + if (!_adjusted.contains(sep)) { // If the query is a single token (doesn't contain a separator), - // the match can be anywhere in the string. - return emojiName.contains(_adjusted); + // allow a match anywhere in the string, too. + if (emojiName.contains(_adjusted)) return EmojiMatchQuality.other; + } else { + // Otherwise, when there is a separator in the query, + // require the match to start at the start of a token. + // (E.g. for 'ab_cd_ef', query could be 'ab_c' or 'cd_ef', + // but not 'b_cd_ef'.) } - - // If there is a separator in the query, then we - // require the match to start at the start of a token. - // (E.g. for 'ab_cd_ef', query could be 'ab_c' or 'cd_ef', - // but not 'b_cd_ef'.) - assert(!emojiName.startsWith(_adjusted)); // checked before calling this method - return emojiName.contains(separator + _adjusted); + return null; } @override