fix(engine): compare logical transition state
Avoid reading inactive Str storage when deciding whether to publish a redraw. Keep the focused engine suite compact by retaining one case for each page, navigation, and empty-result invariant.
This commit is contained in:
41
strans.c
41
strans.c
@@ -835,6 +835,41 @@ transition(u32int ks, u32int mod, Str *com)
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
samestate(Im *a, Search *as, Im *b, Search *bs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(a->l != b->l || scmp(&a->pre, &b->pre) != 0 ||
|
||||
scmp(&a->raw, &b->raw) != 0 || a->nkouho != b->nkouho ||
|
||||
a->sel != b->sel || as->lang != bs->lang ||
|
||||
scmp(&as->raw, &bs->raw) != 0 || scmp(&as->text, &bs->text) != 0)
|
||||
return 0;
|
||||
for(i = 0; i < a->nkouho; i++)
|
||||
if(scmp(&a->kouho[i], &b->kouho[i]) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
savestate(Im *p, Search *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(p, 0, sizeof *p);
|
||||
memset(s, 0, sizeof *s);
|
||||
p->l = im.l;
|
||||
sappend(&p->pre, &im.pre);
|
||||
sappend(&p->raw, &im.raw);
|
||||
p->nkouho = im.nkouho;
|
||||
p->sel = im.sel;
|
||||
for(i = 0; i < im.nkouho; i++)
|
||||
sappend(&p->kouho[i], &im.kouho[i]);
|
||||
s->lang = search.lang;
|
||||
sappend(&s->raw, &search.raw);
|
||||
sappend(&s->text, &search.text);
|
||||
}
|
||||
|
||||
static int
|
||||
keystrokeforce(u32int ks, u32int mod, Str *com, int force)
|
||||
{
|
||||
@@ -842,13 +877,11 @@ keystrokeforce(u32int ks, u32int mod, Str *com, int force)
|
||||
Search oldsearch;
|
||||
int eaten, ncom;
|
||||
|
||||
oldim = im;
|
||||
oldsearch = search;
|
||||
savestate(&oldim, &oldsearch);
|
||||
ncom = com->n;
|
||||
eaten = transition(ks, mod, com);
|
||||
if(force || eaten || com->n != ncom ||
|
||||
memcmp(&oldim, &im, sizeof im) != 0 ||
|
||||
memcmp(&oldsearch, &search, sizeof search) != 0)
|
||||
!samestate(&oldim, &oldsearch, &im, &search))
|
||||
redraw();
|
||||
return eaten;
|
||||
}
|
||||
|
||||
@@ -742,32 +742,20 @@ engine_candidate_page_metadata(struct ct *t)
|
||||
int shown;
|
||||
int local;
|
||||
} cases[] = {
|
||||
{ 1, 0, 0, 1, 0 },
|
||||
{ 9, 8, 0, 9, 8 },
|
||||
{ 10, 8, 0, 9, 8 },
|
||||
{ 10, 9, 9, 1, 0 },
|
||||
{ 18, 8, 0, 9, 8 },
|
||||
{ 18, 17, 9, 9, 8 },
|
||||
{ 19, 0, 0, 9, 0 },
|
||||
{ 32, 8, 0, 9, 8 },
|
||||
{ 32, 17, 9, 9, 8 },
|
||||
{ 32, 26, 18, 9, 8 },
|
||||
{ 32, 31, 27, 5, 4 },
|
||||
};
|
||||
Drawcmd dc;
|
||||
int i;
|
||||
|
||||
/* A clearing draw is the observable zero-candidate snapshot. */
|
||||
candidatebegin(1);
|
||||
redraw();
|
||||
draindraw(nil);
|
||||
setcandidates(0);
|
||||
redraw();
|
||||
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||
CT_EQ_INT(t, 0, dc.nkouho);
|
||||
CT_EQ_INT(t, -1, dc.sel);
|
||||
CT_EQ_INT(t, 0, dc.first);
|
||||
CT_EQ_INT(t, 0, dc.total);
|
||||
}
|
||||
|
||||
for(i = 0; i < nelem(cases); i++){
|
||||
candidatebegin(cases[i].total);
|
||||
im.sel = cases[i].sel;
|
||||
@@ -779,19 +767,19 @@ engine_candidate_page_metadata(struct ct *t)
|
||||
void
|
||||
engine_candidate_page_snapshots(struct ct *t)
|
||||
{
|
||||
static int totals[] = { 0, 1, 9, 10, 18, 19, 32 };
|
||||
int i, n;
|
||||
Drawcmd dc;
|
||||
|
||||
for(i = 0; i < nelem(totals); i++){
|
||||
candidatebegin(totals[i]);
|
||||
CT_EQ_INT(t, totals[i] == 0 ? -1 : 0, im.sel);
|
||||
if(totals[i] == 0){
|
||||
/* Clearing a visible popup must publish an empty snapshot. */
|
||||
candidatebegin(1);
|
||||
redraw();
|
||||
CT_EQ_INT(t, 0, draindraw(nil));
|
||||
continue;
|
||||
}
|
||||
n = totals[i] < Maxdisp ? totals[i] : Maxdisp;
|
||||
checkcandidatepage(t, "default candidate page", 0, n, 0);
|
||||
draindraw(nil);
|
||||
setcandidates(0);
|
||||
redraw();
|
||||
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||
CT_EQ_INT(t, 0, dc.nkouho);
|
||||
CT_EQ_INT(t, -1, dc.sel);
|
||||
CT_EQ_INT(t, 0, dc.first);
|
||||
CT_EQ_INT(t, 0, dc.total);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1416,8 +1404,7 @@ engine_emoji_digit_aliases(struct ct *t)
|
||||
checkstr(t, "missing number commit", "", &com);
|
||||
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);
|
||||
CT_CHECK(t, keystroke(Kesc, 0, &com));
|
||||
}
|
||||
searchend(&f);
|
||||
}
|
||||
@@ -1428,7 +1415,6 @@ engine_emoji_navigation(struct ct *t)
|
||||
Drawcmd dc = {0};
|
||||
Searchfix f;
|
||||
Str com;
|
||||
int i;
|
||||
|
||||
emojibegin(&f, 0);
|
||||
sclear(&com);
|
||||
@@ -1436,8 +1422,7 @@ engine_emoji_navigation(struct ct *t)
|
||||
if(typekeys(t, "many", &com)){
|
||||
CT_EQ_INT(t, 12, im.nkouho);
|
||||
CT_EQ_INT(t, 0, im.sel);
|
||||
for(i = 0; i < Maxdisp; i++)
|
||||
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||
CT_CHECK(t, keystroke(Kpgdown, 0, &com));
|
||||
CT_EQ_INT(t, Maxdisp, im.sel);
|
||||
CT_CHECK(t, draindraw(&dc) > 0);
|
||||
checkstr(t, "second-page first row", "c10", &dc.kouho[0]);
|
||||
@@ -1448,16 +1433,6 @@ engine_emoji_navigation(struct ct *t)
|
||||
checkstr(t, "second-page row one", "c10", &com);
|
||||
}
|
||||
|
||||
sclear(&com);
|
||||
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||
if(typekeys(t, "many", &com)){
|
||||
for(i = 0; i < 11; i++)
|
||||
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||
CT_EQ_INT(t, 11, im.sel);
|
||||
CT_CHECK(t, keystroke('3', 0, &com));
|
||||
checkstr(t, "short-page row three", "c12", &com);
|
||||
}
|
||||
|
||||
sclear(&com);
|
||||
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||
if(typekeys(t, "smile", &com)){
|
||||
@@ -1466,12 +1441,7 @@ engine_emoji_navigation(struct ct *t)
|
||||
CT_EQ_INT(t, 1, im.sel);
|
||||
CT_CHECK(t, keystroke(Ktab, 0, &com));
|
||||
CT_EQ_INT(t, 0, im.sel);
|
||||
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
||||
CT_EQ_INT(t, 1, im.sel);
|
||||
CT_CHECK(t, keystroke(Kup, 0, &com));
|
||||
CT_EQ_INT(t, 0, im.sel);
|
||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||
checkstr(t, "navigated candidate", "😀", &com);
|
||||
CT_CHECK(t, keystroke(Kesc, 0, &com));
|
||||
}
|
||||
searchend(&f);
|
||||
}
|
||||
@@ -1603,22 +1573,6 @@ engine_emoji_start_and_unknown(struct ct *t)
|
||||
int i;
|
||||
|
||||
emojibegin(&f, 0);
|
||||
sclear(&com);
|
||||
if(typekeys(t, "dkssud", &com)){
|
||||
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||
checkstr(t, "committed Korean preedit", "안녕", &com);
|
||||
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.lang);
|
||||
CT_EQ_INT(t, LangKO, im.l->lang);
|
||||
}
|
||||
}
|
||||
|
||||
sclear(&com);
|
||||
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||
if(typekeys(t, "xyz", &com)){
|
||||
@@ -1713,41 +1667,33 @@ cleanup:
|
||||
void
|
||||
engine_hanja_unknown_and_cancel(struct ct *t)
|
||||
{
|
||||
static const struct {
|
||||
char *keys;
|
||||
char *text;
|
||||
} empty[] = {
|
||||
{ "rmf", "글" },
|
||||
{ "r", "ㄱ" },
|
||||
{ "gksrmf", "한글" },
|
||||
};
|
||||
Searchfix f;
|
||||
Str com;
|
||||
int i;
|
||||
|
||||
hanjabegin(&f, LangKO);
|
||||
for(i = 0; i < nelem(empty); i++){
|
||||
sclear(&com);
|
||||
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
|
||||
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)) ||
|
||||
!typekeys(t, empty[i].keys, &com))
|
||||
goto cleanup;
|
||||
if(!typekeys(t, "rmf", &com))
|
||||
goto cleanup;
|
||||
checkstr(t, "unknown Hanja reading", "글", &search.text);
|
||||
checkstr(t, "Hanja reading without candidates",
|
||||
empty[i].text, &search.text);
|
||||
CT_EQ_INT(t, 0, im.nkouho);
|
||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
||||
checkstr(t, "unknown Hanja commit", "글", &com);
|
||||
checkstr(t, "Hanja commit without candidates",
|
||||
empty[i].text, &com);
|
||||
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)))
|
||||
|
||||
Reference in New Issue
Block a user