\n")
}
-func (w *HTMLWriter) writeNodeWithMeta(m NodeWithMeta) {
- nodeW := w.emptyClone()
- nodeW.writeNodes(m.Node)
- nodeString := nodeW.String()
- if rawCaption, ok := m.Meta["CAPTION"]; ok {
- nodes, captionW := w.document.parseInline(rawCaption), w.emptyClone()
- captionW.writeNodes(nodes...)
- caption := `
` + "\n" + captionW.String() + "\n
\n"
- nodeString = `
` + "\n" + nodeString + caption + `
` + "\n"
+func (w *HTMLWriter) writeNodeWithMeta(n NodeWithMeta) {
+ out := w.nodesAsString(n.Node)
+ if p, ok := n.Node.(Paragraph); ok {
+ if len(p.Children) == 1 && isImageOrVideoLink(p.Children[0]) {
+ out = w.nodesAsString(p.Children[0])
+ }
}
- w.WriteString(nodeString)
+ for _, attributes := range n.Meta.HTMLAttributes {
+ out = withHTMLAttributes(out, attributes...) + "\n"
+ }
+ if len(n.Meta.Caption) != 0 {
+ caption := ""
+ for i, ns := range n.Meta.Caption {
+ if i != 0 {
+ caption += " "
+ }
+ caption += w.nodesAsString(ns...)
+ }
+ out = fmt.Sprintf("\n%s\n%s\n\n\n", out, caption)
+ }
+ w.WriteString(out)
}
func (w *HTMLWriter) writeTable(t Table) {
@@ -289,3 +304,24 @@ func (w *HTMLWriter) writeTableHeader(t TableHeader) {
func (w *HTMLWriter) writeTableSeparator(t TableSeparator) {
w.WriteString("
\n")
}
+
+func withHTMLAttributes(input string, kvs ...string) string {
+ if len(kvs)%2 != 0 {
+ panic(fmt.Sprintf("len of kvs must be even: %#v", kvs))
+ }
+ context := &h.Node{Type: h.ElementNode, Data: "body", DataAtom: atom.Body}
+ nodes, err := h.ParseFragment(strings.NewReader(strings.TrimSpace(input)), context)
+ if err != nil || len(nodes) != 1 {
+ panic(fmt.Sprintf("could not extend html attributes of %s: %v (%s)", input, len(nodes), err))
+ }
+ out, node := strings.Builder{}, nodes[0]
+ for i := 0; i < len(kvs)-1; i += 2 {
+ k, v := strings.TrimPrefix(kvs[i], ":"), kvs[i+1]
+ node.Attr = append(node.Attr, h.Attribute{Namespace: "", Key: k, Val: v})
+ }
+ err = h.Render(&out, nodes[0])
+ if err != nil {
+ panic(fmt.Sprintf("could not extend html attributes of %s: %#v (%s)", input, nodes, err))
+ }
+ return out.String()
+}
diff --git a/org/keyword.go b/org/keyword.go
index cbb4829..d4d0399 100644
--- a/org/keyword.go
+++ b/org/keyword.go
@@ -1,6 +1,7 @@
package org
import (
+ "encoding/csv"
"regexp"
"strings"
)
@@ -12,14 +13,18 @@ type Keyword struct {
type NodeWithMeta struct {
Node Node
- Meta map[string]string
+ Meta Metadata
+}
+
+type Metadata struct {
+ Caption [][]Node
+ HTMLAttributes [][]string
}
type Comment struct{ Content string }
var keywordRegexp = regexp.MustCompile(`^(\s*)#\+([^:]+):(\s+(.*)|(\s*)$)`)
var commentRegexp = regexp.MustCompile(`^(\s*)#(.*)`)
-var affiliatedKeywordRegexp = regexp.MustCompile(`^(CAPTION)$`)
func lexKeywordOrComment(line string) (token, bool) {
if m := keywordRegexp.FindStringSubmatch(line); m != nil {
@@ -30,47 +35,44 @@ func lexKeywordOrComment(line string) (token, bool) {
return nilToken, false
}
-func (d *Document) parseKeyword(i int, stop stopFn) (int, Node) {
- k := parseKeyword(d.tokens[i])
- if affiliatedKeywordRegexp.MatchString(k.Key) {
- consumed, node := d.parseAffiliated(i, stop)
- if consumed != 0 {
- return consumed, node
- }
- } else {
- d.BufferSettings[k.Key] = strings.Join([]string{d.BufferSettings[k.Key], k.Value}, "\n")
- }
- return 1, k
-}
-
func (d *Document) parseComment(i int, stop stopFn) (int, Node) {
return 1, Comment{d.tokens[i].content}
}
-func (d *Document) parseAffiliated(i int, stop stopFn) (int, Node) {
- start, meta := i, map[string]string{}
- for ; !stop(d, i) && d.tokens[i].kind == "keyword"; i++ {
- k := parseKeyword(d.tokens[i])
- if !affiliatedKeywordRegexp.MatchString(k.Key) {
- return 0, nil
+func (d *Document) parseKeyword(i int, stop stopFn) (int, Node) {
+ k := parseKeyword(d.tokens[i])
+ if k.Key == "CAPTION" || k.Key == "ATTR_HTML" {
+ consumed, node := d.parseAffiliated(i, stop)
+ if consumed != 0 {
+ return consumed, node
}
- if value, ok := meta[k.Key]; ok {
- meta[k.Key] = value + " " + k.Value
- } else {
- meta[k.Key] = k.Value
+ }
+ d.BufferSettings[k.Key] = strings.Join([]string{d.BufferSettings[k.Key], k.Value}, "\n")
+ return 1, k
+}
+
+func (d *Document) parseAffiliated(i int, stop stopFn) (int, Node) {
+ start, meta := i, Metadata{}
+ for ; !stop(d, i) && d.tokens[i].kind == "keyword"; i++ {
+ switch k := parseKeyword(d.tokens[i]); k.Key {
+ case "CAPTION":
+ meta.Caption = append(meta.Caption, d.parseInline(k.Value))
+ case "ATTR_HTML":
+ r := csv.NewReader(strings.NewReader(k.Value))
+ r.Comma = ' '
+ attributes, err := r.Read()
+ if err != nil {
+ return 0, nil
+ }
+ meta.HTMLAttributes = append(meta.HTMLAttributes, attributes)
+ default:
+ return 0, nil
}
}
if stop(d, i) {
return 0, nil
}
- consumed, node := 0, (Node)(nil)
- if t := d.tokens[i]; t.kind == "text" {
- if nodes := d.parseInline(t.content); len(nodes) == 1 && isImageOrVideoLink(nodes[0]) {
- consumed, node = 1, Paragraph{nodes[:1]}
- }
- } else {
- consumed, node = d.parseOne(i, stop)
- }
+ consumed, node := d.parseOne(i, stop)
if consumed == 0 || node == nil {
return 0, nil
}
diff --git a/org/org.go b/org/org.go
index 87b6d58..3408a34 100644
--- a/org/org.go
+++ b/org/org.go
@@ -173,11 +173,25 @@ func (w *OrgWriter) writeKeyword(k Keyword) {
w.WriteString(w.indent + fmt.Sprintf("#+%s: %s\n", k.Key, k.Value))
}
-func (w *OrgWriter) writeNodeWithMeta(m NodeWithMeta) {
- for k, v := range m.Meta {
- w.writeNodes(Keyword{k, v})
+func (w *OrgWriter) writeNodeWithMeta(n NodeWithMeta) {
+ for _, ns := range n.Meta.Caption {
+ w.WriteString("#+CAPTION: ")
+ w.writeNodes(ns...)
+ w.WriteString("\n")
}
- w.writeNodes(m.Node)
+ for _, attributes := range n.Meta.HTMLAttributes {
+ w.WriteString("#+ATTR_HTML: ")
+ for i := 0; i < len(attributes)-1; i += 2 {
+ w.WriteString(attributes[i] + " ")
+ if strings.ContainsAny(attributes[i+1], "\t ") {
+ w.WriteString(`"` + attributes[i+1] + `"`)
+ } else {
+ w.WriteString(attributes[i+1])
+ }
+ }
+ w.WriteString("\n")
+ }
+ w.writeNodes(n.Node)
}
func (w *OrgWriter) writeComment(c Comment) {
diff --git a/org/testdata/blocks.html b/org/testdata/blocks.html
index 3e2e69d..1e26208 100644
--- a/org/testdata/blocks.html
+++ b/org/testdata/blocks.html
@@ -1,4 +1,4 @@
-
+
echo "a bash source block"
@@ -10,10 +10,10 @@ function hello {
hello
-
+
block caption
-
-
+
+
a source block without a language
diff --git a/org/testdata/captions.html b/org/testdata/captions.html
index 138f066..a964c43 100644
--- a/org/testdata/captions.html
+++ b/org/testdata/captions.html
@@ -1,27 +1,30 @@
Anything can be captioned. Also captions are not real, correct captions but just a paragraph below the element (bothe wrapped into a div)
-
+
echo "i have a caption!"
-
+
captioned soure block
-
-
-
+
+
+
+
+captioned link (image in this case)
+
+
-
+note that the whole paragraph is captioned, so a linebreak is needed for images to caption correctly
-
-captioned link (video in this case)
-
-
+
-note that only that one line is captioned, not the whole paragraph
-
-
-also, normal text lines can't be captioned
+
+see?
+
+captioned link (image in this case)
+
+
diff --git a/org/testdata/captions.org b/org/testdata/captions.org
index 3822b29..87b6e40 100644
--- a/org/testdata/captions.org
+++ b/org/testdata/captions.org
@@ -5,9 +5,12 @@ Anything can be captioned. Also captions are not real, correct captions but just
echo "i have a caption!"
#+END_SRC
-#+CAPTION: captioned link (video in this case)
-[[my-video.mp4]]
-note that only that one line is captioned, not the whole paragraph
+#+CAPTION: captioned link (image in this case)
+[[http://placekitten.com/200/200#.png]]
+
+note that the whole paragraph is captioned, so a linebreak is needed for images to caption correctly
+
+#+CAPTION: captioned link (image in this case)
+[[http://placekitten.com/200/200#.png]]
+see?
-#+CAPTION: not happening!
-also, normal text lines can't be captioned
diff --git a/org/testdata/keywords.html b/org/testdata/keywords.html
new file mode 100644
index 0000000..a108f03
--- /dev/null
+++ b/org/testdata/keywords.html
@@ -0,0 +1,18 @@
+
+
+
echo "a bash source block with custom html attributes"
+
+
+
+and multiple lines of captions!
+
+
+
+and an image with custom html attributes and a caption
+
+
+
+
+kittens!
+
+
diff --git a/org/testdata/keywords.org b/org/testdata/keywords.org
new file mode 100644
index 0000000..cba15b3
--- /dev/null
+++ b/org/testdata/keywords.org
@@ -0,0 +1,13 @@
+
+#+CAPTION: and _multiple_
+#+CAPTION: lines of *captions*!
+#+ATTR_HTML: :class "a b c"
+#+ATTR_HTML: :id it
+#+BEGIN_SRC sh
+echo "a bash source block with custom html attributes"
+#+END_SRC
+
+and an image with custom html attributes and a caption
+#+CAPTION: kittens!
+#+ATTR_HTML: :style "border: 10px solid black"
+[[http://placekitten.com/200/200#.png]]