Add support for latex blocks / environments
current support for latex fragments was inline only, i.e. lines containing block elements (e.g. a line starting with `* `, i.e. a headline) will not be parsed as part of the latex fragment but the respective block element. Parsing latex blocks at the block level should fix that. Note that in any case we don't do any processing and just emit the raw latex (leaving the rendering to e.g. js).
This commit is contained in:
parent
05a2dedbf8
commit
1849701ba7
8 changed files with 77 additions and 5 deletions
39
org/block.go
39
org/block.go
|
@ -1,6 +1,7 @@
|
||||||
package org
|
package org
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
@ -21,9 +22,15 @@ type Example struct {
|
||||||
Children []Node
|
Children []Node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LatexBlock struct {
|
||||||
|
Content []Node
|
||||||
|
}
|
||||||
|
|
||||||
var exampleLineRegexp = regexp.MustCompile(`^(\s*):(\s(.*)|\s*$)`)
|
var exampleLineRegexp = regexp.MustCompile(`^(\s*):(\s(.*)|\s*$)`)
|
||||||
var beginBlockRegexp = regexp.MustCompile(`(?i)^(\s*)#\+BEGIN_(\w+)(.*)`)
|
var beginBlockRegexp = regexp.MustCompile(`(?i)^(\s*)#\+BEGIN_(\w+)(.*)`)
|
||||||
var endBlockRegexp = regexp.MustCompile(`(?i)^(\s*)#\+END_(\w+)`)
|
var endBlockRegexp = regexp.MustCompile(`(?i)^(\s*)#\+END_(\w+)`)
|
||||||
|
var beginLatexBlockRegexp = regexp.MustCompile(`(?i)^(\s*)\\begin{([^}]+)}(\s*)$`)
|
||||||
|
var endLatexBlockRegexp = regexp.MustCompile(`(?i)^(\s*)\\end{([^}]+)}(\s*)$`)
|
||||||
var resultRegexp = regexp.MustCompile(`(?i)^(\s*)#\+RESULTS:`)
|
var resultRegexp = regexp.MustCompile(`(?i)^(\s*)#\+RESULTS:`)
|
||||||
var exampleBlockEscapeRegexp = regexp.MustCompile(`(^|\n)([ \t]*),([ \t]*)(\*|,\*|#\+|,#\+)`)
|
var exampleBlockEscapeRegexp = regexp.MustCompile(`(^|\n)([ \t]*),([ \t]*)(\*|,\*|#\+|,#\+)`)
|
||||||
|
|
||||||
|
@ -36,6 +43,15 @@ func lexBlock(line string) (token, bool) {
|
||||||
return nilToken, false
|
return nilToken, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lexLatexBlock(line string) (token, bool) {
|
||||||
|
if m := beginLatexBlockRegexp.FindStringSubmatch(line); m != nil {
|
||||||
|
return token{"beginLatexBlock", len(m[1]), strings.ToUpper(m[2]), m}, true
|
||||||
|
} else if m := endLatexBlockRegexp.FindStringSubmatch(line); m != nil {
|
||||||
|
return token{"endLatexBlock", len(m[1]), strings.ToUpper(m[2]), m}, true
|
||||||
|
}
|
||||||
|
return nilToken, false
|
||||||
|
}
|
||||||
|
|
||||||
func lexResult(line string) (token, bool) {
|
func lexResult(line string) (token, bool) {
|
||||||
if m := resultRegexp.FindStringSubmatch(line); m != nil {
|
if m := resultRegexp.FindStringSubmatch(line); m != nil {
|
||||||
return token{"result", len(m[1]), "", m}, true
|
return token{"result", len(m[1]), "", m}, true
|
||||||
|
@ -85,6 +101,22 @@ func (d *Document) parseBlock(i int, parentStop stopFn) (int, Node) {
|
||||||
return i + 1 - start, block
|
return i + 1 - start, block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Document) parseLatexBlock(i int, parentStop stopFn) (int, Node) {
|
||||||
|
t, start := d.tokens[i], i
|
||||||
|
name, rawText, trim := t.content, "", trimIndentUpTo(int(math.Max((float64(d.baseLvl)), float64(t.lvl))))
|
||||||
|
stop := func(d *Document, i int) bool {
|
||||||
|
return i >= len(d.tokens) || (d.tokens[i].kind == "endLatexBlock" && d.tokens[i].content == name)
|
||||||
|
}
|
||||||
|
for ; !stop(d, i); i++ {
|
||||||
|
rawText += trim(d.tokens[i].matches[0]) + "\n"
|
||||||
|
}
|
||||||
|
if i >= len(d.tokens) || d.tokens[i].kind != "endLatexBlock" || d.tokens[i].content != name {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
rawText += trim(d.tokens[i].matches[0])
|
||||||
|
return i + 1 - start, LatexBlock{d.parseRawInline(rawText)}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Document) parseSrcBlockResult(i int, parentStop stopFn) (int, Node) {
|
func (d *Document) parseSrcBlockResult(i int, parentStop stopFn) (int, Node) {
|
||||||
start := i
|
start := i
|
||||||
for ; !parentStop(d, i) && d.tokens[i].kind == "text" && d.tokens[i].content == ""; i++ {
|
for ; !parentStop(d, i) && d.tokens[i].kind == "text" && d.tokens[i].content == ""; i++ {
|
||||||
|
@ -145,6 +177,7 @@ func (b Block) ParameterMap() map[string]string {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Example) String() string { return orgWriter.WriteNodesAsString(n) }
|
func (n Example) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n Block) String() string { return orgWriter.WriteNodesAsString(n) }
|
func (n Block) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
func (n Result) String() string { return orgWriter.WriteNodesAsString(n) }
|
func (n LatexBlock) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
|
func (n Result) String() string { return orgWriter.WriteNodesAsString(n) }
|
||||||
|
|
|
@ -72,6 +72,7 @@ var lexFns = []lexFn{
|
||||||
lexKeywordOrComment,
|
lexKeywordOrComment,
|
||||||
lexFootnoteDefinition,
|
lexFootnoteDefinition,
|
||||||
lexExample,
|
lexExample,
|
||||||
|
lexLatexBlock,
|
||||||
lexText,
|
lexText,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +210,8 @@ func (d *Document) parseOne(i int, stop stopFn) (consumed int, node Node) {
|
||||||
consumed, node = d.parseTable(i, stop)
|
consumed, node = d.parseTable(i, stop)
|
||||||
case "beginBlock":
|
case "beginBlock":
|
||||||
consumed, node = d.parseBlock(i, stop)
|
consumed, node = d.parseBlock(i, stop)
|
||||||
|
case "beginLatexBlock":
|
||||||
|
consumed, node = d.parseLatexBlock(i, stop)
|
||||||
case "result":
|
case "result":
|
||||||
consumed, node = d.parseResult(i, stop)
|
consumed, node = d.parseResult(i, stop)
|
||||||
case "beginDrawer":
|
case "beginDrawer":
|
||||||
|
|
|
@ -162,6 +162,11 @@ func (w *HTMLWriter) WriteBlock(b Block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *HTMLWriter) WriteLatexBlock(b LatexBlock) {
|
||||||
|
WriteNodes(w, b.Content...)
|
||||||
|
w.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) WriteResult(r Result) { WriteNodes(w, r.Node) }
|
func (w *HTMLWriter) WriteResult(r Result) { WriteNodes(w, r.Node) }
|
||||||
|
|
||||||
func (w *HTMLWriter) WriteInlineBlock(b InlineBlock) {
|
func (w *HTMLWriter) WriteInlineBlock(b InlineBlock) {
|
||||||
|
|
|
@ -109,6 +109,12 @@ func (w *OrgWriter) WriteBlock(b Block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *OrgWriter) WriteLatexBlock(b LatexBlock) {
|
||||||
|
w.WriteString(w.indent)
|
||||||
|
WriteNodes(w, b.Content...)
|
||||||
|
w.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
func (w *OrgWriter) WriteResult(r Result) {
|
func (w *OrgWriter) WriteResult(r Result) {
|
||||||
w.WriteString("#+RESULTS:\n")
|
w.WriteString("#+RESULTS:\n")
|
||||||
WriteNodes(w, r.Node)
|
WriteNodes(w, r.Node)
|
||||||
|
|
14
org/testdata/latex.html
vendored
14
org/testdata/latex.html
vendored
|
@ -6,8 +6,18 @@ we support <code class="verbatim">\(...\)</code>, <code class="verbatim">\[...\]
|
||||||
<li>\[\sum_{i=1}^n a_n\]</li>
|
<li>\[\sum_{i=1}^n a_n\]</li>
|
||||||
<li>$$\sum_{i=1}^n a_n$$</li>
|
<li>$$\sum_{i=1}^n a_n$$</li>
|
||||||
<li>\begin{xyz}\sum_{i=1}^n a_n\end{xyz}</li>
|
<li>\begin{xyz}\sum_{i=1}^n a_n\end{xyz}</li>
|
||||||
<li>\begin{xyz}
|
<li>
|
||||||
|
\begin{xyz}
|
||||||
\sum_{i=1}^n a_n
|
\sum_{i=1}^n a_n
|
||||||
\end{xyz}</li>
|
\end{xyz}
|
||||||
|
</li>
|
||||||
<li>$2 + 2$, $3 - 3$</li>
|
<li>$2 + 2$, $3 - 3$</li>
|
||||||
|
<li>
|
||||||
|
\begin{xyz}
|
||||||
|
latex block ignores block lvl elements (e.g. list - line starting with -)
|
||||||
|
a = b
|
||||||
|
- c
|
||||||
|
- d
|
||||||
|
\end{xyz}
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
6
org/testdata/latex.org
vendored
6
org/testdata/latex.org
vendored
|
@ -10,3 +10,9 @@ we support =\(...\)=, =\[...\]=, =$$...$$= and =\begin{$env}...\end{$env}= as la
|
||||||
\sum_{i=1}^n a_n
|
\sum_{i=1}^n a_n
|
||||||
\end{xyz}
|
\end{xyz}
|
||||||
- $2 + 2$, $3 - 3$
|
- $2 + 2$, $3 - 3$
|
||||||
|
- \begin{xyz}
|
||||||
|
latex block ignores block lvl elements (e.g. list - line starting with -)
|
||||||
|
a = b
|
||||||
|
- c
|
||||||
|
- d
|
||||||
|
\end{xyz}
|
||||||
|
|
6
org/testdata/latex.pretty_org
vendored
6
org/testdata/latex.pretty_org
vendored
|
@ -10,3 +10,9 @@ we support =\(...\)=, =\[...\]=, =$$...$$= and =\begin{$env}...\end{$env}= as la
|
||||||
\sum_{i=1}^n a_n
|
\sum_{i=1}^n a_n
|
||||||
\end{xyz}
|
\end{xyz}
|
||||||
- $2 + 2$, $3 - 3$
|
- $2 + 2$, $3 - 3$
|
||||||
|
- \begin{xyz}
|
||||||
|
latex block ignores block lvl elements (e.g. list - line starting with -)
|
||||||
|
a = b
|
||||||
|
- c
|
||||||
|
- d
|
||||||
|
\end{xyz}
|
||||||
|
|
|
@ -19,6 +19,7 @@ type Writer interface {
|
||||||
WriteHeadline(Headline)
|
WriteHeadline(Headline)
|
||||||
WriteBlock(Block)
|
WriteBlock(Block)
|
||||||
WriteResult(Result)
|
WriteResult(Result)
|
||||||
|
WriteLatexBlock(LatexBlock)
|
||||||
WriteInlineBlock(InlineBlock)
|
WriteInlineBlock(InlineBlock)
|
||||||
WriteExample(Example)
|
WriteExample(Example)
|
||||||
WriteDrawer(Drawer)
|
WriteDrawer(Drawer)
|
||||||
|
@ -62,6 +63,8 @@ func WriteNodes(w Writer, nodes ...Node) {
|
||||||
w.WriteBlock(n)
|
w.WriteBlock(n)
|
||||||
case Result:
|
case Result:
|
||||||
w.WriteResult(n)
|
w.WriteResult(n)
|
||||||
|
case LatexBlock:
|
||||||
|
w.WriteLatexBlock(n)
|
||||||
case InlineBlock:
|
case InlineBlock:
|
||||||
w.WriteInlineBlock(n)
|
w.WriteInlineBlock(n)
|
||||||
case Example:
|
case Example:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue