Category Archives: AppleScript

Navigation markers added to SD6


The recent update to Script Debugger 6 added a subtle, but much-needed new feature.

Now, scripters can take advantage of the same kind of navigation markers familiar to users of Xcode (pragma marks) to quickly navigate to user-defined sections of the script.

Scripters can now create a marker with a double-dash and double arrow marker, followed by whatever label they choose.

-->> myMarker here!

For me, this is a great boon, and I’ve changed all the section headings in my templates to the new navigation marker syntax, meaning I can easily jump to the various sections from the Navigation bar at the top of the script.

Nice! πŸ™‚

Further Reading:
Script Debugger 6: The Complete Review

applescript: remove characters from a string

Screen Shot 2016-08-26 at 18.01.54

One of the things I’m often finding myself doing is trying to remove characters from strings, particularly html codes and other markdown clutter. Rather than laboriously messing around with offsets and the like, we can make our lives simpler by making a quick handler that leverages Cocoa’s stringByReplacingOccurrencesOfString method.

For example, suppose you’ve got a sourceString containing something like this

Screen Shot 2016-08-26 at 18.08.57

We can strip all the tags out by calling our handler like this, once for the opening tags and again for the closing tags. Note how the variable names have changed in the second call:

Screen Shot 2016-08-26 at 18.13.06

The beauty of this is it doesn’t just remove one instance of the tag, it removes all occurrences of them, so this handler is a real life-saver when you’ve got a whole page of markdown to clean.

To achieve this you’ll need to add a couple of declarations to the top of your script, as well as the handler:

Here’s the declarations you’ll need:

use scripting additions
use framework "Foundation"
property NSString : a reference to current application's NSString

Here’s the code for the handler:

on remove:remove_string fromString:source_string
set s_String to NSString's stringWithString:source_string
set r_String to NSString's stringWithString:remove_string
return s_String's stringByReplacingOccurrencesOfString:r_String withString:""
end remove:fromString:

Enjoy! πŸ™‚

make a Sierra USB bootable installer

Screen Shot 2016-08-21 at 13.06.29
For those participating in Apple’s public beta program or developer program, here’s a script that will make a bootable flash drive installer of Sierra for you. Of course, you’ll need to have downloaded and saved the original installer before running it on your mac for this to work.

When an installer is made available to you from Apple, the first thing to do after downloading it is to quit the installer if it auto runs. Insert your blank USB thumb drive, and make sure it’s at least 8GB (16GB recommended).

Screen Shot 2016-08-21 at 13.36.22

You can either run the script immediately with the installer app still in your /Applications or /Downloads folder, or you can move the installer first to your preferred location. It doesn’t make any difference to the script since it’ll ask you for the location of both the Installer and the USB drive before doing its thing. It’ll also give you an option to cancel out if you made any mistake in specifying the location or you just change your mind. The script will ask you for an administrator password as it needs elevated privileges to run the createInstallMedia routine.

Note the script continues to run in the background until the installer has been created. It sleeps for an interval of 10 secs between checking the job status. Since it takes around ten minutes for the createInstallMedia routine to finish its work, you could comfortably increase that sleep time 30 secs or more if you desire. The script will present you a dialog when it detects all is done:

Screen Shot 2016-08-21 at 13.37.32

To use the bootable installer, just pop it into a mac, reboot holding down the ‘option’ key and choose the USB drive to kick off the installation process on a partition of your choice.

The full script is available here.


ejecting some, all or just specified disks

Screen Shot 2016-08-03 at 13.06.32

We posted this one liner some time ago in response to the fact that you can’t actually get the Finder to eject all volumes on multiple drives at the same time.

However, I thought it’d be good to have a slightly more useful version. In this version, you can choose individual volumes or all volumes from a list. Optionally, you could also include collections.

Screen Shot 2016-08-03 at 13.36.56
Suppose for example you wanted to eject one volumeΒ from one physical drive along with one from another and two from a third? To do that, just uncomment these two lines and supply your own volume names in the collection_1 list:

--if you want to create an item that groups some volumes together uncomment the following two lines:
# set collection_1 to {"Archive 1.5TB", "BUFFALO 500GB", "This disk", "That disk", "Another disk"} -- supply as many disks names you want to group together here
# set diskList to {"All Disks", "Disk Group 1"}
Then, when you run the script, choose ‘Disk Group 1’ to eject that collection of volumes. You could of course adapt the script to include more than one collection.

You can get the full script from my pastebin here.

Enjoy! πŸ™‚

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.

%d bloggers like this: