Skip to content

Commit

Permalink
feat: add indent to list node
Browse files Browse the repository at this point in the history
  • Loading branch information
boojack committed Sep 19, 2024
1 parent c40262b commit 6a369a0
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 2 deletions.
1 change: 1 addition & 0 deletions ast/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ type List struct {
BaseBlock

Kind ListKind
Indent int
Children []Node
}

Expand Down
44 changes: 42 additions & 2 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,22 +119,45 @@ func mergeListItemNodes(nodes []ast.Node) []ast.Node {
switch nodes[i].(type) {
case *ast.OrderedListItem, *ast.UnorderedListItem, *ast.TaskListItem:
var listKind ast.ListKind
var indent int
switch nodes[i].(type) {

Check failure on line 123 in parser/parser.go

View workflow job for this annotation

GitHub Actions / go-static-checks

typeSwitchVar: 3 cases can benefit from type switch with assignment (gocritic)
case *ast.OrderedListItem:
listKind = ast.OrderedList
indent = nodes[i].(*ast.OrderedListItem).Indent
case *ast.UnorderedListItem:
listKind = ast.UnorderedList
indent = nodes[i].(*ast.UnorderedListItem).Indent
case *ast.TaskListItem:
listKind = ast.DescrpitionList
indent = nodes[i].(*ast.TaskListItem).Indent
}
if prevResultNode == nil || prevResultNode.Type() != ast.ListNode || prevResultNode.(*ast.List).Kind != listKind {
indent = indent / 2

Check failure on line 134 in parser/parser.go

View workflow job for this annotation

GitHub Actions / go-static-checks

assignOp: replace `indent = indent / 2` with `indent /= 2` (gocritic)
if prevResultNode == nil || prevResultNode.Type() != ast.ListNode || prevResultNode.(*ast.List).Kind != listKind || prevResultNode.(*ast.List).Indent > indent {
prevResultNode = &ast.List{
BaseBlock: ast.BaseBlock{},
Kind: listKind,
Indent: indent,
Children: []ast.Node{nodes[i]},
}
result = append(result, prevResultNode)
continue
}

listNode := prevResultNode.(*ast.List)

Check failure on line 146 in parser/parser.go

View workflow job for this annotation

GitHub Actions / go-static-checks

unchecked-type-assertion: type cast result is unchecked in prevResultNode.(*ast.List) - type assertion will panic if not matched (revive)
if listNode.Indent != indent {
parent := findPossibleParent(listNode, indent)
if parent == nil {
parent = &ast.List{
BaseBlock: ast.BaseBlock{},
Kind: listKind,
Indent: indent,
}
listNode.Children = append(listNode.Children, parent)
}
parent.Children = append(parent.Children, nodes[i])
} else {
listNode.Children = append(listNode.Children, nodes[i])
}
prevResultNode.(*ast.List).Children = append(prevResultNode.(*ast.List).Children, nodes[i])
case *ast.LineBreak:
if prevResultNode != nil && prevResultNode.Type() == ast.ListNode &&
// Check if the prev node is not a line break node.
Expand Down Expand Up @@ -166,3 +189,20 @@ func mergeTextNodes(nodes []ast.Node) []ast.Node {
}
return result
}

func findPossibleParent(listNode *ast.List, indent int) *ast.List {
if listNode.Indent == indent {
return listNode
}
if listNode.Indent < indent {
return nil
}
if len(listNode.Children) == 0 {
return nil
}
lastChild := listNode.Children[len(listNode.Children)-1]
if lastChild.Type() != ast.ListNode {
return nil
}
return findPossibleParent(lastChild.(*ast.List), indent)
}
130 changes: 130 additions & 0 deletions parser/tests/list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package tests

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"

"github.com/usememos/gomark/ast"
"github.com/usememos/gomark/parser"
"github.com/usememos/gomark/parser/tokenizer"
)

func TestListParser(t *testing.T) {
tests := []struct {
text string
nodes []ast.Node
}{
{
text: "1. hello\n2. world",
nodes: []ast.Node{
&ast.List{
Kind: ast.OrderedList,
Children: []ast.Node{
&ast.OrderedListItem{
Number: "1",
Children: []ast.Node{
&ast.Text{
Content: "hello",
},
},
},
&ast.LineBreak{},
&ast.OrderedListItem{
Number: "2",
Children: []ast.Node{
&ast.Text{
Content: "world",
},
},
},
},
},
},
},
{
text: "1. hello\n 2. world",
nodes: []ast.Node{
&ast.List{
Kind: ast.OrderedList,
Children: []ast.Node{
&ast.OrderedListItem{
Number: "1",
Children: []ast.Node{
&ast.Text{
Content: "hello",
},
},
},
&ast.LineBreak{},
&ast.List{
Kind: ast.OrderedList,
Indent: 1,
Children: []ast.Node{
&ast.OrderedListItem{
Number: "2",
Indent: 2,
Children: []ast.Node{
&ast.Text{
Content: "world",
},
},
},
},
},
},
},
},
},
{
text: "* hello\n * world\n* gomark",
nodes: []ast.Node{
&ast.List{
Kind: ast.UnorderedList,
Children: []ast.Node{
&ast.UnorderedListItem{
Symbol: "*",
Children: []ast.Node{
&ast.Text{
Content: "hello",
},
},
},
&ast.LineBreak{},
&ast.List{
Kind: ast.UnorderedList,
Indent: 1,
Children: []ast.Node{
&ast.UnorderedListItem{
Symbol: "*",
Indent: 2,
Children: []ast.Node{
&ast.Text{
Content: "world",
},
},
},
},
},
&ast.LineBreak{},
&ast.UnorderedListItem{
Symbol: "*",
Children: []ast.Node{
&ast.Text{
Content: "gomark",
},
},
},
},
},
},
},
}

for _, test := range tests {
tokens := tokenizer.Tokenize(test.text)
nodes, _ := parser.Parse(tokens)
require.Equal(t, test.nodes, nodes, fmt.Sprintf("Test case: %s", test.text))
}
}

0 comments on commit 6a369a0

Please sign in to comment.