Add basic support for statistic tokens (e.g. [100%] [1/1])

Org mode does not care where those tokens are when it comes to the
export (afaict). We'll do the same.

(They should only be in the first line of a list item or a headline)
This commit is contained in:
Niklas Fasching 2018-12-18 14:14:08 +01:00
parent dce67eaddf
commit a60f844e38
6 changed files with 59 additions and 6 deletions

View file

@ -103,6 +103,8 @@ func (w *HTMLWriter) writeNodes(ns ...Node) {
w.writeText(n) w.writeText(n)
case Emphasis: case Emphasis:
w.writeEmphasis(n) w.writeEmphasis(n)
case StatisticToken:
w.writeStatisticToken(n)
case ExplicitLineBreak: case ExplicitLineBreak:
w.writeExplicitLineBreak(n) w.writeExplicitLineBreak(n)
case LineBreak: case LineBreak:
@ -234,6 +236,10 @@ func (w *HTMLWriter) writeEmphasis(e Emphasis) {
w.WriteString(tags[1]) w.WriteString(tags[1])
} }
func (w *HTMLWriter) writeStatisticToken(s StatisticToken) {
w.WriteString(fmt.Sprintf(`<code class="statistic">[%s]</code>`, s.Content))
}
func (w *HTMLWriter) writeLineBreak(l LineBreak) { func (w *HTMLWriter) writeLineBreak(l LineBreak) {
w.WriteString(strings.Repeat("\n", l.Count)) w.WriteString(strings.Repeat("\n", l.Count))
} }

View file

