diff --git a/_test/extra.txt b/_test/extra.txt
index c6e84c7..5e2386f 100644
--- a/_test/extra.txt
+++ b/_test/extra.txt
@@ -614,3 +614,28 @@ a
b
//= = = = = = = = = = = = = = = = = = = = = = = =//
+
+
+49: A list item that is indented up to 3 spaces after an empty list item
+//- - - - - - - - -//
+1.
+
+ 1. b
+
+-
+
+ - b
+//- - - - - - - - -//
+
+
+-
+
b
+
+
+
+//= = = = = = = = = = = = = = = = = = = = = = = =//
diff --git a/parser/list.go b/parser/list.go
index a6edc25..2a1c03a 100644
--- a/parser/list.go
+++ b/parser/list.go
@@ -16,6 +16,10 @@ const (
orderedList
)
+var skipListParserKey = NewContextKey()
+var emptyListItemWithBlankLines = NewContextKey()
+var listItemFlagValue interface{} = true
+
// Same as
// `^(([ ]*)([\-\*\+]))(\s+.*)?\n?$`.FindSubmatchIndex or
// `^(([ ]*)(\d{1,9}[\.\)]))(\s+.*)?\n?$`.FindSubmatchIndex
@@ -123,8 +127,8 @@ func (b *listParser) Trigger() []byte {
func (b *listParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State) {
last := pc.LastOpenedBlock().Node
- if _, lok := last.(*ast.List); lok || pc.Get(skipListParser) != nil {
- pc.Set(skipListParser, nil)
+ if _, lok := last.(*ast.List); lok || pc.Get(skipListParserKey) != nil {
+ pc.Set(skipListParserKey, nil)
return nil, NoChildren
}
line, _ := reader.PeekLine()
@@ -154,24 +158,18 @@ func (b *listParser) Open(parent ast.Node, reader text.Reader, pc Context) (ast.
if start > -1 {
node.Start = start
}
+ pc.Set(emptyListItemWithBlankLines, nil)
return node, HasChildren
}
func (b *listParser) Continue(node ast.Node, reader text.Reader, pc Context) State {
list := node.(*ast.List)
line, _ := reader.PeekLine()
- startsWithBlankLines := util.IsBlank(line)
- if startsWithBlankLines {
- if node.LastChild().ChildCount() != 0 {
- return Continue | HasChildren
- }
- for {
- reader.AdvanceLine()
- line, _ = reader.PeekLine()
- if !util.IsBlank(line) {
- break
- }
+ if util.IsBlank(line) {
+ if node.LastChild().ChildCount() == 0 {
+ pc.Set(emptyListItemWithBlankLines, listItemFlagValue)
}
+ return Continue | HasChildren
}
// "offset" means a width that bar indicates.
@@ -182,10 +180,23 @@ func (b *listParser) Continue(node ast.Node, reader text.Reader, pc Context) Sta
// - a
// - b <--- current line
// it maybe a new child of the list.
+ //
+ // Empty list items can have multiple blanklines
+ //
+ // - <--- 1st item is an empty thus "offset" is unknown
+ //
+ //
+ // - <--- current line
+ //
+ // -> 1 list with 2 blank items
+ //
+ // So if the last item is an empty, it maybe a new child of the list.
+ //
offset := lastOffset(node)
+ lastIsEmpty := node.LastChild().ChildCount() == 0
indent, _ := util.IndentWidth(line, reader.LineOffset())
- if indent < offset {
+ if indent < offset || lastIsEmpty {
if indent < 4 {
match, typ := matchesListItem(line, false) // may have a leading spaces more than 3
if typ != notList && match[1]-offset < 4 {
@@ -207,13 +218,23 @@ func (b *listParser) Continue(node ast.Node, reader text.Reader, pc Context) Sta
return Close
}
}
-
return Continue | HasChildren
}
}
- return Close
+ if !lastIsEmpty {
+ return Close
+ }
}
- if startsWithBlankLines {
+
+ // Non empty items can not exist next to an empty list item
+ // with blank lines. So we need to close the current list
+ //
+ // -
+ //
+ // foo
+ //
+ // -> 1 list with 1 blank items and 1 paragraph
+ if pc.Get(emptyListItemWithBlankLines) != nil {
return Close
}
return Continue | HasChildren
diff --git a/parser/list_item.go b/parser/list_item.go
index 4873bf4..81357a9 100644
--- a/parser/list_item.go
+++ b/parser/list_item.go
@@ -17,9 +17,6 @@ func NewListItemParser() BlockParser {
return defaultListItemParser
}
-var skipListParser = NewContextKey()
-var skipListParserValue interface{} = true
-
func (b *listItemParser) Trigger() []byte {
return []byte{'-', '+', '*', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
}
@@ -38,6 +35,9 @@ func (b *listItemParser) Open(parent ast.Node, reader text.Reader, pc Context) (
if match[1]-offset > 3 {
return nil, NoChildren
}
+
+ pc.Set(emptyListItemWithBlankLines, nil)
+
itemOffset := calcListOffset(line, match)
node := ast.NewListItem(match[3] + itemOffset)
if match[4] < 0 || util.IsBlank(line[match[4]:match[5]]) {
@@ -54,19 +54,22 @@ func (b *listItemParser) Continue(node ast.Node, reader text.Reader, pc Context)
line, _ := reader.PeekLine()
if util.IsBlank(line) {
reader.Advance(len(line) - 1)
-
return Continue | HasChildren
}
- indent, _ := util.IndentWidth(line, reader.LineOffset())
offset := lastOffset(node.Parent())
- if indent < offset && indent < 4 {
+ isEmpty := node.ChildCount() == 0
+ indent, _ := util.IndentWidth(line, reader.LineOffset())
+ if (isEmpty || indent < offset) && indent < 4 {
_, typ := matchesListItem(line, true)
// new list item found
if typ != notList {
- pc.Set(skipListParser, skipListParserValue)
+ pc.Set(skipListParserKey, listItemFlagValue)
+ return Close
+ }
+ if !isEmpty {
+ return Close
}
- return Close
}
pos, padding := util.IndentPosition(line, reader.LineOffset(), offset)
reader.AdvanceAndSetPadding(pos, padding)