Add support for Table of Contents
This commit is contained in:
parent
eb7db9b968
commit
d921a68a55
7 changed files with 218 additions and 41 deletions
|
@ -15,6 +15,7 @@ type Document struct {
|
|||
tokens []token
|
||||
Nodes []Node
|
||||
Footnotes Footnotes
|
||||
Outline Outline
|
||||
StatusKeywords []string
|
||||
MaxEmphasisNewLines int
|
||||
AutoLink bool
|
||||
|
@ -71,6 +72,7 @@ func FrontMatterHandler(fm FrontMatter, k, v string) error {
|
|||
}
|
||||
|
||||
func NewDocument() *Document {
|
||||
outlineSection := &Section{}
|
||||
return &Document{
|
||||
Footnotes: Footnotes{
|
||||
Title: "Footnotes",
|
||||
|
@ -78,6 +80,7 @@ func NewDocument() *Document {
|
|||
},
|
||||
AutoLink: true,
|
||||
MaxEmphasisNewLines: 1,
|
||||
Outline: Outline{outlineSection, outlineSection, 0},
|
||||
BufferSettings: map[string]string{},
|
||||
DefaultSettings: map[string]string{
|
||||
"TODO": "TODO | DONE",
|
||||
|
@ -232,6 +235,12 @@ func (d *Document) addFootnote(name string, definition *FootnoteDefinition) {
|
|||
d.Footnotes.addOrder = append(d.Footnotes.addOrder, name)
|
||||
}
|
||||
|
||||
func (d *Document) addHeadline(headline *Headline) int {
|
||||
d.Outline.last.add(&Section{Headline: headline})
|
||||
d.Outline.count++
|
||||
return d.Outline.count
|
||||
}
|
||||
|
||||
func tokenize(line string) token {
|
||||
for _, lexFn := range lexFns {
|
||||
if token, ok := lexFn(line); ok {
|
||||
|
|
|
@ -1,12 +1,26 @@
|
|||
package org
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type Outline struct {
|
||||
*Section
|
||||
last *Section
|
||||
count int
|
||||
}
|
||||
|
||||
type Section struct {
|
||||
Headline *Headline
|
||||
Parent *Section
|
||||
Children []*Section
|
||||
}
|
||||
|
||||
type Headline struct {
|
||||
Index int
|
||||
Lvl int
|
||||
Status string
|
||||
Priority string
|
||||
|
@ -29,6 +43,9 @@ func lexHeadline(line string) (token, bool) {
|
|||
func (d *Document) parseHeadline(i int, parentStop stopFn) (int, Node) {
|
||||
t, headline := d.tokens[i], Headline{}
|
||||
headline.Lvl = len(t.matches[1])
|
||||
|
||||
headline.Index = d.addHeadline(&headline)
|
||||
|
||||
text := t.content
|
||||
todoKeywords := strings.FieldsFunc(d.Get("TODO"), func(r rune) bool { return unicode.IsSpace(r) || r == '|' })
|
||||
for _, k := range todoKeywords {
|
||||
|
@ -64,3 +81,19 @@ func (d *Document) parseHeadline(i int, parentStop stopFn) (int, Node) {
|
|||
headline.Children = nodes
|
||||
return consumed + 1, headline
|
||||
}
|
||||
|
||||
func (h Headline) ID() string {
|
||||
if customID, ok := h.Properties.Get("CUSTOM_ID"); ok {
|
||||
return customID
|
||||
}
|
||||
return fmt.Sprintf("headline-%d", h.Index)
|
||||
}
|
||||
|
||||
func (parent *Section) add(current *Section) {
|
||||
if parent.Headline == nil || parent.Headline.Lvl < current.Headline.Lvl {
|
||||
parent.Children = append(parent.Children, current)
|
||||
current.Parent = parent
|
||||
} else {
|
||||
parent.Parent.add(current)
|
||||
}
|
||||
}
|
||||
|
|
36
org/html.go
36
org/html.go
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"html"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
|
@ -42,6 +43,8 @@ var listItemStatuses = map[string]string{
|
|||
"X": "checked",
|
||||
}
|
||||
|
||||
var cleanHeadlineTitleForHTMLAnchorRegexp = regexp.MustCompile(`</?a[^>]*>`) // nested a tags are not valid HTML
|
||||
|
||||
func NewHTMLWriter() *HTMLWriter {
|
||||
return &HTMLWriter{
|
||||
htmlEscape: true,
|
||||
|
@ -66,6 +69,7 @@ func (w *HTMLWriter) nodesAsString(nodes ...Node) string {
|
|||
func (w *HTMLWriter) before(d *Document) {
|
||||
w.excludeTags = strings.Fields(d.Get("EXCLUDE_TAGS"))
|
||||
w.log = d.Log
|
||||
w.writeOutline(d)
|
||||
}
|
||||
|
||||
func (w *HTMLWriter) after(d *Document) {
|
||||
|
@ -201,6 +205,31 @@ func (w *HTMLWriter) writeFootnotes(d *Document) {
|
|||
w.WriteString("</div>\n</div>\n")
|
||||
}
|
||||
|
||||
func (w *HTMLWriter) writeOutline(d *Document) {
|
||||
if len(d.Outline.Children) != 0 {
|
||||
w.WriteString("<nav>\n<ul>\n")
|
||||
for _, section := range d.Outline.Children {
|
||||
w.writeSection(section)
|
||||
}
|
||||
w.WriteString("</ul>\n</nav>\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *HTMLWriter) writeSection(section *Section) {
|
||||
w.WriteString("<li>\n")
|
||||
h := section.Headline
|
||||
title := cleanHeadlineTitleForHTMLAnchorRegexp.ReplaceAllString(w.nodesAsString(h.Title...), "")
|
||||
w.WriteString(fmt.Sprintf("<a href=\"#%s\">%s</a>\n", h.ID(), title))
|
||||
if len(section.Children) != 0 {
|
||||
w.WriteString("<ul>\n")
|
||||
for _, section := range section.Children {
|
||||
w.writeSection(section)
|
||||
}
|
||||
w.WriteString("</ul>\n")
|
||||
}
|
||||
w.WriteString("</li>\n")
|
||||
}
|
||||
|
||||
func (w *HTMLWriter) writeHeadline(h Headline) {
|
||||
for _, excludeTag := range w.excludeTags {
|
||||
for _, tag := range h.Tags {
|
||||
|
@ -210,12 +239,7 @@ func (w *HTMLWriter) writeHeadline(h Headline) {
|
|||
}
|
||||
}
|
||||
|
||||
if id, ok := h.Properties.Get("CUSTOM_ID"); ok {
|
||||
w.WriteString(fmt.Sprintf(`<h%d id="%s">`, h.Lvl, id) + "\n")
|
||||
} else {
|
||||
w.WriteString(fmt.Sprintf("<h%d>\n", h.Lvl))
|
||||
}
|
||||
|
||||
w.WriteString(fmt.Sprintf(`<h%d id="%s">`, h.Lvl, h.ID()) + "\n")
|
||||
if h.Status != "" {
|
||||
w.WriteString(fmt.Sprintf(`<span class="todo">%s</span>`, h.Status) + "\n")
|
||||
}
|
||||
|
|
14
org/testdata/footnotes.html
vendored
14
org/testdata/footnotes.html
vendored
|
@ -1,4 +1,14 @@
|
|||
<h1>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#headline-1">Using some footnotes</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-2">Footnotes</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<h1 id="headline-1">
|
||||
Using some footnotes
|
||||
</h1>
|
||||
<ul>
|
||||
|
@ -24,7 +34,7 @@ Rather, they are gathered and exported at the end of the document in the footnot
|
|||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h1>
|
||||
<h1 id="headline-2">
|
||||
Footnotes
|
||||
</h1>
|
||||
<p>
|
||||
|
|
30
org/testdata/headlines.html
vendored
30
org/testdata/headlines.html
vendored
|
@ -1,4 +1,26 @@
|
|||
<h1>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#headline-1">Simple Headline <code class="statistic">[1/2]</code></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-2">Headline with todo status & priority</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#this-will-be-the-id-of-the-headline">Headline with TODO status</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-4">Headline with tags & priority</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-5">headline with custom status</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-6">excluded headline</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<h1 id="headline-1">
|
||||
Simple Headline <code class="statistic">[1/2]</code>
|
||||
</h1>
|
||||
<ul>
|
||||
|
@ -20,7 +42,7 @@ not just where they are actually meant to be - even here > <code class="stati
|
|||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h1>
|
||||
<h1 id="headline-2">
|
||||
<span class="todo">TODO</span>
|
||||
<span class="priority">[B]</span>
|
||||
Headline with todo status & priority
|
||||
|
@ -32,7 +54,7 @@ Headline with TODO status
|
|||
<p>
|
||||
we can link to headlines that define a custom_id: <a href="#this-will-be-the-id-of-the-headline">#this-will-be-the-id-of-the-headline</a>
|
||||
</p>
|
||||
<h1>
|
||||
<h1 id="headline-4">
|
||||
<span class="priority">[A]</span>
|
||||
Headline with tags & priority   <span class="tags"><span>foo</span> <span>bar</span></span>
|
||||
</h1>
|
||||
|
@ -45,7 +67,7 @@ This is inside the drawer
|
|||
<p>
|
||||
Still outside the drawer
|
||||
</p>
|
||||
<h1>
|
||||
<h1 id="headline-5">
|
||||
<span class="todo">CUSTOM</span>
|
||||
headline with custom status
|
||||
</h1>
|
||||
|
|
124
org/testdata/misc.html
vendored
124
org/testdata/misc.html
vendored
|
@ -1,12 +1,88 @@
|
|||
<h2>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#headline-1">issues from goorgeous (free test cases, yay!)</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-2">#19: Support #+HTML</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-3">#29: Support verse block</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-4">#31: Support #+INCLUDE</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-5">#33: Wrong output when mixing html with Org mode</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-6">#46: Support for symbols like ndash and mdash</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-7">#47: Consecutive <code>code</code> wrapped text gets joined</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-8">#50: LineBreaks in lists are preserved</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-9">#68: Quote block with inline markup</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-10">#72: Support for #+ATTR_HTML</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-11">#75: Not parsing nested lists correctly</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-12">#77: Recognize <code class="verbatim">code</code>— as code plus dash</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-13">#78: Emphasis at beginning of line</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-14">#82: Crash on empty headline</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-15"></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-16">#84: Paragraphs that are not followed by an empty line are not parsed correctly</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-17">Foo</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-18">Bar</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-19">#86: Multiple hyphens not converted to dashes</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-20">#87: Markup in footnotes is rendered literally</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-21">issues (wrongly) filed with hugo</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-22">#3874 exporting images in org mode</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-23">#4006 source code blocks in org not rendered correctly</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#headline-24">Footnotes</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<h2 id="headline-1">
|
||||
issues from goorgeous (free test cases, yay!)
|
||||
</h2>
|
||||
<h3>
|
||||
<h3 id="headline-2">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/19">#19</a>: Support #+HTML
|
||||
</h3>
|
||||
<p style="border: 1px dotted grey">neato!</p>
|
||||
<h3>
|
||||
<h3 id="headline-3">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/29">#29:</a> Support verse block
|
||||
</h3>
|
||||
|
@ -23,7 +99,7 @@ or even a <strong>totally</strong> <em>custom</em> kind of block
|
|||
crazy ain't it?
|
||||
</p>
|
||||
</div>
|
||||
<h3>
|
||||
<h3 id="headline-4">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/31">#31</a>: Support #+INCLUDE
|
||||
</h3>
|
||||
|
@ -115,7 +191,7 @@ deploy:
|
|||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
<h3 id="headline-5">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/33">#33</a>: Wrong output when mixing html with Org mode
|
||||
</h3>
|
||||
|
@ -133,7 +209,7 @@ deploy:
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h3>
|
||||
<h3 id="headline-6">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/46">#46</a>: Support for symbols like ndash and mdash
|
||||
</h3>
|
||||
|
@ -164,7 +240,7 @@ note that —— is replaced with 2 mdashes and …. becomes ellipsis+. and so o
|
|||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
<h3 id="headline-7">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/47">#47:</a> Consecutive <code>code</code> wrapped text gets joined
|
||||
</h3>
|
||||
|
@ -173,7 +249,7 @@ either <code>this</code> or <code>that</code> foo.
|
|||
either <code>this</code>
|
||||
or <code>that</code> foo.
|
||||
</p>
|
||||
<h3>
|
||||
<h3 id="headline-8">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/50">#50</a>: LineBreaks in lists are preserved
|
||||
</h3>
|
||||
|
@ -208,7 +284,7 @@ foo
|
|||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
<h3>
|
||||
<h3 id="headline-9">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/68">#68</a>: Quote block with inline markup
|
||||
</h3>
|
||||
|
@ -217,12 +293,12 @@ foo
|
|||
<a href="https://www.example.com"><em>this</em> <strong>is</strong> <span style="text-decoration: underline;">markup</span>!</a>
|
||||
</p>
|
||||
</blockquote>
|
||||
<h3>
|
||||
<h3 id="headline-10">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/72">#72</a>: Support for #+ATTR_HTML
|
||||
</h3>
|
||||
<img src="https://golang.org/doc/gopher/pkg.png" alt="Go is fine though." title="https://golang.org/doc/gopher/pkg.png" id="gopher-image" width="300" style="border:2px solid black;"/>
|
||||
<h3>
|
||||
<h3 id="headline-11">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/75">#75</a>: Not parsing nested lists correctly
|
||||
</h3>
|
||||
|
@ -240,11 +316,11 @@ sub bullet
|
|||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
<h3 id="headline-12">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/77">#77</a>: Recognize <code class="verbatim">code</code>— as code plus dash
|
||||
</h3>
|
||||
<h3>
|
||||
<h3 id="headline-13">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/78">#78</a>: Emphasis at beginning of line
|
||||
</h3>
|
||||
|
@ -255,33 +331,33 @@ sub bullet
|
|||
Text
|
||||
<em>italics</em>
|
||||
</p>
|
||||
<h3>
|
||||
<h3 id="headline-14">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/82">#82</a>: Crash on empty headline
|
||||
</h3>
|
||||
<h4>
|
||||
<h4 id="headline-15">
|
||||
|
||||
</h4>
|
||||
<p>
|
||||
just a space as title…
|
||||
</p>
|
||||
<h3>
|
||||
<h3 id="headline-16">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/84">#84</a>: Paragraphs that are not followed by an empty line are not parsed correctly
|
||||
</h3>
|
||||
<h4>
|
||||
<h4 id="headline-17">
|
||||
Foo
|
||||
</h4>
|
||||
<p>
|
||||
Foo paragraph.
|
||||
</p>
|
||||
<h4>
|
||||
<h4 id="headline-18">
|
||||
Bar
|
||||
</h4>
|
||||
<p>
|
||||
Bar paragraph
|
||||
</p>
|
||||
<h3>
|
||||
<h3 id="headline-19">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/86">#86</a>: Multiple hyphens not converted to dashes
|
||||
</h3>
|
||||
|
@ -327,17 +403,17 @@ src/example/export blocks should not be converted!
|
|||
</pre>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>
|
||||
<h3 id="headline-20">
|
||||
<span class="todo">DONE</span>
|
||||
<a href="https://github.com/chaseadamsio/goorgeous/issues/87">#87</a>: Markup in footnotes is rendered literally
|
||||
</h3>
|
||||
<p>
|
||||
footnotes can contain <strong>markup</strong> - and other elements and stuff <sup class="footnote-reference"><a id="footnote-reference-2" href="#footnote-2">2</a></sup>
|
||||
</p>
|
||||
<h2>
|
||||
<h2 id="headline-21">
|
||||
issues (wrongly) filed with hugo
|
||||
</h2>
|
||||
<h3>
|
||||
<h3 id="headline-22">
|
||||
<a href="https://github.com/gohugoio/hugo/issues/3874">#3874</a> exporting images in org mode
|
||||
</h3>
|
||||
<p>
|
||||
|
@ -346,7 +422,7 @@ Hello, I'm writing hugo blogs using org-mode.
|
|||
<p>
|
||||
When inserting an image link like <img src="/home/amos/Pictures/Screenshots/img-2017-09-11-165647.png" alt="/home/amos/Pictures/Screenshots/img-2017-09-11-165647.png" title="/home/amos/Pictures/Screenshots/img-2017-09-11-165647.png" />, hugo doesn't export the image.
|
||||
</p>
|
||||
<h3>
|
||||
<h3 id="headline-23">
|
||||
<a href="https://github.com/gohugoio/hugo/issues/4006">#4006</a> source code blocks in org not rendered correctly
|
||||
</h3>
|
||||
<div class="highlight">
|
||||
|
@ -359,7 +435,7 @@ When inserting an image link like <img src="/home/amos/Pictures/Screenshots/img-
|
|||
(ansi-term))
|
||||
</pre>
|
||||
</div>
|
||||
<h1>
|
||||
<h1 id="headline-24">
|
||||
Footnotes
|
||||
</h1>
|
||||
<div class="footnotes">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue