ref: 5bd859efaf555b67c61b4eeda9caa6444e54353d
parent: 1d405a3895019c8599038e7fcef7f315a7d6a72b
author: demyxology <spicycoldnoodles@gmail.com>
date: Sun Jan 19 10:37:08 EST 2025
* Added Evil Button to toggle updown scrolling * Made scrolling behave like rio * Experimental line numbering
--- a/acme.c
+++ b/acme.c
@@ -521,15 +521,16 @@
}
/* scroll buttons, wheels, etc. */
if(t->what==Body && w != nil && (m.buttons & (8|16))){
- if(m.buttons & 8)
- but = Kscrolloneup;
- else
- but = Kscrollonedown;
- winlock(w, 'M');
- t->eq0 = ~0;
- texttype(t, but);
- winunlock(w);
- goto Continue;
+ winlock(w, 'M');
+ t->eq0 = ~0;
+ if(m.buttons & 8)
+ textscroll(t, 4);
+ else
+ textscroll(t, 5);
+ if(t->w->showlines)
+ textredraw(t, t->r, t->font, t->b, Dx(t->all));
+ winunlock(w);
+ goto Continue;
}
if(ptinrect(m.xy, t->scrollr)){
if(but){
--- a/dat.h
+++ b/dat.h
@@ -243,8 +243,10 @@
uchar isscratch;
uchar filemenu;
uchar dirty;
+ uchar evil;
uchar indent[NINDENT];
uchar showdel;
+ uchar showlines;
int id;
Range addr;
Range limit;
--- a/exec.c
+++ b/exec.c
@@ -33,6 +33,7 @@
void delcol(Text*, Text*, Text*, int, int, Rune*, int);
void dump(Text*, Text*, Text*, int, int, Rune*, int);
void edit(Text*, Text*, Text*, int, int, Rune*, int);
+void evil(Text*, Text*, Text*, int, int, Rune*, int);
void exit(Text*, Text*, Text*, int, int, Rune*, int);
void fontx(Text*, Text*, Text*, int, int, Rune*, int);
void get(Text*, Text*, Text*, int, int, Rune*, int);
@@ -40,6 +41,7 @@
void incl(Text*, Text*, Text*, int, int, Rune*, int);
void indent(Text*, Text*, Text*, int, int, Rune*, int);
void kill(Text*, Text*, Text*, int, int, Rune*, int);
+void xline(Text*, Text*, Text*, int, int, Rune*, int); /* line() is taken by libdraw */
void local(Text*, Text*, Text*, int, int, Rune*, int);
void look(Text*, Text*, Text*, int, int, Rune*, int);
void newcol(Text*, Text*, Text*, int, int, Rune*, int);
@@ -68,6 +70,7 @@
{ L"Delete", del, FALSE, TRUE, XXX },
{ L"Dump", dump, FALSE, TRUE, XXX },
{ L"Edit", edit, FALSE, XXX, XXX },
+ { L"Evil", evil, FALSE, XXX, XXX },
{ L"Exit", exit, FALSE, XXX, XXX },
{ L"Font", fontx, FALSE, XXX, XXX },
{ L"Get", get, FALSE, TRUE, XXX },
@@ -75,6 +78,7 @@
{ L"Incl", incl, FALSE, XXX, XXX },
{ L"Indent", indent, FALSE, AUTOINDENT, XXX },
{ L"Kill", kill, FALSE, XXX, XXX },
+ { L"Line", xline, FALSE, XXX, XXX },
{ L"Load", dump, FALSE, FALSE, XXX },
{ L"Local", local, FALSE, XXX, XXX },
{ L"Look", look, FALSE, XXX, XXX },
@@ -93,6 +97,30 @@
{ L"Zerox", zeroxx, FALSE, XXX, XXX },
{ nil, nil, 0, 0, 0 },
};
+
+void
+xline(Text *et, Text*, Text*, int, int, Rune*, int)
+{
+ Window *w;
+ if(et == nil || et->w == nil)
+ return;
+
+ w = et->w;
+ w->showlines = !w->showlines;
+ winresize(w, w->r, FALSE, TRUE);
+}
+
+void
+evil(Text *et, Text*, Text*, int, int, Rune*, int)
+{
+ Window *w;
+ if(et == nil || et->w == nil)
+ return;
+
+ w = et->w;
+ w->evil = !w->evil;
+ winresize(w, w->r, FALSE, TRUE);
+}
Exectab*
lookup(Rune *r, int n)
--- a/mkfile
+++ b/mkfile
@@ -30,11 +30,6 @@
edit.h\
fns.h\
-UPDATE=\
- mkfile\
- $HFILES\
- ${OFILES:%.$O=%.c}\
-
</sys/src/cmd/mkone
$O.out: /$objtype/lib/libframe.a /$objtype/lib/libdraw.a /$objtype/lib/libthread.a
--- a/scrl.c
+++ b/scrl.c
@@ -105,7 +105,7 @@
return;
}
}
-/*
+
void
textscroll(Text *t, int but)
{
@@ -126,77 +126,29 @@
my = s.max.y;
if(but == 2){
y = my;
- p0 = (vlong)t->file->nc*(y-s.min.y)/h;
- if(p0 >= t->q1)
- p0 = textbacknl(t, p0, 2);
- if(oldp0 != p0)
- textsetorigin(t, p0, FALSE);
- oldp0 = p0;
- readmouse(mousectl);
- continue;
- }
- if(but == 1)
- p0 = textbacknl(t, t->org, (my-s.min.y)/t->font->height);
- else
- p0 = t->org+frcharofpt(t, Pt(s.max.x, my));
- if(oldp0 != p0)
- textsetorigin(t, p0, TRUE);
- oldp0 = p0;
- //debounce
- if(first){
- flushimage(display, 1);
- sleep(200);
- nbrecv(mousectl->c, &mousectl->Mouse);
- first = FALSE;
- }
- scrsleep(80);
- }while(mouse->buttons & (1<<(but-1)));
- while(mouse->buttons)
- readmouse(mousectl);
-} */
-
-void
-textscroll(Text *w, int but)
-{
- uint p0, oldp0;
- Rectangle s;
- int y, my, h, first;
-
- s = insetrect(w->scrollr, 1);
- h = s.max.y-s.min.y;
- oldp0 = ~0;
- first = TRUE;
- do{
- my = mouse->xy.y;
- if(my < s.min.y)
- my = s.min.y;
- if(my >= s.max.y)
- my = s.max.y;
- if(but == 2){
- y = my;
if(y > s.max.y-2)
y = s.max.y-2;
- if(w->file->nc > 1024*1024)
- p0 = ((w->file->nc>>10)*(y-s.min.y)/h)<<10;
+ if(t->file->nc > 1024*1024)
+ p0 = ((t->file->nc>>10)*(y-s.min.y)/h)<<10;
else
- p0 = w->file->nc*(y-s.min.y)/h;
+ p0 = t->file->nc*(y-s.min.y)/h;
if(oldp0 != p0)
- textsetorigin(w, p0, FALSE);
+ textsetorigin(t, p0, FALSE);
oldp0 = p0;
readmouse(mousectl);
continue;
}
if(but == 1 || but == 4){
- y = max(1, (my-s.min.y)/w->font->height);
- p0 = textbacknl(w, w->org, y);
+ y = max(1, (my-s.min.y)/t->font->height);
+ p0 = textbacknl(t, t->org, y);
}else{
- y = max(my, s.min.y+w->font->height);
- p0 = w->org+frcharofpt(w, Pt(s.max.x, y));
+ y = max(my, s.min.y+t->font->height);
+ p0 = t->org+frcharofpt(t, Pt(s.max.x, y));
}
if(oldp0 != p0)
- textsetorigin(w, p0, TRUE);
+ textsetorigin(t, p0, TRUE);
oldp0 = p0;
- /* debounce */
+ //debounce
if(first){
if(display->bufp > display->buf)
flushimage(display, 1);
@@ -206,8 +158,9 @@
nbrecv(mousectl->c, &mousectl->Mouse);
first = FALSE;
}
- scrsleep(100);
+ scrsleep(80);
}while(mouse->buttons & (1<<(but-1)));
while(mouse->buttons)
readmouse(mousectl);
+
}
\ No newline at end of file
--- a/text.c
+++ b/text.c
@@ -39,10 +39,33 @@
void
textredraw(Text *t, Rectangle r, Font *f, Image *b, int odx)
{
- int maxt;
- Rectangle rr;
+ int maxt, y, ln, nw, maxl;
+ char nums[12];
+ Rectangle rr, lr;
+ nw = stringwidth(f, "000000 ");
+
frinit(t, r, f, b, t->Frame.cols);
+
+ /* TODO: Fix drawing, make numbers selectable */
+ if(t->w && t->w->showlines && t->what == Body){
+ lr = t->r;
+ lr.min.x = t->r.min.x - (nw + Scrollwid + Scrollgap);
+ //lr.max.x = t->r.min.x - Scrollwid+Scrollgap;
+ draw(t->b, lr, t->cols[BACK], nil, ZP);
+
+ y = lr.min.y;
+ ln = nlcount(t, 0, t->org, nil) + 1;
+ maxl = nlcount(t, 0, t->file->nc, nil) + 1;
+ while(y < lr.max.y && ln < maxl && ln < 999999){
+ snprint(nums, sizeof(nums), "%6d", ln++);
+ string(b, Pt(lr.min.x, y),
+ t->cols[TEXT], ZP, f, nums);
+ y += f->height;
+ }
+
+ }
+
rr = t->r;
rr.min.x -= Scrollwid+Scrollgap; /* back fill to scroll bar */
draw(t->b, rr, t->cols[BACK], nil, ZP);
@@ -689,25 +712,28 @@
textshow(t, t->q1+1, t->q1+1, TRUE);
return;
case Kdown:
- //n = t->maxlines/3;
- //goto case_Down;
- typecommit(t);
- q0 = t->q0;
- lp = 0;
- /* title bar & rc place the cursor past the end of the "file",
- so we have to re-align it. */
- if(q0 >= t->file->nc) q0 = t->file->nc - 1;
- if(q0 > 0 && textreadc(t, q0) == '\n'){ q0--; lp++; }
- while(q0 > 0 && textreadc(t, q0) != '\n'){ q0--; lp++; }
- if(q0 == 0) lp++;
- q0 = t->q0;
- while(q0<t->file->nc && textreadc(t, q0)!='\n') q0++;
- q0++;
- q1 = q0;
- while(q0<t->file->nc && textreadc(t, q0)!='\n' && q0 < q1+lp-1) q0++;
- q0 = (q0 >= t->file->nc) ? t->file->nc - 1 : q0;
- textshow(t, q0, q0, TRUE);
- return;
+ if(t->w->evil){
+ typecommit(t);
+ q0 = t->q0;
+ lp = 0;
+ /* title bar & win place the cursor past the end of the "file",
+ so we have to re-align it. */
+ if(q0 >= t->file->nc) q0 = t->file->nc - 1;
+ if(q0 > 0 && textreadc(t, q0) == '\n'){ q0--; lp++; }
+ while(q0 > 0 && textreadc(t, q0) != '\n'){ q0--; lp++; }
+ if(q0 == 0) lp++;
+ q0 = t->q0;
+ while(q0<t->file->nc && textreadc(t, q0)!='\n') q0++;
+ q0++;
+ q1 = q0;
+ while(q0<t->file->nc && textreadc(t, q0)!='\n' && q0 < q1+lp-1) q0++;
+ q0 = (q0 >= t->file->nc) ? t->file->nc - 1 : q0;
+ textshow(t, q0, q0, TRUE);
+ return;
+ } else {
+ n = t->maxlines/3;
+ goto case_Down;
+ }
case Kscrollonedown:
n = mousescrollsize(t->maxlines);
if(n <= 0)
@@ -721,25 +747,28 @@
textsetorigin(t, q0, TRUE);
return;
case Kup:
- //n = t->maxlines/3;
- //goto case_Up;
- typecommit(t);
- q0 = t->q0;
- lp = 0;
- if(q0 >= t->file->nc) q0 = t->file->nc - 1;
- if(q0 > 0 && textreadc(t, q0) == '\n') q0--;
- while(q0 > 0 && textreadc(t, q0) != '\n') { q0--; lp++; }
- if(q0 == 0) {
- textshow(t, q0, q0, TRUE);
- return;
+ if(t->w->evil){
+ typecommit(t);
+ q0 = t->q0;
+ lp = 0;
+ if(q0 >= t->file->nc) q0 = t->file->nc - 1;
+ if(q0 > 0 && textreadc(t, q0) == '\n') q0--;
+ while(q0 > 0 && textreadc(t, q0) != '\n') { q0--; lp++; }
+ if(q0 == 0) {
+ textshow(t, q0, q0, TRUE);
+ return;
+ }
+ q0--;
+ while(q0 > 0 && textreadc(t, q0) != '\n') q0--;
+ if(q0 != 0) q0++;
+ q1 = q0; /* q1 keeps the start of the line, lp will be offset from it */
+ while(q0 < t->file->nc && textreadc(t, q0) != '\n' && q0 < q1 + lp - 1) q0++;
+ textshow(t, q0, q0, TRUE);
+ return;
+ } else {
+ n = t->maxlines/3;
+ goto case_Up;
}
- q0--;
- while(q0 > 0 && textreadc(t, q0) != '\n') q0--;
- if(q0 != 0) q0++;
- q1 = q0; /* q1 keeps the start of the line, lp will be offset from it */
- while(q0 < t->file->nc && textreadc(t, q0) != '\n' && q0 < q1 + lp - 1) q0++;
- textshow(t, q0, q0, TRUE);
- return;
case Kscrolloneup:
n = mousescrollsize(t->maxlines);
goto case_Up;
--- a/text.c.bak
+++ /dev/null
@@ -1,1518 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <fcall.h>
-#include <plumb.h>
-#include <complete.h>
-#include "dat.h"
-#include "fns.h"
-
-Image *tagcols[NCOL];
-Image *textcols[NCOL];
-
-enum{
- TABDIR = 3 /* width of tabs in directory windows */
-};
-
-void
-textinit(Text *t, File *f, Rectangle r, Reffont *rf, Image *cols[NCOL])
-{
- t->file = f;
- t->all = r;
- t->scrollr = r;
- t->scrollr.max.x = r.min.x+Scrollwid;
- t->lastsr = nullrect;
- r.min.x += Scrollwid+Scrollgap;
- t->eq0 = ~0;
- t->ncache = 0;
- t->reffont = rf;
- t->tabstop = maxtab;
- memmove(t->Frame.cols, cols, sizeof t->Frame.cols);
- textredraw(t, r, rf->f, screen, -1);
-}
-
-void
-textredraw(Text *t, Rectangle r, Font *f, Image *b, int odx)
-{
- int maxt;
- Rectangle rr;
-
- frinit(t, r, f, b, t->Frame.cols);
- rr = t->r;
- rr.min.x -= Scrollwid+Scrollgap; /* back fill to scroll bar */
- draw(t->b, rr, t->cols[BACK], nil, ZP);
- /* use no wider than 3-space tabs in a directory */
- maxt = maxtab;
- if(t->what == Body){
- if(t->w->isdir)
- maxt = min(TABDIR, maxtab);
- else
- maxt = t->tabstop;
- }
- t->maxtab = maxt*stringwidth(f, "0");
- if(t->what==Body && t->w->isdir && odx!=Dx(t->all)){
- if(t->maxlines > 0){
- textreset(t);
- textcolumnate(t, t->w->dlp, t->w->ndl);
- textshow(t, 0, 0, 1);
- }
- }else{
- textfill(t);
- textsetselect(t, t->q0, t->q1);
- }
-}
-
-int
-textresize(Text *t, Rectangle r, int fillfringe)
-{
- int odx;
-
- if(Dy(r) <= 0)
- r.max.y = r.min.y;
- else if(!fillfringe)
- r.max.y -= Dy(r)%t->font->height;
- odx = Dx(t->all);
- t->all = r;
- t->scrollr = r;
- t->scrollr.max.x = r.min.x+Scrollwid;
- t->lastsr = nullrect;
- r.min.x += Scrollwid+Scrollgap;
- frclear(t, 0);
- textredraw(t, r, t->font, t->b, odx);
- if(fillfringe && t->r.max.y < t->all.max.y){
- /* draw background in bottom fringe of text window */
- r.min.x -= Scrollgap;
- r.min.y = t->r.max.y;
- r.max.y = t->all.max.y;
- draw(screen, r, t->cols[BACK], nil, ZP);
- }
- return t->all.max.y;
-}
-
-void
-textclose(Text *t)
-{
- free(t->cache);
- frclear(t, 1);
- filedeltext(t->file, t);
- t->file = nil;
- rfclose(t->reffont);
- if(argtext == t)
- argtext = nil;
- if(typetext == t)
- typetext = nil;
- if(seltext == t)
- seltext = nil;
- if(mousetext == t)
- mousetext = nil;
- if(barttext == t)
- barttext = nil;
-}
-
-int
-dircmp(void *a, void *b)
-{
- Dirlist *da, *db;
- int i, n;
-
- da = *(Dirlist**)a;
- db = *(Dirlist**)b;
- n = min(da->nr, db->nr);
- i = memcmp(da->r, db->r, n*sizeof(Rune));
- if(i)
- return i;
- return da->nr - db->nr;
-}
-
-void
-textcolumnate(Text *t, Dirlist **dlp, int ndl)
-{
- int i, j, w, colw, mint, maxt, ncol, nrow;
- Dirlist *dl;
- uint q1;
-
- if(t->file->ntext > 1)
- return;
- mint = stringwidth(t->font, "0");
- /* go for narrower tabs if set more than 3 wide */
- t->maxtab = min(maxtab, TABDIR)*mint;
- maxt = t->maxtab;
- colw = 0;
- for(i=0; i<ndl; i++){
- dl = dlp[i];
- w = dl->wid;
- if(maxt-w%maxt < mint || w%maxt==0)
- w += mint;
- if(w % maxt)
- w += maxt-(w%maxt);
- if(w > colw)
- colw = w;
- }
- if(colw == 0)
- ncol = 1;
- else
- ncol = max(1, Dx(t->r)/colw);
- nrow = (ndl+ncol-1)/ncol;
-
- q1 = 0;
- for(i=0; i<nrow; i++){
- for(j=i; j<ndl; j+=nrow){
- dl = dlp[j];
- fileinsert(t->file, q1, dl->r, dl->nr);
- q1 += dl->nr;
- if(j+nrow >= ndl)
- break;
- w = dl->wid;
- if(maxt-w%maxt < mint){
- fileinsert(t->file, q1, L"\t", 1);
- q1++;
- w += mint;
- }
- do{
- fileinsert(t->file, q1, L"\t", 1);
- q1++;
- w += maxt-(w%maxt);
- }while(w < colw);
- }
- fileinsert(t->file, q1, L"\n", 1);
- q1++;
- }
-}
-
-uint
-textload(Text *t, uint q0, char *file, int setqid)
-{
- Rune *rp;
- Dirlist *dl, **dlp;
- int fd, i, j, n, ndl, nulls;
- uint q, q1;
- Dir *d, *dbuf;
- char *tmp;
- Text *u;
-
- if(t->ncache!=0 || t->file->nc || t->w==nil || t!=&t->w->body)
- error("text.load");
- if(t->w->isdir && t->file->nname==0){
- warning(nil, "empty directory name\n");
- return 0;
- }
- fd = open(file, OREAD);
- if(fd < 0){
- warning(nil, "can't open %s: %r\n", file);
- return 0;
- }
- d = dirfstat(fd);
- if(d == nil){
- warning(nil, "can't fstat %s: %r\n", file);
- goto Rescue;
- }
- nulls = FALSE;
- if(d->qid.type & QTDIR){
- /* this is checked in get() but it's possible the file changed underfoot */
- if(t->file->ntext > 1){
- warning(nil, "%s is a directory; can't read with multiple windows on it\n", file);
- goto Rescue;
- }
- t->w->isdir = TRUE;
- t->w->filemenu = FALSE;
- if(t->file->nname > 0 && t->file->name[t->file->nname-1] != '/'){
- rp = runemalloc(t->file->nname+1);
- runemove(rp, t->file->name, t->file->nname);
- rp[t->file->nname] = '/';
- winsetname(t->w, rp, t->file->nname+1);
- free(rp);
- }
- dlp = nil;
- ndl = 0;
- dbuf = nil;
- while((n=dirread(fd, &dbuf)) > 0){
- for(i=0; i<n; i++){
- dl = emalloc(sizeof(Dirlist));
- j = strlen(dbuf[i].name);
- tmp = emalloc(j+1+1);
- memmove(tmp, dbuf[i].name, j);
- if(dbuf[i].qid.type & QTDIR)
- tmp[j++] = '/';
- tmp[j] = '\0';
- dl->r = bytetorune(tmp, &dl->nr);
- dl->wid = stringwidth(t->font, tmp);
- free(tmp);
- ndl++;
- dlp = realloc(dlp, ndl*sizeof(Dirlist*));
- dlp[ndl-1] = dl;
- }
- free(dbuf);
- }
- qsort(dlp, ndl, sizeof(Dirlist*), dircmp);
- t->w->dlp = dlp;
- t->w->ndl = ndl;
- textcolumnate(t, dlp, ndl);
- q1 = t->file->nc;
- }else{
- t->w->isdir = FALSE;
- t->w->filemenu = TRUE;
- q1 = q0 + fileload(t->file, q0, fd, &nulls);
- }
- if(setqid){
- t->file->dev = d->dev;
- t->file->mtime = d->mtime;
- t->file->qidpath = d->qid.path;
- }
- close(fd);
- rp = fbufalloc();
- for(q=q0; q<q1; q+=n){
- n = q1-q;
- if(n > RBUFSIZE)
- n = RBUFSIZE;
- bufread(t->file, q, rp, n);
- if(q < t->org)
- t->org += n;
- else if(q <= t->org+t->nchars)
- frinsert(t, rp, rp+n, q-t->org);
- if(t->lastlinefull)
- break;
- }
- fbuffree(rp);
- for(i=0; i<t->file->ntext; i++){
- u = t->file->text[i];
- if(u != t){
- if(u->org > u->file->nc) /* will be 0 because of reset(), but safety first */
- u->org = 0;
- textresize(u, u->all, TRUE);
- textbacknl(u, u->org, 0); /* go to beginning of line */
- }
- textsetselect(u, q0, q0);
- }
- if(nulls)
- warning(nil, "%s: NUL bytes elided\n", file);
- free(d);
- return q1-q0;
-
- Rescue:
- close(fd);
- return 0;
-}
-
-uint
-textbsinsert(Text *t, uint q0, Rune *r, uint n, int tofile, int *nrp)
-{
- Rune *bp, *tp, *up;
- int i, initial;
-
- if(t->what == Tag){ /* can't happen but safety first: mustn't backspace over file name */
- Err:
- textinsert(t, q0, r, n, tofile);
- *nrp = n;
- return q0;
- }
- bp = r;
- for(i=0; i<n; i++)
- if(*bp++ == '\b'){
- --bp;
- initial = 0;
- tp = runemalloc(n);
- runemove(tp, r, i);
- up = tp+i;
- for(; i<n; i++){
- *up = *bp++;
- if(*up == '\b')
- if(up == tp)
- initial++;
- else
- --up;
- else
- up++;
- }
- if(initial){
- if(initial > q0)
- initial = q0;
- q0 -= initial;
- textdelete(t, q0, q0+initial, tofile);
- }
- n = up-tp;
- textinsert(t, q0, tp, n, tofile);
- free(tp);
- *nrp = n;
- return q0;
- }
- goto Err;
-}
-
-void
-textinsert(Text *t, uint q0, Rune *r, uint n, int tofile)
-{
- int c, i;
- Text *u;
-
- if(tofile && t->ncache != 0)
- error("text.insert");
- if(n == 0)
- return;
- if(tofile){
- fileinsert(t->file, q0, r, n);
- if(t->what == Body){
- t->w->dirty = TRUE;
- t->w->utflastqid = -1;
- }
- if(t->file->ntext > 1)
- for(i=0; i<t->file->ntext; i++){
- u = t->file->text[i];
- if(u != t){
- u->w->dirty = TRUE; /* always a body */
- textinsert(u, q0, r, n, FALSE);
- textsetselect(u, u->q0, u->q1);
- textscrdraw(u);
- }
- }
-
- }
- if(q0 < t->q1)
- t->q1 += n;
- if(q0 < t->q0)
- t->q0 += n;
- if(q0 < t->org)
- t->org += n;
- else if(q0 <= t->org+t->nchars)
- frinsert(t, r, r+n, q0-t->org);
- if(t->w){
- c = 'i';
- if(t->what == Body)
- c = 'I';
- if(n <= EVENTSIZE)
- winevent(t->w, "%c%d %d 0 %d %.*S\n", c, q0, q0+n, n, n, r);
- else
- winevent(t->w, "%c%d %d 0 0 \n", c, q0, q0+n, n);
- }
-}
-
-void
-typecommit(Text *t)
-{
- if(t->w != nil)
- wincommit(t->w, t);
- else
- textcommit(t, TRUE);
-}
-
-void
-textfill(Text *t)
-{
- Rune *rp;
- int i, n, m, nl;
-
- if(t->lastlinefull || t->nofill)
- return;
- if(t->ncache > 0)
- typecommit(t);
- rp = fbufalloc();
- do{
- n = t->file->nc-(t->org+t->nchars);
- if(n == 0)
- break;
- if(n > 2000) /* educated guess at reasonable amount */
- n = 2000;
- bufread(t->file, t->org+t->nchars, rp, n);
- /*
- * it's expensive to frinsert more than we need, so
- * count newlines.
- */
- nl = t->maxlines-t->nlines;
- m = 0;
- for(i=0; i<n; ){
- if(rp[i++] == '\n'){
- m++;
- if(m >= nl)
- break;
- }
- }
- frinsert(t, rp, rp+i, t->nchars);
- }while(t->lastlinefull == FALSE);
- fbuffree(rp);
-}
-
-void
-textdelete(Text *t, uint q0, uint q1, int tofile)
-{
- uint n, p0, p1;
- int i, c;
- Text *u;
-
- if(tofile && t->ncache != 0)
- error("text.delete");
- n = q1-q0;
- if(n == 0)
- return;
- if(tofile){
- filedelete(t->file, q0, q1);
- if(t->what == Body){
- t->w->dirty = TRUE;
- t->w->utflastqid = -1;
- }
- if(t->file->ntext > 1)
- for(i=0; i<t->file->ntext; i++){
- u = t->file->text[i];
- if(u != t){
- u->w->dirty = TRUE; /* always a body */
- textdelete(u, q0, q1, FALSE);
- textsetselect(u, u->q0, u->q1);
- textscrdraw(u);
- }
- }
- }
- if(q0 < t->q0)
- t->q0 -= min(n, t->q0-q0);
- if(q0 < t->q1)
- t->q1 -= min(n, t->q1-q0);
- if(q1 <= t->org)
- t->org -= n;
- else if(q0 < t->org+t->nchars){
- p1 = q1 - t->org;
- if(p1 > t->nchars)
- p1 = t->nchars;
- if(q0 < t->org){
- t->org = q0;
- p0 = 0;
- }else
- p0 = q0 - t->org;
- frdelete(t, p0, p1);
- textfill(t);
- }
- if(t->w){
- c = 'd';
- if(t->what == Body)
- c = 'D';
- winevent(t->w, "%c%d %d 0 0 \n", c, q0, q1);
- }
-}
-
-void
-textconstrain(Text *t, uint q0, uint q1, uint *p0, uint *p1)
-{
- *p0 = min(q0, t->file->nc);
- *p1 = min(q1, t->file->nc);
-}
-
-Rune
-textreadc(Text *t, uint q)
-{
- Rune r;
-
- if(t->cq0<=q && q<t->cq0+t->ncache)
- r = t->cache[q-t->cq0];
- else
- bufread(t->file, q, &r, 1);
- return r;
-}
-
-static int
-spacesindentbswidth(Text *t)
-{
- uint q, col;
- Rune r;
-
- col = textbswidth(t, 0x15);
- q = t->q0;
- while(q > 0){
- r = textreadc(t, q-1);
- if(r != ' ')
- break;
- q--;
- if(--col % t->tabstop == 0)
- break;
- }
- if(t->q0 == q)
- return 1;
- return t->q0-q;
-}
-
-int
-textbswidth(Text *t, Rune c)
-{
- uint q, eq;
- Rune r;
- int skipping;
-
- /* there is known to be at least one character to erase */
- if(c == 0x08){ /* ^H: erase character */
- if(t->what == Body && t->w->indent[SPACESINDENT])
- return spacesindentbswidth(t);
- return 1;
- }
- q = t->q0;
- skipping = TRUE;
- while(q > 0){
- r = textreadc(t, q-1);
- if(r == '\n'){ /* eat at most one more character */
- if(q == t->q0) /* eat the newline */
- --q;
- break;
- }
- if(c == 0x17){
- eq = isalnum(r);
- if(eq && skipping) /* found one; stop skipping */
- skipping = FALSE;
- else if(!eq && !skipping)
- break;
- }
- --q;
- }
- return t->q0-q;
-}
-
-int
-textfilewidth(Text *t, uint q0, int oneelement)
-{
- uint q;
- Rune r;
-
- q = q0;
- while(q > 0){
- r = textreadc(t, q-1);
- if(r <= ' ')
- break;
- if(oneelement && r=='/')
- break;
- --q;
- }
- return q0-q;
-}
-
-Rune*
-textcomplete(Text *t)
-{
- int i, nstr, npath;
- uint q;
- Rune tmp[200];
- Rune *str, *path;
- Rune *rp;
- Completion *c;
- char *s, *dirs;
- Runestr dir;
-
- /* control-f: filename completion; works back to white space or / */
- if(t->q0<t->file->nc && textreadc(t, t->q0)>' ') /* must be at end of word */
- return nil;
- nstr = textfilewidth(t, t->q0, TRUE);
- str = runemalloc(nstr);
- npath = textfilewidth(t, t->q0-nstr, FALSE);
- path = runemalloc(npath);
-
- c = nil;
- rp = nil;
- dirs = nil;
-
- q = t->q0-nstr;
- for(i=0; i<nstr; i++)
- str[i] = textreadc(t, q++);
- q = t->q0-nstr-npath;
- for(i=0; i<npath; i++)
- path[i] = textreadc(t, q++);
- /* is path rooted? if not, we need to make it relative to window path */
- if(npath>0 && path[0]=='/')
- dir = (Runestr){path, npath};
- else{
- dir = dirname(t, nil, 0);
- if(dir.nr + 1 + npath > nelem(tmp)){
- free(dir.r);
- goto Return;
- }
- if(dir.nr == 0){
- dir.nr = 1;
- dir.r = runestrdup(L".");
- }
- runemove(tmp, dir.r, dir.nr);
- tmp[dir.nr] = '/';
- runemove(tmp+dir.nr+1, path, npath);
- free(dir.r);
- dir.r = tmp;
- dir.nr += 1+npath;
- dir = cleanrname(dir);
- }
-
- s = smprint("%.*S", nstr, str);
- dirs = smprint("%.*S", dir.nr, dir.r);
- c = complete(dirs, s);
- free(s);
- if(c == nil){
- warning(nil, "error attempting completion: %r\n");
- goto Return;
- }
-
- if(!c->advance){
- warning(nil, "%.*S%s%.*S*%s\n",
- dir.nr, dir.r,
- dir.nr>0 && dir.r[dir.nr-1]!='/' ? "/" : "",
- nstr, str,
- c->nmatch? "" : ": no matches in:");
- for(i=0; i<c->nfile; i++)
- warning(nil, " %s\n", c->filename[i]);
- }
-
- if(c->advance)
- rp = runesmprint("%s", c->string);
- else
- rp = nil;
- Return:
- freecompletion(c);
- free(dirs);
- free(str);
- free(path);
- return rp;
-}
-
-uint
-getposinline(Text *t){
- // Just count backwards either to the previous newline
- // or the file's beginning
- if(t->q0 == 0) return 0;
- if(t->q0 == 1) return 1;
- uint q = t->q0 - 1;
- while(q > 0 && textreadc(t, q) != '\n') q--;
- return t->q0 - q - 1;
-}
-
-uint
-linelen(Text *t){
- uint q0 = t->q0;
- uint len = getposinline(t);
- while(q0<t->file->nc && textreadc(t, q0)!='\n'){
- q0++; len++;
- }
- return len;
-}
-
-void
-texttype(Text *t, Rune r)
-{
- uint q0, q1, lp, ln, ls;
- int nnb, nb, n, i;
- int nr;
- Rune rr;
- Rune *rp;
- Text *u;
-
- nr = 1;
- rp = &r;
- switch(r){
- case Kleft:
- typecommit(t);
- if(t->q0 > 0)
- textshow(t, t->q0-1, t->q0-1, TRUE);
- return;
- case Kright:
- typecommit(t);
- if(t->q1 < t->file->nc)
- textshow(t, t->q1+1, t->q1+1, TRUE);
- return;
- case Kdown:
- //n = t->maxlines/3;
- //goto case_Down;
- typecommit(t);
- q0 = t->q0;
- lp = getposinline(t);
- while(q0<t->file->nc && textreadc(t, q0)!='\n') q0++;
- q0++;
- q1 = q0;
- while(q0<t->file->nc && textreadc(t, q0)!='\n' && q0 < q1+lp) q0++;
- q0 = (q0 >= t->file->nc) ? t->file->nc - 1 : q0;
- textshow(t, q0, q0, TRUE);
- return;
- case Kscrollonedown:
- n = mousescrollsize(t->maxlines);
- if(n <= 0)
- n = 1;
- goto case_Down;
- case Kpgdown:
- n = 2*t->maxlines/3;
- case_Down:
- q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+n*t->font->height));
- if(t->what == Body)
- textsetorigin(t, q0, TRUE);
- return;
- case Kup:
- //n = t->maxlines/3;
- //goto case_Up;
- typecommit(t);
- q0 = t->q0;
- q1 = q0;
- lp = getposinline(t);
- ls = linelen(t);
- if(ls > q0) {
- textshow(t, 0, 0, TRUE);
- return;
- }
- ln = 1;
- while(q0>0 && textreadc(t, q0 - 1)!='\n') q0--;
- if(q0 > 0) q0--;
- while(q0>0 && textreadc(t, q0 - 1)!='\n'){
- q0--;
- ln++;
- }
- q0 += lp;
- textshow(t, q0, q0, TRUE);
- return;
- case Kscrolloneup:
- n = mousescrollsize(t->maxlines);
- goto case_Up;
- case Kpgup:
- n = 2*t->maxlines/3;
- case_Up:
- q0 = textbacknl(t, t->org, n);
- if(t->what == Body)
- textsetorigin(t, q0, TRUE);
- return;
- case Khome:
- typecommit(t);
- textshow(t, 0, 0, FALSE);
- return;
- case Kend:
- typecommit(t);
- textshow(t, t->file->nc, t->file->nc, FALSE);
- return;
- case 0x01: /* ^A: beginning of line */
- typecommit(t);
- /* go to where ^U would erase, if not already at BOL */
- nnb = 0;
- if(t->q0>0 && textreadc(t, t->q0-1)!='\n')
- nnb = textbswidth(t, 0x15);
- textshow(t, t->q0-nnb, t->q0-nnb, TRUE);
- return;
- case 0x05: /* ^E: end of line */
- typecommit(t);
- q0 = t->q0;
- while(q0<t->file->nc && textreadc(t, q0)!='\n')
- q0++;
- textshow(t, q0, q0, TRUE);
- return;
- }
- if(t->what == Body){
- seq++;
- filemark(t->file);
- }
- if(t->q1 > t->q0){
- if(t->ncache != 0)
- error("text.type");
- cut(t, t, nil, TRUE, TRUE, nil, 0);
- t->eq0 = ~0;
- }
- textshow(t, t->q0, t->q0, 1);
- switch(r){
- case 0x06:
- case Kins:
- rp = textcomplete(t);
- if(rp == nil)
- return;
- nr = runestrlen(rp);
- break; /* fall through to normal insertion case */
- case 0x1B:
- if(t->eq0 != ~0)
- textsetselect(t, t->eq0, t->q0);
- if(t->ncache > 0)
- typecommit(t);
- return;
- case 0x08: /* ^H: erase character */
- case 0x15: /* ^U: erase line */
- case 0x17: /* ^W: erase word */
- if(t->q0 == 0) /* nothing to erase */
- return;
- nnb = textbswidth(t, r);
- q1 = t->q0;
- q0 = q1-nnb;
- /* if selection is at beginning of window, avoid deleting invisible text */
- if(q0 < t->org){
- q0 = t->org;
- nnb = q1-q0;
- }
- if(nnb <= 0)
- return;
- for(i=0; i<t->file->ntext; i++){
- u = t->file->text[i];
- u->nofill = TRUE;
- nb = nnb;
- n = u->ncache;
- if(n > 0){
- if(q1 != u->cq0+n)
- error("text.type backspace");
- if(n > nb)
- n = nb;
- u->ncache -= n;
- textdelete(u, q1-n, q1, FALSE);
- nb -= n;
- }
- if(u->eq0==q1 || u->eq0==~0)
- u->eq0 = q0;
- if(nb && u==t)
- textdelete(u, q0, q0+nb, TRUE);
- if(u != t)
- textsetselect(u, u->q0, u->q1);
- else
- textsetselect(t, q0, q0);
- u->nofill = FALSE;
- }
- for(i=0; i<t->file->ntext; i++)
- textfill(t->file->text[i]);
- return;
- case '\t':
- if(t->what == Body && t->w->indent[SPACESINDENT]){
- nnb = textbswidth(t, 0x15);
- if(nnb == 1 && textreadc(t, t->q0-1) == '\n')
- nnb = 0;
- nnb = t->tabstop - nnb % t->tabstop;
- rp = runemalloc(nnb);
- for(nr = 0; nr < nnb; nr++)
- rp[nr] = ' ';
- }
- break;
- case '\n':
- if(t->what == Body && t->w->indent[AUTOINDENT]){
- /* find beginning of previous line using backspace code */
- nnb = textbswidth(t, 0x15); /* ^U case */
- rp = runemalloc(nnb + 1);
- nr = 0;
- rp[nr++] = r;
- for(i=0; i<nnb; i++){
- rr = textreadc(t, t->q0-nnb+i);
- if(rr != ' ' && rr != '\t')
- break;
- rp[nr++] = rr;
- }
- }
- break; /* fall through to normal code */
- }
- /* otherwise ordinary character; just insert, typically in caches of all texts */
- for(i=0; i<t->file->ntext; i++){
- u = t->file->text[i];
- if(u->eq0 == ~0)
- u->eq0 = t->q0;
- if(u->ncache == 0)
- u->cq0 = t->q0;
- else if(t->q0 != u->cq0+u->ncache)
- error("text.type cq1");
- textinsert(u, t->q0, rp, nr, FALSE);
- if(u != t)
- textsetselect(u, u->q0, u->q1);
- if(u->ncache+nr > u->ncachealloc){
- u->ncachealloc += 10 + nr;
- u->cache = runerealloc(u->cache, u->ncachealloc);
- }
- runemove(u->cache+u->ncache, rp, nr);
- u->ncache += nr;
- }
- if(rp != &r)
- free(rp);
- textsetselect(t, t->q0+nr, t->q0+nr);
- if(r=='\n' && t->w!=nil)
- wincommit(t->w, t);
-}
-
-void
-textcommit(Text *t, int tofile)
-{
- if(t->ncache == 0)
- return;
- if(tofile)
- fileinsert(t->file, t->cq0, t->cache, t->ncache);
- if(t->what == Body){
- t->w->dirty = TRUE;
- t->w->utflastqid = -1;
- }
- t->ncache = 0;
-}
-
-static Text *clicktext;
-static uint clickmsec;
-static int clickcount;
-static Point clickpt;
-static Text *selecttext;
-static uint selectq;
-
-/*
- * called from frame library
- */
-void
-framescroll(Frame *f, int dl)
-{
- if(f != &selecttext->Frame)
- error("frameselect not right frame");
- textframescroll(selecttext, dl);
-}
-
-void
-textframescroll(Text *t, int dl)
-{
- uint q0;
-
- if(dl == 0){
- scrsleep(100);
- return;
- }
- if(dl < 0){
- q0 = textbacknl(t, t->org, -dl);
- if(selectq > t->org+t->p0)
- textsetselect(t, t->org+t->p0, selectq);
- else
- textsetselect(t, selectq, t->org+t->p0);
- }else{
- if(t->org+t->nchars == t->file->nc)
- return;
- q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+dl*t->font->height));
- if(selectq > t->org+t->p1)
- textsetselect(t, t->org+t->p1, selectq);
- else
- textsetselect(t, selectq, t->org+t->p1);
- }
- textsetorigin(t, q0, TRUE);
- flushimage(display, 1);
-}
-
-
-void
-textselect(Text *t)
-{
- uint q0, q1;
- int b, x, y, dx, dy;
- int state;
-
- selecttext = t;
- /*
- * To have double-clicking and chording, we double-click
- * immediately if it might make sense.
- */
- b = mouse->buttons;
- q0 = t->q0;
- q1 = t->q1;
- dx = abs(clickpt.x - mouse->xy.x);
- dy = abs(clickpt.y - mouse->xy.y);
- clickpt = mouse->xy;
- selectq = t->org+frcharofpt(t, mouse->xy);
- clickcount++;
- if(mouse->msec-clickmsec >= 500 || selecttext != t || clickcount > 3 || dx > 3 || dy > 3)
- clickcount = 0;
- if(clickcount >= 1 && selecttext==t && mouse->msec-clickmsec < 500){
- textstretchsel(t, selectq, &q0, &q1, clickcount);
- textsetselect(t, q0, q1);
- flushimage(display, 1);
- x = mouse->xy.x;
- y = mouse->xy.y;
- /* stay here until something interesting happens */
- while(1){
- readmouse(mousectl);
- dx = abs(mouse->xy.x - x);
- dy = abs(mouse->xy.y - y);
- if(mouse->buttons != b || dx >= 3 || dy >= 3)
- break;
- clickcount++;
- clickmsec = mouse->msec;
- }
- mouse->xy.x = x; /* in case we're calling frselect */
- mouse->xy.y = y;
- q0 = t->q0; /* may have changed */
- q1 = t->q1;
- selectq = t->org+frcharofpt(t, mouse->xy);;
- }
- if(mouse->buttons == b && clickcount == 0){
- t->Frame.scroll = framescroll;
- frselect(t, mousectl);
- /* horrible botch: while asleep, may have lost selection altogether */
- if(selectq > t->file->nc)
- selectq = t->org + t->p0;
- t->Frame.scroll = nil;
- if(selectq < t->org)
- q0 = selectq;
- else
- q0 = t->org + t->p0;
- if(selectq > t->org+t->nchars)
- q1 = selectq;
- else
- q1 = t->org+t->p1;
- }
- if(q0 == q1){
- if(q0==t->q0 && mouse->msec-clickmsec<500)
- textstretchsel(t, selectq, &q0, &q1, clickcount);
- else
- clicktext = t;
- clickmsec = mouse->msec;
- }else
- clicktext = nil;
- textsetselect(t, q0, q1);
- flushimage(display, 1);
- state = 0; /* undo when possible; +1 for cut, -1 for paste */
- while(mouse->buttons){
- mouse->msec = 0;
- b = mouse->buttons;
- if((b&1) && (b&6)){
- if(state==0 && t->what==Body){
- seq++;
- filemark(t->w->body.file);
- }
- if(b & 2){
- if(state==-1 && t->what==Body){
- winundo(t->w, TRUE);
- textsetselect(t, q0, t->q0);
- state = 0;
- }else if(state != 1){
- cut(t, t, nil, TRUE, TRUE, nil, 0);
- state = 1;
- }
- }else{
- if(state==1 && t->what==Body){
- winundo(t->w, TRUE);
- textsetselect(t, q0, t->q1);
- state = 0;
- }else if(state != -1){
- paste(t, t, nil, TRUE, FALSE, nil, 0);
- state = -1;
- }
- }
- textscrdraw(t);
- clearmouse();
- }
- flushimage(display, 1);
- while(mouse->buttons == b)
- readmouse(mousectl);
- if(mouse->msec-clickmsec >= 500)
- clicktext = nil;
- }
-}
-
-void
-textshow(Text *t, uint q0, uint q1, int doselect)
-{
- int qe;
- int nl;
- uint q;
-
- if(t->what != Body){
- if(doselect)
- textsetselect(t, q0, q1);
- return;
- }
- if(t->w!=nil && t->maxlines==0)
- colgrow(t->col, t->w, 1);
- if(doselect)
- textsetselect(t, q0, q1);
- qe = t->org+t->nchars;
- if(t->org<=q0 && (q0<qe || (q0==qe && qe==t->file->nc+t->ncache)))
- textscrdraw(t);
- else{
- if(t->w->nopen[QWevent] > 0)
- nl = 3*t->maxlines/4;
- else
- nl = t->maxlines/4;
- q = textbacknl(t, q0, nl);
- /* avoid going backwards if trying to go forwards - long lines! */
- if(!(q0>t->org && q<t->org))
- textsetorigin(t, q, TRUE);
- while(q0 > t->org+t->nchars)
- textsetorigin(t, t->org+1, FALSE);
- }
-}
-
-static
-int
-region(int a, int b)
-{
- if(a < b)
- return -1;
- if(a == b)
- return 0;
- return 1;
-}
-
-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]);
-}
-
-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;
-}
-
-/*
- * Release the button in less than DELAY ms and it's considered a null selection
- * if the mouse hardly moved, regardless of whether it crossed a char boundary.
- */
-enum {
- DELAY = 2,
- MINMOVE = 4,
-};
-
-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;
-}
-
-int
-textselect23(Text *t, uint *q0, uint *q1, Image *high, int mask)
-{
- uint p0, p1;
- int buts;
-
- p0 = xselect(t, mousectl, high, &p1);
- buts = mousectl->buttons;
- if((buts & mask) == 0){
- *q0 = p0+t->org;
- *q1 = p1+t->org;
- }
-
- while(mousectl->buttons)
- readmouse(mousectl);
- return buts;
-}
-
-int
-textselect2(Text *t, uint *q0, uint *q1, Text **tp)
-{
- int buts;
-
- *tp = nil;
- buts = textselect23(t, q0, q1, but2col, 4);
- if(buts & 4)
- return 0;
- if(buts & 1){ /* pick up argument */
- *tp = argtext;
- return 1;
- }
- return 1;
-}
-
-int
-textselect3(Text *t, uint *q0, uint *q1)
-{
- int h;
-
- h = (textselect23(t, q0, q1, but3col, 1|2) == 0);
- return h;
-}
-
-static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 };
-static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 };
-static Rune left2[] = { L'\n', 0 };
-static Rune left3[] = { L'\'', L'"', L'`', 0 };
-
-static
-Rune *left[] = {
- left1,
- left2,
- left3,
- nil
-};
-static
-Rune *right[] = {
- right1,
- left2,
- left3,
- nil
-};
-
-int
-inmode(Rune r, int mode)
-{
- return (mode == 1) ? isalnum(r) : r && !isspace(r);
-}
-
-void
-textstretchsel(Text *t, uint mp, uint *q0, uint *q1, int mode)
-{
- int c, i;
- Rune *r, *l, *p;
- uint q;
-
- *q0 = mp;
- *q1 = mp;
- for(i=0; left[i]!=nil; i++){
- q = *q0;
- l = left[i];
- r = right[i];
- /* try matching character to left, looking right */
- if(q == 0)
- c = '\n';
- else
- c = textreadc(t, q-1);
- p = runestrchr(l, c);
- if(p != nil){
- if(textclickmatch(t, c, r[p-l], 1, &q))
- *q1 = q-(c!='\n');
- return;
- }
- /* try matching character to right, looking left */
- if(q == t->file->nc)
- c = '\n';
- else
- c = textreadc(t, q);
- p = runestrchr(r, c);
- if(p != nil){
- if(textclickmatch(t, c, l[p-r], -1, &q)){
- *q1 = *q0+(*q0<t->file->nc && c=='\n');
- *q0 = q;
- if(c!='\n' || q!=0 || textreadc(t, 0)=='\n')
- (*q0)++;
- }
- return;
- }
- }
- /* try filling out word to right */
- while(*q1<t->file->nc && inmode(textreadc(t, *q1), mode))
- (*q1)++;
- /* try filling out word to left */
- while(*q0>0 && inmode(textreadc(t, *q0-1), mode))
- (*q0)--;
-}
-
-int
-textclickmatch(Text *t, int cl, int cr, int dir, uint *q)
-{
- Rune c;
- int nest;
-
- nest = 1;
- for(;;){
- if(dir > 0){
- if(*q == t->file->nc)
- break;
- c = textreadc(t, *q);
- (*q)++;
- }else{
- if(*q == 0)
- break;
- (*q)--;
- c = textreadc(t, *q);
- }
- if(c == cr){
- if(--nest==0)
- return 1;
- }else if(c == cl)
- nest++;
- }
- return cl=='\n' && nest==1;
-}
-
-uint
-textbacknl(Text *t, uint p, uint n)
-{
- int i, j;
-
- /* look for start of this line if n==0 */
- if(n==0 && p>0 && textreadc(t, p-1)!='\n')
- n = 1;
- i = n;
- while(i-->0 && p>0){
- --p; /* it's at a newline now; back over it */
- if(p == 0)
- break;
- /* at 128 chars, call it a line anyway */
- for(j=128; --j>0 && p>0; p--)
- if(textreadc(t, p-1)=='\n')
- break;
- }
- return p;
-}
-
-void
-textsetorigin(Text *t, uint org, int exact)
-{
- int i, a, fixup;
- Rune *r;
- uint n;
-
- if(org>0 && !exact && textreadc(t, org-1) != '\n'){
- /* 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
-textreset(Text *t)
-{
- t->file->seq = 0;
- t->eq0 = ~0;
- /* do t->delete(0, t->nc, TRUE) without building backup stuff */
- textsetselect(t, t->org, t->org);
- frdelete(t, 0, t->nchars);
- t->org = 0;
- t->q0 = 0;
- t->q1 = 0;
- filereset(t->file);
- bufreset(t->file);
-}
--- a/wind.c
+++ b/wind.c
@@ -167,12 +167,16 @@
int
winresize(Window *w, Rectangle r, int safe, int fillfringe)
{
- int oy, y, mouseintag, mouseinbody;
+ int oy, y, mouseintag, mouseinbody, nw;
Point p;
Rectangle r1;
Image *b;
Rectangle br;
+ nw = 0;
+ if(w->showlines)
+ nw = stringwidth(w->body.font, "000000 ");
+
mouseintag = ptinrect(mouse->xy, w->tag.all);
mouseinbody = ptinrect(mouse->xy, w->body.all);
@@ -222,6 +226,10 @@
/* If needed, resize & redraw body. */
r1 = r;
r1.min.y = y;
+
+ if(w->showlines)
+ r1.min.x += nw;
+
if(!safe || !eqrect(w->body.r, r1)){
oy = y;
if(y+1+w->body.font->height <= r.max.y){ /* room for one line */