hello, applescript 2: user in, user out
If you’re ready to learn AppleScript, this is the place to start! If you’re not sure yet whether AppleScript is for you, take a look at the intro to this series, What’s the Use. For those of you that are ready, let’s fire up Script Debugger and write our first script!
Script 1
OK, you want ‘hello, world’? Of course, you do!
Here it is, with a difference:
Type it in to the editor’s window, then run the script by clicking the Run button or hitting “Command-R” on the keyboard.
Wow. No “print” command for one, and an actual user interface. Cool!
If you don’t see a notification in the top right of your screen, you may need to adjust your Notification preferences.
What happens if you leave off the last quotation mark?
Try it and see:
This is called a compile time error, one of three kinds we’ll learn about (the others are run time and logic errors). When you run a script, the AppleScript compiler first checks it for syntax errors. If all is well, it turns your plain text into “pretty print” (we’ll talk about what the syntax colouring means later in the series); if not, your text isn’t compiled and you get an error message.
You can get a compiler check anytime without running the script by clicking either the
√
button or using “Command-K” on the keyboard.
You’ll notice that when you have a compile time error in Script Debugger, you get a message and the error number in the bottom left corner (you won’t see the error number if you’re using Apple’s Script Editor). These can be useful, so much so that we’ll write a little script ourselves to tell us more about the error based on the error number we get in hello, applescript 4: shelling out.
For now, let’s take a look at the message.
“Expected string but found end of script.”
It may seem rather cryptic at first, but it can be translated simply enough. A string in AppleScript (and most other programming languages), is text placed between a pair of quotation marks. Anything between quotes will be treated as just a piece of ordinary text and not as part of the programming language. display notification isn’t a string in our script: it’s part of the programming language – specifically, a command to do something. “hello, world”, on the other hand, is a string: it’s just the ordinary text we want to display. The compiler says it “expected a string” because it found the first quote mark at the beginning of “hello, indicating the start of a string. It then went looking for the second one to mark the end of the string, but instead found…yes, you guessed it: the end of the script!
Script 2
Replace the missing quotation mark. We’ll come back to error messages shortly, but for now, let’s add our own title to the notification rather than having the default one:
Make sure those quotation marks are balanced!
Script 3
Notifications are useful when all we want to do is pass a simple message, but if you need users to make a choice or you need to provide a longer message, we should use a dialog.
Type in the script as you see it on the left in the image below.
Run it, and click the “OK” button when the dialog appears. Now look at the Results pane (right-hand panel in Script Debugger; bottom Accessory view in Script Editor).
That looks interesting! Let’s explore some more.
Script 4
Let’s add some bells and whistles:
Run the script.
Click either one of the buttons to end the script. Again, remove the quote mark after “world”, but this time don’t try to run the script. Just try to compile it. Remember, you can do that either by clicking the √
button in the toolbar or “Command-K” on the keyboard.
Notice this time we get a different error message and a different number, despite the fact that we seem to have errorred in exactly the same way and in exactly the same place as before:
Or did we? Look at it from the compiler’s point of view. Just as before, the compiler finds the first quote mark and continues looking. But this time it does find the second one! Only it’s not where it’s meant to be. Because we left off the quote mark after “world”, the compiler assumes that the quote mark that prefixes “Message is the closing quote mark for the opening one:
As a result, the term Message looks to the compiler like its supposed to be part of the programming language, as it follows the string “hello world with title ”. That sure is a valid string (you can put any text you like in your string, it doesn’t have to make sense), but what follows it is not a valid part of the programming language. You can learn more about identifiers here, but for now, just note that this error message has the form “this can’t go after that”, and is another clue that our quote marks are unbalanced.
What about the third quote mark? The compiler never sees it. The compiler reads from left to right, so after pairing the first two quote marks it throws the error and stops trying to read any further. If there are further errors in our script, we’ll never know till we fix (all) the preceding ones.
After you dismiss the error alert, the compiler is kind enough to highlight the this (“Message”) that can’t go after the that (“"
“) in your script.
Errors -2740 and -2741 are common enough that whenever you see them, you now know what to check first: are my quotation marks balanced?
Let’s get back to our display dialog command. Are you wondering what happens if you use another number instead of 2 after with icon
? I hope so!
Replace the missing quotation mark, and experiment by changing the number after with icon
for all three values from 0 to 2.
Normally, you’ll use with icon 1
, which will insert the icon of the executing program. In this case, that’s the icon for Script Debugger, but as you go through this series you’ll be learning how to execute your scripts in other ways, and it’s useful to have the icon of the executing program visible in the dialog box so that you know exactly where it’s coming from.
Our dialog box has some unnecessary cruft. We have an “OK” button and a “Cancel” button, but they appear to do the same thing; that is, they halt the script. But look a bit closer at the editor. Run the script again, twice, choosing the “Cancel” button first, and then the “OK” button on the second run.
When you choose “Cancel” there is no result, but there is an error message in the Events pane, specifically, error -128.
Errors, error messages and error numbers are powerful friends. We’ll see how we can harness errors like -128 later in the series.
When you run the script again and choose “OK”, however, there is a result. There are many result types, but in this case you get what is known as a record (similar to a Dictionary or key/value pair in other languages) in the Results view:
{button returned:"OK"}
The record contains a label (in this case, button returned
, and a value (here, "OK"
). This is important, as we’ll see in the following scripts.
Script 5
What if we want to get more than just an acknowledgement, but need some input from the user? Here’s one way:
Run the script, type in an answer, and hit “OK”. Take a look at the result:
{button returned:"OK", text returned:"Phil"}
It’s a record again, with the added pair “text returned” and the text that the user typed.
The default answer parameter is an empty string. What happens if you put some text between the quote marks and run the code?
Script 6
Let’s build on Script 5 and capture the answer that the user provides:
This script has a lot of new stuff going on. Let’s take it from Line 2 (refer back to Script 5 for line 1):
Line 2
This captures the result of the dialog in a variable called dialogAnswer
. The result of the dialog isn’t the name you typed in, but the record of two labels with two values. In other words, the value of dialogAnswer
is:
{button returned: "OK", text returned: "Phil"}
We could have called the variable (almost) anything we liked. I just chose dialogAnswer
because it’s descriptive.
Descriptive names are useful because when I read back my script at some point in the future, it’ll be immediately obvious what this variable represents. However, I could have called it alpha
, or just d
or almost anything else. There are some reserved words in AppleScript that you can’t use, and you also can’t start variable names with a number or use certain special characters in them, as noted here.
Most commonly, we use the set
command to assign values to variables. In many other programming languages, they use the =
sign, like this:
dialogAnswer = result
You can’t do this in AppleScript (or rather you can, but it means something else, not variable assignment), so if you’ve come to AppleScript with a background in another language, you’ll need to make the mental adjustment.
What about result
though? Where did that come from? This is a built-in property, filled with the value of the last command to be executed.
Take a moment to consider that. It means that the result
property changes on (almost) every line of your script.
Before we continue working through the rest of Script 6, let’s take a closer look at the result
property. Type this in, then compile and run it:
Notice that in the Events pane, result
changes from 2, to 3 and finally (in the Results pane) to 6.
AppleScript can use the usual programming conventions for mathematical operators (+
, -
, /
, *
. For x % y
, use x mod y
). That also includes the =
sign, where it means “is equivalent to” (aka “==
” in many other programming languages) and not, as we mentioned above, “assign to”.
In this little script, we also learned how to use the log
command to print the value of a variable to the Events pane. In Script Editor, you’ll need to do that a lot if you want to see the values of your variables at different times in your script. In Script Debugger, however, it’s rarely necessary as you can see the values in the Variables inspector view.
To verify this, try removing the two log
statements and running the script again. The log
statements no longer appear in the Events pane, but Script Debugger captures them anyway in the Variables inspector view.
Line 3
Line 3 of Script 6 is an if statement
, a kind of control flow statement. The clause, in this case, takes the form of a block. That means it evaluates a condition on one line, executes any commands if the condition is met on subsequent lines (Line 4) and then provides an end statement (Line 5) to signal the end of the block.
The conditional here first examines the button returned
property of the result
, which, remember, we’ve captured in the dialogAnswer
variable.
After the conditional has been evaluated and any commands executed if the condition was satisfied, the rest of the script continues to execute as normal. In Script 6 there were no more commands after the block, so the script ends.
Line 4
In Line 4 of Script 6, if the user clicked “OK”, we set a new variable, theName
, and assign it the value of the text returned
property of the dialogAnswer
record. Because we ended the block and the script on the next line, we never actually got to use this new variable, but typically the point of doing this would be so that we can use that value somewhere else in our script.
Where we are: so far!
Woah! We’ve done a lot in this post! We’ve seen how to get data in to our scripts from users and how to get data out, through dialogs, notifications and the Events and Results panes. We’ve had a first go at writing a conditional, logging messages, and viewing variable values. We’ve also been introduced to the compiler’s error messages and AppleScript’s record
class.
If it’s all a bit of a blur, don’t worry. We’ll be practicing all of this, and expanding our skills some more, in the next post in this series, hello, applescript 3: (don’t?) tell me to run!. Be sure to follow Applehelpwriter to be notified when a new post is published.
See you there! 🙂
For extra credit:
1. Try to modify Script 6 so that when you run it and type in your name, it looks exactly like this.
You’ll need to consult the docs for display dialog, so try to find and explore Script Debugger’s Dictionary viewer in order to do that.
2. Go back to Script 4. What happens if you set with icon
to 3?
This is an example of a run time or ‘execution’ error. The script will compile fine, because the parameter, or value, for with icon
only has to be a number in order to compile. AppleScript tells you ‘a resource wasn’t found’ because, unlike ‘icon 0, ‘icon 1’ and ‘icon 2’, there’s no such thing as ‘icon 3’.
That raises a number of questions: how can we tell what kind of parameter an argument or command takes? Why are there only three icon resources and where are they declared? How can I add other icons if I want to? And last, but most importantly, what else do we need to know about run time errors? All this, and much, much more, will be covered in the hello, applescript series. Stay tuned!
Posted on September 3, 2018, in AppleScript. Bookmark the permalink. 4 Comments.
I’m willing to toggle the Dock Indicators with Apple Script (the tick box called “Show indicators for open applications” in Preferences/Dock).
The following script that checks the current settings doesn’t seem to retrieve the status of that particular tick box.
tell application “System Events”
tell dock preferences
get properties
end tell
end tell
Any idea how to do that?
set tog to "0"
set state to (do shell script "defaults read com.apple.Dock \"show-process-indicators\"")
if state = tog then
set tog to "1"
end if
do shell script "killall Dock; defaults write com.apple.Dock \"show-process-indicators\" -integer " & tog
This is one of those where it’s best to “shell out” rather than go into (what I call) “God-mode” (i.e., GUI scripting).
We’ll be discussing using the shell in post 4, as well as how you can easily figure out what the defaults command is for any particular Sys Prefs setting.
🙂
👍