Although a lot can be done with simple scripts and Wily,
some applications will need finer control. Wily can act as a
"user interface server". Clients can create and manipulate
windows, and/or monitor events which happen in windows,
by sending and receiving messages.
There are two "levels" to the interface: an "RPC" level,
where the library looks after low-level details of queueing, packing
and unpacking messages, and a lower-level interface dealing more
directly with message packets.
Handle* rpc_init (int fd);
Create a new RPC handle to use file descriptor fd, which
was probably returned from client_connect
rpc_init cannot fail.
Bool rpc_isconnected(Handle*h);
Return whether or not h is still connected. If the RPC
library starts receiving gibberish messages, it will cut the
connection.
void rpc_freehandle(Handle*h);
Release any resources used by h, and free h
itself.
Requests
If there's any sort of failure, all of these functions return a
pointer to an error message, which is stored in a static buffer and
only guaranteed to remain valid until the next rpc_*
function is called. After a failure, it's possible that the connection
to wily has been lost. This should be checked using
rpc_isconnected
If successful, these functions return (char*)0.
List existing windows
char* rpc_list (Handle*, char **bufptr);
If successful, allocates a string,
and stores a pointer to it in bufptr. It is the programmer's
responsibility to free(*bufptr).
The string contains one line for each window currently open in Wily.
Each line contains the name of the window, some whitespace, and a
unique number which identifies the window. The window identifiers
are not reused within an invocation of Wily.
Below is some example output from rpc_list:
/n/staff/u13/pgrad/gary/src/wily/Doc/C.html 45
/n/staff/u13/pgrad/gary/src/wily/Doc/index.html 41
/n/staff/u13/pgrad/gary/src/wily/Doc/ 40
/n/staff/u13/pgrad/gary/guide 0
Open or create a window
char* rpc_new (Handle*, char *s, Id*id, ushort backup);
Create or open window with name s. If
Wily already has a window named 's', it uses that window,
otherwise it creates a new window.
The identifier for the opened/created window will be stored in
id.
If this request creates (not just opens) the window,
Wily will make sure backups are kept for the window (and indicate
when the window is dirty) if and only if backup is set.
Request events from a window
char* rpc_attach (Handle*, Id w, ushort mask);
Asks Wily to send us events which happen in window w
and match event bitmask mask.
Each window can be sending events to at most one remote process.
The window sends only events which match its event bitmask.
An event bitmask is formed by ORing some combination of (WEexec, WEgoto, WEdestroy, WEreplace) (explained further below).
rpc_attach will
fail if w doesn't exist, or is already sending its
events somewhere else.
To stop receiving events from a window,
use an rpc_attach with a mask of 0.
Change a window's name
char* rpc_setname (Handle*, Id w, char *s);
Set the name of window w to s.
Change a window's "tools"
char* rpc_settools (Handle*, Id w, char *s);
Set the tools section of w to s
Read data from a window
char* rpc_read (Handle*, Id w, Range r, char*buf);
Read range r from w into buf,
which must have enough space (UTFmax * RLEN(r)).
The range r means the Rune offsets in w
>= r.p0 and < r.p1. Don't forget
that each Rune will be potentially encoded in UTFmax
bytes.
rpc_read fails if
r is not fully contained in window w.
rpc_goto may be useful to obtain legal ranges.
Insert, delete or replace text
char* rpc_replace (Handle*, Id w, Range r, char*s);
Replace range r in w with UTF string s
Note that insertion and deletion are special
cases of replacement.
Ask Wily to execute a command
char* rpc_exec (Handle*, Id w , char *s);
Cause Wily to act as though s were selected in
w with button 2.
Note that builtin functions (e.g. Del) can
also be executed with rpc_exec.
Ask Wily to "goto" a file or location
char* rpc_goto (Handle*, Id *w , Range* r, char*s, ushort flag);
Cause Wily to act as though s were selected in
w with button 3.
If this makes Wily do a search within '*w', the start position
for the search is usually taken from '*r'.
The search can instead start from the current selection of the
file if r->p0 > r->p1. If there are multiple
views of the same file, one is chosen arbitrarily.
If the search is successful, '*w' and '*r' are set to the window
and range found by the search. The range found will be selected
and highlighted if and only if 'flag' is set.
Hint: rpc_goto can be used to find useful
ranges for rpc_read and rpc_replace. Don't forget that the search string
can be any address that Wily understands, e.g. :4 or :, or :.,
Events
int rpc_event (Handle*h, Msg *m);
Block until an event is received by h and fill
in m. Returns 0 for success, -1 for failure.
After a successful call to rpc_event,
you will need to free(m->s).
char *rpc_bounce(Handle *h, Msg *m)
Returns m to Wily, and frees m->s.
A precondition is that
m must be an event previously filled
in by rpc_event.
Useful for events which we receive but we'd rather Wily
took the default action on.
Bool rpc_event_iswaiting(Handle*h);
Returns true if rpc_event could be called
without needing to block. Only useful if your program
is reading from other input sources as well. (e.g. see win.c)
Message-Passing Interface
struct Msg {
Mtype t; /* message type */
Id m; /* message */
Id w; /* window */
Range r;
uchar flag;
char *s;
};
All the fields except the message
type are optional. The string s is always null-terminated,
is in UTF format, must be a complete UTF sequence,
and is of zero length if not being used.
These are the message types declared in msg.h, with brief
descriptions, and important parameters:
Request/Reply/Error
WRerror(s)
Message type returned by wily if there's an error with
some request. s contains an error message. On the other
hand, if the request completes successfully wily returns a message with
message type one greater than the message type of the request.
WMlist
Asks wily to send a list of windows currently displayed.
WRlist(s)
Wily's reply to WMlist. Includes a string containing
one line per active window. Each line contains a name and an id (as a
textual number) separated by whitespace.
WMnew(s,flag)
Asks wily to create a window with
a given label (which may be an existing file).
If and only if flag is set, backups will be
kept for the new window.
WRnew(w)
The id of the newly created window.
WMattach(w,flag)
Asks wily to send to the client
events associated with this window, and matching
the event mask set in flag
WRattach()
WMdetach(w)
Asks wily to stop sending to the client
events associated with this window.
WRdetach()
WMsetname(w,s)
Change the name of this window.
WRsetname()
WMsettools(w,s)
Change the tools for this window.
Tools are simply words appearing in the
tag of a window, after the window name and
before the 'pipe' symbol. They are (will be)
automatically maintained, i.e. they will be replaced
if accidentally deleted.
WRsettools()
WMread(w,r)
Read the text from w in range r.
WRread(s)
The requested text, as a UTF string.
WMreplace(w,r,s)
Replace the text from w in range r with UTF string
s
WRreplace()
WMexec(w,s)
Act as if s had been clicked with b2
in w
WRexec()
WMgoto(w,r,flag,s)
Act as if s had been clicked with B3 in w at
r. If flag is set then "dot" is set by wily,
otherwise we return the window and range that would have been jumped
to, but don't actually change "dot".
WRgoto(w,r)
The window and range we went to.
WMfencepost()
Not used for any message. Messages with Mtype less than
WMfencepost are to do with our requests. Messages with Mtype
greater than WMfencepost are events.
Events
These are the messages sent by Wily to clients who request
to be notified of events in a particular window using WMattach
The event types are used to form a mask to be given as a
parameter to the WMattach request. For example, to
request only exec and goto events, set
m.f = WEexec|WEgoto before sending message m
WEexec(w,s)
s was selected with the middle (execute)
button somewhere in w
WEgoto(w,r,s)
s was selected with the right (goto)
button at r in w
WEdestroy(w)
w has been destroyed.
WEreplace(w,r,s)
The text at r in w was
replaced by s.
Packing and Unpacking Messages
int msg_size (Msg *m);
Returns the size of buffer that will be needed to "flatten"
m
void msg_flatten (Msg*m, char*buf);
"Flatten" m into buf, which must have enough storage
space allocated.
ulong msg_bufsize (char*buf);
Returns the total size of the flattened message starting at
buf. Assumes that at least HSIZE bytes are stored in
buf. A useful macro is #define FULLMSG(ptr,n) ( (n) >=
HSIZE && (n) >= msg_bufsize(ptr) )
int msg_init (Msg*m, char*buf);
The reverse of msg_flatten. Fills in the fields of 'm' using
the flat representation starting at buf Msg_init
assumes that buf holds the complete message. m->s
will point to an area within buf, but buf itself is
not modified.
void msg_print (Msg *m);
Print a human-readable form of m to stderr