diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /libtk/textu.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'libtk/textu.c')
| -rw-r--r-- | libtk/textu.c | 1076 |
1 files changed, 1076 insertions, 0 deletions
diff --git a/libtk/textu.c b/libtk/textu.c new file mode 100644 index 00000000..854dc8d5 --- /dev/null +++ b/libtk/textu.c @@ -0,0 +1,1076 @@ +#include "lib9.h" +#include "draw.h" +#include "tk.h" +#include "textw.h" + +#define istring u.string +#define iwin u.win +#define imark u.mark +#define iline u.line + +/* debugging */ +int tktdbg; +extern void tktprinttext(TkText*); +extern void tktprintindex(TkTindex*); +extern void tktprintitem(TkTitem*); +extern void tktprintline(TkTline*); +extern void tktcheck(TkText*, char*); +int tktutfpos(char*, int); + +char* +tktnewitem(int kind, int tagextra,TkTitem **ret) +{ + int n; + TkTitem *i; + + n = sizeof(TkTitem) + tagextra * sizeof(ulong); + i = malloc(n); + if(i == nil) + return TkNomem; + + memset(i, 0, n); + i->kind = kind; + i->tagextra = tagextra; + *ret = i; + return nil; +} + +char* +tktnewline(int flags, TkTitem *items, TkTline *prev, TkTline *next, TkTline **ret) +{ + TkTline *l; + TkTitem *i; + + l = malloc(sizeof(TkTline)); + if(l == nil) + return TkNomem; + + memset(l, 0, sizeof(TkTline)); + l->flags = flags; + l->items = items; + l->prev = prev; + l->next = next; + next->prev = l; + prev->next = l; + + for(i = items; i->next != nil;) + i = i->next; + if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline)) + print("text:tktnewline botch\n"); + i->iline = l; + + *ret = l; + return nil; +} + +/* + * free items; freewins is 0 when the subwindows will be + * freed anyway as the main text widget is being destroyed. + */ +void +tktfreeitems(TkText *tkt, TkTitem *i, int freewins) +{ + TkTitem *n; + Tk *tk; + + while(i != nil) { + n = i->next; + if(tkt->mouse == i) + tkt->mouse = nil; + switch(i->kind) { + case TkTascii: + case TkTrune: + if(i->istring != nil) + free(i->istring); + break; + case TkTwin: + if (i->iwin != nil) { + tk = i->iwin->sub; + if (tk != nil) { + tk->geom = nil; + tk->destroyed = nil; + if (i->iwin->owned && freewins) { + if (tk->name != nil) + tkdestroy(tk->env->top, tk->name->name, nil); + } else { + tk->parent = nil; + tk->geom = nil; + tk->destroyed = nil; + } + } + if(i->iwin->create != nil) + free(i->iwin->create); + free(i->iwin); + } + break; + case TkTmark: + break; + } + free(i); + i = n; + } +} + +void +tktfreelines(TkText *tkt, TkTline *l, int freewins) +{ + TkTline *n; + + while(l != nil) { + n = l->next; + tktfreeitems(tkt, l->items, freewins); + free(l); + l = n; + } +} + +void +tktfreetabs(TkTtabstop *t) +{ + TkTtabstop *n; + + while(t != nil) { + n = t->next; + free(t); + t = n; + } +} + +void +tkfreetext(Tk *tk) +{ + TkText *tkt = TKobj(TkText, tk); + + if(tkt->start.next != nil && tkt->start.next != &(tkt->end)) { + tkt->end.prev->next = nil; + tktfreelines(tkt, tkt->start.next, 0); + } + tktfreeitems(tkt, tkt->start.items, 0); + tktfreeitems(tkt, tkt->end.items, 0); + tktfreetabs(tkt->tabs); + if(tkt->tagshare == nil) + tktfreetags(tkt->tags); + else + tk->binds = nil; + tktfreemarks(tkt->marks); + if(tkt->xscroll != nil) + free(tkt->xscroll); + if(tkt->yscroll != nil) + free(tkt->yscroll); + /* don't free image because it belongs to window */ +} + +/* + * Remove the item at ix, joining previous and next items. + * If item is at end of line, remove next line and join + * its items to this one (except at end). + * On return, ix is adjusted to point to the next item. + */ +void +tktremitem(TkText *tkt, TkTindex *ix) +{ + TkTline *l, *lnext; + TkTindex prev, nx; + TkTitem *i, *ilast; + + l = ix->line; + i = ix->item; + + if(i->next == nil) { + if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline)) { + print("tktremitem: botch 1\n"); + return; + } + lnext = l->next; + if(lnext == &tkt->end) + /* not supposed to remove final newline */ + return; + if(i->kind == TkTnewline) + tkt->nlines--; + ilast = tktlastitem(lnext->items); + ilast->iline = l; + i->next = lnext->items; + l->flags = (l->flags & ~TkTlast) | (lnext->flags & TkTlast); + l->next = lnext->next; + lnext->next->prev = l; + free(lnext); + } + if(l->items == i) + l->items = i->next; + else { + prev = *ix; + if(!tktadjustind(tkt, TkTbyitemback, &prev) && tktdbg) { + print("tktremitem: botch 2\n"); + return; + } + prev.item->next = i->next; + } + ix->item = i->next; + ix->pos = 0; + i->next = nil; + nx = *ix; + tktadjustind(tkt, TkTbycharstart, &nx); + + /* check against cached items */ + if(tkt->selfirst == i) + tkt->selfirst = nx.item; + if(tkt->sellast == i) + tkt->sellast = nx.item; + if(tkt->selfirst == tkt->sellast) { + tkt->selfirst = nil; + tkt->sellast = nil; + } + + tktfreeitems(tkt, i, 1); +} + +int +tktdispwidth(Tk *tk, TkTtabstop *tb, TkTitem *i, Font *f, int x, int pos, int nchars) +{ + int w, del, locked; + TkTtabstop *tbprev; + Display *d; + TkText *tkt; + TkEnv env; + + tkt = TKobj(TkText, tk); + d = tk->env->top->display; + if (tb == nil) + tb = tkt->tabs; + + switch(i->kind) { + case TkTrune: + pos = tktutfpos(i->istring, pos); + /* FALLTHRU */ + case TkTascii: + if(f == nil) { + if(!tktanytags(i)) + f = tk->env->font; + else { + tkttagopts(tk, i, nil, &env, nil, 1); + f = env.font; + } + } + locked = 0; + if(!(tkt->tflag&TkTdlocked)) + locked = lockdisplay(d); + if(nchars >= 0) + w = stringnwidth(f, i->istring+pos, nchars); + else + w = stringwidth(f, i->istring+pos); + if(locked) + unlockdisplay(d); + break; + case TkTtab: + if(tb == nil) + w = 0; + else { + tbprev = nil; + while(tb->pos <= x && tb->next != nil) { + tbprev = tb; + tb = tb->next; + } + w = tb->pos - x; + if(w <= 0) { + del = tb->pos; + if(tbprev != nil) + del -= tbprev->pos; + while(w <= 0) + w += del; + } + /* todo: other kinds of justification */ + } + break; + case TkTwin: + if(i->iwin->sub == 0) + w = 0; + else + w = i->iwin->sub->act.width + 2*i->iwin->padx + 2*i->iwin->sub->borderwidth; + break; + default: + w = 0; + } + return w; +} + +int +tktindrune(TkTindex *ix) +{ + int ans; + Rune r; + + switch(ix->item->kind) { + case TkTascii: + ans = ix->item->istring[ix->pos]; + break; + case TkTrune: + chartorune(&r, ix->item->istring + tktutfpos(ix->item->istring, ix->pos)); + ans = r; + break; + case TkTtab: + ans = '\t'; + break; + case TkTnewline: + ans = '\n'; + break; + default: + /* only care that it isn't a word char */ + ans = 0x80; + } + return ans; +} + +TkTitem* +tktlastitem(TkTitem *i) +{ + while(i->next != nil) + i = i->next; + if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline)) + print("text:tktlastitem botch\n"); + + return i; +} + +TkTline* +tktitemline(TkTitem *i) +{ + i = tktlastitem(i); + return i->iline; +} + +int +tktlinenum(TkText *tkt, TkTindex *p) +{ + int n; + TkTline *l; + + if(p->line->orig.y <= tkt->end.orig.y / 2) { + /* line seems closer to beginning */ + n = 1; + for(l = tkt->start.next; l != p->line; l = l->next) { + if(tktdbg && l->next == nil) { + print("text: tktlinenum botch\n"); + break; + } + if(l->flags & TkTlast) + n++; + } + } + else { + n = tkt->nlines; + for(l = tkt->end.prev; l != p->line; l = l->prev) { + if(tktdbg && l->prev == nil) { + print("text: tktlinenum botch\n"); + break; + } + if(l->flags & TkTfirst) + n--; + } + } + return n; +} + +int +tktlinepos(TkText *tkt, TkTindex *p) +{ + int n; + TkTindex ix; + TkTitem *i; + + n = 0; + ix = *p; + i = ix.item; + tktadjustind(tkt, TkTbylinestart, &ix); + while(ix.item != i) { + if(tktdbg && ix.item->next == nil && (ix.line->flags&TkTlast)) { + print("text: tktlinepos botch\n"); + break; + } + n += tktposcount(ix.item); + if(!tktadjustind(tkt, TkTbyitem, &ix)) { + if(tktdbg) + print("tktlinepos botch\n"); + break; + } + } + return (n+p->pos); +} + +int +tktposcount(TkTitem *i) +{ + int n; + + if(i->kind == TkTascii) + n = strlen(i->istring); + else + if(i->kind == TkTrune) + n = utflen(i->istring); + else + if(i->kind == TkTmark || i->kind == TkTcontline) + n = 0; + else + n = 1; + return n; +} + +/* + * Insert item i before position ins. + * If i is a newline or a contline, make a new line to contain the items up to + * and including the new newline, and make the original line + * contain the items from ins on. + * Adjust ins so that it points just after inserted item. + */ +char* +tktiteminsert(TkText *tkt, TkTindex *ins, TkTitem *i) +{ + int hasprev, flags; + char *e; + TkTindex prev; + TkTline *l; + TkTitem *items; + + prev = *ins; + hasprev = tktadjustind(tkt, TkTbyitemback, &prev); + + if(i->kind == TkTnewline || i->kind == TkTcontline) { + i->next = nil; + if(hasprev && prev.line == ins->line) { + items = ins->line->items; + prev.item->next = i; + } + else + items = i; + + flags = ins->line->flags&TkTfirst; + if(i->kind == TkTnewline) + flags |= TkTlast; + e = tktnewline(flags, items, ins->line->prev, ins->line, &l); + if(e != nil) { + if(hasprev && prev.line == ins->line) + prev.item->next = ins->item; + return e; + } + + if(i->kind == TkTnewline) + ins->line->flags |= TkTfirst; + + if(i->kind == TkTcontline) + ins->line->flags &= ~TkTfirst; + ins->line->items = ins->item; + ins->pos = 0; + } + else { + if(hasprev && prev.line == ins->line) + prev.item->next = i; + else + ins->line->items = i; + i->next = ins->item; + } + + return nil; +} + +/* + * If index p doesn't point at the beginning of an item, + * split the item at p. Adjust p to point to the beginning of + * the item after the split (same character it used to point at). + * If there is a split, the old item gets the characters before + * the split, and a new item gets the characters after it. + */ +char* +tktsplititem(TkTindex *p) +{ + int l1, l2; + char *s1, *s2, *e; + TkTitem *i, *i2; + + i = p->item; + + if(p->pos != 0) { + /* + * Must be TkTascii or TkTrune + * + * Make new item i2, to be inserted after i, + * with portion of string from p->pos on + */ + + if (i->kind == TkTascii) + l1 = p->pos; + else + l1 = tktutfpos(i->istring, p->pos); + l2 = strlen(i->istring) - l1; + if (l2 == 0) + print("tktsplititem botch\n"); + s1 = malloc(l1+1); + if(s1 == nil) + return TkNomem; + s2 = malloc(l2+1); + if(s2 == nil) { + free(s1); + return TkNomem; + } + + memmove(s1, i->istring, l1); + s1[l1] = '\0'; + memmove(s2, i->istring + l1, l2); + s2[l2] = '\0'; + + e = tktnewitem(i->kind, i->tagextra, &i2); + if(e != nil) { + free(s1); + free(s2); + return e; + } + + free(i->istring); + + tkttagcomb(i2, i, 1); + i2->next = i->next; + i->next = i2; + i->istring = s1; + i2->istring = s2; + + p->item = i2; + p->pos = 0; + } + + return nil; +} + +int +tktmaxwid(TkTline *l) +{ + int w, maxw; + + maxw = 0; + while(l != nil) { + w = l->width; + if(w > maxw) + maxw = w; + l = l->next; + } + return maxw; +} + +Rectangle +tktbbox(Tk *tk, TkTindex *ix) +{ + Rectangle r; + int d, w; + TkTitem *i; + TkTline *l; + TkEnv env; + TkTtabstop *tb = nil; + Tk *sub; + TkText *tkt = TKobj(TkText, tk); + int opts[TkTnumopts]; + + l = ix->line; + + /* r in V space */ + r.min = subpt(l->orig, tkt->deltatv); + r.min.y += l->ascent; + + /* tabs dependon tags of first non-mark on display line */ + for(i = l->items; i->kind == TkTmark; ) + i = i->next; + tkttagopts(tk, i, opts, &env, &tb, 1); + + for(i = l->items; i != nil; i = i->next) { + if(i == ix->item) { + tkttagopts(tk, i, opts, &env, nil, 1); + r.min.y -= opts[TkToffset]; + switch(i->kind) { + case TkTascii: + case TkTrune: + d = tktdispwidth(tk, tb, i, nil, r.min.x, 0, ix->pos); + w = tktdispwidth(tk, tb, i, nil, r.min.x, ix->pos, 1); + r.min.x += d; + r.min.y -= env.font->ascent; + r.max.x = r.min.x + w; + r.max.y = r.min.y + env.font->height; + break; + case TkTwin: + sub = i->iwin->sub; + if(sub == nil) + break; + r.min.x += sub->act.x; + r.min.y += sub->act.y; + r.max.x = r.min.x + sub->act.width + 2*sub->borderwidth; + r.max.y = r.min.y + sub->act.height + 2*sub->borderwidth; + break; + case TkTnewline: + r.max.x = r.min.x; + r.min.y -= l->ascent; + r.max.y = r.min.y + l->height; + break; + default: + d = tktdispwidth(tk, tb, i, nil, r.min.x, 0, -1); + r.max.x = r.min.x + d; + r.max.y = r.min.y; + break; + } + return r; + } + r.min.x += tktdispwidth(tk, tb, i, nil, r.min.x, 0, -1); + } + r.min.x = 0; + r.min.y = 0; + r.max.x = 0; + r.max.x = 0; + return r; +} + +/* Return left-at-baseline position of given item, in V coords */ +static Point +tktitempos(Tk *tk, TkTindex *ix) +{ + Point p; + TkTitem *i; + TkTline *l; + TkText *tkt = TKobj(TkText, tk); + + l = ix->line; + + /* p in V space */ + p = subpt(l->orig, tkt->deltatv); + p.y += l->ascent; + + for(i = l->items; i != nil && i != ix->item; i = i->next) + p.x += i->width; + return p; +} + +static Tk* +tktdeliver(Tk *tk, TkTitem *i, TkTitem *tagit, int event, void *data, Point deltasv) +{ + Tk *ftk, *dest; + TkTwind *w; + TkText *tkt; + TkTtaginfo *t; + TkTline *l; + TkMouse m; + Point mp, p; + TkTindex ix; + int bd; + + dest = nil; + if(i != nil) { + tkt = TKobj(TkText, tk); + + if(i->kind == TkTwin) { + w = i->iwin; + if(w->sub != nil) { + if(!(event & TkKey) && (event & TkEmouse)) { + m = *(TkMouse*)data; + mp.x = m.x; + mp.y = m.y; + ix.item = i; + ix.pos = 0; + ix.line = tktitemline(i); + p = tktitempos(tk, &ix); + bd = w->sub->borderwidth; + mp.x = m.x - (deltasv.x + p.x + w->sub->act.x + bd); + mp.y = m.y - (deltasv.y + p.y + w->sub->act.y + bd); + ftk = tkinwindow(w->sub, mp, 0); + if(ftk != w->focus) { + tkdeliver(w->focus, TkLeave, data); + tkdeliver(ftk, TkEnter, data); + + w->focus = ftk; + } + if(ftk != nil) + dest = tkdeliver(ftk, event, &m); + } + else { + if ((event & TkLeave) && (w->focus != w->sub)) { + tkdeliver(w->focus, TkLeave, data); + w->focus = nil; + event &= ~TkLeave; + } + if (event) + tkdeliver(w->sub, event, data); + } + if(Dx(w->sub->dirty) > 0) { + l = tktitemline(i); + tktfixgeom(tk, tktprevwrapline(tk, l), l, 0); + } + if(event & TkKey) + return dest; + } + } + + if(tagit != 0) { + for(t = tkt->tags; t != nil; t = t->next) { + if(t->binds != nil && tkttagset(tagit, t->id)) { + if(tksubdeliver(tk, t->binds, event, data, 0) == TkDbreak) { + return dest; + } + } + } + } + } + return dest; +} + +Tk* +tktinwindow(Tk *tk, Point *p) +{ + TkTindex ix; + Point q; + Tk *sub; + + tktxyind(tk, p->x, p->y, &ix); + if (ix.item == nil || ix.item->kind != TkTwin || ix.item->iwin->sub == nil) + return tk; + sub = ix.item->iwin->sub; + q = tktitempos(tk, &ix); + p->x -= q.x + sub->borderwidth + sub->act.x; + p->y -= q.y + sub->borderwidth + sub->act.y; + return sub; +} + +Tk* +tktextevent(Tk *tk, int event, void *data) +{ + char *e; + TkMouse m, vm; + TkTitem *f, *tagit; + TkText *tkt; + TkTindex ix; + Tk *dest; + Point deltasv; + + tkt = TKobj(TkText, tk); + deltasv = tkposn(tk); + deltasv.x += tk->borderwidth + tk->ipad.x/2; + deltasv.y += tk->borderwidth + tk->ipad.y/2; + + dest = nil; + if(event == TkLeave && tkt->mouse != nil) { + vm.x = 0; + vm.y = 0; + tktdeliver(tk, tkt->mouse, tkt->mouse, TkLeave, data, deltasv); + tkt->mouse = nil; + } + else if((event & TkKey) == 0 && (event & TkEmouse)) { + /* m in S space, tm in V space */ + m = *(TkMouse*)data; + vm = m; + vm.x -= deltasv.x; + vm.y -= deltasv.y; + if((event & TkMotion) == 0 || m.b == 0) { + tkt->current.x = vm.x; + tkt->current.y = vm.y; + } + tktxyind(tk, vm.x, vm.y, &ix); + f = ix.item; + if(tkt->mouse != f) { + tagit = nil; + if(tkt->mouse != nil) { + if(tktanytags(tkt->mouse)) { + e = tktnewitem(TkTascii, tkt->mouse->tagextra, &tagit); + if(e != nil) + return dest; /* XXX propagate error? */ + tkttagcomb(tagit, tkt->mouse, 1); + tkttagcomb(tagit, f, -1); + } + tktdeliver(tk, tkt->mouse, tagit, TkLeave, data, deltasv); + if(tagit) + free(tagit); + tagit = nil; + } + if(tktanytags(f)) { + e = tktnewitem(TkTascii, f->tagextra, &tagit); + if(e != nil) + return dest; /* XXX propagate error? */ + tkttagcomb(tagit, f, 1); + if(tkt->mouse) + tkttagcomb(tagit, tkt->mouse, -1); + } + tktdeliver(tk, f, tagit, TkEnter, data, deltasv); + tkt->mouse = f; + if(tagit) + free(tagit); + } + if(tkt->mouse != nil) + dest = tktdeliver(tk, tkt->mouse, tkt->mouse, event, &m, deltasv); + } + else if(event == TkFocusin) + tktextcursor(tk, " insert", (char **) nil); + /* pass all "real" events on to parent text widget - DBK */ + tksubdeliver(tk, tk->binds, event, data, 0); + return dest; +} + +/* Debugging */ +void +tktprintitem(TkTitem *i) +{ + int j; + + print("%p:", i); + switch(i->kind){ + case TkTascii: + print("\"%s\"", i->istring); + break; + case TkTrune: + print("<rune:%s>", i->istring); + break; + case TkTnewline: + print("<nl:%p>", i->iline); + break; + case TkTcontline: + print("<cont:%p>", i->iline); + break; + case TkTtab: + print("<tab>"); + break; + case TkTmark: + print("<mk:%s>", i->imark->name); + break; + case TkTwin: + if (i->iwin->sub->name != nil) + print("<win:%s>", i->iwin->sub? i->iwin->sub->name->name : "<null>"); + } + print("[%d]", i->width); + if(i->tags !=0 || i->tagextra !=0) { + print("{%lux", i->tags[0]); + for(j=0; j < i->tagextra; j++) + print(" %lux", i->tags[j+1]); + print("}"); + } + print(" "); +} + +void +tktprintline(TkTline *l) +{ + TkTitem *i; + + print("line %p: orig=(%d,%d), w=%d, h=%d, a=%d, f=%x\n\t", + l, l->orig.x, l->orig.y, l->width, l->height, l->ascent, l->flags); + for(i = l->items; i != nil; i = i->next) + tktprintitem(i); + print("\n"); +} + +void +tktprintindex(TkTindex *ix) +{ + print("line=%p,item=%p,pos=%d\n", ix->line, ix->item, ix->pos); +} + +void +tktprinttext(TkText *tkt) +{ + TkTline *l; + TkTtaginfo *ti; + TkTmarkinfo *mi; + + for(ti=tkt->tags; ti != nil; ti=ti->next) + print("%s{%d} ", ti->name, ti->id); + print("\n"); + for(mi = tkt->marks; mi != nil; mi=mi->next) + print("%s{%p} ", mi->name? mi->name : "nil", mi->cur); + print("\n"); + print("selfirst=%p sellast=%p\n", tkt->selfirst, tkt->sellast); + + for(l = &tkt->start; l != nil; l = l->next) + tktprintline(l); +} + +/* + * Check that assumed invariants are true. + * + * - start line and end line have no items + * - all other lines have at least one item + * - start line leads to end line via next pointers + * - prev pointers point to previous lines + * - each line ends in either a TkTnewline or a TkTcontline + * whose iline pointer points to the line itself + * - TkTcontline and TkTmark items have no tags + * (this is so they don't get realloc'd because of tag combination) + * - all cur fields of marks point to nil or a TkTmark + * - selfirst and sellast correctly define select region + * - nlines counts the number of lines + */ +void +tktcheck(TkText *tkt, char *fun) +{ + int nl, insel, selfound; + TkTline *l; + TkTitem *i; + TkTmarkinfo *mi; + TkTindex ix; + char *prob; + + prob = nil; + nl = 0; + + if(tkt->start.items != nil || tkt->end.items != nil) + prob = "start/end has items"; + for(l = tkt->start.next; l != &tkt->end; l = l->next) { + if(l->prev->next != l) { + prob = "prev mismatch"; + break; + } + if(l->next->prev != l) { + prob = "next mismatch"; + break; + } + i = l->items; + if(i == nil) { + prob = "empty line"; + break; + } + while(i->next != nil) { + if(i->kind == TkTnewline || i->kind == TkTcontline) { + prob = "premature end of line"; + break; + } + if(i->kind == TkTmark && (i->tags[0] != 0 || i->tagextra != 0)) { + prob = "mark has tags"; + break; + } + i = i->next; + } + if(i->kind == TkTnewline) + nl++; + if(!(i->kind == TkTnewline || i->kind == TkTcontline)) { + prob = "bad end of line"; + break; + } + if(i->kind == TkTcontline && (i->tags[0] != 0 || i->tagextra != 0)) { + prob = "contline has tags"; + break; + } + if(i->iline != l) { + prob = "bad end-of-line pointer"; + break; + } + } + for(mi = tkt->marks; mi != nil; mi=mi->next) { + if(mi->cur != nil) { + tktstartind(tkt, &ix); + do { + if(ix.item->kind == TkTmark && ix.item == mi->cur) + goto foundmark; + } while(tktadjustind(tkt, TkTbyitem, &ix)); + prob = "bad mark cur"; + break; + foundmark: ; + } + } + insel = 0; + selfound = 0; + tktstartind(tkt, &ix); + do { + i = ix.item; + if(i == tkt->selfirst) { + if(i->kind == TkTmark || i->kind == TkTcontline) { + prob = "selfirst not on character"; + break; + } + if(i == tkt->sellast) { + prob = "selfirst==sellast, not nil"; + break; + } + insel = 1; + selfound = 1; + } + if(i == tkt->sellast) { + if(i->kind == TkTmark || i->kind == TkTcontline) { + prob = "sellast not on character"; + break; + } + insel = 0; + } + if(i->kind != TkTmark && i->kind != TkTcontline) { + if(i->tags[0] & (1<<TkTselid)) { + if(!insel) { + prob = "sel set outside selfirst..sellast"; + break; + } + } + else { + if(insel) { + prob = "sel not set inside selfirst..sellast"; + break; + } + } + } + } while(tktadjustind(tkt, TkTbyitem, &ix)); + if(tkt->selfirst != nil && !selfound) + prob = "selfirst not found"; + + if(prob != nil) { + print("tktcheck problem: %s: %s\n", fun, prob); + tktprinttext(tkt); +abort(); + } +} + +int +tktutfpos(char *s, int pos) +{ + char *s1; + int c; + Rune r; + + for (s1 = s; pos > 0; pos--) { + c = *(uchar *)s1; + if (c < Runeself) { + if (c == '\0') + break; + s1++; + } + else + s1 += chartorune(&r, s1); + } + return s1 - s; +} + +/* +struct timerec { + char *name; + ulong ms; +}; + +static struct timerec tt[100]; +static int ntt = 1; + +int +tktalloctime(char *name) +{ + if(ntt >= 100) + abort(); + tt[ntt].name = strdup(name); + tt[ntt].ms = 0; + return ntt++; +} + +void +tktstarttime(int ind) +{ +return; + tt[ind].ms -= osmillisec(); +} + +void +tktendtime(int ind) +{ +return; + tt[ind].ms += osmillisec(); +} + +void +tktdumptime(void) +{ + int i; + + for(i = 1; i < ntt; i++) + print("%s: %d\n", tt[i].name, tt[i].ms); +} +*/ |
