mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
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
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue