I’m working on moving my Text Expander snippets to Keyboard Maestro. I can reproduce lot of the functionality pretty easily, but there is one Text Expander feature I’m struggling to reproduce in Keyboard Maestro.
All the TE-replacement actions are triggered by typing some unique string, like “;snipA”. In the basic use case, I have an action to paste in some replacement text, like “EXAMPLE SNIPPET TEXT!” But in some of the more complex use cases, I have a snippet that refers to another snippet. This looks something like: “;snipB” -> “Recursive snippet: %snippet:;snipA%”. The “%snippet:(…)%” is a keyword in TE that means to first replace in the text of whatever snippet(s) is(are) named there, then paste in the combined text after expanding all the nested snippets.
It seems like I could do this by executing one KM macro from within another. The problem I’m having is that I can’t execute a KM macro without knowing the name in advance.
I could just go through all of my (hundreds of) Text Expander snippets, find all the “%snippet:(…)%” strings, convert them into “Execute macro” actions referring to specific macros by name, and be done with it. But I would rather automate the problem once and have it work forever, even for new macros. Is there any way for me to pull a bit of text out of a variable, and use that text to execute a specific macro?
P.S. I thought going out to AppleScript might be a solution—for example:
tell application "Keyboard Maestro Engine"
do script ";snipA"
end tell
But I couldn’t figure out how to execute an AppleScript action with a variable. Is that possible?
One caveat, and it’s probably obvious, but the macro name has to be unique.
You can also pass the “UUID” of the macro, and that eliminates the need for the macro name to be unique. But I doubt it applies in your situation. Just mentioning it to be thorough.
I haven’t been able to make the kmtrigger:// url action work to do what I want. When I try to execute a macro from within KM using the Open URL action, it doesn’t execute. (I placed a “Pause Debugger” action at the beginning and can verify that it never triggered.) On the other hand, when I open the “kmtrigger://macro=SomeMacroName” URL in Safari, then the macro does execute.
Even if I do get the Open URL action to execute a macro, I don’t know how to use the value that will be produced. I would want to capture the text produced by the invocation of the nested macro, then use that to modify the text of the first macro (i.e. remove the “%snippet:foo%” string and replace it with the value that I got by executing the macro named “foo”).
The steps you’ve given look correct, but only in the case where a macro is being called from another macro. To be more clear, I’ll give two use cases. In both, note the different behavior of Macro B.
I want to trigger Macro A. It triggers on the text “;macroA”. Its action is to evaluate the text “My text is: %snippet:;macroB%”. It has some logic to figure out the name “;macroB” from that “%snippet:…%” string, and follows the steps you’ve given above to get the value of Macro B. It replaces “%snippet:;macroB%” with that value. Then once all “%snippet:…%” strings are gone, its final action is to paste the final value.
I want to invoke Macro B directly, by typing the trigger string “;macroB”.
In the first case, Macro B’s action is to set its value to a named variable, which would be used by Macro A. In the second case, Macro B pastes its value.
I’m thinking of breaking each TE snippet into two KM macros: one that triggers on a unique set of keystrokes, and another that stores a variable value. The first macro would call the second and paste the value in, whereas the second only sets the variable value (and perhaps also parses the variable for “%snippet:…%” strings and calls other macros to resolve those). In this way, I can preserve the behavior I want—each unique set of keystrokes will trigger a value to be pasted—while still allowing other snippets to provide values without every one of them trying to paste its value in where it isn’t needed directly.
Let me post what I’ve got right now, which will work. I’m probably going to make a plugin for it, because it’s a natural for that. But in the meantime, this should do the trick. Give me a few to make it presentable.
I will need to tweak it before I can get the workflow I’m thinking of. I’m new at KM, so that will take a while. But this gives me a good start. Thanks agin.