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:
parent
60ca2be037
commit
0c79c32675
14 changed files with 270 additions and 100 deletions
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue