aboutsummaryrefslogtreecommitdiff
path: root/markdown
diff options
context:
space:
mode:
Diffstat (limited to 'markdown')
-rw-r--r--markdown/ast.go13
-rw-r--r--markdown/ast_callout.go92
-rw-r--r--markdown/ast_callout_test.go16
-rw-r--r--markdown/ast_quote.go39
-rw-r--r--markdown/ast_test.go6
-rw-r--r--markdown/lexer.go19
-rw-r--r--markdown/lexer_test.go2
7 files changed, 157 insertions, 30 deletions
diff --git a/markdown/ast.go b/markdown/ast.go
index b78104c..f977228 100644
--- a/markdown/ast.go
+++ b/markdown/ast.go
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"html/template"
+ "strings"
)
var ErrUnkownLexType = errors.New("unkown lex type")
@@ -106,3 +107,15 @@ func getBlock(lxs *lexers, newLine bool) (block, *ParseError) {
}
return b, err
}
+
+func evalBlock(bs []*astParagraph, opt *Option) (template.HTML, *ParseError) {
+ var sb strings.Builder
+ for _, c := range bs {
+ ct, err := c.Eval(opt)
+ if err != nil {
+ return "", err
+ }
+ sb.WriteString(string(ct))
+ }
+ return template.HTML(strings.TrimSpace(sb.String())), nil
+}
diff --git a/markdown/ast_callout.go b/markdown/ast_callout.go
new file mode 100644
index 0000000..769d714
--- /dev/null
+++ b/markdown/ast_callout.go
@@ -0,0 +1,92 @@
+package markdown
+
+import (
+ "errors"
+ "html/template"
+ "strings"
+
+ "git.anhgelus.world/anhgelus/small-web/dom"
+)
+
+var (
+ ErrInvalidCallout = errors.New("invalid callout")
+)
+
+type astCallout struct {
+ kind string
+ title *astParagraph
+ content []*astParagraph
+}
+
+func (a *astCallout) Eval(opt *Option) (template.HTML, *ParseError) {
+ inner := dom.NewContentElement("div", make([]dom.Element, 0))
+ for _, c := range a.content {
+ ct, err := c.Eval(opt)
+ if err != nil {
+ return "", err
+ }
+ inner.Contents = append(inner.Contents, dom.NewParagraph(
+ template.HTML(strings.TrimSpace(string(ct))),
+ ))
+ }
+
+ titleContent, err := a.title.Eval(opt)
+ if err != nil {
+ return "", err
+ }
+ titleContent = template.HTML(strings.TrimSpace(string(titleContent)))
+ if len(titleContent) == 0 {
+ titleContent = template.HTML(a.kind)
+ }
+ title := dom.NewLiteralContentElement("h4", titleContent)
+
+ callout := dom.NewContentElement("div", make([]dom.Element, 2))
+ callout.Contents[0] = title
+ callout.Contents[1] = inner
+ callout.SetAttribute("data-kind", a.kind)
+ callout.ClassList().Add("callout")
+ return callout.Render(), nil
+}
+
+func callout(lxs *lexers) (block, *ParseError) {
+ callout := new(astCallout)
+ if lxs.Current().Value != "[!" {
+ return paragraph(lxs, false)
+ }
+ if !lxs.Next() {
+ return nil, &ParseError{lxs: *lxs, internal: ErrInvalidCallout}
+ }
+ callout.kind = strings.ToLower(lxs.Current().Value)
+ if !lxs.Next() || lxs.Current().Type != lexerCallout || lxs.Current().Value != "]" {
+ return nil, &ParseError{lxs: *lxs, internal: ErrInvalidCallout}
+ }
+ var err *ParseError
+ callout.title, err = paragraph(lxs, true)
+ if err != nil {
+ return nil, err
+ }
+ n := 0
+ for lxs.Next() && n < 2 {
+ current := lxs.Current()
+ n = 0
+ switch current.Type {
+ case lexerBreak:
+ n = len(current.Value)
+ case lexerQuote:
+ case lexerLiteral, lexerModifier, lexerCode, lexerExternal:
+ p, err := paragraph(lxs, true)
+ if err != nil {
+ return nil, err
+ }
+ lxs.Before()
+ callout.content = append(callout.content, p)
+ n++
+ default:
+ // because the code did not use it
+ lxs.Before()
+ return callout, nil
+ }
+ }
+ lxs.Before()
+ return callout, nil
+}
diff --git a/markdown/ast_callout_test.go b/markdown/ast_callout_test.go
new file mode 100644
index 0000000..75140d4
--- /dev/null
+++ b/markdown/ast_callout_test.go
@@ -0,0 +1,16 @@
+package markdown
+
+import "testing"
+
+func TestCallout(t *testing.T) {
+ t.Run("callout", func(t *testing.T) {
+ t.Run("simple", test(`
+> [!NOTE]
+`, `<div data-kind="note" class="callout"><h4>note</h4><div></div></div>`))
+ t.Run("multiline", test(`
+> [!NOTE] Hey :3
+> content 1
+> content 2
+`, `<div data-kind="note" class="callout"><h4>Hey :3</h4><div><p>content 1</p><p>content 2</p></div></div>`))
+ })
+}
diff --git a/markdown/ast_quote.go b/markdown/ast_quote.go
index 96669c5..72a43e6 100644
--- a/markdown/ast_quote.go
+++ b/markdown/ast_quote.go
@@ -2,7 +2,6 @@ package markdown
import (
"html/template"
- "strings"
"git.anhgelus.world/anhgelus/small-web/dom"
)
@@ -13,27 +12,18 @@ type astQuote struct {
}
func (a *astQuote) Eval(opt *Option) (template.HTML, *ParseError) {
- var quoteContent template.HTML
- for _, c := range a.quote {
- ct, err := c.Eval(opt)
- if err != nil {
- return "", err
- }
- quoteContent += ct
+ quoteContent, err := evalBlock(a.quote, opt)
+ if err != nil {
+ return "", err
}
blockquote := dom.NewLiteralContentElement(
"blockquote",
- template.HTML(strings.TrimSpace(string(quoteContent))),
+ template.HTML(quoteContent),
)
- var source template.HTML
- for _, c := range a.source {
- ct, err := c.Eval(opt)
- if err != nil {
- return "", err
- }
- source += ct
+ source, err := evalBlock(a.source, opt)
+ if err != nil {
+ return "", err
}
- source = template.HTML(strings.TrimSpace(string(source)))
quote := dom.NewContentElement("div", make([]dom.Element, 0))
quote.ClassList().Add("quote")
quote.Contents = append(quote.Contents, blockquote)
@@ -43,26 +33,31 @@ func (a *astQuote) Eval(opt *Option) (template.HTML, *ParseError) {
return quote.Render(), nil
}
-func quote(lxs *lexers) (*astQuote, *ParseError) {
+func quote(lxs *lexers) (block, *ParseError) {
tree := new(astQuote)
n := 0
quoteContinue := true
source := false
for lxs.Next() && n < 2 {
- switch lxs.Current().Type {
+ current := lxs.Current()
+ n = 0
+ switch current.Type {
case lexerBreak:
- n = len(lxs.Current().Value)
+ n = len(current.Value)
quoteContinue = false
case lexerQuote:
- n = 0
if source {
// because the code did not use it
lxs.Before()
return tree, nil
}
quoteContinue = true
+ case lexerCallout:
+ if len(tree.quote) == 0 {
+ return callout(lxs)
+ }
+ fallthrough
case lexerLiteral, lexerModifier, lexerCode, lexerExternal:
- n = 0
if !quoteContinue {
source = true
}
diff --git a/markdown/ast_test.go b/markdown/ast_test.go
index 034eeb8..8205b4e 100644
--- a/markdown/ast_test.go
+++ b/markdown/ast_test.go
@@ -19,6 +19,10 @@ avec une source
> qui recommence après !
qui a elle aussi une source :D
+> [!NOTE] Hey :3
+> Hehe
+> That's cool
+
- Ceci est une liste
- pas ordonnée
1. et maintenant
@@ -36,6 +40,7 @@ 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><p>qui a elle aussi une source :D</p></div>
+<div data-kind="note" class="callout"><h4>Hey :3</h4><div><p>Hehe</p><p>That&#39;s cool</p></div></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>
@@ -51,6 +56,7 @@ var parsedPoem = `
<p>Et je peux mettre du texte en <b>gras</b>,<br>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><p>qui a elle aussi une source :D</p></div>
+<div data-kind="note" class="callout"><h4>Hey :3</h4><div><p>Hehe</p><p>That&#39;s cool</p></div></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>
diff --git a/markdown/lexer.go b/markdown/lexer.go
index f79b2ec..7386844 100644
--- a/markdown/lexer.go
+++ b/markdown/lexer.go
@@ -139,13 +139,18 @@ func lex(s string, opt *Option) *lexers {
if !newLine && i < len(runes)-1 {
next := runes[i+1]
runes := []rune(previous)
- if c == '[' && next == '!' {
- fn(c, lexerCallout, nil)
- continue
- } else if c == '!' && len(runes) > 0 && previous[len(previous)-1] == '[' {
- fn(c, lexerCallout, nil)
- continue
- } else if c == ']' && next != '(' {
+ if (c == '[' && next == '!') ||
+ (c == '!' && len(runes) > 0 && previous[len(previous)-1] == '[') ||
+ (c == ']' && next != '(') {
+ allSpace := true
+ for i := 0; allSpace && i < len(runes); i++ {
+ if runes[i] != ' ' {
+ allSpace = false
+ }
+ }
+ if allSpace {
+ previous = ""
+ }
fn(c, lexerCallout, nil)
continue
}
diff --git a/markdown/lexer_test.go b/markdown/lexer_test.go
index 5736b2a..57f8606 100644
--- a/markdown/lexer_test.go
+++ b/markdown/lexer_test.go
@@ -30,7 +30,7 @@ func TestLex(t *testing.T) {
}
lxs = lex(`> [!NOTE] title
> hey`, opt)
- if lxs.String() != `Lexers[quote(>) literal( ) callout([!) literal(NOTE) callout(]) literal( title) break({\n}) quote(>) literal( hey) ]` {
+ if lxs.String() != `Lexers[quote(>) callout([!) literal(NOTE) callout(]) literal( title) break({\n}) quote(>) literal( hey) ]` {
t.Errorf("invalid lex, got %s", lxs)
}
}