Hi,
why is there no autocompletion for (existing) tag values when typing the tag and an opening bracket?
CME
Hi,
why is there no autocompletion for (existing) tag values when typing the tag and an opening bracket?
CME
I’m not sure what you mean… there is autocomplete for tags generally. Is that working for you? If that’s not working then make sure that you have “Editor: Auto-complete tags as you type” selected in preference.
If you are talking about something different can you give an example of exactly what you mean. Thanks!
My file contained tags for places.
Let’s say
@Berlin
@Dublin
@London
When I type @Du
it proposes @Dublin
I renamed the tags to
@place(Berlin)
@place(Dublin)
@place(London)
When typing @p
it proposes @place
. When typing @place(
it does not recommend anything (Berlin, Dublin, …)
Thanks!
Sorry for the delay here, been thinking about this, but I don’t see an easy solution that doesn’t also have drawbacks. In your case it seems good, but in cases where there are many potential values (such as @done(data)
) or where multiple tags are used @tag(1, 2, 3)
I see a lot of edge cases that might cause irritation.
Is there an existing app that you think does this well?
Obsidian can autocomplete nested tags, though the underlying mechanism for nested tags might be deeply different from tags with values (though functionally they seem interchangeable).
Brand new to Taskpaper and was looking for exactly the same thing
Perhaps the simplest way to start this is based off the global tags list? So if I have @status(next)
in the global tags list only then it’ll autocomplete. This way you won’t run into the @done(date)
problem
@taskSloth 's script will cycle through @CME 's places as an excellent alternative to autocompletion:
function TaskPaperContextScript(editor, options) {
let outline = editor.outline
let selection = editor.selection
outline.groupUndoAndChanges(() => {
editor.selection.selectedItems.forEach((item) => {
if (item.getAttribute("data-place") === "Berlin"){
item.setAttribute("data-place", "Dublin")
} else if (item.getAttribute("data-place") === "Dublin"){
item.setAttribute("data-place", "London")
} else if (item.getAttribute("data-place") === "London"){
item.setAttribute("data-place", "Paris")
} else {
item.setAttribute("data-place", "Berlin")
}});
})
editor.moveSelectionToItems(selection)
}
Application("TaskPaper").documents[0].evaluate({
script: TaskPaperContextScript.toString()
});
To generalize tag-value cycling a bit, we could specify:
in the withOptions
key-value dictionary passed to document.evaluate
in this kind of pattern:
e.g. for @place or @grade or @sprint
docs.at(0).evaluate({
script: `${TaskPaperContext}`,
withOptions: {
"place": [
"Berlin", "Dublin",
"London", "Paris"
],
"grade": "ABCD",
"sprint": [10, 25, 55]
}
})
Generalized tag-value cycling:
/* eslint-disable max-lines-per-function */
(() => {
"use strict";
// Cycle tag value of:
// - First tag in selection(s) which matches a key in
// options,
// - to the next value in the list given in options
// for that key.
// Rob Trew @2021
// Ver 0.05
// (Where a line has more than one of the tags with
// cycle lists given in options, the *leftmost* of
// these tags in the selected line will be cycled)
// ------------------- JXA CONTEXT -------------------
// main :: IO ()
const main = () => {
const docs = Application("TaskPaper").documents;
return 0 < docs.length ? (
docs.at(0).evaluate({
script: `${TaskPaperContext}`,
withOptions: {
"place": [
"Berlin", "Dublin",
"London", "Paris"
],
"grade": "ABCD",
"sprint": [10, 25, 55]
}
})
) : "No documents open in TaskPaper.";
};
// ---------------- TASKPAPER CONTEXT ----------------
const TaskPaperContext = (editor, options) => {
const tp3Main = () => {
const
selection = editor.selection,
items = selection.selectedItems,
startLocn = selection.location,
endItem = selection.endItem,
endOffset = selection.endOffset,
cyclableNames = Object.keys(options || {})
.map(k => `data-${k}`);
let report = "";
return 0 < items.length ? (
0 < cyclableNames.length ? (
editor.outline.groupUndoAndChanges(() => {
report = items.filter(
x => Boolean(
x.bodyString.trim()
)
)
.map(valueCycled(cyclableNames))
.join("\n");
}),
editor.moveSelectionToRange(
startLocn,
editor.getLocationForItemOffset(
endItem, endOffset
)
),
report
) : "No name list pairs supplied in options."
) : "No TaskPaper items selected";
};
// ---------------- VALUE CYCLING ----------------
// valueCycled :: [String] -> Item -> IO String
const valueCycled = cyclableNames =>
item => {
const
overlap = intersect(
item.attributeNames
)(
cyclableNames
),
tagName = 0 < overlap.length ? (
overlap[0]
) : cyclableNames[0],
shortName = tagName.slice(5),
newValue = nextValue(
// Values as [String] array.
Array.from(options[shortName])
.map(x => `${x}`)
)(
item.getAttribute(tagName)
);
return (
item.setAttribute(tagName, newValue),
`@${shortName} -> ${newValue}`
);
};
// nextValue :: [String] -> String -> String
const nextValue = ks =>
k => {
const iPosn = ks.findIndex(x => k === x);
return -1 !== iPosn ? (
ks[(1 + iPosn) % ks.length]
) : ks[0];
};
// ------------------- GENERIC -------------------
// intersect :: (Eq a) => [a] -> [a] -> [a]
const intersect = xs =>
// The intersection of lists xs and ys.
ys => xs.filter(x => ys.includes(x));
return tp3Main();
};
// JXA main
return main();
})();
Slightly updated above FWIW ( to 0.3, behind disclosure triangle ) for more delicate preservation of selection start and and end when length of lines is changed by value cycling.
Awesome. Added to wiki!
I’m using the tag-value cycling script for my task statuses, but would still love to have autocomplete for @person(firstSurname)
tags that I add to tasks. Would it be possible to add this autocompletion for tags predefined in the tag list? I’d then just predefine the list of @people
tags.
FYI same usecase here: Nesting tags
If autocomplete is a huge desire, I’d recommend using a text expansion utility. They are faster than autocomplete, and they offer a number of other useful features.
I use Keyboard Maestro and find it to be worth every penny (I use it for much more than text expansion). TextExpander and aText are worth trying as well.
Here is an example of a simple text expansion, using Keyboard Maestro. My triggers, in this instance, is a number, typed three times in a row (the trigger could be anything). The first macro took me less than a minute to set up, and the other three were copied and adjusted in seconds.
I have over a hundred text expansions set up, and I couldn’t be happier with them. They save a lot of time, and I don’t have to rely on the implementation of autocomplete. Mine work in any text field of any app.
Hey @Jim - thanks for the great suggestion. I too own and use KM, but didn’t actually consider using it for this use case! I’ll look at putting something together over the weekend and share it for others to use . I guess sometimes the answer is staring you in the face all along
cool here is what I put together for others to use.
Notes:
@person
but can be changed in the 2nd to last stepAutocomplete tag people.zip (1.6 KB)