Best Practices for GUI Scripting

You may not be ready for it yet, but once you’ve got a bit of experience under your belt (and I’ll second AppleScript-1-2-3 + the AppleScript Language Guide, that’s how I learned), you will reap massive rewards from reading Matt Neuberg’s ‘AppleScript: The Definitive Guide’.

It’s a lot of theory (hence you need the experience first), but it will set off dozens of ‘Eureka’ light bulbs in your head as you come to understand all the mysterious behavours you couldn’t figure out about AppleScript. It’s more of a “why this happens” book than a “how to do” book, but is all the more valuable for that. I’ve lost count of how many times I’ve re-read it (and I still know I could do with re-reading it again a few more times).

Phil,

Your product endorsement of “Open Quickly” was the best endorsement I ever heard. After I got to the dreadlocks parts I started laughing. Perhaps you should send that in to Apple :smile:

Bill

bodiequirk,

I read “AppleScript: The Definitive Guide” when it first came out. It is a good book. To this day I still see a lot of people recommending it. It’s a pretty old book, and a lot of newer things aren’t covered but on a basic theoretical level it explains a lot about why things are the way they are in AppleScript. That kind of stuff is helpful when you want to do something complex, or can’t figure out why something complex isn’t working. So like Phil says it something that is useful when you get to more complex stuff.

Also oreilly.com is the real leader in ebooks with no digital rights management in them. Which means you don’t need a special editor to read their books, they are fully searchable, the text can be copied form the book and pasted into actual code while reading it which allows you to try different things the book didn’t do. That can teach you a lot. I’ve never come across one of their books without sample code when it come to AppleScript.

Bill

Well, there are lots of tools available to us, and we each can pick what works best for him/herself.

But, IMO, you guys are missing out on a very powerful tool: Spotlight

I almost never use it (now days) to launch apps, although it certainly does a great job of that. I use LaunchBar for that.

Spotlight is a great, and very fast, search tool. The great thing is that it searches both names and contents (although you can limit it) of all kinds of documents. So, I might search for a script about “CSV”, and find that not only do I have several scripts, but I also have an Evernote Note and several emails. All of which can be very useful.

But if I want only scripts, then I can just add “kind:script”. I have a text expander that makes this easy.

It can also search my Contacts and my Evernote “MasterNotes” very quickly, without me having to go to the specific app.

Using the @ccstone text tag system is very powerful, and is a great way to dramatically reduce false positives. Like any other system, the more you use it the more natural/automatic it is to put the tags in the name and/or content.

Again, I find Spotlight very fast.

