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:
6
dat.h
6
dat.h
@@ -48,12 +48,18 @@ struct Str
|
|||||||
int n;
|
int n;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* What one key does to a composition: text to commit, the new pending
|
||||||
|
* text, and the new raw state (Telex key history, or pending Japanese
|
||||||
|
* romaji), given the old ones in Im.
|
||||||
|
*/
|
||||||
typedef struct Emit Emit;
|
typedef struct Emit Emit;
|
||||||
struct Emit
|
struct Emit
|
||||||
{
|
{
|
||||||
int eat;
|
int eat;
|
||||||
Str s;
|
Str s;
|
||||||
Str next;
|
Str next;
|
||||||
|
Str raw;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Tnode Tnode;
|
typedef struct Tnode Tnode;
|
||||||
|
|||||||
14
ko.c
14
ko.c
@@ -189,6 +189,10 @@ issyl(Rune r)
|
|||||||
return r >= Sbase && r < Sbase + Ncho*Njung*Njong;
|
return r >= Sbase && r < Sbase + Ncho*Njung*Njong;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The pending text is at most one syllable; a key either extends it,
|
||||||
|
* commits it and starts another, or commits it and passes through.
|
||||||
|
*/
|
||||||
Emit
|
Emit
|
||||||
transko(Im *im, Rune c)
|
transko(Im *im, Rune c)
|
||||||
{
|
{
|
||||||
@@ -199,10 +203,7 @@ transko(Im *im, Rune c)
|
|||||||
memset(&e, 0, sizeof e);
|
memset(&e, 0, sizeof e);
|
||||||
jm = keytojamo(c);
|
jm = keytojamo(c);
|
||||||
if(jm == 0){
|
if(jm == 0){
|
||||||
if(im->pre.n > 0){
|
|
||||||
e.s = im->pre;
|
e.s = im->pre;
|
||||||
sclear(&im->pre);
|
|
||||||
}
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,14 +218,12 @@ transko(Im *im, Rune c)
|
|||||||
ci = Choidx(last);
|
ci = Choidx(last);
|
||||||
ji = Jungidx(jm);
|
ji = Jungidx(jm);
|
||||||
if(ci >= 0 && ji >= 0){
|
if(ci >= 0 && ji >= 0){
|
||||||
spopr(&im->pre);
|
|
||||||
sputr(&e.next, compose(ci, ji, 0));
|
sputr(&e.next, compose(ci, ji, 0));
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
if(Jungidx(last) >= 0 && ji >= 0){
|
if(Jungidx(last) >= 0 && ji >= 0){
|
||||||
comb = combine(cvow, nelem(cvow), last, jm);
|
comb = combine(cvow, nelem(cvow), last, jm);
|
||||||
if(comb){
|
if(comb){
|
||||||
spopr(&im->pre);
|
|
||||||
sputr(&e.next, comb);
|
sputr(&e.next, comb);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -239,7 +238,6 @@ transko(Im *im, Rune c)
|
|||||||
if(joi == 0){
|
if(joi == 0){
|
||||||
ni = Jongidx(jm);
|
ni = Jongidx(jm);
|
||||||
if(ni > 0){
|
if(ni > 0){
|
||||||
spopr(&im->pre);
|
|
||||||
sputr(&e.next, compose(ci, ji, ni));
|
sputr(&e.next, compose(ci, ji, ni));
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -248,7 +246,6 @@ transko(Im *im, Rune c)
|
|||||||
comb = combine(cvow, nelem(cvow), jung[ji], jm);
|
comb = combine(cvow, nelem(cvow), jung[ji], jm);
|
||||||
if(comb){
|
if(comb){
|
||||||
ni = Jungidx(comb);
|
ni = Jungidx(comb);
|
||||||
spopr(&im->pre);
|
|
||||||
sputr(&e.next, compose(ci, ni, 0));
|
sputr(&e.next, compose(ci, ni, 0));
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -260,7 +257,6 @@ transko(Im *im, Rune c)
|
|||||||
if(comb){
|
if(comb){
|
||||||
ni = Jongidx(comb);
|
ni = Jongidx(comb);
|
||||||
if(ni > 0){
|
if(ni > 0){
|
||||||
spopr(&im->pre);
|
|
||||||
sputr(&e.next, compose(ci, ji, ni));
|
sputr(&e.next, compose(ci, ji, ni));
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
@@ -271,14 +267,12 @@ transko(Im *im, Rune c)
|
|||||||
if(splitpair(cjong, nelem(cjong), jc, &stay, &next)){
|
if(splitpair(cjong, nelem(cjong), jc, &stay, &next)){
|
||||||
si = Jongidx(stay);
|
si = Jongidx(stay);
|
||||||
ni = Choidx(next);
|
ni = Choidx(next);
|
||||||
spopr(&im->pre);
|
|
||||||
sputr(&e.s, compose(ci, ji, si));
|
sputr(&e.s, compose(ci, ji, si));
|
||||||
sputr(&e.next, compose(ni, vi, 0));
|
sputr(&e.next, compose(ni, vi, 0));
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
ni = Choidx(jc);
|
ni = Choidx(jc);
|
||||||
if(ni >= 0){
|
if(ni >= 0){
|
||||||
spopr(&im->pre);
|
|
||||||
sputr(&e.s, compose(ci, ji, 0));
|
sputr(&e.s, compose(ci, ji, 0));
|
||||||
sputr(&e.next, compose(ni, vi, 0));
|
sputr(&e.next, compose(ni, vi, 0));
|
||||||
return e;
|
return e;
|
||||||
|
|||||||
136
strans.c
136
strans.c
@@ -7,6 +7,7 @@ static void *activeowner;
|
|||||||
static int activecap;
|
static int activecap;
|
||||||
static Caret caret;
|
static Caret caret;
|
||||||
static int candidatechosen;
|
static int candidatechosen;
|
||||||
|
static Emit transjp(Im*, Rune);
|
||||||
static void backjp(Im*);
|
static void backjp(Im*);
|
||||||
static int maplookup(Trie*, Str*, Str*);
|
static int maplookup(Trie*, Str*, Str*);
|
||||||
|
|
||||||
@@ -21,8 +22,8 @@ static Search search;
|
|||||||
|
|
||||||
Lang langs[] = {
|
Lang langs[] = {
|
||||||
{LangEN, nil, nil, nil, nil, nil, nil},
|
{LangEN, nil, nil, nil, nil, nil, nil},
|
||||||
{LangJP, "hira", "kanji", transmap, backjp, nil, nil},
|
{LangJP, "hira", "kanji", transjp, backjp, nil, nil},
|
||||||
{LangJPK, "kata", nil, transmap, backjp, nil, nil},
|
{LangJPK, "kata", nil, transjp, backjp, nil, nil},
|
||||||
{LangKO, nil, nil, transko, backko, nil, nil},
|
{LangKO, nil, nil, transko, backko, nil, nil},
|
||||||
{LangHANJA, nil, "hanja", nil, nil, nil, nil},
|
{LangHANJA, nil, "hanja", nil, nil, nil, nil},
|
||||||
{LangEMOJI, nil, "emoji", nil, nil, nil, nil},
|
{LangEMOJI, nil, "emoji", nil, nil, nil, nil},
|
||||||
@@ -106,28 +107,29 @@ isjp(Im *p)
|
|||||||
/*
|
/*
|
||||||
* Japanese keeps completed kana in pre and an ambiguous romaji syllable in
|
* Japanese keeps completed kana in pre and an ambiguous romaji syllable in
|
||||||
* raw. A mapped raw suffix is part of the reading even while it remains
|
* raw. A mapped raw suffix is part of the reading even while it remains
|
||||||
* pending (notably n, which may still grow into nya).
|
* pending (notably n, which may still grow into nya). Returns whether
|
||||||
|
* the reading is complete.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
jpreading(Im *p, Str *s)
|
jpreading(Trie *map, Str *pre, Str *raw, Str *s)
|
||||||
{
|
{
|
||||||
Str mapped;
|
Str mapped;
|
||||||
|
|
||||||
*s = p->pre;
|
*s = *pre;
|
||||||
if(p->raw.n == 0)
|
if(raw->n == 0)
|
||||||
return 1;
|
return 1;
|
||||||
if(mapget(p->l->map, &p->raw, &mapped)){
|
if(mapget(map, raw, &mapped)){
|
||||||
sappend(s, &mapped);
|
sappend(s, &mapped);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
sappend(s, &p->raw);
|
sappend(s, raw);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
haspre(Im *p)
|
haspre(Im *p)
|
||||||
{
|
{
|
||||||
return p->pre.n != 0 || (isjp(p) && p->raw.n != 0);
|
return p->pre.n != 0 || p->raw.n != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The preedit as clients see it: Telex keys read back through the map. */
|
/* The preedit as clients see it: Telex keys read back through the map. */
|
||||||
@@ -135,7 +137,7 @@ static void
|
|||||||
impre(Str *s)
|
impre(Str *s)
|
||||||
{
|
{
|
||||||
if(isjp(&im))
|
if(isjp(&im))
|
||||||
jpreading(&im, s);
|
jpreading(im.l->map, &im.pre, &im.raw, s);
|
||||||
else if(!mapget(im.l->map, &im.pre, s))
|
else if(!mapget(im.l->map, &im.pre, s))
|
||||||
*s = im.pre;
|
*s = im.pre;
|
||||||
}
|
}
|
||||||
@@ -200,7 +202,7 @@ dictqjp(void)
|
|||||||
Str reading;
|
Str reading;
|
||||||
|
|
||||||
clearkouho();
|
clearkouho();
|
||||||
if(!jpreading(&im, &reading) || reading.n == 0)
|
if(!jpreading(im.l->map, &im.pre, &im.raw, &reading) || reading.n == 0)
|
||||||
return;
|
return;
|
||||||
im.nkouho = dictlookup(im.l, &reading, im.kouho, Maxkouho);
|
im.nkouho = dictlookup(im.l, &reading, im.kouho, Maxkouho);
|
||||||
selectfirst();
|
selectfirst();
|
||||||
@@ -223,13 +225,11 @@ commitim(Im *p, Str *com)
|
|||||||
{
|
{
|
||||||
Str val;
|
Str val;
|
||||||
|
|
||||||
if(isjp(p)){
|
if(isjp(p))
|
||||||
jpreading(p, &val);
|
jpreading(p->l->map, &p->pre, &p->raw, &val);
|
||||||
|
else if(!mapget(p->l->map, &p->pre, &val))
|
||||||
|
val = p->pre;
|
||||||
sappend(com, &val);
|
sappend(com, &val);
|
||||||
}else if(p->l->map != nil && mapget(p->l->map, &p->pre, &val))
|
|
||||||
sappend(com, &val);
|
|
||||||
else
|
|
||||||
sappend(com, &p->pre);
|
|
||||||
sclear(&p->pre);
|
sclear(&p->pre);
|
||||||
sclear(&p->raw);
|
sclear(&p->raw);
|
||||||
}
|
}
|
||||||
@@ -266,78 +266,64 @@ keeptail(Str *s)
|
|||||||
s->n--;
|
s->n--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static Emit
|
||||||
transjp(Im *p, Rune c, Str *com)
|
transjp(Im *p, Rune c)
|
||||||
{
|
{
|
||||||
|
Emit e;
|
||||||
Str key, mapped;
|
Str key, mapped;
|
||||||
|
|
||||||
if(c == '\'' && p->raw.n == 1 && p->raw.r[0] == 'n'){
|
memset(&e, 0, sizeof e);
|
||||||
if(mapget(p->l->map, &p->raw, &mapped))
|
e.eat = 1;
|
||||||
sappend(&p->pre, &mapped);
|
e.next = p->pre;
|
||||||
sclear(&p->raw);
|
e.raw = p->raw;
|
||||||
return 1;
|
if(c == '\'' && e.raw.n == 1 && e.raw.r[0] == 'n'){
|
||||||
|
if(mapget(p->l->map, &e.raw, &mapped))
|
||||||
|
sappend(&e.next, &mapped);
|
||||||
|
sclear(&e.raw);
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
key = p->raw;
|
key = e.raw;
|
||||||
if(key.n < Maxrunes)
|
|
||||||
sputr(&key, c);
|
sputr(&key, c);
|
||||||
sclear(&mapped);
|
|
||||||
if(maplookup(p->l->map, &key, &mapped)){
|
if(maplookup(p->l->map, &key, &mapped)){
|
||||||
p->raw = key;
|
e.raw = key;
|
||||||
if(issmalltsu(&mapped)){
|
if(issmalltsu(&mapped)){
|
||||||
sappend(&p->pre, &mapped);
|
sappend(&e.next, &mapped);
|
||||||
keeptail(&p->raw);
|
keeptail(&e.raw);
|
||||||
}
|
}
|
||||||
return 1;
|
return e;
|
||||||
}
|
}
|
||||||
if(p->raw.n != 0 && mapget(p->l->map, &p->raw, &mapped)){
|
if(e.raw.n != 0 && mapget(p->l->map, &e.raw, &mapped)){
|
||||||
sappend(&p->pre, &mapped);
|
sappend(&e.next, &mapped);
|
||||||
sclear(&p->raw);
|
sclear(&e.raw);
|
||||||
sclear(&key);
|
sclear(&key);
|
||||||
sputr(&key, c);
|
sputr(&key, c);
|
||||||
if(maplookup(p->l->map, &key, &mapped)){
|
if(maplookup(p->l->map, &key, &mapped)){
|
||||||
p->raw = key;
|
e.raw = key;
|
||||||
return 1;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
commitim(p, com);
|
/* The key starts no syllable: flush the reading and pass it on. */
|
||||||
return 0;
|
jpreading(p->l->map, &e.next, &e.raw, &e.s);
|
||||||
|
sclear(&e.next);
|
||||||
|
sclear(&e.raw);
|
||||||
|
e.eat = 0;
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dotrans(Rune c, Str *com)
|
dotrans(Rune c, Str *com)
|
||||||
{
|
{
|
||||||
Emit e;
|
Emit e;
|
||||||
Str mapped;
|
|
||||||
|
|
||||||
if(isjp(&im)){
|
e = im.l->trans(&im, c);
|
||||||
e.eat = transjp(&im, c, com);
|
sappend(com, &e.s);
|
||||||
if(e.eat)
|
im.pre = e.next;
|
||||||
|
im.raw = e.raw;
|
||||||
|
if(e.eat && isjp(&im))
|
||||||
dictqjp();
|
dictqjp();
|
||||||
else
|
else
|
||||||
clearkouho();
|
clearkouho();
|
||||||
return e.eat;
|
return e.eat;
|
||||||
}
|
|
||||||
e = im.l->trans(&im, c);
|
|
||||||
if(im.l->lang == LangVI){
|
|
||||||
if(e.s.n > 0 || !e.eat)
|
|
||||||
sclear(&im.raw);
|
|
||||||
if(e.eat && e.next.n > 0){
|
|
||||||
if(im.raw.n >= Maxrunes){
|
|
||||||
if(!mapget(im.l->map, &e.next, &mapped))
|
|
||||||
mapped = e.next;
|
|
||||||
sappend(com, &mapped);
|
|
||||||
reset();
|
|
||||||
return e.eat;
|
|
||||||
}
|
|
||||||
sputr(&im.raw, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clearkouho();
|
|
||||||
if(e.s.n > 0)
|
|
||||||
sappend(com, &e.s);
|
|
||||||
sclear(&im.pre);
|
|
||||||
sappend(&im.pre, &e.next);
|
|
||||||
return e.eat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Lang*
|
Lang*
|
||||||
@@ -430,42 +416,30 @@ foldascii(Str *s)
|
|||||||
s->r[i] += 'a' - 'A';
|
s->r[i] += 'a' - 'A';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* What typing raw in language l would produce, composition included. */
|
||||||
static void
|
static void
|
||||||
transstr(Lang *l, Str *raw, Str *out)
|
transstr(Lang *l, Str *raw, Str *out)
|
||||||
{
|
{
|
||||||
Im q;
|
Im q;
|
||||||
Emit e;
|
Emit e;
|
||||||
Str mapped;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
sclear(out);
|
sclear(out);
|
||||||
if(l == nil || l->trans == nil || (l->trans == transmap && l->map == nil)){
|
if(l->trans == nil){
|
||||||
*out = *raw;
|
*out = *raw;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memset(&q, 0, sizeof q);
|
memset(&q, 0, sizeof q);
|
||||||
q.l = l;
|
q.l = l;
|
||||||
if(isjp(&q)){
|
|
||||||
for(i = 0; i < raw->n; i++)
|
|
||||||
if(!transjp(&q, raw->r[i], out) && out->n < Maxrunes)
|
|
||||||
sputr(out, raw->r[i]);
|
|
||||||
if(haspre(&q))
|
|
||||||
commitim(&q, out);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for(i = 0; i < raw->n; i++){
|
for(i = 0; i < raw->n; i++){
|
||||||
e = l->trans(&q, raw->r[i]);
|
e = l->trans(&q, raw->r[i]);
|
||||||
sappend(out, &e.s);
|
sappend(out, &e.s);
|
||||||
q.pre = e.next;
|
q.pre = e.next;
|
||||||
if(!e.eat && out->n < Maxrunes)
|
q.raw = e.raw;
|
||||||
|
if(!e.eat)
|
||||||
sputr(out, raw->r[i]);
|
sputr(out, raw->r[i]);
|
||||||
}
|
}
|
||||||
if(q.pre.n == 0)
|
commitim(&q, out);
|
||||||
return;
|
|
||||||
if(l->map != nil && mapget(l->map, &q.pre, &mapped))
|
|
||||||
sappend(out, &mapped);
|
|
||||||
else
|
|
||||||
sappend(out, &q.pre);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ typevi(struct ct *t, char *keys, char *want)
|
|||||||
e = transvi(&state, (uchar)*p);
|
e = transvi(&state, (uchar)*p);
|
||||||
sappend(&out, &e.s);
|
sappend(&out, &e.s);
|
||||||
state.pre = e.next;
|
state.pre = e.next;
|
||||||
|
state.raw = e.raw;
|
||||||
if(!e.eat)
|
if(!e.eat)
|
||||||
sputr(&out, (uchar)*p);
|
sputr(&out, (uchar)*p);
|
||||||
}
|
}
|
||||||
|
|||||||
69
vi.c
69
vi.c
@@ -31,12 +31,6 @@ static struct {
|
|||||||
{L'Y', {L'Ý', L'Ỳ', L'Ỷ', L'Ỹ', L'Ỵ'}},
|
{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
|
static int
|
||||||
toneidx(Rune c)
|
toneidx(Rune c)
|
||||||
{
|
{
|
||||||
@@ -114,20 +108,44 @@ onsetglide(Str *m)
|
|||||||
return -1;
|
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;
|
Str mapped, pre;
|
||||||
int i, tidx, vi, last, penult, glide;
|
int i, tidx, vi, last, penult, glide;
|
||||||
Rune v, b1, b2;
|
Rune v, b1, b2;
|
||||||
|
|
||||||
if(!istone(c) && c != 'z')
|
e = transmap(im, c);
|
||||||
return transmap(im, c);
|
if(e.eat)
|
||||||
mappedkey = transmap(im, c);
|
return e;
|
||||||
if(mappedkey.eat)
|
|
||||||
return mappedkey;
|
|
||||||
|
|
||||||
memset(&e, 0, sizeof e);
|
memset(&e, 0, sizeof e);
|
||||||
if(im->pre.n == 0)
|
if(im->pre.n == 0)
|
||||||
return e;
|
return e;
|
||||||
@@ -175,17 +193,24 @@ transvi(Im *im, Rune c)
|
|||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c == 'z')
|
|
||||||
mapped.r[vi] = removetone(mapped.r[vi]);
|
|
||||||
else{
|
|
||||||
tidx = toneidx(c);
|
tidx = toneidx(c);
|
||||||
|
if(tidx < 0)
|
||||||
|
mapped.r[vi] = removetone(mapped.r[vi]);
|
||||||
|
else
|
||||||
mapped.r[vi] = applytone(mapped.r[vi], tidx);
|
mapped.r[vi] = applytone(mapped.r[vi], tidx);
|
||||||
}
|
|
||||||
e.eat = 1;
|
e.eat = 1;
|
||||||
e.next = mapped;
|
e.next = mapped;
|
||||||
return e;
|
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
|
void
|
||||||
backvi(Im *im)
|
backvi(Im *im)
|
||||||
{
|
{
|
||||||
@@ -200,10 +225,10 @@ backvi(Im *im)
|
|||||||
raw = im->raw;
|
raw = im->raw;
|
||||||
spopr(&raw);
|
spopr(&raw);
|
||||||
sclear(&im->pre);
|
sclear(&im->pre);
|
||||||
|
sclear(&im->raw);
|
||||||
for(i = 0; i < raw.n; i++){
|
for(i = 0; i < raw.n; i++){
|
||||||
e = transvi(im, raw.r[i]);
|
e = transvi(im, raw.r[i]);
|
||||||
sclear(&im->pre);
|
im->pre = e.next;
|
||||||
sappend(&im->pre, &e.next);
|
im->raw = e.raw;
|
||||||
}
|
}
|
||||||
im->raw = raw;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user