In the meanwhile, you could choose a tag from a list, and see the set of values attached to it in the active document, by using a script run from Script Editor or Keyboard Maestro etc
https://guide.taskpaper.com/using-taskpaper/using-scripts.html
To test the rough sketch below:
- Make sure that you have copied all of the source text, right down to to the bottom of the scrolling code panel,
- paste the copied code into Script Editor.
- Choose JavaScript at top left of the Script Editor toolbar, and click Run
(() => {
'use strict';
// TASKPAPER 3 CONTEXT --------------------------------
// allTags :: TP Editor -> Dict -> [String]
const allTags = editor => {
const main = () =>
nub(concatMap(
x => x.attributeNames.filter(
x => 'data-type' !== x && 'indent' !== x
),
editor.outline.items
)).map(x => x.slice(5));
// REUSABLE GENERIC FUNCTIONS ---------------------
// Just :: a -> Just a
const Just = x => ({
type: 'Maybe',
Nothing: false,
Just: x
});
// Nothing :: () -> Nothing
const Nothing = () => ({
type: 'Maybe',
Nothing: true,
});
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = (f, xs) => [].concat.apply([], xs.map(f));
// nub :: [a] -> [a]
const nub = xs => nubBy((a, b) => a === b, xs);
// nubBy :: (a -> a -> Bool) -> [a] -> [a]
const nubBy = (p, xs) => {
const go = xs => xs.length > 0 ? (() => {
const x = xs[0];
return [x].concat(
go(xs.slice(1)
.filter(y => !p(x, y))
)
)
})() : [];
return go(xs);
};
return main();
};
// tagValues :: TP Editor -> Dict ->
// { tagName :: String, values :: [String] }
const tagValues = (editor, options) => {
const main = () => {
const strTag = options.tag;
return nub(
editor.outline
.evaluateItemPath('//@' + strTag)
.map(x => x.getAttribute('data-' + strTag))
).sort();
};
// REUSABLE GENERIC FUNCTIONS ---------------------
// Just :: a -> Just a
const Just = x => ({
type: 'Maybe',
Nothing: false,
Just: x
});
// Nothing :: () -> Nothing
const Nothing = () => ({
type: 'Maybe',
Nothing: true,
});
// nub :: [a] -> [a]
const nub = xs => nubBy((a, b) => a === b, xs);
// nubBy :: (a -> a -> Bool) -> [a] -> [a]
const nubBy = (p, xs) => {
const go = xs => xs.length > 0 ? (() => {
const x = xs[0];
return [x].concat(
go(xs.slice(1)
.filter(y => !p(x, y))
)
)
})() : [];
return go(xs);
};
return main();
};
// JXA CONTEXT------------------------------------------------------------
// Left :: a -> Either a b
const Left = x => ({
type: 'Either',
Left: x
});
// Right :: b -> Either a b
const Right = x => ({
type: 'Either',
Right: x
});
// bindLR (>>=) :: Either a -> (a -> Either b) -> Either b
const bindLR = (m, mf) =>
m.Right !== undefined ? (
mf(m.Right)
) : m;
// unlines :: [String] -> String
const unlines = xs => xs.join('\n');
// standardSEAdditions :: () -> Application
const standardSEAdditions = () =>
Object.assign(Application('System Events'), {
includeStandardAdditions: true
});
// MAIN -----------------------------------------------
const
sa = standardSEAdditions(),
tp3 = Application('TaskPaper'),
ds = tp3.documents,
lrValues = bindLR(
ds.length > 0 ? (
Right(ds.at(0))
) : Left('No documents open'),
d => {
const
tags = d.evaluate({
script: allTags.toString(),
});
return bindLR(
tags.length > 0 ? (
Right(tags)
) : Left('No tags found'),
ts => {
const choice = (
sa.activate(),
sa.chooseFromList(
ts, {
withTitle: 'Tags used',
withPrompt: 'Choose tag:',
defaultItems: ts[0],
multipleSelectionsAllowed: false
}
)
);
return Boolean(choice) ? (
Right({
tagName: choice[0],
values: d.evaluate({
script: tagValues.toString(),
withOptions: {
tag: choice[0]
}
})
})
) : Left('User cancelled');
}
)
}
);
// RESULT ---------------------------------------------
return lrValues.Left || (() => {
const strList = unlines(lrValues.Right.values);
return (
sa.activate(),
sa.displayDialog(
strList, {
withTitle: 'Values for @' + lrValues.Right.tagName
}
),
strList
);
})();
})();