See changelog for
latest changes.
The most updated versions of this document will be found on one of the
following sites:
- http://members.xoom.com/sprimerix
- http://www.geocities.com/SiliconValley/Bit/1962
There are currently two different ways of extending Sula Primerix and
of writing scripts.
I. Using internal programming
This applies to the client release which is obtained by enabling guile
support before compiling. You have to be familiar with the Scheme programming
language in order to understand this.
II. Through external programming (named connections)
No knowledge of a particular programming language is required. You use any
language that can read from standard input and write to standard output. It's
like CGI scripting.
This is Part I of the programming guide. It describes how to program
and extend SPX using Scheme. Part II describes named connections.
2. Programming with Scheme
2.0 Terms and definitions
2.1 Programmer's procedures
2.2 Global variables
DISCLAIMER
The Scheme scriptlets and examples used in this documentation are NOT
intended to demonstrate good Scheme programming techniques. Some examples
may even contain errors. Please send any corections to fotang@techie.com.
2/1999.
(+ 1 2)
==> 3
(strerror 100)
==> Network is down
(bind-key "Escape" (lambda(w k s) (gs-hide-console(gs-console-visible?))))
(server "irc.eskimo.com")
(gs-ctcp-command? name)
Returns true if <name> is currently a valid client CTCP command,
else false.
(gs-new-command name description proc)
(gs-exec "/alias alias_name (procedure_name
\"$1-\"$_)")
(gs-delete-command name)
gs-new-command creates a new client command name. New
commands may be created at any time. description is a brief description
of the command (see commands APROPOS and WHATIS).
proc is the Scheme procedure to be bound to the command. proc
should take two arguments:
(define (foo text w) (gs-execute w "msg * " (string-upcase! text)))
Next, we bind this procedure to an alias "up":
(gs-exec "/alias up (foo \"$1-\" $_)")
[This is equivalent to manually typing /alias up (foo "$1-" $_).]
Now,
/up This is all CAPS!
will be expanded to
(foo "This is all CAPS!" 0)
thereby sending the messsage "THIS IS ALL CAPS!" to whomever the current
target is. $1- expands to user input starting from the second word; $_
expands to the number of the window from which the command came.
gs-delete-command removes the named command. Apart from built-in
commands, all commands may be removed. Built-in commands cannot be removed.
This really does not matter since it is possible to have multiple versions
of a command running at the same time. That will be explained in a while.
gs-delete-command returns #f on failure and true if successful.
Example 0
/alias cd (chdir "$1-")(gs-echo (string-append "Current dir
set to " (getcwd)) $_)
Now,
/cd /tmp
expands to
(chdir "/tmp")(gs-echo (string-append "Current dir
set to " (getcwd)) 0)
if typed in window 1.
Example 1
;; Use /n+ to switch to next nickname
;; Use /n- to switch to previous nickname
(gs-exec "alias n+ (gs-exec \"nick +\" $_)")
(gs-exec "alias n- (gs-exec \"nick -\" $_)")
Example 2
(define (my_command_handler m window)
(let ((command_name (next-word m 0)))
(cond
((string-ci=? command_name
"foo") (display "kung-fu!\n"))
((string-ci=? command_name
"bar")
(if(and
(not(string-null? (next-word m 1)))
(string-ci=? "-help" (next-word m 1))) ;; "/help bar"
(display "help for bar: help help!\n")
(display "Free beer for the world!!\n")))
(else (display (string-append
command_name ": something else\n"))))))
(gs-new-command "foo" "foo foo foo" my_command_handler)
(gs-new-command "bar" "ha bar blab bah" my_command_handler)
(gs-new-command "junk" "junk donk junk" my_command_handler)
We have just created 3 new commands foo, bar and junk. Only bar offers
help:
/help bar ==> "help for bar: help help!"
Four different instances of a command may exist simultaneously:
alias -> script-defined -> externally-defined -> built-in Particular versions of a command may be excluded from the search by placing "exclusion" characters before the command name. Any number of exclusion characters may be given. The following exclusion characters are defined:
Assuming the command character to be "/", type the following and see
what happens!
You can still define aliases and commands named "/", ";", "?", or ",".
Example:
Warning Be careful not to define a command or an alias in terms
of itself. That would lead to an infinite loop. This is a No-no:
|
gs-new-ctcp-command is the same as (gs-new-command) except that
it creates a CTCP command instead of a normal client command.
gs-delete-ctcp-command removes a CTCP command. Built-in CTCP
command may only be replaced; they cannot be removed completely.
It is probably superfluous to offer procedures for creating new CTCP commands. Instead, it may be more elegant to set hooks on CTCP_ALL. The procedure gs-new-ctcp-command will probably be removed in the future.
Example 0
(gs-new-ctcp-command "OOPS" "ooops, heaven help you!" (lambda(m w) (define sender (next-word m 1)) (define nick (sender2nick sender)) (if(not(gs-set? 'verbose_ctcp)) (gs-echo (string-append "Got a CTCP oops from " sender "!") w 1)) (gs-execute w "/reply " nick " OOPS Enough is enough!")))Now, if jjj!lll@mmm.nn types "/ctcp your_nick oops" and verbose_ctcp is /SET off, you'll see this:
Got a CTCP oops from jjj!lll@mmm.nn!
while they'll see something like the following:
CTCP OOPS reply from your_nick: Enough is enough!
If they typed "/ctcp your_nick help oops", they'd see something like the following:
CTCP HELP reply from your_nick: ooops, heaven help you!
Example 1
(gs-new-ctcp-command "CWD" "Sends my cwd" (lambda(m w) (define sender (gs-next-string m 2)) (define nick (sender2nick sender)) (if(not(gs-set? 'verbose_ctcp)) (gs-echo (string-append "Got a CTCP cwd from " sender) w 1)) (gs-execute w "reply " nick " CWD " (getcwd))))
gs-exec executes the client command contained in string as if
the user had actually typed it in a window. If no window is given, a value
is chosen which depends on the command being executed. Commands that send
something to an IRC server look for the first connected window. Others
use the first window found, while a command such as SET uses -1.
gs-execute is a wrapper for gs-exec. It's arguments are
a list of objects which will be printed into a string and then passed on
to gs-exec.
Trouble with the xforms version of SPX: |
The client commands SERVER and ACHAT should not be used to initiate
connections by executing them via gs-exec, unless there is at least
one existing channel window. The result would probably be a Bus error.
The reason is that the commands SERVER and ACHAT create windows if none
are available. Routines that create windows never return (they loop on
forever, receiving and working X events).
Solution: Use the procedure server to connect to servers. The procedure is defined in sula-boot and described under the Miscellaneous section further below. |
Example 0
(gs-exec "kick #test xtz no reason!")
(gs-exec "msg * hello there!" 0)
Example 1
(let loop((x 5))
(gs-execute 0 "msg * (x,sin(x)) =(" x "," (sin x) ")")
(if (> x 0) (loop (- x 1))))
This sends sine values to the current target (channel, query nick or
DCC) on window 1:
<sciz> (x,sin(x)) =(5,-0.958924274663138)
<sciz> (x,sin(x)) =(4,-0.756802495307928)
<sciz> (x,sin(x)) =(3,0.141120008059867)
<sciz> (x,sin(x)) =(2,0.909297426825682)
<sciz> (x,sin(x)) =(1,0.841470984807897)
<sciz> (x,sin(x)) =(0,0.0)
Returns #t if person is current being ignored for message type what, otherwise #f. Use "/help IGNORE" to get information on how to use the IGNORE command.
person is any pattern, e.g. ds!bla@weee. It may contain shell
wildcards (*, ?, [] etc).
what is a string or symbol representing a message type. The
following mesasge types are documented in the IGNORE help file:
Ignore type | Definition |
'abs | absolutely ignored (everything imaginable) |
'all | all message types and DCC requests (CTCP still allowed) |
'ctcp_all | all CTCPs (ping, time etc.) |
'everythang | same as 'abs |
'dcc | DCC requests(chat,file send,...) |
'invites | channel invitations |
'msg | private messages |
'misc | nick, mode, topic changes by the person, plus all else (kicks etc.) |
'notes | what are notes?? The NOTE command, probably |
'pubmsg | channel messages from the person |
'pubnotices | channel notices |
Examples:
(gs-exec "ignore *!*@*.com dcc invites")
(gs-ignored? "fooz!*weezy@techie.com" 'dcc) ==> #t
(gs-ignored? "fooz!*weezy@techie.com" 'msg) ==> #f
These procedures create and handle named connections. A named connection
is either a network connection, or a connection to an executable on your
computer. See part II of the programming guide
(Programming-2.txt) for details about named connections.
gs-run and gs-connect are Scheme implementations of the
commands RUN and CONNECT respectively.
gs-nc-list returns a list of the indices (ID's) of all named
connections.
gs-nc takes an index and returns a list containing information
about the connection (id fd name type other).
type is either 'tcp/ip,'exec, or 'unknown.
name is the name of the connection.
if type is 'exec, other is a list with 2 elements: (PID program).
If type is 'tcp/ip, other is a list with 4 elements: remote_host
port IP arguments.
arguments contains the optional string that was passed to the
RUN command or to gs-connect. arguments is #f is no optional
string was used.
Examples
(gs-run "foooooo" "/home/tano/bin/bots/decy.pl")
(gs-connect "fserv" "jupiter" 6200)
(gs-nc-list) ==> (1 0)
(gs-nc 0)==> (0 8 "fserv" tcp/ip ("jupiter" 6200 "194.153.256.06"
#f))
(gs-nc 1)==> (1 7 "foooooo" exec (11266 "/home/tano/bin/bots/decy.pl"))
(id fd name type PID program)
Related hook types:
(gs-set? name)
(gs-set! name value)
gs-set? returns the value of the built-in SET variable. #f is
returned if there is no such variable. #f is also returned if a Boolean
variable is currently set off.
gs-set! sets the value of the built-in SET variable to the specified
value. For Boolean variables, value is either #t or #f; everything
else toggles the value.
gs-set? and gs-set! are Scheme implementations of the
SET command. They are faster than (gs-exec "set ...")
(gs-remove-variable name)
Removes the named variable. After this, the variable seizes to exist
and the SET command returns "no such variable". Built-in variables cannot
be removed.
(gs-new-variable type name [proc])
Creates a new variable. The variable will be of type type and
will be called name. Type is any of the following: "boolean", "number",
"string", or "char". There is no difference between the new variable and
built-in SET variables, except that variables defined this way may also
be removed. variable is stored in the same tree as all built-in variables.
If proc is specified and is not false (#f), then it will be
called each time the value of the variable changes. proc should
take 3 arguments:
(gs-new-variable 'string "email-address")
(gs-new-variable 'boolean 'anti-idle)
(gs-set! 'anti-idle #t)
(display (gs-set? 'finger))(newline)
(display "Userinfo: ")(display(gs-set? 'userinfo))
(write-line (gs-set? 'fmt_other_part))
(gs-set! 'finger_reply "Go finger your very own self. $X over and
out.")
(gs-set! 'autochat #f)
(gs-set! 'tmout_tips 500)
(gs-add-io-watch fd proc)
This adds the file/socket descriptor fd to the main select loop.
(gs-stop-io-watch fd)
Removes the descriptor from the select loop. The client stops watching
it for data.
proc is the procedure to call whenever data is read from the connection. proc should take 3 arguments:
len = 0 => connection was closed. len < 0 => error occurred while reading from the connection. len > 0 => the data size in bytes.After len <= 0, Sula stops watching the fd automatically. It is then up to you to close the socket, pipe or whatever the fd was based on, as well as the descriptor.
A silly example: Let's create an IRC client within the main client (read-only)
(define ircserver "irc.gimp.org")(define ircport 6667)(define addr
(car(hostent:addr-list (gethostbyname ircserver))))
(define sock (socket AF_INET SOCK_STREAM 0))
(connect sock AF_INET addr ircport)
(send sock "NICK xxxzzz\n")
(send sock (string-append "USER " (getenv "USER") " bla.blah.zz
me.yabadoo.com :Go to hell\n"))
(define fd (port->fdes sock))
(define (sub-irc fd data len)
(cond
((= len 0)
(display "connection closed\n")
(close sock))
((< len 0)
(display "read error\n")
(close sock))
((string-ci=? "PING" (next-word data 0))
(send sock (string-append "PONG
" (next-word data 1) "\n")))
(else
(case (string->number (next-word
data 1))
((432 433 437) (send
sock (display2string "NICK x_y_z" (gs-srandom) "\n")))
(else (display data))))))
(gs-add-io-watch fd sub-irc)
Examples
(gs-alarm 30 do-something)
(gs-clock 'ref 200 '(20 15 30 20 12 1998) do-something)
(gs-clock '(20 15) do-something)
gs-alarm and gs-clock are used for setting timers. Timers are used for carrying out tasks at specific intervals (alarm), or for performing a task on a specified date (clock). A timer is removed when it expires.
If no reference number (ID) is given, a unique negative ID will be computed and assigned. Both procedures return the ID of the timer just created.
gs-delete-clock and gs-delete-alarm remove all timers
having the specified ID.
gs-timer-list returns a list of pairs. The car of each pair
is the ID of a timer and the cdr, #t or #f. #t means that the ID refers
to an alarm; #f denotes a clock.
Examples
- Display some message every 20 seconds:
(gs-alarm 0 (lambda(ref at) (display "starting auto message...\n") (define (alrm_set nr) (gs-alarm 'ref nr 20 (lambda(no t) (display (gs-display "Alarm number " no " expired at " t)) (alrm_set no)))) (alrm_set ref)))- When kicked off a channel, wait 10 seconds before rejoining channel.
- Shutdown client at 22:30:15 today:
(gs-clock '(22 30 15) (lambda(ref arg) (gs-exit 0)))
Returns a list of all existing windows.
Example: /(write-line (gs-window-list)) ==> (1 0)
(gs-create-window)
Create and display a new window. Return value is unspecified.
(gs-kill-window window force)
(force-window-kill window)
Shut down a window. If force is #f, hooks set on WINDOW_DESTROY
will not be checked.
force-window-kill is a convenience procedure defined as (gs-kill-windowwindow
#t).
(window-count)
Returns the total number of existing channel windows.
(window-valid? window)
Returns #t if window is a valid window number.
(gs-window-server [window])
(gs-window-server2 window)
These procedures return a server object representing the server with
which window is associated. Returns an empty list (or null? ?) if
no server is associated with the window.
gs-window-server2 is faster than gs-window-server. However,
gs-window-server2
returns just 3 components of the server object: the socket descriptor,
the nickname, and the away status. The values of other components are not
defined.
To remove the background image, speciffy an empty string "" as image name.
gs-set-input-bg-colour str_colour int_window
gs-set-input-fg-colour str_colour int_window
gs-set-input-font str_font int_window
These change values of the input line of a channel window. If the window
number is is -1, they operate on the input line of the console window.
gs-set-status-bg-pixmap str_file int_window
gs-set-status-bg-colour str_colour int_window
gs-set-status-font str_font int_window
gs-set-status-fg-colour str_colour int_window
These procedures set the back/foreground and font of the status line of the given
channel window.
gs-set-cclock-font str_font
gs-set-cclock-fg-colour str_colour
gs-set-cclock-bg-colour str_colour
These procedures configure the console clock.
All functions returm #f on failure on #t on success.
Examples
Type the following and see what happens...
(gs-set-cclock-bg-colour "brown") (gs-create-window) (gs-set-window-bg-colour "blue" 0) (gs-set-status-bg-pixmap "conf/pixmaps/sky.xpm" 0 1) (gs-set-input-bg-colour "rgbi:0.48/0.48/0.58" -1) (gs-set-status-font "-*-terminator two-medium-r-*-*-*-*-*-*-*-*-*-*" 0)
Hello | there! Oh well! |
Colour indices 0-15 are already defined when client starts up:
Index | colour name/spec |
0 | black |
1 | red |
2 | green |
3 | yellow |
4 | blue |
5 | magenta |
6 | cyan |
7 | white |
8 | rgb:40/130/78 (slateblue) |
9 | rgb:69/69/69 (dimgray) |
10 | rgb:5f/9e/a0 (cadet blue) |
11 | rgb:98/fb/98 (pale green) |
12 | rosybrown |
13 | light pink |
14 | plum |
15 | mediumpurple |
To allocate a new colour, use the folowing procedure:
(gs-parse-colour str_colour_spec) str_colour_spec is a valid colour specification , e.g. "blue" or rgb:0/0/ff or rgbi:0/0/1.0.
gs-parse-colour returns the index of the newly allocated colour,
or #f if the colour could not be parsed or allocated. The returned index
is always greated then 15.
Example:
spx> (define c (gs-parse-colour "rgb:fa/54/6d"))
spx> (say "@C"c"testing..")
A <a
href="http://members.xoom.com/sprimerix/scripts/colours.scm">simple
script</a> is available which displays all currently defined colours
and their indices in all possible background/foreground combinations. The
procedure to use is print-colours. See $libdir/scripts for a copy of the
scripts.
server:fd - procedure
Returns the socket descriptor for the connection to the server.
server:connected? - predicate
Returns #t if a connection to the server exists, else #f.
server:nick - procedure
Returns a string containing your nickname on the server.
server:irc-name - procedure
Returns a string containing your IRC name.
server:modes - procedure
Returns your server modes in a string.
server:alias - procedure
Returns the name of the server as was passed to the SERVER command.
server:name - procedure
Returns the name of the server.
Example:
Upon connecting to a server, check to see whether it's the server to
which you wanted to connect.
(gs-on "#001" 123 "*" (lambda(m w)
(define server (gs-window-server w))
(if(not(string-ci=? (server:name server) (server:alias server)))
(gs-message "You landed on a different
server..." w))))
server:port - procedure
server:last-invite - procedure
Returns a string containing the name of the channel on this server to which you were last invited.
server:away? -predicate
Returns #t if you're currently marked as being away, else #f.
server:read - procedure
Returns the number of bytes read from server so far.
server:wrote - procedure
Returns the number of bytes written to server so far.
server:nickgroup - procedure
The number of the nickname group bound to the server.
server:nickgroup! server number
Changes server nickname group for server object server to number
n.
server:start-time - procedure
Returns the time at which the last connection to server was established.
This is the number of seconds since 1970 or whatever.
Other server specific procedures
(servers-socket-fd)
Returns a list of pairs (server-socket-descriptor . your-nick-on-the-server)
for all server connections. The socket descriptor is whole number; your
nick is of course a string.
(gs-raw-write fd string)
This procedure writes the string directly to the file or socket descriptor
fd, thereby bypassing any parsing by the client. This may come in handy
for quickly quoting to a server/DCC chat connection.
??? alternatively, but probably slower and less elegant,
(define port (fdopen fd "w"))
(send port string)
???
(channel-last-joined [window])
(channel-last-parted [window])
Each returns a pair (<name> . <key>) describing channel last
joined or last left, respectively.
(gs-server-channels [<server name> [<port>]])
Returns a list of channels you are in. Server name defaults to all
servers. Port defaults to all ports; a negative value will be taken to
mean the default IRC port, usually 6667.
The value returned by the procedure has the following format:
((channel1 server1 port1)(channel2 server2 port2) ...)
This procedure is redundant since the same information can be obtained by looking at the window list.
(gs-window-channels [window])
Returns a list of channel objects representing the channels on the window. Also see (gs-channel).
(gs-channel [channel-name [window]])
Takes the name of a channel and returns a channel object describing
the channel.
Example:
(define test (gs-channel "#test"))
(define help (gs-channel "#help" 1))
(gs-channel2 channel-name window)
This is a faster procedure than gs-channel. However, gs-channel2
returns only 2 components of the channel object: channel modes and the
channel key. All other components are set to #f. Also, you must supply
both channel name and window number.
A channel object may be passed to the following procedures.
channel:name
Returns a string. This is the channel name. It is the name of the channel
when it was created. You may be on "#test" but the real channel name might
be "#TeSt".
channel:server
On which server is the channel? This procedure returns a server object.
See (gs-window-server).
channel:window
Returns an integer. That is the window hosting the channel.
channel:modes
Returns a string containing channel modes.
channel:op?
Returns #t if you are channel op, else #f.
channel:voice?
Can you speak on the channel? Returns #t if so, else #f.
channel:limit
Returns channel limit as integer.
channel:key
Returns a string containing the channel key. #f is returned if no key
is set.
channel:topic
Returns the channel topic.
(update-user-list channel)
Updates info about people on this channel. This usually is not necessary.
Equivalent to /WHO -update.
dcc:fd
Socket descriptor for connection. The descriptor can also be passed
as argument to gs-raw-write.
dcc:window
The window hosting the chat.
dcc:nick
The nick to which DCC was established.
dcc:IP
Their address in dotted numeric form.
dcc:read
The number of bytes written to the connection.
dcc:written
Number of bytes read.
(gs-channel-users)
(gs-channel-users channel_name)
(gs-channel-users channel_name window)
This procedure returns lists of user objects representing people in the channel. Each of the following procedures accepts a user object.
user:window
The number of the window having the channel.
user:channel
Channel name.
user:nick
User's nick.
user:modes
Their channel mode. I don't know what this should be. It is currently
either "H" or "H@".
user:address
The user@host.domain string for the person.
user:irc-name
The person's IRC name. If the value is #f, it is unknown. Update user
list and try again (using, for example, either the command "/WHO -update"
or the procedure update-user-list).
gs-create-nickgroup creates a nick name group with the name <label>.
<label> is a string. This procedure returns the ID of the group that
was created. This ID is a small positive whole number.
gs-addto-nickgroup adds a nickname to nickname group with ID
<group>.
gs-list-nickgroups returns a list of pairs representing all
nickname groups. The car of the pair is the ID. The cdr is the group name
(label) as was given to gs-create-nickgroup.
gs-nickgroup returns a list object containing the nicknames
in a group.
gs-server-nickgroup! changes the nickname group for a server
object. This procedure is the same as the procedure server:nickgroup!.
Nickname groups allow the user to define groups of nicknames and bind
them to servers. Each group is a doubly linked circular list which can
be traversed using "/nick +" and "/nick -". See "/help nick".
Nickname groups can be saved or loaded using the NICK command: /nick
-load, /nick -save.
Example of how to create nickname groups
;; create a nickname group and add these nicks to it:
;; "xoOMm", "speedo", "wham", "bamX"
(let* ((group (gs-create-nickgroup "Test nick group!"))) (for-each (lambda(nick) (gs-addto-nickgroup group nick)) '("xoOMm" "speedo" "wham" "bamX"))))Now,
(display (gs-list-nickgroups))(newline)
==> ((1 Test nick group!)(0 default))
(gs-nickgroup 1)
==> (xoOMm speedo wham bamX mtf)
[TODO: add delete group]
gs-create-notify-group <name>
gs-notify-name->id <name>
gs-notify-id->name <id>
gs-delete-notify-group <id>
gs-add-to-notify-group <id> <nickname>
gs-delete-from-notify-group <id> <nickname>
gs-list-notify-groups
gs-query-notify-group <id>
gs-add-server-notify-group <server_object> <id>
gs-drop-server-notify-group <server_object> <id>
gs-list-server-notify-groups <server_object>
Most procedures accept an id. This is the ID of a notify group: each
notify group is represented by a numeric index.
gs-create-notify-group creates a new notify group called <name>.
The group is initially empty. The procedure returns the ID of the new group,
or #f if an error occured. If the group already existed, the ID is returned.
gs-notify-name->id returns the ID of a notify group.
gs-notify-id->name returns the name associated with an ID.
gs-delete-notify-group removes a group from memory.
gs-add-to-notify-group adds the given name to the notify group. If the given name is already in the list, command is ignored.
gs-delete-from-notify-group removes the given name from a notify group. If the name isn't present in the group, command is ignored.
gs-list-notify-groups returns a list of pairs, each pair representing a notify group. The car field of the pair is the ID of the group; the cdr field is the name of the group.
gs-query-notify-group returns a list of pairs. Each pair stands for a person in the notify group. The car field holds the name of the person. The cdr field contains either #f or #t. #t means that the person is currently marked online; #f means they're off-line. You may force an update at any time using the NOTIFY command: (gs-exec "notify --force")
gs-add-server-notify-group attaches the notify group to a server object.
gs-drop-server-notify-group is the opposite of gs-add-server-notify-group.
gs-list-server-notify-groups returns the list of all notify groups
that are attached to a server. Each group information is the same
as the information returned by gs-query-notify-group. This is the
general format:
(group1 group2 group3 ... groupi ... groupn)
where
groupi := (<id> (<nicki0> #t|#f)(<nicki1> #t|#f) ...(<nickin>
#t|#f))
Saving and loading notify groups to/from files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use (gs-exec "notify ...").
gs-bind-key binds a key combination to an action. <name> is
the name of the key to which we want to bind a procedure. The name is as
defined in /usr/X11/include/X11/keysymdef.h,
but with the prefix "XK_" removed as described in the manual for XKeysymToString(3).
Examples of valid key names are "a" for XK_a, "space" for XK_space
and "F1" for XK_F1.
<modifier> is an integer. It is a combination of zero or more key
masks:
modifier := 0 [ | <keymask_0> [ | <keymask_1>] ... [ | <keymask_n>]]
keymask_0, keymask_1, keymask_n are defined in
/usr/X11/include/X11/X.h.
Each represents a bit in <modifier> for each of the special keys Shift,
Lock, Control etc., as well as for each mouse button.
The following table shows a selection of key masks from /usr/X11/include/X11/X.h.
Key | Label | Value |
(None) | 0 | |
Shift | ShiftMask | 1 |
Lock | LockMask | 2 |
Control | ControlMask | 4 |
Mod1 | Mod1Mask | 8 |
Mod2 | Mod2Mask | 16 |
Button1 | Button1Mask | 256 |
Button2 | Button2Mask | 512 |
Button3 | Button3mask | 1024 |
If <procedure> is given, it should be a Scheme procedure taking 3 arguments:
gs-delete-key-binding deletes any key binding on <name> with
the given modifier.
gs-query-key-bindings returns a list of pairs. The car field
of each pair is the name of a key as described under gs-bind-key;
the cdr field contains the value of a modifier as was passed to gs-bind-key.
Examples
(gs-bind-key "i" 12 (lambda(w m c) ;; 12=(Mod1Mask|ControlMask)
(gs-set-input "You pressed Alt+Ctrl+i" w)))
(gs-bind-key "space" 512 (lambda(win mod name)
(display "You pressed space while holding down Mouse
button2\n") #f))
(gs-delete-key-binding "space" 512)
Usage: (bind-key str_keymask [proc | #f]) (delete-key-binding str_keymask) (list-key-bindings) (key-binding->str binding) ;; binding::=(keysym . state) (string->key-binding str_keymask) Examples --------- There is a hotkey script in scripts/hotkeys.scm. Fire up SPX, type the following, and see the walls closing in on you... The following binding causes the key combination Ctrl+i to insert the string "hello world" into the input line of the window that has keyboard focus: (bind-key "Alt+i" (lambda(window char state)(gs-set-input "hello world" window))) Completely deactivate the 'z' key: (bind-key "z") Alt+Ctrl+q prompts for confirmation to shutdown client: (bind-key "Alt+Control+q" (lambda(a b c)(gs-exec "exit"))) Use Ctrl+l to clear channel window: /(bind-key "ctrl+l" (lambda(w k s)(gs-execute w "/window --clear 1"))) First mouse button plus left Shift key does a thing: (bind-key "Button1+Shift_L" (lambda(window char mask) (gs-echo "You pressed button1+shift_left" window))) Bind Ctrl-n to nick++ : (bind-key "control+n" (lambda(w junk knuj)(gs-exec "nick +" w))) Delete key binding "Alt+i": (delete-key-binding "Alt+i") Return the string corresponding to a key binding: (key-binding->str '(q 517)) ==>"SHIFT+CONTROL+BUTTON2+q" Given the string representation, return the pair: (string->key-binding "SHIFT+CONTROL+BUTTON2+q") ==>(q . 517) Arguments to bind-key -------------------- (bind-key key-mask procedure) key-mask is a combination of zero or more modifiers, followed by the name of a key. key-mask ::= modifier+* key_name modifier is the name of any of the special keys Shift, Control, Mod1 to Mod5, as well as the mouse buttons 1 to 5. A modifier may or may not given. It's name is case-insensitive. The following are valid modifier names, each of them corresponding to a key mask defined in /usr/X11/include/X11/X.h; the suffix "Mask" is not needed. Name of modifier Value in $XROOT/include/X11/X.h SHIFT ShiftMask LOCK LockMask CONTROL ControlMask CTRL ControlMask MOD1 Mod1Mask (probably ALT) MOD2 Mod2Mask MOD3 Mod3Mask MOD4 Mod4Mask MOD5 Mod5Mask BUTTON1 Button1Mask BUTTON2 Button2Mask BUTTON3 Button3Mask BUTTON4 Button4Mask BUTTON5 Button5Mask procedure is exactly the same as the procedure assigned to gs-bind. If procedure is #f, or if it is not given at all, then the key sequence is deactivated; the user will not be able to use it anymore. Related programs, files and documentation ---------------------------------- xev(1), xkeycaps(1), xmodmap(1), ~/.Xmodmap, /usr/X11R6/lib/X11/Xmodmap, ~/.xinitrc, /usr/X11/include/X11/X.h, /usr/X11/include/X11/keysymdef.h XStringToKeysym(3)
(gs-client-name) => "Sula PrimeriX"
(gs-version) => "0.7.10"
(gs-major-version) => "0"
(gs-minor-version) => "7"
(gs-revision) => "10"
(gs-release) => 922929504
*sula-home* The name of the directory being used as your personal directory, typically ~/.sula.
*sula-libdir* The name of the system-wide directory for this session, usually /usr/local/lib/sula.
*sula-infosite*
This contains sources of information about the client.
*sula-contact*
Contact e-mail addresses.
(connect-and-join servername port | #f channel [key])
Connect to a server and automatically join the given
channel. If port is FALSE, a default is used. If you are already connected to the server,
we just join the channel.
Example: (connect-and-join "irc.undernet.org" #f "#irchelp")
(gs-exit <exit_code>)
Quit program, returning exit_code to the shell.
(gs-bell [<percent>])
Ring keyboard bell. <Percent> is the volume. It defaults to 0, the
default keyboard setting. <Percent> ranges from -100 to 100. -100 is
the minimum volume (off) and 100, the maximum.
Example: (gs-bell 60)
(gs-delay <microseconds>)
gs-delay is similar to the Guile procedure 'sleep' except that
gs-delay waits for a number of microseconds instead of seconds. gs-delay
returns the value of select(2), or #f if given a bad argument.
Example?
(display "Go wait in a corner...\n")(gs-delay 1500000)(gs-bell)(display
"thank you!\n")
(gs-clear-console)
Clear control window.
(gs-hide-console TRUE|FALSE)
Hide/Reshow console window.
(gs-window-title window)
Retrieve window title. Use -1 for console.
(gs-window-title! string window)
Changes the title of a window. Use -1 for window to change the title
of the console.
(gs-message <string> [<window>])
Displays string on the message bar of a window.
(gs-get-message <string> [<window>])
Returns the message currently displayed on the message bar.
Example:
(let foo((x 5))
(define str (gs-get-message 0))
(gs-message "Hey, Time to wake up..." 0)
(gs-bell 50)(sleep 1)(gs-message str 0)(gs-delay 500000)
(if(> x 0)(foo (1- x))))
(gs-set-status <string> [<window>])
Changes the text on the status bar of a window.
(gs-get-status [<window>])
Returns the current text of the status bar.
Examples:
1. (gs-set-status "-- /help fuer Hilfe --" 0)
2. Append the text "[away]" or "[not away]" to status text if window's
connected to a server
(let((server (gs-window-server 0)))
(if(not (null? server))
(gs-set-status (string-append (gs-get-status 0)
(if(not(server:away? server)) " [not away]" " [away]"))
0)))
(next-word <string> <n>)
Returns the n'th word in <string>, sans sorrounding white spaces.
Indexing begins from 0.
Example:
(next-word " foo ya !" 0); ==> "foo"
(word-index string n)
Returns the start position of word number n.
(word-index "this is ab bad te sst" 3)==>8
(string-rest string n)
Returns string, starting from the (n-1)'th word.
(string-rest " this is ab bad te sst" 3)==>"bad te sst"
(string-start string n)
Returns string up to, and excluding, the nth word.
(string-start " this is ab bad te sst" 3)==>" this is ab "
(gs-display obj1 obj2 ...)
(gs-write obj1 obj2 ...)
Both return a string containing the result of printing the given objects
into a string using display and write respectively.
display2string is a synonym for gs-display.
write2string is a synonym for gs-write.
Example:
(gs-echo (gs-display "sin(2) is " (sin 2) " at " (current-time)))
==> sin(2) is 0.909297426825682 at 910730414
Examples:
(_say2 0 "The sqrt of -1 is " (sqrt -1) " and that's cool...")
==>The sqrt of -1 is 0.0+1.0i and that's cool...
(say sin " is a procedure, and so is " cos)
==>#<procedure sin (z)> is a procedure, and so is #<procedure
cos (z)>
(gs-echo "Hey Joe!")
(gs-echo "Hey there" 0 1)
(gs-set-input <text> [<window>])
(gs-get-input [<window>])
(gs-set-input-cursorpos <pos> [<window>])
(gs-get-input-cursorpos [<window>])
gs-set-input replaces the text in the input field of a channel
window. To clear an input line, use the empty text "".
gs-get-input returns the contents of the input field of a window.
gs-set-input-cursorpos sets the position of cursor inside the
input line.
gs-get-input-cursorpos returns the current position of the cursor
in the input line of the specified window.
Examples:
See the script "hotkeys.scm" in the scripts directory for a definition
of key bindings which insert any pre-defined information into the input
line of a window.
(gs-set-radio <button> [<window>])
(gs-get-radio [<window>])
gs-set-radio activates the radio button <button> on the given
window. The effect is as if the user had pressed the button with the mouse.
<button> is the name of one of the radio buttons on a channel window:
'parse, 'query, 'channel, 'chat or 'echo.
gs-get-radio returns the name of the currently active radio
button. The name is one of the symbols just listed.
Both gs-set-radio and gs-get-radio return #f on failure.
Note that certain buttons cannot always be set. For example, you can't
activate the channel radio button when you are not on any channel. Therefore
gs-set-radio
should be followed by a call gs-get-radio in order to find out if
button was set successfully.
Examples:
(gs-set-radio 'echo 0)
(if(eqv? 'chat (gs-get-radio 0))
(display "input on window 0 currently goes to DCC chat\n"))
gs-handler
This is an error handler for anyone who cares to use it. It prints
a nice error report. Using it ensures that Guile doesn't break off processing
a piece of code when an error is thrown from one statement. Example:
;; ~/.sula/.gsularc
...
(catch #t (lambda() (use-modules (math random))) gs-handler)
(gs-exec "alias m mode $N $1-")
(gs-exec "alias t- topic -clear $C")
...
If the random number module is not found, the interpreter normally
bails out, ignoring all subsequent statements. Using an error handler,
it prints an error text and continues processing the rest of the code.
(gs-random [#f])
Returns a pseudo-random using random(3). If any argument is passed
to the procedure, tv_usec from gettimeofday(2) is used instead of time(NULL)
as seed to srandom(3).
Sula Primerix comes with a random number module for Guile (modules/math/librandom.so)
which produces real random numbers. Use the module instead. There's a README
in the directory.
(gs-raw-write fd string)
This procedure writes the string directly to the file or socket descriptor
fd,
thereby bypassing any parsing by SPX. This may come in handy for quickly
quoting to a server/DCC chat connection.
*sula-random-string*
(string) This is a random word that is generated each time Sula is
run. It comprises of the characters a-z,A-Z and 0-9. *Never* modify.
TRUE is #t, FALSE is #f, all is relative.
-- stop Jul 31 1999 --