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;
|
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
|
static int
|
||||||
keystrokeforce(u32int ks, u32int mod, Str *com, int force)
|
keystrokeforce(u32int ks, u32int mod, Str *com, int force)
|
||||||
{
|
{
|
||||||
@@ -842,13 +877,11 @@ keystrokeforce(u32int ks, u32int mod, Str *com, int force)
|
|||||||
Search oldsearch;
|
Search oldsearch;
|
||||||
int eaten, ncom;
|
int eaten, ncom;
|
||||||
|
|
||||||
oldim = im;
|
savestate(&oldim, &oldsearch);
|
||||||
oldsearch = search;
|
|
||||||
ncom = com->n;
|
ncom = com->n;
|
||||||
eaten = transition(ks, mod, com);
|
eaten = transition(ks, mod, com);
|
||||||
if(force || eaten || com->n != ncom ||
|
if(force || eaten || com->n != ncom ||
|
||||||
memcmp(&oldim, &im, sizeof im) != 0 ||
|
!samestate(&oldim, &oldsearch, &im, &search))
|
||||||
memcmp(&oldsearch, &search, sizeof search) != 0)
|
|
||||||
redraw();
|
redraw();
|
||||||
return eaten;
|
return eaten;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -742,32 +742,20 @@ engine_candidate_page_metadata(struct ct *t)
|
|||||||
int shown;
|
int shown;
|
||||||
int local;
|
int local;
|
||||||
} cases[] = {
|
} cases[] = {
|
||||||
|
{ 1, 0, 0, 1, 0 },
|
||||||
{ 9, 8, 0, 9, 8 },
|
{ 9, 8, 0, 9, 8 },
|
||||||
{ 10, 8, 0, 9, 8 },
|
{ 10, 8, 0, 9, 8 },
|
||||||
{ 10, 9, 9, 1, 0 },
|
{ 10, 9, 9, 1, 0 },
|
||||||
{ 18, 8, 0, 9, 8 },
|
{ 18, 8, 0, 9, 8 },
|
||||||
{ 18, 17, 9, 9, 8 },
|
{ 18, 17, 9, 9, 8 },
|
||||||
|
{ 19, 0, 0, 9, 0 },
|
||||||
{ 32, 8, 0, 9, 8 },
|
{ 32, 8, 0, 9, 8 },
|
||||||
{ 32, 17, 9, 9, 8 },
|
{ 32, 17, 9, 9, 8 },
|
||||||
{ 32, 26, 18, 9, 8 },
|
{ 32, 26, 18, 9, 8 },
|
||||||
{ 32, 31, 27, 5, 4 },
|
{ 32, 31, 27, 5, 4 },
|
||||||
};
|
};
|
||||||
Drawcmd dc;
|
|
||||||
int i;
|
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++){
|
for(i = 0; i < nelem(cases); i++){
|
||||||
candidatebegin(cases[i].total);
|
candidatebegin(cases[i].total);
|
||||||
im.sel = cases[i].sel;
|
im.sel = cases[i].sel;
|
||||||
@@ -779,19 +767,19 @@ engine_candidate_page_metadata(struct ct *t)
|
|||||||
void
|
void
|
||||||
engine_candidate_page_snapshots(struct ct *t)
|
engine_candidate_page_snapshots(struct ct *t)
|
||||||
{
|
{
|
||||||
static int totals[] = { 0, 1, 9, 10, 18, 19, 32 };
|
Drawcmd dc;
|
||||||
int i, n;
|
|
||||||
|
|
||||||
for(i = 0; i < nelem(totals); i++){
|
/* Clearing a visible popup must publish an empty snapshot. */
|
||||||
candidatebegin(totals[i]);
|
candidatebegin(1);
|
||||||
CT_EQ_INT(t, totals[i] == 0 ? -1 : 0, im.sel);
|
|
||||||
if(totals[i] == 0){
|
|
||||||
redraw();
|
redraw();
|
||||||
CT_EQ_INT(t, 0, draindraw(nil));
|
draindraw(nil);
|
||||||
continue;
|
setcandidates(0);
|
||||||
}
|
redraw();
|
||||||
n = totals[i] < Maxdisp ? totals[i] : Maxdisp;
|
if(CT_CHECK(t, draindraw(&dc) > 0)){
|
||||||
checkcandidatepage(t, "default candidate page", 0, n, 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);
|
checkstr(t, "missing number commit", "", &com);
|
||||||
CT_CHECK(t, search.lang);
|
CT_CHECK(t, search.lang);
|
||||||
CT_EQ_INT(t, 0, im.nkouho);
|
CT_EQ_INT(t, 0, im.nkouho);
|
||||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
CT_CHECK(t, keystroke(Kesc, 0, &com));
|
||||||
checkstr(t, "missing number text", "smile9", &com);
|
|
||||||
}
|
}
|
||||||
searchend(&f);
|
searchend(&f);
|
||||||
}
|
}
|
||||||
@@ -1428,7 +1415,6 @@ engine_emoji_navigation(struct ct *t)
|
|||||||
Drawcmd dc = {0};
|
Drawcmd dc = {0};
|
||||||
Searchfix f;
|
Searchfix f;
|
||||||
Str com;
|
Str com;
|
||||||
int i;
|
|
||||||
|
|
||||||
emojibegin(&f, 0);
|
emojibegin(&f, 0);
|
||||||
sclear(&com);
|
sclear(&com);
|
||||||
@@ -1436,8 +1422,7 @@ engine_emoji_navigation(struct ct *t)
|
|||||||
if(typekeys(t, "many", &com)){
|
if(typekeys(t, "many", &com)){
|
||||||
CT_EQ_INT(t, 12, im.nkouho);
|
CT_EQ_INT(t, 12, im.nkouho);
|
||||||
CT_EQ_INT(t, 0, im.sel);
|
CT_EQ_INT(t, 0, im.sel);
|
||||||
for(i = 0; i < Maxdisp; i++)
|
CT_CHECK(t, keystroke(Kpgdown, 0, &com));
|
||||||
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
|
||||||
CT_EQ_INT(t, Maxdisp, im.sel);
|
CT_EQ_INT(t, Maxdisp, im.sel);
|
||||||
CT_CHECK(t, draindraw(&dc) > 0);
|
CT_CHECK(t, draindraw(&dc) > 0);
|
||||||
checkstr(t, "second-page first row", "c10", &dc.kouho[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);
|
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);
|
sclear(&com);
|
||||||
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
if(typekeys(t, "smile", &com)){
|
if(typekeys(t, "smile", &com)){
|
||||||
@@ -1466,12 +1441,7 @@ engine_emoji_navigation(struct ct *t)
|
|||||||
CT_EQ_INT(t, 1, im.sel);
|
CT_EQ_INT(t, 1, im.sel);
|
||||||
CT_CHECK(t, keystroke(Ktab, 0, &com));
|
CT_CHECK(t, keystroke(Ktab, 0, &com));
|
||||||
CT_EQ_INT(t, 0, im.sel);
|
CT_EQ_INT(t, 0, im.sel);
|
||||||
CT_CHECK(t, keystroke(Kdown, 0, &com));
|
CT_CHECK(t, keystroke(Kesc, 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);
|
|
||||||
}
|
}
|
||||||
searchend(&f);
|
searchend(&f);
|
||||||
}
|
}
|
||||||
@@ -1603,22 +1573,6 @@ engine_emoji_start_and_unknown(struct ct *t)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
emojibegin(&f, 0);
|
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);
|
sclear(&com);
|
||||||
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
CT_CHECK(t, keystroke('e', Mctrl, &com));
|
||||||
if(typekeys(t, "xyz", &com)){
|
if(typekeys(t, "xyz", &com)){
|
||||||
@@ -1713,41 +1667,33 @@ cleanup:
|
|||||||
void
|
void
|
||||||
engine_hanja_unknown_and_cancel(struct ct *t)
|
engine_hanja_unknown_and_cancel(struct ct *t)
|
||||||
{
|
{
|
||||||
|
static const struct {
|
||||||
|
char *keys;
|
||||||
|
char *text;
|
||||||
|
} empty[] = {
|
||||||
|
{ "rmf", "글" },
|
||||||
|
{ "r", "ㄱ" },
|
||||||
|
{ "gksrmf", "한글" },
|
||||||
|
};
|
||||||
Searchfix f;
|
Searchfix f;
|
||||||
Str com;
|
Str com;
|
||||||
|
int i;
|
||||||
|
|
||||||
hanjabegin(&f, LangKO);
|
hanjabegin(&f, LangKO);
|
||||||
|
for(i = 0; i < nelem(empty); i++){
|
||||||
sclear(&com);
|
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;
|
goto cleanup;
|
||||||
if(!typekeys(t, "rmf", &com))
|
checkstr(t, "Hanja reading without candidates",
|
||||||
goto cleanup;
|
empty[i].text, &search.text);
|
||||||
checkstr(t, "unknown Hanja reading", "글", &search.text);
|
|
||||||
CT_EQ_INT(t, 0, im.nkouho);
|
CT_EQ_INT(t, 0, im.nkouho);
|
||||||
CT_CHECK(t, keystroke(Kret, 0, &com));
|
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, 0, search.lang);
|
||||||
CT_EQ_INT(t, LangKO, im.l->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);
|
sclear(&com);
|
||||||
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
|
if(!CT_CHECK(t, keystroke('h', Mctrl, &com)))
|
||||||
|
|||||||
Reference in New Issue
Block a user