Get List of KM Macro Names Filtered By Macro Group and Macro Name [Example] Macro (v9.2)

Use Case

  • Provide a demo of how to extract Macros from the complicated Macro plist provided by the KM Engine
  • Since it does NOT require use of the KM Editor app (Keyboard Maestro.app), you can use this when you do not want the KM Editor to be open.
  • Provides an easy way to get a user-filtered list of macros.
  • Provides readable and user-modifiable JXA (JavaScript) code for those who want to use JXA.

My sincere thanks to @DanThomas for providing/publishing the source JXA code this macro/script is based on. You can find it in his great macro MACRO: Execute (Trigger) Macro by Name (Spotlight), which I highly recommend and use many times a day.

Example Output

image

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

MACRO:   Get List of KM Macro Names Filtered By Macro Group and Macro Name [Example]

-~~~ VER: 1.0    2021-03-13 ~~~
Requires: KM 8.2.4+   macOS 10.11 (El Capitan)+
(Macro was written & tested using KM 9.0+ on macOS 10.14.5 (Mojave))

DOWNLOAD Macro File:

Get List of KM Macro Names Filtered By Macro Group and Macro Name [Example].kmmacros
Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.


ReleaseNotes

Author.@JMichaelTX based on JXA Script by @DanThomas

PURPOSE:

  • Get List of KM Macro Names Filtered By Macro Group and Macro Name [Example]
    • Provide a demo of how to extract Macros from the KM Engine Plist.
    • This macro does NOT require the use of the KM Editor app.

HOW TO USE

  1. First, make sure you have followed instructions in the Macro Setup below.
  2. See the below "How to Use" Comment Action
  3. This macro is just an example written in response to a user's request. You will need to use as an example and/or change to meet your workflow automation needs.

MACRO SETUP

  • Carefully review the Release Notes and the Macro Actions
    • Make sure you understand what the Macro will do.
    • You are responsible for running the Macro, not me. ??
      .
      Make These Changes to this Macro
  1. Assign a Trigger to this Macro .
  2. Move this macro to a Macro Group that is only Active when you need this Macro.
  3. ENABLE this Macro, and the Macro Group it is in.
    • For more info, see KM Wiki article on Macro Activation
      .
  • REVIEW/CHANGE THE FOLLOWING MACRO ACTIONS:
    (all shown in the magenta color)

Set DEFALUT Values for These KM Variables

  • Set Variable “Local_FilterBy__MacroGroupName”
  • Set Variable “Local_FilterBy__MacroNameContains”

REQUIRES:

  1. KM 9.0+ (may work in KM 8.2+ in some cases)
  2. macOS 10.12.6 (Sierra)+

TAGS: @Example @Macros @Filter @JXA @Script @KMEngine

REFERENCE:
1. MACRO: Execute (Trigger) Macro by Name (Spotlight) by @DanThomas
2. AppleScript: How to Get a List of Macros in a Macro Group without the KM Editor Being Activated?

Hi @JMichaelTX,

I tested your latest macro with this:

image

I have the Macros as these:
image

But it finds nothing:

Did I miss anything?

Just a shot in the dark here - is the Atom Macro Group active? I noticed when running this macro (thanks for making it JMichaelTx), that it doesn't produce names if the group is inactive, or the names of inactive macros in an active group. I suspect this is a direct result of the original Dan Thomas macro, which logically wouldn't bring up inactive macros for execution, but I could be wrong as to all of this. ComplexPoint's functionally similar macro here will display inactive macros in an active group and any macros in an inactive group.
I don't know enough JavaScript to know how to make either script treat inactives the way the other does.

Yes. It is enabled. All the macros in the group are enabled as well.

OK, so much for shooting in the dark :smile:
I guess we'll have to leave it to the macro author to suss it out.

BINGO!

I intended to remove the JXA that filters out inactive MG and Macros, but forgot to do so.

The code is in the functions at the bottom of the script:

function extractMacrosFromPlist(pPlist) {
  //--- Function Based Mostly on "execute()" function by @DanThomas ---
  //--- Build a simple array of Macro objects;  Compresses the multi-tier arrary of the plist ---
  
    var macroList = [];
    pPlist.forEach(function(group) {
      if (group.macros) {
        group.macros.forEach(function(macro) {
          if (macro.active && macro.enabled) {
            var triggers = "";
            if (macro.triggers && macro.triggers.length > 0) {
              var triggers = macro.triggers.map(function(trigger) {
                return trigger.short;
              }).join(" | \n");
            }
            if (triggers)
              triggers = "; Triggers: " + triggers;
            macroList.push({
              macroUUID: macro.uid,
              macroName: macro.name,
              groupName: group.name,
              triggers: triggers
            });
          }
        });
      }
    });
   return macroList;
}

Do you see the line that does the filtering?
Good opportunity for you to play with the JXA script.
Give it a shot, and if you really get stuck, let me know.

EDIT: Hint: All you need to do is comment out (using the double //) two lines.

I did it!
Thanks for suggesting I learn how to fish instead of just giving me the fish.

1 Like

FWIW the macroList = [] ... .forEach ... .push technique there may be more complicated than it needs to be.

Probably worth looking at the built-in .flatMap method of JS Arrays, which lets you dispense with declaring an empty list and then selectively pushing things into it – you can define the mapped and filtered list you need directly.

Two key points:

  • the function passed to .flatMap returns its values list-wrapped
  • rejected values (filtered out) are returned as empty lists.

Where:

  • .filter can just discard, and
  • .map can only transform (always returning a list of unchanged length)

.flatMap can transform and filter in a single pass:

(() => {
    "use strict";

    const main = () => {

        // Each rejected value is represented
        // by an empty list.

        // evenNumbersTripled :: [Int]
        const evenNumbersTripled = [
            1, 2, 3, 4, 5, 6, 7, 8, 9, 10
        ].flatMap(
            n => even(n) ? (
                [3 * n]
            ) : []
        );

        return JSON.stringify(evenNumbersTripled);

        // --> [6,12,18,24,30]
    };

    // --------------------- GENERIC ---------------------



    // even :: Int -> Bool
    const even = n =>
        // True if 2 is a factor of n.
        0 === n % 2;

    return main();
})();

That could be, but it does work very well and very fast as it is.
FYI, this function was originally written by @DanThomas, who has provided many excellent macros and scripts. So I followed my long-time guideline: "If it ain't broke, don't fix it."
:wink:

Having said all that, I'm always open to learning new things, new techniques.
Thanks for the suggestion. I will investigate.

Thanks for your example. I'll see if I can understand it. :wink:

1 Like