Is There Way For an AppleScript or JXA script To Obtain the Name or Id of the Macro That Is Executing The Script?

I have a lot of Macros that are Executing JXA script. Is there way for the script being executed to find out some kind of name or id of the macro that is executing the script without hard coding the name in the script?
Thanks!

The KM Token "%ExecutingMacro%" will return the name of the currently executing macro. But it appears that, although scripts can "process tokens", this token is NOT working in a script. But it works well in a Macro Action.

This AppleScript returns an empty string (""):

tell application "Keyboard Maestro Engine"
  set kmExecMacro to process tokens "%ExecutingMacro%" -- returns ""
end tell

return kmExecMacro

So, we must resort to setting a KM Variable to this token, and then reading that Variable in the script. The below macro does this.

##Macro Library   [KM] Script Getting Macro Name that Called It [Example]


####DOWNLOAD:
<a class="attachment" href="/uploads/default/original/2X/9/9cc8d5f4fa1a144f823b3e6987a41516022aa00d.kmmacros">[KM] Script Getting Macro Name that Called It [Example].kmmacros</a> (3.5 KB)

---

<img src="/uploads/default/original/2X/4/433c3cc465e2ad9821abca182257f54e208ec174.png" width="506" height="748">

###Results

<img src="/uploads/default/original/2X/b/bbd7652ab8350349f18ba1aa51c7fbc14a3ec02b.png" width="596" height="184">

@peternlewis, I think this may be a bug. Can you please confirm?

Thanks! I also confirmed it in JXA.

kme.processTokens("%ExecutingMacro%") also returns “”.

Chi

Its not a bug per se - scripts simply don't have access to the macro context.

Think of an Execute (any kind of) Script action as conceptually:

  • Fire off the script.
  • Twiddle our thumbs.
  • Get a result back from the script.

The macro actions themselves have access to the context sensitive tokens, but the scripts are executed elsewhere and they do not have any such access.

I assume that's "Fire off", not "First off"?

1 Like

A couple of things, both of which may be obvious, but I wanted to mention them just in case.

First, just set a variable to “%ExecutingMacro%” before running the script. Then you can access the variable from the script. I realize this requires a little more work, but it’s a solution, now that we know that you can’t access the value from a running script.

Secondly, and this is just an FYI/reminder, “%ExecutingMacro%” will give you the name of the macro that initially started the thread, but it’s possible it’s not what you want.

For instance, if a sub-macro runs the script, you might want the name of the sub-macro. If that’s the case, use “%ExecutingThisMacro%” instead of “%ExecutingMacro%”.

2 Likes

Thanks for the additional information!

Chi

Yep, that's what I did in my above macro.

It's good to have the confirmation though. If anyone would have figured out a way around this, it would be Master Macro Man @DanThomas.

1 Like

I see that now, but when I looked previously, I somehow missed it. I actually really looked this time, too!

LOL. Right. Utter crapola, but thanks.

Strange. It seems to me that if a script can call the KM "process token" function to get, say, "SafariTitle", it should be able to get "ExecutingMacro". In both cases the KM engine has to do something to get the info.

No big deal, just thinking out loud.

Actually, this is similar to that issue with the JavaScript “eval” function we talked about the other day. Remember when we showed it wouldn’t work to use “eval” and pass the name of a variable, if that variable wasn’t in scope?

Process Tokens is pretty similar to eval. It can’t return the proper values for tokens that aren’t in scope.

Does that help at all?

1 Like

Sure, it's better than a poke in the eye with a sharp stick. LOL

Seriously, it does. Thanks.

1 Like

It would be nice if the scripts knew their invocation state, but they are basically entirely different processes - in fact they are entirely different processes. So the script doesn’t really know which macro caused it to be run (indeed, there could be multiple macros running multiple scripts, or the same macro running multiple times running multiple instances of the same scripts).

So the script can ask Keyboard Maestro for the safari title because Keyboard Maestro can work that out from scratch.

But it can’t ask about the macro that triggered it because it does not know which macro execution instance that might be (and neither does Keyboard Maestro really).

I hope that makes sense.

There might be some way for the information to be resolved, maybe some way for Keyboard Maestro to track the process of the osascript and use that information when it gets an external request for processing tokens or whatever, but then there is no guarantee that osascript doesn’t fire off another process that only it knows about, or that the system doesn’t run the scripts as another process, or whatever.

Just thinking out loud. Is it possible to pass a parameter to osascript for scripts to grab it?

Chi

1 Like

Not a parameter, but certainly a KM variable.

Yes, you can add parameters after a saved script's filepath in an Execute Shell script call to osascript,

Where the saved script might include AppleScript lines like:

on run argv
    if class of argv = list then
        map(asString, argv)
    else
        "No argument passed ..."
    end if
end run

-- asString :: a -> String
on asString(x)
    x as string
end asString


-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    script mf
        property lambda : f
    end script
    
    set lng to length of xs
    set lst to {}
    repeat with i from 1 to lng
        set end of lst to mf's lambda(item i of xs, i, xs)
    end repeat
    return lst
end map

but as Dan suggests, using a KM variable will probably tend to be simpler,

Yes, there are many ways for passing information from Keyboard Maestro into the script.

But for the process tokens to be able to access the context of the executed macro, some extra information would have to be passed back to Keyboard Maestro at the time. Let:

tell app “Keyboard Maestro Engine” to process tokens "%TriggerValue% iam “something”

Its perfectly possible to do, but its convoluted and ugly.

        script mf
            property lambda : f
        end script

That is one slick trick!

Though I puzzled over this:

        lambda(item i of xs, i, xs)

for a couple of minutes, since asString only takes one parameter. (I eventually realized that extra parameters are ignored and this formulation allows the lambda to take 1, 2, or 3 parameters. Very nice. Probably should remove the 2nd & 3rd args for this example, or add comment explaining.

Do you have a collection of functional programming handlers that you could post? Or just send to me and I can help with feedback for cleanup and documentation.

The three available arguments of

lambda(item i of xs, i, xs)

provide compatibility with Array.prototype.map() in JS

which provides the same set and sequence of references to:

  1. A particular element in the list (x)
  2. its index (i) (1-based in the AS convention, 0-based in the JS convention)
  3. the whole list (xs)

(You can just use the ones you need for a particular [a] -> [b] transformation).

(I find that keeping to that pattern eases translation between the AS and JS idioms)