summaryrefslogtreecommitdiffstats
path: root/vendor/gitlab.com/golang-commonmark/markdown/list.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gitlab.com/golang-commonmark/markdown/list.go')
-rw-r--r--vendor/gitlab.com/golang-commonmark/markdown/list.go285
1 files changed, 285 insertions, 0 deletions
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/list.go b/vendor/gitlab.com/golang-commonmark/markdown/list.go
new file mode 100644
index 00000000..3b2e0230
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/list.go
@@ -0,0 +1,285 @@
+// Copyright 2015 The Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package markdown
+
+import "strconv"
+
+var listTerminatedBy []BlockRule
+
+func skipBulletListMarker(s *StateBlock, startLine int) int {
+ pos := s.BMarks[startLine] + s.TShift[startLine]
+ max := s.EMarks[startLine]
+ src := s.Src
+
+ if pos >= max {
+ return -1
+ }
+
+ marker := src[pos]
+ if marker != '*' && marker != '-' && marker != '+' {
+ return -1
+ }
+ pos++
+
+ if pos < max && !byteIsSpace(src[pos]) {
+ return -1
+ }
+
+ return pos
+}
+
+func skipOrderedListMarker(s *StateBlock, startLine int) int {
+ start := s.BMarks[startLine] + s.TShift[startLine]
+ pos := start
+ max := s.EMarks[startLine]
+
+ if pos+1 >= max {
+ return -1
+ }
+
+ src := s.Src
+ ch := src[pos]
+ if ch < '0' || ch > '9' {
+ return -1
+ }
+ pos++
+
+ for {
+ if pos >= max {
+ return -1
+ }
+
+ ch = src[pos]
+ pos++
+
+ if ch >= '0' && ch <= '9' {
+ if pos-start >= 10 {
+ return -1
+ }
+ continue
+ }
+
+ if ch == ')' || ch == '.' {
+ break
+ }
+
+ return -1
+ }
+
+ if pos < max && !byteIsSpace(src[pos]) {
+ return -1
+ }
+
+ return pos
+}
+
+func markParagraphsTight(s *StateBlock, idx int) {
+ level := s.Level + 2
+ tokens := s.Tokens
+
+ for i := idx + 2; i < len(tokens)-2; i++ {
+ if tokens[i].Level() == level {
+ if tok, ok := tokens[i].(*ParagraphOpen); ok {
+ tok.Hidden = true
+ i += 2
+ tokens[i].(*ParagraphClose).Hidden = true
+ }
+ }
+ }
+}
+
+func ruleList(s *StateBlock, startLine, endLine int, silent bool) bool {
+ isTerminatingParagraph := false
+ tight := true
+
+ if s.SCount[startLine]-s.BlkIndent >= 4 {
+ return false
+ }
+ src := s.Src
+
+ if silent && s.ParentType == ptParagraph {
+ if s.TShift[startLine] >= s.BlkIndent {
+ isTerminatingParagraph = true
+ }
+ }
+
+ var start int
+ var markerValue int
+
+ isOrdered := false
+ posAfterMarker := skipOrderedListMarker(s, startLine)
+ if posAfterMarker > 0 {
+ isOrdered = true
+ start = s.BMarks[startLine] + s.TShift[startLine]
+ markerValue, _ = strconv.Atoi(src[start : posAfterMarker-1])
+
+ if isTerminatingParagraph && markerValue != 1 {
+ return false
+ }
+ } else {
+ posAfterMarker = skipBulletListMarker(s, startLine)
+ if posAfterMarker < 0 {
+ return false
+ }
+ }
+
+ if isTerminatingParagraph {
+ if s.SkipSpaces(posAfterMarker) >= s.EMarks[startLine] {
+ return false
+ }
+ }
+
+ markerChar := src[posAfterMarker-1]
+
+ if silent {
+ return true
+ }
+
+ tokenIdx := len(s.Tokens)
+
+ var listMap *[2]int
+ if isOrdered {
+ tok := &OrderedListOpen{
+ Order: markerValue,
+ Map: [2]int{startLine, 0},
+ }
+ s.PushOpeningToken(tok)
+ listMap = &tok.Map
+ } else {
+ tok := &BulletListOpen{
+ Map: [2]int{startLine, 0},
+ }
+ s.PushOpeningToken(tok)
+ listMap = &tok.Map
+ }
+
+ nextLine := startLine
+ prevEmptyEnd := false
+
+ oldParentType := s.ParentType
+ s.ParentType = ptList
+
+ var pos int
+ var contentStart int
+
+outer:
+ for nextLine < endLine {
+ pos = posAfterMarker
+ max := s.EMarks[nextLine]
+
+ initial := s.SCount[nextLine] + posAfterMarker - (s.BMarks[startLine] + s.TShift[startLine])
+ offset := initial
+
+ loop:
+ for pos < max {
+ switch src[pos] {
+ case '\t':
+ offset += 4 - (offset+s.BSCount[nextLine])%4
+ case ' ':
+ offset++
+ default:
+ break loop
+ }
+ pos++
+ }
+
+ contentStart = pos
+
+ indentAfterMarker := 1
+ if contentStart < max {
+ if iam := offset - initial; iam <= 4 {
+ indentAfterMarker = iam
+ }
+ }
+
+ indent := initial + indentAfterMarker
+
+ tok := &ListItemOpen{
+ Map: [2]int{startLine, 0},
+ }
+ s.PushOpeningToken(tok)
+ itemMap := &tok.Map
+
+ oldIndent := s.BlkIndent
+ oldTight := s.Tight
+ oldTShift := s.TShift[startLine]
+ oldLIndent := s.SCount[startLine]
+ s.BlkIndent = indent
+ s.Tight = true
+ s.TShift[startLine] = contentStart - s.BMarks[startLine]
+ s.SCount[startLine] = offset
+
+ if contentStart >= max && s.IsLineEmpty(startLine+1) {
+ s.Line = min(s.Line+2, endLine)
+ } else {
+ s.Md.Block.Tokenize(s, startLine, endLine)
+ }
+
+ if !s.Tight || prevEmptyEnd {
+ tight = false
+ }
+
+ prevEmptyEnd = s.Line-startLine > 1 && s.IsLineEmpty(s.Line-1)
+
+ s.BlkIndent = oldIndent
+ s.TShift[startLine] = oldTShift
+ s.SCount[startLine] = oldLIndent
+ s.Tight = oldTight
+
+ s.PushClosingToken(&ListItemClose{})
+
+ startLine = s.Line
+ nextLine = startLine
+ (*itemMap)[1] = nextLine
+
+ if nextLine >= endLine {
+ break
+ }
+
+ contentStart = s.BMarks[startLine]
+
+ if s.SCount[nextLine] < s.BlkIndent {
+ break
+ }
+
+ for _, r := range listTerminatedBy {
+ if r(s, nextLine, endLine, true) {
+ break outer
+ }
+ }
+
+ if isOrdered {
+ posAfterMarker = skipOrderedListMarker(s, nextLine)
+ if posAfterMarker < 0 {
+ break
+ }
+ } else {
+ posAfterMarker = skipBulletListMarker(s, nextLine)
+ if posAfterMarker < 0 {
+ break
+ }
+ }
+
+ if markerChar != src[posAfterMarker-1] {
+ break
+ }
+ }
+
+ if isOrdered {
+ s.PushClosingToken(&OrderedListClose{})
+ } else {
+ s.PushClosingToken(&BulletListClose{})
+ }
+
+ (*listMap)[1] = nextLine
+ s.Line = nextLine
+ s.ParentType = oldParentType
+
+ if tight {
+ markParagraphsTight(s, tokenIdx)
+ }
+
+ return true
+}