diff options
Diffstat (limited to 'vendor/gitlab.com/golang-commonmark/markdown/parser_block.go')
-rw-r--r-- | vendor/gitlab.com/golang-commonmark/markdown/parser_block.go | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/parser_block.go b/vendor/gitlab.com/golang-commonmark/markdown/parser_block.go new file mode 100644 index 00000000..8a6ee1ad --- /dev/null +++ b/vendor/gitlab.com/golang-commonmark/markdown/parser_block.go @@ -0,0 +1,159 @@ +// 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 ( + "bytes" + "unicode/utf8" +) + +type ParserBlock struct{} + +type BlockRule func(*StateBlock, int, int, bool) bool + +var blockRules []BlockRule + +var nl = []byte{'\n'} + +func normalizeNewlines(src []byte) ([]byte, int) { + if bytes.IndexByte(src, '\r') == -1 { + return src, bytes.Count(src, nl) + } + n := 0 + buf := make([]byte, 0, len(src)) + for i := 0; i < len(src); i++ { + switch ch := src[i]; ch { + case '\n': + n++ + buf = append(buf, '\n') + case '\r': + buf = append(buf, '\n') + n++ + if i < len(src)-1 && src[i+1] == '\n' { + i++ + } + default: + buf = append(buf, ch) + } + } + return buf, n +} + +func (b ParserBlock) Parse(src []byte, md *Markdown, env *Environment) []Token { + src, n := normalizeNewlines(src) + if len(src) == 0 || src[len(src)-1] != '\n' { + n++ + } + n++ + + indentFound := false + start := 0 + indent := 0 + offset := 0 + + mem := make([]int, 0, n*5) + bMarks := mem[0:0:n] + eMarks := mem[n : n : n*2] + tShift := mem[n*2 : n*2 : n*3] + sCount := mem[n*3 : n*3 : n*4] + bsCount := mem[n*4 : n*4 : n*5] + + _, lastRuneLen := utf8.DecodeLastRune(src) + lastRunePos := len(src) - lastRuneLen + for pos, r := range string(src) { + if !indentFound { + if runeIsSpace(r) { + indent++ + if r == '\t' { + offset += 4 - offset%4 + } else { + offset++ + } + continue + } + indentFound = true + } + + if r == '\n' || pos == lastRunePos { + if r != '\n' { + pos = len(src) + } + bMarks = append(bMarks, start) + eMarks = append(eMarks, pos) + tShift = append(tShift, indent) + sCount = append(sCount, offset) + bsCount = append(bsCount, 0) + + indentFound = false + indent = 0 + offset = 0 + start = pos + 1 + } + } + + bMarks = append(bMarks, len(src)) + eMarks = append(eMarks, len(src)) + tShift = append(tShift, 0) + sCount = append(sCount, 0) + bsCount = append(bsCount, 0) + + var s StateBlock + s.BMarks = bMarks + s.EMarks = eMarks + s.TShift = tShift + s.SCount = sCount + s.BSCount = bsCount + s.LineMax = n - 1 + s.Src = string(src) + s.Md = md + s.Env = env + + b.Tokenize(&s, s.Line, s.LineMax) + + return s.Tokens +} + +func (ParserBlock) Tokenize(s *StateBlock, startLine, endLine int) { + line := startLine + hasEmptyLines := false + maxNesting := s.Md.MaxNesting + + for line < endLine { + line = s.SkipEmptyLines(line) + s.Line = line + if line >= endLine { + break + } + + if s.SCount[line] < s.BlkIndent { + break + } + + if s.Level >= maxNesting { + s.Line = endLine + break + } + + for _, r := range blockRules { + if r(s, line, endLine, false) { + break + } + } + + s.Tight = !hasEmptyLines + + if s.IsLineEmpty(s.Line - 1) { + hasEmptyLines = true + } + + line = s.Line + + if line < endLine && s.IsLineEmpty(line) { + hasEmptyLines = true + line++ + s.Line = line + } + } +} |