Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
98762be1
Commit
98762be1
authored
Jan 14, 2024
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: implement indent for list nodes
parent
d44e74bd
Changes
14
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
309 additions
and
166 deletions
+309
-166
markdown_service.go
api/v2/markdown_service.go
+6
-6
block.go
plugin/gomark/ast/block.go
+17
-7
ordered_list.go
plugin/gomark/parser/ordered_list.go
+24
-5
ordered_list_test.go
plugin/gomark/parser/ordered_list_test.go
+12
-0
paragraph.go
plugin/gomark/parser/paragraph.go
+0
-3
task_list.go
plugin/gomark/parser/task_list.go
+26
-9
task_list_test.go
plugin/gomark/parser/task_list_test.go
+13
-0
unordered_list.go
plugin/gomark/parser/unordered_list.go
+25
-6
markdown_service.proto
proto/api/v2/markdown_service.proto
+7
-4
README.md
proto/gen/api/v2/README.md
+3
-0
markdown_service.pb.go
proto/gen/api/v2/markdown_service.pb.go
+130
-102
OrderedList.tsx
web/src/components/MemoContent/OrderedList.tsx
+15
-8
TaskList.tsx
web/src/components/MemoContent/TaskList.tsx
+16
-8
UnorderedList.tsx
web/src/components/MemoContent/UnorderedList.tsx
+15
-8
No files found.
api/v2/markdown_service.go
View file @
98762be1
...
@@ -54,13 +54,13 @@ func convertFromASTNode(rawNode ast.Node) *apiv2pb.Node {
...
@@ -54,13 +54,13 @@ func convertFromASTNode(rawNode ast.Node) *apiv2pb.Node {
node
.
Node
=
&
apiv2pb
.
Node_BlockquoteNode
{
BlockquoteNode
:
&
apiv2pb
.
BlockquoteNode
{
Children
:
children
}}
node
.
Node
=
&
apiv2pb
.
Node_BlockquoteNode
{
BlockquoteNode
:
&
apiv2pb
.
BlockquoteNode
{
Children
:
children
}}
case
*
ast
.
OrderedList
:
case
*
ast
.
OrderedList
:
children
:=
convertFromASTNodes
(
n
.
Children
)
children
:=
convertFromASTNodes
(
n
.
Children
)
node
.
Node
=
&
apiv2pb
.
Node_OrderedListNode
{
OrderedListNode
:
&
apiv2pb
.
OrderedListNode
{
Number
:
n
.
Number
,
Children
:
children
}}
node
.
Node
=
&
apiv2pb
.
Node_OrderedListNode
{
OrderedListNode
:
&
apiv2pb
.
OrderedListNode
{
Number
:
n
.
Number
,
Indent
:
int32
(
n
.
Indent
),
Children
:
children
}}
case
*
ast
.
UnorderedList
:
case
*
ast
.
UnorderedList
:
children
:=
convertFromASTNodes
(
n
.
Children
)
children
:=
convertFromASTNodes
(
n
.
Children
)
node
.
Node
=
&
apiv2pb
.
Node_UnorderedListNode
{
UnorderedListNode
:
&
apiv2pb
.
UnorderedListNode
{
Symbol
:
n
.
Symbol
,
Children
:
children
}}
node
.
Node
=
&
apiv2pb
.
Node_UnorderedListNode
{
UnorderedListNode
:
&
apiv2pb
.
UnorderedListNode
{
Symbol
:
n
.
Symbol
,
Indent
:
int32
(
n
.
Indent
),
Children
:
children
}}
case
*
ast
.
TaskList
:
case
*
ast
.
TaskList
:
children
:=
convertFromASTNodes
(
n
.
Children
)
children
:=
convertFromASTNodes
(
n
.
Children
)
node
.
Node
=
&
apiv2pb
.
Node_TaskListNode
{
TaskListNode
:
&
apiv2pb
.
TaskListNode
{
Symbol
:
n
.
Symbol
,
Complete
:
n
.
Complete
,
Children
:
children
}}
node
.
Node
=
&
apiv2pb
.
Node_TaskListNode
{
TaskListNode
:
&
apiv2pb
.
TaskListNode
{
Symbol
:
n
.
Symbol
,
Indent
:
int32
(
n
.
Indent
),
Complete
:
n
.
Complete
,
Children
:
children
}}
case
*
ast
.
MathBlock
:
case
*
ast
.
MathBlock
:
node
.
Node
=
&
apiv2pb
.
Node_MathBlockNode
{
MathBlockNode
:
&
apiv2pb
.
MathBlockNode
{
Content
:
n
.
Content
}}
node
.
Node
=
&
apiv2pb
.
Node_MathBlockNode
{
MathBlockNode
:
&
apiv2pb
.
MathBlockNode
{
Content
:
n
.
Content
}}
case
*
ast
.
Text
:
case
*
ast
.
Text
:
...
@@ -123,13 +123,13 @@ func convertToASTNode(node *apiv2pb.Node) ast.Node {
...
@@ -123,13 +123,13 @@ func convertToASTNode(node *apiv2pb.Node) ast.Node {
return
&
ast
.
Blockquote
{
Children
:
children
}
return
&
ast
.
Blockquote
{
Children
:
children
}
case
*
apiv2pb
.
Node_OrderedListNode
:
case
*
apiv2pb
.
Node_OrderedListNode
:
children
:=
convertToASTNodes
(
n
.
OrderedListNode
.
Children
)
children
:=
convertToASTNodes
(
n
.
OrderedListNode
.
Children
)
return
&
ast
.
OrderedList
{
Number
:
n
.
OrderedListNode
.
Number
,
Children
:
children
}
return
&
ast
.
OrderedList
{
Number
:
n
.
OrderedListNode
.
Number
,
Indent
:
int
(
n
.
OrderedListNode
.
Indent
),
Children
:
children
}
case
*
apiv2pb
.
Node_UnorderedListNode
:
case
*
apiv2pb
.
Node_UnorderedListNode
:
children
:=
convertToASTNodes
(
n
.
UnorderedListNode
.
Children
)
children
:=
convertToASTNodes
(
n
.
UnorderedListNode
.
Children
)
return
&
ast
.
UnorderedList
{
Symbol
:
n
.
UnorderedListNode
.
Symbol
,
Children
:
children
}
return
&
ast
.
UnorderedList
{
Symbol
:
n
.
UnorderedListNode
.
Symbol
,
Indent
:
int
(
n
.
UnorderedListNode
.
Indent
),
Children
:
children
}
case
*
apiv2pb
.
Node_TaskListNode
:
case
*
apiv2pb
.
Node_TaskListNode
:
children
:=
convertToASTNodes
(
n
.
TaskListNode
.
Children
)
children
:=
convertToASTNodes
(
n
.
TaskListNode
.
Children
)
return
&
ast
.
TaskList
{
Symbol
:
n
.
TaskListNode
.
Symbol
,
Complete
:
n
.
TaskListNode
.
Complete
,
Children
:
children
}
return
&
ast
.
TaskList
{
Symbol
:
n
.
TaskListNode
.
Symbol
,
Indent
:
int
(
n
.
TaskListNode
.
Indent
),
Complete
:
n
.
TaskListNode
.
Complete
,
Children
:
children
}
case
*
apiv2pb
.
Node_MathBlockNode
:
case
*
apiv2pb
.
Node_MathBlockNode
:
return
&
ast
.
MathBlock
{
Content
:
n
.
MathBlockNode
.
Content
}
return
&
ast
.
MathBlock
{
Content
:
n
.
MathBlockNode
.
Content
}
case
*
apiv2pb
.
Node_TextNode
:
case
*
apiv2pb
.
Node_TextNode
:
...
...
plugin/gomark/ast/block.go
View file @
98762be1
package
ast
package
ast
import
"fmt"
import
(
"fmt"
"strings"
)
type
BaseBlock
struct
{
type
BaseBlock
struct
{
BaseNode
BaseNode
...
@@ -110,7 +113,10 @@ func (n *Blockquote) Restore() string {
...
@@ -110,7 +113,10 @@ func (n *Blockquote) Restore() string {
type
OrderedList
struct
{
type
OrderedList
struct
{
BaseBlock
BaseBlock
Number
string
// Number is the number of the list.
Number
string
// Indent is the number of spaces.
Indent
int
Children
[]
Node
Children
[]
Node
}
}
...
@@ -123,14 +129,16 @@ func (n *OrderedList) Restore() string {
...
@@ -123,14 +129,16 @@ func (n *OrderedList) Restore() string {
for
_
,
child
:=
range
n
.
Children
{
for
_
,
child
:=
range
n
.
Children
{
result
+=
child
.
Restore
()
result
+=
child
.
Restore
()
}
}
return
fmt
.
Sprintf
(
"%s
. %s"
,
n
.
Number
,
result
)
return
fmt
.
Sprintf
(
"%s
%s. %s"
,
strings
.
Repeat
(
" "
,
n
.
Indent
)
,
n
.
Number
,
result
)
}
}
type
UnorderedList
struct
{
type
UnorderedList
struct
{
BaseBlock
BaseBlock
// Symbol is "*" or "-" or "+".
// Symbol is "*" or "-" or "+".
Symbol
string
Symbol
string
// Indent is the number of spaces.
Indent
int
Children
[]
Node
Children
[]
Node
}
}
...
@@ -143,14 +151,16 @@ func (n *UnorderedList) Restore() string {
...
@@ -143,14 +151,16 @@ func (n *UnorderedList) Restore() string {
for
_
,
child
:=
range
n
.
Children
{
for
_
,
child
:=
range
n
.
Children
{
result
+=
child
.
Restore
()
result
+=
child
.
Restore
()
}
}
return
fmt
.
Sprintf
(
"%s
%s"
,
n
.
Symbol
,
result
)
return
fmt
.
Sprintf
(
"%s
%s %s"
,
strings
.
Repeat
(
" "
,
n
.
Indent
)
,
n
.
Symbol
,
result
)
}
}
type
TaskList
struct
{
type
TaskList
struct
{
BaseBlock
BaseBlock
// Symbol is "*" or "-" or "+".
// Symbol is "*" or "-" or "+".
Symbol
string
Symbol
string
// Indent is the number of spaces.
Indent
int
Complete
bool
Complete
bool
Children
[]
Node
Children
[]
Node
}
}
...
@@ -168,7 +178,7 @@ func (n *TaskList) Restore() string {
...
@@ -168,7 +178,7 @@ func (n *TaskList) Restore() string {
if
n
.
Complete
{
if
n
.
Complete
{
complete
=
"x"
complete
=
"x"
}
}
return
fmt
.
Sprintf
(
"%s
[%s] %s"
,
n
.
Symbol
,
complete
,
result
)
return
fmt
.
Sprintf
(
"%s
%s [%s] %s"
,
strings
.
Repeat
(
" "
,
n
.
Indent
)
,
n
.
Symbol
,
complete
,
result
)
}
}
type
MathBlock
struct
{
type
MathBlock
struct
{
...
...
plugin/gomark/parser/ordered_list.go
View file @
98762be1
...
@@ -17,12 +17,22 @@ func (*OrderedListParser) Match(tokens []*tokenizer.Token) (int, bool) {
...
@@ -17,12 +17,22 @@ func (*OrderedListParser) Match(tokens []*tokenizer.Token) (int, bool) {
if
len
(
tokens
)
<
4
{
if
len
(
tokens
)
<
4
{
return
0
,
false
return
0
,
false
}
}
if
tokens
[
0
]
.
Type
!=
tokenizer
.
Number
||
tokens
[
1
]
.
Type
!=
tokenizer
.
Dot
||
tokens
[
2
]
.
Type
!=
tokenizer
.
Space
{
indent
:=
0
for
_
,
token
:=
range
tokens
{
if
token
.
Type
==
tokenizer
.
Space
{
indent
++
}
else
{
break
}
}
corsor
:=
indent
if
tokens
[
corsor
]
.
Type
!=
tokenizer
.
Number
||
tokens
[
corsor
+
1
]
.
Type
!=
tokenizer
.
Dot
||
tokens
[
corsor
+
2
]
.
Type
!=
tokenizer
.
Space
{
return
0
,
false
return
0
,
false
}
}
contentTokens
:=
[]
*
tokenizer
.
Token
{}
contentTokens
:=
[]
*
tokenizer
.
Token
{}
for
_
,
token
:=
range
tokens
[
3
:
]
{
for
_
,
token
:=
range
tokens
[
corsor
+
3
:
]
{
if
token
.
Type
==
tokenizer
.
Newline
{
if
token
.
Type
==
tokenizer
.
Newline
{
break
break
}
}
...
@@ -33,7 +43,7 @@ func (*OrderedListParser) Match(tokens []*tokenizer.Token) (int, bool) {
...
@@ -33,7 +43,7 @@ func (*OrderedListParser) Match(tokens []*tokenizer.Token) (int, bool) {
return
0
,
false
return
0
,
false
}
}
return
len
(
contentTokens
)
+
3
,
true
return
indent
+
len
(
contentTokens
)
+
3
,
true
}
}
func
(
p
*
OrderedListParser
)
Parse
(
tokens
[]
*
tokenizer
.
Token
)
(
ast
.
Node
,
error
)
{
func
(
p
*
OrderedListParser
)
Parse
(
tokens
[]
*
tokenizer
.
Token
)
(
ast
.
Node
,
error
)
{
...
@@ -42,13 +52,22 @@ func (p *OrderedListParser) Parse(tokens []*tokenizer.Token) (ast.Node, error) {
...
@@ -42,13 +52,22 @@ func (p *OrderedListParser) Parse(tokens []*tokenizer.Token) (ast.Node, error) {
return
nil
,
errors
.
New
(
"not matched"
)
return
nil
,
errors
.
New
(
"not matched"
)
}
}
contentTokens
:=
tokens
[
3
:
size
]
indent
:=
0
for
_
,
token
:=
range
tokens
{
if
token
.
Type
==
tokenizer
.
Space
{
indent
++
}
else
{
break
}
}
contentTokens
:=
tokens
[
indent
+
3
:
size
]
children
,
err
:=
ParseInline
(
contentTokens
)
children
,
err
:=
ParseInline
(
contentTokens
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
&
ast
.
OrderedList
{
return
&
ast
.
OrderedList
{
Number
:
tokens
[
0
]
.
Value
,
Number
:
tokens
[
indent
]
.
Value
,
Indent
:
indent
,
Children
:
children
,
Children
:
children
,
},
nil
},
nil
}
}
plugin/gomark/parser/ordered_list_test.go
View file @
98762be1
...
@@ -30,6 +30,18 @@ func TestOrderedListParser(t *testing.T) {
...
@@ -30,6 +30,18 @@ func TestOrderedListParser(t *testing.T) {
},
},
},
},
},
},
{
text
:
" 1. Hello World"
,
node
:
&
ast
.
OrderedList
{
Number
:
"1"
,
Indent
:
2
,
Children
:
[]
ast
.
Node
{
&
ast
.
Text
{
Content
:
"Hello World"
,
},
},
},
},
{
{
text
:
"1aa. Hello World"
,
text
:
"1aa. Hello World"
,
node
:
nil
,
node
:
nil
,
...
...
plugin/gomark/parser/paragraph.go
View file @
98762be1
...
@@ -26,9 +26,6 @@ func (*ParagraphParser) Match(tokens []*tokenizer.Token) (int, bool) {
...
@@ -26,9 +26,6 @@ func (*ParagraphParser) Match(tokens []*tokenizer.Token) (int, bool) {
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
}
}
...
...
plugin/gomark/parser/task_list.go
View file @
98762be1
...
@@ -18,22 +18,30 @@ func (*TaskListParser) Match(tokens []*tokenizer.Token) (int, bool) {
...
@@ -18,22 +18,30 @@ func (*TaskListParser) Match(tokens []*tokenizer.Token) (int, bool) {
return
0
,
false
return
0
,
false
}
}
symbolToken
:=
tokens
[
0
]
indent
:=
0
for
_
,
token
:=
range
tokens
{
if
token
.
Type
==
tokenizer
.
Space
{
indent
++
}
else
{
break
}
}
symbolToken
:=
tokens
[
indent
]
if
symbolToken
.
Type
!=
tokenizer
.
Hyphen
&&
symbolToken
.
Type
!=
tokenizer
.
Asterisk
&&
symbolToken
.
Type
!=
tokenizer
.
PlusSign
{
if
symbolToken
.
Type
!=
tokenizer
.
Hyphen
&&
symbolToken
.
Type
!=
tokenizer
.
Asterisk
&&
symbolToken
.
Type
!=
tokenizer
.
PlusSign
{
return
0
,
false
return
0
,
false
}
}
if
tokens
[
1
]
.
Type
!=
tokenizer
.
Space
{
if
tokens
[
indent
+
1
]
.
Type
!=
tokenizer
.
Space
{
return
0
,
false
return
0
,
false
}
}
if
tokens
[
2
]
.
Type
!=
tokenizer
.
LeftSquareBracket
||
(
tokens
[
3
]
.
Type
!=
tokenizer
.
Space
&&
tokens
[
3
]
.
Value
!=
"x"
)
||
tokens
[
4
]
.
Type
!=
tokenizer
.
RightSquareBracket
{
if
tokens
[
indent
+
2
]
.
Type
!=
tokenizer
.
LeftSquareBracket
||
(
tokens
[
indent
+
3
]
.
Type
!=
tokenizer
.
Space
&&
tokens
[
indent
+
3
]
.
Value
!=
"x"
)
||
tokens
[
indent
+
4
]
.
Type
!=
tokenizer
.
RightSquareBracket
{
return
0
,
false
return
0
,
false
}
}
if
tokens
[
5
]
.
Type
!=
tokenizer
.
Space
{
if
tokens
[
indent
+
5
]
.
Type
!=
tokenizer
.
Space
{
return
0
,
false
return
0
,
false
}
}
contentTokens
:=
[]
*
tokenizer
.
Token
{}
contentTokens
:=
[]
*
tokenizer
.
Token
{}
for
_
,
token
:=
range
tokens
[
6
:
]
{
for
_
,
token
:=
range
tokens
[
indent
+
6
:
]
{
if
token
.
Type
==
tokenizer
.
Newline
{
if
token
.
Type
==
tokenizer
.
Newline
{
break
break
}
}
...
@@ -43,7 +51,7 @@ func (*TaskListParser) Match(tokens []*tokenizer.Token) (int, bool) {
...
@@ -43,7 +51,7 @@ func (*TaskListParser) Match(tokens []*tokenizer.Token) (int, bool) {
return
0
,
false
return
0
,
false
}
}
return
len
(
contentTokens
)
+
6
,
true
return
indent
+
len
(
contentTokens
)
+
6
,
true
}
}
func
(
p
*
TaskListParser
)
Parse
(
tokens
[]
*
tokenizer
.
Token
)
(
ast
.
Node
,
error
)
{
func
(
p
*
TaskListParser
)
Parse
(
tokens
[]
*
tokenizer
.
Token
)
(
ast
.
Node
,
error
)
{
...
@@ -52,15 +60,24 @@ func (p *TaskListParser) Parse(tokens []*tokenizer.Token) (ast.Node, error) {
...
@@ -52,15 +60,24 @@ func (p *TaskListParser) Parse(tokens []*tokenizer.Token) (ast.Node, error) {
return
nil
,
errors
.
New
(
"not matched"
)
return
nil
,
errors
.
New
(
"not matched"
)
}
}
symbolToken
:=
tokens
[
0
]
indent
:=
0
contentTokens
:=
tokens
[
6
:
size
]
for
_
,
token
:=
range
tokens
{
if
token
.
Type
==
tokenizer
.
Space
{
indent
++
}
else
{
break
}
}
symbolToken
:=
tokens
[
indent
]
contentTokens
:=
tokens
[
indent
+
6
:
size
]
children
,
err
:=
ParseInline
(
contentTokens
)
children
,
err
:=
ParseInline
(
contentTokens
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
&
ast
.
TaskList
{
return
&
ast
.
TaskList
{
Symbol
:
symbolToken
.
Type
,
Symbol
:
symbolToken
.
Type
,
Complete
:
tokens
[
3
]
.
Value
==
"x"
,
Indent
:
indent
,
Complete
:
tokens
[
indent
+
3
]
.
Value
==
"x"
,
Children
:
children
,
Children
:
children
,
},
nil
},
nil
}
}
plugin/gomark/parser/task_list_test.go
View file @
98762be1
...
@@ -31,6 +31,19 @@ func TestTaskListParser(t *testing.T) {
...
@@ -31,6 +31,19 @@ func TestTaskListParser(t *testing.T) {
},
},
},
},
},
},
{
text
:
" + [ ] Hello World"
,
node
:
&
ast
.
TaskList
{
Symbol
:
tokenizer
.
PlusSign
,
Indent
:
2
,
Complete
:
false
,
Children
:
[]
ast
.
Node
{
&
ast
.
Text
{
Content
:
"Hello World"
,
},
},
},
},
{
{
text
:
"* [x] **Hello**"
,
text
:
"* [x] **Hello**"
,
node
:
&
ast
.
TaskList
{
node
:
&
ast
.
TaskList
{
...
...
plugin/gomark/parser/unordered_list.go
View file @
98762be1
...
@@ -17,13 +17,23 @@ func (*UnorderedListParser) Match(tokens []*tokenizer.Token) (int, bool) {
...
@@ -17,13 +17,23 @@ func (*UnorderedListParser) Match(tokens []*tokenizer.Token) (int, bool) {
if
len
(
tokens
)
<
3
{
if
len
(
tokens
)
<
3
{
return
0
,
false
return
0
,
false
}
}
symbolToken
:=
tokens
[
0
]
if
(
symbolToken
.
Type
!=
tokenizer
.
Hyphen
&&
symbolToken
.
Type
!=
tokenizer
.
Asterisk
&&
symbolToken
.
Type
!=
tokenizer
.
PlusSign
)
||
tokens
[
1
]
.
Type
!=
tokenizer
.
Space
{
indent
:=
0
for
_
,
token
:=
range
tokens
{
if
token
.
Type
==
tokenizer
.
Space
{
indent
++
}
else
{
break
}
}
corsor
:=
indent
symbolToken
:=
tokens
[
corsor
]
if
(
symbolToken
.
Type
!=
tokenizer
.
Hyphen
&&
symbolToken
.
Type
!=
tokenizer
.
Asterisk
&&
symbolToken
.
Type
!=
tokenizer
.
PlusSign
)
||
tokens
[
corsor
+
1
]
.
Type
!=
tokenizer
.
Space
{
return
0
,
false
return
0
,
false
}
}
contentTokens
:=
[]
*
tokenizer
.
Token
{}
contentTokens
:=
[]
*
tokenizer
.
Token
{}
for
_
,
token
:=
range
tokens
[
2
:
]
{
for
_
,
token
:=
range
tokens
[
corsor
+
2
:
]
{
if
token
.
Type
==
tokenizer
.
Newline
{
if
token
.
Type
==
tokenizer
.
Newline
{
break
break
}
}
...
@@ -33,7 +43,7 @@ func (*UnorderedListParser) Match(tokens []*tokenizer.Token) (int, bool) {
...
@@ -33,7 +43,7 @@ func (*UnorderedListParser) Match(tokens []*tokenizer.Token) (int, bool) {
return
0
,
false
return
0
,
false
}
}
return
len
(
contentTokens
)
+
2
,
true
return
indent
+
len
(
contentTokens
)
+
2
,
true
}
}
func
(
p
*
UnorderedListParser
)
Parse
(
tokens
[]
*
tokenizer
.
Token
)
(
ast
.
Node
,
error
)
{
func
(
p
*
UnorderedListParser
)
Parse
(
tokens
[]
*
tokenizer
.
Token
)
(
ast
.
Node
,
error
)
{
...
@@ -42,14 +52,23 @@ func (p *UnorderedListParser) Parse(tokens []*tokenizer.Token) (ast.Node, error)
...
@@ -42,14 +52,23 @@ func (p *UnorderedListParser) Parse(tokens []*tokenizer.Token) (ast.Node, error)
return
nil
,
errors
.
New
(
"not matched"
)
return
nil
,
errors
.
New
(
"not matched"
)
}
}
symbolToken
:=
tokens
[
0
]
indent
:=
0
contentTokens
:=
tokens
[
2
:
size
]
for
_
,
token
:=
range
tokens
{
if
token
.
Type
==
tokenizer
.
Space
{
indent
++
}
else
{
break
}
}
symbolToken
:=
tokens
[
indent
]
contentTokens
:=
tokens
[
indent
+
2
:
size
]
children
,
err
:=
ParseInline
(
contentTokens
)
children
,
err
:=
ParseInline
(
contentTokens
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
&
ast
.
UnorderedList
{
return
&
ast
.
UnorderedList
{
Symbol
:
symbolToken
.
Type
,
Symbol
:
symbolToken
.
Type
,
Indent
:
indent
,
Children
:
children
,
Children
:
children
,
},
nil
},
nil
}
}
proto/api/v2/markdown_service.proto
View file @
98762be1
...
@@ -103,18 +103,21 @@ message BlockquoteNode {
...
@@ -103,18 +103,21 @@ message BlockquoteNode {
message
OrderedListNode
{
message
OrderedListNode
{
string
number
=
1
;
string
number
=
1
;
repeated
Node
children
=
2
;
int32
indent
=
2
;
repeated
Node
children
=
3
;
}
}
message
UnorderedListNode
{
message
UnorderedListNode
{
string
symbol
=
1
;
string
symbol
=
1
;
repeated
Node
children
=
2
;
int32
indent
=
2
;
repeated
Node
children
=
3
;
}
}
message
TaskListNode
{
message
TaskListNode
{
string
symbol
=
1
;
string
symbol
=
1
;
bool
complete
=
2
;
int32
indent
=
2
;
repeated
Node
children
=
3
;
bool
complete
=
3
;
repeated
Node
children
=
4
;
}
}
message
MathBlockNode
{
message
MathBlockNode
{
...
...
proto/gen/api/v2/README.md
View file @
98762be1
...
@@ -1233,6 +1233,7 @@
...
@@ -1233,6 +1233,7 @@
| Field | Type | Label | Description |
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| ----- | ---- | ----- | ----------- |
| number |
[
string
](
#string
)
| | |
| number |
[
string
](
#string
)
| | |
| indent |
[
int32
](
#int32
)
| | |
| children |
[
Node
](
#memos-api-v2-Node
)
| repeated | |
| children |
[
Node
](
#memos-api-v2-Node
)
| repeated | |
...
@@ -1324,6 +1325,7 @@
...
@@ -1324,6 +1325,7 @@
| Field | Type | Label | Description |
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| ----- | ---- | ----- | ----------- |
| symbol |
[
string
](
#string
)
| | |
| symbol |
[
string
](
#string
)
| | |
| indent |
[
int32
](
#int32
)
| | |
| complete |
[
bool
](
#bool
)
| | |
| complete |
[
bool
](
#bool
)
| | |
| children |
[
Node
](
#memos-api-v2-Node
)
| repeated | |
| children |
[
Node
](
#memos-api-v2-Node
)
| repeated | |
...
@@ -1356,6 +1358,7 @@
...
@@ -1356,6 +1358,7 @@
| Field | Type | Label | Description |
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| ----- | ---- | ----- | ----------- |
| symbol |
[
string
](
#string
)
| | |
| symbol |
[
string
](
#string
)
| | |
| indent |
[
int32
](
#int32
)
| | |
| children |
[
Node
](
#memos-api-v2-Node
)
| repeated | |
| children |
[
Node
](
#memos-api-v2-Node
)
| repeated | |
...
...
proto/gen/api/v2/markdown_service.pb.go
View file @
98762be1
This diff is collapsed.
Click to expand it.
web/src/components/MemoContent/OrderedList.tsx
View file @
98762be1
import
{
repeat
}
from
"lodash-es"
;
import
{
Node
}
from
"@/types/proto/api/v2/markdown_service"
;
import
{
Node
}
from
"@/types/proto/api/v2/markdown_service"
;
import
Renderer
from
"./Renderer"
;
import
Renderer
from
"./Renderer"
;
import
{
BaseProps
}
from
"./types"
;
import
{
BaseProps
}
from
"./types"
;
interface
Props
extends
BaseProps
{
interface
Props
extends
BaseProps
{
number
:
string
;
number
:
string
;
indent
:
number
;
children
:
Node
[];
children
:
Node
[];
}
}
const
OrderedList
:
React
.
FC
<
Props
>
=
({
number
,
children
}:
Props
)
=>
{
const
OrderedList
:
React
.
FC
<
Props
>
=
({
number
,
indent
,
children
}:
Props
)
=>
{
return
(
return
(
<
ol
>
<
ol
>
<
li
className=
"
grid grid-cols-[24px_1fr] gap-1
"
>
<
li
className=
"
w-full flex flex-row
"
>
<
div
className=
"
w-7 h-6 flex justify-center items-center
"
>
<
div
className=
"
block font-mono shrink-0
"
>
<
span
className=
"opacity-80"
>
{
number
}
.
</
span
>
<
span
>
{
repeat
(
" "
,
indent
)
}
</
span
>
</
div
>
</
div
>
<
div
>
<
div
className=
"w-auto grid grid-cols-[24px_1fr] gap-1"
>
{
children
.
map
((
child
,
index
)
=>
(
<
div
className=
"w-7 h-6 flex justify-center items-center"
>
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>
<
span
className=
"opacity-80"
>
{
number
}
.
</
span
>
))
}
</
div
>
<
div
>
{
children
.
map
((
child
,
index
)
=>
(
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>
))
}
</
div
>
</
div
>
</
div
>
</
li
>
</
li
>
</
ol
>
</
ol
>
...
...
web/src/components/MemoContent/TaskList.tsx
View file @
98762be1
import
{
Checkbox
}
from
"@mui/joy"
;
import
{
Checkbox
}
from
"@mui/joy"
;
import
classNames
from
"classnames"
;
import
{
repeat
}
from
"lodash-es"
;
import
{
useContext
}
from
"react"
;
import
{
useContext
}
from
"react"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
Node
,
NodeType
}
from
"@/types/proto/api/v2/markdown_service"
;
import
{
Node
,
NodeType
}
from
"@/types/proto/api/v2/markdown_service"
;
...
@@ -8,11 +10,12 @@ import { RendererContext } from "./types";
...
@@ -8,11 +10,12 @@ import { RendererContext } from "./types";
interface
Props
{
interface
Props
{
index
:
string
;
index
:
string
;
symbol
:
string
;
symbol
:
string
;
indent
:
number
;
complete
:
boolean
;
complete
:
boolean
;
children
:
Node
[];
children
:
Node
[];
}
}
const
TaskList
:
React
.
FC
<
Props
>
=
({
index
,
complete
,
children
}:
Props
)
=>
{
const
TaskList
:
React
.
FC
<
Props
>
=
({
index
,
indent
,
complete
,
children
}:
Props
)
=>
{
const
context
=
useContext
(
RendererContext
);
const
context
=
useContext
(
RendererContext
);
const
memoStore
=
useMemoStore
();
const
memoStore
=
useMemoStore
();
...
@@ -43,14 +46,19 @@ const TaskList: React.FC<Props> = ({ index, complete, children }: Props) => {
...
@@ -43,14 +46,19 @@ const TaskList: React.FC<Props> = ({ index, complete, children }: Props) => {
return
(
return
(
<
ul
>
<
ul
>
<
li
className=
"
grid grid-cols-[24px_1fr] gap-1
"
>
<
li
className=
"
w-full flex flex-row
"
>
<
div
className=
"
w-7 h-6 flex justify-center items-center
"
>
<
div
className=
"
block font-mono shrink-0
"
>
<
Checkbox
size=
"sm"
checked=
{
complete
}
disabled=
{
context
.
readonly
}
onChange=
{
(
e
)
=>
handleCheckboxChange
(
e
.
target
.
checked
)
}
/
>
<
span
>
{
repeat
(
" "
,
indent
)
}
</
span
>
</
div
>
</
div
>
<
div
>
<
div
className=
"w-auto grid grid-cols-[24px_1fr] gap-1"
>
{
children
.
map
((
child
,
subIndex
)
=>
(
<
div
className=
"w-7 h-6 flex justify-center items-center"
>
<
Renderer
key=
{
`${child.type}-${subIndex}`
}
index=
{
`${index}-${subIndex}`
}
node=
{
child
}
/>
<
Checkbox
size=
"sm"
checked=
{
complete
}
disabled=
{
context
.
readonly
}
onChange=
{
(
e
)
=>
handleCheckboxChange
(
e
.
target
.
checked
)
}
/>
))
}
</
div
>
<
div
className=
{
classNames
(
complete
&&
"line-through opacity-80"
)
}
>
{
children
.
map
((
child
,
index
)
=>
(
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>
))
}
</
div
>
</
div
>
</
div
>
</
li
>
</
li
>
</
ul
>
</
ul
>
...
...
web/src/components/MemoContent/UnorderedList.tsx
View file @
98762be1
import
{
repeat
}
from
"lodash-es"
;
import
{
Node
}
from
"@/types/proto/api/v2/markdown_service"
;
import
{
Node
}
from
"@/types/proto/api/v2/markdown_service"
;
import
Renderer
from
"./Renderer"
;
import
Renderer
from
"./Renderer"
;
interface
Props
{
interface
Props
{
symbol
:
string
;
symbol
:
string
;
indent
:
number
;
children
:
Node
[];
children
:
Node
[];
}
}
const
UnorderedList
:
React
.
FC
<
Props
>
=
({
children
}:
Props
)
=>
{
const
UnorderedList
:
React
.
FC
<
Props
>
=
({
indent
,
children
}:
Props
)
=>
{
return
(
return
(
<
ul
>
<
ul
>
<
li
className=
"
grid grid-cols-[24px_1fr] gap-1
"
>
<
li
className=
"
w-full flex flex-row
"
>
<
div
className=
"
w-7 h-6 flex justify-center items-center
"
>
<
div
className=
"
block font-mono shrink-0
"
>
<
span
className=
"opacity-80"
>
•
</
span
>
<
span
>
{
repeat
(
" "
,
indent
)
}
</
span
>
</
div
>
</
div
>
<
div
>
<
div
className=
"w-auto grid grid-cols-[24px_1fr] gap-1"
>
{
children
.
map
((
child
,
index
)
=>
(
<
div
className=
"w-7 h-6 flex justify-center items-center"
>
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>
<
span
className=
"opacity-80"
>
•
</
span
>
))
}
</
div
>
<
div
>
{
children
.
map
((
child
,
index
)
=>
(
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>
))
}
</
div
>
</
div
>
</
div
>
</
li
>
</
li
>
</
ul
>
</
ul
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment