Use Case
- Need to quickly open the script, or sub-macro, in a KM Script Action (or Execute Macro Action)
How To Use
Select an Action in the KM Editor, THEN Run this Script
-
The KM Action MUST be either an Execute Script or Execute Macro
-
You can run this script from any of the following:
- KM Macro that uses the Execute an AppleScript action
- FastScripts
- Script Debugger 7
- Script Editor
-
IF Action is set to use TEXT, then the text will be opened in the appropriate editor
-
ELSE the Script File Path will be used to open the file
using the default app, except for JXA scripts,
which will use Script Editor. -
IF the Action is ExecuteMacro, the Sub-Macro will be opened in the KM Editor.
-
This script handles these Script Action Types:
- Execute AppleScript (AS)
- Execute JavaScriptForAutomation (JXA)
- Execute JavaScript (JS)
- Execute ShellScript (SS)
and also:
- Execute Macro (Sub-Macro)
Requires
- KM Ver 8.2+
- macOS 10.12.5 + (Sierra+)
- BBEdit 12+
Notes
- This script has been highly customized for my Mac, and my preferences
- You may need to make some adjustments for your environment and/or preferences
Comments
- Please feel free to reply with any issues, comments, and/or suggestions you have.
AppleScript
property ptyScriptName : "Edit Script/Sub-Macro in Selected KM Action"
property ptyScriptVer : "2.7.1" -- ADD Open New KM Editor Window if Open ExecuteMacro
property ptyScriptDate : "2019-12-20"
property ptyScriptAuthor : "JMichaelTX"
(*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### Select an Action in the KM Editor, THEN Run this Script ###
โข IF Action is set to use TEXT, then the text will be opened in the appropriate editor
โข ELSE the Script File Path will be used to open the file
using the default app, except for JXA scripts,
which will use Script Editor.
* IF the Action is ExecuteMacro, the Sub-Macro will be opened in the KM Editor.
โข This script handles these Script Action Types:
โข Execute AppleScript (AS)
โข Execute JavaScriptForAutomation (JXA)
โข Execute JavaScript (JS)
โข Execute ShellScript (SS)
and also:
โข Execute Macro (Sub-Macro)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*)
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions
property LF : linefeed
property ptySEAppID : "com.apple.ScriptEditor2" -- Script Editor App ID
try --=========== TRY ==============
set subMacroUID to ""
set scriptPath to ""
set scriptText to ""
set useTextBool to false
tell application "Keyboard Maestro"
set actionList to selection
set oAction to item 1 in actionList
if class of oAction โ action then
error "The selected item is NOT an action!"
end if
tell oAction
set actXML to xml
set actionName to name
end tell -- oAction
end tell
set oDict to my getDict(actXML)
--set keyList to oDict's allKeys() as list
set actionType to my getValueForKey(actionName, oDict, "MacroActionType")
if (actionType = "ExecuteMacro") then
set subMacroUID to my getValueForKey(actionName, oDict, "MacroUID")
else if (actionType = "SetVariableToText") then
set useTextBool to true
set scriptText to my getValueForKey(actionName, oDict, "Text")
else --- GET SCRIPT ACTION DATA ---
set scriptPath to my getValueForKey(actionName, oDict, "Path")
set scriptText to my getValueForKey(actionName, oDict, "Text")
set useTextBool to my getValueForKey(actionName, oDict, "UseText")
end if
set scriptResults to "OK"
if (useTextBool) then
-----------------------------------
-- OPEN TEXT IN EDITOR
-----------------------------------
if (actionType = "ExecuteAppleScript") then
--- OPEN SCRIPT in DEFAULT SCRIPT EDITOR ---
set appInfoRec to getDefautltApp("scpt")
if ((name of appInfoRec) contains "Script Debugger") then
openScriptInSD(scriptText)
else
openScriptInSE(scriptText)
end if
else if (actionType = "ExecuteJavaScriptForAutomation") then
--- OPEN SCRIPT in SCRIPT EDITOR ---
openScriptInSE(scriptText)
else if (actionType = "ExecuteJavaScript") then
--- OPEN SCRIPT in BBEdit | Atom | VisualStudioCode ---
openTextInBBEdit(scriptText, "JavaScript")
else if (actionType = "ExecuteShellScript") then
--- OPEN SCRIPT in BBEdit | Atom | VisualStudioCode ---
openTextInBBEdit(scriptText, "Unix Shell Script")
else if (actionType = "ExecuteSwift") then
--- OPEN SCRIPT in BBEdit | Atom | VisualStudioCode ---
openTextInBBEdit(scriptText, "Unix Shell Script")
else if (actionType = "SetVariableToText") then
--- OPEN SCRIPT in BBEdit ---
openTextInBBEdit(scriptText, "")
else ## ???
set msgStr to "Could not find an Editor for Script Type: " & actionType
my dispDialog(msgStr, {})
set scriptResults to "[ERROR]" & LF & msgStr
end if
else if (scriptPath โ "") then
-----------------------------------
-- OPEN FILE
-----------------------------------
tell application "Keyboard Maestro Engine"
set scriptPath to process tokens scriptPath
end tell
if (actionType = "ExecuteJavaScriptForAutomation") then
my openFileInFinder(scriptPath, ptySEAppID)
else
my openFileInFinder(scriptPath, "")
end if
else if (actionType = "ExecuteMacro") then
-----------------------------------
-- OPEN SUB-MACRO TO EDIT
-----------------------------------
tell application "Keyboard Maestro" to activate
tell application "Keyboard Maestro Engine"
--- OPEN NEW KM EDITOR WINDOW ---
do script "12F56BD3-F2DE-4EDF-84D2-41AA8E2E5AB2"
delay 0.5
tell application "Keyboard Maestro" to editMacro subMacroUID
end tell
end if
on error errMsg number errNum --======= ON ERROR =========
if errNum = -128 then ## User Canceled
set errMsg to "[USER_CANCELED]"
end if
set scriptResults to "[ERROR]" & return & errMsg & return & return ยฌ
& "SCRIPT: " & ptyScriptName & " Ver: " & ptyScriptVer & return ยฌ
& "Error Number: " & errNum
my dispDialog(scriptResults, {"Cancel"})
end try --======== END TRY ==========
return scriptResults
--~~~~~~~~~~~~~~~~~~~ END OF MAIN SCRIPT ~~~~~~~~~~~~~~~~~~~~~~
on getDict(pXML)
set theString to current application's NSString's stringWithString:pXML
-- convert string to data
set stringData to theString's dataUsingEncoding:(current application's NSUTF8StringEncoding)
-- convert plist to mutable dictionary
set {mutableDict, theError} to current application's NSPropertyListSerialization's propertyListWithData:stringData options:(current application's NSPropertyListMutableContainersAndLeaves) format:(missing value) |error|:(reference)
if mutableDict is missing value then error (theError's localizedDescription() as text)
return mutableDict
end getDict
on getValueForKey(pActionName, poDict, pKeyStr)
set LF to linefeed
--- extract Object for Key ---
set nsValueForKey to poDict's objectForKey:pKeyStr
--- Convert to nsArray to Get Proper AS Class ---
(*
FROM: Shane Stanley (2016-06-13)
https://lists.apple.com/archives/applescript-users/2016/Jun/msg00080.html
What this does is makes a single-item array containing theResult.
When that's converted to an AppleScript list, the item within it
will also be converted to an AppleScript item if it can.
So this covers all the bridgeable AS classes
-- text, numbers, lists, records, whatever [including missing value]
*)
set nsValueForKeyArray to current application's NSArray's arrayWithArray:{nsValueForKey}
set valueForKey to item 1 of (nsValueForKeyArray as list)
if (valueForKey is missing value) then ## ERROR Msg ##
set valueForKey to ""
set msgStr to "โฏโฏโฏ ERROR โฎโฎโฎ" & LF & ยฌ
"'" & pKeyStr & "' key was NOT found in XML for Action: " & LF & pActionName
set titleStr to "Handler: getValueForKey"
beep
my dispDialog(msgStr, {"Cancel"})
end if
return valueForKey
end getValueForKey
on openScriptInSD(pScriptStr)
--- USE CODE FOR Script Debugger 5,6 & 7 ---
-- This will run the latest version of SD installed on the user's Mac
repeat with i from 8 to 5 by -1
try
set sdApp to application id ("com.latenightsw.ScriptDebugger" & i)
exit repeat
end try
end repeat
using terms from application "Script Debugger 7"
tell sdApp
activate
set oDoc to make new document with properties {source text:pScriptStr, debugger enabled:false}
tell oDoc to compile
end tell -- sdApp
end using terms from -- application "Script Debugger"
end openScriptInSD
on openScriptInSE(pScriptStr)
tell application "Script Editor"
activate
set oDocSE to make new document with properties {text:pScriptStr}
tell oDocSE to compile
end tell
end openScriptInSE
on openFileInFinder(pPosixPath, pOpenWithAppID)
set pPosixPath to expandPath(pPosixPath)
tell application "Finder"
if ((pOpenWithAppID โ "") and (pOpenWithAppID is not missing value)) then
open (pPosixPath as POSIX file) using application file id pOpenWithAppID
else
open (pPosixPath as POSIX file)
end if
end tell
end openFileInFinder
on openTextInBBEdit(pString, pLangStr)
tell application "BBEdit"
activate
set oDoc to make new text document with properties {contents:pString, source language:pLangStr}
end tell
end openTextInBBEdit
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
on expandPath(pPosixPath) -- @Path @Posix @ASObjC
(* VER: 2.0 2017-03-02
---------------------------------------------------------------------------------
PURPOSE: Expand Tilde in Path to return full Path
PARAMETERS:
โข pPOSIXPath | text | Path that may contain tilde (~)
RETURNS: text โฃ Full Path
AUTHOR: JMichaelTX
REF:
1. Based on script from @ccstone (Chris Stone)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
*)
## Requires: use framework "Foundation"
set fullPath to (current application's NSString's stringWithString:pPosixPath)'s stringByExpandingTildeInPath
return fullPath as text
end expandPath
--~~~~~~~~~~~~~~~ END OF handler expandPath ~~~~~~~~~~~~~~~~~~~~~~~~~
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
on getDefautltApp(pFileExt)
(* VER: 2.0 2018-03-21
---------------------------------------------------------------------------------
PURPOSE: Get Info about the Default App for a Given File Extension
PARAMETERS:
โข pFileExt โ text โ File extension like "scpt"
RETURNS: โ record โ Info about the Default App
name: Name of App
id: ID of App (for use in tell blocks)
url: URL to App file
AUTHOR: JMichaelTX based on scripts by @ShaneStanley & @JonasWhale
REF:
1. 2017-11-26, ShaneStanley
How Do I get the Default App?
http://forum.latenightsw.com/t/how-do-i-get-the-default-app/830/2
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
*)
set thePath to current application's NSTemporaryDirectory()'s stringByAppendingString:("temp." & pFileExt)
current application's NSFileManager's defaultManager()'s createFileAtPath:thePath |contents|:(missing value) attributes:(missing value)
set theWorkspace to current application's NSWorkspace's sharedWorkspace()
set defaultAppURL to theWorkspace's URLForApplicationToOpenURL:(current application's |NSURL|'s fileURLWithPath:thePath)
if defaultAppURL = missing value then return missing value -- or false
set appInfo to ยฌ
{name:defaultAppURL's URLByDeletingPathExtension()'s lastPathComponent() as text, id:(current application's NSBundle's bundleWithURL:defaultAppURL)'s bundleIdentifier() as text, URL:defaultAppURL as ยซclass furlยป} ยฌ
return appInfo
end getDefautltApp
--~~~~~~~~~~~~~~~ END OF handler getDefaultApp ~~~~~~~~~~~~~~~~~~~~~~~~~
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
on dispDialog(pMsgStr, pButtonsList)
(* VER: 2.0 2018-03-23
---------------------------------------------------------------------------------
PURPOSE: Simplify Calling of display dialog Command
PARAMETERS:
โข pMsgStr | text | Text of Message
โข pButtonsList | list or text | Text list of Buttons, last will be default
IF empty, Then {"Cancel", "OK"}
RETURNS: | text | Button that was selected
AUTHOR: JMichaelTX
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
*)
try
set currentApp to ptyCurrentApp
on error
set currentApp to path to frontmost application as text
end try
--- SET DIALOG TITLE ---
try
set titleStr to ptyScriptName
if (titleStr = "") then set titleStr to (name of me)
on error
set titleStr to (name of me)
end try
--- SET DIALOG BUTTONS ---
if (class of pButtonsList โ list) then
set oldTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to {",", ", "}
set pButtonsList to text items of pButtonsList
set AppleScript's text item delimiters to oldTID
end if
if ((pButtonsList = {}) or (pButtonsList = "") or (pButtonsList = missing value)) then
set pButtonsList to {"Cancel", "OK"}
end if
set defaultButton to item -1 of pButtonsList
-----------------------------------
-- DISPLAY DIALOG --
-----------------------------------
tell application currentApp
set oAns to display dialog pMsgStr with title titleStr ยฌ
buttons pButtonsList default button defaultButton with icon caution
end tell
return (button returned of oAns)
end dispDialog
--~~~~~~~~~~~~~~~ END OF handler dispDialog ~~~~~~~~~~~~~~~~~~~~~~~~~