diff options
| -rw-r--r-- | mardown/ast.go | 6 | ||||
| -rw-r--r-- | mardown/ast_list.go | 77 | ||||
| -rw-r--r-- | mardown/ast_list_test.go | 42 | ||||
| -rw-r--r-- | mardown/ast_modifier.go | 2 | ||||
| -rw-r--r-- | mardown/ast_paragraph.go | 4 | ||||
| -rw-r--r-- | mardown/ast_test.go | 9 | ||||
| -rw-r--r-- | mardown/lexer.go | 14 |
7 files changed, 147 insertions, 7 deletions
diff --git a/mardown/ast.go b/mardown/ast.go index 55fd3b9..37d670d 100644 --- a/mardown/ast.go +++ b/mardown/ast.go @@ -75,6 +75,12 @@ func getBlock(lxs *lexers, newLine bool) (block, error) { } else { b, err = paragraph(lxs, false) } + case lexerList: + if newLine { + b, err = list(lxs) + } else { + b, err = paragraph(lxs, false) + } case lexerCode: if !newLine && len(lxs.Current().Value) == 3 { return nil, ErrInvalidCodeBlockPosition diff --git a/mardown/ast_list.go b/mardown/ast_list.go new file mode 100644 index 0000000..39be70c --- /dev/null +++ b/mardown/ast_list.go @@ -0,0 +1,77 @@ +package mardown + +import ( + "fmt" + "html/template" + "regexp" +) + +var regexOrdered = regexp.MustCompile(`\d+\.`) + +type listType string + +const ( + listUnordered listType = "ul" + listOrdered listType = "ol" +) + +type astList struct { + tag listType + content []*astParagraph +} + +func (a *astList) Eval() (template.HTML, error) { + var content template.HTML + for _, c := range a.content { + ct, err := c.Eval() + if err != nil { + return "", err + } + content += template.HTML(fmt.Sprintf("<li>%s</li>", trimSpace(ct))) + } + return template.HTML(fmt.Sprintf("<%s>%s</%s>", a.tag, content, a.tag)), nil +} + +func list(lxs *lexers) (block, error) { + tree := new(astList) + current := lxs.Current().Value + tree.tag = detectListType(current) + if len(tree.tag) == 0 { + return paragraph(lxs, false) + } + n := 0 + for lxs.Next() && n < 2 { + switch lxs.Current().Type { + case lexerBreak: + n++ + case lexerList: + n = 0 + tp := detectListType(lxs.Current().Value) + if tp != tree.tag { + lxs.Before() // because we dit not use it + return tree, nil + } + default: + n = 0 + c, err := paragraph(lxs, true) + if err != nil { + return nil, err + } + tree.content = append(tree.content, c) + } + } + return tree, nil +} + +func detectListType(val string) listType { + if []rune(val)[0] == '-' { + if len(val) > 1 { + return "" + } + return listUnordered + } + if !regexOrdered.MatchString(val) { + return "" + } + return listOrdered +} diff --git a/mardown/ast_list_test.go b/mardown/ast_list_test.go new file mode 100644 index 0000000..895e439 --- /dev/null +++ b/mardown/ast_list_test.go @@ -0,0 +1,42 @@ +package mardown + +import ( + "strings" + "testing" +) + +var rw = ` +- item A +- item B + +1. item 1 +2. item 2 +` + +var expected = ` +<ul> +<li>item A</li> +<li>item B</li> +</ul> +<ol> +<li>item 1</li> +<li>item 2</li> +</ol> +` + +func TestList(t *testing.T) { + lxs := lex(rw) + tree, err := ast(lxs) + if err != nil { + t.Fatal(err) + } + got, err := tree.Eval() + if err != nil { + t.Fatal(err) + } + exp := strings.ReplaceAll(expected, "\n", "") + if string(got) != exp { + t.Errorf("invalid value, got %s", got) + t.Logf("expected %s", exp) + } +} diff --git a/mardown/ast_modifier.go b/mardown/ast_modifier.go index 944cb4a..0107605 100644 --- a/mardown/ast_modifier.go +++ b/mardown/ast_modifier.go @@ -63,7 +63,7 @@ func modifier(lxs *lexers) (*astModifier, error) { var s string for lxs.Next() { switch lxs.Current().Type { - case lexerLiteral, lexerHeader: + case lexerLiteral, lexerHeader, lexerList: s += lxs.Current().Value case lexerModifier: if lxs.Current().Value == mod.symbols { diff --git a/mardown/ast_paragraph.go b/mardown/ast_paragraph.go index 3e8d027..2e8895d 100644 --- a/mardown/ast_paragraph.go +++ b/mardown/ast_paragraph.go @@ -43,9 +43,9 @@ func paragraph(lxs *lexers, oneLine bool) (*astParagraph, error) { switch lxs.Current().Type { case lexerBreak: n = len(lxs.Current().Value) - case lexerQuote: + case lexerQuote, lexerList: if n > 0 { - lxs.Before() + lxs.Before() // because we did not use it return tree, nil } tree.content = append(tree.content, astLiteral(lxs.Current().Value)) diff --git a/mardown/ast_test.go b/mardown/ast_test.go index 811d222..573349e 100644 --- a/mardown/ast_test.go +++ b/mardown/ast_test.go @@ -17,6 +17,12 @@ en *italique* et les **_deux en même temps_** ! > sur plusieurs lignes avec une source > qui recommence après ! + +- Ceci est une liste +- pas ordonnée +1. et maintenant +2. elle l'est +- hehe ` var parsed = ` @@ -25,6 +31,9 @@ var parsed = ` <p>Et je peux mettre du texte en <b>gras</b>, en <em>italique</em> et les <b><em>deux en même temps</em></b> !</p> <div class="quote"><blockquote>Je suis une magnifique citation sur plusieurs lignes</blockquote><p>avec une source</p></div> <div class="quote"><blockquote>qui recommence après !</blockquote></div> +<ul><li>Ceci est une liste</li><li>pas ordonnée</li></ul> +<ol><li>et maintenant</li><li>elle l'est</li></ol> +<ul><li>hehe</li></ul> ` func TestAst(t *testing.T) { diff --git a/mardown/lexer.go b/mardown/lexer.go index 8450032..c056460 100644 --- a/mardown/lexer.go +++ b/mardown/lexer.go @@ -5,13 +5,17 @@ import "fmt" type lexerType string const ( - lexerBreak lexerType = "break" + lexerBreak lexerType = "break" + lexerEscape lexerType = "escape" lexerModifier lexerType = "modifier" - lexerCode lexerType = "code" - lexerHeader lexerType = "header" - lexerQuote lexerType = "quote" + + lexerCode lexerType = "code" + + lexerHeader lexerType = "header" + lexerQuote lexerType = "quote" + lexerList lexerType = "list" lexerExternal lexerType = "external" @@ -94,6 +98,8 @@ func lex(s string) *lexers { fn(c, lexerExternal) case '\\': fn(c, lexerEscape) + case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.': + fn(c, lexerList) default: fn(c, lexerLiteral) } |
