@peternlewis, I need your help please when you have a few moments.
I'm writing an AppleScript to get all KM Variables for a selected macro.
AFAIK, the only way to do this is by searching the Macro XML. If you know otherwise, please advise.
Please confirm/correct that all KM Variables, in all KM Actions, can be identified by this bit of XML from the Macro XML:
Thanks for tackling this task. I've been wanting to for some time but haven't had the oomph.
@peternlewis – please, please expose the XML of the selected macro(s) to AppleScript. So many things you don't want to fool with will become possible for users to build themselves if you do.
I realize this will be a relatively small set of users, but the tools we build will trickle down to others.
Jim - Here's some JXA I wrote many years ago that does what you're talking about. I think the regex is similar, but if it's different, for all I know yours is better - I didn't compare them too closely. You have to pass the XML to it, because at the time I was new to JXA and I didn't know how to get the XML using JXA:
function run() {
'use strict';
var _kme = Application("Keyboard Maestro Engine");
var _string = _kme.getvariable("blvdMacroSource");
var _re = new RegExp("(\\<key>Variable\\</key>\\s*\\<string>)([^\\<]*)", "g");
var _matches = getMatches(_string, _re, 2).filter(onlyUnique).sort().join("\n");
return _matches;
function getMatches(string, regex, groupIndex) {
var _matches = [];
var _match;
while (_match = regex.exec(string)) {
var _varName = _match[groupIndex].trim();
if (!_varName.startsWith("%"))
_matches.push(_varName);
}
return _matches;
}
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
}
But be aware that this concept only works for variables that are specifically set in the macro. Because there's lots of ways for a variable to be referenced in a macro that don't fit that pattern. Actions that have Text fields, for instance.
If you're just talking about "defining" the variable (i.e. setting its value for the first time), there is at least one thing that wouldn't cover: If you call a sub-macro and pass the name of the result variable, and the sub-macro sets the variable's value. So in this instance it's entirely possible to have a variable set to a value, and then do something with the variable, without ever finding it using the regex.
Chris - Perhaps you could clarify what you mean by "expose the XML"? I mean, we know how to get the XML in a variety of ways, right? So what specifically do you mean by "expose the XML"?
I was wondering, is it possible to store individual macros in the exported macro forms, stored in subfolders with the macro group as it's folder name?
E.g.,
"KM Macros" (main folder) → "Global Macro Group" (subfolder) → all macros in the "Global Macro Group" in KM, the file name is the macro name user defined in KM editor.
Advantage:
When a user edit a macro, it only edit the individual macro file. So when two editor windows are open, they will only be operating on two individual macro files. When users move a macro to another macro group, that macro is moved to another folder.
For the question asked in the OP, we only need to search in that macro file.
Rather than "Export" and then upload to forum, and then delete the file, we can add another item in the right click macro contextual menu: "Copy Macro (file)". This will copy that individual macro file to the clipboard, so that we can "Paste" it to the forum post right away.
We can add another item to the contextual menu: "Locate macro in Finder". If copy and paste macro in point 3 does not work well, we can easily locate the macro file and drag or copy from Finder.
Thanks guys. I have a similar AppleScript that uses the KM Editor UI to copy the macro as XML.
It works fairly well, but as you know, any script that relies on an app's UI is somewhat fragile.
What Chris is asking for is much, much better. More robust, and much faster.
And it would be much simpler.
The requested change would provide XML as a properly of the Macro object, just like is provided for the Action object.
tell application "Keyboard Maestro"
set {oMacro} to (get selected macros) -- gets first macro
set macroXML to xml of oMacro --- NEW property that is being requested
set macroName to name of oMacro
end tell
Dan, thanks for sharing your script. Your RegEx is essentially the same as mine.
The problem is that, as you say, that only gets KM Variables that are set using the KM Action Set Variable to.... Turns out that there are many other ways to set/create KM Variables.
Here are just two as an example:
Of course, a KM Macro can reference (use) Global Variables that are set in another Macro.
So, if we want a list of all Variables that are USED in the Macro, we need to include these as well.
Well, yes and no. It depends on how robust you need it to be. I mean, I use my macro regularly, I'm just aware of its limitations. Most of the time it does enough of what I need.
The reason I say that is that I started writing something to handle all possible conditions a while back, and I eventually gave up, because there were just too many possibilities.
But I'll be rooting for you if you want to give it a try!
Wow~ this is another treasure of macros!
Thanks!
I wish this was done natively at the first place.
My wish still has a point though. Editing an individual macro file instead of editing the file that has all macros will make the KM editor much faster.
Almost certainly not. Most variables, but there are likely some actions that don't. Plus there are lots of other things that refer to variables (eg the output of a script) which might have variable names stored in different ways. And that is ignoring any references to tokens.
The XML is not documented at this level, and even if it were is subject to change that would violate this.
No. Keyboard Maestro internally keeps track of variables that are directly referenced by any macro, with reference counting, in order to provide the variables popup menus and such, but there is no connection to the containing macro, nor any sublists based on macros.