Bug Report: Keyboard Maestro Does NOT Error if Macro Does NOT Exist in AppleScript

###Bug Report: Keyboard Maestro Does NOT Error if Macro Does NOT Exist in AppleScript

This command should fail if the Macro does NOT exist:

editMacro macroName

Running Keyboard Maestro 7.3.1 (7.3.1) on macOS 10.11.4

To add to my frustration, AFAIK there is no way to test for whether or not a Macro exists, when you have only the Macro name. And, I don’t see a way to get the Macro UUID from a Macro Name.

This script does NOT return an error, although it should if the Macro does NOT exist:

tell application "Keyboard Maestro Engine"
  set macroName to getvariable "SCPT__MacroName"
end tell

set macroName to "My XXX BAD Macro" ### this macro does NOT exist


if (macroName ≠ "") then
  --–––––––––––––––––––––––––––––––––––––––––––
  try --=========== TRY ==============
    tell application "Keyboard Maestro"
      log macroName
      set existsMacro to exists macroName
      editMacro macroName
      return "OK"
    end tell
    
  on error --======= ON ERROR =========
    return "[ERROR]  Script could NOT Open this Macro: " & macroName
    
    
  end try --======== END TRY ==========
  --–––––––––––––––––––––––––––––––––––––––––––
  
else
  return "[ERROR] KM Variable 'SCPT__MacroName'is empty/missing, so Macro can NOT be edited."
end if


If anyone has a solution/workaround, please post.

Funny that you are mentioning this. I came across the same issue a couple of days ago while writing the EagleFiler Capture macro.

My clumsy workaround is to get – via UI scripting – the value of the name field of the macro opened by the editMacro command and check it against the should-be name.

So, I definitely agree: it should return an error.

I think you're right – UIDs are unique, but the Name properties of macros are not.

You could certainly list the UIDs of macros with a given name (as below, for example), but you might get multiple matches.

(function () {
    'use strict';

    // kmMacroNameUIDs :: String -> [UID]
    function kmMacroNameUIDs(s) {
        return kmGroups()
            .reduce(function (a, g) {
                var ms = g.Macros;

                return ms && ms.length ? (
                    a.concat(
                        concatMap(function (m) {
                            return s === m.Name ? [
                                m.UID
                            ] : [];
                        }, ms)
                    )
                ) : a
            }, [])
    }

    // kmGroups :: () -> [kmGroup]
    function kmGroups() {
        var a = Application.currentApplication();

        return ObjC.deepUnwrap(
                $.NSDictionary.dictionaryWithContentsOfFile(
                    (a.includeStandardAdditions = true, a)
                    .pathTo(
                        'application support', {
                            from: 'user domain'
                        }
                    ) + "/Keyboard Maestro/Keyboard Maestro Macros.plist"
                )
            )
            .MacroGroups;
    }

    // concatMap :: (a -> [b]) -> [a] -> [b]
    function concatMap(f, xs) {
        return [].concat.apply([], xs.map(f));
    }

    return kmMacroNameUIDs("Copy as Markdown");

})();

Thanks. I'm looking for a simple doesMacroExist(macroNameStr) test.
I could just search the plists file for the macro name, but I thought you might have a more elegant solution. Since the Keyboard Maestro Macros.plist file is very large (4MB on my Mac), I'd like a quick, efficient solution.

Any suggestions?

True. Noted.

Yes, there might be multiple UUIDs for a given name. I'll look at adding a token for that.

And I hope to improve AppleScript access to the macros in a future version.

2 Likes

Sorry, I wasn’t at my Mac before.

Here’s a snippet to test for the name:

      tell application "System Events"
        tell its application process "Keyboard Maestro"
          tell its window "Keyboard Maestro Editor"
            tell its group 1
              tell its splitter group 1
                tell its scroll area 3
                  tell its text field 1
                    if its value ≠ (macroTemplateName & space & "copy") then
                      wrongMacroAlert()
                      error number -128
                    else
                      set its value to newMacroName
                    end if
                  end tell
                end tell
              end tell
            end tell
          end tell
        end tell
      end tell
    on error
      renamingAlert()
      error number -128