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 +//- - - - - - - - -// +
    +
  1. +
  2. +

    b

    +
  3. +
+ +//= = = = = = = = = = = = = = = = = = = = = = = =// 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)