From 04567c765e92ad60c685c1b2fe7e77c46e065645 Mon Sep 17 00:00:00 2001
From: Wim
` | false
+ XHTMLOutput | bool | whether to output XHTML instead of HTML | false
+
+## Benchmarks
+
+Rendering spec/spec-0.28.txt on a Intel(R) Core(TM) i5-2400 CPU @ 3.10GHz
+
+ BenchmarkRenderSpecNoHTML 100 10254720 ns/op 2998037 B/op 18225 allocs/op
+ BenchmarkRenderSpec 100 10180241 ns/op 2997307 B/op 18214 allocs/op
+ BenchmarkRenderSpecBlackFriday 200 7241749 ns/op 2834340 B/op 17101 allocs/op
+ BenchmarkRenderSpecBlackFriday2 200 7448256 ns/op 2991202 B/op 16705 allocs/op
+
+## See also
+
+https://github.com/jgm/CommonMark — the reference CommonMark implementations in C and JavaScript,
+ also contains the latest spec and an online demo.
+
+http://talk.commonmark.org — the CommonMark forum, a good place to join together the efforts of the developers.
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/align.go b/vendor/gitlab.com/golang-commonmark/markdown/align.go
new file mode 100644
index 00000000..bcb63600
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/align.go
@@ -0,0 +1,26 @@
+// 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
+
+type Align byte
+
+const (
+ AlignNone = iota
+ AlignLeft
+ AlignCenter
+ AlignRight
+)
+
+func (a Align) String() string {
+ switch a {
+ case AlignLeft:
+ return "left"
+ case AlignCenter:
+ return "center"
+ case AlignRight:
+ return "right"
+ }
+ return ""
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/autolink.go b/vendor/gitlab.com/golang-commonmark/markdown/autolink.go
new file mode 100644
index 00000000..ab51c71b
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/autolink.go
@@ -0,0 +1,70 @@
+// 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 (
+ "regexp"
+ "strings"
+)
+
+var (
+ rAutolink = regexp.MustCompile(`^<([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)>`)
+ rEmail = regexp.MustCompile(`^<([a-zA-Z0-9.!#$%&'*+/=?^_{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>`)
+)
+
+func ruleAutolink(s *StateInline, silent bool) bool {
+ pos := s.Pos
+ src := s.Src
+
+ if src[pos] != '<' {
+ return false
+ }
+
+ tail := src[pos:]
+
+ if strings.IndexByte(tail, '>') < 0 {
+ return false
+ }
+
+ link := rAutolink.FindString(tail)
+ if link != "" {
+ link = link[1 : len(link)-1]
+ href := normalizeLink(link)
+ if !validateLink(href) {
+ return false
+ }
+
+ if !silent {
+ s.PushOpeningToken(&LinkOpen{Href: href})
+ s.PushToken(&Text{Content: normalizeLinkText(link)})
+ s.PushClosingToken(&LinkClose{})
+ }
+
+ s.Pos += len(link) + 2
+
+ return true
+ }
+
+ email := rEmail.FindString(tail)
+ if email != "" {
+ email = email[1 : len(email)-1]
+ href := normalizeLink("mailto:" + email)
+ if !validateLink(href) {
+ return false
+ }
+
+ if !silent {
+ s.PushOpeningToken(&LinkOpen{Href: href})
+ s.PushToken(&Text{Content: normalizeLinkText(email)})
+ s.PushClosingToken(&LinkClose{})
+ }
+
+ s.Pos += len(email) + 2
+
+ return true
+ }
+
+ return false
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/backticks.go b/vendor/gitlab.com/golang-commonmark/markdown/backticks.go
new file mode 100644
index 00000000..07f268dc
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/backticks.go
@@ -0,0 +1,60 @@
+// 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 "strings"
+
+func ruleBackticks(s *StateInline, silent bool) bool {
+ pos := s.Pos
+ src := s.Src
+
+ if src[pos] != '`' {
+ return false
+ }
+
+ start := pos
+ pos++
+ max := s.PosMax
+
+ for pos < max && src[pos] == '`' {
+ pos++
+ }
+
+ marker := src[start:pos]
+
+ matchStart := pos
+ matchEnd := pos
+ for {
+ matchStart = strings.IndexByte(src[matchEnd:], '`')
+ if matchStart == -1 {
+ break
+ }
+ matchStart += matchEnd
+
+ matchEnd = matchStart + 1
+
+ for matchEnd < max && src[matchEnd] == '`' {
+ matchEnd++
+ }
+
+ if matchEnd-matchStart == len(marker) {
+ if !silent {
+ s.PushToken(&CodeInline{
+ Content: normalizeInlineCode(src[pos:matchStart]),
+ })
+ }
+ s.Pos = matchEnd
+ return true
+ }
+ }
+
+ if !silent {
+ s.Pending.WriteString(marker)
+ }
+
+ s.Pos += len(marker)
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/balance_pairs.go b/vendor/gitlab.com/golang-commonmark/markdown/balance_pairs.go
new file mode 100644
index 00000000..d5830634
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/balance_pairs.go
@@ -0,0 +1,43 @@
+// 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
+
+func ruleBalancePairs(s *StateInline) {
+ delimiters := s.Delimiters
+ max := len(delimiters)
+
+ for i := 0; i < max; i++ {
+ lastDelim := delimiters[i]
+
+ if !lastDelim.Close {
+ continue
+ }
+
+ j := i - lastDelim.Jump - 1
+
+ for j >= 0 {
+ currDelim := delimiters[j]
+
+ if currDelim.Open &&
+ currDelim.Marker == lastDelim.Marker &&
+ currDelim.End < 0 &&
+ currDelim.Level == lastDelim.Level {
+ oddMatch := (currDelim.Close || lastDelim.Open) &&
+ currDelim.Length != -1 &&
+ lastDelim.Length != -1 &&
+ (currDelim.Length+lastDelim.Length)%3 == 0
+ if !oddMatch {
+ delimiters[i].Jump = i - j
+ delimiters[i].Open = false
+ delimiters[j].End = i
+ delimiters[j].Jump = 0
+ break
+ }
+ }
+
+ j -= currDelim.Jump + 1
+ }
+ }
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/blockquote.go b/vendor/gitlab.com/golang-commonmark/markdown/blockquote.go
new file mode 100644
index 00000000..f8ad3626
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/blockquote.go
@@ -0,0 +1,233 @@
+// 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 "unicode/utf8"
+
+var blockquoteTerminatedBy []BlockRule
+
+func ruleBlockQuote(s *StateBlock, startLine, endLine int, silent bool) bool {
+ if s.SCount[startLine]-s.BlkIndent >= 4 {
+ return false
+ }
+
+ pos := s.BMarks[startLine] + s.TShift[startLine]
+ max := s.EMarks[startLine]
+ src := s.Src
+
+ if pos >= max {
+ return false
+ }
+ if src[pos] != '>' {
+ return false
+ }
+ pos++
+
+ if silent {
+ return true
+ }
+
+ initial := s.SCount[startLine] + pos - (s.BMarks[startLine] + s.TShift[startLine])
+ offset := initial
+
+ spaceAfterMarker := false
+ adjustTab := false
+ if pos < max {
+ if src[pos] == ' ' {
+ pos++
+ initial++
+ offset++
+ spaceAfterMarker = true
+ } else if src[pos] == '\t' {
+ spaceAfterMarker = true
+ if (s.BSCount[startLine]+offset)%4 == 3 {
+ pos++
+ initial++
+ offset++
+ } else {
+ adjustTab = true
+ }
+ }
+ }
+
+ oldBMarks := []int{s.BMarks[startLine]}
+ s.BMarks[startLine] = pos
+
+ for pos < max {
+ r, size := utf8.DecodeRuneInString(src[pos:])
+ if runeIsSpace(r) {
+ if r == '\t' {
+ d := 0
+ if adjustTab {
+ d = 1
+ }
+ offset += 4 - (offset+s.BSCount[startLine]+d)%4
+ } else {
+ offset++
+ }
+ } else {
+ break
+ }
+ pos += size
+ }
+
+ oldBSCount := []int{s.BSCount[startLine]}
+ d := 0
+ if spaceAfterMarker {
+ d = 1
+ }
+ s.BSCount[startLine] = s.SCount[startLine] + 1 + d
+
+ lastLineEmpty := pos >= max
+
+ oldSCount := []int{s.SCount[startLine]}
+ s.SCount[startLine] = offset - initial
+
+ oldTShift := []int{s.TShift[startLine]}
+ s.TShift[startLine] = pos - s.BMarks[startLine]
+
+ oldParentType := s.ParentType
+ s.ParentType = ptBlockQuote
+ wasOutdented := false
+
+ oldLineMax := s.LineMax
+
+ nextLine := startLine + 1
+ for ; nextLine < endLine; nextLine++ {
+ if s.SCount[nextLine] < s.BlkIndent {
+ wasOutdented = true
+ }
+ pos = s.BMarks[nextLine] + s.TShift[nextLine]
+ max = s.EMarks[nextLine]
+
+ if pos >= max {
+ break
+ }
+
+ pos++
+ if src[pos-1] == '>' && !wasOutdented {
+ initial = s.SCount[nextLine] + pos + (s.BMarks[nextLine] + s.TShift[nextLine])
+ offset = initial
+
+ if pos >= len(src) || src[pos] != ' ' && src[pos] != '\t' {
+ spaceAfterMarker = true
+ } else if src[pos] == ' ' {
+ pos++
+ initial++
+ offset++
+ adjustTab = false
+ spaceAfterMarker = true
+ } else if src[pos] == '\t' {
+ spaceAfterMarker = true
+
+ if (s.BSCount[nextLine]+offset)%4 == 3 {
+ pos++
+ initial++
+ offset++
+ adjustTab = false
+ } else {
+ adjustTab = true
+ }
+ }
+
+ oldBMarks = append(oldBMarks, s.BMarks[nextLine])
+ s.BMarks[nextLine] = pos
+
+ for pos < max {
+ r, size := utf8.DecodeRuneInString(src[pos:])
+ if runeIsSpace(r) {
+ if r == '\t' {
+ d := 0
+ if adjustTab {
+ d = 1
+ }
+ offset += 4 - (offset+s.BSCount[startLine]+d)%4
+ } else {
+ offset++
+ }
+ } else {
+ break
+ }
+ pos += size
+ }
+
+ lastLineEmpty = pos >= max
+
+ oldBSCount = append(oldBSCount, s.BSCount[nextLine])
+ d := 0
+ if spaceAfterMarker {
+ d = 1
+ }
+ s.BSCount[nextLine] = s.SCount[nextLine] + 1 + d
+
+ oldSCount = append(oldSCount, s.SCount[nextLine])
+ s.SCount[nextLine] = offset - initial
+
+ oldTShift = append(oldTShift, s.TShift[nextLine])
+ s.TShift[nextLine] = pos - s.BMarks[nextLine]
+
+ continue
+ }
+
+ if lastLineEmpty {
+ break
+ }
+
+ terminate := false
+ for _, r := range blockquoteTerminatedBy {
+ if r(s, nextLine, endLine, true) {
+ terminate = true
+ break
+ }
+ }
+
+ if terminate {
+ s.LineMax = nextLine
+
+ if s.BlkIndent != 0 {
+ oldBMarks = append(oldBMarks, s.BMarks[nextLine])
+ oldBSCount = append(oldBSCount, s.BSCount[nextLine])
+ oldTShift = append(oldTShift, s.TShift[nextLine])
+ oldSCount = append(oldSCount, s.SCount[nextLine])
+ s.SCount[nextLine] -= s.BlkIndent
+ }
+
+ break
+ }
+
+ oldBMarks = append(oldBMarks, s.BMarks[nextLine])
+ oldBSCount = append(oldBSCount, s.BSCount[nextLine])
+ oldTShift = append(oldTShift, s.TShift[nextLine])
+ oldSCount = append(oldSCount, s.SCount[nextLine])
+
+ s.SCount[nextLine] = -1
+ }
+
+ oldIndent := s.BlkIndent
+ s.BlkIndent = 0
+
+ tok := &BlockquoteOpen{
+ Map: [2]int{startLine, 0},
+ }
+ s.PushOpeningToken(tok)
+
+ s.Md.Block.Tokenize(s, startLine, nextLine)
+
+ s.PushClosingToken(&BlockquoteClose{})
+
+ s.LineMax = oldLineMax
+ s.ParentType = oldParentType
+ tok.Map[1] = s.Line
+
+ for i := 0; i < len(oldTShift); i++ {
+ s.BMarks[startLine+i] = oldBMarks[i]
+ s.TShift[startLine+i] = oldTShift[i]
+ s.SCount[startLine+i] = oldSCount[i]
+ s.BSCount[startLine+i] = oldBSCount[i]
+ }
+ s.BlkIndent = oldIndent
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/code.go b/vendor/gitlab.com/golang-commonmark/markdown/code.go
new file mode 100644
index 00000000..c6dc574e
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/code.go
@@ -0,0 +1,37 @@
+// 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
+
+func ruleCode(s *StateBlock, startLine, endLine int, _ bool) bool {
+ if s.SCount[startLine]-s.BlkIndent < 4 {
+ return false
+ }
+
+ nextLine := startLine + 1
+ last := nextLine
+
+ for nextLine < endLine {
+ if s.IsLineEmpty(nextLine) {
+ nextLine++
+ continue
+ }
+
+ if s.SCount[nextLine]-s.BlkIndent >= 4 {
+ nextLine++
+ last = nextLine
+ continue
+ }
+
+ break
+ }
+
+ s.Line = last
+ s.PushToken(&CodeBlock{
+ Content: s.Lines(startLine, last, 4+s.BlkIndent, true),
+ Map: [2]int{startLine, s.Line},
+ })
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/emphasis.go b/vendor/gitlab.com/golang-commonmark/markdown/emphasis.go
new file mode 100644
index 00000000..ea9cda21
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/emphasis.go
@@ -0,0 +1,89 @@
+// 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
+
+type Delimiter struct {
+ Length int
+ Jump int
+ Token int
+ Level int
+ End int
+ Open bool
+ Close bool
+ Marker byte
+}
+
+func ruleEmphasis(s *StateInline, silent bool) bool {
+ src := s.Src
+ start := s.Pos
+ marker := src[start]
+
+ if silent {
+ return false
+ }
+
+ if marker != '_' && marker != '*' {
+ return false
+ }
+
+ canOpen, canClose, length := s.scanDelims(s.Pos, marker == '*')
+ for i := 0; i < length; i++ {
+ s.PushToken(&Text{Content: string(marker)})
+
+ s.Delimiters = append(s.Delimiters, Delimiter{
+ Marker: marker,
+ Length: length,
+ Jump: i,
+ Token: len(s.Tokens) - 1,
+ Level: s.Level,
+ End: -1,
+ Open: canOpen,
+ Close: canClose,
+ })
+ }
+
+ s.Pos += length
+
+ return true
+}
+
+func ruleEmphasisPostprocess(s *StateInline) {
+ delimiters := s.Delimiters
+ max := len(delimiters)
+ for i := max - 1; i >= 0; i-- {
+ startDelim := delimiters[i]
+ if startDelim.Marker != '_' && startDelim.Marker != '*' {
+ continue
+ }
+
+ if startDelim.End == -1 {
+ continue
+ }
+
+ endDelim := delimiters[startDelim.End]
+
+ isStrong := i > 0 &&
+ delimiters[i-1].End == startDelim.End+1 &&
+ delimiters[i-1].Token == startDelim.Token-1 &&
+ delimiters[startDelim.End+1].Token == endDelim.Token+1 &&
+ delimiters[i-1].Marker == startDelim.Marker
+
+ if isStrong {
+ s.Tokens[startDelim.Token] = &StrongOpen{}
+ s.Tokens[endDelim.Token] = &StrongClose{}
+
+ if text, ok := s.Tokens[delimiters[i-1].Token].(*Text); ok {
+ text.Content = ""
+ }
+ if text, ok := s.Tokens[delimiters[startDelim.End+1].Token].(*Text); ok {
+ text.Content = ""
+ }
+ i--
+ } else {
+ s.Tokens[startDelim.Token] = &EmphasisOpen{}
+ s.Tokens[endDelim.Token] = &EmphasisClose{}
+ }
+ }
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/entity.go b/vendor/gitlab.com/golang-commonmark/markdown/entity.go
new file mode 100644
index 00000000..fd5fba9c
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/entity.go
@@ -0,0 +1,35 @@
+// 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 "gitlab.com/golang-commonmark/html"
+
+func ruleEntity(s *StateInline, silent bool) bool {
+ pos := s.Pos
+ src := s.Src
+
+ if src[pos] != '&' {
+ return false
+ }
+
+ max := s.PosMax
+
+ if pos+1 < max {
+ if e, n := html.ParseEntity(src[pos:]); n > 0 {
+ if !silent {
+ s.Pending.WriteString(e)
+ }
+ s.Pos += n
+ return true
+ }
+ }
+
+ if !silent {
+ s.Pending.WriteByte('&')
+ }
+ s.Pos++
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/escape.go b/vendor/gitlab.com/golang-commonmark/markdown/escape.go
new file mode 100644
index 00000000..634b9735
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/escape.go
@@ -0,0 +1,61 @@
+// 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 "strings"
+
+func escaped(b byte) bool {
+ return strings.IndexByte("\\!\"#$%&'()*+,./:;<=>?@[]^_`{|}~-", b) != -1
+}
+
+func ruleEscape(s *StateInline, silent bool) bool {
+ pos := s.Pos
+ src := s.Src
+
+ if src[pos] != '\\' {
+ return false
+ }
+
+ pos++
+ max := s.PosMax
+
+ if pos < max {
+ b := src[pos]
+
+ if b < 0x7f && escaped(b) {
+ if !silent {
+ s.Pending.WriteByte(b)
+ }
+ s.Pos += 2
+ return true
+ }
+
+ if b == '\n' {
+ if !silent {
+ s.PushToken(&Hardbreak{})
+ }
+
+ pos++
+
+ for pos < max {
+ b := src[pos]
+ if !byteIsSpace(b) {
+ break
+ }
+ pos++
+ }
+
+ s.Pos = pos
+ return true
+ }
+ }
+
+ if !silent {
+ s.Pending.WriteByte('\\')
+ }
+ s.Pos++
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/fence.go b/vendor/gitlab.com/golang-commonmark/markdown/fence.go
new file mode 100644
index 00000000..04924dc4
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/fence.go
@@ -0,0 +1,102 @@
+// 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 "strings"
+
+func ruleFence(s *StateBlock, startLine, endLine int, silent bool) bool {
+ haveEndMarker := false
+ pos := s.BMarks[startLine] + s.TShift[startLine]
+ max := s.EMarks[startLine]
+
+ if s.SCount[startLine]-s.BlkIndent >= 4 {
+ return false
+ }
+ if pos+3 > max {
+ return false
+ }
+
+ src := s.Src
+
+ marker := src[pos]
+ if marker != '~' && marker != '`' {
+ return false
+ }
+
+ mem := pos
+ pos = s.SkipBytes(pos, marker)
+
+ len := pos - mem
+
+ if len < 3 {
+ return false
+ }
+
+ params := strings.TrimSpace(src[pos:max])
+
+ if strings.IndexByte(params, marker) >= 0 {
+ return false
+ }
+
+ if silent {
+ return true
+ }
+
+ nextLine := startLine
+
+ for {
+ nextLine++
+ if nextLine >= endLine {
+ break
+ }
+
+ mem = s.BMarks[nextLine] + s.TShift[nextLine]
+ pos = mem
+ max = s.EMarks[nextLine]
+
+ if pos < max && s.SCount[nextLine] < s.BlkIndent {
+ break
+ }
+
+ if pos >= max || src[pos] != marker {
+ continue
+ }
+
+ if s.SCount[nextLine]-s.BlkIndent >= 4 {
+ continue
+ }
+
+ pos = s.SkipBytes(pos, marker)
+
+ if pos-mem < len {
+ continue
+ }
+
+ pos = s.SkipSpaces(pos)
+
+ if pos < max {
+ continue
+ }
+
+ haveEndMarker = true
+
+ break
+ }
+
+ len = s.SCount[startLine]
+
+ s.Line = nextLine
+ if haveEndMarker {
+ s.Line++
+ }
+
+ s.PushToken(&Fence{
+ Params: params,
+ Content: s.Lines(startLine+1, nextLine, len, true),
+ Map: [2]int{startLine, s.Line},
+ })
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/fuzz.go b/vendor/gitlab.com/golang-commonmark/markdown/fuzz.go
new file mode 100644
index 00000000..66ac7697
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/fuzz.go
@@ -0,0 +1,9 @@
+//+build gofuzz
+
+package markdown
+
+func Fuzz(data []byte) int {
+ md := New(HTML(true))
+ md.Parse(data)
+ return 1
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/heading.go b/vendor/gitlab.com/golang-commonmark/markdown/heading.go
new file mode 100644
index 00000000..a09c4f72
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/heading.go
@@ -0,0 +1,59 @@
+// 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 "strings"
+
+func ruleHeading(s *StateBlock, startLine, _ int, silent bool) bool {
+ pos := s.BMarks[startLine] + s.TShift[startLine]
+ max := s.EMarks[startLine]
+ src := s.Src
+
+ if s.SCount[startLine]-s.BlkIndent >= 4 {
+ return false
+ }
+
+ if pos >= max || src[pos] != '#' {
+ return false
+ }
+
+ level := 1
+ pos++
+ for pos < max && src[pos] == '#' && level <= 6 {
+ level++
+ pos++
+ }
+
+ if level > 6 || (pos < max && !byteIsSpace(src[pos])) {
+ return false
+ }
+
+ if silent {
+ return true
+ }
+
+ max = s.SkipSpacesBack(max, pos)
+ tmp := s.SkipBytesBack(max, '#', pos)
+ if tmp > pos && byteIsSpace(src[tmp-1]) {
+ max = tmp
+ }
+
+ s.Line = startLine + 1
+
+ s.PushOpeningToken(&HeadingOpen{
+ HLevel: level,
+ Map: [2]int{startLine, s.Line},
+ })
+
+ if pos < max {
+ s.PushToken(&Inline{
+ Content: strings.TrimSpace(src[pos:max]),
+ Map: [2]int{startLine, s.Line},
+ })
+ }
+ s.PushClosingToken(&HeadingClose{HLevel: level})
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/helpers.go b/vendor/gitlab.com/golang-commonmark/markdown/helpers.go
new file mode 100644
index 00000000..d158dfcf
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/helpers.go
@@ -0,0 +1,164 @@
+// 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
+
+func parseLinkLabel(s *StateInline, start int, disableNested bool) int {
+ src := s.Src
+ labelEnd := -1
+ max := s.PosMax
+ oldPos := s.Pos
+
+ s.Pos = start + 1
+ level := 1
+ found := false
+
+ for s.Pos < max {
+ marker := src[s.Pos]
+
+ if marker == ']' {
+ level--
+ if level == 0 {
+ found = true
+ break
+ }
+ }
+
+ prevPos := s.Pos
+
+ s.Md.Inline.SkipToken(s)
+
+ if marker == '[' {
+ if prevPos == s.Pos-1 {
+ level++
+ } else if disableNested {
+ s.Pos = oldPos
+ return -1
+ }
+ }
+ }
+
+ if found {
+ labelEnd = s.Pos
+ }
+
+ s.Pos = oldPos
+
+ return labelEnd
+}
+
+func parseLinkDestination(s string, pos, max int) (url string, lines, endpos int, ok bool) {
+ start := pos
+ if pos < max && s[pos] == '<' {
+ pos++
+ for pos < max {
+ b := s[pos]
+ if b == '\n' || byteIsSpace(b) {
+ return
+ }
+ if b == '>' {
+ endpos = pos + 1
+ url = unescapeAll(s[start+1 : pos])
+ ok = true
+ return
+ }
+ if b == '\\' && pos+1 < max {
+ pos += 2
+ continue
+ }
+
+ pos++
+ }
+
+ return
+ }
+
+ level := 0
+ for pos < max {
+ b := s[pos]
+
+ if b == ' ' {
+ break
+ }
+
+ if b < 0x20 || b == 0x7f {
+ break
+ }
+
+ if b == '\\' && pos+1 < max {
+ pos += 2
+ continue
+ }
+
+ if b == '(' {
+ level++
+ }
+
+ if b == ')' {
+ if level == 0 {
+ break
+ }
+ level--
+ }
+
+ pos++
+ }
+
+ if start == pos {
+ return
+ }
+ if level != 0 {
+ return
+ }
+
+ url = unescapeAll(s[start:pos])
+ endpos = pos
+ ok = true
+
+ return
+}
+
+func parseLinkTitle(s string, pos, max int) (title string, nlines, endpos int, ok bool) {
+ lines := 0
+ start := pos
+
+ if pos >= max {
+ return
+ }
+
+ marker := s[pos]
+
+ if marker != '"' && marker != '\'' && marker != '(' {
+ return
+ }
+
+ pos++
+
+ if marker == '(' {
+ marker = ')'
+ }
+
+ for pos < max {
+ switch s[pos] {
+ case marker:
+ endpos = pos + 1
+ nlines = lines
+ title = unescapeAll(s[start+1 : pos])
+ ok = true
+ return
+ case '\n':
+ lines++
+ case '\\':
+ if pos+1 < max {
+ pos++
+ if s[pos] == '\n' {
+ lines++
+ }
+ }
+ }
+ pos++
+ }
+
+ return
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/hr.go b/vendor/gitlab.com/golang-commonmark/markdown/hr.go
new file mode 100644
index 00000000..fe25681d
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/hr.go
@@ -0,0 +1,54 @@
+// 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
+
+func ruleHR(s *StateBlock, startLine, endLine int, silent bool) bool {
+ pos := s.BMarks[startLine] + s.TShift[startLine]
+ max := s.EMarks[startLine]
+
+ if pos >= max {
+ return false
+ }
+
+ if s.SCount[startLine]-s.BlkIndent >= 4 {
+ return false
+ }
+
+ src := s.Src
+ marker := src[pos]
+ pos++
+
+ if marker != '*' && marker != '-' && marker != '_' {
+ return false
+ }
+
+ cnt := 1
+ for pos < max {
+ ch := src[pos]
+ pos++
+ if ch != marker && !byteIsSpace(ch) {
+ return false
+ }
+ if ch == marker {
+ cnt++
+ }
+ }
+
+ if cnt < 3 {
+ return false
+ }
+
+ if silent {
+ return true
+ }
+
+ s.Line = startLine + 1
+
+ s.PushToken(&Hr{
+ Map: [2]int{startLine, s.Line},
+ })
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/html_block.go b/vendor/gitlab.com/golang-commonmark/markdown/html_block.go
new file mode 100644
index 00000000..98a89499
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/html_block.go
@@ -0,0 +1,222 @@
+// 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 (
+ "regexp"
+ "strings"
+)
+
+var (
+ htmlBlocks = []string{
+ "address",
+ "article",
+ "aside",
+ "base",
+ "basefont",
+ "blockquote",
+ "body",
+ "caption",
+ "center",
+ "col",
+ "colgroup",
+ "dd",
+ "details",
+ "dialog",
+ "dir",
+ "div",
+ "dl",
+ "dt",
+ "fieldset",
+ "figcaption",
+ "figure",
+ "footer",
+ "form",
+ "frame",
+ "frameset",
+ "h1",
+ "h2",
+ "h3",
+ "h4",
+ "h5",
+ "h6",
+ "head",
+ "header",
+ "hr",
+ "html",
+ "iframe",
+ "legend",
+ "li",
+ "link",
+ "main",
+ "menu",
+ "menuitem",
+ "meta",
+ "nav",
+ "noframes",
+ "ol",
+ "optgroup",
+ "option",
+ "p",
+ "param",
+ "section",
+ "source",
+ "summary",
+ "table",
+ "tbody",
+ "td",
+ "tfoot",
+ "th",
+ "thead",
+ "title",
+ "tr",
+ "track",
+ "ul",
+ }
+
+ htmlBlocksSet = make(map[string]bool)
+
+ rStartCond1 = regexp.MustCompile(`(?i)^(pre|script|style)([\n\t >]|$)`)
+ rEndCond1 = regexp.MustCompile(`(?i)(pre|script|style)>`)
+ rStartCond6 = regexp.MustCompile(`(?i)^/?(` + strings.Join(htmlBlocks, "|") + `)(\s|$|>|/>)`)
+ rStartCond7 = regexp.MustCompile(`(?i)^(/[a-z][a-z0-9-]*|[a-z][a-z0-9-]*(\s+[a-z_:][a-z0-9_.:-]*\s*=\s*("[^"]*"|'[^']*'|[ "'=<>\x60]))*\s*/?)>\s*$`)
+)
+
+func init() {
+ for _, tag := range htmlBlocks {
+ htmlBlocksSet[tag] = true
+ }
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func matchTagName(s string) string {
+ if len(s) < 2 {
+ return ""
+ }
+
+ i := 0
+ if s[0] == '/' {
+ i++
+ }
+ start := i
+ max := min(15+i, len(s))
+ for i < max && isLetter(s[i]) {
+ i++
+ }
+ if i >= len(s) {
+ return ""
+ }
+
+ switch s[i] {
+ case ' ', '\n', '/', '>':
+ return strings.ToLower(s[start:i])
+ default:
+ return ""
+ }
+}
+
+func ruleHTMLBlock(s *StateBlock, startLine, endLine int, silent bool) bool {
+ if !s.Md.HTML {
+ return false
+ }
+
+ pos := s.BMarks[startLine] + s.TShift[startLine]
+ max := s.EMarks[startLine]
+
+ if pos+1 >= max {
+ return false
+ }
+
+ src := s.Src
+
+ if src[pos] != '<' {
+ return false
+ }
+
+ pos++
+ b := src[pos]
+ if !htmlSecond(b) {
+ return false
+ }
+
+ nextLine := startLine + 1
+
+ var endCond func(string) bool
+
+ if pos+2 < max && isLetter(b) && rStartCond1.MatchString(src[pos:]) {
+ endCond = func(s string) bool {
+ return rEndCond1.MatchString(s)
+ }
+ } else if strings.HasPrefix(src[pos:], "!--") {
+ endCond = func(s string) bool {
+ return strings.Contains(s, "-->")
+ }
+ } else if b == '?' {
+ endCond = func(s string) bool {
+ return strings.Contains(s, "?>")
+ }
+ } else if b == '!' && pos+1 < max && isUppercaseLetter(src[pos+1]) {
+ endCond = func(s string) bool {
+ return strings.Contains(s, ">")
+ }
+ } else if strings.HasPrefix(src[pos:], "![CDATA[") {
+ endCond = func(s string) bool {
+ return strings.Contains(s, "]]>")
+ }
+ } else if pos+2 < max && (isLetter(b) || b == '/' && isLetter(src[pos+1])) {
+ terminator := true
+ if rStartCond6.MatchString(src[pos:max]) {
+ } else if rStartCond7.MatchString(src[pos:max]) {
+ terminator = false
+ } else {
+ return false
+ }
+ if silent {
+ return terminator
+ }
+ endCond = func(s string) bool {
+ return s == ""
+ }
+ } else {
+ return false
+ }
+
+ if silent {
+ return true
+ }
+
+ if !endCond(src[pos:max]) {
+ for nextLine < endLine {
+ if s.SCount[nextLine] < s.BlkIndent {
+ break
+ }
+
+ pos := s.BMarks[nextLine] + s.TShift[nextLine]
+ max := s.EMarks[nextLine]
+ lineText := src[pos:max]
+ if endCond(lineText) {
+ if pos != max {
+ nextLine++
+ }
+ break
+ }
+ nextLine++
+ }
+ }
+
+ s.Line = nextLine
+ s.PushToken(&HTMLBlock{
+ Content: s.Lines(startLine, nextLine, s.BlkIndent, true),
+ Map: [2]int{startLine, nextLine},
+ })
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/html_inline.go b/vendor/gitlab.com/golang-commonmark/markdown/html_inline.go
new file mode 100644
index 00000000..0de54b20
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/html_inline.go
@@ -0,0 +1,57 @@
+// 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 "regexp"
+
+var (
+ attrName = `[a-zA-Z_:][a-zA-Z0-9:._-]*`
+ unquoted = "[^\"'=<>`\\x00-\\x20]+"
+ singleQuoted = `'[^']*'`
+ doubleQuoted = `"[^"]*"`
+ attrValue = `(?:` + unquoted + `|` + singleQuoted + `|` + doubleQuoted + `)`
+ attribute = `(?:\s+` + attrName + `(?:\s*=\s*` + attrValue + `)?)`
+ openTag = `<[A-Za-z][A-Za-z0-9-]*` + attribute + `*\s*/?>`
+ closeTag = `[A-Za-z][A-Za-z0-9-]*\s*>`
+ comment = `|`
+ processing = `<[?].*?[?]>`
+ declaration = `]*>`
+ cdata = ``
+ rHTMLTag = regexp.MustCompile(`^(?:` + openTag + `|` + closeTag + `|` + comment +
+ `|` + processing + `|` + declaration + `|` + cdata + `)`)
+)
+
+func htmlSecond(b byte) bool {
+ return b == '!' || b == '/' || b == '?' || isLetter(b)
+}
+
+func ruleHTMLInline(s *StateInline, silent bool) bool {
+ if !s.Md.HTML {
+ return false
+ }
+
+ pos := s.Pos
+ src := s.Src
+ if pos+2 >= s.PosMax || src[pos] != '<' {
+ return false
+ }
+
+ if !htmlSecond(src[pos+1]) {
+ return false
+ }
+
+ match := rHTMLTag.FindString(src[pos:])
+ if match == "" {
+ return false
+ }
+
+ if !silent {
+ s.PushToken(&HTMLInline{Content: match})
+ }
+
+ s.Pos += len(match)
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/image.go b/vendor/gitlab.com/golang-commonmark/markdown/image.go
new file mode 100644
index 00000000..7f2e67d3
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/image.go
@@ -0,0 +1,131 @@
+// 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
+
+func ruleImage(s *StateInline, silent bool) bool {
+ pos := s.Pos
+ max := s.PosMax
+
+ if pos+2 >= max {
+ return false
+ }
+
+ src := s.Src
+ if src[pos] != '!' || src[pos+1] != '[' {
+ return false
+ }
+
+ labelStart := pos + 2
+ labelEnd := parseLinkLabel(s, pos+1, false)
+ if labelEnd < 0 {
+ return false
+ }
+
+ var href, title, label string
+ oldPos := pos
+ pos = labelEnd + 1
+ if pos < max && src[pos] == '(' {
+ pos++
+ for pos < max {
+ b := src[pos]
+ if !byteIsSpace(b) && b != '\n' {
+ break
+ }
+ pos++
+ }
+ if pos >= max {
+ return false
+ }
+
+ start := pos
+ url, _, endpos, ok := parseLinkDestination(src, pos, s.PosMax)
+ if ok {
+ url = normalizeLink(url)
+ if validateLink(url) {
+ href = url
+ pos = endpos
+ }
+ }
+
+ start = pos
+ for pos < max {
+ b := src[pos]
+ if !byteIsSpace(b) && b != '\n' {
+ break
+ }
+ pos++
+ }
+ if pos >= max {
+ return false
+ }
+
+ title, _, endpos, ok = parseLinkTitle(src, pos, s.PosMax)
+ if pos < max && start != pos && ok {
+ pos = endpos
+ for pos < max {
+ b := src[pos]
+ if !byteIsSpace(b) && b != '\n' {
+ break
+ }
+ pos++
+ }
+ }
+
+ if pos >= max || src[pos] != ')' {
+ s.Pos = oldPos
+ return false
+ }
+
+ pos++
+
+ } else {
+ if s.Env.References == nil {
+ return false
+ }
+
+ if pos < max && src[pos] == '[' {
+ start := pos + 1
+ pos = parseLinkLabel(s, pos, false)
+ if pos >= 0 {
+ label = src[start:pos]
+ pos++
+ } else {
+ pos = labelEnd + 1
+ }
+ } else {
+ pos = labelEnd + 1
+ }
+
+ if label == "" {
+ label = src[labelStart:labelEnd]
+ }
+
+ ref, ok := s.Env.References[normalizeReference(label)]
+ if !ok {
+ s.Pos = oldPos
+ return false
+ }
+
+ href = ref["href"]
+ title = ref["title"]
+ }
+
+ if !silent {
+ content := src[labelStart:labelEnd]
+
+ tokens := s.Md.Inline.Parse(content, s.Md, s.Env)
+
+ s.PushToken(&Image{
+ Src: href,
+ Title: title,
+ Tokens: tokens,
+ })
+ }
+
+ s.Pos = pos
+ s.PosMax = max
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/inline.go b/vendor/gitlab.com/golang-commonmark/markdown/inline.go
new file mode 100644
index 00000000..0bed18ac
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/inline.go
@@ -0,0 +1,13 @@
+// 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
+
+func ruleInline(s *StateCore) {
+ for _, tok := range s.Tokens {
+ if tok, ok := tok.(*Inline); ok {
+ tok.Children = s.Md.Inline.Parse(tok.Content, s.Md, s.Env)
+ }
+ }
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/lheading.go b/vendor/gitlab.com/golang-commonmark/markdown/lheading.go
new file mode 100644
index 00000000..b404066d
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/lheading.go
@@ -0,0 +1,80 @@
+// 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 "strings"
+
+func ruleLHeading(s *StateBlock, startLine, endLine int, silent bool) bool {
+ nextLine := startLine + 1
+
+ if s.SCount[startLine]-s.BlkIndent >= 4 {
+ return false
+ }
+
+ oldParentType := s.ParentType
+ s.ParentType = ptParagraph
+ src := s.Src
+
+ var pos int
+ var hLevel int
+outer:
+ for ; nextLine < endLine && !s.IsLineEmpty(nextLine); nextLine++ {
+ if s.SCount[nextLine]-s.BlkIndent > 3 {
+ continue
+ }
+
+ if s.SCount[nextLine] >= s.BlkIndent {
+ pos = s.BMarks[nextLine] + s.TShift[nextLine]
+ max := s.EMarks[nextLine]
+
+ if pos < max {
+ marker := src[pos]
+
+ if marker == '-' || marker == '=' {
+ pos = s.SkipBytes(pos, marker)
+ pos = s.SkipSpaces(pos)
+
+ if pos >= max {
+ hLevel = 1
+ if marker == '-' {
+ hLevel++
+ }
+ break
+ }
+ }
+ }
+ }
+
+ if s.SCount[nextLine] < 0 {
+ continue
+ }
+
+ for _, r := range paragraphTerminatedBy {
+ if r(s, nextLine, endLine, true) {
+ break outer
+ }
+ }
+ }
+
+ if hLevel == 0 {
+ return false
+ }
+
+ s.Line = nextLine + 1
+
+ s.PushOpeningToken(&HeadingOpen{
+ HLevel: hLevel,
+ Map: [2]int{startLine, s.Line},
+ })
+ s.PushToken(&Inline{
+ Content: strings.TrimSpace(s.Lines(startLine, nextLine, s.BlkIndent, false)),
+ Map: [2]int{startLine, s.Line - 1},
+ })
+ s.PushClosingToken(&HeadingClose{HLevel: hLevel})
+
+ s.ParentType = oldParentType
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/link.go b/vendor/gitlab.com/golang-commonmark/markdown/link.go
new file mode 100644
index 00000000..8ab2c04b
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/link.go
@@ -0,0 +1,132 @@
+// 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
+
+func ruleLink(s *StateInline, silent bool) bool {
+ pos := s.Pos
+ oldPos := s.Pos
+ max := s.PosMax
+ start := s.Pos
+ parseReference := true
+ src := s.Src
+
+ if src[pos] != '[' {
+ return false
+ }
+
+ labelStart := pos + 1
+ labelEnd := parseLinkLabel(s, pos, true)
+
+ if labelEnd < 0 {
+ return false
+ }
+
+ pos = labelEnd + 1
+
+ var title, href, label string
+ if pos < max && src[pos] == '(' {
+ parseReference = false
+
+ pos++
+ for pos < max {
+ code := src[pos]
+ if !byteIsSpace(code) && code != '\n' {
+ break
+ }
+ pos++
+ }
+ if pos >= max {
+ return false
+ }
+
+ start = pos
+ url, _, endpos, ok := parseLinkDestination(src, pos, s.PosMax)
+ if ok {
+ url = normalizeLink(url)
+ if validateLink(url) {
+ pos = endpos
+ href = url
+ }
+ }
+
+ start = pos
+ for pos < max {
+ code := src[pos]
+ if !byteIsSpace(code) && code != '\n' {
+ break
+ }
+ pos++
+ }
+
+ title, _, endpos, ok = parseLinkTitle(src, pos, s.PosMax)
+ if pos < max && start != pos && ok {
+ pos = endpos
+ for pos < max {
+ code := src[pos]
+ if !byteIsSpace(code) && code != '\n' {
+ break
+ }
+ pos++
+ }
+ }
+
+ if pos >= max || src[pos] != ')' {
+ parseReference = true
+ }
+
+ pos++
+ }
+
+ if parseReference {
+ if s.Env.References == nil {
+ return false
+ }
+
+ if pos < max && src[pos] == '[' {
+ start := pos + 1
+ pos = parseLinkLabel(s, pos, false)
+ if pos >= 0 {
+ label = src[start:pos]
+ pos++
+ } else {
+ pos = labelEnd + 1
+ }
+ } else {
+ pos = labelEnd + 1
+ }
+
+ if label == "" {
+ label = src[labelStart:labelEnd]
+ }
+
+ ref, ok := s.Env.References[normalizeReference(label)]
+ if !ok {
+ s.Pos = oldPos
+ return false
+ }
+
+ href = ref["href"]
+ title = ref["title"]
+ }
+
+ if !silent {
+ s.Pos = labelStart
+ s.PosMax = labelEnd
+
+ s.PushOpeningToken(&LinkOpen{
+ Href: href,
+ Title: title,
+ })
+
+ s.Md.Inline.Tokenize(s)
+
+ s.PushClosingToken(&LinkClose{})
+ }
+
+ s.Pos = pos
+ s.PosMax = max
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/linkify.go b/vendor/gitlab.com/golang-commonmark/markdown/linkify.go
new file mode 100644
index 00000000..5935af1b
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/linkify.go
@@ -0,0 +1,131 @@
+// 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 (
+ "strings"
+
+ "gitlab.com/golang-commonmark/linkify"
+)
+
+func isLinkOpen(s string) bool { return isLetter(s[1]) }
+
+func isLinkClose(s string) bool { return s[1] == '/' }
+
+func ruleLinkify(s *StateCore) {
+ blockTokens := s.Tokens
+
+ if !s.Md.Linkify {
+ return
+ }
+
+ for _, tok := range blockTokens {
+ if tok, ok := tok.(*Inline); ok {
+ tokens := tok.Children
+
+ htmlLinkLevel := 0
+
+ for i := len(tokens) - 1; i >= 0; i-- {
+ currentTok := tokens[i]
+
+ if _, ok := currentTok.(*LinkClose); ok {
+ i--
+ for tokens[i].Level() != currentTok.Level() {
+ if _, ok := tokens[i].(*LinkOpen); ok {
+ break
+ }
+ i--
+ }
+ continue
+ }
+
+ if currentTok, ok := currentTok.(*HTMLInline); ok {
+ if isLinkOpen(currentTok.Content) && htmlLinkLevel > 0 {
+ htmlLinkLevel--
+ }
+ if isLinkClose(currentTok.Content) {
+ htmlLinkLevel++
+ }
+ }
+ if htmlLinkLevel > 0 {
+ continue
+ }
+
+ if currentTok, ok := currentTok.(*Text); ok {
+ text := currentTok.Content
+ links := linkify.Links(text)
+ if len(links) == 0 {
+ continue
+ }
+
+ var nodes []Token
+ level := currentTok.Lvl
+ lastPos := 0
+
+ for _, ln := range links {
+ urlText := text[ln.Start:ln.End]
+ url := urlText
+ if ln.Scheme == "" {
+ url = "http://" + url
+ } else if ln.Scheme == "mailto:" && !strings.HasPrefix(url, "mailto:") {
+ url = "mailto:" + url
+ }
+ url = normalizeLink(url)
+ if !validateLink(url) {
+ continue
+ }
+
+ if ln.Scheme == "" {
+ urlText = strings.TrimPrefix(normalizeLinkText("http://"+urlText), "http://")
+ } else if ln.Scheme == "mailto:" && !strings.HasPrefix(urlText, "mailto:") {
+ urlText = strings.TrimPrefix(normalizeLinkText("mailto:"+urlText), "mailto:")
+ } else {
+ urlText = normalizeLinkText(urlText)
+ }
+
+ pos := ln.Start
+
+ if pos > lastPos {
+ tok := Text{
+ Content: text[lastPos:pos],
+ Lvl: level,
+ }
+ nodes = append(nodes, &tok)
+ }
+
+ nodes = append(nodes, &LinkOpen{
+ Href: url,
+ Lvl: level,
+ })
+ nodes = append(nodes, &Text{
+ Content: urlText,
+ Lvl: level + 1,
+ })
+ nodes = append(nodes, &LinkClose{
+ Lvl: level,
+ })
+
+ lastPos = ln.End
+ }
+
+ if lastPos < len(text) {
+ tok := Text{
+ Content: text[lastPos:],
+ Lvl: level,
+ }
+ nodes = append(nodes, &tok)
+ }
+
+ children := make([]Token, len(tokens)+len(nodes)-1)
+ copy(children, tokens[:i])
+ copy(children[i:], nodes)
+ copy(children[i+len(nodes):], tokens[i+1:])
+ tok.Children = children
+ tokens = children
+ }
+ }
+ }
+ }
+}
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
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/markdown.go b/vendor/gitlab.com/golang-commonmark/markdown/markdown.go
new file mode 100644
index 00000000..1e37b3ae
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/markdown.go
@@ -0,0 +1,112 @@
+// 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 provides CommonMark-compliant markdown parser and renderer.
+package markdown
+
+import (
+ "bytes"
+ "io"
+)
+
+type Markdown struct {
+ options
+ Block ParserBlock
+ Inline ParserInline
+ renderOptions RenderOptions
+}
+
+type RenderOptions struct {
+ LangPrefix string // CSS language class prefix for fenced blocks
+ XHTML bool // render as XHTML instead of HTML
+ Breaks bool // convert \n in paragraphs into
+ Nofollow bool // add rel="nofollow" to the links
+}
+
+type options struct {
+ HTML bool // allow raw HTML in the markup
+ Tables bool // GFM tables
+ Linkify bool // autoconvert URL-like text to links
+ Typographer bool // enable some typographic replacements
+ Quotes [4]string // double/single quotes replacement pairs
+ MaxNesting int // maximum nesting level
+}
+
+type Environment struct {
+ References map[string]map[string]string
+}
+
+type CoreRule func(*StateCore)
+
+var coreRules []CoreRule
+
+func New(opts ...option) *Markdown {
+ m := &Markdown{
+ options: options{
+ Tables: true,
+ Linkify: true,
+ Typographer: true,
+ Quotes: [4]string{"“", "”", "‘", "’"},
+ MaxNesting: 20,
+ },
+ renderOptions: RenderOptions{LangPrefix: "language-"},
+ }
+ for _, opt := range opts {
+ opt(m)
+ }
+ return m
+}
+
+func (m *Markdown) Parse(src []byte) []Token {
+ if len(src) == 0 {
+ return nil
+ }
+
+ s := &StateCore{
+ Md: m,
+ Env: &Environment{},
+ }
+ s.Tokens = m.Block.Parse(src, m, s.Env)
+
+ for _, r := range coreRules {
+ r(s)
+ }
+ return s.Tokens
+}
+
+func (m *Markdown) Render(w io.Writer, src []byte) error {
+ if len(src) == 0 {
+ return nil
+ }
+
+ return NewRenderer(w).Render(m.Parse(src), m.renderOptions)
+}
+
+func (m *Markdown) RenderTokens(w io.Writer, tokens []Token) error {
+ if len(tokens) == 0 {
+ return nil
+ }
+
+ return NewRenderer(w).Render(tokens, m.renderOptions)
+}
+
+func (m *Markdown) RenderToString(src []byte) string {
+ if len(src) == 0 {
+ return ""
+ }
+
+ var buf bytes.Buffer
+ NewRenderer(&buf).Render(m.Parse(src), m.renderOptions)
+ return buf.String()
+}
+
+func (m *Markdown) RenderTokensToString(tokens []Token) string {
+ if len(tokens) == 0 {
+ return ""
+ }
+
+ var buf bytes.Buffer
+ NewRenderer(&buf).Render(tokens, m.renderOptions)
+ return buf.String()
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/newline.go b/vendor/gitlab.com/golang-commonmark/markdown/newline.go
new file mode 100644
index 00000000..c69fa3d9
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/newline.go
@@ -0,0 +1,46 @@
+// 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
+
+func ruleNewline(s *StateInline, silent bool) bool {
+ pos := s.Pos
+ src := s.Src
+
+ if src[pos] != '\n' {
+ return false
+ }
+
+ pending := s.Pending.Bytes()
+ pmax := len(pending) - 1
+ max := s.PosMax
+
+ if !silent {
+ if pmax >= 0 && pending[pmax] == ' ' {
+ if pmax >= 1 && pending[pmax-1] == ' ' {
+ pmax -= 2
+ for pmax >= 0 && pending[pmax] == ' ' {
+ pmax--
+ }
+ s.Pending.Truncate(pmax + 1)
+ s.PushToken(&Hardbreak{})
+ } else {
+ s.Pending.Truncate(pmax)
+ s.PushToken(&Softbreak{})
+ }
+ } else {
+ s.PushToken(&Softbreak{})
+ }
+ }
+
+ pos++
+
+ for pos < max && byteIsSpace(src[pos]) {
+ pos++
+ }
+
+ s.Pos = pos
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/options.go b/vendor/gitlab.com/golang-commonmark/markdown/options.go
new file mode 100644
index 00000000..7e5b2cf3
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/options.go
@@ -0,0 +1,77 @@
+// 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
+
+type option func(m *Markdown)
+
+func HTML(b bool) option {
+ return func(m *Markdown) {
+ m.HTML = b
+ }
+}
+
+func Linkify(b bool) option {
+ return func(m *Markdown) {
+ m.Linkify = b
+ }
+}
+
+func Typographer(b bool) option {
+ return func(m *Markdown) {
+ m.Typographer = b
+ }
+}
+
+func Quotes(stringOrArray interface{}) option {
+ if s, ok := stringOrArray.(string); ok {
+ return func(m *Markdown) {
+ for i, r := range []rune(s) {
+ m.Quotes[i] = string(r)
+ }
+ }
+ }
+ a := stringOrArray.([]string)
+ return func(m *Markdown) {
+ for i, s := range a {
+ m.Quotes[i] = s
+ }
+ }
+}
+
+func MaxNesting(n int) option {
+ return func(m *Markdown) {
+ m.MaxNesting = n
+ }
+}
+
+func XHTMLOutput(b bool) option {
+ return func(m *Markdown) {
+ m.renderOptions.XHTML = b
+ }
+}
+
+func Breaks(b bool) option {
+ return func(m *Markdown) {
+ m.renderOptions.Breaks = b
+ }
+}
+
+func LangPrefix(p string) option {
+ return func(m *Markdown) {
+ m.renderOptions.LangPrefix = p
+ }
+}
+
+func Nofollow(b bool) option {
+ return func(m *Markdown) {
+ m.renderOptions.Nofollow = b
+ }
+}
+
+func Tables(b bool) option {
+ return func(m *Markdown) {
+ m.Tables = b
+ }
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/paragraph.go b/vendor/gitlab.com/golang-commonmark/markdown/paragraph.go
new file mode 100644
index 00000000..a3003ef6
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/paragraph.go
@@ -0,0 +1,51 @@
+// 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 "strings"
+
+var paragraphTerminatedBy []BlockRule
+
+func ruleParagraph(s *StateBlock, startLine, _ int, _ bool) bool {
+ nextLine := startLine + 1
+ endLine := s.LineMax
+
+ oldParentType := s.ParentType
+ s.ParentType = ptParagraph
+
+outer:
+ for ; nextLine < endLine && !s.IsLineEmpty(nextLine); nextLine++ {
+ if s.SCount[nextLine]-s.BlkIndent > 3 {
+ continue
+ }
+
+ if s.SCount[nextLine] < 0 {
+ continue
+ }
+
+ for _, r := range paragraphTerminatedBy {
+ if r(s, nextLine, endLine, true) {
+ break outer
+ }
+ }
+ }
+
+ content := strings.TrimSpace(s.Lines(startLine, nextLine, s.BlkIndent, false))
+
+ s.Line = nextLine
+
+ s.PushOpeningToken(&ParagraphOpen{
+ Map: [2]int{startLine, s.Line},
+ })
+ s.PushToken(&Inline{
+ Content: content,
+ Map: [2]int{startLine, s.Line},
+ })
+ s.PushClosingToken(&ParagraphClose{})
+
+ s.ParentType = oldParentType
+
+ return true
+}
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
+ }
+ }
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/parser_inline.go b/vendor/gitlab.com/golang-commonmark/markdown/parser_inline.go
new file mode 100644
index 00000000..5e976ebd
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/parser_inline.go
@@ -0,0 +1,106 @@
+// 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 "unicode/utf8"
+
+type ParserInline struct {
+}
+
+type (
+ InlineRule func(*StateInline, bool) bool
+ PostprocessRule func(*StateInline)
+)
+
+var (
+ inlineRules []InlineRule
+ postprocessRules []PostprocessRule
+)
+
+func (i ParserInline) Parse(src string, md *Markdown, env *Environment) []Token {
+ if src == "" {
+ return nil
+ }
+
+ var s StateInline
+ s.Src = src
+ s.Md = md
+ s.Env = env
+ s.PosMax = len(src)
+ s.Tokens = s.bootstrap[:0]
+
+ i.Tokenize(&s)
+
+ for _, r := range postprocessRules {
+ r(&s)
+ }
+
+ return s.Tokens
+}
+
+func (ParserInline) Tokenize(s *StateInline) {
+ end := s.PosMax
+ src := s.Src
+ maxNesting := s.Md.MaxNesting
+ ok := false
+
+ for s.Pos < end {
+ if s.Level < maxNesting {
+ for _, rule := range inlineRules {
+ ok = rule(s, false)
+ if ok {
+ break
+ }
+ }
+ }
+
+ if ok {
+ if s.Pos >= end {
+ break
+ }
+ continue
+ }
+
+ r, size := utf8.DecodeRuneInString(src[s.Pos:])
+ s.Pending.WriteRune(r)
+ s.Pos += size
+ }
+
+ if s.Pending.Len() > 0 {
+ s.PushPending()
+ }
+}
+
+func (ParserInline) SkipToken(s *StateInline) {
+ pos := s.Pos
+ if s.Cache != nil {
+ if newPos, ok := s.Cache[pos]; ok {
+ s.Pos = newPos
+ return
+ }
+ } else {
+ s.Cache = make(map[int]int)
+ }
+
+ ok := false
+ if s.Level < s.Md.MaxNesting {
+ for _, r := range inlineRules {
+ s.Level++
+ ok = r(s, true)
+ s.Level--
+ if ok {
+ break
+ }
+ }
+ } else {
+ s.Pos = s.PosMax
+ }
+
+ if !ok {
+ _, size := utf8.DecodeRuneInString(s.Src[s.Pos:])
+ s.Pos += size
+ }
+ s.Cache[pos] = s.Pos
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/plugins.go b/vendor/gitlab.com/golang-commonmark/markdown/plugins.go
new file mode 100644
index 00000000..5ba818cd
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/plugins.go
@@ -0,0 +1,158 @@
+// 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 "sort"
+
+type registeredCoreRule struct {
+ id int
+ rule CoreRule
+}
+
+var registeredCoreRules []registeredCoreRule
+
+type registeredBlockRule struct {
+ id int
+ rule BlockRule
+ terminates []int
+}
+
+var registeredBlockRules []registeredBlockRule
+
+type registeredInlineRule struct {
+ id int
+ rule InlineRule
+}
+
+var registeredInlineRules []registeredInlineRule
+
+type registeredPostprocessRule struct {
+ id int
+ rule PostprocessRule
+}
+
+var registeredPostprocessRules []registeredPostprocessRule
+
+func indexInt(a []int, n int) int {
+ for i, m := range a {
+ if m == n {
+ return i
+ }
+ }
+ return -1
+}
+
+func RegisterCoreRule(id int, rule CoreRule) {
+ registeredCoreRules = append(registeredCoreRules, registeredCoreRule{
+ id: id,
+ rule: rule,
+ })
+ sort.Slice(registeredCoreRules, func(i, j int) bool {
+ return registeredCoreRules[i].id < registeredCoreRules[j].id
+ })
+
+ coreRules = coreRules[:0]
+ for _, r := range registeredCoreRules {
+ coreRules = append(coreRules, r.rule)
+ }
+}
+
+func RegisterBlockRule(id int, rule BlockRule, terminates []int) {
+ registeredBlockRules = append(registeredBlockRules, registeredBlockRule{
+ id: id,
+ rule: rule,
+ terminates: terminates,
+ })
+ sort.Slice(registeredBlockRules, func(i, j int) bool {
+ return registeredBlockRules[i].id < registeredBlockRules[j].id
+ })
+
+ blockRules = blockRules[:0]
+ blockquoteTerminatedBy = blockquoteTerminatedBy[:0]
+ listTerminatedBy = listTerminatedBy[:0]
+ referenceTerminatedBy = referenceTerminatedBy[:0]
+ paragraphTerminatedBy = paragraphTerminatedBy[:0]
+ for _, r := range registeredBlockRules {
+ blockRules = append(blockRules, r.rule)
+ if indexInt(r.terminates, 400) != -1 {
+ blockquoteTerminatedBy = append(blockquoteTerminatedBy, r.rule)
+ }
+ if indexInt(r.terminates, 600) != -1 {
+ listTerminatedBy = append(listTerminatedBy, r.rule)
+ }
+ if indexInt(r.terminates, 700) != -1 {
+ referenceTerminatedBy = append(referenceTerminatedBy, r.rule)
+ }
+ if indexInt(r.terminates, 1100) != -1 {
+ paragraphTerminatedBy = append(paragraphTerminatedBy, r.rule)
+ }
+ }
+}
+
+func RegisterInlineRule(id int, rule InlineRule) {
+ registeredInlineRules = append(registeredInlineRules, registeredInlineRule{
+ id: id,
+ rule: rule,
+ })
+ sort.Slice(registeredInlineRules, func(i, j int) bool {
+ return registeredInlineRules[i].id < registeredInlineRules[j].id
+ })
+
+ inlineRules = inlineRules[:0]
+ for _, r := range registeredInlineRules {
+ inlineRules = append(inlineRules, r.rule)
+ }
+}
+
+func RegisterPostprocessRule(id int, rule PostprocessRule) {
+ registeredPostprocessRules = append(registeredPostprocessRules, registeredPostprocessRule{
+ id: id,
+ rule: rule,
+ })
+ sort.Slice(registeredPostprocessRules, func(i, j int) bool {
+ return registeredPostprocessRules[i].id < registeredPostprocessRules[j].id
+ })
+
+ postprocessRules = postprocessRules[:0]
+ for _, r := range registeredPostprocessRules {
+ postprocessRules = append(postprocessRules, r.rule)
+ }
+}
+
+func init() {
+ RegisterCoreRule(100, ruleInline)
+ RegisterCoreRule(200, ruleLinkify)
+ RegisterCoreRule(300, ruleReplacements)
+ RegisterCoreRule(400, ruleSmartQuotes)
+
+ RegisterBlockRule(100, ruleTable, []int{1100, 700})
+ RegisterBlockRule(200, ruleCode, nil)
+ RegisterBlockRule(300, ruleFence, []int{1100, 700, 400, 600})
+ RegisterBlockRule(400, ruleBlockQuote, []int{1100, 700, 400, 600})
+ RegisterBlockRule(500, ruleHR, []int{1100, 700, 400, 600})
+ RegisterBlockRule(600, ruleList, []int{1100, 700, 400})
+ RegisterBlockRule(700, ruleReference, nil)
+ RegisterBlockRule(800, ruleHeading, []int{1100, 700, 400})
+ RegisterBlockRule(900, ruleLHeading, nil)
+ RegisterBlockRule(1000, ruleHTMLBlock, []int{1100, 700, 400})
+ RegisterBlockRule(1100, ruleParagraph, nil)
+
+ RegisterInlineRule(100, ruleText)
+ RegisterInlineRule(200, ruleNewline)
+ RegisterInlineRule(300, ruleEscape)
+ RegisterInlineRule(400, ruleBackticks)
+ RegisterInlineRule(500, ruleStrikeThrough)
+ RegisterInlineRule(600, ruleEmphasis)
+ RegisterInlineRule(700, ruleLink)
+ RegisterInlineRule(800, ruleImage)
+ RegisterInlineRule(900, ruleAutolink)
+ RegisterInlineRule(1000, ruleHTMLInline)
+ RegisterInlineRule(1100, ruleEntity)
+
+ RegisterPostprocessRule(100, ruleBalancePairs)
+ RegisterPostprocessRule(200, ruleStrikethroughPostprocess)
+ RegisterPostprocessRule(300, ruleEmphasisPostprocess)
+ RegisterPostprocessRule(400, ruleTextCollapse)
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/reference.go b/vendor/gitlab.com/golang-commonmark/markdown/reference.go
new file mode 100644
index 00000000..6e97809e
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/reference.go
@@ -0,0 +1,173 @@
+// 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 "strings"
+
+var referenceTerminatedBy []BlockRule
+
+func ruleReference(s *StateBlock, startLine, _ int, silent bool) bool {
+ lines := 0
+ pos := s.BMarks[startLine] + s.TShift[startLine]
+ max := s.EMarks[startLine]
+ nextLine := startLine + 1
+
+ if s.SCount[startLine]-s.BlkIndent >= 4 {
+ return false
+ }
+
+ src := s.Src
+
+ if src[pos] != '[' {
+ return false
+ }
+
+ pos++
+ for pos < max {
+ if src[pos] == ']' && src[pos-1] != '\\' {
+ if pos+1 == max {
+ return false
+ }
+ if src[pos+1] != ':' {
+ return false
+ }
+ break
+ }
+ pos++
+ }
+
+ endLine := s.LineMax
+
+ oldParentType := s.ParentType
+ s.ParentType = ptReference
+outer:
+ for ; nextLine < endLine && !s.IsLineEmpty(nextLine); nextLine++ {
+ if s.SCount[nextLine]-s.BlkIndent > 3 {
+ continue
+ }
+
+ if s.SCount[nextLine] < 0 {
+ continue
+ }
+
+ for _, r := range referenceTerminatedBy {
+ if r(s, nextLine, endLine, true) {
+ break outer
+ }
+ }
+ }
+
+ str := strings.TrimSpace(s.Lines(startLine, nextLine, s.BlkIndent, false))
+ max = len(str)
+
+ var labelEnd int
+ for pos = 1; pos < max; pos++ {
+ b := str[pos]
+ if b == '[' {
+ return false
+ } else if b == ']' {
+ labelEnd = pos
+ break
+ } else if b == '\n' {
+ lines++
+ } else if b == '\\' {
+ pos++
+ if pos < max && str[pos] == '\n' {
+ lines++
+ }
+ }
+ }
+
+ if labelEnd <= 0 || labelEnd+1 >= max || str[labelEnd+1] != ':' {
+ return false
+ }
+
+ for pos = labelEnd + 2; pos < max; pos++ {
+ b := str[pos]
+ if b == '\n' {
+ lines++
+ } else if !byteIsSpace(b) {
+ break
+ }
+ }
+
+ href, nlines, endpos, ok := parseLinkDestination(str, pos, max)
+ if !ok {
+ return false
+ }
+ href = normalizeLink(href)
+ if !validateLink(href) {
+ return false
+ }
+
+ pos = endpos
+ lines += nlines
+
+ destEndPos := pos
+ destEndLineNo := lines
+
+ start := pos
+ for ; pos < max; pos++ {
+ b := str[pos]
+ if b == '\n' {
+ lines++
+ } else if !byteIsSpace(b) {
+ break
+ }
+ }
+
+ title, nlines, endpos, ok := parseLinkTitle(str, pos, max)
+ if pos < max && start != pos && ok {
+ pos = endpos
+ lines += nlines
+ } else {
+ pos = destEndPos
+ lines = destEndLineNo
+ }
+
+ for pos < max && byteIsSpace(str[pos]) {
+ pos++
+ }
+
+ if pos < max && str[pos] != '\n' {
+ if title != "" {
+ title = ""
+ pos = destEndPos
+ lines = destEndLineNo
+ for pos < max && byteIsSpace(src[pos]) {
+ pos++
+ }
+ }
+ }
+
+ if pos < max && str[pos] != '\n' {
+ return false
+ }
+
+ label := normalizeReference(str[1:labelEnd])
+ if label == "" {
+ return false
+ }
+
+ if silent {
+ return true
+ }
+
+ if s.Env.References == nil {
+ s.Env.References = make(map[string]map[string]string)
+ }
+ if _, ok := s.Env.References[label]; !ok {
+ s.Env.References[label] = map[string]string{
+ "title": title,
+ "href": href,
+ }
+ }
+
+ s.ParentType = oldParentType
+
+ s.Line = startLine + lines + 1
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/render.go b/vendor/gitlab.com/golang-commonmark/markdown/render.go
new file mode 100644
index 00000000..3955f051
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/render.go
@@ -0,0 +1,333 @@
+// 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 (
+ "io"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "gitlab.com/golang-commonmark/html"
+)
+
+type Renderer struct {
+ w *monadicWriter
+}
+
+func NewRenderer(w io.Writer) *Renderer {
+ return &Renderer{newMonadicWriter(w)}
+}
+
+func (r *Renderer) Render(tokens []Token, options RenderOptions) error {
+ for i, tok := range tokens {
+ if tok, ok := tok.(*Inline); ok {
+ r.renderInline(tok.Children, options)
+ } else {
+ r.renderToken(tokens, i, options)
+ }
+ }
+
+ r.w.Flush()
+
+ return r.w.err
+}
+
+func (r *Renderer) renderInline(tokens []Token, o RenderOptions) {
+ for i := range tokens {
+ r.renderToken(tokens, i, o)
+ }
+}
+
+func (r *Renderer) renderInlineAsText(tokens []Token) {
+ for _, tok := range tokens {
+ if text, ok := tok.(*Text); ok {
+ html.WriteEscapedString(r.w, text.Content)
+ } else if img, ok := tok.(*Image); ok {
+ r.renderInlineAsText(img.Tokens)
+ }
+ }
+}
+
+var rNotSpace = regexp.MustCompile(`^\S+`)
+
+func (r *Renderer) renderToken(tokens []Token, idx int, options RenderOptions) {
+ tok := tokens[idx]
+
+ if idx > 0 && tok.Block() && !tok.Closing() {
+ switch t := tokens[idx-1].(type) {
+ case *ParagraphOpen:
+ if t.Hidden {
+ r.w.WriteByte('\n')
+ }
+ case *ParagraphClose:
+ if t.Hidden {
+ r.w.WriteByte('\n')
+ }
+ }
+ }
+
+ switch tok := tok.(type) {
+ case *BlockquoteClose:
+ r.w.WriteString("")
+
+ case *BlockquoteOpen:
+ r.w.WriteString("")
+
+ case *BulletListClose:
+ r.w.WriteString("")
+
+ case *BulletListOpen:
+ r.w.WriteString("
")
+
+ case *CodeBlock:
+ r.w.WriteString("
")
+
+ case *CodeInline:
+ r.w.WriteString("")
+ html.WriteEscapedString(r.w, tok.Content)
+ r.w.WriteString("
")
+ html.WriteEscapedString(r.w, tok.Content)
+ r.w.WriteString("
")
+
+ case *EmphasisClose:
+ r.w.WriteString("")
+
+ case *EmphasisOpen:
+ r.w.WriteString("")
+
+ case *Fence:
+ r.w.WriteString("
")
+
+ case *Hardbreak:
+ if options.XHTML {
+ r.w.WriteString("')
+ html.WriteEscapedString(r.w, tok.Content)
+ r.w.WriteString("
\n")
+ } else {
+ r.w.WriteString("
\n")
+ }
+
+ case *HeadingClose:
+ r.w.WriteString("")
+
+ case *HeadingOpen:
+ r.w.WriteString("
")
+ } else {
+ r.w.WriteString("
")
+ }
+
+ case *HTMLBlock:
+ r.w.WriteString(tok.Content)
+ return // no newline
+
+ case *HTMLInline:
+ r.w.WriteString(tok.Content)
+
+ case *Image:
+ r.w.WriteString(`")
+ } else {
+ r.w.WriteByte('>')
+ }
+
+ case *LinkClose:
+ r.w.WriteString("")
+
+ case *LinkOpen:
+ r.w.WriteString(`')
+
+ case *ListItemClose:
+ r.w.WriteString("")
+
+ case *ListItemOpen:
+ r.w.WriteString("
`)
+ } else {
+ r.w.WriteString("
")
+ }
+
+ case *ParagraphClose:
+ if tok.Hidden {
+ return
+ }
+ if !tok.Tight {
+ r.w.WriteString("
")
+ }
+
+ case *Softbreak:
+ if options.Breaks {
+ if options.XHTML {
+ r.w.WriteString("
\n")
+ } else {
+ r.w.WriteString("
\n")
+ }
+ } else {
+ r.w.WriteByte('\n')
+ }
+ return
+
+ case *StrongClose:
+ r.w.WriteString("")
+
+ case *StrongOpen:
+ r.w.WriteString("")
+
+ case *StrikethroughClose:
+ r.w.WriteString("")
+
+ case *StrikethroughOpen:
+ r.w.WriteString("")
+
+ case *TableClose:
+ r.w.WriteString("")
+
+ case *TableOpen:
+ r.w.WriteString("")
+
+ case *TbodyClose:
+ r.w.WriteString("")
+
+ case *TbodyOpen:
+ r.w.WriteString("")
+
+ case *TdClose:
+ r.w.WriteString("")
+
+ case *TdOpen:
+ if tok.Align != AlignNone {
+ r.w.WriteString(`
`)
+ } else {
+ r.w.WriteString(" ")
+ }
+
+ case *Text:
+ html.WriteEscapedString(r.w, tok.Content)
+
+ case *TheadClose:
+ r.w.WriteString("")
+
+ case *TheadOpen:
+ r.w.WriteString("")
+
+ case *ThClose:
+ r.w.WriteString("")
+
+ case *ThOpen:
+ if align := tok.Align; align != AlignNone {
+ r.w.WriteString(` `)
+ } else {
+ r.w.WriteString(" ")
+ }
+
+ case *TrClose:
+ r.w.WriteString("")
+
+ case *TrOpen:
+ r.w.WriteString(" ")
+
+ default:
+ panic("unknown token type")
+ }
+
+ needLf := false
+ if tok.Block() {
+ needLf = true
+
+ if tok.Opening() {
+ nextTok := tokens[idx+1]
+ blockquote := false
+ switch nextTok := nextTok.(type) {
+ case *Inline:
+ needLf = false
+ case *ParagraphOpen:
+ if nextTok.Tight || nextTok.Hidden {
+ needLf = false
+ }
+ case *ParagraphClose:
+ if nextTok.Tight || nextTok.Hidden {
+ needLf = false
+ }
+ case *BlockquoteClose:
+ blockquote = true
+ }
+ if !blockquote && needLf && nextTok.Closing() && nextTok.Tag() == tok.Tag() {
+ needLf = false
+ }
+ }
+ }
+
+ if needLf {
+ r.w.WriteByte('\n')
+ }
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/replacements.go b/vendor/gitlab.com/golang-commonmark/markdown/replacements.go
new file mode 100644
index 00000000..8d67af6e
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/replacements.go
@@ -0,0 +1,229 @@
+// 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 "strings"
+
+func exclquest(b byte) bool {
+ return b == '!' || b == '?'
+}
+
+func byteToLower(b byte) byte {
+ if b >= 'A' && b <= 'Z' {
+ return b - 'A' + 'a'
+ }
+ return b
+}
+
+var replChar = [256]bool{
+ '(': true,
+ '!': true,
+ '+': true,
+ ',': true,
+ '-': true,
+ '.': true,
+ '?': true,
+}
+
+func performReplacements(s string) string {
+ var ss []string
+
+ start := 0
+ for i := 0; i < len(s); i++ {
+ b := s[i]
+
+ if replChar[b] {
+
+ outer:
+ switch b {
+ case '(':
+ if i+2 >= len(s) {
+ break
+ }
+
+ b2 := s[i+1]
+
+ b2 = byteToLower(b2)
+ switch b2 {
+ case 'c', 'r', 'p':
+ if s[i+2] != ')' {
+ break outer
+ }
+ switch b2 {
+ case 'c':
+ if start < i {
+ ss = append(ss, s[start:i])
+ }
+ ss = append(ss, "©")
+ case 'r':
+ if start < i {
+ ss = append(ss, s[start:i])
+ }
+ ss = append(ss, "®")
+ case 'p':
+ if start < i {
+ ss = append(ss, s[start:i])
+ }
+ ss = append(ss, "§")
+ }
+ i += 2
+ start = i + 1
+ continue
+
+ case 't':
+ if i+3 >= len(s) {
+ break outer
+ }
+ if s[i+3] != ')' || byteToLower(s[i+2]) != 'm' {
+ break outer
+ }
+ if start < i {
+ ss = append(ss, s[start:i])
+ }
+ ss = append(ss, "™")
+ i += 3
+ start = i + 1
+ continue
+ default:
+ break outer
+ }
+
+ case '+':
+ if i+1 >= len(s) || s[i+1] != '-' {
+ break
+ }
+ if start < i {
+ ss = append(ss, s[start:i])
+ }
+ ss = append(ss, "±")
+ i++
+ start = i + 1
+ continue
+
+ case '.':
+ if i+1 >= len(s) || s[i+1] != '.' {
+ break
+ }
+
+ j := i + 2
+ for j < len(s) && s[j] == '.' {
+ j++
+ }
+ if start < i {
+ ss = append(ss, s[start:i])
+ }
+ if i == 0 || !(s[i-1] == '?' || s[i-1] == '!') {
+ ss = append(ss, "…")
+ } else {
+ ss = append(ss, "..")
+ }
+ i = j - 1
+ start = i + 1
+ continue
+
+ case '?', '!':
+ if i+3 >= len(s) {
+ break
+ }
+ if !(exclquest(s[i+1]) && exclquest(s[i+2]) && exclquest(s[i+3])) {
+ break
+ }
+ if start < i {
+ ss = append(ss, s[start:i])
+ }
+ ss = append(ss, s[i:i+3])
+ j := i + 3
+ for j < len(s) && exclquest(s[j]) {
+ j++
+ }
+ i = j - 1
+ start = i + 1
+ continue
+
+ case ',':
+ if i+1 >= len(s) || s[i+1] != ',' {
+ break
+ }
+ if start < i {
+ ss = append(ss, s[start:i])
+ }
+ ss = append(ss, ",")
+ j := i + 2
+ for j < len(s) && s[j] == ',' {
+ j++
+ }
+ i = j - 1
+ start = i + 1
+ continue
+
+ case '-':
+ if i+1 >= len(s) || s[i+1] != '-' {
+ break
+ }
+ if i+2 >= len(s) || s[i+2] != '-' {
+ if start < i {
+ ss = append(ss, s[start:i])
+ }
+ ss = append(ss, "–")
+ i++
+ start = i + 1
+ continue
+ }
+ if i+3 >= len(s) || s[i+3] != '-' {
+ if start < i {
+ ss = append(ss, s[start:i])
+ }
+ ss = append(ss, "—")
+ i += 2
+ start = i + 1
+ continue
+ }
+
+ j := i + 3
+ for j < len(s) && s[j] == '-' {
+ j++
+ }
+ if start < i {
+ ss = append(ss, s[start:i])
+ }
+ ss = append(ss, s[i:j])
+ i = j - 1
+ start = i + 1
+ continue
+ }
+ }
+ }
+ if ss == nil {
+ return s
+ }
+ if start < len(s) {
+ ss = append(ss, s[start:])
+ }
+ return strings.Join(ss, "")
+}
+
+func ruleReplacements(s *StateCore) {
+ if !s.Md.Typographer {
+ return
+ }
+
+ insideLink := false
+ for _, tok := range s.Tokens {
+ if tok, ok := tok.(*Inline); ok {
+ for _, itok := range tok.Children {
+ switch itok := itok.(type) {
+ case *LinkOpen:
+ insideLink = true
+ case *LinkClose:
+ insideLink = false
+ case *Text:
+ if !insideLink {
+ itok.Content = performReplacements(itok.Content)
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/smartquotes.go b/vendor/gitlab.com/golang-commonmark/markdown/smartquotes.go
new file mode 100644
index 00000000..cbfa9c58
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/smartquotes.go
@@ -0,0 +1,256 @@
+// 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 (
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+func nextQuoteIndex(s []rune, from int) int {
+ for i := from; i < len(s); i++ {
+ r := s[i]
+ if r == '\'' || r == '"' {
+ return i
+ }
+ }
+ return -1
+}
+
+func firstRune(s string) rune {
+ for _, r := range s {
+ return r
+ }
+ return utf8.RuneError
+}
+
+func replaceQuotes(tokens []Token, s *StateCore) {
+ type stackItem struct {
+ token int
+ text []rune
+ pos int
+ single bool
+ level int
+ }
+ var stack []stackItem
+ var changed map[int][]rune
+
+ for i, tok := range tokens {
+ thisLevel := tok.Level()
+
+ j := len(stack) - 1
+ for j >= 0 {
+ if stack[j].level <= thisLevel {
+ break
+ }
+ j--
+ }
+ stack = stack[:j+1]
+
+ tok, ok := tok.(*Text)
+ if !ok || !strings.ContainsAny(tok.Content, `"'`) {
+ continue
+ }
+
+ text := []rune(tok.Content)
+ pos := 0
+ max := len(text)
+
+ loop:
+ for pos < max {
+ index := nextQuoteIndex(text, pos)
+ if index < 0 {
+ break
+ }
+
+ canOpen := true
+ canClose := true
+ pos = index + 1
+ isSingle := text[index] == '\''
+
+ lastChar := ' '
+ if index-1 > 0 {
+ lastChar = text[index-1]
+ } else {
+ loop1:
+ for j := i - 1; j >= 0; j-- {
+ switch tok := tokens[j].(type) {
+ case *Softbreak:
+ break loop1
+ case *Hardbreak:
+ break loop1
+ case *Text:
+ lastChar, _ = utf8.DecodeLastRuneInString(tok.Content)
+ break loop1
+ default:
+ continue
+ }
+ }
+ }
+
+ nextChar := ' '
+ if pos < max {
+ nextChar = text[pos]
+ } else {
+ loop2:
+ for j := i + 1; j < len(tokens); j++ {
+ switch tok := tokens[j].(type) {
+ case *Softbreak:
+ break loop2
+ case *Hardbreak:
+ break loop2
+ case *Text:
+ nextChar, _ = utf8.DecodeRuneInString(tok.Content)
+ break loop2
+ default:
+ continue
+ }
+ }
+ }
+
+ isLastPunct := isMdAsciiPunct(lastChar) || unicode.IsPunct(lastChar)
+ isNextPunct := isMdAsciiPunct(nextChar) || unicode.IsPunct(nextChar)
+ isLastWhiteSpace := unicode.IsSpace(lastChar)
+ isNextWhiteSpace := unicode.IsSpace(nextChar)
+
+ if isNextWhiteSpace {
+ canOpen = false
+ } else if isNextPunct {
+ if !(isLastWhiteSpace || isLastPunct) {
+ canOpen = false
+ }
+ }
+
+ if isLastWhiteSpace {
+ canClose = false
+ } else if isLastPunct {
+ if !(isNextWhiteSpace || isNextPunct) {
+ canClose = false
+ }
+ }
+
+ if nextChar == '"' && text[index] == '"' {
+ if lastChar >= '0' && lastChar <= '9' {
+ canClose = false
+ canOpen = false
+ }
+ }
+
+ if canOpen && canClose {
+ canOpen = false
+ canClose = isNextPunct
+ }
+
+ if !canOpen && !canClose {
+ if isSingle {
+ text[index] = '’'
+ if changed == nil {
+ changed = make(map[int][]rune)
+ }
+ changed[i] = text
+ }
+ continue
+ }
+
+ if canClose {
+ for j := len(stack) - 1; j >= 0; j-- {
+ item := stack[j]
+ if item.level < thisLevel {
+ break
+ }
+ if item.single == isSingle && item.level == thisLevel {
+ if changed == nil {
+ changed = make(map[int][]rune)
+ }
+
+ var q1, q2 string
+ if isSingle {
+ q1 = s.Md.options.Quotes[2]
+ q2 = s.Md.options.Quotes[3]
+ } else {
+ q1 = s.Md.options.Quotes[0]
+ q2 = s.Md.options.Quotes[1]
+ }
+
+ if utf8.RuneCountInString(q1) == 1 && utf8.RuneCountInString(q2) == 1 {
+ item.text[item.pos] = firstRune(q1)
+ text[index] = firstRune(q2)
+ } else if tok == tokens[item.token] {
+ newText := make([]rune, 0, len(text)-2+len(q1)+len(q2))
+ newText = append(newText, text[:item.pos]...)
+ newText = append(newText, []rune(q1)...)
+ newText = append(newText, text[item.pos+1:index]...)
+ newText = append(newText, []rune(q2)...)
+ newText = append(newText, text[index+1:]...)
+
+ text = newText
+ item.text = newText
+ } else {
+ newText := make([]rune, 0, len(item.text)-1+len(q1))
+ newText = append(newText, item.text[:item.pos]...)
+ newText = append(newText, []rune(q1)...)
+ newText = append(newText, item.text[item.pos+1:]...)
+ item.text = newText
+
+ newText = make([]rune, 0, len(text)-1+len(q2))
+ newText = append(newText, text[:index]...)
+ newText = append(newText, []rune(q2)...)
+ newText = append(newText, text[index+1:]...)
+
+ text = newText
+ }
+
+ max = len(text)
+
+ if changed == nil {
+ changed = make(map[int][]rune)
+ }
+ changed[i] = text
+ changed[item.token] = item.text
+ stack = stack[:j]
+ continue loop
+ }
+ }
+ }
+
+ if canOpen {
+ stack = append(stack, stackItem{
+ token: i,
+ text: text,
+ pos: index,
+ single: isSingle,
+ level: thisLevel,
+ })
+ } else if canClose && isSingle {
+ text[index] = '’'
+ if changed == nil {
+ changed = make(map[int][]rune)
+ }
+ changed[i] = text
+ }
+ }
+ }
+
+ if changed != nil {
+ for i, text := range changed {
+ tokens[i].(*Text).Content = string(text)
+ }
+ }
+}
+
+func ruleSmartQuotes(s *StateCore) {
+ if !s.Md.Typographer {
+ return
+ }
+
+ tokens := s.Tokens
+ for i := len(tokens) - 1; i >= 0; i-- {
+ tok := tokens[i]
+ if tok, ok := tok.(*Inline); ok {
+ replaceQuotes(tok.Children, s)
+ }
+ }
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/state_block.go b/vendor/gitlab.com/golang-commonmark/markdown/state_block.go
new file mode 100644
index 00000000..e1142416
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/state_block.go
@@ -0,0 +1,141 @@
+// 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 "strings"
+
+const (
+ ptRoot = iota
+ ptList
+ ptBlockQuote
+ ptParagraph
+ ptReference
+)
+
+type StateBlock struct {
+ StateCore
+
+ BMarks []int // offsets of the line beginnings
+ EMarks []int // offsets of the line endings
+ TShift []int // indents for each line
+ SCount []int
+ BSCount []int
+ BlkIndent int // required block content indent (in a list etc.)
+ Line int // line index in the source string
+ LineMax int // number of lines
+ Tight bool // loose or tight mode for lists
+ ParentType byte // parent block type
+ Level int
+}
+
+func (s *StateBlock) IsLineEmpty(n int) bool {
+ return s.BMarks[n]+s.TShift[n] >= s.EMarks[n]
+}
+
+func (s *StateBlock) SkipEmptyLines(from int) int {
+ for from < s.LineMax && s.IsLineEmpty(from) {
+ from++
+ }
+ return from
+}
+
+func (s *StateBlock) SkipSpaces(pos int) int {
+ src := s.Src
+ for pos < len(src) && byteIsSpace(src[pos]) {
+ pos++
+ }
+ return pos
+}
+
+func (s *StateBlock) SkipBytes(pos int, b byte) int {
+ src := s.Src
+ for pos < len(src) && src[pos] == b {
+ pos++
+ }
+ return pos
+}
+
+func (s *StateBlock) SkipBytesBack(pos int, b byte, min int) int {
+ for pos > min {
+ pos--
+ if s.Src[pos] != b {
+ return pos + 1
+ }
+ }
+ return pos
+}
+
+func (s *StateBlock) SkipSpacesBack(pos int, min int) int {
+ for pos > min {
+ pos--
+ if !byteIsSpace(s.Src[pos]) {
+ return pos + 1
+ }
+ }
+ return pos
+}
+
+func (s *StateBlock) Lines(begin, end, indent int, keepLastLf bool) string {
+ if begin == end {
+ return ""
+ }
+
+ src := s.Src
+
+ queue := make([]string, end-begin)
+
+ for i, line := 0, begin; line < end; i, line = i+1, line+1 {
+ lineIndent := 0
+ lineStart := s.BMarks[line]
+ first := lineStart
+ last := s.EMarks[line]
+ if (line+1 < end || keepLastLf) && last < len(src) {
+ last++
+ }
+
+ for first < last && lineIndent < indent {
+ ch := src[first]
+
+ if byteIsSpace(ch) {
+ if ch == '\t' {
+ lineIndent += 4 - (lineIndent+s.BSCount[line])%4
+ } else {
+ lineIndent++
+ }
+ } else if first-lineStart < s.TShift[line] {
+ lineIndent++
+ } else {
+ break
+ }
+
+ first++
+ }
+
+ if lineIndent > indent {
+ queue[i] = strings.Repeat(" ", lineIndent-indent) + src[first:last]
+ } else {
+ queue[i] = src[first:last]
+ }
+ }
+
+ return strings.Join(queue, "")
+}
+
+func (s *StateBlock) PushToken(tok Token) {
+ tok.SetLevel(s.Level)
+ s.Tokens = append(s.Tokens, tok)
+}
+
+func (s *StateBlock) PushOpeningToken(tok Token) {
+ tok.SetLevel(s.Level)
+ s.Level++
+ s.Tokens = append(s.Tokens, tok)
+}
+
+func (s *StateBlock) PushClosingToken(tok Token) {
+ s.Level--
+ tok.SetLevel(s.Level)
+ s.Tokens = append(s.Tokens, tok)
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/state_core.go b/vendor/gitlab.com/golang-commonmark/markdown/state_core.go
new file mode 100644
index 00000000..24e51756
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/state_core.go
@@ -0,0 +1,13 @@
+// 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
+
+type StateCore struct {
+ Src string
+ Tokens []Token
+ bootstrap [3]Token
+ Md *Markdown
+ Env *Environment
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/state_inline.go b/vendor/gitlab.com/golang-commonmark/markdown/state_inline.go
new file mode 100644
index 00000000..4bc08cf5
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/state_inline.go
@@ -0,0 +1,116 @@
+// 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"
+ "unicode/utf8"
+)
+
+type StateInline struct {
+ StateCore
+
+ Pos int
+ PosMax int
+ Level int
+ Pending bytes.Buffer
+ PendingLevel int
+ Delimiters []Delimiter
+
+ Cache map[int]int
+}
+
+func (s *StateInline) PushToken(tok Token) {
+ if s.Pending.Len() > 0 {
+ s.PushPending()
+ }
+ tok.SetLevel(s.Level)
+ s.PendingLevel = s.Level
+ s.Tokens = append(s.Tokens, tok)
+}
+
+func (s *StateInline) PushOpeningToken(tok Token) {
+ if s.Pending.Len() > 0 {
+ s.PushPending()
+ }
+ tok.SetLevel(s.Level)
+ s.Level++
+ s.PendingLevel = s.Level
+ s.Tokens = append(s.Tokens, tok)
+}
+
+func (s *StateInline) PushClosingToken(tok Token) {
+ if s.Pending.Len() > 0 {
+ s.PushPending()
+ }
+ s.Level--
+ tok.SetLevel(s.Level)
+ s.PendingLevel = s.Level
+ s.Tokens = append(s.Tokens, tok)
+}
+
+func (s *StateInline) PushPending() {
+ s.Tokens = append(s.Tokens, &Text{
+ Content: s.Pending.String(),
+ Lvl: s.PendingLevel,
+ })
+ s.Pending.Reset()
+}
+
+func (s *StateInline) scanDelims(start int, canSplitWord bool) (canOpen bool, canClose bool, length int) {
+ pos := start
+ max := s.PosMax
+ src := s.Src
+ marker := src[start]
+ leftFlanking, rightFlanking := true, true
+
+ lastChar := ' '
+ if start > 0 {
+ lastChar, _ = utf8.DecodeLastRuneInString(src[:start])
+ }
+
+ for pos < max && src[pos] == marker {
+ pos++
+ }
+ length = pos - start
+
+ nextChar := ' '
+ if pos < max {
+ nextChar, _ = utf8.DecodeRuneInString(src[pos:])
+ }
+
+ isLastPunct := isMdAsciiPunct(lastChar) || unicode.IsPunct(lastChar)
+ isNextPunct := isMdAsciiPunct(nextChar) || unicode.IsPunct(nextChar)
+
+ isLastWhiteSpace := unicode.IsSpace(lastChar)
+ isNextWhiteSpace := unicode.IsSpace(nextChar)
+
+ if isNextWhiteSpace {
+ leftFlanking = false
+ } else if isNextPunct {
+ if !(isLastWhiteSpace || isLastPunct) {
+ leftFlanking = false
+ }
+ }
+
+ if isLastWhiteSpace {
+ rightFlanking = false
+ } else if isLastPunct {
+ if !(isNextWhiteSpace || isNextPunct) {
+ rightFlanking = false
+ }
+ }
+
+ if !canSplitWord {
+ canOpen = leftFlanking && (!rightFlanking || isLastPunct)
+ canClose = rightFlanking && (!leftFlanking || isNextPunct)
+ } else {
+ canOpen = leftFlanking
+ canClose = rightFlanking
+ }
+
+ return
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/strikethrough.go b/vendor/gitlab.com/golang-commonmark/markdown/strikethrough.go
new file mode 100644
index 00000000..18079945
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/strikethrough.go
@@ -0,0 +1,101 @@
+// 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
+
+func ruleStrikeThrough(s *StateInline, silent bool) bool {
+ src := s.Src
+ start := s.Pos
+ marker := src[start]
+
+ if silent {
+ return false
+ }
+
+ if src[start] != '~' {
+ return false
+ }
+
+ canOpen, canClose, length := s.scanDelims(start, true)
+ origLength := length
+ ch := string(marker)
+ if length < 2 {
+ return false
+ }
+
+ if length%2 != 0 {
+ s.PushToken(&Text{
+ Content: ch,
+ })
+ length--
+ }
+
+ for i := 0; i < length; i += 2 {
+ s.PushToken(&Text{
+ Content: ch + ch,
+ })
+
+ s.Delimiters = append(s.Delimiters, Delimiter{
+ Marker: marker,
+ Length: -1,
+ Jump: i,
+ Token: len(s.Tokens) - 1,
+ Level: s.Level,
+ End: -1,
+ Open: canOpen,
+ Close: canClose,
+ })
+ }
+
+ s.Pos += origLength
+
+ return true
+
+}
+
+func ruleStrikethroughPostprocess(s *StateInline) {
+ var loneMarkers []int
+ delimiters := s.Delimiters
+ max := len(delimiters)
+
+ for i := 0; i < max; i++ {
+ startDelim := delimiters[i]
+
+ if startDelim.Marker != '~' {
+ continue
+ }
+
+ if startDelim.End == -1 {
+ continue
+ }
+
+ endDelim := delimiters[startDelim.End]
+
+ s.Tokens[startDelim.Token] = &StrikethroughOpen{}
+ s.Tokens[endDelim.Token] = &StrikethroughClose{}
+
+ if text, ok := s.Tokens[endDelim.Token-1].(*Text); ok && text.Content == "~" {
+ loneMarkers = append(loneMarkers, endDelim.Token-1)
+ }
+ }
+
+ for len(loneMarkers) > 0 {
+ i := loneMarkers[len(loneMarkers)-1]
+ loneMarkers = loneMarkers[:len(loneMarkers)-1]
+ j := i + 1
+
+ for j < len(s.Tokens) {
+ if _, ok := s.Tokens[j].(*StrikethroughClose); !ok {
+ break
+ }
+ j++
+ }
+
+ j--
+
+ if i != j {
+ s.Tokens[i], s.Tokens[j] = s.Tokens[j], s.Tokens[i]
+ }
+ }
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/table.go b/vendor/gitlab.com/golang-commonmark/markdown/table.go
new file mode 100644
index 00000000..52ee176e
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/table.go
@@ -0,0 +1,229 @@
+// 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 (
+ "regexp"
+ "strings"
+)
+
+func getLine(s *StateBlock, line int) string {
+ pos := s.BMarks[line] + s.BlkIndent
+ max := s.EMarks[line]
+ if pos >= max {
+ return ""
+ }
+ return s.Src[pos:max]
+}
+
+func escapedSplit(s string) (result []string) {
+ pos := 0
+ escapes := 0
+ lastPos := 0
+ backTicked := false
+ lastBackTick := 0
+
+ for pos < len(s) {
+ ch := s[pos]
+ if ch == '`' {
+ if backTicked {
+ backTicked = false
+ lastBackTick = pos
+ } else if escapes%2 == 0 {
+ backTicked = true
+ lastBackTick = pos
+ }
+ } else if ch == '|' && (escapes%2 == 0) && !backTicked {
+ result = append(result, s[lastPos:pos])
+ lastPos = pos + 1
+ }
+
+ if ch == '\\' {
+ escapes++
+ } else {
+ escapes = 0
+ }
+
+ pos++
+
+ if pos == len(s) && backTicked {
+ backTicked = false
+ pos = lastBackTick + 1
+ }
+ }
+
+ return append(result, s[lastPos:])
+}
+
+var rColumn = regexp.MustCompile("^:?-+:?$")
+
+func ruleTable(s *StateBlock, startLine, endLine int, silent bool) bool {
+ if !s.Md.Tables {
+ return false
+ }
+
+ if startLine+2 > endLine {
+ return false
+ }
+
+ nextLine := startLine + 1
+
+ if s.SCount[nextLine] < s.BlkIndent {
+ return false
+ }
+
+ if s.SCount[nextLine]-s.BlkIndent >= 4 {
+ return false
+ }
+
+ pos := s.BMarks[nextLine] + s.TShift[nextLine]
+ if pos >= s.EMarks[nextLine] {
+ return false
+ }
+
+ src := s.Src
+ ch := src[pos]
+ pos++
+
+ if ch != '|' && ch != '-' && ch != ':' {
+ return false
+ }
+
+ for pos < s.EMarks[nextLine] {
+ ch = src[pos]
+ if ch != '|' && ch != '-' && ch != ':' && !byteIsSpace(ch) {
+ return false
+ }
+ pos++
+ }
+
+ //
+
+ lineText := getLine(s, startLine+1)
+
+ columns := strings.Split(lineText, "|")
+ var aligns []Align
+ for i := 0; i < len(columns); i++ {
+ t := strings.TrimSpace(columns[i])
+ if t == "" {
+ if i == 0 || i == len(columns)-1 {
+ continue
+ }
+ return false
+ }
+
+ if !rColumn.MatchString(t) {
+ return false
+ }
+
+ if t[len(t)-1] == ':' {
+ if t[0] == ':' {
+ aligns = append(aligns, AlignCenter)
+ } else {
+ aligns = append(aligns, AlignRight)
+ }
+ } else if t[0] == ':' {
+ aligns = append(aligns, AlignLeft)
+ } else {
+ aligns = append(aligns, AlignNone)
+ }
+ }
+
+ lineText = strings.TrimSpace(getLine(s, startLine))
+ if strings.IndexByte(lineText, '|') == -1 {
+ return false
+ }
+ if s.SCount[startLine]-s.BlkIndent >= 4 {
+ return false
+ }
+ columns = escapedSplit(strings.TrimSuffix(strings.TrimPrefix(lineText, "|"), "|"))
+ columnCount := len(columns)
+ if columnCount > len(aligns) {
+ return false
+ }
+
+ if silent {
+ return true
+ }
+
+ tableTok := &TableOpen{
+ Map: [2]int{startLine, 0},
+ }
+ s.PushOpeningToken(tableTok)
+ s.PushOpeningToken(&TheadOpen{
+ Map: [2]int{startLine, startLine + 1},
+ })
+ s.PushOpeningToken(&TrOpen{
+ Map: [2]int{startLine, startLine + 1},
+ })
+
+ for i := 0; i < len(columns); i++ {
+ s.PushOpeningToken(&ThOpen{
+ Align: aligns[i],
+ Map: [2]int{startLine, startLine + 1},
+ })
+ s.PushToken(&Inline{
+ Content: strings.TrimSpace(columns[i]),
+ Map: [2]int{startLine, startLine + 1},
+ })
+ s.PushClosingToken(&ThClose{})
+ }
+
+ s.PushClosingToken(&TrClose{})
+ s.PushClosingToken(&TheadClose{})
+
+ tbodyTok := &TbodyOpen{
+ Map: [2]int{startLine + 2, 0},
+ }
+ s.PushOpeningToken(tbodyTok)
+
+ for nextLine = startLine + 2; nextLine < endLine; nextLine++ {
+ if s.SCount[nextLine] < s.BlkIndent {
+ break
+ }
+
+ lineText = strings.TrimSpace(getLine(s, nextLine))
+ if strings.IndexByte(lineText, '|') == -1 {
+ break
+ }
+ if s.SCount[nextLine]-s.BlkIndent >= 4 {
+ break
+ }
+ columns = escapedSplit(strings.TrimPrefix(strings.TrimSuffix(lineText, "|"), "|"))
+
+ if len(columns) < len(aligns) {
+ columns = append(columns, make([]string, len(aligns)-len(columns))...)
+ } else if len(columns) > len(aligns) {
+ columns = columns[:len(aligns)]
+ }
+
+ s.PushOpeningToken(&TrOpen{})
+ for i := 0; i < columnCount; i++ {
+ tdOpen := TdOpen{}
+ if i < len(aligns) {
+ tdOpen.Align = aligns[i]
+ }
+ s.PushOpeningToken(&tdOpen)
+
+ inline := Inline{}
+ if i < len(columns) {
+ inline.Content = strings.TrimSpace(columns[i])
+ }
+ s.PushToken(&inline)
+
+ s.PushClosingToken(&TdClose{})
+ }
+ s.PushClosingToken(&TrClose{})
+ }
+
+ s.PushClosingToken(&TbodyClose{})
+ s.PushClosingToken(&TableClose{})
+
+ tableTok.Map[1] = nextLine
+ tbodyTok.Map[1] = nextLine
+ s.Line = nextLine
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/table_fsm.go b/vendor/gitlab.com/golang-commonmark/markdown/table_fsm.go
new file mode 100644
index 00000000..b605e45c
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/table_fsm.go
@@ -0,0 +1,108 @@
+// 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
+
+func isHeaderLine(s string) bool {
+ if s == "" {
+ return false
+ }
+
+ st := 0
+ n := 0
+ for i := 0; i < len(s); i++ {
+ b := s[i]
+ switch st {
+ case 0: // initial state
+ switch b {
+ case '|':
+ st = 1
+ case ':':
+ st = 2
+ case '-':
+ st = 3
+ n++
+ case ' ':
+ break
+ default:
+ return false
+ }
+
+ case 1: // |
+ switch b {
+ case ' ':
+ break
+ case ':':
+ st = 2
+ case '-':
+ st = 3
+ n++
+ default:
+ return false
+ }
+
+ case 2: // |:
+ switch b {
+ case ' ':
+ break
+ case '-':
+ st = 3
+ n++
+ default:
+ return false
+ }
+
+ case 3: // |:-
+ switch b {
+ case '-':
+ break
+ case ':':
+ st = 4
+ case '|':
+ st = 5
+ case ' ':
+ st = 6
+ default:
+ return false
+ }
+
+ case 4: // |:---:
+ switch b {
+ case ' ':
+ break
+ case '|':
+ st = 5
+ default:
+ return false
+ }
+
+ case 5: // |:---:|
+ switch b {
+ case ' ':
+ break
+ case ':':
+ st = 2
+ case '-':
+ st = 3
+ n++
+ default:
+ return false
+ }
+
+ case 6: // |:--- SPACE
+ switch b {
+ case ' ':
+ break
+ case ':':
+ st = 4
+ case '|':
+ st = 5
+ default:
+ return false
+ }
+ }
+ }
+
+ return n >= 1
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/text.go b/vendor/gitlab.com/golang-commonmark/markdown/text.go
new file mode 100644
index 00000000..ae98e743
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/text.go
@@ -0,0 +1,52 @@
+// 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
+
+var terminatorCharTable = [256]bool{
+ '\n': true,
+ '!': true,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': true,
+ '*': true,
+ '+': true,
+ '-': true,
+ ':': true,
+ '<': true,
+ '=': true,
+ '>': true,
+ '@': true,
+ '[': true,
+ '\\': true,
+ ']': true,
+ '^': true,
+ '_': true,
+ '`': true,
+ '{': true,
+ '}': true,
+ '~': true,
+}
+
+func ruleText(s *StateInline, silent bool) bool {
+ pos := s.Pos
+ max := s.PosMax
+ src := s.Src
+
+ for pos < max && !terminatorCharTable[src[pos]] {
+ pos++
+ }
+ if pos == s.Pos {
+ return false
+ }
+
+ if !silent {
+ s.Pending.WriteString(src[s.Pos:pos])
+ }
+
+ s.Pos = pos
+
+ return true
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/text_collapse.go b/vendor/gitlab.com/golang-commonmark/markdown/text_collapse.go
new file mode 100644
index 00000000..25b98b80
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/text_collapse.go
@@ -0,0 +1,42 @@
+// 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
+
+func ruleTextCollapse(s *StateInline) {
+ level := 0
+ tokens := s.Tokens
+ max := len(tokens)
+
+ curr := 0
+ last := 0
+ for ; curr < max; curr++ {
+ tok := tokens[curr]
+ if tok.Opening() {
+ level++
+ } else if tok.Closing() {
+ level--
+ }
+
+ tok.SetLevel(level)
+
+ if text, ok := tok.(*Text); ok && curr+1 < max {
+ if text2, ok := tokens[curr+1].(*Text); ok {
+ text2.Content = text.Content + text2.Content
+ continue
+ }
+ }
+
+ if curr != last {
+ tokens[last] = tokens[curr]
+ }
+ last++
+ }
+
+ if curr != last {
+ tokens = tokens[:last]
+ }
+
+ s.Tokens = tokens
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/token.go b/vendor/gitlab.com/golang-commonmark/markdown/token.go
new file mode 100644
index 00000000..1b14e5fe
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/token.go
@@ -0,0 +1,753 @@
+// 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
+
+type Token interface {
+ Tag() string
+ Opening() bool
+ Closing() bool
+ Block() bool
+ Level() int
+ SetLevel(lvl int)
+}
+
+type BlockquoteOpen struct {
+ Map [2]int
+ Lvl int
+}
+
+type BlockquoteClose struct {
+ Lvl int
+}
+
+type BulletListOpen struct {
+ Map [2]int
+ Lvl int
+}
+
+type BulletListClose struct {
+ Lvl int
+}
+
+type OrderedListOpen struct {
+ Order int
+ Map [2]int
+ Lvl int
+}
+
+type OrderedListClose struct {
+ Lvl int
+}
+
+type ListItemOpen struct {
+ Map [2]int
+ Lvl int
+}
+
+type ListItemClose struct {
+ Lvl int
+}
+
+type CodeBlock struct {
+ Content string
+ Map [2]int
+ Lvl int
+}
+
+type CodeInline struct {
+ Content string
+ Lvl int
+}
+
+type EmphasisOpen struct {
+ Lvl int
+}
+
+type EmphasisClose struct {
+ Lvl int
+}
+
+type StrongOpen struct {
+ Lvl int
+}
+
+type StrongClose struct {
+ Lvl int
+}
+
+type StrikethroughOpen struct {
+ Lvl int
+}
+
+type StrikethroughClose struct {
+ Lvl int
+}
+
+type Fence struct {
+ Params string
+ Content string
+ Map [2]int
+ Lvl int
+}
+
+type Softbreak struct {
+ Lvl int
+}
+
+type Hardbreak struct {
+ Lvl int
+}
+
+type HeadingOpen struct {
+ HLevel int
+ Map [2]int
+ Lvl int
+}
+
+type HeadingClose struct {
+ HLevel int
+ Lvl int
+}
+
+type HTMLBlock struct {
+ Content string
+ Map [2]int
+ Lvl int
+}
+
+type HTMLInline struct {
+ Content string
+ Lvl int
+}
+
+type Hr struct {
+ Map [2]int
+ Lvl int
+}
+
+type Image struct {
+ Src string
+ Title string
+ Tokens []Token
+ Lvl int
+}
+
+type Inline struct {
+ Content string
+ Map [2]int
+ Children []Token
+ Lvl int
+}
+
+type LinkOpen struct {
+ Href string
+ Title string
+ Target string
+ Lvl int
+}
+
+type LinkClose struct {
+ Lvl int
+}
+
+type ParagraphOpen struct {
+ Tight bool
+ Hidden bool
+ Map [2]int
+ Lvl int
+}
+
+type ParagraphClose struct {
+ Tight bool
+ Hidden bool
+ Lvl int
+}
+
+type TableOpen struct {
+ Map [2]int
+ Lvl int
+}
+
+type TableClose struct {
+ Lvl int
+}
+
+type TheadOpen struct {
+ Map [2]int
+ Lvl int
+}
+
+type TheadClose struct {
+ Lvl int
+}
+
+type TrOpen struct {
+ Map [2]int
+ Lvl int
+}
+
+type TrClose struct {
+ Lvl int
+}
+
+type ThOpen struct {
+ Align Align
+ Map [2]int
+ Lvl int
+}
+
+type ThClose struct {
+ Lvl int
+}
+
+type TbodyOpen struct {
+ Map [2]int
+ Lvl int
+}
+
+type TbodyClose struct {
+ Lvl int
+}
+
+type TdOpen struct {
+ Align Align
+ Map [2]int
+ Lvl int
+}
+
+type TdClose struct {
+ Lvl int
+}
+
+type Text struct {
+ Content string
+ Lvl int
+}
+
+var htags = []string{
+ "",
+ "h1",
+ "h2",
+ "h3",
+ "h4",
+ "h5",
+ "h6",
+}
+
+func (t *BlockquoteOpen) Level() int { return t.Lvl }
+
+func (t *BlockquoteClose) Level() int { return t.Lvl }
+
+func (t *BulletListOpen) Level() int { return t.Lvl }
+
+func (t *BulletListClose) Level() int { return t.Lvl }
+
+func (t *OrderedListOpen) Level() int { return t.Lvl }
+
+func (t *OrderedListClose) Level() int { return t.Lvl }
+
+func (t *ListItemOpen) Level() int { return t.Lvl }
+
+func (t *ListItemClose) Level() int { return t.Lvl }
+
+func (t *CodeBlock) Level() int { return t.Lvl }
+
+func (t *CodeInline) Level() int { return t.Lvl }
+
+func (t *EmphasisOpen) Level() int { return t.Lvl }
+
+func (t *EmphasisClose) Level() int { return t.Lvl }
+
+func (t *StrongOpen) Level() int { return t.Lvl }
+
+func (t *StrongClose) Level() int { return t.Lvl }
+
+func (t *StrikethroughOpen) Level() int { return t.Lvl }
+
+func (t *StrikethroughClose) Level() int { return t.Lvl }
+
+func (t *Fence) Level() int { return t.Lvl }
+
+func (t *Softbreak) Level() int { return t.Lvl }
+
+func (t *Hardbreak) Level() int { return t.Lvl }
+
+func (t *HeadingOpen) Level() int { return t.Lvl }
+
+func (t *HeadingClose) Level() int { return t.Lvl }
+
+func (t *HTMLBlock) Level() int { return t.Lvl }
+
+func (t *HTMLInline) Level() int { return t.Lvl }
+
+func (t *Hr) Level() int { return t.Lvl }
+
+func (t *Image) Level() int { return t.Lvl }
+
+func (t *Inline) Level() int { return t.Lvl }
+
+func (t *LinkOpen) Level() int { return t.Lvl }
+
+func (t *LinkClose) Level() int { return t.Lvl }
+
+func (t *ParagraphOpen) Level() int { return t.Lvl }
+
+func (t *ParagraphClose) Level() int { return t.Lvl }
+
+func (t *TableOpen) Level() int { return t.Lvl }
+
+func (t *TableClose) Level() int { return t.Lvl }
+
+func (t *TheadOpen) Level() int { return t.Lvl }
+
+func (t *TheadClose) Level() int { return t.Lvl }
+
+func (t *TrOpen) Level() int { return t.Lvl }
+
+func (t *TrClose) Level() int { return t.Lvl }
+
+func (t *ThOpen) Level() int { return t.Lvl }
+
+func (t *ThClose) Level() int { return t.Lvl }
+
+func (t *TbodyOpen) Level() int { return t.Lvl }
+
+func (t *TbodyClose) Level() int { return t.Lvl }
+
+func (t *TdOpen) Level() int { return t.Lvl }
+
+func (t *TdClose) Level() int { return t.Lvl }
+
+func (t *Text) Level() int { return t.Lvl }
+
+func (t *BlockquoteOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *BlockquoteClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *BulletListOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *BulletListClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *OrderedListOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *OrderedListClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *ListItemOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *ListItemClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *CodeBlock) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *CodeInline) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *EmphasisOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *EmphasisClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *StrongOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *StrongClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *StrikethroughOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *StrikethroughClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *Fence) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *Softbreak) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *Hardbreak) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *HeadingOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *HeadingClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *HTMLBlock) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *HTMLInline) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *Hr) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *Image) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *Inline) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *LinkOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *LinkClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *ParagraphOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *ParagraphClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *TableOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *TableClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *TheadOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *TheadClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *TrOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *TrClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *ThOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *ThClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *TbodyOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *TbodyClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *TdOpen) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *TdClose) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *Text) SetLevel(lvl int) { t.Lvl = lvl }
+
+func (t *BlockquoteOpen) Opening() bool { return true }
+
+func (t *BlockquoteClose) Opening() bool { return false }
+
+func (t *BulletListOpen) Opening() bool { return true }
+
+func (t *BulletListClose) Opening() bool { return false }
+
+func (t *OrderedListOpen) Opening() bool { return true }
+
+func (t *OrderedListClose) Opening() bool { return false }
+
+func (t *ListItemOpen) Opening() bool { return true }
+
+func (t *ListItemClose) Opening() bool { return false }
+
+func (t *CodeBlock) Opening() bool { return false }
+
+func (t *CodeInline) Opening() bool { return false }
+
+func (t *EmphasisOpen) Opening() bool { return true }
+
+func (t *EmphasisClose) Opening() bool { return false }
+
+func (t *StrongOpen) Opening() bool { return true }
+
+func (t *StrongClose) Opening() bool { return false }
+
+func (t *StrikethroughOpen) Opening() bool { return true }
+
+func (t *StrikethroughClose) Opening() bool { return false }
+
+func (t *Fence) Opening() bool { return false }
+
+func (t *Softbreak) Opening() bool { return false }
+
+func (t *Hardbreak) Opening() bool { return false }
+
+func (t *HeadingOpen) Opening() bool { return true }
+
+func (t *HeadingClose) Opening() bool { return false }
+
+func (t *HTMLBlock) Opening() bool { return false }
+
+func (t *HTMLInline) Opening() bool { return false }
+
+func (t *Hr) Opening() bool { return false }
+
+func (t *Image) Opening() bool { return false }
+
+func (t *Inline) Opening() bool { return false }
+
+func (t *LinkOpen) Opening() bool { return true }
+
+func (t *LinkClose) Opening() bool { return false }
+
+func (t *ParagraphOpen) Opening() bool { return true }
+
+func (t *ParagraphClose) Opening() bool { return false }
+
+func (t *TableOpen) Opening() bool { return true }
+
+func (t *TableClose) Opening() bool { return false }
+
+func (t *TheadOpen) Opening() bool { return true }
+
+func (t *TheadClose) Opening() bool { return false }
+
+func (t *TrOpen) Opening() bool { return true }
+
+func (t *TrClose) Opening() bool { return false }
+
+func (t *ThOpen) Opening() bool { return true }
+
+func (t *ThClose) Opening() bool { return false }
+
+func (t *TbodyOpen) Opening() bool { return true }
+
+func (t *TbodyClose) Opening() bool { return false }
+
+func (t *TdOpen) Opening() bool { return true }
+
+func (t *TdClose) Opening() bool { return false }
+
+func (t *Text) Opening() bool { return false }
+
+func (t *BlockquoteOpen) Closing() bool { return false }
+
+func (t *BlockquoteClose) Closing() bool { return true }
+
+func (t *BulletListOpen) Closing() bool { return false }
+
+func (t *BulletListClose) Closing() bool { return true }
+
+func (t *OrderedListOpen) Closing() bool { return false }
+
+func (t *OrderedListClose) Closing() bool { return true }
+
+func (t *ListItemOpen) Closing() bool { return false }
+
+func (t *ListItemClose) Closing() bool { return true }
+
+func (t *CodeBlock) Closing() bool { return false }
+
+func (t *CodeInline) Closing() bool { return false }
+
+func (t *EmphasisOpen) Closing() bool { return false }
+
+func (t *EmphasisClose) Closing() bool { return true }
+
+func (t *StrongOpen) Closing() bool { return false }
+
+func (t *StrongClose) Closing() bool { return true }
+
+func (t *StrikethroughOpen) Closing() bool { return false }
+
+func (t *StrikethroughClose) Closing() bool { return true }
+
+func (t *Fence) Closing() bool { return false }
+
+func (t *Softbreak) Closing() bool { return false }
+
+func (t *Hardbreak) Closing() bool { return false }
+
+func (t *HeadingOpen) Closing() bool { return false }
+
+func (t *HeadingClose) Closing() bool { return true }
+
+func (t *HTMLBlock) Closing() bool { return false }
+
+func (t *HTMLInline) Closing() bool { return false }
+
+func (t *Hr) Closing() bool { return false }
+
+func (t *Image) Closing() bool { return false }
+
+func (t *Inline) Closing() bool { return false }
+
+func (t *LinkOpen) Closing() bool { return false }
+
+func (t *LinkClose) Closing() bool { return true }
+
+func (t *ParagraphOpen) Closing() bool { return false }
+
+func (t *ParagraphClose) Closing() bool { return true }
+
+func (t *TableOpen) Closing() bool { return false }
+
+func (t *TableClose) Closing() bool { return true }
+
+func (t *TheadOpen) Closing() bool { return false }
+
+func (t *TheadClose) Closing() bool { return true }
+
+func (t *TrOpen) Closing() bool { return false }
+
+func (t *TrClose) Closing() bool { return true }
+
+func (t *ThOpen) Closing() bool { return false }
+
+func (t *ThClose) Closing() bool { return true }
+
+func (t *TbodyOpen) Closing() bool { return false }
+
+func (t *TbodyClose) Closing() bool { return true }
+
+func (t *TdOpen) Closing() bool { return false }
+
+func (t *TdClose) Closing() bool { return true }
+
+func (t *Text) Closing() bool { return false }
+
+func (t *BlockquoteOpen) Block() bool { return true }
+
+func (t *BlockquoteClose) Block() bool { return true }
+
+func (t *BulletListOpen) Block() bool { return true }
+
+func (t *BulletListClose) Block() bool { return true }
+
+func (t *OrderedListOpen) Block() bool { return true }
+
+func (t *OrderedListClose) Block() bool { return true }
+
+func (t *ListItemOpen) Block() bool { return true }
+
+func (t *ListItemClose) Block() bool { return true }
+
+func (t *CodeBlock) Block() bool { return true }
+
+func (t *CodeInline) Block() bool { return false }
+
+func (t *EmphasisOpen) Block() bool { return false }
+
+func (t *EmphasisClose) Block() bool { return false }
+
+func (t *StrongOpen) Block() bool { return false }
+
+func (t *StrongClose) Block() bool { return false }
+
+func (t *StrikethroughOpen) Block() bool { return false }
+
+func (t *StrikethroughClose) Block() bool { return false }
+
+func (t *Fence) Block() bool { return true }
+
+func (t *Softbreak) Block() bool { return false }
+
+func (t *Hardbreak) Block() bool { return false }
+
+func (t *HeadingOpen) Block() bool { return true }
+
+func (t *HeadingClose) Block() bool { return true }
+
+func (t *HTMLBlock) Block() bool { return true }
+
+func (t *HTMLInline) Block() bool { return false }
+
+func (t *Hr) Block() bool { return true }
+
+func (t *Image) Block() bool { return false }
+
+func (t *Inline) Block() bool { return false }
+
+func (t *LinkOpen) Block() bool { return false }
+
+func (t *LinkClose) Block() bool { return false }
+
+func (t *ParagraphOpen) Block() bool { return true }
+
+func (t *ParagraphClose) Block() bool { return true }
+
+func (t *TableOpen) Block() bool { return true }
+
+func (t *TableClose) Block() bool { return true }
+
+func (t *TheadOpen) Block() bool { return true }
+
+func (t *TheadClose) Block() bool { return true }
+
+func (t *TrOpen) Block() bool { return true }
+
+func (t *TrClose) Block() bool { return true }
+
+func (t *ThOpen) Block() bool { return true }
+
+func (t *ThClose) Block() bool { return true }
+
+func (t *TbodyOpen) Block() bool { return true }
+
+func (t *TbodyClose) Block() bool { return true }
+
+func (t *TdOpen) Block() bool { return true }
+
+func (t *TdClose) Block() bool { return true }
+
+func (t *Text) Block() bool { return false }
+
+func (t *BlockquoteOpen) Tag() string { return "blockquote" }
+
+func (t *BlockquoteClose) Tag() string { return "blockquote" }
+
+func (t *BulletListOpen) Tag() string { return "ul" }
+
+func (t *BulletListClose) Tag() string { return "ul" }
+
+func (t *OrderedListOpen) Tag() string { return "ol" }
+
+func (t *OrderedListClose) Tag() string { return "ol" }
+
+func (t *ListItemOpen) Tag() string { return "li" }
+
+func (t *ListItemClose) Tag() string { return "li" }
+
+func (t *CodeBlock) Tag() string { return "code" }
+
+func (t *CodeInline) Tag() string { return "code" }
+
+func (t *EmphasisOpen) Tag() string { return "em" }
+
+func (t *EmphasisClose) Tag() string { return "em" }
+
+func (t *StrongOpen) Tag() string { return "strong" }
+
+func (t *StrongClose) Tag() string { return "strong" }
+
+func (t *StrikethroughOpen) Tag() string { return "s" }
+
+func (t *StrikethroughClose) Tag() string { return "s" }
+
+func (t *Fence) Tag() string { return "code" }
+
+func (t *Softbreak) Tag() string { return "br" }
+
+func (t *Hardbreak) Tag() string { return "br" }
+
+func (t *HeadingOpen) Tag() string { return htags[t.HLevel] }
+
+func (t *HeadingClose) Tag() string { return htags[t.HLevel] }
+
+func (t *HTMLBlock) Tag() string { return "" }
+
+func (t *HTMLInline) Tag() string { return "" }
+
+func (t *Hr) Tag() string { return "hr" }
+
+func (t *Image) Tag() string { return "img" }
+
+func (t *Inline) Tag() string { return "" }
+
+func (t *LinkOpen) Tag() string { return "a" }
+
+func (t *LinkClose) Tag() string { return "a" }
+
+func (t *ParagraphOpen) Tag() string { return "p" }
+
+func (t *ParagraphClose) Tag() string { return "p" }
+
+func (t *TableOpen) Tag() string { return "table" }
+
+func (t *TableClose) Tag() string { return "table" }
+
+func (t *TheadOpen) Tag() string { return "thead" }
+
+func (t *TheadClose) Tag() string { return "thead" }
+
+func (t *TrOpen) Tag() string { return "tr" }
+
+func (t *TrClose) Tag() string { return "tr" }
+
+func (t *ThOpen) Tag() string { return "th" }
+
+func (t *ThClose) Tag() string { return "th" }
+
+func (t *TbodyOpen) Tag() string { return "tbody" }
+
+func (t *TbodyClose) Tag() string { return "tbody" }
+
+func (t *TdOpen) Tag() string { return "td" }
+
+func (t *TdClose) Tag() string { return "td" }
+
+func (t *Text) Tag() string { return "" }
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/urlschema.go b/vendor/gitlab.com/golang-commonmark/markdown/urlschema.go
new file mode 100644
index 00000000..06b9e6a1
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/urlschema.go
@@ -0,0 +1,185 @@
+// 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
+
+var urlSchemas = []string{
+ "aaa",
+ "aaas",
+ "about",
+ "acap",
+ "adiumxtra",
+ "afp",
+ "afs",
+ "aim",
+ "apt",
+ "attachment",
+ "aw",
+ "beshare",
+ "bitcoin",
+ "bolo",
+ "callto",
+ "cap",
+ "chrome",
+ "chrome-extension",
+ "cid",
+ "coap",
+ "com-eventbrite-attendee",
+ "content",
+ "crid",
+ "cvs",
+ "data",
+ "dav",
+ "dict",
+ "dlna-playcontainer",
+ "dlna-playsingle",
+ "dns",
+ "doi",
+ "dtn",
+ "dvb",
+ "ed2k",
+ "facetime",
+ "feed",
+ "file",
+ "finger",
+ "fish",
+ "ftp",
+ "geo",
+ "gg",
+ "git",
+ "gizmoproject",
+ "go",
+ "gopher",
+ "gtalk",
+ "h323",
+ "hcp",
+ "http",
+ "https",
+ "iax",
+ "icap",
+ "icon",
+ "im",
+ "imap",
+ "info",
+ "ipn",
+ "ipp",
+ "irc",
+ "irc6",
+ "ircs",
+ "iris",
+ "iris.beep",
+ "iris.lwz",
+ "iris.xpc",
+ "iris.xpcs",
+ "itms",
+ "jar",
+ "javascript",
+ "jms",
+ "keyparc",
+ "lastfm",
+ "ldap",
+ "ldaps",
+ "magnet",
+ "mailto",
+ "maps",
+ "market",
+ "message",
+ "mid",
+ "mms",
+ "ms-help",
+ "msnim",
+ "msrp",
+ "msrps",
+ "mtqp",
+ "mumble",
+ "mupdate",
+ "mvn",
+ "news",
+ "nfs",
+ "ni",
+ "nih",
+ "nntp",
+ "notes",
+ "oid",
+ "opaquelocktoken",
+ "palm",
+ "paparazzi",
+ "platform",
+ "pop",
+ "pres",
+ "proxy",
+ "psyc",
+ "query",
+ "res",
+ "resource",
+ "rmi",
+ "rsync",
+ "rtmp",
+ "rtsp",
+ "secondlife",
+ "service",
+ "session",
+ "sftp",
+ "sgn",
+ "shttp",
+ "sieve",
+ "sip",
+ "sips",
+ "skype",
+ "smb",
+ "sms",
+ "snmp",
+ "soap.beep",
+ "soap.beeps",
+ "soldat",
+ "spotify",
+ "ssh",
+ "steam",
+ "svn",
+ "tag",
+ "teamspeak",
+ "tel",
+ "telnet",
+ "tftp",
+ "things",
+ "thismessage",
+ "tip",
+ "tn3270",
+ "tv",
+ "udp",
+ "unreal",
+ "urn",
+ "ut2004",
+ "vemmi",
+ "ventrilo",
+ "view-source",
+ "webcal",
+ "ws",
+ "wss",
+ "wtai",
+ "wyciwyg",
+ "xcon",
+ "xcon-userid",
+ "xfire",
+ "xmlrpc.beep",
+ "xmlrpc.beeps",
+ "xmpp",
+ "xri",
+ "ymsgr",
+ "z39.50r",
+ "z39.50s",
+}
+
+var urlSchemasSet = make(map[string]bool)
+
+func init() {
+ for _, s := range urlSchemas {
+ urlSchemasSet[s] = true
+ }
+}
+
+func matchSchema(s string) bool {
+ _, ok := urlSchemasSet[s]
+ return ok
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/util.go b/vendor/gitlab.com/golang-commonmark/markdown/util.go
new file mode 100644
index 00000000..d821202c
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/util.go
@@ -0,0 +1,264 @@
+// 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"
+ "regexp"
+ "strings"
+ "unicode"
+
+ "gitlab.com/golang-commonmark/html"
+ "gitlab.com/golang-commonmark/mdurl"
+ "gitlab.com/golang-commonmark/puny"
+)
+
+func runeIsSpace(r rune) bool {
+ return r == ' ' || r == '\t'
+}
+
+func byteIsSpace(b byte) bool {
+ return b == ' ' || b == '\t'
+}
+
+func isLetter(b byte) bool {
+ return b >= 'a' && b <= 'z' || b >= 'A' && b <= 'Z'
+}
+
+func isUppercaseLetter(b byte) bool {
+ return b >= 'A' && b <= 'Z'
+}
+
+func mdpunct(b byte) bool {
+ return strings.IndexByte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", b) != -1
+}
+
+func isMdAsciiPunct(r rune) bool {
+ if r > 0x7e {
+ return false
+ }
+ return mdpunct(byte(r))
+}
+
+func recodeHostnameFor(proto string) bool {
+ switch proto {
+ case "http", "https", "mailto":
+ return true
+ }
+ return false
+}
+
+func normalizeLink(url string) string {
+ parsed, err := mdurl.Parse(url)
+ if err != nil {
+ return ""
+ }
+
+ if parsed.Host != "" && (parsed.Scheme == "" || recodeHostnameFor(parsed.Scheme)) {
+ parsed.Host = puny.ToASCII(parsed.Host)
+ }
+
+ parsed.Scheme = parsed.RawScheme
+
+ return mdurl.Encode(parsed.String())
+}
+
+func normalizeLinkText(url string) string {
+ parsed, err := mdurl.Parse(url)
+ if err != nil {
+ return ""
+ }
+
+ if parsed.Host != "" && (parsed.Scheme == "" || recodeHostnameFor(parsed.Scheme)) {
+ parsed.Host = puny.ToUnicode(parsed.Host)
+ }
+
+ parsed.Scheme = parsed.RawScheme
+
+ return mdurl.Decode(parsed.String())
+}
+
+var badProtos = []string{"file", "javascript", "vbscript"}
+
+var rGoodData = regexp.MustCompile(`^data:image/(gif|png|jpeg|webp);`)
+
+func removeSpecial(s string) string {
+ i := 0
+ for i < len(s) && !(s[i] <= 0x20 || s[i] == 0x7f) {
+ i++
+ }
+ if i >= len(s) {
+ return s
+ }
+ buf := make([]byte, len(s))
+ j := 0
+ for i := 0; i < len(s); i++ {
+ if !(s[i] <= 0x20 || s[i] == 0x7f) {
+ buf[j] = s[i]
+ j++
+ }
+ }
+ return string(buf[:j])
+}
+
+func validateLink(url string) bool {
+ str := strings.TrimSpace(url)
+ str = strings.ToLower(str)
+
+ if strings.IndexByte(str, ':') >= 0 {
+ proto := strings.SplitN(str, ":", 2)[0]
+ proto = removeSpecial(proto)
+ for _, p := range badProtos {
+ if proto == p {
+ return false
+ }
+ }
+ if proto == "data" && !rGoodData.MatchString(str) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func unescapeAll(s string) string {
+ anyChanges := false
+ i := 0
+ for i < len(s)-1 {
+ b := s[i]
+ if b == '\\' {
+ if mdpunct(s[i+1]) {
+ anyChanges = true
+ break
+ }
+ } else if b == '&' {
+ if e, n := html.ParseEntity(s[i:]); n > 0 && e != html.BadEntity {
+ anyChanges = true
+ break
+ }
+ }
+ i++
+ }
+
+ if !anyChanges {
+ return s
+ }
+
+ buf := make([]byte, len(s))
+ copy(buf[:i], s)
+ j := i
+ for i < len(s) {
+ b := s[i]
+ if b == '\\' {
+ if i+1 < len(s) {
+ b = s[i+1]
+ if mdpunct(b) {
+ buf[j] = b
+ j++
+ } else {
+ buf[j] = '\\'
+ j++
+ buf[j] = b
+ j++
+ }
+ i += 2
+ continue
+ }
+ } else if b == '&' {
+ if e, n := html.ParseEntity(s[i:]); n > 0 && e != html.BadEntity {
+ if len(e) > n && len(buf) == len(s) {
+ newBuf := make([]byte, cap(buf)*2)
+ copy(newBuf[:j], buf)
+ buf = newBuf
+ }
+ j += copy(buf[j:], e)
+ i += n
+ continue
+ }
+ }
+ buf[j] = b
+ j++
+ i++
+ }
+
+ return string(buf[:j])
+}
+
+func normalizeInlineCode(s string) string {
+ if s == "" {
+ return ""
+ }
+
+ byteFuckery := false
+ i := 0
+ for i < len(s)-1 {
+ b := s[i]
+ if b == '\n' {
+ byteFuckery = true
+ break
+ }
+ if b == ' ' {
+ i++
+ b = s[i]
+ if b == ' ' || b == '\n' {
+ i--
+ byteFuckery = true
+ break
+ }
+ }
+ i++
+ }
+
+ if !byteFuckery {
+ return strings.TrimSpace(s)
+ }
+
+ buf := make([]byte, len(s))
+ copy(buf[:i], s)
+ buf[i] = ' '
+ i++
+ j := i
+ lastSpace := true
+ for i < len(s) {
+ b := s[i]
+ switch b {
+ case ' ', '\n':
+ if lastSpace {
+ break
+ }
+
+ buf[j] = ' '
+ lastSpace = true
+ j++
+ default:
+ buf[j] = b
+ lastSpace = false
+ j++
+ }
+
+ i++
+ }
+
+ return string(bytes.TrimSpace(buf[:j]))
+}
+
+func normalizeReference(s string) string {
+ var buf bytes.Buffer
+ lastSpace := false
+ for _, r := range s {
+ if unicode.IsSpace(r) {
+ if !lastSpace {
+ buf.WriteByte(' ')
+ lastSpace = true
+ }
+ continue
+ }
+
+ buf.WriteRune(unicode.ToLower(r))
+ lastSpace = false
+ }
+
+ return string(bytes.TrimSpace(buf.Bytes()))
+}
diff --git a/vendor/gitlab.com/golang-commonmark/markdown/writer.go b/vendor/gitlab.com/golang-commonmark/markdown/writer.go
new file mode 100644
index 00000000..886a1de4
--- /dev/null
+++ b/vendor/gitlab.com/golang-commonmark/markdown/writer.go
@@ -0,0 +1,69 @@
+// 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 (
+ "bufio"
+ "io"
+)
+
+type writer interface {
+ Write([]byte) (int, error)
+ WriteByte(byte) error
+ WriteString(string) (int, error)
+ Flush() error
+}
+
+type monadicWriter struct {
+ writer
+ err error
+}
+
+func newMonadicWriter(w io.Writer) *monadicWriter {
+ if w, ok := w.(writer); ok {
+ return &monadicWriter{writer: w}
+ }
+ return &monadicWriter{writer: bufio.NewWriter(w)}
+}
+
+func (w *monadicWriter) Write(p []byte) (n int, err error) {
+ if w.err != nil {
+ return
+ }
+
+ n, err = w.writer.Write(p)
+ w.err = err
+ return
+}
+
+func (w *monadicWriter) WriteByte(b byte) (err error) {
+ if w.err != nil {
+ return
+ }
+
+ err = w.writer.WriteByte(b)
+ w.err = err
+ return
+}
+
+func (w *monadicWriter) WriteString(s string) (n int, err error) {
+ if w.err != nil {
+ return
+ }
+
+ n, err = w.writer.WriteString(s)
+ w.err = err
+ return
+}
+
+func (w *monadicWriter) Flush() (err error) {
+ if w.err != nil {
+ return
+ }
+
+ err = w.writer.Flush()
+ w.err = err
+ return
+}
--
cgit v1.2.3