This is incredibly helpful. Thank you so much, @ComplexPoint!
I've modified the JXA code so it now works with both "Execute Subroutine" and "Execute Macro":
Go To Subroutine/Macro selected
ObjC.import("AppKit");
// Edit the Keyboard Maestro macro or subroutine that is
// executed by the copied KM Action (if any)
// Rob Trew @2025
// Ver 0.02 - Adjusted to handle both ExecuteSubroutine and ExecuteMacro
// main :: () -> IO Bool
const main = () => {
const
pb = $.NSPasteboard.generalPasteboard,
nsData = pb.dataForType(
"com.stairways.keyboardmaestro.actionarray"
);
return either(
alert("Jump to Macro or Subroutine")
)(uuid => {
const
km = Application("Keyboard Maestro"),
macro = km.macros.byId(uuid);
return macro.exists()
? (
km.editmacro(uuid),
`Editing macro/subroutine: "${macro.name()}"`
)
: `Macro or subroutine not found: "${uuid}"`
})(
bindLR(
nsData.isNil()
? Left("No 'Execute Subroutine' or 'ExecuteMacro' action copied to clipboard.")
: Right(
ObjC.deepUnwrap(
$.NSPropertyListSerialization
.propertyListWithDataOptionsFormatError(
nsData, $.NSPropertyListImmutable,
null, null
)
)
)
)(kmArray => {
const n = kmArray.length;
return bindLR(
0 < n
? 1 < n
? Left("Select just one 'Execute Subroutine' or 'ExecuteMacro' action.")
: Right(kmArray[0])
: Left("No KM Actions found in clipboard.")
)(dict => {
const
actionType = dict.MacroActionType;
return ("ExecuteSubroutine" === actionType || "ExecuteMacro" === actionType)
? Right(dict.MacroUID)
: Left(`Expected an 'Execute Subroutine' or 'ExecuteMacro' action, but saw: "${actionType}"`);
});
}
)
);
};
// ------------------------- JXA -------------------------
// alert :: String => String -> IO String
const alert = title =>
s => {
const sa = Object.assign(
Application("System Events"), {
includeStandardAdditions: true
});
return (
sa.activate(),
sa.displayDialog(s, {
withTitle: title,
buttons: ["OK"],
defaultButton: "OK"
}),
s
);
};
// ----------------------- GENERIC -----------------------
// Left :: a -> Either a b
const Left = x => ({
type: "Either",
Left: x
});
// Right :: b -> Either a b
const Right = x => ({
type: "Either",
Right: x
});
// bindLR (>>=) :: Either a ->
// (a -> Either b) -> Either b
const bindLR = lr =>
// Bind operator for the Either option type.
// If lr has a Left value then lr unchanged,
// otherwise the function mf applied to the
// Right value in lr.
mf => "Left" in lr
? lr
: mf(lr.Right);
// either :: (a -> c) -> (b -> c) -> Either a b -> c
const either = fl =>
// Application of the function fl to the
// contents of any Left value in e, or
// the application of fr to its Right value.
fr => e => "Left" in e
? fl(e.Left)
: fr(e.Right);
// MAIN ---
main();
Nice macro, @ComplexPoint. I also like the addition.
I have two other suggestions:
Add the Open a URL action when the address begins with: keyboardmaestro://m=
Provide an option to move to the target macro (in the current editor) rather than opening a new KM editor window. As you likely know, the editor becomes very sluggish when more than one window is open.
Just in case it is unknown, from the Execute a Macro/Subroutine macro selector you can go to the macro directly - not quite as quickly as this macro since you have to select from the popup menu of course.
...and their corresponding menu items and keyboard shortcuts. Last Edited is my personal favorite, especially since simply viewing a macro in edit mode marks it as "edited." This means the shortcut effectively lets you switch quickly between two macros.
Great Macro! I've been using it a lot already and these new additions have proven useful. I don't know if it would be possible, but if I could make another suggestion. I have several macros that show a palette for one action and sometimes I find I want to navigate to that macro group. Unlike the execute a macro, or subroutine, actions...when I click on it there is no "Go to Macro" option, or in this case "Go to Group". It would be nice if I could select the action, then run your macro and quickly navigate to the group.
In the example above, running your macro would take me to the Macro Group called Finder Palette.