AppleScript is a scripting language. Scripting languages have all the capabilities
of other programming languages, but are easier to use because their structure
is closer to everyday English.
AppleScripts can store data for later use and examine their surroundings to determine
what to do next. They can also loop through certain instructions, repeating them
as many times as you like, or until something specific happens. These features,
and others, are what makes a scripting language - particularly AppleScript ideal
for anyone that wants to automate a task.
AppleScript is different from other scripting languages because its reach isn't
limited to a single application. AppleScript is part of the Macintosh operating
system, and that enables it to work with several different applications at once
if necessary. You can extract data from one application and hand it to another
for processing with AppleScript, and it can even be used to control other Macs
over the network.
How to start
There are many good books about AppleScript, and I can in particular recommend
"The TAO of AppleScript" by Derrick Schneider and "AppleScript
Language Guide" from Apple.
In order to write an AppleScript that uses Snak, you need to open the Script
Editor application that was installed as part of your operating system. It is
found in the AppleScript folder in the Applications folder.
There are five main parts to AppleScript:
- Objects - which points to items and information inside the application
- Commands - which acts on those items and information
- Variables - which allows you to store data for later use
- Conditionals - which enable your script to make decisions based on a set
- Repeat loops - which give you the capability to execute commands repeatedly
Every scriptable application contains a dictionary of the commands and objects
it knows about. To see the Snak dictionary, run the Script Editor and select
"Open Dictionary" under the file menu and select the Snak application:
Under the heading "Snak Suite" you see all the commands you can send
to Snak -
- connect - sent to an IRCConnection object to open a connection.
- disconnect - sent to an IRCConnection object to close a connection.
- echo - sent to a target (a channel, filter, query etc.) to display a message locally. The message is not sent out.
- type - sends a command or message to a specific target as if the user had typed it directly.
- match - used for fast matching of strings against a pattern.
- store data - used to let a script store a setting in the Snak preference file.
- load data - used to let a script retrieve a setting from the Snak preference file.
Command provided for compatibility with older scripts:
This command should not be used in new scripts.
and all the objects you can access through
- do - sends a command to a specific target as if the user had typed it directly.
channels, connections, users, ignoreitems ... and many more.
In the dictionary you will notice that in order to access some objects you
have to go through other objects. This is called an object hierarchy.
Snak's object hierarchy is:
- The application contains connections (and more)
- A connection contains channels (and more)
- A channel contains users (and more)
Your first AppleScript
This is an example of a simple, yet (somewhat) useful little script. Once it's
loaded into Snak you will be able to type "/countops" to have the
script tell you the ratio of channel operators to normal users. The script asks
Snak how many users are in the current channel, and how many ops there are among
them. Then it calculates the ratio and displays a message.
Open the Scripts folder by choosing "Show Script Folder" in the windows
menu. That will cause the Finder to display the folder where it is. Open the
folder itself by doubleclicking it.
In this folder is a script called "countops". Double click this file
to open the Script Editor. This will open a window with the text of the script.
I have added the line numbers for convenience.
line 1: on run
line 2: tell application "Snak"
line 3: set n to NumberOfUsers of channel CurrentChannel of connection CurrentConnection
line 4: set ops to count (get (every user whose op = true) of channel CurrentChannel of connection CurrentConnection)
line 6: if n > 0 then
line 7: set percent to ops / n * 100 as text
line 8: else
line 9: set percent to 0 as text
line 10: end if
line 12: set percent to (round (percent + 0.49))
line 13: set CommandString to "/me sees " & ops & " gods and " & n - ops & " mortals on " & currentchannel & ".
line 14: " & percent & "% of the people in " & CurrentChannel & " are gods."
line 15: do CommandString
line 16: end tell
line 17:end run
The above script shows examples of objects, commands, conditionals and variables. The bold words are part of the AppleScript language itself, and the Script Editor will automatically format them.
Starting with line 1: "on run" this is a line that tells Snak
in what situation to run the snippet, namely when the uses types "/countops".
Other situations are explained later when event handlers are introduced.
Line 2: "tell application "Snak"" is used by the AppleScript
system itself and is used to set the target for the following block of AppleScript.
Notice how the Script Editor automatically indents the following block.
Now we get to the core of the little script, the place where the interesting action
takes place. Line 3 uses both objects and a variable.
"set n to NumberOfUsers of channel CurrentChannel of connection CurrentConnection"
Just relax and stay calm even if this seems like total gibberish. It is entirely logical and straightforward, once you learn how to recognize the individual pieces.
Here we ask Snak a complex question - how many users are there in the current
channel on the current connection, and we store the result into a variable called
"n". The channel and the connection are examples of objects.
A central concept in understanding AppleScript is that most scriptable applications
have an "object hierarchy" meaning that objects are nested inside each
other. You ask the top object (the application) for an object (the connection)
that contains your ultimate goal (the channel), and then you ask that channel
object for specific information like the number of users.
Line 2: "tell application "Snak"" which you saw first points
out the top object (the application) and the "set n to ..." line will
first ask for the connection from the application, and then ask for the channel
from the connection, and then it asks the channel for the number of users. Try
and read the line from the right and you will see the sequence.
Trust me, once you understand the idea it really makes sense :-)
Line 4 is quite complex.
"set ops to count (get (every user whose op = true) of channel currentchannel
of connection currentconnection)"
Like line 3 it uses a variable and objects, but it also introduces a
conditional operation. Again we find a channel object but this time we ask it
for a list of all users in the channel whose "op" status is true, meaning
that they are channel operators. Then we take the number of results and store
in a variable.
The "whose" conditional allows you to easily gather a collection of
objects that satisfy a condition.
The next few lines perform the ratio calculation, and put together the string
of text that Snak should display with the result.
"set CommandString to "/me sees .."
This line looks difficult, but all it does is to pull together the information
we've already found, and fill out a variable that holds a line of text. The '&' character is used to concatenate two pieces of text.
recognize "/me" as a Snak command, but this line just puts together
a line of text that starts with the "/me" command. The line is stored
in a variable called "CommandString".
As you look at the line you can recognize the variables that were defined above to hold the number of users, the number of ops and the ratio.
If for example, there are 4 users on channel #macintosh, 2 of which are ops the string will end up looking like this:
"/me sees 2 gods and 2 mortals on #macintosh; 50% of the people in #macintosh are gods"
Finally we get to do an actual AppleScript command. We have a potential point
of confusion here because we are mixing two different kinds of commands. There
are normal Snak commands like you type in at the command line like "/me",
and then there are Snak AppleScript commands like "do". The "do"
Snak AppleScript command makes Snak execute a normal command as if you typed it
in through the command line.
That means that you have access to all the built in Snak commands as well as any
commands you define in the existing ircII language, from within an AppleScript.
So the "do CommandString" line simply executes the "/me sees ..."
command as if you had typed it in yourself, which result in the ratio of ops to
normal users being written out and sent as an action message to the channel.
How to load and run AppleScripts
In order to use an AppleScript it needs to be loaded into Snak. Type "/load
scriptname" to make Snak read in and prepare the script to be run. If you
have a handler in the script called "on load" it will be called right
away. Snak will also look for a handler called "on idle" and start executing
it if it's present.
If you type the name of the script as a command, the "on run" handler
in the script will be run. At this time it's not possible to pass parameters
to an AppleScript command, so you are encouraged to use the ircII language to
write command aliases. This shortcoming will be remedied.
During development of an AppleScript it's frequently useful to unload an existing
script in order to modify it and try again. To unload an a loaded AppleScript
type "/unload scriptname".
Snak implements a number of event handlers that enable you to implement extensive
functionality and the number of handlers will be improved in the next version.
I welcome your feedback and suggestions so be sure to let me know if you need
a particular feature.
You can write simple command aliases in AppleScript, but the real power comes
when you use "event handlers". These are snippets of AppleScript that
you write and load into Snak. The events in an Action
is another example of event handlers, except that the events in an Action
comes with a predefined set of responses. If you write your own event handler
in AppleScript you have complete freedom.
Snak will call your event handlers when particular events happen, like someone
joining a channel, leaving a channel, saying something, sending you a private
message and more. The event handlers lets you truly customize the way Snak works
and responds to events.
Example: If you are an IRC server operator you will get a number of messages
from the network itself about the various going ons. This may become annoying
if the messages are of no relevance to you.
With AppleScript you now have a way to intercept those messages and process or
discard them without cluttering up the channels you are in.
Snak will, during its processing of the numerous different events, call some user-defined
"hook functions" or event handlers. Depending on the output of these
event handlers, Snak may or may not continue processing the event. This means
that the user now has the ability to tailor Snak much more closely to his or her
needs than ever before.
Snak comes with the script file SnakEventHandlers which contains examples of all
the event handlers that Snak currently supports, and shows what parameters they
The following example employs an event handler called "on servernotice".
Snak will call the servernotice handler whenever it receives a notice from a server
as opposed to a normal user. The example script will then examine the text of
the notice and if it contains the string [CLONES] the message will be redirected
to a custom window in order not to clutter up the regular channel.
Notice how the return value of the handler in the case of a [CLONES] message is
true. This means that the script has completely processed the event and Snak should
not process it as well.
on servernotice(con, source, sourcehost, target, thestring)
set eventhandled to false
tell application "Snak"
if thestring contains "clones" then
tell connection con
echo thestring in filter "[CLONES]"
-- true tells Snak that this event is completely handled
set eventhandled to true
tell application "Snak"
set con to currentconnection
tell connection con
type "/window new name [CLONES]"
echo "Clone catcher" in filter "[CLONES]"
The script uses the custom windows feature of Snak. The line "type "/window
new name [CLONES]" will open a custom window that you can use to display
text that is filtered out of somewhere else. Such windows are called filter windows.
Stacked event handlers
Snak allows you to have multiple AppleScripts loaded and each of the scripts can
implement whatever event handlers it wants. Snak will then call each event handler
in turn until one of them returns true, meaning that the event was completely
Snak comes with some sample event handler scripts that illustrate this. If you
examine the input1 and input2 scripts in the script folder you will see that they
both have an on input handler. If you load them with "/load input1"
and "/load input2" and type the text that triggers the action, you will
see that both handlers are called.
Likewise, idle handlers can be stacked. The idle1 and idle2 scripts both contain
idle handlers and if you load them with "/load idle1" and "/load
idle2" you will see periodic messages coming from both of them.
This support for stacked handlers will eliminate much complexity from large script