Charles.Forsyth20061220965a0ca19 years agoHistory
1076 lines · 20.6 KB · C
RawDownload
#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. */voidtktfreeitems(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;	}} voidtktfreelines(TkText *tkt, TkTline *l, int freewins){	TkTline *n; 	while(l != nil) {		n = l->next;		tktfreeitems(tkt, l->items, freewins);		free(l);		l = n;	}} voidtktfreetabs(TkTtabstop *t){	TkTtabstop *n; 	while(t != nil) {		n = t->next;		free(t);		t = n;	}} voidtkfreetext(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. */voidtktremitem(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);} inttktdispwidth(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;} inttktindrune(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;} inttktlinenum(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;} inttktlinepos(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);} inttktposcount(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

Lines 1–500 of 1076.