Improve block parameter parsing

The actual parameter parsing logic in emacs org mode is quite complex [1]. All
we want for now is to handle parameter values containing spaces [2]. Splitting
on ` :` gets us close enough for now. As I'm very opposed to copying 100 lines
of parameter parsing logic just to get exports right let's wait for use cases -
no hurt in gathering requirements as we go.

[1] https://github.com/bzg/org-mode/blob/master/lisp/ob-core.el#L1481
[2] I never ran into such parameters before and wrongly assumed that splitting
on spaces would be enough. boy was i wrong - just look at that massive
function [1]! that's why we can't have nice things!
This commit is contained in:
Niklas Fasching 2021-04-11 21:45:19 +02:00
parent b9f05878fa
commit b3edd6c182
4 changed files with 33 additions and 1 deletions

View file

@ -54,7 +54,7 @@ func isRawTextBlock(name string) bool { return name == "SRC" || name == "EXAMPLE
func (d *Document) parseBlock(i int, parentStop stopFn) (int, Node) { func (d *Document) parseBlock(i int, parentStop stopFn) (int, Node) {
t, start := d.tokens[i], i t, start := d.tokens[i], i
name, parameters := t.content, strings.Fields(t.matches[3]) name, parameters := t.content, splitParameters(t.matches[3])
trim := trimIndentUpTo(d.tokens[i].lvl) trim := trimIndentUpTo(d.tokens[i].lvl)
stop := func(d *Document, i int) bool { stop := func(d *Document, i int) bool {
return i >= len(d.tokens) || (d.tokens[i].kind == "endBlock" && d.tokens[i].content == name) return i >= len(d.tokens) || (d.tokens[i].kind == "endBlock" && d.tokens[i].content == name)
@ -121,6 +121,19 @@ func trimIndentUpTo(max int) func(string) string {
} }
} }
func splitParameters(s string) []string {
parameters, parts := []string{}, strings.Split(s, " :")
lang, rest := strings.TrimSpace(parts[0]), parts[1:]
if lang != "" {
parameters = append(parameters, lang)
}
for _, p := range rest {
kv := strings.SplitN(p+" ", " ", 2)
parameters = append(parameters, ":"+kv[0], strings.TrimSpace(kv[1]))
}
return parameters
}
func (b Block) ParameterMap() map[string]string { func (b Block) ParameterMap() map[string]string {
if len(b.Parameters) == 0 { if len(b.Parameters) == 0 {
return nil return nil

View file

@ -40,6 +40,9 @@ a source block with results
a source block that only exports results a source block that only exports results
</pre> </pre>
<pre class="example"> <pre class="example">
but the result block is
</pre>
<pre class="example">
an example block with an example block with
multiple lines including multiple lines including

View file

@ -38,6 +38,14 @@ echo a source block that only exports results
#+RESULTS: #+RESULTS:
: a source block that only exports results : a source block that only exports results
#+begin_src bash :cmdline -foo -bar :exports results
# the code block is not rendered
echo but the result block is
#+end_src
#+RESULTS:
: but the result block is
#+BEGIN_EXAMPLE foo bar baz #+BEGIN_EXAMPLE foo bar baz
an example block with an example block with
multiple lines including multiple lines including

View file

@ -38,6 +38,14 @@ echo a source block that only exports results
#+RESULTS: #+RESULTS:
: a source block that only exports results : a source block that only exports results
#+BEGIN_SRC bash :cmdline -foo -bar :exports results
# the code block is not rendered
echo but the result block is
#+END_SRC
#+RESULTS:
: but the result block is
#+BEGIN_EXAMPLE foo bar baz #+BEGIN_EXAMPLE foo bar baz
an example block with an example block with
multiple lines including multiple lines including