Anyone know if there's a way to check the KM version in a script or Custom HTML Prompt?
Application("Keyboard Maestro Engine").version()
?
Or, of course, more comparably:
Application("Keyboard Maestro Engine")
.version()
.split(".")
.map(x => parseInt(x, 10));
A footnote on comparing / sorting versions – I'm not sure how you prefer to go about that, but here's one approach to defining comparison over integer lists like the ones above:
Given the JS convention of representing LT
EQ
and GT
as -1, 0, 1
(as in the functions we pass to Array.sort
)
The basic JS comparison of two values (of the same type) for their ordering might be written in an 'uncurried' form as:
// compare :: (a, a) -> Ordering
const compare = (x, y) =>
x < y ? -1 : (x > y ? 1 : 0);
and when we want to sort by a property of slightly more complex values (ordering strings by their length, for example, rather than by an alphabetic scheme), we can then step back one level and write:
// comparing :: (a -> b) -> (a -> a -> Ordering)
const comparing = f =>
(x, y) => {
const
a = f(x),
b = f(y);
return compare(a, b);
};
so that an ascending sort of strings by their length might look like:
Expand disclosure triangle for ASC by length
(() => {
"use strict";
const main = () => {
// Ascending sort by length of string.
console.log(
"Ascending length ::",
[
"alpha",
"beta",
"gamma",
"delta",
"epsilon",
"zeta",
"eta",
"theta",
"iota",
"kappa",
"lambda",
"mu",
"nu",
"omicron"
].sort(comparing(x => x.length))
);
};
// --------------------- GENERIC ---------------------
// compare :: (a, a) -> Ordering
const compare = (x, y) =>
x < y ? -1 : (x > y ? 1 : 0);
// comparing :: (a -> b) -> (a -> a -> Ordering)
const comparing = f =>
(x, y) => {
const
a = f(x),
b = f(y);
return compare(a, b);
};
return JSON.stringify(main());
})();
and a descending sort by length:
Expand disclosure triangle to view DESC by length
(() => {
"use strict";
const main = () => {
// Descending sort by length of string.
console.log(
"Descending length ::",
[
"alpha",
"beta",
"gamma",
"delta",
"epsilon",
"zeta",
"eta",
"theta",
"iota",
"kappa",
"lambda",
"mu",
"nu",
"omicron"
].sort(
flip(comparing(x => x.length))
)
);
};
// --------------------- GENERIC ---------------------
// compare :: (a, a) -> Ordering
const compare = (x, y) =>
x < y ? -1 : (x > y ? 1 : 0);
// comparing :: (a -> b) -> (a -> a -> Ordering)
const comparing = f =>
(x, y) => {
const
a = f(x),
b = f(y);
return compare(a, b);
};
// flip :: (a -> b -> c) -> b -> a -> c
const flip = op =>
// The binary function op with
// its arguments reversed.
1 < op.length ? (
(a, b) => op(b, a)
) : (x => y => op(y)(x));
return JSON.stringify(main());
})();
But compare
, and the JS comparison operators, aren't defined for working directly over lists of simple values, so what might a definition of compareList
(that we can use with versions) look like ?
Here's a possible sketch (assuming that we've split the version string on dots, and mapped its integer strings to integer values):
Ascending sort of versions
(() => {
"use strict";
const main = () => {
// Some [Int] versions lists
const versions = [
[5, 0, 1],
[5, 0, 0],
[7, 2, 7],
[7, 0, 8],
[10, 1, 2],
[7, 2, 6],
[10, 1, 1],
[10, 0, 1],
[7, 2, 8]
];
// Ascending sort of versions.
console.log(
"\nAscending version\n",
JSON.stringify(
versions.sort((a, b) => compareList(a, b))
)
);
};
// --------------------- GENERIC ---------------------
// compareList :: ([a], [a]) -> Ordering
const compareList = (xs, ys) => {
const
nx = xs.length,
ny = ys.length;
return 0 === nx ? (
0 === ny ? 0 : -1
) : 0 === ny ? (
1
) : (() => {
const ord = compare(xs[0], ys[0]);
return 0 === ord ? (
compareList(xs.slice(1), ys.slice(1))
) : ord;
})();
};
// compare :: (a, a) -> Ordering
const compare = (x, y) =>
x < y ? -1 : (x > y ? 1 : 0);
return JSON.stringify(main());
})();
Descending sort of versions
(() => {
"use strict";
const main = () => {
// Some [Int] versions lists
const versions = [
[5, 0, 1],
[5, 0, 0],
[7, 2, 7],
[7, 0, 8],
[10, 1, 2],
[7, 2, 6],
[10, 1, 1],
[10, 0, 1],
[7, 2, 8]
];
// Descending sort of version integers.
console.log(
"\nDescending version\n",
JSON.stringify(
versions.sort(
flip(compareList)
)
)
);
};
// --------------------- GENERIC ---------------------
// compareList :: ([a], [a]) -> Ordering
const compareList = (xs, ys) => {
const
nx = xs.length,
ny = ys.length;
return 0 === nx ? (
0 === ny ? 0 : -1
) : 0 === ny ? (
1
) : (() => {
const ord = compare(xs[0], ys[0]);
return 0 === ord ? (
compareList(xs.slice(1), ys.slice(1))
) : ord;
})();
};
// compare :: (a, a) -> Ordering
const compare = (x, y) =>
x < y ? -1 : (x > y ? 1 : 0);
// flip :: (a -> b -> c) -> b -> a -> c
const flip = op =>
// The binary function op with
// its arguments reversed.
1 < op.length ? (
(a, b) => op(b, a)
) : (x => y => op(y)(x));
return JSON.stringify(main());
})();
I've decided I don't need to know the version after all, but thanks anyway.
For any future reader needing version comparisons, a TLDR might be:
// compareList :: ([a], [a]) -> Ordering
const compareList = (xs, ys) =>
// 0 if two lists are identical.
// -1 if xs is empty, or has a lower leftward value.
// 1 if ys is empty, or has a lower leftward value.
compare(
0 === xs.length,
0 === ys.length
) || compare(xs[0], ys[0]) || (
compareList(xs.slice(1), ys.slice(1))
);
// compare :: (a, a) -> Ordering
const compare = (x, y) =>
x < y ? -1 : (x > y ? 1 : 0);
e.g.
Expand disclosure triangle to view working example
(() => {
"use strict";
const main = () => {
// Some [Int] versions lists
const versions = [
[7, 2, 7],
[5, 0, 1],
[5, 0, 0],
[7, 0, 8],
[10, 1, 2],
[7, 2, 6],
[10, 1, 1],
[10, 0, 1],
[7, 2, 8]
];
// Ascending sort of versions.
console.log(
"\nAscending version\n",
JSON.stringify(
versions.sort(compareList)
)
);
// Descending sort of versions.
console.log(
"\nDescending version\n",
JSON.stringify(
versions.sort(flip(compareList))
)
);
};
// --------------------- GENERIC ---------------------
// compareList :: ([a], [a]) -> Ordering
const compareList = (xs, ys) =>
// 0 if two lists are identical.
// -1 if xs is empty, or has a lower leftward value.
// 1 if ys is empty, or has a lower leftward value.
compare(
0 === xs.length,
0 === ys.length
) || compare(xs[0], ys[0]) || (
compareList(xs.slice(1), ys.slice(1))
);
// compare :: (a, a) -> Ordering
const compare = (x, y) =>
x < y ? -1 : (x > y ? 1 : 0);
// flip :: (a -> b -> c) -> b -> a -> c
const flip = op =>
// The binary function op with
// its arguments reversed.
1 < op.length ? (
(a, b) => op(b, a)
) : (x => y => op(y)(x));
return JSON.stringify(main());
})();
The point being that (once we have integer list copies of the version strings) a definition of compare
for lists gives us all the comparisons we need:
< <= === => >
can all be expressed by the ordering values
-
LT
-1 -
EQ
0 -
GT
1
which compareList
returns from a comparison of two lists.