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 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 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; 477dd7cddfSDavid du Colombier rr.min.x -= Scrollwid; /* back fill to scroll bar */ 487dd7cddfSDavid du Colombier draw(t->b, rr, t->cols[BACK], nil, ZP); 497dd7cddfSDavid du Colombier /* use no wider than 3-space tabs in a directory */ 507dd7cddfSDavid du Colombier maxt = maxtab; 517dd7cddfSDavid du Colombier if(t->what == Body){ 527dd7cddfSDavid du Colombier if(t->w->isdir) 537dd7cddfSDavid du Colombier maxt = min(TABDIR, maxtab); 547dd7cddfSDavid du Colombier else 557dd7cddfSDavid du Colombier maxt = t->tabstop; 567dd7cddfSDavid du Colombier } 577dd7cddfSDavid du Colombier t->maxtab = maxt*stringwidth(f, "0"); 587dd7cddfSDavid du Colombier if(t->what==Body && t->w->isdir && odx!=Dx(t->all)){ 597dd7cddfSDavid du Colombier if(t->maxlines > 0){ 607dd7cddfSDavid du Colombier textreset(t); 617dd7cddfSDavid du Colombier textcolumnate(t, t->w->dlp, t->w->ndl); 629a747e4fSDavid du Colombier textshow(t, 0, 0, 1); 637dd7cddfSDavid du Colombier } 647dd7cddfSDavid du Colombier }else{ 657dd7cddfSDavid du Colombier textfill(t); 667dd7cddfSDavid du Colombier textsetselect(t, t->q0, t->q1); 677dd7cddfSDavid du Colombier } 687dd7cddfSDavid du Colombier } 697dd7cddfSDavid du Colombier 707dd7cddfSDavid du Colombier int 717dd7cddfSDavid du Colombier textresize(Text *t, Rectangle r) 727dd7cddfSDavid du Colombier { 737dd7cddfSDavid du Colombier int odx; 747dd7cddfSDavid du Colombier 757dd7cddfSDavid du Colombier if(Dy(r) > 0) 767dd7cddfSDavid du Colombier r.max.y -= Dy(r)%t->font->height; 777dd7cddfSDavid du Colombier else 787dd7cddfSDavid du Colombier r.max.y = r.min.y; 797dd7cddfSDavid du Colombier odx = Dx(t->all); 807dd7cddfSDavid du Colombier t->all = r; 817dd7cddfSDavid du Colombier t->scrollr = r; 827dd7cddfSDavid du Colombier t->scrollr.max.x = r.min.x+Scrollwid; 837dd7cddfSDavid du Colombier t->lastsr = nullrect; 847dd7cddfSDavid du Colombier r.min.x += Scrollwid+Scrollgap; 857dd7cddfSDavid du Colombier frclear(t, 0); 867dd7cddfSDavid du Colombier textredraw(t, r, t->font, t->b, odx); 877dd7cddfSDavid du Colombier return r.max.y; 887dd7cddfSDavid du Colombier } 897dd7cddfSDavid du Colombier 907dd7cddfSDavid du Colombier void 917dd7cddfSDavid du Colombier textclose(Text *t) 927dd7cddfSDavid du Colombier { 937dd7cddfSDavid du Colombier free(t->cache); 947dd7cddfSDavid du Colombier frclear(t, 1); 957dd7cddfSDavid du Colombier filedeltext(t->file, t); 967dd7cddfSDavid du Colombier t->file = nil; 977dd7cddfSDavid du Colombier rfclose(t->reffont); 987dd7cddfSDavid du Colombier if(argtext == t) 997dd7cddfSDavid du Colombier argtext = nil; 1007dd7cddfSDavid du Colombier if(typetext == t) 1017dd7cddfSDavid du Colombier typetext = nil; 1027dd7cddfSDavid du Colombier if(seltext == t) 1037dd7cddfSDavid du Colombier seltext = nil; 1047dd7cddfSDavid du Colombier if(mousetext == t) 1057dd7cddfSDavid du Colombier mousetext = nil; 1067dd7cddfSDavid du Colombier if(barttext == t) 1077dd7cddfSDavid du Colombier barttext = nil; 1087dd7cddfSDavid du Colombier } 1097dd7cddfSDavid du Colombier 1107dd7cddfSDavid du Colombier int 1117dd7cddfSDavid du Colombier dircmp(void *a, void *b) 1127dd7cddfSDavid du Colombier { 1137dd7cddfSDavid du Colombier Dirlist *da, *db; 1147dd7cddfSDavid du Colombier int i, n; 1157dd7cddfSDavid du Colombier 1167dd7cddfSDavid du Colombier da = *(Dirlist**)a; 1177dd7cddfSDavid du Colombier db = *(Dirlist**)b; 1187dd7cddfSDavid du Colombier n = min(da->nr, db->nr); 1197dd7cddfSDavid du Colombier i = memcmp(da->r, db->r, n*sizeof(Rune)); 1207dd7cddfSDavid du Colombier if(i) 1217dd7cddfSDavid du Colombier return i; 1227dd7cddfSDavid du Colombier return da->nr - db->nr; 1237dd7cddfSDavid du Colombier } 1247dd7cddfSDavid du Colombier 1257dd7cddfSDavid du Colombier void 1267dd7cddfSDavid du Colombier textcolumnate(Text *t, Dirlist **dlp, int ndl) 1277dd7cddfSDavid du Colombier { 1287dd7cddfSDavid du Colombier int i, j, w, colw, mint, maxt, ncol, nrow; 1297dd7cddfSDavid du Colombier Dirlist *dl; 1307dd7cddfSDavid du Colombier uint q1; 1317dd7cddfSDavid du Colombier 1327dd7cddfSDavid du Colombier if(t->file->ntext > 1) 1337dd7cddfSDavid du Colombier return; 1347dd7cddfSDavid du Colombier mint = stringwidth(t->font, "0"); 1357dd7cddfSDavid du Colombier /* go for narrower tabs if set more than 3 wide */ 1367dd7cddfSDavid du Colombier t->maxtab = min(maxtab, TABDIR)*mint; 1377dd7cddfSDavid du Colombier maxt = t->maxtab; 1387dd7cddfSDavid du Colombier colw = 0; 1397dd7cddfSDavid du Colombier for(i=0; i<ndl; i++){ 1407dd7cddfSDavid du Colombier dl = dlp[i]; 1417dd7cddfSDavid du Colombier w = dl->wid; 1429a747e4fSDavid du Colombier if(maxt-w%maxt < mint || w%maxt==0) 1437dd7cddfSDavid du Colombier w += mint; 1447dd7cddfSDavid du Colombier if(w % maxt) 1457dd7cddfSDavid du Colombier w += maxt-(w%maxt); 1467dd7cddfSDavid du Colombier if(w > colw) 1477dd7cddfSDavid du Colombier colw = w; 1487dd7cddfSDavid du Colombier } 1497dd7cddfSDavid du Colombier if(colw == 0) 1507dd7cddfSDavid du Colombier ncol = 1; 1517dd7cddfSDavid du Colombier else 1527dd7cddfSDavid du Colombier ncol = max(1, Dx(t->r)/colw); 1537dd7cddfSDavid du Colombier nrow = (ndl+ncol-1)/ncol; 1547dd7cddfSDavid du Colombier 1557dd7cddfSDavid du Colombier q1 = 0; 1567dd7cddfSDavid du Colombier for(i=0; i<nrow; i++){ 1577dd7cddfSDavid du Colombier for(j=i; j<ndl; j+=nrow){ 1587dd7cddfSDavid du Colombier dl = dlp[j]; 1597dd7cddfSDavid du Colombier fileinsert(t->file, q1, dl->r, dl->nr); 1607dd7cddfSDavid du Colombier q1 += dl->nr; 1617dd7cddfSDavid du Colombier if(j+nrow >= ndl) 1627dd7cddfSDavid du Colombier break; 1637dd7cddfSDavid du Colombier w = dl->wid; 1647dd7cddfSDavid du Colombier if(maxt-w%maxt < mint){ 1657dd7cddfSDavid du Colombier fileinsert(t->file, q1, L"\t", 1); 1667dd7cddfSDavid du Colombier q1++; 1677dd7cddfSDavid du Colombier w += mint; 1687dd7cddfSDavid du Colombier } 1697dd7cddfSDavid du Colombier do{ 1707dd7cddfSDavid du Colombier fileinsert(t->file, q1, L"\t", 1); 1717dd7cddfSDavid du Colombier q1++; 1727dd7cddfSDavid du Colombier w += maxt-(w%maxt); 1737dd7cddfSDavid du Colombier }while(w < colw); 1747dd7cddfSDavid du Colombier } 1757dd7cddfSDavid du Colombier fileinsert(t->file, q1, L"\n", 1); 1767dd7cddfSDavid du Colombier q1++; 1777dd7cddfSDavid du Colombier } 1787dd7cddfSDavid du Colombier } 1797dd7cddfSDavid du Colombier 1807dd7cddfSDavid du Colombier uint 1817dd7cddfSDavid du Colombier textload(Text *t, uint q0, char *file, int setqid) 1827dd7cddfSDavid du Colombier { 1837dd7cddfSDavid du Colombier Rune *rp; 1847dd7cddfSDavid du Colombier Dirlist *dl, **dlp; 1859a747e4fSDavid du Colombier int fd, i, j, n, ndl, nulls; 1867dd7cddfSDavid du Colombier uint q, q1; 1879a747e4fSDavid du Colombier Dir *d, *dbuf; 1889a747e4fSDavid du Colombier char *tmp; 1897dd7cddfSDavid du Colombier Text *u; 1907dd7cddfSDavid du Colombier 1913df12bc6SDavid du Colombier if(t->ncache!=0 || t->file->nc || t->w==nil || t!=&t->w->body) 1927dd7cddfSDavid du Colombier error("text.load"); 1933df12bc6SDavid du Colombier if(t->w->isdir && t->file->nname==0){ 1943df12bc6SDavid du Colombier warning(nil, "empty directory name\n"); 1953df12bc6SDavid du Colombier return 0; 1963df12bc6SDavid du Colombier } 1977dd7cddfSDavid du Colombier fd = open(file, OREAD); 1987dd7cddfSDavid du Colombier if(fd < 0){ 1997dd7cddfSDavid du Colombier warning(nil, "can't open %s: %r\n", file); 2007dd7cddfSDavid du Colombier return 0; 2017dd7cddfSDavid du Colombier } 2029a747e4fSDavid du Colombier d = dirfstat(fd); 2039a747e4fSDavid du Colombier if(d == nil){ 2047dd7cddfSDavid du Colombier warning(nil, "can't fstat %s: %r\n", file); 2057dd7cddfSDavid du Colombier goto Rescue; 2067dd7cddfSDavid du Colombier } 2077dd7cddfSDavid du Colombier nulls = FALSE; 2089a747e4fSDavid du Colombier if(d->qid.type & QTDIR){ 2097dd7cddfSDavid du Colombier /* this is checked in get() but it's possible the file changed underfoot */ 2107dd7cddfSDavid du Colombier if(t->file->ntext > 1){ 2117dd7cddfSDavid du Colombier warning(nil, "%s is a directory; can't read with multiple windows on it\n", file); 2127dd7cddfSDavid du Colombier goto Rescue; 2137dd7cddfSDavid du Colombier } 2147dd7cddfSDavid du Colombier t->w->isdir = TRUE; 2157dd7cddfSDavid du Colombier t->w->filemenu = FALSE; 2167dd7cddfSDavid du Colombier if(t->file->name[t->file->nname-1] != '/'){ 2177dd7cddfSDavid du Colombier rp = runemalloc(t->file->nname+1); 2187dd7cddfSDavid du Colombier runemove(rp, t->file->name, t->file->nname); 2197dd7cddfSDavid du Colombier rp[t->file->nname] = '/'; 2207dd7cddfSDavid du Colombier winsetname(t->w, rp, t->file->nname+1); 22159cc4ca5SDavid du Colombier free(rp); 2227dd7cddfSDavid du Colombier } 2237dd7cddfSDavid du Colombier dlp = nil; 2247dd7cddfSDavid du Colombier ndl = 0; 2259a747e4fSDavid du Colombier dbuf = nil; 2269a747e4fSDavid du Colombier while((n=dirread(fd, &dbuf)) > 0){ 2277dd7cddfSDavid du Colombier for(i=0; i<n; i++){ 2287dd7cddfSDavid du Colombier dl = emalloc(sizeof(Dirlist)); 2299a747e4fSDavid du Colombier j = strlen(dbuf[i].name); 2309a747e4fSDavid du Colombier tmp = emalloc(j+1+1); 2319a747e4fSDavid du Colombier memmove(tmp, dbuf[i].name, j); 2329a747e4fSDavid du Colombier if(dbuf[i].qid.type & QTDIR) 2339a747e4fSDavid du Colombier tmp[j++] = '/'; 2349a747e4fSDavid du Colombier tmp[j] = '\0'; 2357dd7cddfSDavid du Colombier dl->r = bytetorune(tmp, &dl->nr); 2367dd7cddfSDavid du Colombier dl->wid = stringwidth(t->font, tmp); 2379a747e4fSDavid du Colombier free(tmp); 2387dd7cddfSDavid du Colombier ndl++; 2397dd7cddfSDavid du Colombier dlp = realloc(dlp, ndl*sizeof(Dirlist*)); 2407dd7cddfSDavid du Colombier dlp[ndl-1] = dl; 2417dd7cddfSDavid du Colombier } 2429a747e4fSDavid du Colombier free(dbuf); 2437dd7cddfSDavid du Colombier } 2447dd7cddfSDavid du Colombier qsort(dlp, ndl, sizeof(Dirlist*), dircmp); 2457dd7cddfSDavid du Colombier t->w->dlp = dlp; 2467dd7cddfSDavid du Colombier t->w->ndl = ndl; 2477dd7cddfSDavid du Colombier textcolumnate(t, dlp, ndl); 2487dd7cddfSDavid du Colombier q1 = t->file->nc; 2497dd7cddfSDavid du Colombier }else{ 2507dd7cddfSDavid du Colombier t->w->isdir = FALSE; 2517dd7cddfSDavid du Colombier t->w->filemenu = TRUE; 2527dd7cddfSDavid du Colombier q1 = q0 + fileload(t->file, q0, fd, &nulls); 2537dd7cddfSDavid du Colombier } 2547dd7cddfSDavid du Colombier if(setqid){ 2559a747e4fSDavid du Colombier t->file->dev = d->dev; 2569a747e4fSDavid du Colombier t->file->mtime = d->mtime; 2579a747e4fSDavid du Colombier t->file->qidpath = d->qid.path; 2587dd7cddfSDavid du Colombier } 2597dd7cddfSDavid du Colombier close(fd); 2607dd7cddfSDavid du Colombier rp = fbufalloc(); 2617dd7cddfSDavid du Colombier for(q=q0; q<q1; q+=n){ 2627dd7cddfSDavid du Colombier n = q1-q; 2637dd7cddfSDavid du Colombier if(n > RBUFSIZE) 2647dd7cddfSDavid du Colombier n = RBUFSIZE; 2657dd7cddfSDavid du Colombier bufread(t->file, q, rp, n); 2667dd7cddfSDavid du Colombier if(q < t->org) 2677dd7cddfSDavid du Colombier t->org += n; 2687dd7cddfSDavid du Colombier else if(q <= t->org+t->nchars) 2697dd7cddfSDavid du Colombier frinsert(t, rp, rp+n, q-t->org); 2707dd7cddfSDavid du Colombier if(t->lastlinefull) 2717dd7cddfSDavid du Colombier break; 2727dd7cddfSDavid du Colombier } 2737dd7cddfSDavid du Colombier fbuffree(rp); 2747dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++){ 2757dd7cddfSDavid du Colombier u = t->file->text[i]; 2767dd7cddfSDavid du Colombier if(u != t){ 2777dd7cddfSDavid du Colombier if(u->org > u->file->nc) /* will be 0 because of reset(), but safety first */ 2787dd7cddfSDavid du Colombier u->org = 0; 2797dd7cddfSDavid du Colombier textresize(u, u->all); 2807dd7cddfSDavid du Colombier textbacknl(u, u->org, 0); /* go to beginning of line */ 2817dd7cddfSDavid du Colombier } 2827dd7cddfSDavid du Colombier textsetselect(u, q0, q0); 2837dd7cddfSDavid du Colombier } 2847dd7cddfSDavid du Colombier if(nulls) 2857dd7cddfSDavid du Colombier warning(nil, "%s: NUL bytes elided\n", file); 2869a747e4fSDavid du Colombier free(d); 2877dd7cddfSDavid du Colombier return q1-q0; 2887dd7cddfSDavid du Colombier 2897dd7cddfSDavid du Colombier Rescue: 2907dd7cddfSDavid du Colombier close(fd); 2917dd7cddfSDavid du Colombier return 0; 2927dd7cddfSDavid du Colombier } 2937dd7cddfSDavid du Colombier 2947dd7cddfSDavid du Colombier uint 2957dd7cddfSDavid du Colombier textbsinsert(Text *t, uint q0, Rune *r, uint n, int tofile, int *nrp) 2967dd7cddfSDavid du Colombier { 2977dd7cddfSDavid du Colombier Rune *bp, *tp, *up; 2987dd7cddfSDavid du Colombier int i, initial; 2997dd7cddfSDavid du Colombier 3007dd7cddfSDavid du Colombier if(t->what == Tag){ /* can't happen but safety first: mustn't backspace over file name */ 3017dd7cddfSDavid du Colombier Err: 3027dd7cddfSDavid du Colombier textinsert(t, q0, r, n, tofile); 3037dd7cddfSDavid du Colombier *nrp = n; 3047dd7cddfSDavid du Colombier return q0; 3057dd7cddfSDavid du Colombier } 3067dd7cddfSDavid du Colombier bp = r; 3077dd7cddfSDavid du Colombier for(i=0; i<n; i++) 3087dd7cddfSDavid du Colombier if(*bp++ == '\b'){ 3097dd7cddfSDavid du Colombier --bp; 3107dd7cddfSDavid du Colombier initial = 0; 3117dd7cddfSDavid du Colombier tp = runemalloc(n); 3127dd7cddfSDavid du Colombier runemove(tp, r, i); 3137dd7cddfSDavid du Colombier up = tp+i; 3147dd7cddfSDavid du Colombier for(; i<n; i++){ 3157dd7cddfSDavid du Colombier *up = *bp++; 3167dd7cddfSDavid du Colombier if(*up == '\b') 3177dd7cddfSDavid du Colombier if(up == tp) 3187dd7cddfSDavid du Colombier initial++; 3197dd7cddfSDavid du Colombier else 3207dd7cddfSDavid du Colombier --up; 3217dd7cddfSDavid du Colombier else 3227dd7cddfSDavid du Colombier up++; 3237dd7cddfSDavid du Colombier } 3247dd7cddfSDavid du Colombier if(initial){ 3257dd7cddfSDavid du Colombier if(initial > q0) 3267dd7cddfSDavid du Colombier initial = q0; 3277dd7cddfSDavid du Colombier q0 -= initial; 3287dd7cddfSDavid du Colombier textdelete(t, q0, q0+initial, tofile); 3297dd7cddfSDavid du Colombier } 3307dd7cddfSDavid du Colombier n = up-tp; 3317dd7cddfSDavid du Colombier textinsert(t, q0, tp, n, tofile); 3327dd7cddfSDavid du Colombier free(tp); 3337dd7cddfSDavid du Colombier *nrp = n; 3347dd7cddfSDavid du Colombier return q0; 3357dd7cddfSDavid du Colombier } 3367dd7cddfSDavid du Colombier goto Err; 3377dd7cddfSDavid du Colombier } 3387dd7cddfSDavid du Colombier 3397dd7cddfSDavid du Colombier void 3407dd7cddfSDavid du Colombier textinsert(Text *t, uint q0, Rune *r, uint n, int tofile) 3417dd7cddfSDavid du Colombier { 3427dd7cddfSDavid du Colombier int c, i; 3437dd7cddfSDavid du Colombier Text *u; 3447dd7cddfSDavid du Colombier 3457dd7cddfSDavid du Colombier if(tofile && t->ncache != 0) 3467dd7cddfSDavid du Colombier error("text.insert"); 3477dd7cddfSDavid du Colombier if(n == 0) 3487dd7cddfSDavid du Colombier return; 3497dd7cddfSDavid du Colombier if(tofile){ 3507dd7cddfSDavid du Colombier fileinsert(t->file, q0, r, n); 3517dd7cddfSDavid du Colombier if(t->what == Body){ 3527dd7cddfSDavid du Colombier t->w->dirty = TRUE; 3537dd7cddfSDavid du Colombier t->w->utflastqid = -1; 3547dd7cddfSDavid du Colombier } 3557dd7cddfSDavid du Colombier if(t->file->ntext > 1) 3567dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++){ 3577dd7cddfSDavid du Colombier u = t->file->text[i]; 3587dd7cddfSDavid du Colombier if(u != t){ 3597dd7cddfSDavid du Colombier u->w->dirty = TRUE; /* always a body */ 3607dd7cddfSDavid du Colombier textinsert(u, q0, r, n, FALSE); 3617dd7cddfSDavid du Colombier textsetselect(u, u->q0, u->q1); 3627dd7cddfSDavid du Colombier textscrdraw(u); 3637dd7cddfSDavid du Colombier } 3647dd7cddfSDavid du Colombier } 3657dd7cddfSDavid du Colombier 3667dd7cddfSDavid du Colombier } 3677dd7cddfSDavid du Colombier if(q0 < t->q1) 3687dd7cddfSDavid du Colombier t->q1 += n; 3697dd7cddfSDavid du Colombier if(q0 < t->q0) 3707dd7cddfSDavid du Colombier t->q0 += n; 3717dd7cddfSDavid du Colombier if(q0 < t->org) 3727dd7cddfSDavid du Colombier t->org += n; 3737dd7cddfSDavid du Colombier else if(q0 <= t->org+t->nchars) 3747dd7cddfSDavid du Colombier frinsert(t, r, r+n, q0-t->org); 3757dd7cddfSDavid du Colombier if(t->w){ 3767dd7cddfSDavid du Colombier c = 'i'; 3777dd7cddfSDavid du Colombier if(t->what == Body) 3787dd7cddfSDavid du Colombier c = 'I'; 3797dd7cddfSDavid du Colombier if(n <= EVENTSIZE) 3807dd7cddfSDavid du Colombier winevent(t->w, "%c%d %d 0 %d %.*S\n", c, q0, q0+n, n, n, r); 3817dd7cddfSDavid du Colombier else 3827dd7cddfSDavid du Colombier winevent(t->w, "%c%d %d 0 0 \n", c, q0, q0+n, n); 3837dd7cddfSDavid du Colombier } 3847dd7cddfSDavid du Colombier } 3857dd7cddfSDavid du Colombier 3867dd7cddfSDavid du Colombier 3877dd7cddfSDavid du Colombier void 3887dd7cddfSDavid du Colombier textfill(Text *t) 3897dd7cddfSDavid du Colombier { 3907dd7cddfSDavid du Colombier Rune *rp; 3917dd7cddfSDavid du Colombier int i, n, m, nl; 3927dd7cddfSDavid du Colombier 3937dd7cddfSDavid du Colombier if(t->lastlinefull || t->nofill) 3947dd7cddfSDavid du Colombier return; 3957dd7cddfSDavid du Colombier if(t->ncache > 0){ 3967dd7cddfSDavid du Colombier if(t->w != nil) 3977dd7cddfSDavid du Colombier wincommit(t->w, t); 3987dd7cddfSDavid du Colombier else 3997dd7cddfSDavid du Colombier textcommit(t, TRUE); 4007dd7cddfSDavid du Colombier } 4017dd7cddfSDavid du Colombier rp = fbufalloc(); 4027dd7cddfSDavid du Colombier do{ 4037dd7cddfSDavid du Colombier n = t->file->nc-(t->org+t->nchars); 4047dd7cddfSDavid du Colombier if(n == 0) 4057dd7cddfSDavid du Colombier break; 4067dd7cddfSDavid du Colombier if(n > 2000) /* educated guess at reasonable amount */ 4077dd7cddfSDavid du Colombier n = 2000; 4087dd7cddfSDavid du Colombier bufread(t->file, t->org+t->nchars, rp, n); 4097dd7cddfSDavid du Colombier /* 4107dd7cddfSDavid du Colombier * it's expensive to frinsert more than we need, so 4117dd7cddfSDavid du Colombier * count newlines. 4127dd7cddfSDavid du Colombier */ 4137dd7cddfSDavid du Colombier nl = t->maxlines-t->nlines; 4147dd7cddfSDavid du Colombier m = 0; 4157dd7cddfSDavid du Colombier for(i=0; i<n; ){ 4167dd7cddfSDavid du Colombier if(rp[i++] == '\n'){ 4177dd7cddfSDavid du Colombier m++; 4187dd7cddfSDavid du Colombier if(m >= nl) 4197dd7cddfSDavid du Colombier break; 4207dd7cddfSDavid du Colombier } 4217dd7cddfSDavid du Colombier } 4227dd7cddfSDavid du Colombier frinsert(t, rp, rp+i, t->nchars); 4237dd7cddfSDavid du Colombier }while(t->lastlinefull == FALSE); 4247dd7cddfSDavid du Colombier fbuffree(rp); 4257dd7cddfSDavid du Colombier } 4267dd7cddfSDavid du Colombier 4277dd7cddfSDavid du Colombier void 4287dd7cddfSDavid du Colombier textdelete(Text *t, uint q0, uint q1, int tofile) 4297dd7cddfSDavid du Colombier { 4307dd7cddfSDavid du Colombier uint n, p0, p1; 4317dd7cddfSDavid du Colombier int i, c; 4327dd7cddfSDavid du Colombier Text *u; 4337dd7cddfSDavid du Colombier 4347dd7cddfSDavid du Colombier if(tofile && t->ncache != 0) 4357dd7cddfSDavid du Colombier error("text.delete"); 4367dd7cddfSDavid du Colombier n = q1-q0; 4377dd7cddfSDavid du Colombier if(n == 0) 4387dd7cddfSDavid du Colombier return; 4397dd7cddfSDavid du Colombier if(tofile){ 4407dd7cddfSDavid du Colombier filedelete(t->file, q0, q1); 4417dd7cddfSDavid du Colombier if(t->what == Body){ 4427dd7cddfSDavid du Colombier t->w->dirty = TRUE; 4437dd7cddfSDavid du Colombier t->w->utflastqid = -1; 4447dd7cddfSDavid du Colombier } 4457dd7cddfSDavid du Colombier if(t->file->ntext > 1) 4467dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++){ 4477dd7cddfSDavid du Colombier u = t->file->text[i]; 4487dd7cddfSDavid du Colombier if(u != t){ 4497dd7cddfSDavid du Colombier u->w->dirty = TRUE; /* always a body */ 4507dd7cddfSDavid du Colombier textdelete(u, q0, q1, FALSE); 4517dd7cddfSDavid du Colombier textsetselect(u, u->q0, u->q1); 4527dd7cddfSDavid du Colombier textscrdraw(u); 4537dd7cddfSDavid du Colombier } 4547dd7cddfSDavid du Colombier } 4557dd7cddfSDavid du Colombier } 4567dd7cddfSDavid du Colombier if(q0 < t->q0) 4577dd7cddfSDavid du Colombier t->q0 -= min(n, t->q0-q0); 4587dd7cddfSDavid du Colombier if(q0 < t->q1) 4597dd7cddfSDavid du Colombier t->q1 -= min(n, t->q1-q0); 4607dd7cddfSDavid du Colombier if(q1 <= t->org) 4617dd7cddfSDavid du Colombier t->org -= n; 4627dd7cddfSDavid du Colombier else if(q0 < t->org+t->nchars){ 4637dd7cddfSDavid du Colombier p1 = q1 - t->org; 4647dd7cddfSDavid du Colombier if(p1 > t->nchars) 4657dd7cddfSDavid du Colombier p1 = t->nchars; 4667dd7cddfSDavid du Colombier if(q0 < t->org){ 4677dd7cddfSDavid du Colombier t->org = q0; 4687dd7cddfSDavid du Colombier p0 = 0; 4697dd7cddfSDavid du Colombier }else 4707dd7cddfSDavid du Colombier p0 = q0 - t->org; 4717dd7cddfSDavid du Colombier frdelete(t, p0, p1); 4727dd7cddfSDavid du Colombier textfill(t); 4737dd7cddfSDavid du Colombier } 4747dd7cddfSDavid du Colombier if(t->w){ 4757dd7cddfSDavid du Colombier c = 'd'; 4767dd7cddfSDavid du Colombier if(t->what == Body) 4777dd7cddfSDavid du Colombier c = 'D'; 4787dd7cddfSDavid du Colombier winevent(t->w, "%c%d %d 0 0 \n", c, q0, q1); 4797dd7cddfSDavid du Colombier } 4807dd7cddfSDavid du Colombier } 4817dd7cddfSDavid du Colombier 4826b6b9ac8SDavid du Colombier void 4836b6b9ac8SDavid du Colombier textconstrain(Text *t, uint q0, uint q1, uint *p0, uint *p1) 4846b6b9ac8SDavid du Colombier { 4856b6b9ac8SDavid du Colombier *p0 = min(q0, t->file->nc); 4866b6b9ac8SDavid du Colombier *p1 = min(q1, t->file->nc); 4876b6b9ac8SDavid du Colombier } 4886b6b9ac8SDavid du Colombier 4897dd7cddfSDavid du Colombier Rune 4907dd7cddfSDavid du Colombier textreadc(Text *t, uint q) 4917dd7cddfSDavid du Colombier { 4927dd7cddfSDavid du Colombier Rune r; 4937dd7cddfSDavid du Colombier 4947dd7cddfSDavid du Colombier if(t->cq0<=q && q<t->cq0+t->ncache) 4957dd7cddfSDavid du Colombier r = t->cache[q-t->cq0]; 4967dd7cddfSDavid du Colombier else 4977dd7cddfSDavid du Colombier bufread(t->file, q, &r, 1); 4987dd7cddfSDavid du Colombier return r; 4997dd7cddfSDavid du Colombier } 5007dd7cddfSDavid du Colombier 5017dd7cddfSDavid du Colombier int 5027dd7cddfSDavid du Colombier textbswidth(Text *t, Rune c) 5037dd7cddfSDavid du Colombier { 5047dd7cddfSDavid du Colombier uint q, eq; 5057dd7cddfSDavid du Colombier Rune r; 5067dd7cddfSDavid du Colombier int skipping; 5077dd7cddfSDavid du Colombier 5087dd7cddfSDavid du Colombier /* there is known to be at least one character to erase */ 5097dd7cddfSDavid du Colombier if(c == 0x08) /* ^H: erase character */ 5107dd7cddfSDavid du Colombier return 1; 5117dd7cddfSDavid du Colombier q = t->q0; 5127dd7cddfSDavid du Colombier skipping = TRUE; 5137dd7cddfSDavid du Colombier while(q > 0){ 5147dd7cddfSDavid du Colombier r = textreadc(t, q-1); 5157dd7cddfSDavid du Colombier if(r == '\n'){ /* eat at most one more character */ 5167dd7cddfSDavid du Colombier if(q == t->q0) /* eat the newline */ 5177dd7cddfSDavid du Colombier --q; 5187dd7cddfSDavid du Colombier break; 5197dd7cddfSDavid du Colombier } 5207dd7cddfSDavid du Colombier if(c == 0x17){ 5217dd7cddfSDavid du Colombier eq = isalnum(r); 5227dd7cddfSDavid du Colombier if(eq && skipping) /* found one; stop skipping */ 5237dd7cddfSDavid du Colombier skipping = FALSE; 5247dd7cddfSDavid du Colombier else if(!eq && !skipping) 5257dd7cddfSDavid du Colombier break; 5267dd7cddfSDavid du Colombier } 5277dd7cddfSDavid du Colombier --q; 5287dd7cddfSDavid du Colombier } 5297dd7cddfSDavid du Colombier return t->q0-q; 5307dd7cddfSDavid du Colombier } 5317dd7cddfSDavid du Colombier 532fe853e23SDavid du Colombier int 533fe853e23SDavid du Colombier textfilewidth(Text *t, uint q0, int oneelement) 534fe853e23SDavid du Colombier { 535fe853e23SDavid du Colombier uint q; 536fe853e23SDavid du Colombier Rune r; 537fe853e23SDavid du Colombier 538fe853e23SDavid du Colombier q = q0; 539fe853e23SDavid du Colombier while(q > 0){ 540fe853e23SDavid du Colombier r = textreadc(t, q-1); 541fe853e23SDavid du Colombier if(r <= ' ') 542fe853e23SDavid du Colombier break; 543fe853e23SDavid du Colombier if(oneelement && r=='/') 544fe853e23SDavid du Colombier break; 545fe853e23SDavid du Colombier --q; 546fe853e23SDavid du Colombier } 547fe853e23SDavid du Colombier return q0-q; 548fe853e23SDavid du Colombier } 549fe853e23SDavid du Colombier 550fe853e23SDavid du Colombier Rune* 551fe853e23SDavid du Colombier textcomplete(Text *t) 552fe853e23SDavid du Colombier { 553fe853e23SDavid du Colombier int i, nstr, npath; 554fe853e23SDavid du Colombier uint q; 555fe853e23SDavid du Colombier Rune tmp[200]; 556fe853e23SDavid du Colombier Rune *str, *path; 557fe853e23SDavid du Colombier Rune *rp; 558fe853e23SDavid du Colombier Completion *c; 559fe853e23SDavid du Colombier char *s, *dirs; 560fe853e23SDavid du Colombier Runestr dir; 561fe853e23SDavid du Colombier 562fe853e23SDavid du Colombier /* control-f: filename completion; works back to white space or / */ 563fe853e23SDavid du Colombier if(t->q0<t->file->nc && textreadc(t, t->q0)>' ') /* must be at end of word */ 564fe853e23SDavid du Colombier return nil; 565fe853e23SDavid du Colombier nstr = textfilewidth(t, t->q0, TRUE); 566fe853e23SDavid du Colombier str = runemalloc(nstr); 567fe853e23SDavid du Colombier npath = textfilewidth(t, t->q0-nstr, FALSE); 568fe853e23SDavid du Colombier path = runemalloc(npath); 569fe853e23SDavid du Colombier 570fe853e23SDavid du Colombier c = nil; 571fe853e23SDavid du Colombier rp = nil; 572fe853e23SDavid du Colombier dirs = nil; 573fe853e23SDavid du Colombier 574fe853e23SDavid du Colombier q = t->q0-nstr; 575fe853e23SDavid du Colombier for(i=0; i<nstr; i++) 576fe853e23SDavid du Colombier str[i] = textreadc(t, q++); 577fe853e23SDavid du Colombier q = t->q0-nstr-npath; 578fe853e23SDavid du Colombier for(i=0; i<npath; i++) 579fe853e23SDavid du Colombier path[i] = textreadc(t, q++); 580fe853e23SDavid du Colombier /* is path rooted? if not, we need to make it relative to window path */ 581fe853e23SDavid du Colombier if(npath>0 && path[0]=='/') 582fe853e23SDavid du Colombier dir = (Runestr){path, npath}; 583fe853e23SDavid du Colombier else{ 584fe853e23SDavid du Colombier dir = dirname(t, nil, 0); 585fe853e23SDavid du Colombier if(dir.nr + 1 + npath > nelem(tmp)){ 586fe853e23SDavid du Colombier free(dir.r); 587fe853e23SDavid du Colombier goto Return; 588fe853e23SDavid du Colombier } 589fe853e23SDavid du Colombier if(dir.nr == 0){ 590fe853e23SDavid du Colombier dir.nr = 1; 591fe853e23SDavid du Colombier dir.r = runestrdup(L"."); 592fe853e23SDavid du Colombier } 593fe853e23SDavid du Colombier runemove(tmp, dir.r, dir.nr); 594fe853e23SDavid du Colombier tmp[dir.nr] = '/'; 595fe853e23SDavid du Colombier runemove(tmp+dir.nr+1, path, npath); 596fe853e23SDavid du Colombier free(dir.r); 597fe853e23SDavid du Colombier dir.r = tmp; 598fe853e23SDavid du Colombier dir.nr += 1+npath; 599fe853e23SDavid du Colombier dir = cleanrname(dir); 600fe853e23SDavid du Colombier } 601fe853e23SDavid du Colombier 602fe853e23SDavid du Colombier s = smprint("%.*S", nstr, str); 603fe853e23SDavid du Colombier dirs = smprint("%.*S", dir.nr, dir.r); 604fe853e23SDavid du Colombier c = complete(dirs, s); 605fe853e23SDavid du Colombier free(s); 606fe853e23SDavid du Colombier if(c == nil){ 607fe853e23SDavid du Colombier warning(nil, "error attempting completion: %r\n"); 608fe853e23SDavid du Colombier goto Return; 609fe853e23SDavid du Colombier } 610fe853e23SDavid du Colombier 611fe853e23SDavid du Colombier if(!c->advance){ 6124fec87e5SDavid du Colombier warning(nil, "%.*S%s%.*S*%s\n", 613fe853e23SDavid du Colombier dir.nr, dir.r, 614fe853e23SDavid du Colombier dir.nr>0 && dir.r[dir.nr-1]!='/' ? "/" : "", 6154fec87e5SDavid du Colombier nstr, str, 6164fec87e5SDavid du Colombier c->nmatch? "" : ": no matches in:"); 617fe853e23SDavid du Colombier for(i=0; i<c->nfile; i++) 618fe853e23SDavid du Colombier warning(nil, " %s\n", c->filename[i]); 619fe853e23SDavid du Colombier } 620fe853e23SDavid du Colombier 621fe853e23SDavid du Colombier if(c->advance) 622fe853e23SDavid du Colombier rp = runesmprint("%s", c->string); 623fe853e23SDavid du Colombier else 624fe853e23SDavid du Colombier rp = nil; 625fe853e23SDavid du Colombier Return: 626fe853e23SDavid du Colombier freecompletion(c); 627fe853e23SDavid du Colombier free(dirs); 628fe853e23SDavid du Colombier free(str); 629fe853e23SDavid du Colombier free(path); 630fe853e23SDavid du Colombier return rp; 631fe853e23SDavid du Colombier } 632fe853e23SDavid du Colombier 6337dd7cddfSDavid du Colombier void 6347dd7cddfSDavid du Colombier texttype(Text *t, Rune r) 6357dd7cddfSDavid du Colombier { 6367dd7cddfSDavid du Colombier uint q0, q1; 6377dd7cddfSDavid du Colombier int nnb, nb, n, i; 638fe853e23SDavid du Colombier int nr; 639fe853e23SDavid du Colombier Rune *rp; 6407dd7cddfSDavid du Colombier Text *u; 6417dd7cddfSDavid du Colombier 6427dd7cddfSDavid du Colombier if(t->what!=Body && r=='\n') 6437dd7cddfSDavid du Colombier return; 644fe853e23SDavid du Colombier nr = 1; 645fe853e23SDavid du Colombier rp = &r; 6467dd7cddfSDavid du Colombier switch(r){ 6477dd7cddfSDavid du Colombier case Kleft: 648fe853e23SDavid du Colombier if(t->q0 > 0){ 649*a8453668SDavid du Colombier wincommit(t->w, t); 650fe853e23SDavid du Colombier textshow(t, t->q0-1, t->q0-1, TRUE); 651fe853e23SDavid du Colombier } 652fe853e23SDavid du Colombier return; 6537dd7cddfSDavid du Colombier case Kright: 654fe853e23SDavid du Colombier if(t->q1 < t->file->nc){ 655*a8453668SDavid du Colombier wincommit(t->w, t); 656fe853e23SDavid du Colombier textshow(t, t->q1+1, t->q1+1, TRUE); 657fe853e23SDavid du Colombier } 658fe853e23SDavid du Colombier return; 659fe853e23SDavid du Colombier case Kdown: 660fe853e23SDavid du Colombier n = t->maxlines/3; 661fe853e23SDavid du Colombier goto case_Down; 662*a8453668SDavid du Colombier case Kscrollonedown: 663*a8453668SDavid du Colombier n = mousescrollsize(t->maxlines); 664*a8453668SDavid du Colombier if(n <= 0) 665*a8453668SDavid du Colombier n = 1; 666*a8453668SDavid du Colombier goto case_Down; 667fe853e23SDavid du Colombier case Kpgdown: 668fe853e23SDavid du Colombier n = 2*t->maxlines/3; 669fe853e23SDavid du Colombier case_Down: 6707dd7cddfSDavid du Colombier q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+n*t->font->height)); 6717dd7cddfSDavid du Colombier textsetorigin(t, q0, FALSE); 6727dd7cddfSDavid du Colombier return; 6737dd7cddfSDavid du Colombier case Kup: 674fe853e23SDavid du Colombier n = t->maxlines/3; 675fe853e23SDavid du Colombier goto case_Up; 676*a8453668SDavid du Colombier case Kscrolloneup: 677*a8453668SDavid du Colombier n = mousescrollsize(t->maxlines); 678*a8453668SDavid du Colombier goto case_Up; 679fe853e23SDavid du Colombier case Kpgup: 680fe853e23SDavid du Colombier n = 2*t->maxlines/3; 681fe853e23SDavid du Colombier case_Up: 6827dd7cddfSDavid du Colombier q0 = textbacknl(t, t->org, n); 6837dd7cddfSDavid du Colombier textsetorigin(t, q0, FALSE); 6847dd7cddfSDavid du Colombier return; 685fe853e23SDavid du Colombier case Khome: 686fe853e23SDavid du Colombier textshow(t, 0, 0, FALSE); 687fe853e23SDavid du Colombier return; 688fe853e23SDavid du Colombier case Kend: 689fe853e23SDavid du Colombier if(t->w) 690fe853e23SDavid du Colombier wincommit(t->w, t); 691fe853e23SDavid du Colombier else 692fe853e23SDavid du Colombier textcommit(t, TRUE); 693fe853e23SDavid du Colombier textshow(t, t->file->nc, t->file->nc, FALSE); 694fe853e23SDavid du Colombier return; 6957dd7cddfSDavid du Colombier } 6967dd7cddfSDavid du Colombier if(t->what == Body){ 6977dd7cddfSDavid du Colombier seq++; 6987dd7cddfSDavid du Colombier filemark(t->file); 6997dd7cddfSDavid du Colombier } 7007dd7cddfSDavid du Colombier if(t->q1 > t->q0){ 7017dd7cddfSDavid du Colombier if(t->ncache != 0) 7027dd7cddfSDavid du Colombier error("text.type"); 7037dd7cddfSDavid du Colombier cut(t, t, nil, TRUE, TRUE, nil, 0); 7047dd7cddfSDavid du Colombier t->eq0 = ~0; 7057dd7cddfSDavid du Colombier } 7069a747e4fSDavid du Colombier textshow(t, t->q0, t->q0, 1); 7077dd7cddfSDavid du Colombier switch(r){ 708fe853e23SDavid du Colombier case 0x06: 709fe853e23SDavid du Colombier case Kins: 710fe853e23SDavid du Colombier rp = textcomplete(t); 711fe853e23SDavid du Colombier if(rp == nil) 712fe853e23SDavid du Colombier return; 713fe853e23SDavid du Colombier nr = runestrlen(rp); 714fe853e23SDavid du Colombier break; /* fall through to normal insertion case */ 7157dd7cddfSDavid du Colombier case 0x1B: 7167dd7cddfSDavid du Colombier if(t->eq0 != ~0) 7177dd7cddfSDavid du Colombier textsetselect(t, t->eq0, t->q0); 7187dd7cddfSDavid du Colombier if(t->ncache > 0){ 7197dd7cddfSDavid du Colombier if(t->w != nil) 7207dd7cddfSDavid du Colombier wincommit(t->w, t); 7217dd7cddfSDavid du Colombier else 7227dd7cddfSDavid du Colombier textcommit(t, TRUE); 7237dd7cddfSDavid du Colombier } 7247dd7cddfSDavid du Colombier return; 7257dd7cddfSDavid du Colombier case 0x08: /* ^H: erase character */ 7267dd7cddfSDavid du Colombier case 0x15: /* ^U: erase line */ 7277dd7cddfSDavid du Colombier case 0x17: /* ^W: erase word */ 72880ee5cbfSDavid du Colombier if(t->q0 == 0) /* nothing to erase */ 7297dd7cddfSDavid du Colombier return; 7307dd7cddfSDavid du Colombier nnb = textbswidth(t, r); 7317dd7cddfSDavid du Colombier q1 = t->q0; 7327dd7cddfSDavid du Colombier q0 = q1-nnb; 73380ee5cbfSDavid du Colombier /* if selection is at beginning of window, avoid deleting invisible text */ 73480ee5cbfSDavid du Colombier if(q0 < t->org){ 73580ee5cbfSDavid du Colombier q0 = t->org; 73680ee5cbfSDavid du Colombier nnb = q1-q0; 73780ee5cbfSDavid du Colombier } 73880ee5cbfSDavid du Colombier if(nnb <= 0) 73980ee5cbfSDavid du Colombier return; 7407dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++){ 7417dd7cddfSDavid du Colombier u = t->file->text[i]; 7427dd7cddfSDavid du Colombier u->nofill = TRUE; 7437dd7cddfSDavid du Colombier nb = nnb; 7447dd7cddfSDavid du Colombier n = u->ncache; 7457dd7cddfSDavid du Colombier if(n > 0){ 7467dd7cddfSDavid du Colombier if(q1 != u->cq0+n) 7477dd7cddfSDavid du Colombier error("text.type backspace"); 7487dd7cddfSDavid du Colombier if(n > nb) 7497dd7cddfSDavid du Colombier n = nb; 7507dd7cddfSDavid du Colombier u->ncache -= n; 7517dd7cddfSDavid du Colombier textdelete(u, q1-n, q1, FALSE); 7527dd7cddfSDavid du Colombier nb -= n; 7537dd7cddfSDavid du Colombier } 7547dd7cddfSDavid du Colombier if(u->eq0==q1 || u->eq0==~0) 7557dd7cddfSDavid du Colombier u->eq0 = q0; 7567dd7cddfSDavid du Colombier if(nb && u==t) 7577dd7cddfSDavid du Colombier textdelete(u, q0, q0+nb, TRUE); 7587dd7cddfSDavid du Colombier if(u != t) 7597dd7cddfSDavid du Colombier textsetselect(u, u->q0, u->q1); 7607dd7cddfSDavid du Colombier else 7617dd7cddfSDavid du Colombier textsetselect(t, q0, q0); 7627dd7cddfSDavid du Colombier u->nofill = FALSE; 7637dd7cddfSDavid du Colombier } 7647dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++) 7657dd7cddfSDavid du Colombier textfill(t->file->text[i]); 7667dd7cddfSDavid du Colombier return; 7674fec87e5SDavid du Colombier case '\n': 7684fec87e5SDavid du Colombier if(t->w->autoindent){ 7694fec87e5SDavid du Colombier /* find beginning of previous line using backspace code */ 7704fec87e5SDavid du Colombier nnb = textbswidth(t, 0x15); /* ^U case */ 7714fec87e5SDavid du Colombier rp = runemalloc(nnb + 1); 7724fec87e5SDavid du Colombier nr = 0; 7734fec87e5SDavid du Colombier rp[nr++] = r; 7744fec87e5SDavid du Colombier for(i=0; i<nnb; i++){ 7754fec87e5SDavid du Colombier r = textreadc(t, t->q0-nnb+i); 7764fec87e5SDavid du Colombier if(r != ' ' && r != '\t') 7774fec87e5SDavid du Colombier break; 7784fec87e5SDavid du Colombier rp[nr++] = r; 7794fec87e5SDavid du Colombier } 7804fec87e5SDavid du Colombier } 7814fec87e5SDavid du Colombier break; /* fall through to normal code */ 7827dd7cddfSDavid du Colombier } 7837dd7cddfSDavid du Colombier /* otherwise ordinary character; just insert, typically in caches of all texts */ 7847dd7cddfSDavid du Colombier for(i=0; i<t->file->ntext; i++){ 7857dd7cddfSDavid du Colombier u = t->file->text[i]; 7867dd7cddfSDavid du Colombier if(u->eq0 == ~0) 7877dd7cddfSDavid du Colombier u->eq0 = t->q0; 7887dd7cddfSDavid du Colombier if(u->ncache == 0) 7897dd7cddfSDavid du Colombier u->cq0 = t->q0; 7907dd7cddfSDavid du Colombier else if(t->q0 != u->cq0+u->ncache) 7917dd7cddfSDavid du Colombier error("text.type cq1"); 792fe853e23SDavid du Colombier textinsert(u, t->q0, rp, nr, FALSE); 7937dd7cddfSDavid du Colombier if(u != t) 7947dd7cddfSDavid du Colombier textsetselect(u, u->q0, u->q1); 795fe853e23SDavid du Colombier if(u->ncache+nr > u->ncachealloc){ 796fe853e23SDavid du Colombier u->ncachealloc += 10 + nr; 7977dd7cddfSDavid du Colombier u->cache = runerealloc(u->cache, u->ncachealloc); 7987dd7cddfSDavid du Colombier } 799fe853e23SDavid du Colombier runemove(u->cache+u->ncache, rp, nr); 800fe853e23SDavid du Colombier u->ncache += nr; 8017dd7cddfSDavid du Colombier } 802fe853e23SDavid du Colombier if(rp != &r) 803fe853e23SDavid du Colombier free(rp); 804fe853e23SDavid du Colombier textsetselect(t, t->q0+nr, t->q0+nr); 8057dd7cddfSDavid du Colombier if(r=='\n' && t->w!=nil) 8067dd7cddfSDavid du Colombier wincommit(t->w, t); 8077dd7cddfSDavid du Colombier } 8087dd7cddfSDavid du Colombier 8097dd7cddfSDavid du Colombier void 8107dd7cddfSDavid du Colombier textcommit(Text *t, int tofile) 8117dd7cddfSDavid du Colombier { 8127dd7cddfSDavid du Colombier if(t->ncache == 0) 8137dd7cddfSDavid du Colombier return; 8147dd7cddfSDavid du Colombier if(tofile) 8157dd7cddfSDavid du Colombier fileinsert(t->file, t->cq0, t->cache, t->ncache); 8167dd7cddfSDavid du Colombier if(t->what == Body){ 8177dd7cddfSDavid du Colombier t->w->dirty = TRUE; 8187dd7cddfSDavid du Colombier t->w->utflastqid = -1; 8197dd7cddfSDavid du Colombier } 8207dd7cddfSDavid du Colombier t->ncache = 0; 8217dd7cddfSDavid du Colombier } 8227dd7cddfSDavid du Colombier 8237dd7cddfSDavid du Colombier static Text *clicktext; 8247dd7cddfSDavid du Colombier static uint clickmsec; 8257dd7cddfSDavid du Colombier static Text *selecttext; 8267dd7cddfSDavid du Colombier static uint selectq; 8277dd7cddfSDavid du Colombier 8287dd7cddfSDavid du Colombier /* 8297dd7cddfSDavid du Colombier * called from frame library 8307dd7cddfSDavid du Colombier */ 8317dd7cddfSDavid du Colombier void 8327dd7cddfSDavid du Colombier framescroll(Frame *f, int dl) 8337dd7cddfSDavid du Colombier { 8347dd7cddfSDavid du Colombier if(f != &selecttext->Frame) 8357dd7cddfSDavid du Colombier error("frameselect not right frame"); 8367dd7cddfSDavid du Colombier textframescroll(selecttext, dl); 8377dd7cddfSDavid du Colombier } 8387dd7cddfSDavid du Colombier 8397dd7cddfSDavid du Colombier void 8407dd7cddfSDavid du Colombier textframescroll(Text *t, int dl) 8417dd7cddfSDavid du Colombier { 8427dd7cddfSDavid du Colombier uint q0; 8437dd7cddfSDavid du Colombier 8447dd7cddfSDavid du Colombier if(dl == 0){ 8457dd7cddfSDavid du Colombier scrsleep(100); 8467dd7cddfSDavid du Colombier return; 8477dd7cddfSDavid du Colombier } 8487dd7cddfSDavid du Colombier if(dl < 0){ 8497dd7cddfSDavid du Colombier q0 = textbacknl(t, t->org, -dl); 8507dd7cddfSDavid du Colombier if(selectq > t->org+t->p0) 8517dd7cddfSDavid du Colombier textsetselect(t, t->org+t->p0, selectq); 8527dd7cddfSDavid du Colombier else 8537dd7cddfSDavid du Colombier textsetselect(t, selectq, t->org+t->p0); 8547dd7cddfSDavid du Colombier }else{ 8557dd7cddfSDavid du Colombier if(t->org+t->nchars == t->file->nc) 8567dd7cddfSDavid du Colombier return; 8577dd7cddfSDavid du Colombier q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+dl*t->font->height)); 8587dd7cddfSDavid du Colombier if(selectq > t->org+t->p1) 8597dd7cddfSDavid du Colombier textsetselect(t, t->org+t->p1, selectq); 8607dd7cddfSDavid du Colombier else 8617dd7cddfSDavid du Colombier textsetselect(t, selectq, t->org+t->p1); 8627dd7cddfSDavid du Colombier } 8637dd7cddfSDavid du Colombier textsetorigin(t, q0, TRUE); 8647dd7cddfSDavid du Colombier } 8657dd7cddfSDavid du Colombier 8667dd7cddfSDavid du Colombier 8677dd7cddfSDavid du Colombier void 8687dd7cddfSDavid du Colombier textselect(Text *t) 8697dd7cddfSDavid du Colombier { 8707dd7cddfSDavid du Colombier uint q0, q1; 8717dd7cddfSDavid du Colombier int b, x, y; 872e0d6d19cSDavid du Colombier int state, op; 8737dd7cddfSDavid du Colombier 8747dd7cddfSDavid du Colombier selecttext = t; 8757dd7cddfSDavid du Colombier /* 8767dd7cddfSDavid du Colombier * To have double-clicking and chording, we double-click 8777dd7cddfSDavid du Colombier * immediately if it might make sense. 8787dd7cddfSDavid du Colombier */ 8797dd7cddfSDavid du Colombier b = mouse->buttons; 8807dd7cddfSDavid du Colombier q0 = t->q0; 8817dd7cddfSDavid du Colombier q1 = t->q1; 8827dd7cddfSDavid du Colombier selectq = t->org+frcharofpt(t, mouse->xy); 8837dd7cddfSDavid du Colombier if(clicktext==t && mouse->msec-clickmsec<500) 8847dd7cddfSDavid du Colombier if(q0==q1 && selectq==q0){ 8857dd7cddfSDavid du Colombier textdoubleclick(t, &q0, &q1); 8867dd7cddfSDavid du Colombier textsetselect(t, q0, q1); 8877dd7cddfSDavid du Colombier flushimage(display, 1); 8887dd7cddfSDavid du Colombier x = mouse->xy.x; 8897dd7cddfSDavid du Colombier y = mouse->xy.y; 8907dd7cddfSDavid du Colombier /* stay here until something interesting happens */ 8917dd7cddfSDavid du Colombier do 8927dd7cddfSDavid du Colombier readmouse(mousectl); 8937dd7cddfSDavid du Colombier while(mouse->buttons==b && abs(mouse->xy.x-x)<3 && abs(mouse->xy.y-y)<3); 8947dd7cddfSDavid du Colombier mouse->xy.x = x; /* in case we're calling frselect */ 8957dd7cddfSDavid du Colombier mouse->xy.y = y; 8967dd7cddfSDavid du Colombier q0 = t->q0; /* may have changed */ 8977dd7cddfSDavid du Colombier q1 = t->q1; 8987dd7cddfSDavid du Colombier selectq = q0; 8997dd7cddfSDavid du Colombier } 9007dd7cddfSDavid du Colombier if(mouse->buttons == b){ 9017dd7cddfSDavid du Colombier t->Frame.scroll = framescroll; 9027dd7cddfSDavid du Colombier frselect(t, mousectl); 9037dd7cddfSDavid du Colombier /* horrible botch: while asleep, may have lost selection altogether */ 9047dd7cddfSDavid du Colombier if(selectq > t->file->nc) 9057dd7cddfSDavid du Colombier selectq = t->org + t->p0; 9067dd7cddfSDavid du Colombier t->Frame.scroll = nil; 9077dd7cddfSDavid du Colombier if(selectq < t->org) 9087dd7cddfSDavid du Colombier q0 = selectq; 9097dd7cddfSDavid du Colombier else 9107dd7cddfSDavid du Colombier q0 = t->org + t->p0; 9117dd7cddfSDavid du Colombier if(selectq > t->org+t->nchars) 9127dd7cddfSDavid du Colombier q1 = selectq; 9137dd7cddfSDavid du Colombier else 9147dd7cddfSDavid du Colombier q1 = t->org+t->p1; 9157dd7cddfSDavid du Colombier } 9167dd7cddfSDavid du Colombier if(q0 == q1){ 9177dd7cddfSDavid du Colombier if(q0==t->q0 && clicktext==t && mouse->msec-clickmsec<500){ 9187dd7cddfSDavid du Colombier textdoubleclick(t, &q0, &q1); 9197dd7cddfSDavid du Colombier clicktext = nil; 9207dd7cddfSDavid du Colombier }else{ 9217dd7cddfSDavid du Colombier clicktext = t; 9227dd7cddfSDavid du Colombier clickmsec = mouse->msec; 9237dd7cddfSDavid du Colombier } 9247dd7cddfSDavid du Colombier }else 9257dd7cddfSDavid du Colombier clicktext = nil; 9267dd7cddfSDavid du Colombier textsetselect(t, q0, q1); 9277dd7cddfSDavid du Colombier flushimage(display, 1); 928e0d6d19cSDavid du Colombier state = op = 0; /* undo when possible; +1 for cut, -1 for paste */ 9297dd7cddfSDavid du Colombier while(mouse->buttons){ 9307dd7cddfSDavid du Colombier mouse->msec = 0; 9317dd7cddfSDavid du Colombier b = mouse->buttons; 9327dd7cddfSDavid du Colombier if(b & 6){ 933e0d6d19cSDavid du Colombier if(state==0 && op==0 && t->what==Body){ 9347dd7cddfSDavid du Colombier seq++; 9357dd7cddfSDavid du Colombier filemark(t->w->body.file); 9367dd7cddfSDavid du Colombier } 9377dd7cddfSDavid du Colombier if(b & 2){ 9387dd7cddfSDavid du Colombier if(state==-1 && t->what==Body){ 9397dd7cddfSDavid du Colombier winundo(t->w, TRUE); 9407dd7cddfSDavid du Colombier textsetselect(t, q0, t->q0); 9417dd7cddfSDavid du Colombier state = 0; 942e0d6d19cSDavid du Colombier }else if(state != 1 && op != -1){ 9437dd7cddfSDavid du Colombier cut(t, t, nil, TRUE, TRUE, nil, 0); 944e0d6d19cSDavid du Colombier op = state = 1; 9457dd7cddfSDavid du Colombier } 9467dd7cddfSDavid du Colombier }else{ 9477dd7cddfSDavid du Colombier if(state==1 && t->what==Body){ 9487dd7cddfSDavid du Colombier winundo(t->w, TRUE); 9497dd7cddfSDavid du Colombier textsetselect(t, q0, t->q1); 9507dd7cddfSDavid du Colombier state = 0; 951e0d6d19cSDavid du Colombier }else if(state != -1 && op != 1){ 95259cc4ca5SDavid du Colombier paste(t, t, nil, TRUE, FALSE, nil, 0); 953e0d6d19cSDavid du Colombier op = state = -1; 9547dd7cddfSDavid du Colombier } 9557dd7cddfSDavid du Colombier } 9567dd7cddfSDavid du Colombier textscrdraw(t); 9577dd7cddfSDavid du Colombier clearmouse(); 9587dd7cddfSDavid du Colombier } 9597dd7cddfSDavid du Colombier flushimage(display, 1); 9607dd7cddfSDavid du Colombier while(mouse->buttons == b) 9617dd7cddfSDavid du Colombier readmouse(mousectl); 9627dd7cddfSDavid du Colombier clicktext = nil; 9637dd7cddfSDavid du Colombier } 9647dd7cddfSDavid du Colombier } 9657dd7cddfSDavid du Colombier 9667dd7cddfSDavid du Colombier void 9679a747e4fSDavid du Colombier textshow(Text *t, uint q0, uint q1, int doselect) 9687dd7cddfSDavid du Colombier { 9697dd7cddfSDavid du Colombier int qe; 9707dd7cddfSDavid du Colombier int nl; 9717dd7cddfSDavid du Colombier uint q; 9727dd7cddfSDavid du Colombier 9732af003dfSDavid du Colombier if(t->what != Body){ 9742af003dfSDavid du Colombier if(doselect) 9752af003dfSDavid du Colombier textsetselect(t, q0, q1); 9767dd7cddfSDavid du Colombier return; 9772af003dfSDavid du Colombier } 9787dd7cddfSDavid du Colombier if(t->w!=nil && t->maxlines==0) 9797dd7cddfSDavid du Colombier colgrow(t->col, t->w, 1); 9809a747e4fSDavid du Colombier if(doselect) 9817dd7cddfSDavid du Colombier textsetselect(t, q0, q1); 9827dd7cddfSDavid du Colombier qe = t->org+t->nchars; 9837dd7cddfSDavid du Colombier if(t->org<=q0 && (q0<qe || (q0==qe && qe==t->file->nc+t->ncache))) 9847dd7cddfSDavid du Colombier textscrdraw(t); 9857dd7cddfSDavid du Colombier else{ 9867dd7cddfSDavid du Colombier if(t->w->nopen[QWevent] > 0) 9877dd7cddfSDavid du Colombier nl = 3*t->maxlines/4; 9887dd7cddfSDavid du Colombier else 9897dd7cddfSDavid du Colombier nl = t->maxlines/4; 9907dd7cddfSDavid du Colombier q = textbacknl(t, q0, nl); 9917dd7cddfSDavid du Colombier /* avoid going backwards if trying to go forwards - long lines! */ 9927dd7cddfSDavid du Colombier if(!(q0>t->org && q<t->org)) 9937dd7cddfSDavid du Colombier textsetorigin(t, q, TRUE); 9947dd7cddfSDavid du Colombier while(q0 > t->org+t->nchars) 9957dd7cddfSDavid du Colombier textsetorigin(t, t->org+1, FALSE); 9967dd7cddfSDavid du Colombier } 9977dd7cddfSDavid du Colombier } 9987dd7cddfSDavid du Colombier 9997dd7cddfSDavid du Colombier static 10007dd7cddfSDavid du Colombier int 10017dd7cddfSDavid du Colombier region(int a, int b) 10027dd7cddfSDavid du Colombier { 10037dd7cddfSDavid du Colombier if(a < b) 10047dd7cddfSDavid du Colombier return -1; 10057dd7cddfSDavid du Colombier if(a == b) 10067dd7cddfSDavid du Colombier return 0; 10077dd7cddfSDavid du Colombier return 1; 10087dd7cddfSDavid du Colombier } 10097dd7cddfSDavid du Colombier 10107dd7cddfSDavid du Colombier void 10117dd7cddfSDavid du Colombier selrestore(Frame *f, Point pt0, uint p0, uint p1) 10127dd7cddfSDavid du Colombier { 10137dd7cddfSDavid du Colombier if(p1<=f->p0 || p0>=f->p1){ 10147dd7cddfSDavid du Colombier /* no overlap */ 10157dd7cddfSDavid du Colombier frdrawsel0(f, pt0, p0, p1, f->cols[BACK], f->cols[TEXT]); 10167dd7cddfSDavid du Colombier return; 10177dd7cddfSDavid du Colombier } 10187dd7cddfSDavid du Colombier if(p0>=f->p0 && p1<=f->p1){ 10197dd7cddfSDavid du Colombier /* entirely inside */ 10207dd7cddfSDavid du Colombier frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]); 10217dd7cddfSDavid du Colombier return; 10227dd7cddfSDavid du Colombier } 10237dd7cddfSDavid du Colombier 10247dd7cddfSDavid du Colombier /* they now are known to overlap */ 10257dd7cddfSDavid du Colombier 10267dd7cddfSDavid du Colombier /* before selection */ 10277dd7cddfSDavid du Colombier if(p0 < f->p0){ 10287dd7cddfSDavid du Colombier frdrawsel0(f, pt0, p0, f->p0, f->cols[BACK], f->cols[TEXT]); 10297dd7cddfSDavid du Colombier p0 = f->p0; 10307dd7cddfSDavid du Colombier pt0 = frptofchar(f, p0); 10317dd7cddfSDavid du Colombier } 10327dd7cddfSDavid du Colombier /* after selection */ 10337dd7cddfSDavid du Colombier if(p1 > f->p1){ 10347dd7cddfSDavid du Colombier frdrawsel0(f, frptofchar(f, f->p1), f->p1, p1, f->cols[BACK], f->cols[TEXT]); 10357dd7cddfSDavid du Colombier p1 = f->p1; 10367dd7cddfSDavid du Colombier } 10377dd7cddfSDavid du Colombier /* inside selection */ 10387dd7cddfSDavid du Colombier frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]); 10397dd7cddfSDavid du Colombier } 10407dd7cddfSDavid du Colombier 10417dd7cddfSDavid du Colombier void 10427dd7cddfSDavid du Colombier textsetselect(Text *t, uint q0, uint q1) 10437dd7cddfSDavid du Colombier { 10447dd7cddfSDavid du Colombier int p0, p1; 10457dd7cddfSDavid du Colombier 10467dd7cddfSDavid du Colombier /* t->p0 and t->p1 are always right; t->q0 and t->q1 may be off */ 10477dd7cddfSDavid du Colombier t->q0 = q0; 10487dd7cddfSDavid du Colombier t->q1 = q1; 10497dd7cddfSDavid du Colombier /* compute desired p0,p1 from q0,q1 */ 10507dd7cddfSDavid du Colombier p0 = q0-t->org; 10517dd7cddfSDavid du Colombier p1 = q1-t->org; 10527dd7cddfSDavid du Colombier if(p0 < 0) 10537dd7cddfSDavid du Colombier p0 = 0; 10547dd7cddfSDavid du Colombier if(p1 < 0) 10557dd7cddfSDavid du Colombier p1 = 0; 10567dd7cddfSDavid du Colombier if(p0 > t->nchars) 10577dd7cddfSDavid du Colombier p0 = t->nchars; 10587dd7cddfSDavid du Colombier if(p1 > t->nchars) 10597dd7cddfSDavid du Colombier p1 = t->nchars; 10607dd7cddfSDavid du Colombier if(p0==t->p0 && p1==t->p1) 10617dd7cddfSDavid du Colombier return; 10627dd7cddfSDavid du Colombier /* screen disagrees with desired selection */ 10637dd7cddfSDavid du Colombier if(t->p1<=p0 || p1<=t->p0 || p0==p1 || t->p1==t->p0){ 10647dd7cddfSDavid du Colombier /* no overlap or too easy to bother trying */ 10657dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, t->p0), t->p0, t->p1, 0); 10667dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, p0), p0, p1, 1); 10677dd7cddfSDavid du Colombier goto Return; 10687dd7cddfSDavid du Colombier } 10697dd7cddfSDavid du Colombier /* overlap; avoid unnecessary painting */ 10707dd7cddfSDavid du Colombier if(p0 < t->p0){ 10717dd7cddfSDavid du Colombier /* extend selection backwards */ 10727dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, p0), p0, t->p0, 1); 10737dd7cddfSDavid du Colombier }else if(p0 > t->p0){ 10747dd7cddfSDavid du Colombier /* trim first part of selection */ 10757dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, t->p0), t->p0, p0, 0); 10767dd7cddfSDavid du Colombier } 10777dd7cddfSDavid du Colombier if(p1 > t->p1){ 10787dd7cddfSDavid du Colombier /* extend selection forwards */ 10797dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, t->p1), t->p1, p1, 1); 10807dd7cddfSDavid du Colombier }else if(p1 < t->p1){ 10817dd7cddfSDavid du Colombier /* trim last part of selection */ 10827dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, p1), p1, t->p1, 0); 10837dd7cddfSDavid du Colombier } 10847dd7cddfSDavid du Colombier 10857dd7cddfSDavid du Colombier Return: 10867dd7cddfSDavid du Colombier t->p0 = p0; 10877dd7cddfSDavid du Colombier t->p1 = p1; 10887dd7cddfSDavid du Colombier } 10897dd7cddfSDavid du Colombier 10909a747e4fSDavid du Colombier /* 10919a747e4fSDavid du Colombier * Release the button in less than DELAY ms and it's considered a null selection 10929a747e4fSDavid du Colombier * if the mouse hardly moved, regardless of whether it crossed a char boundary. 10939a747e4fSDavid du Colombier */ 10949a747e4fSDavid du Colombier enum { 10959a747e4fSDavid du Colombier DELAY = 2, 10969a747e4fSDavid du Colombier MINMOVE = 4, 10979a747e4fSDavid du Colombier }; 10989a747e4fSDavid du Colombier 10999a747e4fSDavid du Colombier uint 11007dd7cddfSDavid du Colombier xselect(Frame *f, Mousectl *mc, Image *col, uint *p1p) /* when called, button is down */ 11017dd7cddfSDavid du Colombier { 11027dd7cddfSDavid du Colombier uint p0, p1, q, tmp; 11039a747e4fSDavid du Colombier ulong msec; 11047dd7cddfSDavid du Colombier Point mp, pt0, pt1, qt; 11057dd7cddfSDavid du Colombier int reg, b; 11067dd7cddfSDavid du Colombier 11077dd7cddfSDavid du Colombier mp = mc->xy; 11087dd7cddfSDavid du Colombier b = mc->buttons; 11099a747e4fSDavid du Colombier msec = mc->msec; 11107dd7cddfSDavid du Colombier 11117dd7cddfSDavid du Colombier /* remove tick */ 11127dd7cddfSDavid du Colombier if(f->p0 == f->p1) 11137dd7cddfSDavid du Colombier frtick(f, frptofchar(f, f->p0), 0); 11147dd7cddfSDavid du Colombier p0 = p1 = frcharofpt(f, mp); 11157dd7cddfSDavid du Colombier pt0 = frptofchar(f, p0); 11167dd7cddfSDavid du Colombier pt1 = frptofchar(f, p1); 11177dd7cddfSDavid du Colombier reg = 0; 11187dd7cddfSDavid du Colombier frtick(f, pt0, 1); 11197dd7cddfSDavid du Colombier do{ 11207dd7cddfSDavid du Colombier q = frcharofpt(f, mc->xy); 11217dd7cddfSDavid du Colombier if(p1 != q){ 11227dd7cddfSDavid du Colombier if(p0 == p1) 11237dd7cddfSDavid du Colombier frtick(f, pt0, 0); 11247dd7cddfSDavid du Colombier if(reg != region(q, p0)){ /* crossed starting point; reset */ 11257dd7cddfSDavid du Colombier if(reg > 0) 11267dd7cddfSDavid du Colombier selrestore(f, pt0, p0, p1); 11277dd7cddfSDavid du Colombier else if(reg < 0) 11287dd7cddfSDavid du Colombier selrestore(f, pt1, p1, p0); 11297dd7cddfSDavid du Colombier p1 = p0; 11307dd7cddfSDavid du Colombier pt1 = pt0; 11317dd7cddfSDavid du Colombier reg = region(q, p0); 11327dd7cddfSDavid du Colombier if(reg == 0) 11337dd7cddfSDavid du Colombier frdrawsel0(f, pt0, p0, p1, col, display->white); 11347dd7cddfSDavid du Colombier } 11357dd7cddfSDavid du Colombier qt = frptofchar(f, q); 11367dd7cddfSDavid du Colombier if(reg > 0){ 11377dd7cddfSDavid du Colombier if(q > p1) 11387dd7cddfSDavid du Colombier frdrawsel0(f, pt1, p1, q, col, display->white); 11397dd7cddfSDavid du Colombier 11407dd7cddfSDavid du Colombier else if(q < p1) 11417dd7cddfSDavid du Colombier selrestore(f, qt, q, p1); 11427dd7cddfSDavid du Colombier }else if(reg < 0){ 11437dd7cddfSDavid du Colombier if(q > p1) 11447dd7cddfSDavid du Colombier selrestore(f, pt1, p1, q); 11457dd7cddfSDavid du Colombier else 11467dd7cddfSDavid du Colombier frdrawsel0(f, qt, q, p1, col, display->white); 11477dd7cddfSDavid du Colombier } 11487dd7cddfSDavid du Colombier p1 = q; 11497dd7cddfSDavid du Colombier pt1 = qt; 11507dd7cddfSDavid du Colombier } 11517dd7cddfSDavid du Colombier if(p0 == p1) 11527dd7cddfSDavid du Colombier frtick(f, pt0, 1); 11537dd7cddfSDavid du Colombier flushimage(f->display, 1); 11547dd7cddfSDavid du Colombier readmouse(mc); 11557dd7cddfSDavid du Colombier }while(mc->buttons == b); 11569a747e4fSDavid du Colombier if(mc->msec-msec < DELAY && p0!=p1 11579a747e4fSDavid du Colombier && abs(mp.x-mc->xy.x)<MINMOVE 11589a747e4fSDavid du Colombier && abs(mp.y-mc->xy.y)<MINMOVE) { 11599a747e4fSDavid du Colombier if(reg > 0) 11609a747e4fSDavid du Colombier selrestore(f, pt0, p0, p1); 11619a747e4fSDavid du Colombier else if(reg < 0) 11629a747e4fSDavid du Colombier selrestore(f, pt1, p1, p0); 11639a747e4fSDavid du Colombier p1 = p0; 11649a747e4fSDavid du Colombier } 11657dd7cddfSDavid du Colombier if(p1 < p0){ 11667dd7cddfSDavid du Colombier tmp = p0; 11677dd7cddfSDavid du Colombier p0 = p1; 11687dd7cddfSDavid du Colombier p1 = tmp; 11697dd7cddfSDavid du Colombier } 11707dd7cddfSDavid du Colombier pt0 = frptofchar(f, p0); 11717dd7cddfSDavid du Colombier if(p0 == p1) 11727dd7cddfSDavid du Colombier frtick(f, pt0, 0); 11737dd7cddfSDavid du Colombier selrestore(f, pt0, p0, p1); 11747dd7cddfSDavid du Colombier /* restore tick */ 11757dd7cddfSDavid du Colombier if(f->p0 == f->p1) 11767dd7cddfSDavid du Colombier frtick(f, frptofchar(f, f->p0), 1); 11777dd7cddfSDavid du Colombier flushimage(f->display, 1); 11787dd7cddfSDavid du Colombier *p1p = p1; 11797dd7cddfSDavid du Colombier return p0; 11807dd7cddfSDavid du Colombier } 11817dd7cddfSDavid du Colombier 11827dd7cddfSDavid du Colombier int 11837dd7cddfSDavid du Colombier textselect23(Text *t, uint *q0, uint *q1, Image *high, int mask) 11847dd7cddfSDavid du Colombier { 11857dd7cddfSDavid du Colombier uint p0, p1; 11867dd7cddfSDavid du Colombier int buts; 11877dd7cddfSDavid du Colombier 11887dd7cddfSDavid du Colombier p0 = xselect(t, mousectl, high, &p1); 11897dd7cddfSDavid du Colombier buts = mousectl->buttons; 11907dd7cddfSDavid du Colombier if((buts & mask) == 0){ 11917dd7cddfSDavid du Colombier *q0 = p0+t->org; 11927dd7cddfSDavid du Colombier *q1 = p1+t->org; 11937dd7cddfSDavid du Colombier } 11947dd7cddfSDavid du Colombier 11957dd7cddfSDavid du Colombier while(mousectl->buttons) 11967dd7cddfSDavid du Colombier readmouse(mousectl); 11977dd7cddfSDavid du Colombier return buts; 11987dd7cddfSDavid du Colombier } 11997dd7cddfSDavid du Colombier 12007dd7cddfSDavid du Colombier int 12017dd7cddfSDavid du Colombier textselect2(Text *t, uint *q0, uint *q1, Text **tp) 12027dd7cddfSDavid du Colombier { 12037dd7cddfSDavid du Colombier int buts; 12047dd7cddfSDavid du Colombier 12057dd7cddfSDavid du Colombier *tp = nil; 12067dd7cddfSDavid du Colombier buts = textselect23(t, q0, q1, but2col, 4); 12077dd7cddfSDavid du Colombier if(buts & 4) 12087dd7cddfSDavid du Colombier return 0; 12097dd7cddfSDavid du Colombier if(buts & 1){ /* pick up argument */ 12107dd7cddfSDavid du Colombier *tp = argtext; 12117dd7cddfSDavid du Colombier return 1; 12127dd7cddfSDavid du Colombier } 12137dd7cddfSDavid du Colombier return 1; 12147dd7cddfSDavid du Colombier } 12157dd7cddfSDavid du Colombier 12167dd7cddfSDavid du Colombier int 12177dd7cddfSDavid du Colombier textselect3(Text *t, uint *q0, uint *q1) 12187dd7cddfSDavid du Colombier { 12197dd7cddfSDavid du Colombier int h; 12207dd7cddfSDavid du Colombier 12217dd7cddfSDavid du Colombier h = (textselect23(t, q0, q1, but3col, 1|2) == 0); 12227dd7cddfSDavid du Colombier return h; 12237dd7cddfSDavid du Colombier } 12247dd7cddfSDavid du Colombier 12257dd7cddfSDavid du Colombier static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 }; 12267dd7cddfSDavid du Colombier static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 }; 12277dd7cddfSDavid du Colombier static Rune left2[] = { L'\n', 0 }; 12287dd7cddfSDavid du Colombier static Rune left3[] = { L'\'', L'"', L'`', 0 }; 12297dd7cddfSDavid du Colombier 12307dd7cddfSDavid du Colombier static 12317dd7cddfSDavid du Colombier Rune *left[] = { 12327dd7cddfSDavid du Colombier left1, 12337dd7cddfSDavid du Colombier left2, 12347dd7cddfSDavid du Colombier left3, 12357dd7cddfSDavid du Colombier nil 12367dd7cddfSDavid du Colombier }; 12377dd7cddfSDavid du Colombier static 12387dd7cddfSDavid du Colombier Rune *right[] = { 12397dd7cddfSDavid du Colombier right1, 12407dd7cddfSDavid du Colombier left2, 12417dd7cddfSDavid du Colombier left3, 12427dd7cddfSDavid du Colombier nil 12437dd7cddfSDavid du Colombier }; 12447dd7cddfSDavid du Colombier 12457dd7cddfSDavid du Colombier void 12467dd7cddfSDavid du Colombier textdoubleclick(Text *t, uint *q0, uint *q1) 12477dd7cddfSDavid du Colombier { 12487dd7cddfSDavid du Colombier int c, i; 12497dd7cddfSDavid du Colombier Rune *r, *l, *p; 12507dd7cddfSDavid du Colombier uint q; 12517dd7cddfSDavid du Colombier 12527dd7cddfSDavid du Colombier for(i=0; left[i]!=nil; i++){ 12537dd7cddfSDavid du Colombier q = *q0; 12547dd7cddfSDavid du Colombier l = left[i]; 12557dd7cddfSDavid du Colombier r = right[i]; 12567dd7cddfSDavid du Colombier /* try matching character to left, looking right */ 12577dd7cddfSDavid du Colombier if(q == 0) 12587dd7cddfSDavid du Colombier c = '\n'; 12597dd7cddfSDavid du Colombier else 12607dd7cddfSDavid du Colombier c = textreadc(t, q-1); 126159cc4ca5SDavid du Colombier p = runestrchr(l, c); 12627dd7cddfSDavid du Colombier if(p != nil){ 12637dd7cddfSDavid du Colombier if(textclickmatch(t, c, r[p-l], 1, &q)) 12647dd7cddfSDavid du Colombier *q1 = q-(c!='\n'); 12657dd7cddfSDavid du Colombier return; 12667dd7cddfSDavid du Colombier } 12677dd7cddfSDavid du Colombier /* try matching character to right, looking left */ 12687dd7cddfSDavid du Colombier if(q == t->file->nc) 12697dd7cddfSDavid du Colombier c = '\n'; 12707dd7cddfSDavid du Colombier else 12717dd7cddfSDavid du Colombier c = textreadc(t, q); 127259cc4ca5SDavid du Colombier p = runestrchr(r, c); 12737dd7cddfSDavid du Colombier if(p != nil){ 12747dd7cddfSDavid du Colombier if(textclickmatch(t, c, l[p-r], -1, &q)){ 12757dd7cddfSDavid du Colombier *q1 = *q0+(*q0<t->file->nc && c=='\n'); 12767dd7cddfSDavid du Colombier *q0 = q; 12777dd7cddfSDavid du Colombier if(c!='\n' || q!=0 || textreadc(t, 0)=='\n') 12787dd7cddfSDavid du Colombier (*q0)++; 12797dd7cddfSDavid du Colombier } 12807dd7cddfSDavid du Colombier return; 12817dd7cddfSDavid du Colombier } 12827dd7cddfSDavid du Colombier } 12837dd7cddfSDavid du Colombier /* try filling out word to right */ 12847dd7cddfSDavid du Colombier while(*q1<t->file->nc && isalnum(textreadc(t, *q1))) 12857dd7cddfSDavid du Colombier (*q1)++; 12867dd7cddfSDavid du Colombier /* try filling out word to left */ 12877dd7cddfSDavid du Colombier while(*q0>0 && isalnum(textreadc(t, *q0-1))) 12887dd7cddfSDavid du Colombier (*q0)--; 12897dd7cddfSDavid du Colombier } 12907dd7cddfSDavid du Colombier 12917dd7cddfSDavid du Colombier int 12927dd7cddfSDavid du Colombier textclickmatch(Text *t, int cl, int cr, int dir, uint *q) 12937dd7cddfSDavid du Colombier { 12947dd7cddfSDavid du Colombier Rune c; 12957dd7cddfSDavid du Colombier int nest; 12967dd7cddfSDavid du Colombier 12977dd7cddfSDavid du Colombier nest = 1; 12987dd7cddfSDavid du Colombier for(;;){ 12997dd7cddfSDavid du Colombier if(dir > 0){ 13007dd7cddfSDavid du Colombier if(*q == t->file->nc) 13017dd7cddfSDavid du Colombier break; 13027dd7cddfSDavid du Colombier c = textreadc(t, *q); 13037dd7cddfSDavid du Colombier (*q)++; 13047dd7cddfSDavid du Colombier }else{ 13057dd7cddfSDavid du Colombier if(*q == 0) 13067dd7cddfSDavid du Colombier break; 13077dd7cddfSDavid du Colombier (*q)--; 13087dd7cddfSDavid du Colombier c = textreadc(t, *q); 13097dd7cddfSDavid du Colombier } 13107dd7cddfSDavid du Colombier if(c == cr){ 13117dd7cddfSDavid du Colombier if(--nest==0) 13127dd7cddfSDavid du Colombier return 1; 13137dd7cddfSDavid du Colombier }else if(c == cl) 13147dd7cddfSDavid du Colombier nest++; 13157dd7cddfSDavid du Colombier } 13167dd7cddfSDavid du Colombier return cl=='\n' && nest==1; 13177dd7cddfSDavid du Colombier } 13187dd7cddfSDavid du Colombier 13197dd7cddfSDavid du Colombier uint 13207dd7cddfSDavid du Colombier textbacknl(Text *t, uint p, uint n) 13217dd7cddfSDavid du Colombier { 13227dd7cddfSDavid du Colombier int i, j; 13237dd7cddfSDavid du Colombier 13247dd7cddfSDavid du Colombier /* look for start of this line if n==0 */ 13257dd7cddfSDavid du Colombier if(n==0 && p>0 && textreadc(t, p-1)!='\n') 13267dd7cddfSDavid du Colombier n = 1; 13277dd7cddfSDavid du Colombier i = n; 13287dd7cddfSDavid du Colombier while(i-->0 && p>0){ 13297dd7cddfSDavid du Colombier --p; /* it's at a newline now; back over it */ 13307dd7cddfSDavid du Colombier if(p == 0) 13317dd7cddfSDavid du Colombier break; 13327dd7cddfSDavid du Colombier /* at 128 chars, call it a line anyway */ 13337dd7cddfSDavid du Colombier for(j=128; --j>0 && p>0; p--) 13347dd7cddfSDavid du Colombier if(textreadc(t, p-1)=='\n') 13357dd7cddfSDavid du Colombier break; 13367dd7cddfSDavid du Colombier } 13377dd7cddfSDavid du Colombier return p; 13387dd7cddfSDavid du Colombier } 13397dd7cddfSDavid du Colombier 13407dd7cddfSDavid du Colombier void 13417dd7cddfSDavid du Colombier textsetorigin(Text *t, uint org, int exact) 13427dd7cddfSDavid du Colombier { 13437dd7cddfSDavid du Colombier int i, a, fixup; 13447dd7cddfSDavid du Colombier Rune *r; 13457dd7cddfSDavid du Colombier uint n; 13467dd7cddfSDavid du Colombier 13477dd7cddfSDavid du Colombier if(org>0 && !exact){ 13487dd7cddfSDavid du Colombier /* org is an estimate of the char posn; find a newline */ 13497dd7cddfSDavid du Colombier /* don't try harder than 256 chars */ 13507dd7cddfSDavid du Colombier for(i=0; i<256 && org<t->file->nc; i++){ 13517dd7cddfSDavid du Colombier if(textreadc(t, org) == '\n'){ 13527dd7cddfSDavid du Colombier org++; 13537dd7cddfSDavid du Colombier break; 13547dd7cddfSDavid du Colombier } 13557dd7cddfSDavid du Colombier org++; 13567dd7cddfSDavid du Colombier } 13577dd7cddfSDavid du Colombier } 13587dd7cddfSDavid du Colombier a = org-t->org; 13597dd7cddfSDavid du Colombier fixup = 0; 13607dd7cddfSDavid du Colombier if(a>=0 && a<t->nchars){ 13617dd7cddfSDavid du Colombier frdelete(t, 0, a); 13627dd7cddfSDavid du Colombier fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */ 13637dd7cddfSDavid du Colombier } 13647dd7cddfSDavid du Colombier else if(a<0 && -a<t->nchars){ 13657dd7cddfSDavid du Colombier n = t->org - org; 13667dd7cddfSDavid du Colombier r = runemalloc(n); 13677dd7cddfSDavid du Colombier bufread(t->file, org, r, n); 13687dd7cddfSDavid du Colombier frinsert(t, r, r+n, 0); 13697dd7cddfSDavid du Colombier free(r); 13707dd7cddfSDavid du Colombier }else 13717dd7cddfSDavid du Colombier frdelete(t, 0, t->nchars); 13727dd7cddfSDavid du Colombier t->org = org; 13737dd7cddfSDavid du Colombier textfill(t); 13747dd7cddfSDavid du Colombier textscrdraw(t); 13757dd7cddfSDavid du Colombier textsetselect(t, t->q0, t->q1); 13767dd7cddfSDavid du Colombier if(fixup && t->p1 > t->p0) 13777dd7cddfSDavid du Colombier frdrawsel(t, frptofchar(t, t->p1-1), t->p1-1, t->p1, 1); 13787dd7cddfSDavid du Colombier } 13797dd7cddfSDavid du Colombier 13807dd7cddfSDavid du Colombier void 13817dd7cddfSDavid du Colombier textreset(Text *t) 13827dd7cddfSDavid du Colombier { 13837dd7cddfSDavid du Colombier t->file->seq = 0; 13847dd7cddfSDavid du Colombier t->eq0 = ~0; 13857dd7cddfSDavid du Colombier /* do t->delete(0, t->nc, TRUE) without building backup stuff */ 13867dd7cddfSDavid du Colombier textsetselect(t, t->org, t->org); 13877dd7cddfSDavid du Colombier frdelete(t, 0, t->nchars); 13887dd7cddfSDavid du Colombier t->org = 0; 13897dd7cddfSDavid du Colombier t->q0 = 0; 13907dd7cddfSDavid du Colombier t->q1 = 0; 13917dd7cddfSDavid du Colombier filereset(t->file); 13927dd7cddfSDavid du Colombier bufreset(t->file); 13937dd7cddfSDavid du Colombier } 1394