Save AppleScript text as .scpt

From what I've read, compiled scripts run faster than text scripts in an Execute an AppleScript action, so I thought I'd try to automate saving my scripts to a repository and adjusting the existing actions to run them.

Here's where I've got to...

With an Execute an AppleScript action selected, this will copy the contents of its text field and write it to a .scpt file in a user-defined folder.

Challenges...

  1. Currently, the resultant filename will inexplicably contain a "?" at the end, before the extension.

  2. Once I switch back to the KM editor, I need to move focus out of the action's text field so that I can switch to Execute a Script. Perhaps there's a neat way to do this, but I can't think of one.

  3. The saved scripts don't seem to work if they rely on KM variables, whereas they work fine when run from text in the action.

NB: the first action triggers my rename action macro in order to obtain the action's title, so substitute this for a select menu item action if need be.

Any help appreciated!

Convert AS Text to Compiled Script.kmmacros (45 KB)

Macro screenshot

Hello @noisneil

first of all - saving to a particular folder with ".scpt" using the Write to File - Action does not work.

you have to to the way using the Mac's osacompile - Commandline Tool to do that.
(thinking of developing a Custom KM Action to use this tool .....)

because I have the same thing on my Todo list here are some other thoughts:

Maybe you have more than one Script in a Macro to compile so I would first use the Macro as XML to search for The particular Action(s) using AppleScript and Regex - this can help you to automate the process - not just finding them - using this method you can also get the Action-UID which can help you to replace each AppleScript - Action (using Text) with an AppleScript - Action (using the Path) in the right Place.

You can also find a way to restore any Colapsed Action(s) as they were before when AppleScripts are nested in Collapsed Action(s) - if you want ...

the other thing I would mention is Editing support for the Script - Files - If you want to just save changes to an AppleScript using Script Debugger there will be an issue that Script Debugger will not just save it(them) - because it doesn't know that the Script(s) was(were) saved before when you open it(them) for example for the first time using Script Debugger ....

It is a quite complex task - but I am really sure it will save you a lot of trouble ....

Because of that I would save the compiled Script(s) using Script Debugger - after that you can just save the Script(s) without any hassle when you editing it(them).

there is even some thing - KM has Navigation for Text Actions in its Menus - have you tried to use them ??

Greetings from Germany

Tobias

I'm not sure how great the differences will prove to be in practice, but in any case, it might be worth asking @peternlewis about the Execute Script File option in KM AppleScript actions, in which you can supply a path to a .scpt file, rather than supplying source code.

If that option is pointing to a .scpt file, and maintains a compiled cache, then the difference may not be great.

(A compiled .scpt file is easily made with File > Save As in Script Editor, of course, if an osacompile shell script seems fiddly).

If you have contexts in which execution speed really is impinging (rare, on the whole) then it might also be worth experimenting with FastScripts – which aims for competitive advantage by doing all the cacheing possible, in pursuit of speed.

(It might also be worth experimenting with JavaScript, which can be very significantly faster than AppleScript for some purposes)

1 Like

hello @ComplexPoint

By far as my knowledge is - KM will read the compiled Script-File and execute it instantly after it was read. no need for KM to compile it at run time.

if you are for instance working with Git and Script-Files that are uncompiled (".applescript" Extension) Km need to compile it and then run it - which is just the same as when you use text scripts as Source Code in the Action - but without Version Control.

For the Use of Scripts in Macros which are executed by implementing FastScripts into the execution Process you have to use Scripts again for Running others by FastScripts with its own execution Command from its Scripting Dictionary.

Or you have to use a developed Third Party PlugIn designed to run Scripts from FastScripts Script Menu what can also be great in some cases - when you have a workflow where you need to run more Scripts at a time and run them simultaneously - what can be done if you have FastScripts 3.

Greetings from Germany

Tobias

Thankyou both for your detailed replies!

The files do run, but don't play nicely with KM variables, so does that mean they're not actually compiled?

I looked into this and couldn't figure out how to actually add the text. If you figure it out, please let me know.

This is all a bit beyond my current capability unfortunately.

I did actually make a version of the macro that saved via Script Debugger, but scrapped it when I thought of using Write to a file, so now I feel a bit silly that I'll have to redo it. :man_facepalming:t2:

You mean for changing focused elements? Where in the menus can I find these? I looked but didn't see anything.

Yes, exactly. This is what I'm trying to do. Perhaps I didn't explain very well. I'm basing my assumptions about increased speed on posts I've seen by people like @ccstone, along the lines of "this will run much faster if saved as a compiled script". That said, it might be because the scripts in question were very long and involved. For simpler ones, perhaps the difference is negligible. In my own experience, I have noticed that AppleScripts seem to take a noticeable moment longer than native KM actions doing the same simple tasks. Perhaps that's unavoidable.

Thanks for the heads up. I'll look into it.

I'm a real beginner with scripting, and I'm only just getting to grips with AppleScript, so I think maybe that might be more than I can chew at the moment. I wouldn't really fancy re-writing all my scripts in a different language even if I knew how!

