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