diff options
| author | Anhgelus Morhtuuzh <william@herges.fr> | 2025-10-01 15:04:54 +0200 |
|---|---|---|
| committer | Anhgelus Morhtuuzh <william@herges.fr> | 2025-10-01 15:04:54 +0200 |
| commit | 511ad88f6bf7b0ec971df407469c494d9dcb139e (patch) | |
| tree | a654ebad83f1123c0ea23fe52f3f9d809bcbe56c | |
| parent | 02f1e42a7f83f041627eace65675c1d6cea7e8cc (diff) | |
feat(markdown): rewrite modifier parser to construct a better tree
| -rw-r--r-- | mardown/ast_modifier.go | 94 | ||||
| -rw-r--r-- | mardown/ast_modifier_test.go | 4 | ||||
| -rw-r--r-- | mardown/ast_paragraph.go | 3 | ||||
| -rw-r--r-- | mardown/ast_test.go | 6 | ||||
| -rw-r--r-- | mardown/lexer.go | 9 |
5 files changed, 65 insertions, 51 deletions
diff --git a/mardown/ast_modifier.go b/mardown/ast_modifier.go index 46d5874..944cb4a 100644 --- a/mardown/ast_modifier.go +++ b/mardown/ast_modifier.go @@ -1,6 +1,7 @@ package mardown import ( + "encoding/json" "errors" "fmt" "html/template" @@ -23,7 +24,6 @@ type astModifier struct { symbols string tag modifierTag content []block - parent *astModifier } func (a *astModifier) Eval() (template.HTML, error) { @@ -38,75 +38,79 @@ func (a *astModifier) Eval() (template.HTML, error) { return template.HTML(fmt.Sprintf("<%s>%s</%s>", a.tag, content, a.tag)), nil } +func (a *astModifier) String() string { + content := "[" + for _, c := range a.content { + content += "\n\t" + if v, ok := c.(fmt.Stringer); ok { + content += v.String() + } else { + b, _ := json.MarshalIndent(a.content, "\t", " ") + content += string(b) + } + content += ",\n\t" + } + content += "]" + return fmt.Sprintf("modifier{sym: %s, tag: %s, content: %s\n}", a.symbols, a.tag, content) +} + func modifier(lxs *lexers) (*astModifier, error) { current := lxs.Current().Value - mod := modifierDetect(current) - modInside := mod - if len(mod.content) > 0 { - var ok bool - modInside, ok = mod.content[0].(*astModifier) - if modInside.content != nil && !ok { - return nil, ErrInternalError - } - // getting the last modifier - for len(modInside.content) > 0 { - modInside, ok = modInside.content[0].(*astModifier) - if modInside.content != nil && !ok { - return nil, ErrInternalError - } - } + mod, err := modifierDetect(current) + if err != nil { + return nil, err } var s string - for modInside != nil && lxs.Next() { + for lxs.Next() { switch lxs.Current().Type { - case lexerLiteral: + case lexerLiteral, lexerHeader: s += lxs.Current().Value case lexerModifier: - n := len(modInside.symbols) - if len(lxs.Current().Value) < n { - return nil, ErrInvalidModifier + if lxs.Current().Value == mod.symbols { + mod.content = append(mod.content, astLiteral(s)) + return mod, nil } - if lxs.Current().Value[:n] != modInside.symbols { - return nil, ErrInvalidModifier + if len(s) != 0 { + mod.content = append(mod.content, astLiteral(s)) + s = "" + } + c, err := modifier(lxs) + if err != nil { + return nil, err } - modInside.content = append(modInside.content, astLiteral(s)) - s = "" - modInside = modInside.parent + mod.content = append(mod.content, c) case lexerBreak: - lxs.current-- // because we did not use it + lxs.Before() // because we did not use it + if len(s) != 0 { + return nil, ErrInvalidModifier + } return mod, nil case lexerExternal: if lxs.Current().Value == "!" { s += lxs.Current().Value } default: - println(lxs.Current().Type, lxs.Current().Value) return nil, ErrInvalidTypeInModifier } } + if len(s) != 0 { + return nil, ErrInvalidModifier + } return mod, nil } -func modifierDetect(val string) *astModifier { +func modifierDetect(val string) (*astModifier, error) { mod := new(astModifier) - if len(val) == 1 { + switch len(val) { + case 1: mod.symbols = val mod.tag = emTag - return mod - } - if val[:2] == "**" || val[:2] == "__" { - mod.symbols = val[:2] + return mod, nil + case 2: + mod.symbols = val mod.tag = boldTag - if len(val) > 2 { - next := modifierDetect(val[2:]) - next.parent = mod - mod.content = append(mod.content, next) - } - } else { - mod = modifierDetect(val[:1]) - next := modifierDetect(val[1:]) - next.parent = mod - mod.content = append(mod.content, next) + return mod, nil + default: + return nil, ErrInvalidModifier } - return mod } diff --git a/mardown/ast_modifier_test.go b/mardown/ast_modifier_test.go index d805f22..1539aa4 100644 --- a/mardown/ast_modifier_test.go +++ b/mardown/ast_modifier_test.go @@ -4,7 +4,7 @@ import "testing" func TestModifier(t *testing.T) { content := ` -***bon*soir** +**bo*n*soir** ` lxs := lex(content) tree, err := ast(lxs) @@ -15,7 +15,7 @@ func TestModifier(t *testing.T) { if err != nil { t.Fatal(err) } - if c != "<p><b><em>bon</em>soir</b></p>" { + if c != "<p><b>bo<em>n</em>soir</b></p>" { t.Errorf("failed, got %s", c) t.Logf("lxs: %s\ntree: %s", lxs, tree) } diff --git a/mardown/ast_paragraph.go b/mardown/ast_paragraph.go index 1a78ced..3e8d027 100644 --- a/mardown/ast_paragraph.go +++ b/mardown/ast_paragraph.go @@ -69,6 +69,9 @@ func paragraph(lxs *lexers, oneLine bool) (*astParagraph, error) { //TODO: handle case lexerExternal: n = 0 + if lxs.Current().Value == "!" { + tree.content = append(tree.content, astLiteral(lxs.Current().Value)) + } //TODO: handle case lexerCode: n = 0 diff --git a/mardown/ast_test.go b/mardown/ast_test.go index 971e6ac..c0860f4 100644 --- a/mardown/ast_test.go +++ b/mardown/ast_test.go @@ -20,7 +20,7 @@ avec une source var parsed = ` <h1>Je suis un titre</h1> -<p>Avec une description classique, sur plusieurs lignes</p> +<p>Avec une description classique, sur plusieurs lignes !</p> <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> ` @@ -37,7 +37,7 @@ func TestAst(t *testing.T) { } wanted := strings.ReplaceAll(parsed, "\n", "") if string(res) != wanted { - t.Errorf("invalid string, got %s", res) - t.Logf("wanted %s", wanted) + t.Errorf("invalid string, got\n%s", res) + t.Logf("wanted\n%s", wanted) } } diff --git a/mardown/lexer.go b/mardown/lexer.go index f87e61c..8450032 100644 --- a/mardown/lexer.go +++ b/mardown/lexer.go @@ -74,7 +74,14 @@ func lex(s string) *lexers { for _, c := range []rune(s) { switch c { case '*', '_': - fn(c, lexerModifier) + if (currentType != lexerModifier && len(previous) > 0) || + (len(previous) > 0 && []rune(previous)[0] != c) || + len(previous) > 2 { + lexs = append(lexs, lexer{Type: currentType, Value: previous}) + previous = "" + } + currentType = lexerModifier + previous += string(c) case '`': fn(c, lexerCode) case '\n': |
