mirror of
https://github.com/cwinfo/matterbridge.git
synced 2024-12-26 02:55:39 +00:00
This uses our own gomatrix lib with the SendHTML function which adds HTML to formatted_body in matrix. golang-commonmark is used to convert markdown into valid HTML.
This commit is contained in:
parent
048158ad6d
commit
04567c765e
@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gitlab.com/golang-commonmark/markdown"
|
||||
)
|
||||
|
||||
func DownloadFile(url string) (*[]byte, error) {
|
||||
@ -151,3 +152,8 @@ func ClipMessage(text string, length int) string {
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
func ParseMarkdown(input string) string {
|
||||
md := markdown.New(markdown.XHTMLOutput(true), markdown.Breaks(true))
|
||||
return (md.RenderToString([]byte(input)))
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package bmatrix
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html"
|
||||
"mime"
|
||||
"regexp"
|
||||
"strings"
|
||||
@ -112,8 +113,8 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
||||
// Edit message if we have an ID
|
||||
// matrix has no editing support
|
||||
|
||||
// Post normal message
|
||||
resp, err := b.mc.SendText(channel, msg.Username+msg.Text)
|
||||
// Post normal message with HTML support (eg riot.im)
|
||||
resp, err := b.mc.SendHTML(channel, msg.Text, html.EscapeString(msg.Username)+helper.ParseMarkdown(msg.Text))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
6
go.mod
6
go.mod
@ -61,6 +61,12 @@ require (
|
||||
github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 // indirect
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
|
||||
github.com/zfjagann/golang-ring v0.0.0-20141111230621-17637388c9f6
|
||||
gitlab.com/golang-commonmark/html v0.0.0-20180917080848-cfaf75183c4a // indirect
|
||||
gitlab.com/golang-commonmark/linkify v0.0.0-20180917065525-c22b7bdb1179 // indirect
|
||||
gitlab.com/golang-commonmark/markdown v0.0.0-20181102083822-772775880e1f
|
||||
gitlab.com/golang-commonmark/mdurl v0.0.0-20180912090424-e5bce34c34f2 // indirect
|
||||
gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe // indirect
|
||||
gitlab.com/opennota/wd v0.0.0-20180912061657-c5d65f63c638 // indirect
|
||||
go.uber.org/atomic v1.3.2 // indirect
|
||||
go.uber.org/multierr v1.1.0 // indirect
|
||||
go.uber.org/zap v1.9.1 // indirect
|
||||
|
16
go.sum
16
go.sum
@ -16,8 +16,6 @@ github.com/dgrijalva/jwt-go v0.0.0-20170508165458-6c8dedd55f8a h1:MuHMeSsXbNEeUy
|
||||
github.com/dgrijalva/jwt-go v0.0.0-20170508165458-6c8dedd55f8a/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible h1:i64CCJcSqkRIkm5OSdZQjZq84/gJsk2zNwHWIRYWlKE=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
||||
github.com/golang/protobuf v0.0.0-20170613224224-e325f446bebc h1:wdhDSKrkYy24mcfzuA3oYm58h0QkyXjwERCkzJDP5kA=
|
||||
@ -55,8 +53,6 @@ github.com/labstack/echo v3.3.5+incompatible h1:9PfxPUmasKzeJor9uQTaXLT6WUG/r+vS
|
||||
github.com/labstack/echo v3.3.5+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
||||
github.com/labstack/gommon v0.2.1 h1:C+I4NYknueQncqKYZQ34kHsLZJVeB5KwPUhnO0nmbpU=
|
||||
github.com/labstack/gommon v0.2.1/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4=
|
||||
github.com/lrstanley/girc v0.0.0-20181114171214-3aee8c249519 h1:o7duXxs4nxplgWrFRJoyGrPAS+U9Sk5eQyc2mflk6/Q=
|
||||
github.com/lrstanley/girc v0.0.0-20181114171214-3aee8c249519/go.mod h1:7cRs1SIBfKQ7e3Tam6GKTILSNHzR862JD0JpINaZoJk=
|
||||
github.com/lrstanley/girc v0.0.0-20190102153329-c1e59a02f488 h1:dDEQN5oaa0WOzEiPDSbOugW/e2I/SWY98HYRdcwmGfY=
|
||||
github.com/lrstanley/girc v0.0.0-20190102153329-c1e59a02f488/go.mod h1:7cRs1SIBfKQ7e3Tam6GKTILSNHzR862JD0JpINaZoJk=
|
||||
github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 h1:AsEBgzv3DhuYHI/GiQh2HxvTP71HCCE9E/tzGUzGdtU=
|
||||
@ -153,6 +149,18 @@ github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJ
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
|
||||
github.com/zfjagann/golang-ring v0.0.0-20141111230621-17637388c9f6 h1:/WULP+6asFz569UbOwg87f3iDT7T+GF5/vjLmL51Pdk=
|
||||
github.com/zfjagann/golang-ring v0.0.0-20141111230621-17637388c9f6/go.mod h1:0MsIttMJIF/8Y7x0XjonJP7K99t3sR6bjj4m5S4JmqU=
|
||||
gitlab.com/golang-commonmark/html v0.0.0-20180917080848-cfaf75183c4a h1:Ax7kdHNICZiIeFpmevmaEWb0Ae3BUj3zCTKhZHZ+zd0=
|
||||
gitlab.com/golang-commonmark/html v0.0.0-20180917080848-cfaf75183c4a/go.mod h1:JT4uoTz0tfPoyVH88GZoWDNm5NHJI2VbUW+eyPClueI=
|
||||
gitlab.com/golang-commonmark/linkify v0.0.0-20180917065525-c22b7bdb1179 h1:rbON2KwBnWuFMlSHM8LELLlwroDRZw6xv0e6il6e5dk=
|
||||
gitlab.com/golang-commonmark/linkify v0.0.0-20180917065525-c22b7bdb1179/go.mod h1:Gn+LZmCrhPECMD3SOKlE+BOHwhOYD9j7WT9NUtkCrC8=
|
||||
gitlab.com/golang-commonmark/markdown v0.0.0-20181102083822-772775880e1f h1:jwXy/CsM4xS2aoiF2fHAlukmInWhd2TlWB+HDCyvzKc=
|
||||
gitlab.com/golang-commonmark/markdown v0.0.0-20181102083822-772775880e1f/go.mod h1:SIHlEr9462fpIfTrVWf3GqQDxnA65Vm3BMMsUtuA6W0=
|
||||
gitlab.com/golang-commonmark/mdurl v0.0.0-20180912090424-e5bce34c34f2 h1:wD/sPUgx2QJFPTyXZpJnLaROolfeKuruh06U4pRV0WY=
|
||||
gitlab.com/golang-commonmark/mdurl v0.0.0-20180912090424-e5bce34c34f2/go.mod h1:wQk4rLkWrdOPjUAtqJRJ10hIlseLSVYWP95PLrjDF9s=
|
||||
gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe h1:5kUPFAF52umOUPH12MuNUmyVTseJRNBftDl/KfsvX3I=
|
||||
gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe/go.mod h1:P9LSM1KVzrIstFgUaveuwiAm8PK5VTB3yJEU8kqlbrU=
|
||||
gitlab.com/opennota/wd v0.0.0-20180912061657-c5d65f63c638 h1:uPZaMiz6Sz0PZs3IZJWpU5qHKGNy///1pacZC9txiUI=
|
||||
gitlab.com/opennota/wd v0.0.0-20180912061657-c5d65f63c638/go.mod h1:EGRJaqe2eO9XGmFtQCvV3Lm9NLico3UhFwUpCG/+mVU=
|
||||
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||
|
16
vendor/gitlab.com/golang-commonmark/html/.gitlab-ci.yml
generated
vendored
Normal file
16
vendor/gitlab.com/golang-commonmark/html/.gitlab-ci.yml
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
image: golang:1.11
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- go build ./...
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- test -z "$(gofmt -l . | tee /dev/stderr)"
|
||||
- go test ./...
|
10
vendor/gitlab.com/golang-commonmark/html/LICENSE
generated
vendored
Normal file
10
vendor/gitlab.com/golang-commonmark/html/LICENSE
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
Copyright (c) 2015, The Authors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
8
vendor/gitlab.com/golang-commonmark/html/README.md
generated
vendored
Normal file
8
vendor/gitlab.com/golang-commonmark/html/README.md
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
html [![License](https://img.shields.io/badge/licence-BSD--2--Clause-blue.svg)](https://opensource.org/licenses/BSD-2-Clause) [![GoDoc](http://godoc.org/gitlab.com/golang-commonmark/html?status.svg)](http://godoc.org/gitlab.com/golang-commonmark/html) [![Pipeline status](https://gitlab.com/golang-commonmark/html/badges/master/pipeline.svg)](https://gitlab.com/golang-commonmark/html/commits/master)
|
||||
====
|
||||
|
||||
Package html provides functions for escaping/unescaping HTML text and for parsing HTML entities.
|
||||
|
||||
## Install
|
||||
|
||||
go get -u gitlab.com/golang-commonmark/html
|
211
vendor/gitlab.com/golang-commonmark/html/html.go
generated
vendored
Normal file
211
vendor/gitlab.com/golang-commonmark/html/html.go
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
// 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 html provides functions for escaping/unescaping HTML text and for parsing HTML entities.
|
||||
package html
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const BadEntity = string(utf8.RuneError)
|
||||
|
||||
var htmlEscapeReplacer = strings.NewReplacer(
|
||||
"&", "&",
|
||||
"<", "<",
|
||||
">", ">",
|
||||
`"`, """,
|
||||
)
|
||||
|
||||
func EscapeString(s string) string {
|
||||
return htmlEscapeReplacer.Replace(s)
|
||||
}
|
||||
|
||||
func WriteEscapedString(w io.Writer, s string) error {
|
||||
_, err := htmlEscapeReplacer.WriteString(w, s)
|
||||
return err
|
||||
}
|
||||
|
||||
func isValidEntityCode(c int64) bool {
|
||||
switch {
|
||||
case !utf8.ValidRune(rune(c)):
|
||||
return false
|
||||
|
||||
// never used
|
||||
case c >= 0xfdd0 && c <= 0xfdef:
|
||||
return false
|
||||
case c&0xffff == 0xffff || c&0xffff == 0xfffe:
|
||||
return false
|
||||
// control codes
|
||||
case c >= 0x00 && c <= 0x08:
|
||||
return false
|
||||
case c == 0x0b:
|
||||
return false
|
||||
case c >= 0x0e && c <= 0x1f:
|
||||
return false
|
||||
case c >= 0x7f && c <= 0x9f:
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func letter(b byte) bool { return b >= 'a' && b <= 'z' || b >= 'A' && b <= 'Z' }
|
||||
|
||||
func digit(b byte) bool { return b >= '0' && b <= '9' }
|
||||
|
||||
func alphanum(b byte) bool { return letter(b) || digit(b) }
|
||||
|
||||
func hexDigit(b byte) bool {
|
||||
return digit(b) || b >= 'a' && b <= 'f' || b >= 'A' && b <= 'F'
|
||||
}
|
||||
|
||||
func ParseEntity(s string) (string, int) {
|
||||
st := 0
|
||||
var n int
|
||||
|
||||
for i := 1; i < len(s); i++ {
|
||||
b := s[i]
|
||||
|
||||
switch st {
|
||||
case 0: // initial state
|
||||
switch {
|
||||
case b == '#':
|
||||
st = 1
|
||||
case letter(b):
|
||||
n = 1
|
||||
st = 2
|
||||
default:
|
||||
return "", 0
|
||||
}
|
||||
|
||||
case 1: // &#
|
||||
switch {
|
||||
case b == 'x' || b == 'X':
|
||||
st = 3
|
||||
case digit(b):
|
||||
n = 1
|
||||
st = 4
|
||||
default:
|
||||
return "", 0
|
||||
}
|
||||
|
||||
case 2: // &q
|
||||
switch {
|
||||
case alphanum(b):
|
||||
n++
|
||||
if n > 31 {
|
||||
return "", 0
|
||||
}
|
||||
case b == ';':
|
||||
if e, ok := entities[s[i-n:i]]; ok {
|
||||
return e, i + 1
|
||||
}
|
||||
return "", 0
|
||||
default:
|
||||
return "", 0
|
||||
}
|
||||
|
||||
case 3: // &#x
|
||||
switch {
|
||||
case hexDigit(b):
|
||||
n = 1
|
||||
st = 5
|
||||
default:
|
||||
return "", 0
|
||||
}
|
||||
|
||||
case 4: // �
|
||||
switch {
|
||||
case digit(b):
|
||||
n++
|
||||
if n > 8 {
|
||||
return "", 0
|
||||
}
|
||||
case b == ';':
|
||||
c, _ := strconv.ParseInt(s[i-n:i], 10, 32)
|
||||
if !isValidEntityCode(c) {
|
||||
return BadEntity, i + 1
|
||||
}
|
||||
return string(rune(c)), i + 1
|
||||
default:
|
||||
return "", 0
|
||||
}
|
||||
|
||||
case 5: // �
|
||||
switch {
|
||||
case hexDigit(b):
|
||||
n++
|
||||
if n > 8 {
|
||||
return "", 0
|
||||
}
|
||||
case b == ';':
|
||||
c, err := strconv.ParseInt(s[i-n:i], 16, 32)
|
||||
if err != nil {
|
||||
return BadEntity, i + 1
|
||||
}
|
||||
if !isValidEntityCode(c) {
|
||||
return BadEntity, i + 1
|
||||
}
|
||||
return string(rune(c)), i + 1
|
||||
default:
|
||||
return "", 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", 0
|
||||
}
|
||||
|
||||
func UnescapeString(s string) string {
|
||||
i := strings.IndexByte(s, '&')
|
||||
if i < 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
anyChanges := false
|
||||
var entityStr string
|
||||
var entityLen int
|
||||
for i < len(s) {
|
||||
if s[i] == '&' {
|
||||
entityStr, entityLen = ParseEntity(s[i:])
|
||||
if entityLen > 0 {
|
||||
anyChanges = true
|
||||
break
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
if !anyChanges {
|
||||
return s
|
||||
}
|
||||
|
||||
buf := make([]byte, len(s)-entityLen+len(entityStr))
|
||||
copy(buf[:i], s)
|
||||
n := copy(buf[i:], entityStr)
|
||||
j := i + n
|
||||
i += entityLen
|
||||
for i < len(s) {
|
||||
b := s[i]
|
||||
if b == '&' {
|
||||
entityStr, entityLen = ParseEntity(s[i:])
|
||||
if entityLen > 0 {
|
||||
n = copy(buf[j:], entityStr)
|
||||
j += n
|
||||
i += entityLen
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
buf[j] = b
|
||||
j++
|
||||
i++
|
||||
}
|
||||
|
||||
return string(buf[:j])
|
||||
}
|
2133
vendor/gitlab.com/golang-commonmark/html/html5_entities.go
generated
vendored
Normal file
2133
vendor/gitlab.com/golang-commonmark/html/html5_entities.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
19
vendor/gitlab.com/golang-commonmark/linkify/.gitlab-ci.yml
generated
vendored
Normal file
19
vendor/gitlab.com/golang-commonmark/linkify/.gitlab-ci.yml
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
image: golang:1.11
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
|
||||
before_script:
|
||||
- go get golang.org/x/text/unicode/rangetable
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- go build ./...
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- test -z "$(gofmt -l . | tee /dev/stderr)"
|
||||
- go test ./...
|
10
vendor/gitlab.com/golang-commonmark/linkify/LICENSE
generated
vendored
Normal file
10
vendor/gitlab.com/golang-commonmark/linkify/LICENSE
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
Copyright (c) 2015, The Authors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
12
vendor/gitlab.com/golang-commonmark/linkify/README.md
generated
vendored
Normal file
12
vendor/gitlab.com/golang-commonmark/linkify/README.md
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
linkify [![License](https://img.shields.io/badge/licence-BSD--2--Clause-blue.svg)](https://opensource.org/licenses/BSD-2-Clause) [![GoDoc](http://godoc.org/gitlab.com/golang-commonmark/linkify?status.svg)](http://godoc.org/gitlab.com/golang-commonmark/linkify) [![Pipeline status](https://gitlab.com/golang-commonmark/linkify/badges/master/pipeline.svg)](https://gitlab.com/golang-commonmark/linkify/commits/master)
|
||||
=======
|
||||
|
||||
Package linkify provides a way to find what looks like links in plain text.
|
||||
|
||||
## Install
|
||||
|
||||
go get -u gitlab.com/golang-commonmark/linkify
|
||||
|
||||
## Use
|
||||
|
||||
See an [example](https://gitlab.com/golang-commonmark/linkify/blob/master/linkify_example_test.go).
|
51
vendor/gitlab.com/golang-commonmark/linkify/charset.go
generated
vendored
Normal file
51
vendor/gitlab.com/golang-commonmark/linkify/charset.go
generated
vendored
Normal file
@ -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 linkify
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
|
||||
"golang.org/x/text/unicode/rangetable"
|
||||
)
|
||||
|
||||
var (
|
||||
unreserved = [256]bool{'-': true, '.': true, '_': true, '~': true}
|
||||
basicPunct = [256]bool{'.': true, ',': true, '?': true, '!': true, ';': true, ':': true}
|
||||
subdelims = [256]bool{'!': true, '$': true, '&': true, '\'': true, '(': true, ')': true,
|
||||
'*': true, '+': true, ',': true, ';': true, '=': true}
|
||||
emailcs = [256]bool{'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true,
|
||||
'h': true, 'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true,
|
||||
'p': true, 'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true,
|
||||
'x': true, 'y': true, 'z': true, 'A': true, 'B': true, 'C': true, 'D': true, 'E': true,
|
||||
'F': true, 'G': true, 'H': true, 'I': true, 'J': true, 'K': true, 'L': true, 'M': true,
|
||||
'N': true, 'O': true, 'P': true, 'Q': true, 'R': true, 'S': true, 'T': true, 'U': true,
|
||||
'V': true, 'W': true, 'X': true, 'Y': true, 'Z': true, '0': true, '1': true, '2': true,
|
||||
'3': true, '4': true, '5': true, '6': true, '7': true, '8': true, '9': true, '!': true,
|
||||
'#': true, '$': true, '%': true, '&': true, '\'': true, '*': true, '+': true, '/': true,
|
||||
'=': true, '?': true, '^': true, '_': true, '`': true, '{': true, '|': true, '}': true,
|
||||
'~': true, '-': true}
|
||||
letterOrDigit = rangetable.Merge(unicode.Letter, unicode.Digit)
|
||||
punctSpaceCc = rangetable.Merge(unicode.Punct, unicode.Space, unicode.Cc)
|
||||
)
|
||||
|
||||
func isAllowedInEmail(r rune) bool {
|
||||
return r < 0x7f && emailcs[r]
|
||||
}
|
||||
|
||||
func isLetterOrDigit(r rune) bool {
|
||||
return unicode.Is(letterOrDigit, r)
|
||||
}
|
||||
|
||||
func isPunctOrSpaceOrControl(r rune) bool {
|
||||
return r == '<' || r == '>' || r == '\uff5c' || unicode.Is(punctSpaceCc, r)
|
||||
}
|
||||
|
||||
func isUnreserved(r rune) bool {
|
||||
return (r < 0x7f && unreserved[r]) || unicode.Is(letterOrDigit, r)
|
||||
}
|
||||
|
||||
func isSubDelimiter(r rune) bool {
|
||||
return r < 0x7f && subdelims[r]
|
||||
}
|
93
vendor/gitlab.com/golang-commonmark/linkify/email.go
generated
vendored
Normal file
93
vendor/gitlab.com/golang-commonmark/linkify/email.go
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
// 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 linkify
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func findEmailStart(s string, start int) (_ int, _ bool) {
|
||||
end := start
|
||||
allowDot := false
|
||||
for end >= 0 {
|
||||
b := s[end]
|
||||
switch {
|
||||
case emailcs[b]:
|
||||
allowDot = true
|
||||
case b == '.':
|
||||
if !allowDot {
|
||||
return
|
||||
}
|
||||
allowDot = false
|
||||
default:
|
||||
if end == start {
|
||||
return
|
||||
}
|
||||
if s[end+1] == '.' {
|
||||
return
|
||||
}
|
||||
r, _ := utf8.DecodeLastRuneInString(s[:end+1])
|
||||
if r == utf8.RuneError {
|
||||
return
|
||||
}
|
||||
if !unicode.IsSpace(r) {
|
||||
return
|
||||
}
|
||||
return end + 1, true
|
||||
}
|
||||
end--
|
||||
}
|
||||
if end < start && s[end+1] == '.' {
|
||||
return
|
||||
}
|
||||
return end + 1, true
|
||||
}
|
||||
|
||||
func findEmailEnd(s string, start int) (_ int, _ bool) {
|
||||
end := start
|
||||
allowDot := false
|
||||
loop:
|
||||
for end < len(s) {
|
||||
b := s[end]
|
||||
switch {
|
||||
case emailcs[b]:
|
||||
allowDot = true
|
||||
case b == '.':
|
||||
if !allowDot {
|
||||
return
|
||||
}
|
||||
allowDot = false
|
||||
case b == '@':
|
||||
break loop
|
||||
default:
|
||||
return
|
||||
}
|
||||
end++
|
||||
}
|
||||
if end >= len(s)-5 {
|
||||
return
|
||||
}
|
||||
if end > start && s[end-1] == '.' {
|
||||
return
|
||||
}
|
||||
|
||||
var dot int
|
||||
var ok bool
|
||||
end, dot, ok = findHostnameEnd(s, end+1)
|
||||
if !ok || dot == -1 {
|
||||
return
|
||||
}
|
||||
|
||||
if dot+5 <= len(s) && s[dot+1:dot+5] == "xn--" {
|
||||
return end, true
|
||||
}
|
||||
|
||||
if length := match(s[dot+1:]); dot+length+1 != end {
|
||||
return
|
||||
}
|
||||
|
||||
return end, true
|
||||
}
|
18175
vendor/gitlab.com/golang-commonmark/linkify/generated.go
generated
vendored
Normal file
18175
vendor/gitlab.com/golang-commonmark/linkify/generated.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
462
vendor/gitlab.com/golang-commonmark/linkify/linkify.go
generated
vendored
Normal file
462
vendor/gitlab.com/golang-commonmark/linkify/linkify.go
generated
vendored
Normal file
@ -0,0 +1,462 @@
|
||||
// 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 linkify provides a way to find links in plain text.
|
||||
package linkify
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Link represents a link found in a string with a schema and a position in the string.
|
||||
type Link struct {
|
||||
Scheme string
|
||||
Start, End int
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a >= b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Links returns links found in s.
|
||||
func Links(s string) (links []Link) {
|
||||
for i := 0; i < len(s)-2; i++ {
|
||||
switch s[i] {
|
||||
case '.': // IP address or domain name
|
||||
if i == 0 {
|
||||
continue // . at the start of a line
|
||||
}
|
||||
if length := match(s[i+1:]); length > 0 {
|
||||
pos := i + 1 + length
|
||||
switch s[pos-1] {
|
||||
case '.': // IP address
|
||||
if pos >= len(s) {
|
||||
continue // . at the end of line
|
||||
}
|
||||
if !digit(s[i-1]) {
|
||||
i = pos
|
||||
continue // . should be preceded by a digit
|
||||
}
|
||||
if !digit(s[pos]) {
|
||||
i = pos
|
||||
continue // . should be followed by a digit
|
||||
}
|
||||
|
||||
// find the start of the IP address
|
||||
j := i - 2
|
||||
m := max(0, j-3)
|
||||
for j >= m && digit(s[j]) {
|
||||
j--
|
||||
}
|
||||
if i-2-j > 2 {
|
||||
i = pos + 1
|
||||
continue // at most 3 digits
|
||||
}
|
||||
start := 0
|
||||
if j >= 0 {
|
||||
r, rlen := utf8.DecodeLastRuneInString(s[:j+1])
|
||||
if !isPunctOrSpaceOrControl(r) {
|
||||
i = pos + 1
|
||||
continue
|
||||
}
|
||||
switch r {
|
||||
case '.', ':', '/', '\\', '-', '_':
|
||||
i = pos + 1
|
||||
continue
|
||||
}
|
||||
start = j + 2 - rlen
|
||||
}
|
||||
|
||||
length, ok := skipIPv4(s[start:])
|
||||
if !ok {
|
||||
i = pos + 1
|
||||
continue
|
||||
}
|
||||
end := start + length
|
||||
if end == len(s) {
|
||||
links = append(links, Link{
|
||||
Scheme: "",
|
||||
Start: start,
|
||||
End: end,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
r, _ := utf8.DecodeRuneInString(s[end:])
|
||||
if !isPunctOrSpaceOrControl(r) {
|
||||
continue
|
||||
}
|
||||
|
||||
end = skipPort(s, end)
|
||||
end = skipPath(s, end)
|
||||
end = skipQuery(s, end)
|
||||
end = skipFragment(s, end)
|
||||
end = unskipPunct(s, end)
|
||||
|
||||
if end < len(s) {
|
||||
r, _ = utf8.DecodeRuneInString(s[end:])
|
||||
if !isPunctOrSpaceOrControl(r) || r == '%' {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
links = append(links, Link{
|
||||
Scheme: "",
|
||||
Start: start,
|
||||
End: end,
|
||||
})
|
||||
i = end
|
||||
|
||||
default: // domain name
|
||||
r, _ := utf8.DecodeLastRuneInString(s[:i])
|
||||
if isPunctOrSpaceOrControl(r) {
|
||||
continue
|
||||
}
|
||||
|
||||
if pos == len(s) {
|
||||
start, ok := findHostnameStart(s, i)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
links = append(links, Link{
|
||||
Scheme: "",
|
||||
Start: start,
|
||||
End: pos,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if s[i+1:pos] != "xn--" {
|
||||
r, _ = utf8.DecodeRuneInString(s[pos:])
|
||||
if isLetterOrDigit(r) {
|
||||
continue // should not be followed by a letter or a digit
|
||||
}
|
||||
}
|
||||
|
||||
end, dot, ok := findHostnameEnd(s, pos)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
dot = max(dot, i)
|
||||
|
||||
if !(dot+5 <= len(s) && s[dot+1:dot+5] == "xn--") {
|
||||
if length := match(s[dot+1:]); dot+length+1 != end {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
start, ok := findHostnameStart(s, i)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
end = skipPort(s, end)
|
||||
end = skipPath(s, end)
|
||||
end = skipQuery(s, end)
|
||||
end = skipFragment(s, end)
|
||||
end = unskipPunct(s, end)
|
||||
|
||||
if end < len(s) {
|
||||
r, _ = utf8.DecodeRuneInString(s[end:])
|
||||
if !isPunctOrSpaceOrControl(r) || r == '%' {
|
||||
continue // should be followed by punctuation or space
|
||||
}
|
||||
}
|
||||
|
||||
links = append(links, Link{
|
||||
Scheme: "",
|
||||
Start: start,
|
||||
End: end,
|
||||
})
|
||||
i = end
|
||||
}
|
||||
}
|
||||
|
||||
case '/': // schema-less link
|
||||
if s[i+1] != '/' {
|
||||
continue
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
if s[i-1] == ':' {
|
||||
i++
|
||||
continue // should not be preceded by a colon
|
||||
}
|
||||
r, _ := utf8.DecodeLastRuneInString(s[:i])
|
||||
if !isPunctOrSpaceOrControl(r) {
|
||||
i++
|
||||
continue // should be preceded by punctuation or space
|
||||
}
|
||||
}
|
||||
|
||||
r, _ := utf8.DecodeRuneInString(s[i+2:])
|
||||
if !isLetterOrDigit(r) {
|
||||
i++
|
||||
continue // should be followed by a letter or a digit
|
||||
}
|
||||
|
||||
start := i
|
||||
end, dot, ok := findHostnameEnd(s, i+2)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if s[i+2:end] != "localhost" {
|
||||
if dot == -1 {
|
||||
continue // no dot
|
||||
}
|
||||
if length, ok := skipIPv4(s[i+2:]); !ok || i+2+length != end {
|
||||
if length := match(s[dot+1:]); dot+length+1 != end {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end = skipPort(s, end)
|
||||
end = skipPath(s, end)
|
||||
end = skipQuery(s, end)
|
||||
end = skipFragment(s, end)
|
||||
end = unskipPunct(s, end)
|
||||
|
||||
if end < len(s) {
|
||||
r, _ = utf8.DecodeRuneInString(s[end:])
|
||||
if !isPunctOrSpaceOrControl(r) || r == '%' {
|
||||
continue // should be followed by punctuation or space
|
||||
}
|
||||
}
|
||||
|
||||
links = append(links, Link{
|
||||
Scheme: "//",
|
||||
Start: start,
|
||||
End: end,
|
||||
})
|
||||
i = end
|
||||
|
||||
case ':': // http, https, ftp, mailto or localhost
|
||||
if i < 3 { // at least ftp:
|
||||
continue
|
||||
}
|
||||
|
||||
if i >= 9 && s[i-1] == 't' && s[i-9:i] == "localhost" {
|
||||
j := i - 9
|
||||
if !digit(s[j+10]) {
|
||||
continue
|
||||
}
|
||||
if j > 0 {
|
||||
r, _ := utf8.DecodeLastRuneInString(s[:j])
|
||||
if !isPunctOrSpaceOrControl(r) {
|
||||
i++
|
||||
continue // should be preceded by punctuation or space
|
||||
}
|
||||
}
|
||||
|
||||
start := j
|
||||
pos := j + 9
|
||||
end := skipPort(s, pos)
|
||||
if end == pos {
|
||||
continue // invalid port
|
||||
}
|
||||
end = skipPath(s, end)
|
||||
end = skipQuery(s, end)
|
||||
end = skipFragment(s, end)
|
||||
end = unskipPunct(s, end)
|
||||
|
||||
if end < len(s) {
|
||||
r, _ := utf8.DecodeRuneInString(s[end:])
|
||||
if !isPunctOrSpaceOrControl(r) || r == '%' {
|
||||
i++
|
||||
continue // should be followed by punctuation or space
|
||||
}
|
||||
}
|
||||
|
||||
links = append(links, Link{
|
||||
Scheme: "",
|
||||
Start: start,
|
||||
End: end,
|
||||
})
|
||||
i = end
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
j := i - 1
|
||||
var start int
|
||||
var schema string
|
||||
|
||||
switch byteToLower(s[j]) {
|
||||
case 'o': // mailto
|
||||
if j < 5 {
|
||||
continue // too short for mailto
|
||||
}
|
||||
if len(s)-j < 8 {
|
||||
continue // insufficient length after
|
||||
}
|
||||
if strings.ToLower(s[j-5:j+2]) != "mailto:" {
|
||||
continue
|
||||
}
|
||||
r, _ := utf8.DecodeLastRuneInString(s[:j-5])
|
||||
if isLetterOrDigit(r) {
|
||||
continue // should not be preceded by a letter or a digit
|
||||
}
|
||||
r, _ = utf8.DecodeRuneInString(s[j+2:])
|
||||
if !isAllowedInEmail(r) {
|
||||
continue // should be followed by a valid e-mail character
|
||||
}
|
||||
|
||||
start = j - 5
|
||||
end, ok := findEmailEnd(s, j+2)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
links = append(links, Link{
|
||||
Scheme: "mailto:",
|
||||
Start: start,
|
||||
End: end,
|
||||
})
|
||||
i = end
|
||||
continue // continue processing
|
||||
|
||||
case 'p': // http or ftp
|
||||
if len(s)-j < 8 {
|
||||
continue // insufficient length after
|
||||
}
|
||||
switch byteToLower(s[j-2]) {
|
||||
case 'f':
|
||||
if strings.ToLower(s[j-2:j+4]) != "ftp://" {
|
||||
continue
|
||||
}
|
||||
start = j - 2
|
||||
schema = "ftp:"
|
||||
case 't':
|
||||
if j < 3 {
|
||||
continue
|
||||
}
|
||||
if strings.ToLower(s[j-3:j+4]) != "http://" {
|
||||
continue
|
||||
}
|
||||
start = j - 3
|
||||
schema = "http:"
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
case 's': // https
|
||||
if j < 4 {
|
||||
continue // too short for https
|
||||
}
|
||||
if len(s)-j < 8 {
|
||||
continue // insufficient length after
|
||||
}
|
||||
start = j - 4
|
||||
if strings.ToLower(s[start:j+4]) != "https://" {
|
||||
continue
|
||||
}
|
||||
schema = "https:"
|
||||
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
// http, https or ftp
|
||||
|
||||
if start > 0 {
|
||||
r, _ := utf8.DecodeLastRuneInString(s[:start])
|
||||
if !isPunctOrSpaceOrControl(r) {
|
||||
continue // should be preceded by punctuation or space
|
||||
}
|
||||
}
|
||||
|
||||
r, _ := utf8.DecodeRuneInString(s[j+4:])
|
||||
if isPunctOrSpaceOrControl(r) {
|
||||
continue
|
||||
}
|
||||
|
||||
end, dot, ok := findHostnameEnd(s, j+4)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if s[j+4:end] != "localhost" {
|
||||
if dot == -1 {
|
||||
continue // no dot
|
||||
}
|
||||
if length, ok := skipIPv4(s[j+4:]); !ok || j+4+length != end {
|
||||
if !(dot+5 <= len(s) && s[dot+1:dot+5] == "xn--") {
|
||||
if length := match(s[dot+1:]); dot+length+1 != end {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end = skipPort(s, end)
|
||||
end = skipPath(s, end)
|
||||
end = skipQuery(s, end)
|
||||
end = skipFragment(s, end)
|
||||
end = unskipPunct(s, end)
|
||||
|
||||
if end < len(s) {
|
||||
r, _ = utf8.DecodeRuneInString(s[end:])
|
||||
if !isPunctOrSpaceOrControl(r) || r == '%' {
|
||||
continue // should be followed by punctuation or space
|
||||
}
|
||||
}
|
||||
|
||||
links = append(links, Link{
|
||||
Scheme: schema,
|
||||
Start: start,
|
||||
End: end,
|
||||
})
|
||||
i = end
|
||||
|
||||
case '@': // schema-less e-mail
|
||||
if i == 0 {
|
||||
continue // @ at the start of a line
|
||||
}
|
||||
|
||||
if len(s)-i < 5 {
|
||||
continue // insufficient length after
|
||||
}
|
||||
|
||||
r, _ := utf8.DecodeLastRuneInString(s[:i])
|
||||
if !isAllowedInEmail(r) {
|
||||
continue // should be preceded by a valid e-mail character
|
||||
}
|
||||
|
||||
r, _ = utf8.DecodeRuneInString(s[i+1:])
|
||||
if !isLetterOrDigit(r) {
|
||||
continue // should be followed by a letter or a digit
|
||||
}
|
||||
|
||||
start, ok := findEmailStart(s, i-1)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
end, dot, ok := findHostnameEnd(s, i+1)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if dot == -1 {
|
||||
continue // no dot
|
||||
}
|
||||
if !(dot+5 <= len(s) && s[dot+1:dot+5] == "xn--") {
|
||||
if length := match(s[dot+1:]); dot+length+1 != end {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
links = append(links, Link{
|
||||
Scheme: "mailto:",
|
||||
Start: start,
|
||||
End: end,
|
||||
})
|
||||
i = end
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
404
vendor/gitlab.com/golang-commonmark/linkify/url.go
generated
vendored
Normal file
404
vendor/gitlab.com/golang-commonmark/linkify/url.go
generated
vendored
Normal file
@ -0,0 +1,404 @@
|
||||
// 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 linkify
|
||||
|
||||
import "unicode/utf8"
|
||||
|
||||
func atoi3(s string, start int) (int, bool) {
|
||||
n := 0
|
||||
var i int
|
||||
for i = start; i < len(s) && digit(s[i]); i++ {
|
||||
n = n*10 + int(s[i]-'0')
|
||||
if n > 255 {
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
if i == start {
|
||||
return 0, false
|
||||
}
|
||||
return i, true
|
||||
}
|
||||
|
||||
func skipIPv4(s string) (_ int, _ bool) {
|
||||
j := 0
|
||||
for i := 0; i < 4; i++ {
|
||||
if j >= len(s) {
|
||||
return
|
||||
}
|
||||
if i > 0 {
|
||||
if s[j] != '.' {
|
||||
return
|
||||
}
|
||||
j++
|
||||
}
|
||||
n, ok := atoi3(s, j)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
j = n
|
||||
}
|
||||
return j, true
|
||||
}
|
||||
|
||||
func atoi5(s string, start int) (int, bool) {
|
||||
n := 0
|
||||
var i int
|
||||
for i = start; i < len(s) && digit(s[i]); i++ {
|
||||
n = n*10 + int(s[i]-'0')
|
||||
if n > 65535 {
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
if i == start || n == 0 {
|
||||
return 0, false
|
||||
}
|
||||
return i, true
|
||||
}
|
||||
|
||||
func skipPort(s string, start int) int {
|
||||
if start >= len(s) || s[start] != ':' {
|
||||
return start
|
||||
}
|
||||
end, ok := atoi5(s, start+1)
|
||||
if !ok {
|
||||
return start
|
||||
}
|
||||
return end
|
||||
}
|
||||
|
||||
func skipPath(s string, start int) int {
|
||||
if start >= len(s) || s[start] != '/' {
|
||||
return start // skip empty path
|
||||
}
|
||||
var stack []rune
|
||||
var notClosedIndex int
|
||||
var nHyphen int
|
||||
end := start + 1
|
||||
loop:
|
||||
for end < len(s) {
|
||||
r, rlen := utf8.DecodeRuneInString(s[end:])
|
||||
if r == utf8.RuneError {
|
||||
nHyphen = 0
|
||||
break
|
||||
}
|
||||
|
||||
switch {
|
||||
case isUnreserved(r):
|
||||
if r == '-' {
|
||||
nHyphen++
|
||||
if nHyphen > 1 {
|
||||
break loop
|
||||
}
|
||||
} else {
|
||||
nHyphen = 0
|
||||
}
|
||||
case isSubDelimiter(r) || r == '[' || r == ']':
|
||||
nHyphen = 0
|
||||
switch r {
|
||||
case '[', '(':
|
||||
if len(stack) == 0 {
|
||||
notClosedIndex = end
|
||||
}
|
||||
stack = append(stack, r)
|
||||
case ']', ')':
|
||||
opening := '['
|
||||
if r == ')' {
|
||||
opening = '('
|
||||
}
|
||||
if len(stack) == 0 || stack[len(stack)-1] != opening {
|
||||
break loop
|
||||
}
|
||||
stack = stack[:len(stack)-1]
|
||||
}
|
||||
case r == '/' || r == ':' || r == '@':
|
||||
nHyphen = 0
|
||||
case r == '%':
|
||||
nHyphen = 0
|
||||
if end+2 >= len(s) {
|
||||
break loop
|
||||
}
|
||||
if !(hexDigit(s[end+1]) &&
|
||||
hexDigit(s[end+2])) {
|
||||
break loop
|
||||
}
|
||||
end += 2
|
||||
default:
|
||||
nHyphen = 0
|
||||
if r != ' ' || len(stack) == 0 {
|
||||
break loop
|
||||
}
|
||||
}
|
||||
end += rlen
|
||||
}
|
||||
if len(stack) > 0 {
|
||||
return notClosedIndex
|
||||
}
|
||||
if nHyphen > 0 {
|
||||
return end - nHyphen + 1
|
||||
}
|
||||
return end
|
||||
}
|
||||
|
||||
func skipQuery(s string, start int) int {
|
||||
if start >= len(s) || s[start] != '?' {
|
||||
return start
|
||||
}
|
||||
var stack []rune
|
||||
var notClosedIndex int
|
||||
var nHyphen int
|
||||
end := start + 1
|
||||
loop:
|
||||
for end < len(s) {
|
||||
r, rlen := utf8.DecodeRuneInString(s[end:])
|
||||
if r == utf8.RuneError {
|
||||
nHyphen = 0
|
||||
break
|
||||
}
|
||||
|
||||
switch {
|
||||
case isUnreserved(r):
|
||||
if r == '-' {
|
||||
nHyphen++
|
||||
if nHyphen > 1 {
|
||||
break loop
|
||||
}
|
||||
} else {
|
||||
nHyphen = 0
|
||||
}
|
||||
case isSubDelimiter(r) || r == '[' || r == ']':
|
||||
nHyphen = 0
|
||||
switch r {
|
||||
case '[', '(':
|
||||
if len(stack) == 0 {
|
||||
notClosedIndex = end
|
||||
}
|
||||
stack = append(stack, r)
|
||||
case ']', ')':
|
||||
opening := '['
|
||||
if r == ')' {
|
||||
opening = '('
|
||||
}
|
||||
if len(stack) == 0 || stack[len(stack)-1] != opening {
|
||||
break loop
|
||||
}
|
||||
stack = stack[:len(stack)-1]
|
||||
}
|
||||
case r == '?' || r == '/' || r == ':' || r == '@':
|
||||
nHyphen = 0
|
||||
case r == '%':
|
||||
nHyphen = 0
|
||||
if end+2 >= len(s) {
|
||||
break loop
|
||||
}
|
||||
if !(hexDigit(s[end+1]) &&
|
||||
hexDigit(s[end+2])) {
|
||||
break loop
|
||||
}
|
||||
end += 2
|
||||
default:
|
||||
nHyphen = 0
|
||||
if r != ' ' || len(stack) == 0 {
|
||||
break loop
|
||||
}
|
||||
}
|
||||
end += rlen
|
||||
}
|
||||
if len(stack) > 0 {
|
||||
return notClosedIndex
|
||||
}
|
||||
if nHyphen > 0 {
|
||||
return end - nHyphen + 1
|
||||
}
|
||||
return end
|
||||
}
|
||||
|
||||
func skipFragment(s string, start int) int {
|
||||
if start >= len(s) || s[start] != '#' {
|
||||
return start
|
||||
}
|
||||
var stack []rune
|
||||
var notClosedIndex int
|
||||
var nHyphen int
|
||||
end := start + 1
|
||||
loop:
|
||||
for end < len(s) {
|
||||
r, rlen := utf8.DecodeRuneInString(s[end:])
|
||||
if r == utf8.RuneError {
|
||||
nHyphen = 0
|
||||
break
|
||||
}
|
||||
|
||||
switch {
|
||||
case isUnreserved(r):
|
||||
if r == '-' {
|
||||
nHyphen++
|
||||
if nHyphen > 1 {
|
||||
break loop
|
||||
}
|
||||
} else {
|
||||
nHyphen = 0
|
||||
}
|
||||
case isSubDelimiter(r) || r == '[' || r == ']':
|
||||
nHyphen = 0
|
||||
switch r {
|
||||
case '[', '(':
|
||||
if len(stack) == 0 {
|
||||
notClosedIndex = end
|
||||
}
|
||||
stack = append(stack, r)
|
||||
case ']', ')':
|
||||
opening := '['
|
||||
if r == ')' {
|
||||
opening = '('
|
||||
}
|
||||
if len(stack) == 0 || stack[len(stack)-1] != opening {
|
||||
break loop
|
||||
}
|
||||
stack = stack[:len(stack)-1]
|
||||
}
|
||||
case r == '?' || r == '/' || r == ':' || r == '@':
|
||||
nHyphen = 0
|
||||
case r == '%':
|
||||
nHyphen = 0
|
||||
if end+2 >= len(s) {
|
||||
break loop
|
||||
}
|
||||
if !(hexDigit(s[end+1]) &&
|
||||
hexDigit(s[end+2])) {
|
||||
break loop
|
||||
}
|
||||
end += 2
|
||||
default:
|
||||
nHyphen = 0
|
||||
if r != ' ' || len(stack) == 0 {
|
||||
break loop
|
||||
}
|
||||
}
|
||||
end += rlen
|
||||
}
|
||||
if len(stack) > 0 {
|
||||
return notClosedIndex
|
||||
}
|
||||
if nHyphen > 0 {
|
||||
return end - nHyphen + 1
|
||||
}
|
||||
return end
|
||||
}
|
||||
|
||||
func unskipPunct(s string, start int) int {
|
||||
end := start - 1
|
||||
if end < 0 || end >= len(s) || !basicPunct[s[end]] {
|
||||
return start
|
||||
}
|
||||
return end
|
||||
}
|
||||
|
||||
func findHostnameStart(s string, start int) (_ int, _ bool) {
|
||||
end := start
|
||||
lastDot := true
|
||||
nHyphen := 0
|
||||
loop:
|
||||
for end > 0 {
|
||||
r, rlen := utf8.DecodeLastRuneInString(s[:end])
|
||||
if r == utf8.RuneError {
|
||||
return
|
||||
}
|
||||
|
||||
switch {
|
||||
case r == '.':
|
||||
if nHyphen > 0 {
|
||||
return
|
||||
}
|
||||
lastDot = true
|
||||
case r == '-':
|
||||
if end == start {
|
||||
return
|
||||
}
|
||||
if lastDot {
|
||||
return
|
||||
}
|
||||
nHyphen++
|
||||
if nHyphen == 3 {
|
||||
return
|
||||
}
|
||||
case r == ':' || r == '/' || r == '\\' || r == '_':
|
||||
return
|
||||
case isPunctOrSpaceOrControl(r):
|
||||
break loop
|
||||
default:
|
||||
lastDot = false
|
||||
nHyphen = 0
|
||||
}
|
||||
end -= rlen
|
||||
}
|
||||
if lastDot || nHyphen > 0 {
|
||||
return
|
||||
}
|
||||
return end, true
|
||||
}
|
||||
|
||||
func findHostnameEnd(s string, start int) (_ int, _ int, _ bool) {
|
||||
end := start
|
||||
lastDot := false
|
||||
lastDotPos := -1
|
||||
nHyphen := 0
|
||||
loop:
|
||||
for end < len(s) {
|
||||
r, rlen := utf8.DecodeRuneInString(s[end:])
|
||||
if r == utf8.RuneError {
|
||||
return
|
||||
}
|
||||
|
||||
switch {
|
||||
case r == '.':
|
||||
if nHyphen > 0 {
|
||||
return
|
||||
}
|
||||
if lastDot {
|
||||
break loop
|
||||
}
|
||||
lastDot = true
|
||||
lastDotPos = end
|
||||
nHyphen = 0
|
||||
case r == '-':
|
||||
lastDot = false
|
||||
if end == start {
|
||||
return
|
||||
}
|
||||
if lastDot {
|
||||
return
|
||||
}
|
||||
nHyphen++
|
||||
if nHyphen == 3 {
|
||||
break loop
|
||||
}
|
||||
case r == '\\' || r == '_':
|
||||
return
|
||||
case isPunctOrSpaceOrControl(r):
|
||||
break loop
|
||||
default:
|
||||
lastDot = false
|
||||
nHyphen = 0
|
||||
}
|
||||
end += rlen
|
||||
}
|
||||
|
||||
if nHyphen > 0 {
|
||||
end -= nHyphen
|
||||
} else if lastDot {
|
||||
if s[end-1] == '.' {
|
||||
end--
|
||||
}
|
||||
lastDotPos = end - 1
|
||||
for lastDotPos >= start && s[lastDotPos] != '.' {
|
||||
lastDotPos--
|
||||
}
|
||||
if lastDotPos < start {
|
||||
lastDotPos = -1
|
||||
}
|
||||
}
|
||||
|
||||
return end, lastDotPos, true
|
||||
}
|
20
vendor/gitlab.com/golang-commonmark/linkify/util.go
generated
vendored
Normal file
20
vendor/gitlab.com/golang-commonmark/linkify/util.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// 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 linkify
|
||||
|
||||
func digit(b byte) bool {
|
||||
return b >= '0' && b <= '9'
|
||||
}
|
||||
|
||||
func hexDigit(b byte) bool {
|
||||
return digit(b) || b >= 'a' && b <= 'f' || b >= 'A' && b <= 'F'
|
||||
}
|
||||
|
||||
func byteToLower(b byte) byte {
|
||||
if b >= 'A' && b <= 'Z' {
|
||||
return b - 'A' + 'a'
|
||||
}
|
||||
return b
|
||||
}
|
25
vendor/gitlab.com/golang-commonmark/markdown/.gitlab-ci.yml
generated
vendored
Normal file
25
vendor/gitlab.com/golang-commonmark/markdown/.gitlab-ci.yml
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
image: golang:1.11
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
|
||||
before_script:
|
||||
- go get github.com/russross/blackfriday
|
||||
- go get gitlab.com/golang-commonmark/html
|
||||
- go get gitlab.com/golang-commonmark/linkify
|
||||
- go get gitlab.com/golang-commonmark/mdurl
|
||||
- go get gitlab.com/golang-commonmark/puny
|
||||
- go get gitlab.com/opennota/wd
|
||||
- go get gopkg.in/russross/blackfriday.v2
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- go build ./...
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- test -z "$(gofmt -l . | tee /dev/stderr)"
|
||||
- go test -cover ./...
|
1
vendor/gitlab.com/golang-commonmark/markdown/AUTHORS
generated
vendored
Normal file
1
vendor/gitlab.com/golang-commonmark/markdown/AUTHORS
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
opennota@gmail.com
|
10
vendor/gitlab.com/golang-commonmark/markdown/LICENSE
generated
vendored
Normal file
10
vendor/gitlab.com/golang-commonmark/markdown/LICENSE
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
Copyright (c) 2015, The Authors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
64
vendor/gitlab.com/golang-commonmark/markdown/README.md
generated
vendored
Normal file
64
vendor/gitlab.com/golang-commonmark/markdown/README.md
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
markdown [![GoDoc](http://godoc.org/gitlab.com/golang-commonmark/markdown?status.svg)](http://godoc.org/gitlab.com/golang-commonmark/markdown) [![License](https://img.shields.io/badge/licence-BSD--2--Clause-blue.svg)](https://opensource.org/licenses/BSD-2-Clause) [![Pipeline status](https://gitlab.com/golang-commonmark/markdown/badges/master/pipeline.svg)](https://gitlab.com/golang-commonmark/markdown/commits/master) [![Coverage report](https://gitlab.com/golang-commonmark/markdown/badges/master/coverage.svg)](https://gitlab.com/golang-commonmark/markdown/commits/master)
|
||||
========
|
||||
|
||||
Package golang-commonmark/markdown provides a CommonMark-compliant markdown parser and renderer, written in Go.
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u gitlab.com/golang-commonmark/markdown
|
||||
|
||||
You can also go get [mdtool](https://gitlab.com/golang-commonmark/mdtool), an example command-line tool:
|
||||
|
||||
go get -u gitlab.com/golang-commonmark/mdtool
|
||||
|
||||
## Standards support
|
||||
|
||||
Currently supported CommonMark spec: [v0.28](http://spec.commonmark.org/0.28/).
|
||||
|
||||
## Extensions
|
||||
|
||||
Besides the features required by CommonMark, golang-commonmark/markdown supports:
|
||||
|
||||
* Tables (GFM)
|
||||
* Strikethrough (GFM)
|
||||
* Autoconverting plain-text URLs to links
|
||||
* Typographic replacements (smart quotes and other)
|
||||
|
||||
## Usage
|
||||
|
||||
``` go
|
||||
md := markdown.New(markdown.XHTMLOutput(true))
|
||||
fmt.Println(md.RenderToString([]byte("Header\n===\nText")))
|
||||
```
|
||||
|
||||
Check out [the source of mdtool](https://gitlab.com/golang-commonmark/mdtool/blob/master/main.go) for a more complete example.
|
||||
|
||||
The following options are currently supported:
|
||||
|
||||
Name | Type | Description | Default
|
||||
--------------- | --------- | ----------------------------------------------------------- | ---------
|
||||
HTML | bool | whether to enable raw HTML | false
|
||||
Tables | bool | whether to enable GFM tables | true
|
||||
Linkify | bool | whether to autoconvert plain-text URLs to links | true
|
||||
Typographer | bool | whether to enable typographic replacements | true
|
||||
Quotes | string / []string | double + single quote replacement pairs for the typographer | “”‘’
|
||||
MaxNesting | int | maximum nesting level | 20
|
||||
LangPrefix | string | CSS language prefix for fenced blocks | language-
|
||||
Breaks | bool | whether to convert newlines inside paragraphs into `<br>` | 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.
|
26
vendor/gitlab.com/golang-commonmark/markdown/align.go
generated
vendored
Normal file
26
vendor/gitlab.com/golang-commonmark/markdown/align.go
generated
vendored
Normal file
@ -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 ""
|
||||
}
|
70
vendor/gitlab.com/golang-commonmark/markdown/autolink.go
generated
vendored
Normal file
70
vendor/gitlab.com/golang-commonmark/markdown/autolink.go
generated
vendored
Normal file
@ -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
|
||||
}
|
60
vendor/gitlab.com/golang-commonmark/markdown/backticks.go
generated
vendored
Normal file
60
vendor/gitlab.com/golang-commonmark/markdown/backticks.go
generated
vendored
Normal file
@ -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
|
||||
}
|
43
vendor/gitlab.com/golang-commonmark/markdown/balance_pairs.go
generated
vendored
Normal file
43
vendor/gitlab.com/golang-commonmark/markdown/balance_pairs.go
generated
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
233
vendor/gitlab.com/golang-commonmark/markdown/blockquote.go
generated
vendored
Normal file
233
vendor/gitlab.com/golang-commonmark/markdown/blockquote.go
generated
vendored
Normal file
@ -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
|
||||
}
|
37
vendor/gitlab.com/golang-commonmark/markdown/code.go
generated
vendored
Normal file
37
vendor/gitlab.com/golang-commonmark/markdown/code.go
generated
vendored
Normal file
@ -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
|
||||
}
|
89
vendor/gitlab.com/golang-commonmark/markdown/emphasis.go
generated
vendored
Normal file
89
vendor/gitlab.com/golang-commonmark/markdown/emphasis.go
generated
vendored
Normal file
@ -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{}
|
||||
}
|
||||
}
|
||||
}
|
35
vendor/gitlab.com/golang-commonmark/markdown/entity.go
generated
vendored
Normal file
35
vendor/gitlab.com/golang-commonmark/markdown/entity.go
generated
vendored
Normal file
@ -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
|
||||
}
|
61
vendor/gitlab.com/golang-commonmark/markdown/escape.go
generated
vendored
Normal file
61
vendor/gitlab.com/golang-commonmark/markdown/escape.go
generated
vendored
Normal file
@ -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
|
||||
}
|
102
vendor/gitlab.com/golang-commonmark/markdown/fence.go
generated
vendored
Normal file
102
vendor/gitlab.com/golang-commonmark/markdown/fence.go
generated
vendored
Normal file
@ -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
|
||||
}
|
9
vendor/gitlab.com/golang-commonmark/markdown/fuzz.go
generated
vendored
Normal file
9
vendor/gitlab.com/golang-commonmark/markdown/fuzz.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
//+build gofuzz
|
||||
|
||||
package markdown
|
||||
|
||||
func Fuzz(data []byte) int {
|
||||
md := New(HTML(true))
|
||||
md.Parse(data)
|
||||
return 1
|
||||
}
|
59
vendor/gitlab.com/golang-commonmark/markdown/heading.go
generated
vendored
Normal file
59
vendor/gitlab.com/golang-commonmark/markdown/heading.go
generated
vendored
Normal file
@ -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
|
||||
}
|
164
vendor/gitlab.com/golang-commonmark/markdown/helpers.go
generated
vendored
Normal file
164
vendor/gitlab.com/golang-commonmark/markdown/helpers.go
generated
vendored
Normal file
@ -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
|
||||
}
|
54
vendor/gitlab.com/golang-commonmark/markdown/hr.go
generated
vendored
Normal file
54
vendor/gitlab.com/golang-commonmark/markdown/hr.go
generated
vendored
Normal file
@ -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
|
||||
}
|
222
vendor/gitlab.com/golang-commonmark/markdown/html_block.go
generated
vendored
Normal file
222
vendor/gitlab.com/golang-commonmark/markdown/html_block.go
generated
vendored
Normal file
@ -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
|
||||
}
|
57
vendor/gitlab.com/golang-commonmark/markdown/html_inline.go
generated
vendored
Normal file
57
vendor/gitlab.com/golang-commonmark/markdown/html_inline.go
generated
vendored
Normal file
@ -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 = `<![A-Z]+\s+[^>]*>`
|
||||
cdata = `<!\[CDATA\[[\s\S]*?\]\]>`
|
||||
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
|
||||
}
|
131
vendor/gitlab.com/golang-commonmark/markdown/image.go
generated
vendored
Normal file
131
vendor/gitlab.com/golang-commonmark/markdown/image.go
generated
vendored
Normal file
@ -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
|
||||
}
|
13
vendor/gitlab.com/golang-commonmark/markdown/inline.go
generated
vendored
Normal file
13
vendor/gitlab.com/golang-commonmark/markdown/inline.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
80
vendor/gitlab.com/golang-commonmark/markdown/lheading.go
generated
vendored
Normal file
80
vendor/gitlab.com/golang-commonmark/markdown/lheading.go
generated
vendored
Normal file
@ -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
|
||||
}
|
132
vendor/gitlab.com/golang-commonmark/markdown/link.go
generated
vendored
Normal file
132
vendor/gitlab.com/golang-commonmark/markdown/link.go
generated
vendored
Normal file
@ -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
|
||||
}
|
131
vendor/gitlab.com/golang-commonmark/markdown/linkify.go
generated
vendored
Normal file
131
vendor/gitlab.com/golang-commonmark/markdown/linkify.go
generated
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
285
vendor/gitlab.com/golang-commonmark/markdown/list.go
generated
vendored
Normal file
285
vendor/gitlab.com/golang-commonmark/markdown/list.go
generated
vendored
Normal file
@ -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
|
||||
}
|
112
vendor/gitlab.com/golang-commonmark/markdown/markdown.go
generated
vendored
Normal file
112
vendor/gitlab.com/golang-commonmark/markdown/markdown.go
generated
vendored
Normal file
@ -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 <br>
|
||||
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()
|
||||
}
|
46
vendor/gitlab.com/golang-commonmark/markdown/newline.go
generated
vendored
Normal file
46
vendor/gitlab.com/golang-commonmark/markdown/newline.go
generated
vendored
Normal file
@ -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
|
||||
}
|
77
vendor/gitlab.com/golang-commonmark/markdown/options.go
generated
vendored
Normal file
77
vendor/gitlab.com/golang-commonmark/markdown/options.go
generated
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
51
vendor/gitlab.com/golang-commonmark/markdown/paragraph.go
generated
vendored
Normal file
51
vendor/gitlab.com/golang-commonmark/markdown/paragraph.go
generated
vendored
Normal file
@ -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
|
||||
}
|
159
vendor/gitlab.com/golang-commonmark/markdown/parser_block.go
generated
vendored
Normal file
159
vendor/gitlab.com/golang-commonmark/markdown/parser_block.go
generated
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
106
vendor/gitlab.com/golang-commonmark/markdown/parser_inline.go
generated
vendored
Normal file
106
vendor/gitlab.com/golang-commonmark/markdown/parser_inline.go
generated
vendored
Normal file
@ -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
|
||||
}
|
158
vendor/gitlab.com/golang-commonmark/markdown/plugins.go
generated
vendored
Normal file
158
vendor/gitlab.com/golang-commonmark/markdown/plugins.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
173
vendor/gitlab.com/golang-commonmark/markdown/reference.go
generated
vendored
Normal file
173
vendor/gitlab.com/golang-commonmark/markdown/reference.go
generated
vendored
Normal file
@ -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
|
||||
}
|
333
vendor/gitlab.com/golang-commonmark/markdown/render.go
generated
vendored
Normal file
333
vendor/gitlab.com/golang-commonmark/markdown/render.go
generated
vendored
Normal file
@ -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("</blockquote>")
|
||||
|
||||
case *BlockquoteOpen:
|
||||
r.w.WriteString("<blockquote>")
|
||||
|
||||
case *BulletListClose:
|
||||
r.w.WriteString("</ul>")
|
||||
|
||||
case *BulletListOpen:
|
||||
r.w.WriteString("<ul>")
|
||||
|
||||
case *CodeBlock:
|
||||
r.w.WriteString("<pre><code>")
|
||||
html.WriteEscapedString(r.w, tok.Content)
|
||||
r.w.WriteString("</code></pre>")
|
||||
|
||||
case *CodeInline:
|
||||
r.w.WriteString("<code>")
|
||||
html.WriteEscapedString(r.w, tok.Content)
|
||||
r.w.WriteString("</code>")
|
||||
|
||||
case *EmphasisClose:
|
||||
r.w.WriteString("</em>")
|
||||
|
||||
case *EmphasisOpen:
|
||||
r.w.WriteString("<em>")
|
||||
|
||||
case *Fence:
|
||||
r.w.WriteString("<pre><code")
|
||||
if tok.Params != "" {
|
||||
langName := strings.SplitN(unescapeAll(tok.Params), " ", 2)[0]
|
||||
langName = rNotSpace.FindString(langName)
|
||||
if langName != "" {
|
||||
r.w.WriteString(` class="`)
|
||||
r.w.WriteString(options.LangPrefix)
|
||||
html.WriteEscapedString(r.w, langName)
|
||||
r.w.WriteByte('"')
|
||||
}
|
||||
}
|
||||
r.w.WriteByte('>')
|
||||
html.WriteEscapedString(r.w, tok.Content)
|
||||
r.w.WriteString("</code></pre>")
|
||||
|
||||
case *Hardbreak:
|
||||
if options.XHTML {
|
||||
r.w.WriteString("<br />\n")
|
||||
} else {
|
||||
r.w.WriteString("<br>\n")
|
||||
}
|
||||
|
||||
case *HeadingClose:
|
||||
r.w.WriteString("</h")
|
||||
r.w.WriteByte("0123456789"[tok.HLevel])
|
||||
r.w.WriteString(">")
|
||||
|
||||
case *HeadingOpen:
|
||||
r.w.WriteString("<h")
|
||||
r.w.WriteByte("0123456789"[tok.HLevel])
|
||||
r.w.WriteByte('>')
|
||||
|
||||
case *Hr:
|
||||
if options.XHTML {
|
||||
r.w.WriteString("<hr />")
|
||||
} else {
|
||||
r.w.WriteString("<hr>")
|
||||
}
|
||||
|
||||
case *HTMLBlock:
|
||||
r.w.WriteString(tok.Content)
|
||||
return // no newline
|
||||
|
||||
case *HTMLInline:
|
||||
r.w.WriteString(tok.Content)
|
||||
|
||||
case *Image:
|
||||
r.w.WriteString(`<img src="`)
|
||||
html.WriteEscapedString(r.w, tok.Src)
|
||||
r.w.WriteString(`" alt="`)
|
||||
r.renderInlineAsText(tok.Tokens)
|
||||
r.w.WriteByte('"')
|
||||
|
||||
if tok.Title != "" {
|
||||
r.w.WriteString(` title="`)
|
||||
html.WriteEscapedString(r.w, tok.Title)
|
||||
r.w.WriteByte('"')
|
||||
}
|
||||
if options.XHTML {
|
||||
r.w.WriteString(" />")
|
||||
} else {
|
||||
r.w.WriteByte('>')
|
||||
}
|
||||
|
||||
case *LinkClose:
|
||||
r.w.WriteString("</a>")
|
||||
|
||||
case *LinkOpen:
|
||||
r.w.WriteString(`<a href="`)
|
||||
html.WriteEscapedString(r.w, tok.Href)
|
||||
r.w.WriteByte('"')
|
||||
if tok.Title != "" {
|
||||
r.w.WriteString(` title="`)
|
||||
html.WriteEscapedString(r.w, (tok.Title))
|
||||
r.w.WriteByte('"')
|
||||
}
|
||||
if tok.Target != "" {
|
||||
r.w.WriteString(` target="`)
|
||||
html.WriteEscapedString(r.w, tok.Target)
|
||||
r.w.WriteByte('"')
|
||||
}
|
||||
if options.Nofollow {
|
||||
r.w.WriteString(` rel="nofollow"`)
|
||||
}
|
||||
r.w.WriteByte('>')
|
||||
|
||||
case *ListItemClose:
|
||||
r.w.WriteString("</li>")
|
||||
|
||||
case *ListItemOpen:
|
||||
r.w.WriteString("<li>")
|
||||
|
||||
case *OrderedListClose:
|
||||
r.w.WriteString("</ol>")
|
||||
|
||||
case *OrderedListOpen:
|
||||
if tok.Order != 1 {
|
||||
r.w.WriteString(`<ol start="`)
|
||||
r.w.WriteString(strconv.Itoa(tok.Order))
|
||||
r.w.WriteString(`">`)
|
||||
} else {
|
||||
r.w.WriteString("<ol>")
|
||||
}
|
||||
|
||||
case *ParagraphClose:
|
||||
if tok.Hidden {
|
||||
return
|
||||
}
|
||||
if !tok.Tight {
|
||||
r.w.WriteString("</p>")
|
||||
} else if tokens[idx+1].Closing() {
|
||||
return // no newline
|
||||
}
|
||||
|
||||
case *ParagraphOpen:
|
||||
if tok.Hidden {
|
||||
return
|
||||
}
|
||||
if !tok.Tight {
|
||||
r.w.WriteString("<p>")
|
||||
}
|
||||
|
||||
case *Softbreak:
|
||||
if options.Breaks {
|
||||
if options.XHTML {
|
||||
r.w.WriteString("<br />\n")
|
||||
} else {
|
||||
r.w.WriteString("<br>\n")
|
||||
}
|
||||
} else {
|
||||
r.w.WriteByte('\n')
|
||||
}
|
||||
return
|
||||
|
||||
case *StrongClose:
|
||||
r.w.WriteString("</strong>")
|
||||
|
||||
case *StrongOpen:
|
||||
r.w.WriteString("<strong>")
|
||||
|
||||
case *StrikethroughClose:
|
||||
r.w.WriteString("</s>")
|
||||
|
||||
case *StrikethroughOpen:
|
||||
r.w.WriteString("<s>")
|
||||
|
||||
case *TableClose:
|
||||
r.w.WriteString("</table>")
|
||||
|
||||
case *TableOpen:
|
||||
r.w.WriteString("<table>")
|
||||
|
||||
case *TbodyClose:
|
||||
r.w.WriteString("</tbody>")
|
||||
|
||||
case *TbodyOpen:
|
||||
r.w.WriteString("<tbody>")
|
||||
|
||||
case *TdClose:
|
||||
r.w.WriteString("</td>")
|
||||
|
||||
case *TdOpen:
|
||||
if tok.Align != AlignNone {
|
||||
r.w.WriteString(`<td style="text-align:`)
|
||||
r.w.WriteString(tok.Align.String())
|
||||
r.w.WriteString(`">`)
|
||||
} else {
|
||||
r.w.WriteString("<td>")
|
||||
}
|
||||
|
||||
case *Text:
|
||||
html.WriteEscapedString(r.w, tok.Content)
|
||||
|
||||
case *TheadClose:
|
||||
r.w.WriteString("</thead>")
|
||||
|
||||
case *TheadOpen:
|
||||
r.w.WriteString("<thead>")
|
||||
|
||||
case *ThClose:
|
||||
r.w.WriteString("</th>")
|
||||
|
||||
case *ThOpen:
|
||||
if align := tok.Align; align != AlignNone {
|
||||
r.w.WriteString(`<th style="text-align:`)
|
||||
r.w.WriteString(align.String())
|
||||
r.w.WriteString(`">`)
|
||||
} else {
|
||||
r.w.WriteString("<th>")
|
||||
}
|
||||
|
||||
case *TrClose:
|
||||
r.w.WriteString("</tr>")
|
||||
|
||||
case *TrOpen:
|
||||
r.w.WriteString("<tr>")
|
||||
|
||||
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')
|
||||
}
|
||||
}
|
229
vendor/gitlab.com/golang-commonmark/markdown/replacements.go
generated
vendored
Normal file
229
vendor/gitlab.com/golang-commonmark/markdown/replacements.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
256
vendor/gitlab.com/golang-commonmark/markdown/smartquotes.go
generated
vendored
Normal file
256
vendor/gitlab.com/golang-commonmark/markdown/smartquotes.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
141
vendor/gitlab.com/golang-commonmark/markdown/state_block.go
generated
vendored
Normal file
141
vendor/gitlab.com/golang-commonmark/markdown/state_block.go
generated
vendored
Normal file
@ -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)
|
||||
}
|
13
vendor/gitlab.com/golang-commonmark/markdown/state_core.go
generated
vendored
Normal file
13
vendor/gitlab.com/golang-commonmark/markdown/state_core.go
generated
vendored
Normal file
@ -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
|
||||
}
|
116
vendor/gitlab.com/golang-commonmark/markdown/state_inline.go
generated
vendored
Normal file
116
vendor/gitlab.com/golang-commonmark/markdown/state_inline.go
generated
vendored
Normal file
@ -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
|
||||
}
|
101
vendor/gitlab.com/golang-commonmark/markdown/strikethrough.go
generated
vendored
Normal file
101
vendor/gitlab.com/golang-commonmark/markdown/strikethrough.go
generated
vendored
Normal file
@ -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]
|
||||
}
|
||||
}
|
||||
}
|
229
vendor/gitlab.com/golang-commonmark/markdown/table.go
generated
vendored
Normal file
229
vendor/gitlab.com/golang-commonmark/markdown/table.go
generated
vendored
Normal file
@ -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
|
||||
}
|
108
vendor/gitlab.com/golang-commonmark/markdown/table_fsm.go
generated
vendored
Normal file
108
vendor/gitlab.com/golang-commonmark/markdown/table_fsm.go
generated
vendored
Normal file
@ -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
|
||||
}
|
52
vendor/gitlab.com/golang-commonmark/markdown/text.go
generated
vendored
Normal file
52
vendor/gitlab.com/golang-commonmark/markdown/text.go
generated
vendored
Normal file
@ -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
|
||||
}
|
42
vendor/gitlab.com/golang-commonmark/markdown/text_collapse.go
generated
vendored
Normal file
42
vendor/gitlab.com/golang-commonmark/markdown/text_collapse.go
generated
vendored
Normal file
@ -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
|
||||
}
|
753
vendor/gitlab.com/golang-commonmark/markdown/token.go
generated
vendored
Normal file
753
vendor/gitlab.com/golang-commonmark/markdown/token.go
generated
vendored
Normal file
@ -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 "" }
|
185
vendor/gitlab.com/golang-commonmark/markdown/urlschema.go
generated
vendored
Normal file
185
vendor/gitlab.com/golang-commonmark/markdown/urlschema.go
generated
vendored
Normal file
@ -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
|
||||
}
|
264
vendor/gitlab.com/golang-commonmark/markdown/util.go
generated
vendored
Normal file
264
vendor/gitlab.com/golang-commonmark/markdown/util.go
generated
vendored
Normal file
@ -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()))
|
||||
}
|
69
vendor/gitlab.com/golang-commonmark/markdown/writer.go
generated
vendored
Normal file
69
vendor/gitlab.com/golang-commonmark/markdown/writer.go
generated
vendored
Normal file
@ -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
|
||||
}
|
16
vendor/gitlab.com/golang-commonmark/mdurl/.gitlab-ci.yml
generated
vendored
Normal file
16
vendor/gitlab.com/golang-commonmark/mdurl/.gitlab-ci.yml
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
image: golang:1.11
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- go build ./...
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- test -z "$(gofmt -l . | tee /dev/stderr)"
|
||||
- go test ./...
|
10
vendor/gitlab.com/golang-commonmark/mdurl/LICENSE
generated
vendored
Normal file
10
vendor/gitlab.com/golang-commonmark/mdurl/LICENSE
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
Copyright (c) 2015, The Authors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
8
vendor/gitlab.com/golang-commonmark/mdurl/README.md
generated
vendored
Normal file
8
vendor/gitlab.com/golang-commonmark/mdurl/README.md
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
mdurl [![License](https://img.shields.io/badge/licence-BSD--2--Clause-blue.svg)](https://opensource.org/licenses/BSD-2-Clause) [![GoDoc](http://godoc.org/gitlab.com/golang-commonmark/mdurl?status.svg)](http://godoc.org/gitlab.com/golang-commonmark/mdurl) [![Pipeline status](https://gitlab.com/golang-commonmark/mdurl/badges/master/pipeline.svg)](https://gitlab.com/golang-commonmark/mdurl/commits/master)
|
||||
=====
|
||||
|
||||
Package mdurl provides functions for parsing, decoding and encoding URLs.
|
||||
|
||||
## Install
|
||||
|
||||
go get -u gitlab.com/golang-commonmark/mdurl
|
80
vendor/gitlab.com/golang-commonmark/mdurl/decode.go
generated
vendored
Normal file
80
vendor/gitlab.com/golang-commonmark/mdurl/decode.go
generated
vendored
Normal file
@ -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 mdurl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func advance(s string, pos int) (byte, int) {
|
||||
if pos >= len(s) {
|
||||
return 0, len(s) + 1
|
||||
}
|
||||
if s[pos] != '%' {
|
||||
return s[pos], pos + 1
|
||||
}
|
||||
if pos+2 < len(s) &&
|
||||
hexDigit(s[pos+1]) &&
|
||||
hexDigit(s[pos+2]) {
|
||||
return unhex(s[pos+1])<<4 | unhex(s[pos+2]), pos + 3
|
||||
}
|
||||
return '%', pos + 1
|
||||
}
|
||||
|
||||
// Decode decodes a percent-encoded URL.
|
||||
// Invalid percent-encoded sequences are left as is.
|
||||
// Invalid UTF-8 sequences are replaced with U+FFFD.
|
||||
func Decode(rawurl string) string {
|
||||
var buf bytes.Buffer
|
||||
i := 0
|
||||
const replacement = "\xEF\xBF\xBD"
|
||||
outer:
|
||||
for i < len(rawurl) {
|
||||
r, rlen := utf8.DecodeRuneInString(rawurl[i:])
|
||||
if r == '%' && i+2 < len(rawurl) &&
|
||||
hexDigit(rawurl[i+1]) &&
|
||||
hexDigit(rawurl[i+2]) {
|
||||
b := unhex(rawurl[i+1])<<4 | unhex(rawurl[i+2])
|
||||
if b < 0x80 {
|
||||
buf.WriteByte(b)
|
||||
i += 3
|
||||
continue
|
||||
}
|
||||
var n int
|
||||
if b&0xe0 == 0xc0 {
|
||||
n = 1
|
||||
} else if b&0xf0 == 0xe0 {
|
||||
n = 2
|
||||
} else if b&0xf8 == 0xf0 {
|
||||
n = 3
|
||||
}
|
||||
if n == 0 {
|
||||
buf.WriteString(replacement)
|
||||
i += 3
|
||||
continue
|
||||
}
|
||||
rb := make([]byte, n+1)
|
||||
rb[0] = b
|
||||
j := i + 3
|
||||
for k := 0; k < n; k++ {
|
||||
b, j = advance(rawurl, j)
|
||||
if j > len(rawurl) || b&0xc0 != 0x80 {
|
||||
buf.WriteString(replacement)
|
||||
i += 3
|
||||
continue outer
|
||||
}
|
||||
rb[k+1] = b
|
||||
}
|
||||
r, _ := utf8.DecodeRune(rb)
|
||||
buf.WriteRune(r)
|
||||
i = j
|
||||
continue
|
||||
}
|
||||
buf.WriteRune(r)
|
||||
i += rlen
|
||||
}
|
||||
return buf.String()
|
||||
}
|
53
vendor/gitlab.com/golang-commonmark/mdurl/encode.go
generated
vendored
Normal file
53
vendor/gitlab.com/golang-commonmark/mdurl/encode.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
// 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 mdurl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Encode percent-encodes rawurl, avoiding double encoding.
|
||||
// It doesn't touch:
|
||||
// - alphanumeric characters ([0-9a-zA-Z]);
|
||||
// - percent-encoded characters (%[0-9a-fA-F]{2});
|
||||
// - excluded characters ([;/?:@&=+$,-_.!~*'()#]).
|
||||
// Invalid UTF-8 sequences are replaced with U+FFFD.
|
||||
func Encode(rawurl string) string {
|
||||
const hexdigit = "0123456789ABCDEF"
|
||||
var buf bytes.Buffer
|
||||
i := 0
|
||||
for i < len(rawurl) {
|
||||
r, rlen := utf8.DecodeRuneInString(rawurl[i:])
|
||||
if r >= 0x80 {
|
||||
for j, n := i, i+rlen; j < n; j++ {
|
||||
b := rawurl[j]
|
||||
buf.WriteByte('%')
|
||||
buf.WriteByte(hexdigit[(b>>4)&0xf])
|
||||
buf.WriteByte(hexdigit[b&0xf])
|
||||
}
|
||||
} else if r == '%' {
|
||||
if i+2 < len(rawurl) &&
|
||||
hexDigit(rawurl[i+1]) &&
|
||||
hexDigit(rawurl[i+2]) {
|
||||
buf.WriteByte('%')
|
||||
buf.WriteByte(byteToUpper(rawurl[i+1]))
|
||||
buf.WriteByte(byteToUpper(rawurl[i+2]))
|
||||
i += 2
|
||||
} else {
|
||||
buf.WriteString("%25")
|
||||
}
|
||||
} else if strings.IndexByte("!#$&'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~", byte(r)) == -1 {
|
||||
buf.WriteByte('%')
|
||||
buf.WriteByte(hexdigit[(r>>4)&0xf])
|
||||
buf.WriteByte(hexdigit[r&0xf])
|
||||
} else {
|
||||
buf.WriteByte(byte(r))
|
||||
}
|
||||
i += rlen
|
||||
}
|
||||
return buf.String()
|
||||
}
|
146
vendor/gitlab.com/golang-commonmark/mdurl/parse.go
generated
vendored
Normal file
146
vendor/gitlab.com/golang-commonmark/mdurl/parse.go
generated
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
// 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 mdurl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrMissingScheme error is returned by Parse if the passed URL starts with a colon.
|
||||
var ErrMissingScheme = errors.New("missing protocol scheme")
|
||||
|
||||
var slashedProtocol = map[string]bool{
|
||||
"http": true,
|
||||
"https": true,
|
||||
"ftp": true,
|
||||
"gopher": true,
|
||||
"file": true,
|
||||
}
|
||||
|
||||
func split(s string, c byte) (string, string, bool) {
|
||||
i := strings.IndexByte(s, c)
|
||||
if i < 0 {
|
||||
return s, "", false
|
||||
}
|
||||
return s[:i], s[i+1:], true
|
||||
}
|
||||
|
||||
func findScheme(s string) (int, error) {
|
||||
if s == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
b := s[0]
|
||||
if b == ':' {
|
||||
return 0, ErrMissingScheme
|
||||
}
|
||||
if !letter(b) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
for i := 1; i < len(s); i++ {
|
||||
b := s[i]
|
||||
switch {
|
||||
case b == ':':
|
||||
return i, nil
|
||||
case strings.IndexByte("+-.0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", b) != -1:
|
||||
// do nothing
|
||||
default:
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Parse parses rawurl into a URL structure.
|
||||
func Parse(rawurl string) (*URL, error) {
|
||||
n, err := findScheme(rawurl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var url URL
|
||||
rest := rawurl
|
||||
hostless := false
|
||||
if n > 0 {
|
||||
url.RawScheme = rest[:n]
|
||||
url.Scheme, rest = strings.ToLower(rest[:n]), rest[n+1:]
|
||||
if url.Scheme == "javascript" {
|
||||
hostless = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hostless && strings.HasPrefix(rest, "//") {
|
||||
url.Slashes, rest = true, rest[2:]
|
||||
}
|
||||
|
||||
if !hostless && (url.Slashes || (url.Scheme != "" && !slashedProtocol[url.Scheme])) {
|
||||
hostEnd := strings.IndexAny(rest, "#/?")
|
||||
atSign := -1
|
||||
i := hostEnd
|
||||
if i == -1 {
|
||||
i = len(rest) - 1
|
||||
}
|
||||
for i >= 0 {
|
||||
if rest[i] == '@' {
|
||||
atSign = i
|
||||
break
|
||||
}
|
||||
i--
|
||||
}
|
||||
|
||||
if atSign != -1 {
|
||||
url.Auth, rest = rest[:atSign], rest[atSign+1:]
|
||||
}
|
||||
|
||||
hostEnd = strings.IndexAny(rest, "\t\r\n \"#%'/;<>?\\^`{|}")
|
||||
if hostEnd == -1 {
|
||||
hostEnd = len(rest)
|
||||
}
|
||||
if hostEnd > 0 && hostEnd < len(rest) && rest[hostEnd-1] == ':' {
|
||||
hostEnd--
|
||||
}
|
||||
host := rest[:hostEnd]
|
||||
|
||||
if len(host) > 1 {
|
||||
b := host[hostEnd-1]
|
||||
if digit(b) {
|
||||
for i := len(host) - 2; i >= 0; i-- {
|
||||
b := host[i]
|
||||
if b == ':' {
|
||||
url.Host, url.Port = host[:i], host[i+1:]
|
||||
break
|
||||
}
|
||||
if !digit(b) {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if b == ':' {
|
||||
host = host[:hostEnd-1]
|
||||
hostEnd--
|
||||
}
|
||||
}
|
||||
if url.Port == "" {
|
||||
url.Host = host
|
||||
}
|
||||
rest = rest[hostEnd:]
|
||||
|
||||
if ipv6 := len(url.Host) > 2 &&
|
||||
url.Host[0] == '[' &&
|
||||
url.Host[len(url.Host)-1] == ']'; ipv6 {
|
||||
url.Host = url.Host[1 : len(url.Host)-1]
|
||||
url.IPv6 = true
|
||||
} else if i := strings.IndexByte(url.Host, ':'); i >= 0 {
|
||||
url.Host, rest = url.Host[:i], url.Host[i:]+rest
|
||||
}
|
||||
}
|
||||
|
||||
rest, url.Fragment, url.HasFragment = split(rest, '#')
|
||||
url.Path, url.RawQuery, url.HasQuery = split(rest, '?')
|
||||
|
||||
return &url, nil
|
||||
}
|
101
vendor/gitlab.com/golang-commonmark/mdurl/url.go
generated
vendored
Normal file
101
vendor/gitlab.com/golang-commonmark/mdurl/url.go
generated
vendored
Normal file
@ -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 url provides functions for parsing, decoding and encoding URLs.
|
||||
package mdurl
|
||||
|
||||
// A URL represents a parsed URL.
|
||||
type URL struct {
|
||||
Scheme string
|
||||
RawScheme string
|
||||
Slashes bool
|
||||
Auth string
|
||||
Host string
|
||||
Port string
|
||||
Path string
|
||||
RawQuery string
|
||||
HasQuery bool
|
||||
Fragment string
|
||||
HasFragment bool
|
||||
IPv6 bool
|
||||
}
|
||||
|
||||
// String reassembles the URL into a URL string.
|
||||
func (u *URL) String() string {
|
||||
size := len(u.Path)
|
||||
if u.Scheme != "" {
|
||||
size += len(u.Scheme) + 1
|
||||
}
|
||||
if u.Slashes {
|
||||
size += 2
|
||||
}
|
||||
if u.Auth != "" {
|
||||
size += len(u.Auth) + 1
|
||||
}
|
||||
if u.Host != "" {
|
||||
size += len(u.Host)
|
||||
if u.IPv6 {
|
||||
size += 2
|
||||
}
|
||||
}
|
||||
if u.Port != "" {
|
||||
size += len(u.Port) + 1
|
||||
}
|
||||
if u.HasQuery {
|
||||
size += len(u.RawQuery) + 1
|
||||
}
|
||||
if u.HasFragment {
|
||||
size += len(u.Fragment) + 1
|
||||
}
|
||||
if size == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
buf := make([]byte, size)
|
||||
i := 0
|
||||
if u.Scheme != "" {
|
||||
i += copy(buf, u.Scheme)
|
||||
buf[i] = ':'
|
||||
i++
|
||||
}
|
||||
if u.Slashes {
|
||||
buf[i] = '/'
|
||||
i++
|
||||
buf[i] = '/'
|
||||
i++
|
||||
}
|
||||
if u.Auth != "" {
|
||||
i += copy(buf[i:], u.Auth)
|
||||
buf[i] = '@'
|
||||
i++
|
||||
}
|
||||
if u.Host != "" {
|
||||
if u.IPv6 {
|
||||
buf[i] = '['
|
||||
i++
|
||||
i += copy(buf[i:], u.Host)
|
||||
buf[i] = ']'
|
||||
i++
|
||||
} else {
|
||||
i += copy(buf[i:], u.Host)
|
||||
}
|
||||
}
|
||||
if u.Port != "" {
|
||||
buf[i] = ':'
|
||||
i++
|
||||
i += copy(buf[i:], u.Port)
|
||||
}
|
||||
i += copy(buf[i:], u.Path)
|
||||
if u.HasQuery {
|
||||
buf[i] = '?'
|
||||
i++
|
||||
i += copy(buf[i:], u.RawQuery)
|
||||
}
|
||||
if u.HasFragment {
|
||||
buf[i] = '#'
|
||||
i++
|
||||
i += copy(buf[i:], u.Fragment)
|
||||
}
|
||||
return string(buf)
|
||||
}
|
36
vendor/gitlab.com/golang-commonmark/mdurl/util.go
generated
vendored
Normal file
36
vendor/gitlab.com/golang-commonmark/mdurl/util.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// 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 mdurl
|
||||
|
||||
func hexDigit(b byte) bool {
|
||||
return digit(b) || b >= 'a' && b <= 'f' || b >= 'A' && b <= 'F'
|
||||
}
|
||||
|
||||
func unhex(b byte) byte {
|
||||
switch {
|
||||
case digit(b):
|
||||
return b - '0'
|
||||
case b >= 'a' && b <= 'f':
|
||||
return b - 'a' + 10
|
||||
case b >= 'A' && b <= 'F':
|
||||
return b - 'A' + 10
|
||||
}
|
||||
panic("unhex: not a hex digit")
|
||||
}
|
||||
|
||||
func letter(b byte) bool {
|
||||
return b >= 'a' && b <= 'z' || b >= 'A' && b <= 'Z'
|
||||
}
|
||||
|
||||
func digit(b byte) bool {
|
||||
return b >= '0' && b <= '9'
|
||||
}
|
||||
|
||||
func byteToUpper(b byte) byte {
|
||||
if b >= 'a' && b <= 'z' {
|
||||
return b - 'a' + 'A'
|
||||
}
|
||||
return b
|
||||
}
|
16
vendor/gitlab.com/golang-commonmark/puny/.gitlab-ci.yml
generated
vendored
Normal file
16
vendor/gitlab.com/golang-commonmark/puny/.gitlab-ci.yml
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
image: golang:1.11
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
|
||||
build:
|
||||
stage: build
|
||||
script:
|
||||
- go build ./...
|
||||
|
||||
test:
|
||||
stage: test
|
||||
script:
|
||||
- test -z "$(gofmt -l . | tee /dev/stderr)"
|
||||
- go test ./...
|
10
vendor/gitlab.com/golang-commonmark/puny/LICENSE
generated
vendored
Normal file
10
vendor/gitlab.com/golang-commonmark/puny/LICENSE
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
Copyright (c) 2015, The Authors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
8
vendor/gitlab.com/golang-commonmark/puny/README.md
generated
vendored
Normal file
8
vendor/gitlab.com/golang-commonmark/puny/README.md
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
puny [![License](https://img.shields.io/badge/licence-BSD--2--Clause-blue.svg)](https://opensource.org/licenses/BSD-2-Clause) [![GoDoc](http://godoc.org/gitlab.com/golang-commonmark/puny?status.svg)](http://godoc.org/gitlab.com/golang-commonmark/puny) [![Pipeline status](https://gitlab.com/golang-commonmark/puny/badges/master/pipeline.svg)](https://gitlab.com/golang-commonmark/puny/commits/master)
|
||||
====
|
||||
|
||||
Package puny provides functions for encoding/decoding to/from punycode.
|
||||
|
||||
## Install
|
||||
|
||||
go get -u gitlab.com/golang-commonmark/puny
|
287
vendor/gitlab.com/golang-commonmark/puny/puny.go
generated
vendored
Normal file
287
vendor/gitlab.com/golang-commonmark/puny/puny.go
generated
vendored
Normal file
@ -0,0 +1,287 @@
|
||||
// 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 puny provides functions for encoding/decoding to/from punycode.
|
||||
package puny
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
maxInt32 int32 = 2147483647
|
||||
base int32 = 36
|
||||
tMin int32 = 1
|
||||
baseMinusTMin = base - tMin
|
||||
tMax int32 = 26
|
||||
skew int32 = 38
|
||||
damp int32 = 700
|
||||
initialBias int32 = 72
|
||||
initialN int32 = 128
|
||||
)
|
||||
|
||||
var (
|
||||
ErrOverflow = errors.New("overflow: input needs wider integers to process")
|
||||
ErrNotBasic = errors.New("illegal input >= 0x80 (not a basic code point)")
|
||||
ErrInvalidInput = errors.New("invalid input")
|
||||
)
|
||||
|
||||
func adapt(delta, numPoints int32, firstTime bool) int32 {
|
||||
if firstTime {
|
||||
delta /= damp
|
||||
} else {
|
||||
delta /= 2
|
||||
}
|
||||
delta += delta / numPoints
|
||||
k := int32(0)
|
||||
for delta > baseMinusTMin*tMax/2 {
|
||||
delta = delta / baseMinusTMin
|
||||
k += base
|
||||
}
|
||||
return k + (baseMinusTMin+1)*delta/(delta+skew)
|
||||
}
|
||||
|
||||
func basicToDigit(b byte) int32 {
|
||||
switch {
|
||||
case b >= '0' && b <= '9':
|
||||
return int32(b - 22)
|
||||
case b >= 'A' && b <= 'Z':
|
||||
return int32(b - 'A')
|
||||
case b >= 'a' && b <= 'z':
|
||||
return int32(b - 'a')
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
func digitToBasic(digit int32) byte {
|
||||
switch {
|
||||
case digit >= 0 && digit <= 25:
|
||||
return byte(digit) + 'a'
|
||||
case digit >= 26 && digit <= 35:
|
||||
return byte(digit) - 26 + '0'
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func lastIndex(s string, c byte) int {
|
||||
for i := len(s) - 1; i >= 0; i-- {
|
||||
if s[i] == c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func ascii(s string) bool {
|
||||
for _, r := range s {
|
||||
if r > 0x7e {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Decode converts a Punycode string of ASCII-only symbols to a string of Unicode symbols.
|
||||
func Decode(s string) (string, error) {
|
||||
basic := lastIndex(s, '-')
|
||||
output := make([]rune, 0, len(s))
|
||||
for i := 0; i < basic; i++ {
|
||||
b := s[i]
|
||||
if b >= 0x80 {
|
||||
return "", ErrNotBasic
|
||||
}
|
||||
output = append(output, rune(b))
|
||||
}
|
||||
|
||||
i, n, bias, pos := int32(0), initialN, initialBias, basic+1
|
||||
|
||||
for pos < len(s) {
|
||||
oldi, w, k := i, int32(1), base
|
||||
for {
|
||||
digit := basicToDigit(s[pos])
|
||||
pos++
|
||||
|
||||
if digit >= base || digit > (maxInt32-i)/w {
|
||||
return "", ErrOverflow
|
||||
}
|
||||
|
||||
i += digit * w
|
||||
|
||||
t := k - bias
|
||||
if t < tMin {
|
||||
t = tMin
|
||||
} else if t > tMax {
|
||||
t = tMax
|
||||
}
|
||||
|
||||
if digit < t {
|
||||
break
|
||||
}
|
||||
|
||||
if pos == len(s) {
|
||||
return "", ErrInvalidInput
|
||||
}
|
||||
|
||||
baseMinusT := base - t
|
||||
if w > maxInt32/baseMinusT {
|
||||
return "", ErrOverflow
|
||||
}
|
||||
|
||||
w *= baseMinusT
|
||||
k += base
|
||||
}
|
||||
|
||||
out := int32(len(output) + 1)
|
||||
bias = adapt(i-oldi, out, oldi == 0)
|
||||
|
||||
if i/out > maxInt32-n {
|
||||
return "", ErrOverflow
|
||||
}
|
||||
|
||||
n += i / out
|
||||
i %= out
|
||||
|
||||
output = append(output, 0)
|
||||
copy(output[i+1:], output[i:])
|
||||
output[i] = rune(n)
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
// Encode converts a string of Unicode symbols (e.g. a domain name label) to a
|
||||
// Punycode string of ASCII-only symbols.
|
||||
func Encode(input string) (string, error) {
|
||||
n := initialN
|
||||
delta := int32(0)
|
||||
bias := initialBias
|
||||
|
||||
var output []byte
|
||||
runes := 0
|
||||
for _, r := range input {
|
||||
if r >= 0x80 {
|
||||
runes++
|
||||
continue
|
||||
}
|
||||
output = append(output, byte(r))
|
||||
}
|
||||
|
||||
basicLength := len(output)
|
||||
handledCPCount := basicLength
|
||||
|
||||
if basicLength > 0 {
|
||||
output = append(output, '-')
|
||||
}
|
||||
|
||||
for runes > 0 {
|
||||
m := maxInt32
|
||||
for _, r := range input {
|
||||
if r >= n && r < m {
|
||||
m = r
|
||||
}
|
||||
}
|
||||
|
||||
handledCPCountPlusOne := int32(handledCPCount + 1)
|
||||
if m-n > (maxInt32-delta)/handledCPCountPlusOne {
|
||||
return "", ErrOverflow
|
||||
}
|
||||
|
||||
delta += (m - n) * handledCPCountPlusOne
|
||||
n = m
|
||||
|
||||
for _, r := range input {
|
||||
if r < n {
|
||||
delta++
|
||||
if delta < 0 {
|
||||
return "", ErrOverflow
|
||||
}
|
||||
continue
|
||||
}
|
||||
if r > n {
|
||||
continue
|
||||
}
|
||||
q := delta
|
||||
for k := base; ; k += base {
|
||||
t := k - bias
|
||||
if t < tMin {
|
||||
t = tMin
|
||||
} else if t > tMax {
|
||||
t = tMax
|
||||
}
|
||||
if q < t {
|
||||
break
|
||||
}
|
||||
qMinusT := q - t
|
||||
baseMinusT := base - t
|
||||
output = append(output, digitToBasic(t+qMinusT%baseMinusT))
|
||||
q = qMinusT / baseMinusT
|
||||
}
|
||||
|
||||
output = append(output, digitToBasic(q))
|
||||
bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength)
|
||||
delta = 0
|
||||
handledCPCount++
|
||||
runes--
|
||||
}
|
||||
delta++
|
||||
n++
|
||||
}
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
func sep(r rune) bool { return r == '.' || r == '。' || r == '.' || r == '。' }
|
||||
|
||||
func mapLabels(s string, fn func(string) string) string {
|
||||
var result string
|
||||
i := strings.IndexByte(s, '@')
|
||||
if i != -1 {
|
||||
result = s[:i+1]
|
||||
s = s[i+1:]
|
||||
}
|
||||
var labels []string
|
||||
start := 0
|
||||
for i, r := range s {
|
||||
if !sep(r) {
|
||||
continue
|
||||
}
|
||||
labels = append(labels, fn(s[start:i]))
|
||||
start = i + utf8.RuneLen(r)
|
||||
}
|
||||
labels = append(labels, fn(s[start:]))
|
||||
return result + strings.Join(labels, ".")
|
||||
}
|
||||
|
||||
// ToUnicode converts a Punycode string representing a domain name or an email address
|
||||
// to Unicode. Only the Punycoded parts of the input will be converted.
|
||||
func ToUnicode(s string) string {
|
||||
return mapLabels(s, func(s string) string {
|
||||
if !strings.HasPrefix(s, "xn--") {
|
||||
return s
|
||||
}
|
||||
d, err := Decode(strings.ToLower(s[4:]))
|
||||
if err != nil {
|
||||
return s
|
||||
}
|
||||
return d
|
||||
})
|
||||
}
|
||||
|
||||
// ToASCII converts a Unicode string representing a domain name or an email address to
|
||||
// Punycode. Only the non-ASCII parts of the domain name will be converted.
|
||||
func ToASCII(s string) string {
|
||||
return mapLabels(s, func(s string) string {
|
||||
if ascii(s) {
|
||||
return s
|
||||
}
|
||||
d, err := Encode(s)
|
||||
if err != nil {
|
||||
return s
|
||||
}
|
||||
return "xn--" + d
|
||||
})
|
||||
}
|
115
vendor/golang.org/x/text/unicode/rangetable/gen.go
generated
vendored
Normal file
115
vendor/golang.org/x/text/unicode/rangetable/gen.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"golang.org/x/text/collate"
|
||||
"golang.org/x/text/internal/gen"
|
||||
"golang.org/x/text/internal/ucd"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/unicode/rangetable"
|
||||
)
|
||||
|
||||
var versionList = flag.String("versions", "",
|
||||
"list of versions for which to generate RangeTables")
|
||||
|
||||
const bootstrapMessage = `No versions specified.
|
||||
To bootstrap the code generation, run:
|
||||
go run gen.go --versions=4.1.0,5.0.0,6.0.0,6.1.0,6.2.0,6.3.0,7.0.0
|
||||
|
||||
and ensure that the latest versions are included by checking:
|
||||
http://www.unicode.org/Public/`
|
||||
|
||||
func getVersions() []string {
|
||||
if *versionList == "" {
|
||||
log.Fatal(bootstrapMessage)
|
||||
}
|
||||
|
||||
c := collate.New(language.Und, collate.Numeric)
|
||||
versions := strings.Split(*versionList, ",")
|
||||
c.SortStrings(versions)
|
||||
|
||||
// Ensure that at least the current version is included.
|
||||
for _, v := range versions {
|
||||
if v == gen.UnicodeVersion() {
|
||||
return versions
|
||||
}
|
||||
}
|
||||
|
||||
versions = append(versions, gen.UnicodeVersion())
|
||||
c.SortStrings(versions)
|
||||
return versions
|
||||
}
|
||||
|
||||
func main() {
|
||||
gen.Init()
|
||||
|
||||
versions := getVersions()
|
||||
|
||||
w := &bytes.Buffer{}
|
||||
|
||||
fmt.Fprintf(w, "//go:generate go run gen.go --versions=%s\n\n", strings.Join(versions, ","))
|
||||
fmt.Fprintf(w, "import \"unicode\"\n\n")
|
||||
|
||||
vstr := func(s string) string { return strings.Replace(s, ".", "_", -1) }
|
||||
|
||||
fmt.Fprintf(w, "var assigned = map[string]*unicode.RangeTable{\n")
|
||||
for _, v := range versions {
|
||||
fmt.Fprintf(w, "\t%q: assigned%s,\n", v, vstr(v))
|
||||
}
|
||||
fmt.Fprintf(w, "}\n\n")
|
||||
|
||||
var size int
|
||||
for _, v := range versions {
|
||||
assigned := []rune{}
|
||||
|
||||
r := gen.Open("http://www.unicode.org/Public/", "", v+"/ucd/UnicodeData.txt")
|
||||
ucd.Parse(r, func(p *ucd.Parser) {
|
||||
assigned = append(assigned, p.Rune(0))
|
||||
})
|
||||
|
||||
rt := rangetable.New(assigned...)
|
||||
sz := int(reflect.TypeOf(unicode.RangeTable{}).Size())
|
||||
sz += int(reflect.TypeOf(unicode.Range16{}).Size()) * len(rt.R16)
|
||||
sz += int(reflect.TypeOf(unicode.Range32{}).Size()) * len(rt.R32)
|
||||
|
||||
fmt.Fprintf(w, "// size %d bytes (%d KiB)\n", sz, sz/1024)
|
||||
fmt.Fprintf(w, "var assigned%s = ", vstr(v))
|
||||
print(w, rt)
|
||||
|
||||
size += sz
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "// Total size %d bytes (%d KiB)\n", size, size/1024)
|
||||
|
||||
gen.WriteVersionedGoFile("tables.go", "rangetable", w.Bytes())
|
||||
}
|
||||
|
||||
func print(w io.Writer, rt *unicode.RangeTable) {
|
||||
fmt.Fprintln(w, "&unicode.RangeTable{")
|
||||
fmt.Fprintln(w, "\tR16: []unicode.Range16{")
|
||||
for _, r := range rt.R16 {
|
||||
fmt.Fprintf(w, "\t\t{%#04x, %#04x, %d},\n", r.Lo, r.Hi, r.Stride)
|
||||
}
|
||||
fmt.Fprintln(w, "\t},")
|
||||
fmt.Fprintln(w, "\tR32: []unicode.Range32{")
|
||||
for _, r := range rt.R32 {
|
||||
fmt.Fprintf(w, "\t\t{%#08x, %#08x, %d},\n", r.Lo, r.Hi, r.Stride)
|
||||
}
|
||||
fmt.Fprintln(w, "\t},")
|
||||
fmt.Fprintf(w, "\tLatinOffset: %d,\n", rt.LatinOffset)
|
||||
fmt.Fprintf(w, "}\n\n")
|
||||
}
|
260
vendor/golang.org/x/text/unicode/rangetable/merge.go
generated
vendored
Normal file
260
vendor/golang.org/x/text/unicode/rangetable/merge.go
generated
vendored
Normal file
@ -0,0 +1,260 @@
|
||||
// Copyright 2015 The Go 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 rangetable
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// atEnd is used to mark a completed iteration.
|
||||
const atEnd = unicode.MaxRune + 1
|
||||
|
||||
// Merge returns a new RangeTable that is the union of the given tables.
|
||||
// It can also be used to compact user-created RangeTables. The entries in
|
||||
// R16 and R32 for any given RangeTable should be sorted and non-overlapping.
|
||||
//
|
||||
// A lookup in the resulting table can be several times faster than using In
|
||||
// directly on the ranges. Merge is an expensive operation, however, and only
|
||||
// makes sense if one intends to use the result for more than a couple of
|
||||
// hundred lookups.
|
||||
func Merge(ranges ...*unicode.RangeTable) *unicode.RangeTable {
|
||||
rt := &unicode.RangeTable{}
|
||||
if len(ranges) == 0 {
|
||||
return rt
|
||||
}
|
||||
|
||||
iter := tablesIter(make([]tableIndex, len(ranges)))
|
||||
|
||||
for i, t := range ranges {
|
||||
iter[i] = tableIndex{t, 0, atEnd}
|
||||
if len(t.R16) > 0 {
|
||||
iter[i].next = rune(t.R16[0].Lo)
|
||||
}
|
||||
}
|
||||
|
||||
if r0 := iter.next16(); r0.Stride != 0 {
|
||||
for {
|
||||
r1 := iter.next16()
|
||||
if r1.Stride == 0 {
|
||||
rt.R16 = append(rt.R16, r0)
|
||||
break
|
||||
}
|
||||
stride := r1.Lo - r0.Hi
|
||||
if (r1.Lo == r1.Hi || stride == r1.Stride) && (r0.Lo == r0.Hi || stride == r0.Stride) {
|
||||
// Fully merge the next range into the previous one.
|
||||
r0.Hi, r0.Stride = r1.Hi, stride
|
||||
continue
|
||||
} else if stride == r0.Stride {
|
||||
// Move the first element of r1 to r0. This may eliminate an
|
||||
// entry.
|
||||
r0.Hi = r1.Lo
|
||||
r0.Stride = stride
|
||||
r1.Lo = r1.Lo + r1.Stride
|
||||
if r1.Lo > r1.Hi {
|
||||
continue
|
||||
}
|
||||
}
|
||||
rt.R16 = append(rt.R16, r0)
|
||||
r0 = r1
|
||||
}
|
||||
}
|
||||
|
||||
for i, t := range ranges {
|
||||
iter[i] = tableIndex{t, 0, atEnd}
|
||||
if len(t.R32) > 0 {
|
||||
iter[i].next = rune(t.R32[0].Lo)
|
||||
}
|
||||
}
|
||||
|
||||
if r0 := iter.next32(); r0.Stride != 0 {
|
||||
for {
|
||||
r1 := iter.next32()
|
||||
if r1.Stride == 0 {
|
||||
rt.R32 = append(rt.R32, r0)
|
||||
break
|
||||
}
|
||||
stride := r1.Lo - r0.Hi
|
||||
if (r1.Lo == r1.Hi || stride == r1.Stride) && (r0.Lo == r0.Hi || stride == r0.Stride) {
|
||||
// Fully merge the next range into the previous one.
|
||||
r0.Hi, r0.Stride = r1.Hi, stride
|
||||
continue
|
||||
} else if stride == r0.Stride {
|
||||
// Move the first element of r1 to r0. This may eliminate an
|
||||
// entry.
|
||||
r0.Hi = r1.Lo
|
||||
r1.Lo = r1.Lo + r1.Stride
|
||||
if r1.Lo > r1.Hi {
|
||||
continue
|
||||
}
|
||||
}
|
||||
rt.R32 = append(rt.R32, r0)
|
||||
r0 = r1
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(rt.R16) && rt.R16[i].Hi <= unicode.MaxLatin1; i++ {
|
||||
rt.LatinOffset = i + 1
|
||||
}
|
||||
|
||||
return rt
|
||||
}
|
||||
|
||||
type tableIndex struct {
|
||||
t *unicode.RangeTable
|
||||
p uint32
|
||||
next rune
|
||||
}
|
||||
|
||||
type tablesIter []tableIndex
|
||||
|
||||
// sortIter does an insertion sort using the next field of tableIndex. Insertion
|
||||
// sort is a good sorting algorithm for this case.
|
||||
func sortIter(t []tableIndex) {
|
||||
for i := range t {
|
||||
for j := i; j > 0 && t[j-1].next > t[j].next; j-- {
|
||||
t[j], t[j-1] = t[j-1], t[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// next16 finds the ranged to be added to the table. If ranges overlap between
|
||||
// multiple tables it clips the result to a non-overlapping range if the
|
||||
// elements are not fully subsumed. It returns a zero range if there are no more
|
||||
// ranges.
|
||||
func (ti tablesIter) next16() unicode.Range16 {
|
||||
sortIter(ti)
|
||||
|
||||
t0 := ti[0]
|
||||
if t0.next == atEnd {
|
||||
return unicode.Range16{}
|
||||
}
|
||||
r0 := t0.t.R16[t0.p]
|
||||
r0.Lo = uint16(t0.next)
|
||||
|
||||
// We restrict the Hi of the current range if it overlaps with another range.
|
||||
for i := range ti {
|
||||
tn := ti[i]
|
||||
// Since our tableIndices are sorted by next, we can break if the there
|
||||
// is no overlap. The first value of a next range can always be merged
|
||||
// into the current one, so we can break in case of equality as well.
|
||||
if rune(r0.Hi) <= tn.next {
|
||||
break
|
||||
}
|
||||
rn := tn.t.R16[tn.p]
|
||||
rn.Lo = uint16(tn.next)
|
||||
|
||||
// Limit r0.Hi based on next ranges in list, but allow it to overlap
|
||||
// with ranges as long as it subsumes it.
|
||||
m := (rn.Lo - r0.Lo) % r0.Stride
|
||||
if m == 0 && (rn.Stride == r0.Stride || rn.Lo == rn.Hi) {
|
||||
// Overlap, take the min of the two Hi values: for simplicity's sake
|
||||
// we only process one range at a time.
|
||||
if r0.Hi > rn.Hi {
|
||||
r0.Hi = rn.Hi
|
||||
}
|
||||
} else {
|
||||
// Not a compatible stride. Set to the last possible value before
|
||||
// rn.Lo, but ensure there is at least one value.
|
||||
if x := rn.Lo - m; r0.Lo <= x {
|
||||
r0.Hi = x
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Update the next values for each table.
|
||||
for i := range ti {
|
||||
tn := &ti[i]
|
||||
if rune(r0.Hi) < tn.next {
|
||||
break
|
||||
}
|
||||
rn := tn.t.R16[tn.p]
|
||||
stride := rune(rn.Stride)
|
||||
tn.next += stride * (1 + ((rune(r0.Hi) - tn.next) / stride))
|
||||
if rune(rn.Hi) < tn.next {
|
||||
if tn.p++; int(tn.p) == len(tn.t.R16) {
|
||||
tn.next = atEnd
|
||||
} else {
|
||||
tn.next = rune(tn.t.R16[tn.p].Lo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r0.Lo == r0.Hi {
|
||||
r0.Stride = 1
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// next32 finds the ranged to be added to the table. If ranges overlap between
|
||||
// multiple tables it clips the result to a non-overlapping range if the
|
||||
// elements are not fully subsumed. It returns a zero range if there are no more
|
||||
// ranges.
|
||||
func (ti tablesIter) next32() unicode.Range32 {
|
||||
sortIter(ti)
|
||||
|
||||
t0 := ti[0]
|
||||
if t0.next == atEnd {
|
||||
return unicode.Range32{}
|
||||
}
|
||||
r0 := t0.t.R32[t0.p]
|
||||
r0.Lo = uint32(t0.next)
|
||||
|
||||
// We restrict the Hi of the current range if it overlaps with another range.
|
||||
for i := range ti {
|
||||
tn := ti[i]
|
||||
// Since our tableIndices are sorted by next, we can break if the there
|
||||
// is no overlap. The first value of a next range can always be merged
|
||||
// into the current one, so we can break in case of equality as well.
|
||||
if rune(r0.Hi) <= tn.next {
|
||||
break
|
||||
}
|
||||
rn := tn.t.R32[tn.p]
|
||||
rn.Lo = uint32(tn.next)
|
||||
|
||||
// Limit r0.Hi based on next ranges in list, but allow it to overlap
|
||||
// with ranges as long as it subsumes it.
|
||||
m := (rn.Lo - r0.Lo) % r0.Stride
|
||||
if m == 0 && (rn.Stride == r0.Stride || rn.Lo == rn.Hi) {
|
||||
// Overlap, take the min of the two Hi values: for simplicity's sake
|
||||
// we only process one range at a time.
|
||||
if r0.Hi > rn.Hi {
|
||||
r0.Hi = rn.Hi
|
||||
}
|
||||
} else {
|
||||
// Not a compatible stride. Set to the last possible value before
|
||||
// rn.Lo, but ensure there is at least one value.
|
||||
if x := rn.Lo - m; r0.Lo <= x {
|
||||
r0.Hi = x
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Update the next values for each table.
|
||||
for i := range ti {
|
||||
tn := &ti[i]
|
||||
if rune(r0.Hi) < tn.next {
|
||||
break
|
||||
}
|
||||
rn := tn.t.R32[tn.p]
|
||||
stride := rune(rn.Stride)
|
||||
tn.next += stride * (1 + ((rune(r0.Hi) - tn.next) / stride))
|
||||
if rune(rn.Hi) < tn.next {
|
||||
if tn.p++; int(tn.p) == len(tn.t.R32) {
|
||||
tn.next = atEnd
|
||||
} else {
|
||||
tn.next = rune(tn.t.R32[tn.p].Lo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r0.Lo == r0.Hi {
|
||||
r0.Stride = 1
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
70
vendor/golang.org/x/text/unicode/rangetable/rangetable.go
generated
vendored
Normal file
70
vendor/golang.org/x/text/unicode/rangetable/rangetable.go
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2015 The Go 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 rangetable provides utilities for creating and inspecting
|
||||
// unicode.RangeTables.
|
||||
package rangetable
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// New creates a RangeTable from the given runes, which may contain duplicates.
|
||||
func New(r ...rune) *unicode.RangeTable {
|
||||
if len(r) == 0 {
|
||||
return &unicode.RangeTable{}
|
||||
}
|
||||
|
||||
sort.Sort(byRune(r))
|
||||
|
||||
// Remove duplicates.
|
||||
k := 1
|
||||
for i := 1; i < len(r); i++ {
|
||||
if r[k-1] != r[i] {
|
||||
r[k] = r[i]
|
||||
k++
|
||||
}
|
||||
}
|
||||
|
||||
var rt unicode.RangeTable
|
||||
for _, r := range r[:k] {
|
||||
if r <= 0xFFFF {
|
||||
rt.R16 = append(rt.R16, unicode.Range16{Lo: uint16(r), Hi: uint16(r), Stride: 1})
|
||||
} else {
|
||||
rt.R32 = append(rt.R32, unicode.Range32{Lo: uint32(r), Hi: uint32(r), Stride: 1})
|
||||
}
|
||||
}
|
||||
|
||||
// Optimize RangeTable.
|
||||
return Merge(&rt)
|
||||
}
|
||||
|
||||
type byRune []rune
|
||||
|
||||
func (r byRune) Len() int { return len(r) }
|
||||
func (r byRune) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||
func (r byRune) Less(i, j int) bool { return r[i] < r[j] }
|
||||
|
||||
// Visit visits all runes in the given RangeTable in order, calling fn for each.
|
||||
func Visit(rt *unicode.RangeTable, fn func(rune)) {
|
||||
for _, r16 := range rt.R16 {
|
||||
for r := rune(r16.Lo); r <= rune(r16.Hi); r += rune(r16.Stride) {
|
||||
fn(r)
|
||||
}
|
||||
}
|
||||
for _, r32 := range rt.R32 {
|
||||
for r := rune(r32.Lo); r <= rune(r32.Hi); r += rune(r32.Stride) {
|
||||
fn(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assigned returns a RangeTable with all assigned code points for a given
|
||||
// Unicode version. This includes graphic, format, control, and private-use
|
||||
// characters. It returns nil if the data for the given version is not
|
||||
// available.
|
||||
func Assigned(version string) *unicode.RangeTable {
|
||||
return assigned[version]
|
||||
}
|
6378
vendor/golang.org/x/text/unicode/rangetable/tables10.0.0.go
generated
vendored
Normal file
6378
vendor/golang.org/x/text/unicode/rangetable/tables10.0.0.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5737
vendor/golang.org/x/text/unicode/rangetable/tables9.0.0.go
generated
vendored
Normal file
5737
vendor/golang.org/x/text/unicode/rangetable/tables9.0.0.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
11
vendor/modules.txt
vendored
11
vendor/modules.txt
vendored
@ -147,6 +147,16 @@ github.com/valyala/bytebufferpool
|
||||
github.com/valyala/fasttemplate
|
||||
# github.com/zfjagann/golang-ring v0.0.0-20141111230621-17637388c9f6
|
||||
github.com/zfjagann/golang-ring
|
||||
# gitlab.com/golang-commonmark/html v0.0.0-20180917080848-cfaf75183c4a
|
||||
gitlab.com/golang-commonmark/html
|
||||
# gitlab.com/golang-commonmark/linkify v0.0.0-20180917065525-c22b7bdb1179
|
||||
gitlab.com/golang-commonmark/linkify
|
||||
# gitlab.com/golang-commonmark/markdown v0.0.0-20181102083822-772775880e1f
|
||||
gitlab.com/golang-commonmark/markdown
|
||||
# gitlab.com/golang-commonmark/mdurl v0.0.0-20180912090424-e5bce34c34f2
|
||||
gitlab.com/golang-commonmark/mdurl
|
||||
# gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe
|
||||
gitlab.com/golang-commonmark/puny
|
||||
# go.uber.org/atomic v1.3.2
|
||||
go.uber.org/atomic
|
||||
# go.uber.org/multierr v1.1.0
|
||||
@ -184,6 +194,7 @@ golang.org/x/text/encoding/simplifiedchinese
|
||||
golang.org/x/text/encoding/traditionalchinese
|
||||
golang.org/x/text/transform
|
||||
golang.org/x/text/unicode/norm
|
||||
golang.org/x/text/unicode/rangetable
|
||||
golang.org/x/text/encoding/internal/identifier
|
||||
golang.org/x/text/encoding/internal
|
||||
# gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
|
Loading…
Reference in New Issue
Block a user