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

@ -29,7 +29,7 @@ conventionally
When programs need to access files in the tree, When programs need to access files in the tree,
they expect the they expect the
.B $PLAN9 .B $PLAN9
environment variable environment variable
to contain the name of the root of the tree. to contain the name of the root of the tree.
See See
.MR install (1) .MR install (1)
@ -57,7 +57,7 @@ expect Plan 9 regular expressions
(see (see
.MR regexp (7) ), .MR regexp (7) ),
which are closest to what Unix calls extended regular expressions. which are closest to what Unix calls extended regular expressions.
Because of these differences, it is not recommended to put Because of these differences, it is not recommended to put
.B $PLAN9/bin .B $PLAN9/bin
before the usual system before the usual system
.B bin .B bin
@ -99,6 +99,11 @@ The argument is one of
\fL'\fIxmin ymin xmax ymax\fL'\fR, \fL'\fIxmin ymin xmax ymax\fL'\fR,
\fRor \fRor
\fIxmin\fL,\fIymin\fL,\fIxmax\fL,\fIymax\fR. \fIxmin\fL,\fIymin\fL,\fIxmax\fL,\fIymax\fR.
See
.MR devdraw (1)
and
.MR keyboard (7)
for details about typing and clicking in graphical applications.
.PP .PP
The The
.MR plumber (4) .MR plumber (4)
@ -135,7 +140,7 @@ is an experimental client for acme.
Some programs rely on large databases that would be Some programs rely on large databases that would be
cumbersome to include in every release. cumbersome to include in every release.
Scripts are provided that download these databases separately. Scripts are provided that download these databases separately.
These databases can be downloaded separately. These databases can be downloaded separately.
See See
.B $PLAN9/dict/README .B $PLAN9/dict/README
and and
@ -148,7 +153,7 @@ and
(see (see
.MR 9c (1) ) .MR 9c (1) )
provide a simple interface to the underlying system compiler and linker, provide a simple interface to the underlying system compiler and linker,
similar to the similar to the
.I 2c .I 2c
and and
.I 2l .I 2l
@ -201,7 +206,7 @@ cannot)
and dump data structures, and dump data structures,
but that it is the extent to which they have been developed and exercised. but that it is the extent to which they have been developed and exercised.
.SS Porting programs .SS Porting programs
The vast majority of the familiar Plan 9 programs The vast majority of the familiar Plan 9 programs
have been ported, including the Unicode-aware have been ported, including the Unicode-aware
.MR troff (1) . .MR troff (1) .
.PP .PP
@ -222,7 +227,7 @@ is in progress; see
.SS Porting to new systems .SS Porting to new systems
Porting the tree to new operating systems or architectures Porting the tree to new operating systems or architectures
should be straightforward, as system-specific code has been should be straightforward, as system-specific code has been
kept to a minimum. kept to a minimum.
The largest pieces of system-specific code are The largest pieces of system-specific code are
.BR <u.h> , .BR <u.h> ,
which must include the right system files and which must include the right system files and
@ -231,7 +236,7 @@ and
.IR libthread , .IR libthread ,
which must implement spin locks, operating system thread which must implement spin locks, operating system thread
creation, and context switching routines. creation, and context switching routines.
Portable implementations of these using Portable implementations of these using
.B <pthread.h> .B <pthread.h>
and and
.B <ucontext.h> .B <ucontext.h>
@ -259,7 +264,7 @@ so that the Unix
utility can handle it. utility can handle it.
Some systems, for example Debian Linux, Some systems, for example Debian Linux,
deduce the man page locations from the search path, so that deduce the man page locations from the search path, so that
adding adding
.B $PLAN9/bin .B $PLAN9/bin
to your path is sufficient to cause to your path is sufficient to cause
.B $PLAN9/man .B $PLAN9/man

View file

