From 8c34be92a661d6614bfdd1e5893e937da43caed2 Mon Sep 17 00:00:00 2001 From: boojack Date: Tue, 23 May 2023 20:49:32 +0800 Subject: [PATCH] feat(gomark): add bold parser (#1724) --- plugin/gomark/parser/bold.go | 46 +++++++++++++++ plugin/gomark/parser/bold_test.go | 88 ++++++++++++++++++++++++++++ plugin/gomark/parser/heading.go | 11 ++-- plugin/gomark/parser/heading_test.go | 12 ++-- 4 files changed, 146 insertions(+), 11 deletions(-) create mode 100644 plugin/gomark/parser/bold.go create mode 100644 plugin/gomark/parser/bold_test.go diff --git a/plugin/gomark/parser/bold.go b/plugin/gomark/parser/bold.go new file mode 100644 index 00000000..a47dc018 --- /dev/null +++ b/plugin/gomark/parser/bold.go @@ -0,0 +1,46 @@ +package parser + +import ( + "github.com/usememos/memos/plugin/gomark/parser/tokenizer" +) + +type BoldParser struct { + ContentTokens []*tokenizer.Token +} + +func NewBoldParser() *BoldParser { + return &BoldParser{} +} + +func (*BoldParser) Match(tokens []*tokenizer.Token) *BoldParser { + if len(tokens) < 5 { + return nil + } + + prefixTokens := tokens[:2] + if len(prefixTokens) != 2 || prefixTokens[0].Type != prefixTokens[1].Type { + return nil + } + prefixTokenType := prefixTokens[0].Type + + contentTokens := []*tokenizer.Token{} + cursor := 2 + for ; cursor < len(tokens)-1; cursor++ { + token, nextToken := tokens[cursor], tokens[cursor+1] + + if token.Type == tokenizer.Newline || nextToken.Type == tokenizer.Newline { + break + } + if token.Type == prefixTokenType && nextToken.Type == prefixTokenType { + break + } + contentTokens = append(contentTokens, token) + } + if cursor != len(tokens)-2 { + return nil + } + + return &BoldParser{ + ContentTokens: contentTokens, + } +} diff --git a/plugin/gomark/parser/bold_test.go b/plugin/gomark/parser/bold_test.go new file mode 100644 index 00000000..adeabef2 --- /dev/null +++ b/plugin/gomark/parser/bold_test.go @@ -0,0 +1,88 @@ +package parser + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/usememos/memos/plugin/gomark/parser/tokenizer" +) + +func TestBoldParser(t *testing.T) { + tests := []struct { + text string + bold *BoldParser + }{ + { + text: "*Hello world!", + bold: nil, + }, + { + text: "**Hello**", + bold: &BoldParser{ + ContentTokens: []*tokenizer.Token{ + { + Type: tokenizer.Text, + Value: "Hello", + }, + }, + }, + }, + { + text: "** Hello **", + bold: &BoldParser{ + ContentTokens: []*tokenizer.Token{ + { + Type: tokenizer.Space, + Value: " ", + }, + { + Type: tokenizer.Text, + Value: "Hello", + }, + { + Type: tokenizer.Space, + Value: " ", + }, + }, + }, + }, + { + text: "** Hello * *", + bold: nil, + }, + { + text: "* * Hello **", + bold: nil, + }, + { + text: `** Hello +**`, + bold: nil, + }, + { + text: `**Hello \n**`, + bold: &BoldParser{ + ContentTokens: []*tokenizer.Token{ + { + Type: tokenizer.Text, + Value: "Hello", + }, + { + Type: tokenizer.Space, + Value: " ", + }, + { + Type: tokenizer.Text, + Value: `\n`, + }, + }, + }, + }, + } + + for _, test := range tests { + tokens := tokenizer.Tokenize(test.text) + bold := NewBoldParser() + require.Equal(t, test.bold, bold.Match(tokens)) + } +} diff --git a/plugin/gomark/parser/heading.go b/plugin/gomark/parser/heading.go index bd366c85..c9c26323 100644 --- a/plugin/gomark/parser/heading.go +++ b/plugin/gomark/parser/heading.go @@ -4,16 +4,16 @@ import ( "github.com/usememos/memos/plugin/gomark/parser/tokenizer" ) -type HeadingTokenizer struct { +type HeadingParser struct { Level int ContentTokens []*tokenizer.Token } -func NewHeadingTokenizer() *HeadingTokenizer { - return &HeadingTokenizer{} +func NewHeadingParser() *HeadingParser { + return &HeadingParser{} } -func (*HeadingTokenizer) Match(tokens []*tokenizer.Token) *HeadingTokenizer { +func (*HeadingParser) Match(tokens []*tokenizer.Token) *HeadingParser { cursor := 0 for _, token := range tokens { if token.Type == tokenizer.Hash { @@ -40,12 +40,13 @@ func (*HeadingTokenizer) Match(tokens []*tokenizer.Token) *HeadingTokenizer { break } contentTokens = append(contentTokens, token) + cursor++ } if len(contentTokens) == 0 { return nil } - return &HeadingTokenizer{ + return &HeadingParser{ Level: level, ContentTokens: contentTokens, } diff --git a/plugin/gomark/parser/heading_test.go b/plugin/gomark/parser/heading_test.go index d4a18c13..7a8f99a4 100644 --- a/plugin/gomark/parser/heading_test.go +++ b/plugin/gomark/parser/heading_test.go @@ -10,7 +10,7 @@ import ( func TestHeadingParser(t *testing.T) { tests := []struct { text string - heading *HeadingTokenizer + heading *HeadingParser }{ { text: "*Hello world!", @@ -18,7 +18,7 @@ func TestHeadingParser(t *testing.T) { }, { text: "## Hello World!", - heading: &HeadingTokenizer{ + heading: &HeadingParser{ Level: 2, ContentTokens: []*tokenizer.Token{ { @@ -38,7 +38,7 @@ func TestHeadingParser(t *testing.T) { }, { text: "# # Hello World", - heading: &HeadingTokenizer{ + heading: &HeadingParser{ Level: 1, ContentTokens: []*tokenizer.Token{ { @@ -71,7 +71,7 @@ func TestHeadingParser(t *testing.T) { { text: `# 123 Hello World!`, - heading: &HeadingTokenizer{ + heading: &HeadingParser{ Level: 1, ContentTokens: []*tokenizer.Token{ { @@ -89,7 +89,7 @@ Hello World!`, for _, test := range tests { tokens := tokenizer.Tokenize(test.text) - headingTokenizer := NewHeadingTokenizer() - require.Equal(t, test.heading, headingTokenizer.Match(tokens)) + heading := NewHeadingParser() + require.Equal(t, test.heading, heading.Match(tokens)) } }