diff --git a/main.go b/main.go index 0c1f8df..f07cc32 100644 --- a/main.go +++ b/main.go @@ -25,19 +25,22 @@ func main() { if err != nil { log.Fatal(err) } - r, out := bytes.NewReader(bs), "" + r, out, err := bytes.NewReader(bs), "", nil switch strings.ToLower(os.Args[2]) { case "org": - out = org.NewDocument().Parse(r).Write(org.NewOrgWriter()).String() + out, err = org.NewDocument().Parse(r).Write(org.NewOrgWriter()) case "html": - out = org.NewDocument().Parse(r).Write(org.NewHTMLWriter()).String() + out, err = org.NewDocument().Parse(r).Write(org.NewHTMLWriter()) case "html-chroma": writer := org.NewHTMLWriter() writer.HighlightCodeBlock = highlightCodeBlock - out = org.NewDocument().Parse(r).Write(writer).String() + out, err = org.NewDocument().Parse(r).Write(writer) default: log.Fatal("Unsupported output format") } + if err != nil { + log.Fatal(err) + } log.Print(out) } diff --git a/org/document.go b/org/document.go index 13b3c5a..9791de0 100644 --- a/org/document.go +++ b/org/document.go @@ -9,6 +9,7 @@ import ( ) type Document struct { + Path string tokens []token Nodes []Node Footnotes *Footnotes @@ -17,6 +18,7 @@ type Document struct { AutoLink bool BufferSettings map[string]string DefaultSettings map[string]string + Error error } type Writer interface { @@ -77,24 +79,45 @@ func NewDocument() *Document { } } -func (d *Document) Write(w Writer) Writer { - if d.Nodes == nil { - panic("cannot Write() empty document: you must call Parse() first") +func (d *Document) Write(w Writer) (out string, err error) { + defer func() { + if recovered := recover(); recovered != nil { + err = fmt.Errorf("could not write output: %s", recovered) + } + }() + if d.Error != nil { + return "", d.Error + } else if d.Nodes == nil { + return "", fmt.Errorf("could not write output: parse was not called") } w.before(d) w.writeNodes(d.Nodes...) w.after(d) - return w + return w.String(), err } func (d *Document) Parse(input io.Reader) *Document { + defer func() { + if err := recover(); err != nil { + d.Error = fmt.Errorf("could not parse input: %s", err) + } + }() + if d.tokens != nil { + d.Error = fmt.Errorf("parse was called multiple times") + } 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{} { +func (d *Document) FrontMatter(input io.Reader, f func(string, string) interface{}) (_ map[string]interface{}, err error) { + defer func() { + d.tokens = nil + if recovered := recover(); recovered != nil { + err = fmt.Errorf("could not parse input: %s", recovered) + } + }() d.tokenize(input) d.parseMany(0, func(d *Document, i int) bool { if !(i < len(d.tokens)) { @@ -107,7 +130,7 @@ func (d *Document) FrontMatter(input io.Reader, f func(string, string) interface for k, v := range d.BufferSettings { frontMatter[k] = f(k, v) } - return frontMatter + return frontMatter, err } func (d *Document) tokenize(input io.Reader) { @@ -117,7 +140,7 @@ func (d *Document) tokenize(input io.Reader) { d.tokens = append(d.tokens, tokenize(scanner.Text())) } if err := scanner.Err(); err != nil { - panic(err) + d.Error = fmt.Errorf("could not tokenize input: %s", err) } } diff --git a/org/document_test.go b/org/document_test.go index ca5ed2c..95e35c7 100644 --- a/org/document_test.go +++ b/org/document_test.go @@ -64,7 +64,11 @@ var frontMatterTests = []frontMatterTest{ func TestParseFrontMatter(t *testing.T) { for _, test := range frontMatterTests { - actual := NewDocument().FrontMatter(strings.NewReader(test.input), test.handler) + actual, err := NewDocument().FrontMatter(strings.NewReader(test.input), test.handler) + if err != nil { + t.Errorf("%s\n got error: %s", test.name, err) + continue + } if !reflect.DeepEqual(test.expected, actual) { t.Errorf("%s\n got: %#v\nexpected: %#v\n%s'", test.name, actual, test.expected, test.input) } diff --git a/org/html_test.go b/org/html_test.go index fe2daf2..955ad6d 100644 --- a/org/html_test.go +++ b/org/html_test.go @@ -8,9 +8,12 @@ import ( func TestHTMLWriter(t *testing.T) { for _, path := range orgTestFiles() { reader, writer := strings.NewReader(fileString(path)), NewHTMLWriter() - actual := NewDocument().Parse(reader).Write(writer).String() + actual, err := NewDocument().Parse(reader).Write(writer) + if err != nil { + t.Errorf("%s\n got error: %s", path, err) + continue + } expected := fileString(path[:len(path)-len(".org")] + ".html") - if expected != actual { t.Errorf("%s:\n%s'", path, diff(actual, expected)) } else { diff --git a/org/org_test.go b/org/org_test.go index 157687d..94f88a7 100644 --- a/org/org_test.go +++ b/org/org_test.go @@ -14,7 +14,11 @@ func TestOrgWriter(t *testing.T) { for _, path := range orgTestFiles() { expected := fileString(path) reader, writer := strings.NewReader(expected), NewOrgWriter() - actual := NewDocument().Parse(reader).Write(writer).String() + actual, err := NewDocument().Parse(reader).Write(writer) + if err != nil { + t.Errorf("%s\n got error: %s", path, err) + continue + } if actual != expected { t.Errorf("%s:\n%s'", path, diff(actual, expected)) } else {