mirror of
https://github.com/usememos/memos.git
synced 2025-04-04 04:41:10 +02:00
chore: implement html renderer
This commit is contained in:
parent
43ef9eaced
commit
5266a62685
@ -17,17 +17,18 @@ func NewParagraphParser() *ParagraphParser {
|
|||||||
|
|
||||||
func (*ParagraphParser) Match(tokens []*tokenizer.Token) (int, bool) {
|
func (*ParagraphParser) Match(tokens []*tokenizer.Token) (int, bool) {
|
||||||
contentTokens := []*tokenizer.Token{}
|
contentTokens := []*tokenizer.Token{}
|
||||||
cursor := 0
|
for _, token := range tokens {
|
||||||
for ; cursor < len(tokens); cursor++ {
|
contentTokens = append(contentTokens, token)
|
||||||
token := tokens[cursor]
|
|
||||||
if token.Type == tokenizer.Newline {
|
if token.Type == tokenizer.Newline {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
contentTokens = append(contentTokens, token)
|
|
||||||
}
|
}
|
||||||
if len(contentTokens) == 0 {
|
if len(contentTokens) == 0 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
if len(contentTokens) == 1 && contentTokens[0].Type == tokenizer.Newline {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
return len(contentTokens), true
|
return len(contentTokens), true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,10 @@ func TestParagraphParser(t *testing.T) {
|
|||||||
text: "",
|
text: "",
|
||||||
paragraph: nil,
|
paragraph: nil,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: "\n",
|
||||||
|
paragraph: nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: "Hello world!",
|
text: "Hello world!",
|
||||||
paragraph: &ast.Paragraph{
|
paragraph: &ast.Paragraph{
|
||||||
@ -28,6 +32,28 @@ func TestParagraphParser(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: "Hello world!\n",
|
||||||
|
paragraph: &ast.Paragraph{
|
||||||
|
Children: []ast.Node{
|
||||||
|
&ast.Text{
|
||||||
|
Content: "Hello world!",
|
||||||
|
},
|
||||||
|
&ast.LineBreak{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "Hello world!\n\nNew paragraph.",
|
||||||
|
paragraph: &ast.Paragraph{
|
||||||
|
Children: []ast.Node{
|
||||||
|
&ast.Text{
|
||||||
|
Content: "Hello world!",
|
||||||
|
},
|
||||||
|
&ast.LineBreak{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
@ -57,9 +57,9 @@ func TestParser(t *testing.T) {
|
|||||||
&ast.Text{
|
&ast.Text{
|
||||||
Content: "!",
|
Content: "!",
|
||||||
},
|
},
|
||||||
|
&ast.LineBreak{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&ast.LineBreak{},
|
|
||||||
&ast.Paragraph{
|
&ast.Paragraph{
|
||||||
Children: []ast.Node{
|
Children: []ast.Node{
|
||||||
&ast.Text{
|
&ast.Text{
|
||||||
@ -84,15 +84,36 @@ func TestParser(t *testing.T) {
|
|||||||
&ast.Text{
|
&ast.Text{
|
||||||
Content: "!",
|
Content: "!",
|
||||||
},
|
},
|
||||||
|
&ast.LineBreak{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&ast.LineBreak{},
|
|
||||||
&ast.CodeBlock{
|
&ast.CodeBlock{
|
||||||
Language: "javascript",
|
Language: "javascript",
|
||||||
Content: "console.log(\"Hello world!\");",
|
Content: "console.log(\"Hello world!\");",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: "Hello world!\n\nNew paragraph.",
|
||||||
|
nodes: []ast.Node{
|
||||||
|
&ast.Paragraph{
|
||||||
|
Children: []ast.Node{
|
||||||
|
&ast.Text{
|
||||||
|
Content: "Hello world!",
|
||||||
|
},
|
||||||
|
&ast.LineBreak{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&ast.LineBreak{},
|
||||||
|
&ast.Paragraph{
|
||||||
|
Children: []ast.Node{
|
||||||
|
&ast.Text{
|
||||||
|
Content: "New paragraph.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
@ -11,17 +11,17 @@ import (
|
|||||||
// nolint
|
// nolint
|
||||||
type HTMLRenderer struct {
|
type HTMLRenderer struct {
|
||||||
output *bytes.Buffer
|
output *bytes.Buffer
|
||||||
context *renderContext
|
context *RendererContext
|
||||||
}
|
}
|
||||||
|
|
||||||
type renderContext struct {
|
type RendererContext struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHTMLRenderer creates a new HTMLRenderer.
|
// NewHTMLRenderer creates a new HTMLRenderer.
|
||||||
func NewHTMLRenderer() *HTMLRenderer {
|
func NewHTMLRenderer() *HTMLRenderer {
|
||||||
return &HTMLRenderer{
|
return &HTMLRenderer{
|
||||||
output: new(bytes.Buffer),
|
output: new(bytes.Buffer),
|
||||||
context: &renderContext{},
|
context: &RendererContext{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +57,43 @@ func (r *HTMLRenderer) RenderNode(node ast.Node) {
|
|||||||
if prevSibling == nil || prevSibling.Type() != ast.NodeTypeBlockquote {
|
if prevSibling == nil || prevSibling.Type() != ast.NodeTypeBlockquote {
|
||||||
r.output.WriteString("</blockquote>")
|
r.output.WriteString("</blockquote>")
|
||||||
}
|
}
|
||||||
|
case *ast.BoldItalic:
|
||||||
|
r.output.WriteString("<strong><em>")
|
||||||
|
r.output.WriteString(n.Content)
|
||||||
|
r.output.WriteString("</em></strong>")
|
||||||
|
case *ast.Bold:
|
||||||
|
r.output.WriteString("<strong>")
|
||||||
|
r.output.WriteString(n.Content)
|
||||||
|
r.output.WriteString("</strong>")
|
||||||
|
case *ast.Italic:
|
||||||
|
r.output.WriteString("<em>")
|
||||||
|
r.output.WriteString(n.Content)
|
||||||
|
r.output.WriteString("</em>")
|
||||||
|
case *ast.Code:
|
||||||
|
r.output.WriteString("<code>")
|
||||||
|
r.output.WriteString(n.Content)
|
||||||
|
r.output.WriteString("</code>")
|
||||||
|
case *ast.Link:
|
||||||
|
r.output.WriteString(`<a href="`)
|
||||||
|
r.output.WriteString(n.URL)
|
||||||
|
r.output.WriteString(`">`)
|
||||||
|
r.output.WriteString(n.Text)
|
||||||
|
r.output.WriteString("</a>")
|
||||||
|
case *ast.Image:
|
||||||
|
r.output.WriteString(`<img src="`)
|
||||||
|
r.output.WriteString(n.URL)
|
||||||
|
r.output.WriteString(`" alt="`)
|
||||||
|
r.output.WriteString(n.AltText)
|
||||||
|
r.output.WriteString(`" />`)
|
||||||
|
case *ast.Tag:
|
||||||
|
r.output.WriteString(`<span>`)
|
||||||
|
r.output.WriteString(`# `)
|
||||||
|
r.output.WriteString(n.Content)
|
||||||
|
r.output.WriteString(`</span>`)
|
||||||
|
case *ast.Strikethrough:
|
||||||
|
r.output.WriteString(`<del>`)
|
||||||
|
r.output.WriteString(n.Content)
|
||||||
|
r.output.WriteString(`</del>`)
|
||||||
case *ast.Text:
|
case *ast.Text:
|
||||||
r.output.WriteString(n.Content)
|
r.output.WriteString(n.Content)
|
||||||
default:
|
default:
|
||||||
|
@ -22,6 +22,14 @@ func TestHTMLRenderer(t *testing.T) {
|
|||||||
text: "> Hello\n> world!",
|
text: "> Hello\n> world!",
|
||||||
expected: `<blockquote>Hello<br>world!</blockquote>`,
|
expected: `<blockquote>Hello<br>world!</blockquote>`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: "*Hello* world!",
|
||||||
|
expected: `<p><em>Hello</em> world!</p>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "**Hello** world!",
|
||||||
|
expected: `<p><strong>Hello</strong> world!</p>`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
@ -29,8 +37,6 @@ func TestHTMLRenderer(t *testing.T) {
|
|||||||
nodes, err := parser.Parse(tokens)
|
nodes, err := parser.Parse(tokens)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
actual := NewHTMLRenderer().Render(nodes)
|
actual := NewHTMLRenderer().Render(nodes)
|
||||||
if actual != test.expected {
|
require.Equal(t, test.expected, actual)
|
||||||
t.Errorf("expected: %s, actual: %s", test.expected, actual)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user