Beispiel #1
0
void
textfill(Text *t)
{
	Rune *rp;
	int i, n, m, nl;

	if(t->lastlinefull || t->nofill)
		return;
	if(t->ncache > 0)
		typecommit(t);
	rp = fbufalloc();
	do{
		n = t->file->nc-(t->org+t->nchars);
		if(n == 0)
			break;
		if(n > 2000)	/* educated guess at reasonable amount */
			n = 2000;
		bufread(t->file, t->org+t->nchars, rp, n);
		/*
		 * it's expensive to frinsert more than we need, so
		 * count newlines.
		 */
		nl = t->maxlines-t->nlines;
		m = 0;
		for(i=0; i<n; ){
			if(rp[i++] == '\n'){
				m++;
				if(m >= nl)
					break;
			}
		}
		frinsert(t, rp, rp+i, t->nchars);
	}while(t->lastlinefull == FALSE);
	fbuffree(rp);
}
Beispiel #2
0
void
texttype(Text *t, Rune r)
{
	uint q0, q1;
	int nnb, nb, n, i;
	int nr;
	Rune *rp;
	Text *u;

	if(t->what!=Body && r=='\n')
		return;
	nr = 1;
	rp = &r;
	switch(r){
	case Kleft:
		if(t->q0 > 0){
			typecommit(t);
			textshow(t, t->q0-1, t->q0-1, TRUE);
		}
		return;
	case Kright:
		if(t->q1 < t->file->nc){
			typecommit(t);
			textshow(t, t->q1+1, t->q1+1, TRUE);
		}
		return;
	case Kdown:
		n = t->maxlines/3;
		goto case_Down;
	case Kscrollonedown:
		n = mousescrollsize(t->maxlines);
		if(n <= 0)
			n = 1;
		goto case_Down;
	case Kpgdown:
		n = 2*t->maxlines/3;
	case_Down:
		q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+n*t->font->height));
		textsetorigin(t, q0, TRUE);
		return;
	case Kup:
		n = t->maxlines/3;
		goto case_Up;
	case Kscrolloneup:
		n = mousescrollsize(t->maxlines);
		goto case_Up;
	case Kpgup:
		n = 2*t->maxlines/3;
	case_Up:
		q0 = textbacknl(t, t->org, n);
		textsetorigin(t, q0, TRUE);
		return;
	case Khome:
		typecommit(t);
		textshow(t, 0, 0, FALSE);
		return;
	case Kend:
		typecommit(t);
		textshow(t, t->file->nc, t->file->nc, FALSE);
		return;
	case 0x01:	/* ^A: beginning of line */
		typecommit(t);
		/* go to where ^U would erase, if not already at BOL */
		nnb = 0;
		if(t->q0>0 && textreadc(t, t->q0-1)!='\n')
			nnb = textbswidth(t, 0x15);
		textshow(t, t->q0-nnb, t->q0-nnb, TRUE);
		return;
	case 0x05:	/* ^E: end of line */
		typecommit(t);
		q0 = t->q0;
		while(q0<t->file->nc && textreadc(t, q0)!='\n')
			q0++;
		textshow(t, q0, q0, TRUE);
		return;
	}
	if(t->what == Body){
		seq++;
		filemark(t->file);
	}
	if(t->q1 > t->q0){
		if(t->ncache != 0)
			error("text.type");
		cut(t, t, nil, TRUE, TRUE, nil, 0);
		t->eq0 = ~0;
	}
	textshow(t, t->q0, t->q0, 1);
	switch(r){
	case 0x06:
	case Kins:
		rp = textcomplete(t);
		if(rp == nil)
			return;
		nr = runestrlen(rp);
		break;	/* fall through to normal insertion case */
	case 0x1B:
		if(t->eq0 != ~0)
			textsetselect(t, t->eq0, t->q0);
		if(t->ncache > 0)
			typecommit(t);
		return;
	case 0x08:	/* ^H: erase character */
	case 0x15:	/* ^U: erase line */
	case 0x17:	/* ^W: erase word */
		if(t->q0 == 0)	/* nothing to erase */
			return;
		nnb = textbswidth(t, r);
		q1 = t->q0;
		q0 = q1-nnb;
		/* if selection is at beginning of window, avoid deleting invisible text */
		if(q0 < t->org){
			q0 = t->org;
			nnb = q1-q0;
		}
		if(nnb <= 0)
			return;
		for(i=0; i<t->file->ntext; i++){
			u = t->file->text[i];
			u->nofill = TRUE;
			nb = nnb;
			n = u->ncache;
			if(n > 0){
				if(q1 != u->cq0+n)
					error("text.type backspace");
				if(n > nb)
					n = nb;
				u->ncache -= n;
				textdelete(u, q1-n, q1, FALSE);
				nb -= n;
			}
			if(u->eq0==q1 || u->eq0==~0)
				u->eq0 = q0;
			if(nb && u==t)
				textdelete(u, q0, q0+nb, TRUE);
			if(u != t)
				textsetselect(u, u->q0, u->q1);
			else
				textsetselect(t, q0, q0);
			u->nofill = FALSE;
		}
		for(i=0; i<t->file->ntext; i++)
			textfill(t->file->text[i]);
		return;
	case '\n':
		if(t->w->autoindent){
			/* find beginning of previous line using backspace code */
			nnb = textbswidth(t, 0x15); /* ^U case */
			rp = runemalloc(nnb + 1);
			nr = 0;
			rp[nr++] = r;
			for(i=0; i<nnb; i++){
				r = textreadc(t, t->q0-nnb+i);
				if(r != ' ' && r != '\t')
					break;
				rp[nr++] = r;
			}
		}
		break; /* fall through to normal code */
	}
	/* otherwise ordinary character; just insert, typically in caches of all texts */
	for(i=0; i<t->file->ntext; i++){
		u = t->file->text[i];
		if(u->eq0 == ~0)
			u->eq0 = t->q0;
		if(u->ncache == 0)
			u->cq0 = t->q0;
		else if(t->q0 != u->cq0+u->ncache)
			error("text.type cq1");
		textinsert(u, t->q0, rp, nr, FALSE);
		if(u != t)
			textsetselect(u, u->q0, u->q1);
		if(u->ncache+nr > u->ncachealloc){
			u->ncachealloc += 10 + nr;
			u->cache = runerealloc(u->cache, u->ncachealloc);
		}
		runemove(u->cache+u->ncache, rp, nr);
		u->ncache += nr;
	}
	if(rp != &r)
		free(rp);
	textsetselect(t, t->q0+nr, t->q0+nr);
	if(r=='\n' && t->w!=nil)
		wincommit(t->w, t);
}
Beispiel #3
0
void
texttype(Text *t, Rune r)
{
	uint q0, q1;
	int nnb, nb, n, i;
	int nr;
	Rune *rp;
	Text *u;

	if(t->what!=Body && t->what!=Tag && r=='\n')
		return;
	if(t->what == Tag)
		t->w->tagsafe = FALSE;

	nr = 1;
	rp = &r;
	switch(r){
	case Kleft:
		typecommit(t);
		if(t->q0 > 0)
			textshow(t, t->q0-1, t->q0-1, TRUE);
		return;
	case Kright:
		typecommit(t);
		if(t->q1 < t->file->b.nc)
			textshow(t, t->q1+1, t->q1+1, TRUE);
		return;
	case Kdown:
		if(t->what == Tag)
			goto Tagdown;
		n = t->fr.maxlines/3;
		goto case_Down;
	case Kscrollonedown:
		if(t->what == Tag)
			goto Tagdown;
		n = mousescrollsize(t->fr.maxlines);
		if(n <= 0)
			n = 1;
		goto case_Down;
	case Kpgdown:
		n = 2*t->fr.maxlines/3;
	case_Down:
		q0 = t->org+frcharofpt(&t->fr, Pt(t->fr.r.min.x, t->fr.r.min.y+n*t->fr.font->height));
		textsetorigin(t, q0, TRUE);
		return;
	case Kup:
		if(t->what == Tag)
			goto Tagup;
		n = t->fr.maxlines/3;
		goto case_Up;
	case Kscrolloneup:
		if(t->what == Tag)
			goto Tagup;
		n = mousescrollsize(t->fr.maxlines);
		goto case_Up;
	case Kpgup:
		n = 2*t->fr.maxlines/3;
	case_Up:
		q0 = textbacknl(t, t->org, n);
		textsetorigin(t, q0, TRUE);
		return;
	case Khome:
		typecommit(t);
		if(t->org > t->iq1) {
			q0 = textbacknl(t, t->iq1, 1);
			textsetorigin(t, q0, TRUE);
		} else
			textshow(t, 0, 0, FALSE);
		return;
	case Kend:
		typecommit(t);
		if(t->iq1 > t->org+t->fr.nchars) {
			if(t->iq1 > t->file->b.nc) {
				// should not happen, but does. and it will crash textbacknl.
				t->iq1 = t->file->b.nc;
			}
			q0 = textbacknl(t, t->iq1, 1);
			textsetorigin(t, q0, TRUE);
		} else
			textshow(t, t->file->b.nc, t->file->b.nc, FALSE);
		return;
	case 0x01:	/* ^A: beginning of line */
		typecommit(t);
		/* go to where ^U would erase, if not already at BOL */
		nnb = 0;
		if(t->q0>0 && textreadc(t, t->q0-1)!='\n')
			nnb = textbswidth(t, 0x15);
		textshow(t, t->q0-nnb, t->q0-nnb, TRUE);
		return;
	case 0x05:	/* ^E: end of line */
		typecommit(t);
		q0 = t->q0;
		while(q0<t->file->b.nc && textreadc(t, q0)!='\n')
			q0++;
		textshow(t, q0, q0, TRUE);
		return;
	case Kcmd+'c':	/* %C: copy */
		typecommit(t);
		cut(t, t, nil, TRUE, FALSE, nil, 0);
		return;
	case Kcmd+'z':	/* %Z: undo */
	 	typecommit(t);
		undo(t, nil, nil, TRUE, 0, nil, 0);
		return;

	Tagdown:
		/* expand tag to show all text */
		if(!t->w->tagexpand){
			t->w->tagexpand = TRUE;
			winresize(t->w, t->w->r, FALSE, TRUE);
		}
		return;
	
	Tagup:
		/* shrink tag to single line */
		if(t->w->tagexpand){
			t->w->tagexpand = FALSE;
			t->w->taglines = 1;
			winresize(t->w, t->w->r, FALSE, TRUE);
		}
		return;
	}
	if(t->what == Body){
		seq++;
		filemark(t->file);
	}
	/* cut/paste must be done after the seq++/filemark */
	switch(r){
	case Kcmd+'x':	/* %X: cut */
		typecommit(t);
		if(t->what == Body){
			seq++;
			filemark(t->file);
		}
		cut(t, t, nil, TRUE, TRUE, nil, 0);
		textshow(t, t->q0, t->q0, 1);
		t->iq1 = t->q0;
		return;
	case Kcmd+'v':	/* %V: paste */
		typecommit(t);
		if(t->what == Body){
			seq++;
			filemark(t->file);
		}
		paste(t, t, nil, TRUE, FALSE, nil, 0);
		textshow(t, t->q0, t->q1, 1);
		t->iq1 = t->q1;
		return;
	}
	if(t->q1 > t->q0){
		if(t->ncache != 0)
			error("text.type");
		cut(t, t, nil, TRUE, TRUE, nil, 0);
		t->eq0 = ~0;
	}
	textshow(t, t->q0, t->q0, 1);
	switch(r){
	case 0x06:	/* ^F: complete */
	case Kins:
		typecommit(t);
		rp = textcomplete(t);
		if(rp == nil)
			return;
		nr = runestrlen(rp);
		break;	/* fall through to normal insertion case */
	case 0x1B:
		if(t->eq0 != ~0) {
			if(t->eq0 <= t->q0)
				textsetselect(t, t->eq0, t->q0);
			else
				textsetselect(t, t->q0, t->eq0);
		}
		if(t->ncache > 0)
			typecommit(t);
		t->iq1 = t->q0;
		return;
	case 0x08:	/* ^H: erase character */
	case 0x15:	/* ^U: erase line */
	case 0x17:	/* ^W: erase word */
		if(t->q0 == 0)	/* nothing to erase */
			return;
		nnb = textbswidth(t, r);
		q1 = t->q0;
		q0 = q1-nnb;
		/* if selection is at beginning of window, avoid deleting invisible text */
		if(q0 < t->org){
			q0 = t->org;
			nnb = q1-q0;
		}
		if(nnb <= 0)
			return;
		for(i=0; i<t->file->ntext; i++){
			u = t->file->text[i];
			u->nofill = TRUE;
			nb = nnb;
			n = u->ncache;
			if(n > 0){
				if(q1 != u->cq0+n)
					error("text.type backspace");
				if(n > nb)
					n = nb;
				u->ncache -= n;
				textdelete(u, q1-n, q1, FALSE);
				nb -= n;
			}
			if(u->eq0==q1 || u->eq0==~0)
				u->eq0 = q0;
			if(nb && u==t)
				textdelete(u, q0, q0+nb, TRUE);
			if(u != t)
				textsetselect(u, u->q0, u->q1);
			else
				textsetselect(t, q0, q0);
			u->nofill = FALSE;
		}
		for(i=0; i<t->file->ntext; i++)
			textfill(t->file->text[i]);
		t->iq1 = t->q0;
		return;
	case '\n':
		if(t->w->autoindent){
			/* find beginning of previous line using backspace code */
			nnb = textbswidth(t, 0x15); /* ^U case */
			rp = runemalloc(nnb + 1);
			nr = 0;
			rp[nr++] = r;
			for(i=0; i<nnb; i++){
				r = textreadc(t, t->q0-nnb+i);
				if(r != ' ' && r != '\t')
					break;
				rp[nr++] = r;
			}
		}
		break; /* fall through to normal code */
	}
	/* otherwise ordinary character; just insert, typically in caches of all texts */
	for(i=0; i<t->file->ntext; i++){
		u = t->file->text[i];
		if(u->eq0 == ~0)
			u->eq0 = t->q0;
		if(u->ncache == 0)
			u->cq0 = t->q0;
		else if(t->q0 != u->cq0+u->ncache)
			error("text.type cq1");
		/*
		 * Change the tag before we add to ncache,
		 * so that if the window body is resized the
		 * commit will not find anything in ncache.
		 */
		if(u->what==Body && u->ncache == 0){
			u->needundo = TRUE;
			winsettag(t->w);
			u->needundo = FALSE;
		}
		textinsert(u, t->q0, rp, nr, FALSE);
		if(u != t)
			textsetselect(u, u->q0, u->q1);
		if(u->ncache+nr > u->ncachealloc){
			u->ncachealloc += 10 + nr;
			u->cache = runerealloc(u->cache, u->ncachealloc);
		}
		runemove(u->cache+u->ncache, rp, nr);
		u->ncache += nr;
	}
	if(rp != &r)
		free(rp);
	textsetselect(t, t->q0+nr, t->q0+nr);
	if(r=='\n' && t->w!=nil)
		wincommit(t->w, t);
	t->iq1 = t->q0;
}