Macro: Delete KM Actions in Selected Macro by Name [Example]

Continuing the discussion from Find and Delete Macro Actions?:

This macro was built in response to the above request.

###MACRO:   Delete KM Actions in Selected Macro by Name [Example]

~~~ VER: 2.0    2017-11-03 ~~~

####DOWNLOAD:
Delete KM Actions in Selected Macro by Name [Example].kmmacros (17 KB)
Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.


Limitations

  1. This works ONLY on the currently selected Macro
  2. It searches ONLY the top-level Actions.
  • So, for example, Actions in another Action (like a Group Action) will NOT be searched.
  1. I strongly recommend that you backup your macro BEFORE running this macro.
  2. The function that searches for the match of Actions is complicated.
  • While I have made a number of tests, it is possible that it could fail
  • I think the failure would be most likely not finding a valid sequence of Actions, but I can't be sure
  • If you observe any unusual results, please discontinue use immediately, and notify me immediately by PM.

###ReleaseNotes

~~~ ReleaseNotes for VER: 2.0 2017-11-03 ~~~
Author.@JMichaelTX

PURPOSE:

  • Delete Sequence of Actions in Selected Macro
  • Note: Searches ONLY for top-level Actions in the Macro
    • So, for example, Actions in another Action (like a Group Action) will NOT be searched.

REQUIRES:

  1. KM 8.0.2+
  • But it can be written in KM 7.3.1+
  • It is KM8 specific just because some of the Actions have changed to make things simpler, but equivalent Actions are available in KM 7.3.1.
    .
  1. macOS 10.11.6+ (El Capitan)
  • KM 8 Requires Yosemite or later, so this macro will probably run on Yosemite, but I make no guarantees. :wink:

NOTICE: This macro/script is just an Example

  • It has had very limited testing.
  • You need to test further before using in a production environment.
  • It does not have extensive error checking/handling.
  • It may not be complete. It is provided as an example to show you one approach to solving a problem.

HOW TO USE:

  1. Enter the List of Action Names you want to delete into the first (magenta) Action of this Macro
  2. Enter the Compare Type: "Starts with" or blank (which means exact match)
  3. Select the Macro in the KM Editor for which you want the Actions to be deleted
  4. Make a backup copy of this macro
  5. Trigger this macro

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. :wink:
      .
  • Assign a Trigger to this maro.
  • Move this macro to a Macro Group that is only Active when you need this Macro.
    • Should be a group where the KM Editor app is allowed
  • ENABLE this Macro.
    .
  • REVIEW/CHANGE THE FOLLOWING MACRO ACTIONS:
    (all shown in the magenta color)
    • Set Variable Local__ActionNamesToDelete
    • Set Variable Local__CompareType
      • Set to empty (blank) for exact match
      • Set to "Starts with" to match Actions that start with your list to delete

TAGS: @KM @Actions @Edit @AppleScript

USER SETTINGS:

  • Any Action in magenta color is designed to be changed by end-user

ACTION COLOR CODES

  • To facilitate the reading, customizing, and maintenance of this macro,
    key Actions are colored as follows:
  • GREEN -- Key Comments designed to highlight main sections of macro
  • MAGENTA -- Actions designed to be customized by user
  • YELLOW -- Primary Actions (usually the main purpose of the macro)
  • ORANGE -- Actions that permanently destroy Variables or Clipboards,
    OR IF/THEN and PAUSE Actions

USE AT YOUR OWN RISK

  • While I have given this limited testing, and to the best of my knowledge will do no harm, I cannot guarantee it.
  • If you have any doubts or questions:
    • Ask first
    • Turn on the KM Debugger from the KM Status Menu, and step through the macro, making sure you understand what it is doing with each Action.


AppleScript

property ptyScriptName : "Delete Sequence of KM Macro Actions"
property ptyScriptVer : "3.0"
property ptyScriptDate : "2017-11-03"
property ptyScriptAuthor : "JMichaelTX"

(*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PURPOSE:
  • For the currently selected Macro, search for a sequence of Action Names,
      and if found, delete them.
  • Note:  The Actions must appear in exactly the order listed.
  • Strongly Recommend that your BACKUP your Macro BEFORE running this script.


REQUIRED:
  1.  macOS 10.11.6+
  2.  Mac Applications
      • KM 8.0.3+
      
KM VARIABLES REQUIRED:
  •  Local__ActionNamesToDelete    -- list of Action Names to Delete (one per line)
        
REF:  The following were used in some way in the writing of this script.
  1.  https://forum.keyboardmaestro.com/t/find-and-delete-macro-actions/8452
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*)
--- Method Used to Compare Action Names to Delete with Actual Name ---
property compareType : "" -- Set to "Starts with" or ""

### Example Input Data
# set actionNamesToDelete to {"Comment “Name 1”", "Comment “Name 2”"}

set kmInst to system attribute "KMINSTANCE"

tell application "Keyboard Maestro Engine"
  set actionNamesToDelete to paragraphs of (getvariable "Local__ActionNamesToDelete" instance kmInst)
  set compareType to getvariable "Local__CompareType" instance kmInst
end tell

tell application "Keyboard Maestro"
  
  --- GET the First Selected Macro ---
  --    (Changes will be made to it)
  
  set oMacro to first item of (get selected macros)
  set actionNameList to name of actions of oMacro
  
  --- Get The Starting and Ending Index of Actions that Match the Actions to Delete ---
  set {matchStart, matchStop, actionNamesFound} to my getSeqMatch(actionNameList, actionNamesToDelete, compareType)
  
  --- IF a Match of the Complete Sequence of Actions was Made; THEN Delete Those Actions ---
  
  if (matchStart > 0) then
    --  Get List of id's of All Actions of Macro --
    set actionIDList to id of actions of oMacro
    
    -------------------------------------
    --  DELETE ACTIONS --
    -------------------------------------
    
    tell oMacro
      set macroName to name
      
      repeat with i from matchStart to matchStop
        --- We Must Delete by Action ID, NOT by Action Name ---
        --    (there can be multiple Actions with the same name)
        
        delete action id (contents of item i of actionIDList)
      end repeat
    end tell -- oMacro
    
    set AppleScript's text item delimiters to (linefeed & tab & "• ")
    
    set scriptResults to "❯❯❯ ACTIONS DELETED ❮❮❮ in Macro " & macroName & linefeed & "• Action #'s: " & ¬
      "From: " & matchStart & "   To: " & matchStop & linefeed & ¬
      "• Action Names: " & (linefeed & tab & "• ") & (actionNamesFound as text)
    
  else
    set AppleScript's text item delimiters to (linefeed & tab & "• ")
    
    set scriptResults to "❯❯❯ NO Actions Were Deleted ❮❮❮ in Macro " & macroName & linefeed & linefeed & ¬
      "Could NOT find a match for this sequence of Actions: " & (linefeed & tab & "• ") & ¬
      (actionNamesToDelete as text)
    
  end if
  
end tell -- "Keyboard Maestro"



return scriptResults

--~~~~~~~~~~~~~~ END OF MAIN SCRIPT ~~~~~~~~~~~~~~~~~~~~

--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

on getSeqMatch(pMainList, pListToFind, pCompare)
  (*  VER: 3.0    2017-11-03
    PURPOSE:  Search the pMainList to Determine if it Contains
                  a sequence of Items in the pListToFind
                If it does, then Get The Starting and Ending Index# of the Item Sequence
    PARAMETERS:
      • pMainList    | List of text items to search
      • pListToFind  |  List of Items to Find in Sequence
    RETURNS:  List:  {Start Index#, End Index#} in pMainList
                          {0, 0} if sequence not found
    AUTHOR:  JMichaelTX
    COMMENT:  I'm sure this can be further optimized.  It is still a draft.
        
  *)
  local iLastMatch, iMain, iFind, oItemMain, oItemFind, numMainList, numListToFind
  
  --- CHECK FOR VALID PARAMETERS ---
  if ((class of pMainList is not list) or (pMainList = {}) or ¬
    (class of pListToFind is not list) or (pListToFind = {})) then
    --------------
    return {0, 0}
    --------------
  end if
  
  set iLastMatch to 0 -- index in MainList that matched last compare
  set iMain to 0 -- current index in MainList
  set iFind to 1 -- current index in ListToFind
  set numItemsMatched to 0
  
  set numMainList to count of pMainList
  set numListToFind to count of pListToFind
  
  ---------------------------------------------------------
  --- Loop Thu MainList To Search ---
  ---------------------------------------------------------
  --   Try to find a sequence match starting with each MainList Item --
  
  repeat with iMain from 1 to numMainList
    
    set iLastMatch to 0
    set numItemsMatched to 0
    set actionNamesFound to {}
    
    --- Remaining Items in MainList MUST be ≥ Num of Items in Find List ---
    if ((numMainList - iMain + 1) ≥ numListToFind) then
      
      set iMainSeq to iMain - 1
      
      --------------------------------------------------------
      --- Attempt to Match Seq of All Items in ListTofind ---
      --------------------------------------------------------
      
      repeat with iFind from 1 to numListToFind
        set iMainSeq to iMainSeq + 1
        set oItemMain to contents of (item iMainSeq in pMainList)
        set oItemFind to contents of (item iFind in pListToFind)
        
        --- Compare Main Item with ItemToFind ---
        
        if (pCompare = "Starts with") then
          set foundBool to (oItemMain starts with oItemFind)
        else
          set foundBool to (oItemMain = oItemFind)
        end if
        
        --- IF Match was Found ---
        if foundBool then
          --- Set LastMatch Index to Current Main List Index ---
          set iLastMatch to iMainSeq
          set numItemsMatched to numItemsMatched + 1
          set end of actionNamesFound to oItemMain
          
        else -- Could NOT match all Items
          set iLastMatch to 0
          set numItemsMatched to 0
          set actionNamesFound to {}
          exit repeat -- move to next Item in MainList
        end if
        
      end repeat -- with iFind
      
    end if
    
    --- EXIT SEARCH When All Items Found in Sequence ---
    if (numItemsMatched = numListToFind) then
      exit repeat
    end if
    
  end repeat -- with iMain
  
  --- IF All Items were NOT Found, Set Last Match to 0 ---
  if (numItemsMatched ≠ numListToFind) then
    set iLastMatch to 0
    set iStartMatch to 0
  else
    set iStartMatch to iLastMatch - numListToFind + 1
  end if
  
  return {iStartMatch, iLastMatch, actionNamesFound}
  
  
end getSeqMatch
--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2 Likes