Hey Folks,
I originally wrote scripts to extract Script Debugger AppleScript-Library text back in the mid-1990’s using one of the osaxen that would read file resources (AKUA Sweets?). The major design criteria was speed, and even on that old hardware with MacOS 8-9 the resource-reading-method was very, very fast.
I had some scripts that employed an osax with regular expression support and the Dialog Director osax to do all kinds of nice things with that source-text.
When I finally moved to OSX in 2002 (Jaguar) I was fairly heartbroken to lose all of my osaxen (outside of the Classic environment), but the following year (2003) the Satimage.osax came out and solved most of my problems. It had regEx support and could read/write file resources.
I’ve used osadecompile on and off since it became available, but I’ve always avoided it like the plague for regular operations – because it has the bad habit of launching certain applications when decompiling scripts containing their terminology.
Having 20 apps launch unexpectedly whenever you run a script was (and is) NOT supportable, so I kept using the file-resource-reading method.
Fast-forward to Script Debugger 6 — Mark discontinues Script Debugger libraries in favor of the new AppleScript library structure that debuted in Mavericks.
I would have to change my ways — again…
I tried osascript again, and found it still had a penchant to launch apps – so I looked for another method.
Shane gave me the idea to use the main.recover.rtf files in Script Debugger’s script-bundle scripts and helpfully provided some AppleScriptObjC code to do the job.
This didn’t work for anyone who didn’t have Script Debugger, but it was outstanding for me – because it was lightning fast and never, ever launched an app I didn’t want launched.
I’ve used this method for years to do all kinds of useful things.
Now – let’s revisit osadecompile.
Sometime in the last few years I asked Shane if that job could be done with AppleScriptObjC, and the answer was yes. Unfortunately it still launched apps I didn’t want launched, so I gave up on it again.
But — I tested recently on Sierra and didn’t have any app-launching problems. I don’t know if this has something to do with OS changes, or whether more developers are using the modern sdef format that stops that misbehavior. In any case osascript is working on my system (so far) without launching apps without my consent.
The AppleScriptObjC script below replicates the sort of thing I’ve been doing for just about 20 years — the last 14 ± using the Satimage.osax.
-
It filters the libraries to only the ones I want using a regular expression.
-
It extracts the source-text of all found libraries.
-
It has regular expression support for filtering the output text.
– There’s a pre-built filter to output only handler-calls.
------------------------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2017/03/12 22:04
# dMod: 2017/03/15 16:52
# Appl: AppleScriptObjC
# Task: Osadecompile from ASObjC - decompile AppleScript Libraries.
# : RegEx filter to select only desired libraries.
# : RegEx filter to output only hander-calls.
# Libs: None
# Osax: None
# Tags: @Applescript, @Script, @ASObjC, @OSAdecompile, @Decompile, @Library, @Libraries
------------------------------------------------------------------------------
use framework "Foundation"
use framework "OSAKit"
use scripting additions
------------------------------------------------------------------------------
set scptLibFldrPath to "~/Library/Script Libraries/"
set scptLibFldrPath to current application's NSString's stringWithString:scptLibFldrPath
set scptLibFldrPath to scptLibFldrPath's stringByExpandingTildeInPath() as string
set libFileList to its findFilesWithRegEx:".*Lb.*" inDir:scptLibFldrPath -- filter files using a regEx
set scriptLibraryText to {}
repeat with libFile in libFileList
set end of scriptLibraryText to linefeed & "••••• LIBRARY SEPARATOR •••••" & linefeed
set end of scriptLibraryText to (its extractScriptSourceFrom:libFile)
end repeat
set AppleScript's text item delimiters to linefeed
set scriptLibraryText to scriptLibraryText as text -- entire text of all libraries
# return scriptLibraryText
# Filter library text using a regular expression – extract handler-calls:
set handlerList to its regexMatch:"(?m)^on (\\w.+)" fromString:scriptLibraryText captureTemplate:"$1"
set handlerList to handlerList as text
return handlerList
------------------------------------------------------------------------------
--» HANDLERS
------------------------------------------------------------------------------
on extractScriptSourceFrom:scriptPath
set aURL to current application's |NSURL|'s fileURLWithPath:scriptPath
set theScript to current application's OSAScript's alloc()'s initWithContentsOfURL:aURL |error|:(missing value)
return theScript's source() as text
end extractScriptSourceFrom:
------------------------------------------------------------------------------
on findFilesWithRegEx:findPattern inDir:srcDirPath
set fileManager to current application's NSFileManager's defaultManager()
set sourceURL to current application's |NSURL|'s fileURLWithPath:srcDirPath
set theURLs to fileManager's contentsOfDirectoryAtURL:sourceURL includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
set theURLs to theURLs's allObjects()
set foundItemList to current application's NSPredicate's predicateWithFormat_("lastPathComponent matches %@", findPattern)
set foundItemList to theURLs's filteredArrayUsingPredicate:foundItemList
set foundItemList to (foundItemList's valueForKey:"path") as list
end findFilesWithRegEx:inDir:
------------------------------------------------------------------------------
on regexMatch:thePattern fromString:theString captureTemplate:templateStr
set theString to current application's NSString's stringWithString:theString
set theRegEx to current application's NSRegularExpression's regularExpressionWithPattern:thePattern options:0 |error|:(missing value)
set theFinds to theRegEx's matchesInString:theString options:0 range:{0, theString's |length|()}
set theResult to current application's NSMutableArray's array()
repeat with aFind in theFinds
set foundString to (theRegEx's replacementStringForResult:aFind inString:theString |offset|:0 template:templateStr)
(theResult's addObject:foundString)
end repeat
return theResult as list
end regexMatch:fromString:captureTemplate:
------------------------------------------------------------------------------
I have a script that uses a similar method to export all of my handler-calls to a couple of sets in Typinator with one keystroke. It takes less than 1/2 a second to refresh the sets when I’ve changed my libraries.
Typinator’s Quick Search feature gives me very quick, smart-searchable access to my handlers.
I keep the ones I use every day in Script Debugger’s own text-substitutions, but this lets me find what I want on demand and is especially convenient when my memory is fuzzy.
-Chris