engine: one trans contract for every language

Japanese was never dispatched through the Lang table: dotrans and
transstr both special-cased it into transjp, which edited Im in place
and wrote commits through a side argument, while transko popped and
cleared a pre that every caller overwrote anyway, and Vietnamese kept
its key history in dotrans. Emit now carries the new raw state next to
the new pre; transjp, transko and transvi are pure functions of (Im,
key), and dotrans and transstr have a single path. Vietnamese history
bookkeeping lives in vi.c, where the full-history flush no longer
resets the caret as a side effect; istone was toneidx() >= 0.
This commit is contained in:
2026-08-16 16:04:57 +09:00
parent abaea77248
commit a557fb114a
5 changed files with 118 additions and 118 deletions

69
vi.c
View File

@@ -31,12 +31,6 @@ static struct {
{L'Y', {L'Ý', L'', L'', L'', L''}},
};
static int
istone(Rune c)
{
return c == 's' || c == 'f' || c == 'r' || c == 'x' || c == 'j';
}
static int
toneidx(Rune c)
{
@@ -114,20 +108,44 @@ onsetglide(Str *m)
return -1;
}
Emit
transvi(Im *im, Rune c)
/*
* The pending text is the key sequence itself, read through the map for
* display; raw keeps every key of it so Backspace can replay one fewer.
*/
static Emit
history(Im *im, Rune c, Emit e)
{
Emit e, mappedkey;
Str mapped;
e.raw = im->raw;
if(e.s.n > 0 || !e.eat)
sclear(&e.raw);
if(!e.eat || e.next.n == 0)
return e;
if(e.raw.n < Maxrunes){
sputr(&e.raw, c);
return e;
}
/* The history is full: flush the composed text as it stands. */
if(!mapget(im->l->map, &e.next, &mapped))
mapped = e.next;
sappend(&e.s, &mapped);
sclear(&e.next);
sclear(&e.raw);
return e;
}
static Emit
tone(Im *im, Rune c)
{
Emit e;
Str mapped, pre;
int i, tidx, vi, last, penult, glide;
Rune v, b1, b2;
if(!istone(c) && c != 'z')
return transmap(im, c);
mappedkey = transmap(im, c);
if(mappedkey.eat)
return mappedkey;
e = transmap(im, c);
if(e.eat)
return e;
memset(&e, 0, sizeof e);
if(im->pre.n == 0)
return e;
@@ -175,17 +193,24 @@ transvi(Im *im, Rune c)
return e;
}
if(c == 'z')
tidx = toneidx(c);
if(tidx < 0)
mapped.r[vi] = removetone(mapped.r[vi]);
else{
tidx = toneidx(c);
else
mapped.r[vi] = applytone(mapped.r[vi], tidx);
}
e.eat = 1;
e.next = mapped;
return e;
}
Emit
transvi(Im *im, Rune c)
{
if(toneidx(c) < 0 && c != 'z')
return history(im, c, transmap(im, c));
return history(im, c, tone(im, c));
}
void
backvi(Im *im)
{
@@ -200,10 +225,10 @@ backvi(Im *im)
raw = im->raw;
spopr(&raw);
sclear(&im->pre);
sclear(&im->raw);
for(i = 0; i < raw.n; i++){
e = transvi(im, raw.r[i]);
sclear(&im->pre);
sappend(&im->pre, &e.next);
im->pre = e.next;
im->raw = e.raw;
}
im->raw = raw;
}