go-org-orgwiki/org/keyword.go
Niklas Fasching a0e87057d6 Fix BufferSettings append & add ParseFrontMatter
until now buffersettings were always appended using \n which means the first
value would already be written as "\nVALUE". Not anymore.

Also we finally add an option to parse just the front matter. Still not
efficient as we tokenize the whole org file but i don't think saving a few
milliseconds would be worth making the code uglier.
2018-12-13 17:44:26 +01:00

91 lines
2.1 KiB
Go

package org
import (
"encoding/csv"
"regexp"
"strings"
)
type Keyword struct {
Key string
Value string
}
type NodeWithMeta struct {
Node Node
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*)#(.*)`)
func lexKeywordOrComment(line string) (token, bool) {
if m := keywordRegexp.FindStringSubmatch(line); m != nil {
return token{"keyword", len(m[1]), m[2], m}, true
} else if m := commentRegexp.FindStringSubmatch(line); m != nil {
return token{"comment", len(m[1]), m[2], m}, true
}
return nilToken, false
}
func (d *Document) parseComment(i int, stop stopFn) (int, Node) {
return 1, Comment{d.tokens[i].content}
}
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 _, ok := d.BufferSettings[k.Key]; ok {
d.BufferSettings[k.Key] = strings.Join([]string{d.BufferSettings[k.Key], k.Value}, "\n")
} else {
d.BufferSettings[k.Key] = k.Value
}
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 := d.parseOne(i, stop)
if consumed == 0 || node == nil {
return 0, nil
}
i += consumed
return i - start, NodeWithMeta{node, meta}
}
func parseKeyword(t token) Keyword {
k, v := t.matches[2], t.matches[4]
k = strings.ToUpper(k)
return Keyword{k, v}
}