Files
strans/dict.c
Hojun-Cho abff5ed122 emoji: search the dictionary by prefix in the engine, not in the data
mkemoji wrote a row for every prefix of every alias, so that a query
matched as it was typed; the trie is a prefix index already, and with a
real emoji list those rows would be four times the aliases themselves.
Now emoji.dict has one row per alias, trienode() names a key's node, and
dictlookup walks the entries at and below it, the key's own first, up to
Maxkouho.  Trie children are appended rather than pushed, so the walk
keeps the file's order and a bare digit still picks the superscript or
subscript it always did.

The hand-written symbol rows move to symbol.src; emoji.src is left to
the emoji.  mkemoji reads both by default, or the files it is given.
2026-08-17 01:07:10 +09:00

89 lines
1.8 KiB
C

#include "dat.h"
#include "fn.h"
/*
* Appends the space-separated words of a node's entry to out[], up to
* max: its candidates, minus the key itself, except in the emoji
* dictionary, where a query may name its own answer.
*/
static int
words(Lang *l, Str *key, Tnode *nd, Str *out, int n, int max)
{
char *p, *e, *sp;
Str tmp;
if(nd->val == nil)
return n;
p = nd->val;
e = p + nd->vlen;
while(n < max && p < e){
while(p < e && *p == ' ')
p++;
sp = p;
while(p < e && *p != ' ')
p++;
if(sinit(&tmp, sp, p - sp) && tmp.n > 0 &&
(l->lang == LangEMOJI || scmp(&tmp, key) != 0))
out[n++] = tmp;
}
return n;
}
/* The entries at and below a node, in the dictionary's order. */
static int
below(Lang *l, Str *key, int ni, Str *out, int n, int max)
{
Tnode *nd;
int ci;
nd = &l->dict->nodes[ni];
n = words(l, key, nd, out, n, max);
for(ci = nd->child; ci >= 0 && n < max; ci = l->dict->nodes[ci].sibling)
n = below(l, key, ci, out, n, max);
return n;
}
/*
* Fills out[] with up to max candidates for key. The emoji dictionary is
* searched by prefix, the key's own entry first; the others exactly.
*/
int
dictlookup(Lang *l, Str *key, Str *out, int max)
{
int ni;
ni = key->n == 0 ? -1 : trienode(l->dict, key);
if(ni < 0)
return 0;
if(l->lang == LangEMOJI)
return below(l, key, ni, out, 0, max);
return words(l, key, &l->dict->nodes[ni], out, 0, max);
}
static Trie*
langopen(char *dir, char *name, char *ext)
{
char *path;
Trie *t;
path = smprint("%s/%s.%s", dir, name, ext);
if(path == nil)
die("out of memory");
t = trieopen(path);
free(path);
return t;
}
void
langinit(char *dir)
{
Lang *l;
for(l = langs; l < langs + nlang; l++){
if(l->mapname != nil)
l->map = langopen(dir, l->mapname, "map");
if(l->dictname != nil)
l->dict = langopen(dir, l->dictname, "dict");
}
}