hanja: separate temporary search mode

This commit is contained in:
2026-08-12 21:23:10 +09:00
parent 4e1c15dde4
commit 136695a900
6 changed files with 216 additions and 195 deletions

View File

@@ -421,15 +421,17 @@ engine_direct_language_modes(struct ct *t)
CT_EQ_INT(t, 0, im.pre.n);
CT_EQ_INT(t, 0, im.raw.n);
CT_CHECK(t, keystroke('e', Mctrl, &com));
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, LangEN, im.l->lang);
CT_CHECK(t, keystroke(Kesc, 0, &com));
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_CHECK(t, keystroke('s', Mctrl, &com));
CT_EQ_INT(t, LangKO, im.l->lang);
CT_EQ_PTR(t, nil, im.l->mapname);
CT_EQ_PTR(t, nil, im.l->map);
CT_EQ_PTR(t, nil, im.l->dictname);
CT_EQ_PTR(t, nil, im.l->dictq);
CT_CHECK(t, strcmp(getlang(LangHANJA)->dictname, "hanja") == 0);
CT_CHECK(t, keystroke('r', 0, &com));
checkstr(t, "Korean without map", "", &im.pre);
CT_CHECK(t, keystroke(Kback, 0, &com));
@@ -509,11 +511,12 @@ engine_language_switch_state(struct ct *t)
vi->map = saved;
}
typedef struct Emojifix Emojifix;
struct Emojifix
typedef struct Searchfix Searchfix;
struct Searchfix
{
Im im;
Search search;
Lang *dictlang;
Hmap *dict;
int popup;
int visible;
@@ -544,33 +547,37 @@ setdict(Hmap **dict, char *key, char *val)
}
static void
emojibegin(Emojifix *f, int showpre)
searchsave(Searchfix *f, int lang)
{
Lang *l;
l = getlang(LangEMOJI);
f->im = im;
f->search = search;
f->dict = l->dict;
f->dictlang = getlang(lang);
f->dict = f->dictlang->dict;
f->popup = popup;
f->visible = visible;
draindraw(nil);
l->dict = hmapalloc(32);
setdict(&l->dict, "a", "A B");
setdict(&l->dict, "", "B C");
setdict(&l->dict, "alpha", "α");
setdict(&l->dict, "smil", "😀 😄");
setdict(&l->dict, "smile", "😀 😄");
setdict(&l->dict, "웃음", "😀 😄 😂");
setdict(&l->dict, "えがお", "😀 😄 😊");
setdict(&l->dict, "エガオ", "😀 😄 😊");
setdict(&l->dict, "heart", "❤️");
setdict(&l->dict, "coffee", "☕️");
setdict(&l->dict, "^", "¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁽");
setdict(&l->dict, "^0", "");
setdict(&l->dict, "_", "₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₍");
setdict(&l->dict, "<", "← ≤ ♥ ≠");
setdict(&l->dict, "many",
}
static void
emojibegin(Searchfix *f, int showpre)
{
searchsave(f, LangEMOJI);
f->dictlang->dict = hmapalloc(32);
setdict(&f->dictlang->dict, "a", "A B");
setdict(&f->dictlang->dict, "", "B C");
setdict(&f->dictlang->dict, "alpha", "α");
setdict(&f->dictlang->dict, "smil", "😀 😄");
setdict(&f->dictlang->dict, "smile", "😀 😄");
setdict(&f->dictlang->dict, "웃음", "😀 😄 😂");
setdict(&f->dictlang->dict, "えがお", "😀 😄 😊");
setdict(&f->dictlang->dict, "エガオ", "😀 😄 😊");
setdict(&f->dictlang->dict, "heart", "❤️");
setdict(&f->dictlang->dict, "coffee", "☕️");
setdict(&f->dictlang->dict, "^", "¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁽");
setdict(&f->dictlang->dict, "^0", "");
setdict(&f->dictlang->dict, "_", "₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₍");
setdict(&f->dictlang->dict, "<", "← ≤ ♥ ≠");
setdict(&f->dictlang->dict, "many",
"c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12");
init();
im.l = getlang(LangKO);
@@ -578,14 +585,12 @@ emojibegin(Emojifix *f, int showpre)
}
static void
emojiend(Emojifix *f)
searchend(Searchfix *f)
{
Lang *l;
Hmap *dict;
l = getlang(LangEMOJI);
dict = l->dict;
l->dict = f->dict;
dict = f->dictlang->dict;
f->dictlang->dict = f->dict;
hmapfree(dict);
draindraw(nil);
im = f->im;
@@ -594,50 +599,18 @@ emojiend(Emojifix *f)
visible = f->visible;
}
typedef struct Hanjafix Hanjafix;
struct Hanjafix
{
Im im;
Search search;
Hmap *dict;
int popup;
int visible;
};
static void
hanjabegin(Hanjafix *f)
hanjabegin(Searchfix *f, int lang)
{
Lang *l;
l = getlang(LangKO);
f->im = im;
f->search = search;
f->dict = l->dict;
f->popup = popup;
f->visible = visible;
draindraw(nil);
l->dict = hmapalloc(8);
setdict(&l->dict, "", "漢 韓");
setdict(&l->dict, "", "");
searchsave(f, LangHANJA);
f->dictlang->dict = hmapalloc(8);
setdict(&f->dictlang->dict, "", "漢 韓");
setdict(&f->dictlang->dict, "", "");
setdict(&f->dictlang->dict, "", "");
setdict(&f->dictlang->dict, "한글", "");
setdict(&f->dictlang->dict, "", "");
init();
im.l = l;
}
static void
hanjaend(Hanjafix *f)
{
Lang *l;
Hmap *dict;
l = getlang(LangKO);
dict = l->dict;
l->dict = f->dict;
hmapfree(dict);
draindraw(nil);
im = f->im;
search = f->search;
popup = f->popup;
visible = f->visible;
im.l = getlang(lang);
}
static int
@@ -817,7 +790,7 @@ void
engine_emoji_single_candidate(struct ct *t)
{
Drawcmd dc = {0};
Emojifix f;
Searchfix f;
Str com;
emojibegin(&f, 1);
@@ -825,12 +798,12 @@ engine_emoji_single_candidate(struct ct *t)
CT_CHECK(t, keystroke('p', Mctrl, &com));
CT_EQ_INT(t, 0, popup);
CT_CHECK(t, keystroke('e', Mctrl, &com));
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
if(typekeys(t, "alpha", &com)){
checkstr(t, "no automatic commit", "", &com);
checkstr(t, "raw English query", "alpha", &search.text);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, 1, im.nkouho);
checkstr(t, "single candidate", "α", &im.kouho[0]);
CT_CHECK(t, draindraw(&dc) > 0);
@@ -838,21 +811,21 @@ engine_emoji_single_candidate(struct ct *t)
CT_EQ_INT(t, 1, dc.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "explicit candidate commit", "α", &com);
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
show();
CT_CHECK(t, draindraw(&dc) > 0);
CT_EQ_INT(t, 0, dc.pre.n);
CT_EQ_INT(t, 0, dc.nkouho);
}
emojiend(&f);
searchend(&f);
}
void
engine_emoji_queries(struct ct *t)
{
Drawcmd dc = {0};
Emojifix f;
Searchfix f;
Str com;
emojibegin(&f, 1);
@@ -900,16 +873,16 @@ engine_emoji_queries(struct ct *t)
CT_EQ_INT(t, 3, dc.nkouho);
CT_CHECK(t, keystroke(Kesc, 0, &com));
checkstr(t, "cancel commit", "", &com);
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
}
emojiend(&f);
searchend(&f);
}
void
engine_emoji_japanese_and_multirune(struct ct *t)
{
Emojifix f;
Searchfix f;
Str com;
emojibegin(&f, 0);
@@ -950,7 +923,7 @@ engine_emoji_japanese_and_multirune(struct ct *t)
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "multi-codepoint emoji", "☕️", &com);
}
emojiend(&f);
searchend(&f);
}
void
@@ -966,7 +939,7 @@ engine_emoji_digit_aliases(struct ct *t)
{ "_2", '_', '2', "" },
{ "<3", '<', '3', "" },
};
Emojifix f;
Searchfix f;
Str com;
int i;
@@ -978,7 +951,7 @@ engine_emoji_digit_aliases(struct ct *t)
CT_CHECK(t, im.nkouho >= cases[i].digit - '0');
CT_CHECK(t, keystroke(cases[i].digit, 0, &com));
checkstr(t, cases[i].name, cases[i].want, &com);
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
}
@@ -998,19 +971,19 @@ engine_emoji_digit_aliases(struct ct *t)
CT_CHECK(t, keystroke('9', 0, &com));
checkstr(t, "missing number query", "smile9", &search.text);
checkstr(t, "missing number commit", "", &com);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, 0, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "missing number text", "smile9", &com);
}
emojiend(&f);
searchend(&f);
}
void
engine_emoji_navigation(struct ct *t)
{
Drawcmd dc = {0};
Emojifix f;
Searchfix f;
Str com;
int i;
@@ -1054,13 +1027,13 @@ engine_emoji_navigation(struct ct *t)
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "navigated candidate", "😄", &com);
}
emojiend(&f);
searchend(&f);
}
void
engine_emoji_preedit_languages(struct ct *t)
{
Emojifix f;
Searchfix f;
Str com, shown;
int p;
@@ -1074,26 +1047,26 @@ engine_emoji_preedit_languages(struct ct *t)
checkstr(t, "modifier preserves Japanese", "", &shown);
CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com));
checkstr(t, "committed Japanese preedit", "", &com);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, LangJP, im.l->lang);
CT_CHECK(t, keystroke('E', Mctrl|Malt, &com));
CT_EQ_INT(t, SearchOff, search.kind);
CT_CHECK(t, !keystroke('E', Mctrl|Malt, &com));
CT_EQ_INT(t, 0, search.lang);
CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com));
CT_CHECK(t, keystroke('E', Mctrl|Msuper, &com));
CT_EQ_INT(t, SearchOff, search.kind);
CT_CHECK(t, !keystroke('E', Mctrl|Msuper, &com));
CT_EQ_INT(t, 0, search.lang);
CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com));
CT_EQ_INT(t, LangJP, im.l->lang);
CT_CHECK(t, keystroke('a', 0, &com));
p = popup;
CT_CHECK(t, !keystroke(Kmodfirst+2, 0, &com));
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
checkstr(t, "modifier preserves search", "a", &search.text);
CT_CHECK(t, keystroke('P', Mctrl|Mshift, &com));
CT_EQ_INT(t, !p, popup);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_CHECK(t, !keystroke(Kmodfirst+2, 0, &com));
CT_CHECK(t, keystroke('E', Mctrl|Mshift, &com));
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
sclear(&com);
if(typekeys(t, "na", &com)){
shown = shownpre(&im);
@@ -1123,7 +1096,7 @@ engine_emoji_preedit_languages(struct ct *t)
CT_CHECK(t, keystroke('e', Mctrl, &com));
checkstr(t, "committed Telex preedit", "á", &com);
CT_CHECK(t, keystroke(Kesc, 0, &com));
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_PTR(t, &testvi, im.l);
sclear(&com);
if(typekeys(t, "as", &com)){
@@ -1132,13 +1105,13 @@ engine_emoji_preedit_languages(struct ct *t)
checkstr(t, "Telex raw resumed", "as", &im.raw);
}
}
emojiend(&f);
searchend(&f);
}
void
engine_emoji_start_and_unknown(struct ct *t)
{
Emojifix f;
Searchfix f;
Str com;
char want[Maxrunes+1];
int i;
@@ -1148,14 +1121,14 @@ engine_emoji_start_and_unknown(struct ct *t)
if(typekeys(t, "dkssud", &com)){
CT_CHECK(t, keystroke('e', Mctrl, &com));
checkstr(t, "committed Korean preedit", "안녕", &com);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
if(typekeys(t, "xyz", &com)){
checkstr(t, "unknown displayed query", "xyz", &search.text);
CT_EQ_INT(t, 0, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "unknown query commit", "안녕xyz", &com);
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
}
}
@@ -1165,7 +1138,7 @@ engine_emoji_start_and_unknown(struct ct *t)
if(typekeys(t, "xyz", &com)){
CT_CHECK(t, !keystroke(Kspec|0x51, 0, &com));
checkstr(t, "special commits shown query", "xyz", &com);
CT_CHECK(t, !search.kind);
CT_CHECK(t, !search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
}
@@ -1174,20 +1147,20 @@ engine_emoji_start_and_unknown(struct ct *t)
for(i = 0; i < Maxrunes; i++)
CT_CHECK(t, keystroke('q', 0, &com));
CT_EQ_INT(t, Maxrunes, search.raw.n);
CT_CHECK(t, search.kind);
CT_CHECK(t, search.lang);
CT_CHECK(t, !keystroke('z', 0, &com));
memset(want, 'q', Maxrunes);
want[Maxrunes] = '\0';
checkstr(t, "bounded query commit", want, &com);
CT_CHECK(t, !search.kind);
emojiend(&f);
CT_CHECK(t, !search.lang);
searchend(&f);
}
void
engine_emoji_dictionary_identity(struct ct *t)
{
Dictres res;
Emojifix f;
Searchfix f;
emojibegin(&f, 0);
im.pre = mkstr("same");
@@ -1210,31 +1183,31 @@ engine_emoji_dictionary_identity(struct ct *t)
checkstr(t, "wrong preedit ignored", "old", &im.kouho[0]);
res.key = im.pre;
search.kind = SearchEmoji;
search.lang = LangEMOJI;
dictresult(&res);
CT_EQ_INT(t, 1, im.nkouho);
checkstr(t, "search response ignored", "old", &im.kouho[0]);
search.kind = SearchOff;
search.lang = 0;
res.kouho[0] = mkstr("right");
dictresult(&res);
CT_EQ_INT(t, 1, im.nkouho);
CT_EQ_INT(t, -1, im.sel);
checkstr(t, "matching response accepted", "right", &im.kouho[0]);
emojiend(&f);
searchend(&f);
}
void
engine_hanja_search(struct ct *t)
{
Hanjafix f;
Searchfix f;
Str com;
hanjabegin(&f);
hanjabegin(&f, LangKO);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
CT_EQ_INT(t, SearchHanja, search.kind);
CT_EQ_INT(t, LangHANJA, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
if(!typekeys(t, "gks", &com))
goto cleanup;
@@ -1244,19 +1217,19 @@ engine_hanja_search(struct ct *t)
CT_CHECK(t, keystroke(Kdown, 0, &com));
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "navigated Hanja", "", &com);
CT_EQ_INT(t, SearchOff, search.kind);
CT_EQ_INT(t, 0, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
cleanup:
hanjaend(&f);
searchend(&f);
}
void
engine_hanja_unknown_and_cancel(struct ct *t)
{
Hanjafix f;
Searchfix f;
Str com;
hanjabegin(&f);
hanjabegin(&f, LangKO);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
@@ -1266,9 +1239,29 @@ engine_hanja_unknown_and_cancel(struct ct *t)
CT_EQ_INT(t, 0, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "unknown Hanja commit", "", &com);
CT_EQ_INT(t, SearchOff, search.kind);
CT_EQ_INT(t, 0, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
if(!typekeys(t, "r", &com))
goto cleanup;
checkstr(t, "incomplete Hanja reading", "", &search.text);
CT_EQ_INT(t, 0, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "incomplete Hanja commit", "", &com);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
if(!typekeys(t, "gksrmf", &com))
goto cleanup;
checkstr(t, "multiple Hanja syllables", "한글", &search.text);
CT_EQ_INT(t, 0, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "multiple Hanja syllable commit", "한글", &com);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
@@ -1277,25 +1270,25 @@ engine_hanja_unknown_and_cancel(struct ct *t)
CT_EQ_INT(t, 2, im.nkouho);
CT_CHECK(t, keystroke(Kesc, 0, &com));
checkstr(t, "cancelled Hanja", "", &com);
CT_EQ_INT(t, SearchOff, search.kind);
CT_EQ_INT(t, 0, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang);
sclear(&com);
CT_CHECK(t, keystroke('h', Mctrl, &com));
CT_EQ_INT(t, SearchHanja, search.kind);
CT_EQ_INT(t, LangHANJA, search.lang);
CT_CHECK(t, keystroke('h', Mctrl, &com));
CT_EQ_INT(t, SearchOff, search.kind);
CT_EQ_INT(t, 0, search.lang);
cleanup:
hanjaend(&f);
searchend(&f);
}
void
engine_hanja_korean_keys(struct ct *t)
{
Hanjafix f;
Searchfix f;
Str com;
hanjabegin(&f);
hanjabegin(&f, LangKO);
sclear(&com);
CT_CHECK(t, keystroke('h', Mctrl, &com));
CT_CHECK(t, keystroke('r', Mshift, &com));
@@ -1309,38 +1302,69 @@ engine_hanja_korean_keys(struct ct *t)
checkstr(t, "Caps Lock Hanja reading", "", &search.text);
CT_EQ_INT(t, 1, im.nkouho);
CT_CHECK(t, keystroke(Kesc, 0, &com));
hanjaend(&f);
searchend(&f);
}
void
engine_hanja_korean_only(struct ct *t)
engine_hanja_input_languages(struct ct *t)
{
Hmap *dict;
Lang *l;
Str com, shown;
Searchfix f;
Str com;
hanjabegin(&f, LangEN);
sclear(&com);
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
if(!typekeys(t, "gks", &com))
goto cleanup;
checkstr(t, "English Hanja input", "gks", &search.text);
CT_EQ_INT(t, 0, im.nkouho);
CT_EQ_INT(t, LangEN, im.l->lang);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "English Hanja commit", "gks", &com);
CT_EQ_INT(t, LangEN, im.l->lang);
init();
im.l = getlang(LangJP);
sclear(&com);
if(typekeys(t, "ka", &com)){
CT_CHECK(t, !keystroke('h', Mctrl, &com));
CT_CHECK(t, !search.kind);
CT_EQ_INT(t, LangJP, im.l->lang);
shown = shownpre(&im);
checkstr(t, "non-Korean Ctrl-H reset", "", &shown);
checkstr(t, "non-Korean Ctrl-H commit", "", &com);
}
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
goto cleanup;
if(!typekeys(t, "ka", &com))
goto cleanup;
checkstr(t, "Japanese Hanja input", "", &search.text);
CT_EQ_INT(t, 0, im.nkouho);
CT_EQ_INT(t, LangJP, im.l->lang);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "Japanese Hanja commit", "", &com);
CT_EQ_INT(t, LangJP, im.l->lang);
l = getlang(LangKO);
dict = l->dict;
l->dict = nil;
init();
im.l = l;
im.l = getlang(LangEN);
sclear(&com);
CT_CHECK(t, keystroke('h', Mctrl, &com));
CT_EQ_INT(t, SearchHanja, search.kind);
CT_CHECK(t, keystroke(Kesc, 0, &com));
l->dict = dict;
CT_CHECK(t, keystroke(L'', 0, &com));
checkstr(t, "direct Hanja input", "", &search.text);
CT_EQ_INT(t, 2, im.nkouho);
CT_CHECK(t, keystroke(Kret, 0, &com));
checkstr(t, "direct Hanja selection", "", &com);
CT_EQ_INT(t, LangEN, im.l->lang);
init();
im.l = getlang(LangJP);
sclear(&com);
CT_CHECK(t, keystroke('h', Mctrl, &com));
if(!typekeys(t, "ka", &com))
goto cleanup;
CT_CHECK(t, !keystroke('e', Mctrl|Malt, &com));
checkstr(t, "modified search boundary", "", &com);
CT_EQ_INT(t, 0, search.lang);
CT_EQ_INT(t, LangJP, im.l->lang);
sclear(&com);
CT_CHECK(t, !keystroke('h', Mctrl|Msuper, &com));
CT_EQ_INT(t, 0, search.lang);
CT_EQ_INT(t, LangJP, im.l->lang);
cleanup:
searchend(&f);
}
static u32int
@@ -1364,7 +1388,7 @@ engine_randomized_stress(struct ct *t)
'u', 'w', 'y', '1', '2', '9', '\'', ' ', L'',
};
static Rune modes[] = { 't', 'n', 'k', 's', 'v' };
Emojifix f;
Searchfix f;
Lang *vi;
Trie *vimap;
Keyres res;
@@ -1452,7 +1476,7 @@ engine_randomized_stress(struct ct *t)
break;
}
}
emojiend(&f);
searchend(&f);
vi->map = vimap;
}