void selrestore(Frame *f, Point pt0, uint p0, uint p1) { if(p1<=f->p0 || p0>=f->p1){ /* no overlap */ frdrawsel0(f, pt0, p0, p1, f->cols[BACK], f->cols[TEXT]); return; } if(p0>=f->p0 && p1<=f->p1){ /* entirely inside */ frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]); return; } /* they now are known to overlap */ /* before selection */ if(p0 < f->p0){ frdrawsel0(f, pt0, p0, f->p0, f->cols[BACK], f->cols[TEXT]); p0 = f->p0; pt0 = frptofchar(f, p0); } /* after selection */ if(p1 > f->p1){ frdrawsel0(f, frptofchar(f, f->p1), f->p1, p1, f->cols[BACK], f->cols[TEXT]); p1 = f->p1; } /* inside selection */ frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]); }
static void setsel(Win *w, int p0, int p1) { frdrawsel(&w->fr, frptofchar(&w->fr, w->fr.p0), w->fr.p0, w->fr.p1, 0); w->fr.p0 = p0; w->fr.p1 = p1; frdrawsel(&w->fr, frptofchar(&w->fr, p0), p0, p1, 1); }
void textsetselect(Text *t, uint q0, uint q1) { int p0, p1, ticked; /* t->fr.p0 and t->fr.p1 are always right; t->q0 and t->q1 may be off */ t->q0 = q0; t->q1 = q1; /* compute desired p0,p1 from q0,q1 */ p0 = q0-t->org; p1 = q1-t->org; ticked = 1; if(p0 < 0){ ticked = 0; p0 = 0; } if(p1 < 0) p1 = 0; if(p0 > t->fr.nchars) p0 = t->fr.nchars; if(p1 > t->fr.nchars){ ticked = 0; p1 = t->fr.nchars; } if(p0==t->fr.p0 && p1==t->fr.p1){ if(p0 == p1 && ticked != t->fr.ticked) frtick(&t->fr, frptofchar(&t->fr, p0), ticked); return; } if(p0 > p1) sysfatal("acme: textsetselect p0=%d p1=%d q0=%ud q1=%ud t->org=%d nchars=%d", p0, p1, q0, q1, (int)t->org, (int)t->fr.nchars); /* screen disagrees with desired selection */ if(t->fr.p1<=p0 || p1<=t->fr.p0 || p0==p1 || t->fr.p1==t->fr.p0){ /* no overlap or too easy to bother trying */ frdrawsel(&t->fr, frptofchar(&t->fr, t->fr.p0), t->fr.p0, t->fr.p1, 0); if(p0 != p1 || ticked) frdrawsel(&t->fr, frptofchar(&t->fr, p0), p0, p1, 1); goto Return; } /* overlap; avoid unnecessary painting */ if(p0 < t->fr.p0){ /* extend selection backwards */ frdrawsel(&t->fr, frptofchar(&t->fr, p0), p0, t->fr.p0, 1); }else if(p0 > t->fr.p0){ /* trim first part of selection */ frdrawsel(&t->fr, frptofchar(&t->fr, t->fr.p0), t->fr.p0, p0, 0); } if(p1 > t->fr.p1){ /* extend selection forwards */ frdrawsel(&t->fr, frptofchar(&t->fr, t->fr.p1), t->fr.p1, p1, 1); }else if(p1 < t->fr.p1){ /* trim last part of selection */ frdrawsel(&t->fr, frptofchar(&t->fr, p1), p1, t->fr.p1, 0); } Return: t->fr.p0 = p0; t->fr.p1 = p1; }
void frredraw(Frame *f) { int ticked; Point pt; if(f->p0 == f->p1) { ticked = f->ticked; if(ticked) frtick(f, frptofchar(f, f->p0), 0); frdrawsel0(f, frptofchar(f, 0), 0, f->nchars, f->cols[BACK], f->cols[TEXT]); if(ticked) frtick(f, frptofchar(f, f->p0), 1); return; } pt = frptofchar(f, 0); pt = frdrawsel0(f, pt, 0, f->p0, f->cols[BACK], f->cols[TEXT]); pt = frdrawsel0(f, pt, f->p0, f->p1, f->cols[HIGH], f->cols[HTEXT]); pt = frdrawsel0(f, pt, f->p1, f->nchars, f->cols[BACK], f->cols[TEXT]); }
void textsetselect(Text *t, uint q0, uint q1) { int p0, p1; /* t->p0 and t->p1 are always right; t->q0 and t->q1 may be off */ t->q0 = q0; t->q1 = q1; /* compute desired p0,p1 from q0,q1 */ p0 = q0-t->org; p1 = q1-t->org; if(p0 < 0) p0 = 0; if(p1 < 0) p1 = 0; if(p0 > t->nchars) p0 = t->nchars; if(p1 > t->nchars) p1 = t->nchars; if(p0==t->p0 && p1==t->p1) return; /* screen disagrees with desired selection */ if(t->p1<=p0 || p1<=t->p0 || p0==p1 || t->p1==t->p0){ /* no overlap or too easy to bother trying */ frdrawsel(t, frptofchar(t, t->p0), t->p0, t->p1, 0); frdrawsel(t, frptofchar(t, p0), p0, p1, 1); goto Return; } /* overlap; avoid unnecessary painting */ if(p0 < t->p0){ /* extend selection backwards */ frdrawsel(t, frptofchar(t, p0), p0, t->p0, 1); }else if(p0 > t->p0){ /* trim first part of selection */ frdrawsel(t, frptofchar(t, t->p0), t->p0, p0, 0); } if(p1 > t->p1){ /* extend selection forwards */ frdrawsel(t, frptofchar(t, t->p1), t->p1, p1, 1); }else if(p1 < t->p1){ /* trim last part of selection */ frdrawsel(t, frptofchar(t, p1), p1, t->p1, 0); } Return: t->p0 = p0; t->p1 = p1; }
void textsetorigin(Text *t, uint org, int exact) { int i, a, fixup; Rune *r; uint n; if(org>0 && !exact){ /* org is an estimate of the char posn; find a newline */ /* don't try harder than 256 chars */ for(i=0; i<256 && org<t->file->nc; i++){ if(textreadc(t, org) == '\n'){ org++; break; } org++; } } a = org-t->org; fixup = 0; if(a>=0 && a<t->nchars){ frdelete(t, 0, a); fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */ } else if(a<0 && -a<t->nchars){ n = t->org - org; r = runemalloc(n); bufread(t->file, org, r, n); frinsert(t, r, r+n, 0); free(r); }else frdelete(t, 0, t->nchars); t->org = org; textfill(t); textscrdraw(t); textsetselect(t, t->q0, t->q1); if(fixup && t->p1 > t->p0) frdrawsel(t, frptofchar(t, t->p1-1), t->p1-1, t->p1, 1); }
void frdrawsel(Frame *f, Point pt, uint32_t p0, uint32_t p1, int issel) { Image *back, *text; if(f->ticked) frtick(f, frptofchar(f, f->p0), 0); if(p0 == p1) { frtick(f, pt, issel); return; } if(issel) { back = f->cols[HIGH]; text = f->cols[HTEXT]; } else { back = f->cols[BACK]; text = f->cols[TEXT]; } frdrawsel0(f, pt, p0, p1, back, text); }
uint xselect(Frame *f, Mousectl *mc, Image *col, uint *p1p) /* when called, button is down */ { uint p0, p1, q, tmp; ulong msec; Point mp, pt0, pt1, qt; int reg, b; mp = mc->xy; b = mc->buttons; msec = mc->msec; /* remove tick */ if(f->p0 == f->p1) frtick(f, frptofchar(f, f->p0), 0); p0 = p1 = frcharofpt(f, mp); pt0 = frptofchar(f, p0); pt1 = frptofchar(f, p1); reg = 0; frtick(f, pt0, 1); do{ q = frcharofpt(f, mc->xy); if(p1 != q){ if(p0 == p1) frtick(f, pt0, 0); if(reg != region(q, p0)){ /* crossed starting point; reset */ if(reg > 0) selrestore(f, pt0, p0, p1); else if(reg < 0) selrestore(f, pt1, p1, p0); p1 = p0; pt1 = pt0; reg = region(q, p0); if(reg == 0) frdrawsel0(f, pt0, p0, p1, col, display->white); } qt = frptofchar(f, q); if(reg > 0){ if(q > p1) frdrawsel0(f, pt1, p1, q, col, display->white); else if(q < p1) selrestore(f, qt, q, p1); }else if(reg < 0){ if(q > p1) selrestore(f, pt1, p1, q); else frdrawsel0(f, qt, q, p1, col, display->white); } p1 = q; pt1 = qt; } if(p0 == p1) frtick(f, pt0, 1); flushimage(f->display, 1); readmouse(mc); }while(mc->buttons == b); if(mc->msec-msec < DELAY && p0!=p1 && abs(mp.x-mc->xy.x)<MINMOVE && abs(mp.y-mc->xy.y)<MINMOVE) { if(reg > 0) selrestore(f, pt0, p0, p1); else if(reg < 0) selrestore(f, pt1, p1, p0); p1 = p0; } if(p1 < p0){ tmp = p0; p0 = p1; p1 = tmp; } pt0 = frptofchar(f, p0); if(p0 == p1) frtick(f, pt0, 0); selrestore(f, pt0, p0, p1); /* restore tick */ if(f->p0 == f->p1) frtick(f, frptofchar(f, f->p0), 1); flushimage(f->display, 1); *p1p = p1; return p0; }
void look3(Text *t, uint q0, uint q1, int external) { int n, c, f, expanded; Text *ct; Expand e; Rune *r; uint p; Plumbmsg *m; Runestr dir; char buf[32]; ct = seltext; if(ct == nil) seltext = t; expanded = expand(t, q0, q1, &e); if(!external && t->w!=nil && t->w->nopen[QWevent]>0){ /* send alphanumeric expansion to external client */ if(expanded == FALSE) return; f = 0; if((e.u.at!=nil && t->w!=nil) || (e.nname>0 && lookfile(e.name, e.nname)!=nil)) f = 1; /* acme can do it without loading a file */ if(q0!=e.q0 || q1!=e.q1) f |= 2; /* second (post-expand) message follows */ if(e.nname) f |= 4; /* it's a file name */ c = 'l'; if(t->what == Body) c = 'L'; n = q1-q0; if(n <= EVENTSIZE){ r = runemalloc(n); bufread(&t->file->b, q0, r, n); winevent(t->w, "%c%d %d %d %d %.*S\n", c, q0, q1, f, n, n, r); free(r); }else winevent(t->w, "%c%d %d %d 0 \n", c, q0, q1, f, n); if(q0==e.q0 && q1==e.q1) return; if(e.nname){ n = e.nname; if(e.a1 > e.a0) n += 1+(e.a1-e.a0); r = runemalloc(n); runemove(r, e.name, e.nname); if(e.a1 > e.a0){ r[e.nname] = ':'; bufread(&e.u.at->file->b, e.a0, r+e.nname+1, e.a1-e.a0); } }else{ n = e.q1 - e.q0; r = runemalloc(n); bufread(&t->file->b, e.q0, r, n); } f &= ~2; if(n <= EVENTSIZE) winevent(t->w, "%c%d %d %d %d %.*S\n", c, e.q0, e.q1, f, n, n, r); else winevent(t->w, "%c%d %d %d 0 \n", c, e.q0, e.q1, f, n); free(r); goto Return; } if(plumbsendfid != nil){ /* send whitespace-delimited word to plumber */ m = emalloc(sizeof(Plumbmsg)); m->src = estrdup("acme"); m->dst = nil; dir = dirname(t, nil, 0); if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */ free(dir.r); dir.r = nil; dir.nr = 0; } if(dir.nr == 0) m->wdir = estrdup(wdir); else m->wdir = runetobyte(dir.r, dir.nr); free(dir.r); m->type = estrdup("text"); m->attr = nil; buf[0] = '\0'; if(q1 == q0){ if(t->q1>t->q0 && t->q0<=q0 && q0<=t->q1){ q0 = t->q0; q1 = t->q1; }else{ p = q0; while(q0>0 && (c=tgetc(t, q0-1))!=' ' && c!='\t' && c!='\n') q0--; while(q1<t->file->b.nc && (c=tgetc(t, q1))!=' ' && c!='\t' && c!='\n') q1++; if(q1 == q0){ plumbfree(m); goto Return; } sprint(buf, "click=%d", p-q0); m->attr = plumbunpackattr(buf); } } r = runemalloc(q1-q0); bufread(&t->file->b, q0, r, q1-q0); m->data = runetobyte(r, q1-q0); m->ndata = strlen(m->data); free(r); if(m->ndata<messagesize-1024 && plumbsendtofid(plumbsendfid, m) >= 0){ plumbfree(m); goto Return; } plumbfree(m); /* plumber failed to match; fall through */ } /* interpret alphanumeric string ourselves */ if(expanded == FALSE) return; if(e.name || e.u.at) openfile(t, &e); else{ if(t->w == nil) return; ct = &t->w->body; if(t->w != ct->w) winlock(ct->w, 'M'); if(t == ct) textsetselect(ct, e.q1, e.q1); n = e.q1 - e.q0; r = runemalloc(n); bufread(&t->file->b, e.q0, r, n); if(search(ct, r, n) && e.jump) moveto(mousectl, addpt(frptofchar(&ct->fr, ct->fr.p0), Pt(4, ct->fr.font->height-4))); if(t->w != ct->w) winunlock(ct->w); free(r); } Return: free(e.name); free(e.bname); }
Window* openfile(Text *t, Expand *e) { Range r; Window *w, *ow; int eval, i, n; Rune *rp; Runestr rs; uint dummy; r.q0 = 0; r.q1 = 0; if(e->nname == 0){ w = t->w; if(w == nil) return nil; }else{ w = lookfile(e->name, e->nname); if(w == nil && e->name[0] != '/'){ /* * Unrooted path in new window. * This can happen if we type a pwd-relative path * in the topmost tag or the column tags. * Most of the time plumber takes care of these, * but plumber might not be running or might not * be configured to accept plumbed directories. * Make the name a full path, just like we would if * opening via the plumber. */ n = utflen(wdir)+1+e->nname+1; rp = runemalloc(n); runesnprint(rp, n, "%s/%.*S", wdir, e->nname, e->name); rs = cleanrname(runestr(rp, n-1)); free(e->name); e->name = rs.r; e->nname = rs.nr; w = lookfile(e->name, e->nname); } } if(w){ t = &w->body; if(!t->col->safe && t->fr.maxlines==0) /* window is obscured by full-column window */ colgrow(t->col, t->col->w[0], 1); }else{ ow = nil; if(t) ow = t->w; w = makenewwindow(t); t = &w->body; winsetname(w, e->name, e->nname); if(textload(t, 0, e->bname, 1) >= 0) t->file->unread = FALSE; t->file->mod = FALSE; t->w->dirty = FALSE; winsettag(t->w); textsetselect(&t->w->tag, t->w->tag.file->b.nc, t->w->tag.file->b.nc); if(ow != nil){ for(i=ow->nincl; --i>=0; ){ n = runestrlen(ow->incl[i]); rp = runemalloc(n); runemove(rp, ow->incl[i], n); winaddincl(w, rp, n); } w->autoindent = ow->autoindent; }else w->autoindent = globalautoindent; xfidlog(w, "new"); } if(e->a1 == e->a0) eval = FALSE; else{ eval = TRUE; r = address(TRUE, t, range(-1,-1), range(t->q0, t->q1), e->u.at, e->a0, e->a1, e->agetc, &eval, &dummy); if(r.q0 > r.q1) { eval = FALSE; warning(nil, "addresses out of order\n"); } if(eval == FALSE) e->jump = FALSE; /* don't jump if invalid address */ } if(eval == FALSE){ r.q0 = t->q0; r.q1 = t->q1; } textshow(t, r.q0, r.q1, 1); winsettag(t->w); seltext = t; if(e->jump) moveto(mousectl, addpt(frptofchar(&t->fr, t->fr.p0), Pt(4, font->height-4))); return w; }