diff --git a/ast/node.go b/ast/node.go index 5a85671..c4d01f3 100644 --- a/ast/node.go +++ b/ast/node.go @@ -1,7 +1,6 @@ package ast import ( - "bytes" "fmt" ) @@ -462,37 +461,3 @@ func WalkFunc(n Node, f NodeVisitorFunc) { visitor := NodeVisitorFunc(f) Walk(n, visitor) } - -func dump(ast Node) { - fmt.Println(dumpString(ast)) -} - -func getContent(node Node) []byte { - if c := node.AsContainer(); c != nil { - if c.Literal != nil { - return c.Literal - } - return c.Content - } - return nil -} - -func dumpR(ast Node, depth int) string { - if ast == nil { - return "" - } - indent := bytes.Repeat([]byte("\t"), depth) - content := ast.AsContainer().Literal - if content == nil { - content = ast.AsContainer().Content - } - result := fmt.Sprintf("%s%T(%q)\n", indent, ast, content) - for _, child := range ast.GetChildren() { - result += dumpR(child, depth+1) - } - return result -} - -func dumpString(ast Node) string { - return dumpR(ast, 0) -} diff --git a/ast/print.go b/ast/print.go new file mode 100644 index 0000000..60ced2d --- /dev/null +++ b/ast/print.go @@ -0,0 +1,90 @@ +package ast + +import ( + "bytes" + "fmt" + "io" + "strings" +) + +// Print is for debugging. It prints a string representation of parsed +// markdown doc (result of parser.Parse()) to dst. +// +// To make output readable, it shortens text output. +func Print(dst io.Writer, doc Node) { + PrintWithPrefix(dst, doc, " ") +} + +// PrintWithPrefix is like Pring but allows customizing prefix used for +// indentation. By default it's 2 spaces. You can change it to e.g. tab +// by passing "\t" +func PrintWithPrefix(w io.Writer, doc Node, prefix string) { + printRecur(w, doc, prefix, 0) +} + +// ToString is like Dump but returns result as a string +func ToString(doc Node) string { + var buf bytes.Buffer + Print(&buf, doc) + return buf.String() +} + +func contentToString(d1 []byte, d2 []byte) string { + if d1 != nil { + return string(d1) + } + if d2 != nil { + return string(d2) + } + return "" +} + +func getContent(node Node) string { + if c := node.AsContainer(); c != nil { + return contentToString(c.Literal, c.Content) + } + leaf := node.AsLeaf() + return contentToString(leaf.Literal, leaf.Content) +} + +func shortenString(s string, maxLen int) string { + // for cleaner, one-line ouput, replace some white-space chars + // with their escaped version + s = strings.Replace(s, "\n", `\n`, -1) + s = strings.Replace(s, "\r", `\r`, -1) + s = strings.Replace(s, "\t", `\t`, -1) + if maxLen < 0 { + return s + } + if len(s) < maxLen { + return s + } + // add "..." to indicate truncation + return s[:maxLen-3] + "..." +} + +// get a short name of the type of v which excludes package name +// and strips "()" from the end +func getNodeType(node Node) string { + s := fmt.Sprintf("%T", node) + s = strings.TrimSuffix(s, "()") + if idx := strings.Index(s, "."); idx != -1 { + return s[idx+1:] + } + return s +} + +func printRecur(w io.Writer, node Node, prefix string, depth int) { + if node == nil { + return + } + indent := strings.Repeat(prefix, depth) + io.WriteString(w, indent) + + content := shortenString(getContent(node), 40) + typeName := getNodeType(node) + fmt.Fprintf(w, "%s%s '%s'\n", indent, typeName, content) + for _, child := range node.GetChildren() { + printRecur(w, child, prefix, depth+1) + } +} diff --git a/cmd/printast/main.go b/cmd/printast/main.go new file mode 100644 index 0000000..4a19977 --- /dev/null +++ b/cmd/printast/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/gomarkdown/markdown" + "github.com/gomarkdown/markdown/ast" +) + +// This prints AST of parsed markdown document. +// Usage: printast + +func usageAndExit() { + fmt.Printf("Usage: printast \n") + os.Exit(1) +} + +func main() { + nFiles := len(os.Args) - 1 + if nFiles < 1 { + usageAndExit() + } + for i := 0; i < nFiles; i++ { + fileName := os.Args[i+1] + d, err := ioutil.ReadFile(fileName) + if err != nil { + fmt.Fprintf(os.Stderr, "Couldn't open '%s', error: '%s'\n", fileName, err) + continue + } + doc := markdown.Parse(d, nil) + fmt.Printf("Ast of file '%s':\n", fileName) + ast.Print(os.Stdout, doc) + fmt.Print("\n") + } +}