KristopherGBaker/Maaku

Add support for gfm task lists

KristopherGBaker opened this issue · 3 comments

Task lists are now supported in libcmark-gfm, add the support to Maaku.

https://github.github.com/gfm/#task-list-items-extension-

I've got a chunk of this done. I've got a question as to what might be a better approach.

One approach is to have Lists contain ListItems as now, and include a TaskList item as the first item in the ListItem's block that captures the info of whether the task is completed. This would lead to a tree kind of like:

List
   ListItem
      TaskList
      Paragraph
   ListItem
     TaskList
     Paragraph

With this style, the only thing a LIst will contain directly are ListItem objects. A Tasklist only captures the state of whether the task was complete or not. The text of the task is captured as other parts of the ListItem. This is somewhat analogous to how the HTML is generated: the task adds an input (<input type="checkbox" checked="" disabled="" /> for example) between the <li> and the text of the list item.

Another approach is to have the TaskList item itself contain the text of the task. This would lead to a tree like:

List
   ListItem
      TaskList
        Paragraph
   ListItem
     TaskList
       Paragraph

I like this approach, because TaskList.attributedString could make the task text look different depending on whether the task was completed (e.g. use strikethrough so it's obvious that the task is completed). [If you like the first approach (TaskList is just one item among many under the LIstItem), there could be a function on TaskList that takes an array of items and creates an appropriate attributed string on them based on the completion status, allowing the user a way to get the task completion status to affect the attributes of the text of the task].

A different approach is to have TaskItem be roughly equivalent with ListItem -- so a List would be composed of any combination of ListItem or TaskItem pieces. This is somewhat equivalent to what the rendered XML is. However, that means when processing a List, you have potentially two different types of objects in it. The approaches above have the benefit of Lists only having one type of object in them.

I can give you CMark with tasklist extensions right now, and could give you whichever of the three approaches above pretty quickly (I first tried the first then switched to the second when playing around).

For comparison, the following CommonMark:

- [ ] task 1
- [x] completed ~~task~~
- [X] another completed task
- not a task

generates this HTML (note list only contains <li> items):

<ul>
<li><input type="checkbox" disabled="" /> task 1</li>
<li><input type="checkbox" checked="" disabled="" /> completed ~~task~~</li>
<li><input type="checkbox" checked="" disabled="" /> another completed task</li>
<li>not a task</li>
</ul>

and this XML (note list contains both <tasklist> and <item>):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE document SYSTEM "CommonMark.dtd">
<document xmlns="http://commonmark.org/xml/1.0">
  <list type="bullet" tight="true">
    <tasklist completed="false">
      <paragraph>
        <text xml:space="preserve">task 1</text>
      </paragraph>
    </tasklist>
    <tasklist completed="true">
      <paragraph>
        <text xml:space="preserve">completed ~~task~~</text>
      </paragraph>
    </tasklist>
    <tasklist completed="true">
      <paragraph>
        <text xml:space="preserve">another completed task</text>
      </paragraph>
    </tasklist>
    <item>
      <paragraph>
        <text xml:space="preserve">not a task</text>
      </paragraph>
    </item>
  </list>
</document>

This XML was generated with changes I made to the tasklist extension and have issued a pull request for to the cmark-gfm repository and includes the completion state of the task in the element. The standard library just has the tasklist tag, but no info about completion state

I prefer the second or third approach. For the third approach, do you think it would work if ListItem and TaskItem shared a common Item protocol, and then when processing a list you would only generally care about using the protocol? You're more familiar with task lists, so I'll trust your judgement on which approach to take. Thanks for all of your work on this.

I like your idea of doing the third approach, but with an Item protocol that both ListItem and TaskItem support. Let me play with this for a day or so to see how it all works out. I do think that making the XML version be a kind of "standard" might make future design decisions easier.