I think the reason a lot of people don’t like SpotLight is the interface, or the lack of interface. I use something called HoudahSpot (https://www.houdah.com/houdahSpot/) which has all the power of SpotLight and a wonderful interface. Huda is a front end for sport light searches and uses the same index as SpotLight. With Huda you can easily make very complex searches without having to know much about SpotLight. I’ve never failed to find a file since I’ve had it because it is so easy to make power and complex searches.

The fact that it is like a command in terminal in that you have to specify the file kind with kind:script turns a lot of people off.

Bill

Hey Bodie,

Buy UI Browser. It’s not inexpensive, but it will save you hours of frustration. (I’ve been using it since 2005.)

Join the UI Browser User Group:

https://groups.yahoo.com/neo/groups/uibrowser/info

There is NO good, methodical documentation for UI-Scripting, so you have to dissect other people’s scripts, ask questions, and gain experience.

You’ll find quite a few of mine on the Keyboard Maestro forum.

Keyboard Maestro is by far the most powerful macro utility available for the macOS today, and I’ve been using it since early 2004 when v1.0 came out.

BUT – I don’t use it to run most of my AppleScripts. I use FastScripts which is a much improved analog of Apple’s AppleScript menu (and probably the most productive $9.95 I’ve ever spent on software.)


Why FastScripts?


FastScripts is very easy to use.

Unlike Apple’s AppleScript menu, FastScripts has the ability to assign app-specific and global keyboard shortcuts.

It has a keyboard shortcut to open the main menu, so you can type-select.

The FastScripts menu works more reliably with type-select than does the Keyboard Maestro status menu.

I have nearly 600 AppleScripts that are mostly hotkey-driven.

I run AppleScripts from compiled-script-files rather than text-scripts, because there is a distinct performance advantage – FastScripts is a more convenient mechanism for managing AppleScripts on-disk than Keyboard Maestro.

I can open a script for editing by depressing the Option-key when selecting it from the FastScripts menu.

I can reveal the script in the Finder by depressing the Shift-key when selecting it from the FastScripts menu.

FastScripts uses a different mechanism to run AppleScripts than Keyboard Maestro, so I can use it to test with if Keyboard Maestro is choking on something and see whether KM is the problem or not.

Because of the different AppleScript-runner mechanism, FastScripts will run some AppleScriptObjC code that Keyboard Maestro won’t.

FastScripts gives me a second means of running AppleScripts and shell scripts, so I can offload jobs that take time on it (or KM) and still have the other unencumbered.

I do drive a very few pure AppleScript macros from Keyboard Maestro, because on occasion I get better performance – but I’m more likely to use AppleScripts with Keyboard Maestro when they are part of a larger macro.

FastScripts lets me work with the Keyboard Maestro Editor without involving Keyboard Maestro which is especially useful if I’ve quit the engine.

There are other reasons that have cropped up over the last 13 years, but I don’t remember all of them.


FastScripts uses ~/Library/Scripts as its base folder.

Global scripts go directly in that folder (or subfolders).

App-Specific scripts go in the Applications subfolder.

~/Library/Scripts/Applications

It’s very straightforward.

I have a folder for working scripts bound to a hotkey in the Finder and in Default Folder, and I have it indexed in LaunchBar as well – so I have very quick access to them.

I have a script that creates my normal script header.

I have an abbreviated dev-header for when I need to track what I’m working on but don’t want the clutter of the full header.

I have another script that will save the script I’m working on in my script library based on the app-name or other routing information in the header.

The library is for reference and not for running scripts, and it too is indexed in LaunchBar.

~/Documents/Scripts (Library)/

So – between LaunchBar and Spotlight I can very quickly (usually) find saved code I want to reuse.

(This doesn’t include all the boilerplate and handlers I have in Script Debugger’s text-expansions and in Typinator.)

Well done!  :smile:

UI elements can often be called by name, and there are other tricks.

I use UI Browser to explore the UI of a given app, and I use it to grab my initial reference to an element.

I have a script that turns UI Browser’s flat reference into a hierarchical one.

Then I usually use this construct for analyzing the node I’m in – in combination with Script Debugger’s best view result window.

set diagnosticsList to {¬
“----- PROPERTIES -----”, ¬
properties, ¬
“----- UI ELEMENTS -----”, ¬
UI elements, ¬
“----- ATTRIBUTES -----”, ¬
attributes, ¬
“----- ACTIONS -----”, ¬
actions, ¬
“----- END -----”}

I have it in a text-substitution, so it’s easy to emplace.

You can get name and value (and other aspects) of UI elements, and these can frequently be used to reference them.

I often refer to the front window of an app like this to filter out floating windows and such:

tell (first window whose subrole is "AXStandardWindow")

Here’s the practical example of getting Safari’s uni-field:

  1. UI Browser is used in combination with one of its keyboard shortcuts to identify the field.
  2. Cmd-Opt-R is used to send the reference to the field to Script Debugger.
text field 1 of UI element 1 of group 2 of tool bar 1 of window "Best Practices for GUI Scripting - AppleScript - Late Night Software Ltd."  of application process "Safari"
  1. I select the line and hit Ctrl-Shift-U to activate my hierarchical script and get this:
tell application process "Safari"
   tell window "Best Practices for GUI Scripting - AppleScript - Late Night Software Ltd."
      tell toolbar 1
         tell group 2
            tell UI element 1
               
            end tell
         end tell
      end tell
   end tell
end tell

** At some point I’ll automate adding the System Events tell-app-block.

  1. I change the above to:
tell application "System Events"
   tell application process "Safari"
      tell (first window whose subrole is "AXStandardWindow")
         tell toolbar 1
            tell group 2
               tell UI element 1
                  it
               end tell
            end tell
         end tell
      end tell
   end tell
end tell
  1. Then I use Script Debugger’s result window in Best-mode to explore the UI element.

  2. With a little more information I might change the script some more:

tell application "System Events"
   tell application process "Safari"
      tell (first window whose subrole is "AXStandardWindow")
         tell toolbar 1
            tell group 2
               tell (first UI element whose role is "AXSafariAddressAndSearchField")
                  it
               end tell
            end tell
         end tell
      end tell
   end tell
end tell
  1. Sometimes I prefer to explore with Script Debugger Source-mode, and I’ll do this:
tell application "System Events"
   tell application process "Safari"
      tell (first window whose subrole is "AXStandardWindow")
         tell toolbar 1
            tell group 2
               tell (first UI element whose role is "AXSafariAddressAndSearchField")
                  set diagnosticsList to {¬
                     "----- PROPERTIES -----", ¬
                     properties, ¬
                     "----- UI ELEMENTS -----", ¬
                     UI elements, ¬
                     "----- ATTRIBUTES -----", ¬
                     attributes, ¬
                     "----- ACTIONS -----", ¬
                     actions, ¬
                     "----- END -----"}
               end tell
            end tell
         end tell
      end tell
   end tell
end tell

I can toggle this between Source and Best modes and get the best of both worlds.

So – you opened a can of worms didn’t you.   :sunglasses:

There’s a reason why there are quite a few books about AppleScript.

But you cannot learn AppleScript well from a book, because no book covers the wide variety of scriptable apps out there (and each one has its quirks).

You need one or two good books on AppleScript to learn basics and have for reference.

You need to join available AppleScript communities – as you have with this forum – but let me also suggest MacScripter.net and the Applescript Users List.

(If you’re interested in automation beyond scripting then I suggest you look carefully at Keyboard Maestro. The Keyboard Maestro community is strong.)

You need some personal mentoring. If you don’t have a few go-to-guys then you’ll end up banging your head against the wall far too often.

Script Debugger too is a total no-brainer for anyone who is really interested in becoming more productive through the use of AppleScript. (Especially since the price has been lowered.)

Most people just do not GET how much SD improves the AppleScript learning, coding, and debugging experience.

I think I spent 3 days with Script Debugger v1.0, before I paid the (then) hefty sum of $129.95 for it in 1996(?), but I knew in 3 hours that it was far superior to Scripter and that I should buy it if I wanted to continue with AppleScript.

Since that day Script Debugger has run 24/7 on my system.

-Chris

People that like HoudahSpot often rave about it. I tried it a few years ago, but wasn’t that impressed. Maybe I need to give it another spin . . .

So many tools, so little time . . . :wink:

It’s quick, but it’s not very powerful. There’s a lot of places it doesn’t search,
I used to use EasyFind for those, but then I wrote my own search tool instead that combines both NSMetadataQuery and the find utility. It can also open folders if given a / path, something Spotlight could really do with.

We also lost the ability to order search results in Spotlight Prefs after Mavericks or Yosemite. I filed a regression against that, but you can guess what came from Apple: “working as intended”.

Phil,

That’s a funny was to put it. Spotlight is a reasonably powerful search. The fact that it can’t index anywhere Apple considers outside the designated areas for data to be placed is not a matter of power, it’s about Apple being stupid. They are 2 different things. Unpowerful things can be enhanced, while stupidity has an enduring quality to it and often nothing can be done about it. :slight_smile:

Bill

1 Like

WOW!

I am truly blown away at the amount of awesome advice this post has generated! Thank you all so much for the warm welcome and for helping me dive right in.:slight_smile:

I don’t even know how to respond to all the awesomeness! ha ha

First off, @sphil: You were the one who got me all fired up about GUI scripting in the first place! Thank you for your awesome Script Debugger tutorials! More please! Also, for the recommendation on “AppleScript: The Definitive Guide”. I will look into that one after AppleScript 1-2-3.

@BillKopp: Thanks so much for the book recommendations. I already went, found, and downloaded all of the scripts from those books!

@ccstone: BRO, EPIC POST! Wow, thanks so much for taking the time to dump that pile of glory upon me! You really gave me some clutch advice and spoke directly to some of my questions with your advice and recommendations.

I just bought UI Browser yesterday (didn’t know about the users group, thanks for that), already a huge fan of Keyboard Maestro but appreciated your advice to not use it for AppleScripts and use FastScripts instead (just bought that, too). Thanks for outlining on the benefits, you sold me!

Thanks also for the sample code, that is what I really need at this stage: lots of examples (thanks also for pointing me to additional resources to get those).

Would you be willing to share the script that converts UI Browser’s flat code to the hierarchical code that SD generates? That is one of my current hangups with UI Browser: a clean method to send code to Script Debugger from UI Browser. I don’t know how to do that yet. Love some suggestions there, too.

Thanks to all of you for your awesome advice and dialogue. Looking forward to many more discussions like this one!

Bodie

I think you’re confusing Spotlight (a crippled search engine) with NSMetadataQuery (the underlying, and very powerful, API that Spotlight uses, but not to its full extent).

I guess we’ll have to agree to disagree on this. I find Spotlight very powerful.
But then perhaps “powerful” is like “beauty”, varies according to the eyes of the beholder. :wink:

I could add more, but since we are considerably off-topic in our “Spotlight” discussion, I’ll refrain from adding more. I’m all for each person using the tools they prefer.

Hey JM,

Let’s just say that Spotlight has some infuriating and unnecessary limitations…   :sunglasses:

-Chris

1 Like

Hey Bodie,

Sure.

NOTE – This script REQUIRES the Satimage.osax AppleScript Extension to be INSTALLED.

The most recent version can be found (here) – as of today it is at Satimage osax 3.7.0 (build 420).

If you just use the Satimage.osax installer then only one osax package file is installed. (The full Smile installer will install other things as well.)

UI Browser has it’s own keyboard shortcut for sending the current reference to Script Debugger.

R

I have my script bound to:

U

So usage is to send the reference to Script Debugger.

Select the line.

(I have a line-select macro in Keyboard Maestro for that. SD doesn’t have such a command, which is a bit peculiar for a programming editor.)

Run my script via keyboard shortcut.

Hit the button to select the stub token in the code, and go-to-town.

-Chris


Convert UI Browser Flat Ref to Hierarchical Ref v1.00.zip (11.5 KB)

------------------------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2017/04/05 10:10
# dMod: 2017/04/19 17:01
# Appl: Script Debugger
# Task: Change a flat reference from UI Browser to a vertical hierarchy.
# Libs: None
# Osax: Satimage.osax – http://tinyurl.com/satimage-osaxen OR http://tinyurl.com/smile-beta-page
# Tags: @Applescript, @Script, @Script_Debugger, @Satimage.osax, @Change, @Flat, @Reference, @UI_Browser, @Vertical, @Hierarchy
# Vers: 1.00
------------------------------------------------------------------------------

set tabPad to "																				"
set stubToken to "#" & "~stub~" & "#"

set myPath to (path to me as text)
if myPath ends with "Script Debugger.app:" then error "This script must be saved!"

tell application "Script Debugger"
   if myPath = (get file spec of front document as text) then
      set scriptDoc to a reference to document 2
   else
      set scriptDoc to a reference to document 1
   end if
   
   if scriptDoc exists then
      tell scriptDoc
         
         set selectedText to selection
         
         set cmdHierarchy to cng("\\A\\s+|\\s+\\Z", "", selectedText) of me
         set cmdHierarchy to splittext cmdHierarchy using " +of +" with regexp
         set cmdHierarchy to reverse of cmdHierarchy
         set cmdCount to length of cmdHierarchy
         set cmdHierarchy to cng("^", "tell ", cmdHierarchy) of me
         set end of cmdHierarchy to stubToken
         
         repeat with i from 1 to cmdCount
            set end of cmdHierarchy to "end tell"
         end repeat
         
         set cmdCount to (length of cmdHierarchy)
         set linesToIndent to (cmdCount div 2) - 1
         
         repeat with i from 1 to linesToIndent
            set plusItem to (a reference to item (i + 1) of cmdHierarchy)
            set minusItem to (a reference to item (-i - 1) of cmdHierarchy)
            set thePad to text 1 thru i of tabPad
            set (plusItem's contents) to thePad & (plusItem's contents)
            set (minusItem's contents) to thePad & (minusItem's contents)
         end repeat
         
         set blankLine to linesToIndent + 2
         set (item blankLine of cmdHierarchy) to thePad & tab & (item blankLine of cmdHierarchy)
         set cmdHierarchy to cng("^", "\\t", cmdHierarchy) of me
         set beginning of cmdHierarchy to "tell application \"System Events\""
         set end of cmdHierarchy to "end tell"
         set cmdHierarchy to join cmdHierarchy using linefeed
         
         set selection to cmdHierarchy
         
      end tell
   end if
   
end tell

------------------------------------------------------------------------------
--» HANDLERS
------------------------------------------------------------------------------
on cng(_find, _replace, _data)
   change _find into _replace in _data with regexp without case sensitive
end cng
------------------------------------------------------------------------------

That’s something you ought to post in the UI Browser forum too :slight_smile:

It’s the same on my mac as it is on yours, Jim.

Try searching for ‘csrutil’ in Spotlight, and see what it finds. It sure won’t find either the LaunchDaemon in System Library, nor will it find the executable in /usr/bin.

There’s nothing ‘in the eye of the beholder’ about that. It’s just a fact. Spotlight doesn’t search those places (and many others). Spotlight also doesn’t return certain files, even if they’re in a place it searches.

we are considerably off-topic

Noted.

@ccstone You mentioned 600+ scripts in FastScript that are all hot-key driven… What system do you use for your hotkey shortcuts that scales up that well? I have purchased FastScript and am wanting to develop a logical system of my scripts from the get-go, and would love some advice.

Anyone else, please jump in as well!

Thanks!

Hey Phil,

This particular bugaboo is easy to overcome in Spotlight, but you have to know how.

The image depicts two bootable drives on my system.

Not only do you have to add “System files” to the search, but you have to know to enable them in the “other…” section of the pop-up search-criteria-menu.

No normal Mac-user is likely to figure this out. You have to be an enthusiast or pro who studies Mac-publications.

HoudahSpot on the other hand finds csrutil on the first try without special settings…

-Chris

@sphil, @ccstone, et al:

I have created a new topic where we can discuss Spotlight without polluting this thread:
###Mac Search Tools

ATTN Forum Moderator: You might want to move all of the Spotlight posts in this thread to the new thread.

1 Like

Hey Bodie,

That of course encompasses many apps.

I try to use keyboard shortcuts that are as mnemonic as possible.

Here is my FastScripts Finder Menu to give an example of the sort of systems I use (click in the image to see it full size – you may have to click and then click again):

I used to put a bunch of stuff in subfolders, but that makes type-select more difficult — so I only use subfolders here and there.

-Chris