I literally understand none of that right now, but I'll try the demo and see if I gain any clarity.

Thanks again!

Since I currently have not much time putting together an example for now - I just type in some things for you to get this done by yourself .... If you then even struggle with that I will post an example of how to accomplish this task if I have the Time.

  • write the Script from the Action to a file using the Extension ".applescript"
  • use osacompile in a shell script with the path to the .applescript - File.

that's all I have for now....

The Menus are "Enter Action" & "Parent Action"

Greetings from Germany

Tobias

This sounds like premature optimisation.

Unless you can point to a specific case where the script runs faster by enough that you can actually notice in a real world situation, you are entirely wasting your time. If you are having fun with this, by all means continue, but otherwise, stop and go back and figure out what case you are actually trying to solve and what makes you think a compiled script would help the solution, and what tests you have run to determine that it does.

2 Likes

Thanks @peternlewis. Your word is good enough for me, so if you think it's a waste of time, I won't bother. As I mentioned earlier in this thread, my assumptions were formed after reading numerous posts in which users with far more experience than I have recommended running compiled scripts, but perhaps they're labouring under the same misapprehension.

1 Like

If you are running a macro and either:

  1. You run it all the time and it's slow enough that it annoys you.
    or
  2. You run a macro occasionally, and it's really slow enough that it annoys you.

Then by all means look at what you can do to speed up the macro. Likely there is a faster way, maybe the entire process is wrong and should be done a different way. In rare cases, maybe it is running a script and the script is not quite fast enough.

But generally I find even if a macro takes a while to run, it is likely doing something that would take me way more time to do and I just sit there smiling while I watch the macro do the work for me.

3 Likes

I was already 90% done at this stage, so here's an AppleScript -- it wouldn't take much to make it an action in a KM macro. It works on the currently selected action, but it wouldn't take much to make it work through a list of actions for batch processing -- revisit the tmpFileName section if you think you'll be processing faster than 1 per second!

Compiled files are named "actionname-actionID.scpt" -- AFAIK, action names needn't be unique but IDs are, so that'll prevent name clashes while preserving readability and "human searching" in eg a Finder window. Paths are quoted, so should cope with most of the characters you might throw at them, though I'll confess I've only tested by using double quotes in an Action name! The temp file is deleted as soon as it is used, in case there's anything confidential in the XML.

I've used a rather kludgey way of stripping the beginning and end off the "Text" retrieved from the XML. AFAIK the XML formatting is consistent and it should always work -- more importantly for this, it was an easy way to strip only the starting "" and closing "" without worrying if there was more of the same in the script itself!

Paste into Script Editor, change line 2 to the POSIX path to where you want to save your compiled scripts, select an AppleScript-containing action in KM, and give it a whirl...

-- set output folder for compiled script
set outputFolderPath to "/Users/exampleuser/Desktop/Compiled Scripts/"

-- get info from KM
tell application "Keyboard Maestro"
	set theAction to item 1 of (get the selection)
	set compiledFileName to name of theAction & "-" & id of theAction & ".scpt"
	set theXML to xml of item 1 of theAction
	
	set {oldTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {"<key>", "</key>"}}
	set xmlList to every text item of theXML
	repeat with x from 1 to length of xmlList
		if item x of xmlList is "Text" then
			set theString to item (x + 1) of xmlList
			exit repeat
		end if
	end repeat
	set theString to text 11 thru -12 of theString	
	set AppleScript's text item delimiters to oldTIDs
end tell

-- write the text to a file in /tmp
set currentDate to (get current date)
set tmpFileName to "" & year of currentDate & "-" & (text -2 thru -1 of ("0" & (month of currentDate as number))) & "-" & (text -2 thru -1 of ("0" & day of currentDate)) & "-" & (text -2 thru -1 of ("0" & hours of currentDate)) & (text -2 thru -1 of ("0" & minutes of currentDate)) & (text -2 thru -1 of ("0" & seconds of currentDate))
set fileRef to (open for access POSIX file ("/tmp/" & tmpFileName) with write permission)
write theString to fileRef
close access fileRef

-- create and run the shell script command to compile then delete the temp file
set outputFilePath to quoted form of (outputFolderPath & compiledFileName)
set theScript to "osacompile -o " & outputFilePath & " /tmp/" & tmpFileName & ";rm /tmp/" & tmpFileName
do shell script theScript

There's more that could be done -- batch processing, subdividing your compiled script storage into folders corresponding to KM macro groups, etc. But if the idea's dead in the water anyway...

It was a fun little project though, and maybe someone can take something from it.

2 Likes

Here is an AppleScript from @kevin_funderburg ‘s GitHub that helps for editing AppleScript Sourcecode as well as a compiled Script that is embedded using the path to the File of the currently selected AppleScript Action in KM - it uses Script Debugger - if I remember it right.

I use that code every time to open an embedded AppleScript Source code in Script Debugger for editing… this Script is worth it to have in the Toolbox

Greetings from Germany

Tobias

1 Like