From da3064343bfc76e8402adf5cd5ed68824c1e42da Mon Sep 17 00:00:00 2001
From: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
Date: Fri, 24 Nov 2023 06:37:06 +0900
Subject: enhance(frontend): 絵文字のオートコンプリートのアルゴリズムの改善
 (MisskeyIO#261)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* 実際は同じ絵文字なら重複してサジェストに出ないように
* エイリアスではない絵文字>前方一致>部分一致>あいまい検索順で表示されるようになるように
---
 .../frontend/src/components/MkAutocomplete.vue     | 40 ++++++++++------------
 1 file changed, 18 insertions(+), 22 deletions(-)

(limited to 'packages/frontend/src/components/MkAutocomplete.vue')

diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue
index a0f4961116..c1fcbd7ac1 100644
--- a/packages/frontend/src/components/MkAutocomplete.vue
+++ b/packages/frontend/src/components/MkAutocomplete.vue
@@ -265,7 +265,7 @@ function emojiAutoComplete(query: string | null, emojiDb: EmojiDef[], max = 30):
 	// 前方一致（エイリアスなし）
 	emojiDb.some(x => {
 		if (x.name.startsWith(query) && !x.aliasOf) {
-			matched.set(x.name, { emoji: x, score: query.length });
+			matched.set(x.name, { emoji: x, score: query.length + 1 });
 		}
 		return matched.size === max;
 	});
@@ -273,8 +273,8 @@ function emojiAutoComplete(query: string | null, emojiDb: EmojiDef[], max = 30):
 	// 前方一致（エイリアス込み）
 	if (matched.size < max) {
 		emojiDb.some(x => {
-			if (x.name.startsWith(query)) {
-				matched.set(x.name, { emoji: x, score: query.length });
+			if (x.name.startsWith(query) && !matched.has(x.aliasOf ?? x.name)) {
+				matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length });
 			}
 			return matched.size === max;
 		});
@@ -283,36 +283,32 @@ function emojiAutoComplete(query: string | null, emojiDb: EmojiDef[], max = 30):
 	// 部分一致（エイリアス込み）
 	if (matched.size < max) {
 		emojiDb.some(x => {
-			if (x.name.includes(query)) {
-				matched.set(x.name, { emoji: x, score: query.length });
+			if (x.name.includes(query) && !matched.has(x.aliasOf ?? x.name)) {
+				matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length - 1 });
 			}
 			return matched.size === max;
 		});
 	}
 
-	// 簡易あいまい検索
-	if (matched.size < max) {
+	// 簡易あいまい検索（3文字以上）
+	if (matched.size < max && query.length > 3) {
 		const queryChars = [...query];
 		const hitEmojis = new Map<string, EmojiScore>();
 
 		for (const x of emojiDb) {
-			// クエリ文字列の1文字単位で絵文字名にヒットするかを見る
-			// ただし、過剰に検出されるのを防ぐためクエリ文字列に登場する順番で絵文字名を走査する
-
-			let queryCharHitPos = 0;
-			let queryCharHitCount = 0;
-			for (let idx = 0; idx < queryChars.length; idx++) {
-				queryCharHitPos = x.name.indexOf(queryChars[idx], queryCharHitPos);
-				if (queryCharHitPos <= -1) {
-					break;
-				}
-
-				queryCharHitCount++;
+			// 文字列の位置を進めながら、クエリの文字を順番に探す
+
+			let pos = 0;
+			let hit = 0;
+			for (const c of queryChars) {
+				pos = x.name.indexOf(c, pos);
+				if (pos <= -1) break;
+				hit++;
 			}
 
-			// ヒット数が少なすぎると検索結果が汚れるので調節する
-			if (queryCharHitCount > 2) {
-				hitEmojis.set(x.name, { emoji: x, score: queryCharHitCount });
+			// 半分以上の文字が含まれていればヒットとする
+			if (hit > Math.ceil(queryChars.length / 2) && hit - 2 > (matched.get(x.aliasOf ?? x.name)?.score ?? 0)) {
+				hitEmojis.set(x.aliasOf ?? x.name, { emoji: x, score: hit - 2 });
 			}
 		}
 
-- 
cgit v1.2.3-freya

