Adds or clears simple row numbering in a series of selected rows.
Notes:
1. Descendants of the selected rows are ignored.
(for example this line would be unchanged)
2. Blank lines are ignored.
A Keyboard Maestro version:
BIKE Outliner – Toggle numbering of selected rows - Macro Library - Keyboard Maestro Discourse
And the script itself for testing in Script Editor.app
(with language selector at top left set to JavaScript)
or for using in other launchers like FastScripts and Alfred.
Expand disclosure triangle to view JS source
(() => {
"use strict";
// Toggle numbering of selected rows.
// Adds or clears simple numbering for a
// sequence of selected peers.
// Notes:
// 1. Descendants of the selected rows are ignored.
// (for example this line would be unchanged)
// 2. Blank lines are ignored.
// Rob Trew @2022
//
// Ver 0.03
// -------- TOGGLE NUMBERING OF SELECTED ROWS --------
// main :: IO ()
const main = () => {
const
doc = Application("Bike").documents.at(0);
return doc.exists() ? (() => {
const
inSelection = selected(),
rows = doc.rows.where(inSelection),
minIndent = Math.min(...rows.level()),
topPeers = rows.where({
_and: [
minimumLevel(minIndent),
...inSelection._and
]
});
return numbersCleared(topPeers) ? (
"Numbering cleared."
) : numberedPeers(topPeers);
})() : "No documents open in Bike.";
};
// numbersCleared :: Bike Rows -> IO Bool
const numbersCleared = peerRows => {
const rgxNumbering = /^\s*\d+\. /u;
return 0 < peerRows().flatMap(x => {
const s = x.name();
return rgxNumbering.test(s) ? [(
x.name = s.replace(
rgxNumbering, ""
),
1
)] : [];
}).length;
};
// numberedPeers :: Bike Rows -> IO String
const numberedPeers = peerRows => {
const nDigits = (`${peerRows.length}`).length;
return (
zipWith(
row => k => row.name = k
)(peerRows())(
peerRows.name().map((s, i) => {
const
prefix = `${1 + i}`
.padStart(nDigits, " ");
return `${prefix}. ${s}`;
})
),
`Numbered up to ${peerRows.length}.`
);
};
// selected :: () -> JXA Condition
const selected = () => ({
_and: [
{selected: true},
{_not: [{
name: ""
}]}
]
});
// minimumLevel :: n -> JXA Condition
const minimumLevel = n => ({
level: {
_lessThanEquals: n
}
});
// --------------------- GENERIC ---------------------
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = f =>
// A list constructed by zipping with a
// custom function, rather than with the
// default tuple constructor.
xs => ys => xs.map(
(x, i) => f(x)(ys[i])
).slice(
0, Math.min(xs.length, ys.length)
);
// MAIN ---
return main();
})();
See: Using Scripts - Bike