Querying grouping & sorting across several text files with the FoldingText Command Line Interface


A first experiment with adding grouping and and sorting to FoldingText nodepath queries across several files with the FoldingText CLI

A plugin and applescript for single document queries,
and a shell script + .js for multi-file queries using Jesse’s CLI tool.

(Offers menus of custom perspectives, based on @key(value) tags, dated or otherwise, and on FT nodepaths)

Sorting items with tags by due date?

This is really amazing. I think the ftdoc:// links in the overdue perspective are really cool–I could see this implemented in a “start date” report as well (e.g., give me all the items starting this week with links back, or starting this week and those started in the past which are not yet @done). Would it be possible to do something with start and due dates? e.g., “forecast” view of OmniFocus: those things started this week, started in the past, due this week, overdue. I’ve not yet had the opportunity to review the “node path syntax” so I’m not quite sure what’s possible yet in terms of searches.

It also solves a dilemma I’ve been working over re: keeping all my projects in one big file (for filtering purposes) or several files. I think several files makes iOS integration easier (I can have several drafts actions for appending to different files) and now this CLI perspective review makes it easier to review all the files at once.


Good ! I’m glad that it seems to make sense : - )

Would it be possible to do something with start and due dates? e.g., “forecast” view of OmniFocus: those things started this week, started in the past, due this week, overdue. I’ve not yet had the opportunity to review the “node path syntax” so I’m not quite sure what’s possible yet in terms of searches.

Certainly – I think we should, in principle, be able to reach anything that OmniFocus gets to and more.

The next thing on my list is to package it all into one Applescript front end with a menu (for multi-file queries as well as single file / open document searches).

In the meanwhile, if you or others want to give me descriptions of the perspectives you would like, I can sketch them and then refine them in response to feedback.


I’m really liking the “allocated time” report–especially the way it adds up the time of each item to create a total in the header. For anyone curious, it takes:

Big project

First sub-project

  • first task @mins(30)
  • second task @mins(20)

second sub-project

  • first @mins(5)
  • second @mins(2)

And returns:

Big Project:: total 57m

  • first task (30m)
  • second task (20m)
  • first (5m)
  • second (2m)


So I was thinking last night that this set of tools could be a neat way to create a Taskpaper weekly forecast based on a folder of FoldingText project files. The Taskpaper file would be more portable to iOS for reminders (e.g., through the Listacular app) or for remembering non-computer based tasks. (Personally, I like to plan weekly on the Mac, but then work through the tasks for the week using iOS for reminders and quick reviews of what’s planned for each day).

Where I got stuck was imagining how tasks marked “done” on the Taskpaper report might be “synced” back to the original FoldingText files. Would this be possible?

Here’s my imagined workflow in more detail:

  • Create one FoldingText file per project–mix of tasks (in .todo sections), paragraphs of text, outlines, etc–located in one specific folder (e.g., Projects).
  • Run a perspective report using this script that would return something like below, formatted in Taskpaper format, with colons for headings and with tasks indented under the heading:
    • Overdue Tasks:
    • Started (and not complete) Previous to this Week:
    • Due Monday:
    • Starting Monday:
    • Due Tuesday:
    • Starting Tuesday:
    • etc. for the rest of the week
  • Sync that Taskpaper file with iOS
  • Check tasks as complete on iOS Taskpaper file
  • On Friday (or whenever), run the “reverse” script, which scans Taskpaper file for tasks tagged “done” and adds that tag to corresponding lines/tasks in each particular FoldingText project file.

I suppose, even if it’s not possible to automate this process, it would be easy enough to follow ft2doc:// links on each line back to the task and use a keyboard shortcut to mark it “done” in FT.


Thanks - I’ll give all that some thought, and sketch out first versions of the queries


I’ve continued to play with this script and am finding it very useful. I’ve run into two more general features that I think would be useful. I regret to say that I am still out of my depth in trying to read/interpret the ViewMenu.json file. I was able to add a report that swapped due dates for start dates, but other than that, I haven’t been able to tinker much and get any results.

At any rate: would it be possible to:

  1. return child lines along with tagged lines? E.g., my files often look like this:

    - task name with tags @tag note for the task (this line should be indented to be a child of above line but forum software not letting me do that)

but in the reports, the note line (the child) doesn’t appear.

  1. display other tags on lines in the reports?

For example, in a report that displays lines by due date, I’d like to also see the other tags that were on the line



- task name @tag1 @tag2 @due(2014-07-22)

would become:

`# Due 7-22-2014

  • task name @tag1 @tag2`

whereas now the additional tags don’t appear.



Hi – things have been a bit busy, have done a bit of maintenance on this, and hope to get back to it on Friday. In the meanwhile:

Q2 (tags)

If $item is mapped to a line, {$item} will just be translated to the ‘text’ part (no syntax prefixes or terminal tags), but
{$item@line} will be translated to the whole raw line, prefixes, tags and all.
If it’s the value of a particular @mytag that you want, you can write:

return: “- {$item} {$item@mytag}”

but it sounds as if I should add something like fn:tags($item) to return the tags of the line without its syntactic prefixes.

Q1 (descendants)

Do you want the full set of descendants of the displayed line, or just its immediate children ?

(If you want to send me the rough JSON of what you want, or the existing template that you want to work from, I should be able to sketch an approach for you )


PS I think that in the version you have, you should be able to write:

return: "- {$item} {$item@tags}"


# Due 7-22-2014
- task name @tag1 @tag2  @due(2014-07-22)

but I’ll need to add an fn:tagsubset of some kind so that we can select which ones to show inline.


I think in practice this would be the same for the way I use it, but for edge cases, I think full descendants would be best.

This is great–you’ve taken my meaning exactly. Thanks for responding to my requests. No worry on the timeline–if you’re busy put if off!

"Started (with ftdoc:// links)": {
		"title": "## Started This WEEK",
		"for": "$item in //@start < {now}",
		"let": "$day = fn:daypart($item@start)",
		"groupby": "$day",
		"orderby": "$day",
		"return": [
			"### {$day}",
				"for": "$i in $item",
				"orderby": "$i@start",
				"return": "- fn:timepart({$i@start}) {$i} {$i@tags} [Link]({$i@url})"

Based on your recent response, this is pretty close to exactly what I’d want (adapted from your “due with ftdoc links” report).

The only other changes that might be nice would be:

  • if “Link” could be replaced with the file name from which the line came (which in my use, is the project name).
  • if tagged lines brought their descendants (Q1 descendants, from above)


Here’s a new query I wrote that returns “@next” tagged items and groups them by their parent item. In other words, if you have lines tagged “@next” in .todo blocks, it returns something like:

## Original project header.todo
   - task name :: [Link](ftdoc://link to original item) @next @read

I use this to search across all my project files for next actions. Would be best if the project header also contained a reference to the filename as well (which, for me, is the name of the overarching project), but I can’t figure out how to get that to display yet.

"Next Actions with Link": {
		"title": "# Next Actions",
		"for": "$item in //@next",
		"let": "$project = $item@parent",
		"orderby": "$project",
		"groupby": "$project",
		"return": [
			"## {$project}.todo",
				"for": "$i in $item",
				"return": "- {$i} :: [Link]({$i@url}) {$i@parent} {$i@tags}"


Looking for a bit of help here. In my “next actions” query above, $i@parent correctly returns the parent line of any line tagged @next. However, why doesn’t $i@child do the same thing? Instead of returning the child line, it returns some gibberish numbers. Here’s the whole query:

"Next Actions with Link": {
		"title": "# Next Actions",
		"for": "$item in //@next",
		"let": "$project = $item@parent", 
		"orderby": "$project",
		"groupby": "$project",
		"return": [
			"## {$project}.todo",
				"for": "$i in $item",
				"return": "- {$i} :: [Link]({$i@url}) {$i@tags} \n {i@child}",


Excellent - I’m hoping to get back to all that on Friday, and I’ll take a look at including filenames then.


Made some improvements to my started query. Now it groups by date, then groups by “project” (the parent header of the returned tasks) and it filters out @done tasks:

"Started (with ftdoc:// links)": {
		"title": "# Starting in the Next 7 Days",
		"for": "$item in //@start <= {today + 7d} except //@done",
		"let": "$day = fn:daypart($item@start)",
		"groupby": "$day",
		"orderby": "$day",
		"return": [
			"## {$day}",
				"for": "$i in $item",
				"let": "$project = $item@parent",
				"groupby": "$project",
				"return": [
					"### {$project}.todo",
						"for": "$j in $i",
						"return": "- {$j} :: [Link]({$j@url}) {$j@tags}",



@parent is a uniquely defined property of a node/line, and you can look at its derivation in the getAttrib() function in the plugin.

@child is not a uniquely defined property of a node (any given node might have various different children), so it’s not one of the properties that getAttrib() can return.

But could you tell me more about what exactly you mean by the the/a child line ? (To Foldingtext its any one of the next generation descendants … but it sounds like you may have something more narrowly defined in mind)


Just trying to bring along the task’s “note”. E.g., I have my .todo sections set up similar to Taskpaper format:

# Header.todo
  - task @next @read
    my note about the task
  - my second task @read

In other words, if a line has a “note” (a descendant? I’m not sure of the nomenclature here), I’d like it to be brought along into the report.


OK, so just the first child line ? or might the note have line breaks, and consist of a set of peer lines ?


yeah, some notes do have line breaks and would consist of peer lines. But in my usage, no “notes” would have children of their own. But, if necessary, I could survive with just the first child line (this covers 90% of my current files and I could easily change practices here to accommodate).


I think we should be able to give you the set of immediate children of type body - off the top of my head, it will probably be by entering one more return loop, and defining that set of children.

(But possibly cleaner to add a @note property to getAttrib(), I’ll take a look – thanks for the work and feedback – it’s very helpful)