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

@ -1,4 +1,5 @@
#include <u.h>
#include <pwd.h>
#include <signal.h>
#include <libc.h>
#include <ctype.h>
@ -56,7 +57,7 @@ threadmaybackground(void)
void
threadmain(int argc, char *argv[])
{
char *p;
char *p, *env;
rfork(RFNOTEG);
font = nil;
@ -64,6 +65,25 @@ threadmain(int argc, char *argv[])
mainpid = getpid();
messagesize = 8192;
threadmaybackground();
env = getenv("__CFBundleIdentifier");
if(env != nil && strcmp(env, "com.swtch.9term") == 0) {
// Being invoked as $PLAN9/mac/9term.app.
// Set $SHELL and daemonize to let parent exit.
// This makes sure that each click on 9term
// brings up a new window.
extern void _threaddaemonize(void);
struct passwd *pw;
unsetenv("__CFBundleIdentifier");
pw = getpwuid(getuid());
if(pw != nil && pw->pw_shell != nil)
setenv("SHELL", pw->pw_shell, 1);
loginshell = TRUE;
//_threaddaemonize();
}
ARGBEGIN{
default:
usage();

View file

@ -518,6 +518,7 @@ mousethread(void *v)
Mouse m;
char *act;
enum { MResize, MMouse, MPlumb, MWarnings, NMALT };
enum { Shift = 5 };
static Alt alts[NMALT+1];
USED(v);
@ -661,9 +662,9 @@ mousethread(void *v)
}else if(m.buttons & 2){
if(textselect2(t, &q0, &q1, &argt))
execute(t, q0, q1, FALSE, argt);
}else if(m.buttons & 4){
}else if(m.buttons & (4|(4<<Shift))){
if(textselect3(t, &q0, &q1))
look3(t, q0, q1, FALSE);
look3(t, q0, q1, FALSE, (m.buttons&(4<<Shift))!=0);
}
if(w)
winunlock(w);
@ -770,7 +771,7 @@ waitthread(void *v)
pids = p;
}
}else{
if(search(t, c->name, c->nname)){
if(search(t, c->name, c->nname, FALSE)){
textdelete(t, t->q0, t->q1, TRUE);
textsetselect(t, 0, 0);
}

View file

@ -172,7 +172,7 @@ regexp(uint showerr, Text *t, Range lim, Range r, Rune *pat, int dir, int *found
}
Range
address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp)
address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp, int reverse)
{
int dir, size, npat;
int prevc, c, nc, n;
@ -183,6 +183,8 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
r = ar;
q = q0;
dir = None;
if(reverse)
dir = Back;
size = Line;
c = 0;
while(q < q1){
@ -201,7 +203,7 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */
r.q1 = t->file->b.nc;
else{
nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q);
nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q, FALSE);
r.q1 = nr.q1;
}
*qp = q;

View file

@ -454,6 +454,7 @@ struct Expand
int nname;
char *bname;
int jump;
int reverse;
union{
Text *at;
Rune *ar;

View file

@ -280,13 +280,14 @@ getarg(Text *argt, int doaddr, int dofile, Rune **rp, int *nrp)
Expand e;
char *a;
memset(&e, 0, sizeof e);
*rp = nil;
*nrp = 0;
if(argt == nil)
return nil;
a = nil;
textcommit(argt, TRUE);
if(expand(argt, argt->q0, argt->q1, &e)){
if(expand(argt, argt->q0, argt->q1, &e, FALSE)){
free(e.bname);
if(e.nname && dofile){
e.name = runerealloc(e.name, e.nname+1);
@ -1083,7 +1084,7 @@ look(Text *et, Text *t, Text *argt, int _0, int _1, Rune *arg, int narg)
if(et && et->w){
t = &et->w->body;
if(narg > 0){
search(t, arg, narg);
search(t, arg, narg, FALSE);
return;
}
getarg(argt, FALSE, FALSE, &r, &n);
@ -1092,7 +1093,7 @@ look(Text *et, Text *t, Text *argt, int _0, int _1, Rune *arg, int narg)
r = runemalloc(n);
bufread(&t->file->b, t->q0, r, n);
}
search(t, r, n);
search(t, r, n, FALSE);
free(r);
}
}

View file

@ -63,8 +63,8 @@ void fontx(Text*, Text*, Text*, int, int, Rune*, int);
#define isalnum acmeisalnum
int isalnum(Rune);
void execute(Text*, uint, uint, int, Text*);
int search(Text*, Rune*, uint);
void look3(Text*, uint, uint, int);
int search(Text*, Rune*, uint, int);
void look3(Text*, uint, uint, int, int);
void editcmd(Text*, Rune*, uint);
uint min(uint, uint);
uint max(uint, uint);
@ -85,11 +85,11 @@ int isregexc(int);
void *emalloc(uint);
void *erealloc(void*, uint);
char *estrdup(char*);
Range address(uint, Text*, Range, Range, void*, uint, uint, int (*)(void*, uint), int*, uint*);
Range address(uint, Text*, Range, Range, void*, uint, uint, int (*)(void*, uint), int*, uint*, int);
int rxexecute(Text*, Rune*, uint, uint, Rangeset*);
int rxbexecute(Text*, uint, Rangeset*);
Window* makenewwindow(Text *t);
int expand(Text*, uint, uint, Expand*);
int expand(Text*, uint, uint, Expand*, int);
Rune* skipbl(Rune*, int, int*);
Rune* findbl(Rune*, int, int*);
char* edittext(Window*, int, Rune*, int);

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");

View file

@ -486,7 +486,7 @@ xfidwrite(Xfid *x)
t = &w->body;
wincommit(w, t);
eval = TRUE;
a = address(FALSE, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);
a = address(FALSE, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb, FALSE);
free(r);
if(nb < nr){
respond(x, &fc, Ebadaddr);
@ -900,7 +900,11 @@ xfideventwrite(Xfid *x, Window *w)
break;
case 'l':
case 'L':
look3(t, q0, q1, TRUE);
look3(t, q0, q1, TRUE, FALSE);
break;
case 'r':
case 'R':
look3(t, q0, q1, TRUE, TRUE);
break;
default:
qunlock(&row.lk);

View file

@ -631,12 +631,17 @@ rpc_resizewindow(Client *c, Rectangle r)
b = [NSEvent pressedMouseButtons];
b = (b&~6) | (b&4)>>1 | (b&2)<<1;
if(b){
int x;
x = 0;
if(m & ~omod & NSEventModifierFlagControl)
b |= 1;
x = 1;
if(m & ~omod & NSEventModifierFlagOption)
b |= 2;
x = 2;
if(m & ~omod & NSEventModifierFlagCommand)
b |= 4;
x = 4;
if(m & NSEventModifierFlagShift)
x <<= 5;
b |= x;
[self sendmouse:b];
}else if(m & ~omod & NSEventModifierFlagOption)
gfx_keystroke(self.client, Kalt);
@ -701,6 +706,8 @@ rpc_resizewindow(Client *c, Rectangle r)
}else
if(m & NSEventModifierFlagCommand)
b = 4;
if(m & NSEventModifierFlagShift)
b <<= 5;
}
[self sendmouse:b];
}