17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
59a747e4fSDavid du Colombier #include <cursor.h>
67dd7cddfSDavid du Colombier #include <mouse.h>
77dd7cddfSDavid du Colombier #include <keyboard.h>
87dd7cddfSDavid du Colombier #include <frame.h>
97dd7cddfSDavid du Colombier #include <fcall.h>
107dd7cddfSDavid du Colombier #include <plumb.h>
11fe853e23SDavid du Colombier #include <complete.h>
127dd7cddfSDavid du Colombier #include "dat.h"
137dd7cddfSDavid du Colombier #include "fns.h"
147dd7cddfSDavid du Colombier
157dd7cddfSDavid du Colombier Image *tagcols[NCOL];
167dd7cddfSDavid du Colombier Image *textcols[NCOL];
177dd7cddfSDavid du Colombier
187dd7cddfSDavid du Colombier enum{
197dd7cddfSDavid du Colombier TABDIR = 3 /* width of tabs in directory windows */
207dd7cddfSDavid du Colombier };
217dd7cddfSDavid du Colombier
227dd7cddfSDavid du Colombier void
textinit(Text * t,File * f,Rectangle r,Reffont * rf,Image * cols[NCOL])237dd7cddfSDavid du Colombier textinit(Text *t, File *f, Rectangle r, Reffont *rf, Image *cols[NCOL])
247dd7cddfSDavid du Colombier {
257dd7cddfSDavid du Colombier t->file = f;
267dd7cddfSDavid du Colombier t->all = r;
277dd7cddfSDavid du Colombier t->scrollr = r;
287dd7cddfSDavid du Colombier t->scrollr.max.x = r.min.x+Scrollwid;
297dd7cddfSDavid du Colombier t->lastsr = nullrect;
307dd7cddfSDavid du Colombier r.min.x += Scrollwid+Scrollgap;
317dd7cddfSDavid du Colombier t->eq0 = ~0;
327dd7cddfSDavid du Colombier t->ncache = 0;
337dd7cddfSDavid du Colombier t->reffont = rf;
347dd7cddfSDavid du Colombier t->tabstop = maxtab;
357dd7cddfSDavid du Colombier memmove(t->Frame.cols, cols, sizeof t->Frame.cols);
367dd7cddfSDavid du Colombier textredraw(t, r, rf->f, screen, -1);
377dd7cddfSDavid du Colombier }
387dd7cddfSDavid du Colombier
397dd7cddfSDavid du Colombier void
textredraw(Text * t,Rectangle r,Font * f,Image * b,int odx)407dd7cddfSDavid du Colombier textredraw(Text *t, Rectangle r, Font *f, Image *b, int odx)
417dd7cddfSDavid du Colombier {
427dd7cddfSDavid du Colombier int maxt;
437dd7cddfSDavid du Colombier Rectangle rr;
447dd7cddfSDavid du Colombier
457dd7cddfSDavid du Colombier frinit(t, r, f, b, t->Frame.cols);
467dd7cddfSDavid du Colombier rr = t->r;
479d4e827aSDavid du Colombier rr.min.x -= Scrollwid+Scrollgap; /* back fill to scroll bar */
48*2c2299ceSDavid du Colombier if(!t->noredraw)
497dd7cddfSDavid du Colombier draw(t->b, rr, t->cols[BACK], nil, ZP);
507dd7cddfSDavid du Colombier /* use no wider than 3-space tabs in a directory */
517dd7cddfSDavid du Colombier maxt = maxtab;
527dd7cddfSDavid du Colombier if(t->what == Body){
537dd7cddfSDavid du Colombier if(t->w->isdir)
547dd7cddfSDavid du Colombier maxt = min(TABDIR, maxtab);
557dd7cddfSDavid du Colombier else
567dd7cddfSDavid du Colombier maxt = t->tabstop;
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier t->maxtab = maxt*stringwidth(f, "0");
597dd7cddfSDavid du Colombier if(t->what==Body && t->w->isdir && odx!=Dx(t->all)){
607dd7cddfSDavid du Colombier if(t->maxlines > 0){
617dd7cddfSDavid du Colombier textreset(t);
627dd7cddfSDavid du Colombier textcolumnate(t, t->w->dlp, t->w->ndl);
639a747e4fSDavid du Colombier textshow(t, 0, 0, 1);
647dd7cddfSDavid du Colombier }
657dd7cddfSDavid du Colombier }else{
667dd7cddfSDavid du Colombier textfill(t);
677dd7cddfSDavid du Colombier textsetselect(t, t->q0, t->q1);
687dd7cddfSDavid du Colombier }
697dd7cddfSDavid du Colombier }
707dd7cddfSDavid du Colombier
717dd7cddfSDavid du Colombier int
textresize(Text * t,Rectangle r,int keepextra)72*2c2299ceSDavid du Colombier textresize(Text *t, Rectangle r, int keepextra)
737dd7cddfSDavid du Colombier {
747dd7cddfSDavid du Colombier int odx;
757dd7cddfSDavid du Colombier
76*2c2299ceSDavid du Colombier if(Dy(r) <= 0)
777dd7cddfSDavid du Colombier r.max.y = r.min.y;
78*2c2299ceSDavid du Colombier else if(!keepextra)
79*2c2299ceSDavid du Colombier r.max.y -= Dy(r)%t->font->height;
807dd7cddfSDavid du Colombier odx = Dx(t->all);
817dd7cddfSDavid du Colombier t->all = r;
827dd7cddfSDavid du Colombier t->scrollr = r;
837dd7cddfSDavid du Colombier t->scrollr.max.x = r.min.x+Scrollwid;
847dd7cddfSDavid du Colombier t->lastsr = nullrect;
857dd7cddfSDavid du Colombier r.min.x += Scrollwid+Scrollgap;
867dd7cddfSDavid du Colombier frclear(t, 0);
877dd7cddfSDavid du Colombier textredraw(t, r, t->font, t->b, odx);
88*2c2299ceSDavid du Colombier if(keepextra && t->r.max.y < t->all.max.y && !t->noredraw){
89*2c2299ceSDavid du Colombier /* draw background in bottom fringe of window */
90*2c2299ceSDavid du Colombier r.min.x -= Scrollgap;
91*2c2299ceSDavid du Colombier r.min.y = t->r.max.y;
92*2c2299ceSDavid du Colombier r.max.y = t->all.max.y;
93*2c2299ceSDavid du Colombier draw(screen, r, t->cols[BACK], nil, ZP);
94*2c2299ceSDavid du Colombier }
95*2c2299ceSDavid du Colombier return t->all.max.y;
967dd7cddfSDavid du Colombier }
977dd7cddfSDavid du Colombier
987dd7cddfSDavid du Colombier void
textclose(Text * t)997dd7cddfSDavid du Colombier textclose(Text *t)
1007dd7cddfSDavid du Colombier {
1017dd7cddfSDavid du Colombier free(t->cache);
1027dd7cddfSDavid du Colombier frclear(t, 1);
1037dd7cddfSDavid du Colombier filedeltext(t->file, t);
1047dd7cddfSDavid du Colombier t->file = nil;
1057dd7cddfSDavid du Colombier rfclose(t->reffont);
1067dd7cddfSDavid du Colombier if(argtext == t)
1077dd7cddfSDavid du Colombier argtext = nil;
1087dd7cddfSDavid du Colombier if(typetext == t)
1097dd7cddfSDavid du Colombier typetext = nil;
1107dd7cddfSDavid du Colombier if(seltext == t)
1117dd7cddfSDavid du Colombier seltext = nil;
1127dd7cddfSDavid du Colombier if(mousetext == t)
1137dd7cddfSDavid du Colombier mousetext = nil;
1147dd7cddfSDavid du Colombier if(barttext == t)
1157dd7cddfSDavid du Colombier barttext = nil;
1167dd7cddfSDavid du Colombier }
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier int
dircmp(void * a,void * b)1197dd7cddfSDavid du Colombier dircmp(void *a, void *b)
1207dd7cddfSDavid du Colombier {
1217dd7cddfSDavid du Colombier Dirlist *da, *db;
1227dd7cddfSDavid du Colombier int i, n;
1237dd7cddfSDavid du Colombier
1247dd7cddfSDavid du Colombier da = *(Dirlist**)a;
1257dd7cddfSDavid du Colombier db = *(Dirlist**)b;
1267dd7cddfSDavid du Colombier n = min(da->nr, db->nr);
1277dd7cddfSDavid du Colombier i = memcmp(da->r, db->r, n*sizeof(Rune));
1287dd7cddfSDavid du Colombier if(i)
1297dd7cddfSDavid du Colombier return i;
1307dd7cddfSDavid du Colombier return da->nr - db->nr;
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier
1337dd7cddfSDavid du Colombier void
textcolumnate(Text * t,Dirlist ** dlp,int ndl)1347dd7cddfSDavid du Colombier textcolumnate(Text *t, Dirlist **dlp, int ndl)
1357dd7cddfSDavid du Colombier {
1367dd7cddfSDavid du Colombier int i, j, w, colw, mint, maxt, ncol, nrow;
1377dd7cddfSDavid du Colombier Dirlist *dl;
1387dd7cddfSDavid du Colombier uint q1;
1397dd7cddfSDavid du Colombier
1407dd7cddfSDavid du Colombier if(t->file->ntext > 1)
1417dd7cddfSDavid du Colombier return;
1427dd7cddfSDavid du Colombier mint = stringwidth(t->font, "0");
1437dd7cddfSDavid du Colombier /* go for narrower tabs if set more than 3 wide */
1447dd7cddfSDavid du Colombier t->maxtab = min(maxtab, TABDIR)*mint;
1457dd7cddfSDavid du Colombier maxt = t->maxtab;
1467dd7cddfSDavid du Colombier colw = 0;
1477dd7cddfSDavid du Colombier for(i=0; i<ndl; i++){
1487dd7cddfSDavid du Colombier dl = dlp[i];
1497dd7cddfSDavid du Colombier w = dl->wid;
1509a747e4fSDavid du Colombier if(maxt-w%maxt < mint || w%maxt==0)
1517dd7cddfSDavid du Colombier w += mint;
1527dd7cddfSDavid du Colombier if(w % maxt)
1537dd7cddfSDavid du Colombier w += maxt-(w%maxt);
1547dd7cddfSDavid du Colombier if(w > colw)
1557dd7cddfSDavid du Colombier colw = w;
1567dd7cddfSDavid du Colombier }
1577dd7cddfSDavid du Colombier if(colw == 0)
1587dd7cddfSDavid du Colombier ncol = 1;
1597dd7cddfSDavid du Colombier else
1607dd7cddfSDavid du Colombier ncol = max(1, Dx(t->r)/colw);
1617dd7cddfSDavid du Colombier nrow = (ndl+ncol-1)/ncol;
1627dd7cddfSDavid du Colombier
1637dd7cddfSDavid du Colombier q1 = 0;
1647dd7cddfSDavid du Colombier for(i=0; i<nrow; i++){
1657dd7cddfSDavid du Colombier for(j=i; j<ndl; j+=nrow){
1667dd7cddfSDavid du Colombier dl = dlp[j];
1677dd7cddfSDavid du Colombier fileinsert(t->file, q1, dl->r, dl->nr);
1687dd7cddfSDavid du Colombier q1 += dl->nr;
1697dd7cddfSDavid du Colombier if(j+nrow >= ndl)
1707dd7cddfSDavid du Colombier break;
1717dd7cddfSDavid du Colombier w = dl->wid;
1727dd7cddfSDavid du Colombier if(maxt-w%maxt < mint){
1737dd7cddfSDavid du Colombier fileinsert(t->file, q1, L"\t", 1);
1747dd7cddfSDavid du Colombier q1++;
1757dd7cddfSDavid du Colombier w += mint;
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier do{
1787dd7cddfSDavid du Colombier fileinsert(t->file, q1, L"\t", 1);
1797dd7cddfSDavid du Colombier q1++;
1807dd7cddfSDavid du Colombier w += maxt-(w%maxt);
1817dd7cddfSDavid du Colombier }while(w < colw);
1827dd7cddfSDavid du Colombier }
1837dd7cddfSDavid du Colombier fileinsert(t->file, q1, L"\n", 1);
1847dd7cddfSDavid du Colombier q1++;
1857dd7cddfSDavid du Colombier }
1867dd7cddfSDavid du Colombier }
1877dd7cddfSDavid du Colombier
1887dd7cddfSDavid du Colombier uint
textload(Text * t,uint q0,char * file,int setqid)1897dd7cddfSDavid du Colombier textload(Text *t, uint q0, char *file, int setqid)
1907dd7cddfSDavid du Colombier {
1917dd7cddfSDavid du Colombier Rune *rp;
1927dd7cddfSDavid du Colombier Dirlist *dl, **dlp;
1939a747e4fSDavid du Colombier int fd, i, j, n, ndl, nulls;
1947dd7cddfSDavid du Colombier uint q, q1;
1959a747e4fSDavid du Colombier Dir *d, *dbuf;
1969a747e4fSDavid du Colombier char *tmp;
1977dd7cddfSDavid du Colombier Text *u;
1987dd7cddfSDavid du Colombier
1993df12bc6SDavid du Colombier if(t->ncache!=0 || t->file->nc || t->w==nil || t!=&t->w->body)
2007dd7cddfSDavid du Colombier error("text.load");
2013df12bc6SDavid du Colombier if(t->w->isdir && t->file->nname==0){
2023df12bc6SDavid du Colombier warning(nil, "empty directory name\n");
2033df12bc6SDavid du Colombier return 0;
2043df12bc6SDavid du Colombier }
2057dd7cddfSDavid du Colombier fd = open(file, OREAD);
2067dd7cddfSDavid du Colombier if(fd < 0){
2077dd7cddfSDavid du Colombier warning(nil, "can't open %s: %r\n", file);
2087dd7cddfSDavid du Colombier return 0;
2097dd7cddfSDavid du Colombier }
2109a747e4fSDavid du Colombier d = dirfstat(fd);
2119a747e4fSDavid du Colombier if(d == nil){
2127dd7cddfSDavid du Colombier warning(nil, "can't fstat %s: %r\n", file);
2137dd7cddfSDavid du Colombier goto Rescue;
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier nulls = FALSE;
2169a747e4fSDavid du Colombier if(d->qid.type & QTDIR){
2177dd7cddfSDavid du Colombier /* this is checked in get() but it's possible the file changed underfoot */
2187dd7cddfSDavid du Colombier if(t->file->ntext > 1){
2197dd7cddfSDavid du Colombier warning(nil, "%s is a directory; can't read with multiple windows on it\n", file);
2207dd7cddfSDavid du Colombier goto Rescue;
2217dd7cddfSDavid du Colombier }
2227dd7cddfSDavid du Colombier t->w->isdir = TRUE;
2237dd7cddfSDavid du Colombier t->w->filemenu = FALSE;
2247dd7cddfSDavid du Colombier if(t->file->name[t->file->nname-1] != '/'){
2257dd7cddfSDavid du Colombier rp = runemalloc(t->file->nname+1);
2267dd7cddfSDavid du Colombier runemove(rp, t->file->name, t->file->nname);
2277dd7cddfSDavid du Colombier rp[t->file->nname] = '/';
2287dd7cddfSDavid du Colombier winsetname(t->w, rp, t->file->nname+1);
22959cc4ca5SDavid du Colombier free(rp);
2307dd7cddfSDavid du Colombier }
2317dd7cddfSDavid du Colombier dlp = nil;
2327dd7cddfSDavid du Colombier ndl = 0;
2339a747e4fSDavid du Colombier dbuf = nil;
2349a747e4fSDavid du Colombier while((n=dirread(fd, &dbuf)) > 0){
2357dd7cddfSDavid du Colombier for(i=0; i<n; i++){
2367dd7cddfSDavid du Colombier dl = emalloc(sizeof(Dirlist));
2379a747e4fSDavid du Colombier j = strlen(dbuf[i].name);
2389a747e4fSDavid du Colombier tmp = emalloc(j+1+1);
2399a747e4fSDavid du Colombier memmove(tmp, dbuf[i].name, j);
2409a747e4fSDavid du Colombier if(dbuf[i].qid.type & QTDIR)
2419a747e4fSDavid du Colombier tmp[j++] = '/';
2429a747e4fSDavid du Colombier tmp[j] = '\0';
2437dd7cddfSDavid du Colombier dl->r = bytetorune(tmp, &dl->nr);
2447dd7cddfSDavid du Colombier dl->wid = stringwidth(t->font, tmp);
2459a747e4fSDavid du Colombier free(tmp);
2467dd7cddfSDavid du Colombier ndl++;
2477dd7cddfSDavid du Colombier dlp = realloc(dlp, ndl*sizeof(Dirlist*));
2487dd7cddfSDavid du Colombier dlp[ndl-1] = dl;
2497dd7cddfSDavid du Colombier }
2509a747e4fSDavid du Colombier free(dbuf);
2517dd7cddfSDavid du Colombier }
2527dd7cddfSDavid du Colombier qsort(dlp, ndl, sizeof(Dirlist*), dircmp);
2537dd7cddfSDavid du Colombier t->w->dlp = dlp;
2547dd7cddfSDavid du Colombier t->w->ndl = ndl;
2557dd7cddfSDavid du Colombier textcolumnate(t, dlp, ndl);
2567dd7cddfSDavid du Colombier q1 = t->file->nc;
2577dd7cddfSDavid du Colombier }else{
2587dd7cddfSDavid du Colombier t->w->isdir = FALSE;
2597dd7cddfSDavid du Colombier t->w->filemenu = TRUE;
2607dd7cddfSDavid du Colombier q1 = q0 + fileload(t->file, q0, fd, &nulls);
2617dd7cddfSDavid du Colombier }
2627dd7cddfSDavid du Colombier if(setqid){
2639a747e4fSDavid du Colombier t->file->dev = d->dev;
2649a747e4fSDavid du Colombier t->file->mtime = d->mtime;
2659a747e4fSDavid du Colombier t->file->qidpath = d->qid.path;
2667dd7cddfSDavid du Colombier }
2677dd7cddfSDavid du Colombier close(fd);
2687dd7cddfSDavid du Colombier rp = fbufalloc();
2697dd7cddfSDavid du Colombier for(q=q0; q<q1; q+=n){
2707dd7cddfSDavid du Colombier n = q1-q;
2717dd7cddfSDavid du Colombier if(n > RBUFSIZE)
2727dd7cddfSDavid du Colombier n = RBUFSIZE;
2737dd7cddfSDavid du Colombier bufread(t->file, q, rp, n);
2747dd7cddfSDavid du Colombier if(q < t->org)
2757dd7cddfSDavid du Colombier t->org += n;
2767dd7cddfSDavid du Colombier else if(q <= t->org+t->nchars)
2777dd7cddfSDavid du Colombier frinsert(t, rp, rp+n, q-t->org);
2787dd7cddfSDavid du Colombier if(t->lastlinefull)
2797dd7cddfSDavid du Colombier break;
2807dd7cddfSDavid du Colombier }
2817dd7cddfSDavid du Colombier fbuffree(rp);
2827dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++){
2837dd7cddfSDavid du Colombier u = t->file->text[i];
2847dd7cddfSDavid du Colombier if(u != t){
2857dd7cddfSDavid du Colombier if(u->org > u->file->nc) /* will be 0 because of reset(), but safety first */
2867dd7cddfSDavid du Colombier u->org = 0;
287*2c2299ceSDavid du Colombier textresize(u, u->all, TRUE);
2887dd7cddfSDavid du Colombier textbacknl(u, u->org, 0); /* go to beginning of line */
2897dd7cddfSDavid du Colombier }
2907dd7cddfSDavid du Colombier textsetselect(u, q0, q0);
2917dd7cddfSDavid du Colombier }
2927dd7cddfSDavid du Colombier if(nulls)
2937dd7cddfSDavid du Colombier warning(nil, "%s: NUL bytes elided\n", file);
2949a747e4fSDavid du Colombier free(d);
2957dd7cddfSDavid du Colombier return q1-q0;
2967dd7cddfSDavid du Colombier
2977dd7cddfSDavid du Colombier Rescue:
2987dd7cddfSDavid du Colombier close(fd);
2997dd7cddfSDavid du Colombier return 0;
3007dd7cddfSDavid du Colombier }
3017dd7cddfSDavid du Colombier
3027dd7cddfSDavid du Colombier uint
textbsinsert(Text * t,uint q0,Rune * r,uint n,int tofile,int * nrp)3037dd7cddfSDavid du Colombier textbsinsert(Text *t, uint q0, Rune *r, uint n, int tofile, int *nrp)
3047dd7cddfSDavid du Colombier {
3057dd7cddfSDavid du Colombier Rune *bp, *tp, *up;
3067dd7cddfSDavid du Colombier int i, initial;
3077dd7cddfSDavid du Colombier
3087dd7cddfSDavid du Colombier if(t->what == Tag){ /* can't happen but safety first: mustn't backspace over file name */
3097dd7cddfSDavid du Colombier Err:
3107dd7cddfSDavid du Colombier textinsert(t, q0, r, n, tofile);
3117dd7cddfSDavid du Colombier *nrp = n;
3127dd7cddfSDavid du Colombier return q0;
3137dd7cddfSDavid du Colombier }
3147dd7cddfSDavid du Colombier bp = r;
3157dd7cddfSDavid du Colombier for(i=0; i<n; i++)
3167dd7cddfSDavid du Colombier if(*bp++ == '\b'){
3177dd7cddfSDavid du Colombier --bp;
3187dd7cddfSDavid du Colombier initial = 0;
3197dd7cddfSDavid du Colombier tp = runemalloc(n);
3207dd7cddfSDavid du Colombier runemove(tp, r, i);
3217dd7cddfSDavid du Colombier up = tp+i;
3227dd7cddfSDavid du Colombier for(; i<n; i++){
3237dd7cddfSDavid du Colombier *up = *bp++;
3247dd7cddfSDavid du Colombier if(*up == '\b')
3257dd7cddfSDavid du Colombier if(up == tp)
3267dd7cddfSDavid du Colombier initial++;
3277dd7cddfSDavid du Colombier else
3287dd7cddfSDavid du Colombier --up;
3297dd7cddfSDavid du Colombier else
3307dd7cddfSDavid du Colombier up++;
3317dd7cddfSDavid du Colombier }
3327dd7cddfSDavid du Colombier if(initial){
3337dd7cddfSDavid du Colombier if(initial > q0)
3347dd7cddfSDavid du Colombier initial = q0;
3357dd7cddfSDavid du Colombier q0 -= initial;
3367dd7cddfSDavid du Colombier textdelete(t, q0, q0+initial, tofile);
3377dd7cddfSDavid du Colombier }
3387dd7cddfSDavid du Colombier n = up-tp;
3397dd7cddfSDavid du Colombier textinsert(t, q0, tp, n, tofile);
3407dd7cddfSDavid du Colombier free(tp);
3417dd7cddfSDavid du Colombier *nrp = n;
3427dd7cddfSDavid du Colombier return q0;
3437dd7cddfSDavid du Colombier }
3447dd7cddfSDavid du Colombier goto Err;
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier void
textinsert(Text * t,uint q0,Rune * r,uint n,int tofile)3487dd7cddfSDavid du Colombier textinsert(Text *t, uint q0, Rune *r, uint n, int tofile)
3497dd7cddfSDavid du Colombier {
3507dd7cddfSDavid du Colombier int c, i;
3517dd7cddfSDavid du Colombier Text *u;
3527dd7cddfSDavid du Colombier
3537dd7cddfSDavid du Colombier if(tofile && t->ncache != 0)
3547dd7cddfSDavid du Colombier error("text.insert");
3557dd7cddfSDavid du Colombier if(n == 0)
3567dd7cddfSDavid du Colombier return;
3577dd7cddfSDavid du Colombier if(tofile){
3587dd7cddfSDavid du Colombier fileinsert(t->file, q0, r, n);
3597dd7cddfSDavid du Colombier if(t->what == Body){
3607dd7cddfSDavid du Colombier t->w->dirty = TRUE;
3617dd7cddfSDavid du Colombier t->w->utflastqid = -1;
3627dd7cddfSDavid du Colombier }
3637dd7cddfSDavid du Colombier if(t->file->ntext > 1)
3647dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++){
3657dd7cddfSDavid du Colombier u = t->file->text[i];
3667dd7cddfSDavid du Colombier if(u != t){
3677dd7cddfSDavid du Colombier u->w->dirty = TRUE; /* always a body */
3687dd7cddfSDavid du Colombier textinsert(u, q0, r, n, FALSE);
3697dd7cddfSDavid du Colombier textsetselect(u, u->q0, u->q1);
3707dd7cddfSDavid du Colombier textscrdraw(u);
3717dd7cddfSDavid du Colombier }
3727dd7cddfSDavid du Colombier }
3737dd7cddfSDavid du Colombier
3747dd7cddfSDavid du Colombier }
3757dd7cddfSDavid du Colombier if(q0 < t->q1)
3767dd7cddfSDavid du Colombier t->q1 += n;
3777dd7cddfSDavid du Colombier if(q0 < t->q0)
3787dd7cddfSDavid du Colombier t->q0 += n;
3797dd7cddfSDavid du Colombier if(q0 < t->org)
3807dd7cddfSDavid du Colombier t->org += n;
3817dd7cddfSDavid du Colombier else if(q0 <= t->org+t->nchars)
3827dd7cddfSDavid du Colombier frinsert(t, r, r+n, q0-t->org);
3837dd7cddfSDavid du Colombier if(t->w){
3847dd7cddfSDavid du Colombier c = 'i';
3857dd7cddfSDavid du Colombier if(t->what == Body)
3867dd7cddfSDavid du Colombier c = 'I';
3877dd7cddfSDavid du Colombier if(n <= EVENTSIZE)
3887dd7cddfSDavid du Colombier winevent(t->w, "%c%d %d 0 %d %.*S\n", c, q0, q0+n, n, n, r);
3897dd7cddfSDavid du Colombier else
3907dd7cddfSDavid du Colombier winevent(t->w, "%c%d %d 0 0 \n", c, q0, q0+n, n);
3917dd7cddfSDavid du Colombier }
3927dd7cddfSDavid du Colombier }
3937dd7cddfSDavid du Colombier
394e7d29567SDavid du Colombier void
typecommit(Text * t)395e7d29567SDavid du Colombier typecommit(Text *t)
396e7d29567SDavid du Colombier {
397e7d29567SDavid du Colombier if(t->w != nil)
398e7d29567SDavid du Colombier wincommit(t->w, t);
399e7d29567SDavid du Colombier else
400e7d29567SDavid du Colombier textcommit(t, TRUE);
401e7d29567SDavid du Colombier }
4027dd7cddfSDavid du Colombier
4037dd7cddfSDavid du Colombier void
textfill(Text * t)4047dd7cddfSDavid du Colombier textfill(Text *t)
4057dd7cddfSDavid du Colombier {
4067dd7cddfSDavid du Colombier Rune *rp;
4077dd7cddfSDavid du Colombier int i, n, m, nl;
4087dd7cddfSDavid du Colombier
4097dd7cddfSDavid du Colombier if(t->lastlinefull || t->nofill)
4107dd7cddfSDavid du Colombier return;
411e7d29567SDavid du Colombier if(t->ncache > 0)
412e7d29567SDavid du Colombier typecommit(t);
4137dd7cddfSDavid du Colombier rp = fbufalloc();
4147dd7cddfSDavid du Colombier do{
4157dd7cddfSDavid du Colombier n = t->file->nc-(t->org+t->nchars);
4167dd7cddfSDavid du Colombier if(n == 0)
4177dd7cddfSDavid du Colombier break;
4187dd7cddfSDavid du Colombier if(n > 2000) /* educated guess at reasonable amount */
4197dd7cddfSDavid du Colombier n = 2000;
4207dd7cddfSDavid du Colombier bufread(t->file, t->org+t->nchars, rp, n);
4217dd7cddfSDavid du Colombier /*
4227dd7cddfSDavid du Colombier * it's expensive to frinsert more than we need, so
4237dd7cddfSDavid du Colombier * count newlines.
4247dd7cddfSDavid du Colombier */
4257dd7cddfSDavid du Colombier nl = t->maxlines-t->nlines;
4267dd7cddfSDavid du Colombier m = 0;
4277dd7cddfSDavid du Colombier for(i=0; i<n; ){
4287dd7cddfSDavid du Colombier if(rp[i++] == '\n'){
4297dd7cddfSDavid du Colombier m++;
4307dd7cddfSDavid du Colombier if(m >= nl)
4317dd7cddfSDavid du Colombier break;
4327dd7cddfSDavid du Colombier }
4337dd7cddfSDavid du Colombier }
4347dd7cddfSDavid du Colombier frinsert(t, rp, rp+i, t->nchars);
4357dd7cddfSDavid du Colombier }while(t->lastlinefull == FALSE);
4367dd7cddfSDavid du Colombier fbuffree(rp);
4377dd7cddfSDavid du Colombier }
4387dd7cddfSDavid du Colombier
4397dd7cddfSDavid du Colombier void
textdelete(Text * t,uint q0,uint q1,int tofile)4407dd7cddfSDavid du Colombier textdelete(Text *t, uint q0, uint q1, int tofile)
4417dd7cddfSDavid du Colombier {
4427dd7cddfSDavid du Colombier uint n, p0, p1;
4437dd7cddfSDavid du Colombier int i, c;
4447dd7cddfSDavid du Colombier Text *u;
4457dd7cddfSDavid du Colombier
4467dd7cddfSDavid du Colombier if(tofile && t->ncache != 0)
4477dd7cddfSDavid du Colombier error("text.delete");
4487dd7cddfSDavid du Colombier n = q1-q0;
4497dd7cddfSDavid du Colombier if(n == 0)
4507dd7cddfSDavid du Colombier return;
4517dd7cddfSDavid du Colombier if(tofile){
4527dd7cddfSDavid du Colombier filedelete(t->file, q0, q1);
4537dd7cddfSDavid du Colombier if(t->what == Body){
4547dd7cddfSDavid du Colombier t->w->dirty = TRUE;
4557dd7cddfSDavid du Colombier t->w->utflastqid = -1;
4567dd7cddfSDavid du Colombier }
4577dd7cddfSDavid du Colombier if(t->file->ntext > 1)
4587dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++){
4597dd7cddfSDavid du Colombier u = t->file->text[i];
4607dd7cddfSDavid du Colombier if(u != t){
4617dd7cddfSDavid du Colombier u->w->dirty = TRUE; /* always a body */
4627dd7cddfSDavid du Colombier textdelete(u, q0, q1, FALSE);
4637dd7cddfSDavid du Colombier textsetselect(u, u->q0, u->q1);
4647dd7cddfSDavid du Colombier textscrdraw(u);
4657dd7cddfSDavid du Colombier }
4667dd7cddfSDavid du Colombier }
4677dd7cddfSDavid du Colombier }
4687dd7cddfSDavid du Colombier if(q0 < t->q0)
4697dd7cddfSDavid du Colombier t->q0 -= min(n, t->q0-q0);
4707dd7cddfSDavid du Colombier if(q0 < t->q1)
4717dd7cddfSDavid du Colombier t->q1 -= min(n, t->q1-q0);
4727dd7cddfSDavid du Colombier if(q1 <= t->org)
4737dd7cddfSDavid du Colombier t->org -= n;
4747dd7cddfSDavid du Colombier else if(q0 < t->org+t->nchars){
4757dd7cddfSDavid du Colombier p1 = q1 - t->org;
4767dd7cddfSDavid du Colombier if(p1 > t->nchars)
4777dd7cddfSDavid du Colombier p1 = t->nchars;
4787dd7cddfSDavid du Colombier if(q0 < t->org){
4797dd7cddfSDavid du Colombier t->org = q0;
4807dd7cddfSDavid du Colombier p0 = 0;
4817dd7cddfSDavid du Colombier }else
4827dd7cddfSDavid du Colombier p0 = q0 - t->org;
4837dd7cddfSDavid du Colombier frdelete(t, p0, p1);
4847dd7cddfSDavid du Colombier textfill(t);
4857dd7cddfSDavid du Colombier }
4867dd7cddfSDavid du Colombier if(t->w){
4877dd7cddfSDavid du Colombier c = 'd';
4887dd7cddfSDavid du Colombier if(t->what == Body)
4897dd7cddfSDavid du Colombier c = 'D';
4907dd7cddfSDavid du Colombier winevent(t->w, "%c%d %d 0 0 \n", c, q0, q1);
4917dd7cddfSDavid du Colombier }
4927dd7cddfSDavid du Colombier }
4937dd7cddfSDavid du Colombier
4946b6b9ac8SDavid du Colombier void
textconstrain(Text * t,uint q0,uint q1,uint * p0,uint * p1)4956b6b9ac8SDavid du Colombier textconstrain(Text *t, uint q0, uint q1, uint *p0, uint *p1)
4966b6b9ac8SDavid du Colombier {
4976b6b9ac8SDavid du Colombier *p0 = min(q0, t->file->nc);
4986b6b9ac8SDavid du Colombier *p1 = min(q1, t->file->nc);
4996b6b9ac8SDavid du Colombier }
5006b6b9ac8SDavid du Colombier
5017dd7cddfSDavid du Colombier Rune
textreadc(Text * t,uint q)5027dd7cddfSDavid du Colombier textreadc(Text *t, uint q)
5037dd7cddfSDavid du Colombier {
5047dd7cddfSDavid du Colombier Rune r;
5057dd7cddfSDavid du Colombier
5067dd7cddfSDavid du Colombier if(t->cq0<=q && q<t->cq0+t->ncache)
5077dd7cddfSDavid du Colombier r = t->cache[q-t->cq0];
5087dd7cddfSDavid du Colombier else
5097dd7cddfSDavid du Colombier bufread(t->file, q, &r, 1);
5107dd7cddfSDavid du Colombier return r;
5117dd7cddfSDavid du Colombier }
5127dd7cddfSDavid du Colombier
5137dd7cddfSDavid du Colombier int
textbswidth(Text * t,Rune c)5147dd7cddfSDavid du Colombier textbswidth(Text *t, Rune c)
5157dd7cddfSDavid du Colombier {
5167dd7cddfSDavid du Colombier uint q, eq;
5177dd7cddfSDavid du Colombier Rune r;
5187dd7cddfSDavid du Colombier int skipping;
5197dd7cddfSDavid du Colombier
5207dd7cddfSDavid du Colombier /* there is known to be at least one character to erase */
5217dd7cddfSDavid du Colombier if(c == 0x08) /* ^H: erase character */
5227dd7cddfSDavid du Colombier return 1;
5237dd7cddfSDavid du Colombier q = t->q0;
5247dd7cddfSDavid du Colombier skipping = TRUE;
5257dd7cddfSDavid du Colombier while(q > 0){
5267dd7cddfSDavid du Colombier r = textreadc(t, q-1);
5277dd7cddfSDavid du Colombier if(r == '\n'){ /* eat at most one more character */
5287dd7cddfSDavid du Colombier if(q == t->q0) /* eat the newline */
5297dd7cddfSDavid du Colombier --q;
5307dd7cddfSDavid du Colombier break;
5317dd7cddfSDavid du Colombier }
5327dd7cddfSDavid du Colombier if(c == 0x17){
5337dd7cddfSDavid du Colombier eq = isalnum(r);
5347dd7cddfSDavid du Colombier if(eq && skipping) /* found one; stop skipping */
5357dd7cddfSDavid du Colombier skipping = FALSE;
5367dd7cddfSDavid du Colombier else if(!eq && !skipping)
5377dd7cddfSDavid du Colombier break;
5387dd7cddfSDavid du Colombier }
5397dd7cddfSDavid du Colombier --q;
5407dd7cddfSDavid du Colombier }
5417dd7cddfSDavid du Colombier return t->q0-q;
5427dd7cddfSDavid du Colombier }
5437dd7cddfSDavid du Colombier
544fe853e23SDavid du Colombier int
textfilewidth(Text * t,uint q0,int oneelement)545fe853e23SDavid du Colombier textfilewidth(Text *t, uint q0, int oneelement)
546fe853e23SDavid du Colombier {
547fe853e23SDavid du Colombier uint q;
548fe853e23SDavid du Colombier Rune r;
549fe853e23SDavid du Colombier
550fe853e23SDavid du Colombier q = q0;
551fe853e23SDavid du Colombier while(q > 0){
552fe853e23SDavid du Colombier r = textreadc(t, q-1);
553fe853e23SDavid du Colombier if(r <= ' ')
554fe853e23SDavid du Colombier break;
555fe853e23SDavid du Colombier if(oneelement && r=='/')
556fe853e23SDavid du Colombier break;
557fe853e23SDavid du Colombier --q;
558fe853e23SDavid du Colombier }
559fe853e23SDavid du Colombier return q0-q;
560fe853e23SDavid du Colombier }
561fe853e23SDavid du Colombier
562fe853e23SDavid du Colombier Rune*
textcomplete(Text * t)563fe853e23SDavid du Colombier textcomplete(Text *t)
564fe853e23SDavid du Colombier {
565fe853e23SDavid du Colombier int i, nstr, npath;
566fe853e23SDavid du Colombier uint q;
567fe853e23SDavid du Colombier Rune tmp[200];
568fe853e23SDavid du Colombier Rune *str, *path;
569fe853e23SDavid du Colombier Rune *rp;
570fe853e23SDavid du Colombier Completion *c;
571fe853e23SDavid du Colombier char *s, *dirs;
572fe853e23SDavid du Colombier Runestr dir;
573fe853e23SDavid du Colombier
574fe853e23SDavid du Colombier /* control-f: filename completion; works back to white space or / */
575fe853e23SDavid du Colombier if(t->q0<t->file->nc && textreadc(t, t->q0)>' ') /* must be at end of word */
576fe853e23SDavid du Colombier return nil;
577fe853e23SDavid du Colombier nstr = textfilewidth(t, t->q0, TRUE);
578fe853e23SDavid du Colombier str = runemalloc(nstr);
579fe853e23SDavid du Colombier npath = textfilewidth(t, t->q0-nstr, FALSE);
580fe853e23SDavid du Colombier path = runemalloc(npath);
581fe853e23SDavid du Colombier
582fe853e23SDavid du Colombier c = nil;
583fe853e23SDavid du Colombier rp = nil;
584fe853e23SDavid du Colombier dirs = nil;
585fe853e23SDavid du Colombier
586fe853e23SDavid du Colombier q = t->q0-nstr;
587fe853e23SDavid du Colombier for(i=0; i<nstr; i++)
588fe853e23SDavid du Colombier str[i] = textreadc(t, q++);
589fe853e23SDavid du Colombier q = t->q0-nstr-npath;
590fe853e23SDavid du Colombier for(i=0; i<npath; i++)
591fe853e23SDavid du Colombier path[i] = textreadc(t, q++);
592fe853e23SDavid du Colombier /* is path rooted? if not, we need to make it relative to window path */
593fe853e23SDavid du Colombier if(npath>0 && path[0]=='/')
594fe853e23SDavid du Colombier dir = (Runestr){path, npath};
595fe853e23SDavid du Colombier else{
596fe853e23SDavid du Colombier dir = dirname(t, nil, 0);
597fe853e23SDavid du Colombier if(dir.nr + 1 + npath > nelem(tmp)){
598fe853e23SDavid du Colombier free(dir.r);
599fe853e23SDavid du Colombier goto Return;
600fe853e23SDavid du Colombier }
601fe853e23SDavid du Colombier if(dir.nr == 0){
602fe853e23SDavid du Colombier dir.nr = 1;
603fe853e23SDavid du Colombier dir.r = runestrdup(L".");
604fe853e23SDavid du Colombier }
605fe853e23SDavid du Colombier runemove(tmp, dir.r, dir.nr);
606fe853e23SDavid du Colombier tmp[dir.nr] = '/';
607fe853e23SDavid du Colombier runemove(tmp+dir.nr+1, path, npath);
608fe853e23SDavid du Colombier free(dir.r);
609fe853e23SDavid du Colombier dir.r = tmp;
610fe853e23SDavid du Colombier dir.nr += 1+npath;
611fe853e23SDavid du Colombier dir = cleanrname(dir);
612fe853e23SDavid du Colombier }
613fe853e23SDavid du Colombier
614fe853e23SDavid du Colombier s = smprint("%.*S", nstr, str);
615fe853e23SDavid du Colombier dirs = smprint("%.*S", dir.nr, dir.r);
616fe853e23SDavid du Colombier c = complete(dirs, s);
617fe853e23SDavid du Colombier free(s);
618fe853e23SDavid du Colombier if(c == nil){
619fe853e23SDavid du Colombier warning(nil, "error attempting completion: %r\n");
620fe853e23SDavid du Colombier goto Return;
621fe853e23SDavid du Colombier }
622fe853e23SDavid du Colombier
623fe853e23SDavid du Colombier if(!c->advance){
6244fec87e5SDavid du Colombier warning(nil, "%.*S%s%.*S*%s\n",
625fe853e23SDavid du Colombier dir.nr, dir.r,
626fe853e23SDavid du Colombier dir.nr>0 && dir.r[dir.nr-1]!='/' ? "/" : "",
6274fec87e5SDavid du Colombier nstr, str,
6284fec87e5SDavid du Colombier c->nmatch? "" : ": no matches in:");
629fe853e23SDavid du Colombier for(i=0; i<c->nfile; i++)
630fe853e23SDavid du Colombier warning(nil, " %s\n", c->filename[i]);
631fe853e23SDavid du Colombier }
632fe853e23SDavid du Colombier
633fe853e23SDavid du Colombier if(c->advance)
634fe853e23SDavid du Colombier rp = runesmprint("%s", c->string);
635fe853e23SDavid du Colombier else
636fe853e23SDavid du Colombier rp = nil;
637fe853e23SDavid du Colombier Return:
638fe853e23SDavid du Colombier freecompletion(c);
639fe853e23SDavid du Colombier free(dirs);
640fe853e23SDavid du Colombier free(str);
641fe853e23SDavid du Colombier free(path);
642fe853e23SDavid du Colombier return rp;
643fe853e23SDavid du Colombier }
644fe853e23SDavid du Colombier
6457dd7cddfSDavid du Colombier void
texttype(Text * t,Rune r)6467dd7cddfSDavid du Colombier texttype(Text *t, Rune r)
6477dd7cddfSDavid du Colombier {
6487dd7cddfSDavid du Colombier uint q0, q1;
6497dd7cddfSDavid du Colombier int nnb, nb, n, i;
650fe853e23SDavid du Colombier int nr;
651fe853e23SDavid du Colombier Rune *rp;
6527dd7cddfSDavid du Colombier Text *u;
6537dd7cddfSDavid du Colombier
654*2c2299ceSDavid du Colombier if(t->what!=Body && t->what!=Tag && r=='\n')
6557dd7cddfSDavid du Colombier return;
656*2c2299ceSDavid du Colombier if(t->what == Tag)
657*2c2299ceSDavid du Colombier t->w->tagsafe = FALSE;
658*2c2299ceSDavid du Colombier
659fe853e23SDavid du Colombier nr = 1;
660fe853e23SDavid du Colombier rp = &r;
6617dd7cddfSDavid du Colombier switch(r){
6627dd7cddfSDavid du Colombier case Kleft:
663fe853e23SDavid du Colombier if(t->q0 > 0){
664e7d29567SDavid du Colombier typecommit(t);
665fe853e23SDavid du Colombier textshow(t, t->q0-1, t->q0-1, TRUE);
666fe853e23SDavid du Colombier }
667fe853e23SDavid du Colombier return;
6687dd7cddfSDavid du Colombier case Kright:
669fe853e23SDavid du Colombier if(t->q1 < t->file->nc){
670e7d29567SDavid du Colombier typecommit(t);
671fe853e23SDavid du Colombier textshow(t, t->q1+1, t->q1+1, TRUE);
672fe853e23SDavid du Colombier }
673fe853e23SDavid du Colombier return;
674fe853e23SDavid du Colombier case Kdown:
675*2c2299ceSDavid du Colombier if(t->what == Tag)
676*2c2299ceSDavid du Colombier goto Tagdown;
677fe853e23SDavid du Colombier n = t->maxlines/3;
678fe853e23SDavid du Colombier goto case_Down;
679a8453668SDavid du Colombier case Kscrollonedown:
680*2c2299ceSDavid du Colombier if(t->what == Tag)
681*2c2299ceSDavid du Colombier goto Tagdown;
682a8453668SDavid du Colombier n = mousescrollsize(t->maxlines);
683a8453668SDavid du Colombier if(n <= 0)
684a8453668SDavid du Colombier n = 1;
685a8453668SDavid du Colombier goto case_Down;
686fe853e23SDavid du Colombier case Kpgdown:
687fe853e23SDavid du Colombier n = 2*t->maxlines/3;
688fe853e23SDavid du Colombier case_Down:
6897dd7cddfSDavid du Colombier q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+n*t->font->height));
6909847521cSDavid du Colombier textsetorigin(t, q0, TRUE);
6917dd7cddfSDavid du Colombier return;
6927dd7cddfSDavid du Colombier case Kup:
693*2c2299ceSDavid du Colombier if(t->what == Tag)
694*2c2299ceSDavid du Colombier goto Tagup;
695fe853e23SDavid du Colombier n = t->maxlines/3;
696fe853e23SDavid du Colombier goto case_Up;
697a8453668SDavid du Colombier case Kscrolloneup:
698*2c2299ceSDavid du Colombier if(t->what == Tag)
699*2c2299ceSDavid du Colombier goto Tagup;
700a8453668SDavid du Colombier n = mousescrollsize(t->maxlines);
701a8453668SDavid du Colombier goto case_Up;
702fe853e23SDavid du Colombier case Kpgup:
703fe853e23SDavid du Colombier n = 2*t->maxlines/3;
704fe853e23SDavid du Colombier case_Up:
7057dd7cddfSDavid du Colombier q0 = textbacknl(t, t->org, n);
7069847521cSDavid du Colombier textsetorigin(t, q0, TRUE);
7077dd7cddfSDavid du Colombier return;
708fe853e23SDavid du Colombier case Khome:
709e7d29567SDavid du Colombier typecommit(t);
710fe853e23SDavid du Colombier textshow(t, 0, 0, FALSE);
711fe853e23SDavid du Colombier return;
712fe853e23SDavid du Colombier case Kend:
713e7d29567SDavid du Colombier typecommit(t);
714fe853e23SDavid du Colombier textshow(t, t->file->nc, t->file->nc, FALSE);
715fe853e23SDavid du Colombier return;
716e7d29567SDavid du Colombier case 0x01: /* ^A: beginning of line */
717e7d29567SDavid du Colombier typecommit(t);
718e7d29567SDavid du Colombier /* go to where ^U would erase, if not already at BOL */
719e7d29567SDavid du Colombier nnb = 0;
720e7d29567SDavid du Colombier if(t->q0>0 && textreadc(t, t->q0-1)!='\n')
721e7d29567SDavid du Colombier nnb = textbswidth(t, 0x15);
722e7d29567SDavid du Colombier textshow(t, t->q0-nnb, t->q0-nnb, TRUE);
723e7d29567SDavid du Colombier return;
724e7d29567SDavid du Colombier case 0x05: /* ^E: end of line */
725e7d29567SDavid du Colombier typecommit(t);
726e7d29567SDavid du Colombier q0 = t->q0;
727e7d29567SDavid du Colombier while(q0<t->file->nc && textreadc(t, q0)!='\n')
728e7d29567SDavid du Colombier q0++;
729e7d29567SDavid du Colombier textshow(t, q0, q0, TRUE);
730e7d29567SDavid du Colombier return;
731*2c2299ceSDavid du Colombier
732*2c2299ceSDavid du Colombier Tagdown:
733*2c2299ceSDavid du Colombier /* expand tag to show all text */
734*2c2299ceSDavid du Colombier if(!t->w->tagexpand){
735*2c2299ceSDavid du Colombier t->w->tagexpand = TRUE;
736*2c2299ceSDavid du Colombier winresize(t->w, t->w->r, FALSE, TRUE);
737*2c2299ceSDavid du Colombier }
738*2c2299ceSDavid du Colombier return;
739*2c2299ceSDavid du Colombier
740*2c2299ceSDavid du Colombier Tagup:
741*2c2299ceSDavid du Colombier /* shrink tag to single line */
742*2c2299ceSDavid du Colombier if(t->w->tagexpand){
743*2c2299ceSDavid du Colombier t->w->tagexpand = FALSE;
744*2c2299ceSDavid du Colombier t->w->taglines = 1;
745*2c2299ceSDavid du Colombier winresize(t->w, t->w->r, FALSE, TRUE);
746*2c2299ceSDavid du Colombier }
747*2c2299ceSDavid du Colombier return;
7487dd7cddfSDavid du Colombier }
7497dd7cddfSDavid du Colombier if(t->what == Body){
7507dd7cddfSDavid du Colombier seq++;
7517dd7cddfSDavid du Colombier filemark(t->file);
7527dd7cddfSDavid du Colombier }
7537dd7cddfSDavid du Colombier if(t->q1 > t->q0){
7547dd7cddfSDavid du Colombier if(t->ncache != 0)
7557dd7cddfSDavid du Colombier error("text.type");
7567dd7cddfSDavid du Colombier cut(t, t, nil, TRUE, TRUE, nil, 0);
7577dd7cddfSDavid du Colombier t->eq0 = ~0;
7587dd7cddfSDavid du Colombier }
7599a747e4fSDavid du Colombier textshow(t, t->q0, t->q0, 1);
7607dd7cddfSDavid du Colombier switch(r){
761fe853e23SDavid du Colombier case 0x06:
762fe853e23SDavid du Colombier case Kins:
763fe853e23SDavid du Colombier rp = textcomplete(t);
764fe853e23SDavid du Colombier if(rp == nil)
765fe853e23SDavid du Colombier return;
766fe853e23SDavid du Colombier nr = runestrlen(rp);
767fe853e23SDavid du Colombier break; /* fall through to normal insertion case */
7687dd7cddfSDavid du Colombier case 0x1B:
7697dd7cddfSDavid du Colombier if(t->eq0 != ~0)
7707dd7cddfSDavid du Colombier textsetselect(t, t->eq0, t->q0);
771e7d29567SDavid du Colombier if(t->ncache > 0)
772e7d29567SDavid du Colombier typecommit(t);
7737dd7cddfSDavid du Colombier return;
7747dd7cddfSDavid du Colombier case 0x08: /* ^H: erase character */
7757dd7cddfSDavid du Colombier case 0x15: /* ^U: erase line */
7767dd7cddfSDavid du Colombier case 0x17: /* ^W: erase word */
77780ee5cbfSDavid du Colombier if(t->q0 == 0) /* nothing to erase */
7787dd7cddfSDavid du Colombier return;
7797dd7cddfSDavid du Colombier nnb = textbswidth(t, r);
7807dd7cddfSDavid du Colombier q1 = t->q0;
7817dd7cddfSDavid du Colombier q0 = q1-nnb;
78280ee5cbfSDavid du Colombier /* if selection is at beginning of window, avoid deleting invisible text */
78380ee5cbfSDavid du Colombier if(q0 < t->org){
78480ee5cbfSDavid du Colombier q0 = t->org;
78580ee5cbfSDavid du Colombier nnb = q1-q0;
78680ee5cbfSDavid du Colombier }
78780ee5cbfSDavid du Colombier if(nnb <= 0)
78880ee5cbfSDavid du Colombier return;
7897dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++){
7907dd7cddfSDavid du Colombier u = t->file->text[i];
7917dd7cddfSDavid du Colombier u->nofill = TRUE;
7927dd7cddfSDavid du Colombier nb = nnb;
7937dd7cddfSDavid du Colombier n = u->ncache;
7947dd7cddfSDavid du Colombier if(n > 0){
7957dd7cddfSDavid du Colombier if(q1 != u->cq0+n)
7967dd7cddfSDavid du Colombier error("text.type backspace");
7977dd7cddfSDavid du Colombier if(n > nb)
7987dd7cddfSDavid du Colombier n = nb;
7997dd7cddfSDavid du Colombier u->ncache -= n;
8007dd7cddfSDavid du Colombier textdelete(u, q1-n, q1, FALSE);
8017dd7cddfSDavid du Colombier nb -= n;
8027dd7cddfSDavid du Colombier }
8037dd7cddfSDavid du Colombier if(u->eq0==q1 || u->eq0==~0)
8047dd7cddfSDavid du Colombier u->eq0 = q0;
8057dd7cddfSDavid du Colombier if(nb && u==t)
8067dd7cddfSDavid du Colombier textdelete(u, q0, q0+nb, TRUE);
8077dd7cddfSDavid du Colombier if(u != t)
8087dd7cddfSDavid du Colombier textsetselect(u, u->q0, u->q1);
8097dd7cddfSDavid du Colombier else
8107dd7cddfSDavid du Colombier textsetselect(t, q0, q0);
8117dd7cddfSDavid du Colombier u->nofill = FALSE;
8127dd7cddfSDavid du Colombier }
8137dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++)
8147dd7cddfSDavid du Colombier textfill(t->file->text[i]);
8157dd7cddfSDavid du Colombier return;
8164fec87e5SDavid du Colombier case '\n':
8174fec87e5SDavid du Colombier if(t->w->autoindent){
8184fec87e5SDavid du Colombier /* find beginning of previous line using backspace code */
8194fec87e5SDavid du Colombier nnb = textbswidth(t, 0x15); /* ^U case */
8204fec87e5SDavid du Colombier rp = runemalloc(nnb + 1);
8214fec87e5SDavid du Colombier nr = 0;
8224fec87e5SDavid du Colombier rp[nr++] = r;
8234fec87e5SDavid du Colombier for(i=0; i<nnb; i++){
8244fec87e5SDavid du Colombier r = textreadc(t, t->q0-nnb+i);
8254fec87e5SDavid du Colombier if(r != ' ' && r != '\t')
8264fec87e5SDavid du Colombier break;
8274fec87e5SDavid du Colombier rp[nr++] = r;
8284fec87e5SDavid du Colombier }
8294fec87e5SDavid du Colombier }
8304fec87e5SDavid du Colombier break; /* fall through to normal code */
8317dd7cddfSDavid du Colombier }
8327dd7cddfSDavid du Colombier /* otherwise ordinary character; just insert, typically in caches of all texts */
8337dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++){
8347dd7cddfSDavid du Colombier u = t->file->text[i];
8357dd7cddfSDavid du Colombier if(u->eq0 == ~0)
8367dd7cddfSDavid du Colombier u->eq0 = t->q0;
8377dd7cddfSDavid du Colombier if(u->ncache == 0)
8387dd7cddfSDavid du Colombier u->cq0 = t->q0;
8397dd7cddfSDavid du Colombier else if(t->q0 != u->cq0+u->ncache)
8407dd7cddfSDavid du Colombier error("text.type cq1");
841fe853e23SDavid du Colombier textinsert(u, t->q0, rp, nr, FALSE);
8427dd7cddfSDavid du Colombier if(u != t)
8437dd7cddfSDavid du Colombier textsetselect(u, u->q0, u->q1);
844fe853e23SDavid du Colombier if(u->ncache+nr > u->ncachealloc){
845fe853e23SDavid du Colombier u->ncachealloc += 10 + nr;
8467dd7cddfSDavid du Colombier u->cache = runerealloc(u->cache, u->ncachealloc);
8477dd7cddfSDavid du Colombier }
848fe853e23SDavid du Colombier runemove(u->cache+u->ncache, rp, nr);
849fe853e23SDavid du Colombier u->ncache += nr;
8507dd7cddfSDavid du Colombier }
851fe853e23SDavid du Colombier if(rp != &r)
852fe853e23SDavid du Colombier free(rp);
853fe853e23SDavid du Colombier textsetselect(t, t->q0+nr, t->q0+nr);
8547dd7cddfSDavid du Colombier if(r=='\n' && t->w!=nil)
8557dd7cddfSDavid du Colombier wincommit(t->w, t);
8567dd7cddfSDavid du Colombier }
8577dd7cddfSDavid du Colombier
8587dd7cddfSDavid du Colombier void
textcommit(Text * t,int tofile)8597dd7cddfSDavid du Colombier textcommit(Text *t, int tofile)
8607dd7cddfSDavid du Colombier {
8617dd7cddfSDavid du Colombier if(t->ncache == 0)
8627dd7cddfSDavid du Colombier return;
8637dd7cddfSDavid du Colombier if(tofile)
8647dd7cddfSDavid du Colombier fileinsert(t->file, t->cq0, t->cache, t->ncache);
8657dd7cddfSDavid du Colombier if(t->what == Body){
8667dd7cddfSDavid du Colombier t->w->dirty = TRUE;
8677dd7cddfSDavid du Colombier t->w->utflastqid = -1;
8687dd7cddfSDavid du Colombier }
8697dd7cddfSDavid du Colombier t->ncache = 0;
8707dd7cddfSDavid du Colombier }
8717dd7cddfSDavid du Colombier
8727dd7cddfSDavid du Colombier static Text *clicktext;
8737dd7cddfSDavid du Colombier static uint clickmsec;
8747dd7cddfSDavid du Colombier static Text *selecttext;
8757dd7cddfSDavid du Colombier static uint selectq;
8767dd7cddfSDavid du Colombier
8777dd7cddfSDavid du Colombier /*
8787dd7cddfSDavid du Colombier * called from frame library
8797dd7cddfSDavid du Colombier */
8807dd7cddfSDavid du Colombier void
framescroll(Frame * f,int dl)8817dd7cddfSDavid du Colombier framescroll(Frame *f, int dl)
8827dd7cddfSDavid du Colombier {
8837dd7cddfSDavid du Colombier if(f != &selecttext->Frame)
8847dd7cddfSDavid du Colombier error("frameselect not right frame");
8857dd7cddfSDavid du Colombier textframescroll(selecttext, dl);
8867dd7cddfSDavid du Colombier }
8877dd7cddfSDavid du Colombier
8887dd7cddfSDavid du Colombier void
textframescroll(Text * t,int dl)8897dd7cddfSDavid du Colombier textframescroll(Text *t, int dl)
8907dd7cddfSDavid du Colombier {
8917dd7cddfSDavid du Colombier uint q0;
8927dd7cddfSDavid du Colombier
8937dd7cddfSDavid du Colombier if(dl == 0){
8947dd7cddfSDavid du Colombier scrsleep(100);
8957dd7cddfSDavid du Colombier return;
8967dd7cddfSDavid du Colombier }
8977dd7cddfSDavid du Colombier if(dl < 0){
8987dd7cddfSDavid du Colombier q0 = textbacknl(t, t->org, -dl);
8997dd7cddfSDavid du Colombier if(selectq > t->org+t->p0)
9007dd7cddfSDavid du Colombier textsetselect(t, t->org+t->p0, selectq);
9017dd7cddfSDavid du Colombier else
9027dd7cddfSDavid du Colombier textsetselect(t, selectq, t->org+t->p0);
9037dd7cddfSDavid du Colombier }else{
9047dd7cddfSDavid du Colombier if(t->org+t->nchars == t->file->nc)
9057dd7cddfSDavid du Colombier return;
9067dd7cddfSDavid du Colombier q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+dl*t->font->height));
9077dd7cddfSDavid du Colombier if(selectq > t->org+t->p1)
9087dd7cddfSDavid du Colombier textsetselect(t, t->org+t->p1, selectq);
9097dd7cddfSDavid du Colombier else
9107dd7cddfSDavid du Colombier textsetselect(t, selectq, t->org+t->p1);
9117dd7cddfSDavid du Colombier }
9127dd7cddfSDavid du Colombier textsetorigin(t, q0, TRUE);
9137dd7cddfSDavid du Colombier }
9147dd7cddfSDavid du Colombier
9157dd7cddfSDavid du Colombier
9167dd7cddfSDavid du Colombier void
textselect(Text * t)9177dd7cddfSDavid du Colombier textselect(Text *t)
9187dd7cddfSDavid du Colombier {
9197dd7cddfSDavid du Colombier uint q0, q1;
9207dd7cddfSDavid du Colombier int b, x, y;
92143f160e5SDavid du Colombier int state;
9227dd7cddfSDavid du Colombier
9237dd7cddfSDavid du Colombier selecttext = t;
9247dd7cddfSDavid du Colombier /*
9257dd7cddfSDavid du Colombier * To have double-clicking and chording, we double-click
9267dd7cddfSDavid du Colombier * immediately if it might make sense.
9277dd7cddfSDavid du Colombier */
9287dd7cddfSDavid du Colombier b = mouse->buttons;
9297dd7cddfSDavid du Colombier q0 = t->q0;
9307dd7cddfSDavid du Colombier q1 = t->q1;
9317dd7cddfSDavid du Colombier selectq = t->org+frcharofpt(t, mouse->xy);
9327dd7cddfSDavid du Colombier if(clicktext==t && mouse->msec-clickmsec<500)
9337dd7cddfSDavid du Colombier if(q0==q1 && selectq==q0){
9347dd7cddfSDavid du Colombier textdoubleclick(t, &q0, &q1);
9357dd7cddfSDavid du Colombier textsetselect(t, q0, q1);
9367dd7cddfSDavid du Colombier flushimage(display, 1);
9377dd7cddfSDavid du Colombier x = mouse->xy.x;
9387dd7cddfSDavid du Colombier y = mouse->xy.y;
9397dd7cddfSDavid du Colombier /* stay here until something interesting happens */
9407dd7cddfSDavid du Colombier do
9417dd7cddfSDavid du Colombier readmouse(mousectl);
9427dd7cddfSDavid du Colombier while(mouse->buttons==b && abs(mouse->xy.x-x)<3 && abs(mouse->xy.y-y)<3);
9437dd7cddfSDavid du Colombier mouse->xy.x = x; /* in case we're calling frselect */
9447dd7cddfSDavid du Colombier mouse->xy.y = y;
9457dd7cddfSDavid du Colombier q0 = t->q0; /* may have changed */
9467dd7cddfSDavid du Colombier q1 = t->q1;
9477dd7cddfSDavid du Colombier selectq = q0;
9487dd7cddfSDavid du Colombier }
9497dd7cddfSDavid du Colombier if(mouse->buttons == b){
9507dd7cddfSDavid du Colombier t->Frame.scroll = framescroll;
9517dd7cddfSDavid du Colombier frselect(t, mousectl);
9527dd7cddfSDavid du Colombier /* horrible botch: while asleep, may have lost selection altogether */
9537dd7cddfSDavid du Colombier if(selectq > t->file->nc)
9547dd7cddfSDavid du Colombier selectq = t->org + t->p0;
9557dd7cddfSDavid du Colombier t->Frame.scroll = nil;
9567dd7cddfSDavid du Colombier if(selectq < t->org)
9577dd7cddfSDavid du Colombier q0 = selectq;
9587dd7cddfSDavid du Colombier else
9597dd7cddfSDavid du Colombier q0 = t->org + t->p0;
9607dd7cddfSDavid du Colombier if(selectq > t->org+t->nchars)
9617dd7cddfSDavid du Colombier q1 = selectq;
9627dd7cddfSDavid du Colombier else
9637dd7cddfSDavid du Colombier q1 = t->org+t->p1;
9647dd7cddfSDavid du Colombier }
9657dd7cddfSDavid du Colombier if(q0 == q1){
9667dd7cddfSDavid du Colombier if(q0==t->q0 && clicktext==t && mouse->msec-clickmsec<500){
9677dd7cddfSDavid du Colombier textdoubleclick(t, &q0, &q1);
9687dd7cddfSDavid du Colombier clicktext = nil;
9697dd7cddfSDavid du Colombier }else{
9707dd7cddfSDavid du Colombier clicktext = t;
9717dd7cddfSDavid du Colombier clickmsec = mouse->msec;
9727dd7cddfSDavid du Colombier }
9737dd7cddfSDavid du Colombier }else
9747dd7cddfSDavid du Colombier clicktext = nil;
9757dd7cddfSDavid du Colombier textsetselect(t, q0, q1);
9767dd7cddfSDavid du Colombier flushimage(display, 1);
97743f160e5SDavid du Colombier state = 0; /* undo when possible; +1 for cut, -1 for paste */
9787dd7cddfSDavid du Colombier while(mouse->buttons){
9797dd7cddfSDavid du Colombier mouse->msec = 0;
9807dd7cddfSDavid du Colombier b = mouse->buttons;
98143f160e5SDavid du Colombier if((b&1) && (b&6)){
98243f160e5SDavid du Colombier if(state==0 && t->what==Body){
9837dd7cddfSDavid du Colombier seq++;
9847dd7cddfSDavid du Colombier filemark(t->w->body.file);
9857dd7cddfSDavid du Colombier }
9867dd7cddfSDavid du Colombier if(b & 2){
9877dd7cddfSDavid du Colombier if(state==-1 && t->what==Body){
9887dd7cddfSDavid du Colombier winundo(t->w, TRUE);
9897dd7cddfSDavid du Colombier textsetselect(t, q0, t->q0);
9907dd7cddfSDavid du Colombier state = 0;
99143f160e5SDavid du Colombier }else if(state != 1){
9927dd7cddfSDavid du Colombier cut(t, t, nil, TRUE, TRUE, nil, 0);
99343f160e5SDavid du Colombier state = 1;
9947dd7cddfSDavid du Colombier }
9957dd7cddfSDavid du Colombier }else{
9967dd7cddfSDavid du Colombier if(state==1 && t->what==Body){
9977dd7cddfSDavid du Colombier winundo(t->w, TRUE);
9987dd7cddfSDavid du Colombier textsetselect(t, q0, t->q1);
9997dd7cddfSDavid du Colombier state = 0;
100043f160e5SDavid du Colombier }else if(state != -1){
100159cc4ca5SDavid du Colombier paste(t, t, nil, TRUE, FALSE, nil, 0);
100243f160e5SDavid du Colombier state = -1;
10037dd7cddfSDavid du Colombier }
10047dd7cddfSDavid du Colombier }
10057dd7cddfSDavid du Colombier textscrdraw(t);
10067dd7cddfSDavid du Colombier clearmouse();
10077dd7cddfSDavid du Colombier }
10087dd7cddfSDavid du Colombier flushimage(display, 1);
10097dd7cddfSDavid du Colombier while(mouse->buttons == b)
10107dd7cddfSDavid du Colombier readmouse(mousectl);
10117dd7cddfSDavid du Colombier clicktext = nil;
10127dd7cddfSDavid du Colombier }
10137dd7cddfSDavid du Colombier }
10147dd7cddfSDavid du Colombier
10157dd7cddfSDavid du Colombier void
textshow(Text * t,uint q0,uint q1,int doselect)10169a747e4fSDavid du Colombier textshow(Text *t, uint q0, uint q1, int doselect)
10177dd7cddfSDavid du Colombier {
10187dd7cddfSDavid du Colombier int qe;
10197dd7cddfSDavid du Colombier int nl;
10207dd7cddfSDavid du Colombier uint q;
10217dd7cddfSDavid du Colombier
10222af003dfSDavid du Colombier if(t->what != Body){
10232af003dfSDavid du Colombier if(doselect)
10242af003dfSDavid du Colombier textsetselect(t, q0, q1);
10257dd7cddfSDavid du Colombier return;
10262af003dfSDavid du Colombier }
10277dd7cddfSDavid du Colombier if(t->w!=nil && t->maxlines==0)
10287dd7cddfSDavid du Colombier colgrow(t->col, t->w, 1);
10299a747e4fSDavid du Colombier if(doselect)
10307dd7cddfSDavid du Colombier textsetselect(t, q0, q1);
10317dd7cddfSDavid du Colombier qe = t->org+t->nchars;
10327dd7cddfSDavid du Colombier if(t->org<=q0 && (q0<qe || (q0==qe && qe==t->file->nc+t->ncache)))
10337dd7cddfSDavid du Colombier textscrdraw(t);
10347dd7cddfSDavid du Colombier else{
10357dd7cddfSDavid du Colombier if(t->w->nopen[QWevent] > 0)
10367dd7cddfSDavid du Colombier nl = 3*t->maxlines/4;
10377dd7cddfSDavid du Colombier else
10387dd7cddfSDavid du Colombier nl = t->maxlines/4;
10397dd7cddfSDavid du Colombier q = textbacknl(t, q0, nl);
10407dd7cddfSDavid du Colombier /* avoid going backwards if trying to go forwards - long lines! */
10417dd7cddfSDavid du Colombier if(!(q0>t->org && q<t->org))
10427dd7cddfSDavid du Colombier textsetorigin(t, q, TRUE);
10437dd7cddfSDavid du Colombier while(q0 > t->org+t->nchars)
10447dd7cddfSDavid du Colombier textsetorigin(t, t->org+1, FALSE);
10457dd7cddfSDavid du Colombier }
10467dd7cddfSDavid du Colombier }
10477dd7cddfSDavid du Colombier
10487dd7cddfSDavid du Colombier static
10497dd7cddfSDavid du Colombier int
region(int a,int b)10507dd7cddfSDavid du Colombier region(int a, int b)
10517dd7cddfSDavid du Colombier {
10527dd7cddfSDavid du Colombier if(a < b)
10537dd7cddfSDavid du Colombier return -1;
10547dd7cddfSDavid du Colombier if(a == b)
10557dd7cddfSDavid du Colombier return 0;
10567dd7cddfSDavid du Colombier return 1;
10577dd7cddfSDavid du Colombier }
10587dd7cddfSDavid du Colombier
10597dd7cddfSDavid du Colombier void
selrestore(Frame * f,Point pt0,uint p0,uint p1)10607dd7cddfSDavid du Colombier selrestore(Frame *f, Point pt0, uint p0, uint p1)
10617dd7cddfSDavid du Colombier {
10627dd7cddfSDavid du Colombier if(p1<=f->p0 || p0>=f->p1){
10637dd7cddfSDavid du Colombier /* no overlap */
10647dd7cddfSDavid du Colombier frdrawsel0(f, pt0, p0, p1, f->cols[BACK], f->cols[TEXT]);
10657dd7cddfSDavid du Colombier return;
10667dd7cddfSDavid du Colombier }
10677dd7cddfSDavid du Colombier if(p0>=f->p0 && p1<=f->p1){
10687dd7cddfSDavid du Colombier /* entirely inside */
10697dd7cddfSDavid du Colombier frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]);
10707dd7cddfSDavid du Colombier return;
10717dd7cddfSDavid du Colombier }
10727dd7cddfSDavid du Colombier
10737dd7cddfSDavid du Colombier /* they now are known to overlap */
10747dd7cddfSDavid du Colombier
10757dd7cddfSDavid du Colombier /* before selection */
10767dd7cddfSDavid du Colombier if(p0 < f->p0){
10777dd7cddfSDavid du Colombier frdrawsel0(f, pt0, p0, f->p0, f->cols[BACK], f->cols[TEXT]);
10787dd7cddfSDavid du Colombier p0 = f->p0;
10797dd7cddfSDavid du Colombier pt0 = frptofchar(f, p0);
10807dd7cddfSDavid du Colombier }
10817dd7cddfSDavid du Colombier /* after selection */
10827dd7cddfSDavid du Colombier if(p1 > f->p1){
10837dd7cddfSDavid du Colombier frdrawsel0(f, frptofchar(f, f->p1), f->p1, p1, f->cols[BACK], f->cols[TEXT]);
10847dd7cddfSDavid du Colombier p1 = f->p1;
10857dd7cddfSDavid du Colombier }
10867dd7cddfSDavid du Colombier /* inside selection */
10877dd7cddfSDavid du Colombier frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]);
10887dd7cddfSDavid du Colombier }
10897dd7cddfSDavid du Colombier
10907dd7cddfSDavid du Colombier void
textsetselect(Text * t,uint q0,uint q1)10917dd7cddfSDavid du Colombier textsetselect(Text *t, uint q0, uint q1)
10927dd7cddfSDavid du Colombier {
10937dd7cddfSDavid du Colombier int p0, p1;
10947dd7cddfSDavid du Colombier
10957dd7cddfSDavid du Colombier /* t->p0 and t->p1 are always right; t->q0 and t->q1 may be off */
10967dd7cddfSDavid du Colombier t->q0 = q0;
10977dd7cddfSDavid du Colombier t->q1 = q1;
10987dd7cddfSDavid du Colombier /* compute desired p0,p1 from q0,q1 */
10997dd7cddfSDavid du Colombier p0 = q0-t->org;
11007dd7cddfSDavid du Colombier p1 = q1-t->org;
11017dd7cddfSDavid du Colombier if(p0 < 0)
11027dd7cddfSDavid du Colombier p0 = 0;
11037dd7cddfSDavid du Colombier if(p1 < 0)
11047dd7cddfSDavid du Colombier p1 = 0;
11057dd7cddfSDavid du Colombier if(p0 > t->nchars)
11067dd7cddfSDavid du Colombier p0 = t->nchars;
11077dd7cddfSDavid du Colombier if(p1 > t->nchars)
11087dd7cddfSDavid du Colombier p1 = t->nchars;
11097dd7cddfSDavid du Colombier if(p0==t->p0 && p1==t->p1)
11107dd7cddfSDavid du Colombier return;
11117dd7cddfSDavid du Colombier /* screen disagrees with desired selection */
11127dd7cddfSDavid du Colombier if(t->p1<=p0 || p1<=t->p0 || p0==p1 || t->p1==t->p0){
11137dd7cddfSDavid du Colombier /* no overlap or too easy to bother trying */
11147dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, t->p0), t->p0, t->p1, 0);
11157dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, p0), p0, p1, 1);
11167dd7cddfSDavid du Colombier goto Return;
11177dd7cddfSDavid du Colombier }
11187dd7cddfSDavid du Colombier /* overlap; avoid unnecessary painting */
11197dd7cddfSDavid du Colombier if(p0 < t->p0){
11207dd7cddfSDavid du Colombier /* extend selection backwards */
11217dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, p0), p0, t->p0, 1);
11227dd7cddfSDavid du Colombier }else if(p0 > t->p0){
11237dd7cddfSDavid du Colombier /* trim first part of selection */
11247dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, t->p0), t->p0, p0, 0);
11257dd7cddfSDavid du Colombier }
11267dd7cddfSDavid du Colombier if(p1 > t->p1){
11277dd7cddfSDavid du Colombier /* extend selection forwards */
11287dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, t->p1), t->p1, p1, 1);
11297dd7cddfSDavid du Colombier }else if(p1 < t->p1){
11307dd7cddfSDavid du Colombier /* trim last part of selection */
11317dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, p1), p1, t->p1, 0);
11327dd7cddfSDavid du Colombier }
11337dd7cddfSDavid du Colombier
11347dd7cddfSDavid du Colombier Return:
11357dd7cddfSDavid du Colombier t->p0 = p0;
11367dd7cddfSDavid du Colombier t->p1 = p1;
11377dd7cddfSDavid du Colombier }
11387dd7cddfSDavid du Colombier
11399a747e4fSDavid du Colombier /*
11409a747e4fSDavid du Colombier * Release the button in less than DELAY ms and it's considered a null selection
11419a747e4fSDavid du Colombier * if the mouse hardly moved, regardless of whether it crossed a char boundary.
11429a747e4fSDavid du Colombier */
11439a747e4fSDavid du Colombier enum {
11449a747e4fSDavid du Colombier DELAY = 2,
11459a747e4fSDavid du Colombier MINMOVE = 4,
11469a747e4fSDavid du Colombier };
11479a747e4fSDavid du Colombier
11489a747e4fSDavid du Colombier uint
xselect(Frame * f,Mousectl * mc,Image * col,uint * p1p)11497dd7cddfSDavid du Colombier xselect(Frame *f, Mousectl *mc, Image *col, uint *p1p) /* when called, button is down */
11507dd7cddfSDavid du Colombier {
11517dd7cddfSDavid du Colombier uint p0, p1, q, tmp;
11529a747e4fSDavid du Colombier ulong msec;
11537dd7cddfSDavid du Colombier Point mp, pt0, pt1, qt;
11547dd7cddfSDavid du Colombier int reg, b;
11557dd7cddfSDavid du Colombier
11567dd7cddfSDavid du Colombier mp = mc->xy;
11577dd7cddfSDavid du Colombier b = mc->buttons;
11589a747e4fSDavid du Colombier msec = mc->msec;
11597dd7cddfSDavid du Colombier
11607dd7cddfSDavid du Colombier /* remove tick */
11617dd7cddfSDavid du Colombier if(f->p0 == f->p1)
11627dd7cddfSDavid du Colombier frtick(f, frptofchar(f, f->p0), 0);
11637dd7cddfSDavid du Colombier p0 = p1 = frcharofpt(f, mp);
11647dd7cddfSDavid du Colombier pt0 = frptofchar(f, p0);
11657dd7cddfSDavid du Colombier pt1 = frptofchar(f, p1);
11667dd7cddfSDavid du Colombier reg = 0;
11677dd7cddfSDavid du Colombier frtick(f, pt0, 1);
11687dd7cddfSDavid du Colombier do{
11697dd7cddfSDavid du Colombier q = frcharofpt(f, mc->xy);
11707dd7cddfSDavid du Colombier if(p1 != q){
11717dd7cddfSDavid du Colombier if(p0 == p1)
11727dd7cddfSDavid du Colombier frtick(f, pt0, 0);
11737dd7cddfSDavid du Colombier if(reg != region(q, p0)){ /* crossed starting point; reset */
11747dd7cddfSDavid du Colombier if(reg > 0)
11757dd7cddfSDavid du Colombier selrestore(f, pt0, p0, p1);
11767dd7cddfSDavid du Colombier else if(reg < 0)
11777dd7cddfSDavid du Colombier selrestore(f, pt1, p1, p0);
11787dd7cddfSDavid du Colombier p1 = p0;
11797dd7cddfSDavid du Colombier pt1 = pt0;
11807dd7cddfSDavid du Colombier reg = region(q, p0);
11817dd7cddfSDavid du Colombier if(reg == 0)
11827dd7cddfSDavid du Colombier frdrawsel0(f, pt0, p0, p1, col, display->white);
11837dd7cddfSDavid du Colombier }
11847dd7cddfSDavid du Colombier qt = frptofchar(f, q);
11857dd7cddfSDavid du Colombier if(reg > 0){
11867dd7cddfSDavid du Colombier if(q > p1)
11877dd7cddfSDavid du Colombier frdrawsel0(f, pt1, p1, q, col, display->white);
11887dd7cddfSDavid du Colombier
11897dd7cddfSDavid du Colombier else if(q < p1)
11907dd7cddfSDavid du Colombier selrestore(f, qt, q, p1);
11917dd7cddfSDavid du Colombier }else if(reg < 0){
11927dd7cddfSDavid du Colombier if(q > p1)
11937dd7cddfSDavid du Colombier selrestore(f, pt1, p1, q);
11947dd7cddfSDavid du Colombier else
11957dd7cddfSDavid du Colombier frdrawsel0(f, qt, q, p1, col, display->white);
11967dd7cddfSDavid du Colombier }
11977dd7cddfSDavid du Colombier p1 = q;
11987dd7cddfSDavid du Colombier pt1 = qt;
11997dd7cddfSDavid du Colombier }
12007dd7cddfSDavid du Colombier if(p0 == p1)
12017dd7cddfSDavid du Colombier frtick(f, pt0, 1);
12027dd7cddfSDavid du Colombier flushimage(f->display, 1);
12037dd7cddfSDavid du Colombier readmouse(mc);
12047dd7cddfSDavid du Colombier }while(mc->buttons == b);
12059a747e4fSDavid du Colombier if(mc->msec-msec < DELAY && p0!=p1
12069a747e4fSDavid du Colombier && abs(mp.x-mc->xy.x)<MINMOVE
12079a747e4fSDavid du Colombier && abs(mp.y-mc->xy.y)<MINMOVE) {
12089a747e4fSDavid du Colombier if(reg > 0)
12099a747e4fSDavid du Colombier selrestore(f, pt0, p0, p1);
12109a747e4fSDavid du Colombier else if(reg < 0)
12119a747e4fSDavid du Colombier selrestore(f, pt1, p1, p0);
12129a747e4fSDavid du Colombier p1 = p0;
12139a747e4fSDavid du Colombier }
12147dd7cddfSDavid du Colombier if(p1 < p0){
12157dd7cddfSDavid du Colombier tmp = p0;
12167dd7cddfSDavid du Colombier p0 = p1;
12177dd7cddfSDavid du Colombier p1 = tmp;
12187dd7cddfSDavid du Colombier }
12197dd7cddfSDavid du Colombier pt0 = frptofchar(f, p0);
12207dd7cddfSDavid du Colombier if(p0 == p1)
12217dd7cddfSDavid du Colombier frtick(f, pt0, 0);
12227dd7cddfSDavid du Colombier selrestore(f, pt0, p0, p1);
12237dd7cddfSDavid du Colombier /* restore tick */
12247dd7cddfSDavid du Colombier if(f->p0 == f->p1)
12257dd7cddfSDavid du Colombier frtick(f, frptofchar(f, f->p0), 1);
12267dd7cddfSDavid du Colombier flushimage(f->display, 1);
12277dd7cddfSDavid du Colombier *p1p = p1;
12287dd7cddfSDavid du Colombier return p0;
12297dd7cddfSDavid du Colombier }
12307dd7cddfSDavid du Colombier
12317dd7cddfSDavid du Colombier int
textselect23(Text * t,uint * q0,uint * q1,Image * high,int mask)12327dd7cddfSDavid du Colombier textselect23(Text *t, uint *q0, uint *q1, Image *high, int mask)
12337dd7cddfSDavid du Colombier {
12347dd7cddfSDavid du Colombier uint p0, p1;
12357dd7cddfSDavid du Colombier int buts;
12367dd7cddfSDavid du Colombier
12377dd7cddfSDavid du Colombier p0 = xselect(t, mousectl, high, &p1);
12387dd7cddfSDavid du Colombier buts = mousectl->buttons;
12397dd7cddfSDavid du Colombier if((buts & mask) == 0){
12407dd7cddfSDavid du Colombier *q0 = p0+t->org;
12417dd7cddfSDavid du Colombier *q1 = p1+t->org;
12427dd7cddfSDavid du Colombier }
12437dd7cddfSDavid du Colombier
12447dd7cddfSDavid du Colombier while(mousectl->buttons)
12457dd7cddfSDavid du Colombier readmouse(mousectl);
12467dd7cddfSDavid du Colombier return buts;
12477dd7cddfSDavid du Colombier }
12487dd7cddfSDavid du Colombier
12497dd7cddfSDavid du Colombier int
textselect2(Text * t,uint * q0,uint * q1,Text ** tp)12507dd7cddfSDavid du Colombier textselect2(Text *t, uint *q0, uint *q1, Text **tp)
12517dd7cddfSDavid du Colombier {
12527dd7cddfSDavid du Colombier int buts;
12537dd7cddfSDavid du Colombier
12547dd7cddfSDavid du Colombier *tp = nil;
12557dd7cddfSDavid du Colombier buts = textselect23(t, q0, q1, but2col, 4);
12567dd7cddfSDavid du Colombier if(buts & 4)
12577dd7cddfSDavid du Colombier return 0;
12587dd7cddfSDavid du Colombier if(buts & 1){ /* pick up argument */
12597dd7cddfSDavid du Colombier *tp = argtext;
12607dd7cddfSDavid du Colombier return 1;
12617dd7cddfSDavid du Colombier }
12627dd7cddfSDavid du Colombier return 1;
12637dd7cddfSDavid du Colombier }
12647dd7cddfSDavid du Colombier
12657dd7cddfSDavid du Colombier int
textselect3(Text * t,uint * q0,uint * q1)12667dd7cddfSDavid du Colombier textselect3(Text *t, uint *q0, uint *q1)
12677dd7cddfSDavid du Colombier {
12687dd7cddfSDavid du Colombier int h;
12697dd7cddfSDavid du Colombier
12707dd7cddfSDavid du Colombier h = (textselect23(t, q0, q1, but3col, 1|2) == 0);
12717dd7cddfSDavid du Colombier return h;
12727dd7cddfSDavid du Colombier }
12737dd7cddfSDavid du Colombier
12747dd7cddfSDavid du Colombier static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 };
12757dd7cddfSDavid du Colombier static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
12767dd7cddfSDavid du Colombier static Rune left2[] = { L'\n', 0 };
12777dd7cddfSDavid du Colombier static Rune left3[] = { L'\'', L'"', L'`', 0 };
12787dd7cddfSDavid du Colombier
12797dd7cddfSDavid du Colombier static
12807dd7cddfSDavid du Colombier Rune *left[] = {
12817dd7cddfSDavid du Colombier left1,
12827dd7cddfSDavid du Colombier left2,
12837dd7cddfSDavid du Colombier left3,
12847dd7cddfSDavid du Colombier nil
12857dd7cddfSDavid du Colombier };
12867dd7cddfSDavid du Colombier static
12877dd7cddfSDavid du Colombier Rune *right[] = {
12887dd7cddfSDavid du Colombier right1,
12897dd7cddfSDavid du Colombier left2,
12907dd7cddfSDavid du Colombier left3,
12917dd7cddfSDavid du Colombier nil
12927dd7cddfSDavid du Colombier };
12937dd7cddfSDavid du Colombier
12947dd7cddfSDavid du Colombier void
textdoubleclick(Text * t,uint * q0,uint * q1)12957dd7cddfSDavid du Colombier textdoubleclick(Text *t, uint *q0, uint *q1)
12967dd7cddfSDavid du Colombier {
12977dd7cddfSDavid du Colombier int c, i;
12987dd7cddfSDavid du Colombier Rune *r, *l, *p;
12997dd7cddfSDavid du Colombier uint q;
13007dd7cddfSDavid du Colombier
13017dd7cddfSDavid du Colombier for(i=0; left[i]!=nil; i++){
13027dd7cddfSDavid du Colombier q = *q0;
13037dd7cddfSDavid du Colombier l = left[i];
13047dd7cddfSDavid du Colombier r = right[i];
13057dd7cddfSDavid du Colombier /* try matching character to left, looking right */
13067dd7cddfSDavid du Colombier if(q == 0)
13077dd7cddfSDavid du Colombier c = '\n';
13087dd7cddfSDavid du Colombier else
13097dd7cddfSDavid du Colombier c = textreadc(t, q-1);
131059cc4ca5SDavid du Colombier p = runestrchr(l, c);
13117dd7cddfSDavid du Colombier if(p != nil){
13127dd7cddfSDavid du Colombier if(textclickmatch(t, c, r[p-l], 1, &q))
13137dd7cddfSDavid du Colombier *q1 = q-(c!='\n');
13147dd7cddfSDavid du Colombier return;
13157dd7cddfSDavid du Colombier }
13167dd7cddfSDavid du Colombier /* try matching character to right, looking left */
13177dd7cddfSDavid du Colombier if(q == t->file->nc)
13187dd7cddfSDavid du Colombier c = '\n';
13197dd7cddfSDavid du Colombier else
13207dd7cddfSDavid du Colombier c = textreadc(t, q);
132159cc4ca5SDavid du Colombier p = runestrchr(r, c);
13227dd7cddfSDavid du Colombier if(p != nil){
13237dd7cddfSDavid du Colombier if(textclickmatch(t, c, l[p-r], -1, &q)){
13247dd7cddfSDavid du Colombier *q1 = *q0+(*q0<t->file->nc && c=='\n');
13257dd7cddfSDavid du Colombier *q0 = q;
13267dd7cddfSDavid du Colombier if(c!='\n' || q!=0 || textreadc(t, 0)=='\n')
13277dd7cddfSDavid du Colombier (*q0)++;
13287dd7cddfSDavid du Colombier }
13297dd7cddfSDavid du Colombier return;
13307dd7cddfSDavid du Colombier }
13317dd7cddfSDavid du Colombier }
13327dd7cddfSDavid du Colombier /* try filling out word to right */
13337dd7cddfSDavid du Colombier while(*q1<t->file->nc && isalnum(textreadc(t, *q1)))
13347dd7cddfSDavid du Colombier (*q1)++;
13357dd7cddfSDavid du Colombier /* try filling out word to left */
13367dd7cddfSDavid du Colombier while(*q0>0 && isalnum(textreadc(t, *q0-1)))
13377dd7cddfSDavid du Colombier (*q0)--;
13387dd7cddfSDavid du Colombier }
13397dd7cddfSDavid du Colombier
13407dd7cddfSDavid du Colombier int
textclickmatch(Text * t,int cl,int cr,int dir,uint * q)13417dd7cddfSDavid du Colombier textclickmatch(Text *t, int cl, int cr, int dir, uint *q)
13427dd7cddfSDavid du Colombier {
13437dd7cddfSDavid du Colombier Rune c;
13447dd7cddfSDavid du Colombier int nest;
13457dd7cddfSDavid du Colombier
13467dd7cddfSDavid du Colombier nest = 1;
13477dd7cddfSDavid du Colombier for(;;){
13487dd7cddfSDavid du Colombier if(dir > 0){
13497dd7cddfSDavid du Colombier if(*q == t->file->nc)
13507dd7cddfSDavid du Colombier break;
13517dd7cddfSDavid du Colombier c = textreadc(t, *q);
13527dd7cddfSDavid du Colombier (*q)++;
13537dd7cddfSDavid du Colombier }else{
13547dd7cddfSDavid du Colombier if(*q == 0)
13557dd7cddfSDavid du Colombier break;
13567dd7cddfSDavid du Colombier (*q)--;
13577dd7cddfSDavid du Colombier c = textreadc(t, *q);
13587dd7cddfSDavid du Colombier }
13597dd7cddfSDavid du Colombier if(c == cr){
13607dd7cddfSDavid du Colombier if(--nest==0)
13617dd7cddfSDavid du Colombier return 1;
13627dd7cddfSDavid du Colombier }else if(c == cl)
13637dd7cddfSDavid du Colombier nest++;
13647dd7cddfSDavid du Colombier }
13657dd7cddfSDavid du Colombier return cl=='\n' && nest==1;
13667dd7cddfSDavid du Colombier }
13677dd7cddfSDavid du Colombier
13687dd7cddfSDavid du Colombier uint
textbacknl(Text * t,uint p,uint n)13697dd7cddfSDavid du Colombier textbacknl(Text *t, uint p, uint n)
13707dd7cddfSDavid du Colombier {
13717dd7cddfSDavid du Colombier int i, j;
13727dd7cddfSDavid du Colombier
13737dd7cddfSDavid du Colombier /* look for start of this line if n==0 */
13747dd7cddfSDavid du Colombier if(n==0 && p>0 && textreadc(t, p-1)!='\n')
13757dd7cddfSDavid du Colombier n = 1;
13767dd7cddfSDavid du Colombier i = n;
13777dd7cddfSDavid du Colombier while(i-->0 && p>0){
13787dd7cddfSDavid du Colombier --p; /* it's at a newline now; back over it */
13797dd7cddfSDavid du Colombier if(p == 0)
13807dd7cddfSDavid du Colombier break;
13817dd7cddfSDavid du Colombier /* at 128 chars, call it a line anyway */
13827dd7cddfSDavid du Colombier for(j=128; --j>0 && p>0; p--)
13837dd7cddfSDavid du Colombier if(textreadc(t, p-1)=='\n')
13847dd7cddfSDavid du Colombier break;
13857dd7cddfSDavid du Colombier }
13867dd7cddfSDavid du Colombier return p;
13877dd7cddfSDavid du Colombier }
13887dd7cddfSDavid du Colombier
13897dd7cddfSDavid du Colombier void
textsetorigin(Text * t,uint org,int exact)13907dd7cddfSDavid du Colombier textsetorigin(Text *t, uint org, int exact)
13917dd7cddfSDavid du Colombier {
13927dd7cddfSDavid du Colombier int i, a, fixup;
13937dd7cddfSDavid du Colombier Rune *r;
13947dd7cddfSDavid du Colombier uint n;
13957dd7cddfSDavid du Colombier
13967dd7cddfSDavid du Colombier if(org>0 && !exact){
13977dd7cddfSDavid du Colombier /* org is an estimate of the char posn; find a newline */
13987dd7cddfSDavid du Colombier /* don't try harder than 256 chars */
13997dd7cddfSDavid du Colombier for(i=0; i<256 && org<t->file->nc; i++){
14007dd7cddfSDavid du Colombier if(textreadc(t, org) == '\n'){
14017dd7cddfSDavid du Colombier org++;
14027dd7cddfSDavid du Colombier break;
14037dd7cddfSDavid du Colombier }
14047dd7cddfSDavid du Colombier org++;
14057dd7cddfSDavid du Colombier }
14067dd7cddfSDavid du Colombier }
14077dd7cddfSDavid du Colombier a = org-t->org;
14087dd7cddfSDavid du Colombier fixup = 0;
14097dd7cddfSDavid du Colombier if(a>=0 && a<t->nchars){
14107dd7cddfSDavid du Colombier frdelete(t, 0, a);
14117dd7cddfSDavid du Colombier fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */
14127dd7cddfSDavid du Colombier }
14137dd7cddfSDavid du Colombier else if(a<0 && -a<t->nchars){
14147dd7cddfSDavid du Colombier n = t->org - org;
14157dd7cddfSDavid du Colombier r = runemalloc(n);
14167dd7cddfSDavid du Colombier bufread(t->file, org, r, n);
14177dd7cddfSDavid du Colombier frinsert(t, r, r+n, 0);
14187dd7cddfSDavid du Colombier free(r);
14197dd7cddfSDavid du Colombier }else
14207dd7cddfSDavid du Colombier frdelete(t, 0, t->nchars);
14217dd7cddfSDavid du Colombier t->org = org;
14227dd7cddfSDavid du Colombier textfill(t);
14237dd7cddfSDavid du Colombier textscrdraw(t);
14247dd7cddfSDavid du Colombier textsetselect(t, t->q0, t->q1);
14257dd7cddfSDavid du Colombier if(fixup && t->p1 > t->p0)
14267dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, t->p1-1), t->p1-1, t->p1, 1);
14277dd7cddfSDavid du Colombier }
14287dd7cddfSDavid du Colombier
14297dd7cddfSDavid du Colombier void
textreset(Text * t)14307dd7cddfSDavid du Colombier textreset(Text *t)
14317dd7cddfSDavid du Colombier {
14327dd7cddfSDavid du Colombier t->file->seq = 0;
14337dd7cddfSDavid du Colombier t->eq0 = ~0;
14347dd7cddfSDavid du Colombier /* do t->delete(0, t->nc, TRUE) without building backup stuff */
14357dd7cddfSDavid du Colombier textsetselect(t, t->org, t->org);
14367dd7cddfSDavid du Colombier frdelete(t, 0, t->nchars);
14377dd7cddfSDavid du Colombier t->org = 0;
14387dd7cddfSDavid du Colombier t->q0 = 0;
14397dd7cddfSDavid du Colombier t->q1 = 0;
14407dd7cddfSDavid du Colombier filereset(t->file);
14417dd7cddfSDavid du Colombier bufreset(t->file);
14427dd7cddfSDavid du Colombier }
1443