A script can receive arguments using run script
or osascript
, but a script application has more options. I’ve seen topics about various argument passing schemes, but nothing that combines several of them together.
Like a script, including a single parameter to the run
handler allows it to receive arguments, but there are a few additional ways (other than the open
hander) that a regular script application can be called, with slight variations in how arguments are passed:
- The application is double-clicked:
Therun
handler is called with an empty list argument. - Items are dropped onto the application:
Theopen
handler is called with a list of arguments. - The application is reopened (double-clicking an active app, its Dock icon, etc):
Thereopen
handler is called with a list of arguments. - Using a handler called from a menu item or other UI control
A regular script doesn’t use NSApplicationDelegate, so none of those methods (such as managing the Dock menu) can be used. - Using the command line via
osascript
:
This calls therun
handler, passing a list of any arguments. Simple script applications can be used, but sinceosascript
is primarily designed to run scripts, more complex scripts and AppleScriptObj-C can be problematic. Also remember that when a script is run, it will try to modify itself to update any properties and global variables (the historical way script values are persisted), so there may be a warning if this fails (read-only, code-signing, etc). - Using the command line via
open
:
The-a
option specifies the application to use, and the--args
option will pass following items as arguments. Therun
handler is called, but instead of an argument list,current application
is passed. This can be tested for, andNSProcessInfo
used to get the arguments - note is that the executable is passed in the first item of its argument list. - Command-dragged into a Finder window’s toolbar or added to the Script Menu:
These call the app like #1 or #3 above, withcurrent application
as the argument and only the executable in theNSProcessInfo
argument list. This can also be used as an indication to get the current Finder selection.
Of course, using the Cocoa-AppleScript template gives you access to the various Cocoa delegate methods (including applicationDockMenu:
), but for whatever reason you don’t see that used much these days (well, in forums anyway).
Although the following script can be run from the editor or menu, it is designed to be run as an application. The main differences when running from the editor or menu (other than the open
and reopen
handlers not being used) include the argument me
being passed to the run
handler, and different NSProcessInfo arguments. There may be other issues such as interactions with the Script Monitor app, but I haven’t tested much with that. For a script application though, a sample skeleton that can use the variations above would be something like:
use framework "Foundation" -- for AppleScriptObjC stuff
use scripting additions
property fileMenu : missing value -- outlet and flag for UI setup
to run args
if fileMenu is missing value then setupUI()
doStuff(getArguments(args))
end run
to open droppedFiles -- items dropped onto the app
if fileMenu is missing value then setupUI()
doStuff(droppedFiles)
end open
to reopen addedFiles -- stay-open app reopened (open app double-clicked, Dock menu, etc)
if addedFiles is in {{}, current application} then -- no files, so look for other sources
doStuff(getArguments(addedFiles))
else
doStuff(addedFiles)
end if
end reopen
on setupUI() -- add an alternative to editing the Dock menu, as NSApplicationDelegate isn't used
if name of current application is not in {"Script Debugger", "Script Editor"} then -- don't modify editor
set my fileMenu to (current application's NSApp's mainMenu's itemWithTitle:"File")'s submenu
fileMenu's removeItemAtIndex:0 -- don't need "Use Startup Screen" item
(fileMenu's addItemWithTitle:"Open New Document" action:"menuAction:" keyEquivalent:"o")'s setTarget:me
end if
end setupUI
on menuAction:sender -- action for added menu item (blank/new document, etc)
doStuff({"Menu Item"}) -- {} or whatever
end menuAction:
on doStuff(theFiles) -- main handler to do stuff
try
set dialogTitle to "Selected file items"
set {prevTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, return} -- for dialog
if (class of theFiles is list) and ((count theFiles) > 0) then
display dialog (theFiles as text) with title dialogTitle -- do stuff for selected file items
else
if theFiles is not missing value then
display dialog "No selection" with title dialogTitle -- do stuff for no selection (blank/new file items, etc)
else
display dialog "Alternate for no selection" with title dialogTitle -- alternate for canceled choose dialog
end if
end if
on error errmess
display alert "Error Doing Stuff" message errmess
end try
set AppleScript's text item delimiters to prevTID
return theFiles
end doStuff
to getArguments(args) -- get an argument list by going through the various sources
try
set selectedFiles to {} -- default
if args is in {me, current application} then -- app double-clicked, 'open -a' with '--args', or script editor
set processList to (current application's NSProcessInfo's processInfo's arguments) as list
if (count processList) > 0 and first item of processList is not "/usr/bin/osascript" then -- skip if script menu
set selectedFiles to rest of processList -- drop the first item (executable path)
end if
else if args is not in {} then -- osascript with arguments
set selectedFiles to args
end if
set shiftKey to ((current application's NSEvent's modifierFlags()) div 131072 mod 2 is 1) -- NSEventModifierFlagShift
if (not shiftKey) and (selectedFiles is {}) then -- shift key skips user selections
tell application "Finder" to if (get windows) is not {} then -- try current Finder selection
set selectedFiles to get selection as alias list -- note that this will be the app or alias if double-clicked
end if
if selectedFiles is {} or (((path to me) is in selectedFiles) and ((count selectedFiles) is 1)) then
activate me
set selectedFiles to (choose file with multiple selections allowed) -- of whatever type
end if
end if
return selectedFiles
on error errmess
display alert "Error Getting Arguments" message errmess
return missing value -- provide an alternate value for indication (cancel, etc)
end try
end getArguments