From 7331d24452fd73b2de1d5c5b24651bc96f0e76c7 Mon Sep 17 00:00:00 2001
From: Niklas Fasching
Date: Tue, 18 Dec 2018 14:15:35 +0100
Subject: [PATCH] Add support for list item checkboxes (e.g. [X])
see https://orgmode.org/manual/Checkboxes.html
We're deviating from Org mode regarding the assigned css classes but the chosen
classes feel better than (on, off, trans) and it's not like the export matches
1:1 otherwise.
---
README.org | 8 --------
org/html.go | 19 +++++++++++++++++--
org/list.go | 13 ++++++++++---
org/org.go | 6 ++++++
org/testdata/headlines.html | 8 ++++----
org/testdata/lists.html | 18 +++++++++---------
org/testdata/lists.org | 18 +++++++++---------
7 files changed, 55 insertions(+), 35 deletions(-)
diff --git a/README.org b/README.org
index ddfed79..eac45db 100644
--- a/README.org
+++ b/README.org
@@ -10,15 +10,7 @@ Take a look at [[https://niklasfasching.github.io/go-org/][github pages]] for so
- see [[https://github.com/kaushalmodi/ox-hugo/blob/8472cf2d8667754c9da3728255634e8001a1da6d/ox-hugo.el#L1785-L1850][ox-hugo]] for auto generation
- improve list parsing
- handle list items with empty first line
- - handle checkboxes & statistic cookies
- handle ordered list overrides [@10]
-** TODO list checkboxes & statistics [0/2]
-https://orgmode.org/manual/Checkboxes.html
-1. [ ] parse checkbox of list item
- - convert to html radio button unchecked, indeterminate (visual only), checked
-2. [ ] parse statistic cookies of headlines & first line of list items
- -convert to =[sub 11⁄2] || [90%]=
-
* differences to goorgeous
To get a feeling take a look at goorgeous vs go-org html rendering of the examples [[https://niklasfasching.github.io/go-org/go-org-vs-goorgeous][comparison]].
Please note that a visual comparison is not fair to goorgeous as the stylesheet is not adapted to it.
diff --git a/org/html.go b/org/html.go
index be5a965..176b968 100644
--- a/org/html.go
+++ b/org/html.go
@@ -34,6 +34,12 @@ var listTags = map[string][]string{
"descriptive": []string{"", "
"},
}
+var listItemStatuses = map[string]string{
+ " ": "unchecked",
+ "-": "indeterminate",
+ "X": "checked",
+}
+
func NewHTMLWriter() *HTMLWriter {
return &HTMLWriter{
htmlEscape: true,
@@ -283,13 +289,22 @@ func (w *HTMLWriter) writeList(l List) {
}
func (w *HTMLWriter) writeListItem(li ListItem) {
- w.WriteString("\n")
+ if li.Status != "" {
+ w.WriteString(fmt.Sprintf("\n", listItemStatuses[li.Status]))
+ } else {
+ w.WriteString("\n")
+ }
w.writeNodes(li.Children...)
w.WriteString("\n")
}
func (w *HTMLWriter) writeDescriptiveListItem(di DescriptiveListItem) {
- w.WriteString("\n")
+ if di.Status != "" {
+ w.WriteString(fmt.Sprintf("\n", listItemStatuses[di.Status]))
+ } else {
+ w.WriteString("\n")
+ }
+
if len(di.Term) != 0 {
w.writeNodes(di.Term...)
} else {
diff --git a/org/list.go b/org/list.go
index 3e2ece6..a8272d6 100644
--- a/org/list.go
+++ b/org/list.go
@@ -14,11 +14,13 @@ type List struct {
type ListItem struct {
Bullet string
+ Status string
Children []Node
}
type DescriptiveListItem struct {
Bullet string
+ Status string
Term []Node
Details []Node
}
@@ -26,6 +28,7 @@ type DescriptiveListItem struct {
var unorderedListRegexp = regexp.MustCompile(`^(\s*)([-]|[+]|[*])\s(.*)`)
var orderedListRegexp = regexp.MustCompile(`^(\s*)(([0-9]+|[a-zA-Z])[.)])\s+(.*)`)
var descriptiveListItemRegexp = regexp.MustCompile(`\s::(\s|$)`)
+var listItemStatusRegexp = regexp.MustCompile(`\[( |X|-)\]\s`)
func lexList(line string) (token, bool) {
if m := unorderedListRegexp.FindStringSubmatch(line); m != nil {
@@ -79,12 +82,16 @@ func (d *Document) parseList(i int, parentStop stopFn) (int, Node) {
func (d *Document) parseListItem(l List, i int, parentStop stopFn) (int, Node) {
start, nodes, bullet := i, []Node{}, d.tokens[i].matches[2]
- minIndent, dterm, content := d.tokens[i].lvl+len(bullet), "", d.tokens[i].content
+ minIndent, dterm, content, status := d.tokens[i].lvl+len(bullet), "", d.tokens[i].content, ""
+ if m := listItemStatusRegexp.FindStringSubmatch(content); m != nil {
+ status, content = m[1], content[len("[ ] "):]
+ }
if l.Kind == "descriptive" {
if m := descriptiveListItemRegexp.FindStringIndex(content); m != nil {
dterm, content = content[:m[0]], content[m[1]:]
}
}
+
d.tokens[i] = tokenize(strings.Repeat(" ", minIndent) + content)
stop := func(d *Document, i int) bool {
if parentStop(d, i) {
@@ -99,7 +106,7 @@ func (d *Document) parseListItem(l List, i int, parentStop stopFn) (int, Node) {
nodes = append(nodes, node)
}
if l.Kind == "descriptive" {
- return i - start, DescriptiveListItem{bullet, d.parseInline(dterm), nodes}
+ return i - start, DescriptiveListItem{bullet, status, d.parseInline(dterm), nodes}
}
- return i - start, ListItem{bullet, nodes}
+ return i - start, ListItem{bullet, status, nodes}
}
diff --git a/org/org.go b/org/org.go
index 386ea6e..ee813c9 100644
--- a/org/org.go
+++ b/org/org.go
@@ -203,6 +203,9 @@ func (w *OrgWriter) writeListItem(li ListItem) {
liWriter.writeNodes(li.Children...)
content := strings.TrimPrefix(liWriter.String(), liWriter.indent)
w.WriteString(w.indent + li.Bullet)
+ if li.Status != "" {
+ w.WriteString(fmt.Sprintf(" [%s]", li.Status))
+ }
if len(content) > 0 && content[0] == '\n' {
w.WriteString(content)
} else {
@@ -212,6 +215,9 @@ func (w *OrgWriter) writeListItem(li ListItem) {
func (w *OrgWriter) writeDescriptiveListItem(di DescriptiveListItem) {
w.WriteString(w.indent + di.Bullet)
+ if di.Status != "" {
+ w.WriteString(fmt.Sprintf(" [%s]", di.Status))
+ }
indent := w.indent + strings.Repeat(" ", len(di.Bullet)+1)
if len(di.Term) != 0 {
term := w.nodesAsString(di.Term...)
diff --git a/org/testdata/headlines.html b/org/testdata/headlines.html
index ef0c3b8..389a341 100644
--- a/org/testdata/headlines.html
+++ b/org/testdata/headlines.html
@@ -2,14 +2,14 @@
Simple Headline [1/2]
--
+
-
ordered sublist item 1
--
+
-
ordered sublist item 1
--
+
-
ordered sublist item 2
--
+
-
ordered sublist item 3
@@ -38,7 +38,7 @@ ordered sublist item 2
--
+
-
unordered list item 3 - and a link
and some lines of text
@@ -95,20 +95,20 @@ that spans multiple lines
descriptive lists
--
+
-
term
-
details
continued details
-
-
-
+
-
?
-
details without a term
-
-
-
+
-
term
-
details on a new line
diff --git a/org/testdata/lists.org b/org/testdata/lists.org
index 43d0627..13948d7 100644
--- a/org/testdata/lists.org
+++ b/org/testdata/lists.org
@@ -1,11 +1,11 @@
-- unordered list item 1
+- [ ] unordered list item 1
- unordered list item 2 - with ~inline~ /markup/
- 1. ordered sublist item 1
- a) ordered sublist item 1
- b) ordered sublist item 2
- c) ordered sublist item 3
+ 1. [-] ordered sublist item 1
+ a) [X] ordered sublist item 1
+ b) [ ] ordered sublist item 2
+ c) [X] ordered sublist item 3
2. ordered sublist item 2
-- unordered list item 3 - and a [[https://example.com][link]]
+- [X] unordered list item 3 - and a [[https://example.com][link]]
and some lines of text
1. and another subitem
#+BEGIN_SRC sh
@@ -24,10 +24,10 @@
descriptive lists
-- term :: details
+- [ ] term :: details
continued details
-- details without a term
-- term ::
+- [ ] details without a term
+- [X] term ::
details on a new line
- term ::