@ -588,6 +588,9 @@ not just
or or
.BR 127 . .BR 127 .
(There is an easier way to locate literal text; see below.) (There is an easier way to locate literal text; see below.)
If shift is held down during the selection or click,
any leading regular expression search defaults to
searching backward in the text instead of forward.
.PP .PP
If the text is a file name followed by a colon and an address, If the text is a file name followed by a colon and an address,
.I acme .I acme
@ -608,6 +611,8 @@ moved there. Thus, to search for occurrences of a word in a file,
just click button 3 on the word. Because of the rule of using the just click button 3 on the word. Because of the rule of using the
selection as the button 3 action, subsequent clicks will find subsequent selection as the button 3 action, subsequent clicks will find subsequent
occurrences without moving the mouse. occurrences without moving the mouse.
If shift is held down during the selection or click,
the search looks backward in the file.
.PP .PP
In all these actions, the mouse motion is not done if the text is a null string In all these actions, the mouse motion is not done if the text is a null string
within a non-null selected string in the tag, so that (for example) complex regular expressions within a non-null selected string in the tag, so that (for example) complex regular expressions

View file

@ -2,7 +2,7 @@
.SH NAME .SH NAME
devdraw \- draw device simulator devdraw \- draw device simulator
.SH SYNOPSIS .SH SYNOPSIS
invoked via invoked via
.I initdraw .I initdraw
(see (see
.MR graphics (3) ) .MR graphics (3) )
@ -10,19 +10,71 @@ invoked via
.I Devdraw .I Devdraw
serves a custom graphics protocol and is the only program serves a custom graphics protocol and is the only program
that talks directly to X window servers. that talks directly to X window servers.
On Macintosh, setting .PP
.BI devdrawretina .SS "Apple macOS
to .PP
.BI 1 On macOS, because a laptop trackpad click only has one button (the trackpad itself)
will cause Option-click is button 2, and Command-click is button 3.
.I devdraw While the main mouse button is held down,
to use all available physical pixels on a retina display. Control, Option, and Command serve as simulated buttons 1, 2, 3 for chording in
.MR acme (4) .
For example, the 1-3 pasting chord in acme can be executed by
highlighting text while holding down the trackpad button
and then, while still holding down the button, pressing the Command key.
.PP
As usual, buttons 4 and 5 represent a scroll wheel.
Two-finger scrolling on the trackpad sends those button events.
.PP
Holding down shift while clicking adds 5 to the button number.
For example, Command-Click is button 3, so Command-Shift-Click is button 8.
Most programs do not respond to those buttons; one notable exception is
.MR acme (1) ,
which interprets button 8 (shifted button 3) as a reverse search.
.PP
Typing Command-F toggles full screen mode.
.PP
.I Devdraw
automatically detects high-resolution (retina) displays.
For debugging, typing Command-R toggles retina mode.
.PP
Other than the special cases mentioned above,
holding down Command while typing a character
.B Kcmd
(0xF100)
plus that character.
Some programs (notably
.IR acme (1))
recognize standard keyboard shortcuts such as
Command-Z (undo), Command-Shift-Z (redo),
Command-X (cut), and Command-V (paste).
.SS "X Windows
.PP
On Unix systems, Control-click is mouse button 2,
and Alt-click is mouse button 3.
While the main mouse button is held down,
Control and Alt serve as simulated buttons 2, 3 for chording in
.MR acme (4) .
For example, the 1-3 pasting chord in acme can be executed by
highlighting text while holding down the trackpad button
and then, while still holding down the button, pressing the Alt key.
.PP
Because the Control and Alt keys have other meanings
(see
.MR keyboard (7)
for the Alt key's meaning)
and there is no third modifier key like on the Mac,
there is no way to type
.B Kcmd
variants,
so there is no access to keyboard shortcuts for
undo, redo, cut, and paste.
.SH SOURCE .SH SOURCE
.B \*9/src/cmd/devdraw .B \*9/src/cmd/devdraw
.SH "SEE ALSO .SH "SEE ALSO
.MR draw (3) , .MR draw (3) ,
.MR drawfcall (3) , .MR drawfcall (3) ,
.MR graphics (3) .MR graphics (3) ,
.MR keyboard (7)
.SH BUGS .SH BUGS
.I Devdraw .I Devdraw
should probably present a standard 9P server should probably present a standard 9P server

View file

@ -361,6 +361,10 @@ for text inserted to the tag,
for a button 3 action in the body, for a button 3 action in the body,
.B l .B l
for a button 3 action in the tag, for a button 3 action in the tag,
.B R
for a shifted button 3 action in the body,
.B r
for a shifted button 3 action in the tag,
.B X .B X
for a button 2 action in the body, and for a button 2 action in the body, and
.B x .B x

View file

@ -62,16 +62,11 @@ Any rune can be typed using a compose key followed by several
other keys. other keys.
The compose key is also generally near the lower right of the main key area: The compose key is also generally near the lower right of the main key area:
the the
.B NUM PAD
key on the Gnot, the
.B Alternate
key on the Next, the
.B Compose
key on the SLC, the
.B Option .B Option
key on the Magnum, and either key on the Mac
and the
.B Alt .B Alt
key on the PC. key on Unix systems.
To type a single rune with the value specified by To type a single rune with the value specified by
a given four-digit hexadecimal number, a given four-digit hexadecimal number,
type the compose key, type the compose key,

View file

@ -1,4 +1,5 @@
#include <u.h> #include <u.h>
#include <pwd.h>
#include <signal.h> #include <signal.h>
#include <libc.h> #include <libc.h>
#include <ctype.h> #include <ctype.h>
@ -56,7 +57,7 @@ threadmaybackground(void)
void void
threadmain(int argc, char *argv[]) threadmain(int argc, char *argv[])
{ {
char *p; char *p, *env;
rfork(RFNOTEG); rfork(RFNOTEG);
font = nil; font = nil;
@ -64,6 +65,25 @@ threadmain(int argc, char *argv[])
mainpid = getpid(); mainpid = getpid();
messagesize = 8192; 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{ ARGBEGIN{
default: default:
usage(); usage();

View file

@ -518,6 +518,7 @@ mousethread(void *v)
Mouse m; Mouse m;
char *act; char *act;
enum { MResize, MMouse, MPlumb, MWarnings, NMALT }; enum { MResize, MMouse, MPlumb, MWarnings, NMALT };
enum { Shift = 5 };
static Alt alts[NMALT+1]; static Alt alts[NMALT+1];
USED(v); USED(v);
@ -661,9 +662,9 @@ mousethread(void *v)
}else if(m.buttons & 2){ }else if(m.buttons & 2){
if(textselect2(t, &q0, &q1, &argt)) if(textselect2(t, &q0, &q1, &argt))
execute(t, q0, q1, FALSE, argt); execute(t, q0, q1, FALSE, argt);
}else if(m.buttons & 4){ }else if(m.buttons & (4|(4<<Shift))){
if(textselect3(t, &q0, &q1)) if(textselect3(t, &q0, &q1))
look3(t, q0, q1, FALSE); look3(t, q0, q1, FALSE, (m.buttons&(4<<Shift))!=0);
} }
if(w) if(w)
winunlock(w); winunlock(w);
@ -770,7 +771,7 @@ waitthread(void *v)
pids = p; pids = p;
} }
}else{ }else{
if(search(t, c->name, c->nname)){ if(search(t, c->name, c->nname, FALSE)){
textdelete(t, t->q0, t->q1, TRUE); textdelete(t, t->q0, t->q1, TRUE);
textsetselect(t, 0, 0); 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 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 dir, size, npat;
int prevc, c, nc, n; 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; r = ar;
q = q0; q = q0;
dir = None; dir = None;
if(reverse)
dir = Back;
size = Line; size = Line;
c = 0; c = 0;
while(q < q1){ 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 $ */ if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */
r.q1 = t->file->b.nc; r.q1 = t->file->b.nc;
else{ 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; r.q1 = nr.q1;
} }
*qp = q; *qp = q;

View file

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

View file

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

View file

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

View file

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

View file

@ -486,7 +486,7 @@ xfidwrite(Xfid *x)
t = &w->body; t = &w->body;
wincommit(w, t); wincommit(w, t);
eval = TRUE; 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); free(r);
if(nb < nr){ if(nb < nr){
respond(x, &fc, Ebadaddr); respond(x, &fc, Ebadaddr);
@ -900,7 +900,11 @@ xfideventwrite(Xfid *x, Window *w)
break; break;
case 'l': case 'l':
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; break;
default: default:
qunlock(&row.lk); qunlock(&row.lk);

View file

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