Heading based tasks

Hi,
Thanks for creating this tool. There is alot of potential here and I’m enjoying learning how it works.
TLDR: I’d like to extend tasks plug to recognize headings as tasks.

One of the previous PKM tools I’ve used is org-mode in emacs. With org-mode, you define tasks using headings, which allows you to summarize task in headings and then add further details in text under headings. This was really helpful for adding logs/details as I worked on task.
Since moving markdown tools like silverbullet and obsidian, I’ve missed the ability to add ton of details to a task. Using lists as tasks is great for simple tasks, but it breaks down quick when you want to add more into to tasks.
I’m considering writing a plug to recognize headings as tasks. For this, I think I’ll need to figure out a way to configure tasks at heading level. Some thoughts I’ve had:

  • set properties at heading level
  • use a custom code block to assign “metadata/frontmatter” to headings

What do folks think of this idea? Or do any of you have suggestions/advice as to how to go about implementing this?

1 Like

It’s not the same as a task, but I make specific headings traceable by adding attributes to them: Attributes

You can then query them like tasks :slight_smile:

Or you can add the #task/[tag: task] tag and it will show up in the same query with the list tasks. You can mark them completed by adding [done: true]. It’s a bit uglier, but same effect.

Example query to get the tasks:

${query[[from index.tag "task" where level and not done]]}

Headings have a level attribute that can be used to find them. So we can filter the tasks based on whether they have this attribute or not.

There’s probably also a way to set the done attribute with a command.

1 Like

I’ve been playing around a bit with space-lua and you could do something like this:

Define a task with a heading (one or more pound symbols)

# My very detailed task #task

With some accompanying text.

Add this command in a space-lua block:

command.define {
  name = "Big Task: Mark Completed",
  run = function()
    local pos = editor.getCursor()
    local pageText = editor.getText():sub(1, pos)
    local lineStart, lineEnd = 0, 0
    while lineStart < 1 and pos > 0 do
      lineStart, lineEnd = pageText:find("#+ ", pos)
      pos = pos - 1
    end
    
    editor.insertAtPos("✅ ", lineEnd - 1)
  end
}

And use this query:

${query[[from index.tag "task" where level and not name:startsWith("✅")]]}

Running the command will mark the task closest to the cursor (looking backwards) as completed by prepending the ‘title’ with a checkmark :white_check_mark: The query then filters these tasks out to only show open tasks.

2 Likes

Wow, thank you for your suggestions. My next task, figure out how to you this for my workflow.
I’m glad to learn that this is already somewhat part of api.

1 Like

Nice. But I’d rather see per-object checkboxes, like in some Markdown variants. You just place [ ] or [x] in a paragraph, in a header etc. and the object becomes “task”. Issue is with interpretation of what would one task marker in the middle if a paragraph and second at the end mean.

I’d say that semantic could be that the task marker preceding/following the whole object content (e.g., content of a paragraph, of a header right after sequence of #s or following it’s content, preceding or following a paragraph without empty lines etc.) and if it was placed inside the object content, than it will split it into serialized parts and it will belong to the part following (or preceding) it (this should be further discussed what feels more natural to the majority of people, both variants are OK, it’s just a matter of informed choice; but see below in the examples). The nicest think about it is that it is fully backwards compatible with thencurrent list items tasks! Last, task marker standing alone on separated line will belong to section (whatever it is, e.g. third-level of the document based on headings etc.). I will like to see the same principle applied for tags and for the attributes.

Examples:

Paragraph

[x] A paragraph of text turned into a task paragraph.

Another paragraph of text turned into a task paragraph. [x]

[x]
A paragraph
of text, the same principle (due to how Markdown is parsed).

The very same
paragraph task. [x]

Splitted paragraph (by preceding; see above in the description)

[x] The first task in a paragraph. [x] The second one. [x] The third one.

I would prefare the second variant (by following; see above in the description)

The first task in a paragraph. [x] The second one. [x] The third one. [x]

This second variant have some advantages over the variant “by preceding”:

  1. It feels more natural and leave space for syntactic denoting of inline lists like: We (1) do something [x], then (2) we do something else [ ].

    Look how this, in fact, renders here in the forum:

    We (1) do something , then (2) we do something else .

  2. Easier to parse. There is no need to parse whole paragraph to get the idea whether it is already splitted into task parts or not, also avoiding some uglier: [x] [x] text text [x] text where the first [x] is for the whole paragraph followed by the [x] for the first part. It’s non-intuitive and ugly. On the other hand, the [x] text text [x] text [x] is far more clear, I think and it indeed does not break the backward compatibility with the list item tasks.

Headers

# [x] Header turned into a task

##### Header turned into a task [x]

## [x] Header splitted into [x] three tasks [x] beying a task as whole [x]

Lists

- [ ] nothing changed
- [ ] except they can be also [x] split as anything else [ ]

So, the only interpretation decision for the parser concerning the trailing task marker that is left is simply to count splits - be there no split, then the whole content of the object is a task, be there a split it belongs to the last part. Easy.

Quotes

[x]
> The whole quote is a task.
>
> - [ ] with
> - [x] some
> - [ ] sub-tasks.

We can clearly continue to imagine that every block object consisting of text can be either turned into task or even split into several of them or both. And the very same principles should hold also for assigning the [attr: ibutes] and the #hashtags.

Sidenote: To clear my point of view about all this. I think about the tasks, attributes and hashtags etc. rather as about “taskiness”, “attributiness” and “tagginess” assigned to some portions of content (they are all, in fact, just data and are becoming metadata that is forming the metacontents only tohether with the content they are assigned to).

What do you think? Also pinging @zef to know his opinion.

1 Like