123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077 |
- #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;
- r.max = r.min;
- /* 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.y = 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);
- }
- */
|