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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
package markdown
import (
"encoding/json"
"errors"
"fmt"
"html/template"
"git.anhgelus.world/anhgelus/small-web/dom"
)
var (
ErrInvalidUsage = errors.Join(ErrInvalidParagraph, errors.New("invalid modifier usage"))
ErrInvalidTypeInModifier = errors.Join(ErrInvalidParagraph, errors.New("invalid type in modifier"))
)
type modifierTag string
const (
boldTag modifierTag = "b"
emTag modifierTag = "em"
)
type astModifier struct {
symbols string
tag modifierTag
content []block
super bool
}
func (a *astModifier) Eval(opt *Option) (template.HTML, *ParseError) {
var content template.HTML
for _, c := range a.content {
ct, err := c.Eval(opt)
if err != nil {
return "", &ParseError{lxs: lexers{}, internal: err}
}
content += ct
}
if a.super {
return content, nil
}
return dom.NewLiteralContentElement(string(a.tag), content).Render(), 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, super: %v, content: %s\n}", a.symbols, a.tag, a.super, content)
}
func modifier(lxs *lexers) (*astModifier, error) {
current := lxs.Current().Value
mod, err := modifierDetect(current)
if err != nil {
return nil, err
}
var s string
for lxs.Next() {
switch lxs.Current().Type {
case lexerLiteral, lexerHeading, lexerList:
s += lxs.Current().Value
case lexerModifier:
if mod.super && []rune(mod.symbols)[0] == []rune(lxs.Current().Value)[0] &&
len(mod.symbols) >= len(lxs.Current().Value) {
mod.symbols = mod.symbols[len(lxs.Current().Value):]
subMod, err := modifierDetect(lxs.Current().Value)
if err != nil {
return nil, err
}
if !subMod.super {
subMod.content = append(subMod.content, astLiteral(s))
mod, err = modifierDetect(mod.symbols) // this trick is so cool :D
if err != nil {
return nil, err
}
} else {
subMod, _ = modifierDetect("**")
subEm, _ := modifierDetect("*")
subEm.content = append(subEm.content, astLiteral(s))
subMod.content = append(subMod.content, subEm)
}
s = ""
mod.content = append(mod.content, subMod)
if len(mod.symbols) == 0 {
return mod, nil
}
} else {
if lxs.Current().Value == mod.symbols {
mod.content = append(mod.content, astLiteral(s))
return mod, nil
} else if len(s) != 0 {
mod.content = append(mod.content, astLiteral(s))
s = ""
}
c, err := modifier(lxs)
if err != nil {
return nil, err
}
mod.content = append(mod.content, c)
}
case lexerBreak:
lxs.Before() // because we did not use it
if len(s) != 0 {
return nil, ErrInvalidUsage
}
return mod, nil
case lexerExternal:
if lxs.Current().Value == "!" {
s += lxs.Current().Value
} else {
ext, err := external(lxs)
if err != nil {
return nil, err
}
mod.content = append(mod.content, ext)
}
default:
return nil, ErrInvalidTypeInModifier
}
}
if len(s) != 0 {
return nil, ErrInvalidUsage
}
return mod, nil
}
func modifierDetect(val string) (*astModifier, error) {
mod := new(astModifier)
mod.symbols = val
switch len(val) {
case 1:
mod.tag = emTag
case 2:
mod.tag = boldTag
case 3:
mod.super = true
default:
return nil, ErrInvalidUsage
}
return mod, nil
}
|