Following up from an earlier extension from a two-macro cycle to a question about a three-macro cycle
Here is an approach to using one trigger to cycle through any number of macros.
Macro cycle Macros.kmmacros (10.0 KB)
Essentially you create a pipe-delimited text variable containing the name of each macro in the cycle, in the order that you need.
To cycle through 4 macros named:
- A macro
- Bee macro
- See macro, and
- Tea macro
you can create a variable called pipeDelimitedMacroNames
in the following pattern:
A macro | Bee macro | See macro | Tea macro
(with or without spaces flanking the pipe characters)
and then run this meta-macro, in which a script step rotates the variable, and runs whichever macro's name has come to the front:
Script source:
(() => {
const main = () => {
const
k = 'pipeDelimitedMacroNames',
kme = Application('Keyboard Maestro Engine'),
xs = rotate(1,
map(strip,
splitOn(
'|',
kme.getvariable(k)
)
)
);
return (
kme.setvariable(k, {
to: xs.join('|')
}),
kme.doScript(head(xs))
);
};
// GENERIC FUNCTIONS ----------------------------------
// https://github.com/RobTrew/prelude-jxa
// concat :: [[a]] -> [a]
// concat :: [String] -> String
const concat = xs =>
0 < xs.length ? (() => {
const unit = 'string' !== typeof xs[0] ? (
[]
) : '';
return unit.concat.apply(unit, xs);
})() : [];
// drop :: Int -> [a] -> [a]
// drop :: Int -> String -> String
const drop = (n, xs) => xs.slice(n);
// head :: [a] -> a
const head = xs => xs.length ? xs[0] : undefined;
// map :: (a -> b) -> [a] -> [b]
const map = (f, xs) => xs.map(f);
// replicate :: Int -> a -> [a]
const replicate = (n, x) =>
Array.from({
length: n
}, () => x);
// rotate :: Int -> [a] -> [a]
const rotate = (n, xs) => {
const lng = xs.length;
return lng > 0 ? takeDropCycle(lng, n, xs) : [];
};
// splitOn :: String -> String -> [String]
const splitOn = (pat, src) =>
src.split(pat);
// strip :: String -> String
const strip = s => s.trim();
// take :: Int -> [a] -> [a]
const take = (n, xs) => xs.slice(0, n);
// N items taken from an infinite cycle of xs, starting from index i
// takeDropCycle :: Int -> [a] -> [a]
const takeDropCycle = (n, i, xs) => {
const
lng = xs.length,
m = n + i;
return drop(i,
take(m,
(lng >= m ? xs : concat(replicate(Math.ceil(m / lng), xs)))
)
);
};
// MAIN ---
return main();
})();