@ -15,6 +15,8 @@ type Text struct {
type LineBreak struct{ Count int } type LineBreak struct{ Count int }
type ExplicitLineBreak struct{} type ExplicitLineBreak struct{}
type StatisticToken struct{ Content string }
type Emphasis struct { type Emphasis struct {
Kind string Kind string
Content []Node Content []Node
@ -39,6 +41,7 @@ var videoExtensionRegexp = regexp.MustCompile(`^[.](webm|mp4)$`)
var subScriptSuperScriptRegexp = regexp.MustCompile(`([_^])\{(.*?)\}`) var subScriptSuperScriptRegexp = regexp.MustCompile(`([_^])\{(.*?)\}`)
var footnoteRegexp = regexp.MustCompile(`\[fn:([\w-]+?)(:(.*?))?\]`) var footnoteRegexp = regexp.MustCompile(`\[fn:([\w-]+?)(:(.*?))?\]`)
var statisticsTokenRegexp = regexp.MustCompile(`\[(\d+/\d+|\d+%)\]`)
func (d *Document) parseInline(input string) (nodes []Node) { func (d *Document) parseInline(input string) (nodes []Node) {
previous, current := 0, 0 previous, current := 0, 0
@ -54,7 +57,7 @@ func (d *Document) parseInline(input string) (nodes []Node) {
case '=', '~': case '=', '~':
consumed, node = d.parseEmphasis(input, current, true) consumed, node = d.parseEmphasis(input, current, true)
case '[': case '[':
consumed, node = d.parseRegularLinkOrFootnoteReference(input, current) consumed, node = d.parseOpeningBracket(input, current)
case '\\': case '\\':
consumed, node = d.parseExplicitLineBreak(input, current) consumed, node = d.parseExplicitLineBreak(input, current)
case '\n': case '\n':
@ -140,11 +143,13 @@ func (d *Document) parseSubScriptOrEmphasis(input string, start int) (int, Node)
return d.parseEmphasis(input, start, false) return d.parseEmphasis(input, start, false)
} }
func (d *Document) parseRegularLinkOrFootnoteReference(input string, start int) (int, Node) { func (d *Document) parseOpeningBracket(input string, start int) (int, Node) {
if len(input[start:]) >= 2 && input[start] == '[' && input[start+1] == '[' { if len(input[start:]) >= 2 && input[start] == '[' && input[start+1] == '[' {
return d.parseRegularLink(input, start) return d.parseRegularLink(input, start)
} else if len(input[start:]) >= 1 && input[start] == '[' { } else if footnoteRegexp.MatchString(input[start:]) {
return d.parseFootnoteReference(input, start) return d.parseFootnoteReference(input, start)
} else if statisticsTokenRegexp.MatchString(input[start:]) {
return d.parseStatisticToken(input, start)
} }
return 0, nil return 0, nil
} }
@ -162,6 +167,13 @@ func (d *Document) parseFootnoteReference(input string, start int) (int, Node) {
return 0, nil return 0, nil
} }
func (d *Document) parseStatisticToken(input string, start int) (int, Node) {
if m := statisticsTokenRegexp.FindStringSubmatch(input[start:]); m != nil {
return len(m[1]) + 2, StatisticToken{m[1]}
}
return 0, nil
}
func (d *Document) parseAutoLink(input string, start int) (int, int, Node) { func (d *Document) parseAutoLink(input string, start int) (int, int, Node) {
if !d.AutoLink || len(input[start:]) < 3 || input[start+1] != '/' || input[start+2] != '/' { if !d.AutoLink || len(input[start:]) < 3 || input[start+1] != '/' || input[start+2] != '/' {
return 0, 0, nil return 0, 0, nil

View file

@ -86,6 +86,8 @@ func (w *OrgWriter) writeNodes(ns ...Node) {
w.writeText(n) w.writeText(n)
case Emphasis: case Emphasis:
w.writeEmphasis(n) w.writeEmphasis(n)
case StatisticToken:
w.writeStatisticToken(n)
case LineBreak: case LineBreak:
w.writeLineBreak(n) w.writeLineBreak(n)
case ExplicitLineBreak: case ExplicitLineBreak:
@ -285,6 +287,10 @@ func (w *OrgWriter) writeEmphasis(e Emphasis) {
w.WriteString(borders[1]) w.WriteString(borders[1])
} }
func (w *OrgWriter) writeStatisticToken(s StatisticToken) {
w.WriteString(fmt.Sprintf("[%s]", s.Content))
}
func (w *OrgWriter) writeLineBreak(l LineBreak) { func (w *OrgWriter) writeLineBreak(l LineBreak) {
w.WriteString(strings.Repeat("\n"+w.indent, l.Count)) w.WriteString(strings.Repeat("\n"+w.indent, l.Count))
} }

View file

@ -1,6 +1,25 @@
<h1> <h1>
Simple Headline Simple Headline <code class="statistic">[1/2]</code>
</h1> </h1>
<ul>
<li>
<p>
[X] checked
</p>
</li>
<li>
<p>
[ ] unchecked
</p>
</li>
<li>
<p>
note that statistic tokens are marked up anywhere
not just where they are actually meant to be - even here &gt; <code class="statistic">[100%]</code> &lt;
(Org mode proper does the same)
</p>
</li>
</ul>
<h1> <h1>
<span class="todo">TODO</span> <span class="todo">TODO</span>
<span class="priority">B</span> <span class="priority">B</span>

View file

@ -1,4 +1,9 @@
* Simple Headline * Simple Headline [1/2]
- [X] checked
- [ ] unchecked
- note that statistic tokens are marked up anywhere
not just where they are actually meant to be - even here > [100%] <
(Org mode proper does the same)
* TODO [#B] Headline with todo status & priority * TODO [#B] Headline with todo status & priority
* DONE Headline with TODO status * DONE Headline with TODO status
:PROPERTIES: :PROPERTIES:

View file

@ -43,7 +43,12 @@ src block
</p> </p>
<div class="highlight"> <div class="highlight">
<pre> <pre>
* Simple Headline * Simple Headline [1/2]
- [X] checked
- [ ] unchecked
- note that statistic tokens are marked up anywhere
not just where they are actually meant to be - even here &gt; [100%] &lt;
(Org mode proper does the same)
* TODO [#B] Headline with todo status &amp; priority * TODO [#B] Headline with todo status &amp; priority
* DONE Headline with TODO status * DONE Headline with TODO status
:PROPERTIES: :PROPERTIES: