Keyboard Maestro 8.0.4 “Super Swap” Macro
Name: Super Swap
Author: Mike Pasini
Last Update: 7 December 2017
Keyboard Maestro comes with a Swap Characters macro in the Macro Library which does the job for those of us who regularly transpose characters.
I have elevated that defect to a higher level by transposing words and even phrases. So I wrote some macros to swap those as well.
But I started to get trigger happy with multiple swapping macros. So I consolidated them into one macro with the same trigger whose behavior changes based on the selection.
I no longer have to remember how to invoke the correct routine. The macro itself knows what to do.
This macro swaps characters if no selection is made, words if there are just two words selected, outer words if three are selected and whole phrases separated by an "and" or an "or." You can also use a double caret to delimit two elements to swap.
If the macro can't handle your selection, it leaves it alone.
Each case is illustrated below with an example in which the | indicates cursor position when the whole original is not selected. The swapped line in each example was actually created by the macro.
1) To swap characters, put the cursor before the first of the two characters to swap or just select both characters.
2) To swap words, just select the two words and the space between them.
3) To swap outer words (like "second before first" or "last came first"), just select the three words and the spaces between them.
worse is better
better is worse
4) To swap phrases (like "the usual second award or the grand prize"), just select the whole phrase. The "and" or "or" will stay put and the outer phrases will be swapped.
the first time I saw Rome and my first trip to Europe
my first trip to Europe and the first time I saw Rome
a $100 mail-in rebate or a free set of ink cartridges
a free set of ink cartridges or a $100 mail-in rebate
5) To swap elements of a series, select the two items including their punctuation. Elements can be on their own line, as well.
two, one, three
one, two, three
6) To swap anything at all, use two carets (^^) as a fulcrum in your selection. Existing whitespace at the ends of each piece in the selection will be ignored with a space inserted between the two pieces with the caret deleted. A return will be preserved.
and so on 'abc'^^ but about the 'def'
but about the 'def' and so on 'abc'
If the result isn't what you expect, you can restore the original with a Command-Z to undo the swap. That's when you might resort to the double caret trick or a simple drag-and-drop.
DETECTING A SELECTION
We use a simple, but fast, method of detecting a selection. It works in the applications we use, which include a variety of text editors and InDesign.
If it doesn't work for you, there is a more sophisticated way to check for a selection. You can use this method (https://forum.keyboardmaestro.com/t/cb-how-to-detect-when-clipboard-has-changed-example/4836) based on the clipboardseed function (https://wiki.keyboardmaestro.com/function/CLIPBOARDSEED), for example.
You can, and we did (initially), write this macro using Keyboard Maestro actions instead of a shell script.
But Keyboard Maestro's visual If-Then-Else constructs, helpful in simple cases, quickly became unwieldy. As we added options, a simple Perl script that looked for specific clues in the selection to apply simple regexes to it made it easier to test and expand the macro.
Testing was done with a Perl script in BBEdit that threw a number of test strings at the Perl code, which also identified which branch made the substitution, which was edifying, to say the least.
This is simple enough that other languages could easily have handled the task too. We just admire the economy of working with regexes in Perl.
Nothing tricky going on here except the evaluation of the selection.
The embedded Perl script handles all four possible selections. Otherwise (no selection) we revert to what Swap Characters does except this version skips an action by requiring you to put the cursor after the last correct character rather than between the transposed ones. You can just use the original Swap Characters actions if you prefer.
One might quibble about using \s+ for whitespace but it fits the bill for this task. Except for Case 5 above, the whitespace is not preserved but replaced by (one might say "tidied up with") a single space. In Case 5, it is preserved to handle elements on individual lines.
Case 5 is pretty forgiving about trailing punctuation and space. In the example above, you can either include the space after "one," or not and it will be correctly formatted. You don't have to remember to be symmetrical in your selection.
The simpler swaps don't pay any attention to what whitespace the original used on the theory that, in a phrase, spaces delimit the words.
If Case 6 doesn't work for you, consider the drag-and-drop approach of selecting one element and dragging it by the other to complete the swap. Because the initial selection is often deselected when the cursor is repositioned and the mouse clicked to begin the drag, I added Case 6 to provide an alternative.
The initial public release of this macro comes during the 2017 holiday season as small thank you to the members of this forum whose work has illuminated my own and made life easier.
Super Swap.kmmacros (13 KB)