Category Archives: AppleScript

applescript: many buttons

Screen Shot 2016-07-21 at 18.04.41

I thought I’d share some code Shane Stanley wrote in response to a question I posed on ASUsers list a few weeks back. Both Shane and myself have modified that original answer, which wasn’t directly about how to display a dialog with more than three buttons like this.

This should work on all versions of OS X / macOS from 10.10 Yosemite onwards and produce something like the screenshot above. Obviously, you’ll want to adapt the size, message and buttons to fit your own circumstances. The parts you need to edit are near the end and begin with the commented line ‘set up the paramaters…’.

The script is helpfully peppered with notes but if you get stuck, just drop a question in the Comments below.

use AppleScript version "2.4" -- 10.10 or later
use framework "Foundation"
use framework "AppKit"
use framework "Carbon" -- AEInteractWithUser() is in Carbon
use scripting additions
property returnCode : missing value

on showMessage:theMessage withTitle:boldBit textFrame:textFieldSize textMaxWidth:maxWidth withButtons:buttonsList
# credit to Shane Stanley for this handler
-- make attributed string system font with monospaced digits
set fontSize to current application's NSFont's systemFontSizeForControlSize:(current application's NSRegularControlSize)
set theFont to current application's NSFont's systemFontOfSize:fontSize
set attsDict to current application's NSDictionary's dictionaryWithObject:theFont forKey:(current application's NSFontAttributeName)
set attString to current application's NSAttributedString's alloc()'s initWithString:theMessage attributes:attsDict
-- make a text field to hold the message
set theField to (current application's NSTextField's alloc()'s initWithFrame:textFieldSize)
tell theField
(its setEditable:false)
(its setBordered:false)
its setDrawsBackground:false
its (cell()'s setWraps:true)
its setPreferredMaxLayoutWidth:maxWidth
its setAttributedStringValue:attString
end tell

-- make it fit; needs to be done on the main thread
my performSelectorOnMainThread:"fitToSizeView:" withObject:theField waitUntilDone:true
-- make sure we have permission
set theError to current application's AEInteractWithUser(-1, missing value, missing value) -- -1 is kAEDefaultTimeout
if theError is not 0 then error "User interaction disallowed" number theError
-- create an alert
set theAlert to current application's NSAlert's alloc()'s init()
tell theAlert
its setMessageText:boldBit
repeat with anEntry in buttonsList
(its addButtonWithTitle:anEntry)
end repeat
its setAccessoryView:theField
end tell
-- show the alert; needs to be done on the main thread
my performSelectorOnMainThread:"showTheAlert:" withObject:theAlert waitUntilDone:true
set buttonNumber to returnCode mod 1000 + 1 -- where 1 = right-most button
set buttonName to item buttonNumber of buttonsList
return buttonName
end showMessage:withTitle:textFrame:textMaxWidth:withButtons:

on showTheAlert:theAlert
# credit to Shane Stanley for this handler
-- check we are running in foreground
if not (current application's NSThread's isMainThread()) as boolean then error "This handler must be called on the main thread." from current application
set my returnCode to theAlert's runModal()
end showTheAlert:

on fitToSizeView:aView
# credit to Shane Stanley for this handler
aView's setFrameSize:(aView's fittingSize())
end fitToSizeView:

# set up the parameters for the showMessage call:
set theMessage to "How many buttons would you like? There's no real limit except for practical and aesthetic considerations." & return & "Of course, I hope you'll never really think about using something as ugly as this!" & return & return & "Choose your heart out!"
set theTitle to "Many Buttons"

# increase or decrease the second item's numbers
# to fit larger or smaller amounts of text
# the '650' here is the text field's width
# the '80' is its height
set theTextFieldSize to {{0, 0}, {650, 80}}
set buttonsToDisplay to {"OK", "Five", "Four", "Three", "Two", "One", "Cancel"}

set theButtonReturned to its showMessage:theMessage withTitle:theTitle textFrame:theTextFieldSize textMaxWidth:(650) withButtons:buttonsToDisplay

Enjoy 🙂

applescript: get item number of list item

Screen Shot 2016-07-31 at 21.45.31

One of the annoying ‘missing features’ in AppleScript is the lack of any way to get the item number of an item in a list.

Fortunately, since Cocoa does of course include an ‘indexOfObject’ function, we can leverage Cocoa in our AppleScript to write a nice little handler (you could add this to my list and string handlers library I posted here or just add it directly in your own scripts).

First, make sure your script or library already has two lines like these to import the Foundation framework and declare an NSArray:

use framework "Foundation"

property NSArray : a reference to current application's NSArray

Then after that add the handler:

on getIndexOfItem:anItem inList:aList
set anArray to NSArray's arrayWithArray:aList
set ind to ((anArray's indexOfObject:anItem) as number) + 1 # see note below
if ind is greater than (count of aList) then
display dialog "Item '" & anItem & "' not found in list." buttons "OK" default button "OK" with icon 2 with title "Error"
return 0
return ind
end if
end getIndexOfItem:inList:

You can now call the code like this:

# example
set thisList to {"I", "see", "a", "red", "door", "and", "I", "want", "to", "paint", "it", "black"}
set aNum to its getIndexOfItem:"paint" inList:thisList
(* Result --> 10 *)
if aNum is not 0 then
-- do something
end if

# Note: Remember AppleScript lists are indexed from 1, unlike Cocoa arrays which start at index 0.

Enjoy! 🙂

Hack That Mac 2: Bash & Root

applescript: how to rant on Twitter

Screen Shot 2016-07-27 at 16.07.19
Well, hopefully you won’t…but if you wanted to post something longer than the 142 character limit without manually having to break it all up, this script will do it for you.

All you do is set the ‘tweetRant’ variable to whatever missive of massive importance you want to convey, and run the script. It’ll break your text into tweet-sized strings, add ellipses to them where appropriate and post them in 10-second intervals.

Of course, using this for spamming would likely not win you many friends…and besides, it’s not the only way to abuse Twitter’s 142 rule.:p

A more responsible use would be to adapt this script to create your own kind of Buffer service. You’d need to add scheduling via Calendar or a launch agent to do that, a subject we’ll tackle in an upcoming post.

Download the script from my pastebin…

Enjoy! 🙂

Hack That Mac 1: Who’s who

applescript: file & folder handlers

Screen Shot 2016-07-26 at 17.06.40

Here’s a few of
the AppleScript handlers I use for getting contents of folders (examples 1 & 2), or for getting the text of a file (example 3).

In all three cases, you give the handler a path string in POSIX form, e.g, ~/Desktop or (for example 3), ~/Desktop/sometext.txt.

In example 1, what you get back is a list of the item names in the folder. It doesn’t include hidden or invisible files.

In example 2, what you get back is a record of all the items and their properties. This can be an immensely useful and powerful handler.

In example 3, what you get back is a text variable whose value is the complete text of the file.

Hope these come in as handy for you folks as they have for me!

Click here to get the handlers from my pastebin.

Enjoy! 🙂

Note: The getFileContents() handler requires OSX 10.10 or higher.

Using Handlers Pt1

Using Cocoa in AppleScript

applescript: easiest way to GUI script


Script Debugger is third-party software available from here.

Disclaimer: I have no financial or any other compensatory connection with the developers.

Script Debugger 6: the complete review

SD Shot 2

It feels like cheating. When you’ve spent pretty much your entire AppleScripting life behind the wheel of Apple’s austere Script Editor application, taking Script Debugger 6 out for a 20-day spin feels like someone’s let you in on a secret you’re not supposed to know. Hurdles you’ve taught yourself to clear – through considerable effort, frustration and no small amount of bloody-minded tenacity – are removed before you get to them; obstacles you’ve habitually steered around or avoided have disappeared, and dark holes of AppleScript mystery appear, in the light shone on them by SD6, to be not the menacing entities you once feared but new friends that offer ways to do things faster and more effectively. The secret that Script Debugger seems to lay bare is that AppleScripting doesn’t have to be as painful as we’ve been conditioned to believe. And that does feel like a cheat. Read the full review…

%d bloggers like this: