Markdown listing of all macros, by group and name, with any initial comment

A draft script which places a sorted Markdown list of all your Keyboard Maestro macros, by group and name, in the clipboard.

( Marked 2 can generate rich text and PDF from markdown clipboards )

(If the first action is a comment, also includes the comment title and text).

Reads the main Keyboard Maestro Macros.plist directly, so the script should not be used unless that file is fully backed up.

Yosemite only – uses Javascript for Applications.

Markdown listing of all macros, with any initial comments.kmmacros (20.2 KB)

Uncompressed source:

// Markdown listing of Keyboard Maestro library
// Sorted by Groups and Macro names
// Includes any initial comment (i.e. if first action of Macro is comment)

// CAUTION: Reads directly from the user's main Keyboard Maestro Macros.plist.
// 
// Even read-only operations should only be done on important data
// IF IT IS WELL BACKED UP

// Back up your KM data **before** running this script

/****
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****/

// Rob Trew, MIT license, 2015

// draft 0.3 Add comments, slight tidy

function run() {

  var a = Application.currentApplication(),
    sa = (a.includeStandardAdditions = true, a);

  // Keyboard Maestro Macros.plist or specified file read to Markdown
  // MaybePath || PathToMain plist --> Markdown --> Markdown Clipboard
  function kmMacrosMarkDown(strPlistPath) {
    strPlistPath = strPlistPath || sa.pathTo(
      'application support', {
        from: 'user domain'
      }
    ) + "/Keyboard Maestro/Keyboard Maestro Macros.plist";


    var strGroupHdr = '\n#### ',
      strMacroHdr = '- ';


    // Objects ranked by any .name string
    // a --> b --> (-1 | 0 | 1)
    var nameSort = function (a, b) {
      var aName = a.name,
        bName = b.name;
      
      a = aName ? aName.toLowerCase() : '';
      b = bName ? bName.toLowerCase() : '';

      return (a < b) ? -1 : (a > b ? 1 : 0);
    };

    var lstGroups = ObjC.deepUnwrap(
        $.NSDictionary.dictionaryWithContentsOfFile(strPlistPath)
      ).MacroGroups,

      // Unsorted list of Group objects with name and Markdown macro listings
      lstG = lstGroups.reduce(
        function (lstG, g) {

          // Unsorted list of Macro objects with name and MD for any starting comment
          var oMacros = g.Macros,
            lstMacros = oMacros ? oMacros.reduce(
              function (lstM, m) {
                var oActions = m.Actions,
                  dctFirstAction = (oActions && oActions.length) ?
                  oActions[0] : null;

                // MACRO OBJECT with name and any initial comment 
                return lstM.push({
                  name: m.Name,
                  comment: "Comment" === (
                    dctFirstAction ? dctFirstAction.MacroActionType : ""
                  ) ? "\t<b>" + dctFirstAction.Title + "</b>\n\t" + (
                    dctFirstAction.Text.split("\n").join("\n\t") + "\n"
                  ) : ""
                }), lstM;
              }, []
            ) : [];

          // GROUP OBJECT with name and MD for sorted macros
          return (lstG.push({
            name: g.Name,
            macros: (lstMacros.sort(nameSort), lstMacros).reduce(
              function (s, m) {
                return s + strMacroHdr + m.name + '\n' + m.comment + '\n';
              }, ''
            )
          }), lstG);
        }, []
      );

    // Markdown listing of sorted Groups, with their sorted macros
    return (lstG.sort(nameSort), lstG).reduce(
      function (s, g) {
        return s + strGroupHdr + g.name + '\n' + g.macros;
      }, ''
    );
  }


  // Defaults to reading:
  // ~/Library/Application Support/Keyboard Maestro/Keyboard Maestro Macros.plist
  var strReport = kmMacrosMarkDown();

  return (
    sa.setTheClipboardTo(strReport), strReport
  );
}
6 Likes