How many layers of indentation does this TaskPaper outline have ?
And how many leaves (lines without further ‘children’ indented below them) ?
We could find out by writing something like this:
(function () {
'use strict';
// TASKPAPER CONTEXT
function TaskPaperContext(editor, options) {
// The sum of the leafCounts of all the item's children
// (or just 1, if it has no children)
// leafCount :: tp3Item -> Int
function leafCount(item) {
return item.hasChildren ? item.children
.reduce(function (value, child) {
return value + leafCount(child);
}, 0) : 1;
}
// One more than the layerCount of the deepest of all its children
// layerCount :: tp3Item -> Int
function layerCount(item) {
return item.hasChildren ? item.children.map(layerCount)
.reduce(function (value, n) {
return value < n ? n : value;
}, 0) + 1 : 0;
}
var root = editor.outline.root;
return {
leaves: leafCount(root),
layers: layerCount(root)
}
}
// JAVASCRIPT FOR AUTOMATION
var ds = Application("TaskPaper")
.documents;
return ds.length ? ds[0].evaluate({
script: TaskPaperContext.toString(),
}) : undefined;
})()
TaskPaper provides the item.hasChilden test here, and the item.children list, while JavaScript provides Array.reduce(function, initialValue) and Array.map(function) – two very generally useful alternatives to looping through a list of values.
Simple examples of .reduce (sometimes called fold or foldl in other languages) might be:
(function () {
'use strict';
// sum :: [a] -> Num
function sum(xs) {
var startValue = 0;
return xs
.reduce(function (value, x) {
return value + x;
}, startValue);
}
// product :: [a] -> Num
function product(xs) {
var startValue = 1;
return xs
.reduce(function (value, x) {
return value * x;
}, startValue);
}
var lst = [1, 2, 3, 4, 5, 6, 7, 8, 9];
return {
sum: sum(lst),
product: product(lst)
}
})();
See: Array.prototype.reduce() - JavaScript | MDN
and:
Array.prototype.map() - JavaScript | MDN
If you are more accustomed to AppleScript, you can see examples of how AppleScript can be coaxed into doing something similar at: