acme: shift button 3 for reverse search

An experiment. Let's see if it's any good.
Also document the Mac conventions in devdraw(3).
This commit is contained in:
Russ Cox 2024-06-15 10:55:21 -04:00
parent 60ca2be037
commit 0c79c32675
14 changed files with 270 additions and 100 deletions

View file

@ -80,7 +80,7 @@ startplumbing(void)
void
look3(Text *t, uint q0, uint q1, int external)
look3(Text *t, uint q0, uint q1, int external, int reverse)
{
int n, c, f, expanded;
Text *ct;
@ -94,7 +94,7 @@ look3(Text *t, uint q0, uint q1, int external)
ct = seltext;
if(ct == nil)
seltext = t;
expanded = expand(t, q0, q1, &e);
expanded = expand(t, q0, q1, &e, reverse);
if(!external && t->w!=nil && t->w->nopen[QWevent]>0){
/* send alphanumeric expansion to external client */
if(expanded == FALSE)
@ -109,6 +109,8 @@ look3(Text *t, uint q0, uint q1, int external)
c = 'l';
if(t->what == Body)
c = 'L';
if(reverse)
c += 'R' - 'L';
n = q1-q0;
if(n <= EVENTSIZE){
r = runemalloc(n);
@ -203,12 +205,17 @@ look3(Text *t, uint q0, uint q1, int external)
ct = &t->w->body;
if(t->w != ct->w)
winlock(ct->w, 'M');
if(t == ct)
textsetselect(ct, e.q1, e.q1);
if(t == ct) {
uint q;
q = e.q1;
if(reverse)
q = e.q0;
textsetselect(ct, q, q);
}
n = e.q1 - e.q0;
r = runemalloc(n);
bufread(&t->file->b, e.q0, r, n);
if(search(ct, r, n) && e.jump)
if(search(ct, r, n, reverse) && 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);
@ -241,6 +248,7 @@ plumblook(Plumbmsg *m)
warning(nil, "insanely long file name (%d bytes) in plumb message (%.32s...)\n", m->ndata, m->data);
return;
}
memset(&e, 0, sizeof e);
e.q0 = 0;
e.q1 = 0;
if(m->data[0] == '\0')
@ -303,11 +311,11 @@ plumbshow(Plumbmsg *m)
}
int
search(Text *ct, Rune *r, uint n)
search(Text *ct, Rune *r, uint n, int reverse)
{
uint q, nb, maxn;
uint nb, maxn;
int around;
Rune *s, *b, *c;
Rune *s, *b;
if(n==0 || n>ct->file->b.nc)
return FALSE;
@ -321,55 +329,111 @@ search(Text *ct, Rune *r, uint n)
nb = 0;
b[nb] = 0;
around = 0;
q = ct->q1;
for(;;){
if(q >= ct->file->b.nc){
q = 0;
around = 1;
nb = 0;
b[nb] = 0;
}
if(nb > 0){
c = runestrchr(b, r[0]);
if(c == nil){
q += nb;
if(reverse){
uint q1;
q1 = ct->q0; // q1 is (past) end of text being searched.
for(;;){
if(q1 <= 0){
q1 = ct->file->b.nc;
around = 1;
nb = 0;
b[nb] = 0;
if(around && q>=ct->q1)
break;
continue;
}
q += (c-b);
nb -= (c-b);
b = c;
}
/* reload if buffer covers neither string nor rest of file */
if(nb<n && nb!=ct->file->b.nc-q){
nb = ct->file->b.nc-q;
if(nb >= maxn)
nb = maxn-1;
bufread(&ct->file->b, q, s, nb);
b = s;
b[nb] = '\0';
}
/* this runeeq is fishy but the null at b[nb] makes it safe */
if(runeeq(b, n, r, n)==TRUE){
if(ct->w){
textshow(ct, q, q+n, 1);
winsettag(ct->w);
}else{
ct->q0 = q;
ct->q1 = q+n;
if(nb > 0){
Rune *c;
for(c=b+nb; c>b; c--)
if(c[-1] == r[n-1])
break;
if(c == b) {
q1 -= nb;
nb = 0;
b[nb] = 0;
if(around && q1 <= 0)
break;
continue;
}
q1 -= nb - (c - b);
nb = c - b;
}
seltext = ct;
fbuffree(s);
return TRUE;
/* reload if buffer covers neither string nor beginning of file */
if(nb<n && nb!=q1){
nb = q1;
if(nb >= maxn)
nb = maxn-1;
bufread(&ct->file->b, q1-nb, s, nb);
b = s;
b[nb] = '\0';
}
if(runeeq(b+nb-n, n, r, n)==TRUE){
if(ct->w){
textshow(ct, q1-n, q1, 1);
winsettag(ct->w);
}else{
ct->q0 = q1-n;
ct->q1 = q1;
}
seltext = ct;
fbuffree(s);
return TRUE;
}
q1--;
nb--;
if(around && q1 <= 0)
break;
}
}else{
uint q;
q = ct->q1;
for(;;){
if(q >= ct->file->b.nc){
q = 0;
around = 1;
nb = 0;
b[nb] = 0;
}
if(nb > 0){
Rune *c;
c = runestrchr(b, r[0]);
if(c == nil){
q += nb;
nb = 0;
b[nb] = 0;
if(around && q>=ct->q1)
break;
continue;
}
q += (c-b);
nb -= (c-b);
b = c;
}
/* reload if buffer covers neither string nor rest of file */
if(nb<n && nb!=ct->file->b.nc-q){
nb = ct->file->b.nc-q;
if(nb >= maxn)
nb = maxn-1;
bufread(&ct->file->b, q, s, nb);
b = s;
b[nb] = '\0';
}
/* this runeeq is fishy but the null at b[nb] makes it safe */
if(runeeq(b, n, r, n)==TRUE){
if(ct->w){
textshow(ct, q, q+n, 1);
winsettag(ct->w);
}else{
ct->q0 = q;
ct->q1 = q+n;
}
seltext = ct;
fbuffree(s);
return TRUE;
}
--nb;
b++;
q++;
if(around && q>=ct->q1)
break;
}
--nb;
b++;
q++;
if(around && q>=ct->q1)
break;
}
fbuffree(s);
return FALSE;
@ -526,7 +590,7 @@ texthas(Text *t, uint q0, Rune *r)
}
int
expandfile(Text *t, uint q0, uint q1, Expand *e)
expandfile(Text *t, uint q0, uint q1, Expand *e, int reverse)
{
int i, n, nname, colon, eval;
uint amin, amax;
@ -570,6 +634,11 @@ expandfile(Text *t, uint q0, uint q1, Expand *e)
break;
}else
amax = t->file->b.nc;
if(colon != q0)
reverse = FALSE;
}else if(reverse){
if(textreadc(t, q0) != ':')
reverse = FALSE;
}
amin = amax;
e->q0 = q0;
@ -643,12 +712,16 @@ expandfile(Text *t, uint q0, uint q1, Expand *e)
}
Isfile:
print("isfile reverse=%d colon=%d q0=%d\n", reverse, colon, q0);
e->name = r;
e->nname = nname;
e->u.at = t;
e->a0 = amin+1;
e->reverse = reverse;
eval = FALSE;
address(TRUE, nil, range(-1,-1), range(0,0), t, e->a0, amax, tgetc, &eval, (uint*)&e->a1);
// Note: address is repeated in openfile when
// expandfile returns to expand returns to look3.
address(TRUE, nil, range(-1,-1), range(0,0), t, e->a0, amax, tgetc, &eval, (uint*)&e->a1, e->reverse);
return TRUE;
Isntfile:
@ -657,7 +730,7 @@ expandfile(Text *t, uint q0, uint q1, Expand *e)
}
int
expand(Text *t, uint q0, uint q1, Expand *e)
expand(Text *t, uint q0, uint q1, Expand *e, int reverse)
{
memset(e, 0, sizeof *e);
e->agetc = tgetc;
@ -670,7 +743,7 @@ expand(Text *t, uint q0, uint q1, Expand *e)
e->jump = FALSE;
}
if(expandfile(t, q0, q1, e))
if(expandfile(t, q0, q1, e, reverse))
return TRUE;
if(q0 == q1){
@ -806,7 +879,7 @@ openfile(Text *t, Expand *e)
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);
r = address(TRUE, t, range(-1,-1), range(t->q0, t->q1), e->u.at, e->a0, e->a1, e->agetc, &eval, &dummy, e->reverse);
if(r.q0 > r.q1) {
eval = FALSE;
warning(nil, "addresses out of order\n");