mirror of
https://github.com/octoleo/restic.git
synced 2024-11-26 06:46:34 +00:00
Vendor dependencies for manpage generation
This commit is contained in:
parent
a3ab17b470
commit
57d198f99a
28
Gopkg.lock
generated
28
Gopkg.lock
generated
@ -7,6 +7,12 @@
|
|||||||
packages = [".","fs","fuseutil"]
|
packages = [".","fs","fuseutil"]
|
||||||
revision = "371fbbdaa8987b715bdd21d6adc4c9b20155f748"
|
revision = "371fbbdaa8987b715bdd21d6adc4c9b20155f748"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/cpuguy83/go-md2man"
|
||||||
|
packages = ["md2man"]
|
||||||
|
revision = "a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa"
|
||||||
|
version = "v1.0.6"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/elithrar/simple-scrypt"
|
name = "github.com/elithrar/simple-scrypt"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
@ -85,10 +91,22 @@
|
|||||||
revision = "bb2ecf9a98e35a0b336ffc23fc515fb6e7961577"
|
revision = "bb2ecf9a98e35a0b336ffc23fc515fb6e7961577"
|
||||||
version = "v0.1.0"
|
version = "v0.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/russross/blackfriday"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "0b647d0506a698cca42caca173e55559b12a69f2"
|
||||||
|
version = "v1.4"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/shurcooL/sanitized_anchor_name"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "541ff5ee47f1dddf6a5281af78307d921524bcb5"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/spf13/cobra"
|
name = "github.com/spf13/cobra"
|
||||||
packages = ["."]
|
packages = [".","doc"]
|
||||||
revision = "f20b4e9c32bb3e9d44773ca208db814f24dcd21b"
|
revision = "f20b4e9c32bb3e9d44773ca208db814f24dcd21b"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
@ -115,9 +133,15 @@
|
|||||||
packages = ["unix"]
|
packages = ["unix"]
|
||||||
revision = "c4489faa6e5ab84c0ef40d6ee878f7a030281f0f"
|
revision = "c4489faa6e5ab84c0ef40d6ee878f7a030281f0f"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "v2"
|
||||||
|
name = "gopkg.in/yaml.v2"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "25c4ec802a7d637f88d584ab26798e94ad14c13b"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "b4de858790fd06b6d1df19baa8a3246f23b2fded9ab6eb85325ddb3ee91003b8"
|
inputs-digest = "10287830033309dd91c5e7e381e1a56cd3bf135fd4e776954232c404c39be210"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
1
vendor/github.com/cpuguy83/go-md2man/.gitignore
generated
vendored
Normal file
1
vendor/github.com/cpuguy83/go-md2man/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
go-md2man
|
21
vendor/github.com/cpuguy83/go-md2man/LICENSE.md
generated
vendored
Normal file
21
vendor/github.com/cpuguy83/go-md2man/LICENSE.md
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014 Brian Goff
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
18
vendor/github.com/cpuguy83/go-md2man/README.md
generated
vendored
Normal file
18
vendor/github.com/cpuguy83/go-md2man/README.md
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
go-md2man
|
||||||
|
=========
|
||||||
|
|
||||||
|
** Work in Progress **
|
||||||
|
This still needs a lot of help to be complete, or even usable!
|
||||||
|
|
||||||
|
Uses blackfriday to process markdown into man pages.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
./md2man -in /path/to/markdownfile.md -out /manfile/output/path
|
||||||
|
|
||||||
|
### How to contribute
|
||||||
|
|
||||||
|
We use [govend](https://github.com/govend/govend) for vendoring Go packages.
|
||||||
|
|
||||||
|
How to update dependencies: `govend -v -u --prune`
|
||||||
|
|
23
vendor/github.com/cpuguy83/go-md2man/go-md2man.1.md
generated
vendored
Normal file
23
vendor/github.com/cpuguy83/go-md2man/go-md2man.1.md
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
go-md2man 1 "January 2015" go-md2man "User Manual"
|
||||||
|
==================================================
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
go-md2man - Convert mardown files into manpages
|
||||||
|
|
||||||
|
# SYNOPSIS
|
||||||
|
go-md2man -in=[/path/to/md/file] -out=[/path/to/output]
|
||||||
|
|
||||||
|
# Description
|
||||||
|
go-md2man converts standard markdown formatted documents into manpages. It is
|
||||||
|
written purely in Go so as to reduce dependencies on 3rd party libs.
|
||||||
|
|
||||||
|
By default, the input is stdin and the output is stdout.
|
||||||
|
|
||||||
|
# Example
|
||||||
|
Convert the markdown file "go-md2man.1.md" into a manpage.
|
||||||
|
|
||||||
|
go-md2man -in=README.md -out=go-md2man.1.out
|
||||||
|
|
||||||
|
# HISTORY
|
||||||
|
January 2015, Originally compiled by Brian Goff( cpuguy83@gmail.com )
|
||||||
|
|
51
vendor/github.com/cpuguy83/go-md2man/md2man.go
generated
vendored
Normal file
51
vendor/github.com/cpuguy83/go-md2man/md2man.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/cpuguy83/go-md2man/md2man"
|
||||||
|
)
|
||||||
|
|
||||||
|
var inFilePath = flag.String("in", "", "Path to file to be processed (default: stdin)")
|
||||||
|
var outFilePath = flag.String("out", "", "Path to output processed file (default: stdout)")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
inFile := os.Stdin
|
||||||
|
if *inFilePath != "" {
|
||||||
|
inFile, err = os.Open(*inFilePath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer inFile.Close()
|
||||||
|
|
||||||
|
doc, err := ioutil.ReadAll(inFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
out := md2man.Render(doc)
|
||||||
|
|
||||||
|
outFile := os.Stdout
|
||||||
|
if *outFilePath != "" {
|
||||||
|
outFile, err = os.Create(*outFilePath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer outFile.Close()
|
||||||
|
}
|
||||||
|
_, err = outFile.Write(out)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
19
vendor/github.com/cpuguy83/go-md2man/md2man/md2man.go
generated
vendored
Normal file
19
vendor/github.com/cpuguy83/go-md2man/md2man/md2man.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package md2man
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/russross/blackfriday"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Render(doc []byte) []byte {
|
||||||
|
renderer := RoffRenderer(0)
|
||||||
|
extensions := 0
|
||||||
|
extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
|
||||||
|
extensions |= blackfriday.EXTENSION_TABLES
|
||||||
|
extensions |= blackfriday.EXTENSION_FENCED_CODE
|
||||||
|
extensions |= blackfriday.EXTENSION_AUTOLINK
|
||||||
|
extensions |= blackfriday.EXTENSION_SPACE_HEADERS
|
||||||
|
extensions |= blackfriday.EXTENSION_FOOTNOTES
|
||||||
|
extensions |= blackfriday.EXTENSION_TITLEBLOCK
|
||||||
|
|
||||||
|
return blackfriday.Markdown(doc, renderer, extensions)
|
||||||
|
}
|
282
vendor/github.com/cpuguy83/go-md2man/md2man/roff.go
generated
vendored
Normal file
282
vendor/github.com/cpuguy83/go-md2man/md2man/roff.go
generated
vendored
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
package md2man
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"html"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/russross/blackfriday"
|
||||||
|
)
|
||||||
|
|
||||||
|
type roffRenderer struct{}
|
||||||
|
|
||||||
|
var listCounter int
|
||||||
|
|
||||||
|
func RoffRenderer(flags int) blackfriday.Renderer {
|
||||||
|
return &roffRenderer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) GetFlags() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) TitleBlock(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString(".TH ")
|
||||||
|
|
||||||
|
splitText := bytes.Split(text, []byte("\n"))
|
||||||
|
for i, line := range splitText {
|
||||||
|
line = bytes.TrimPrefix(line, []byte("% "))
|
||||||
|
if i == 0 {
|
||||||
|
line = bytes.Replace(line, []byte("("), []byte("\" \""), 1)
|
||||||
|
line = bytes.Replace(line, []byte(")"), []byte("\" \""), 1)
|
||||||
|
}
|
||||||
|
line = append([]byte("\""), line...)
|
||||||
|
line = append(line, []byte("\" ")...)
|
||||||
|
out.Write(line)
|
||||||
|
}
|
||||||
|
out.WriteString("\n")
|
||||||
|
|
||||||
|
// disable hyphenation
|
||||||
|
out.WriteString(".nh\n")
|
||||||
|
// disable justification (adjust text to left margin only)
|
||||||
|
out.WriteString(".ad l\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string) {
|
||||||
|
out.WriteString("\n.PP\n.RS\n\n.nf\n")
|
||||||
|
escapeSpecialChars(out, text)
|
||||||
|
out.WriteString("\n.fi\n.RE\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) BlockQuote(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("\n.PP\n.RS\n")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("\n.RE\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) BlockHtml(out *bytes.Buffer, text []byte) {
|
||||||
|
out.Write(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) Header(out *bytes.Buffer, text func() bool, level int, id string) {
|
||||||
|
marker := out.Len()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case marker == 0:
|
||||||
|
// This is the doc header
|
||||||
|
out.WriteString(".TH ")
|
||||||
|
case level == 1:
|
||||||
|
out.WriteString("\n\n.SH ")
|
||||||
|
case level == 2:
|
||||||
|
out.WriteString("\n.SH ")
|
||||||
|
default:
|
||||||
|
out.WriteString("\n.SS ")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !text() {
|
||||||
|
out.Truncate(marker)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) HRule(out *bytes.Buffer) {
|
||||||
|
out.WriteString("\n.ti 0\n\\l'\\n(.lu'\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) List(out *bytes.Buffer, text func() bool, flags int) {
|
||||||
|
marker := out.Len()
|
||||||
|
if flags&blackfriday.LIST_TYPE_ORDERED != 0 {
|
||||||
|
listCounter = 1
|
||||||
|
}
|
||||||
|
if !text() {
|
||||||
|
out.Truncate(marker)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) ListItem(out *bytes.Buffer, text []byte, flags int) {
|
||||||
|
if flags&blackfriday.LIST_TYPE_ORDERED != 0 {
|
||||||
|
out.WriteString(fmt.Sprintf(".IP \"%3d.\" 5\n", listCounter))
|
||||||
|
listCounter += 1
|
||||||
|
} else {
|
||||||
|
out.WriteString(".IP \\(bu 2\n")
|
||||||
|
}
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) Paragraph(out *bytes.Buffer, text func() bool) {
|
||||||
|
marker := out.Len()
|
||||||
|
out.WriteString("\n.PP\n")
|
||||||
|
if !text() {
|
||||||
|
out.Truncate(marker)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if marker != 0 {
|
||||||
|
out.WriteString("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This might now work
|
||||||
|
func (r *roffRenderer) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
|
||||||
|
out.WriteString(".TS\nallbox;\n")
|
||||||
|
|
||||||
|
out.Write(header)
|
||||||
|
out.Write(body)
|
||||||
|
out.WriteString("\n.TE\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) TableRow(out *bytes.Buffer, text []byte) {
|
||||||
|
if out.Len() > 0 {
|
||||||
|
out.WriteString("\n")
|
||||||
|
}
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
|
||||||
|
if out.Len() > 0 {
|
||||||
|
out.WriteString(" ")
|
||||||
|
}
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This is probably broken
|
||||||
|
func (r *roffRenderer) TableCell(out *bytes.Buffer, text []byte, align int) {
|
||||||
|
if out.Len() > 0 {
|
||||||
|
out.WriteString("\t")
|
||||||
|
}
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("\t")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) Footnotes(out *bytes.Buffer, text func() bool) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) AutoLink(out *bytes.Buffer, link []byte, kind int) {
|
||||||
|
out.WriteString("\n\\[la]")
|
||||||
|
out.Write(link)
|
||||||
|
out.WriteString("\\[ra]")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) CodeSpan(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("\\fB\\fC")
|
||||||
|
escapeSpecialChars(out, text)
|
||||||
|
out.WriteString("\\fR")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) DoubleEmphasis(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("\\fB")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("\\fP")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) Emphasis(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("\\fI")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("\\fP")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) LineBreak(out *bytes.Buffer) {
|
||||||
|
out.WriteString("\n.br\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
|
||||||
|
out.Write(content)
|
||||||
|
r.AutoLink(out, link, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) RawHtmlTag(out *bytes.Buffer, tag []byte) {
|
||||||
|
out.Write(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) TripleEmphasis(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("\\s+2")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("\\s-2")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) StrikeThrough(out *bytes.Buffer, text []byte) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) Entity(out *bytes.Buffer, entity []byte) {
|
||||||
|
out.WriteString(html.UnescapeString(string(entity)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func processFooterText(text []byte) []byte {
|
||||||
|
text = bytes.TrimPrefix(text, []byte("% "))
|
||||||
|
newText := []byte{}
|
||||||
|
textArr := strings.Split(string(text), ") ")
|
||||||
|
|
||||||
|
for i, w := range textArr {
|
||||||
|
if i == 0 {
|
||||||
|
w = strings.Replace(w, "(", "\" \"", 1)
|
||||||
|
w = fmt.Sprintf("\"%s\"", w)
|
||||||
|
} else {
|
||||||
|
w = fmt.Sprintf(" \"%s\"", w)
|
||||||
|
}
|
||||||
|
newText = append(newText, []byte(w)...)
|
||||||
|
}
|
||||||
|
newText = append(newText, []byte(" \"\"")...)
|
||||||
|
|
||||||
|
return newText
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) NormalText(out *bytes.Buffer, text []byte) {
|
||||||
|
escapeSpecialChars(out, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) DocumentHeader(out *bytes.Buffer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *roffRenderer) DocumentFooter(out *bytes.Buffer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func needsBackslash(c byte) bool {
|
||||||
|
for _, r := range []byte("-_&\\~") {
|
||||||
|
if c == r {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func escapeSpecialChars(out *bytes.Buffer, text []byte) {
|
||||||
|
for i := 0; i < len(text); i++ {
|
||||||
|
// escape initial apostrophe or period
|
||||||
|
if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') {
|
||||||
|
out.WriteString("\\&")
|
||||||
|
}
|
||||||
|
|
||||||
|
// directly copy normal characters
|
||||||
|
org := i
|
||||||
|
|
||||||
|
for i < len(text) && !needsBackslash(text[i]) {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i > org {
|
||||||
|
out.Write(text[org:i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// escape a character
|
||||||
|
if i >= len(text) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
out.WriteByte('\\')
|
||||||
|
out.WriteByte(text[i])
|
||||||
|
}
|
||||||
|
}
|
5
vendor/github.com/cpuguy83/go-md2man/vendor.yml
generated
vendored
Normal file
5
vendor/github.com/cpuguy83/go-md2man/vendor.yml
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
vendors:
|
||||||
|
- path: github.com/russross/blackfriday
|
||||||
|
rev: 93622da34e54fb6529bfb7c57e710f37a8d9cbd8
|
||||||
|
- path: github.com/shurcooL/sanitized_anchor_name
|
||||||
|
rev: 10ef21a441db47d8b13ebcc5fd2310f636973c77
|
8
vendor/github.com/russross/blackfriday/.gitignore
generated
vendored
Normal file
8
vendor/github.com/russross/blackfriday/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
*.out
|
||||||
|
*.swp
|
||||||
|
*.8
|
||||||
|
*.6
|
||||||
|
_obj
|
||||||
|
_test*
|
||||||
|
markdown
|
||||||
|
tags
|
18
vendor/github.com/russross/blackfriday/.travis.yml
generated
vendored
Normal file
18
vendor/github.com/russross/blackfriday/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Travis CI (http://travis-ci.org/) is a continuous integration service for
|
||||||
|
# open source projects. This file configures it to run unit tests for
|
||||||
|
# blackfriday.
|
||||||
|
|
||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.2
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- 1.5
|
||||||
|
|
||||||
|
install:
|
||||||
|
- go get -d -t -v ./...
|
||||||
|
- go build -v ./...
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test -v ./...
|
29
vendor/github.com/russross/blackfriday/LICENSE.txt
generated
vendored
Normal file
29
vendor/github.com/russross/blackfriday/LICENSE.txt
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
Blackfriday is distributed under the Simplified BSD License:
|
||||||
|
|
||||||
|
> Copyright © 2011 Russ Ross
|
||||||
|
> 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.
|
265
vendor/github.com/russross/blackfriday/README.md
generated
vendored
Normal file
265
vendor/github.com/russross/blackfriday/README.md
generated
vendored
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
Blackfriday [![Build Status](https://travis-ci.org/russross/blackfriday.svg?branch=master)](https://travis-ci.org/russross/blackfriday)
|
||||||
|
===========
|
||||||
|
|
||||||
|
Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It
|
||||||
|
is paranoid about its input (so you can safely feed it user-supplied
|
||||||
|
data), it is fast, it supports common extensions (tables, smart
|
||||||
|
punctuation substitutions, etc.), and it is safe for all utf-8
|
||||||
|
(unicode) input.
|
||||||
|
|
||||||
|
HTML output is currently supported, along with Smartypants
|
||||||
|
extensions. An experimental LaTeX output engine is also included.
|
||||||
|
|
||||||
|
It started as a translation from C of [Sundown][3].
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
Blackfriday is compatible with Go 1. If you are using an older
|
||||||
|
release of Go, consider using v1.1 of blackfriday, which was based
|
||||||
|
on the last stable release of Go prior to Go 1. You can find it as a
|
||||||
|
tagged commit on github.
|
||||||
|
|
||||||
|
With Go 1 and git installed:
|
||||||
|
|
||||||
|
go get github.com/russross/blackfriday
|
||||||
|
|
||||||
|
will download, compile, and install the package into your `$GOPATH`
|
||||||
|
directory hierarchy. Alternatively, you can achieve the same if you
|
||||||
|
import it into a project:
|
||||||
|
|
||||||
|
import "github.com/russross/blackfriday"
|
||||||
|
|
||||||
|
and `go get` without parameters.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
For basic usage, it is as simple as getting your input into a byte
|
||||||
|
slice and calling:
|
||||||
|
|
||||||
|
output := blackfriday.MarkdownBasic(input)
|
||||||
|
|
||||||
|
This renders it with no extensions enabled. To get a more useful
|
||||||
|
feature set, use this instead:
|
||||||
|
|
||||||
|
output := blackfriday.MarkdownCommon(input)
|
||||||
|
|
||||||
|
### Sanitize untrusted content
|
||||||
|
|
||||||
|
Blackfriday itself does nothing to protect against malicious content. If you are
|
||||||
|
dealing with user-supplied markdown, we recommend running blackfriday's output
|
||||||
|
through HTML sanitizer such as
|
||||||
|
[Bluemonday](https://github.com/microcosm-cc/bluemonday).
|
||||||
|
|
||||||
|
Here's an example of simple usage of blackfriday together with bluemonday:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
import (
|
||||||
|
"github.com/microcosm-cc/bluemonday"
|
||||||
|
"github.com/russross/blackfriday"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ...
|
||||||
|
unsafe := blackfriday.MarkdownCommon(input)
|
||||||
|
html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom options
|
||||||
|
|
||||||
|
If you want to customize the set of options, first get a renderer
|
||||||
|
(currently either the HTML or LaTeX output engines), then use it to
|
||||||
|
call the more general `Markdown` function. For examples, see the
|
||||||
|
implementations of `MarkdownBasic` and `MarkdownCommon` in
|
||||||
|
`markdown.go`.
|
||||||
|
|
||||||
|
You can also check out `blackfriday-tool` for a more complete example
|
||||||
|
of how to use it. Download and install it using:
|
||||||
|
|
||||||
|
go get github.com/russross/blackfriday-tool
|
||||||
|
|
||||||
|
This is a simple command-line tool that allows you to process a
|
||||||
|
markdown file using a standalone program. You can also browse the
|
||||||
|
source directly on github if you are just looking for some example
|
||||||
|
code:
|
||||||
|
|
||||||
|
* <http://github.com/russross/blackfriday-tool>
|
||||||
|
|
||||||
|
Note that if you have not already done so, installing
|
||||||
|
`blackfriday-tool` will be sufficient to download and install
|
||||||
|
blackfriday in addition to the tool itself. The tool binary will be
|
||||||
|
installed in `$GOPATH/bin`. This is a statically-linked binary that
|
||||||
|
can be copied to wherever you need it without worrying about
|
||||||
|
dependencies and library versions.
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
All features of Sundown are supported, including:
|
||||||
|
|
||||||
|
* **Compatibility**. The Markdown v1.0.3 test suite passes with
|
||||||
|
the `--tidy` option. Without `--tidy`, the differences are
|
||||||
|
mostly in whitespace and entity escaping, where blackfriday is
|
||||||
|
more consistent and cleaner.
|
||||||
|
|
||||||
|
* **Common extensions**, including table support, fenced code
|
||||||
|
blocks, autolinks, strikethroughs, non-strict emphasis, etc.
|
||||||
|
|
||||||
|
* **Safety**. Blackfriday is paranoid when parsing, making it safe
|
||||||
|
to feed untrusted user input without fear of bad things
|
||||||
|
happening. The test suite stress tests this and there are no
|
||||||
|
known inputs that make it crash. If you find one, please let me
|
||||||
|
know and send me the input that does it.
|
||||||
|
|
||||||
|
NOTE: "safety" in this context means *runtime safety only*. In order to
|
||||||
|
protect yourself agains JavaScript injection in untrusted content, see
|
||||||
|
[this example](https://github.com/russross/blackfriday#sanitize-untrusted-content).
|
||||||
|
|
||||||
|
* **Fast processing**. It is fast enough to render on-demand in
|
||||||
|
most web applications without having to cache the output.
|
||||||
|
|
||||||
|
* **Thread safety**. You can run multiple parsers in different
|
||||||
|
goroutines without ill effect. There is no dependence on global
|
||||||
|
shared state.
|
||||||
|
|
||||||
|
* **Minimal dependencies**. Blackfriday only depends on standard
|
||||||
|
library packages in Go. The source code is pretty
|
||||||
|
self-contained, so it is easy to add to any project, including
|
||||||
|
Google App Engine projects.
|
||||||
|
|
||||||
|
* **Standards compliant**. Output successfully validates using the
|
||||||
|
W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.
|
||||||
|
|
||||||
|
|
||||||
|
Extensions
|
||||||
|
----------
|
||||||
|
|
||||||
|
In addition to the standard markdown syntax, this package
|
||||||
|
implements the following extensions:
|
||||||
|
|
||||||
|
* **Intra-word emphasis supression**. The `_` character is
|
||||||
|
commonly used inside words when discussing code, so having
|
||||||
|
markdown interpret it as an emphasis command is usually the
|
||||||
|
wrong thing. Blackfriday lets you treat all emphasis markers as
|
||||||
|
normal characters when they occur inside a word.
|
||||||
|
|
||||||
|
* **Tables**. Tables can be created by drawing them in the input
|
||||||
|
using a simple syntax:
|
||||||
|
|
||||||
|
```
|
||||||
|
Name | Age
|
||||||
|
--------|------
|
||||||
|
Bob | 27
|
||||||
|
Alice | 23
|
||||||
|
```
|
||||||
|
|
||||||
|
* **Fenced code blocks**. In addition to the normal 4-space
|
||||||
|
indentation to mark code blocks, you can explicitly mark them
|
||||||
|
and supply a language (to make syntax highlighting simple). Just
|
||||||
|
mark it like this:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
func getTrue() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use 3 or more backticks to mark the beginning of the
|
||||||
|
block, and the same number to mark the end of the block.
|
||||||
|
|
||||||
|
* **Definition lists**. A simple definition list is made of a single-line
|
||||||
|
term followed by a colon and the definition for that term.
|
||||||
|
|
||||||
|
Cat
|
||||||
|
: Fluffy animal everyone likes
|
||||||
|
|
||||||
|
Internet
|
||||||
|
: Vector of transmission for pictures of cats
|
||||||
|
|
||||||
|
Terms must be separated from the previous definition by a blank line.
|
||||||
|
|
||||||
|
* **Footnotes**. A marker in the text that will become a superscript number;
|
||||||
|
a footnote definition that will be placed in a list of footnotes at the
|
||||||
|
end of the document. A footnote looks like this:
|
||||||
|
|
||||||
|
This is a footnote.[^1]
|
||||||
|
|
||||||
|
[^1]: the footnote text.
|
||||||
|
|
||||||
|
* **Autolinking**. Blackfriday can find URLs that have not been
|
||||||
|
explicitly marked as links and turn them into links.
|
||||||
|
|
||||||
|
* **Strikethrough**. Use two tildes (`~~`) to mark text that
|
||||||
|
should be crossed out.
|
||||||
|
|
||||||
|
* **Hard line breaks**. With this extension enabled (it is off by
|
||||||
|
default in the `MarkdownBasic` and `MarkdownCommon` convenience
|
||||||
|
functions), newlines in the input translate into line breaks in
|
||||||
|
the output.
|
||||||
|
|
||||||
|
* **Smart quotes**. Smartypants-style punctuation substitution is
|
||||||
|
supported, turning normal double- and single-quote marks into
|
||||||
|
curly quotes, etc.
|
||||||
|
|
||||||
|
* **LaTeX-style dash parsing** is an additional option, where `--`
|
||||||
|
is translated into `–`, and `---` is translated into
|
||||||
|
`—`. This differs from most smartypants processors, which
|
||||||
|
turn a single hyphen into an ndash and a double hyphen into an
|
||||||
|
mdash.
|
||||||
|
|
||||||
|
* **Smart fractions**, where anything that looks like a fraction
|
||||||
|
is translated into suitable HTML (instead of just a few special
|
||||||
|
cases like most smartypant processors). For example, `4/5`
|
||||||
|
becomes `<sup>4</sup>⁄<sub>5</sub>`, which renders as
|
||||||
|
<sup>4</sup>⁄<sub>5</sub>.
|
||||||
|
|
||||||
|
|
||||||
|
Other renderers
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Blackfriday is structured to allow alternative rendering engines. Here
|
||||||
|
are a few of note:
|
||||||
|
|
||||||
|
* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/github_flavored_markdown):
|
||||||
|
provides a GitHub Flavored Markdown renderer with fenced code block
|
||||||
|
highlighting, clickable header anchor links.
|
||||||
|
|
||||||
|
It's not customizable, and its goal is to produce HTML output
|
||||||
|
equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode),
|
||||||
|
except the rendering is performed locally.
|
||||||
|
|
||||||
|
* [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt,
|
||||||
|
but for markdown.
|
||||||
|
|
||||||
|
* LaTeX output: renders output as LaTeX. This is currently part of the
|
||||||
|
main Blackfriday repository, but may be split into its own project
|
||||||
|
in the future. If you are interested in owning and maintaining the
|
||||||
|
LaTeX output component, please be in touch.
|
||||||
|
|
||||||
|
It renders some basic documents, but is only experimental at this
|
||||||
|
point. In particular, it does not do any inline escaping, so input
|
||||||
|
that happens to look like LaTeX code will be passed through without
|
||||||
|
modification.
|
||||||
|
|
||||||
|
|
||||||
|
Todo
|
||||||
|
----
|
||||||
|
|
||||||
|
* More unit testing
|
||||||
|
* Improve unicode support. It does not understand all unicode
|
||||||
|
rules (about what constitutes a letter, a punctuation symbol,
|
||||||
|
etc.), so it may fail to detect word boundaries correctly in
|
||||||
|
some instances. It is safe on all utf-8 input.
|
||||||
|
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
[Blackfriday is distributed under the Simplified BSD License](LICENSE.txt)
|
||||||
|
|
||||||
|
|
||||||
|
[1]: http://daringfireball.net/projects/markdown/ "Markdown"
|
||||||
|
[2]: http://golang.org/ "Go Language"
|
||||||
|
[3]: https://github.com/vmg/sundown "Sundown"
|
1398
vendor/github.com/russross/blackfriday/block.go
generated
vendored
Normal file
1398
vendor/github.com/russross/blackfriday/block.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1532
vendor/github.com/russross/blackfriday/block_test.go
generated
vendored
Normal file
1532
vendor/github.com/russross/blackfriday/block_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
949
vendor/github.com/russross/blackfriday/html.go
generated
vendored
Normal file
949
vendor/github.com/russross/blackfriday/html.go
generated
vendored
Normal file
@ -0,0 +1,949 @@
|
|||||||
|
//
|
||||||
|
// Blackfriday Markdown Processor
|
||||||
|
// Available at http://github.com/russross/blackfriday
|
||||||
|
//
|
||||||
|
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
||||||
|
// Distributed under the Simplified BSD License.
|
||||||
|
// See README.md for details.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// HTML rendering backend
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
package blackfriday
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Html renderer configuration options.
|
||||||
|
const (
|
||||||
|
HTML_SKIP_HTML = 1 << iota // skip preformatted HTML blocks
|
||||||
|
HTML_SKIP_STYLE // skip embedded <style> elements
|
||||||
|
HTML_SKIP_IMAGES // skip embedded images
|
||||||
|
HTML_SKIP_LINKS // skip all links
|
||||||
|
HTML_SAFELINK // only link to trusted protocols
|
||||||
|
HTML_NOFOLLOW_LINKS // only link with rel="nofollow"
|
||||||
|
HTML_NOREFERRER_LINKS // only link with rel="noreferrer"
|
||||||
|
HTML_HREF_TARGET_BLANK // add a blank target
|
||||||
|
HTML_TOC // generate a table of contents
|
||||||
|
HTML_OMIT_CONTENTS // skip the main contents (for a standalone table of contents)
|
||||||
|
HTML_COMPLETE_PAGE // generate a complete HTML page
|
||||||
|
HTML_USE_XHTML // generate XHTML output instead of HTML
|
||||||
|
HTML_USE_SMARTYPANTS // enable smart punctuation substitutions
|
||||||
|
HTML_SMARTYPANTS_FRACTIONS // enable smart fractions (with HTML_USE_SMARTYPANTS)
|
||||||
|
HTML_SMARTYPANTS_DASHES // enable smart dashes (with HTML_USE_SMARTYPANTS)
|
||||||
|
HTML_SMARTYPANTS_LATEX_DASHES // enable LaTeX-style dashes (with HTML_USE_SMARTYPANTS and HTML_SMARTYPANTS_DASHES)
|
||||||
|
HTML_SMARTYPANTS_ANGLED_QUOTES // enable angled double quotes (with HTML_USE_SMARTYPANTS) for double quotes rendering
|
||||||
|
HTML_FOOTNOTE_RETURN_LINKS // generate a link at the end of a footnote to return to the source
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
alignments = []string{
|
||||||
|
"left",
|
||||||
|
"right",
|
||||||
|
"center",
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: improve this regexp to catch all possible entities:
|
||||||
|
htmlEntity = regexp.MustCompile(`&[a-z]{2,5};`)
|
||||||
|
)
|
||||||
|
|
||||||
|
type HtmlRendererParameters struct {
|
||||||
|
// Prepend this text to each relative URL.
|
||||||
|
AbsolutePrefix string
|
||||||
|
// Add this text to each footnote anchor, to ensure uniqueness.
|
||||||
|
FootnoteAnchorPrefix string
|
||||||
|
// Show this text inside the <a> tag for a footnote return link, if the
|
||||||
|
// HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string
|
||||||
|
// <sup>[return]</sup> is used.
|
||||||
|
FootnoteReturnLinkContents string
|
||||||
|
// If set, add this text to the front of each Header ID, to ensure
|
||||||
|
// uniqueness.
|
||||||
|
HeaderIDPrefix string
|
||||||
|
// If set, add this text to the back of each Header ID, to ensure uniqueness.
|
||||||
|
HeaderIDSuffix string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Html is a type that implements the Renderer interface for HTML output.
|
||||||
|
//
|
||||||
|
// Do not create this directly, instead use the HtmlRenderer function.
|
||||||
|
type Html struct {
|
||||||
|
flags int // HTML_* options
|
||||||
|
closeTag string // how to end singleton tags: either " />" or ">"
|
||||||
|
title string // document title
|
||||||
|
css string // optional css file url (used with HTML_COMPLETE_PAGE)
|
||||||
|
|
||||||
|
parameters HtmlRendererParameters
|
||||||
|
|
||||||
|
// table of contents data
|
||||||
|
tocMarker int
|
||||||
|
headerCount int
|
||||||
|
currentLevel int
|
||||||
|
toc *bytes.Buffer
|
||||||
|
|
||||||
|
// Track header IDs to prevent ID collision in a single generation.
|
||||||
|
headerIDs map[string]int
|
||||||
|
|
||||||
|
smartypants *smartypantsRenderer
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
xhtmlClose = " />"
|
||||||
|
htmlClose = ">"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HtmlRenderer creates and configures an Html object, which
|
||||||
|
// satisfies the Renderer interface.
|
||||||
|
//
|
||||||
|
// flags is a set of HTML_* options ORed together.
|
||||||
|
// title is the title of the document, and css is a URL for the document's
|
||||||
|
// stylesheet.
|
||||||
|
// title and css are only used when HTML_COMPLETE_PAGE is selected.
|
||||||
|
func HtmlRenderer(flags int, title string, css string) Renderer {
|
||||||
|
return HtmlRendererWithParameters(flags, title, css, HtmlRendererParameters{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HtmlRendererWithParameters(flags int, title string,
|
||||||
|
css string, renderParameters HtmlRendererParameters) Renderer {
|
||||||
|
// configure the rendering engine
|
||||||
|
closeTag := htmlClose
|
||||||
|
if flags&HTML_USE_XHTML != 0 {
|
||||||
|
closeTag = xhtmlClose
|
||||||
|
}
|
||||||
|
|
||||||
|
if renderParameters.FootnoteReturnLinkContents == "" {
|
||||||
|
renderParameters.FootnoteReturnLinkContents = `<sup>[return]</sup>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Html{
|
||||||
|
flags: flags,
|
||||||
|
closeTag: closeTag,
|
||||||
|
title: title,
|
||||||
|
css: css,
|
||||||
|
parameters: renderParameters,
|
||||||
|
|
||||||
|
headerCount: 0,
|
||||||
|
currentLevel: 0,
|
||||||
|
toc: new(bytes.Buffer),
|
||||||
|
|
||||||
|
headerIDs: make(map[string]int),
|
||||||
|
|
||||||
|
smartypants: smartypants(flags),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using if statements is a bit faster than a switch statement. As the compiler
|
||||||
|
// improves, this should be unnecessary this is only worthwhile because
|
||||||
|
// attrEscape is the single largest CPU user in normal use.
|
||||||
|
// Also tried using map, but that gave a ~3x slowdown.
|
||||||
|
func escapeSingleChar(char byte) (string, bool) {
|
||||||
|
if char == '"' {
|
||||||
|
return """, true
|
||||||
|
}
|
||||||
|
if char == '&' {
|
||||||
|
return "&", true
|
||||||
|
}
|
||||||
|
if char == '<' {
|
||||||
|
return "<", true
|
||||||
|
}
|
||||||
|
if char == '>' {
|
||||||
|
return ">", true
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func attrEscape(out *bytes.Buffer, src []byte) {
|
||||||
|
org := 0
|
||||||
|
for i, ch := range src {
|
||||||
|
if entity, ok := escapeSingleChar(ch); ok {
|
||||||
|
if i > org {
|
||||||
|
// copy all the normal characters since the last escape
|
||||||
|
out.Write(src[org:i])
|
||||||
|
}
|
||||||
|
org = i + 1
|
||||||
|
out.WriteString(entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if org < len(src) {
|
||||||
|
out.Write(src[org:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func entityEscapeWithSkip(out *bytes.Buffer, src []byte, skipRanges [][]int) {
|
||||||
|
end := 0
|
||||||
|
for _, rang := range skipRanges {
|
||||||
|
attrEscape(out, src[end:rang[0]])
|
||||||
|
out.Write(src[rang[0]:rang[1]])
|
||||||
|
end = rang[1]
|
||||||
|
}
|
||||||
|
attrEscape(out, src[end:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) GetFlags() int {
|
||||||
|
return options.flags
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) TitleBlock(out *bytes.Buffer, text []byte) {
|
||||||
|
text = bytes.TrimPrefix(text, []byte("% "))
|
||||||
|
text = bytes.Replace(text, []byte("\n% "), []byte("\n"), -1)
|
||||||
|
out.WriteString("<h1 class=\"title\">")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("\n</h1>")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) Header(out *bytes.Buffer, text func() bool, level int, id string) {
|
||||||
|
marker := out.Len()
|
||||||
|
doubleSpace(out)
|
||||||
|
|
||||||
|
if id == "" && options.flags&HTML_TOC != 0 {
|
||||||
|
id = fmt.Sprintf("toc_%d", options.headerCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
if id != "" {
|
||||||
|
id = options.ensureUniqueHeaderID(id)
|
||||||
|
|
||||||
|
if options.parameters.HeaderIDPrefix != "" {
|
||||||
|
id = options.parameters.HeaderIDPrefix + id
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.parameters.HeaderIDSuffix != "" {
|
||||||
|
id = id + options.parameters.HeaderIDSuffix
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteString(fmt.Sprintf("<h%d id=\"%s\">", level, id))
|
||||||
|
} else {
|
||||||
|
out.WriteString(fmt.Sprintf("<h%d>", level))
|
||||||
|
}
|
||||||
|
|
||||||
|
tocMarker := out.Len()
|
||||||
|
if !text() {
|
||||||
|
out.Truncate(marker)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// are we building a table of contents?
|
||||||
|
if options.flags&HTML_TOC != 0 {
|
||||||
|
options.TocHeaderWithAnchor(out.Bytes()[tocMarker:], level, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteString(fmt.Sprintf("</h%d>\n", level))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) BlockHtml(out *bytes.Buffer, text []byte) {
|
||||||
|
if options.flags&HTML_SKIP_HTML != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
doubleSpace(out)
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteByte('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) HRule(out *bytes.Buffer) {
|
||||||
|
doubleSpace(out)
|
||||||
|
out.WriteString("<hr")
|
||||||
|
out.WriteString(options.closeTag)
|
||||||
|
out.WriteByte('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) BlockCode(out *bytes.Buffer, text []byte, lang string) {
|
||||||
|
doubleSpace(out)
|
||||||
|
|
||||||
|
// parse out the language names/classes
|
||||||
|
count := 0
|
||||||
|
for _, elt := range strings.Fields(lang) {
|
||||||
|
if elt[0] == '.' {
|
||||||
|
elt = elt[1:]
|
||||||
|
}
|
||||||
|
if len(elt) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
out.WriteString("<pre><code class=\"language-")
|
||||||
|
} else {
|
||||||
|
out.WriteByte(' ')
|
||||||
|
}
|
||||||
|
attrEscape(out, []byte(elt))
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
if count == 0 {
|
||||||
|
out.WriteString("<pre><code>")
|
||||||
|
} else {
|
||||||
|
out.WriteString("\">")
|
||||||
|
}
|
||||||
|
|
||||||
|
attrEscape(out, text)
|
||||||
|
out.WriteString("</code></pre>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) BlockQuote(out *bytes.Buffer, text []byte) {
|
||||||
|
doubleSpace(out)
|
||||||
|
out.WriteString("<blockquote>\n")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("</blockquote>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
|
||||||
|
doubleSpace(out)
|
||||||
|
out.WriteString("<table>\n<thead>\n")
|
||||||
|
out.Write(header)
|
||||||
|
out.WriteString("</thead>\n\n<tbody>\n")
|
||||||
|
out.Write(body)
|
||||||
|
out.WriteString("</tbody>\n</table>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) TableRow(out *bytes.Buffer, text []byte) {
|
||||||
|
doubleSpace(out)
|
||||||
|
out.WriteString("<tr>\n")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("\n</tr>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
|
||||||
|
doubleSpace(out)
|
||||||
|
switch align {
|
||||||
|
case TABLE_ALIGNMENT_LEFT:
|
||||||
|
out.WriteString("<th align=\"left\">")
|
||||||
|
case TABLE_ALIGNMENT_RIGHT:
|
||||||
|
out.WriteString("<th align=\"right\">")
|
||||||
|
case TABLE_ALIGNMENT_CENTER:
|
||||||
|
out.WriteString("<th align=\"center\">")
|
||||||
|
default:
|
||||||
|
out.WriteString("<th>")
|
||||||
|
}
|
||||||
|
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("</th>")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) TableCell(out *bytes.Buffer, text []byte, align int) {
|
||||||
|
doubleSpace(out)
|
||||||
|
switch align {
|
||||||
|
case TABLE_ALIGNMENT_LEFT:
|
||||||
|
out.WriteString("<td align=\"left\">")
|
||||||
|
case TABLE_ALIGNMENT_RIGHT:
|
||||||
|
out.WriteString("<td align=\"right\">")
|
||||||
|
case TABLE_ALIGNMENT_CENTER:
|
||||||
|
out.WriteString("<td align=\"center\">")
|
||||||
|
default:
|
||||||
|
out.WriteString("<td>")
|
||||||
|
}
|
||||||
|
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("</td>")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) Footnotes(out *bytes.Buffer, text func() bool) {
|
||||||
|
out.WriteString("<div class=\"footnotes\">\n")
|
||||||
|
options.HRule(out)
|
||||||
|
options.List(out, text, LIST_TYPE_ORDERED)
|
||||||
|
out.WriteString("</div>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
|
||||||
|
if flags&LIST_ITEM_CONTAINS_BLOCK != 0 || flags&LIST_ITEM_BEGINNING_OF_LIST != 0 {
|
||||||
|
doubleSpace(out)
|
||||||
|
}
|
||||||
|
slug := slugify(name)
|
||||||
|
out.WriteString(`<li id="`)
|
||||||
|
out.WriteString(`fn:`)
|
||||||
|
out.WriteString(options.parameters.FootnoteAnchorPrefix)
|
||||||
|
out.Write(slug)
|
||||||
|
out.WriteString(`">`)
|
||||||
|
out.Write(text)
|
||||||
|
if options.flags&HTML_FOOTNOTE_RETURN_LINKS != 0 {
|
||||||
|
out.WriteString(` <a class="footnote-return" href="#`)
|
||||||
|
out.WriteString(`fnref:`)
|
||||||
|
out.WriteString(options.parameters.FootnoteAnchorPrefix)
|
||||||
|
out.Write(slug)
|
||||||
|
out.WriteString(`">`)
|
||||||
|
out.WriteString(options.parameters.FootnoteReturnLinkContents)
|
||||||
|
out.WriteString(`</a>`)
|
||||||
|
}
|
||||||
|
out.WriteString("</li>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) List(out *bytes.Buffer, text func() bool, flags int) {
|
||||||
|
marker := out.Len()
|
||||||
|
doubleSpace(out)
|
||||||
|
|
||||||
|
if flags&LIST_TYPE_DEFINITION != 0 {
|
||||||
|
out.WriteString("<dl>")
|
||||||
|
} else if flags&LIST_TYPE_ORDERED != 0 {
|
||||||
|
out.WriteString("<ol>")
|
||||||
|
} else {
|
||||||
|
out.WriteString("<ul>")
|
||||||
|
}
|
||||||
|
if !text() {
|
||||||
|
out.Truncate(marker)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if flags&LIST_TYPE_DEFINITION != 0 {
|
||||||
|
out.WriteString("</dl>\n")
|
||||||
|
} else if flags&LIST_TYPE_ORDERED != 0 {
|
||||||
|
out.WriteString("</ol>\n")
|
||||||
|
} else {
|
||||||
|
out.WriteString("</ul>\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) ListItem(out *bytes.Buffer, text []byte, flags int) {
|
||||||
|
if (flags&LIST_ITEM_CONTAINS_BLOCK != 0 && flags&LIST_TYPE_DEFINITION == 0) ||
|
||||||
|
flags&LIST_ITEM_BEGINNING_OF_LIST != 0 {
|
||||||
|
doubleSpace(out)
|
||||||
|
}
|
||||||
|
if flags&LIST_TYPE_TERM != 0 {
|
||||||
|
out.WriteString("<dt>")
|
||||||
|
} else if flags&LIST_TYPE_DEFINITION != 0 {
|
||||||
|
out.WriteString("<dd>")
|
||||||
|
} else {
|
||||||
|
out.WriteString("<li>")
|
||||||
|
}
|
||||||
|
out.Write(text)
|
||||||
|
if flags&LIST_TYPE_TERM != 0 {
|
||||||
|
out.WriteString("</dt>\n")
|
||||||
|
} else if flags&LIST_TYPE_DEFINITION != 0 {
|
||||||
|
out.WriteString("</dd>\n")
|
||||||
|
} else {
|
||||||
|
out.WriteString("</li>\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) Paragraph(out *bytes.Buffer, text func() bool) {
|
||||||
|
marker := out.Len()
|
||||||
|
doubleSpace(out)
|
||||||
|
|
||||||
|
out.WriteString("<p>")
|
||||||
|
if !text() {
|
||||||
|
out.Truncate(marker)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
out.WriteString("</p>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) AutoLink(out *bytes.Buffer, link []byte, kind int) {
|
||||||
|
skipRanges := htmlEntity.FindAllIndex(link, -1)
|
||||||
|
if options.flags&HTML_SAFELINK != 0 && !isSafeLink(link) && kind != LINK_TYPE_EMAIL {
|
||||||
|
// mark it but don't link it if it is not a safe link: no smartypants
|
||||||
|
out.WriteString("<tt>")
|
||||||
|
entityEscapeWithSkip(out, link, skipRanges)
|
||||||
|
out.WriteString("</tt>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteString("<a href=\"")
|
||||||
|
if kind == LINK_TYPE_EMAIL {
|
||||||
|
out.WriteString("mailto:")
|
||||||
|
} else {
|
||||||
|
options.maybeWriteAbsolutePrefix(out, link)
|
||||||
|
}
|
||||||
|
|
||||||
|
entityEscapeWithSkip(out, link, skipRanges)
|
||||||
|
|
||||||
|
var relAttrs []string
|
||||||
|
if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) {
|
||||||
|
relAttrs = append(relAttrs, "nofollow")
|
||||||
|
}
|
||||||
|
if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) {
|
||||||
|
relAttrs = append(relAttrs, "noreferrer")
|
||||||
|
}
|
||||||
|
if len(relAttrs) > 0 {
|
||||||
|
out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// blank target only add to external link
|
||||||
|
if options.flags&HTML_HREF_TARGET_BLANK != 0 && !isRelativeLink(link) {
|
||||||
|
out.WriteString("\" target=\"_blank")
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteString("\">")
|
||||||
|
|
||||||
|
// Pretty print: if we get an email address as
|
||||||
|
// an actual URI, e.g. `mailto:foo@bar.com`, we don't
|
||||||
|
// want to print the `mailto:` prefix
|
||||||
|
switch {
|
||||||
|
case bytes.HasPrefix(link, []byte("mailto://")):
|
||||||
|
attrEscape(out, link[len("mailto://"):])
|
||||||
|
case bytes.HasPrefix(link, []byte("mailto:")):
|
||||||
|
attrEscape(out, link[len("mailto:"):])
|
||||||
|
default:
|
||||||
|
entityEscapeWithSkip(out, link, skipRanges)
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteString("</a>")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) CodeSpan(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("<code>")
|
||||||
|
attrEscape(out, text)
|
||||||
|
out.WriteString("</code>")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) DoubleEmphasis(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("<strong>")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("</strong>")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) Emphasis(out *bytes.Buffer, text []byte) {
|
||||||
|
if len(text) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
out.WriteString("<em>")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("</em>")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) maybeWriteAbsolutePrefix(out *bytes.Buffer, link []byte) {
|
||||||
|
if options.parameters.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' {
|
||||||
|
out.WriteString(options.parameters.AbsolutePrefix)
|
||||||
|
if link[0] != '/' {
|
||||||
|
out.WriteByte('/')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
||||||
|
if options.flags&HTML_SKIP_IMAGES != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteString("<img src=\"")
|
||||||
|
options.maybeWriteAbsolutePrefix(out, link)
|
||||||
|
attrEscape(out, link)
|
||||||
|
out.WriteString("\" alt=\"")
|
||||||
|
if len(alt) > 0 {
|
||||||
|
attrEscape(out, alt)
|
||||||
|
}
|
||||||
|
if len(title) > 0 {
|
||||||
|
out.WriteString("\" title=\"")
|
||||||
|
attrEscape(out, title)
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteByte('"')
|
||||||
|
out.WriteString(options.closeTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) LineBreak(out *bytes.Buffer) {
|
||||||
|
out.WriteString("<br")
|
||||||
|
out.WriteString(options.closeTag)
|
||||||
|
out.WriteByte('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
|
||||||
|
if options.flags&HTML_SKIP_LINKS != 0 {
|
||||||
|
// write the link text out but don't link it, just mark it with typewriter font
|
||||||
|
out.WriteString("<tt>")
|
||||||
|
attrEscape(out, content)
|
||||||
|
out.WriteString("</tt>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.flags&HTML_SAFELINK != 0 && !isSafeLink(link) {
|
||||||
|
// write the link text out but don't link it, just mark it with typewriter font
|
||||||
|
out.WriteString("<tt>")
|
||||||
|
attrEscape(out, content)
|
||||||
|
out.WriteString("</tt>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteString("<a href=\"")
|
||||||
|
options.maybeWriteAbsolutePrefix(out, link)
|
||||||
|
attrEscape(out, link)
|
||||||
|
if len(title) > 0 {
|
||||||
|
out.WriteString("\" title=\"")
|
||||||
|
attrEscape(out, title)
|
||||||
|
}
|
||||||
|
var relAttrs []string
|
||||||
|
if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) {
|
||||||
|
relAttrs = append(relAttrs, "nofollow")
|
||||||
|
}
|
||||||
|
if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) {
|
||||||
|
relAttrs = append(relAttrs, "noreferrer")
|
||||||
|
}
|
||||||
|
if len(relAttrs) > 0 {
|
||||||
|
out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// blank target only add to external link
|
||||||
|
if options.flags&HTML_HREF_TARGET_BLANK != 0 && !isRelativeLink(link) {
|
||||||
|
out.WriteString("\" target=\"_blank")
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteString("\">")
|
||||||
|
out.Write(content)
|
||||||
|
out.WriteString("</a>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) RawHtmlTag(out *bytes.Buffer, text []byte) {
|
||||||
|
if options.flags&HTML_SKIP_HTML != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if options.flags&HTML_SKIP_STYLE != 0 && isHtmlTag(text, "style") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if options.flags&HTML_SKIP_LINKS != 0 && isHtmlTag(text, "a") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if options.flags&HTML_SKIP_IMAGES != 0 && isHtmlTag(text, "img") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
out.Write(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) TripleEmphasis(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("<strong><em>")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("</em></strong>")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) StrikeThrough(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("<del>")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("</del>")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
|
||||||
|
slug := slugify(ref)
|
||||||
|
out.WriteString(`<sup class="footnote-ref" id="`)
|
||||||
|
out.WriteString(`fnref:`)
|
||||||
|
out.WriteString(options.parameters.FootnoteAnchorPrefix)
|
||||||
|
out.Write(slug)
|
||||||
|
out.WriteString(`"><a rel="footnote" href="#`)
|
||||||
|
out.WriteString(`fn:`)
|
||||||
|
out.WriteString(options.parameters.FootnoteAnchorPrefix)
|
||||||
|
out.Write(slug)
|
||||||
|
out.WriteString(`">`)
|
||||||
|
out.WriteString(strconv.Itoa(id))
|
||||||
|
out.WriteString(`</a></sup>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) Entity(out *bytes.Buffer, entity []byte) {
|
||||||
|
out.Write(entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) NormalText(out *bytes.Buffer, text []byte) {
|
||||||
|
if options.flags&HTML_USE_SMARTYPANTS != 0 {
|
||||||
|
options.Smartypants(out, text)
|
||||||
|
} else {
|
||||||
|
attrEscape(out, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) Smartypants(out *bytes.Buffer, text []byte) {
|
||||||
|
smrt := smartypantsData{false, false}
|
||||||
|
|
||||||
|
// first do normal entity escaping
|
||||||
|
var escaped bytes.Buffer
|
||||||
|
attrEscape(&escaped, text)
|
||||||
|
text = escaped.Bytes()
|
||||||
|
|
||||||
|
mark := 0
|
||||||
|
for i := 0; i < len(text); i++ {
|
||||||
|
if action := options.smartypants[text[i]]; action != nil {
|
||||||
|
if i > mark {
|
||||||
|
out.Write(text[mark:i])
|
||||||
|
}
|
||||||
|
|
||||||
|
previousChar := byte(0)
|
||||||
|
if i > 0 {
|
||||||
|
previousChar = text[i-1]
|
||||||
|
}
|
||||||
|
i += action(out, &smrt, previousChar, text[i:])
|
||||||
|
mark = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mark < len(text) {
|
||||||
|
out.Write(text[mark:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) DocumentHeader(out *bytes.Buffer) {
|
||||||
|
if options.flags&HTML_COMPLETE_PAGE == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ending := ""
|
||||||
|
if options.flags&HTML_USE_XHTML != 0 {
|
||||||
|
out.WriteString("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ")
|
||||||
|
out.WriteString("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n")
|
||||||
|
out.WriteString("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n")
|
||||||
|
ending = " /"
|
||||||
|
} else {
|
||||||
|
out.WriteString("<!DOCTYPE html>\n")
|
||||||
|
out.WriteString("<html>\n")
|
||||||
|
}
|
||||||
|
out.WriteString("<head>\n")
|
||||||
|
out.WriteString(" <title>")
|
||||||
|
options.NormalText(out, []byte(options.title))
|
||||||
|
out.WriteString("</title>\n")
|
||||||
|
out.WriteString(" <meta name=\"GENERATOR\" content=\"Blackfriday Markdown Processor v")
|
||||||
|
out.WriteString(VERSION)
|
||||||
|
out.WriteString("\"")
|
||||||
|
out.WriteString(ending)
|
||||||
|
out.WriteString(">\n")
|
||||||
|
out.WriteString(" <meta charset=\"utf-8\"")
|
||||||
|
out.WriteString(ending)
|
||||||
|
out.WriteString(">\n")
|
||||||
|
if options.css != "" {
|
||||||
|
out.WriteString(" <link rel=\"stylesheet\" type=\"text/css\" href=\"")
|
||||||
|
attrEscape(out, []byte(options.css))
|
||||||
|
out.WriteString("\"")
|
||||||
|
out.WriteString(ending)
|
||||||
|
out.WriteString(">\n")
|
||||||
|
}
|
||||||
|
out.WriteString("</head>\n")
|
||||||
|
out.WriteString("<body>\n")
|
||||||
|
|
||||||
|
options.tocMarker = out.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) DocumentFooter(out *bytes.Buffer) {
|
||||||
|
// finalize and insert the table of contents
|
||||||
|
if options.flags&HTML_TOC != 0 {
|
||||||
|
options.TocFinalize()
|
||||||
|
|
||||||
|
// now we have to insert the table of contents into the document
|
||||||
|
var temp bytes.Buffer
|
||||||
|
|
||||||
|
// start by making a copy of everything after the document header
|
||||||
|
temp.Write(out.Bytes()[options.tocMarker:])
|
||||||
|
|
||||||
|
// now clear the copied material from the main output buffer
|
||||||
|
out.Truncate(options.tocMarker)
|
||||||
|
|
||||||
|
// corner case spacing issue
|
||||||
|
if options.flags&HTML_COMPLETE_PAGE != 0 {
|
||||||
|
out.WriteByte('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert the table of contents
|
||||||
|
out.WriteString("<nav>\n")
|
||||||
|
out.Write(options.toc.Bytes())
|
||||||
|
out.WriteString("</nav>\n")
|
||||||
|
|
||||||
|
// corner case spacing issue
|
||||||
|
if options.flags&HTML_COMPLETE_PAGE == 0 && options.flags&HTML_OMIT_CONTENTS == 0 {
|
||||||
|
out.WriteByte('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
// write out everything that came after it
|
||||||
|
if options.flags&HTML_OMIT_CONTENTS == 0 {
|
||||||
|
out.Write(temp.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.flags&HTML_COMPLETE_PAGE != 0 {
|
||||||
|
out.WriteString("\n</body>\n")
|
||||||
|
out.WriteString("</html>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) TocHeaderWithAnchor(text []byte, level int, anchor string) {
|
||||||
|
for level > options.currentLevel {
|
||||||
|
switch {
|
||||||
|
case bytes.HasSuffix(options.toc.Bytes(), []byte("</li>\n")):
|
||||||
|
// this sublist can nest underneath a header
|
||||||
|
size := options.toc.Len()
|
||||||
|
options.toc.Truncate(size - len("</li>\n"))
|
||||||
|
|
||||||
|
case options.currentLevel > 0:
|
||||||
|
options.toc.WriteString("<li>")
|
||||||
|
}
|
||||||
|
if options.toc.Len() > 0 {
|
||||||
|
options.toc.WriteByte('\n')
|
||||||
|
}
|
||||||
|
options.toc.WriteString("<ul>\n")
|
||||||
|
options.currentLevel++
|
||||||
|
}
|
||||||
|
|
||||||
|
for level < options.currentLevel {
|
||||||
|
options.toc.WriteString("</ul>")
|
||||||
|
if options.currentLevel > 1 {
|
||||||
|
options.toc.WriteString("</li>\n")
|
||||||
|
}
|
||||||
|
options.currentLevel--
|
||||||
|
}
|
||||||
|
|
||||||
|
options.toc.WriteString("<li><a href=\"#")
|
||||||
|
if anchor != "" {
|
||||||
|
options.toc.WriteString(anchor)
|
||||||
|
} else {
|
||||||
|
options.toc.WriteString("toc_")
|
||||||
|
options.toc.WriteString(strconv.Itoa(options.headerCount))
|
||||||
|
}
|
||||||
|
options.toc.WriteString("\">")
|
||||||
|
options.headerCount++
|
||||||
|
|
||||||
|
options.toc.Write(text)
|
||||||
|
|
||||||
|
options.toc.WriteString("</a></li>\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) TocHeader(text []byte, level int) {
|
||||||
|
options.TocHeaderWithAnchor(text, level, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) TocFinalize() {
|
||||||
|
for options.currentLevel > 1 {
|
||||||
|
options.toc.WriteString("</ul></li>\n")
|
||||||
|
options.currentLevel--
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.currentLevel > 0 {
|
||||||
|
options.toc.WriteString("</ul>\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHtmlTag(tag []byte, tagname string) bool {
|
||||||
|
found, _ := findHtmlTagPos(tag, tagname)
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a character, but ignore it when it's in any kind of quotes, it
|
||||||
|
// might be JavaScript
|
||||||
|
func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int {
|
||||||
|
inSingleQuote := false
|
||||||
|
inDoubleQuote := false
|
||||||
|
inGraveQuote := false
|
||||||
|
i := start
|
||||||
|
for i < len(html) {
|
||||||
|
switch {
|
||||||
|
case html[i] == char && !inSingleQuote && !inDoubleQuote && !inGraveQuote:
|
||||||
|
return i
|
||||||
|
case html[i] == '\'':
|
||||||
|
inSingleQuote = !inSingleQuote
|
||||||
|
case html[i] == '"':
|
||||||
|
inDoubleQuote = !inDoubleQuote
|
||||||
|
case html[i] == '`':
|
||||||
|
inGraveQuote = !inGraveQuote
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return start
|
||||||
|
}
|
||||||
|
|
||||||
|
func findHtmlTagPos(tag []byte, tagname string) (bool, int) {
|
||||||
|
i := 0
|
||||||
|
if i < len(tag) && tag[0] != '<' {
|
||||||
|
return false, -1
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
i = skipSpace(tag, i)
|
||||||
|
|
||||||
|
if i < len(tag) && tag[i] == '/' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
i = skipSpace(tag, i)
|
||||||
|
j := 0
|
||||||
|
for ; i < len(tag); i, j = i+1, j+1 {
|
||||||
|
if j >= len(tagname) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.ToLower(string(tag[i]))[0] != tagname[j] {
|
||||||
|
return false, -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == len(tag) {
|
||||||
|
return false, -1
|
||||||
|
}
|
||||||
|
|
||||||
|
rightAngle := skipUntilCharIgnoreQuotes(tag, i, '>')
|
||||||
|
if rightAngle > i {
|
||||||
|
return true, rightAngle
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func skipUntilChar(text []byte, start int, char byte) int {
|
||||||
|
i := start
|
||||||
|
for i < len(text) && text[i] != char {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func skipSpace(tag []byte, i int) int {
|
||||||
|
for i < len(tag) && isspace(tag[i]) {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func skipChar(data []byte, start int, char byte) int {
|
||||||
|
i := start
|
||||||
|
for i < len(data) && data[i] == char {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func doubleSpace(out *bytes.Buffer) {
|
||||||
|
if out.Len() > 0 {
|
||||||
|
out.WriteByte('\n')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isRelativeLink(link []byte) (yes bool) {
|
||||||
|
// a tag begin with '#'
|
||||||
|
if link[0] == '#' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// link begin with '/' but not '//', the second maybe a protocol relative link
|
||||||
|
if len(link) >= 2 && link[0] == '/' && link[1] != '/' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// only the root '/'
|
||||||
|
if len(link) == 1 && link[0] == '/' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// current directory : begin with "./"
|
||||||
|
if bytes.HasPrefix(link, []byte("./")) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// parent directory : begin with "../"
|
||||||
|
if bytes.HasPrefix(link, []byte("../")) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Html) ensureUniqueHeaderID(id string) string {
|
||||||
|
for count, found := options.headerIDs[id]; found; count, found = options.headerIDs[id] {
|
||||||
|
tmp := fmt.Sprintf("%s-%d", id, count+1)
|
||||||
|
|
||||||
|
if _, tmpFound := options.headerIDs[tmp]; !tmpFound {
|
||||||
|
options.headerIDs[id] = count + 1
|
||||||
|
id = tmp
|
||||||
|
} else {
|
||||||
|
id = id + "-1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, found := options.headerIDs[id]; !found {
|
||||||
|
options.headerIDs[id] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return id
|
||||||
|
}
|
1133
vendor/github.com/russross/blackfriday/inline.go
generated
vendored
Normal file
1133
vendor/github.com/russross/blackfriday/inline.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1153
vendor/github.com/russross/blackfriday/inline_test.go
generated
vendored
Normal file
1153
vendor/github.com/russross/blackfriday/inline_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
332
vendor/github.com/russross/blackfriday/latex.go
generated
vendored
Normal file
332
vendor/github.com/russross/blackfriday/latex.go
generated
vendored
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
//
|
||||||
|
// Blackfriday Markdown Processor
|
||||||
|
// Available at http://github.com/russross/blackfriday
|
||||||
|
//
|
||||||
|
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
||||||
|
// Distributed under the Simplified BSD License.
|
||||||
|
// See README.md for details.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// LaTeX rendering backend
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
package blackfriday
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Latex is a type that implements the Renderer interface for LaTeX output.
|
||||||
|
//
|
||||||
|
// Do not create this directly, instead use the LatexRenderer function.
|
||||||
|
type Latex struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// LatexRenderer creates and configures a Latex object, which
|
||||||
|
// satisfies the Renderer interface.
|
||||||
|
//
|
||||||
|
// flags is a set of LATEX_* options ORed together (currently no such options
|
||||||
|
// are defined).
|
||||||
|
func LatexRenderer(flags int) Renderer {
|
||||||
|
return &Latex{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) GetFlags() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// render code chunks using verbatim, or listings if we have a language
|
||||||
|
func (options *Latex) BlockCode(out *bytes.Buffer, text []byte, lang string) {
|
||||||
|
if lang == "" {
|
||||||
|
out.WriteString("\n\\begin{verbatim}\n")
|
||||||
|
} else {
|
||||||
|
out.WriteString("\n\\begin{lstlisting}[language=")
|
||||||
|
out.WriteString(lang)
|
||||||
|
out.WriteString("]\n")
|
||||||
|
}
|
||||||
|
out.Write(text)
|
||||||
|
if lang == "" {
|
||||||
|
out.WriteString("\n\\end{verbatim}\n")
|
||||||
|
} else {
|
||||||
|
out.WriteString("\n\\end{lstlisting}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) TitleBlock(out *bytes.Buffer, text []byte) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) BlockQuote(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("\n\\begin{quotation}\n")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("\n\\end{quotation}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) BlockHtml(out *bytes.Buffer, text []byte) {
|
||||||
|
// a pretty lame thing to do...
|
||||||
|
out.WriteString("\n\\begin{verbatim}\n")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("\n\\end{verbatim}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) Header(out *bytes.Buffer, text func() bool, level int, id string) {
|
||||||
|
marker := out.Len()
|
||||||
|
|
||||||
|
switch level {
|
||||||
|
case 1:
|
||||||
|
out.WriteString("\n\\section{")
|
||||||
|
case 2:
|
||||||
|
out.WriteString("\n\\subsection{")
|
||||||
|
case 3:
|
||||||
|
out.WriteString("\n\\subsubsection{")
|
||||||
|
case 4:
|
||||||
|
out.WriteString("\n\\paragraph{")
|
||||||
|
case 5:
|
||||||
|
out.WriteString("\n\\subparagraph{")
|
||||||
|
case 6:
|
||||||
|
out.WriteString("\n\\textbf{")
|
||||||
|
}
|
||||||
|
if !text() {
|
||||||
|
out.Truncate(marker)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
out.WriteString("}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) HRule(out *bytes.Buffer) {
|
||||||
|
out.WriteString("\n\\HRule\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) List(out *bytes.Buffer, text func() bool, flags int) {
|
||||||
|
marker := out.Len()
|
||||||
|
if flags&LIST_TYPE_ORDERED != 0 {
|
||||||
|
out.WriteString("\n\\begin{enumerate}\n")
|
||||||
|
} else {
|
||||||
|
out.WriteString("\n\\begin{itemize}\n")
|
||||||
|
}
|
||||||
|
if !text() {
|
||||||
|
out.Truncate(marker)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if flags&LIST_TYPE_ORDERED != 0 {
|
||||||
|
out.WriteString("\n\\end{enumerate}\n")
|
||||||
|
} else {
|
||||||
|
out.WriteString("\n\\end{itemize}\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) ListItem(out *bytes.Buffer, text []byte, flags int) {
|
||||||
|
out.WriteString("\n\\item ")
|
||||||
|
out.Write(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) Paragraph(out *bytes.Buffer, text func() bool) {
|
||||||
|
marker := out.Len()
|
||||||
|
out.WriteString("\n")
|
||||||
|
if !text() {
|
||||||
|
out.Truncate(marker)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
out.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
|
||||||
|
out.WriteString("\n\\begin{tabular}{")
|
||||||
|
for _, elt := range columnData {
|
||||||
|
switch elt {
|
||||||
|
case TABLE_ALIGNMENT_LEFT:
|
||||||
|
out.WriteByte('l')
|
||||||
|
case TABLE_ALIGNMENT_RIGHT:
|
||||||
|
out.WriteByte('r')
|
||||||
|
default:
|
||||||
|
out.WriteByte('c')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.WriteString("}\n")
|
||||||
|
out.Write(header)
|
||||||
|
out.WriteString(" \\\\\n\\hline\n")
|
||||||
|
out.Write(body)
|
||||||
|
out.WriteString("\n\\end{tabular}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) TableRow(out *bytes.Buffer, text []byte) {
|
||||||
|
if out.Len() > 0 {
|
||||||
|
out.WriteString(" \\\\\n")
|
||||||
|
}
|
||||||
|
out.Write(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
|
||||||
|
if out.Len() > 0 {
|
||||||
|
out.WriteString(" & ")
|
||||||
|
}
|
||||||
|
out.Write(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) TableCell(out *bytes.Buffer, text []byte, align int) {
|
||||||
|
if out.Len() > 0 {
|
||||||
|
out.WriteString(" & ")
|
||||||
|
}
|
||||||
|
out.Write(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this
|
||||||
|
func (options *Latex) Footnotes(out *bytes.Buffer, text func() bool) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) AutoLink(out *bytes.Buffer, link []byte, kind int) {
|
||||||
|
out.WriteString("\\href{")
|
||||||
|
if kind == LINK_TYPE_EMAIL {
|
||||||
|
out.WriteString("mailto:")
|
||||||
|
}
|
||||||
|
out.Write(link)
|
||||||
|
out.WriteString("}{")
|
||||||
|
out.Write(link)
|
||||||
|
out.WriteString("}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) CodeSpan(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("\\texttt{")
|
||||||
|
escapeSpecialChars(out, text)
|
||||||
|
out.WriteString("}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) DoubleEmphasis(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("\\textbf{")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) Emphasis(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("\\textit{")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
||||||
|
if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) {
|
||||||
|
// treat it like a link
|
||||||
|
out.WriteString("\\href{")
|
||||||
|
out.Write(link)
|
||||||
|
out.WriteString("}{")
|
||||||
|
out.Write(alt)
|
||||||
|
out.WriteString("}")
|
||||||
|
} else {
|
||||||
|
out.WriteString("\\includegraphics{")
|
||||||
|
out.Write(link)
|
||||||
|
out.WriteString("}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) LineBreak(out *bytes.Buffer) {
|
||||||
|
out.WriteString(" \\\\\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
|
||||||
|
out.WriteString("\\href{")
|
||||||
|
out.Write(link)
|
||||||
|
out.WriteString("}{")
|
||||||
|
out.Write(content)
|
||||||
|
out.WriteString("}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) RawHtmlTag(out *bytes.Buffer, tag []byte) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) TripleEmphasis(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("\\textbf{\\textit{")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("}}")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) StrikeThrough(out *bytes.Buffer, text []byte) {
|
||||||
|
out.WriteString("\\sout{")
|
||||||
|
out.Write(text)
|
||||||
|
out.WriteString("}")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this
|
||||||
|
func (options *Latex) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func needsBackslash(c byte) bool {
|
||||||
|
for _, r := range []byte("_{}%$&\\~#") {
|
||||||
|
if c == r {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func escapeSpecialChars(out *bytes.Buffer, text []byte) {
|
||||||
|
for i := 0; i < len(text); i++ {
|
||||||
|
// directly copy normal characters
|
||||||
|
org := i
|
||||||
|
|
||||||
|
for i < len(text) && !needsBackslash(text[i]) {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i > org {
|
||||||
|
out.Write(text[org:i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// escape a character
|
||||||
|
if i >= len(text) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
out.WriteByte('\\')
|
||||||
|
out.WriteByte(text[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) Entity(out *bytes.Buffer, entity []byte) {
|
||||||
|
// TODO: convert this into a unicode character or something
|
||||||
|
out.Write(entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) NormalText(out *bytes.Buffer, text []byte) {
|
||||||
|
escapeSpecialChars(out, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// header and footer
|
||||||
|
func (options *Latex) DocumentHeader(out *bytes.Buffer) {
|
||||||
|
out.WriteString("\\documentclass{article}\n")
|
||||||
|
out.WriteString("\n")
|
||||||
|
out.WriteString("\\usepackage{graphicx}\n")
|
||||||
|
out.WriteString("\\usepackage{listings}\n")
|
||||||
|
out.WriteString("\\usepackage[margin=1in]{geometry}\n")
|
||||||
|
out.WriteString("\\usepackage[utf8]{inputenc}\n")
|
||||||
|
out.WriteString("\\usepackage{verbatim}\n")
|
||||||
|
out.WriteString("\\usepackage[normalem]{ulem}\n")
|
||||||
|
out.WriteString("\\usepackage{hyperref}\n")
|
||||||
|
out.WriteString("\n")
|
||||||
|
out.WriteString("\\hypersetup{colorlinks,%\n")
|
||||||
|
out.WriteString(" citecolor=black,%\n")
|
||||||
|
out.WriteString(" filecolor=black,%\n")
|
||||||
|
out.WriteString(" linkcolor=black,%\n")
|
||||||
|
out.WriteString(" urlcolor=black,%\n")
|
||||||
|
out.WriteString(" pdfstartview=FitH,%\n")
|
||||||
|
out.WriteString(" breaklinks=true,%\n")
|
||||||
|
out.WriteString(" pdfauthor={Blackfriday Markdown Processor v")
|
||||||
|
out.WriteString(VERSION)
|
||||||
|
out.WriteString("}}\n")
|
||||||
|
out.WriteString("\n")
|
||||||
|
out.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n")
|
||||||
|
out.WriteString("\\addtolength{\\parskip}{0.5\\baselineskip}\n")
|
||||||
|
out.WriteString("\\parindent=0pt\n")
|
||||||
|
out.WriteString("\n")
|
||||||
|
out.WriteString("\\begin{document}\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (options *Latex) DocumentFooter(out *bytes.Buffer) {
|
||||||
|
out.WriteString("\n\\end{document}\n")
|
||||||
|
}
|
926
vendor/github.com/russross/blackfriday/markdown.go
generated
vendored
Normal file
926
vendor/github.com/russross/blackfriday/markdown.go
generated
vendored
Normal file
@ -0,0 +1,926 @@
|
|||||||
|
//
|
||||||
|
// Blackfriday Markdown Processor
|
||||||
|
// Available at http://github.com/russross/blackfriday
|
||||||
|
//
|
||||||
|
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
||||||
|
// Distributed under the Simplified BSD License.
|
||||||
|
// See README.md for details.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Markdown parsing and processing
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
// Blackfriday markdown processor.
|
||||||
|
//
|
||||||
|
// Translates plain text with simple formatting rules into HTML or LaTeX.
|
||||||
|
package blackfriday
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
const VERSION = "1.4"
|
||||||
|
|
||||||
|
// These are the supported markdown parsing extensions.
|
||||||
|
// OR these values together to select multiple extensions.
|
||||||
|
const (
|
||||||
|
EXTENSION_NO_INTRA_EMPHASIS = 1 << iota // ignore emphasis markers inside words
|
||||||
|
EXTENSION_TABLES // render tables
|
||||||
|
EXTENSION_FENCED_CODE // render fenced code blocks
|
||||||
|
EXTENSION_AUTOLINK // detect embedded URLs that are not explicitly marked
|
||||||
|
EXTENSION_STRIKETHROUGH // strikethrough text using ~~test~~
|
||||||
|
EXTENSION_LAX_HTML_BLOCKS // loosen up HTML block parsing rules
|
||||||
|
EXTENSION_SPACE_HEADERS // be strict about prefix header rules
|
||||||
|
EXTENSION_HARD_LINE_BREAK // translate newlines into line breaks
|
||||||
|
EXTENSION_TAB_SIZE_EIGHT // expand tabs to eight spaces instead of four
|
||||||
|
EXTENSION_FOOTNOTES // Pandoc-style footnotes
|
||||||
|
EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block
|
||||||
|
EXTENSION_HEADER_IDS // specify header IDs with {#id}
|
||||||
|
EXTENSION_TITLEBLOCK // Titleblock ala pandoc
|
||||||
|
EXTENSION_AUTO_HEADER_IDS // Create the header ID from the text
|
||||||
|
EXTENSION_BACKSLASH_LINE_BREAK // translate trailing backslashes into line breaks
|
||||||
|
EXTENSION_DEFINITION_LISTS // render definition lists
|
||||||
|
|
||||||
|
commonHtmlFlags = 0 |
|
||||||
|
HTML_USE_XHTML |
|
||||||
|
HTML_USE_SMARTYPANTS |
|
||||||
|
HTML_SMARTYPANTS_FRACTIONS |
|
||||||
|
HTML_SMARTYPANTS_DASHES |
|
||||||
|
HTML_SMARTYPANTS_LATEX_DASHES
|
||||||
|
|
||||||
|
commonExtensions = 0 |
|
||||||
|
EXTENSION_NO_INTRA_EMPHASIS |
|
||||||
|
EXTENSION_TABLES |
|
||||||
|
EXTENSION_FENCED_CODE |
|
||||||
|
EXTENSION_AUTOLINK |
|
||||||
|
EXTENSION_STRIKETHROUGH |
|
||||||
|
EXTENSION_SPACE_HEADERS |
|
||||||
|
EXTENSION_HEADER_IDS |
|
||||||
|
EXTENSION_BACKSLASH_LINE_BREAK |
|
||||||
|
EXTENSION_DEFINITION_LISTS
|
||||||
|
)
|
||||||
|
|
||||||
|
// These are the possible flag values for the link renderer.
|
||||||
|
// Only a single one of these values will be used; they are not ORed together.
|
||||||
|
// These are mostly of interest if you are writing a new output format.
|
||||||
|
const (
|
||||||
|
LINK_TYPE_NOT_AUTOLINK = iota
|
||||||
|
LINK_TYPE_NORMAL
|
||||||
|
LINK_TYPE_EMAIL
|
||||||
|
)
|
||||||
|
|
||||||
|
// These are the possible flag values for the ListItem renderer.
|
||||||
|
// Multiple flag values may be ORed together.
|
||||||
|
// These are mostly of interest if you are writing a new output format.
|
||||||
|
const (
|
||||||
|
LIST_TYPE_ORDERED = 1 << iota
|
||||||
|
LIST_TYPE_DEFINITION
|
||||||
|
LIST_TYPE_TERM
|
||||||
|
LIST_ITEM_CONTAINS_BLOCK
|
||||||
|
LIST_ITEM_BEGINNING_OF_LIST
|
||||||
|
LIST_ITEM_END_OF_LIST
|
||||||
|
)
|
||||||
|
|
||||||
|
// These are the possible flag values for the table cell renderer.
|
||||||
|
// Only a single one of these values will be used; they are not ORed together.
|
||||||
|
// These are mostly of interest if you are writing a new output format.
|
||||||
|
const (
|
||||||
|
TABLE_ALIGNMENT_LEFT = 1 << iota
|
||||||
|
TABLE_ALIGNMENT_RIGHT
|
||||||
|
TABLE_ALIGNMENT_CENTER = (TABLE_ALIGNMENT_LEFT | TABLE_ALIGNMENT_RIGHT)
|
||||||
|
)
|
||||||
|
|
||||||
|
// The size of a tab stop.
|
||||||
|
const (
|
||||||
|
TAB_SIZE_DEFAULT = 4
|
||||||
|
TAB_SIZE_EIGHT = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
// blockTags is a set of tags that are recognized as HTML block tags.
|
||||||
|
// Any of these can be included in markdown text without special escaping.
|
||||||
|
var blockTags = map[string]struct{}{
|
||||||
|
"blockquote": struct{}{},
|
||||||
|
"del": struct{}{},
|
||||||
|
"div": struct{}{},
|
||||||
|
"dl": struct{}{},
|
||||||
|
"fieldset": struct{}{},
|
||||||
|
"form": struct{}{},
|
||||||
|
"h1": struct{}{},
|
||||||
|
"h2": struct{}{},
|
||||||
|
"h3": struct{}{},
|
||||||
|
"h4": struct{}{},
|
||||||
|
"h5": struct{}{},
|
||||||
|
"h6": struct{}{},
|
||||||
|
"iframe": struct{}{},
|
||||||
|
"ins": struct{}{},
|
||||||
|
"math": struct{}{},
|
||||||
|
"noscript": struct{}{},
|
||||||
|
"ol": struct{}{},
|
||||||
|
"pre": struct{}{},
|
||||||
|
"p": struct{}{},
|
||||||
|
"script": struct{}{},
|
||||||
|
"style": struct{}{},
|
||||||
|
"table": struct{}{},
|
||||||
|
"ul": struct{}{},
|
||||||
|
|
||||||
|
// HTML5
|
||||||
|
"address": struct{}{},
|
||||||
|
"article": struct{}{},
|
||||||
|
"aside": struct{}{},
|
||||||
|
"canvas": struct{}{},
|
||||||
|
"figcaption": struct{}{},
|
||||||
|
"figure": struct{}{},
|
||||||
|
"footer": struct{}{},
|
||||||
|
"header": struct{}{},
|
||||||
|
"hgroup": struct{}{},
|
||||||
|
"main": struct{}{},
|
||||||
|
"nav": struct{}{},
|
||||||
|
"output": struct{}{},
|
||||||
|
"progress": struct{}{},
|
||||||
|
"section": struct{}{},
|
||||||
|
"video": struct{}{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renderer is the rendering interface.
|
||||||
|
// This is mostly of interest if you are implementing a new rendering format.
|
||||||
|
//
|
||||||
|
// When a byte slice is provided, it contains the (rendered) contents of the
|
||||||
|
// element.
|
||||||
|
//
|
||||||
|
// When a callback is provided instead, it will write the contents of the
|
||||||
|
// respective element directly to the output buffer and return true on success.
|
||||||
|
// If the callback returns false, the rendering function should reset the
|
||||||
|
// output buffer as though it had never been called.
|
||||||
|
//
|
||||||
|
// Currently Html and Latex implementations are provided
|
||||||
|
type Renderer interface {
|
||||||
|
// block-level callbacks
|
||||||
|
BlockCode(out *bytes.Buffer, text []byte, lang string)
|
||||||
|
BlockQuote(out *bytes.Buffer, text []byte)
|
||||||
|
BlockHtml(out *bytes.Buffer, text []byte)
|
||||||
|
Header(out *bytes.Buffer, text func() bool, level int, id string)
|
||||||
|
HRule(out *bytes.Buffer)
|
||||||
|
List(out *bytes.Buffer, text func() bool, flags int)
|
||||||
|
ListItem(out *bytes.Buffer, text []byte, flags int)
|
||||||
|
Paragraph(out *bytes.Buffer, text func() bool)
|
||||||
|
Table(out *bytes.Buffer, header []byte, body []byte, columnData []int)
|
||||||
|
TableRow(out *bytes.Buffer, text []byte)
|
||||||
|
TableHeaderCell(out *bytes.Buffer, text []byte, flags int)
|
||||||
|
TableCell(out *bytes.Buffer, text []byte, flags int)
|
||||||
|
Footnotes(out *bytes.Buffer, text func() bool)
|
||||||
|
FootnoteItem(out *bytes.Buffer, name, text []byte, flags int)
|
||||||
|
TitleBlock(out *bytes.Buffer, text []byte)
|
||||||
|
|
||||||
|
// Span-level callbacks
|
||||||
|
AutoLink(out *bytes.Buffer, link []byte, kind int)
|
||||||
|
CodeSpan(out *bytes.Buffer, text []byte)
|
||||||
|
DoubleEmphasis(out *bytes.Buffer, text []byte)
|
||||||
|
Emphasis(out *bytes.Buffer, text []byte)
|
||||||
|
Image(out *bytes.Buffer, link []byte, title []byte, alt []byte)
|
||||||
|
LineBreak(out *bytes.Buffer)
|
||||||
|
Link(out *bytes.Buffer, link []byte, title []byte, content []byte)
|
||||||
|
RawHtmlTag(out *bytes.Buffer, tag []byte)
|
||||||
|
TripleEmphasis(out *bytes.Buffer, text []byte)
|
||||||
|
StrikeThrough(out *bytes.Buffer, text []byte)
|
||||||
|
FootnoteRef(out *bytes.Buffer, ref []byte, id int)
|
||||||
|
|
||||||
|
// Low-level callbacks
|
||||||
|
Entity(out *bytes.Buffer, entity []byte)
|
||||||
|
NormalText(out *bytes.Buffer, text []byte)
|
||||||
|
|
||||||
|
// Header and footer
|
||||||
|
DocumentHeader(out *bytes.Buffer)
|
||||||
|
DocumentFooter(out *bytes.Buffer)
|
||||||
|
|
||||||
|
GetFlags() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback functions for inline parsing. One such function is defined
|
||||||
|
// for each character that triggers a response when parsing inline data.
|
||||||
|
type inlineParser func(p *parser, out *bytes.Buffer, data []byte, offset int) int
|
||||||
|
|
||||||
|
// Parser holds runtime state used by the parser.
|
||||||
|
// This is constructed by the Markdown function.
|
||||||
|
type parser struct {
|
||||||
|
r Renderer
|
||||||
|
refOverride ReferenceOverrideFunc
|
||||||
|
refs map[string]*reference
|
||||||
|
inlineCallback [256]inlineParser
|
||||||
|
flags int
|
||||||
|
nesting int
|
||||||
|
maxNesting int
|
||||||
|
insideLink bool
|
||||||
|
|
||||||
|
// Footnotes need to be ordered as well as available to quickly check for
|
||||||
|
// presence. If a ref is also a footnote, it's stored both in refs and here
|
||||||
|
// in notes. Slice is nil if footnotes not enabled.
|
||||||
|
notes []*reference
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) getRef(refid string) (ref *reference, found bool) {
|
||||||
|
if p.refOverride != nil {
|
||||||
|
r, overridden := p.refOverride(refid)
|
||||||
|
if overridden {
|
||||||
|
if r == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return &reference{
|
||||||
|
link: []byte(r.Link),
|
||||||
|
title: []byte(r.Title),
|
||||||
|
noteId: 0,
|
||||||
|
hasBlock: false,
|
||||||
|
text: []byte(r.Text)}, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// refs are case insensitive
|
||||||
|
ref, found = p.refs[strings.ToLower(refid)]
|
||||||
|
return ref, found
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Public interface
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
// Reference represents the details of a link.
|
||||||
|
// See the documentation in Options for more details on use-case.
|
||||||
|
type Reference struct {
|
||||||
|
// Link is usually the URL the reference points to.
|
||||||
|
Link string
|
||||||
|
// Title is the alternate text describing the link in more detail.
|
||||||
|
Title string
|
||||||
|
// Text is the optional text to override the ref with if the syntax used was
|
||||||
|
// [refid][]
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReferenceOverrideFunc is expected to be called with a reference string and
|
||||||
|
// return either a valid Reference type that the reference string maps to or
|
||||||
|
// nil. If overridden is false, the default reference logic will be executed.
|
||||||
|
// See the documentation in Options for more details on use-case.
|
||||||
|
type ReferenceOverrideFunc func(reference string) (ref *Reference, overridden bool)
|
||||||
|
|
||||||
|
// Options represents configurable overrides and callbacks (in addition to the
|
||||||
|
// extension flag set) for configuring a Markdown parse.
|
||||||
|
type Options struct {
|
||||||
|
// Extensions is a flag set of bit-wise ORed extension bits. See the
|
||||||
|
// EXTENSION_* flags defined in this package.
|
||||||
|
Extensions int
|
||||||
|
|
||||||
|
// ReferenceOverride is an optional function callback that is called every
|
||||||
|
// time a reference is resolved.
|
||||||
|
//
|
||||||
|
// In Markdown, the link reference syntax can be made to resolve a link to
|
||||||
|
// a reference instead of an inline URL, in one of the following ways:
|
||||||
|
//
|
||||||
|
// * [link text][refid]
|
||||||
|
// * [refid][]
|
||||||
|
//
|
||||||
|
// Usually, the refid is defined at the bottom of the Markdown document. If
|
||||||
|
// this override function is provided, the refid is passed to the override
|
||||||
|
// function first, before consulting the defined refids at the bottom. If
|
||||||
|
// the override function indicates an override did not occur, the refids at
|
||||||
|
// the bottom will be used to fill in the link details.
|
||||||
|
ReferenceOverride ReferenceOverrideFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarkdownBasic is a convenience function for simple rendering.
|
||||||
|
// It processes markdown input with no extensions enabled.
|
||||||
|
func MarkdownBasic(input []byte) []byte {
|
||||||
|
// set up the HTML renderer
|
||||||
|
htmlFlags := HTML_USE_XHTML
|
||||||
|
renderer := HtmlRenderer(htmlFlags, "", "")
|
||||||
|
|
||||||
|
// set up the parser
|
||||||
|
return MarkdownOptions(input, renderer, Options{Extensions: 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call Markdown with most useful extensions enabled
|
||||||
|
// MarkdownCommon is a convenience function for simple rendering.
|
||||||
|
// It processes markdown input with common extensions enabled, including:
|
||||||
|
//
|
||||||
|
// * Smartypants processing with smart fractions and LaTeX dashes
|
||||||
|
//
|
||||||
|
// * Intra-word emphasis suppression
|
||||||
|
//
|
||||||
|
// * Tables
|
||||||
|
//
|
||||||
|
// * Fenced code blocks
|
||||||
|
//
|
||||||
|
// * Autolinking
|
||||||
|
//
|
||||||
|
// * Strikethrough support
|
||||||
|
//
|
||||||
|
// * Strict header parsing
|
||||||
|
//
|
||||||
|
// * Custom Header IDs
|
||||||
|
func MarkdownCommon(input []byte) []byte {
|
||||||
|
// set up the HTML renderer
|
||||||
|
renderer := HtmlRenderer(commonHtmlFlags, "", "")
|
||||||
|
return MarkdownOptions(input, renderer, Options{
|
||||||
|
Extensions: commonExtensions})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Markdown is the main rendering function.
|
||||||
|
// It parses and renders a block of markdown-encoded text.
|
||||||
|
// The supplied Renderer is used to format the output, and extensions dictates
|
||||||
|
// which non-standard extensions are enabled.
|
||||||
|
//
|
||||||
|
// To use the supplied Html or LaTeX renderers, see HtmlRenderer and
|
||||||
|
// LatexRenderer, respectively.
|
||||||
|
func Markdown(input []byte, renderer Renderer, extensions int) []byte {
|
||||||
|
return MarkdownOptions(input, renderer, Options{
|
||||||
|
Extensions: extensions})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarkdownOptions is just like Markdown but takes additional options through
|
||||||
|
// the Options struct.
|
||||||
|
func MarkdownOptions(input []byte, renderer Renderer, opts Options) []byte {
|
||||||
|
// no point in parsing if we can't render
|
||||||
|
if renderer == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions := opts.Extensions
|
||||||
|
|
||||||
|
// fill in the render structure
|
||||||
|
p := new(parser)
|
||||||
|
p.r = renderer
|
||||||
|
p.flags = extensions
|
||||||
|
p.refOverride = opts.ReferenceOverride
|
||||||
|
p.refs = make(map[string]*reference)
|
||||||
|
p.maxNesting = 16
|
||||||
|
p.insideLink = false
|
||||||
|
|
||||||
|
// register inline parsers
|
||||||
|
p.inlineCallback['*'] = emphasis
|
||||||
|
p.inlineCallback['_'] = emphasis
|
||||||
|
if extensions&EXTENSION_STRIKETHROUGH != 0 {
|
||||||
|
p.inlineCallback['~'] = emphasis
|
||||||
|
}
|
||||||
|
p.inlineCallback['`'] = codeSpan
|
||||||
|
p.inlineCallback['\n'] = lineBreak
|
||||||
|
p.inlineCallback['['] = link
|
||||||
|
p.inlineCallback['<'] = leftAngle
|
||||||
|
p.inlineCallback['\\'] = escape
|
||||||
|
p.inlineCallback['&'] = entity
|
||||||
|
|
||||||
|
if extensions&EXTENSION_AUTOLINK != 0 {
|
||||||
|
p.inlineCallback[':'] = autoLink
|
||||||
|
}
|
||||||
|
|
||||||
|
if extensions&EXTENSION_FOOTNOTES != 0 {
|
||||||
|
p.notes = make([]*reference, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
first := firstPass(p, input)
|
||||||
|
second := secondPass(p, first)
|
||||||
|
return second
|
||||||
|
}
|
||||||
|
|
||||||
|
// first pass:
|
||||||
|
// - extract references
|
||||||
|
// - expand tabs
|
||||||
|
// - normalize newlines
|
||||||
|
// - copy everything else
|
||||||
|
func firstPass(p *parser, input []byte) []byte {
|
||||||
|
var out bytes.Buffer
|
||||||
|
tabSize := TAB_SIZE_DEFAULT
|
||||||
|
if p.flags&EXTENSION_TAB_SIZE_EIGHT != 0 {
|
||||||
|
tabSize = TAB_SIZE_EIGHT
|
||||||
|
}
|
||||||
|
beg, end := 0, 0
|
||||||
|
lastFencedCodeBlockEnd := 0
|
||||||
|
for beg < len(input) { // iterate over lines
|
||||||
|
if end = isReference(p, input[beg:], tabSize); end > 0 {
|
||||||
|
beg += end
|
||||||
|
} else { // skip to the next line
|
||||||
|
end = beg
|
||||||
|
for end < len(input) && input[end] != '\n' && input[end] != '\r' {
|
||||||
|
end++
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.flags&EXTENSION_FENCED_CODE != 0 {
|
||||||
|
// track fenced code block boundaries to suppress tab expansion
|
||||||
|
// inside them:
|
||||||
|
if beg >= lastFencedCodeBlockEnd {
|
||||||
|
if i := p.fencedCode(&out, input[beg:], false); i > 0 {
|
||||||
|
lastFencedCodeBlockEnd = beg + i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the line body if present
|
||||||
|
if end > beg {
|
||||||
|
if end < lastFencedCodeBlockEnd { // Do not expand tabs while inside fenced code blocks.
|
||||||
|
out.Write(input[beg:end])
|
||||||
|
} else {
|
||||||
|
expandTabs(&out, input[beg:end], tabSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.WriteByte('\n')
|
||||||
|
|
||||||
|
if end < len(input) && input[end] == '\r' {
|
||||||
|
end++
|
||||||
|
}
|
||||||
|
if end < len(input) && input[end] == '\n' {
|
||||||
|
end++
|
||||||
|
}
|
||||||
|
|
||||||
|
beg = end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// empty input?
|
||||||
|
if out.Len() == 0 {
|
||||||
|
out.WriteByte('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// second pass: actual rendering
|
||||||
|
func secondPass(p *parser, input []byte) []byte {
|
||||||
|
var output bytes.Buffer
|
||||||
|
|
||||||
|
p.r.DocumentHeader(&output)
|
||||||
|
p.block(&output, input)
|
||||||
|
|
||||||
|
if p.flags&EXTENSION_FOOTNOTES != 0 && len(p.notes) > 0 {
|
||||||
|
p.r.Footnotes(&output, func() bool {
|
||||||
|
flags := LIST_ITEM_BEGINNING_OF_LIST
|
||||||
|
for i := 0; i < len(p.notes); i += 1 {
|
||||||
|
ref := p.notes[i]
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if ref.hasBlock {
|
||||||
|
flags |= LIST_ITEM_CONTAINS_BLOCK
|
||||||
|
p.block(&buf, ref.title)
|
||||||
|
} else {
|
||||||
|
p.inline(&buf, ref.title)
|
||||||
|
}
|
||||||
|
p.r.FootnoteItem(&output, ref.link, buf.Bytes(), flags)
|
||||||
|
flags &^= LIST_ITEM_BEGINNING_OF_LIST | LIST_ITEM_CONTAINS_BLOCK
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
p.r.DocumentFooter(&output)
|
||||||
|
|
||||||
|
if p.nesting != 0 {
|
||||||
|
panic("Nesting level did not end at zero")
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Link references
|
||||||
|
//
|
||||||
|
// This section implements support for references that (usually) appear
|
||||||
|
// as footnotes in a document, and can be referenced anywhere in the document.
|
||||||
|
// The basic format is:
|
||||||
|
//
|
||||||
|
// [1]: http://www.google.com/ "Google"
|
||||||
|
// [2]: http://www.github.com/ "Github"
|
||||||
|
//
|
||||||
|
// Anywhere in the document, the reference can be linked by referring to its
|
||||||
|
// label, i.e., 1 and 2 in this example, as in:
|
||||||
|
//
|
||||||
|
// This library is hosted on [Github][2], a git hosting site.
|
||||||
|
//
|
||||||
|
// Actual footnotes as specified in Pandoc and supported by some other Markdown
|
||||||
|
// libraries such as php-markdown are also taken care of. They look like this:
|
||||||
|
//
|
||||||
|
// This sentence needs a bit of further explanation.[^note]
|
||||||
|
//
|
||||||
|
// [^note]: This is the explanation.
|
||||||
|
//
|
||||||
|
// Footnotes should be placed at the end of the document in an ordered list.
|
||||||
|
// Inline footnotes such as:
|
||||||
|
//
|
||||||
|
// Inline footnotes^[Not supported.] also exist.
|
||||||
|
//
|
||||||
|
// are not yet supported.
|
||||||
|
|
||||||
|
// References are parsed and stored in this struct.
|
||||||
|
type reference struct {
|
||||||
|
link []byte
|
||||||
|
title []byte
|
||||||
|
noteId int // 0 if not a footnote ref
|
||||||
|
hasBlock bool
|
||||||
|
text []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reference) String() string {
|
||||||
|
return fmt.Sprintf("{link: %q, title: %q, text: %q, noteId: %d, hasBlock: %v}",
|
||||||
|
r.link, r.title, r.text, r.noteId, r.hasBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether or not data starts with a reference link.
|
||||||
|
// If so, it is parsed and stored in the list of references
|
||||||
|
// (in the render struct).
|
||||||
|
// Returns the number of bytes to skip to move past it,
|
||||||
|
// or zero if the first line is not a reference.
|
||||||
|
func isReference(p *parser, data []byte, tabSize int) int {
|
||||||
|
// up to 3 optional leading spaces
|
||||||
|
if len(data) < 4 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
i := 0
|
||||||
|
for i < 3 && data[i] == ' ' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
noteId := 0
|
||||||
|
|
||||||
|
// id part: anything but a newline between brackets
|
||||||
|
if data[i] != '[' {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
if p.flags&EXTENSION_FOOTNOTES != 0 {
|
||||||
|
if i < len(data) && data[i] == '^' {
|
||||||
|
// we can set it to anything here because the proper noteIds will
|
||||||
|
// be assigned later during the second pass. It just has to be != 0
|
||||||
|
noteId = 1
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
idOffset := i
|
||||||
|
for i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != ']' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i >= len(data) || data[i] != ']' {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
idEnd := i
|
||||||
|
|
||||||
|
// spacer: colon (space | tab)* newline? (space | tab)*
|
||||||
|
i++
|
||||||
|
if i >= len(data) || data[i] != ':' {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i < len(data) && (data[i] == '\n' || data[i] == '\r') {
|
||||||
|
i++
|
||||||
|
if i < len(data) && data[i] == '\n' && data[i-1] == '\r' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i >= len(data) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
linkOffset, linkEnd int
|
||||||
|
titleOffset, titleEnd int
|
||||||
|
lineEnd int
|
||||||
|
raw []byte
|
||||||
|
hasBlock bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if p.flags&EXTENSION_FOOTNOTES != 0 && noteId != 0 {
|
||||||
|
linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize)
|
||||||
|
lineEnd = linkEnd
|
||||||
|
} else {
|
||||||
|
linkOffset, linkEnd, titleOffset, titleEnd, lineEnd = scanLinkRef(p, data, i)
|
||||||
|
}
|
||||||
|
if lineEnd == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// a valid ref has been found
|
||||||
|
|
||||||
|
ref := &reference{
|
||||||
|
noteId: noteId,
|
||||||
|
hasBlock: hasBlock,
|
||||||
|
}
|
||||||
|
|
||||||
|
if noteId > 0 {
|
||||||
|
// reusing the link field for the id since footnotes don't have links
|
||||||
|
ref.link = data[idOffset:idEnd]
|
||||||
|
// if footnote, it's not really a title, it's the contained text
|
||||||
|
ref.title = raw
|
||||||
|
} else {
|
||||||
|
ref.link = data[linkOffset:linkEnd]
|
||||||
|
ref.title = data[titleOffset:titleEnd]
|
||||||
|
}
|
||||||
|
|
||||||
|
// id matches are case-insensitive
|
||||||
|
id := string(bytes.ToLower(data[idOffset:idEnd]))
|
||||||
|
|
||||||
|
p.refs[id] = ref
|
||||||
|
|
||||||
|
return lineEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanLinkRef(p *parser, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) {
|
||||||
|
// link: whitespace-free sequence, optionally between angle brackets
|
||||||
|
if data[i] == '<' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
linkOffset = i
|
||||||
|
for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i == len(data) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
linkEnd = i
|
||||||
|
if data[linkOffset] == '<' && data[linkEnd-1] == '>' {
|
||||||
|
linkOffset++
|
||||||
|
linkEnd--
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional spacer: (space | tab)* (newline | '\'' | '"' | '(' )
|
||||||
|
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(' {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute end-of-line
|
||||||
|
if i >= len(data) || data[i] == '\r' || data[i] == '\n' {
|
||||||
|
lineEnd = i
|
||||||
|
}
|
||||||
|
if i+1 < len(data) && data[i] == '\r' && data[i+1] == '\n' {
|
||||||
|
lineEnd++
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional (space|tab)* spacer after a newline
|
||||||
|
if lineEnd > 0 {
|
||||||
|
i = lineEnd + 1
|
||||||
|
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional title: any non-newline sequence enclosed in '"() alone on its line
|
||||||
|
if i+1 < len(data) && (data[i] == '\'' || data[i] == '"' || data[i] == '(') {
|
||||||
|
i++
|
||||||
|
titleOffset = i
|
||||||
|
|
||||||
|
// look for EOL
|
||||||
|
for i < len(data) && data[i] != '\n' && data[i] != '\r' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i+1 < len(data) && data[i] == '\n' && data[i+1] == '\r' {
|
||||||
|
titleEnd = i + 1
|
||||||
|
} else {
|
||||||
|
titleEnd = i
|
||||||
|
}
|
||||||
|
|
||||||
|
// step back
|
||||||
|
i--
|
||||||
|
for i > titleOffset && (data[i] == ' ' || data[i] == '\t') {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
if i > titleOffset && (data[i] == '\'' || data[i] == '"' || data[i] == ')') {
|
||||||
|
lineEnd = titleEnd
|
||||||
|
titleEnd = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first bit of this logic is the same as (*parser).listItem, but the rest
|
||||||
|
// is much simpler. This function simply finds the entire block and shifts it
|
||||||
|
// over by one tab if it is indeed a block (just returns the line if it's not).
|
||||||
|
// blockEnd is the end of the section in the input buffer, and contents is the
|
||||||
|
// extracted text that was shifted over one tab. It will need to be rendered at
|
||||||
|
// the end of the document.
|
||||||
|
func scanFootnote(p *parser, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) {
|
||||||
|
if i == 0 || len(data) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip leading whitespace on first line
|
||||||
|
for i < len(data) && data[i] == ' ' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
blockStart = i
|
||||||
|
|
||||||
|
// find the end of the line
|
||||||
|
blockEnd = i
|
||||||
|
for i < len(data) && data[i-1] != '\n' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
// get working buffer
|
||||||
|
var raw bytes.Buffer
|
||||||
|
|
||||||
|
// put the first line into the working buffer
|
||||||
|
raw.Write(data[blockEnd:i])
|
||||||
|
blockEnd = i
|
||||||
|
|
||||||
|
// process the following lines
|
||||||
|
containsBlankLine := false
|
||||||
|
|
||||||
|
gatherLines:
|
||||||
|
for blockEnd < len(data) {
|
||||||
|
i++
|
||||||
|
|
||||||
|
// find the end of this line
|
||||||
|
for i < len(data) && data[i-1] != '\n' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it is an empty line, guess that it is part of this item
|
||||||
|
// and move on to the next line
|
||||||
|
if p.isEmpty(data[blockEnd:i]) > 0 {
|
||||||
|
containsBlankLine = true
|
||||||
|
blockEnd = i
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
n := 0
|
||||||
|
if n = isIndented(data[blockEnd:i], indentSize); n == 0 {
|
||||||
|
// this is the end of the block.
|
||||||
|
// we don't want to include this last line in the index.
|
||||||
|
break gatherLines
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there were blank lines before this one, insert a new one now
|
||||||
|
if containsBlankLine {
|
||||||
|
raw.WriteByte('\n')
|
||||||
|
containsBlankLine = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// get rid of that first tab, write to buffer
|
||||||
|
raw.Write(data[blockEnd+n : i])
|
||||||
|
hasBlock = true
|
||||||
|
|
||||||
|
blockEnd = i
|
||||||
|
}
|
||||||
|
|
||||||
|
if data[blockEnd-1] != '\n' {
|
||||||
|
raw.WriteByte('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
contents = raw.Bytes()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Miscellaneous helper functions
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
// Test if a character is a punctuation symbol.
|
||||||
|
// Taken from a private function in regexp in the stdlib.
|
||||||
|
func ispunct(c byte) bool {
|
||||||
|
for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") {
|
||||||
|
if c == r {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if a character is a whitespace character.
|
||||||
|
func isspace(c byte) bool {
|
||||||
|
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if a character is letter.
|
||||||
|
func isletter(c byte) bool {
|
||||||
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if a character is a letter or a digit.
|
||||||
|
// TODO: check when this is looking for ASCII alnum and when it should use unicode
|
||||||
|
func isalnum(c byte) bool {
|
||||||
|
return (c >= '0' && c <= '9') || isletter(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace tab characters with spaces, aligning to the next TAB_SIZE column.
|
||||||
|
// always ends output with a newline
|
||||||
|
func expandTabs(out *bytes.Buffer, line []byte, tabSize int) {
|
||||||
|
// first, check for common cases: no tabs, or only tabs at beginning of line
|
||||||
|
i, prefix := 0, 0
|
||||||
|
slowcase := false
|
||||||
|
for i = 0; i < len(line); i++ {
|
||||||
|
if line[i] == '\t' {
|
||||||
|
if prefix == i {
|
||||||
|
prefix++
|
||||||
|
} else {
|
||||||
|
slowcase = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no need to decode runes if all tabs are at the beginning of the line
|
||||||
|
if !slowcase {
|
||||||
|
for i = 0; i < prefix*tabSize; i++ {
|
||||||
|
out.WriteByte(' ')
|
||||||
|
}
|
||||||
|
out.Write(line[prefix:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// the slow case: we need to count runes to figure out how
|
||||||
|
// many spaces to insert for each tab
|
||||||
|
column := 0
|
||||||
|
i = 0
|
||||||
|
for i < len(line) {
|
||||||
|
start := i
|
||||||
|
for i < len(line) && line[i] != '\t' {
|
||||||
|
_, size := utf8.DecodeRune(line[i:])
|
||||||
|
i += size
|
||||||
|
column++
|
||||||
|
}
|
||||||
|
|
||||||
|
if i > start {
|
||||||
|
out.Write(line[start:i])
|
||||||
|
}
|
||||||
|
|
||||||
|
if i >= len(line) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
out.WriteByte(' ')
|
||||||
|
column++
|
||||||
|
if column%tabSize == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find if a line counts as indented or not.
|
||||||
|
// Returns number of characters the indent is (0 = not indented).
|
||||||
|
func isIndented(data []byte, indentSize int) int {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if data[0] == '\t' {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if len(data) < indentSize {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
for i := 0; i < indentSize; i++ {
|
||||||
|
if data[i] != ' ' {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return indentSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a url-safe slug for fragments
|
||||||
|
func slugify(in []byte) []byte {
|
||||||
|
if len(in) == 0 {
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
out := make([]byte, 0, len(in))
|
||||||
|
sym := false
|
||||||
|
|
||||||
|
for _, ch := range in {
|
||||||
|
if isalnum(ch) {
|
||||||
|
sym = false
|
||||||
|
out = append(out, ch)
|
||||||
|
} else if sym {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
out = append(out, '-')
|
||||||
|
sym = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var a, b int
|
||||||
|
var ch byte
|
||||||
|
for a, ch = range out {
|
||||||
|
if ch != '-' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for b = len(out) - 1; b > 0; b-- {
|
||||||
|
if out[b] != '-' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out[a : b+1]
|
||||||
|
}
|
128
vendor/github.com/russross/blackfriday/ref_test.go
generated
vendored
Normal file
128
vendor/github.com/russross/blackfriday/ref_test.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
//
|
||||||
|
// Blackfriday Markdown Processor
|
||||||
|
// Available at http://github.com/russross/blackfriday
|
||||||
|
//
|
||||||
|
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
||||||
|
// Distributed under the Simplified BSD License.
|
||||||
|
// See README.md for details.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Markdown 1.0.3 reference tests
|
||||||
|
//
|
||||||
|
|
||||||
|
package blackfriday
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func runMarkdownReference(input string, flag int) string {
|
||||||
|
renderer := HtmlRenderer(0, "", "")
|
||||||
|
return string(Markdown([]byte(input), renderer, flag))
|
||||||
|
}
|
||||||
|
|
||||||
|
func doTestsReference(t *testing.T, files []string, flag int) {
|
||||||
|
// catch and report panics
|
||||||
|
var candidate string
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
t.Errorf("\npanic while processing [%#v]\n", candidate)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, basename := range files {
|
||||||
|
filename := filepath.Join("testdata", basename+".text")
|
||||||
|
inputBytes, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
input := string(inputBytes)
|
||||||
|
|
||||||
|
filename = filepath.Join("testdata", basename+".html")
|
||||||
|
expectedBytes, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
expected := string(expectedBytes)
|
||||||
|
|
||||||
|
// fmt.Fprintf(os.Stderr, "processing %s ...", filename)
|
||||||
|
actual := string(runMarkdownReference(input, flag))
|
||||||
|
if actual != expected {
|
||||||
|
t.Errorf("\n [%#v]\nExpected[%#v]\nActual [%#v]",
|
||||||
|
basename+".text", expected, actual)
|
||||||
|
}
|
||||||
|
// fmt.Fprintf(os.Stderr, " ok\n")
|
||||||
|
|
||||||
|
// now test every prefix of every input to check for
|
||||||
|
// bounds checking
|
||||||
|
if !testing.Short() {
|
||||||
|
start, max := 0, len(input)
|
||||||
|
for end := start + 1; end <= max; end++ {
|
||||||
|
candidate = input[start:end]
|
||||||
|
// fmt.Fprintf(os.Stderr, " %s %d:%d/%d\n", filename, start, end, max)
|
||||||
|
_ = runMarkdownReference(candidate, flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReference(t *testing.T) {
|
||||||
|
files := []string{
|
||||||
|
"Amps and angle encoding",
|
||||||
|
"Auto links",
|
||||||
|
"Backslash escapes",
|
||||||
|
"Blockquotes with code blocks",
|
||||||
|
"Code Blocks",
|
||||||
|
"Code Spans",
|
||||||
|
"Hard-wrapped paragraphs with list-like lines",
|
||||||
|
"Horizontal rules",
|
||||||
|
"Inline HTML (Advanced)",
|
||||||
|
"Inline HTML (Simple)",
|
||||||
|
"Inline HTML comments",
|
||||||
|
"Links, inline style",
|
||||||
|
"Links, reference style",
|
||||||
|
"Links, shortcut references",
|
||||||
|
"Literal quotes in titles",
|
||||||
|
"Markdown Documentation - Basics",
|
||||||
|
"Markdown Documentation - Syntax",
|
||||||
|
"Nested blockquotes",
|
||||||
|
"Ordered and unordered lists",
|
||||||
|
"Strong and em together",
|
||||||
|
"Tabs",
|
||||||
|
"Tidyness",
|
||||||
|
}
|
||||||
|
doTestsReference(t, files, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReference_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) {
|
||||||
|
files := []string{
|
||||||
|
"Amps and angle encoding",
|
||||||
|
"Auto links",
|
||||||
|
"Backslash escapes",
|
||||||
|
"Blockquotes with code blocks",
|
||||||
|
"Code Blocks",
|
||||||
|
"Code Spans",
|
||||||
|
"Hard-wrapped paragraphs with list-like lines no empty line before block",
|
||||||
|
"Horizontal rules",
|
||||||
|
"Inline HTML (Advanced)",
|
||||||
|
"Inline HTML (Simple)",
|
||||||
|
"Inline HTML comments",
|
||||||
|
"Links, inline style",
|
||||||
|
"Links, reference style",
|
||||||
|
"Links, shortcut references",
|
||||||
|
"Literal quotes in titles",
|
||||||
|
"Markdown Documentation - Basics",
|
||||||
|
"Markdown Documentation - Syntax",
|
||||||
|
"Nested blockquotes",
|
||||||
|
"Ordered and unordered lists",
|
||||||
|
"Strong and em together",
|
||||||
|
"Tabs",
|
||||||
|
"Tidyness",
|
||||||
|
}
|
||||||
|
doTestsReference(t, files, EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK)
|
||||||
|
}
|
400
vendor/github.com/russross/blackfriday/smartypants.go
generated
vendored
Normal file
400
vendor/github.com/russross/blackfriday/smartypants.go
generated
vendored
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
//
|
||||||
|
// Blackfriday Markdown Processor
|
||||||
|
// Available at http://github.com/russross/blackfriday
|
||||||
|
//
|
||||||
|
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
||||||
|
// Distributed under the Simplified BSD License.
|
||||||
|
// See README.md for details.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// SmartyPants rendering
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
package blackfriday
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type smartypantsData struct {
|
||||||
|
inSingleQuote bool
|
||||||
|
inDoubleQuote bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func wordBoundary(c byte) bool {
|
||||||
|
return c == 0 || isspace(c) || ispunct(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tolower(c byte) byte {
|
||||||
|
if c >= 'A' && c <= 'Z' {
|
||||||
|
return c - 'A' + 'a'
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func isdigit(c byte) bool {
|
||||||
|
return c >= '0' && c <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool) bool {
|
||||||
|
// edge of the buffer is likely to be a tag that we don't get to see,
|
||||||
|
// so we treat it like text sometimes
|
||||||
|
|
||||||
|
// enumerate all sixteen possibilities for (previousChar, nextChar)
|
||||||
|
// each can be one of {0, space, punct, other}
|
||||||
|
switch {
|
||||||
|
case previousChar == 0 && nextChar == 0:
|
||||||
|
// context is not any help here, so toggle
|
||||||
|
*isOpen = !*isOpen
|
||||||
|
case isspace(previousChar) && nextChar == 0:
|
||||||
|
// [ "] might be [ "<code>foo...]
|
||||||
|
*isOpen = true
|
||||||
|
case ispunct(previousChar) && nextChar == 0:
|
||||||
|
// [!"] hmm... could be [Run!"] or [("<code>...]
|
||||||
|
*isOpen = false
|
||||||
|
case /* isnormal(previousChar) && */ nextChar == 0:
|
||||||
|
// [a"] is probably a close
|
||||||
|
*isOpen = false
|
||||||
|
case previousChar == 0 && isspace(nextChar):
|
||||||
|
// [" ] might be [...foo</code>" ]
|
||||||
|
*isOpen = false
|
||||||
|
case isspace(previousChar) && isspace(nextChar):
|
||||||
|
// [ " ] context is not any help here, so toggle
|
||||||
|
*isOpen = !*isOpen
|
||||||
|
case ispunct(previousChar) && isspace(nextChar):
|
||||||
|
// [!" ] is probably a close
|
||||||
|
*isOpen = false
|
||||||
|
case /* isnormal(previousChar) && */ isspace(nextChar):
|
||||||
|
// [a" ] this is one of the easy cases
|
||||||
|
*isOpen = false
|
||||||
|
case previousChar == 0 && ispunct(nextChar):
|
||||||
|
// ["!] hmm... could be ["$1.95] or [</code>"!...]
|
||||||
|
*isOpen = false
|
||||||
|
case isspace(previousChar) && ispunct(nextChar):
|
||||||
|
// [ "!] looks more like [ "$1.95]
|
||||||
|
*isOpen = true
|
||||||
|
case ispunct(previousChar) && ispunct(nextChar):
|
||||||
|
// [!"!] context is not any help here, so toggle
|
||||||
|
*isOpen = !*isOpen
|
||||||
|
case /* isnormal(previousChar) && */ ispunct(nextChar):
|
||||||
|
// [a"!] is probably a close
|
||||||
|
*isOpen = false
|
||||||
|
case previousChar == 0 /* && isnormal(nextChar) */ :
|
||||||
|
// ["a] is probably an open
|
||||||
|
*isOpen = true
|
||||||
|
case isspace(previousChar) /* && isnormal(nextChar) */ :
|
||||||
|
// [ "a] this is one of the easy cases
|
||||||
|
*isOpen = true
|
||||||
|
case ispunct(previousChar) /* && isnormal(nextChar) */ :
|
||||||
|
// [!"a] is probably an open
|
||||||
|
*isOpen = true
|
||||||
|
default:
|
||||||
|
// [a'b] maybe a contraction?
|
||||||
|
*isOpen = false
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteByte('&')
|
||||||
|
if *isOpen {
|
||||||
|
out.WriteByte('l')
|
||||||
|
} else {
|
||||||
|
out.WriteByte('r')
|
||||||
|
}
|
||||||
|
out.WriteByte(quote)
|
||||||
|
out.WriteString("quo;")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartSingleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
if len(text) >= 2 {
|
||||||
|
t1 := tolower(text[1])
|
||||||
|
|
||||||
|
if t1 == '\'' {
|
||||||
|
nextChar := byte(0)
|
||||||
|
if len(text) >= 3 {
|
||||||
|
nextChar = text[2]
|
||||||
|
}
|
||||||
|
if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && (len(text) < 3 || wordBoundary(text[2])) {
|
||||||
|
out.WriteString("’")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(text) >= 3 {
|
||||||
|
t2 := tolower(text[2])
|
||||||
|
|
||||||
|
if ((t1 == 'r' && t2 == 'e') || (t1 == 'l' && t2 == 'l') || (t1 == 'v' && t2 == 'e')) &&
|
||||||
|
(len(text) < 4 || wordBoundary(text[3])) {
|
||||||
|
out.WriteString("’")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextChar := byte(0)
|
||||||
|
if len(text) > 1 {
|
||||||
|
nextChar = text[1]
|
||||||
|
}
|
||||||
|
if smartQuoteHelper(out, previousChar, nextChar, 's', &smrt.inSingleQuote) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteByte(text[0])
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartParens(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
if len(text) >= 3 {
|
||||||
|
t1 := tolower(text[1])
|
||||||
|
t2 := tolower(text[2])
|
||||||
|
|
||||||
|
if t1 == 'c' && t2 == ')' {
|
||||||
|
out.WriteString("©")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if t1 == 'r' && t2 == ')' {
|
||||||
|
out.WriteString("®")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(text) >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')' {
|
||||||
|
out.WriteString("™")
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteByte(text[0])
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartDash(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
if len(text) >= 2 {
|
||||||
|
if text[1] == '-' {
|
||||||
|
out.WriteString("—")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if wordBoundary(previousChar) && wordBoundary(text[1]) {
|
||||||
|
out.WriteString("–")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteByte(text[0])
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartDashLatex(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
if len(text) >= 3 && text[1] == '-' && text[2] == '-' {
|
||||||
|
out.WriteString("—")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
if len(text) >= 2 && text[1] == '-' {
|
||||||
|
out.WriteString("–")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteByte(text[0])
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartAmpVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int {
|
||||||
|
if bytes.HasPrefix(text, []byte(""")) {
|
||||||
|
nextChar := byte(0)
|
||||||
|
if len(text) >= 7 {
|
||||||
|
nextChar = text[6]
|
||||||
|
}
|
||||||
|
if smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) {
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.HasPrefix(text, []byte("�")) {
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteByte('&')
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartAmp(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
return smartAmpVariant(out, smrt, previousChar, text, 'd')
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartAmpAngledQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
return smartAmpVariant(out, smrt, previousChar, text, 'a')
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartPeriod(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
if len(text) >= 3 && text[1] == '.' && text[2] == '.' {
|
||||||
|
out.WriteString("…")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(text) >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.' {
|
||||||
|
out.WriteString("…")
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteByte(text[0])
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartBacktick(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
if len(text) >= 2 && text[1] == '`' {
|
||||||
|
nextChar := byte(0)
|
||||||
|
if len(text) >= 3 {
|
||||||
|
nextChar = text[2]
|
||||||
|
}
|
||||||
|
if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteByte(text[0])
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartNumberGeneric(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
|
||||||
|
// is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b
|
||||||
|
// note: check for regular slash (/) or fraction slash (⁄, 0x2044, or 0xe2 81 84 in utf-8)
|
||||||
|
// and avoid changing dates like 1/23/2005 into fractions.
|
||||||
|
numEnd := 0
|
||||||
|
for len(text) > numEnd && isdigit(text[numEnd]) {
|
||||||
|
numEnd++
|
||||||
|
}
|
||||||
|
if numEnd == 0 {
|
||||||
|
out.WriteByte(text[0])
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
denStart := numEnd + 1
|
||||||
|
if len(text) > numEnd+3 && text[numEnd] == 0xe2 && text[numEnd+1] == 0x81 && text[numEnd+2] == 0x84 {
|
||||||
|
denStart = numEnd + 3
|
||||||
|
} else if len(text) < numEnd+2 || text[numEnd] != '/' {
|
||||||
|
out.WriteByte(text[0])
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
denEnd := denStart
|
||||||
|
for len(text) > denEnd && isdigit(text[denEnd]) {
|
||||||
|
denEnd++
|
||||||
|
}
|
||||||
|
if denEnd == denStart {
|
||||||
|
out.WriteByte(text[0])
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if len(text) == denEnd || wordBoundary(text[denEnd]) && text[denEnd] != '/' {
|
||||||
|
out.WriteString("<sup>")
|
||||||
|
out.Write(text[:numEnd])
|
||||||
|
out.WriteString("</sup>⁄<sub>")
|
||||||
|
out.Write(text[denStart:denEnd])
|
||||||
|
out.WriteString("</sub>")
|
||||||
|
return denEnd - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteByte(text[0])
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartNumber(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
|
||||||
|
if text[0] == '1' && text[1] == '/' && text[2] == '2' {
|
||||||
|
if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' {
|
||||||
|
out.WriteString("½")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if text[0] == '1' && text[1] == '/' && text[2] == '4' {
|
||||||
|
if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h') {
|
||||||
|
out.WriteString("¼")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if text[0] == '3' && text[1] == '/' && text[2] == '4' {
|
||||||
|
if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's') {
|
||||||
|
out.WriteString("¾")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteByte(text[0])
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartDoubleQuoteVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int {
|
||||||
|
nextChar := byte(0)
|
||||||
|
if len(text) > 1 {
|
||||||
|
nextChar = text[1]
|
||||||
|
}
|
||||||
|
if !smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) {
|
||||||
|
out.WriteString(""")
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'd')
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartAngledDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'a')
|
||||||
|
}
|
||||||
|
|
||||||
|
func smartLeftAngle(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||||
|
i := 0
|
||||||
|
|
||||||
|
for i < len(text) && text[i] != '>' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
out.Write(text[:i+1])
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
type smartCallback func(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int
|
||||||
|
|
||||||
|
type smartypantsRenderer [256]smartCallback
|
||||||
|
|
||||||
|
func smartypants(flags int) *smartypantsRenderer {
|
||||||
|
r := new(smartypantsRenderer)
|
||||||
|
if flags&HTML_SMARTYPANTS_ANGLED_QUOTES == 0 {
|
||||||
|
r['"'] = smartDoubleQuote
|
||||||
|
r['&'] = smartAmp
|
||||||
|
} else {
|
||||||
|
r['"'] = smartAngledDoubleQuote
|
||||||
|
r['&'] = smartAmpAngledQuote
|
||||||
|
}
|
||||||
|
r['\''] = smartSingleQuote
|
||||||
|
r['('] = smartParens
|
||||||
|
if flags&HTML_SMARTYPANTS_DASHES != 0 {
|
||||||
|
if flags&HTML_SMARTYPANTS_LATEX_DASHES == 0 {
|
||||||
|
r['-'] = smartDash
|
||||||
|
} else {
|
||||||
|
r['-'] = smartDashLatex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r['.'] = smartPeriod
|
||||||
|
if flags&HTML_SMARTYPANTS_FRACTIONS == 0 {
|
||||||
|
r['1'] = smartNumber
|
||||||
|
r['3'] = smartNumber
|
||||||
|
} else {
|
||||||
|
for ch := '1'; ch <= '9'; ch++ {
|
||||||
|
r[ch] = smartNumberGeneric
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r['<'] = smartLeftAngle
|
||||||
|
r['`'] = smartBacktick
|
||||||
|
return r
|
||||||
|
}
|
17
vendor/github.com/russross/blackfriday/testdata/Amps and angle encoding.html
generated
vendored
Normal file
17
vendor/github.com/russross/blackfriday/testdata/Amps and angle encoding.html
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<p>AT&T has an ampersand in their name.</p>
|
||||||
|
|
||||||
|
<p>AT&T is another way to write it.</p>
|
||||||
|
|
||||||
|
<p>This & that.</p>
|
||||||
|
|
||||||
|
<p>4 < 5.</p>
|
||||||
|
|
||||||
|
<p>6 > 5.</p>
|
||||||
|
|
||||||
|
<p>Here's a <a href="http://example.com/?foo=1&bar=2">link</a> with an ampersand in the URL.</p>
|
||||||
|
|
||||||
|
<p>Here's a link with an amersand in the link text: <a href="http://att.com/" title="AT&T">AT&T</a>.</p>
|
||||||
|
|
||||||
|
<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>
|
||||||
|
|
||||||
|
<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>
|
21
vendor/github.com/russross/blackfriday/testdata/Amps and angle encoding.text
generated
vendored
Normal file
21
vendor/github.com/russross/blackfriday/testdata/Amps and angle encoding.text
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
AT&T has an ampersand in their name.
|
||||||
|
|
||||||
|
AT&T is another way to write it.
|
||||||
|
|
||||||
|
This & that.
|
||||||
|
|
||||||
|
4 < 5.
|
||||||
|
|
||||||
|
6 > 5.
|
||||||
|
|
||||||
|
Here's a [link] [1] with an ampersand in the URL.
|
||||||
|
|
||||||
|
Here's a link with an amersand in the link text: [AT&T] [2].
|
||||||
|
|
||||||
|
Here's an inline [link](/script?foo=1&bar=2).
|
||||||
|
|
||||||
|
Here's an inline [link](</script?foo=1&bar=2>).
|
||||||
|
|
||||||
|
|
||||||
|
[1]: http://example.com/?foo=1&bar=2
|
||||||
|
[2]: http://att.com/ "AT&T"
|
18
vendor/github.com/russross/blackfriday/testdata/Auto links.html
generated
vendored
Normal file
18
vendor/github.com/russross/blackfriday/testdata/Auto links.html
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<p>Link: <a href="http://example.com/">http://example.com/</a>.</p>
|
||||||
|
|
||||||
|
<p>With an ampersand: <a href="http://example.com/?foo=1&bar=2">http://example.com/?foo=1&bar=2</a></p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>In a list?</li>
|
||||||
|
<li><a href="http://example.com/">http://example.com/</a></li>
|
||||||
|
<li>It should.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<p>Blockquoted: <a href="http://example.com/">http://example.com/</a></p>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>Auto-links should not occur here: <code><http://example.com/></code></p>
|
||||||
|
|
||||||
|
<pre><code>or here: <http://example.com/>
|
||||||
|
</code></pre>
|
13
vendor/github.com/russross/blackfriday/testdata/Auto links.text
generated
vendored
Normal file
13
vendor/github.com/russross/blackfriday/testdata/Auto links.text
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Link: <http://example.com/>.
|
||||||
|
|
||||||
|
With an ampersand: <http://example.com/?foo=1&bar=2>
|
||||||
|
|
||||||
|
* In a list?
|
||||||
|
* <http://example.com/>
|
||||||
|
* It should.
|
||||||
|
|
||||||
|
> Blockquoted: <http://example.com/>
|
||||||
|
|
||||||
|
Auto-links should not occur here: `<http://example.com/>`
|
||||||
|
|
||||||
|
or here: <http://example.com/>
|
123
vendor/github.com/russross/blackfriday/testdata/Backslash escapes.html
generated
vendored
Normal file
123
vendor/github.com/russross/blackfriday/testdata/Backslash escapes.html
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<p>These should all get escaped:</p>
|
||||||
|
|
||||||
|
<p>Backslash: \</p>
|
||||||
|
|
||||||
|
<p>Backtick: `</p>
|
||||||
|
|
||||||
|
<p>Asterisk: *</p>
|
||||||
|
|
||||||
|
<p>Underscore: _</p>
|
||||||
|
|
||||||
|
<p>Left brace: {</p>
|
||||||
|
|
||||||
|
<p>Right brace: }</p>
|
||||||
|
|
||||||
|
<p>Left bracket: [</p>
|
||||||
|
|
||||||
|
<p>Right bracket: ]</p>
|
||||||
|
|
||||||
|
<p>Left paren: (</p>
|
||||||
|
|
||||||
|
<p>Right paren: )</p>
|
||||||
|
|
||||||
|
<p>Greater-than: ></p>
|
||||||
|
|
||||||
|
<p>Hash: #</p>
|
||||||
|
|
||||||
|
<p>Period: .</p>
|
||||||
|
|
||||||
|
<p>Bang: !</p>
|
||||||
|
|
||||||
|
<p>Plus: +</p>
|
||||||
|
|
||||||
|
<p>Minus: -</p>
|
||||||
|
|
||||||
|
<p>Tilde: ~</p>
|
||||||
|
|
||||||
|
<p>These should not, because they occur within a code block:</p>
|
||||||
|
|
||||||
|
<pre><code>Backslash: \\
|
||||||
|
|
||||||
|
Backtick: \`
|
||||||
|
|
||||||
|
Asterisk: \*
|
||||||
|
|
||||||
|
Underscore: \_
|
||||||
|
|
||||||
|
Left brace: \{
|
||||||
|
|
||||||
|
Right brace: \}
|
||||||
|
|
||||||
|
Left bracket: \[
|
||||||
|
|
||||||
|
Right bracket: \]
|
||||||
|
|
||||||
|
Left paren: \(
|
||||||
|
|
||||||
|
Right paren: \)
|
||||||
|
|
||||||
|
Greater-than: \>
|
||||||
|
|
||||||
|
Hash: \#
|
||||||
|
|
||||||
|
Period: \.
|
||||||
|
|
||||||
|
Bang: \!
|
||||||
|
|
||||||
|
Plus: \+
|
||||||
|
|
||||||
|
Minus: \-
|
||||||
|
|
||||||
|
Tilde: \~
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Nor should these, which occur in code spans:</p>
|
||||||
|
|
||||||
|
<p>Backslash: <code>\\</code></p>
|
||||||
|
|
||||||
|
<p>Backtick: <code>\`</code></p>
|
||||||
|
|
||||||
|
<p>Asterisk: <code>\*</code></p>
|
||||||
|
|
||||||
|
<p>Underscore: <code>\_</code></p>
|
||||||
|
|
||||||
|
<p>Left brace: <code>\{</code></p>
|
||||||
|
|
||||||
|
<p>Right brace: <code>\}</code></p>
|
||||||
|
|
||||||
|
<p>Left bracket: <code>\[</code></p>
|
||||||
|
|
||||||
|
<p>Right bracket: <code>\]</code></p>
|
||||||
|
|
||||||
|
<p>Left paren: <code>\(</code></p>
|
||||||
|
|
||||||
|
<p>Right paren: <code>\)</code></p>
|
||||||
|
|
||||||
|
<p>Greater-than: <code>\></code></p>
|
||||||
|
|
||||||
|
<p>Hash: <code>\#</code></p>
|
||||||
|
|
||||||
|
<p>Period: <code>\.</code></p>
|
||||||
|
|
||||||
|
<p>Bang: <code>\!</code></p>
|
||||||
|
|
||||||
|
<p>Plus: <code>\+</code></p>
|
||||||
|
|
||||||
|
<p>Minus: <code>\-</code></p>
|
||||||
|
|
||||||
|
<p>Tilde: <code>\~</code></p>
|
||||||
|
|
||||||
|
<p>These should get escaped, even though they're matching pairs for
|
||||||
|
other Markdown constructs:</p>
|
||||||
|
|
||||||
|
<p>*asterisks*</p>
|
||||||
|
|
||||||
|
<p>_underscores_</p>
|
||||||
|
|
||||||
|
<p>`backticks`</p>
|
||||||
|
|
||||||
|
<p>This is a code span with a literal backslash-backtick sequence: <code>\`</code></p>
|
||||||
|
|
||||||
|
<p>This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.</p>
|
||||||
|
|
||||||
|
<p>This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.</p>
|
126
vendor/github.com/russross/blackfriday/testdata/Backslash escapes.text
generated
vendored
Normal file
126
vendor/github.com/russross/blackfriday/testdata/Backslash escapes.text
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
These should all get escaped:
|
||||||
|
|
||||||
|
Backslash: \\
|
||||||
|
|
||||||
|
Backtick: \`
|
||||||
|
|
||||||
|
Asterisk: \*
|
||||||
|
|
||||||
|
Underscore: \_
|
||||||
|
|
||||||
|
Left brace: \{
|
||||||
|
|
||||||
|
Right brace: \}
|
||||||
|
|
||||||
|
Left bracket: \[
|
||||||
|
|
||||||
|
Right bracket: \]
|
||||||
|
|
||||||
|
Left paren: \(
|
||||||
|
|
||||||
|
Right paren: \)
|
||||||
|
|
||||||
|
Greater-than: \>
|
||||||
|
|
||||||
|
Hash: \#
|
||||||
|
|
||||||
|
Period: \.
|
||||||
|
|
||||||
|
Bang: \!
|
||||||
|
|
||||||
|
Plus: \+
|
||||||
|
|
||||||
|
Minus: \-
|
||||||
|
|
||||||
|
Tilde: \~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
These should not, because they occur within a code block:
|
||||||
|
|
||||||
|
Backslash: \\
|
||||||
|
|
||||||
|
Backtick: \`
|
||||||
|
|
||||||
|
Asterisk: \*
|
||||||
|
|
||||||
|
Underscore: \_
|
||||||
|
|
||||||
|
Left brace: \{
|
||||||
|
|
||||||
|
Right brace: \}
|
||||||
|
|
||||||
|
Left bracket: \[
|
||||||
|
|
||||||
|
Right bracket: \]
|
||||||
|
|
||||||
|
Left paren: \(
|
||||||
|
|
||||||
|
Right paren: \)
|
||||||
|
|
||||||
|
Greater-than: \>
|
||||||
|
|
||||||
|
Hash: \#
|
||||||
|
|
||||||
|
Period: \.
|
||||||
|
|
||||||
|
Bang: \!
|
||||||
|
|
||||||
|
Plus: \+
|
||||||
|
|
||||||
|
Minus: \-
|
||||||
|
|
||||||
|
Tilde: \~
|
||||||
|
|
||||||
|
|
||||||
|
Nor should these, which occur in code spans:
|
||||||
|
|
||||||
|
Backslash: `\\`
|
||||||
|
|
||||||
|
Backtick: `` \` ``
|
||||||
|
|
||||||
|
Asterisk: `\*`
|
||||||
|
|
||||||
|
Underscore: `\_`
|
||||||
|
|
||||||
|
Left brace: `\{`
|
||||||
|
|
||||||
|
Right brace: `\}`
|
||||||
|
|
||||||
|
Left bracket: `\[`
|
||||||
|
|
||||||
|
Right bracket: `\]`
|
||||||
|
|
||||||
|
Left paren: `\(`
|
||||||
|
|
||||||
|
Right paren: `\)`
|
||||||
|
|
||||||
|
Greater-than: `\>`
|
||||||
|
|
||||||
|
Hash: `\#`
|
||||||
|
|
||||||
|
Period: `\.`
|
||||||
|
|
||||||
|
Bang: `\!`
|
||||||
|
|
||||||
|
Plus: `\+`
|
||||||
|
|
||||||
|
Minus: `\-`
|
||||||
|
|
||||||
|
Tilde: `\~`
|
||||||
|
|
||||||
|
|
||||||
|
These should get escaped, even though they're matching pairs for
|
||||||
|
other Markdown constructs:
|
||||||
|
|
||||||
|
\*asterisks\*
|
||||||
|
|
||||||
|
\_underscores\_
|
||||||
|
|
||||||
|
\`backticks\`
|
||||||
|
|
||||||
|
This is a code span with a literal backslash-backtick sequence: `` \` ``
|
||||||
|
|
||||||
|
This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.
|
||||||
|
|
||||||
|
This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.
|
15
vendor/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html
generated
vendored
Normal file
15
vendor/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<blockquote>
|
||||||
|
<p>Example:</p>
|
||||||
|
|
||||||
|
<pre><code>sub status {
|
||||||
|
print "working";
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Or:</p>
|
||||||
|
|
||||||
|
<pre><code>sub status {
|
||||||
|
return "working";
|
||||||
|
}
|
||||||
|
</code></pre>
|
||||||
|
</blockquote>
|
11
vendor/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text
generated
vendored
Normal file
11
vendor/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
> Example:
|
||||||
|
>
|
||||||
|
> sub status {
|
||||||
|
> print "working";
|
||||||
|
> }
|
||||||
|
>
|
||||||
|
> Or:
|
||||||
|
>
|
||||||
|
> sub status {
|
||||||
|
> return "working";
|
||||||
|
> }
|
18
vendor/github.com/russross/blackfriday/testdata/Code Blocks.html
generated
vendored
Normal file
18
vendor/github.com/russross/blackfriday/testdata/Code Blocks.html
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<pre><code>code block on the first line
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Regular text.</p>
|
||||||
|
|
||||||
|
<pre><code>code block indented by spaces
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Regular text.</p>
|
||||||
|
|
||||||
|
<pre><code>the lines in this block
|
||||||
|
all contain trailing spaces
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Regular Text.</p>
|
||||||
|
|
||||||
|
<pre><code>code block on the last line
|
||||||
|
</code></pre>
|
14
vendor/github.com/russross/blackfriday/testdata/Code Blocks.text
generated
vendored
Normal file
14
vendor/github.com/russross/blackfriday/testdata/Code Blocks.text
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
code block on the first line
|
||||||
|
|
||||||
|
Regular text.
|
||||||
|
|
||||||
|
code block indented by spaces
|
||||||
|
|
||||||
|
Regular text.
|
||||||
|
|
||||||
|
the lines in this block
|
||||||
|
all contain trailing spaces
|
||||||
|
|
||||||
|
Regular Text.
|
||||||
|
|
||||||
|
code block on the last line
|
5
vendor/github.com/russross/blackfriday/testdata/Code Spans.html
generated
vendored
Normal file
5
vendor/github.com/russross/blackfriday/testdata/Code Spans.html
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<p><code><test a="</code> content of attribute <code>"></code></p>
|
||||||
|
|
||||||
|
<p>Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span></p>
|
||||||
|
|
||||||
|
<p>Here's how you put <code>`backticks`</code> in a code span.</p>
|
6
vendor/github.com/russross/blackfriday/testdata/Code Spans.text
generated
vendored
Normal file
6
vendor/github.com/russross/blackfriday/testdata/Code Spans.text
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
`<test a="` content of attribute `">`
|
||||||
|
|
||||||
|
Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span>
|
||||||
|
|
||||||
|
Here's how you put `` `backticks` `` in a code span.
|
||||||
|
|
14
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html
generated
vendored
Normal file
14
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<p>In Markdown 1.0.0 and earlier. Version</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>This line turns into a list item.
|
||||||
|
Because a hard-wrapped line in the
|
||||||
|
middle of a paragraph looked like a
|
||||||
|
list item.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>Here's one with a bullet.</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>criminey.</li>
|
||||||
|
</ul>
|
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text
generated
vendored
Normal file
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
In Markdown 1.0.0 and earlier. Version
|
||||||
|
8. This line turns into a list item.
|
||||||
|
Because a hard-wrapped line in the
|
||||||
|
middle of a paragraph looked like a
|
||||||
|
list item.
|
||||||
|
|
||||||
|
Here's one with a bullet.
|
||||||
|
* criminey.
|
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html
generated
vendored
Normal file
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<p>In Markdown 1.0.0 and earlier. Version
|
||||||
|
8. This line turns into a list item.
|
||||||
|
Because a hard-wrapped line in the
|
||||||
|
middle of a paragraph looked like a
|
||||||
|
list item.</p>
|
||||||
|
|
||||||
|
<p>Here's one with a bullet.
|
||||||
|
* criminey.</p>
|
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text
generated
vendored
Normal file
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
In Markdown 1.0.0 and earlier. Version
|
||||||
|
8. This line turns into a list item.
|
||||||
|
Because a hard-wrapped line in the
|
||||||
|
middle of a paragraph looked like a
|
||||||
|
list item.
|
||||||
|
|
||||||
|
Here's one with a bullet.
|
||||||
|
* criminey.
|
71
vendor/github.com/russross/blackfriday/testdata/Horizontal rules.html
generated
vendored
Normal file
71
vendor/github.com/russross/blackfriday/testdata/Horizontal rules.html
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<p>Dashes:</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<pre><code>---
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<pre><code>- - -
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Asterisks:</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<pre><code>***
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<pre><code>* * *
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Underscores:</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<pre><code>___
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<pre><code>_ _ _
|
||||||
|
</code></pre>
|
67
vendor/github.com/russross/blackfriday/testdata/Horizontal rules.text
generated
vendored
Normal file
67
vendor/github.com/russross/blackfriday/testdata/Horizontal rules.text
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
Dashes:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
- - -
|
||||||
|
|
||||||
|
- - -
|
||||||
|
|
||||||
|
- - -
|
||||||
|
|
||||||
|
- - -
|
||||||
|
|
||||||
|
- - -
|
||||||
|
|
||||||
|
|
||||||
|
Asterisks:
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
|
||||||
|
Underscores:
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
_ _ _
|
||||||
|
|
||||||
|
_ _ _
|
||||||
|
|
||||||
|
_ _ _
|
||||||
|
|
||||||
|
_ _ _
|
||||||
|
|
||||||
|
_ _ _
|
15
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html
generated
vendored
Normal file
15
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<p>Simple block on one line:</p>
|
||||||
|
|
||||||
|
<div>foo</div>
|
||||||
|
|
||||||
|
<p>And nested without indentation:</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
foo
|
||||||
|
</div>
|
||||||
|
<div style=">"/>
|
||||||
|
</div>
|
||||||
|
<div>bar</div>
|
||||||
|
</div>
|
15
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text
generated
vendored
Normal file
15
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Simple block on one line:
|
||||||
|
|
||||||
|
<div>foo</div>
|
||||||
|
|
||||||
|
And nested without indentation:
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
foo
|
||||||
|
</div>
|
||||||
|
<div style=">"/>
|
||||||
|
</div>
|
||||||
|
<div>bar</div>
|
||||||
|
</div>
|
72
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html
generated
vendored
Normal file
72
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<p>Here's a simple block:</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
foo
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>This should be a code block, though:</p>
|
||||||
|
|
||||||
|
<pre><code><div>
|
||||||
|
foo
|
||||||
|
</div>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>As should this:</p>
|
||||||
|
|
||||||
|
<pre><code><div>foo</div>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Now, nested:</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
foo
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>This should just be an HTML comment:</p>
|
||||||
|
|
||||||
|
<!-- Comment -->
|
||||||
|
|
||||||
|
<p>Multiline:</p>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Blah
|
||||||
|
Blah
|
||||||
|
-->
|
||||||
|
|
||||||
|
<p>Code block:</p>
|
||||||
|
|
||||||
|
<pre><code><!-- Comment -->
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Just plain comment, with trailing spaces on the line:</p>
|
||||||
|
|
||||||
|
<!-- foo -->
|
||||||
|
|
||||||
|
<p>Code:</p>
|
||||||
|
|
||||||
|
<pre><code><hr />
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Hr's:</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<hr class="foo" id="bar" />
|
||||||
|
|
||||||
|
<hr class="foo" id="bar"/>
|
||||||
|
|
||||||
|
<hr class="foo" id="bar" >
|
69
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text
generated
vendored
Normal file
69
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
Here's a simple block:
|
||||||
|
|
||||||
|
<div>
|
||||||
|
foo
|
||||||
|
</div>
|
||||||
|
|
||||||
|
This should be a code block, though:
|
||||||
|
|
||||||
|
<div>
|
||||||
|
foo
|
||||||
|
</div>
|
||||||
|
|
||||||
|
As should this:
|
||||||
|
|
||||||
|
<div>foo</div>
|
||||||
|
|
||||||
|
Now, nested:
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
foo
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
This should just be an HTML comment:
|
||||||
|
|
||||||
|
<!-- Comment -->
|
||||||
|
|
||||||
|
Multiline:
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Blah
|
||||||
|
Blah
|
||||||
|
-->
|
||||||
|
|
||||||
|
Code block:
|
||||||
|
|
||||||
|
<!-- Comment -->
|
||||||
|
|
||||||
|
Just plain comment, with trailing spaces on the line:
|
||||||
|
|
||||||
|
<!-- foo -->
|
||||||
|
|
||||||
|
Code:
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
Hr's:
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<hr class="foo" id="bar" />
|
||||||
|
|
||||||
|
<hr class="foo" id="bar"/>
|
||||||
|
|
||||||
|
<hr class="foo" id="bar" >
|
||||||
|
|
13
vendor/github.com/russross/blackfriday/testdata/Inline HTML comments.html
generated
vendored
Normal file
13
vendor/github.com/russross/blackfriday/testdata/Inline HTML comments.html
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<p>Paragraph one.</p>
|
||||||
|
|
||||||
|
<!-- This is a simple comment -->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This is another comment.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<p>Paragraph two.</p>
|
||||||
|
|
||||||
|
<!-- one comment block -- -- with two comments -->
|
||||||
|
|
||||||
|
<p>The end.</p>
|
13
vendor/github.com/russross/blackfriday/testdata/Inline HTML comments.text
generated
vendored
Normal file
13
vendor/github.com/russross/blackfriday/testdata/Inline HTML comments.text
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Paragraph one.
|
||||||
|
|
||||||
|
<!-- This is a simple comment -->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This is another comment.
|
||||||
|
-->
|
||||||
|
|
||||||
|
Paragraph two.
|
||||||
|
|
||||||
|
<!-- one comment block -- -- with two comments -->
|
||||||
|
|
||||||
|
The end.
|
11
vendor/github.com/russross/blackfriday/testdata/Links, inline style.html
generated
vendored
Normal file
11
vendor/github.com/russross/blackfriday/testdata/Links, inline style.html
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<p>Just a <a href="/url/">URL</a>.</p>
|
||||||
|
|
||||||
|
<p><a href="/url/" title="title">URL and title</a>.</p>
|
||||||
|
|
||||||
|
<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>
|
||||||
|
|
||||||
|
<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>
|
||||||
|
|
||||||
|
<p><a href="/url/" title="title has spaces afterward">URL and title</a>.</p>
|
||||||
|
|
||||||
|
<p>[Empty]().</p>
|
12
vendor/github.com/russross/blackfriday/testdata/Links, inline style.text
generated
vendored
Normal file
12
vendor/github.com/russross/blackfriday/testdata/Links, inline style.text
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
Just a [URL](/url/).
|
||||||
|
|
||||||
|
[URL and title](/url/ "title").
|
||||||
|
|
||||||
|
[URL and title](/url/ "title preceded by two spaces").
|
||||||
|
|
||||||
|
[URL and title](/url/ "title preceded by a tab").
|
||||||
|
|
||||||
|
[URL and title](/url/ "title has spaces afterward" ).
|
||||||
|
|
||||||
|
|
||||||
|
[Empty]().
|
52
vendor/github.com/russross/blackfriday/testdata/Links, reference style.html
generated
vendored
Normal file
52
vendor/github.com/russross/blackfriday/testdata/Links, reference style.html
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<p>Foo <a href="/url/" title="Title">bar</a>.</p>
|
||||||
|
|
||||||
|
<p>Foo <a href="/url/" title="Title">bar</a>.</p>
|
||||||
|
|
||||||
|
<p>Foo <a href="/url/" title="Title">bar</a>.</p>
|
||||||
|
|
||||||
|
<p>With <a href="/url/">embedded [brackets]</a>.</p>
|
||||||
|
|
||||||
|
<p>Indented <a href="/url">once</a>.</p>
|
||||||
|
|
||||||
|
<p>Indented <a href="/url">twice</a>.</p>
|
||||||
|
|
||||||
|
<p>Indented <a href="/url">thrice</a>.</p>
|
||||||
|
|
||||||
|
<p>Indented [four][] times.</p>
|
||||||
|
|
||||||
|
<pre><code>[four]: /url
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p><a href="foo">this</a> should work</p>
|
||||||
|
|
||||||
|
<p>So should <a href="foo">this</a>.</p>
|
||||||
|
|
||||||
|
<p>And <a href="foo">this</a>.</p>
|
||||||
|
|
||||||
|
<p>And <a href="foo">this</a>.</p>
|
||||||
|
|
||||||
|
<p>And <a href="foo">this</a>.</p>
|
||||||
|
|
||||||
|
<p>But not [that] [].</p>
|
||||||
|
|
||||||
|
<p>Nor [that][].</p>
|
||||||
|
|
||||||
|
<p>Nor [that].</p>
|
||||||
|
|
||||||
|
<p>[Something in brackets like <a href="foo">this</a> should work]</p>
|
||||||
|
|
||||||
|
<p>[Same with <a href="foo">this</a>.]</p>
|
||||||
|
|
||||||
|
<p>In this case, <a href="/somethingelse/">this</a> points to something else.</p>
|
||||||
|
|
||||||
|
<p>Backslashing should suppress [this] and [this].</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p>Here's one where the <a href="/url/">link
|
||||||
|
breaks</a> across lines.</p>
|
||||||
|
|
||||||
|
<p>Here's another where the <a href="/url/">link
|
||||||
|
breaks</a> across lines, but with a line-ending space.</p>
|
71
vendor/github.com/russross/blackfriday/testdata/Links, reference style.text
generated
vendored
Normal file
71
vendor/github.com/russross/blackfriday/testdata/Links, reference style.text
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
Foo [bar] [1].
|
||||||
|
|
||||||
|
Foo [bar][1].
|
||||||
|
|
||||||
|
Foo [bar]
|
||||||
|
[1].
|
||||||
|
|
||||||
|
[1]: /url/ "Title"
|
||||||
|
|
||||||
|
|
||||||
|
With [embedded [brackets]] [b].
|
||||||
|
|
||||||
|
|
||||||
|
Indented [once][].
|
||||||
|
|
||||||
|
Indented [twice][].
|
||||||
|
|
||||||
|
Indented [thrice][].
|
||||||
|
|
||||||
|
Indented [four][] times.
|
||||||
|
|
||||||
|
[once]: /url
|
||||||
|
|
||||||
|
[twice]: /url
|
||||||
|
|
||||||
|
[thrice]: /url
|
||||||
|
|
||||||
|
[four]: /url
|
||||||
|
|
||||||
|
|
||||||
|
[b]: /url/
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
[this] [this] should work
|
||||||
|
|
||||||
|
So should [this][this].
|
||||||
|
|
||||||
|
And [this] [].
|
||||||
|
|
||||||
|
And [this][].
|
||||||
|
|
||||||
|
And [this].
|
||||||
|
|
||||||
|
But not [that] [].
|
||||||
|
|
||||||
|
Nor [that][].
|
||||||
|
|
||||||
|
Nor [that].
|
||||||
|
|
||||||
|
[Something in brackets like [this][] should work]
|
||||||
|
|
||||||
|
[Same with [this].]
|
||||||
|
|
||||||
|
In this case, [this](/somethingelse/) points to something else.
|
||||||
|
|
||||||
|
Backslashing should suppress \[this] and [this\].
|
||||||
|
|
||||||
|
[this]: foo
|
||||||
|
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
Here's one where the [link
|
||||||
|
breaks] across lines.
|
||||||
|
|
||||||
|
Here's another where the [link
|
||||||
|
breaks] across lines, but with a line-ending space.
|
||||||
|
|
||||||
|
|
||||||
|
[link breaks]: /url/
|
9
vendor/github.com/russross/blackfriday/testdata/Links, shortcut references.html
generated
vendored
Normal file
9
vendor/github.com/russross/blackfriday/testdata/Links, shortcut references.html
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<p>This is the <a href="/simple">simple case</a>.</p>
|
||||||
|
|
||||||
|
<p>This one has a <a href="/foo">line
|
||||||
|
break</a>.</p>
|
||||||
|
|
||||||
|
<p>This one has a <a href="/foo">line
|
||||||
|
break</a> with a line-ending space.</p>
|
||||||
|
|
||||||
|
<p><a href="/that">this</a> and the <a href="/other">other</a></p>
|
20
vendor/github.com/russross/blackfriday/testdata/Links, shortcut references.text
generated
vendored
Normal file
20
vendor/github.com/russross/blackfriday/testdata/Links, shortcut references.text
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
This is the [simple case].
|
||||||
|
|
||||||
|
[simple case]: /simple
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This one has a [line
|
||||||
|
break].
|
||||||
|
|
||||||
|
This one has a [line
|
||||||
|
break] with a line-ending space.
|
||||||
|
|
||||||
|
[line break]: /foo
|
||||||
|
|
||||||
|
|
||||||
|
[this] [that] and the [other]
|
||||||
|
|
||||||
|
[this]: /this
|
||||||
|
[that]: /that
|
||||||
|
[other]: /other
|
3
vendor/github.com/russross/blackfriday/testdata/Literal quotes in titles.html
generated
vendored
Normal file
3
vendor/github.com/russross/blackfriday/testdata/Literal quotes in titles.html
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>
|
||||||
|
|
||||||
|
<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>
|
7
vendor/github.com/russross/blackfriday/testdata/Literal quotes in titles.text
generated
vendored
Normal file
7
vendor/github.com/russross/blackfriday/testdata/Literal quotes in titles.text
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Foo [bar][].
|
||||||
|
|
||||||
|
Foo [bar](/url/ "Title with "quotes" inside").
|
||||||
|
|
||||||
|
|
||||||
|
[bar]: /url/ "Title with "quotes" inside"
|
||||||
|
|
314
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html
generated
vendored
Normal file
314
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html
generated
vendored
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
<h1>Markdown: Basics</h1>
|
||||||
|
|
||||||
|
<ul id="ProjectSubmenu">
|
||||||
|
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||||
|
<li><a class="selected" title="Markdown Basics">Basics</a></li>
|
||||||
|
<li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||||
|
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||||
|
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Getting the Gist of Markdown's Formatting Syntax</h2>
|
||||||
|
|
||||||
|
<p>This page offers a brief overview of what it's like to use Markdown.
|
||||||
|
The <a href="/projects/markdown/syntax" title="Markdown Syntax">syntax page</a> provides complete, detailed documentation for
|
||||||
|
every feature, but Markdown should be very easy to pick up simply by
|
||||||
|
looking at a few examples of it in action. The examples on this page
|
||||||
|
are written in a before/after style, showing example syntax and the
|
||||||
|
HTML output produced by Markdown.</p>
|
||||||
|
|
||||||
|
<p>It's also helpful to simply try Markdown out; the <a href="/projects/markdown/dingus" title="Markdown Dingus">Dingus</a> is a
|
||||||
|
web application that allows you type your own Markdown-formatted text
|
||||||
|
and translate it to XHTML.</p>
|
||||||
|
|
||||||
|
<p><strong>Note:</strong> This document is itself written using Markdown; you
|
||||||
|
can <a href="/projects/markdown/basics.text">see the source for it by adding '.text' to the URL</a>.</p>
|
||||||
|
|
||||||
|
<h2>Paragraphs, Headers, Blockquotes</h2>
|
||||||
|
|
||||||
|
<p>A paragraph is simply one or more consecutive lines of text, separated
|
||||||
|
by one or more blank lines. (A blank line is any line that looks like a
|
||||||
|
blank line -- a line containing nothing spaces or tabs is considered
|
||||||
|
blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
|
||||||
|
|
||||||
|
<p>Markdown offers two styles of headers: <em>Setext</em> and <em>atx</em>.
|
||||||
|
Setext-style headers for <code><h1></code> and <code><h2></code> are created by
|
||||||
|
"underlining" with equal signs (<code>=</code>) and hyphens (<code>-</code>), respectively.
|
||||||
|
To create an atx-style header, you put 1-6 hash marks (<code>#</code>) at the
|
||||||
|
beginning of the line -- the number of hashes equals the resulting
|
||||||
|
HTML header level.</p>
|
||||||
|
|
||||||
|
<p>Blockquotes are indicated using email-style '<code>></code>' angle brackets.</p>
|
||||||
|
|
||||||
|
<p>Markdown:</p>
|
||||||
|
|
||||||
|
<pre><code>A First Level Header
|
||||||
|
====================
|
||||||
|
|
||||||
|
A Second Level Header
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Now is the time for all good men to come to
|
||||||
|
the aid of their country. This is just a
|
||||||
|
regular paragraph.
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy
|
||||||
|
dog's back.
|
||||||
|
|
||||||
|
### Header 3
|
||||||
|
|
||||||
|
> This is a blockquote.
|
||||||
|
>
|
||||||
|
> This is the second paragraph in the blockquote.
|
||||||
|
>
|
||||||
|
> ## This is an H2 in a blockquote
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Output:</p>
|
||||||
|
|
||||||
|
<pre><code><h1>A First Level Header</h1>
|
||||||
|
|
||||||
|
<h2>A Second Level Header</h2>
|
||||||
|
|
||||||
|
<p>Now is the time for all good men to come to
|
||||||
|
the aid of their country. This is just a
|
||||||
|
regular paragraph.</p>
|
||||||
|
|
||||||
|
<p>The quick brown fox jumped over the lazy
|
||||||
|
dog's back.</p>
|
||||||
|
|
||||||
|
<h3>Header 3</h3>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<p>This is a blockquote.</p>
|
||||||
|
|
||||||
|
<p>This is the second paragraph in the blockquote.</p>
|
||||||
|
|
||||||
|
<h2>This is an H2 in a blockquote</h2>
|
||||||
|
</blockquote>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h3>Phrase Emphasis</h3>
|
||||||
|
|
||||||
|
<p>Markdown uses asterisks and underscores to indicate spans of emphasis.</p>
|
||||||
|
|
||||||
|
<p>Markdown:</p>
|
||||||
|
|
||||||
|
<pre><code>Some of these words *are emphasized*.
|
||||||
|
Some of these words _are emphasized also_.
|
||||||
|
|
||||||
|
Use two asterisks for **strong emphasis**.
|
||||||
|
Or, if you prefer, __use two underscores instead__.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Output:</p>
|
||||||
|
|
||||||
|
<pre><code><p>Some of these words <em>are emphasized</em>.
|
||||||
|
Some of these words <em>are emphasized also</em>.</p>
|
||||||
|
|
||||||
|
<p>Use two asterisks for <strong>strong emphasis</strong>.
|
||||||
|
Or, if you prefer, <strong>use two underscores instead</strong>.</p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h2>Lists</h2>
|
||||||
|
|
||||||
|
<p>Unordered (bulleted) lists use asterisks, pluses, and hyphens (<code>*</code>,
|
||||||
|
<code>+</code>, and <code>-</code>) as list markers. These three markers are
|
||||||
|
interchangable; this:</p>
|
||||||
|
|
||||||
|
<pre><code>* Candy.
|
||||||
|
* Gum.
|
||||||
|
* Booze.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>this:</p>
|
||||||
|
|
||||||
|
<pre><code>+ Candy.
|
||||||
|
+ Gum.
|
||||||
|
+ Booze.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>and this:</p>
|
||||||
|
|
||||||
|
<pre><code>- Candy.
|
||||||
|
- Gum.
|
||||||
|
- Booze.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>all produce the same output:</p>
|
||||||
|
|
||||||
|
<pre><code><ul>
|
||||||
|
<li>Candy.</li>
|
||||||
|
<li>Gum.</li>
|
||||||
|
<li>Booze.</li>
|
||||||
|
</ul>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Ordered (numbered) lists use regular numbers, followed by periods, as
|
||||||
|
list markers:</p>
|
||||||
|
|
||||||
|
<pre><code>1. Red
|
||||||
|
2. Green
|
||||||
|
3. Blue
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Output:</p>
|
||||||
|
|
||||||
|
<pre><code><ol>
|
||||||
|
<li>Red</li>
|
||||||
|
<li>Green</li>
|
||||||
|
<li>Blue</li>
|
||||||
|
</ol>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>If you put blank lines between items, you'll get <code><p></code> tags for the
|
||||||
|
list item text. You can create multi-paragraph list items by indenting
|
||||||
|
the paragraphs by 4 spaces or 1 tab:</p>
|
||||||
|
|
||||||
|
<pre><code>* A list item.
|
||||||
|
|
||||||
|
With multiple paragraphs.
|
||||||
|
|
||||||
|
* Another item in the list.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Output:</p>
|
||||||
|
|
||||||
|
<pre><code><ul>
|
||||||
|
<li><p>A list item.</p>
|
||||||
|
<p>With multiple paragraphs.</p></li>
|
||||||
|
<li><p>Another item in the list.</p></li>
|
||||||
|
</ul>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h3>Links</h3>
|
||||||
|
|
||||||
|
<p>Markdown supports two styles for creating links: <em>inline</em> and
|
||||||
|
<em>reference</em>. With both styles, you use square brackets to delimit the
|
||||||
|
text you want to turn into a link.</p>
|
||||||
|
|
||||||
|
<p>Inline-style links use parentheses immediately after the link text.
|
||||||
|
For example:</p>
|
||||||
|
|
||||||
|
<pre><code>This is an [example link](http://example.com/).
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Output:</p>
|
||||||
|
|
||||||
|
<pre><code><p>This is an <a href="http://example.com/">
|
||||||
|
example link</a>.</p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Optionally, you may include a title attribute in the parentheses:</p>
|
||||||
|
|
||||||
|
<pre><code>This is an [example link](http://example.com/ "With a Title").
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Output:</p>
|
||||||
|
|
||||||
|
<pre><code><p>This is an <a href="http://example.com/" title="With a Title">
|
||||||
|
example link</a>.</p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Reference-style links allow you to refer to your links by names, which
|
||||||
|
you define elsewhere in your document:</p>
|
||||||
|
|
||||||
|
<pre><code>I get 10 times more traffic from [Google][1] than from
|
||||||
|
[Yahoo][2] or [MSN][3].
|
||||||
|
|
||||||
|
[1]: http://google.com/ "Google"
|
||||||
|
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||||
|
[3]: http://search.msn.com/ "MSN Search"
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Output:</p>
|
||||||
|
|
||||||
|
<pre><code><p>I get 10 times more traffic from <a href="http://google.com/"
|
||||||
|
title="Google">Google</a> than from <a href="http://search.yahoo.com/"
|
||||||
|
title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
|
||||||
|
title="MSN Search">MSN</a>.</p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>The title attribute is optional. Link names may contain letters,
|
||||||
|
numbers and spaces, but are <em>not</em> case sensitive:</p>
|
||||||
|
|
||||||
|
<pre><code>I start my morning with a cup of coffee and
|
||||||
|
[The New York Times][NY Times].
|
||||||
|
|
||||||
|
[ny times]: http://www.nytimes.com/
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Output:</p>
|
||||||
|
|
||||||
|
<pre><code><p>I start my morning with a cup of coffee and
|
||||||
|
<a href="http://www.nytimes.com/">The New York Times</a>.</p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h3>Images</h3>
|
||||||
|
|
||||||
|
<p>Image syntax is very much like link syntax.</p>
|
||||||
|
|
||||||
|
<p>Inline (titles are optional):</p>
|
||||||
|
|
||||||
|
<pre><code>![alt text](/path/to/img.jpg "Title")
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Reference-style:</p>
|
||||||
|
|
||||||
|
<pre><code>![alt text][id]
|
||||||
|
|
||||||
|
[id]: /path/to/img.jpg "Title"
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Both of the above examples produce the same output:</p>
|
||||||
|
|
||||||
|
<pre><code><img src="/path/to/img.jpg" alt="alt text" title="Title" />
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h3>Code</h3>
|
||||||
|
|
||||||
|
<p>In a regular paragraph, you can create code span by wrapping text in
|
||||||
|
backtick quotes. Any ampersands (<code>&</code>) and angle brackets (<code><</code> or
|
||||||
|
<code>></code>) will automatically be translated into HTML entities. This makes
|
||||||
|
it easy to use Markdown to write about HTML example code:</p>
|
||||||
|
|
||||||
|
<pre><code>I strongly recommend against using any `<blink>` tags.
|
||||||
|
|
||||||
|
I wish SmartyPants used named entities like `&mdash;`
|
||||||
|
instead of decimal-encoded entites like `&#8212;`.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Output:</p>
|
||||||
|
|
||||||
|
<pre><code><p>I strongly recommend against using any
|
||||||
|
<code>&lt;blink&gt;</code> tags.</p>
|
||||||
|
|
||||||
|
<p>I wish SmartyPants used named entities like
|
||||||
|
<code>&amp;mdash;</code> instead of decimal-encoded
|
||||||
|
entites like <code>&amp;#8212;</code>.</p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>To specify an entire block of pre-formatted code, indent every line of
|
||||||
|
the block by 4 spaces or 1 tab. Just like with code spans, <code>&</code>, <code><</code>,
|
||||||
|
and <code>></code> characters will be escaped automatically.</p>
|
||||||
|
|
||||||
|
<p>Markdown:</p>
|
||||||
|
|
||||||
|
<pre><code>If you want your page to validate under XHTML 1.0 Strict,
|
||||||
|
you've got to put paragraph tags in your blockquotes:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<p>For example.</p>
|
||||||
|
</blockquote>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Output:</p>
|
||||||
|
|
||||||
|
<pre><code><p>If you want your page to validate under XHTML 1.0 Strict,
|
||||||
|
you've got to put paragraph tags in your blockquotes:</p>
|
||||||
|
|
||||||
|
<pre><code>&lt;blockquote&gt;
|
||||||
|
&lt;p&gt;For example.&lt;/p&gt;
|
||||||
|
&lt;/blockquote&gt;
|
||||||
|
</code></pre>
|
||||||
|
</code></pre>
|
306
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text
generated
vendored
Normal file
306
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text
generated
vendored
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
Markdown: Basics
|
||||||
|
================
|
||||||
|
|
||||||
|
<ul id="ProjectSubmenu">
|
||||||
|
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||||
|
<li><a class="selected" title="Markdown Basics">Basics</a></li>
|
||||||
|
<li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||||
|
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||||
|
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
Getting the Gist of Markdown's Formatting Syntax
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
This page offers a brief overview of what it's like to use Markdown.
|
||||||
|
The [syntax page] [s] provides complete, detailed documentation for
|
||||||
|
every feature, but Markdown should be very easy to pick up simply by
|
||||||
|
looking at a few examples of it in action. The examples on this page
|
||||||
|
are written in a before/after style, showing example syntax and the
|
||||||
|
HTML output produced by Markdown.
|
||||||
|
|
||||||
|
It's also helpful to simply try Markdown out; the [Dingus] [d] is a
|
||||||
|
web application that allows you type your own Markdown-formatted text
|
||||||
|
and translate it to XHTML.
|
||||||
|
|
||||||
|
**Note:** This document is itself written using Markdown; you
|
||||||
|
can [see the source for it by adding '.text' to the URL] [src].
|
||||||
|
|
||||||
|
[s]: /projects/markdown/syntax "Markdown Syntax"
|
||||||
|
[d]: /projects/markdown/dingus "Markdown Dingus"
|
||||||
|
[src]: /projects/markdown/basics.text
|
||||||
|
|
||||||
|
|
||||||
|
## Paragraphs, Headers, Blockquotes ##
|
||||||
|
|
||||||
|
A paragraph is simply one or more consecutive lines of text, separated
|
||||||
|
by one or more blank lines. (A blank line is any line that looks like a
|
||||||
|
blank line -- a line containing nothing spaces or tabs is considered
|
||||||
|
blank.) Normal paragraphs should not be intended with spaces or tabs.
|
||||||
|
|
||||||
|
Markdown offers two styles of headers: *Setext* and *atx*.
|
||||||
|
Setext-style headers for `<h1>` and `<h2>` are created by
|
||||||
|
"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
|
||||||
|
To create an atx-style header, you put 1-6 hash marks (`#`) at the
|
||||||
|
beginning of the line -- the number of hashes equals the resulting
|
||||||
|
HTML header level.
|
||||||
|
|
||||||
|
Blockquotes are indicated using email-style '`>`' angle brackets.
|
||||||
|
|
||||||
|
Markdown:
|
||||||
|
|
||||||
|
A First Level Header
|
||||||
|
====================
|
||||||
|
|
||||||
|
A Second Level Header
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Now is the time for all good men to come to
|
||||||
|
the aid of their country. This is just a
|
||||||
|
regular paragraph.
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy
|
||||||
|
dog's back.
|
||||||
|
|
||||||
|
### Header 3
|
||||||
|
|
||||||
|
> This is a blockquote.
|
||||||
|
>
|
||||||
|
> This is the second paragraph in the blockquote.
|
||||||
|
>
|
||||||
|
> ## This is an H2 in a blockquote
|
||||||
|
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
<h1>A First Level Header</h1>
|
||||||
|
|
||||||
|
<h2>A Second Level Header</h2>
|
||||||
|
|
||||||
|
<p>Now is the time for all good men to come to
|
||||||
|
the aid of their country. This is just a
|
||||||
|
regular paragraph.</p>
|
||||||
|
|
||||||
|
<p>The quick brown fox jumped over the lazy
|
||||||
|
dog's back.</p>
|
||||||
|
|
||||||
|
<h3>Header 3</h3>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<p>This is a blockquote.</p>
|
||||||
|
|
||||||
|
<p>This is the second paragraph in the blockquote.</p>
|
||||||
|
|
||||||
|
<h2>This is an H2 in a blockquote</h2>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Phrase Emphasis ###
|
||||||
|
|
||||||
|
Markdown uses asterisks and underscores to indicate spans of emphasis.
|
||||||
|
|
||||||
|
Markdown:
|
||||||
|
|
||||||
|
Some of these words *are emphasized*.
|
||||||
|
Some of these words _are emphasized also_.
|
||||||
|
|
||||||
|
Use two asterisks for **strong emphasis**.
|
||||||
|
Or, if you prefer, __use two underscores instead__.
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
<p>Some of these words <em>are emphasized</em>.
|
||||||
|
Some of these words <em>are emphasized also</em>.</p>
|
||||||
|
|
||||||
|
<p>Use two asterisks for <strong>strong emphasis</strong>.
|
||||||
|
Or, if you prefer, <strong>use two underscores instead</strong>.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Lists ##
|
||||||
|
|
||||||
|
Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
|
||||||
|
`+`, and `-`) as list markers. These three markers are
|
||||||
|
interchangable; this:
|
||||||
|
|
||||||
|
* Candy.
|
||||||
|
* Gum.
|
||||||
|
* Booze.
|
||||||
|
|
||||||
|
this:
|
||||||
|
|
||||||
|
+ Candy.
|
||||||
|
+ Gum.
|
||||||
|
+ Booze.
|
||||||
|
|
||||||
|
and this:
|
||||||
|
|
||||||
|
- Candy.
|
||||||
|
- Gum.
|
||||||
|
- Booze.
|
||||||
|
|
||||||
|
all produce the same output:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Candy.</li>
|
||||||
|
<li>Gum.</li>
|
||||||
|
<li>Booze.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Ordered (numbered) lists use regular numbers, followed by periods, as
|
||||||
|
list markers:
|
||||||
|
|
||||||
|
1. Red
|
||||||
|
2. Green
|
||||||
|
3. Blue
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>Red</li>
|
||||||
|
<li>Green</li>
|
||||||
|
<li>Blue</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
If you put blank lines between items, you'll get `<p>` tags for the
|
||||||
|
list item text. You can create multi-paragraph list items by indenting
|
||||||
|
the paragraphs by 4 spaces or 1 tab:
|
||||||
|
|
||||||
|
* A list item.
|
||||||
|
|
||||||
|
With multiple paragraphs.
|
||||||
|
|
||||||
|
* Another item in the list.
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><p>A list item.</p>
|
||||||
|
<p>With multiple paragraphs.</p></li>
|
||||||
|
<li><p>Another item in the list.</p></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Links ###
|
||||||
|
|
||||||
|
Markdown supports two styles for creating links: *inline* and
|
||||||
|
*reference*. With both styles, you use square brackets to delimit the
|
||||||
|
text you want to turn into a link.
|
||||||
|
|
||||||
|
Inline-style links use parentheses immediately after the link text.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
This is an [example link](http://example.com/).
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
<p>This is an <a href="http://example.com/">
|
||||||
|
example link</a>.</p>
|
||||||
|
|
||||||
|
Optionally, you may include a title attribute in the parentheses:
|
||||||
|
|
||||||
|
This is an [example link](http://example.com/ "With a Title").
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
<p>This is an <a href="http://example.com/" title="With a Title">
|
||||||
|
example link</a>.</p>
|
||||||
|
|
||||||
|
Reference-style links allow you to refer to your links by names, which
|
||||||
|
you define elsewhere in your document:
|
||||||
|
|
||||||
|
I get 10 times more traffic from [Google][1] than from
|
||||||
|
[Yahoo][2] or [MSN][3].
|
||||||
|
|
||||||
|
[1]: http://google.com/ "Google"
|
||||||
|
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||||
|
[3]: http://search.msn.com/ "MSN Search"
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
<p>I get 10 times more traffic from <a href="http://google.com/"
|
||||||
|
title="Google">Google</a> than from <a href="http://search.yahoo.com/"
|
||||||
|
title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
|
||||||
|
title="MSN Search">MSN</a>.</p>
|
||||||
|
|
||||||
|
The title attribute is optional. Link names may contain letters,
|
||||||
|
numbers and spaces, but are *not* case sensitive:
|
||||||
|
|
||||||
|
I start my morning with a cup of coffee and
|
||||||
|
[The New York Times][NY Times].
|
||||||
|
|
||||||
|
[ny times]: http://www.nytimes.com/
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
<p>I start my morning with a cup of coffee and
|
||||||
|
<a href="http://www.nytimes.com/">The New York Times</a>.</p>
|
||||||
|
|
||||||
|
|
||||||
|
### Images ###
|
||||||
|
|
||||||
|
Image syntax is very much like link syntax.
|
||||||
|
|
||||||
|
Inline (titles are optional):
|
||||||
|
|
||||||
|
![alt text](/path/to/img.jpg "Title")
|
||||||
|
|
||||||
|
Reference-style:
|
||||||
|
|
||||||
|
![alt text][id]
|
||||||
|
|
||||||
|
[id]: /path/to/img.jpg "Title"
|
||||||
|
|
||||||
|
Both of the above examples produce the same output:
|
||||||
|
|
||||||
|
<img src="/path/to/img.jpg" alt="alt text" title="Title" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Code ###
|
||||||
|
|
||||||
|
In a regular paragraph, you can create code span by wrapping text in
|
||||||
|
backtick quotes. Any ampersands (`&`) and angle brackets (`<` or
|
||||||
|
`>`) will automatically be translated into HTML entities. This makes
|
||||||
|
it easy to use Markdown to write about HTML example code:
|
||||||
|
|
||||||
|
I strongly recommend against using any `<blink>` tags.
|
||||||
|
|
||||||
|
I wish SmartyPants used named entities like `—`
|
||||||
|
instead of decimal-encoded entites like `—`.
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
<p>I strongly recommend against using any
|
||||||
|
<code><blink></code> tags.</p>
|
||||||
|
|
||||||
|
<p>I wish SmartyPants used named entities like
|
||||||
|
<code>&mdash;</code> instead of decimal-encoded
|
||||||
|
entites like <code>&#8212;</code>.</p>
|
||||||
|
|
||||||
|
|
||||||
|
To specify an entire block of pre-formatted code, indent every line of
|
||||||
|
the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`,
|
||||||
|
and `>` characters will be escaped automatically.
|
||||||
|
|
||||||
|
Markdown:
|
||||||
|
|
||||||
|
If you want your page to validate under XHTML 1.0 Strict,
|
||||||
|
you've got to put paragraph tags in your blockquotes:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<p>For example.</p>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
<p>If you want your page to validate under XHTML 1.0 Strict,
|
||||||
|
you've got to put paragraph tags in your blockquotes:</p>
|
||||||
|
|
||||||
|
<pre><code><blockquote>
|
||||||
|
<p>For example.</p>
|
||||||
|
</blockquote>
|
||||||
|
</code></pre>
|
946
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html
generated
vendored
Normal file
946
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html
generated
vendored
Normal file
@ -0,0 +1,946 @@
|
|||||||
|
<h1>Markdown: Syntax</h1>
|
||||||
|
|
||||||
|
<ul id="ProjectSubmenu">
|
||||||
|
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||||
|
<li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
|
||||||
|
<li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||||
|
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||||
|
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="#overview">Overview</a>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="#philosophy">Philosophy</a></li>
|
||||||
|
<li><a href="#html">Inline HTML</a></li>
|
||||||
|
<li><a href="#autoescape">Automatic Escaping for Special Characters</a></li>
|
||||||
|
</ul></li>
|
||||||
|
<li><a href="#block">Block Elements</a>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="#p">Paragraphs and Line Breaks</a></li>
|
||||||
|
<li><a href="#header">Headers</a></li>
|
||||||
|
<li><a href="#blockquote">Blockquotes</a></li>
|
||||||
|
<li><a href="#list">Lists</a></li>
|
||||||
|
<li><a href="#precode">Code Blocks</a></li>
|
||||||
|
<li><a href="#hr">Horizontal Rules</a></li>
|
||||||
|
</ul></li>
|
||||||
|
<li><a href="#span">Span Elements</a>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="#link">Links</a></li>
|
||||||
|
<li><a href="#em">Emphasis</a></li>
|
||||||
|
<li><a href="#code">Code</a></li>
|
||||||
|
<li><a href="#img">Images</a></li>
|
||||||
|
</ul></li>
|
||||||
|
<li><a href="#misc">Miscellaneous</a>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="#backslash">Backslash Escapes</a></li>
|
||||||
|
<li><a href="#autolink">Automatic Links</a></li>
|
||||||
|
</ul></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p><strong>Note:</strong> This document is itself written using Markdown; you
|
||||||
|
can <a href="/projects/markdown/syntax.text">see the source for it by adding '.text' to the URL</a>.</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2 id="overview">Overview</h2>
|
||||||
|
|
||||||
|
<h3 id="philosophy">Philosophy</h3>
|
||||||
|
|
||||||
|
<p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</p>
|
||||||
|
|
||||||
|
<p>Readability, however, is emphasized above all else. A Markdown-formatted
|
||||||
|
document should be publishable as-is, as plain text, without looking
|
||||||
|
like it's been marked up with tags or formatting instructions. While
|
||||||
|
Markdown's syntax has been influenced by several existing text-to-HTML
|
||||||
|
filters -- including <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a>, <a href="http://www.aaronsw.com/2002/atx/">atx</a>, <a href="http://textism.com/tools/textile/">Textile</a>, <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>,
|
||||||
|
<a href="http://www.triptico.com/software/grutatxt.html">Grutatext</a>, and <a href="http://ettext.taint.org/doc/">EtText</a> -- the single biggest source of
|
||||||
|
inspiration for Markdown's syntax is the format of plain text email.</p>
|
||||||
|
|
||||||
|
<p>To this end, Markdown's syntax is comprised entirely of punctuation
|
||||||
|
characters, which punctuation characters have been carefully chosen so
|
||||||
|
as to look like what they mean. E.g., asterisks around a word actually
|
||||||
|
look like *emphasis*. Markdown lists look like, well, lists. Even
|
||||||
|
blockquotes look like quoted passages of text, assuming you've ever
|
||||||
|
used email.</p>
|
||||||
|
|
||||||
|
<h3 id="html">Inline HTML</h3>
|
||||||
|
|
||||||
|
<p>Markdown's syntax is intended for one purpose: to be used as a
|
||||||
|
format for <em>writing</em> for the web.</p>
|
||||||
|
|
||||||
|
<p>Markdown is not a replacement for HTML, or even close to it. Its
|
||||||
|
syntax is very small, corresponding only to a very small subset of
|
||||||
|
HTML tags. The idea is <em>not</em> to create a syntax that makes it easier
|
||||||
|
to insert HTML tags. In my opinion, HTML tags are already easy to
|
||||||
|
insert. The idea for Markdown is to make it easy to read, write, and
|
||||||
|
edit prose. HTML is a <em>publishing</em> format; Markdown is a <em>writing</em>
|
||||||
|
format. Thus, Markdown's formatting syntax only addresses issues that
|
||||||
|
can be conveyed in plain text.</p>
|
||||||
|
|
||||||
|
<p>For any markup that is not covered by Markdown's syntax, you simply
|
||||||
|
use HTML itself. There's no need to preface it or delimit it to
|
||||||
|
indicate that you're switching from Markdown to HTML; you just use
|
||||||
|
the tags.</p>
|
||||||
|
|
||||||
|
<p>The only restrictions are that block-level HTML elements -- e.g. <code><div></code>,
|
||||||
|
<code><table></code>, <code><pre></code>, <code><p></code>, etc. -- must be separated from surrounding
|
||||||
|
content by blank lines, and the start and end tags of the block should
|
||||||
|
not be indented with tabs or spaces. Markdown is smart enough not
|
||||||
|
to add extra (unwanted) <code><p></code> tags around HTML block-level tags.</p>
|
||||||
|
|
||||||
|
<p>For example, to add an HTML table to a Markdown article:</p>
|
||||||
|
|
||||||
|
<pre><code>This is a regular paragraph.
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Foo</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
This is another regular paragraph.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Note that Markdown formatting syntax is not processed within block-level
|
||||||
|
HTML tags. E.g., you can't use Markdown-style <code>*emphasis*</code> inside an
|
||||||
|
HTML block.</p>
|
||||||
|
|
||||||
|
<p>Span-level HTML tags -- e.g. <code><span></code>, <code><cite></code>, or <code><del></code> -- can be
|
||||||
|
used anywhere in a Markdown paragraph, list item, or header. If you
|
||||||
|
want, you can even use HTML tags instead of Markdown formatting; e.g. if
|
||||||
|
you'd prefer to use HTML <code><a></code> or <code><img></code> tags instead of Markdown's
|
||||||
|
link or image syntax, go right ahead.</p>
|
||||||
|
|
||||||
|
<p>Unlike block-level HTML tags, Markdown syntax <em>is</em> processed within
|
||||||
|
span-level tags.</p>
|
||||||
|
|
||||||
|
<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
|
||||||
|
|
||||||
|
<p>In HTML, there are two characters that demand special treatment: <code><</code>
|
||||||
|
and <code>&</code>. Left angle brackets are used to start tags; ampersands are
|
||||||
|
used to denote HTML entities. If you want to use them as literal
|
||||||
|
characters, you must escape them as entities, e.g. <code>&lt;</code>, and
|
||||||
|
<code>&amp;</code>.</p>
|
||||||
|
|
||||||
|
<p>Ampersands in particular are bedeviling for web writers. If you want to
|
||||||
|
write about 'AT&T', you need to write '<code>AT&amp;T</code>'. You even need to
|
||||||
|
escape ampersands within URLs. Thus, if you want to link to:</p>
|
||||||
|
|
||||||
|
<pre><code>http://images.google.com/images?num=30&q=larry+bird
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>you need to encode the URL as:</p>
|
||||||
|
|
||||||
|
<pre><code>http://images.google.com/images?num=30&amp;q=larry+bird
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>in your anchor tag <code>href</code> attribute. Needless to say, this is easy to
|
||||||
|
forget, and is probably the single most common source of HTML validation
|
||||||
|
errors in otherwise well-marked-up web sites.</p>
|
||||||
|
|
||||||
|
<p>Markdown allows you to use these characters naturally, taking care of
|
||||||
|
all the necessary escaping for you. If you use an ampersand as part of
|
||||||
|
an HTML entity, it remains unchanged; otherwise it will be translated
|
||||||
|
into <code>&amp;</code>.</p>
|
||||||
|
|
||||||
|
<p>So, if you want to include a copyright symbol in your article, you can write:</p>
|
||||||
|
|
||||||
|
<pre><code>&copy;
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>and Markdown will leave it alone. But if you write:</p>
|
||||||
|
|
||||||
|
<pre><code>AT&T
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Markdown will translate it to:</p>
|
||||||
|
|
||||||
|
<pre><code>AT&amp;T
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Similarly, because Markdown supports <a href="#html">inline HTML</a>, if you use
|
||||||
|
angle brackets as delimiters for HTML tags, Markdown will treat them as
|
||||||
|
such. But if you write:</p>
|
||||||
|
|
||||||
|
<pre><code>4 < 5
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Markdown will translate it to:</p>
|
||||||
|
|
||||||
|
<pre><code>4 &lt; 5
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>However, inside Markdown code spans and blocks, angle brackets and
|
||||||
|
ampersands are <em>always</em> encoded automatically. This makes it easy to use
|
||||||
|
Markdown to write about HTML code. (As opposed to raw HTML, which is a
|
||||||
|
terrible format for writing about HTML syntax, because every single <code><</code>
|
||||||
|
and <code>&</code> in your example code needs to be escaped.)</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2 id="block">Block Elements</h2>
|
||||||
|
|
||||||
|
<h3 id="p">Paragraphs and Line Breaks</h3>
|
||||||
|
|
||||||
|
<p>A paragraph is simply one or more consecutive lines of text, separated
|
||||||
|
by one or more blank lines. (A blank line is any line that looks like a
|
||||||
|
blank line -- a line containing nothing but spaces or tabs is considered
|
||||||
|
blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
|
||||||
|
|
||||||
|
<p>The implication of the "one or more consecutive lines of text" rule is
|
||||||
|
that Markdown supports "hard-wrapped" text paragraphs. This differs
|
||||||
|
significantly from most other text-to-HTML formatters (including Movable
|
||||||
|
Type's "Convert Line Breaks" option) which translate every line break
|
||||||
|
character in a paragraph into a <code><br /></code> tag.</p>
|
||||||
|
|
||||||
|
<p>When you <em>do</em> want to insert a <code><br /></code> break tag using Markdown, you
|
||||||
|
end a line with two or more spaces, then type return.</p>
|
||||||
|
|
||||||
|
<p>Yes, this takes a tad more effort to create a <code><br /></code>, but a simplistic
|
||||||
|
"every line break is a <code><br /></code>" rule wouldn't work for Markdown.
|
||||||
|
Markdown's email-style <a href="#blockquote">blockquoting</a> and multi-paragraph <a href="#list">list items</a>
|
||||||
|
work best -- and look better -- when you format them with hard breaks.</p>
|
||||||
|
|
||||||
|
<h3 id="header">Headers</h3>
|
||||||
|
|
||||||
|
<p>Markdown supports two styles of headers, <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a> and <a href="http://www.aaronsw.com/2002/atx/">atx</a>.</p>
|
||||||
|
|
||||||
|
<p>Setext-style headers are "underlined" using equal signs (for first-level
|
||||||
|
headers) and dashes (for second-level headers). For example:</p>
|
||||||
|
|
||||||
|
<pre><code>This is an H1
|
||||||
|
=============
|
||||||
|
|
||||||
|
This is an H2
|
||||||
|
-------------
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Any number of underlining <code>=</code>'s or <code>-</code>'s will work.</p>
|
||||||
|
|
||||||
|
<p>Atx-style headers use 1-6 hash characters at the start of the line,
|
||||||
|
corresponding to header levels 1-6. For example:</p>
|
||||||
|
|
||||||
|
<pre><code># This is an H1
|
||||||
|
|
||||||
|
## This is an H2
|
||||||
|
|
||||||
|
###### This is an H6
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Optionally, you may "close" atx-style headers. This is purely
|
||||||
|
cosmetic -- you can use this if you think it looks better. The
|
||||||
|
closing hashes don't even need to match the number of hashes
|
||||||
|
used to open the header. (The number of opening hashes
|
||||||
|
determines the header level.) :</p>
|
||||||
|
|
||||||
|
<pre><code># This is an H1 #
|
||||||
|
|
||||||
|
## This is an H2 ##
|
||||||
|
|
||||||
|
### This is an H3 ######
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h3 id="blockquote">Blockquotes</h3>
|
||||||
|
|
||||||
|
<p>Markdown uses email-style <code>></code> characters for blockquoting. If you're
|
||||||
|
familiar with quoting passages of text in an email message, then you
|
||||||
|
know how to create a blockquote in Markdown. It looks best if you hard
|
||||||
|
wrap the text and put a <code>></code> before every line:</p>
|
||||||
|
|
||||||
|
<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||||
|
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||||
|
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||||
|
>
|
||||||
|
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||||
|
> id sem consectetuer libero luctus adipiscing.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Markdown allows you to be lazy and only put the <code>></code> before the first
|
||||||
|
line of a hard-wrapped paragraph:</p>
|
||||||
|
|
||||||
|
<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||||
|
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||||
|
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||||
|
|
||||||
|
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||||
|
id sem consectetuer libero luctus adipiscing.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
|
||||||
|
adding additional levels of <code>></code>:</p>
|
||||||
|
|
||||||
|
<pre><code>> This is the first level of quoting.
|
||||||
|
>
|
||||||
|
> > This is nested blockquote.
|
||||||
|
>
|
||||||
|
> Back to the first level.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Blockquotes can contain other Markdown elements, including headers, lists,
|
||||||
|
and code blocks:</p>
|
||||||
|
|
||||||
|
<pre><code>> ## This is a header.
|
||||||
|
>
|
||||||
|
> 1. This is the first list item.
|
||||||
|
> 2. This is the second list item.
|
||||||
|
>
|
||||||
|
> Here's some example code:
|
||||||
|
>
|
||||||
|
> return shell_exec("echo $input | $markdown_script");
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Any decent text editor should make email-style quoting easy. For
|
||||||
|
example, with BBEdit, you can make a selection and choose Increase
|
||||||
|
Quote Level from the Text menu.</p>
|
||||||
|
|
||||||
|
<h3 id="list">Lists</h3>
|
||||||
|
|
||||||
|
<p>Markdown supports ordered (numbered) and unordered (bulleted) lists.</p>
|
||||||
|
|
||||||
|
<p>Unordered lists use asterisks, pluses, and hyphens -- interchangably
|
||||||
|
-- as list markers:</p>
|
||||||
|
|
||||||
|
<pre><code>* Red
|
||||||
|
* Green
|
||||||
|
* Blue
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>is equivalent to:</p>
|
||||||
|
|
||||||
|
<pre><code>+ Red
|
||||||
|
+ Green
|
||||||
|
+ Blue
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>and:</p>
|
||||||
|
|
||||||
|
<pre><code>- Red
|
||||||
|
- Green
|
||||||
|
- Blue
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Ordered lists use numbers followed by periods:</p>
|
||||||
|
|
||||||
|
<pre><code>1. Bird
|
||||||
|
2. McHale
|
||||||
|
3. Parish
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>It's important to note that the actual numbers you use to mark the
|
||||||
|
list have no effect on the HTML output Markdown produces. The HTML
|
||||||
|
Markdown produces from the above list is:</p>
|
||||||
|
|
||||||
|
<pre><code><ol>
|
||||||
|
<li>Bird</li>
|
||||||
|
<li>McHale</li>
|
||||||
|
<li>Parish</li>
|
||||||
|
</ol>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>If you instead wrote the list in Markdown like this:</p>
|
||||||
|
|
||||||
|
<pre><code>1. Bird
|
||||||
|
1. McHale
|
||||||
|
1. Parish
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>or even:</p>
|
||||||
|
|
||||||
|
<pre><code>3. Bird
|
||||||
|
1. McHale
|
||||||
|
8. Parish
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>you'd get the exact same HTML output. The point is, if you want to,
|
||||||
|
you can use ordinal numbers in your ordered Markdown lists, so that
|
||||||
|
the numbers in your source match the numbers in your published HTML.
|
||||||
|
But if you want to be lazy, you don't have to.</p>
|
||||||
|
|
||||||
|
<p>If you do use lazy list numbering, however, you should still start the
|
||||||
|
list with the number 1. At some point in the future, Markdown may support
|
||||||
|
starting ordered lists at an arbitrary number.</p>
|
||||||
|
|
||||||
|
<p>List markers typically start at the left margin, but may be indented by
|
||||||
|
up to three spaces. List markers must be followed by one or more spaces
|
||||||
|
or a tab.</p>
|
||||||
|
|
||||||
|
<p>To make lists look nice, you can wrap items with hanging indents:</p>
|
||||||
|
|
||||||
|
<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||||
|
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||||
|
viverra nec, fringilla in, laoreet vitae, risus.
|
||||||
|
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||||
|
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>But if you want to be lazy, you don't have to:</p>
|
||||||
|
|
||||||
|
<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||||
|
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||||
|
viverra nec, fringilla in, laoreet vitae, risus.
|
||||||
|
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||||
|
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>If list items are separated by blank lines, Markdown will wrap the
|
||||||
|
items in <code><p></code> tags in the HTML output. For example, this input:</p>
|
||||||
|
|
||||||
|
<pre><code>* Bird
|
||||||
|
* Magic
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>will turn into:</p>
|
||||||
|
|
||||||
|
<pre><code><ul>
|
||||||
|
<li>Bird</li>
|
||||||
|
<li>Magic</li>
|
||||||
|
</ul>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>But this:</p>
|
||||||
|
|
||||||
|
<pre><code>* Bird
|
||||||
|
|
||||||
|
* Magic
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>will turn into:</p>
|
||||||
|
|
||||||
|
<pre><code><ul>
|
||||||
|
<li><p>Bird</p></li>
|
||||||
|
<li><p>Magic</p></li>
|
||||||
|
</ul>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>List items may consist of multiple paragraphs. Each subsequent
|
||||||
|
paragraph in a list item must be intended by either 4 spaces
|
||||||
|
or one tab:</p>
|
||||||
|
|
||||||
|
<pre><code>1. This is a list item with two paragraphs. Lorem ipsum dolor
|
||||||
|
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
|
||||||
|
mi posuere lectus.
|
||||||
|
|
||||||
|
Vestibulum enim wisi, viverra nec, fringilla in, laoreet
|
||||||
|
vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
|
||||||
|
sit amet velit.
|
||||||
|
|
||||||
|
2. Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>It looks nice if you indent every line of the subsequent
|
||||||
|
paragraphs, but here again, Markdown will allow you to be
|
||||||
|
lazy:</p>
|
||||||
|
|
||||||
|
<pre><code>* This is a list item with two paragraphs.
|
||||||
|
|
||||||
|
This is the second paragraph in the list item. You're
|
||||||
|
only required to indent the first line. Lorem ipsum dolor
|
||||||
|
sit amet, consectetuer adipiscing elit.
|
||||||
|
|
||||||
|
* Another item in the same list.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>To put a blockquote within a list item, the blockquote's <code>></code>
|
||||||
|
delimiters need to be indented:</p>
|
||||||
|
|
||||||
|
<pre><code>* A list item with a blockquote:
|
||||||
|
|
||||||
|
> This is a blockquote
|
||||||
|
> inside a list item.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>To put a code block within a list item, the code block needs
|
||||||
|
to be indented <em>twice</em> -- 8 spaces or two tabs:</p>
|
||||||
|
|
||||||
|
<pre><code>* A list item with a code block:
|
||||||
|
|
||||||
|
<code goes here>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>It's worth noting that it's possible to trigger an ordered list by
|
||||||
|
accident, by writing something like this:</p>
|
||||||
|
|
||||||
|
<pre><code>1986. What a great season.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>In other words, a <em>number-period-space</em> sequence at the beginning of a
|
||||||
|
line. To avoid this, you can backslash-escape the period:</p>
|
||||||
|
|
||||||
|
<pre><code>1986\. What a great season.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h3 id="precode">Code Blocks</h3>
|
||||||
|
|
||||||
|
<p>Pre-formatted code blocks are used for writing about programming or
|
||||||
|
markup source code. Rather than forming normal paragraphs, the lines
|
||||||
|
of a code block are interpreted literally. Markdown wraps a code block
|
||||||
|
in both <code><pre></code> and <code><code></code> tags.</p>
|
||||||
|
|
||||||
|
<p>To produce a code block in Markdown, simply indent every line of the
|
||||||
|
block by at least 4 spaces or 1 tab. For example, given this input:</p>
|
||||||
|
|
||||||
|
<pre><code>This is a normal paragraph:
|
||||||
|
|
||||||
|
This is a code block.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Markdown will generate:</p>
|
||||||
|
|
||||||
|
<pre><code><p>This is a normal paragraph:</p>
|
||||||
|
|
||||||
|
<pre><code>This is a code block.
|
||||||
|
</code></pre>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>One level of indentation -- 4 spaces or 1 tab -- is removed from each
|
||||||
|
line of the code block. For example, this:</p>
|
||||||
|
|
||||||
|
<pre><code>Here is an example of AppleScript:
|
||||||
|
|
||||||
|
tell application "Foo"
|
||||||
|
beep
|
||||||
|
end tell
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>will turn into:</p>
|
||||||
|
|
||||||
|
<pre><code><p>Here is an example of AppleScript:</p>
|
||||||
|
|
||||||
|
<pre><code>tell application "Foo"
|
||||||
|
beep
|
||||||
|
end tell
|
||||||
|
</code></pre>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>A code block continues until it reaches a line that is not indented
|
||||||
|
(or the end of the article).</p>
|
||||||
|
|
||||||
|
<p>Within a code block, ampersands (<code>&</code>) and angle brackets (<code><</code> and <code>></code>)
|
||||||
|
are automatically converted into HTML entities. This makes it very
|
||||||
|
easy to include example HTML source code using Markdown -- just paste
|
||||||
|
it and indent it, and Markdown will handle the hassle of encoding the
|
||||||
|
ampersands and angle brackets. For example, this:</p>
|
||||||
|
|
||||||
|
<pre><code> <div class="footer">
|
||||||
|
&copy; 2004 Foo Corporation
|
||||||
|
</div>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>will turn into:</p>
|
||||||
|
|
||||||
|
<pre><code><pre><code>&lt;div class="footer"&gt;
|
||||||
|
&amp;copy; 2004 Foo Corporation
|
||||||
|
&lt;/div&gt;
|
||||||
|
</code></pre>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Regular Markdown syntax is not processed within code blocks. E.g.,
|
||||||
|
asterisks are just literal asterisks within a code block. This means
|
||||||
|
it's also easy to use Markdown to write about Markdown's own syntax.</p>
|
||||||
|
|
||||||
|
<h3 id="hr">Horizontal Rules</h3>
|
||||||
|
|
||||||
|
<p>You can produce a horizontal rule tag (<code><hr /></code>) by placing three or
|
||||||
|
more hyphens, asterisks, or underscores on a line by themselves. If you
|
||||||
|
wish, you may use spaces between the hyphens or asterisks. Each of the
|
||||||
|
following lines will produce a horizontal rule:</p>
|
||||||
|
|
||||||
|
<pre><code>* * *
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
*****
|
||||||
|
|
||||||
|
- - -
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
_ _ _
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2 id="span">Span Elements</h2>
|
||||||
|
|
||||||
|
<h3 id="link">Links</h3>
|
||||||
|
|
||||||
|
<p>Markdown supports two style of links: <em>inline</em> and <em>reference</em>.</p>
|
||||||
|
|
||||||
|
<p>In both styles, the link text is delimited by [square brackets].</p>
|
||||||
|
|
||||||
|
<p>To create an inline link, use a set of regular parentheses immediately
|
||||||
|
after the link text's closing square bracket. Inside the parentheses,
|
||||||
|
put the URL where you want the link to point, along with an <em>optional</em>
|
||||||
|
title for the link, surrounded in quotes. For example:</p>
|
||||||
|
|
||||||
|
<pre><code>This is [an example](http://example.com/ "Title") inline link.
|
||||||
|
|
||||||
|
[This link](http://example.net/) has no title attribute.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Will produce:</p>
|
||||||
|
|
||||||
|
<pre><code><p>This is <a href="http://example.com/" title="Title">
|
||||||
|
an example</a> inline link.</p>
|
||||||
|
|
||||||
|
<p><a href="http://example.net/">This link</a> has no
|
||||||
|
title attribute.</p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>If you're referring to a local resource on the same server, you can
|
||||||
|
use relative paths:</p>
|
||||||
|
|
||||||
|
<pre><code>See my [About](/about/) page for details.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Reference-style links use a second set of square brackets, inside
|
||||||
|
which you place a label of your choosing to identify the link:</p>
|
||||||
|
|
||||||
|
<pre><code>This is [an example][id] reference-style link.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>You can optionally use a space to separate the sets of brackets:</p>
|
||||||
|
|
||||||
|
<pre><code>This is [an example] [id] reference-style link.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Then, anywhere in the document, you define your link label like this,
|
||||||
|
on a line by itself:</p>
|
||||||
|
|
||||||
|
<pre><code>[id]: http://example.com/ "Optional Title Here"
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>That is:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Square brackets containing the link identifier (optionally
|
||||||
|
indented from the left margin using up to three spaces);</li>
|
||||||
|
<li>followed by a colon;</li>
|
||||||
|
<li>followed by one or more spaces (or tabs);</li>
|
||||||
|
<li>followed by the URL for the link;</li>
|
||||||
|
<li>optionally followed by a title attribute for the link, enclosed
|
||||||
|
in double or single quotes.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>The link URL may, optionally, be surrounded by angle brackets:</p>
|
||||||
|
|
||||||
|
<pre><code>[id]: <http://example.com/> "Optional Title Here"
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>You can put the title attribute on the next line and use extra spaces
|
||||||
|
or tabs for padding, which tends to look better with longer URLs:</p>
|
||||||
|
|
||||||
|
<pre><code>[id]: http://example.com/longish/path/to/resource/here
|
||||||
|
"Optional Title Here"
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Link definitions are only used for creating links during Markdown
|
||||||
|
processing, and are stripped from your document in the HTML output.</p>
|
||||||
|
|
||||||
|
<p>Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are <em>not</em> case sensitive. E.g. these two links:</p>
|
||||||
|
|
||||||
|
<pre><code>[link text][a]
|
||||||
|
[link text][A]
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>are equivalent.</p>
|
||||||
|
|
||||||
|
<p>The <em>implicit link name</em> shortcut allows you to omit the name of the
|
||||||
|
link, in which case the link text itself is used as the name.
|
||||||
|
Just use an empty set of square brackets -- e.g., to link the word
|
||||||
|
"Google" to the google.com web site, you could simply write:</p>
|
||||||
|
|
||||||
|
<pre><code>[Google][]
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>And then define the link:</p>
|
||||||
|
|
||||||
|
<pre><code>[Google]: http://google.com/
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Because link names may contain spaces, this shortcut even works for
|
||||||
|
multiple words in the link text:</p>
|
||||||
|
|
||||||
|
<pre><code>Visit [Daring Fireball][] for more information.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>And then define the link:</p>
|
||||||
|
|
||||||
|
<pre><code>[Daring Fireball]: http://daringfireball.net/
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Link definitions can be placed anywhere in your Markdown document. I
|
||||||
|
tend to put them immediately after each paragraph in which they're
|
||||||
|
used, but if you want, you can put them all at the end of your
|
||||||
|
document, sort of like footnotes.</p>
|
||||||
|
|
||||||
|
<p>Here's an example of reference links in action:</p>
|
||||||
|
|
||||||
|
<pre><code>I get 10 times more traffic from [Google] [1] than from
|
||||||
|
[Yahoo] [2] or [MSN] [3].
|
||||||
|
|
||||||
|
[1]: http://google.com/ "Google"
|
||||||
|
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||||
|
[3]: http://search.msn.com/ "MSN Search"
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Using the implicit link name shortcut, you could instead write:</p>
|
||||||
|
|
||||||
|
<pre><code>I get 10 times more traffic from [Google][] than from
|
||||||
|
[Yahoo][] or [MSN][].
|
||||||
|
|
||||||
|
[google]: http://google.com/ "Google"
|
||||||
|
[yahoo]: http://search.yahoo.com/ "Yahoo Search"
|
||||||
|
[msn]: http://search.msn.com/ "MSN Search"
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Both of the above examples will produce the following HTML output:</p>
|
||||||
|
|
||||||
|
<pre><code><p>I get 10 times more traffic from <a href="http://google.com/"
|
||||||
|
title="Google">Google</a> than from
|
||||||
|
<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
|
||||||
|
or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>For comparison, here is the same paragraph written using
|
||||||
|
Markdown's inline link style:</p>
|
||||||
|
|
||||||
|
<pre><code>I get 10 times more traffic from [Google](http://google.com/ "Google")
|
||||||
|
than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
|
||||||
|
[MSN](http://search.msn.com/ "MSN Search").
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>The point of reference-style links is not that they're easier to
|
||||||
|
write. The point is that with reference-style links, your document
|
||||||
|
source is vastly more readable. Compare the above examples: using
|
||||||
|
reference-style links, the paragraph itself is only 81 characters
|
||||||
|
long; with inline-style links, it's 176 characters; and as raw HTML,
|
||||||
|
it's 234 characters. In the raw HTML, there's more markup than there
|
||||||
|
is text.</p>
|
||||||
|
|
||||||
|
<p>With Markdown's reference-style links, a source document much more
|
||||||
|
closely resembles the final output, as rendered in a browser. By
|
||||||
|
allowing you to move the markup-related metadata out of the paragraph,
|
||||||
|
you can add links without interrupting the narrative flow of your
|
||||||
|
prose.</p>
|
||||||
|
|
||||||
|
<h3 id="em">Emphasis</h3>
|
||||||
|
|
||||||
|
<p>Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of
|
||||||
|
emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an
|
||||||
|
HTML <code><em></code> tag; double <code>*</code>'s or <code>_</code>'s will be wrapped with an HTML
|
||||||
|
<code><strong></code> tag. E.g., this input:</p>
|
||||||
|
|
||||||
|
<pre><code>*single asterisks*
|
||||||
|
|
||||||
|
_single underscores_
|
||||||
|
|
||||||
|
**double asterisks**
|
||||||
|
|
||||||
|
__double underscores__
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>will produce:</p>
|
||||||
|
|
||||||
|
<pre><code><em>single asterisks</em>
|
||||||
|
|
||||||
|
<em>single underscores</em>
|
||||||
|
|
||||||
|
<strong>double asterisks</strong>
|
||||||
|
|
||||||
|
<strong>double underscores</strong>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>You can use whichever style you prefer; the lone restriction is that
|
||||||
|
the same character must be used to open and close an emphasis span.</p>
|
||||||
|
|
||||||
|
<p>Emphasis can be used in the middle of a word:</p>
|
||||||
|
|
||||||
|
<pre><code>un*fucking*believable
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>But if you surround an <code>*</code> or <code>_</code> with spaces, it'll be treated as a
|
||||||
|
literal asterisk or underscore.</p>
|
||||||
|
|
||||||
|
<p>To produce a literal asterisk or underscore at a position where it
|
||||||
|
would otherwise be used as an emphasis delimiter, you can backslash
|
||||||
|
escape it:</p>
|
||||||
|
|
||||||
|
<pre><code>\*this text is surrounded by literal asterisks\*
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h3 id="code">Code</h3>
|
||||||
|
|
||||||
|
<p>To indicate a span of code, wrap it with backtick quotes (<code>`</code>).
|
||||||
|
Unlike a pre-formatted code block, a code span indicates code within a
|
||||||
|
normal paragraph. For example:</p>
|
||||||
|
|
||||||
|
<pre><code>Use the `printf()` function.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>will produce:</p>
|
||||||
|
|
||||||
|
<pre><code><p>Use the <code>printf()</code> function.</p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>To include a literal backtick character within a code span, you can use
|
||||||
|
multiple backticks as the opening and closing delimiters:</p>
|
||||||
|
|
||||||
|
<pre><code>``There is a literal backtick (`) here.``
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>which will produce this:</p>
|
||||||
|
|
||||||
|
<pre><code><p><code>There is a literal backtick (`) here.</code></p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>The backtick delimiters surrounding a code span may include spaces --
|
||||||
|
one after the opening, one before the closing. This allows you to place
|
||||||
|
literal backtick characters at the beginning or end of a code span:</p>
|
||||||
|
|
||||||
|
<pre><code>A single backtick in a code span: `` ` ``
|
||||||
|
|
||||||
|
A backtick-delimited string in a code span: `` `foo` ``
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>will produce:</p>
|
||||||
|
|
||||||
|
<pre><code><p>A single backtick in a code span: <code>`</code></p>
|
||||||
|
|
||||||
|
<p>A backtick-delimited string in a code span: <code>`foo`</code></p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>With a code span, ampersands and angle brackets are encoded as HTML
|
||||||
|
entities automatically, which makes it easy to include example HTML
|
||||||
|
tags. Markdown will turn this:</p>
|
||||||
|
|
||||||
|
<pre><code>Please don't use any `<blink>` tags.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>into:</p>
|
||||||
|
|
||||||
|
<pre><code><p>Please don't use any <code>&lt;blink&gt;</code> tags.</p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>You can write this:</p>
|
||||||
|
|
||||||
|
<pre><code>`&#8212;` is the decimal-encoded equivalent of `&mdash;`.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>to produce:</p>
|
||||||
|
|
||||||
|
<pre><code><p><code>&amp;#8212;</code> is the decimal-encoded
|
||||||
|
equivalent of <code>&amp;mdash;</code>.</p>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<h3 id="img">Images</h3>
|
||||||
|
|
||||||
|
<p>Admittedly, it's fairly difficult to devise a "natural" syntax for
|
||||||
|
placing images into a plain text document format.</p>
|
||||||
|
|
||||||
|
<p>Markdown uses an image syntax that is intended to resemble the syntax
|
||||||
|
for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
|
||||||
|
|
||||||
|
<p>Inline image syntax looks like this:</p>
|
||||||
|
|
||||||
|
<pre><code>![Alt text](/path/to/img.jpg)
|
||||||
|
|
||||||
|
![Alt text](/path/to/img.jpg "Optional title")
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>That is:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>An exclamation mark: <code>!</code>;</li>
|
||||||
|
<li>followed by a set of square brackets, containing the <code>alt</code>
|
||||||
|
attribute text for the image;</li>
|
||||||
|
<li>followed by a set of parentheses, containing the URL or path to
|
||||||
|
the image, and an optional <code>title</code> attribute enclosed in double
|
||||||
|
or single quotes.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Reference-style image syntax looks like this:</p>
|
||||||
|
|
||||||
|
<pre><code>![Alt text][id]
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Where "id" is the name of a defined image reference. Image references
|
||||||
|
are defined using syntax identical to link references:</p>
|
||||||
|
|
||||||
|
<pre><code>[id]: url/to/image "Optional title attribute"
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>As of this writing, Markdown has no syntax for specifying the
|
||||||
|
dimensions of an image; if this is important to you, you can simply
|
||||||
|
use regular HTML <code><img></code> tags.</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2 id="misc">Miscellaneous</h2>
|
||||||
|
|
||||||
|
<h3 id="autolink">Automatic Links</h3>
|
||||||
|
|
||||||
|
<p>Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:</p>
|
||||||
|
|
||||||
|
<pre><code><http://example.com/>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Markdown will turn this into:</p>
|
||||||
|
|
||||||
|
<pre><code><a href="http://example.com/">http://example.com/</a>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Automatic links for email addresses work similarly, except that
|
||||||
|
Markdown will also perform a bit of randomized decimal and hex
|
||||||
|
entity-encoding to help obscure your address from address-harvesting
|
||||||
|
spambots. For example, Markdown will turn this:</p>
|
||||||
|
|
||||||
|
<pre><code><address@example.com>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>into something like this:</p>
|
||||||
|
|
||||||
|
<pre><code><a href="&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:&#x61;&#x64;&#x64;&#x72;&#x65;
|
||||||
|
&#115;&#115;&#64;&#101;&#120;&#x61;&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;
|
||||||
|
&#109;">&#x61;&#x64;&#x64;&#x72;&#x65;&#115;&#115;&#64;&#101;&#120;&#x61;
|
||||||
|
&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;&#109;</a>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>which will render in a browser as a clickable link to "address@example.com".</p>
|
||||||
|
|
||||||
|
<p>(This sort of entity-encoding trick will indeed fool many, if not
|
||||||
|
most, address-harvesting bots, but it definitely won't fool all of
|
||||||
|
them. It's better than nothing, but an address published in this way
|
||||||
|
will probably eventually start receiving spam.)</p>
|
||||||
|
|
||||||
|
<h3 id="backslash">Backslash Escapes</h3>
|
||||||
|
|
||||||
|
<p>Markdown allows you to use backslash escapes to generate literal
|
||||||
|
characters which would otherwise have special meaning in Markdown's
|
||||||
|
formatting syntax. For example, if you wanted to surround a word with
|
||||||
|
literal asterisks (instead of an HTML <code><em></code> tag), you can backslashes
|
||||||
|
before the asterisks, like this:</p>
|
||||||
|
|
||||||
|
<pre><code>\*literal asterisks\*
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>Markdown provides backslash escapes for the following characters:</p>
|
||||||
|
|
||||||
|
<pre><code>\ backslash
|
||||||
|
` backtick
|
||||||
|
* asterisk
|
||||||
|
_ underscore
|
||||||
|
{} curly braces
|
||||||
|
[] square brackets
|
||||||
|
() parentheses
|
||||||
|
# hash mark
|
||||||
|
+ plus sign
|
||||||
|
- minus sign (hyphen)
|
||||||
|
. dot
|
||||||
|
! exclamation mark
|
||||||
|
</code></pre>
|
888
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text
generated
vendored
Normal file
888
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text
generated
vendored
Normal file
@ -0,0 +1,888 @@
|
|||||||
|
Markdown: Syntax
|
||||||
|
================
|
||||||
|
|
||||||
|
<ul id="ProjectSubmenu">
|
||||||
|
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||||
|
<li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
|
||||||
|
<li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||||
|
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||||
|
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
* [Overview](#overview)
|
||||||
|
* [Philosophy](#philosophy)
|
||||||
|
* [Inline HTML](#html)
|
||||||
|
* [Automatic Escaping for Special Characters](#autoescape)
|
||||||
|
* [Block Elements](#block)
|
||||||
|
* [Paragraphs and Line Breaks](#p)
|
||||||
|
* [Headers](#header)
|
||||||
|
* [Blockquotes](#blockquote)
|
||||||
|
* [Lists](#list)
|
||||||
|
* [Code Blocks](#precode)
|
||||||
|
* [Horizontal Rules](#hr)
|
||||||
|
* [Span Elements](#span)
|
||||||
|
* [Links](#link)
|
||||||
|
* [Emphasis](#em)
|
||||||
|
* [Code](#code)
|
||||||
|
* [Images](#img)
|
||||||
|
* [Miscellaneous](#misc)
|
||||||
|
* [Backslash Escapes](#backslash)
|
||||||
|
* [Automatic Links](#autolink)
|
||||||
|
|
||||||
|
|
||||||
|
**Note:** This document is itself written using Markdown; you
|
||||||
|
can [see the source for it by adding '.text' to the URL][src].
|
||||||
|
|
||||||
|
[src]: /projects/markdown/syntax.text
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
<h2 id="overview">Overview</h2>
|
||||||
|
|
||||||
|
<h3 id="philosophy">Philosophy</h3>
|
||||||
|
|
||||||
|
Markdown is intended to be as easy-to-read and easy-to-write as is feasible.
|
||||||
|
|
||||||
|
Readability, however, is emphasized above all else. A Markdown-formatted
|
||||||
|
document should be publishable as-is, as plain text, without looking
|
||||||
|
like it's been marked up with tags or formatting instructions. While
|
||||||
|
Markdown's syntax has been influenced by several existing text-to-HTML
|
||||||
|
filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4],
|
||||||
|
[Grutatext] [5], and [EtText] [6] -- the single biggest source of
|
||||||
|
inspiration for Markdown's syntax is the format of plain text email.
|
||||||
|
|
||||||
|
[1]: http://docutils.sourceforge.net/mirror/setext.html
|
||||||
|
[2]: http://www.aaronsw.com/2002/atx/
|
||||||
|
[3]: http://textism.com/tools/textile/
|
||||||
|
[4]: http://docutils.sourceforge.net/rst.html
|
||||||
|
[5]: http://www.triptico.com/software/grutatxt.html
|
||||||
|
[6]: http://ettext.taint.org/doc/
|
||||||
|
|
||||||
|
To this end, Markdown's syntax is comprised entirely of punctuation
|
||||||
|
characters, which punctuation characters have been carefully chosen so
|
||||||
|
as to look like what they mean. E.g., asterisks around a word actually
|
||||||
|
look like \*emphasis\*. Markdown lists look like, well, lists. Even
|
||||||
|
blockquotes look like quoted passages of text, assuming you've ever
|
||||||
|
used email.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="html">Inline HTML</h3>
|
||||||
|
|
||||||
|
Markdown's syntax is intended for one purpose: to be used as a
|
||||||
|
format for *writing* for the web.
|
||||||
|
|
||||||
|
Markdown is not a replacement for HTML, or even close to it. Its
|
||||||
|
syntax is very small, corresponding only to a very small subset of
|
||||||
|
HTML tags. The idea is *not* to create a syntax that makes it easier
|
||||||
|
to insert HTML tags. In my opinion, HTML tags are already easy to
|
||||||
|
insert. The idea for Markdown is to make it easy to read, write, and
|
||||||
|
edit prose. HTML is a *publishing* format; Markdown is a *writing*
|
||||||
|
format. Thus, Markdown's formatting syntax only addresses issues that
|
||||||
|
can be conveyed in plain text.
|
||||||
|
|
||||||
|
For any markup that is not covered by Markdown's syntax, you simply
|
||||||
|
use HTML itself. There's no need to preface it or delimit it to
|
||||||
|
indicate that you're switching from Markdown to HTML; you just use
|
||||||
|
the tags.
|
||||||
|
|
||||||
|
The only restrictions are that block-level HTML elements -- e.g. `<div>`,
|
||||||
|
`<table>`, `<pre>`, `<p>`, etc. -- must be separated from surrounding
|
||||||
|
content by blank lines, and the start and end tags of the block should
|
||||||
|
not be indented with tabs or spaces. Markdown is smart enough not
|
||||||
|
to add extra (unwanted) `<p>` tags around HTML block-level tags.
|
||||||
|
|
||||||
|
For example, to add an HTML table to a Markdown article:
|
||||||
|
|
||||||
|
This is a regular paragraph.
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Foo</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
This is another regular paragraph.
|
||||||
|
|
||||||
|
Note that Markdown formatting syntax is not processed within block-level
|
||||||
|
HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an
|
||||||
|
HTML block.
|
||||||
|
|
||||||
|
Span-level HTML tags -- e.g. `<span>`, `<cite>`, or `<del>` -- can be
|
||||||
|
used anywhere in a Markdown paragraph, list item, or header. If you
|
||||||
|
want, you can even use HTML tags instead of Markdown formatting; e.g. if
|
||||||
|
you'd prefer to use HTML `<a>` or `<img>` tags instead of Markdown's
|
||||||
|
link or image syntax, go right ahead.
|
||||||
|
|
||||||
|
Unlike block-level HTML tags, Markdown syntax *is* processed within
|
||||||
|
span-level tags.
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
|
||||||
|
|
||||||
|
In HTML, there are two characters that demand special treatment: `<`
|
||||||
|
and `&`. Left angle brackets are used to start tags; ampersands are
|
||||||
|
used to denote HTML entities. If you want to use them as literal
|
||||||
|
characters, you must escape them as entities, e.g. `<`, and
|
||||||
|
`&`.
|
||||||
|
|
||||||
|
Ampersands in particular are bedeviling for web writers. If you want to
|
||||||
|
write about 'AT&T', you need to write '`AT&T`'. You even need to
|
||||||
|
escape ampersands within URLs. Thus, if you want to link to:
|
||||||
|
|
||||||
|
http://images.google.com/images?num=30&q=larry+bird
|
||||||
|
|
||||||
|
you need to encode the URL as:
|
||||||
|
|
||||||
|
http://images.google.com/images?num=30&q=larry+bird
|
||||||
|
|
||||||
|
in your anchor tag `href` attribute. Needless to say, this is easy to
|
||||||
|
forget, and is probably the single most common source of HTML validation
|
||||||
|
errors in otherwise well-marked-up web sites.
|
||||||
|
|
||||||
|
Markdown allows you to use these characters naturally, taking care of
|
||||||
|
all the necessary escaping for you. If you use an ampersand as part of
|
||||||
|
an HTML entity, it remains unchanged; otherwise it will be translated
|
||||||
|
into `&`.
|
||||||
|
|
||||||
|
So, if you want to include a copyright symbol in your article, you can write:
|
||||||
|
|
||||||
|
©
|
||||||
|
|
||||||
|
and Markdown will leave it alone. But if you write:
|
||||||
|
|
||||||
|
AT&T
|
||||||
|
|
||||||
|
Markdown will translate it to:
|
||||||
|
|
||||||
|
AT&T
|
||||||
|
|
||||||
|
Similarly, because Markdown supports [inline HTML](#html), if you use
|
||||||
|
angle brackets as delimiters for HTML tags, Markdown will treat them as
|
||||||
|
such. But if you write:
|
||||||
|
|
||||||
|
4 < 5
|
||||||
|
|
||||||
|
Markdown will translate it to:
|
||||||
|
|
||||||
|
4 < 5
|
||||||
|
|
||||||
|
However, inside Markdown code spans and blocks, angle brackets and
|
||||||
|
ampersands are *always* encoded automatically. This makes it easy to use
|
||||||
|
Markdown to write about HTML code. (As opposed to raw HTML, which is a
|
||||||
|
terrible format for writing about HTML syntax, because every single `<`
|
||||||
|
and `&` in your example code needs to be escaped.)
|
||||||
|
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="block">Block Elements</h2>
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="p">Paragraphs and Line Breaks</h3>
|
||||||
|
|
||||||
|
A paragraph is simply one or more consecutive lines of text, separated
|
||||||
|
by one or more blank lines. (A blank line is any line that looks like a
|
||||||
|
blank line -- a line containing nothing but spaces or tabs is considered
|
||||||
|
blank.) Normal paragraphs should not be intended with spaces or tabs.
|
||||||
|
|
||||||
|
The implication of the "one or more consecutive lines of text" rule is
|
||||||
|
that Markdown supports "hard-wrapped" text paragraphs. This differs
|
||||||
|
significantly from most other text-to-HTML formatters (including Movable
|
||||||
|
Type's "Convert Line Breaks" option) which translate every line break
|
||||||
|
character in a paragraph into a `<br />` tag.
|
||||||
|
|
||||||
|
When you *do* want to insert a `<br />` break tag using Markdown, you
|
||||||
|
end a line with two or more spaces, then type return.
|
||||||
|
|
||||||
|
Yes, this takes a tad more effort to create a `<br />`, but a simplistic
|
||||||
|
"every line break is a `<br />`" rule wouldn't work for Markdown.
|
||||||
|
Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l]
|
||||||
|
work best -- and look better -- when you format them with hard breaks.
|
||||||
|
|
||||||
|
[bq]: #blockquote
|
||||||
|
[l]: #list
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="header">Headers</h3>
|
||||||
|
|
||||||
|
Markdown supports two styles of headers, [Setext] [1] and [atx] [2].
|
||||||
|
|
||||||
|
Setext-style headers are "underlined" using equal signs (for first-level
|
||||||
|
headers) and dashes (for second-level headers). For example:
|
||||||
|
|
||||||
|
This is an H1
|
||||||
|
=============
|
||||||
|
|
||||||
|
This is an H2
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Any number of underlining `=`'s or `-`'s will work.
|
||||||
|
|
||||||
|
Atx-style headers use 1-6 hash characters at the start of the line,
|
||||||
|
corresponding to header levels 1-6. For example:
|
||||||
|
|
||||||
|
# This is an H1
|
||||||
|
|
||||||
|
## This is an H2
|
||||||
|
|
||||||
|
###### This is an H6
|
||||||
|
|
||||||
|
Optionally, you may "close" atx-style headers. This is purely
|
||||||
|
cosmetic -- you can use this if you think it looks better. The
|
||||||
|
closing hashes don't even need to match the number of hashes
|
||||||
|
used to open the header. (The number of opening hashes
|
||||||
|
determines the header level.) :
|
||||||
|
|
||||||
|
# This is an H1 #
|
||||||
|
|
||||||
|
## This is an H2 ##
|
||||||
|
|
||||||
|
### This is an H3 ######
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="blockquote">Blockquotes</h3>
|
||||||
|
|
||||||
|
Markdown uses email-style `>` characters for blockquoting. If you're
|
||||||
|
familiar with quoting passages of text in an email message, then you
|
||||||
|
know how to create a blockquote in Markdown. It looks best if you hard
|
||||||
|
wrap the text and put a `>` before every line:
|
||||||
|
|
||||||
|
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||||
|
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||||
|
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||||
|
>
|
||||||
|
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||||
|
> id sem consectetuer libero luctus adipiscing.
|
||||||
|
|
||||||
|
Markdown allows you to be lazy and only put the `>` before the first
|
||||||
|
line of a hard-wrapped paragraph:
|
||||||
|
|
||||||
|
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||||
|
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||||
|
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||||
|
|
||||||
|
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||||
|
id sem consectetuer libero luctus adipiscing.
|
||||||
|
|
||||||
|
Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
|
||||||
|
adding additional levels of `>`:
|
||||||
|
|
||||||
|
> This is the first level of quoting.
|
||||||
|
>
|
||||||
|
> > This is nested blockquote.
|
||||||
|
>
|
||||||
|
> Back to the first level.
|
||||||
|
|
||||||
|
Blockquotes can contain other Markdown elements, including headers, lists,
|
||||||
|
and code blocks:
|
||||||
|
|
||||||
|
> ## This is a header.
|
||||||
|
>
|
||||||
|
> 1. This is the first list item.
|
||||||
|
> 2. This is the second list item.
|
||||||
|
>
|
||||||
|
> Here's some example code:
|
||||||
|
>
|
||||||
|
> return shell_exec("echo $input | $markdown_script");
|
||||||
|
|
||||||
|
Any decent text editor should make email-style quoting easy. For
|
||||||
|
example, with BBEdit, you can make a selection and choose Increase
|
||||||
|
Quote Level from the Text menu.
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="list">Lists</h3>
|
||||||
|
|
||||||
|
Markdown supports ordered (numbered) and unordered (bulleted) lists.
|
||||||
|
|
||||||
|
Unordered lists use asterisks, pluses, and hyphens -- interchangably
|
||||||
|
-- as list markers:
|
||||||
|
|
||||||
|
* Red
|
||||||
|
* Green
|
||||||
|
* Blue
|
||||||
|
|
||||||
|
is equivalent to:
|
||||||
|
|
||||||
|
+ Red
|
||||||
|
+ Green
|
||||||
|
+ Blue
|
||||||
|
|
||||||
|
and:
|
||||||
|
|
||||||
|
- Red
|
||||||
|
- Green
|
||||||
|
- Blue
|
||||||
|
|
||||||
|
Ordered lists use numbers followed by periods:
|
||||||
|
|
||||||
|
1. Bird
|
||||||
|
2. McHale
|
||||||
|
3. Parish
|
||||||
|
|
||||||
|
It's important to note that the actual numbers you use to mark the
|
||||||
|
list have no effect on the HTML output Markdown produces. The HTML
|
||||||
|
Markdown produces from the above list is:
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>Bird</li>
|
||||||
|
<li>McHale</li>
|
||||||
|
<li>Parish</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
If you instead wrote the list in Markdown like this:
|
||||||
|
|
||||||
|
1. Bird
|
||||||
|
1. McHale
|
||||||
|
1. Parish
|
||||||
|
|
||||||
|
or even:
|
||||||
|
|
||||||
|
3. Bird
|
||||||
|
1. McHale
|
||||||
|
8. Parish
|
||||||
|
|
||||||
|
you'd get the exact same HTML output. The point is, if you want to,
|
||||||
|
you can use ordinal numbers in your ordered Markdown lists, so that
|
||||||
|
the numbers in your source match the numbers in your published HTML.
|
||||||
|
But if you want to be lazy, you don't have to.
|
||||||
|
|
||||||
|
If you do use lazy list numbering, however, you should still start the
|
||||||
|
list with the number 1. At some point in the future, Markdown may support
|
||||||
|
starting ordered lists at an arbitrary number.
|
||||||
|
|
||||||
|
List markers typically start at the left margin, but may be indented by
|
||||||
|
up to three spaces. List markers must be followed by one or more spaces
|
||||||
|
or a tab.
|
||||||
|
|
||||||
|
To make lists look nice, you can wrap items with hanging indents:
|
||||||
|
|
||||||
|
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||||
|
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||||
|
viverra nec, fringilla in, laoreet vitae, risus.
|
||||||
|
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||||
|
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||||
|
|
||||||
|
But if you want to be lazy, you don't have to:
|
||||||
|
|
||||||
|
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||||
|
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||||
|
viverra nec, fringilla in, laoreet vitae, risus.
|
||||||
|
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||||
|
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||||
|
|
||||||
|
If list items are separated by blank lines, Markdown will wrap the
|
||||||
|
items in `<p>` tags in the HTML output. For example, this input:
|
||||||
|
|
||||||
|
* Bird
|
||||||
|
* Magic
|
||||||
|
|
||||||
|
will turn into:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Bird</li>
|
||||||
|
<li>Magic</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
But this:
|
||||||
|
|
||||||
|
* Bird
|
||||||
|
|
||||||
|
* Magic
|
||||||
|
|
||||||
|
will turn into:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><p>Bird</p></li>
|
||||||
|
<li><p>Magic</p></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
List items may consist of multiple paragraphs. Each subsequent
|
||||||
|
paragraph in a list item must be intended by either 4 spaces
|
||||||
|
or one tab:
|
||||||
|
|
||||||
|
1. This is a list item with two paragraphs. Lorem ipsum dolor
|
||||||
|
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
|
||||||
|
mi posuere lectus.
|
||||||
|
|
||||||
|
Vestibulum enim wisi, viverra nec, fringilla in, laoreet
|
||||||
|
vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
|
||||||
|
sit amet velit.
|
||||||
|
|
||||||
|
2. Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||||
|
|
||||||
|
It looks nice if you indent every line of the subsequent
|
||||||
|
paragraphs, but here again, Markdown will allow you to be
|
||||||
|
lazy:
|
||||||
|
|
||||||
|
* This is a list item with two paragraphs.
|
||||||
|
|
||||||
|
This is the second paragraph in the list item. You're
|
||||||
|
only required to indent the first line. Lorem ipsum dolor
|
||||||
|
sit amet, consectetuer adipiscing elit.
|
||||||
|
|
||||||
|
* Another item in the same list.
|
||||||
|
|
||||||
|
To put a blockquote within a list item, the blockquote's `>`
|
||||||
|
delimiters need to be indented:
|
||||||
|
|
||||||
|
* A list item with a blockquote:
|
||||||
|
|
||||||
|
> This is a blockquote
|
||||||
|
> inside a list item.
|
||||||
|
|
||||||
|
To put a code block within a list item, the code block needs
|
||||||
|
to be indented *twice* -- 8 spaces or two tabs:
|
||||||
|
|
||||||
|
* A list item with a code block:
|
||||||
|
|
||||||
|
<code goes here>
|
||||||
|
|
||||||
|
|
||||||
|
It's worth noting that it's possible to trigger an ordered list by
|
||||||
|
accident, by writing something like this:
|
||||||
|
|
||||||
|
1986. What a great season.
|
||||||
|
|
||||||
|
In other words, a *number-period-space* sequence at the beginning of a
|
||||||
|
line. To avoid this, you can backslash-escape the period:
|
||||||
|
|
||||||
|
1986\. What a great season.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="precode">Code Blocks</h3>
|
||||||
|
|
||||||
|
Pre-formatted code blocks are used for writing about programming or
|
||||||
|
markup source code. Rather than forming normal paragraphs, the lines
|
||||||
|
of a code block are interpreted literally. Markdown wraps a code block
|
||||||
|
in both `<pre>` and `<code>` tags.
|
||||||
|
|
||||||
|
To produce a code block in Markdown, simply indent every line of the
|
||||||
|
block by at least 4 spaces or 1 tab. For example, given this input:
|
||||||
|
|
||||||
|
This is a normal paragraph:
|
||||||
|
|
||||||
|
This is a code block.
|
||||||
|
|
||||||
|
Markdown will generate:
|
||||||
|
|
||||||
|
<p>This is a normal paragraph:</p>
|
||||||
|
|
||||||
|
<pre><code>This is a code block.
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
One level of indentation -- 4 spaces or 1 tab -- is removed from each
|
||||||
|
line of the code block. For example, this:
|
||||||
|
|
||||||
|
Here is an example of AppleScript:
|
||||||
|
|
||||||
|
tell application "Foo"
|
||||||
|
beep
|
||||||
|
end tell
|
||||||
|
|
||||||
|
will turn into:
|
||||||
|
|
||||||
|
<p>Here is an example of AppleScript:</p>
|
||||||
|
|
||||||
|
<pre><code>tell application "Foo"
|
||||||
|
beep
|
||||||
|
end tell
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
A code block continues until it reaches a line that is not indented
|
||||||
|
(or the end of the article).
|
||||||
|
|
||||||
|
Within a code block, ampersands (`&`) and angle brackets (`<` and `>`)
|
||||||
|
are automatically converted into HTML entities. This makes it very
|
||||||
|
easy to include example HTML source code using Markdown -- just paste
|
||||||
|
it and indent it, and Markdown will handle the hassle of encoding the
|
||||||
|
ampersands and angle brackets. For example, this:
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
© 2004 Foo Corporation
|
||||||
|
</div>
|
||||||
|
|
||||||
|
will turn into:
|
||||||
|
|
||||||
|
<pre><code><div class="footer">
|
||||||
|
&copy; 2004 Foo Corporation
|
||||||
|
</div>
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
Regular Markdown syntax is not processed within code blocks. E.g.,
|
||||||
|
asterisks are just literal asterisks within a code block. This means
|
||||||
|
it's also easy to use Markdown to write about Markdown's own syntax.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="hr">Horizontal Rules</h3>
|
||||||
|
|
||||||
|
You can produce a horizontal rule tag (`<hr />`) by placing three or
|
||||||
|
more hyphens, asterisks, or underscores on a line by themselves. If you
|
||||||
|
wish, you may use spaces between the hyphens or asterisks. Each of the
|
||||||
|
following lines will produce a horizontal rule:
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
*****
|
||||||
|
|
||||||
|
- - -
|
||||||
|
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
_ _ _
|
||||||
|
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
<h2 id="span">Span Elements</h2>
|
||||||
|
|
||||||
|
<h3 id="link">Links</h3>
|
||||||
|
|
||||||
|
Markdown supports two style of links: *inline* and *reference*.
|
||||||
|
|
||||||
|
In both styles, the link text is delimited by [square brackets].
|
||||||
|
|
||||||
|
To create an inline link, use a set of regular parentheses immediately
|
||||||
|
after the link text's closing square bracket. Inside the parentheses,
|
||||||
|
put the URL where you want the link to point, along with an *optional*
|
||||||
|
title for the link, surrounded in quotes. For example:
|
||||||
|
|
||||||
|
This is [an example](http://example.com/ "Title") inline link.
|
||||||
|
|
||||||
|
[This link](http://example.net/) has no title attribute.
|
||||||
|
|
||||||
|
Will produce:
|
||||||
|
|
||||||
|
<p>This is <a href="http://example.com/" title="Title">
|
||||||
|
an example</a> inline link.</p>
|
||||||
|
|
||||||
|
<p><a href="http://example.net/">This link</a> has no
|
||||||
|
title attribute.</p>
|
||||||
|
|
||||||
|
If you're referring to a local resource on the same server, you can
|
||||||
|
use relative paths:
|
||||||
|
|
||||||
|
See my [About](/about/) page for details.
|
||||||
|
|
||||||
|
Reference-style links use a second set of square brackets, inside
|
||||||
|
which you place a label of your choosing to identify the link:
|
||||||
|
|
||||||
|
This is [an example][id] reference-style link.
|
||||||
|
|
||||||
|
You can optionally use a space to separate the sets of brackets:
|
||||||
|
|
||||||
|
This is [an example] [id] reference-style link.
|
||||||
|
|
||||||
|
Then, anywhere in the document, you define your link label like this,
|
||||||
|
on a line by itself:
|
||||||
|
|
||||||
|
[id]: http://example.com/ "Optional Title Here"
|
||||||
|
|
||||||
|
That is:
|
||||||
|
|
||||||
|
* Square brackets containing the link identifier (optionally
|
||||||
|
indented from the left margin using up to three spaces);
|
||||||
|
* followed by a colon;
|
||||||
|
* followed by one or more spaces (or tabs);
|
||||||
|
* followed by the URL for the link;
|
||||||
|
* optionally followed by a title attribute for the link, enclosed
|
||||||
|
in double or single quotes.
|
||||||
|
|
||||||
|
The link URL may, optionally, be surrounded by angle brackets:
|
||||||
|
|
||||||
|
[id]: <http://example.com/> "Optional Title Here"
|
||||||
|
|
||||||
|
You can put the title attribute on the next line and use extra spaces
|
||||||
|
or tabs for padding, which tends to look better with longer URLs:
|
||||||
|
|
||||||
|
[id]: http://example.com/longish/path/to/resource/here
|
||||||
|
"Optional Title Here"
|
||||||
|
|
||||||
|
Link definitions are only used for creating links during Markdown
|
||||||
|
processing, and are stripped from your document in the HTML output.
|
||||||
|
|
||||||
|
Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are *not* case sensitive. E.g. these two links:
|
||||||
|
|
||||||
|
[link text][a]
|
||||||
|
[link text][A]
|
||||||
|
|
||||||
|
are equivalent.
|
||||||
|
|
||||||
|
The *implicit link name* shortcut allows you to omit the name of the
|
||||||
|
link, in which case the link text itself is used as the name.
|
||||||
|
Just use an empty set of square brackets -- e.g., to link the word
|
||||||
|
"Google" to the google.com web site, you could simply write:
|
||||||
|
|
||||||
|
[Google][]
|
||||||
|
|
||||||
|
And then define the link:
|
||||||
|
|
||||||
|
[Google]: http://google.com/
|
||||||
|
|
||||||
|
Because link names may contain spaces, this shortcut even works for
|
||||||
|
multiple words in the link text:
|
||||||
|
|
||||||
|
Visit [Daring Fireball][] for more information.
|
||||||
|
|
||||||
|
And then define the link:
|
||||||
|
|
||||||
|
[Daring Fireball]: http://daringfireball.net/
|
||||||
|
|
||||||
|
Link definitions can be placed anywhere in your Markdown document. I
|
||||||
|
tend to put them immediately after each paragraph in which they're
|
||||||
|
used, but if you want, you can put them all at the end of your
|
||||||
|
document, sort of like footnotes.
|
||||||
|
|
||||||
|
Here's an example of reference links in action:
|
||||||
|
|
||||||
|
I get 10 times more traffic from [Google] [1] than from
|
||||||
|
[Yahoo] [2] or [MSN] [3].
|
||||||
|
|
||||||
|
[1]: http://google.com/ "Google"
|
||||||
|
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||||
|
[3]: http://search.msn.com/ "MSN Search"
|
||||||
|
|
||||||
|
Using the implicit link name shortcut, you could instead write:
|
||||||
|
|
||||||
|
I get 10 times more traffic from [Google][] than from
|
||||||
|
[Yahoo][] or [MSN][].
|
||||||
|
|
||||||
|
[google]: http://google.com/ "Google"
|
||||||
|
[yahoo]: http://search.yahoo.com/ "Yahoo Search"
|
||||||
|
[msn]: http://search.msn.com/ "MSN Search"
|
||||||
|
|
||||||
|
Both of the above examples will produce the following HTML output:
|
||||||
|
|
||||||
|
<p>I get 10 times more traffic from <a href="http://google.com/"
|
||||||
|
title="Google">Google</a> than from
|
||||||
|
<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
|
||||||
|
or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
|
||||||
|
|
||||||
|
For comparison, here is the same paragraph written using
|
||||||
|
Markdown's inline link style:
|
||||||
|
|
||||||
|
I get 10 times more traffic from [Google](http://google.com/ "Google")
|
||||||
|
than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
|
||||||
|
[MSN](http://search.msn.com/ "MSN Search").
|
||||||
|
|
||||||
|
The point of reference-style links is not that they're easier to
|
||||||
|
write. The point is that with reference-style links, your document
|
||||||
|
source is vastly more readable. Compare the above examples: using
|
||||||
|
reference-style links, the paragraph itself is only 81 characters
|
||||||
|
long; with inline-style links, it's 176 characters; and as raw HTML,
|
||||||
|
it's 234 characters. In the raw HTML, there's more markup than there
|
||||||
|
is text.
|
||||||
|
|
||||||
|
With Markdown's reference-style links, a source document much more
|
||||||
|
closely resembles the final output, as rendered in a browser. By
|
||||||
|
allowing you to move the markup-related metadata out of the paragraph,
|
||||||
|
you can add links without interrupting the narrative flow of your
|
||||||
|
prose.
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="em">Emphasis</h3>
|
||||||
|
|
||||||
|
Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
|
||||||
|
emphasis. Text wrapped with one `*` or `_` will be wrapped with an
|
||||||
|
HTML `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML
|
||||||
|
`<strong>` tag. E.g., this input:
|
||||||
|
|
||||||
|
*single asterisks*
|
||||||
|
|
||||||
|
_single underscores_
|
||||||
|
|
||||||
|
**double asterisks**
|
||||||
|
|
||||||
|
__double underscores__
|
||||||
|
|
||||||
|
will produce:
|
||||||
|
|
||||||
|
<em>single asterisks</em>
|
||||||
|
|
||||||
|
<em>single underscores</em>
|
||||||
|
|
||||||
|
<strong>double asterisks</strong>
|
||||||
|
|
||||||
|
<strong>double underscores</strong>
|
||||||
|
|
||||||
|
You can use whichever style you prefer; the lone restriction is that
|
||||||
|
the same character must be used to open and close an emphasis span.
|
||||||
|
|
||||||
|
Emphasis can be used in the middle of a word:
|
||||||
|
|
||||||
|
un*fucking*believable
|
||||||
|
|
||||||
|
But if you surround an `*` or `_` with spaces, it'll be treated as a
|
||||||
|
literal asterisk or underscore.
|
||||||
|
|
||||||
|
To produce a literal asterisk or underscore at a position where it
|
||||||
|
would otherwise be used as an emphasis delimiter, you can backslash
|
||||||
|
escape it:
|
||||||
|
|
||||||
|
\*this text is surrounded by literal asterisks\*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="code">Code</h3>
|
||||||
|
|
||||||
|
To indicate a span of code, wrap it with backtick quotes (`` ` ``).
|
||||||
|
Unlike a pre-formatted code block, a code span indicates code within a
|
||||||
|
normal paragraph. For example:
|
||||||
|
|
||||||
|
Use the `printf()` function.
|
||||||
|
|
||||||
|
will produce:
|
||||||
|
|
||||||
|
<p>Use the <code>printf()</code> function.</p>
|
||||||
|
|
||||||
|
To include a literal backtick character within a code span, you can use
|
||||||
|
multiple backticks as the opening and closing delimiters:
|
||||||
|
|
||||||
|
``There is a literal backtick (`) here.``
|
||||||
|
|
||||||
|
which will produce this:
|
||||||
|
|
||||||
|
<p><code>There is a literal backtick (`) here.</code></p>
|
||||||
|
|
||||||
|
The backtick delimiters surrounding a code span may include spaces --
|
||||||
|
one after the opening, one before the closing. This allows you to place
|
||||||
|
literal backtick characters at the beginning or end of a code span:
|
||||||
|
|
||||||
|
A single backtick in a code span: `` ` ``
|
||||||
|
|
||||||
|
A backtick-delimited string in a code span: `` `foo` ``
|
||||||
|
|
||||||
|
will produce:
|
||||||
|
|
||||||
|
<p>A single backtick in a code span: <code>`</code></p>
|
||||||
|
|
||||||
|
<p>A backtick-delimited string in a code span: <code>`foo`</code></p>
|
||||||
|
|
||||||
|
With a code span, ampersands and angle brackets are encoded as HTML
|
||||||
|
entities automatically, which makes it easy to include example HTML
|
||||||
|
tags. Markdown will turn this:
|
||||||
|
|
||||||
|
Please don't use any `<blink>` tags.
|
||||||
|
|
||||||
|
into:
|
||||||
|
|
||||||
|
<p>Please don't use any <code><blink></code> tags.</p>
|
||||||
|
|
||||||
|
You can write this:
|
||||||
|
|
||||||
|
`—` is the decimal-encoded equivalent of `—`.
|
||||||
|
|
||||||
|
to produce:
|
||||||
|
|
||||||
|
<p><code>&#8212;</code> is the decimal-encoded
|
||||||
|
equivalent of <code>&mdash;</code>.</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="img">Images</h3>
|
||||||
|
|
||||||
|
Admittedly, it's fairly difficult to devise a "natural" syntax for
|
||||||
|
placing images into a plain text document format.
|
||||||
|
|
||||||
|
Markdown uses an image syntax that is intended to resemble the syntax
|
||||||
|
for links, allowing for two styles: *inline* and *reference*.
|
||||||
|
|
||||||
|
Inline image syntax looks like this:
|
||||||
|
|
||||||
|
![Alt text](/path/to/img.jpg)
|
||||||
|
|
||||||
|
![Alt text](/path/to/img.jpg "Optional title")
|
||||||
|
|
||||||
|
That is:
|
||||||
|
|
||||||
|
* An exclamation mark: `!`;
|
||||||
|
* followed by a set of square brackets, containing the `alt`
|
||||||
|
attribute text for the image;
|
||||||
|
* followed by a set of parentheses, containing the URL or path to
|
||||||
|
the image, and an optional `title` attribute enclosed in double
|
||||||
|
or single quotes.
|
||||||
|
|
||||||
|
Reference-style image syntax looks like this:
|
||||||
|
|
||||||
|
![Alt text][id]
|
||||||
|
|
||||||
|
Where "id" is the name of a defined image reference. Image references
|
||||||
|
are defined using syntax identical to link references:
|
||||||
|
|
||||||
|
[id]: url/to/image "Optional title attribute"
|
||||||
|
|
||||||
|
As of this writing, Markdown has no syntax for specifying the
|
||||||
|
dimensions of an image; if this is important to you, you can simply
|
||||||
|
use regular HTML `<img>` tags.
|
||||||
|
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
|
||||||
|
<h2 id="misc">Miscellaneous</h2>
|
||||||
|
|
||||||
|
<h3 id="autolink">Automatic Links</h3>
|
||||||
|
|
||||||
|
Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:
|
||||||
|
|
||||||
|
<http://example.com/>
|
||||||
|
|
||||||
|
Markdown will turn this into:
|
||||||
|
|
||||||
|
<a href="http://example.com/">http://example.com/</a>
|
||||||
|
|
||||||
|
Automatic links for email addresses work similarly, except that
|
||||||
|
Markdown will also perform a bit of randomized decimal and hex
|
||||||
|
entity-encoding to help obscure your address from address-harvesting
|
||||||
|
spambots. For example, Markdown will turn this:
|
||||||
|
|
||||||
|
<address@example.com>
|
||||||
|
|
||||||
|
into something like this:
|
||||||
|
|
||||||
|
<a href="mailto:addre
|
||||||
|
ss@example.co
|
||||||
|
m">address@exa
|
||||||
|
mple.com</a>
|
||||||
|
|
||||||
|
which will render in a browser as a clickable link to "address@example.com".
|
||||||
|
|
||||||
|
(This sort of entity-encoding trick will indeed fool many, if not
|
||||||
|
most, address-harvesting bots, but it definitely won't fool all of
|
||||||
|
them. It's better than nothing, but an address published in this way
|
||||||
|
will probably eventually start receiving spam.)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="backslash">Backslash Escapes</h3>
|
||||||
|
|
||||||
|
Markdown allows you to use backslash escapes to generate literal
|
||||||
|
characters which would otherwise have special meaning in Markdown's
|
||||||
|
formatting syntax. For example, if you wanted to surround a word with
|
||||||
|
literal asterisks (instead of an HTML `<em>` tag), you can backslashes
|
||||||
|
before the asterisks, like this:
|
||||||
|
|
||||||
|
\*literal asterisks\*
|
||||||
|
|
||||||
|
Markdown provides backslash escapes for the following characters:
|
||||||
|
|
||||||
|
\ backslash
|
||||||
|
` backtick
|
||||||
|
* asterisk
|
||||||
|
_ underscore
|
||||||
|
{} curly braces
|
||||||
|
[] square brackets
|
||||||
|
() parentheses
|
||||||
|
# hash mark
|
||||||
|
+ plus sign
|
||||||
|
- minus sign (hyphen)
|
||||||
|
. dot
|
||||||
|
! exclamation mark
|
||||||
|
|
9
vendor/github.com/russross/blackfriday/testdata/Nested blockquotes.html
generated
vendored
Normal file
9
vendor/github.com/russross/blackfriday/testdata/Nested blockquotes.html
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<blockquote>
|
||||||
|
<p>foo</p>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<p>bar</p>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>foo</p>
|
||||||
|
</blockquote>
|
5
vendor/github.com/russross/blackfriday/testdata/Nested blockquotes.text
generated
vendored
Normal file
5
vendor/github.com/russross/blackfriday/testdata/Nested blockquotes.text
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
> foo
|
||||||
|
>
|
||||||
|
> > bar
|
||||||
|
>
|
||||||
|
> foo
|
166
vendor/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html
generated
vendored
Normal file
166
vendor/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<h2>Unordered</h2>
|
||||||
|
|
||||||
|
<p>Asterisks tight:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>asterisk 1</li>
|
||||||
|
<li>asterisk 2</li>
|
||||||
|
<li>asterisk 3</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Asterisks loose:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><p>asterisk 1</p></li>
|
||||||
|
|
||||||
|
<li><p>asterisk 2</p></li>
|
||||||
|
|
||||||
|
<li><p>asterisk 3</p></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p>Pluses tight:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Plus 1</li>
|
||||||
|
<li>Plus 2</li>
|
||||||
|
<li>Plus 3</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Pluses loose:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><p>Plus 1</p></li>
|
||||||
|
|
||||||
|
<li><p>Plus 2</p></li>
|
||||||
|
|
||||||
|
<li><p>Plus 3</p></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p>Minuses tight:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Minus 1</li>
|
||||||
|
<li>Minus 2</li>
|
||||||
|
<li>Minus 3</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Minuses loose:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><p>Minus 1</p></li>
|
||||||
|
|
||||||
|
<li><p>Minus 2</p></li>
|
||||||
|
|
||||||
|
<li><p>Minus 3</p></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Ordered</h2>
|
||||||
|
|
||||||
|
<p>Tight:</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>First</li>
|
||||||
|
<li>Second</li>
|
||||||
|
<li>Third</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>and:</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>One</li>
|
||||||
|
<li>Two</li>
|
||||||
|
<li>Three</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>Loose using tabs:</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li><p>First</p></li>
|
||||||
|
|
||||||
|
<li><p>Second</p></li>
|
||||||
|
|
||||||
|
<li><p>Third</p></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>and using spaces:</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li><p>One</p></li>
|
||||||
|
|
||||||
|
<li><p>Two</p></li>
|
||||||
|
|
||||||
|
<li><p>Three</p></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>Multiple paragraphs:</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li><p>Item 1, graf one.</p>
|
||||||
|
|
||||||
|
<p>Item 2. graf two. The quick brown fox jumped over the lazy dog's
|
||||||
|
back.</p></li>
|
||||||
|
|
||||||
|
<li><p>Item 2.</p></li>
|
||||||
|
|
||||||
|
<li><p>Item 3.</p></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h2>Nested</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Tab
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Tab
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Tab</li>
|
||||||
|
</ul></li>
|
||||||
|
</ul></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Here's another:</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>First</li>
|
||||||
|
<li>Second:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Fee</li>
|
||||||
|
<li>Fie</li>
|
||||||
|
<li>Foe</li>
|
||||||
|
</ul></li>
|
||||||
|
<li>Third</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>Same thing but with paragraphs:</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li><p>First</p></li>
|
||||||
|
|
||||||
|
<li><p>Second:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Fee</li>
|
||||||
|
<li>Fie</li>
|
||||||
|
<li>Foe</li>
|
||||||
|
</ul></li>
|
||||||
|
|
||||||
|
<li><p>Third</p></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>This was an error in Markdown 1.0.1:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><p>this</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>sub</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>that</p></li>
|
||||||
|
</ul>
|
131
vendor/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text
generated
vendored
Normal file
131
vendor/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text
generated
vendored
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
## Unordered
|
||||||
|
|
||||||
|
Asterisks tight:
|
||||||
|
|
||||||
|
* asterisk 1
|
||||||
|
* asterisk 2
|
||||||
|
* asterisk 3
|
||||||
|
|
||||||
|
|
||||||
|
Asterisks loose:
|
||||||
|
|
||||||
|
* asterisk 1
|
||||||
|
|
||||||
|
* asterisk 2
|
||||||
|
|
||||||
|
* asterisk 3
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
Pluses tight:
|
||||||
|
|
||||||
|
+ Plus 1
|
||||||
|
+ Plus 2
|
||||||
|
+ Plus 3
|
||||||
|
|
||||||
|
|
||||||
|
Pluses loose:
|
||||||
|
|
||||||
|
+ Plus 1
|
||||||
|
|
||||||
|
+ Plus 2
|
||||||
|
|
||||||
|
+ Plus 3
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
|
||||||
|
Minuses tight:
|
||||||
|
|
||||||
|
- Minus 1
|
||||||
|
- Minus 2
|
||||||
|
- Minus 3
|
||||||
|
|
||||||
|
|
||||||
|
Minuses loose:
|
||||||
|
|
||||||
|
- Minus 1
|
||||||
|
|
||||||
|
- Minus 2
|
||||||
|
|
||||||
|
- Minus 3
|
||||||
|
|
||||||
|
|
||||||
|
## Ordered
|
||||||
|
|
||||||
|
Tight:
|
||||||
|
|
||||||
|
1. First
|
||||||
|
2. Second
|
||||||
|
3. Third
|
||||||
|
|
||||||
|
and:
|
||||||
|
|
||||||
|
1. One
|
||||||
|
2. Two
|
||||||
|
3. Three
|
||||||
|
|
||||||
|
|
||||||
|
Loose using tabs:
|
||||||
|
|
||||||
|
1. First
|
||||||
|
|
||||||
|
2. Second
|
||||||
|
|
||||||
|
3. Third
|
||||||
|
|
||||||
|
and using spaces:
|
||||||
|
|
||||||
|
1. One
|
||||||
|
|
||||||
|
2. Two
|
||||||
|
|
||||||
|
3. Three
|
||||||
|
|
||||||
|
Multiple paragraphs:
|
||||||
|
|
||||||
|
1. Item 1, graf one.
|
||||||
|
|
||||||
|
Item 2. graf two. The quick brown fox jumped over the lazy dog's
|
||||||
|
back.
|
||||||
|
|
||||||
|
2. Item 2.
|
||||||
|
|
||||||
|
3. Item 3.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Nested
|
||||||
|
|
||||||
|
* Tab
|
||||||
|
* Tab
|
||||||
|
* Tab
|
||||||
|
|
||||||
|
Here's another:
|
||||||
|
|
||||||
|
1. First
|
||||||
|
2. Second:
|
||||||
|
* Fee
|
||||||
|
* Fie
|
||||||
|
* Foe
|
||||||
|
3. Third
|
||||||
|
|
||||||
|
Same thing but with paragraphs:
|
||||||
|
|
||||||
|
1. First
|
||||||
|
|
||||||
|
2. Second:
|
||||||
|
* Fee
|
||||||
|
* Fie
|
||||||
|
* Foe
|
||||||
|
|
||||||
|
3. Third
|
||||||
|
|
||||||
|
|
||||||
|
This was an error in Markdown 1.0.1:
|
||||||
|
|
||||||
|
* this
|
||||||
|
|
||||||
|
* sub
|
||||||
|
|
||||||
|
that
|
7
vendor/github.com/russross/blackfriday/testdata/Strong and em together.html
generated
vendored
Normal file
7
vendor/github.com/russross/blackfriday/testdata/Strong and em together.html
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<p><strong><em>This is strong and em.</em></strong></p>
|
||||||
|
|
||||||
|
<p>So is <strong><em>this</em></strong> word.</p>
|
||||||
|
|
||||||
|
<p><strong><em>This is strong and em.</em></strong></p>
|
||||||
|
|
||||||
|
<p>So is <strong><em>this</em></strong> word.</p>
|
7
vendor/github.com/russross/blackfriday/testdata/Strong and em together.text
generated
vendored
Normal file
7
vendor/github.com/russross/blackfriday/testdata/Strong and em together.text
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
***This is strong and em.***
|
||||||
|
|
||||||
|
So is ***this*** word.
|
||||||
|
|
||||||
|
___This is strong and em.___
|
||||||
|
|
||||||
|
So is ___this___ word.
|
26
vendor/github.com/russross/blackfriday/testdata/Tabs.html
generated
vendored
Normal file
26
vendor/github.com/russross/blackfriday/testdata/Tabs.html
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<ul>
|
||||||
|
<li><p>this is a list item
|
||||||
|
indented with tabs</p></li>
|
||||||
|
|
||||||
|
<li><p>this is a list item
|
||||||
|
indented with spaces</p></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Code:</p>
|
||||||
|
|
||||||
|
<pre><code>this code block is indented by one tab
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>And:</p>
|
||||||
|
|
||||||
|
<pre><code> this code block is indented by two tabs
|
||||||
|
</code></pre>
|
||||||
|
|
||||||
|
<p>And:</p>
|
||||||
|
|
||||||
|
<pre><code>+ this is an example list item
|
||||||
|
indented with tabs
|
||||||
|
|
||||||
|
+ this is an example list item
|
||||||
|
indented with spaces
|
||||||
|
</code></pre>
|
21
vendor/github.com/russross/blackfriday/testdata/Tabs.text
generated
vendored
Normal file
21
vendor/github.com/russross/blackfriday/testdata/Tabs.text
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
+ this is a list item
|
||||||
|
indented with tabs
|
||||||
|
|
||||||
|
+ this is a list item
|
||||||
|
indented with spaces
|
||||||
|
|
||||||
|
Code:
|
||||||
|
|
||||||
|
this code block is indented by one tab
|
||||||
|
|
||||||
|
And:
|
||||||
|
|
||||||
|
this code block is indented by two tabs
|
||||||
|
|
||||||
|
And:
|
||||||
|
|
||||||
|
+ this is an example list item
|
||||||
|
indented with tabs
|
||||||
|
|
||||||
|
+ this is an example list item
|
||||||
|
indented with spaces
|
9
vendor/github.com/russross/blackfriday/testdata/Tidyness.html
generated
vendored
Normal file
9
vendor/github.com/russross/blackfriday/testdata/Tidyness.html
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<blockquote>
|
||||||
|
<p>A list within a blockquote:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>asterisk 1</li>
|
||||||
|
<li>asterisk 2</li>
|
||||||
|
<li>asterisk 3</li>
|
||||||
|
</ul>
|
||||||
|
</blockquote>
|
5
vendor/github.com/russross/blackfriday/testdata/Tidyness.text
generated
vendored
Normal file
5
vendor/github.com/russross/blackfriday/testdata/Tidyness.text
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
> A list within a blockquote:
|
||||||
|
>
|
||||||
|
> * asterisk 1
|
||||||
|
> * asterisk 2
|
||||||
|
> * asterisk 3
|
16
vendor/github.com/shurcooL/sanitized_anchor_name/.travis.yml
generated
vendored
Normal file
16
vendor/github.com/shurcooL/sanitized_anchor_name/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
sudo: false
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.x
|
||||||
|
- master
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- go: master
|
||||||
|
fast_finish: true
|
||||||
|
install:
|
||||||
|
- # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step).
|
||||||
|
script:
|
||||||
|
- go get -t -v ./...
|
||||||
|
- diff -u <(echo -n) <(gofmt -d -s .)
|
||||||
|
- go tool vet .
|
||||||
|
- go test -v -race ./...
|
21
vendor/github.com/shurcooL/sanitized_anchor_name/LICENSE
generated
vendored
Normal file
21
vendor/github.com/shurcooL/sanitized_anchor_name/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2015 Dmitri Shuralyov
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
36
vendor/github.com/shurcooL/sanitized_anchor_name/README.md
generated
vendored
Normal file
36
vendor/github.com/shurcooL/sanitized_anchor_name/README.md
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
sanitized_anchor_name
|
||||||
|
=====================
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/shurcooL/sanitized_anchor_name.svg?branch=master)](https://travis-ci.org/shurcooL/sanitized_anchor_name) [![GoDoc](https://godoc.org/github.com/shurcooL/sanitized_anchor_name?status.svg)](https://godoc.org/github.com/shurcooL/sanitized_anchor_name)
|
||||||
|
|
||||||
|
Package sanitized_anchor_name provides a func to create sanitized anchor names.
|
||||||
|
|
||||||
|
Its logic can be reused by multiple packages to create interoperable anchor names
|
||||||
|
and links to those anchors.
|
||||||
|
|
||||||
|
At this time, it does not try to ensure that generated anchor names
|
||||||
|
are unique, that responsibility falls on the caller.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get -u github.com/shurcooL/sanitized_anchor_name
|
||||||
|
```
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
```Go
|
||||||
|
anchorName := sanitized_anchor_name.Create("This is a header")
|
||||||
|
|
||||||
|
fmt.Println(anchorName)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// this-is-a-header
|
||||||
|
```
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
- [MIT License](LICENSE)
|
29
vendor/github.com/shurcooL/sanitized_anchor_name/main.go
generated
vendored
Normal file
29
vendor/github.com/shurcooL/sanitized_anchor_name/main.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Package sanitized_anchor_name provides a func to create sanitized anchor names.
|
||||||
|
//
|
||||||
|
// Its logic can be reused by multiple packages to create interoperable anchor names
|
||||||
|
// and links to those anchors.
|
||||||
|
//
|
||||||
|
// At this time, it does not try to ensure that generated anchor names
|
||||||
|
// are unique, that responsibility falls on the caller.
|
||||||
|
package sanitized_anchor_name // import "github.com/shurcooL/sanitized_anchor_name"
|
||||||
|
|
||||||
|
import "unicode"
|
||||||
|
|
||||||
|
// Create returns a sanitized anchor name for the given text.
|
||||||
|
func Create(text string) string {
|
||||||
|
var anchorName []rune
|
||||||
|
var futureDash = false
|
||||||
|
for _, r := range []rune(text) {
|
||||||
|
switch {
|
||||||
|
case unicode.IsLetter(r) || unicode.IsNumber(r):
|
||||||
|
if futureDash && len(anchorName) > 0 {
|
||||||
|
anchorName = append(anchorName, '-')
|
||||||
|
}
|
||||||
|
futureDash = false
|
||||||
|
anchorName = append(anchorName, unicode.ToLower(r))
|
||||||
|
default:
|
||||||
|
futureDash = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(anchorName)
|
||||||
|
}
|
35
vendor/github.com/shurcooL/sanitized_anchor_name/main_test.go
generated
vendored
Normal file
35
vendor/github.com/shurcooL/sanitized_anchor_name/main_test.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package sanitized_anchor_name_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/shurcooL/sanitized_anchor_name"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleCreate() {
|
||||||
|
anchorName := sanitized_anchor_name.Create("This is a header")
|
||||||
|
|
||||||
|
fmt.Println(anchorName)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// this-is-a-header
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleCreate_two() {
|
||||||
|
fmt.Println(sanitized_anchor_name.Create("This is a header"))
|
||||||
|
fmt.Println(sanitized_anchor_name.Create("This is also a header"))
|
||||||
|
fmt.Println(sanitized_anchor_name.Create("main.go"))
|
||||||
|
fmt.Println(sanitized_anchor_name.Create("Article 123"))
|
||||||
|
fmt.Println(sanitized_anchor_name.Create("<- Let's try this, shall we?"))
|
||||||
|
fmt.Printf("%q\n", sanitized_anchor_name.Create(" "))
|
||||||
|
fmt.Println(sanitized_anchor_name.Create("Hello, 世界"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// this-is-a-header
|
||||||
|
// this-is-also-a-header
|
||||||
|
// main-go
|
||||||
|
// article-123
|
||||||
|
// let-s-try-this-shall-we
|
||||||
|
// ""
|
||||||
|
// hello-世界
|
||||||
|
}
|
9
vendor/gopkg.in/yaml.v2/.travis.yml
generated
vendored
Normal file
9
vendor/gopkg.in/yaml.v2/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.4
|
||||||
|
- 1.5
|
||||||
|
- 1.6
|
||||||
|
- tip
|
||||||
|
|
||||||
|
go_import_path: gopkg.in/yaml.v2
|
13
vendor/gopkg.in/yaml.v2/LICENSE
generated
vendored
Normal file
13
vendor/gopkg.in/yaml.v2/LICENSE
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Copyright 2011-2016 Canonical Ltd.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
31
vendor/gopkg.in/yaml.v2/LICENSE.libyaml
generated
vendored
Normal file
31
vendor/gopkg.in/yaml.v2/LICENSE.libyaml
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
The following files were ported to Go from C files of libyaml, and thus
|
||||||
|
are still covered by their original copyright and license:
|
||||||
|
|
||||||
|
apic.go
|
||||||
|
emitterc.go
|
||||||
|
parserc.go
|
||||||
|
readerc.go
|
||||||
|
scannerc.go
|
||||||
|
writerc.go
|
||||||
|
yamlh.go
|
||||||
|
yamlprivateh.go
|
||||||
|
|
||||||
|
Copyright (c) 2006 Kirill Simonov
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
133
vendor/gopkg.in/yaml.v2/README.md
generated
vendored
Normal file
133
vendor/gopkg.in/yaml.v2/README.md
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
# YAML support for the Go language
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
The yaml package enables Go programs to comfortably encode and decode YAML
|
||||||
|
values. It was developed within [Canonical](https://www.canonical.com) as
|
||||||
|
part of the [juju](https://juju.ubuntu.com) project, and is based on a
|
||||||
|
pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML)
|
||||||
|
C library to parse and generate YAML data quickly and reliably.
|
||||||
|
|
||||||
|
Compatibility
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The yaml package supports most of YAML 1.1 and 1.2, including support for
|
||||||
|
anchors, tags, map merging, etc. Multi-document unmarshalling is not yet
|
||||||
|
implemented, and base-60 floats from YAML 1.1 are purposefully not
|
||||||
|
supported since they're a poor design and are gone in YAML 1.2.
|
||||||
|
|
||||||
|
Installation and usage
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
The import path for the package is *gopkg.in/yaml.v2*.
|
||||||
|
|
||||||
|
To install it, run:
|
||||||
|
|
||||||
|
go get gopkg.in/yaml.v2
|
||||||
|
|
||||||
|
API documentation
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
If opened in a browser, the import path itself leads to the API documentation:
|
||||||
|
|
||||||
|
* [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2)
|
||||||
|
|
||||||
|
API stability
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in).
|
||||||
|
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
The yaml package is licensed under the Apache License 2.0. Please see the LICENSE file for details.
|
||||||
|
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
Some more examples can be found in the "examples" folder.
|
||||||
|
|
||||||
|
```Go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var data = `
|
||||||
|
a: Easy!
|
||||||
|
b:
|
||||||
|
c: 2
|
||||||
|
d: [3, 4]
|
||||||
|
`
|
||||||
|
|
||||||
|
type T struct {
|
||||||
|
A string
|
||||||
|
B struct {
|
||||||
|
RenamedC int `yaml:"c"`
|
||||||
|
D []int `yaml:",flow"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
t := T{}
|
||||||
|
|
||||||
|
err := yaml.Unmarshal([]byte(data), &t)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("--- t:\n%v\n\n", t)
|
||||||
|
|
||||||
|
d, err := yaml.Marshal(&t)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("--- t dump:\n%s\n\n", string(d))
|
||||||
|
|
||||||
|
m := make(map[interface{}]interface{})
|
||||||
|
|
||||||
|
err = yaml.Unmarshal([]byte(data), &m)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("--- m:\n%v\n\n", m)
|
||||||
|
|
||||||
|
d, err = yaml.Marshal(&m)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Printf("--- m dump:\n%s\n\n", string(d))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This example will generate the following output:
|
||||||
|
|
||||||
|
```
|
||||||
|
--- t:
|
||||||
|
{Easy! {2 [3 4]}}
|
||||||
|
|
||||||
|
--- t dump:
|
||||||
|
a: Easy!
|
||||||
|
b:
|
||||||
|
c: 2
|
||||||
|
d: [3, 4]
|
||||||
|
|
||||||
|
|
||||||
|
--- m:
|
||||||
|
map[a:Easy! b:map[c:2 d:[3 4]]]
|
||||||
|
|
||||||
|
--- m dump:
|
||||||
|
a: Easy!
|
||||||
|
b:
|
||||||
|
c: 2
|
||||||
|
d:
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
```
|
||||||
|
|
742
vendor/gopkg.in/yaml.v2/apic.go
generated
vendored
Normal file
742
vendor/gopkg.in/yaml.v2/apic.go
generated
vendored
Normal file
@ -0,0 +1,742 @@
|
|||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) {
|
||||||
|
//fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens))
|
||||||
|
|
||||||
|
// Check if we can move the queue at the beginning of the buffer.
|
||||||
|
if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) {
|
||||||
|
if parser.tokens_head != len(parser.tokens) {
|
||||||
|
copy(parser.tokens, parser.tokens[parser.tokens_head:])
|
||||||
|
}
|
||||||
|
parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head]
|
||||||
|
parser.tokens_head = 0
|
||||||
|
}
|
||||||
|
parser.tokens = append(parser.tokens, *token)
|
||||||
|
if pos < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:])
|
||||||
|
parser.tokens[parser.tokens_head+pos] = *token
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new parser object.
|
||||||
|
func yaml_parser_initialize(parser *yaml_parser_t) bool {
|
||||||
|
*parser = yaml_parser_t{
|
||||||
|
raw_buffer: make([]byte, 0, input_raw_buffer_size),
|
||||||
|
buffer: make([]byte, 0, input_buffer_size),
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy a parser object.
|
||||||
|
func yaml_parser_delete(parser *yaml_parser_t) {
|
||||||
|
*parser = yaml_parser_t{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String read handler.
|
||||||
|
func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
|
||||||
|
if parser.input_pos == len(parser.input) {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
n = copy(buffer, parser.input[parser.input_pos:])
|
||||||
|
parser.input_pos += n
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// File read handler.
|
||||||
|
func yaml_file_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) {
|
||||||
|
return parser.input_file.Read(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a string input.
|
||||||
|
func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) {
|
||||||
|
if parser.read_handler != nil {
|
||||||
|
panic("must set the input source only once")
|
||||||
|
}
|
||||||
|
parser.read_handler = yaml_string_read_handler
|
||||||
|
parser.input = input
|
||||||
|
parser.input_pos = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a file input.
|
||||||
|
func yaml_parser_set_input_file(parser *yaml_parser_t, file *os.File) {
|
||||||
|
if parser.read_handler != nil {
|
||||||
|
panic("must set the input source only once")
|
||||||
|
}
|
||||||
|
parser.read_handler = yaml_file_read_handler
|
||||||
|
parser.input_file = file
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the source encoding.
|
||||||
|
func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
|
||||||
|
if parser.encoding != yaml_ANY_ENCODING {
|
||||||
|
panic("must set the encoding only once")
|
||||||
|
}
|
||||||
|
parser.encoding = encoding
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new emitter object.
|
||||||
|
func yaml_emitter_initialize(emitter *yaml_emitter_t) bool {
|
||||||
|
*emitter = yaml_emitter_t{
|
||||||
|
buffer: make([]byte, output_buffer_size),
|
||||||
|
raw_buffer: make([]byte, 0, output_raw_buffer_size),
|
||||||
|
states: make([]yaml_emitter_state_t, 0, initial_stack_size),
|
||||||
|
events: make([]yaml_event_t, 0, initial_queue_size),
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy an emitter object.
|
||||||
|
func yaml_emitter_delete(emitter *yaml_emitter_t) {
|
||||||
|
*emitter = yaml_emitter_t{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String write handler.
|
||||||
|
func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
|
||||||
|
*emitter.output_buffer = append(*emitter.output_buffer, buffer...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// File write handler.
|
||||||
|
func yaml_file_write_handler(emitter *yaml_emitter_t, buffer []byte) error {
|
||||||
|
_, err := emitter.output_file.Write(buffer)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a string output.
|
||||||
|
func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) {
|
||||||
|
if emitter.write_handler != nil {
|
||||||
|
panic("must set the output target only once")
|
||||||
|
}
|
||||||
|
emitter.write_handler = yaml_string_write_handler
|
||||||
|
emitter.output_buffer = output_buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a file output.
|
||||||
|
func yaml_emitter_set_output_file(emitter *yaml_emitter_t, file io.Writer) {
|
||||||
|
if emitter.write_handler != nil {
|
||||||
|
panic("must set the output target only once")
|
||||||
|
}
|
||||||
|
emitter.write_handler = yaml_file_write_handler
|
||||||
|
emitter.output_file = file
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the output encoding.
|
||||||
|
func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) {
|
||||||
|
if emitter.encoding != yaml_ANY_ENCODING {
|
||||||
|
panic("must set the output encoding only once")
|
||||||
|
}
|
||||||
|
emitter.encoding = encoding
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the canonical output style.
|
||||||
|
func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) {
|
||||||
|
emitter.canonical = canonical
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Set the indentation increment.
|
||||||
|
func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) {
|
||||||
|
if indent < 2 || indent > 9 {
|
||||||
|
indent = 2
|
||||||
|
}
|
||||||
|
emitter.best_indent = indent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the preferred line width.
|
||||||
|
func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) {
|
||||||
|
if width < 0 {
|
||||||
|
width = -1
|
||||||
|
}
|
||||||
|
emitter.best_width = width
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set if unescaped non-ASCII characters are allowed.
|
||||||
|
func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) {
|
||||||
|
emitter.unicode = unicode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the preferred line break character.
|
||||||
|
func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) {
|
||||||
|
emitter.line_break = line_break
|
||||||
|
}
|
||||||
|
|
||||||
|
///*
|
||||||
|
// * Destroy a token object.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(void)
|
||||||
|
//yaml_token_delete(yaml_token_t *token)
|
||||||
|
//{
|
||||||
|
// assert(token); // Non-NULL token object expected.
|
||||||
|
//
|
||||||
|
// switch (token.type)
|
||||||
|
// {
|
||||||
|
// case YAML_TAG_DIRECTIVE_TOKEN:
|
||||||
|
// yaml_free(token.data.tag_directive.handle);
|
||||||
|
// yaml_free(token.data.tag_directive.prefix);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case YAML_ALIAS_TOKEN:
|
||||||
|
// yaml_free(token.data.alias.value);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case YAML_ANCHOR_TOKEN:
|
||||||
|
// yaml_free(token.data.anchor.value);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case YAML_TAG_TOKEN:
|
||||||
|
// yaml_free(token.data.tag.handle);
|
||||||
|
// yaml_free(token.data.tag.suffix);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case YAML_SCALAR_TOKEN:
|
||||||
|
// yaml_free(token.data.scalar.value);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// memset(token, 0, sizeof(yaml_token_t));
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Check if a string is a valid UTF-8 sequence.
|
||||||
|
// *
|
||||||
|
// * Check 'reader.c' for more details on UTF-8 encoding.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//static int
|
||||||
|
//yaml_check_utf8(yaml_char_t *start, size_t length)
|
||||||
|
//{
|
||||||
|
// yaml_char_t *end = start+length;
|
||||||
|
// yaml_char_t *pointer = start;
|
||||||
|
//
|
||||||
|
// while (pointer < end) {
|
||||||
|
// unsigned char octet;
|
||||||
|
// unsigned int width;
|
||||||
|
// unsigned int value;
|
||||||
|
// size_t k;
|
||||||
|
//
|
||||||
|
// octet = pointer[0];
|
||||||
|
// width = (octet & 0x80) == 0x00 ? 1 :
|
||||||
|
// (octet & 0xE0) == 0xC0 ? 2 :
|
||||||
|
// (octet & 0xF0) == 0xE0 ? 3 :
|
||||||
|
// (octet & 0xF8) == 0xF0 ? 4 : 0;
|
||||||
|
// value = (octet & 0x80) == 0x00 ? octet & 0x7F :
|
||||||
|
// (octet & 0xE0) == 0xC0 ? octet & 0x1F :
|
||||||
|
// (octet & 0xF0) == 0xE0 ? octet & 0x0F :
|
||||||
|
// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0;
|
||||||
|
// if (!width) return 0;
|
||||||
|
// if (pointer+width > end) return 0;
|
||||||
|
// for (k = 1; k < width; k ++) {
|
||||||
|
// octet = pointer[k];
|
||||||
|
// if ((octet & 0xC0) != 0x80) return 0;
|
||||||
|
// value = (value << 6) + (octet & 0x3F);
|
||||||
|
// }
|
||||||
|
// if (!((width == 1) ||
|
||||||
|
// (width == 2 && value >= 0x80) ||
|
||||||
|
// (width == 3 && value >= 0x800) ||
|
||||||
|
// (width == 4 && value >= 0x10000))) return 0;
|
||||||
|
//
|
||||||
|
// pointer += width;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return 1;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
|
||||||
|
// Create STREAM-START.
|
||||||
|
func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_STREAM_START_EVENT,
|
||||||
|
encoding: encoding,
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create STREAM-END.
|
||||||
|
func yaml_stream_end_event_initialize(event *yaml_event_t) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_STREAM_END_EVENT,
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create DOCUMENT-START.
|
||||||
|
func yaml_document_start_event_initialize(event *yaml_event_t, version_directive *yaml_version_directive_t,
|
||||||
|
tag_directives []yaml_tag_directive_t, implicit bool) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_DOCUMENT_START_EVENT,
|
||||||
|
version_directive: version_directive,
|
||||||
|
tag_directives: tag_directives,
|
||||||
|
implicit: implicit,
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create DOCUMENT-END.
|
||||||
|
func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_DOCUMENT_END_EVENT,
|
||||||
|
implicit: implicit,
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
///*
|
||||||
|
// * Create ALIAS.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_alias_event_initialize(event *yaml_event_t, anchor *yaml_char_t)
|
||||||
|
//{
|
||||||
|
// mark yaml_mark_t = { 0, 0, 0 }
|
||||||
|
// anchor_copy *yaml_char_t = NULL
|
||||||
|
//
|
||||||
|
// assert(event) // Non-NULL event object is expected.
|
||||||
|
// assert(anchor) // Non-NULL anchor is expected.
|
||||||
|
//
|
||||||
|
// if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0
|
||||||
|
//
|
||||||
|
// anchor_copy = yaml_strdup(anchor)
|
||||||
|
// if (!anchor_copy)
|
||||||
|
// return 0
|
||||||
|
//
|
||||||
|
// ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark)
|
||||||
|
//
|
||||||
|
// return 1
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Create SCALAR.
|
||||||
|
func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_SCALAR_EVENT,
|
||||||
|
anchor: anchor,
|
||||||
|
tag: tag,
|
||||||
|
value: value,
|
||||||
|
implicit: plain_implicit,
|
||||||
|
quoted_implicit: quoted_implicit,
|
||||||
|
style: yaml_style_t(style),
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create SEQUENCE-START.
|
||||||
|
func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_SEQUENCE_START_EVENT,
|
||||||
|
anchor: anchor,
|
||||||
|
tag: tag,
|
||||||
|
implicit: implicit,
|
||||||
|
style: yaml_style_t(style),
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create SEQUENCE-END.
|
||||||
|
func yaml_sequence_end_event_initialize(event *yaml_event_t) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_SEQUENCE_END_EVENT,
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create MAPPING-START.
|
||||||
|
func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_MAPPING_START_EVENT,
|
||||||
|
anchor: anchor,
|
||||||
|
tag: tag,
|
||||||
|
implicit: implicit,
|
||||||
|
style: yaml_style_t(style),
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create MAPPING-END.
|
||||||
|
func yaml_mapping_end_event_initialize(event *yaml_event_t) bool {
|
||||||
|
*event = yaml_event_t{
|
||||||
|
typ: yaml_MAPPING_END_EVENT,
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy an event object.
|
||||||
|
func yaml_event_delete(event *yaml_event_t) {
|
||||||
|
*event = yaml_event_t{}
|
||||||
|
}
|
||||||
|
|
||||||
|
///*
|
||||||
|
// * Create a document object.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_initialize(document *yaml_document_t,
|
||||||
|
// version_directive *yaml_version_directive_t,
|
||||||
|
// tag_directives_start *yaml_tag_directive_t,
|
||||||
|
// tag_directives_end *yaml_tag_directive_t,
|
||||||
|
// start_implicit int, end_implicit int)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
// struct {
|
||||||
|
// start *yaml_node_t
|
||||||
|
// end *yaml_node_t
|
||||||
|
// top *yaml_node_t
|
||||||
|
// } nodes = { NULL, NULL, NULL }
|
||||||
|
// version_directive_copy *yaml_version_directive_t = NULL
|
||||||
|
// struct {
|
||||||
|
// start *yaml_tag_directive_t
|
||||||
|
// end *yaml_tag_directive_t
|
||||||
|
// top *yaml_tag_directive_t
|
||||||
|
// } tag_directives_copy = { NULL, NULL, NULL }
|
||||||
|
// value yaml_tag_directive_t = { NULL, NULL }
|
||||||
|
// mark yaml_mark_t = { 0, 0, 0 }
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
// assert((tag_directives_start && tag_directives_end) ||
|
||||||
|
// (tag_directives_start == tag_directives_end))
|
||||||
|
// // Valid tag directives are expected.
|
||||||
|
//
|
||||||
|
// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error
|
||||||
|
//
|
||||||
|
// if (version_directive) {
|
||||||
|
// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t))
|
||||||
|
// if (!version_directive_copy) goto error
|
||||||
|
// version_directive_copy.major = version_directive.major
|
||||||
|
// version_directive_copy.minor = version_directive.minor
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (tag_directives_start != tag_directives_end) {
|
||||||
|
// tag_directive *yaml_tag_directive_t
|
||||||
|
// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE))
|
||||||
|
// goto error
|
||||||
|
// for (tag_directive = tag_directives_start
|
||||||
|
// tag_directive != tag_directives_end; tag_directive ++) {
|
||||||
|
// assert(tag_directive.handle)
|
||||||
|
// assert(tag_directive.prefix)
|
||||||
|
// if (!yaml_check_utf8(tag_directive.handle,
|
||||||
|
// strlen((char *)tag_directive.handle)))
|
||||||
|
// goto error
|
||||||
|
// if (!yaml_check_utf8(tag_directive.prefix,
|
||||||
|
// strlen((char *)tag_directive.prefix)))
|
||||||
|
// goto error
|
||||||
|
// value.handle = yaml_strdup(tag_directive.handle)
|
||||||
|
// value.prefix = yaml_strdup(tag_directive.prefix)
|
||||||
|
// if (!value.handle || !value.prefix) goto error
|
||||||
|
// if (!PUSH(&context, tag_directives_copy, value))
|
||||||
|
// goto error
|
||||||
|
// value.handle = NULL
|
||||||
|
// value.prefix = NULL
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy,
|
||||||
|
// tag_directives_copy.start, tag_directives_copy.top,
|
||||||
|
// start_implicit, end_implicit, mark, mark)
|
||||||
|
//
|
||||||
|
// return 1
|
||||||
|
//
|
||||||
|
//error:
|
||||||
|
// STACK_DEL(&context, nodes)
|
||||||
|
// yaml_free(version_directive_copy)
|
||||||
|
// while (!STACK_EMPTY(&context, tag_directives_copy)) {
|
||||||
|
// value yaml_tag_directive_t = POP(&context, tag_directives_copy)
|
||||||
|
// yaml_free(value.handle)
|
||||||
|
// yaml_free(value.prefix)
|
||||||
|
// }
|
||||||
|
// STACK_DEL(&context, tag_directives_copy)
|
||||||
|
// yaml_free(value.handle)
|
||||||
|
// yaml_free(value.prefix)
|
||||||
|
//
|
||||||
|
// return 0
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Destroy a document object.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(void)
|
||||||
|
//yaml_document_delete(document *yaml_document_t)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
// tag_directive *yaml_tag_directive_t
|
||||||
|
//
|
||||||
|
// context.error = YAML_NO_ERROR // Eliminate a compliler warning.
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
//
|
||||||
|
// while (!STACK_EMPTY(&context, document.nodes)) {
|
||||||
|
// node yaml_node_t = POP(&context, document.nodes)
|
||||||
|
// yaml_free(node.tag)
|
||||||
|
// switch (node.type) {
|
||||||
|
// case YAML_SCALAR_NODE:
|
||||||
|
// yaml_free(node.data.scalar.value)
|
||||||
|
// break
|
||||||
|
// case YAML_SEQUENCE_NODE:
|
||||||
|
// STACK_DEL(&context, node.data.sequence.items)
|
||||||
|
// break
|
||||||
|
// case YAML_MAPPING_NODE:
|
||||||
|
// STACK_DEL(&context, node.data.mapping.pairs)
|
||||||
|
// break
|
||||||
|
// default:
|
||||||
|
// assert(0) // Should not happen.
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// STACK_DEL(&context, document.nodes)
|
||||||
|
//
|
||||||
|
// yaml_free(document.version_directive)
|
||||||
|
// for (tag_directive = document.tag_directives.start
|
||||||
|
// tag_directive != document.tag_directives.end
|
||||||
|
// tag_directive++) {
|
||||||
|
// yaml_free(tag_directive.handle)
|
||||||
|
// yaml_free(tag_directive.prefix)
|
||||||
|
// }
|
||||||
|
// yaml_free(document.tag_directives.start)
|
||||||
|
//
|
||||||
|
// memset(document, 0, sizeof(yaml_document_t))
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * Get a document node.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(yaml_node_t *)
|
||||||
|
//yaml_document_get_node(document *yaml_document_t, index int)
|
||||||
|
//{
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
//
|
||||||
|
// if (index > 0 && document.nodes.start + index <= document.nodes.top) {
|
||||||
|
// return document.nodes.start + index - 1
|
||||||
|
// }
|
||||||
|
// return NULL
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// * Get the root object.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(yaml_node_t *)
|
||||||
|
//yaml_document_get_root_node(document *yaml_document_t)
|
||||||
|
//{
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
//
|
||||||
|
// if (document.nodes.top != document.nodes.start) {
|
||||||
|
// return document.nodes.start
|
||||||
|
// }
|
||||||
|
// return NULL
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Add a scalar node to a document.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_add_scalar(document *yaml_document_t,
|
||||||
|
// tag *yaml_char_t, value *yaml_char_t, length int,
|
||||||
|
// style yaml_scalar_style_t)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
// mark yaml_mark_t = { 0, 0, 0 }
|
||||||
|
// tag_copy *yaml_char_t = NULL
|
||||||
|
// value_copy *yaml_char_t = NULL
|
||||||
|
// node yaml_node_t
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
// assert(value) // Non-NULL value is expected.
|
||||||
|
//
|
||||||
|
// if (!tag) {
|
||||||
|
// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
|
||||||
|
// tag_copy = yaml_strdup(tag)
|
||||||
|
// if (!tag_copy) goto error
|
||||||
|
//
|
||||||
|
// if (length < 0) {
|
||||||
|
// length = strlen((char *)value)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!yaml_check_utf8(value, length)) goto error
|
||||||
|
// value_copy = yaml_malloc(length+1)
|
||||||
|
// if (!value_copy) goto error
|
||||||
|
// memcpy(value_copy, value, length)
|
||||||
|
// value_copy[length] = '\0'
|
||||||
|
//
|
||||||
|
// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark)
|
||||||
|
// if (!PUSH(&context, document.nodes, node)) goto error
|
||||||
|
//
|
||||||
|
// return document.nodes.top - document.nodes.start
|
||||||
|
//
|
||||||
|
//error:
|
||||||
|
// yaml_free(tag_copy)
|
||||||
|
// yaml_free(value_copy)
|
||||||
|
//
|
||||||
|
// return 0
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Add a sequence node to a document.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_add_sequence(document *yaml_document_t,
|
||||||
|
// tag *yaml_char_t, style yaml_sequence_style_t)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
// mark yaml_mark_t = { 0, 0, 0 }
|
||||||
|
// tag_copy *yaml_char_t = NULL
|
||||||
|
// struct {
|
||||||
|
// start *yaml_node_item_t
|
||||||
|
// end *yaml_node_item_t
|
||||||
|
// top *yaml_node_item_t
|
||||||
|
// } items = { NULL, NULL, NULL }
|
||||||
|
// node yaml_node_t
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
//
|
||||||
|
// if (!tag) {
|
||||||
|
// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
|
||||||
|
// tag_copy = yaml_strdup(tag)
|
||||||
|
// if (!tag_copy) goto error
|
||||||
|
//
|
||||||
|
// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error
|
||||||
|
//
|
||||||
|
// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end,
|
||||||
|
// style, mark, mark)
|
||||||
|
// if (!PUSH(&context, document.nodes, node)) goto error
|
||||||
|
//
|
||||||
|
// return document.nodes.top - document.nodes.start
|
||||||
|
//
|
||||||
|
//error:
|
||||||
|
// STACK_DEL(&context, items)
|
||||||
|
// yaml_free(tag_copy)
|
||||||
|
//
|
||||||
|
// return 0
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Add a mapping node to a document.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_add_mapping(document *yaml_document_t,
|
||||||
|
// tag *yaml_char_t, style yaml_mapping_style_t)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
// mark yaml_mark_t = { 0, 0, 0 }
|
||||||
|
// tag_copy *yaml_char_t = NULL
|
||||||
|
// struct {
|
||||||
|
// start *yaml_node_pair_t
|
||||||
|
// end *yaml_node_pair_t
|
||||||
|
// top *yaml_node_pair_t
|
||||||
|
// } pairs = { NULL, NULL, NULL }
|
||||||
|
// node yaml_node_t
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document object is expected.
|
||||||
|
//
|
||||||
|
// if (!tag) {
|
||||||
|
// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error
|
||||||
|
// tag_copy = yaml_strdup(tag)
|
||||||
|
// if (!tag_copy) goto error
|
||||||
|
//
|
||||||
|
// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error
|
||||||
|
//
|
||||||
|
// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end,
|
||||||
|
// style, mark, mark)
|
||||||
|
// if (!PUSH(&context, document.nodes, node)) goto error
|
||||||
|
//
|
||||||
|
// return document.nodes.top - document.nodes.start
|
||||||
|
//
|
||||||
|
//error:
|
||||||
|
// STACK_DEL(&context, pairs)
|
||||||
|
// yaml_free(tag_copy)
|
||||||
|
//
|
||||||
|
// return 0
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Append an item to a sequence node.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_append_sequence_item(document *yaml_document_t,
|
||||||
|
// sequence int, item int)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document is required.
|
||||||
|
// assert(sequence > 0
|
||||||
|
// && document.nodes.start + sequence <= document.nodes.top)
|
||||||
|
// // Valid sequence id is required.
|
||||||
|
// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE)
|
||||||
|
// // A sequence node is required.
|
||||||
|
// assert(item > 0 && document.nodes.start + item <= document.nodes.top)
|
||||||
|
// // Valid item id is required.
|
||||||
|
//
|
||||||
|
// if (!PUSH(&context,
|
||||||
|
// document.nodes.start[sequence-1].data.sequence.items, item))
|
||||||
|
// return 0
|
||||||
|
//
|
||||||
|
// return 1
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
///*
|
||||||
|
// * Append a pair of a key and a value to a mapping node.
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
//YAML_DECLARE(int)
|
||||||
|
//yaml_document_append_mapping_pair(document *yaml_document_t,
|
||||||
|
// mapping int, key int, value int)
|
||||||
|
//{
|
||||||
|
// struct {
|
||||||
|
// error yaml_error_type_t
|
||||||
|
// } context
|
||||||
|
//
|
||||||
|
// pair yaml_node_pair_t
|
||||||
|
//
|
||||||
|
// assert(document) // Non-NULL document is required.
|
||||||
|
// assert(mapping > 0
|
||||||
|
// && document.nodes.start + mapping <= document.nodes.top)
|
||||||
|
// // Valid mapping id is required.
|
||||||
|
// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE)
|
||||||
|
// // A mapping node is required.
|
||||||
|
// assert(key > 0 && document.nodes.start + key <= document.nodes.top)
|
||||||
|
// // Valid key id is required.
|
||||||
|
// assert(value > 0 && document.nodes.start + value <= document.nodes.top)
|
||||||
|
// // Valid value id is required.
|
||||||
|
//
|
||||||
|
// pair.key = key
|
||||||
|
// pair.value = value
|
||||||
|
//
|
||||||
|
// if (!PUSH(&context,
|
||||||
|
// document.nodes.start[mapping-1].data.mapping.pairs, pair))
|
||||||
|
// return 0
|
||||||
|
//
|
||||||
|
// return 1
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
685
vendor/gopkg.in/yaml.v2/decode.go
generated
vendored
Normal file
685
vendor/gopkg.in/yaml.v2/decode.go
generated
vendored
Normal file
@ -0,0 +1,685 @@
|
|||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
documentNode = 1 << iota
|
||||||
|
mappingNode
|
||||||
|
sequenceNode
|
||||||
|
scalarNode
|
||||||
|
aliasNode
|
||||||
|
)
|
||||||
|
|
||||||
|
type node struct {
|
||||||
|
kind int
|
||||||
|
line, column int
|
||||||
|
tag string
|
||||||
|
value string
|
||||||
|
implicit bool
|
||||||
|
children []*node
|
||||||
|
anchors map[string]*node
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Parser, produces a node tree out of a libyaml event stream.
|
||||||
|
|
||||||
|
type parser struct {
|
||||||
|
parser yaml_parser_t
|
||||||
|
event yaml_event_t
|
||||||
|
doc *node
|
||||||
|
}
|
||||||
|
|
||||||
|
func newParser(b []byte) *parser {
|
||||||
|
p := parser{}
|
||||||
|
if !yaml_parser_initialize(&p.parser) {
|
||||||
|
panic("failed to initialize YAML emitter")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(b) == 0 {
|
||||||
|
b = []byte{'\n'}
|
||||||
|
}
|
||||||
|
|
||||||
|
yaml_parser_set_input_string(&p.parser, b)
|
||||||
|
|
||||||
|
p.skip()
|
||||||
|
if p.event.typ != yaml_STREAM_START_EVENT {
|
||||||
|
panic("expected stream start event, got " + strconv.Itoa(int(p.event.typ)))
|
||||||
|
}
|
||||||
|
p.skip()
|
||||||
|
return &p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) destroy() {
|
||||||
|
if p.event.typ != yaml_NO_EVENT {
|
||||||
|
yaml_event_delete(&p.event)
|
||||||
|
}
|
||||||
|
yaml_parser_delete(&p.parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) skip() {
|
||||||
|
if p.event.typ != yaml_NO_EVENT {
|
||||||
|
if p.event.typ == yaml_STREAM_END_EVENT {
|
||||||
|
failf("attempted to go past the end of stream; corrupted value?")
|
||||||
|
}
|
||||||
|
yaml_event_delete(&p.event)
|
||||||
|
}
|
||||||
|
if !yaml_parser_parse(&p.parser, &p.event) {
|
||||||
|
p.fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) fail() {
|
||||||
|
var where string
|
||||||
|
var line int
|
||||||
|
if p.parser.problem_mark.line != 0 {
|
||||||
|
line = p.parser.problem_mark.line
|
||||||
|
} else if p.parser.context_mark.line != 0 {
|
||||||
|
line = p.parser.context_mark.line
|
||||||
|
}
|
||||||
|
if line != 0 {
|
||||||
|
where = "line " + strconv.Itoa(line) + ": "
|
||||||
|
}
|
||||||
|
var msg string
|
||||||
|
if len(p.parser.problem) > 0 {
|
||||||
|
msg = p.parser.problem
|
||||||
|
} else {
|
||||||
|
msg = "unknown problem parsing YAML content"
|
||||||
|
}
|
||||||
|
failf("%s%s", where, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) anchor(n *node, anchor []byte) {
|
||||||
|
if anchor != nil {
|
||||||
|
p.doc.anchors[string(anchor)] = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) parse() *node {
|
||||||
|
switch p.event.typ {
|
||||||
|
case yaml_SCALAR_EVENT:
|
||||||
|
return p.scalar()
|
||||||
|
case yaml_ALIAS_EVENT:
|
||||||
|
return p.alias()
|
||||||
|
case yaml_MAPPING_START_EVENT:
|
||||||
|
return p.mapping()
|
||||||
|
case yaml_SEQUENCE_START_EVENT:
|
||||||
|
return p.sequence()
|
||||||
|
case yaml_DOCUMENT_START_EVENT:
|
||||||
|
return p.document()
|
||||||
|
case yaml_STREAM_END_EVENT:
|
||||||
|
// Happens when attempting to decode an empty buffer.
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
panic("attempted to parse unknown event: " + strconv.Itoa(int(p.event.typ)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) node(kind int) *node {
|
||||||
|
return &node{
|
||||||
|
kind: kind,
|
||||||
|
line: p.event.start_mark.line,
|
||||||
|
column: p.event.start_mark.column,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) document() *node {
|
||||||
|
n := p.node(documentNode)
|
||||||
|
n.anchors = make(map[string]*node)
|
||||||
|
p.doc = n
|
||||||
|
p.skip()
|
||||||
|
n.children = append(n.children, p.parse())
|
||||||
|
if p.event.typ != yaml_DOCUMENT_END_EVENT {
|
||||||
|
panic("expected end of document event but got " + strconv.Itoa(int(p.event.typ)))
|
||||||
|
}
|
||||||
|
p.skip()
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) alias() *node {
|
||||||
|
n := p.node(aliasNode)
|
||||||
|
n.value = string(p.event.anchor)
|
||||||
|
p.skip()
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) scalar() *node {
|
||||||
|
n := p.node(scalarNode)
|
||||||
|
n.value = string(p.event.value)
|
||||||
|
n.tag = string(p.event.tag)
|
||||||
|
n.implicit = p.event.implicit
|
||||||
|
p.anchor(n, p.event.anchor)
|
||||||
|
p.skip()
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) sequence() *node {
|
||||||
|
n := p.node(sequenceNode)
|
||||||
|
p.anchor(n, p.event.anchor)
|
||||||
|
p.skip()
|
||||||
|
for p.event.typ != yaml_SEQUENCE_END_EVENT {
|
||||||
|
n.children = append(n.children, p.parse())
|
||||||
|
}
|
||||||
|
p.skip()
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) mapping() *node {
|
||||||
|
n := p.node(mappingNode)
|
||||||
|
p.anchor(n, p.event.anchor)
|
||||||
|
p.skip()
|
||||||
|
for p.event.typ != yaml_MAPPING_END_EVENT {
|
||||||
|
n.children = append(n.children, p.parse(), p.parse())
|
||||||
|
}
|
||||||
|
p.skip()
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Decoder, unmarshals a node into a provided value.
|
||||||
|
|
||||||
|
type decoder struct {
|
||||||
|
doc *node
|
||||||
|
aliases map[string]bool
|
||||||
|
mapType reflect.Type
|
||||||
|
terrors []string
|
||||||
|
strict bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
mapItemType = reflect.TypeOf(MapItem{})
|
||||||
|
durationType = reflect.TypeOf(time.Duration(0))
|
||||||
|
defaultMapType = reflect.TypeOf(map[interface{}]interface{}{})
|
||||||
|
ifaceType = defaultMapType.Elem()
|
||||||
|
)
|
||||||
|
|
||||||
|
func newDecoder(strict bool) *decoder {
|
||||||
|
d := &decoder{mapType: defaultMapType, strict: strict}
|
||||||
|
d.aliases = make(map[string]bool)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) terror(n *node, tag string, out reflect.Value) {
|
||||||
|
if n.tag != "" {
|
||||||
|
tag = n.tag
|
||||||
|
}
|
||||||
|
value := n.value
|
||||||
|
if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG {
|
||||||
|
if len(value) > 10 {
|
||||||
|
value = " `" + value[:7] + "...`"
|
||||||
|
} else {
|
||||||
|
value = " `" + value + "`"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) {
|
||||||
|
terrlen := len(d.terrors)
|
||||||
|
err := u.UnmarshalYAML(func(v interface{}) (err error) {
|
||||||
|
defer handleErr(&err)
|
||||||
|
d.unmarshal(n, reflect.ValueOf(v))
|
||||||
|
if len(d.terrors) > terrlen {
|
||||||
|
issues := d.terrors[terrlen:]
|
||||||
|
d.terrors = d.terrors[:terrlen]
|
||||||
|
return &TypeError{issues}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if e, ok := err.(*TypeError); ok {
|
||||||
|
d.terrors = append(d.terrors, e.Errors...)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
fail(err)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
|
||||||
|
// if a value is found to implement it.
|
||||||
|
// It returns the initialized and dereferenced out value, whether
|
||||||
|
// unmarshalling was already done by UnmarshalYAML, and if so whether
|
||||||
|
// its types unmarshalled appropriately.
|
||||||
|
//
|
||||||
|
// If n holds a null value, prepare returns before doing anything.
|
||||||
|
func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
|
||||||
|
if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "" && n.implicit) {
|
||||||
|
return out, false, false
|
||||||
|
}
|
||||||
|
again := true
|
||||||
|
for again {
|
||||||
|
again = false
|
||||||
|
if out.Kind() == reflect.Ptr {
|
||||||
|
if out.IsNil() {
|
||||||
|
out.Set(reflect.New(out.Type().Elem()))
|
||||||
|
}
|
||||||
|
out = out.Elem()
|
||||||
|
again = true
|
||||||
|
}
|
||||||
|
if out.CanAddr() {
|
||||||
|
if u, ok := out.Addr().Interface().(Unmarshaler); ok {
|
||||||
|
good = d.callUnmarshaler(n, u)
|
||||||
|
return out, true, good
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
|
||||||
|
switch n.kind {
|
||||||
|
case documentNode:
|
||||||
|
return d.document(n, out)
|
||||||
|
case aliasNode:
|
||||||
|
return d.alias(n, out)
|
||||||
|
}
|
||||||
|
out, unmarshaled, good := d.prepare(n, out)
|
||||||
|
if unmarshaled {
|
||||||
|
return good
|
||||||
|
}
|
||||||
|
switch n.kind {
|
||||||
|
case scalarNode:
|
||||||
|
good = d.scalar(n, out)
|
||||||
|
case mappingNode:
|
||||||
|
good = d.mapping(n, out)
|
||||||
|
case sequenceNode:
|
||||||
|
good = d.sequence(n, out)
|
||||||
|
default:
|
||||||
|
panic("internal error: unknown node kind: " + strconv.Itoa(n.kind))
|
||||||
|
}
|
||||||
|
return good
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) document(n *node, out reflect.Value) (good bool) {
|
||||||
|
if len(n.children) == 1 {
|
||||||
|
d.doc = n
|
||||||
|
d.unmarshal(n.children[0], out)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
|
||||||
|
an, ok := d.doc.anchors[n.value]
|
||||||
|
if !ok {
|
||||||
|
failf("unknown anchor '%s' referenced", n.value)
|
||||||
|
}
|
||||||
|
if d.aliases[n.value] {
|
||||||
|
failf("anchor '%s' value contains itself", n.value)
|
||||||
|
}
|
||||||
|
d.aliases[n.value] = true
|
||||||
|
good = d.unmarshal(an, out)
|
||||||
|
delete(d.aliases, n.value)
|
||||||
|
return good
|
||||||
|
}
|
||||||
|
|
||||||
|
var zeroValue reflect.Value
|
||||||
|
|
||||||
|
func resetMap(out reflect.Value) {
|
||||||
|
for _, k := range out.MapKeys() {
|
||||||
|
out.SetMapIndex(k, zeroValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) scalar(n *node, out reflect.Value) (good bool) {
|
||||||
|
var tag string
|
||||||
|
var resolved interface{}
|
||||||
|
if n.tag == "" && !n.implicit {
|
||||||
|
tag = yaml_STR_TAG
|
||||||
|
resolved = n.value
|
||||||
|
} else {
|
||||||
|
tag, resolved = resolve(n.tag, n.value)
|
||||||
|
if tag == yaml_BINARY_TAG {
|
||||||
|
data, err := base64.StdEncoding.DecodeString(resolved.(string))
|
||||||
|
if err != nil {
|
||||||
|
failf("!!binary value contains invalid base64 data")
|
||||||
|
}
|
||||||
|
resolved = string(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resolved == nil {
|
||||||
|
if out.Kind() == reflect.Map && !out.CanAddr() {
|
||||||
|
resetMap(out)
|
||||||
|
} else {
|
||||||
|
out.Set(reflect.Zero(out.Type()))
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if s, ok := resolved.(string); ok && out.CanAddr() {
|
||||||
|
if u, ok := out.Addr().Interface().(encoding.TextUnmarshaler); ok {
|
||||||
|
err := u.UnmarshalText([]byte(s))
|
||||||
|
if err != nil {
|
||||||
|
fail(err)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch out.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
if tag == yaml_BINARY_TAG {
|
||||||
|
out.SetString(resolved.(string))
|
||||||
|
good = true
|
||||||
|
} else if resolved != nil {
|
||||||
|
out.SetString(n.value)
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
case reflect.Interface:
|
||||||
|
if resolved == nil {
|
||||||
|
out.Set(reflect.Zero(out.Type()))
|
||||||
|
} else {
|
||||||
|
out.Set(reflect.ValueOf(resolved))
|
||||||
|
}
|
||||||
|
good = true
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
switch resolved := resolved.(type) {
|
||||||
|
case int:
|
||||||
|
if !out.OverflowInt(int64(resolved)) {
|
||||||
|
out.SetInt(int64(resolved))
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
case int64:
|
||||||
|
if !out.OverflowInt(resolved) {
|
||||||
|
out.SetInt(resolved)
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
case uint64:
|
||||||
|
if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
|
||||||
|
out.SetInt(int64(resolved))
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
|
||||||
|
out.SetInt(int64(resolved))
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
if out.Type() == durationType {
|
||||||
|
d, err := time.ParseDuration(resolved)
|
||||||
|
if err == nil {
|
||||||
|
out.SetInt(int64(d))
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
switch resolved := resolved.(type) {
|
||||||
|
case int:
|
||||||
|
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
|
||||||
|
out.SetUint(uint64(resolved))
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
case int64:
|
||||||
|
if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
|
||||||
|
out.SetUint(uint64(resolved))
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
case uint64:
|
||||||
|
if !out.OverflowUint(uint64(resolved)) {
|
||||||
|
out.SetUint(uint64(resolved))
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
|
||||||
|
out.SetUint(uint64(resolved))
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Bool:
|
||||||
|
switch resolved := resolved.(type) {
|
||||||
|
case bool:
|
||||||
|
out.SetBool(resolved)
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
switch resolved := resolved.(type) {
|
||||||
|
case int:
|
||||||
|
out.SetFloat(float64(resolved))
|
||||||
|
good = true
|
||||||
|
case int64:
|
||||||
|
out.SetFloat(float64(resolved))
|
||||||
|
good = true
|
||||||
|
case uint64:
|
||||||
|
out.SetFloat(float64(resolved))
|
||||||
|
good = true
|
||||||
|
case float64:
|
||||||
|
out.SetFloat(resolved)
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
case reflect.Ptr:
|
||||||
|
if out.Type().Elem() == reflect.TypeOf(resolved) {
|
||||||
|
// TODO DOes this make sense? When is out a Ptr except when decoding a nil value?
|
||||||
|
elem := reflect.New(out.Type().Elem())
|
||||||
|
elem.Elem().Set(reflect.ValueOf(resolved))
|
||||||
|
out.Set(elem)
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !good {
|
||||||
|
d.terror(n, tag, out)
|
||||||
|
}
|
||||||
|
return good
|
||||||
|
}
|
||||||
|
|
||||||
|
func settableValueOf(i interface{}) reflect.Value {
|
||||||
|
v := reflect.ValueOf(i)
|
||||||
|
sv := reflect.New(v.Type()).Elem()
|
||||||
|
sv.Set(v)
|
||||||
|
return sv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
|
||||||
|
l := len(n.children)
|
||||||
|
|
||||||
|
var iface reflect.Value
|
||||||
|
switch out.Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
out.Set(reflect.MakeSlice(out.Type(), l, l))
|
||||||
|
case reflect.Interface:
|
||||||
|
// No type hints. Will have to use a generic sequence.
|
||||||
|
iface = out
|
||||||
|
out = settableValueOf(make([]interface{}, l))
|
||||||
|
default:
|
||||||
|
d.terror(n, yaml_SEQ_TAG, out)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
et := out.Type().Elem()
|
||||||
|
|
||||||
|
j := 0
|
||||||
|
for i := 0; i < l; i++ {
|
||||||
|
e := reflect.New(et).Elem()
|
||||||
|
if ok := d.unmarshal(n.children[i], e); ok {
|
||||||
|
out.Index(j).Set(e)
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Set(out.Slice(0, j))
|
||||||
|
if iface.IsValid() {
|
||||||
|
iface.Set(out)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
|
||||||
|
switch out.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
return d.mappingStruct(n, out)
|
||||||
|
case reflect.Slice:
|
||||||
|
return d.mappingSlice(n, out)
|
||||||
|
case reflect.Map:
|
||||||
|
// okay
|
||||||
|
case reflect.Interface:
|
||||||
|
if d.mapType.Kind() == reflect.Map {
|
||||||
|
iface := out
|
||||||
|
out = reflect.MakeMap(d.mapType)
|
||||||
|
iface.Set(out)
|
||||||
|
} else {
|
||||||
|
slicev := reflect.New(d.mapType).Elem()
|
||||||
|
if !d.mappingSlice(n, slicev) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
out.Set(slicev)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
d.terror(n, yaml_MAP_TAG, out)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
outt := out.Type()
|
||||||
|
kt := outt.Key()
|
||||||
|
et := outt.Elem()
|
||||||
|
|
||||||
|
mapType := d.mapType
|
||||||
|
if outt.Key() == ifaceType && outt.Elem() == ifaceType {
|
||||||
|
d.mapType = outt
|
||||||
|
}
|
||||||
|
|
||||||
|
if out.IsNil() {
|
||||||
|
out.Set(reflect.MakeMap(outt))
|
||||||
|
}
|
||||||
|
l := len(n.children)
|
||||||
|
for i := 0; i < l; i += 2 {
|
||||||
|
if isMerge(n.children[i]) {
|
||||||
|
d.merge(n.children[i+1], out)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k := reflect.New(kt).Elem()
|
||||||
|
if d.unmarshal(n.children[i], k) {
|
||||||
|
kkind := k.Kind()
|
||||||
|
if kkind == reflect.Interface {
|
||||||
|
kkind = k.Elem().Kind()
|
||||||
|
}
|
||||||
|
if kkind == reflect.Map || kkind == reflect.Slice {
|
||||||
|
failf("invalid map key: %#v", k.Interface())
|
||||||
|
}
|
||||||
|
e := reflect.New(et).Elem()
|
||||||
|
if d.unmarshal(n.children[i+1], e) {
|
||||||
|
out.SetMapIndex(k, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.mapType = mapType
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
|
||||||
|
outt := out.Type()
|
||||||
|
if outt.Elem() != mapItemType {
|
||||||
|
d.terror(n, yaml_MAP_TAG, out)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
mapType := d.mapType
|
||||||
|
d.mapType = outt
|
||||||
|
|
||||||
|
var slice []MapItem
|
||||||
|
var l = len(n.children)
|
||||||
|
for i := 0; i < l; i += 2 {
|
||||||
|
if isMerge(n.children[i]) {
|
||||||
|
d.merge(n.children[i+1], out)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
item := MapItem{}
|
||||||
|
k := reflect.ValueOf(&item.Key).Elem()
|
||||||
|
if d.unmarshal(n.children[i], k) {
|
||||||
|
v := reflect.ValueOf(&item.Value).Elem()
|
||||||
|
if d.unmarshal(n.children[i+1], v) {
|
||||||
|
slice = append(slice, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.Set(reflect.ValueOf(slice))
|
||||||
|
d.mapType = mapType
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
|
||||||
|
sinfo, err := getStructInfo(out.Type())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
name := settableValueOf("")
|
||||||
|
l := len(n.children)
|
||||||
|
|
||||||
|
var inlineMap reflect.Value
|
||||||
|
var elemType reflect.Type
|
||||||
|
if sinfo.InlineMap != -1 {
|
||||||
|
inlineMap = out.Field(sinfo.InlineMap)
|
||||||
|
inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
|
||||||
|
elemType = inlineMap.Type().Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < l; i += 2 {
|
||||||
|
ni := n.children[i]
|
||||||
|
if isMerge(ni) {
|
||||||
|
d.merge(n.children[i+1], out)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !d.unmarshal(ni, name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info, ok := sinfo.FieldsMap[name.String()]; ok {
|
||||||
|
var field reflect.Value
|
||||||
|
if info.Inline == nil {
|
||||||
|
field = out.Field(info.Num)
|
||||||
|
} else {
|
||||||
|
field = out.FieldByIndex(info.Inline)
|
||||||
|
}
|
||||||
|
d.unmarshal(n.children[i+1], field)
|
||||||
|
} else if sinfo.InlineMap != -1 {
|
||||||
|
if inlineMap.IsNil() {
|
||||||
|
inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
|
||||||
|
}
|
||||||
|
value := reflect.New(elemType).Elem()
|
||||||
|
d.unmarshal(n.children[i+1], value)
|
||||||
|
inlineMap.SetMapIndex(name, value)
|
||||||
|
} else if d.strict {
|
||||||
|
d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in struct %s", n.line+1, name.String(), out.Type()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func failWantMap() {
|
||||||
|
failf("map merge requires map or sequence of maps as the value")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *decoder) merge(n *node, out reflect.Value) {
|
||||||
|
switch n.kind {
|
||||||
|
case mappingNode:
|
||||||
|
d.unmarshal(n, out)
|
||||||
|
case aliasNode:
|
||||||
|
an, ok := d.doc.anchors[n.value]
|
||||||
|
if ok && an.kind != mappingNode {
|
||||||
|
failWantMap()
|
||||||
|
}
|
||||||
|
d.unmarshal(n, out)
|
||||||
|
case sequenceNode:
|
||||||
|
// Step backwards as earlier nodes take precedence.
|
||||||
|
for i := len(n.children) - 1; i >= 0; i-- {
|
||||||
|
ni := n.children[i]
|
||||||
|
if ni.kind == aliasNode {
|
||||||
|
an, ok := d.doc.anchors[ni.value]
|
||||||
|
if ok && an.kind != mappingNode {
|
||||||
|
failWantMap()
|
||||||
|
}
|
||||||
|
} else if ni.kind != mappingNode {
|
||||||
|
failWantMap()
|
||||||
|
}
|
||||||
|
d.unmarshal(ni, out)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
failWantMap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isMerge(n *node) bool {
|
||||||
|
return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG)
|
||||||
|
}
|
1017
vendor/gopkg.in/yaml.v2/decode_test.go
generated
vendored
Normal file
1017
vendor/gopkg.in/yaml.v2/decode_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1684
vendor/gopkg.in/yaml.v2/emitterc.go
generated
vendored
Normal file
1684
vendor/gopkg.in/yaml.v2/emitterc.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
306
vendor/gopkg.in/yaml.v2/encode.go
generated
vendored
Normal file
306
vendor/gopkg.in/yaml.v2/encode.go
generated
vendored
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type encoder struct {
|
||||||
|
emitter yaml_emitter_t
|
||||||
|
event yaml_event_t
|
||||||
|
out []byte
|
||||||
|
flow bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEncoder() (e *encoder) {
|
||||||
|
e = &encoder{}
|
||||||
|
e.must(yaml_emitter_initialize(&e.emitter))
|
||||||
|
yaml_emitter_set_output_string(&e.emitter, &e.out)
|
||||||
|
yaml_emitter_set_unicode(&e.emitter, true)
|
||||||
|
e.must(yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING))
|
||||||
|
e.emit()
|
||||||
|
e.must(yaml_document_start_event_initialize(&e.event, nil, nil, true))
|
||||||
|
e.emit()
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) finish() {
|
||||||
|
e.must(yaml_document_end_event_initialize(&e.event, true))
|
||||||
|
e.emit()
|
||||||
|
e.emitter.open_ended = false
|
||||||
|
e.must(yaml_stream_end_event_initialize(&e.event))
|
||||||
|
e.emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) destroy() {
|
||||||
|
yaml_emitter_delete(&e.emitter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) emit() {
|
||||||
|
// This will internally delete the e.event value.
|
||||||
|
if !yaml_emitter_emit(&e.emitter, &e.event) && e.event.typ != yaml_DOCUMENT_END_EVENT && e.event.typ != yaml_STREAM_END_EVENT {
|
||||||
|
e.must(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) must(ok bool) {
|
||||||
|
if !ok {
|
||||||
|
msg := e.emitter.problem
|
||||||
|
if msg == "" {
|
||||||
|
msg = "unknown problem generating YAML content"
|
||||||
|
}
|
||||||
|
failf("%s", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) marshal(tag string, in reflect.Value) {
|
||||||
|
if !in.IsValid() {
|
||||||
|
e.nilv()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
iface := in.Interface()
|
||||||
|
if m, ok := iface.(Marshaler); ok {
|
||||||
|
v, err := m.MarshalYAML()
|
||||||
|
if err != nil {
|
||||||
|
fail(err)
|
||||||
|
}
|
||||||
|
if v == nil {
|
||||||
|
e.nilv()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
in = reflect.ValueOf(v)
|
||||||
|
} else if m, ok := iface.(encoding.TextMarshaler); ok {
|
||||||
|
text, err := m.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
fail(err)
|
||||||
|
}
|
||||||
|
in = reflect.ValueOf(string(text))
|
||||||
|
}
|
||||||
|
switch in.Kind() {
|
||||||
|
case reflect.Interface:
|
||||||
|
if in.IsNil() {
|
||||||
|
e.nilv()
|
||||||
|
} else {
|
||||||
|
e.marshal(tag, in.Elem())
|
||||||
|
}
|
||||||
|
case reflect.Map:
|
||||||
|
e.mapv(tag, in)
|
||||||
|
case reflect.Ptr:
|
||||||
|
if in.IsNil() {
|
||||||
|
e.nilv()
|
||||||
|
} else {
|
||||||
|
e.marshal(tag, in.Elem())
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
e.structv(tag, in)
|
||||||
|
case reflect.Slice:
|
||||||
|
if in.Type().Elem() == mapItemType {
|
||||||
|
e.itemsv(tag, in)
|
||||||
|
} else {
|
||||||
|
e.slicev(tag, in)
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
e.stringv(tag, in)
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
if in.Type() == durationType {
|
||||||
|
e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String()))
|
||||||
|
} else {
|
||||||
|
e.intv(tag, in)
|
||||||
|
}
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
e.uintv(tag, in)
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
e.floatv(tag, in)
|
||||||
|
case reflect.Bool:
|
||||||
|
e.boolv(tag, in)
|
||||||
|
default:
|
||||||
|
panic("cannot marshal type: " + in.Type().String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) mapv(tag string, in reflect.Value) {
|
||||||
|
e.mappingv(tag, func() {
|
||||||
|
keys := keyList(in.MapKeys())
|
||||||
|
sort.Sort(keys)
|
||||||
|
for _, k := range keys {
|
||||||
|
e.marshal("", k)
|
||||||
|
e.marshal("", in.MapIndex(k))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) itemsv(tag string, in reflect.Value) {
|
||||||
|
e.mappingv(tag, func() {
|
||||||
|
slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem)
|
||||||
|
for _, item := range slice {
|
||||||
|
e.marshal("", reflect.ValueOf(item.Key))
|
||||||
|
e.marshal("", reflect.ValueOf(item.Value))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) structv(tag string, in reflect.Value) {
|
||||||
|
sinfo, err := getStructInfo(in.Type())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
e.mappingv(tag, func() {
|
||||||
|
for _, info := range sinfo.FieldsList {
|
||||||
|
var value reflect.Value
|
||||||
|
if info.Inline == nil {
|
||||||
|
value = in.Field(info.Num)
|
||||||
|
} else {
|
||||||
|
value = in.FieldByIndex(info.Inline)
|
||||||
|
}
|
||||||
|
if info.OmitEmpty && isZero(value) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
e.marshal("", reflect.ValueOf(info.Key))
|
||||||
|
e.flow = info.Flow
|
||||||
|
e.marshal("", value)
|
||||||
|
}
|
||||||
|
if sinfo.InlineMap >= 0 {
|
||||||
|
m := in.Field(sinfo.InlineMap)
|
||||||
|
if m.Len() > 0 {
|
||||||
|
e.flow = false
|
||||||
|
keys := keyList(m.MapKeys())
|
||||||
|
sort.Sort(keys)
|
||||||
|
for _, k := range keys {
|
||||||
|
if _, found := sinfo.FieldsMap[k.String()]; found {
|
||||||
|
panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String()))
|
||||||
|
}
|
||||||
|
e.marshal("", k)
|
||||||
|
e.flow = false
|
||||||
|
e.marshal("", m.MapIndex(k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) mappingv(tag string, f func()) {
|
||||||
|
implicit := tag == ""
|
||||||
|
style := yaml_BLOCK_MAPPING_STYLE
|
||||||
|
if e.flow {
|
||||||
|
e.flow = false
|
||||||
|
style = yaml_FLOW_MAPPING_STYLE
|
||||||
|
}
|
||||||
|
e.must(yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
|
||||||
|
e.emit()
|
||||||
|
f()
|
||||||
|
e.must(yaml_mapping_end_event_initialize(&e.event))
|
||||||
|
e.emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) slicev(tag string, in reflect.Value) {
|
||||||
|
implicit := tag == ""
|
||||||
|
style := yaml_BLOCK_SEQUENCE_STYLE
|
||||||
|
if e.flow {
|
||||||
|
e.flow = false
|
||||||
|
style = yaml_FLOW_SEQUENCE_STYLE
|
||||||
|
}
|
||||||
|
e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
|
||||||
|
e.emit()
|
||||||
|
n := in.Len()
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
e.marshal("", in.Index(i))
|
||||||
|
}
|
||||||
|
e.must(yaml_sequence_end_event_initialize(&e.event))
|
||||||
|
e.emit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1.
|
||||||
|
//
|
||||||
|
// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported
|
||||||
|
// in YAML 1.2 and by this package, but these should be marshalled quoted for
|
||||||
|
// the time being for compatibility with other parsers.
|
||||||
|
func isBase60Float(s string) (result bool) {
|
||||||
|
// Fast path.
|
||||||
|
if s == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
c := s[0]
|
||||||
|
if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Do the full match.
|
||||||
|
return base60float.MatchString(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// From http://yaml.org/type/float.html, except the regular expression there
|
||||||
|
// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix.
|
||||||
|
var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`)
|
||||||
|
|
||||||
|
func (e *encoder) stringv(tag string, in reflect.Value) {
|
||||||
|
var style yaml_scalar_style_t
|
||||||
|
s := in.String()
|
||||||
|
rtag, rs := resolve("", s)
|
||||||
|
if rtag == yaml_BINARY_TAG {
|
||||||
|
if tag == "" || tag == yaml_STR_TAG {
|
||||||
|
tag = rtag
|
||||||
|
s = rs.(string)
|
||||||
|
} else if tag == yaml_BINARY_TAG {
|
||||||
|
failf("explicitly tagged !!binary data must be base64-encoded")
|
||||||
|
} else {
|
||||||
|
failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tag == "" && (rtag != yaml_STR_TAG || isBase60Float(s)) {
|
||||||
|
style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
|
||||||
|
} else if strings.Contains(s, "\n") {
|
||||||
|
style = yaml_LITERAL_SCALAR_STYLE
|
||||||
|
} else {
|
||||||
|
style = yaml_PLAIN_SCALAR_STYLE
|
||||||
|
}
|
||||||
|
e.emitScalar(s, "", tag, style)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) boolv(tag string, in reflect.Value) {
|
||||||
|
var s string
|
||||||
|
if in.Bool() {
|
||||||
|
s = "true"
|
||||||
|
} else {
|
||||||
|
s = "false"
|
||||||
|
}
|
||||||
|
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) intv(tag string, in reflect.Value) {
|
||||||
|
s := strconv.FormatInt(in.Int(), 10)
|
||||||
|
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) uintv(tag string, in reflect.Value) {
|
||||||
|
s := strconv.FormatUint(in.Uint(), 10)
|
||||||
|
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) floatv(tag string, in reflect.Value) {
|
||||||
|
// FIXME: Handle 64 bits here.
|
||||||
|
s := strconv.FormatFloat(float64(in.Float()), 'g', -1, 32)
|
||||||
|
switch s {
|
||||||
|
case "+Inf":
|
||||||
|
s = ".inf"
|
||||||
|
case "-Inf":
|
||||||
|
s = "-.inf"
|
||||||
|
case "NaN":
|
||||||
|
s = ".nan"
|
||||||
|
}
|
||||||
|
e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) nilv() {
|
||||||
|
e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) {
|
||||||
|
implicit := tag == ""
|
||||||
|
e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
|
||||||
|
e.emit()
|
||||||
|
}
|
501
vendor/gopkg.in/yaml.v2/encode_test.go
generated
vendored
Normal file
501
vendor/gopkg.in/yaml.v2/encode_test.go
generated
vendored
Normal file
@ -0,0 +1,501 @@
|
|||||||
|
package yaml_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
. "gopkg.in/check.v1"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var marshalIntTest = 123
|
||||||
|
|
||||||
|
var marshalTests = []struct {
|
||||||
|
value interface{}
|
||||||
|
data string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
nil,
|
||||||
|
"null\n",
|
||||||
|
}, {
|
||||||
|
&struct{}{},
|
||||||
|
"{}\n",
|
||||||
|
}, {
|
||||||
|
map[string]string{"v": "hi"},
|
||||||
|
"v: hi\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": "hi"},
|
||||||
|
"v: hi\n",
|
||||||
|
}, {
|
||||||
|
map[string]string{"v": "true"},
|
||||||
|
"v: \"true\"\n",
|
||||||
|
}, {
|
||||||
|
map[string]string{"v": "false"},
|
||||||
|
"v: \"false\"\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": true},
|
||||||
|
"v: true\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": false},
|
||||||
|
"v: false\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": 10},
|
||||||
|
"v: 10\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": -10},
|
||||||
|
"v: -10\n",
|
||||||
|
}, {
|
||||||
|
map[string]uint{"v": 42},
|
||||||
|
"v: 42\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": int64(4294967296)},
|
||||||
|
"v: 4294967296\n",
|
||||||
|
}, {
|
||||||
|
map[string]int64{"v": int64(4294967296)},
|
||||||
|
"v: 4294967296\n",
|
||||||
|
}, {
|
||||||
|
map[string]uint64{"v": 4294967296},
|
||||||
|
"v: 4294967296\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": "10"},
|
||||||
|
"v: \"10\"\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": 0.1},
|
||||||
|
"v: 0.1\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": float64(0.1)},
|
||||||
|
"v: 0.1\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": -0.1},
|
||||||
|
"v: -0.1\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": math.Inf(+1)},
|
||||||
|
"v: .inf\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": math.Inf(-1)},
|
||||||
|
"v: -.inf\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": math.NaN()},
|
||||||
|
"v: .nan\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": nil},
|
||||||
|
"v: null\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"v": ""},
|
||||||
|
"v: \"\"\n",
|
||||||
|
}, {
|
||||||
|
map[string][]string{"v": []string{"A", "B"}},
|
||||||
|
"v:\n- A\n- B\n",
|
||||||
|
}, {
|
||||||
|
map[string][]string{"v": []string{"A", "B\nC"}},
|
||||||
|
"v:\n- A\n- |-\n B\n C\n",
|
||||||
|
}, {
|
||||||
|
map[string][]interface{}{"v": []interface{}{"A", 1, map[string][]int{"B": []int{2, 3}}}},
|
||||||
|
"v:\n- A\n- 1\n- B:\n - 2\n - 3\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
|
||||||
|
"a:\n b: c\n",
|
||||||
|
}, {
|
||||||
|
map[string]interface{}{"a": "-"},
|
||||||
|
"a: '-'\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Simple values.
|
||||||
|
{
|
||||||
|
&marshalIntTest,
|
||||||
|
"123\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Structures
|
||||||
|
{
|
||||||
|
&struct{ Hello string }{"world"},
|
||||||
|
"hello: world\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A struct {
|
||||||
|
B string
|
||||||
|
}
|
||||||
|
}{struct{ B string }{"c"}},
|
||||||
|
"a:\n b: c\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A *struct {
|
||||||
|
B string
|
||||||
|
}
|
||||||
|
}{&struct{ B string }{"c"}},
|
||||||
|
"a:\n b: c\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A *struct {
|
||||||
|
B string
|
||||||
|
}
|
||||||
|
}{},
|
||||||
|
"a: null\n",
|
||||||
|
}, {
|
||||||
|
&struct{ A int }{1},
|
||||||
|
"a: 1\n",
|
||||||
|
}, {
|
||||||
|
&struct{ A []int }{[]int{1, 2}},
|
||||||
|
"a:\n- 1\n- 2\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
B int "a"
|
||||||
|
}{1},
|
||||||
|
"a: 1\n",
|
||||||
|
}, {
|
||||||
|
&struct{ A bool }{true},
|
||||||
|
"a: true\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Conditional flag
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
A int "a,omitempty"
|
||||||
|
B int "b,omitempty"
|
||||||
|
}{1, 0},
|
||||||
|
"a: 1\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A int "a,omitempty"
|
||||||
|
B int "b,omitempty"
|
||||||
|
}{0, 0},
|
||||||
|
"{}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A *struct{ X, y int } "a,omitempty,flow"
|
||||||
|
}{&struct{ X, y int }{1, 2}},
|
||||||
|
"a: {x: 1}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A *struct{ X, y int } "a,omitempty,flow"
|
||||||
|
}{nil},
|
||||||
|
"{}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A *struct{ X, y int } "a,omitempty,flow"
|
||||||
|
}{&struct{ X, y int }{}},
|
||||||
|
"a: {x: 0}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A struct{ X, y int } "a,omitempty,flow"
|
||||||
|
}{struct{ X, y int }{1, 2}},
|
||||||
|
"a: {x: 1}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A struct{ X, y int } "a,omitempty,flow"
|
||||||
|
}{struct{ X, y int }{0, 1}},
|
||||||
|
"{}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A float64 "a,omitempty"
|
||||||
|
B float64 "b,omitempty"
|
||||||
|
}{1, 0},
|
||||||
|
"a: 1\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Flow flag
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
A []int "a,flow"
|
||||||
|
}{[]int{1, 2}},
|
||||||
|
"a: [1, 2]\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A map[string]string "a,flow"
|
||||||
|
}{map[string]string{"b": "c", "d": "e"}},
|
||||||
|
"a: {b: c, d: e}\n",
|
||||||
|
}, {
|
||||||
|
&struct {
|
||||||
|
A struct {
|
||||||
|
B, D string
|
||||||
|
} "a,flow"
|
||||||
|
}{struct{ B, D string }{"c", "e"}},
|
||||||
|
"a: {b: c, d: e}\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Unexported field
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
u int
|
||||||
|
A int
|
||||||
|
}{0, 1},
|
||||||
|
"a: 1\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Ignored field
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
A int
|
||||||
|
B int "-"
|
||||||
|
}{1, 2},
|
||||||
|
"a: 1\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Struct inlining
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
A int
|
||||||
|
C inlineB `yaml:",inline"`
|
||||||
|
}{1, inlineB{2, inlineC{3}}},
|
||||||
|
"a: 1\nb: 2\nc: 3\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Map inlining
|
||||||
|
{
|
||||||
|
&struct {
|
||||||
|
A int
|
||||||
|
C map[string]int `yaml:",inline"`
|
||||||
|
}{1, map[string]int{"b": 2, "c": 3}},
|
||||||
|
"a: 1\nb: 2\nc: 3\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Duration
|
||||||
|
{
|
||||||
|
map[string]time.Duration{"a": 3 * time.Second},
|
||||||
|
"a: 3s\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Issue #24: bug in map merging logic.
|
||||||
|
{
|
||||||
|
map[string]string{"a": "<foo>"},
|
||||||
|
"a: <foo>\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Issue #34: marshal unsupported base 60 floats quoted for compatibility
|
||||||
|
// with old YAML 1.1 parsers.
|
||||||
|
{
|
||||||
|
map[string]string{"a": "1:1"},
|
||||||
|
"a: \"1:1\"\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Binary data.
|
||||||
|
{
|
||||||
|
map[string]string{"a": "\x00"},
|
||||||
|
"a: \"\\0\"\n",
|
||||||
|
}, {
|
||||||
|
map[string]string{"a": "\x80\x81\x82"},
|
||||||
|
"a: !!binary gIGC\n",
|
||||||
|
}, {
|
||||||
|
map[string]string{"a": strings.Repeat("\x90", 54)},
|
||||||
|
"a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Ordered maps.
|
||||||
|
{
|
||||||
|
&yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}},
|
||||||
|
"b: 2\na: 1\nd: 4\nc: 3\nsub:\n e: 5\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Encode unicode as utf-8 rather than in escaped form.
|
||||||
|
{
|
||||||
|
map[string]string{"a": "你好"},
|
||||||
|
"a: 你好\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Support encoding.TextMarshaler.
|
||||||
|
{
|
||||||
|
map[string]net.IP{"a": net.IPv4(1, 2, 3, 4)},
|
||||||
|
"a: 1.2.3.4\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]time.Time{"a": time.Unix(1424801979, 0)},
|
||||||
|
"a: 2015-02-24T18:19:39Z\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Ensure strings containing ": " are quoted (reported as PR #43, but not reproducible).
|
||||||
|
{
|
||||||
|
map[string]string{"a": "b: c"},
|
||||||
|
"a: 'b: c'\n",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Containing hash mark ('#') in string should be quoted
|
||||||
|
{
|
||||||
|
map[string]string{"a": "Hello #comment"},
|
||||||
|
"a: 'Hello #comment'\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]string{"a": "你好 #comment"},
|
||||||
|
"a: '你好 #comment'\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestMarshal(c *C) {
|
||||||
|
defer os.Setenv("TZ", os.Getenv("TZ"))
|
||||||
|
os.Setenv("TZ", "UTC")
|
||||||
|
for _, item := range marshalTests {
|
||||||
|
data, err := yaml.Marshal(item.value)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(string(data), Equals, item.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var marshalErrorTests = []struct {
|
||||||
|
value interface{}
|
||||||
|
error string
|
||||||
|
panic string
|
||||||
|
}{{
|
||||||
|
value: &struct {
|
||||||
|
B int
|
||||||
|
inlineB ",inline"
|
||||||
|
}{1, inlineB{2, inlineC{3}}},
|
||||||
|
panic: `Duplicated key 'b' in struct struct \{ B int; .*`,
|
||||||
|
}, {
|
||||||
|
value: &struct {
|
||||||
|
A int
|
||||||
|
B map[string]int ",inline"
|
||||||
|
}{1, map[string]int{"a": 2}},
|
||||||
|
panic: `Can't have key "a" in inlined map; conflicts with struct field`,
|
||||||
|
}}
|
||||||
|
|
||||||
|
func (s *S) TestMarshalErrors(c *C) {
|
||||||
|
for _, item := range marshalErrorTests {
|
||||||
|
if item.panic != "" {
|
||||||
|
c.Assert(func() { yaml.Marshal(item.value) }, PanicMatches, item.panic)
|
||||||
|
} else {
|
||||||
|
_, err := yaml.Marshal(item.value)
|
||||||
|
c.Assert(err, ErrorMatches, item.error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestMarshalTypeCache(c *C) {
|
||||||
|
var data []byte
|
||||||
|
var err error
|
||||||
|
func() {
|
||||||
|
type T struct{ A int }
|
||||||
|
data, err = yaml.Marshal(&T{})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
}()
|
||||||
|
func() {
|
||||||
|
type T struct{ B int }
|
||||||
|
data, err = yaml.Marshal(&T{})
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
}()
|
||||||
|
c.Assert(string(data), Equals, "b: 0\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
var marshalerTests = []struct {
|
||||||
|
data string
|
||||||
|
value interface{}
|
||||||
|
}{
|
||||||
|
{"_:\n hi: there\n", map[interface{}]interface{}{"hi": "there"}},
|
||||||
|
{"_:\n- 1\n- A\n", []interface{}{1, "A"}},
|
||||||
|
{"_: 10\n", 10},
|
||||||
|
{"_: null\n", nil},
|
||||||
|
{"_: BAR!\n", "BAR!"},
|
||||||
|
}
|
||||||
|
|
||||||
|
type marshalerType struct {
|
||||||
|
value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o marshalerType) MarshalText() ([]byte, error) {
|
||||||
|
panic("MarshalText called on type with MarshalYAML")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o marshalerType) MarshalYAML() (interface{}, error) {
|
||||||
|
return o.value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type marshalerValue struct {
|
||||||
|
Field marshalerType "_"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestMarshaler(c *C) {
|
||||||
|
for _, item := range marshalerTests {
|
||||||
|
obj := &marshalerValue{}
|
||||||
|
obj.Field.value = item.value
|
||||||
|
data, err := yaml.Marshal(obj)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(string(data), Equals, string(item.data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestMarshalerWholeDocument(c *C) {
|
||||||
|
obj := &marshalerType{}
|
||||||
|
obj.value = map[string]string{"hello": "world!"}
|
||||||
|
data, err := yaml.Marshal(obj)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(string(data), Equals, "hello: world!\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
type failingMarshaler struct{}
|
||||||
|
|
||||||
|
func (ft *failingMarshaler) MarshalYAML() (interface{}, error) {
|
||||||
|
return nil, failingErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestMarshalerError(c *C) {
|
||||||
|
_, err := yaml.Marshal(&failingMarshaler{})
|
||||||
|
c.Assert(err, Equals, failingErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *S) TestSortedOutput(c *C) {
|
||||||
|
order := []interface{}{
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
uint(1),
|
||||||
|
1.0,
|
||||||
|
1.1,
|
||||||
|
1.2,
|
||||||
|
2,
|
||||||
|
uint(2),
|
||||||
|
2.0,
|
||||||
|
2.1,
|
||||||
|
"",
|
||||||
|
".1",
|
||||||
|
".2",
|
||||||
|
".a",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"a!10",
|
||||||
|
"a/2",
|
||||||
|
"a/10",
|
||||||
|
"a~10",
|
||||||
|
"ab/1",
|
||||||
|
"b/1",
|
||||||
|
"b/01",
|
||||||
|
"b/2",
|
||||||
|
"b/02",
|
||||||
|
"b/3",
|
||||||
|
"b/03",
|
||||||
|
"b1",
|
||||||
|
"b01",
|
||||||
|
"b3",
|
||||||
|
"c2.10",
|
||||||
|
"c10.2",
|
||||||
|
"d1",
|
||||||
|
"d12",
|
||||||
|
"d12a",
|
||||||
|
}
|
||||||
|
m := make(map[interface{}]int)
|
||||||
|
for _, k := range order {
|
||||||
|
m[k] = 1
|
||||||
|
}
|
||||||
|
data, err := yaml.Marshal(m)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
out := "\n" + string(data)
|
||||||
|
last := 0
|
||||||
|
for i, k := range order {
|
||||||
|
repr := fmt.Sprint(k)
|
||||||
|
if s, ok := k.(string); ok {
|
||||||
|
if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil {
|
||||||
|
repr = `"` + repr + `"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index := strings.Index(out, "\n"+repr+":")
|
||||||
|
if index == -1 {
|
||||||
|
c.Fatalf("%#v is not in the output: %#v", k, out)
|
||||||
|
}
|
||||||
|
if index < last {
|
||||||
|
c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
|
||||||
|
}
|
||||||
|
last = index
|
||||||
|
}
|
||||||
|
}
|
41
vendor/gopkg.in/yaml.v2/example_embedded_test.go
generated
vendored
Normal file
41
vendor/gopkg.in/yaml.v2/example_embedded_test.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package yaml_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An example showing how to unmarshal embedded
|
||||||
|
// structs from YAML.
|
||||||
|
|
||||||
|
type StructA struct {
|
||||||
|
A string `yaml:"a"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StructB struct {
|
||||||
|
// Embedded structs are not treated as embedded in YAML by default. To do that,
|
||||||
|
// add the ",inline" annotation below
|
||||||
|
StructA `yaml:",inline"`
|
||||||
|
B string `yaml:"b"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = `
|
||||||
|
a: a string from struct A
|
||||||
|
b: a string from struct B
|
||||||
|
`
|
||||||
|
|
||||||
|
func ExampleUnmarshal_embedded() {
|
||||||
|
var b StructB
|
||||||
|
|
||||||
|
err := yaml.Unmarshal([]byte(data), &b)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("cannot unmarshal data: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println(b.A)
|
||||||
|
fmt.Println(b.B)
|
||||||
|
// Output:
|
||||||
|
// a string from struct A
|
||||||
|
// a string from struct B
|
||||||
|
}
|
1095
vendor/gopkg.in/yaml.v2/parserc.go
generated
vendored
Normal file
1095
vendor/gopkg.in/yaml.v2/parserc.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
394
vendor/gopkg.in/yaml.v2/readerc.go
generated
vendored
Normal file
394
vendor/gopkg.in/yaml.v2/readerc.go
generated
vendored
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set the reader error and return 0.
|
||||||
|
func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool {
|
||||||
|
parser.error = yaml_READER_ERROR
|
||||||
|
parser.problem = problem
|
||||||
|
parser.problem_offset = offset
|
||||||
|
parser.problem_value = value
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Byte order marks.
|
||||||
|
const (
|
||||||
|
bom_UTF8 = "\xef\xbb\xbf"
|
||||||
|
bom_UTF16LE = "\xff\xfe"
|
||||||
|
bom_UTF16BE = "\xfe\xff"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Determine the input stream encoding by checking the BOM symbol. If no BOM is
|
||||||
|
// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure.
|
||||||
|
func yaml_parser_determine_encoding(parser *yaml_parser_t) bool {
|
||||||
|
// Ensure that we had enough bytes in the raw buffer.
|
||||||
|
for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 {
|
||||||
|
if !yaml_parser_update_raw_buffer(parser) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the encoding.
|
||||||
|
buf := parser.raw_buffer
|
||||||
|
pos := parser.raw_buffer_pos
|
||||||
|
avail := len(buf) - pos
|
||||||
|
if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] {
|
||||||
|
parser.encoding = yaml_UTF16LE_ENCODING
|
||||||
|
parser.raw_buffer_pos += 2
|
||||||
|
parser.offset += 2
|
||||||
|
} else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] {
|
||||||
|
parser.encoding = yaml_UTF16BE_ENCODING
|
||||||
|
parser.raw_buffer_pos += 2
|
||||||
|
parser.offset += 2
|
||||||
|
} else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] {
|
||||||
|
parser.encoding = yaml_UTF8_ENCODING
|
||||||
|
parser.raw_buffer_pos += 3
|
||||||
|
parser.offset += 3
|
||||||
|
} else {
|
||||||
|
parser.encoding = yaml_UTF8_ENCODING
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the raw buffer.
|
||||||
|
func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool {
|
||||||
|
size_read := 0
|
||||||
|
|
||||||
|
// Return if the raw buffer is full.
|
||||||
|
if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return on EOF.
|
||||||
|
if parser.eof {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the remaining bytes in the raw buffer to the beginning.
|
||||||
|
if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) {
|
||||||
|
copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:])
|
||||||
|
}
|
||||||
|
parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos]
|
||||||
|
parser.raw_buffer_pos = 0
|
||||||
|
|
||||||
|
// Call the read handler to fill the buffer.
|
||||||
|
size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)])
|
||||||
|
parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read]
|
||||||
|
if err == io.EOF {
|
||||||
|
parser.eof = true
|
||||||
|
} else if err != nil {
|
||||||
|
return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the buffer contains at least `length` characters.
|
||||||
|
// Return true on success, false on failure.
|
||||||
|
//
|
||||||
|
// The length is supposed to be significantly less that the buffer size.
|
||||||
|
func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool {
|
||||||
|
if parser.read_handler == nil {
|
||||||
|
panic("read handler must be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the EOF flag is set and the raw buffer is empty, do nothing.
|
||||||
|
if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if the buffer contains enough characters.
|
||||||
|
if parser.unread >= length {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the input encoding if it is not known yet.
|
||||||
|
if parser.encoding == yaml_ANY_ENCODING {
|
||||||
|
if !yaml_parser_determine_encoding(parser) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the unread characters to the beginning of the buffer.
|
||||||
|
buffer_len := len(parser.buffer)
|
||||||
|
if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len {
|
||||||
|
copy(parser.buffer, parser.buffer[parser.buffer_pos:])
|
||||||
|
buffer_len -= parser.buffer_pos
|
||||||
|
parser.buffer_pos = 0
|
||||||
|
} else if parser.buffer_pos == buffer_len {
|
||||||
|
buffer_len = 0
|
||||||
|
parser.buffer_pos = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the whole buffer for writing, and cut it before returning.
|
||||||
|
parser.buffer = parser.buffer[:cap(parser.buffer)]
|
||||||
|
|
||||||
|
// Fill the buffer until it has enough characters.
|
||||||
|
first := true
|
||||||
|
for parser.unread < length {
|
||||||
|
|
||||||
|
// Fill the raw buffer if necessary.
|
||||||
|
if !first || parser.raw_buffer_pos == len(parser.raw_buffer) {
|
||||||
|
if !yaml_parser_update_raw_buffer(parser) {
|
||||||
|
parser.buffer = parser.buffer[:buffer_len]
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
first = false
|
||||||
|
|
||||||
|
// Decode the raw buffer.
|
||||||
|
inner:
|
||||||
|
for parser.raw_buffer_pos != len(parser.raw_buffer) {
|
||||||
|
var value rune
|
||||||
|
var width int
|
||||||
|
|
||||||
|
raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos
|
||||||
|
|
||||||
|
// Decode the next character.
|
||||||
|
switch parser.encoding {
|
||||||
|
case yaml_UTF8_ENCODING:
|
||||||
|
// Decode a UTF-8 character. Check RFC 3629
|
||||||
|
// (http://www.ietf.org/rfc/rfc3629.txt) for more details.
|
||||||
|
//
|
||||||
|
// The following table (taken from the RFC) is used for
|
||||||
|
// decoding.
|
||||||
|
//
|
||||||
|
// Char. number range | UTF-8 octet sequence
|
||||||
|
// (hexadecimal) | (binary)
|
||||||
|
// --------------------+------------------------------------
|
||||||
|
// 0000 0000-0000 007F | 0xxxxxxx
|
||||||
|
// 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
|
||||||
|
// 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
// 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
//
|
||||||
|
// Additionally, the characters in the range 0xD800-0xDFFF
|
||||||
|
// are prohibited as they are reserved for use with UTF-16
|
||||||
|
// surrogate pairs.
|
||||||
|
|
||||||
|
// Determine the length of the UTF-8 sequence.
|
||||||
|
octet := parser.raw_buffer[parser.raw_buffer_pos]
|
||||||
|
switch {
|
||||||
|
case octet&0x80 == 0x00:
|
||||||
|
width = 1
|
||||||
|
case octet&0xE0 == 0xC0:
|
||||||
|
width = 2
|
||||||
|
case octet&0xF0 == 0xE0:
|
||||||
|
width = 3
|
||||||
|
case octet&0xF8 == 0xF0:
|
||||||
|
width = 4
|
||||||
|
default:
|
||||||
|
// The leading octet is invalid.
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"invalid leading UTF-8 octet",
|
||||||
|
parser.offset, int(octet))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the raw buffer contains an incomplete character.
|
||||||
|
if width > raw_unread {
|
||||||
|
if parser.eof {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"incomplete UTF-8 octet sequence",
|
||||||
|
parser.offset, -1)
|
||||||
|
}
|
||||||
|
break inner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the leading octet.
|
||||||
|
switch {
|
||||||
|
case octet&0x80 == 0x00:
|
||||||
|
value = rune(octet & 0x7F)
|
||||||
|
case octet&0xE0 == 0xC0:
|
||||||
|
value = rune(octet & 0x1F)
|
||||||
|
case octet&0xF0 == 0xE0:
|
||||||
|
value = rune(octet & 0x0F)
|
||||||
|
case octet&0xF8 == 0xF0:
|
||||||
|
value = rune(octet & 0x07)
|
||||||
|
default:
|
||||||
|
value = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and decode the trailing octets.
|
||||||
|
for k := 1; k < width; k++ {
|
||||||
|
octet = parser.raw_buffer[parser.raw_buffer_pos+k]
|
||||||
|
|
||||||
|
// Check if the octet is valid.
|
||||||
|
if (octet & 0xC0) != 0x80 {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"invalid trailing UTF-8 octet",
|
||||||
|
parser.offset+k, int(octet))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the octet.
|
||||||
|
value = (value << 6) + rune(octet&0x3F)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the length of the sequence against the value.
|
||||||
|
switch {
|
||||||
|
case width == 1:
|
||||||
|
case width == 2 && value >= 0x80:
|
||||||
|
case width == 3 && value >= 0x800:
|
||||||
|
case width == 4 && value >= 0x10000:
|
||||||
|
default:
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"invalid length of a UTF-8 sequence",
|
||||||
|
parser.offset, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the range of the value.
|
||||||
|
if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"invalid Unicode character",
|
||||||
|
parser.offset, int(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING:
|
||||||
|
var low, high int
|
||||||
|
if parser.encoding == yaml_UTF16LE_ENCODING {
|
||||||
|
low, high = 0, 1
|
||||||
|
} else {
|
||||||
|
low, high = 1, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// The UTF-16 encoding is not as simple as one might
|
||||||
|
// naively think. Check RFC 2781
|
||||||
|
// (http://www.ietf.org/rfc/rfc2781.txt).
|
||||||
|
//
|
||||||
|
// Normally, two subsequent bytes describe a Unicode
|
||||||
|
// character. However a special technique (called a
|
||||||
|
// surrogate pair) is used for specifying character
|
||||||
|
// values larger than 0xFFFF.
|
||||||
|
//
|
||||||
|
// A surrogate pair consists of two pseudo-characters:
|
||||||
|
// high surrogate area (0xD800-0xDBFF)
|
||||||
|
// low surrogate area (0xDC00-0xDFFF)
|
||||||
|
//
|
||||||
|
// The following formulas are used for decoding
|
||||||
|
// and encoding characters using surrogate pairs:
|
||||||
|
//
|
||||||
|
// U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF)
|
||||||
|
// U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF)
|
||||||
|
// W1 = 110110yyyyyyyyyy
|
||||||
|
// W2 = 110111xxxxxxxxxx
|
||||||
|
//
|
||||||
|
// where U is the character value, W1 is the high surrogate
|
||||||
|
// area, W2 is the low surrogate area.
|
||||||
|
|
||||||
|
// Check for incomplete UTF-16 character.
|
||||||
|
if raw_unread < 2 {
|
||||||
|
if parser.eof {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"incomplete UTF-16 character",
|
||||||
|
parser.offset, -1)
|
||||||
|
}
|
||||||
|
break inner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the character.
|
||||||
|
value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) +
|
||||||
|
(rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8)
|
||||||
|
|
||||||
|
// Check for unexpected low surrogate area.
|
||||||
|
if value&0xFC00 == 0xDC00 {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"unexpected low surrogate area",
|
||||||
|
parser.offset, int(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a high surrogate area.
|
||||||
|
if value&0xFC00 == 0xD800 {
|
||||||
|
width = 4
|
||||||
|
|
||||||
|
// Check for incomplete surrogate pair.
|
||||||
|
if raw_unread < 4 {
|
||||||
|
if parser.eof {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"incomplete UTF-16 surrogate pair",
|
||||||
|
parser.offset, -1)
|
||||||
|
}
|
||||||
|
break inner
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next character.
|
||||||
|
value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) +
|
||||||
|
(rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8)
|
||||||
|
|
||||||
|
// Check for a low surrogate area.
|
||||||
|
if value2&0xFC00 != 0xDC00 {
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"expected low surrogate area",
|
||||||
|
parser.offset+2, int(value2))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the value of the surrogate pair.
|
||||||
|
value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF)
|
||||||
|
} else {
|
||||||
|
width = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("impossible")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character is in the allowed range:
|
||||||
|
// #x9 | #xA | #xD | [#x20-#x7E] (8 bit)
|
||||||
|
// | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit)
|
||||||
|
// | [#x10000-#x10FFFF] (32 bit)
|
||||||
|
switch {
|
||||||
|
case value == 0x09:
|
||||||
|
case value == 0x0A:
|
||||||
|
case value == 0x0D:
|
||||||
|
case value >= 0x20 && value <= 0x7E:
|
||||||
|
case value == 0x85:
|
||||||
|
case value >= 0xA0 && value <= 0xD7FF:
|
||||||
|
case value >= 0xE000 && value <= 0xFFFD:
|
||||||
|
case value >= 0x10000 && value <= 0x10FFFF:
|
||||||
|
default:
|
||||||
|
return yaml_parser_set_reader_error(parser,
|
||||||
|
"control characters are not allowed",
|
||||||
|
parser.offset, int(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the raw pointers.
|
||||||
|
parser.raw_buffer_pos += width
|
||||||
|
parser.offset += width
|
||||||
|
|
||||||
|
// Finally put the character into the buffer.
|
||||||
|
if value <= 0x7F {
|
||||||
|
// 0000 0000-0000 007F . 0xxxxxxx
|
||||||
|
parser.buffer[buffer_len+0] = byte(value)
|
||||||
|
buffer_len += 1
|
||||||
|
} else if value <= 0x7FF {
|
||||||
|
// 0000 0080-0000 07FF . 110xxxxx 10xxxxxx
|
||||||
|
parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6))
|
||||||
|
parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F))
|
||||||
|
buffer_len += 2
|
||||||
|
} else if value <= 0xFFFF {
|
||||||
|
// 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12))
|
||||||
|
parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F))
|
||||||
|
parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F))
|
||||||
|
buffer_len += 3
|
||||||
|
} else {
|
||||||
|
// 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18))
|
||||||
|
parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F))
|
||||||
|
parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F))
|
||||||
|
parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F))
|
||||||
|
buffer_len += 4
|
||||||
|
}
|
||||||
|
|
||||||
|
parser.unread++
|
||||||
|
}
|
||||||
|
|
||||||
|
// On EOF, put NUL into the buffer and return.
|
||||||
|
if parser.eof {
|
||||||
|
parser.buffer[buffer_len] = 0
|
||||||
|
buffer_len++
|
||||||
|
parser.unread++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parser.buffer = parser.buffer[:buffer_len]
|
||||||
|
return true
|
||||||
|
}
|
208
vendor/gopkg.in/yaml.v2/resolve.go
generated
vendored
Normal file
208
vendor/gopkg.in/yaml.v2/resolve.go
generated
vendored
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"math"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type resolveMapItem struct {
|
||||||
|
value interface{}
|
||||||
|
tag string
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolveTable = make([]byte, 256)
|
||||||
|
var resolveMap = make(map[string]resolveMapItem)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
t := resolveTable
|
||||||
|
t[int('+')] = 'S' // Sign
|
||||||
|
t[int('-')] = 'S'
|
||||||
|
for _, c := range "0123456789" {
|
||||||
|
t[int(c)] = 'D' // Digit
|
||||||
|
}
|
||||||
|
for _, c := range "yYnNtTfFoO~" {
|
||||||
|
t[int(c)] = 'M' // In map
|
||||||
|
}
|
||||||
|
t[int('.')] = '.' // Float (potentially in map)
|
||||||
|
|
||||||
|
var resolveMapList = []struct {
|
||||||
|
v interface{}
|
||||||
|
tag string
|
||||||
|
l []string
|
||||||
|
}{
|
||||||
|
{true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}},
|
||||||
|
{true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}},
|
||||||
|
{true, yaml_BOOL_TAG, []string{"on", "On", "ON"}},
|
||||||
|
{false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}},
|
||||||
|
{false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}},
|
||||||
|
{false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}},
|
||||||
|
{nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}},
|
||||||
|
{math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}},
|
||||||
|
{math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}},
|
||||||
|
{math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}},
|
||||||
|
{math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}},
|
||||||
|
{"<<", yaml_MERGE_TAG, []string{"<<"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
m := resolveMap
|
||||||
|
for _, item := range resolveMapList {
|
||||||
|
for _, s := range item.l {
|
||||||
|
m[s] = resolveMapItem{item.v, item.tag}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const longTagPrefix = "tag:yaml.org,2002:"
|
||||||
|
|
||||||
|
func shortTag(tag string) string {
|
||||||
|
// TODO This can easily be made faster and produce less garbage.
|
||||||
|
if strings.HasPrefix(tag, longTagPrefix) {
|
||||||
|
return "!!" + tag[len(longTagPrefix):]
|
||||||
|
}
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
|
||||||
|
func longTag(tag string) string {
|
||||||
|
if strings.HasPrefix(tag, "!!") {
|
||||||
|
return longTagPrefix + tag[2:]
|
||||||
|
}
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolvableTag(tag string) bool {
|
||||||
|
switch tag {
|
||||||
|
case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`)
|
||||||
|
|
||||||
|
func resolve(tag string, in string) (rtag string, out interface{}) {
|
||||||
|
if !resolvableTag(tag) {
|
||||||
|
return tag, in
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
switch tag {
|
||||||
|
case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag))
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Any data is accepted as a !!str or !!binary.
|
||||||
|
// Otherwise, the prefix is enough of a hint about what it might be.
|
||||||
|
hint := byte('N')
|
||||||
|
if in != "" {
|
||||||
|
hint = resolveTable[in[0]]
|
||||||
|
}
|
||||||
|
if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG {
|
||||||
|
// Handle things we can lookup in a map.
|
||||||
|
if item, ok := resolveMap[in]; ok {
|
||||||
|
return item.tag, item.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base 60 floats are a bad idea, were dropped in YAML 1.2, and
|
||||||
|
// are purposefully unsupported here. They're still quoted on
|
||||||
|
// the way out for compatibility with other parser, though.
|
||||||
|
|
||||||
|
switch hint {
|
||||||
|
case 'M':
|
||||||
|
// We've already checked the map above.
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
// Not in the map, so maybe a normal float.
|
||||||
|
floatv, err := strconv.ParseFloat(in, 64)
|
||||||
|
if err == nil {
|
||||||
|
return yaml_FLOAT_TAG, floatv
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'D', 'S':
|
||||||
|
// Int, float, or timestamp.
|
||||||
|
plain := strings.Replace(in, "_", "", -1)
|
||||||
|
intv, err := strconv.ParseInt(plain, 0, 64)
|
||||||
|
if err == nil {
|
||||||
|
if intv == int64(int(intv)) {
|
||||||
|
return yaml_INT_TAG, int(intv)
|
||||||
|
} else {
|
||||||
|
return yaml_INT_TAG, intv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uintv, err := strconv.ParseUint(plain, 0, 64)
|
||||||
|
if err == nil {
|
||||||
|
return yaml_INT_TAG, uintv
|
||||||
|
}
|
||||||
|
if yamlStyleFloat.MatchString(plain) {
|
||||||
|
floatv, err := strconv.ParseFloat(plain, 64)
|
||||||
|
if err == nil {
|
||||||
|
return yaml_FLOAT_TAG, floatv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(plain, "0b") {
|
||||||
|
intv, err := strconv.ParseInt(plain[2:], 2, 64)
|
||||||
|
if err == nil {
|
||||||
|
if intv == int64(int(intv)) {
|
||||||
|
return yaml_INT_TAG, int(intv)
|
||||||
|
} else {
|
||||||
|
return yaml_INT_TAG, intv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uintv, err := strconv.ParseUint(plain[2:], 2, 64)
|
||||||
|
if err == nil {
|
||||||
|
return yaml_INT_TAG, uintv
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(plain, "-0b") {
|
||||||
|
intv, err := strconv.ParseInt(plain[3:], 2, 64)
|
||||||
|
if err == nil {
|
||||||
|
if intv == int64(int(intv)) {
|
||||||
|
return yaml_INT_TAG, -int(intv)
|
||||||
|
} else {
|
||||||
|
return yaml_INT_TAG, -intv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// XXX Handle timestamps here.
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tag == yaml_BINARY_TAG {
|
||||||
|
return yaml_BINARY_TAG, in
|
||||||
|
}
|
||||||
|
if utf8.ValidString(in) {
|
||||||
|
return yaml_STR_TAG, in
|
||||||
|
}
|
||||||
|
return yaml_BINARY_TAG, encodeBase64(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeBase64 encodes s as base64 that is broken up into multiple lines
|
||||||
|
// as appropriate for the resulting length.
|
||||||
|
func encodeBase64(s string) string {
|
||||||
|
const lineLen = 70
|
||||||
|
encLen := base64.StdEncoding.EncodedLen(len(s))
|
||||||
|
lines := encLen/lineLen + 1
|
||||||
|
buf := make([]byte, encLen*2+lines)
|
||||||
|
in := buf[0:encLen]
|
||||||
|
out := buf[encLen:]
|
||||||
|
base64.StdEncoding.Encode(in, []byte(s))
|
||||||
|
k := 0
|
||||||
|
for i := 0; i < len(in); i += lineLen {
|
||||||
|
j := i + lineLen
|
||||||
|
if j > len(in) {
|
||||||
|
j = len(in)
|
||||||
|
}
|
||||||
|
k += copy(out[k:], in[i:j])
|
||||||
|
if lines > 1 {
|
||||||
|
out[k] = '\n'
|
||||||
|
k++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(out[:k])
|
||||||
|
}
|
2711
vendor/gopkg.in/yaml.v2/scannerc.go
generated
vendored
Normal file
2711
vendor/gopkg.in/yaml.v2/scannerc.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
104
vendor/gopkg.in/yaml.v2/sorter.go
generated
vendored
Normal file
104
vendor/gopkg.in/yaml.v2/sorter.go
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
type keyList []reflect.Value
|
||||||
|
|
||||||
|
func (l keyList) Len() int { return len(l) }
|
||||||
|
func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
|
||||||
|
func (l keyList) Less(i, j int) bool {
|
||||||
|
a := l[i]
|
||||||
|
b := l[j]
|
||||||
|
ak := a.Kind()
|
||||||
|
bk := b.Kind()
|
||||||
|
for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() {
|
||||||
|
a = a.Elem()
|
||||||
|
ak = a.Kind()
|
||||||
|
}
|
||||||
|
for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() {
|
||||||
|
b = b.Elem()
|
||||||
|
bk = b.Kind()
|
||||||
|
}
|
||||||
|
af, aok := keyFloat(a)
|
||||||
|
bf, bok := keyFloat(b)
|
||||||
|
if aok && bok {
|
||||||
|
if af != bf {
|
||||||
|
return af < bf
|
||||||
|
}
|
||||||
|
if ak != bk {
|
||||||
|
return ak < bk
|
||||||
|
}
|
||||||
|
return numLess(a, b)
|
||||||
|
}
|
||||||
|
if ak != reflect.String || bk != reflect.String {
|
||||||
|
return ak < bk
|
||||||
|
}
|
||||||
|
ar, br := []rune(a.String()), []rune(b.String())
|
||||||
|
for i := 0; i < len(ar) && i < len(br); i++ {
|
||||||
|
if ar[i] == br[i] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
al := unicode.IsLetter(ar[i])
|
||||||
|
bl := unicode.IsLetter(br[i])
|
||||||
|
if al && bl {
|
||||||
|
return ar[i] < br[i]
|
||||||
|
}
|
||||||
|
if al || bl {
|
||||||
|
return bl
|
||||||
|
}
|
||||||
|
var ai, bi int
|
||||||
|
var an, bn int64
|
||||||
|
for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ {
|
||||||
|
an = an*10 + int64(ar[ai]-'0')
|
||||||
|
}
|
||||||
|
for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ {
|
||||||
|
bn = bn*10 + int64(br[bi]-'0')
|
||||||
|
}
|
||||||
|
if an != bn {
|
||||||
|
return an < bn
|
||||||
|
}
|
||||||
|
if ai != bi {
|
||||||
|
return ai < bi
|
||||||
|
}
|
||||||
|
return ar[i] < br[i]
|
||||||
|
}
|
||||||
|
return len(ar) < len(br)
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyFloat returns a float value for v if it is a number/bool
|
||||||
|
// and whether it is a number/bool or not.
|
||||||
|
func keyFloat(v reflect.Value) (f float64, ok bool) {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return float64(v.Int()), true
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v.Float(), true
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return float64(v.Uint()), true
|
||||||
|
case reflect.Bool:
|
||||||
|
if v.Bool() {
|
||||||
|
return 1, true
|
||||||
|
}
|
||||||
|
return 0, true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// numLess returns whether a < b.
|
||||||
|
// a and b must necessarily have the same kind.
|
||||||
|
func numLess(a, b reflect.Value) bool {
|
||||||
|
switch a.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return a.Int() < b.Int()
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return a.Float() < b.Float()
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return a.Uint() < b.Uint()
|
||||||
|
case reflect.Bool:
|
||||||
|
return !a.Bool() && b.Bool()
|
||||||
|
}
|
||||||
|
panic("not a number")
|
||||||
|
}
|
12
vendor/gopkg.in/yaml.v2/suite_test.go
generated
vendored
Normal file
12
vendor/gopkg.in/yaml.v2/suite_test.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package yaml_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "gopkg.in/check.v1"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test(t *testing.T) { TestingT(t) }
|
||||||
|
|
||||||
|
type S struct{}
|
||||||
|
|
||||||
|
var _ = Suite(&S{})
|
89
vendor/gopkg.in/yaml.v2/writerc.go
generated
vendored
Normal file
89
vendor/gopkg.in/yaml.v2/writerc.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package yaml
|
||||||
|
|
||||||
|
// Set the writer error and return false.
|
||||||
|
func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool {
|
||||||
|
emitter.error = yaml_WRITER_ERROR
|
||||||
|
emitter.problem = problem
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the output buffer.
|
||||||
|
func yaml_emitter_flush(emitter *yaml_emitter_t) bool {
|
||||||
|
if emitter.write_handler == nil {
|
||||||
|
panic("write handler not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the buffer is empty.
|
||||||
|
if emitter.buffer_pos == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the output encoding is UTF-8, we don't need to recode the buffer.
|
||||||
|
if emitter.encoding == yaml_UTF8_ENCODING {
|
||||||
|
if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil {
|
||||||
|
return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
|
||||||
|
}
|
||||||
|
emitter.buffer_pos = 0
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recode the buffer into the raw buffer.
|
||||||
|
var low, high int
|
||||||
|
if emitter.encoding == yaml_UTF16LE_ENCODING {
|
||||||
|
low, high = 0, 1
|
||||||
|
} else {
|
||||||
|
high, low = 1, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pos := 0
|
||||||
|
for pos < emitter.buffer_pos {
|
||||||
|
// See the "reader.c" code for more details on UTF-8 encoding. Note
|
||||||
|
// that we assume that the buffer contains a valid UTF-8 sequence.
|
||||||
|
|
||||||
|
// Read the next UTF-8 character.
|
||||||
|
octet := emitter.buffer[pos]
|
||||||
|
|
||||||
|
var w int
|
||||||
|
var value rune
|
||||||
|
switch {
|
||||||
|
case octet&0x80 == 0x00:
|
||||||
|
w, value = 1, rune(octet&0x7F)
|
||||||
|
case octet&0xE0 == 0xC0:
|
||||||
|
w, value = 2, rune(octet&0x1F)
|
||||||
|
case octet&0xF0 == 0xE0:
|
||||||
|
w, value = 3, rune(octet&0x0F)
|
||||||
|
case octet&0xF8 == 0xF0:
|
||||||
|
w, value = 4, rune(octet&0x07)
|
||||||
|
}
|
||||||
|
for k := 1; k < w; k++ {
|
||||||
|
octet = emitter.buffer[pos+k]
|
||||||
|
value = (value << 6) + (rune(octet) & 0x3F)
|
||||||
|
}
|
||||||
|
pos += w
|
||||||
|
|
||||||
|
// Write the character.
|
||||||
|
if value < 0x10000 {
|
||||||
|
var b [2]byte
|
||||||
|
b[high] = byte(value >> 8)
|
||||||
|
b[low] = byte(value & 0xFF)
|
||||||
|
emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1])
|
||||||
|
} else {
|
||||||
|
// Write the character using a surrogate pair (check "reader.c").
|
||||||
|
var b [4]byte
|
||||||
|
value -= 0x10000
|
||||||
|
b[high] = byte(0xD8 + (value >> 18))
|
||||||
|
b[low] = byte((value >> 10) & 0xFF)
|
||||||
|
b[high+2] = byte(0xDC + ((value >> 8) & 0xFF))
|
||||||
|
b[low+2] = byte(value & 0xFF)
|
||||||
|
emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1], b[2], b[3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the raw buffer.
|
||||||
|
if err := emitter.write_handler(emitter, emitter.raw_buffer); err != nil {
|
||||||
|
return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error())
|
||||||
|
}
|
||||||
|
emitter.buffer_pos = 0
|
||||||
|
emitter.raw_buffer = emitter.raw_buffer[:0]
|
||||||
|
return true
|
||||||
|
}
|
357
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
Normal file
357
vendor/gopkg.in/yaml.v2/yaml.go
generated
vendored
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
// Package yaml implements YAML support for the Go language.
|
||||||
|
//
|
||||||
|
// Source code and other details for the project are available at GitHub:
|
||||||
|
//
|
||||||
|
// https://github.com/go-yaml/yaml
|
||||||
|
//
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MapSlice encodes and decodes as a YAML map.
|
||||||
|
// The order of keys is preserved when encoding and decoding.
|
||||||
|
type MapSlice []MapItem
|
||||||
|
|
||||||
|
// MapItem is an item in a MapSlice.
|
||||||
|
type MapItem struct {
|
||||||
|
Key, Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Unmarshaler interface may be implemented by types to customize their
|
||||||
|
// behavior when being unmarshaled from a YAML document. The UnmarshalYAML
|
||||||
|
// method receives a function that may be called to unmarshal the original
|
||||||
|
// YAML value into a field or variable. It is safe to call the unmarshal
|
||||||
|
// function parameter more than once if necessary.
|
||||||
|
type Unmarshaler interface {
|
||||||
|
UnmarshalYAML(unmarshal func(interface{}) error) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Marshaler interface may be implemented by types to customize their
|
||||||
|
// behavior when being marshaled into a YAML document. The returned value
|
||||||
|
// is marshaled in place of the original value implementing Marshaler.
|
||||||
|
//
|
||||||
|
// If an error is returned by MarshalYAML, the marshaling procedure stops
|
||||||
|
// and returns with the provided error.
|
||||||
|
type Marshaler interface {
|
||||||
|
MarshalYAML() (interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal decodes the first document found within the in byte slice
|
||||||
|
// and assigns decoded values into the out value.
|
||||||
|
//
|
||||||
|
// Maps and pointers (to a struct, string, int, etc) are accepted as out
|
||||||
|
// values. If an internal pointer within a struct is not initialized,
|
||||||
|
// the yaml package will initialize it if necessary for unmarshalling
|
||||||
|
// the provided data. The out parameter must not be nil.
|
||||||
|
//
|
||||||
|
// The type of the decoded values should be compatible with the respective
|
||||||
|
// values in out. If one or more values cannot be decoded due to a type
|
||||||
|
// mismatches, decoding continues partially until the end of the YAML
|
||||||
|
// content, and a *yaml.TypeError is returned with details for all
|
||||||
|
// missed values.
|
||||||
|
//
|
||||||
|
// Struct fields are only unmarshalled if they are exported (have an
|
||||||
|
// upper case first letter), and are unmarshalled using the field name
|
||||||
|
// lowercased as the default key. Custom keys may be defined via the
|
||||||
|
// "yaml" name in the field tag: the content preceding the first comma
|
||||||
|
// is used as the key, and the following comma-separated options are
|
||||||
|
// used to tweak the marshalling process (see Marshal).
|
||||||
|
// Conflicting names result in a runtime error.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// type T struct {
|
||||||
|
// F int `yaml:"a,omitempty"`
|
||||||
|
// B int
|
||||||
|
// }
|
||||||
|
// var t T
|
||||||
|
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
|
||||||
|
//
|
||||||
|
// See the documentation of Marshal for the format of tags and a list of
|
||||||
|
// supported tag options.
|
||||||
|
//
|
||||||
|
func Unmarshal(in []byte, out interface{}) (err error) {
|
||||||
|
return unmarshal(in, out, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalStrict is like Unmarshal except that any fields that are found
|
||||||
|
// in the data that do not have corresponding struct members will result in
|
||||||
|
// an error.
|
||||||
|
func UnmarshalStrict(in []byte, out interface{}) (err error) {
|
||||||
|
return unmarshal(in, out, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshal(in []byte, out interface{}, strict bool) (err error) {
|
||||||
|
defer handleErr(&err)
|
||||||
|
d := newDecoder(strict)
|
||||||
|
p := newParser(in)
|
||||||
|
defer p.destroy()
|
||||||
|
node := p.parse()
|
||||||
|
if node != nil {
|
||||||
|
v := reflect.ValueOf(out)
|
||||||
|
if v.Kind() == reflect.Ptr && !v.IsNil() {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
d.unmarshal(node, v)
|
||||||
|
}
|
||||||
|
if len(d.terrors) > 0 {
|
||||||
|
return &TypeError{d.terrors}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal serializes the value provided into a YAML document. The structure
|
||||||
|
// of the generated document will reflect the structure of the value itself.
|
||||||
|
// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
|
||||||
|
//
|
||||||
|
// Struct fields are only unmarshalled if they are exported (have an upper case
|
||||||
|
// first letter), and are unmarshalled using the field name lowercased as the
|
||||||
|
// default key. Custom keys may be defined via the "yaml" name in the field
|
||||||
|
// tag: the content preceding the first comma is used as the key, and the
|
||||||
|
// following comma-separated options are used to tweak the marshalling process.
|
||||||
|
// Conflicting names result in a runtime error.
|
||||||
|
//
|
||||||
|
// The field tag format accepted is:
|
||||||
|
//
|
||||||
|
// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
|
||||||
|
//
|
||||||
|
// The following flags are currently supported:
|
||||||
|
//
|
||||||
|
// omitempty Only include the field if it's not set to the zero
|
||||||
|
// value for the type or to empty slices or maps.
|
||||||
|
// Does not apply to zero valued structs.
|
||||||
|
//
|
||||||
|
// flow Marshal using a flow style (useful for structs,
|
||||||
|
// sequences and maps).
|
||||||
|
//
|
||||||
|
// inline Inline the field, which must be a struct or a map,
|
||||||
|
// causing all of its fields or keys to be processed as if
|
||||||
|
// they were part of the outer struct. For maps, keys must
|
||||||
|
// not conflict with the yaml keys of other struct fields.
|
||||||
|
//
|
||||||
|
// In addition, if the key is "-", the field is ignored.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// type T struct {
|
||||||
|
// F int "a,omitempty"
|
||||||
|
// B int
|
||||||
|
// }
|
||||||
|
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
|
||||||
|
// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
|
||||||
|
//
|
||||||
|
func Marshal(in interface{}) (out []byte, err error) {
|
||||||
|
defer handleErr(&err)
|
||||||
|
e := newEncoder()
|
||||||
|
defer e.destroy()
|
||||||
|
e.marshal("", reflect.ValueOf(in))
|
||||||
|
e.finish()
|
||||||
|
out = e.out
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleErr(err *error) {
|
||||||
|
if v := recover(); v != nil {
|
||||||
|
if e, ok := v.(yamlError); ok {
|
||||||
|
*err = e.err
|
||||||
|
} else {
|
||||||
|
panic(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type yamlError struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func fail(err error) {
|
||||||
|
panic(yamlError{err})
|
||||||
|
}
|
||||||
|
|
||||||
|
func failf(format string, args ...interface{}) {
|
||||||
|
panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// A TypeError is returned by Unmarshal when one or more fields in
|
||||||
|
// the YAML document cannot be properly decoded into the requested
|
||||||
|
// types. When this error is returned, the value is still
|
||||||
|
// unmarshaled partially.
|
||||||
|
type TypeError struct {
|
||||||
|
Errors []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *TypeError) Error() string {
|
||||||
|
return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n "))
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// Maintain a mapping of keys to structure field indexes
|
||||||
|
|
||||||
|
// The code in this section was copied from mgo/bson.
|
||||||
|
|
||||||
|
// structInfo holds details for the serialization of fields of
|
||||||
|
// a given struct.
|
||||||
|
type structInfo struct {
|
||||||
|
FieldsMap map[string]fieldInfo
|
||||||
|
FieldsList []fieldInfo
|
||||||
|
|
||||||
|
// InlineMap is the number of the field in the struct that
|
||||||
|
// contains an ,inline map, or -1 if there's none.
|
||||||
|
InlineMap int
|
||||||
|
}
|
||||||
|
|
||||||
|
type fieldInfo struct {
|
||||||
|
Key string
|
||||||
|
Num int
|
||||||
|
OmitEmpty bool
|
||||||
|
Flow bool
|
||||||
|
|
||||||
|
// Inline holds the field index if the field is part of an inlined struct.
|
||||||
|
Inline []int
|
||||||
|
}
|
||||||
|
|
||||||
|
var structMap = make(map[reflect.Type]*structInfo)
|
||||||
|
var fieldMapMutex sync.RWMutex
|
||||||
|
|
||||||
|
func getStructInfo(st reflect.Type) (*structInfo, error) {
|
||||||
|
fieldMapMutex.RLock()
|
||||||
|
sinfo, found := structMap[st]
|
||||||
|
fieldMapMutex.RUnlock()
|
||||||
|
if found {
|
||||||
|
return sinfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
n := st.NumField()
|
||||||
|
fieldsMap := make(map[string]fieldInfo)
|
||||||
|
fieldsList := make([]fieldInfo, 0, n)
|
||||||
|
inlineMap := -1
|
||||||
|
for i := 0; i != n; i++ {
|
||||||
|
field := st.Field(i)
|
||||||
|
if field.PkgPath != "" && !field.Anonymous {
|
||||||
|
continue // Private field
|
||||||
|
}
|
||||||
|
|
||||||
|
info := fieldInfo{Num: i}
|
||||||
|
|
||||||
|
tag := field.Tag.Get("yaml")
|
||||||
|
if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
|
||||||
|
tag = string(field.Tag)
|
||||||
|
}
|
||||||
|
if tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
inline := false
|
||||||
|
fields := strings.Split(tag, ",")
|
||||||
|
if len(fields) > 1 {
|
||||||
|
for _, flag := range fields[1:] {
|
||||||
|
switch flag {
|
||||||
|
case "omitempty":
|
||||||
|
info.OmitEmpty = true
|
||||||
|
case "flow":
|
||||||
|
info.Flow = true
|
||||||
|
case "inline":
|
||||||
|
inline = true
|
||||||
|
default:
|
||||||
|
return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tag = fields[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if inline {
|
||||||
|
switch field.Type.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
if inlineMap >= 0 {
|
||||||
|
return nil, errors.New("Multiple ,inline maps in struct " + st.String())
|
||||||
|
}
|
||||||
|
if field.Type.Key() != reflect.TypeOf("") {
|
||||||
|
return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
|
||||||
|
}
|
||||||
|
inlineMap = info.Num
|
||||||
|
case reflect.Struct:
|
||||||
|
sinfo, err := getStructInfo(field.Type)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, finfo := range sinfo.FieldsList {
|
||||||
|
if _, found := fieldsMap[finfo.Key]; found {
|
||||||
|
msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
|
||||||
|
return nil, errors.New(msg)
|
||||||
|
}
|
||||||
|
if finfo.Inline == nil {
|
||||||
|
finfo.Inline = []int{i, finfo.Num}
|
||||||
|
} else {
|
||||||
|
finfo.Inline = append([]int{i}, finfo.Inline...)
|
||||||
|
}
|
||||||
|
fieldsMap[finfo.Key] = finfo
|
||||||
|
fieldsList = append(fieldsList, finfo)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
//return nil, errors.New("Option ,inline needs a struct value or map field")
|
||||||
|
return nil, errors.New("Option ,inline needs a struct value field")
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if tag != "" {
|
||||||
|
info.Key = tag
|
||||||
|
} else {
|
||||||
|
info.Key = strings.ToLower(field.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, found = fieldsMap[info.Key]; found {
|
||||||
|
msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
|
||||||
|
return nil, errors.New(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldsList = append(fieldsList, info)
|
||||||
|
fieldsMap[info.Key] = info
|
||||||
|
}
|
||||||
|
|
||||||
|
sinfo = &structInfo{fieldsMap, fieldsList, inlineMap}
|
||||||
|
|
||||||
|
fieldMapMutex.Lock()
|
||||||
|
structMap[st] = sinfo
|
||||||
|
fieldMapMutex.Unlock()
|
||||||
|
return sinfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isZero(v reflect.Value) bool {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
return len(v.String()) == 0
|
||||||
|
case reflect.Interface, reflect.Ptr:
|
||||||
|
return v.IsNil()
|
||||||
|
case reflect.Slice:
|
||||||
|
return v.Len() == 0
|
||||||
|
case reflect.Map:
|
||||||
|
return v.Len() == 0
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return v.Int() == 0
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v.Float() == 0
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return v.Uint() == 0
|
||||||
|
case reflect.Bool:
|
||||||
|
return !v.Bool()
|
||||||
|
case reflect.Struct:
|
||||||
|
vt := v.Type()
|
||||||
|
for i := v.NumField() - 1; i >= 0; i-- {
|
||||||
|
if vt.Field(i).PkgPath != "" {
|
||||||
|
continue // Private field
|
||||||
|
}
|
||||||
|
if !isZero(v.Field(i)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
716
vendor/gopkg.in/yaml.v2/yamlh.go
generated
vendored
Normal file
716
vendor/gopkg.in/yaml.v2/yamlh.go
generated
vendored
Normal file
@ -0,0 +1,716 @@
|
|||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The version directive data.
|
||||||
|
type yaml_version_directive_t struct {
|
||||||
|
major int8 // The major version number.
|
||||||
|
minor int8 // The minor version number.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The tag directive data.
|
||||||
|
type yaml_tag_directive_t struct {
|
||||||
|
handle []byte // The tag handle.
|
||||||
|
prefix []byte // The tag prefix.
|
||||||
|
}
|
||||||
|
|
||||||
|
type yaml_encoding_t int
|
||||||
|
|
||||||
|
// The stream encoding.
|
||||||
|
const (
|
||||||
|
// Let the parser choose the encoding.
|
||||||
|
yaml_ANY_ENCODING yaml_encoding_t = iota
|
||||||
|
|
||||||
|
yaml_UTF8_ENCODING // The default UTF-8 encoding.
|
||||||
|
yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM.
|
||||||
|
yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM.
|
||||||
|
)
|
||||||
|
|
||||||
|
type yaml_break_t int
|
||||||
|
|
||||||
|
// Line break types.
|
||||||
|
const (
|
||||||
|
// Let the parser choose the break type.
|
||||||
|
yaml_ANY_BREAK yaml_break_t = iota
|
||||||
|
|
||||||
|
yaml_CR_BREAK // Use CR for line breaks (Mac style).
|
||||||
|
yaml_LN_BREAK // Use LN for line breaks (Unix style).
|
||||||
|
yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style).
|
||||||
|
)
|
||||||
|
|
||||||
|
type yaml_error_type_t int
|
||||||
|
|
||||||
|
// Many bad things could happen with the parser and emitter.
|
||||||
|
const (
|
||||||
|
// No error is produced.
|
||||||
|
yaml_NO_ERROR yaml_error_type_t = iota
|
||||||
|
|
||||||
|
yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory.
|
||||||
|
yaml_READER_ERROR // Cannot read or decode the input stream.
|
||||||
|
yaml_SCANNER_ERROR // Cannot scan the input stream.
|
||||||
|
yaml_PARSER_ERROR // Cannot parse the input stream.
|
||||||
|
yaml_COMPOSER_ERROR // Cannot compose a YAML document.
|
||||||
|
yaml_WRITER_ERROR // Cannot write to the output stream.
|
||||||
|
yaml_EMITTER_ERROR // Cannot emit a YAML stream.
|
||||||
|
)
|
||||||
|
|
||||||
|
// The pointer position.
|
||||||
|
type yaml_mark_t struct {
|
||||||
|
index int // The position index.
|
||||||
|
line int // The position line.
|
||||||
|
column int // The position column.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node Styles
|
||||||
|
|
||||||
|
type yaml_style_t int8
|
||||||
|
|
||||||
|
type yaml_scalar_style_t yaml_style_t
|
||||||
|
|
||||||
|
// Scalar styles.
|
||||||
|
const (
|
||||||
|
// Let the emitter choose the style.
|
||||||
|
yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = iota
|
||||||
|
|
||||||
|
yaml_PLAIN_SCALAR_STYLE // The plain scalar style.
|
||||||
|
yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style.
|
||||||
|
yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style.
|
||||||
|
yaml_LITERAL_SCALAR_STYLE // The literal scalar style.
|
||||||
|
yaml_FOLDED_SCALAR_STYLE // The folded scalar style.
|
||||||
|
)
|
||||||
|
|
||||||
|
type yaml_sequence_style_t yaml_style_t
|
||||||
|
|
||||||
|
// Sequence styles.
|
||||||
|
const (
|
||||||
|
// Let the emitter choose the style.
|
||||||
|
yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota
|
||||||
|
|
||||||
|
yaml_BLOCK_SEQUENCE_STYLE // The block sequence style.
|
||||||
|
yaml_FLOW_SEQUENCE_STYLE // The flow sequence style.
|
||||||
|
)
|
||||||
|
|
||||||
|
type yaml_mapping_style_t yaml_style_t
|
||||||
|
|
||||||
|
// Mapping styles.
|
||||||
|
const (
|
||||||
|
// Let the emitter choose the style.
|
||||||
|
yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota
|
||||||
|
|
||||||
|
yaml_BLOCK_MAPPING_STYLE // The block mapping style.
|
||||||
|
yaml_FLOW_MAPPING_STYLE // The flow mapping style.
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tokens
|
||||||
|
|
||||||
|
type yaml_token_type_t int
|
||||||
|
|
||||||
|
// Token types.
|
||||||
|
const (
|
||||||
|
// An empty token.
|
||||||
|
yaml_NO_TOKEN yaml_token_type_t = iota
|
||||||
|
|
||||||
|
yaml_STREAM_START_TOKEN // A STREAM-START token.
|
||||||
|
yaml_STREAM_END_TOKEN // A STREAM-END token.
|
||||||
|
|
||||||
|
yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token.
|
||||||
|
yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token.
|
||||||
|
yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token.
|
||||||
|
yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token.
|
||||||
|
|
||||||
|
yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token.
|
||||||
|
yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token.
|
||||||
|
yaml_BLOCK_END_TOKEN // A BLOCK-END token.
|
||||||
|
|
||||||
|
yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token.
|
||||||
|
yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token.
|
||||||
|
yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token.
|
||||||
|
yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token.
|
||||||
|
|
||||||
|
yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token.
|
||||||
|
yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token.
|
||||||
|
yaml_KEY_TOKEN // A KEY token.
|
||||||
|
yaml_VALUE_TOKEN // A VALUE token.
|
||||||
|
|
||||||
|
yaml_ALIAS_TOKEN // An ALIAS token.
|
||||||
|
yaml_ANCHOR_TOKEN // An ANCHOR token.
|
||||||
|
yaml_TAG_TOKEN // A TAG token.
|
||||||
|
yaml_SCALAR_TOKEN // A SCALAR token.
|
||||||
|
)
|
||||||
|
|
||||||
|
func (tt yaml_token_type_t) String() string {
|
||||||
|
switch tt {
|
||||||
|
case yaml_NO_TOKEN:
|
||||||
|
return "yaml_NO_TOKEN"
|
||||||
|
case yaml_STREAM_START_TOKEN:
|
||||||
|
return "yaml_STREAM_START_TOKEN"
|
||||||
|
case yaml_STREAM_END_TOKEN:
|
||||||
|
return "yaml_STREAM_END_TOKEN"
|
||||||
|
case yaml_VERSION_DIRECTIVE_TOKEN:
|
||||||
|
return "yaml_VERSION_DIRECTIVE_TOKEN"
|
||||||
|
case yaml_TAG_DIRECTIVE_TOKEN:
|
||||||
|
return "yaml_TAG_DIRECTIVE_TOKEN"
|
||||||
|
case yaml_DOCUMENT_START_TOKEN:
|
||||||
|
return "yaml_DOCUMENT_START_TOKEN"
|
||||||
|
case yaml_DOCUMENT_END_TOKEN:
|
||||||
|
return "yaml_DOCUMENT_END_TOKEN"
|
||||||
|
case yaml_BLOCK_SEQUENCE_START_TOKEN:
|
||||||
|
return "yaml_BLOCK_SEQUENCE_START_TOKEN"
|
||||||
|
case yaml_BLOCK_MAPPING_START_TOKEN:
|
||||||
|
return "yaml_BLOCK_MAPPING_START_TOKEN"
|
||||||
|
case yaml_BLOCK_END_TOKEN:
|
||||||
|
return "yaml_BLOCK_END_TOKEN"
|
||||||
|
case yaml_FLOW_SEQUENCE_START_TOKEN:
|
||||||
|
return "yaml_FLOW_SEQUENCE_START_TOKEN"
|
||||||
|
case yaml_FLOW_SEQUENCE_END_TOKEN:
|
||||||
|
return "yaml_FLOW_SEQUENCE_END_TOKEN"
|
||||||
|
case yaml_FLOW_MAPPING_START_TOKEN:
|
||||||
|
return "yaml_FLOW_MAPPING_START_TOKEN"
|
||||||
|
case yaml_FLOW_MAPPING_END_TOKEN:
|
||||||
|
return "yaml_FLOW_MAPPING_END_TOKEN"
|
||||||
|
case yaml_BLOCK_ENTRY_TOKEN:
|
||||||
|
return "yaml_BLOCK_ENTRY_TOKEN"
|
||||||
|
case yaml_FLOW_ENTRY_TOKEN:
|
||||||
|
return "yaml_FLOW_ENTRY_TOKEN"
|
||||||
|
case yaml_KEY_TOKEN:
|
||||||
|
return "yaml_KEY_TOKEN"
|
||||||
|
case yaml_VALUE_TOKEN:
|
||||||
|
return "yaml_VALUE_TOKEN"
|
||||||
|
case yaml_ALIAS_TOKEN:
|
||||||
|
return "yaml_ALIAS_TOKEN"
|
||||||
|
case yaml_ANCHOR_TOKEN:
|
||||||
|
return "yaml_ANCHOR_TOKEN"
|
||||||
|
case yaml_TAG_TOKEN:
|
||||||
|
return "yaml_TAG_TOKEN"
|
||||||
|
case yaml_SCALAR_TOKEN:
|
||||||
|
return "yaml_SCALAR_TOKEN"
|
||||||
|
}
|
||||||
|
return "<unknown token>"
|
||||||
|
}
|
||||||
|
|
||||||
|
// The token structure.
|
||||||
|
type yaml_token_t struct {
|
||||||
|
// The token type.
|
||||||
|
typ yaml_token_type_t
|
||||||
|
|
||||||
|
// The start/end of the token.
|
||||||
|
start_mark, end_mark yaml_mark_t
|
||||||
|
|
||||||
|
// The stream encoding (for yaml_STREAM_START_TOKEN).
|
||||||
|
encoding yaml_encoding_t
|
||||||
|
|
||||||
|
// The alias/anchor/scalar value or tag/tag directive handle
|
||||||
|
// (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN).
|
||||||
|
value []byte
|
||||||
|
|
||||||
|
// The tag suffix (for yaml_TAG_TOKEN).
|
||||||
|
suffix []byte
|
||||||
|
|
||||||
|
// The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN).
|
||||||
|
prefix []byte
|
||||||
|
|
||||||
|
// The scalar style (for yaml_SCALAR_TOKEN).
|
||||||
|
style yaml_scalar_style_t
|
||||||
|
|
||||||
|
// The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN).
|
||||||
|
major, minor int8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events
|
||||||
|
|
||||||
|
type yaml_event_type_t int8
|
||||||
|
|
||||||
|
// Event types.
|
||||||
|
const (
|
||||||
|
// An empty event.
|
||||||
|
yaml_NO_EVENT yaml_event_type_t = iota
|
||||||
|
|
||||||
|
yaml_STREAM_START_EVENT // A STREAM-START event.
|
||||||
|
yaml_STREAM_END_EVENT // A STREAM-END event.
|
||||||
|
yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event.
|
||||||
|
yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event.
|
||||||
|
yaml_ALIAS_EVENT // An ALIAS event.
|
||||||
|
yaml_SCALAR_EVENT // A SCALAR event.
|
||||||
|
yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event.
|
||||||
|
yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event.
|
||||||
|
yaml_MAPPING_START_EVENT // A MAPPING-START event.
|
||||||
|
yaml_MAPPING_END_EVENT // A MAPPING-END event.
|
||||||
|
)
|
||||||
|
|
||||||
|
// The event structure.
|
||||||
|
type yaml_event_t struct {
|
||||||
|
|
||||||
|
// The event type.
|
||||||
|
typ yaml_event_type_t
|
||||||
|
|
||||||
|
// The start and end of the event.
|
||||||
|
start_mark, end_mark yaml_mark_t
|
||||||
|
|
||||||
|
// The document encoding (for yaml_STREAM_START_EVENT).
|
||||||
|
encoding yaml_encoding_t
|
||||||
|
|
||||||
|
// The version directive (for yaml_DOCUMENT_START_EVENT).
|
||||||
|
version_directive *yaml_version_directive_t
|
||||||
|
|
||||||
|
// The list of tag directives (for yaml_DOCUMENT_START_EVENT).
|
||||||
|
tag_directives []yaml_tag_directive_t
|
||||||
|
|
||||||
|
// The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT).
|
||||||
|
anchor []byte
|
||||||
|
|
||||||
|
// The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
|
||||||
|
tag []byte
|
||||||
|
|
||||||
|
// The scalar value (for yaml_SCALAR_EVENT).
|
||||||
|
value []byte
|
||||||
|
|
||||||
|
// Is the document start/end indicator implicit, or the tag optional?
|
||||||
|
// (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT).
|
||||||
|
implicit bool
|
||||||
|
|
||||||
|
// Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT).
|
||||||
|
quoted_implicit bool
|
||||||
|
|
||||||
|
// The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT).
|
||||||
|
style yaml_style_t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) }
|
||||||
|
func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) }
|
||||||
|
func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) }
|
||||||
|
|
||||||
|
// Nodes
|
||||||
|
|
||||||
|
const (
|
||||||
|
yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null.
|
||||||
|
yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false.
|
||||||
|
yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values.
|
||||||
|
yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values.
|
||||||
|
yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values.
|
||||||
|
yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values.
|
||||||
|
|
||||||
|
yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences.
|
||||||
|
yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping.
|
||||||
|
|
||||||
|
// Not in original libyaml.
|
||||||
|
yaml_BINARY_TAG = "tag:yaml.org,2002:binary"
|
||||||
|
yaml_MERGE_TAG = "tag:yaml.org,2002:merge"
|
||||||
|
|
||||||
|
yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str.
|
||||||
|
yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq.
|
||||||
|
yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map.
|
||||||
|
)
|
||||||
|
|
||||||
|
type yaml_node_type_t int
|
||||||
|
|
||||||
|
// Node types.
|
||||||
|
const (
|
||||||
|
// An empty node.
|
||||||
|
yaml_NO_NODE yaml_node_type_t = iota
|
||||||
|
|
||||||
|
yaml_SCALAR_NODE // A scalar node.
|
||||||
|
yaml_SEQUENCE_NODE // A sequence node.
|
||||||
|
yaml_MAPPING_NODE // A mapping node.
|
||||||
|
)
|
||||||
|
|
||||||
|
// An element of a sequence node.
|
||||||
|
type yaml_node_item_t int
|
||||||
|
|
||||||
|
// An element of a mapping node.
|
||||||
|
type yaml_node_pair_t struct {
|
||||||
|
key int // The key of the element.
|
||||||
|
value int // The value of the element.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The node structure.
|
||||||
|
type yaml_node_t struct {
|
||||||
|
typ yaml_node_type_t // The node type.
|
||||||
|
tag []byte // The node tag.
|
||||||
|
|
||||||
|
// The node data.
|
||||||
|
|
||||||
|
// The scalar parameters (for yaml_SCALAR_NODE).
|
||||||
|
scalar struct {
|
||||||
|
value []byte // The scalar value.
|
||||||
|
length int // The length of the scalar value.
|
||||||
|
style yaml_scalar_style_t // The scalar style.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The sequence parameters (for YAML_SEQUENCE_NODE).
|
||||||
|
sequence struct {
|
||||||
|
items_data []yaml_node_item_t // The stack of sequence items.
|
||||||
|
style yaml_sequence_style_t // The sequence style.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The mapping parameters (for yaml_MAPPING_NODE).
|
||||||
|
mapping struct {
|
||||||
|
pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value).
|
||||||
|
pairs_start *yaml_node_pair_t // The beginning of the stack.
|
||||||
|
pairs_end *yaml_node_pair_t // The end of the stack.
|
||||||
|
pairs_top *yaml_node_pair_t // The top of the stack.
|
||||||
|
style yaml_mapping_style_t // The mapping style.
|
||||||
|
}
|
||||||
|
|
||||||
|
start_mark yaml_mark_t // The beginning of the node.
|
||||||
|
end_mark yaml_mark_t // The end of the node.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// The document structure.
|
||||||
|
type yaml_document_t struct {
|
||||||
|
|
||||||
|
// The document nodes.
|
||||||
|
nodes []yaml_node_t
|
||||||
|
|
||||||
|
// The version directive.
|
||||||
|
version_directive *yaml_version_directive_t
|
||||||
|
|
||||||
|
// The list of tag directives.
|
||||||
|
tag_directives_data []yaml_tag_directive_t
|
||||||
|
tag_directives_start int // The beginning of the tag directives list.
|
||||||
|
tag_directives_end int // The end of the tag directives list.
|
||||||
|
|
||||||
|
start_implicit int // Is the document start indicator implicit?
|
||||||
|
end_implicit int // Is the document end indicator implicit?
|
||||||
|
|
||||||
|
// The start/end of the document.
|
||||||
|
start_mark, end_mark yaml_mark_t
|
||||||
|
}
|
||||||
|
|
||||||
|
// The prototype of a read handler.
|
||||||
|
//
|
||||||
|
// The read handler is called when the parser needs to read more bytes from the
|
||||||
|
// source. The handler should write not more than size bytes to the buffer.
|
||||||
|
// The number of written bytes should be set to the size_read variable.
|
||||||
|
//
|
||||||
|
// [in,out] data A pointer to an application data specified by
|
||||||
|
// yaml_parser_set_input().
|
||||||
|
// [out] buffer The buffer to write the data from the source.
|
||||||
|
// [in] size The size of the buffer.
|
||||||
|
// [out] size_read The actual number of bytes read from the source.
|
||||||
|
//
|
||||||
|
// On success, the handler should return 1. If the handler failed,
|
||||||
|
// the returned value should be 0. On EOF, the handler should set the
|
||||||
|
// size_read to 0 and return 1.
|
||||||
|
type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error)
|
||||||
|
|
||||||
|
// This structure holds information about a potential simple key.
|
||||||
|
type yaml_simple_key_t struct {
|
||||||
|
possible bool // Is a simple key possible?
|
||||||
|
required bool // Is a simple key required?
|
||||||
|
token_number int // The number of the token.
|
||||||
|
mark yaml_mark_t // The position mark.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The states of the parser.
|
||||||
|
type yaml_parser_state_t int
|
||||||
|
|
||||||
|
const (
|
||||||
|
yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota
|
||||||
|
|
||||||
|
yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document.
|
||||||
|
yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START.
|
||||||
|
yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document.
|
||||||
|
yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END.
|
||||||
|
yaml_PARSE_BLOCK_NODE_STATE // Expect a block node.
|
||||||
|
yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence.
|
||||||
|
yaml_PARSE_FLOW_NODE_STATE // Expect a flow node.
|
||||||
|
yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence.
|
||||||
|
yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence.
|
||||||
|
yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence.
|
||||||
|
yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
|
||||||
|
yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key.
|
||||||
|
yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value.
|
||||||
|
yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence.
|
||||||
|
yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence.
|
||||||
|
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping.
|
||||||
|
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping.
|
||||||
|
yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry.
|
||||||
|
yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
|
||||||
|
yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
|
||||||
|
yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
|
||||||
|
yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping.
|
||||||
|
yaml_PARSE_END_STATE // Expect nothing.
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ps yaml_parser_state_t) String() string {
|
||||||
|
switch ps {
|
||||||
|
case yaml_PARSE_STREAM_START_STATE:
|
||||||
|
return "yaml_PARSE_STREAM_START_STATE"
|
||||||
|
case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE:
|
||||||
|
return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE"
|
||||||
|
case yaml_PARSE_DOCUMENT_START_STATE:
|
||||||
|
return "yaml_PARSE_DOCUMENT_START_STATE"
|
||||||
|
case yaml_PARSE_DOCUMENT_CONTENT_STATE:
|
||||||
|
return "yaml_PARSE_DOCUMENT_CONTENT_STATE"
|
||||||
|
case yaml_PARSE_DOCUMENT_END_STATE:
|
||||||
|
return "yaml_PARSE_DOCUMENT_END_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_NODE_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_NODE_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE"
|
||||||
|
case yaml_PARSE_FLOW_NODE_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_NODE_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE"
|
||||||
|
case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE:
|
||||||
|
return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_MAPPING_KEY_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE"
|
||||||
|
case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE:
|
||||||
|
return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE"
|
||||||
|
case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE"
|
||||||
|
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE"
|
||||||
|
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE"
|
||||||
|
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE"
|
||||||
|
case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE"
|
||||||
|
case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE"
|
||||||
|
case yaml_PARSE_FLOW_MAPPING_KEY_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_MAPPING_KEY_STATE"
|
||||||
|
case yaml_PARSE_FLOW_MAPPING_VALUE_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE"
|
||||||
|
case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE:
|
||||||
|
return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE"
|
||||||
|
case yaml_PARSE_END_STATE:
|
||||||
|
return "yaml_PARSE_END_STATE"
|
||||||
|
}
|
||||||
|
return "<unknown parser state>"
|
||||||
|
}
|
||||||
|
|
||||||
|
// This structure holds aliases data.
|
||||||
|
type yaml_alias_data_t struct {
|
||||||
|
anchor []byte // The anchor.
|
||||||
|
index int // The node id.
|
||||||
|
mark yaml_mark_t // The anchor mark.
|
||||||
|
}
|
||||||
|
|
||||||
|
// The parser structure.
|
||||||
|
//
|
||||||
|
// All members are internal. Manage the structure using the
|
||||||
|
// yaml_parser_ family of functions.
|
||||||
|
type yaml_parser_t struct {
|
||||||
|
|
||||||
|
// Error handling
|
||||||
|
|
||||||
|
error yaml_error_type_t // Error type.
|
||||||
|
|
||||||
|
problem string // Error description.
|
||||||
|
|
||||||
|
// The byte about which the problem occurred.
|
||||||
|
problem_offset int
|
||||||
|
problem_value int
|
||||||
|
problem_mark yaml_mark_t
|
||||||
|
|
||||||
|
// The error context.
|
||||||
|
context string
|
||||||
|
context_mark yaml_mark_t
|
||||||
|
|
||||||
|
// Reader stuff
|
||||||
|
|
||||||
|
read_handler yaml_read_handler_t // Read handler.
|
||||||
|
|
||||||
|
input_file io.Reader // File input data.
|
||||||
|
input []byte // String input data.
|
||||||
|
input_pos int
|
||||||
|
|
||||||
|
eof bool // EOF flag
|
||||||
|
|
||||||
|
buffer []byte // The working buffer.
|
||||||
|
buffer_pos int // The current position of the buffer.
|
||||||
|
|
||||||
|
unread int // The number of unread characters in the buffer.
|
||||||
|
|
||||||
|
raw_buffer []byte // The raw buffer.
|
||||||
|
raw_buffer_pos int // The current position of the buffer.
|
||||||
|
|
||||||
|
encoding yaml_encoding_t // The input encoding.
|
||||||
|
|
||||||
|
offset int // The offset of the current position (in bytes).
|
||||||
|
mark yaml_mark_t // The mark of the current position.
|
||||||
|
|
||||||
|
// Scanner stuff
|
||||||
|
|
||||||
|
stream_start_produced bool // Have we started to scan the input stream?
|
||||||
|
stream_end_produced bool // Have we reached the end of the input stream?
|
||||||
|
|
||||||
|
flow_level int // The number of unclosed '[' and '{' indicators.
|
||||||
|
|
||||||
|
tokens []yaml_token_t // The tokens queue.
|
||||||
|
tokens_head int // The head of the tokens queue.
|
||||||
|
tokens_parsed int // The number of tokens fetched from the queue.
|
||||||
|
token_available bool // Does the tokens queue contain a token ready for dequeueing.
|
||||||
|
|
||||||
|
indent int // The current indentation level.
|
||||||
|
indents []int // The indentation levels stack.
|
||||||
|
|
||||||
|
simple_key_allowed bool // May a simple key occur at the current position?
|
||||||
|
simple_keys []yaml_simple_key_t // The stack of simple keys.
|
||||||
|
|
||||||
|
// Parser stuff
|
||||||
|
|
||||||
|
state yaml_parser_state_t // The current parser state.
|
||||||
|
states []yaml_parser_state_t // The parser states stack.
|
||||||
|
marks []yaml_mark_t // The stack of marks.
|
||||||
|
tag_directives []yaml_tag_directive_t // The list of TAG directives.
|
||||||
|
|
||||||
|
// Dumper stuff
|
||||||
|
|
||||||
|
aliases []yaml_alias_data_t // The alias data.
|
||||||
|
|
||||||
|
document *yaml_document_t // The currently parsed document.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emitter Definitions
|
||||||
|
|
||||||
|
// The prototype of a write handler.
|
||||||
|
//
|
||||||
|
// The write handler is called when the emitter needs to flush the accumulated
|
||||||
|
// characters to the output. The handler should write @a size bytes of the
|
||||||
|
// @a buffer to the output.
|
||||||
|
//
|
||||||
|
// @param[in,out] data A pointer to an application data specified by
|
||||||
|
// yaml_emitter_set_output().
|
||||||
|
// @param[in] buffer The buffer with bytes to be written.
|
||||||
|
// @param[in] size The size of the buffer.
|
||||||
|
//
|
||||||
|
// @returns On success, the handler should return @c 1. If the handler failed,
|
||||||
|
// the returned value should be @c 0.
|
||||||
|
//
|
||||||
|
type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error
|
||||||
|
|
||||||
|
type yaml_emitter_state_t int
|
||||||
|
|
||||||
|
// The emitter states.
|
||||||
|
const (
|
||||||
|
// Expect STREAM-START.
|
||||||
|
yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota
|
||||||
|
|
||||||
|
yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END.
|
||||||
|
yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END.
|
||||||
|
yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document.
|
||||||
|
yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END.
|
||||||
|
yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence.
|
||||||
|
yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence.
|
||||||
|
yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping.
|
||||||
|
yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping.
|
||||||
|
yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping.
|
||||||
|
yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping.
|
||||||
|
yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence.
|
||||||
|
yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence.
|
||||||
|
yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping.
|
||||||
|
yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping.
|
||||||
|
yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping.
|
||||||
|
yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping.
|
||||||
|
yaml_EMIT_END_STATE // Expect nothing.
|
||||||
|
)
|
||||||
|
|
||||||
|
// The emitter structure.
|
||||||
|
//
|
||||||
|
// All members are internal. Manage the structure using the @c yaml_emitter_
|
||||||
|
// family of functions.
|
||||||
|
type yaml_emitter_t struct {
|
||||||
|
|
||||||
|
// Error handling
|
||||||
|
|
||||||
|
error yaml_error_type_t // Error type.
|
||||||
|
problem string // Error description.
|
||||||
|
|
||||||
|
// Writer stuff
|
||||||
|
|
||||||
|
write_handler yaml_write_handler_t // Write handler.
|
||||||
|
|
||||||
|
output_buffer *[]byte // String output data.
|
||||||
|
output_file io.Writer // File output data.
|
||||||
|
|
||||||
|
buffer []byte // The working buffer.
|
||||||
|
buffer_pos int // The current position of the buffer.
|
||||||
|
|
||||||
|
raw_buffer []byte // The raw buffer.
|
||||||
|
raw_buffer_pos int // The current position of the buffer.
|
||||||
|
|
||||||
|
encoding yaml_encoding_t // The stream encoding.
|
||||||
|
|
||||||
|
// Emitter stuff
|
||||||
|
|
||||||
|
canonical bool // If the output is in the canonical style?
|
||||||
|
best_indent int // The number of indentation spaces.
|
||||||
|
best_width int // The preferred width of the output lines.
|
||||||
|
unicode bool // Allow unescaped non-ASCII characters?
|
||||||
|
line_break yaml_break_t // The preferred line break.
|
||||||
|
|
||||||
|
state yaml_emitter_state_t // The current emitter state.
|
||||||
|
states []yaml_emitter_state_t // The stack of states.
|
||||||
|
|
||||||
|
events []yaml_event_t // The event queue.
|
||||||
|
events_head int // The head of the event queue.
|
||||||
|
|
||||||
|
indents []int // The stack of indentation levels.
|
||||||
|
|
||||||
|
tag_directives []yaml_tag_directive_t // The list of tag directives.
|
||||||
|
|
||||||
|
indent int // The current indentation level.
|
||||||
|
|
||||||
|
flow_level int // The current flow level.
|
||||||
|
|
||||||
|
root_context bool // Is it the document root context?
|
||||||
|
sequence_context bool // Is it a sequence context?
|
||||||
|
mapping_context bool // Is it a mapping context?
|
||||||
|
simple_key_context bool // Is it a simple mapping key context?
|
||||||
|
|
||||||
|
line int // The current line.
|
||||||
|
column int // The current column.
|
||||||
|
whitespace bool // If the last character was a whitespace?
|
||||||
|
indention bool // If the last character was an indentation character (' ', '-', '?', ':')?
|
||||||
|
open_ended bool // If an explicit document end is required?
|
||||||
|
|
||||||
|
// Anchor analysis.
|
||||||
|
anchor_data struct {
|
||||||
|
anchor []byte // The anchor value.
|
||||||
|
alias bool // Is it an alias?
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag analysis.
|
||||||
|
tag_data struct {
|
||||||
|
handle []byte // The tag handle.
|
||||||
|
suffix []byte // The tag suffix.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scalar analysis.
|
||||||
|
scalar_data struct {
|
||||||
|
value []byte // The scalar value.
|
||||||
|
multiline bool // Does the scalar contain line breaks?
|
||||||
|
flow_plain_allowed bool // Can the scalar be expessed in the flow plain style?
|
||||||
|
block_plain_allowed bool // Can the scalar be expressed in the block plain style?
|
||||||
|
single_quoted_allowed bool // Can the scalar be expressed in the single quoted style?
|
||||||
|
block_allowed bool // Can the scalar be expressed in the literal or folded styles?
|
||||||
|
style yaml_scalar_style_t // The output style.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dumper stuff
|
||||||
|
|
||||||
|
opened bool // If the stream was already opened?
|
||||||
|
closed bool // If the stream was already closed?
|
||||||
|
|
||||||
|
// The information associated with the document nodes.
|
||||||
|
anchors *struct {
|
||||||
|
references int // The number of references.
|
||||||
|
anchor int // The anchor id.
|
||||||
|
serialized bool // If the node has been emitted?
|
||||||
|
}
|
||||||
|
|
||||||
|
last_anchor_id int // The last assigned anchor id.
|
||||||
|
|
||||||
|
document *yaml_document_t // The currently emitted document.
|
||||||
|
}
|
173
vendor/gopkg.in/yaml.v2/yamlprivateh.go
generated
vendored
Normal file
173
vendor/gopkg.in/yaml.v2/yamlprivateh.go
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
package yaml
|
||||||
|
|
||||||
|
const (
|
||||||
|
// The size of the input raw buffer.
|
||||||
|
input_raw_buffer_size = 512
|
||||||
|
|
||||||
|
// The size of the input buffer.
|
||||||
|
// It should be possible to decode the whole raw buffer.
|
||||||
|
input_buffer_size = input_raw_buffer_size * 3
|
||||||
|
|
||||||
|
// The size of the output buffer.
|
||||||
|
output_buffer_size = 128
|
||||||
|
|
||||||
|
// The size of the output raw buffer.
|
||||||
|
// It should be possible to encode the whole output buffer.
|
||||||
|
output_raw_buffer_size = (output_buffer_size*2 + 2)
|
||||||
|
|
||||||
|
// The size of other stacks and queues.
|
||||||
|
initial_stack_size = 16
|
||||||
|
initial_queue_size = 16
|
||||||
|
initial_string_size = 16
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check if the character at the specified position is an alphabetical
|
||||||
|
// character, a digit, '_', or '-'.
|
||||||
|
func is_alpha(b []byte, i int) bool {
|
||||||
|
return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character at the specified position is a digit.
|
||||||
|
func is_digit(b []byte, i int) bool {
|
||||||
|
return b[i] >= '0' && b[i] <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the value of a digit.
|
||||||
|
func as_digit(b []byte, i int) int {
|
||||||
|
return int(b[i]) - '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character at the specified position is a hex-digit.
|
||||||
|
func is_hex(b []byte, i int) bool {
|
||||||
|
return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the value of a hex-digit.
|
||||||
|
func as_hex(b []byte, i int) int {
|
||||||
|
bi := b[i]
|
||||||
|
if bi >= 'A' && bi <= 'F' {
|
||||||
|
return int(bi) - 'A' + 10
|
||||||
|
}
|
||||||
|
if bi >= 'a' && bi <= 'f' {
|
||||||
|
return int(bi) - 'a' + 10
|
||||||
|
}
|
||||||
|
return int(bi) - '0'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character is ASCII.
|
||||||
|
func is_ascii(b []byte, i int) bool {
|
||||||
|
return b[i] <= 0x7F
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character at the start of the buffer can be printed unescaped.
|
||||||
|
func is_printable(b []byte, i int) bool {
|
||||||
|
return ((b[i] == 0x0A) || // . == #x0A
|
||||||
|
(b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E
|
||||||
|
(b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF
|
||||||
|
(b[i] > 0xC2 && b[i] < 0xED) ||
|
||||||
|
(b[i] == 0xED && b[i+1] < 0xA0) ||
|
||||||
|
(b[i] == 0xEE) ||
|
||||||
|
(b[i] == 0xEF && // #xE000 <= . <= #xFFFD
|
||||||
|
!(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF
|
||||||
|
!(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character at the specified position is NUL.
|
||||||
|
func is_z(b []byte, i int) bool {
|
||||||
|
return b[i] == 0x00
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the beginning of the buffer is a BOM.
|
||||||
|
func is_bom(b []byte, i int) bool {
|
||||||
|
return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character at the specified position is space.
|
||||||
|
func is_space(b []byte, i int) bool {
|
||||||
|
return b[i] == ' '
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character at the specified position is tab.
|
||||||
|
func is_tab(b []byte, i int) bool {
|
||||||
|
return b[i] == '\t'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character at the specified position is blank (space or tab).
|
||||||
|
func is_blank(b []byte, i int) bool {
|
||||||
|
//return is_space(b, i) || is_tab(b, i)
|
||||||
|
return b[i] == ' ' || b[i] == '\t'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character at the specified position is a line break.
|
||||||
|
func is_break(b []byte, i int) bool {
|
||||||
|
return (b[i] == '\r' || // CR (#xD)
|
||||||
|
b[i] == '\n' || // LF (#xA)
|
||||||
|
b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
|
||||||
|
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
|
||||||
|
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029)
|
||||||
|
}
|
||||||
|
|
||||||
|
func is_crlf(b []byte, i int) bool {
|
||||||
|
return b[i] == '\r' && b[i+1] == '\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character is a line break or NUL.
|
||||||
|
func is_breakz(b []byte, i int) bool {
|
||||||
|
//return is_break(b, i) || is_z(b, i)
|
||||||
|
return ( // is_break:
|
||||||
|
b[i] == '\r' || // CR (#xD)
|
||||||
|
b[i] == '\n' || // LF (#xA)
|
||||||
|
b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
|
||||||
|
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
|
||||||
|
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
|
||||||
|
// is_z:
|
||||||
|
b[i] == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character is a line break, space, or NUL.
|
||||||
|
func is_spacez(b []byte, i int) bool {
|
||||||
|
//return is_space(b, i) || is_breakz(b, i)
|
||||||
|
return ( // is_space:
|
||||||
|
b[i] == ' ' ||
|
||||||
|
// is_breakz:
|
||||||
|
b[i] == '\r' || // CR (#xD)
|
||||||
|
b[i] == '\n' || // LF (#xA)
|
||||||
|
b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
|
||||||
|
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
|
||||||
|
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
|
||||||
|
b[i] == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the character is a line break, space, tab, or NUL.
|
||||||
|
func is_blankz(b []byte, i int) bool {
|
||||||
|
//return is_blank(b, i) || is_breakz(b, i)
|
||||||
|
return ( // is_blank:
|
||||||
|
b[i] == ' ' || b[i] == '\t' ||
|
||||||
|
// is_breakz:
|
||||||
|
b[i] == '\r' || // CR (#xD)
|
||||||
|
b[i] == '\n' || // LF (#xA)
|
||||||
|
b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85)
|
||||||
|
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028)
|
||||||
|
b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029)
|
||||||
|
b[i] == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the width of the character.
|
||||||
|
func width(b byte) int {
|
||||||
|
// Don't replace these by a switch without first
|
||||||
|
// confirming that it is being inlined.
|
||||||
|
if b&0x80 == 0x00 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if b&0xE0 == 0xC0 {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
if b&0xF0 == 0xE0 {
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
if b&0xF8 == 0xF0 {
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user