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.
This commit is contained in:
parent
0255a129e2
commit
a0e87057d6
3 changed files with 110 additions and 4 deletions
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Document struct {
|
type Document struct {
|
||||||
|
@ -51,6 +52,15 @@ var lexFns = []lexFn{
|
||||||
|
|
||||||
var nilToken = token{"nil", -1, "", nil}
|
var nilToken = token{"nil", -1, "", nil}
|
||||||
|
|
||||||
|
var DefaultFrontMatterHandler = func(k, v string) interface{} {
|
||||||
|
switch k {
|
||||||
|
case "TAGS":
|
||||||
|
return strings.Fields(v)
|
||||||
|
default:
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func NewDocument() *Document {
|
func NewDocument() *Document {
|
||||||
return &Document{
|
return &Document{
|
||||||
Footnotes: &Footnotes{
|
Footnotes: &Footnotes{
|
||||||
|
@ -78,6 +88,29 @@ func (d *Document) Write(w Writer) Writer {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Document) Parse(input io.Reader) *Document {
|
func (d *Document) Parse(input io.Reader) *Document {
|
||||||
|
d.tokenize(input)
|
||||||
|
_, nodes := d.parseMany(0, func(d *Document, i int) bool { return !(i < len(d.tokens)) })
|
||||||
|
d.Nodes = nodes
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Document) FrontMatter(input io.Reader, f func(string, string) interface{}) map[string]interface{} {
|
||||||
|
d.tokenize(input)
|
||||||
|
d.parseMany(0, func(d *Document, i int) bool {
|
||||||
|
if !(i < len(d.tokens)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
t := d.tokens[i]
|
||||||
|
return t.kind != "keyword" && !(t.kind == "text" && t.content == "")
|
||||||
|
})
|
||||||
|
frontMatter := make(map[string]interface{}, len(d.BufferSettings))
|
||||||
|
for k, v := range d.BufferSettings {
|
||||||
|
frontMatter[k] = f(k, v)
|
||||||
|
}
|
||||||
|
return frontMatter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Document) tokenize(input io.Reader) {
|
||||||
d.tokens = []token{}
|
d.tokens = []token{}
|
||||||
scanner := bufio.NewScanner(input)
|
scanner := bufio.NewScanner(input)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
|
@ -86,9 +119,6 @@ func (d *Document) Parse(input io.Reader) *Document {
|
||||||
if err := scanner.Err(); err != nil {
|
if err := scanner.Err(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
_, nodes := d.parseMany(0, func(d *Document, i int) bool { return !(i < len(d.tokens)) })
|
|
||||||
d.Nodes = nodes
|
|
||||||
return d
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Document) Get(key string) string {
|
func (d *Document) Get(key string) string {
|
||||||
|
|
72
org/document_test.go
Normal file
72
org/document_test.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package org
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type frontMatterTest struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
handler func(string, string) interface{}
|
||||||
|
expected map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var frontMatterTests = []frontMatterTest{
|
||||||
|
{`basic`,
|
||||||
|
`#+TITLE: The Title`,
|
||||||
|
DefaultFrontMatterHandler,
|
||||||
|
map[string]interface{}{"TITLE": "The Title"}},
|
||||||
|
{`empty`,
|
||||||
|
`* No frontmatter here`,
|
||||||
|
DefaultFrontMatterHandler,
|
||||||
|
map[string]interface{}{}},
|
||||||
|
{`custom handler`,
|
||||||
|
`
|
||||||
|
#+TITLE: The Title
|
||||||
|
|
||||||
|
#+TAGS: foo bar
|
||||||
|
|
||||||
|
`,
|
||||||
|
func(k, v string) interface{} {
|
||||||
|
switch k {
|
||||||
|
case "TITLE":
|
||||||
|
return "Thanks For All The Fish"
|
||||||
|
default:
|
||||||
|
return DefaultFrontMatterHandler(k, v)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"TITLE": "Thanks For All The Fish",
|
||||||
|
"TAGS": []string{"foo", "bar"},
|
||||||
|
}},
|
||||||
|
{`multiple + ignored keyword`,
|
||||||
|
`
|
||||||
|
#+TITLE: The Title
|
||||||
|
#+AUTHOR: The Author
|
||||||
|
|
||||||
|
#+OTHER: some other keyword
|
||||||
|
#+TAGS: this will become []string
|
||||||
|
|
||||||
|
something that's not a keyword or a text line without content
|
||||||
|
|
||||||
|
#+SUBTITLE: The Subtitle`,
|
||||||
|
DefaultFrontMatterHandler,
|
||||||
|
map[string]interface{}{
|
||||||
|
"TITLE": "The Title",
|
||||||
|
"AUTHOR": "The Author",
|
||||||
|
"OTHER": "some other keyword",
|
||||||
|
"TAGS": []string{"this", "will", "become", "[]string"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseFrontMatter(t *testing.T) {
|
||||||
|
for _, test := range frontMatterTests {
|
||||||
|
actual := NewDocument().FrontMatter(strings.NewReader(test.input), test.handler)
|
||||||
|
if !reflect.DeepEqual(test.expected, actual) {
|
||||||
|
t.Errorf("%s\n got: %#v\nexpected: %#v\n%s'", test.name, actual, test.expected, test.input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,7 +47,11 @@ func (d *Document) parseKeyword(i int, stop stopFn) (int, Node) {
|
||||||
return consumed, node
|
return consumed, node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.BufferSettings[k.Key] = strings.Join([]string{d.BufferSettings[k.Key], k.Value}, "\n")
|
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
|
return 1, k
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue