emoji: add one-shot candidate search
This commit is contained in:
279
strans.c
279
strans.c
@@ -3,8 +3,18 @@
|
||||
|
||||
static Im im;
|
||||
static int popup = 0;
|
||||
static int visible = 0;
|
||||
static void dictqmap(Im*);
|
||||
|
||||
typedef struct Search Search;
|
||||
struct Search
|
||||
{
|
||||
int on;
|
||||
Str raw;
|
||||
Str text;
|
||||
};
|
||||
static Search search;
|
||||
|
||||
static void
|
||||
backmap(Im *im)
|
||||
{
|
||||
@@ -16,7 +26,7 @@ Lang langs[] = {
|
||||
{LangJP, "hira", "kanji", transmap, backmap, dictqmap, nil, nil},
|
||||
{LangJPK, "kata", "kanji", transmap, backmap, dictqmap, nil, nil},
|
||||
{LangKO, "hangul", nil, transko, backko, dictqmap, nil, nil},
|
||||
{LangEMOJI, "emoji", "emoji", transmap, backmap, dictqmap, nil, nil},
|
||||
{LangEMOJI, nil, "emoji", nil, nil, nil, nil, nil},
|
||||
{LangVI, "telex", nil, transvi, backvi, dictqmap, nil, nil},
|
||||
};
|
||||
int nlang = nelem(langs);
|
||||
@@ -44,13 +54,15 @@ static void
|
||||
show(void)
|
||||
{
|
||||
Drawcmd dc;
|
||||
Str *pre;
|
||||
int i, first, n;
|
||||
|
||||
if(!popup)
|
||||
return;
|
||||
sclear(&dc.pre);
|
||||
if(!mapget(im.l->map, &im.pre, &dc.pre))
|
||||
dc.pre = im.pre;
|
||||
pre = search.on ? &search.text : &im.pre;
|
||||
if(popup){
|
||||
if(search.on || im.l->map == nil || !mapget(im.l->map, pre, &dc.pre))
|
||||
dc.pre = *pre;
|
||||
}
|
||||
first = im.sel >= Maxdisp ? im.sel - Maxdisp + 1 : 0;
|
||||
n = im.nkouho - first;
|
||||
if(n > Maxdisp) n = Maxdisp;
|
||||
@@ -58,6 +70,9 @@ show(void)
|
||||
dc.sel = im.sel >= 0 ? im.sel - first : -1;
|
||||
for(i = 0; i < n; i++)
|
||||
dc.kouho[i] = im.kouho[first + i];
|
||||
if(dc.pre.n == 0 && n == 0 && !visible)
|
||||
return;
|
||||
visible = dc.pre.n != 0 || n != 0;
|
||||
chansend(drawc, &dc);
|
||||
}
|
||||
|
||||
@@ -110,7 +125,7 @@ commit(Str *com)
|
||||
{
|
||||
Str val;
|
||||
|
||||
if(mapget(im.l->map, &im.pre, &val))
|
||||
if(im.l->map != nil && mapget(im.l->map, &im.pre, &val))
|
||||
sappend(com, &val);
|
||||
else
|
||||
sappend(com, &im.pre);
|
||||
@@ -209,13 +224,240 @@ transmap(Im *im, Rune c)
|
||||
return e;
|
||||
}
|
||||
|
||||
static Rune
|
||||
ctrlkey(Rune c)
|
||||
{
|
||||
if(c >= 'a' && c <= 'z')
|
||||
return c - 'a' + 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
foldascii(Str *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < s->n; i++)
|
||||
if(s->r[i] >= 'A' && s->r[i] <= 'Z')
|
||||
s->r[i] += 'a' - 'A';
|
||||
}
|
||||
|
||||
static void
|
||||
transstr(Lang *l, Str *raw, Str *out)
|
||||
{
|
||||
static Im q;
|
||||
Emit e;
|
||||
Str mapped;
|
||||
int i;
|
||||
|
||||
sclear(out);
|
||||
if(l == nil || l->trans == nil || (l->trans == transmap && l->map == nil)){
|
||||
*out = *raw;
|
||||
return;
|
||||
}
|
||||
memset(&q, 0, sizeof q);
|
||||
q.l = l;
|
||||
for(i = 0; i < raw->n; i++){
|
||||
e = l->trans(&q, raw->r[i]);
|
||||
sappend(out, &e.s);
|
||||
q.pre = e.next;
|
||||
if(!e.eat && out->n < Maxrunes)
|
||||
sputr(out, raw->r[i]);
|
||||
}
|
||||
if(q.pre.n == 0)
|
||||
return;
|
||||
if(l->map != nil && mapget(l->map, &q.pre, &mapped))
|
||||
sappend(out, &mapped);
|
||||
else
|
||||
sappend(out, &q.pre);
|
||||
}
|
||||
|
||||
static void
|
||||
addkouho(Str *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < im.nkouho; i++)
|
||||
if(scmp(&im.kouho[i], s) == 0)
|
||||
return;
|
||||
if(im.nkouho < Maxkouho)
|
||||
im.kouho[im.nkouho++] = *s;
|
||||
}
|
||||
|
||||
static void
|
||||
emojilookup(Str *key, Dictres *res)
|
||||
{
|
||||
Dictreq req;
|
||||
|
||||
req.key = *key;
|
||||
req.pre = req.key;
|
||||
req.lang = LangEMOJI;
|
||||
dictlookup(&req, res);
|
||||
}
|
||||
|
||||
static void
|
||||
emojiquery(void)
|
||||
{
|
||||
static Dictres res;
|
||||
Str raw, local;
|
||||
int i, rawhit, localhit;
|
||||
|
||||
raw = search.raw;
|
||||
foldascii(&raw);
|
||||
transstr(im.l, &search.raw, &local);
|
||||
foldascii(&local);
|
||||
clearkouho();
|
||||
emojilookup(&raw, &res);
|
||||
rawhit = res.nkouho != 0;
|
||||
for(i = 0; i < res.nkouho; i++)
|
||||
addkouho(&res.kouho[i]);
|
||||
localhit = 0;
|
||||
if(scmp(&raw, &local) != 0){
|
||||
emojilookup(&local, &res);
|
||||
localhit = res.nkouho != 0;
|
||||
for(i = 0; i < res.nkouho; i++)
|
||||
addkouho(&res.kouho[i]);
|
||||
}
|
||||
search.text = rawhit || !localhit ? raw : local;
|
||||
show();
|
||||
}
|
||||
|
||||
static void
|
||||
endsearch(void)
|
||||
{
|
||||
search.on = 0;
|
||||
sclear(&search.raw);
|
||||
sclear(&search.text);
|
||||
clearkouho();
|
||||
show();
|
||||
}
|
||||
|
||||
static void
|
||||
startsearch(Str *com)
|
||||
{
|
||||
if(im.pre.n > 0)
|
||||
commit(com);
|
||||
sclear(&im.pre);
|
||||
sclear(&im.raw);
|
||||
clearkouho();
|
||||
search.on = 1;
|
||||
sclear(&search.raw);
|
||||
sclear(&search.text);
|
||||
show();
|
||||
}
|
||||
|
||||
static void
|
||||
commitsearch(Str *com)
|
||||
{
|
||||
sappend(com, &search.text);
|
||||
endsearch();
|
||||
}
|
||||
|
||||
static int
|
||||
pickemoji(int n, Str *com)
|
||||
{
|
||||
if(n < 0 || n >= im.nkouho)
|
||||
return 0;
|
||||
sappend(com, &im.kouho[n]);
|
||||
endsearch();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
searchkey(u32int ks, u32int mod, Str *com)
|
||||
{
|
||||
int n, off;
|
||||
Rune c;
|
||||
|
||||
if(ks == Ksuper || ks == Kshift)
|
||||
return 1;
|
||||
if(ks == Kdown || ks == Kup){
|
||||
if(im.nkouho == 0)
|
||||
return 1;
|
||||
if(ks == Kdown && im.sel < im.nkouho - 1)
|
||||
im.sel++;
|
||||
if(ks == Kup && im.sel > 0)
|
||||
im.sel--;
|
||||
show();
|
||||
return 1;
|
||||
}
|
||||
n = ks - '1';
|
||||
off = im.sel >= Maxdisp ? im.sel - Maxdisp + 1 : 0;
|
||||
if((mod & Malt) && n >= 0 && n < Maxdisp){
|
||||
pickemoji(off + n, com);
|
||||
return 1;
|
||||
}
|
||||
if(ks == Ktab){
|
||||
if(im.nkouho == 0)
|
||||
return 1;
|
||||
if(mod & Mshift){
|
||||
if(im.sel <= 0)
|
||||
im.sel = im.nkouho - 1;
|
||||
else
|
||||
im.sel--;
|
||||
}else if(im.sel >= im.nkouho - 1)
|
||||
im.sel = 0;
|
||||
else
|
||||
im.sel++;
|
||||
show();
|
||||
return 1;
|
||||
}
|
||||
if(ks == Kret){
|
||||
if(im.nkouho > 0)
|
||||
return pickemoji(im.sel >= 0 ? im.sel : 0, com);
|
||||
commitsearch(com);
|
||||
return 1;
|
||||
}
|
||||
if(ks == Kback){
|
||||
if(search.raw.n == 0)
|
||||
return 1;
|
||||
spopr(&search.raw);
|
||||
emojiquery();
|
||||
return 1;
|
||||
}
|
||||
if(ks == Kesc){
|
||||
endsearch();
|
||||
return 1;
|
||||
}
|
||||
if(mod & Mctrl){
|
||||
c = ctrlkey(ks);
|
||||
if(c == LangEMOJI){
|
||||
endsearch();
|
||||
return 1;
|
||||
}
|
||||
if(c == 0x10){
|
||||
popup = !popup;
|
||||
show();
|
||||
return 1;
|
||||
}
|
||||
endsearch();
|
||||
if(setlang(c))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
if(ks >= Kspec || ks < ' ' || (mod & (Malt|Msuper))){
|
||||
commitsearch(com);
|
||||
return 0;
|
||||
}
|
||||
if(search.raw.n >= Maxrunes){
|
||||
commitsearch(com);
|
||||
return 0;
|
||||
}
|
||||
sputr(&search.raw, ks);
|
||||
emojiquery();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
keystroke(u32int ks, u32int mod, Str *com)
|
||||
{
|
||||
int n, off;
|
||||
Rune c;
|
||||
|
||||
if(ks == Ksuper || ks == Kshift)
|
||||
return 1;
|
||||
if(search.on)
|
||||
return searchkey(ks, mod, com);
|
||||
if(ks == Kdown || ks == Kup){
|
||||
if(im.nkouho == 0)
|
||||
return 0;
|
||||
@@ -271,14 +513,18 @@ keystroke(u32int ks, u32int mod, Str *com)
|
||||
return 0;
|
||||
}
|
||||
if(mod & Mctrl){
|
||||
reset();
|
||||
if(ks >= 'a' && ks <= 'z')
|
||||
ks -= 'a' - 1;
|
||||
if(ks == 0x10){
|
||||
popup = !popup;
|
||||
c = ctrlkey(ks);
|
||||
if(c == LangEMOJI){
|
||||
startsearch(com);
|
||||
return 1;
|
||||
}
|
||||
if(setlang(ks))
|
||||
if(c == 0x10){
|
||||
popup = !popup;
|
||||
show();
|
||||
return 1;
|
||||
}
|
||||
reset();
|
||||
if(setlang(c))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -305,6 +551,8 @@ init(void)
|
||||
{
|
||||
memset(&im, 0, sizeof(im));
|
||||
im.l = getlang(LangEN);
|
||||
memset(&search, 0, sizeof search);
|
||||
visible = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -316,15 +564,15 @@ imhandlekey(Keyreq *kr)
|
||||
sclear(&res.preedit);
|
||||
res.eaten = keystroke(kr->ks, kr->mod, &res.commit);
|
||||
if(kr->want)
|
||||
res.preedit = im.pre;
|
||||
res.preedit = search.on ? search.text : im.pre;
|
||||
chansend(kr->reply, &res);
|
||||
}
|
||||
|
||||
void
|
||||
imthread(void*)
|
||||
{
|
||||
static Dictres res;
|
||||
Keyreq kr;
|
||||
Dictres res;
|
||||
Alt alts[] = {
|
||||
{keyc, &kr, CHANRCV, nil},
|
||||
{dictresc, &res, CHANRCV, nil},
|
||||
@@ -339,7 +587,8 @@ imthread(void*)
|
||||
imhandlekey(&kr);
|
||||
break;
|
||||
case 1:
|
||||
if(scmp(&res.key, &im.pre) == 0){
|
||||
if(!search.on && res.lang == im.l->lang &&
|
||||
scmp(&res.key, &im.pre) == 0){
|
||||
setkouho(&res);
|
||||
show();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user