-
Notifications
You must be signed in to change notification settings - Fork 7
/
gofmtmd.go
48 lines (43 loc) · 1.32 KB
/
gofmtmd.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package gofmtmd
import (
"bytes"
"fmt"
"go/format"
"strconv"
"strings"
"gopkg.in/russross/blackfriday.v2"
)
// FmtGoCodeInMarkdown formats go code in Markdown.
// returns error if code has syntax error.
func FmtGoCodeInMarkdown(md []byte) ([]byte, error) {
var err error
n := blackfriday.New(blackfriday.WithExtensions(blackfriday.FencedCode)).Parse(md)
n.Walk(genFmtWalker(&md, &err))
if err != nil {
return nil, fmt.Errorf("[gofmtmd] %w", err)
}
return md, nil
}
func isGoCodeBlock(node *blackfriday.Node) bool {
return node.Type == blackfriday.CodeBlock && string(node.CodeBlockData.Info) == "go"
}
func genFmtWalker(md *[]byte, fmterr *error) blackfriday.NodeVisitor {
return func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
if isGoCodeBlock(node) {
fmted, err := format.Source(node.Literal)
if err != nil {
line := strings.Split(err.Error(), ":")[0]
i, cvtErr := strconv.Atoi(line)
if cvtErr != nil {
*fmterr = fmt.Errorf("failed to parse error msg: %w", cvtErr)
} else {
code := bytes.Split(node.Literal, []byte("\n"))
*fmterr = fmt.Errorf("line='%s', msg='%w'", string(code[i+1]), err)
}
return blackfriday.Terminate
}
*md = bytes.ReplaceAll(*md, bytes.TrimRight(node.Literal, "\n"), bytes.TrimRight(fmted, "\n"))
}
return blackfriday.GoToNext
}
}