From fabce14933f3f5575f96ef1511ff9101d4bc2c1c Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Wed, 12 Aug 2026 15:36:37 +0900 Subject: [PATCH] fix: tighten emoji lookup contracts --- dict.c | 2 +- map/emoji.dict | 68 ++++++++++++++++++++++++++++++++++++++++++- map/emoji.src | 13 +++++---- map/mkemoji | 2 +- tests/dict_test.c | 25 ++++++++++++++++ tests/engine_test.c | 51 ++++++++++++++++++++++++++++++++ tests/mkemoji_test.py | 1 + tests/test.h | 2 ++ tests/unit_test.c | 2 ++ 9 files changed, 157 insertions(+), 9 deletions(-) diff --git a/dict.c b/dict.c index b0a82d4..e4bb646 100644 --- a/dict.c +++ b/dict.c @@ -33,7 +33,7 @@ dictlookup(Dictreq *req, Dictres *res) while(p < e && *p != ' ') p++; sinit(&tmp, sp, p - sp); - if(scmp(&tmp, &req->key) != 0) + if(req->lang == LangEMOJI || scmp(&tmp, &req->key) != 0) res->kouho[res->nkouho++] = tmp; if(p < e) p++; diff --git a/map/emoji.dict b/map/emoji.dict index a64a504..2e9d606 100644 --- a/map/emoji.dict +++ b/map/emoji.dict @@ -75,9 +75,14 @@ bl 😊 blu 😊 blus 😊 blush 😊 -c Ο‡ +c Ο‡ β˜•οΈ ch Ο‡ chi Ο‡ +co β˜•οΈ +cof β˜•οΈ +coff β˜•οΈ +coffe β˜•οΈ +coffee β˜•οΈ d Β° Ξ΄ Ξ” ↓ de Ξ” Β° Ξ΄ deg Β° @@ -198,6 +203,65 @@ zet ΞΆ zeta ΞΆ ~ β‰ˆ ~= β‰ˆ +あ ❀️ +あい ❀️ +い πŸ‘ +いい πŸ‘ +いいね πŸ‘ +え πŸ˜€ πŸ˜„ 😊 +えが πŸ˜€ πŸ˜„ 😊 +えがお πŸ˜€ πŸ˜„ 😊 +こ β˜•οΈ +こー β˜•οΈ +こーひ β˜•οΈ +こーひー β˜•οΈ +さ πŸ‘ +さん πŸ‘ +さんせ πŸ‘ +さんせい πŸ‘ +ば πŸ˜‚ +ばく πŸ˜‚ +ばくし πŸ˜‚ +ばくしょ πŸ˜‚ +ばくしょう πŸ˜‚ +ほ πŸ˜„ 😊 +ほほ πŸ˜„ 😊 +ほほえ πŸ˜„ 😊 +ほほえみ πŸ˜„ 😊 +わ πŸ˜€ πŸ˜‚ +わら πŸ˜€ πŸ˜‚ +わらい πŸ˜€ πŸ˜‚ +γ‚’ ❀️ +γ‚’γ‚€ ❀️ +γ‚€ πŸ‘ +γ‚€γ‚€ πŸ‘ +むむネ πŸ‘ +エ πŸ˜€ πŸ˜„ 😊 +エガ πŸ˜€ πŸ˜„ 😊 +エガγ‚ͺ πŸ˜€ πŸ˜„ 😊 +γ‚³ β˜•οΈ +γ‚³γƒΌ β˜•οΈ +γ‚³γƒΌγƒ’ β˜•οΈ +γ‚³γƒΌγƒ’γƒΌ β˜•οΈ +γ‚΅ πŸ‘ +ァン πŸ‘ +ァンセ πŸ‘ +ァンセむ πŸ‘ +ハ ❀️ +ハー ❀️ +γƒγƒΌγƒˆ ❀️ +バ πŸ˜‚ +バク πŸ˜‚ +バクシ πŸ˜‚ +バクショ πŸ˜‚ +バクショウ πŸ˜‚ +ホ πŸ˜„ 😊 +ホホ πŸ˜„ 😊 +ホホエ πŸ˜„ 😊 +γƒ›γƒ›γ‚¨γƒŸ πŸ˜„ 😊 +γƒ― πŸ˜€ πŸ˜‚ +ワラ πŸ˜€ πŸ˜‚ +ワラむ πŸ˜€ πŸ˜‚ λ”° πŸ‘ 따봉 πŸ‘ λ―Έ πŸ˜„ 😊 @@ -220,6 +284,8 @@ zeta ΞΆ μ’‹μ•„μš” πŸ‘ μ°¬ πŸ‘ μ°¬μ„± πŸ‘ +컀 β˜•οΈ +컀피 β˜•οΈ 폭 πŸ˜‚ ν­μ†Œ πŸ˜‚ ν•˜ ❀️ diff --git a/map/emoji.src b/map/emoji.src index 2b7a844..cccab72 100644 --- a/map/emoji.src +++ b/map/emoji.src @@ -103,9 +103,10 @@ ΞΆ zeta # Small multilingual emoji seed. Shared aliases intentionally produce choices. -πŸ˜€ μ›ƒμŒ 웃닀 슀마일 smile grin -πŸ˜„ μ›ƒμŒ λ―Έμ†Œ 슀마일 smile happy -πŸ˜‚ μ›ƒμŒ ν­μ†Œ 웃겨 joy lol -😊 λ―Έμ†Œ λ°©κΈ‹ smile blush happy -❀️ μ‚¬λž‘ ν•˜νŠΈ heart love -πŸ‘ μ’‹μ•„μš” μ°¬μ„± 따봉 μ—„μ§€ thumbsup like +πŸ˜€ μ›ƒμŒ 웃닀 슀마일 えがお エガγ‚ͺ わらい ワラむ smile grin +πŸ˜„ μ›ƒμŒ λ―Έμ†Œ 슀마일 えがお エガγ‚ͺ ほほえみ γƒ›γƒ›γ‚¨γƒŸ smile happy +πŸ˜‚ μ›ƒμŒ ν­μ†Œ 웃겨 ばくしょう バクショウ わらい ワラむ joy lol +😊 λ―Έμ†Œ λ°©κΈ‹ ほほえみ γƒ›γƒ›γ‚¨γƒŸ えがお エガγ‚ͺ smile blush happy +❀️ μ‚¬λž‘ ν•˜νŠΈ あい γ‚’γ‚€ γƒγƒΌγƒˆ heart love +πŸ‘ μ’‹μ•„μš” μ°¬μ„± 따봉 μ—„μ§€ いいね むむネ さんせい ァンセむ thumbsup like +β˜•οΈ 컀피 こーひー γ‚³γƒΌγƒ’γƒΌ coffee diff --git a/map/mkemoji b/map/mkemoji index 193378a..661997a 100755 --- a/map/mkemoji +++ b/map/mkemoji @@ -38,7 +38,7 @@ def read(path): for field in fields[1:]: alias = fold(field) if (not alias or len(alias) > MAXRUNES or hascontrol(alias) - or alias != alias.strip()): + or alias != alias.strip() or alias.startswith(";")): raise ValueError(f"{path}:{lineno}: bad alias") entries.append((result, alias)) return entries diff --git a/tests/dict_test.c b/tests/dict_test.c index 8476529..4bf8639 100644 --- a/tests/dict_test.c +++ b/tests/dict_test.c @@ -89,3 +89,28 @@ dictionary_misses_clear_result(struct ct *t) hmapfree(lang->dict); lang->dict = saved; } + +void +dictionary_emoji_identity(struct ct *t) +{ + Dictreq req; + Dictres res; + Hmap *saved; + Lang *lang; + Str key; + + lang = getlang(LangEMOJI); + saved = lang->dict; + lang->dict = hmapalloc(2); + key = mkstr("Γ©"); + hmapset(&lang->dict, &key, "Γ©", strlen("Γ©")); + memset(&req, 0, sizeof req); + req.key = key; + req.pre = key; + req.lang = LangEMOJI; + dictlookup(&req, &res); + if(CT_EQ_INT(t, 1, res.nkouho)) + checkstr(t, "emoji identity candidate", "Γ©", &res.kouho[0]); + hmapfree(lang->dict); + lang->dict = saved; +} diff --git a/tests/engine_test.c b/tests/engine_test.c index bb6691a..744fb1f 100644 --- a/tests/engine_test.c +++ b/tests/engine_test.c @@ -404,6 +404,10 @@ emojibegin(Emojifix *f, int showpre) setemoji(&l->dict, "smil", "πŸ˜€ πŸ˜„"); setemoji(&l->dict, "smile", "πŸ˜€ πŸ˜„"); setemoji(&l->dict, "μ›ƒμŒ", "πŸ˜€ πŸ˜„ πŸ˜‚"); + setemoji(&l->dict, "えがお", "πŸ˜€ πŸ˜„ 😊"); + setemoji(&l->dict, "エガγ‚ͺ", "πŸ˜€ πŸ˜„ 😊"); + setemoji(&l->dict, "heart", "❀️"); + setemoji(&l->dict, "coffee", "β˜•οΈ"); setemoji(&l->dict, "^", "ΒΉ Β² Β³ ⁴ ⁡ ⁢ ⁷ ⁸ ⁹ ⁽"); setemoji(&l->dict, "^0", "⁰"); setemoji(&l->dict, "_", "₁ β‚‚ ₃ β‚„ β‚… ₆ ₇ β‚ˆ ₉ ₍"); @@ -698,6 +702,53 @@ engine_emoji_queries(struct ct *t) emojiend(&f); } +void +engine_emoji_japanese_and_multirune(struct ct *t) +{ + Emojifix f; + Str com; + + emojibegin(&f, 0); + init(); + im.l = getlang(LangJP); + sclear(&com); + CT_CHECK(t, keystroke('e', Mctrl, &com)); + if(typekeys(t, "egao", &com)){ + checkstr(t, "localized Hiragana query", "えがお", &search.text); + CT_EQ_INT(t, 3, im.nkouho); + CT_CHECK(t, keystroke(Kesc, 0, &com)); + } + + init(); + im.l = getlang(LangJPK); + sclear(&com); + CT_CHECK(t, keystroke('e', Mctrl, &com)); + if(typekeys(t, "egao", &com)){ + checkstr(t, "localized Katakana query", "エガγ‚ͺ", &search.text); + CT_EQ_INT(t, 3, im.nkouho); + CT_CHECK(t, keystroke(Kesc, 0, &com)); + } + + init(); + im.l = getlang(LangEN); + sclear(&com); + CT_CHECK(t, keystroke('e', Mctrl, &com)); + if(typekeys(t, "heart", &com)){ + CT_EQ_INT(t, 1, im.nkouho); + CT_CHECK(t, keystroke(Kret, 0, &com)); + checkstr(t, "variation-selector emoji", "❀️", &com); + } + + sclear(&com); + CT_CHECK(t, keystroke('e', Mctrl, &com)); + if(typekeys(t, "coffee", &com)){ + CT_EQ_INT(t, 1, im.nkouho); + CT_CHECK(t, keystroke(Kret, 0, &com)); + checkstr(t, "multi-codepoint emoji", "β˜•οΈ", &com); + } + emojiend(&f); +} + void engine_emoji_digit_aliases(struct ct *t) { diff --git a/tests/mkemoji_test.py b/tests/mkemoji_test.py index 60d46ba..852287e 100644 --- a/tests/mkemoji_test.py +++ b/tests/mkemoji_test.py @@ -66,6 +66,7 @@ class MkemojiTest(unittest.TestCase): "x\t a\n", "\0\ta\n", "x\ta\0b\n", + "x\t;hidden\n", "x" * 65 + "\ta\n", "x\t" + "a" * 65 + "\n", ] diff --git a/tests/test.h b/tests/test.h index 91cfcf7..a16b451 100644 --- a/tests/test.h +++ b/tests/test.h @@ -43,6 +43,7 @@ void engine_japanese_backspace_and_boundaries(struct ct*); void engine_katakana_sequences(struct ct*); void engine_emoji_single_candidate(struct ct*); void engine_emoji_queries(struct ct*); +void engine_emoji_japanese_and_multirune(struct ct*); void engine_emoji_digit_aliases(struct ct*); void engine_emoji_navigation(struct ct*); void engine_emoji_preedit_languages(struct ct*); @@ -50,6 +51,7 @@ void engine_emoji_start_and_unknown(struct ct*); void engine_emoji_dictionary_identity(struct ct*); void dictionary_candidates(struct ct*); void dictionary_misses_clear_result(struct ct*); +void dictionary_emoji_identity(struct ct*); void ipc_masks_modifiers(struct ct*); #endif diff --git a/tests/unit_test.c b/tests/unit_test.c index e857557..aecefc8 100644 --- a/tests/unit_test.c +++ b/tests/unit_test.c @@ -92,6 +92,7 @@ static const struct ct_test tests[] = { { "engine/katakana-sequences", engine_katakana_sequences }, { "engine/emoji-single-candidate", engine_emoji_single_candidate }, { "engine/emoji-queries", engine_emoji_queries }, + { "engine/emoji-japanese-multirune", engine_emoji_japanese_and_multirune }, { "engine/emoji-digit-aliases", engine_emoji_digit_aliases }, { "engine/emoji-navigation", engine_emoji_navigation }, { "engine/emoji-preedit-languages", engine_emoji_preedit_languages }, @@ -99,6 +100,7 @@ static const struct ct_test tests[] = { { "engine/emoji-dictionary-identity", engine_emoji_dictionary_identity }, { "dict/candidates", dictionary_candidates }, { "dict/misses-clear-result", dictionary_misses_clear_result }, + { "dict/emoji-identity", dictionary_emoji_identity }, { "ipc/masks-modifiers", ipc_masks_modifiers }, };