aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mardown/ast.go6
-rw-r--r--mardown/ast_list.go77
-rw-r--r--mardown/ast_list_test.go42
-rw-r--r--mardown/ast_modifier.go2
-rw-r--r--mardown/ast_paragraph.go4
-rw-r--r--mardown/ast_test.go9
-rw-r--r--mardown/lexer.go14
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&#39;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)
}