Skip to content

Category tags

Package: TAGS_PACKAGE. Registered by createEngine(); for a slimmer engine, register it explicitly (see choosing packages).

A running note often groups its numbers by hand: a shopping list, a set of expenses, a few figures that belong together. A #tag written mid-line labels a line as belonging to a category, and the aggregates gather every line carrying that tag, wherever they sit in the document.

The tag itself is dropped from the line it annotates, so a tagged line still calculates to its own number:

40 + 15 #grocery // 55

Four forms read the whole document and collect the lines that carry a tag. Each reads the same set; they differ only in what they do with it.

ExpressionMeaning
total of #grocerythe sum of every line tagged #grocery
sum of #grocerythe same, sum is a synonym for total
average of #grocerythe mean of the tagged lines
count of #groceryhow many lines carry the tag

A worked note. The tagged lines need not be adjacent; lines carrying other tags, untagged lines, and blank lines between them are all ignored:

40 + 15 #grocery
30 #transport
12.50 #grocery
total of #grocery // 67.50

A #tag after one of those four openers names the group; it does not join it. So a tag can answer as many questions as you like, and each answers as though it were the only one:

40 #grocery
12.50 #grocery
total of #grocery // 52.50
average of #grocery // 26.25
count of #grocery // 2

A line can do both at once, because the rule is about each # rather than about the line: the tag being asked about is a question, and any other tag on the line is still a mark.

40 #grocery #reviewed
12.50 #grocery
9 #reviewed
total of #grocery // 52.50
total of #reviewed // 49

The first line is counted in both totals, and neither aggregate line is counted in either.

count answers presence rather than value: it counts every line that carries the tag, and a non-numeric tagged line (a note to yourself) counts too, where total and average would reject it.

40 #grocery
12.50 #grocery
count of #grocery // 2

Money and units carry through. A tag whose lines are all in dollars totals to dollars:

$40 #food
$25 #food
total of #food // $65.00

A few boundaries, each deliberate:

  • A tag that is a line’s first token is a heading, not a data line, so #grocery list at the top of a note is a title rather than a tagged figure.
  • The match is on the whole tag, so a prefix does not collide: #housing does not gather #housingcost. Tag names are matched case-insensitively.
  • The # must sit at a boundary. A # glued to the end of a word or number is not a tag: 100#food and a#food are left whole and the # reads as an ordinary comment; only 100 #food, with a space, tags the line. This keeps the tag the reader sees and the tag the totals count the same one.
  • A tag may be named after an ordinary word, even one the grammar uses elsewhere. #column or #assuming is a category like any other, on a data line and in an aggregate alike:
1200 #assuming
800 #assuming
total of #assuming // 2,000
  • One aggregate line per tag per note. An aggregate line carries the tag it sums, so a second one would try to include the first, and each would wait on the other. The query line always skips itself; a second query is left out of scope rather than guessed at.
  • A clear error, never a silent figure. Mixing units under one tag, or tagging a line that is not a number then asking for its total, is an error rather than a guessed number. No tagged lines at all is an error for total and average, and zero for count.

A tag name must start with a letter, which keeps it clear of the colour literals: #grocery is a tag, #c0ffee is a colour, and #12a (all hex digits) is a colour too, not a tag. A # followed by a space is still an ordinary heading or comment.

Like line references, these forms only work inside a document, since they read other lines. They return an error through the single-expression entry point, which has no document to gather from.