diff --git a/Makefile b/Makefile
index aa7572c..769353c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,12 @@
DESTDIR ?=
-GOFLAGS ?= -v -buildvcs=false -mod=vendor -buildmode=exe -ldflags "-w -X `go list`.Date=${DATE} -X `go list`.Vendor=${GOOS} -X `go list`.Version=${VERSION}"
+GO ?= go
+GOFLAGS ?= -v -buildvcs=false -buildmode=exe -ldflags "-w -X `${GO} list`.Date=${DATE} -X `${GO} list`.Vendor=${GOOS} -X `${GO} list`.Version=${VERSION}"
PREFIX ?= /usr/local
DATE ?= `date -u +%F`
-GOOS ?= `go env GOOS`
-VERSION ?= `git describe --tags`
+GOOS ?= `${GO} env GOOS`
+VERSION ?= 1.0F
build:
- go build ${GOFLAGS} ./cmd/aya
+ ${GO} build ${GOFLAGS} ./cmd/aya
clean:
rm -f aya
dist:
diff --git a/README.md b/README.md
index c260806..ddc273c 100644
--- a/README.md
+++ b/README.md
@@ -17,9 +17,9 @@ Named after [Aya Shameimaru](https://en.touhouwiki.net/wiki/Aya_Shameimaru) from
Build it manually provided you have Go (>=1.17) installed:
- $ go install marisa.chaotic.ninja/aya/cmd/aya@latest (1)
+ $ go install mahou-no-mori.yakumo.dev/aya/cmd/aya@latest (1)
--- or ---
- $ git clone https://git.chaotic.ninja/yakumo_izuru/aya
+ $ git clone https://git.yakumo.dev/yakumo.izuru/aya
$ cd aya
$ make
# make install
@@ -84,7 +84,7 @@ for f in ./blog/*/*.md ; do
url=`$AYA var $f url`
title=`$AYA var $f title | tr A-Z a-z`
descr=`$AYA var $f description`
- echo $timestamp "$title https://technicalmarisa.chaotic.ninja/blog/$url$descr $(gdate --date @$timestamp -R) http://technicalmarisa.chaotic.ninja/blog/$url "
+ echo $timestamp "$title https://technicalmarisa.yakumo.dev/blog/$url$descr $(gdate --date @$timestamp -R) http://technicalmarisa.yakumo.dev/blog/$url "
fi
done | sort -r -n | cut -d' ' -f2- >> $AYA_OUTDIR/blog/rss.xml
echo '' >> $AYA_OUTDIR/blog/rss.xml
@@ -104,24 +104,6 @@ Read `aya(1)`
## License
The software is distributed under the [MIT/X11](LICENSE) license.
-## Sites using Aya!
-(I know, I made the majority of them, but they still count)
-
-| Title | Author | Link |
-|------------------------|--------------------------------------------------|---------------------------------------|
-| Aya (project homepage) | Izuru Yakumo | https://aya.chaotic.ninja |
-| Chaotic Ninja | Izuru Yakumo, Mima-sama | https://chaotic.ninja |
-| Geidontei | Izuru Yakumo | https://geidontei.chaotic.ninja |
-| ChaoticIRC Network | Izuru Yakumo | https://im.chaotic.ninja |
-| Kanako | Izuru Yakumo | https://kanako.chaotic.ninja |
-| Kill-9 The Revival | Various authors | https://kill-9.chaotic.ninja |
-| PXIMG(7) | Izuru Yakumo | https://pximg.chaotic.ninja |
-| Shinmyoumaru | Mima-sama | https://shinmyoumaru.chaotic.ninja |
-| Suika | Izuru Yakumo | https://suika.chaotic.ninja |
-| TechnicalMarisa | Izuru Yakumo | https://technicalmarisa.chaotic.ninja |
-| Tengu Space | [DeviousTengu](https://fedi.tengu.space/devious) | https://tengu.space |
-| WindowMaker Shrine | Izuru Yakumo | https://themes.chaotic.ninja |
-
---
Ayaya~
diff --git a/cmd/aya/main.go b/cmd/aya/main.go
index 592a7fa..660c4ac 100644
--- a/cmd/aya/main.go
+++ b/cmd/aya/main.go
@@ -1,4 +1,3 @@
-// $TheSupernovaDuo: marisa.chaotic.ninja/aya/cmd/aya, v1.0.1 2023-12-12 14:27:02+0000, yakumo_izuru Exp $
package main
import (
@@ -7,7 +6,7 @@ import (
"os"
"strings"
- "marisa.chaotic.ninja/aya"
+ "mahou-no-mori.yakumo.dev/aya"
)
// Define global constants here
@@ -73,7 +72,7 @@ func main() {
fmt.Println(strings.TrimSpace(s))
}
case "version":
- aya.PrintVersion()
+ fmt.Println(aya.PrintVersion())
os.Exit(0)
case "watch":
buildAll(true)
diff --git a/go.mod b/go.mod
index bace8b6..5e14e97 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module marisa.chaotic.ninja/aya
+module mahou-no-mori.yakumo.dev/aya
go 1.17
diff --git a/serve.go b/serve.go
index fc23984..71b9a89 100644
--- a/serve.go
+++ b/serve.go
@@ -1,4 +1,5 @@
-// Taken from https://github.com/fogleman/serve and repurposed as a library
+/* The following code has been taken from https://github.com/fogleman/serve and it is used on this project as a library */
+/* Attribution goes to its original author */
package aya
import (
diff --git a/usage.go b/usage.go
index 0d0f160..113bdf2 100644
--- a/usage.go
+++ b/usage.go
@@ -7,8 +7,8 @@ import (
// This function is called by the `aya help` subcommand
func PrintUsage() {
fmt.Printf("aya/%v\n", PrintFullVersion())
- fmt.Println("Homepage: https://aya.chaotic.ninja")
- fmt.Println("Repository: https://git.chaotic.ninja/usr/yakumo_izuru/aya")
+ fmt.Println("Homepage: https://suzunaan.yakumo.dev/aya/")
+ fmt.Println("Repository: https://svn.yakumo.dev/yakumo.izuru/aya")
fmt.Println("==")
fmt.Println("build [file] · (Re)build a site or a file in particular")
fmt.Println("clean · Remove the generated .pub directory")
diff --git a/vendor/github.com/eknkc/amber/.travis.yml b/vendor/github.com/eknkc/amber/.travis.yml
deleted file mode 100644
index fa3d8d3..0000000
--- a/vendor/github.com/eknkc/amber/.travis.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-language: go
-
-go:
- - tip
-
-script:
- - go test -v ./...
diff --git a/vendor/github.com/eknkc/amber/LICENSE b/vendor/github.com/eknkc/amber/LICENSE
deleted file mode 100644
index 77dfb91..0000000
--- a/vendor/github.com/eknkc/amber/LICENSE
+++ /dev/null
@@ -1,9 +0,0 @@
-(The MIT License)
-
-Copyright (c) 2012 Ekin Koc ekin@eknkc.com
-
-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.
diff --git a/vendor/github.com/eknkc/amber/README.md b/vendor/github.com/eknkc/amber/README.md
deleted file mode 100644
index ec0e52f..0000000
--- a/vendor/github.com/eknkc/amber/README.md
+++ /dev/null
@@ -1,442 +0,0 @@
-# amber [](http://godoc.org/github.com/eknkc/amber) [](https://travis-ci.org/eknkc/amber)
-
-## Notice
-> While Amber is perfectly fine and stable to use, I've been working on a direct Pug.js port for Go. It is somewhat hacky at the moment but take a look at [Pug.go](https://github.com/eknkc/pug) if you are looking for a [Pug.js](https://github.com/pugjs/pug) compatible Go template engine.
-
-### Usage
-```go
-import "github.com/eknkc/amber"
-```
-
-Amber is an elegant templating engine for Go Programming Language
-It is inspired from HAML and Jade
-
-### Tags
-
-A tag is simply a word:
-
- html
-
-is converted to
-
-```html
-
-```
-
-It is possible to add ID and CLASS attributes to tags:
-
- div#main
- span.time
-
-are converted to
-
-```html
-
-
-```
-
-Any arbitrary attribute name / value pair can be added this way:
-
- a[href="http://www.google.com"]
-
-You can mix multiple attributes together
-
- a#someid[href="/"][title="Main Page"].main.link Click Link
-
-gets converted to
-
-```html
-Click Link
-```
-
-It is also possible to define these attributes within the block of a tag
-
- a
- #someid
- [href="/"]
- [title="Main Page"]
- .main
- .link
- | Click Link
-
-### Doctypes
-
-To add a doctype, use `!!!` or `doctype` keywords:
-
- !!! transitional
- //
-
-or use `doctype`
-
- doctype 5
- //
-
-Available options: `5`, `default`, `xml`, `transitional`, `strict`, `frameset`, `1.1`, `basic`, `mobile`
-
-### Tag Content
-
-For single line tag text, you can just append the text after tag name:
-
- p Testing!
-
-would yield
-
- Testing!
-
-For multi line tag text, or nested tags, use indentation:
-
- html
- head
- title Page Title
- body
- div#content
- p
- | This is a long page content
- | These lines are all part of the parent p
-
- a[href="/"] Go To Main Page
-
-### Data
-
-Input template data can be reached by key names directly. For example, assuming the template has been
-executed with following JSON data:
-
-```json
-{
- "Name": "Ekin",
- "LastName": "Koc",
- "Repositories": [
- "amber",
- "dateformat"
- ],
- "Avatar": "/images/ekin.jpg",
- "Friends": 17
-}
-```
-
-It is possible to interpolate fields using `#{}`
-
- p Welcome #{Name}!
-
-would print
-
-```html
-Welcome Ekin!
-```
-
-Attributes can have field names as well
-
- a[title=Name][href="/ekin.koc"]
-
-would print
-
-```html
-
-```
-
-### Expressions
-
-Amber can expand basic expressions. For example, it is possible to concatenate strings with + operator:
-
- p Welcome #{Name + " " + LastName}
-
-Arithmetic expressions are also supported:
-
- p You need #{50 - Friends} more friends to reach 50!
-
-Expressions can be used within attributes
-
- img[alt=Name + " " + LastName][src=Avatar]
-
-### Variables
-
-It is possible to define dynamic variables within templates,
-all variables must start with a $ character and can be assigned as in the following example:
-
- div
- $fullname = Name + " " + LastName
- p Welcome #{$fullname}
-
-If you need to access the supplied data itself (i.e. the object containing Name, LastName etc fields.) you can use `$` variable
-
- p $.Name
-
-### Conditions
-
-For conditional blocks, it is possible to use `if `
-
- div
- if Friends > 10
- p You have more than 10 friends
- else if Friends > 5
- p You have more than 5 friends
- else
- p You need more friends
-
-Again, it is possible to use arithmetic and boolean operators
-
- div
- if Name == "Ekin" && LastName == "Koc"
- p Hey! I know you..
-
-There is a special syntax for conditional attributes. Only block attributes can have conditions;
-
- div
- .hasfriends ? Friends > 0
-
-This would yield a div with `hasfriends` class only if the `Friends > 0` condition holds. It is
-perfectly fine to use the same method for other types of attributes:
-
- div
- #foo ? Name == "Ekin"
- [bar=baz] ? len(Repositories) > 0
-
-### Iterations
-
-It is possible to iterate over arrays and maps using `each`:
-
- each $repo in Repositories
- p #{$repo}
-
-would print
-
- p amber
- p dateformat
-
-It is also possible to iterate over values and indexes at the same time
-
- each $i, $repo in Repositories
- p
- .even ? $i % 2 == 0
- .odd ? $i % 2 == 1
-
-### Mixins
-
-Mixins (reusable template blocks that accept arguments) can be defined:
-
- mixin surprise
- span Surprise!
- mixin link($href, $title, $text)
- a[href=$href][title=$title] #{$text}
-
-and then called multiple times within a template (or even within another mixin definition):
-
- div
- +surprise
- +surprise
- +link("http://google.com", "Google", "Check out Google")
-
-Template data, variables, expressions, etc., can all be passed as arguments:
-
- +link(GoogleUrl, $googleTitle, "Check out " + $googleTitle)
-
-### Imports
-
-A template can import other templates using `import`:
-
- a.amber
- p this is template a
-
- b.amber
- p this is template b
-
- c.amber
- div
- import a
- import b
-
-gets compiled to
-
- div
- p this is template a
- p this is template b
-
-### Inheritance
-
-A template can inherit other templates. In order to inherit another template, an `extends` keyword should be used.
-Parent template can define several named blocks and child template can modify the blocks.
-
- master.amber
- !!! 5
- html
- head
- block meta
- meta[name="description"][content="This is a great website"]
-
- title
- block title
- | Default title
- body
- block content
-
- subpage.amber
- extends master
-
- block title
- | Some sub page!
-
- block append meta
- // This will be added after the description meta tag. It is also possible
- // to prepend someting to an existing block
- meta[name="keywords"][content="foo bar"]
-
- block content
- div#main
- p Some content here
-
-### License
-(The MIT License)
-
-Copyright (c) 2012 Ekin Koc
-
-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.
-
-## Usage
-
-```go
-var DefaultOptions = Options{true, false}
-var DefaultDirOptions = DirOptions{".amber", true}
-```
-
-#### func Compile
-
-```go
-func Compile(input string, options Options) (*template.Template, error)
-```
-Parses and compiles the supplied amber template string. Returns corresponding Go
-Template (html/templates) instance. Necessary runtime functions will be injected
-and the template will be ready to be executed.
-
-#### func CompileFile
-
-```go
-func CompileFile(filename string, options Options) (*template.Template, error)
-```
-Parses and compiles the contents of supplied filename. Returns corresponding Go
-Template (html/templates) instance. Necessary runtime functions will be injected
-and the template will be ready to be executed.
-
-#### func CompileDir
-```go
-func CompileDir(dirname string, dopt DirOptions, opt Options) (map[string]*template.Template, error)
-```
-Parses and compiles the contents of a supplied directory name. Returns a mapping of template name (extension stripped) to corresponding Go Template (html/template) instance. Necessary runtime functions will be injected and the template will be ready to be executed.
-
-If there are templates in subdirectories, its key in the map will be it's path relative to `dirname`. For example:
-```
-templates/
- |-- index.amber
- |-- layouts/
- |-- base.amber
-```
-```go
-templates, err := amber.CompileDir("templates/", amber.DefaultDirOptions, amber.DefaultOptions)
-templates["index"] // index.amber Go Template
-templates["layouts/base"] // base.amber Go Template
-```
-By default, the search will be recursive and will match only files ending in ".amber". If recursive is turned off, it will only search the top level of the directory. Specified extension must start with a period.
-
-#### type Compiler
-
-```go
-type Compiler struct {
- // Compiler options
- Options
-}
-```
-
-Compiler is the main interface of Amber Template Engine. In order to use an
-Amber template, it is required to create a Compiler and compile an Amber source
-to native Go template.
-
- compiler := amber.New()
- // Parse the input file
- err := compiler.ParseFile("./input.amber")
- if err == nil {
- // Compile input file to Go template
- tpl, err := compiler.Compile()
- if err == nil {
- // Check built in html/template documentation for further details
- tpl.Execute(os.Stdout, somedata)
- }
- }
-
-#### func New
-
-```go
-func New() *Compiler
-```
-Create and initialize a new Compiler
-
-#### func (*Compiler) Compile
-
-```go
-func (c *Compiler) Compile() (*template.Template, error)
-```
-Compile amber and create a Go Template (html/templates) instance. Necessary
-runtime functions will be injected and the template will be ready to be
-executed.
-
-#### func (*Compiler) CompileString
-
-```go
-func (c *Compiler) CompileString() (string, error)
-```
-Compile template and return the Go Template source You would not be using this
-unless debugging / checking the output. Please use Compile method to obtain a
-template instance directly.
-
-#### func (*Compiler) CompileWriter
-
-```go
-func (c *Compiler) CompileWriter(out io.Writer) (err error)
-```
-Compile amber and write the Go Template source into given io.Writer instance You
-would not be using this unless debugging / checking the output. Please use
-Compile method to obtain a template instance directly.
-
-#### func (*Compiler) Parse
-
-```go
-func (c *Compiler) Parse(input string) (err error)
-```
-Parse given raw amber template string.
-
-#### func (*Compiler) ParseFile
-
-```go
-func (c *Compiler) ParseFile(filename string) (err error)
-```
-Parse the amber template file in given path
-
-#### type Options
-
-```go
-type Options struct {
- // Setting if pretty printing is enabled.
- // Pretty printing ensures that the output html is properly indented and in human readable form.
- // If disabled, produced HTML is compact. This might be more suitable in production environments.
- // Defaukt: true
- PrettyPrint bool
- // Setting if line number emitting is enabled
- // In this form, Amber emits line number comments in the output template. It is usable in debugging environments.
- // Default: false
- LineNumbers bool
-}
-```
-
-#### type DirOptions
-
-```go
-// Used to provide options to directory compilation
-type DirOptions struct {
- // File extension to match for compilation
- Ext string
- // Whether or not to walk subdirectories
- Recursive bool
-}
-```
diff --git a/vendor/github.com/eknkc/amber/compiler.go b/vendor/github.com/eknkc/amber/compiler.go
deleted file mode 100644
index bec57b7..0000000
--- a/vendor/github.com/eknkc/amber/compiler.go
+++ /dev/null
@@ -1,844 +0,0 @@
-package amber
-
-import (
- "bytes"
- "container/list"
- "errors"
- "fmt"
- "go/ast"
- gp "go/parser"
- gt "go/token"
- "html/template"
- "io"
- "net/http"
- "os"
- "path/filepath"
- "reflect"
- "regexp"
- "sort"
- "strconv"
- "strings"
-
- "github.com/eknkc/amber/parser"
-)
-
-var builtinFunctions = [...]string{
- "len",
- "print",
- "printf",
- "println",
- "urlquery",
- "js",
- "json",
- "index",
- "html",
- "unescaped",
-}
-
-const (
- dollar = "__DOLLAR__"
-)
-
-// Compiler is the main interface of Amber Template Engine.
-// In order to use an Amber template, it is required to create a Compiler and
-// compile an Amber source to native Go template.
-// compiler := amber.New()
-// // Parse the input file
-// err := compiler.ParseFile("./input.amber")
-// if err == nil {
-// // Compile input file to Go template
-// tpl, err := compiler.Compile()
-// if err == nil {
-// // Check built in html/template documentation for further details
-// tpl.Execute(os.Stdout, somedata)
-// }
-// }
-type Compiler struct {
- // Compiler options
- Options
- filename string
- node parser.Node
- indentLevel int
- newline bool
- buffer *bytes.Buffer
- tempvarIndex int
- mixins map[string]*parser.Mixin
-}
-
-// New creates and initialize a new Compiler.
-func New() *Compiler {
- compiler := new(Compiler)
- compiler.filename = ""
- compiler.tempvarIndex = 0
- compiler.PrettyPrint = true
- compiler.Options = DefaultOptions
- compiler.mixins = make(map[string]*parser.Mixin)
-
- return compiler
-}
-
-// Options defines template output behavior.
-type Options struct {
- // Setting if pretty printing is enabled.
- // Pretty printing ensures that the output html is properly indented and in human readable form.
- // If disabled, produced HTML is compact. This might be more suitable in production environments.
- // Default: true
- PrettyPrint bool
- // Setting if line number emitting is enabled
- // In this form, Amber emits line number comments in the output template. It is usable in debugging environments.
- // Default: false
- LineNumbers bool
- // Setting the virtual filesystem to use
- // If set, will attempt to use a virtual filesystem provided instead of os.
- // Default: nil
- VirtualFilesystem http.FileSystem
-}
-
-// DirOptions is used to provide options to directory compilation.
-type DirOptions struct {
- // File extension to match for compilation
- Ext string
- // Whether or not to walk subdirectories
- Recursive bool
-}
-
-// DefaultOptions sets pretty-printing to true and line numbering to false.
-var DefaultOptions = Options{true, false, nil}
-
-// DefaultDirOptions sets expected file extension to ".amber" and recursive search for templates within a directory to true.
-var DefaultDirOptions = DirOptions{".amber", true}
-
-// Compile parses and compiles the supplied amber template string. Returns corresponding Go Template (html/templates) instance.
-// Necessary runtime functions will be injected and the template will be ready to be executed.
-func Compile(input string, options Options) (*template.Template, error) {
- comp := New()
- comp.Options = options
-
- err := comp.Parse(input)
- if err != nil {
- return nil, err
- }
-
- return comp.Compile()
-}
-
-// Compile parses and compiles the supplied amber template []byte.
-// Returns corresponding Go Template (html/templates) instance.
-// Necessary runtime functions will be injected and the template will be ready to be executed.
-func CompileData(input []byte, filename string, options Options) (*template.Template, error) {
- comp := New()
- comp.Options = options
-
- err := comp.ParseData(input, filename)
- if err != nil {
- return nil, err
- }
-
- return comp.Compile()
-}
-
-// MustCompile is the same as Compile, except the input is assumed error free. If else, panic.
-func MustCompile(input string, options Options) *template.Template {
- t, err := Compile(input, options)
- if err != nil {
- panic(err)
- }
- return t
-}
-
-// CompileFile parses and compiles the contents of supplied filename. Returns corresponding Go Template (html/templates) instance.
-// Necessary runtime functions will be injected and the template will be ready to be executed.
-func CompileFile(filename string, options Options) (*template.Template, error) {
- comp := New()
- comp.Options = options
-
- err := comp.ParseFile(filename)
- if err != nil {
- return nil, err
- }
-
- return comp.Compile()
-}
-
-// MustCompileFile is the same as CompileFile, except the input is assumed error free. If else, panic.
-func MustCompileFile(filename string, options Options) *template.Template {
- t, err := CompileFile(filename, options)
- if err != nil {
- panic(err)
- }
- return t
-}
-
-// CompileDir parses and compiles the contents of a supplied directory path, with options.
-// Returns a map of a template identifier (key) to a Go Template instance.
-// Ex: if the dirname="templates/" had a file "index.amber" the key would be "index"
-// If option for recursive is True, this parses every file of relevant extension
-// in all subdirectories. The key then is the path e.g: "layouts/layout"
-func CompileDir(dirname string, dopt DirOptions, opt Options) (map[string]*template.Template, error) {
- dir, err := os.Open(dirname)
- if err != nil && opt.VirtualFilesystem != nil {
- vdir, err := opt.VirtualFilesystem.Open(dirname)
- if err != nil {
- return nil, err
- }
- dir = vdir.(*os.File)
- } else if err != nil {
- return nil, err
- }
- defer dir.Close()
-
- files, err := dir.Readdir(0)
- if err != nil {
- return nil, err
- }
-
- compiled := make(map[string]*template.Template)
- for _, file := range files {
- // filename is for example "index.amber"
- filename := file.Name()
- fileext := filepath.Ext(filename)
-
- // If recursive is true and there's a subdirectory, recurse
- if dopt.Recursive && file.IsDir() {
- dirpath := filepath.Join(dirname, filename)
- subcompiled, err := CompileDir(dirpath, dopt, opt)
- if err != nil {
- return nil, err
- }
- // Copy templates from subdirectory into parent template mapping
- for k, v := range subcompiled {
- // Concat with parent directory name for unique paths
- key := filepath.Join(filename, k)
- compiled[key] = v
- }
- } else if fileext == dopt.Ext {
- // Otherwise compile the file and add to mapping
- fullpath := filepath.Join(dirname, filename)
- tmpl, err := CompileFile(fullpath, opt)
- if err != nil {
- return nil, err
- }
- // Strip extension
- key := filename[0 : len(filename)-len(fileext)]
- compiled[key] = tmpl
- }
- }
-
- return compiled, nil
-}
-
-// MustCompileDir is the same as CompileDir, except input is assumed error free. If else, panic.
-func MustCompileDir(dirname string, dopt DirOptions, opt Options) map[string]*template.Template {
- m, err := CompileDir(dirname, dopt, opt)
- if err != nil {
- panic(err)
- }
- return m
-}
-
-// Parse given raw amber template string.
-func (c *Compiler) Parse(input string) (err error) {
- defer func() {
- if r := recover(); r != nil {
- err = errors.New(r.(string))
- }
- }()
-
- parser, err := parser.StringParser(input)
-
- if err != nil {
- return
- }
-
- c.node = parser.Parse()
- return
-}
-
-// Parse given raw amber template bytes, and the filename that belongs with it
-func (c *Compiler) ParseData(input []byte, filename string) (err error) {
- defer func() {
- if r := recover(); r != nil {
- err = errors.New(r.(string))
- }
- }()
-
- parser, err := parser.ByteParser(input)
- parser.SetFilename(filename)
- if c.VirtualFilesystem != nil {
- parser.SetVirtualFilesystem(c.VirtualFilesystem)
- }
-
- if err != nil {
- return
- }
-
- c.node = parser.Parse()
- return
-}
-
-// ParseFile parses the amber template file in given path.
-func (c *Compiler) ParseFile(filename string) (err error) {
- defer func() {
- if r := recover(); r != nil {
- err = errors.New(r.(string))
- }
- }()
-
- p, err := parser.FileParser(filename)
- if err != nil && c.VirtualFilesystem != nil {
- p, err = parser.VirtualFileParser(filename, c.VirtualFilesystem)
- }
- if err != nil {
- return
- }
-
- c.node = p.Parse()
- c.filename = filename
- return
-}
-
-// Compile amber and create a Go Template (html/templates) instance.
-// Necessary runtime functions will be injected and the template will be ready to be executed.
-func (c *Compiler) Compile() (*template.Template, error) {
- return c.CompileWithName(filepath.Base(c.filename))
-}
-
-// CompileWithName is the same as Compile, but allows to specify a name for the template.
-func (c *Compiler) CompileWithName(name string) (*template.Template, error) {
- return c.CompileWithTemplate(template.New(name))
-}
-
-// CompileWithTemplate is the same as Compile but allows to specify a template.
-func (c *Compiler) CompileWithTemplate(t *template.Template) (*template.Template, error) {
- data, err := c.CompileString()
-
- if err != nil {
- return nil, err
- }
-
- tpl, err := t.Funcs(FuncMap).Parse(data)
-
- if err != nil {
- return nil, err
- }
-
- return tpl, nil
-}
-
-// CompileWriter compiles amber and writes the Go Template source into given io.Writer instance.
-// You would not be using this unless debugging / checking the output. Please use Compile
-// method to obtain a template instance directly.
-func (c *Compiler) CompileWriter(out io.Writer) (err error) {
- defer func() {
- if r := recover(); r != nil {
- err = errors.New(r.(string))
- }
- }()
-
- c.buffer = new(bytes.Buffer)
- c.visit(c.node)
-
- if c.buffer.Len() > 0 {
- c.write("\n")
- }
-
- _, err = c.buffer.WriteTo(out)
- return
-}
-
-// CompileString compiles the template and returns the Go Template source.
-// You would not be using this unless debugging / checking the output. Please use Compile
-// method to obtain a template instance directly.
-func (c *Compiler) CompileString() (string, error) {
- var buf bytes.Buffer
-
- if err := c.CompileWriter(&buf); err != nil {
- return "", err
- }
-
- result := buf.String()
-
- return result, nil
-}
-
-func (c *Compiler) visit(node parser.Node) {
- defer func() {
- if r := recover(); r != nil {
- if rs, ok := r.(string); ok && rs[:len("Amber Error")] == "Amber Error" {
- panic(r)
- }
-
- pos := node.Pos()
-
- if len(pos.Filename) > 0 {
- panic(fmt.Sprintf("Amber Error in <%s>: %v - Line: %d, Column: %d, Length: %d", pos.Filename, r, pos.LineNum, pos.ColNum, pos.TokenLength))
- } else {
- panic(fmt.Sprintf("Amber Error: %v - Line: %d, Column: %d, Length: %d", r, pos.LineNum, pos.ColNum, pos.TokenLength))
- }
- }
- }()
-
- switch node.(type) {
- case *parser.Block:
- c.visitBlock(node.(*parser.Block))
- case *parser.Doctype:
- c.visitDoctype(node.(*parser.Doctype))
- case *parser.Comment:
- c.visitComment(node.(*parser.Comment))
- case *parser.Tag:
- c.visitTag(node.(*parser.Tag))
- case *parser.Text:
- c.visitText(node.(*parser.Text))
- case *parser.Condition:
- c.visitCondition(node.(*parser.Condition))
- case *parser.Each:
- c.visitEach(node.(*parser.Each))
- case *parser.Assignment:
- c.visitAssignment(node.(*parser.Assignment))
- case *parser.Mixin:
- c.visitMixin(node.(*parser.Mixin))
- case *parser.MixinCall:
- c.visitMixinCall(node.(*parser.MixinCall))
- }
-}
-
-func (c *Compiler) write(value string) {
- c.buffer.WriteString(value)
-}
-
-func (c *Compiler) indent(offset int, newline bool) {
- if !c.PrettyPrint {
- return
- }
-
- if newline && c.buffer.Len() > 0 {
- c.write("\n")
- }
-
- for i := 0; i < c.indentLevel+offset; i++ {
- c.write("\t")
- }
-}
-
-func (c *Compiler) tempvar() string {
- c.tempvarIndex++
- return "$__amber_" + strconv.Itoa(c.tempvarIndex)
-}
-
-func (c *Compiler) escape(input string) string {
- return strings.Replace(strings.Replace(input, `\`, `\\`, -1), `"`, `\"`, -1)
-}
-
-func (c *Compiler) visitBlock(block *parser.Block) {
- for _, node := range block.Children {
- if _, ok := node.(*parser.Text); !block.CanInline() && ok {
- c.indent(0, true)
- }
-
- c.visit(node)
- }
-}
-
-func (c *Compiler) visitDoctype(doctype *parser.Doctype) {
- c.write(doctype.String())
-}
-
-func (c *Compiler) visitComment(comment *parser.Comment) {
- if comment.Silent {
- return
- }
-
- c.indent(0, false)
-
- if comment.Block == nil {
- c.write(`{{unescaped ""}}`)
- } else {
- c.write(``)
- }
-}
-
-func (c *Compiler) visitCondition(condition *parser.Condition) {
- c.write(`{{if ` + c.visitRawInterpolation(condition.Expression) + `}}`)
- c.visitBlock(condition.Positive)
- if condition.Negative != nil {
- c.write(`{{else}}`)
- c.visitBlock(condition.Negative)
- }
- c.write(`{{end}}`)
-}
-
-func (c *Compiler) visitEach(each *parser.Each) {
- if each.Block == nil {
- return
- }
-
- if len(each.Y) == 0 {
- c.write(`{{range ` + each.X + ` := ` + c.visitRawInterpolation(each.Expression) + `}}`)
- } else {
- c.write(`{{range ` + each.X + `, ` + each.Y + ` := ` + c.visitRawInterpolation(each.Expression) + `}}`)
- }
- c.visitBlock(each.Block)
- c.write(`{{end}}`)
-}
-
-func (c *Compiler) visitAssignment(assgn *parser.Assignment) {
- c.write(`{{` + assgn.X + ` := ` + c.visitRawInterpolation(assgn.Expression) + `}}`)
-}
-
-func (c *Compiler) visitTag(tag *parser.Tag) {
- type attrib struct {
- name string
- value func() string
- condition string
- }
-
- attribs := make(map[string]*attrib)
-
- for _, item := range tag.Attributes {
- attritem := item
- attr := new(attrib)
- attr.name = item.Name
-
- attr.value = func() string {
- if !attritem.IsRaw {
- return c.visitInterpolation(attritem.Value)
- } else if attritem.Value == "" {
- return ""
- } else {
- return attritem.Value
- }
- }
-
- if len(attritem.Condition) != 0 {
- attr.condition = c.visitRawInterpolation(attritem.Condition)
- }
-
- if attr.name == "class" && attribs["class"] != nil {
- prevclass := attribs["class"]
- prevvalue := prevclass.value
-
- prevclass.value = func() string {
- aval := attr.value()
-
- if len(attr.condition) > 0 {
- aval = `{{if ` + attr.condition + `}}` + aval + `{{end}}`
- }
-
- if len(prevclass.condition) > 0 {
- return `{{if ` + prevclass.condition + `}}` + prevvalue() + `{{end}} ` + aval
- }
-
- return prevvalue() + " " + aval
- }
- } else {
- attribs[attritem.Name] = attr
- }
- }
-
- keys := make([]string, 0, len(attribs))
- for key := range attribs {
- keys = append(keys, key)
- }
- sort.Strings(keys)
-
- c.indent(0, true)
- c.write("<" + tag.Name)
-
- for _, name := range keys {
- value := attribs[name]
-
- if len(value.condition) > 0 {
- c.write(`{{if ` + value.condition + `}}`)
- }
-
- val := value.value()
-
- if val == "" {
- c.write(` ` + name)
- } else {
- c.write(` ` + name + `="` + val + `"`)
- }
-
- if len(value.condition) > 0 {
- c.write(`{{end}}`)
- }
- }
-
- if tag.IsSelfClosing() {
- c.write(` />`)
- } else {
- c.write(`>`)
-
- if tag.Block != nil {
- if !tag.Block.CanInline() {
- c.indentLevel++
- }
-
- c.visitBlock(tag.Block)
-
- if !tag.Block.CanInline() {
- c.indentLevel--
- c.indent(0, true)
- }
- }
-
- c.write(`` + tag.Name + `>`)
- }
-}
-
-var textInterpolateRegexp = regexp.MustCompile(`#\{(.*?)\}`)
-var textEscapeRegexp = regexp.MustCompile(`\{\{(.*?)\}\}`)
-
-func (c *Compiler) visitText(txt *parser.Text) {
- value := textEscapeRegexp.ReplaceAllStringFunc(txt.Value, func(value string) string {
- return `{{"{{"}}` + value[2:len(value)-2] + `{{"}}"}}`
- })
-
- value = textInterpolateRegexp.ReplaceAllStringFunc(value, func(value string) string {
- return c.visitInterpolation(value[2 : len(value)-1])
- })
-
- lines := strings.Split(value, "\n")
- for i := 0; i < len(lines); i++ {
- c.write(lines[i])
-
- if i < len(lines)-1 {
- c.write("\n")
- c.indent(0, false)
- }
- }
-}
-
-func (c *Compiler) visitInterpolation(value string) string {
- return `{{` + c.visitRawInterpolation(value) + `}}`
-}
-
-func (c *Compiler) visitRawInterpolation(value string) string {
- if value == "" {
- value = "\"\""
- }
-
- value = strings.Replace(value, "$", dollar, -1)
- expr, err := gp.ParseExpr(value)
- if err != nil {
- panic("Unable to parse expression.")
- }
- value = strings.Replace(c.visitExpression(expr), dollar, "$", -1)
- return value
-}
-
-func (c *Compiler) visitExpression(outerexpr ast.Expr) string {
- stack := list.New()
-
- pop := func() string {
- if stack.Front() == nil {
- return ""
- }
-
- val := stack.Front().Value.(string)
- stack.Remove(stack.Front())
- return val
- }
-
- var exec func(ast.Expr)
-
- exec = func(expr ast.Expr) {
- switch expr := expr.(type) {
- case *ast.BinaryExpr:
- {
- be := expr
-
- exec(be.Y)
- exec(be.X)
-
- negate := false
- name := c.tempvar()
- c.write(`{{` + name + ` := `)
-
- switch be.Op {
- case gt.ADD:
- c.write("__amber_add ")
- case gt.SUB:
- c.write("__amber_sub ")
- case gt.MUL:
- c.write("__amber_mul ")
- case gt.QUO:
- c.write("__amber_quo ")
- case gt.REM:
- c.write("__amber_rem ")
- case gt.LAND:
- c.write("and ")
- case gt.LOR:
- c.write("or ")
- case gt.EQL:
- c.write("__amber_eql ")
- case gt.NEQ:
- c.write("__amber_eql ")
- negate = true
- case gt.LSS:
- c.write("__amber_lss ")
- case gt.GTR:
- c.write("__amber_gtr ")
- case gt.LEQ:
- c.write("__amber_gtr ")
- negate = true
- case gt.GEQ:
- c.write("__amber_lss ")
- negate = true
- default:
- panic("Unexpected operator!")
- }
-
- c.write(pop() + ` ` + pop() + `}}`)
-
- if !negate {
- stack.PushFront(name)
- } else {
- negname := c.tempvar()
- c.write(`{{` + negname + ` := not ` + name + `}}`)
- stack.PushFront(negname)
- }
- }
- case *ast.UnaryExpr:
- {
- ue := expr
-
- exec(ue.X)
-
- name := c.tempvar()
- c.write(`{{` + name + ` := `)
-
- switch ue.Op {
- case gt.SUB:
- c.write("__amber_minus ")
- case gt.ADD:
- c.write("__amber_plus ")
- case gt.NOT:
- c.write("not ")
- default:
- panic("Unexpected operator!")
- }
-
- c.write(pop() + `}}`)
- stack.PushFront(name)
- }
- case *ast.ParenExpr:
- exec(expr.X)
- case *ast.BasicLit:
- stack.PushFront(strings.Replace(expr.Value, dollar, "$", -1))
- case *ast.Ident:
- name := expr.Name
- if len(name) >= len(dollar) && name[:len(dollar)] == dollar {
- if name == dollar {
- stack.PushFront(`.`)
- } else {
- stack.PushFront(`$` + expr.Name[len(dollar):])
- }
- } else {
- stack.PushFront(`.` + expr.Name)
- }
- case *ast.SelectorExpr:
- se := expr
- exec(se.X)
- x := pop()
-
- if x == "." {
- x = ""
- }
-
- name := c.tempvar()
- c.write(`{{` + name + ` := ` + x + `.` + se.Sel.Name + `}}`)
- stack.PushFront(name)
- case *ast.CallExpr:
- ce := expr
-
- for i := len(ce.Args) - 1; i >= 0; i-- {
- exec(ce.Args[i])
- }
-
- name := c.tempvar()
- builtin := false
-
- if ident, ok := ce.Fun.(*ast.Ident); ok {
- for _, fname := range builtinFunctions {
- if fname == ident.Name {
- builtin = true
- break
- }
- }
- for fname, _ := range FuncMap {
- if fname == ident.Name {
- builtin = true
- break
- }
- }
- }
-
- if builtin {
- stack.PushFront(ce.Fun.(*ast.Ident).Name)
- c.write(`{{` + name + ` := ` + pop())
- } else if se, ok := ce.Fun.(*ast.SelectorExpr); ok {
- exec(se.X)
- x := pop()
-
- if x == "." {
- x = ""
- }
- stack.PushFront(se.Sel.Name)
- c.write(`{{` + name + ` := ` + x + `.` + pop())
- } else {
- exec(ce.Fun)
- c.write(`{{` + name + ` := call ` + pop())
- }
-
- for i := 0; i < len(ce.Args); i++ {
- c.write(` `)
- c.write(pop())
- }
-
- c.write(`}}`)
-
- stack.PushFront(name)
- default:
- panic("Unable to parse expression. Unsupported: " + reflect.TypeOf(expr).String())
- }
- }
-
- exec(outerexpr)
- return pop()
-}
-
-func (c *Compiler) visitMixin(mixin *parser.Mixin) {
- c.mixins[mixin.Name] = mixin
-}
-
-func (c *Compiler) visitMixinCall(mixinCall *parser.MixinCall) {
- mixin := c.mixins[mixinCall.Name]
-
- switch {
- case mixin == nil:
- panic(fmt.Sprintf("unknown mixin %q", mixinCall.Name))
-
- case len(mixinCall.Args) < len(mixin.Args):
- panic(fmt.Sprintf(
- "not enough arguments in call to mixin %q (have: %d, want: %d)",
- mixinCall.Name,
- len(mixinCall.Args),
- len(mixin.Args),
- ))
- case len(mixinCall.Args) > len(mixin.Args):
- panic(fmt.Sprintf(
- "too many arguments in call to mixin %q (have: %d, want: %d)",
- mixinCall.Name,
- len(mixinCall.Args),
- len(mixin.Args),
- ))
- }
-
- for i, arg := range mixin.Args {
- c.write(fmt.Sprintf(`{{%s := %s}}`, arg, c.visitRawInterpolation(mixinCall.Args[i])))
- }
- c.visitBlock(mixin.Block)
-}
diff --git a/vendor/github.com/eknkc/amber/doc.go b/vendor/github.com/eknkc/amber/doc.go
deleted file mode 100644
index 76ee96a..0000000
--- a/vendor/github.com/eknkc/amber/doc.go
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
-Package amber is an elegant templating engine for Go Programming Language.
-It is inspired from HAML and Jade.
-
-Tags
-
-A tag is simply a word:
-
- html
-
-is converted to
-
-
-
-It is possible to add ID and CLASS attributes to tags:
-
- div#main
- span.time
-
-are converted to
-
-
-
-
-Any arbitrary attribute name / value pair can be added this way:
-
- a[href="http://www.google.com"]
-
-You can mix multiple attributes together
-
- a#someid[href="/"][title="Main Page"].main.link Click Link
-
-gets converted to
-
- Click Link
-
-It is also possible to define these attributes within the block of a tag
-
- a
- #someid
- [href="/"]
- [title="Main Page"]
- .main
- .link
- | Click Link
-
-Doctypes
-
-To add a doctype, use `!!!` or `doctype` keywords:
-
- !!! transitional
- //
-
-or use `doctype`
-
- doctype 5
- //
-
-Available options: `5`, `default`, `xml`, `transitional`, `strict`, `frameset`, `1.1`, `basic`, `mobile`
-
-Tag Content
-
-For single line tag text, you can just append the text after tag name:
-
- p Testing!
-
-would yield
-
- Testing!
-
-For multi line tag text, or nested tags, use indentation:
-
- html
- head
- title Page Title
- body
- div#content
- p
- | This is a long page content
- | These lines are all part of the parent p
-
- a[href="/"] Go To Main Page
-
-Data
-
-Input template data can be reached by key names directly. For example, assuming the template has been
-executed with following JSON data:
-
- {
- "Name": "Ekin",
- "LastName": "Koc",
- "Repositories": [
- "amber",
- "dateformat"
- ],
- "Avatar": "/images/ekin.jpg",
- "Friends": 17
- }
-
-It is possible to interpolate fields using `#{}`
-
- p Welcome #{Name}!
-
-would print
-
- Welcome Ekin!
-
-Attributes can have field names as well
-
- a[title=Name][href="/ekin.koc"]
-
-would print
-
-
-
-Expressions
-
-Amber can expand basic expressions. For example, it is possible to concatenate strings with + operator:
-
- p Welcome #{Name + " " + LastName}
-
-Arithmetic expressions are also supported:
-
- p You need #{50 - Friends} more friends to reach 50!
-
-Expressions can be used within attributes
-
- img[alt=Name + " " + LastName][src=Avatar]
-
-Variables
-
-It is possible to define dynamic variables within templates,
-all variables must start with a $ character and can be assigned as in the following example:
-
- div
- $fullname = Name + " " + LastName
- p Welcome #{$fullname}
-
-If you need to access the supplied data itself (i.e. the object containing Name, LastName etc fields.) you can use `$` variable
-
- p $.Name
-
-Conditions
-
-For conditional blocks, it is possible to use `if `
-
- div
- if Friends > 10
- p You have more than 10 friends
- else if Friends > 5
- p You have more than 5 friends
- else
- p You need more friends
-
-Again, it is possible to use arithmetic and boolean operators
-
- div
- if Name == "Ekin" && LastName == "Koc"
- p Hey! I know you..
-
-There is a special syntax for conditional attributes. Only block attributes can have conditions;
-
- div
- .hasfriends ? Friends > 0
-
-This would yield a div with `hasfriends` class only if the `Friends > 0` condition holds. It is
-perfectly fine to use the same method for other types of attributes:
-
- div
- #foo ? Name == "Ekin"
- [bar=baz] ? len(Repositories) > 0
-
-Iterations
-
-It is possible to iterate over arrays and maps using `each`:
-
- each $repo in Repositories
- p #{$repo}
-
-would print
-
- p amber
- p dateformat
-
-It is also possible to iterate over values and indexes at the same time
-
- each $i, $repo in Repositories
- p
- .even ? $i % 2 == 0
- .odd ? $i % 2 == 1
-
-Includes
-
-A template can include other templates using `include`:
-
- a.amber
- p this is template a
-
- b.amber
- p this is template b
-
- c.amber
- div
- include a
- include b
-
-gets compiled to
-
- div
- p this is template a
- p this is template b
-
-Inheritance
-
-A template can inherit other templates. In order to inherit another template, an `extends` keyword should be used.
-Parent template can define several named blocks and child template can modify the blocks.
-
- master.amber
- !!! 5
- html
- head
- block meta
- meta[name="description"][content="This is a great website"]
-
- title
- block title
- | Default title
- body
- block content
-
- subpage.amber
- extends master
-
- block title
- | Some sub page!
-
- block append meta
- // This will be added after the description meta tag. It is also possible
- // to prepend something to an existing block
- meta[name="keywords"][content="foo bar"]
-
- block content
- div#main
- p Some content here
-
-License
-(The MIT License)
-
-Copyright (c) 2012 Ekin Koc
-
-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.
-*/
-package amber
diff --git a/vendor/github.com/eknkc/amber/parser/nodes.go b/vendor/github.com/eknkc/amber/parser/nodes.go
deleted file mode 100644
index 2f75ddd..0000000
--- a/vendor/github.com/eknkc/amber/parser/nodes.go
+++ /dev/null
@@ -1,285 +0,0 @@
-package parser
-
-import (
- "regexp"
- "strings"
-)
-
-var selfClosingTags = [...]string{
- "meta",
- "img",
- "link",
- "input",
- "source",
- "area",
- "base",
- "col",
- "br",
- "hr",
-}
-
-var doctypes = map[string]string{
- "5": ``,
- "default": ``,
- "xml": ``,
- "transitional": ``,
- "strict": ``,
- "frameset": ``,
- "1.1": ``,
- "basic": ``,
- "mobile": ``,
-}
-
-type Node interface {
- Pos() SourcePosition
-}
-
-type SourcePosition struct {
- LineNum int
- ColNum int
- TokenLength int
- Filename string
-}
-
-func (s *SourcePosition) Pos() SourcePosition {
- return *s
-}
-
-type Doctype struct {
- SourcePosition
- Value string
-}
-
-func newDoctype(value string) *Doctype {
- dt := new(Doctype)
- dt.Value = value
- return dt
-}
-
-func (d *Doctype) String() string {
- if defined := doctypes[d.Value]; len(defined) != 0 {
- return defined
- }
-
- return ``
-}
-
-type Comment struct {
- SourcePosition
- Value string
- Block *Block
- Silent bool
-}
-
-func newComment(value string) *Comment {
- dt := new(Comment)
- dt.Value = value
- dt.Block = nil
- dt.Silent = false
- return dt
-}
-
-type Text struct {
- SourcePosition
- Value string
- Raw bool
-}
-
-func newText(value string, raw bool) *Text {
- dt := new(Text)
- dt.Value = value
- dt.Raw = raw
- return dt
-}
-
-type Block struct {
- SourcePosition
- Children []Node
-}
-
-func newBlock() *Block {
- block := new(Block)
- block.Children = make([]Node, 0)
- return block
-}
-
-func (b *Block) push(node Node) {
- b.Children = append(b.Children, node)
-}
-
-func (b *Block) pushFront(node Node) {
- b.Children = append([]Node{node}, b.Children...)
-}
-
-func (b *Block) CanInline() bool {
- if len(b.Children) == 0 {
- return true
- }
-
- allText := true
-
- for _, child := range b.Children {
- if txt, ok := child.(*Text); !ok || txt.Raw {
- allText = false
- break
- }
- }
-
- return allText
-}
-
-const (
- NamedBlockDefault = iota
- NamedBlockAppend
- NamedBlockPrepend
-)
-
-type NamedBlock struct {
- Block
- Name string
- Modifier int
-}
-
-func newNamedBlock(name string) *NamedBlock {
- bb := new(NamedBlock)
- bb.Name = name
- bb.Block.Children = make([]Node, 0)
- bb.Modifier = NamedBlockDefault
- return bb
-}
-
-type Attribute struct {
- SourcePosition
- Name string
- Value string
- IsRaw bool
- Condition string
-}
-
-type Tag struct {
- SourcePosition
- Block *Block
- Name string
- IsInterpolated bool
- Attributes []Attribute
-}
-
-func newTag(name string) *Tag {
- tag := new(Tag)
- tag.Block = nil
- tag.Name = name
- tag.Attributes = make([]Attribute, 0)
- tag.IsInterpolated = false
- return tag
-
-}
-
-func (t *Tag) IsSelfClosing() bool {
- for _, tag := range selfClosingTags {
- if tag == t.Name {
- return true
- }
- }
-
- return false
-}
-
-func (t *Tag) IsRawText() bool {
- return t.Name == "style" || t.Name == "script"
-}
-
-type Condition struct {
- SourcePosition
- Positive *Block
- Negative *Block
- Expression string
-}
-
-func newCondition(exp string) *Condition {
- cond := new(Condition)
- cond.Expression = exp
- return cond
-}
-
-type Each struct {
- SourcePosition
- X string
- Y string
- Expression string
- Block *Block
-}
-
-func newEach(exp string) *Each {
- each := new(Each)
- each.Expression = exp
- return each
-}
-
-type Assignment struct {
- SourcePosition
- X string
- Expression string
-}
-
-func newAssignment(x, expression string) *Assignment {
- assgn := new(Assignment)
- assgn.X = x
- assgn.Expression = expression
- return assgn
-}
-
-type Mixin struct {
- SourcePosition
- Block *Block
- Name string
- Args []string
-}
-
-func newMixin(name, args string) *Mixin {
- mixin := new(Mixin)
- mixin.Name = name
-
- delExp := regexp.MustCompile(`,\s`)
- mixin.Args = delExp.Split(args, -1)
-
- for i := 0; i < len(mixin.Args); i++ {
- mixin.Args[i] = strings.TrimSpace(mixin.Args[i])
- if mixin.Args[i] == "" {
- mixin.Args = append(mixin.Args[:i], mixin.Args[i+1:]...)
- i--
- }
- }
-
- return mixin
-}
-
-type MixinCall struct {
- SourcePosition
- Name string
- Args []string
-}
-
-func newMixinCall(name, args string) *MixinCall {
- mixinCall := new(MixinCall)
- mixinCall.Name = name
-
- if args != "" {
- const t = "%s"
- quoteExp := regexp.MustCompile(`"(.*?)"`)
- delExp := regexp.MustCompile(`,\s`)
-
- quotes := quoteExp.FindAllString(args, -1)
- replaced := quoteExp.ReplaceAllString(args, t)
- mixinCall.Args = delExp.Split(replaced, -1)
-
- qi := 0
- for i, arg := range mixinCall.Args {
- if arg == t {
- mixinCall.Args[i] = quotes[qi]
- qi++
- }
- }
- }
-
- return mixinCall
-}
diff --git a/vendor/github.com/eknkc/amber/parser/parser.go b/vendor/github.com/eknkc/amber/parser/parser.go
deleted file mode 100644
index 9769f0b..0000000
--- a/vendor/github.com/eknkc/amber/parser/parser.go
+++ /dev/null
@@ -1,482 +0,0 @@
-package parser
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "path/filepath"
- "strings"
-)
-
-type Parser struct {
- scanner *scanner
- filename string
- fs http.FileSystem
- currenttoken *token
- namedBlocks map[string]*NamedBlock
- parent *Parser
- result *Block
-}
-
-func newParser(rdr io.Reader) *Parser {
- p := new(Parser)
- p.scanner = newScanner(rdr)
- p.namedBlocks = make(map[string]*NamedBlock)
- return p
-}
-
-func StringParser(input string) (*Parser, error) {
- return newParser(bytes.NewReader([]byte(input))), nil
-}
-
-func ByteParser(input []byte) (*Parser, error) {
- return newParser(bytes.NewReader(input)), nil
-}
-
-func (p *Parser) SetFilename(filename string) {
- p.filename = filename
-}
-
-func (p *Parser) SetVirtualFilesystem(fs http.FileSystem) {
- p.fs = fs
-}
-
-func FileParser(filename string) (*Parser, error) {
- data, err := ioutil.ReadFile(filename)
-
- if err != nil {
- return nil, err
- }
-
- parser := newParser(bytes.NewReader(data))
- parser.filename = filename
- return parser, nil
-}
-
-func VirtualFileParser(filename string, fs http.FileSystem) (*Parser, error) {
- file, err := fs.Open(filename)
- if err != nil {
- return nil, err
- }
-
- data, err := ioutil.ReadAll(file)
- if err != nil {
- return nil, err
- }
-
- parser := newParser(bytes.NewReader(data))
- parser.filename = filename
- parser.fs = fs
- return parser, nil
-}
-
-func (p *Parser) Parse() *Block {
- if p.result != nil {
- return p.result
- }
-
- defer func() {
- if r := recover(); r != nil {
- if rs, ok := r.(string); ok && rs[:len("Amber Error")] == "Amber Error" {
- panic(r)
- }
-
- pos := p.pos()
-
- if len(pos.Filename) > 0 {
- panic(fmt.Sprintf("Amber Error in <%s>: %v - Line: %d, Column: %d, Length: %d", pos.Filename, r, pos.LineNum, pos.ColNum, pos.TokenLength))
- } else {
- panic(fmt.Sprintf("Amber Error: %v - Line: %d, Column: %d, Length: %d", r, pos.LineNum, pos.ColNum, pos.TokenLength))
- }
- }
- }()
-
- block := newBlock()
- p.advance()
-
- for {
- if p.currenttoken == nil || p.currenttoken.Kind == tokEOF {
- break
- }
-
- if p.currenttoken.Kind == tokBlank {
- p.advance()
- continue
- }
-
- block.push(p.parse())
- }
-
- if p.parent != nil {
- p.parent.Parse()
-
- for _, prev := range p.parent.namedBlocks {
- ours := p.namedBlocks[prev.Name]
-
- if ours == nil {
- // Put a copy of the named block into current context, so that sub-templates can use the block
- p.namedBlocks[prev.Name] = prev
- continue
- }
-
- top := findTopmostParentWithNamedBlock(p, prev.Name)
- nb := top.namedBlocks[prev.Name]
- switch ours.Modifier {
- case NamedBlockAppend:
- for i := 0; i < len(ours.Children); i++ {
- nb.push(ours.Children[i])
- }
- case NamedBlockPrepend:
- for i := len(ours.Children) - 1; i >= 0; i-- {
- nb.pushFront(ours.Children[i])
- }
- default:
- nb.Children = ours.Children
- }
- }
-
- block = p.parent.result
- }
-
- p.result = block
- return block
-}
-
-func (p *Parser) pos() SourcePosition {
- pos := p.scanner.Pos()
- pos.Filename = p.filename
- return pos
-}
-
-func (p *Parser) parseRelativeFile(filename string) *Parser {
- if len(p.filename) == 0 {
- panic("Unable to import or extend " + filename + " in a non filesystem based parser.")
- }
-
- filename = filepath.Join(filepath.Dir(p.filename), filename)
-
- if strings.IndexRune(filepath.Base(filename), '.') < 0 {
- filename = filename + ".amber"
- }
-
- parser, err := FileParser(filename)
- if err != nil && p.fs != nil {
- parser, err = VirtualFileParser(filename, p.fs)
- }
- if err != nil {
- panic("Unable to read " + filename + ", Error: " + string(err.Error()))
- }
-
- return parser
-}
-
-func (p *Parser) parse() Node {
- switch p.currenttoken.Kind {
- case tokDoctype:
- return p.parseDoctype()
- case tokComment:
- return p.parseComment()
- case tokText:
- return p.parseText()
- case tokIf:
- return p.parseIf()
- case tokEach:
- return p.parseEach()
- case tokImport:
- return p.parseImport()
- case tokTag:
- return p.parseTag()
- case tokAssignment:
- return p.parseAssignment()
- case tokNamedBlock:
- return p.parseNamedBlock()
- case tokExtends:
- return p.parseExtends()
- case tokIndent:
- return p.parseBlock(nil)
- case tokMixin:
- return p.parseMixin()
- case tokMixinCall:
- return p.parseMixinCall()
- }
-
- panic(fmt.Sprintf("Unexpected token: %d", p.currenttoken.Kind))
-}
-
-func (p *Parser) expect(typ rune) *token {
- if p.currenttoken.Kind != typ {
- panic("Unexpected token!")
- }
- curtok := p.currenttoken
- p.advance()
- return curtok
-}
-
-func (p *Parser) advance() {
- p.currenttoken = p.scanner.Next()
-}
-
-func (p *Parser) parseExtends() *Block {
- if p.parent != nil {
- panic("Unable to extend multiple parent templates.")
- }
-
- tok := p.expect(tokExtends)
- parser := p.parseRelativeFile(tok.Value)
- parser.Parse()
- p.parent = parser
- return newBlock()
-}
-
-func (p *Parser) parseBlock(parent Node) *Block {
- p.expect(tokIndent)
- block := newBlock()
- block.SourcePosition = p.pos()
-
- for {
- if p.currenttoken == nil || p.currenttoken.Kind == tokEOF || p.currenttoken.Kind == tokOutdent {
- break
- }
-
- if p.currenttoken.Kind == tokBlank {
- p.advance()
- continue
- }
-
- if p.currenttoken.Kind == tokId ||
- p.currenttoken.Kind == tokClassName ||
- p.currenttoken.Kind == tokAttribute {
-
- if tag, ok := parent.(*Tag); ok {
- attr := p.expect(p.currenttoken.Kind)
- cond := attr.Data["Condition"]
-
- switch attr.Kind {
- case tokId:
- tag.Attributes = append(tag.Attributes, Attribute{p.pos(), "id", attr.Value, true, cond})
- case tokClassName:
- tag.Attributes = append(tag.Attributes, Attribute{p.pos(), "class", attr.Value, true, cond})
- case tokAttribute:
- tag.Attributes = append(tag.Attributes, Attribute{p.pos(), attr.Value, attr.Data["Content"], attr.Data["Mode"] == "raw", cond})
- }
-
- continue
- } else {
- panic("Conditional attributes must be placed immediately within a parent tag.")
- }
- }
-
- block.push(p.parse())
- }
-
- p.expect(tokOutdent)
-
- return block
-}
-
-func (p *Parser) parseIf() *Condition {
- tok := p.expect(tokIf)
- cnd := newCondition(tok.Value)
- cnd.SourcePosition = p.pos()
-
-readmore:
- switch p.currenttoken.Kind {
- case tokIndent:
- cnd.Positive = p.parseBlock(cnd)
- goto readmore
- case tokElse:
- p.expect(tokElse)
- if p.currenttoken.Kind == tokIf {
- cnd.Negative = newBlock()
- cnd.Negative.push(p.parseIf())
- } else if p.currenttoken.Kind == tokIndent {
- cnd.Negative = p.parseBlock(cnd)
- } else {
- panic("Unexpected token!")
- }
- goto readmore
- }
-
- return cnd
-}
-
-func (p *Parser) parseEach() *Each {
- tok := p.expect(tokEach)
- ech := newEach(tok.Value)
- ech.SourcePosition = p.pos()
- ech.X = tok.Data["X"]
- ech.Y = tok.Data["Y"]
-
- if p.currenttoken.Kind == tokIndent {
- ech.Block = p.parseBlock(ech)
- }
-
- return ech
-}
-
-func (p *Parser) parseImport() *Block {
- tok := p.expect(tokImport)
- node := p.parseRelativeFile(tok.Value).Parse()
- node.SourcePosition = p.pos()
- return node
-}
-
-func (p *Parser) parseNamedBlock() *Block {
- tok := p.expect(tokNamedBlock)
-
- if p.namedBlocks[tok.Value] != nil {
- panic("Multiple definitions of named blocks are not permitted. Block " + tok.Value + " has been re defined.")
- }
-
- block := newNamedBlock(tok.Value)
- block.SourcePosition = p.pos()
-
- if tok.Data["Modifier"] == "append" {
- block.Modifier = NamedBlockAppend
- } else if tok.Data["Modifier"] == "prepend" {
- block.Modifier = NamedBlockPrepend
- }
-
- if p.currenttoken.Kind == tokIndent {
- block.Block = *(p.parseBlock(nil))
- }
-
- p.namedBlocks[block.Name] = block
-
- if block.Modifier == NamedBlockDefault {
- return &block.Block
- }
-
- return newBlock()
-}
-
-func (p *Parser) parseDoctype() *Doctype {
- tok := p.expect(tokDoctype)
- node := newDoctype(tok.Value)
- node.SourcePosition = p.pos()
- return node
-}
-
-func (p *Parser) parseComment() *Comment {
- tok := p.expect(tokComment)
- cmnt := newComment(tok.Value)
- cmnt.SourcePosition = p.pos()
- cmnt.Silent = tok.Data["Mode"] == "silent"
-
- if p.currenttoken.Kind == tokIndent {
- cmnt.Block = p.parseBlock(cmnt)
- }
-
- return cmnt
-}
-
-func (p *Parser) parseText() *Text {
- tok := p.expect(tokText)
- node := newText(tok.Value, tok.Data["Mode"] == "raw")
- node.SourcePosition = p.pos()
- return node
-}
-
-func (p *Parser) parseAssignment() *Assignment {
- tok := p.expect(tokAssignment)
- node := newAssignment(tok.Data["X"], tok.Value)
- node.SourcePosition = p.pos()
- return node
-}
-
-func (p *Parser) parseTag() *Tag {
- tok := p.expect(tokTag)
- tag := newTag(tok.Value)
- tag.SourcePosition = p.pos()
-
- ensureBlock := func() {
- if tag.Block == nil {
- tag.Block = newBlock()
- }
- }
-
-readmore:
- switch p.currenttoken.Kind {
- case tokIndent:
- if tag.IsRawText() {
- p.scanner.readRaw = true
- }
-
- block := p.parseBlock(tag)
- if tag.Block == nil {
- tag.Block = block
- } else {
- for _, c := range block.Children {
- tag.Block.push(c)
- }
- }
- case tokId:
- id := p.expect(tokId)
- if len(id.Data["Condition"]) > 0 {
- panic("Conditional attributes must be placed in a block within a tag.")
- }
- tag.Attributes = append(tag.Attributes, Attribute{p.pos(), "id", id.Value, true, ""})
- goto readmore
- case tokClassName:
- cls := p.expect(tokClassName)
- if len(cls.Data["Condition"]) > 0 {
- panic("Conditional attributes must be placed in a block within a tag.")
- }
- tag.Attributes = append(tag.Attributes, Attribute{p.pos(), "class", cls.Value, true, ""})
- goto readmore
- case tokAttribute:
- attr := p.expect(tokAttribute)
- if len(attr.Data["Condition"]) > 0 {
- panic("Conditional attributes must be placed in a block within a tag.")
- }
- tag.Attributes = append(tag.Attributes, Attribute{p.pos(), attr.Value, attr.Data["Content"], attr.Data["Mode"] == "raw", ""})
- goto readmore
- case tokText:
- if p.currenttoken.Data["Mode"] != "piped" {
- ensureBlock()
- tag.Block.pushFront(p.parseText())
- goto readmore
- }
- }
-
- return tag
-}
-
-func (p *Parser) parseMixin() *Mixin {
- tok := p.expect(tokMixin)
- mixin := newMixin(tok.Value, tok.Data["Args"])
- mixin.SourcePosition = p.pos()
-
- if p.currenttoken.Kind == tokIndent {
- mixin.Block = p.parseBlock(mixin)
- }
-
- return mixin
-}
-
-func (p *Parser) parseMixinCall() *MixinCall {
- tok := p.expect(tokMixinCall)
- mixinCall := newMixinCall(tok.Value, tok.Data["Args"])
- mixinCall.SourcePosition = p.pos()
- return mixinCall
-}
-
-func findTopmostParentWithNamedBlock(p *Parser, name string) *Parser {
- top := p
-
- for {
- if top.namedBlocks[name] == nil {
- return nil
- }
- if top.parent == nil {
- return top
- }
- if top.parent.namedBlocks[name] != nil {
- top = top.parent
- } else {
- return top
- }
- }
-}
diff --git a/vendor/github.com/eknkc/amber/parser/scanner.go b/vendor/github.com/eknkc/amber/parser/scanner.go
deleted file mode 100644
index 70e0203..0000000
--- a/vendor/github.com/eknkc/amber/parser/scanner.go
+++ /dev/null
@@ -1,501 +0,0 @@
-package parser
-
-import (
- "bufio"
- "container/list"
- "fmt"
- "io"
- "regexp"
-)
-
-const (
- tokEOF = -(iota + 1)
- tokDoctype
- tokComment
- tokIndent
- tokOutdent
- tokBlank
- tokId
- tokClassName
- tokTag
- tokText
- tokAttribute
- tokIf
- tokElse
- tokEach
- tokAssignment
- tokImport
- tokNamedBlock
- tokExtends
- tokMixin
- tokMixinCall
-)
-
-const (
- scnNewLine = iota
- scnLine
- scnEOF
-)
-
-type scanner struct {
- reader *bufio.Reader
- indentStack *list.List
- stash *list.List
-
- state int32
- buffer string
-
- line int
- col int
- lastTokenLine int
- lastTokenCol int
- lastTokenSize int
-
- readRaw bool
-}
-
-type token struct {
- Kind rune
- Value string
- Data map[string]string
-}
-
-func newScanner(r io.Reader) *scanner {
- s := new(scanner)
- s.reader = bufio.NewReader(r)
- s.indentStack = list.New()
- s.stash = list.New()
- s.state = scnNewLine
- s.line = -1
- s.col = 0
-
- return s
-}
-
-func (s *scanner) Pos() SourcePosition {
- return SourcePosition{s.lastTokenLine + 1, s.lastTokenCol + 1, s.lastTokenSize, ""}
-}
-
-// Returns next token found in buffer
-func (s *scanner) Next() *token {
- if s.readRaw {
- s.readRaw = false
- return s.NextRaw()
- }
-
- s.ensureBuffer()
-
- if stashed := s.stash.Front(); stashed != nil {
- tok := stashed.Value.(*token)
- s.stash.Remove(stashed)
- return tok
- }
-
- switch s.state {
- case scnEOF:
- if outdent := s.indentStack.Back(); outdent != nil {
- s.indentStack.Remove(outdent)
- return &token{tokOutdent, "", nil}
- }
-
- return &token{tokEOF, "", nil}
- case scnNewLine:
- s.state = scnLine
-
- if tok := s.scanIndent(); tok != nil {
- return tok
- }
-
- return s.Next()
- case scnLine:
- if tok := s.scanMixin(); tok != nil {
- return tok
- }
-
- if tok := s.scanMixinCall(); tok != nil {
- return tok
- }
-
- if tok := s.scanDoctype(); tok != nil {
- return tok
- }
-
- if tok := s.scanCondition(); tok != nil {
- return tok
- }
-
- if tok := s.scanEach(); tok != nil {
- return tok
- }
-
- if tok := s.scanImport(); tok != nil {
- return tok
- }
-
- if tok := s.scanExtends(); tok != nil {
- return tok
- }
-
- if tok := s.scanBlock(); tok != nil {
- return tok
- }
-
- if tok := s.scanAssignment(); tok != nil {
- return tok
- }
-
- if tok := s.scanTag(); tok != nil {
- return tok
- }
-
- if tok := s.scanId(); tok != nil {
- return tok
- }
-
- if tok := s.scanClassName(); tok != nil {
- return tok
- }
-
- if tok := s.scanAttribute(); tok != nil {
- return tok
- }
-
- if tok := s.scanComment(); tok != nil {
- return tok
- }
-
- if tok := s.scanText(); tok != nil {
- return tok
- }
- }
-
- return nil
-}
-
-func (s *scanner) NextRaw() *token {
- result := ""
- level := 0
-
- for {
- s.ensureBuffer()
-
- switch s.state {
- case scnEOF:
- return &token{tokText, result, map[string]string{"Mode": "raw"}}
- case scnNewLine:
- s.state = scnLine
-
- if tok := s.scanIndent(); tok != nil {
- if tok.Kind == tokIndent {
- level++
- } else if tok.Kind == tokOutdent {
- level--
- } else {
- result = result + "\n"
- continue
- }
-
- if level < 0 {
- s.stash.PushBack(&token{tokOutdent, "", nil})
-
- if len(result) > 0 && result[len(result)-1] == '\n' {
- result = result[:len(result)-1]
- }
-
- return &token{tokText, result, map[string]string{"Mode": "raw"}}
- }
- }
- case scnLine:
- if len(result) > 0 {
- result = result + "\n"
- }
- for i := 0; i < level; i++ {
- result += "\t"
- }
- result = result + s.buffer
- s.consume(len(s.buffer))
- }
- }
-
- return nil
-}
-
-var rgxIndent = regexp.MustCompile(`^(\s+)`)
-
-func (s *scanner) scanIndent() *token {
- if len(s.buffer) == 0 {
- return &token{tokBlank, "", nil}
- }
-
- var head *list.Element
- for head = s.indentStack.Front(); head != nil; head = head.Next() {
- value := head.Value.(*regexp.Regexp)
-
- if match := value.FindString(s.buffer); len(match) != 0 {
- s.consume(len(match))
- } else {
- break
- }
- }
-
- newIndent := rgxIndent.FindString(s.buffer)
-
- if len(newIndent) != 0 && head == nil {
- s.indentStack.PushBack(regexp.MustCompile(regexp.QuoteMeta(newIndent)))
- s.consume(len(newIndent))
- return &token{tokIndent, newIndent, nil}
- }
-
- if len(newIndent) == 0 && head != nil {
- for head != nil {
- next := head.Next()
- s.indentStack.Remove(head)
- if next == nil {
- return &token{tokOutdent, "", nil}
- } else {
- s.stash.PushBack(&token{tokOutdent, "", nil})
- }
- head = next
- }
- }
-
- if len(newIndent) != 0 && head != nil {
- panic("Mismatching indentation. Please use a coherent indent schema.")
- }
-
- return nil
-}
-
-var rgxDoctype = regexp.MustCompile(`^(!!!|doctype)\s*(.*)`)
-
-func (s *scanner) scanDoctype() *token {
- if sm := rgxDoctype.FindStringSubmatch(s.buffer); len(sm) != 0 {
- if len(sm[2]) == 0 {
- sm[2] = "html"
- }
-
- s.consume(len(sm[0]))
- return &token{tokDoctype, sm[2], nil}
- }
-
- return nil
-}
-
-var rgxIf = regexp.MustCompile(`^if\s+(.+)$`)
-var rgxElse = regexp.MustCompile(`^else\s*`)
-
-func (s *scanner) scanCondition() *token {
- if sm := rgxIf.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokIf, sm[1], nil}
- }
-
- if sm := rgxElse.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokElse, "", nil}
- }
-
- return nil
-}
-
-var rgxEach = regexp.MustCompile(`^each\s+(\$[\w0-9\-_]*)(?:\s*,\s*(\$[\w0-9\-_]*))?\s+in\s+(.+)$`)
-
-func (s *scanner) scanEach() *token {
- if sm := rgxEach.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokEach, sm[3], map[string]string{"X": sm[1], "Y": sm[2]}}
- }
-
- return nil
-}
-
-var rgxAssignment = regexp.MustCompile(`^(\$[\w0-9\-_]*)?\s*=\s*(.+)$`)
-
-func (s *scanner) scanAssignment() *token {
- if sm := rgxAssignment.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokAssignment, sm[2], map[string]string{"X": sm[1]}}
- }
-
- return nil
-}
-
-var rgxComment = regexp.MustCompile(`^\/\/(-)?\s*(.*)$`)
-
-func (s *scanner) scanComment() *token {
- if sm := rgxComment.FindStringSubmatch(s.buffer); len(sm) != 0 {
- mode := "embed"
- if len(sm[1]) != 0 {
- mode = "silent"
- }
-
- s.consume(len(sm[0]))
- return &token{tokComment, sm[2], map[string]string{"Mode": mode}}
- }
-
- return nil
-}
-
-var rgxId = regexp.MustCompile(`^#([\w-]+)(?:\s*\?\s*(.*)$)?`)
-
-func (s *scanner) scanId() *token {
- if sm := rgxId.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokId, sm[1], map[string]string{"Condition": sm[2]}}
- }
-
- return nil
-}
-
-var rgxClassName = regexp.MustCompile(`^\.([\w-]+)(?:\s*\?\s*(.*)$)?`)
-
-func (s *scanner) scanClassName() *token {
- if sm := rgxClassName.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokClassName, sm[1], map[string]string{"Condition": sm[2]}}
- }
-
- return nil
-}
-
-var rgxAttribute = regexp.MustCompile(`^\[([\w\-:@\.]+)\s*(?:=\s*(\"([^\"\\]*)\"|([^\]]+)))?\](?:\s*\?\s*(.*)$)?`)
-
-func (s *scanner) scanAttribute() *token {
- if sm := rgxAttribute.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
-
- if len(sm[3]) != 0 || sm[2] == "" {
- return &token{tokAttribute, sm[1], map[string]string{"Content": sm[3], "Mode": "raw", "Condition": sm[5]}}
- }
-
- return &token{tokAttribute, sm[1], map[string]string{"Content": sm[4], "Mode": "expression", "Condition": sm[5]}}
- }
-
- return nil
-}
-
-var rgxImport = regexp.MustCompile(`^import\s+([0-9a-zA-Z_\-\. \/]*)$`)
-
-func (s *scanner) scanImport() *token {
- if sm := rgxImport.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokImport, sm[1], nil}
- }
-
- return nil
-}
-
-var rgxExtends = regexp.MustCompile(`^extends\s+([0-9a-zA-Z_\-\. \/]*)$`)
-
-func (s *scanner) scanExtends() *token {
- if sm := rgxExtends.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokExtends, sm[1], nil}
- }
-
- return nil
-}
-
-var rgxBlock = regexp.MustCompile(`^block\s+(?:(append|prepend)\s+)?([0-9a-zA-Z_\-\. \/]*)$`)
-
-func (s *scanner) scanBlock() *token {
- if sm := rgxBlock.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokNamedBlock, sm[2], map[string]string{"Modifier": sm[1]}}
- }
-
- return nil
-}
-
-var rgxTag = regexp.MustCompile(`^(\w[-:\w]*)`)
-
-func (s *scanner) scanTag() *token {
- if sm := rgxTag.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokTag, sm[1], nil}
- }
-
- return nil
-}
-
-var rgxMixin = regexp.MustCompile(`^mixin ([a-zA-Z_-]+\w*)(\(((\$\w*(,\s)?)*)\))?$`)
-
-func (s *scanner) scanMixin() *token {
- if sm := rgxMixin.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokMixin, sm[1], map[string]string{"Args": sm[3]}}
- }
-
- return nil
-}
-
-var rgxMixinCall = regexp.MustCompile(`^\+([A-Za-z_-]+\w*)(\((.+(,\s)?)*\))?$`)
-
-func (s *scanner) scanMixinCall() *token {
- if sm := rgxMixinCall.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
- return &token{tokMixinCall, sm[1], map[string]string{"Args": sm[3]}}
- }
-
- return nil
-}
-
-var rgxText = regexp.MustCompile(`^(\|)? ?(.*)$`)
-
-func (s *scanner) scanText() *token {
- if sm := rgxText.FindStringSubmatch(s.buffer); len(sm) != 0 {
- s.consume(len(sm[0]))
-
- mode := "inline"
- if sm[1] == "|" {
- mode = "piped"
- }
-
- return &token{tokText, sm[2], map[string]string{"Mode": mode}}
- }
-
- return nil
-}
-
-// Moves position forward, and removes beginning of s.buffer (len bytes)
-func (s *scanner) consume(runes int) {
- if len(s.buffer) < runes {
- panic(fmt.Sprintf("Unable to consume %d runes from buffer.", runes))
- }
-
- s.lastTokenLine = s.line
- s.lastTokenCol = s.col
- s.lastTokenSize = runes
-
- s.buffer = s.buffer[runes:]
- s.col += runes
-}
-
-// Reads string into s.buffer
-func (s *scanner) ensureBuffer() {
- if len(s.buffer) > 0 {
- return
- }
-
- buf, err := s.reader.ReadString('\n')
-
- if err != nil && err != io.EOF {
- panic(err)
- } else if err != nil && len(buf) == 0 {
- s.state = scnEOF
- } else {
- // endline "LF only" or "\n" use Unix, Linux, modern MacOS X, FreeBSD, BeOS, RISC OS
- if buf[len(buf)-1] == '\n' {
- buf = buf[:len(buf)-1]
- }
- // endline "CR+LF" or "\r\n" use internet protocols, DEC RT-11, Windows, CP/M, MS-DOS, OS/2, Symbian OS
- if len(buf) > 0 && buf[len(buf)-1] == '\r' {
- buf = buf[:len(buf)-1]
- }
-
- s.state = scnNewLine
- s.buffer = buf
- s.line += 1
- s.col = 0
- }
-}
diff --git a/vendor/github.com/eknkc/amber/runtime.go b/vendor/github.com/eknkc/amber/runtime.go
deleted file mode 100644
index 6438fd1..0000000
--- a/vendor/github.com/eknkc/amber/runtime.go
+++ /dev/null
@@ -1,287 +0,0 @@
-package amber
-
-import (
- "encoding/json"
- "fmt"
- "html/template"
- "reflect"
-)
-
-var FuncMap = template.FuncMap{
- "__amber_add": runtime_add,
- "__amber_sub": runtime_sub,
- "__amber_mul": runtime_mul,
- "__amber_quo": runtime_quo,
- "__amber_rem": runtime_rem,
- "__amber_minus": runtime_minus,
- "__amber_plus": runtime_plus,
- "__amber_eql": runtime_eql,
- "__amber_gtr": runtime_gtr,
- "__amber_lss": runtime_lss,
-
- "json": runtime_json,
- "unescaped": runtime_unescaped,
-}
-
-func runtime_add(x, y interface{}) interface{} {
- vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
- switch vx.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Int() + vy.Int()
- case reflect.Float32, reflect.Float64:
- return float64(vx.Int()) + vy.Float()
- case reflect.String:
- return fmt.Sprintf("%d%s", vx.Int(), vy.String())
- }
- }
- case reflect.Float32, reflect.Float64:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Float() + float64(vy.Int())
- case reflect.Float32, reflect.Float64:
- return vx.Float() + vy.Float()
- case reflect.String:
- return fmt.Sprintf("%f%s", vx.Float(), vy.String())
- }
- }
- case reflect.String:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return fmt.Sprintf("%s%d", vx.String(), vy.Int())
- case reflect.Float32, reflect.Float64:
- return fmt.Sprintf("%s%f", vx.String(), vy.Float())
- case reflect.String:
- return fmt.Sprintf("%s%s", vx.String(), vy.String())
- }
- }
- }
-
- return ""
-}
-
-func runtime_sub(x, y interface{}) interface{} {
- vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
- switch vx.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Int() - vy.Int()
- case reflect.Float32, reflect.Float64:
- return float64(vx.Int()) - vy.Float()
- }
- }
- case reflect.Float32, reflect.Float64:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Float() - float64(vy.Int())
- case reflect.Float32, reflect.Float64:
- return vx.Float() - vy.Float()
- }
- }
- }
-
- return ""
-}
-
-func runtime_mul(x, y interface{}) interface{} {
- vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
- switch vx.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Int() * vy.Int()
- case reflect.Float32, reflect.Float64:
- return float64(vx.Int()) * vy.Float()
- }
- }
- case reflect.Float32, reflect.Float64:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Float() * float64(vy.Int())
- case reflect.Float32, reflect.Float64:
- return vx.Float() * vy.Float()
- }
- }
- }
-
- return ""
-}
-
-func runtime_quo(x, y interface{}) interface{} {
- vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
- switch vx.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Int() / vy.Int()
- case reflect.Float32, reflect.Float64:
- return float64(vx.Int()) / vy.Float()
- }
- }
- case reflect.Float32, reflect.Float64:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Float() / float64(vy.Int())
- case reflect.Float32, reflect.Float64:
- return vx.Float() / vy.Float()
- }
- }
- }
-
- return ""
-}
-
-func runtime_rem(x, y interface{}) interface{} {
- vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
- switch vx.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Int() % vy.Int()
- }
- }
- }
-
- return ""
-}
-
-func runtime_minus(x interface{}) interface{} {
- vx := reflect.ValueOf(x)
- switch vx.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return -vx.Int()
- case reflect.Float32, reflect.Float64:
- return -vx.Float()
- }
-
- return ""
-}
-
-func runtime_plus(x interface{}) interface{} {
- vx := reflect.ValueOf(x)
- switch vx.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return +vx.Int()
- case reflect.Float32, reflect.Float64:
- return +vx.Float()
- }
-
- return ""
-}
-
-func runtime_eql(x, y interface{}) bool {
- vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
- switch vx.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Int() == vy.Int()
- case reflect.Float32, reflect.Float64:
- return float64(vx.Int()) == vy.Float()
- case reflect.String:
- return fmt.Sprintf("%d", vx.Int()) == vy.String()
- }
- }
- case reflect.Float32, reflect.Float64:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Float() == float64(vy.Int())
- case reflect.Float32, reflect.Float64:
- return vx.Float() == vy.Float()
- case reflect.String:
- return fmt.Sprintf("%f", vx.Float()) == vy.String()
- }
- }
- case reflect.String:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.String() == fmt.Sprintf("%d", vy.Int())
- case reflect.Float32, reflect.Float64:
- return vx.String() == fmt.Sprintf("%f", vy.Float())
- case reflect.String:
- return vx.String() == fmt.Sprintf("%s", vy.String())
- }
- }
- case reflect.Bool:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Bool() && vy.Int() != 0
- case reflect.Bool:
- return vx.Bool() == vy.Bool()
- }
- }
- }
-
- return false
-}
-
-func runtime_lss(x, y interface{}) bool {
- vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
- switch vx.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Int() < vy.Int()
- case reflect.Float32, reflect.Float64:
- return float64(vx.Int()) < vy.Float()
- case reflect.String:
- return fmt.Sprintf("%d", vx.Int()) < vy.String()
- }
- }
- case reflect.Float32, reflect.Float64:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.Float() < float64(vy.Int())
- case reflect.Float32, reflect.Float64:
- return vx.Float() < vy.Float()
- case reflect.String:
- return fmt.Sprintf("%f", vx.Float()) < vy.String()
- }
- }
- case reflect.String:
- {
- switch vy.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64, reflect.Int16, reflect.Int8:
- return vx.String() < fmt.Sprintf("%d", vy.Int())
- case reflect.Float32, reflect.Float64:
- return vx.String() < fmt.Sprintf("%f", vy.Float())
- case reflect.String:
- return vx.String() < vy.String()
- }
- }
- }
-
- return false
-}
-
-func runtime_gtr(x, y interface{}) bool {
- return !runtime_lss(x, y) && !runtime_eql(x, y)
-}
-
-func runtime_json(x interface{}) (res string, err error) {
- bres, err := json.Marshal(x)
- res = string(bres)
- return
-}
-
-func runtime_unescaped(x string) interface{} {
- return template.HTML(x)
-}
diff --git a/vendor/github.com/russross/blackfriday/v2/.gitignore b/vendor/github.com/russross/blackfriday/v2/.gitignore
deleted file mode 100644
index 75623dc..0000000
--- a/vendor/github.com/russross/blackfriday/v2/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-*.out
-*.swp
-*.8
-*.6
-_obj
-_test*
-markdown
-tags
diff --git a/vendor/github.com/russross/blackfriday/v2/.travis.yml b/vendor/github.com/russross/blackfriday/v2/.travis.yml
deleted file mode 100644
index b0b525a..0000000
--- a/vendor/github.com/russross/blackfriday/v2/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-sudo: false
-language: go
-go:
- - "1.10.x"
- - "1.11.x"
- - tip
-matrix:
- fast_finish: true
- allow_failures:
- - go: tip
-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 ./...
diff --git a/vendor/github.com/russross/blackfriday/v2/LICENSE.txt b/vendor/github.com/russross/blackfriday/v2/LICENSE.txt
deleted file mode 100644
index 2885af3..0000000
--- a/vendor/github.com/russross/blackfriday/v2/LICENSE.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-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.
diff --git a/vendor/github.com/russross/blackfriday/v2/README.md b/vendor/github.com/russross/blackfriday/v2/README.md
deleted file mode 100644
index d9c08a2..0000000
--- a/vendor/github.com/russross/blackfriday/v2/README.md
+++ /dev/null
@@ -1,335 +0,0 @@
-Blackfriday
-[![Build Status][BuildV2SVG]][BuildV2URL]
-[![PkgGoDev][PkgGoDevV2SVG]][PkgGoDevV2URL]
-===========
-
-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.
-
-It started as a translation from C of [Sundown][3].
-
-
-Installation
-------------
-
-Blackfriday is compatible with modern Go releases in module mode.
-With Go installed:
-
- go get github.com/russross/blackfriday/v2
-
-will resolve and add the package to the current development module,
-then build and install it. Alternatively, you can achieve the same
-if you import it in a package:
-
- import "github.com/russross/blackfriday/v2"
-
-and `go get` without parameters.
-
-Legacy GOPATH mode is unsupported.
-
-
-Versions
---------
-
-Currently maintained and recommended version of Blackfriday is `v2`. It's being
-developed on its own branch: https://github.com/russross/blackfriday/tree/v2 and the
-documentation is available at
-https://pkg.go.dev/github.com/russross/blackfriday/v2.
-
-It is `go get`-able in module mode at `github.com/russross/blackfriday/v2`.
-
-Version 2 offers a number of improvements over v1:
-
-* Cleaned up API
-* A separate call to [`Parse`][4], which produces an abstract syntax tree for
- the document
-* Latest bug fixes
-* Flexibility to easily add your own rendering extensions
-
-Potential drawbacks:
-
-* Our benchmarks show v2 to be slightly slower than v1. Currently in the
- ballpark of around 15%.
-* API breakage. If you can't afford modifying your code to adhere to the new API
- and don't care too much about the new features, v2 is probably not for you.
-* Several bug fixes are trailing behind and still need to be forward-ported to
- v2. See issue [#348](https://github.com/russross/blackfriday/issues/348) for
- tracking.
-
-If you are still interested in the legacy `v1`, you can import it from
-`github.com/russross/blackfriday`. Documentation for the legacy v1 can be found
-here: https://pkg.go.dev/github.com/russross/blackfriday.
-
-
-Usage
------
-
-For the most sensible markdown processing, it is as simple as getting your input
-into a byte slice and calling:
-
-```go
-output := blackfriday.Run(input)
-```
-
-Your input will be parsed and the output rendered with a set of most popular
-extensions enabled. If you want the most basic feature set, corresponding with
-the bare Markdown specification, use:
-
-```go
-output := blackfriday.Run(input, blackfriday.WithNoExtensions())
-```
-
-### 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][5].
-
-Here's an example of simple usage of Blackfriday together with Bluemonday:
-
-```go
-import (
- "github.com/microcosm-cc/bluemonday"
- "github.com/russross/blackfriday/v2"
-)
-
-// ...
-unsafe := blackfriday.Run(input)
-html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
-```
-
-### Custom options
-
-If you want to customize the set of options, use `blackfriday.WithExtensions`,
-`blackfriday.WithRenderer` and `blackfriday.WithRefOverride`.
-
-### `blackfriday-tool`
-
-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:
-
-*
-
-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.
-
-### Sanitized anchor names
-
-Blackfriday includes an algorithm for creating sanitized anchor names
-corresponding to a given input text. This algorithm is used to create
-anchors for headings when `AutoHeadingIDs` extension is enabled. The
-algorithm has a specification, so that other packages can create
-compatible anchor names and links to those anchors.
-
-The specification is located at https://pkg.go.dev/github.com/russross/blackfriday/v2#hdr-Sanitized_Anchor_Names.
-
-[`SanitizedAnchorName`](https://pkg.go.dev/github.com/russross/blackfriday/v2#SanitizedAnchorName) exposes this functionality, and can be used to
-create compatible links to the anchor names generated by blackfriday.
-This algorithm is also implemented in a small standalone package at
-[`github.com/shurcooL/sanitized_anchor_name`](https://pkg.go.dev/github.com/shurcooL/sanitized_anchor_name). It can be useful for clients
-that want a small package and don't need full functionality of blackfriday.
-
-
-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 against 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.
-
- To preserve classes of fenced code blocks while using the bluemonday
- HTML sanitizer, use the following policy:
-
- ```go
- p := bluemonday.UGCPolicy()
- p.AllowAttrs("class").Matching(regexp.MustCompile("^language-[a-zA-Z0-9]+$")).OnElements("code")
- html := p.SanitizeBytes(unsafe)
- ```
-
-* **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 newlines in the input
- translate into line breaks in the output. This extension is off by default.
-
-* **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 `4 ⁄5 `, which renders as
- 4 ⁄5 .
-
-
-Other renderers
----------------
-
-Blackfriday is structured to allow alternative rendering engines. Here
-are a few of note:
-
-* [github_flavored_markdown](https://pkg.go.dev/github.com/shurcooL/github_flavored_markdown):
- provides a GitHub Flavored Markdown renderer with fenced code block
- highlighting, clickable heading 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](https://gitlab.com/ambrevar/blackfriday-latex):
- renders output as LaTeX.
-
-* [bfchroma](https://github.com/Depado/bfchroma/): provides convenience
- integration with the [Chroma](https://github.com/alecthomas/chroma) code
- highlighting library. bfchroma is only compatible with v2 of Blackfriday and
- provides a drop-in renderer ready to use with Blackfriday, as well as
- options and means for further customization.
-
-* [Blackfriday-Confluence](https://github.com/kentaro-m/blackfriday-confluence): provides a [Confluence Wiki Markup](https://confluence.atlassian.com/doc/confluence-wiki-markup-251003035.html) renderer.
-
-* [Blackfriday-Slack](https://github.com/karriereat/blackfriday-slack): converts markdown to slack message style
-
-
-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]: https://daringfireball.net/projects/markdown/ "Markdown"
- [2]: https://golang.org/ "Go Language"
- [3]: https://github.com/vmg/sundown "Sundown"
- [4]: https://pkg.go.dev/github.com/russross/blackfriday/v2#Parse "Parse func"
- [5]: https://github.com/microcosm-cc/bluemonday "Bluemonday"
-
- [BuildV2SVG]: https://travis-ci.org/russross/blackfriday.svg?branch=v2
- [BuildV2URL]: https://travis-ci.org/russross/blackfriday
- [PkgGoDevV2SVG]: https://pkg.go.dev/badge/github.com/russross/blackfriday/v2
- [PkgGoDevV2URL]: https://pkg.go.dev/github.com/russross/blackfriday/v2
diff --git a/vendor/github.com/russross/blackfriday/v2/block.go b/vendor/github.com/russross/blackfriday/v2/block.go
deleted file mode 100644
index dcd61e6..0000000
--- a/vendor/github.com/russross/blackfriday/v2/block.go
+++ /dev/null
@@ -1,1612 +0,0 @@
-//
-// Blackfriday Markdown Processor
-// Available at http://github.com/russross/blackfriday
-//
-// Copyright © 2011 Russ Ross .
-// Distributed under the Simplified BSD License.
-// See README.md for details.
-//
-
-//
-// Functions to parse block-level elements.
-//
-
-package blackfriday
-
-import (
- "bytes"
- "html"
- "regexp"
- "strings"
- "unicode"
-)
-
-const (
- charEntity = "&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});"
- escapable = "[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]"
-)
-
-var (
- reBackslashOrAmp = regexp.MustCompile("[\\&]")
- reEntityOrEscapedChar = regexp.MustCompile("(?i)\\\\" + escapable + "|" + charEntity)
-)
-
-// Parse block-level data.
-// Note: this function and many that it calls assume that
-// the input buffer ends with a newline.
-func (p *Markdown) block(data []byte) {
- // this is called recursively: enforce a maximum depth
- if p.nesting >= p.maxNesting {
- return
- }
- p.nesting++
-
- // parse out one block-level construct at a time
- for len(data) > 0 {
- // prefixed heading:
- //
- // # Heading 1
- // ## Heading 2
- // ...
- // ###### Heading 6
- if p.isPrefixHeading(data) {
- data = data[p.prefixHeading(data):]
- continue
- }
-
- // block of preformatted HTML:
- //
- //
- // ...
- //
- if data[0] == '<' {
- if i := p.html(data, true); i > 0 {
- data = data[i:]
- continue
- }
- }
-
- // title block
- //
- // % stuff
- // % more stuff
- // % even more stuff
- if p.extensions&Titleblock != 0 {
- if data[0] == '%' {
- if i := p.titleBlock(data, true); i > 0 {
- data = data[i:]
- continue
- }
- }
- }
-
- // blank lines. note: returns the # of bytes to skip
- if i := p.isEmpty(data); i > 0 {
- data = data[i:]
- continue
- }
-
- // indented code block:
- //
- // func max(a, b int) int {
- // if a > b {
- // return a
- // }
- // return b
- // }
- if p.codePrefix(data) > 0 {
- data = data[p.code(data):]
- continue
- }
-
- // fenced code block:
- //
- // ``` go
- // func fact(n int) int {
- // if n <= 1 {
- // return n
- // }
- // return n * fact(n-1)
- // }
- // ```
- if p.extensions&FencedCode != 0 {
- if i := p.fencedCodeBlock(data, true); i > 0 {
- data = data[i:]
- continue
- }
- }
-
- // horizontal rule:
- //
- // ------
- // or
- // ******
- // or
- // ______
- if p.isHRule(data) {
- p.addBlock(HorizontalRule, nil)
- var i int
- for i = 0; i < len(data) && data[i] != '\n'; i++ {
- }
- data = data[i:]
- continue
- }
-
- // block quote:
- //
- // > A big quote I found somewhere
- // > on the web
- if p.quotePrefix(data) > 0 {
- data = data[p.quote(data):]
- continue
- }
-
- // table:
- //
- // Name | Age | Phone
- // ------|-----|---------
- // Bob | 31 | 555-1234
- // Alice | 27 | 555-4321
- if p.extensions&Tables != 0 {
- if i := p.table(data); i > 0 {
- data = data[i:]
- continue
- }
- }
-
- // an itemized/unordered list:
- //
- // * Item 1
- // * Item 2
- //
- // also works with + or -
- if p.uliPrefix(data) > 0 {
- data = data[p.list(data, 0):]
- continue
- }
-
- // a numbered/ordered list:
- //
- // 1. Item 1
- // 2. Item 2
- if p.oliPrefix(data) > 0 {
- data = data[p.list(data, ListTypeOrdered):]
- continue
- }
-
- // definition lists:
- //
- // Term 1
- // : Definition a
- // : Definition b
- //
- // Term 2
- // : Definition c
- if p.extensions&DefinitionLists != 0 {
- if p.dliPrefix(data) > 0 {
- data = data[p.list(data, ListTypeDefinition):]
- continue
- }
- }
-
- // anything else must look like a normal paragraph
- // note: this finds underlined headings, too
- data = data[p.paragraph(data):]
- }
-
- p.nesting--
-}
-
-func (p *Markdown) addBlock(typ NodeType, content []byte) *Node {
- p.closeUnmatchedBlocks()
- container := p.addChild(typ, 0)
- container.content = content
- return container
-}
-
-func (p *Markdown) isPrefixHeading(data []byte) bool {
- if data[0] != '#' {
- return false
- }
-
- if p.extensions&SpaceHeadings != 0 {
- level := 0
- for level < 6 && level < len(data) && data[level] == '#' {
- level++
- }
- if level == len(data) || data[level] != ' ' {
- return false
- }
- }
- return true
-}
-
-func (p *Markdown) prefixHeading(data []byte) int {
- level := 0
- for level < 6 && level < len(data) && data[level] == '#' {
- level++
- }
- i := skipChar(data, level, ' ')
- end := skipUntilChar(data, i, '\n')
- skip := end
- id := ""
- if p.extensions&HeadingIDs != 0 {
- j, k := 0, 0
- // find start/end of heading id
- for j = i; j < end-1 && (data[j] != '{' || data[j+1] != '#'); j++ {
- }
- for k = j + 1; k < end && data[k] != '}'; k++ {
- }
- // extract heading id iff found
- if j < end && k < end {
- id = string(data[j+2 : k])
- end = j
- skip = k + 1
- for end > 0 && data[end-1] == ' ' {
- end--
- }
- }
- }
- for end > 0 && data[end-1] == '#' {
- if isBackslashEscaped(data, end-1) {
- break
- }
- end--
- }
- for end > 0 && data[end-1] == ' ' {
- end--
- }
- if end > i {
- if id == "" && p.extensions&AutoHeadingIDs != 0 {
- id = SanitizedAnchorName(string(data[i:end]))
- }
- block := p.addBlock(Heading, data[i:end])
- block.HeadingID = id
- block.Level = level
- }
- return skip
-}
-
-func (p *Markdown) isUnderlinedHeading(data []byte) int {
- // test of level 1 heading
- if data[0] == '=' {
- i := skipChar(data, 1, '=')
- i = skipChar(data, i, ' ')
- if i < len(data) && data[i] == '\n' {
- return 1
- }
- return 0
- }
-
- // test of level 2 heading
- if data[0] == '-' {
- i := skipChar(data, 1, '-')
- i = skipChar(data, i, ' ')
- if i < len(data) && data[i] == '\n' {
- return 2
- }
- return 0
- }
-
- return 0
-}
-
-func (p *Markdown) titleBlock(data []byte, doRender bool) int {
- if data[0] != '%' {
- return 0
- }
- splitData := bytes.Split(data, []byte("\n"))
- var i int
- for idx, b := range splitData {
- if !bytes.HasPrefix(b, []byte("%")) {
- i = idx // - 1
- break
- }
- }
-
- data = bytes.Join(splitData[0:i], []byte("\n"))
- consumed := len(data)
- data = bytes.TrimPrefix(data, []byte("% "))
- data = bytes.Replace(data, []byte("\n% "), []byte("\n"), -1)
- block := p.addBlock(Heading, data)
- block.Level = 1
- block.IsTitleblock = true
-
- return consumed
-}
-
-func (p *Markdown) html(data []byte, doRender bool) int {
- var i, j int
-
- // identify the opening tag
- if data[0] != '<' {
- return 0
- }
- curtag, tagfound := p.htmlFindTag(data[1:])
-
- // handle special cases
- if !tagfound {
- // check for an HTML comment
- if size := p.htmlComment(data, doRender); size > 0 {
- return size
- }
-
- // check for an tag
- if size := p.htmlHr(data, doRender); size > 0 {
- return size
- }
-
- // no special case recognized
- return 0
- }
-
- // look for an unindented matching closing tag
- // followed by a blank line
- found := false
- /*
- closetag := []byte("\n" + curtag + ">")
- j = len(curtag) + 1
- for !found {
- // scan for a closing tag at the beginning of a line
- if skip := bytes.Index(data[j:], closetag); skip >= 0 {
- j += skip + len(closetag)
- } else {
- break
- }
-
- // see if it is the only thing on the line
- if skip := p.isEmpty(data[j:]); skip > 0 {
- // see if it is followed by a blank line/eof
- j += skip
- if j >= len(data) {
- found = true
- i = j
- } else {
- if skip := p.isEmpty(data[j:]); skip > 0 {
- j += skip
- found = true
- i = j
- }
- }
- }
- }
- */
-
- // if not found, try a second pass looking for indented match
- // but not if tag is "ins" or "del" (following original Markdown.pl)
- if !found && curtag != "ins" && curtag != "del" {
- i = 1
- for i < len(data) {
- i++
- for i < len(data) && !(data[i-1] == '<' && data[i] == '/') {
- i++
- }
-
- if i+2+len(curtag) >= len(data) {
- break
- }
-
- j = p.htmlFindEnd(curtag, data[i-1:])
-
- if j > 0 {
- i += j - 1
- found = true
- break
- }
- }
- }
-
- if !found {
- return 0
- }
-
- // the end of the block has been found
- if doRender {
- // trim newlines
- end := i
- for end > 0 && data[end-1] == '\n' {
- end--
- }
- finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end]))
- }
-
- return i
-}
-
-func finalizeHTMLBlock(block *Node) {
- block.Literal = block.content
- block.content = nil
-}
-
-// HTML comment, lax form
-func (p *Markdown) htmlComment(data []byte, doRender bool) int {
- i := p.inlineHTMLComment(data)
- // needs to end with a blank line
- if j := p.isEmpty(data[i:]); j > 0 {
- size := i + j
- if doRender {
- // trim trailing newlines
- end := size
- for end > 0 && data[end-1] == '\n' {
- end--
- }
- block := p.addBlock(HTMLBlock, data[:end])
- finalizeHTMLBlock(block)
- }
- return size
- }
- return 0
-}
-
-// HR, which is the only self-closing block tag considered
-func (p *Markdown) htmlHr(data []byte, doRender bool) int {
- if len(data) < 4 {
- return 0
- }
- if data[0] != '<' || (data[1] != 'h' && data[1] != 'H') || (data[2] != 'r' && data[2] != 'R') {
- return 0
- }
- if data[3] != ' ' && data[3] != '/' && data[3] != '>' {
- // not an tag after all; at least not a valid one
- return 0
- }
- i := 3
- for i < len(data) && data[i] != '>' && data[i] != '\n' {
- i++
- }
- if i < len(data) && data[i] == '>' {
- i++
- if j := p.isEmpty(data[i:]); j > 0 {
- size := i + j
- if doRender {
- // trim newlines
- end := size
- for end > 0 && data[end-1] == '\n' {
- end--
- }
- finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end]))
- }
- return size
- }
- }
- return 0
-}
-
-func (p *Markdown) htmlFindTag(data []byte) (string, bool) {
- i := 0
- for i < len(data) && isalnum(data[i]) {
- i++
- }
- key := string(data[:i])
- if _, ok := blockTags[key]; ok {
- return key, true
- }
- return "", false
-}
-
-func (p *Markdown) htmlFindEnd(tag string, data []byte) int {
- // assume data[0] == '<' && data[1] == '/' already tested
- if tag == "hr" {
- return 2
- }
- // check if tag is a match
- closetag := []byte("" + tag + ">")
- if !bytes.HasPrefix(data, closetag) {
- return 0
- }
- i := len(closetag)
-
- // check that the rest of the line is blank
- skip := 0
- if skip = p.isEmpty(data[i:]); skip == 0 {
- return 0
- }
- i += skip
- skip = 0
-
- if i >= len(data) {
- return i
- }
-
- if p.extensions&LaxHTMLBlocks != 0 {
- return i
- }
- if skip = p.isEmpty(data[i:]); skip == 0 {
- // following line must be blank
- return 0
- }
-
- return i + skip
-}
-
-func (*Markdown) isEmpty(data []byte) int {
- // it is okay to call isEmpty on an empty buffer
- if len(data) == 0 {
- return 0
- }
-
- var i int
- for i = 0; i < len(data) && data[i] != '\n'; i++ {
- if data[i] != ' ' && data[i] != '\t' {
- return 0
- }
- }
- if i < len(data) && data[i] == '\n' {
- i++
- }
- return i
-}
-
-func (*Markdown) isHRule(data []byte) bool {
- i := 0
-
- // skip up to three spaces
- for i < 3 && data[i] == ' ' {
- i++
- }
-
- // look at the hrule char
- if data[i] != '*' && data[i] != '-' && data[i] != '_' {
- return false
- }
- c := data[i]
-
- // the whole line must be the char or whitespace
- n := 0
- for i < len(data) && data[i] != '\n' {
- switch {
- case data[i] == c:
- n++
- case data[i] != ' ':
- return false
- }
- i++
- }
-
- return n >= 3
-}
-
-// isFenceLine checks if there's a fence line (e.g., ``` or ``` go) at the beginning of data,
-// and returns the end index if so, or 0 otherwise. It also returns the marker found.
-// If info is not nil, it gets set to the syntax specified in the fence line.
-func isFenceLine(data []byte, info *string, oldmarker string) (end int, marker string) {
- i, size := 0, 0
-
- // skip up to three spaces
- for i < len(data) && i < 3 && data[i] == ' ' {
- i++
- }
-
- // check for the marker characters: ~ or `
- if i >= len(data) {
- return 0, ""
- }
- if data[i] != '~' && data[i] != '`' {
- return 0, ""
- }
-
- c := data[i]
-
- // the whole line must be the same char or whitespace
- for i < len(data) && data[i] == c {
- size++
- i++
- }
-
- // the marker char must occur at least 3 times
- if size < 3 {
- return 0, ""
- }
- marker = string(data[i-size : i])
-
- // if this is the end marker, it must match the beginning marker
- if oldmarker != "" && marker != oldmarker {
- return 0, ""
- }
-
- // TODO(shurcooL): It's probably a good idea to simplify the 2 code paths here
- // into one, always get the info string, and discard it if the caller doesn't care.
- if info != nil {
- infoLength := 0
- i = skipChar(data, i, ' ')
-
- if i >= len(data) {
- if i == len(data) {
- return i, marker
- }
- return 0, ""
- }
-
- infoStart := i
-
- if data[i] == '{' {
- i++
- infoStart++
-
- for i < len(data) && data[i] != '}' && data[i] != '\n' {
- infoLength++
- i++
- }
-
- if i >= len(data) || data[i] != '}' {
- return 0, ""
- }
-
- // strip all whitespace at the beginning and the end
- // of the {} block
- for infoLength > 0 && isspace(data[infoStart]) {
- infoStart++
- infoLength--
- }
-
- for infoLength > 0 && isspace(data[infoStart+infoLength-1]) {
- infoLength--
- }
- i++
- i = skipChar(data, i, ' ')
- } else {
- for i < len(data) && !isverticalspace(data[i]) {
- infoLength++
- i++
- }
- }
-
- *info = strings.TrimSpace(string(data[infoStart : infoStart+infoLength]))
- }
-
- if i == len(data) {
- return i, marker
- }
- if i > len(data) || data[i] != '\n' {
- return 0, ""
- }
- return i + 1, marker // Take newline into account.
-}
-
-// fencedCodeBlock returns the end index if data contains a fenced code block at the beginning,
-// or 0 otherwise. It writes to out if doRender is true, otherwise it has no side effects.
-// If doRender is true, a final newline is mandatory to recognize the fenced code block.
-func (p *Markdown) fencedCodeBlock(data []byte, doRender bool) int {
- var info string
- beg, marker := isFenceLine(data, &info, "")
- if beg == 0 || beg >= len(data) {
- return 0
- }
- fenceLength := beg - 1
-
- var work bytes.Buffer
- work.Write([]byte(info))
- work.WriteByte('\n')
-
- for {
- // safe to assume beg < len(data)
-
- // check for the end of the code block
- fenceEnd, _ := isFenceLine(data[beg:], nil, marker)
- if fenceEnd != 0 {
- beg += fenceEnd
- break
- }
-
- // copy the current line
- end := skipUntilChar(data, beg, '\n') + 1
-
- // did we reach the end of the buffer without a closing marker?
- if end >= len(data) {
- return 0
- }
-
- // verbatim copy to the working buffer
- if doRender {
- work.Write(data[beg:end])
- }
- beg = end
- }
-
- if doRender {
- block := p.addBlock(CodeBlock, work.Bytes()) // TODO: get rid of temp buffer
- block.IsFenced = true
- block.FenceLength = fenceLength
- finalizeCodeBlock(block)
- }
-
- return beg
-}
-
-func unescapeChar(str []byte) []byte {
- if str[0] == '\\' {
- return []byte{str[1]}
- }
- return []byte(html.UnescapeString(string(str)))
-}
-
-func unescapeString(str []byte) []byte {
- if reBackslashOrAmp.Match(str) {
- return reEntityOrEscapedChar.ReplaceAllFunc(str, unescapeChar)
- }
- return str
-}
-
-func finalizeCodeBlock(block *Node) {
- if block.IsFenced {
- newlinePos := bytes.IndexByte(block.content, '\n')
- firstLine := block.content[:newlinePos]
- rest := block.content[newlinePos+1:]
- block.Info = unescapeString(bytes.Trim(firstLine, "\n"))
- block.Literal = rest
- } else {
- block.Literal = block.content
- }
- block.content = nil
-}
-
-func (p *Markdown) table(data []byte) int {
- table := p.addBlock(Table, nil)
- i, columns := p.tableHeader(data)
- if i == 0 {
- p.tip = table.Parent
- table.Unlink()
- return 0
- }
-
- p.addBlock(TableBody, nil)
-
- for i < len(data) {
- pipes, rowStart := 0, i
- for ; i < len(data) && data[i] != '\n'; i++ {
- if data[i] == '|' {
- pipes++
- }
- }
-
- if pipes == 0 {
- i = rowStart
- break
- }
-
- // include the newline in data sent to tableRow
- if i < len(data) && data[i] == '\n' {
- i++
- }
- p.tableRow(data[rowStart:i], columns, false)
- }
-
- return i
-}
-
-// check if the specified position is preceded by an odd number of backslashes
-func isBackslashEscaped(data []byte, i int) bool {
- backslashes := 0
- for i-backslashes-1 >= 0 && data[i-backslashes-1] == '\\' {
- backslashes++
- }
- return backslashes&1 == 1
-}
-
-func (p *Markdown) tableHeader(data []byte) (size int, columns []CellAlignFlags) {
- i := 0
- colCount := 1
- for i = 0; i < len(data) && data[i] != '\n'; i++ {
- if data[i] == '|' && !isBackslashEscaped(data, i) {
- colCount++
- }
- }
-
- // doesn't look like a table header
- if colCount == 1 {
- return
- }
-
- // include the newline in the data sent to tableRow
- j := i
- if j < len(data) && data[j] == '\n' {
- j++
- }
- header := data[:j]
-
- // column count ignores pipes at beginning or end of line
- if data[0] == '|' {
- colCount--
- }
- if i > 2 && data[i-1] == '|' && !isBackslashEscaped(data, i-1) {
- colCount--
- }
-
- columns = make([]CellAlignFlags, colCount)
-
- // move on to the header underline
- i++
- if i >= len(data) {
- return
- }
-
- if data[i] == '|' && !isBackslashEscaped(data, i) {
- i++
- }
- i = skipChar(data, i, ' ')
-
- // each column header is of form: / *:?-+:? *|/ with # dashes + # colons >= 3
- // and trailing | optional on last column
- col := 0
- for i < len(data) && data[i] != '\n' {
- dashes := 0
-
- if data[i] == ':' {
- i++
- columns[col] |= TableAlignmentLeft
- dashes++
- }
- for i < len(data) && data[i] == '-' {
- i++
- dashes++
- }
- if i < len(data) && data[i] == ':' {
- i++
- columns[col] |= TableAlignmentRight
- dashes++
- }
- for i < len(data) && data[i] == ' ' {
- i++
- }
- if i == len(data) {
- return
- }
- // end of column test is messy
- switch {
- case dashes < 3:
- // not a valid column
- return
-
- case data[i] == '|' && !isBackslashEscaped(data, i):
- // marker found, now skip past trailing whitespace
- col++
- i++
- for i < len(data) && data[i] == ' ' {
- i++
- }
-
- // trailing junk found after last column
- if col >= colCount && i < len(data) && data[i] != '\n' {
- return
- }
-
- case (data[i] != '|' || isBackslashEscaped(data, i)) && col+1 < colCount:
- // something else found where marker was required
- return
-
- case data[i] == '\n':
- // marker is optional for the last column
- col++
-
- default:
- // trailing junk found after last column
- return
- }
- }
- if col != colCount {
- return
- }
-
- p.addBlock(TableHead, nil)
- p.tableRow(header, columns, true)
- size = i
- if size < len(data) && data[size] == '\n' {
- size++
- }
- return
-}
-
-func (p *Markdown) tableRow(data []byte, columns []CellAlignFlags, header bool) {
- p.addBlock(TableRow, nil)
- i, col := 0, 0
-
- if data[i] == '|' && !isBackslashEscaped(data, i) {
- i++
- }
-
- for col = 0; col < len(columns) && i < len(data); col++ {
- for i < len(data) && data[i] == ' ' {
- i++
- }
-
- cellStart := i
-
- for i < len(data) && (data[i] != '|' || isBackslashEscaped(data, i)) && data[i] != '\n' {
- i++
- }
-
- cellEnd := i
-
- // skip the end-of-cell marker, possibly taking us past end of buffer
- i++
-
- for cellEnd > cellStart && cellEnd-1 < len(data) && data[cellEnd-1] == ' ' {
- cellEnd--
- }
-
- cell := p.addBlock(TableCell, data[cellStart:cellEnd])
- cell.IsHeader = header
- cell.Align = columns[col]
- }
-
- // pad it out with empty columns to get the right number
- for ; col < len(columns); col++ {
- cell := p.addBlock(TableCell, nil)
- cell.IsHeader = header
- cell.Align = columns[col]
- }
-
- // silently ignore rows with too many cells
-}
-
-// returns blockquote prefix length
-func (p *Markdown) quotePrefix(data []byte) int {
- i := 0
- for i < 3 && i < len(data) && data[i] == ' ' {
- i++
- }
- if i < len(data) && data[i] == '>' {
- if i+1 < len(data) && data[i+1] == ' ' {
- return i + 2
- }
- return i + 1
- }
- return 0
-}
-
-// blockquote ends with at least one blank line
-// followed by something without a blockquote prefix
-func (p *Markdown) terminateBlockquote(data []byte, beg, end int) bool {
- if p.isEmpty(data[beg:]) <= 0 {
- return false
- }
- if end >= len(data) {
- return true
- }
- return p.quotePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0
-}
-
-// parse a blockquote fragment
-func (p *Markdown) quote(data []byte) int {
- block := p.addBlock(BlockQuote, nil)
- var raw bytes.Buffer
- beg, end := 0, 0
- for beg < len(data) {
- end = beg
- // Step over whole lines, collecting them. While doing that, check for
- // fenced code and if one's found, incorporate it altogether,
- // irregardless of any contents inside it
- for end < len(data) && data[end] != '\n' {
- if p.extensions&FencedCode != 0 {
- if i := p.fencedCodeBlock(data[end:], false); i > 0 {
- // -1 to compensate for the extra end++ after the loop:
- end += i - 1
- break
- }
- }
- end++
- }
- if end < len(data) && data[end] == '\n' {
- end++
- }
- if pre := p.quotePrefix(data[beg:]); pre > 0 {
- // skip the prefix
- beg += pre
- } else if p.terminateBlockquote(data, beg, end) {
- break
- }
- // this line is part of the blockquote
- raw.Write(data[beg:end])
- beg = end
- }
- p.block(raw.Bytes())
- p.finalize(block)
- return end
-}
-
-// returns prefix length for block code
-func (p *Markdown) codePrefix(data []byte) int {
- if len(data) >= 1 && data[0] == '\t' {
- return 1
- }
- if len(data) >= 4 && data[0] == ' ' && data[1] == ' ' && data[2] == ' ' && data[3] == ' ' {
- return 4
- }
- return 0
-}
-
-func (p *Markdown) code(data []byte) int {
- var work bytes.Buffer
-
- i := 0
- for i < len(data) {
- beg := i
- for i < len(data) && data[i] != '\n' {
- i++
- }
- if i < len(data) && data[i] == '\n' {
- i++
- }
-
- blankline := p.isEmpty(data[beg:i]) > 0
- if pre := p.codePrefix(data[beg:i]); pre > 0 {
- beg += pre
- } else if !blankline {
- // non-empty, non-prefixed line breaks the pre
- i = beg
- break
- }
-
- // verbatim copy to the working buffer
- if blankline {
- work.WriteByte('\n')
- } else {
- work.Write(data[beg:i])
- }
- }
-
- // trim all the \n off the end of work
- workbytes := work.Bytes()
- eol := len(workbytes)
- for eol > 0 && workbytes[eol-1] == '\n' {
- eol--
- }
- if eol != len(workbytes) {
- work.Truncate(eol)
- }
-
- work.WriteByte('\n')
-
- block := p.addBlock(CodeBlock, work.Bytes()) // TODO: get rid of temp buffer
- block.IsFenced = false
- finalizeCodeBlock(block)
-
- return i
-}
-
-// returns unordered list item prefix
-func (p *Markdown) uliPrefix(data []byte) int {
- i := 0
- // start with up to 3 spaces
- for i < len(data) && i < 3 && data[i] == ' ' {
- i++
- }
- if i >= len(data)-1 {
- return 0
- }
- // need one of {'*', '+', '-'} followed by a space or a tab
- if (data[i] != '*' && data[i] != '+' && data[i] != '-') ||
- (data[i+1] != ' ' && data[i+1] != '\t') {
- return 0
- }
- return i + 2
-}
-
-// returns ordered list item prefix
-func (p *Markdown) oliPrefix(data []byte) int {
- i := 0
-
- // start with up to 3 spaces
- for i < 3 && i < len(data) && data[i] == ' ' {
- i++
- }
-
- // count the digits
- start := i
- for i < len(data) && data[i] >= '0' && data[i] <= '9' {
- i++
- }
- if start == i || i >= len(data)-1 {
- return 0
- }
-
- // we need >= 1 digits followed by a dot and a space or a tab
- if data[i] != '.' || !(data[i+1] == ' ' || data[i+1] == '\t') {
- return 0
- }
- return i + 2
-}
-
-// returns definition list item prefix
-func (p *Markdown) dliPrefix(data []byte) int {
- if len(data) < 2 {
- return 0
- }
- i := 0
- // need a ':' followed by a space or a tab
- if data[i] != ':' || !(data[i+1] == ' ' || data[i+1] == '\t') {
- return 0
- }
- for i < len(data) && data[i] == ' ' {
- i++
- }
- return i + 2
-}
-
-// parse ordered or unordered list block
-func (p *Markdown) list(data []byte, flags ListType) int {
- i := 0
- flags |= ListItemBeginningOfList
- block := p.addBlock(List, nil)
- block.ListFlags = flags
- block.Tight = true
-
- for i < len(data) {
- skip := p.listItem(data[i:], &flags)
- if flags&ListItemContainsBlock != 0 {
- block.ListData.Tight = false
- }
- i += skip
- if skip == 0 || flags&ListItemEndOfList != 0 {
- break
- }
- flags &= ^ListItemBeginningOfList
- }
-
- above := block.Parent
- finalizeList(block)
- p.tip = above
- return i
-}
-
-// Returns true if the list item is not the same type as its parent list
-func (p *Markdown) listTypeChanged(data []byte, flags *ListType) bool {
- if p.dliPrefix(data) > 0 && *flags&ListTypeDefinition == 0 {
- return true
- } else if p.oliPrefix(data) > 0 && *flags&ListTypeOrdered == 0 {
- return true
- } else if p.uliPrefix(data) > 0 && (*flags&ListTypeOrdered != 0 || *flags&ListTypeDefinition != 0) {
- return true
- }
- return false
-}
-
-// Returns true if block ends with a blank line, descending if needed
-// into lists and sublists.
-func endsWithBlankLine(block *Node) bool {
- // TODO: figure this out. Always false now.
- for block != nil {
- //if block.lastLineBlank {
- //return true
- //}
- t := block.Type
- if t == List || t == Item {
- block = block.LastChild
- } else {
- break
- }
- }
- return false
-}
-
-func finalizeList(block *Node) {
- block.open = false
- item := block.FirstChild
- for item != nil {
- // check for non-final list item ending with blank line:
- if endsWithBlankLine(item) && item.Next != nil {
- block.ListData.Tight = false
- break
- }
- // recurse into children of list item, to see if there are spaces
- // between any of them:
- subItem := item.FirstChild
- for subItem != nil {
- if endsWithBlankLine(subItem) && (item.Next != nil || subItem.Next != nil) {
- block.ListData.Tight = false
- break
- }
- subItem = subItem.Next
- }
- item = item.Next
- }
-}
-
-// Parse a single list item.
-// Assumes initial prefix is already removed if this is a sublist.
-func (p *Markdown) listItem(data []byte, flags *ListType) int {
- // keep track of the indentation of the first line
- itemIndent := 0
- if data[0] == '\t' {
- itemIndent += 4
- } else {
- for itemIndent < 3 && data[itemIndent] == ' ' {
- itemIndent++
- }
- }
-
- var bulletChar byte = '*'
- i := p.uliPrefix(data)
- if i == 0 {
- i = p.oliPrefix(data)
- } else {
- bulletChar = data[i-2]
- }
- if i == 0 {
- i = p.dliPrefix(data)
- // reset definition term flag
- if i > 0 {
- *flags &= ^ListTypeTerm
- }
- }
- if i == 0 {
- // if in definition list, set term flag and continue
- if *flags&ListTypeDefinition != 0 {
- *flags |= ListTypeTerm
- } else {
- return 0
- }
- }
-
- // skip leading whitespace on first line
- for i < len(data) && data[i] == ' ' {
- i++
- }
-
- // find the end of the line
- line := i
- for i > 0 && 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[line:i])
- line = i
-
- // process the following lines
- containsBlankLine := false
- sublist := 0
- codeBlockMarker := ""
-
-gatherlines:
- for line < 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[line:i]) > 0 {
- containsBlankLine = true
- line = i
- continue
- }
-
- // calculate the indentation
- indent := 0
- indentIndex := 0
- if data[line] == '\t' {
- indentIndex++
- indent += 4
- } else {
- for indent < 4 && line+indent < i && data[line+indent] == ' ' {
- indent++
- indentIndex++
- }
- }
-
- chunk := data[line+indentIndex : i]
-
- if p.extensions&FencedCode != 0 {
- // determine if in or out of codeblock
- // if in codeblock, ignore normal list processing
- _, marker := isFenceLine(chunk, nil, codeBlockMarker)
- if marker != "" {
- if codeBlockMarker == "" {
- // start of codeblock
- codeBlockMarker = marker
- } else {
- // end of codeblock.
- codeBlockMarker = ""
- }
- }
- // we are in a codeblock, write line, and continue
- if codeBlockMarker != "" || marker != "" {
- raw.Write(data[line+indentIndex : i])
- line = i
- continue gatherlines
- }
- }
-
- // evaluate how this line fits in
- switch {
- // is this a nested list item?
- case (p.uliPrefix(chunk) > 0 && !p.isHRule(chunk)) ||
- p.oliPrefix(chunk) > 0 ||
- p.dliPrefix(chunk) > 0:
-
- // to be a nested list, it must be indented more
- // if not, it is either a different kind of list
- // or the next item in the same list
- if indent <= itemIndent {
- if p.listTypeChanged(chunk, flags) {
- *flags |= ListItemEndOfList
- } else if containsBlankLine {
- *flags |= ListItemContainsBlock
- }
-
- break gatherlines
- }
-
- if containsBlankLine {
- *flags |= ListItemContainsBlock
- }
-
- // is this the first item in the nested list?
- if sublist == 0 {
- sublist = raw.Len()
- }
-
- // is this a nested prefix heading?
- case p.isPrefixHeading(chunk):
- // if the heading is not indented, it is not nested in the list
- // and thus ends the list
- if containsBlankLine && indent < 4 {
- *flags |= ListItemEndOfList
- break gatherlines
- }
- *flags |= ListItemContainsBlock
-
- // anything following an empty line is only part
- // of this item if it is indented 4 spaces
- // (regardless of the indentation of the beginning of the item)
- case containsBlankLine && indent < 4:
- if *flags&ListTypeDefinition != 0 && i < len(data)-1 {
- // is the next item still a part of this list?
- next := i
- for next < len(data) && data[next] != '\n' {
- next++
- }
- for next < len(data)-1 && data[next] == '\n' {
- next++
- }
- if i < len(data)-1 && data[i] != ':' && data[next] != ':' {
- *flags |= ListItemEndOfList
- }
- } else {
- *flags |= ListItemEndOfList
- }
- break gatherlines
-
- // a blank line means this should be parsed as a block
- case containsBlankLine:
- raw.WriteByte('\n')
- *flags |= ListItemContainsBlock
- }
-
- // if this line was preceded by one or more blanks,
- // re-introduce the blank into the buffer
- if containsBlankLine {
- containsBlankLine = false
- raw.WriteByte('\n')
- }
-
- // add the line into the working buffer without prefix
- raw.Write(data[line+indentIndex : i])
-
- line = i
- }
-
- rawBytes := raw.Bytes()
-
- block := p.addBlock(Item, nil)
- block.ListFlags = *flags
- block.Tight = false
- block.BulletChar = bulletChar
- block.Delimiter = '.' // Only '.' is possible in Markdown, but ')' will also be possible in CommonMark
-
- // render the contents of the list item
- if *flags&ListItemContainsBlock != 0 && *flags&ListTypeTerm == 0 {
- // intermediate render of block item, except for definition term
- if sublist > 0 {
- p.block(rawBytes[:sublist])
- p.block(rawBytes[sublist:])
- } else {
- p.block(rawBytes)
- }
- } else {
- // intermediate render of inline item
- if sublist > 0 {
- child := p.addChild(Paragraph, 0)
- child.content = rawBytes[:sublist]
- p.block(rawBytes[sublist:])
- } else {
- child := p.addChild(Paragraph, 0)
- child.content = rawBytes
- }
- }
- return line
-}
-
-// render a single paragraph that has already been parsed out
-func (p *Markdown) renderParagraph(data []byte) {
- if len(data) == 0 {
- return
- }
-
- // trim leading spaces
- beg := 0
- for data[beg] == ' ' {
- beg++
- }
-
- end := len(data)
- // trim trailing newline
- if data[len(data)-1] == '\n' {
- end--
- }
-
- // trim trailing spaces
- for end > beg && data[end-1] == ' ' {
- end--
- }
-
- p.addBlock(Paragraph, data[beg:end])
-}
-
-func (p *Markdown) paragraph(data []byte) int {
- // prev: index of 1st char of previous line
- // line: index of 1st char of current line
- // i: index of cursor/end of current line
- var prev, line, i int
- tabSize := TabSizeDefault
- if p.extensions&TabSizeEight != 0 {
- tabSize = TabSizeDouble
- }
- // keep going until we find something to mark the end of the paragraph
- for i < len(data) {
- // mark the beginning of the current line
- prev = line
- current := data[i:]
- line = i
-
- // did we find a reference or a footnote? If so, end a paragraph
- // preceding it and report that we have consumed up to the end of that
- // reference:
- if refEnd := isReference(p, current, tabSize); refEnd > 0 {
- p.renderParagraph(data[:i])
- return i + refEnd
- }
-
- // did we find a blank line marking the end of the paragraph?
- if n := p.isEmpty(current); n > 0 {
- // did this blank line followed by a definition list item?
- if p.extensions&DefinitionLists != 0 {
- if i < len(data)-1 && data[i+1] == ':' {
- return p.list(data[prev:], ListTypeDefinition)
- }
- }
-
- p.renderParagraph(data[:i])
- return i + n
- }
-
- // an underline under some text marks a heading, so our paragraph ended on prev line
- if i > 0 {
- if level := p.isUnderlinedHeading(current); level > 0 {
- // render the paragraph
- p.renderParagraph(data[:prev])
-
- // ignore leading and trailing whitespace
- eol := i - 1
- for prev < eol && data[prev] == ' ' {
- prev++
- }
- for eol > prev && data[eol-1] == ' ' {
- eol--
- }
-
- id := ""
- if p.extensions&AutoHeadingIDs != 0 {
- id = SanitizedAnchorName(string(data[prev:eol]))
- }
-
- block := p.addBlock(Heading, data[prev:eol])
- block.Level = level
- block.HeadingID = id
-
- // find the end of the underline
- for i < len(data) && data[i] != '\n' {
- i++
- }
- return i
- }
- }
-
- // if the next line starts a block of HTML, then the paragraph ends here
- if p.extensions&LaxHTMLBlocks != 0 {
- if data[i] == '<' && p.html(current, false) > 0 {
- // rewind to before the HTML block
- p.renderParagraph(data[:i])
- return i
- }
- }
-
- // if there's a prefixed heading or a horizontal rule after this, paragraph is over
- if p.isPrefixHeading(current) || p.isHRule(current) {
- p.renderParagraph(data[:i])
- return i
- }
-
- // if there's a fenced code block, paragraph is over
- if p.extensions&FencedCode != 0 {
- if p.fencedCodeBlock(current, false) > 0 {
- p.renderParagraph(data[:i])
- return i
- }
- }
-
- // if there's a definition list item, prev line is a definition term
- if p.extensions&DefinitionLists != 0 {
- if p.dliPrefix(current) != 0 {
- ret := p.list(data[prev:], ListTypeDefinition)
- return ret
- }
- }
-
- // if there's a list after this, paragraph is over
- if p.extensions&NoEmptyLineBeforeBlock != 0 {
- if p.uliPrefix(current) != 0 ||
- p.oliPrefix(current) != 0 ||
- p.quotePrefix(current) != 0 ||
- p.codePrefix(current) != 0 {
- p.renderParagraph(data[:i])
- return i
- }
- }
-
- // otherwise, scan to the beginning of the next line
- nl := bytes.IndexByte(data[i:], '\n')
- if nl >= 0 {
- i += nl + 1
- } else {
- i += len(data[i:])
- }
- }
-
- p.renderParagraph(data[: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 skipUntilChar(text []byte, start int, char byte) int {
- i := start
- for i < len(text) && text[i] != char {
- i++
- }
- return i
-}
-
-// SanitizedAnchorName returns a sanitized anchor name for the given text.
-//
-// It implements the algorithm specified in the package comment.
-func SanitizedAnchorName(text string) string {
- var anchorName []rune
- futureDash := false
- for _, r := range 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)
-}
diff --git a/vendor/github.com/russross/blackfriday/v2/doc.go b/vendor/github.com/russross/blackfriday/v2/doc.go
deleted file mode 100644
index 57ff152..0000000
--- a/vendor/github.com/russross/blackfriday/v2/doc.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// Package blackfriday is a markdown processor.
-//
-// It translates plain text with simple formatting rules into an AST, which can
-// then be further processed to HTML (provided by Blackfriday itself) or other
-// formats (provided by the community).
-//
-// The simplest way to invoke Blackfriday is to call the Run function. It will
-// take a text input and produce a text output in HTML (or other format).
-//
-// A slightly more sophisticated way to use Blackfriday is to create a Markdown
-// processor and to call Parse, which returns a syntax tree for the input
-// document. You can leverage Blackfriday's parsing for content extraction from
-// markdown documents. You can assign a custom renderer and set various options
-// to the Markdown processor.
-//
-// If you're interested in calling Blackfriday from command line, see
-// https://github.com/russross/blackfriday-tool.
-//
-// Sanitized Anchor Names
-//
-// Blackfriday includes an algorithm for creating sanitized anchor names
-// corresponding to a given input text. This algorithm is used to create
-// anchors for headings when AutoHeadingIDs extension is enabled. The
-// algorithm is specified below, so that other packages can create
-// compatible anchor names and links to those anchors.
-//
-// The algorithm iterates over the input text, interpreted as UTF-8,
-// one Unicode code point (rune) at a time. All runes that are letters (category L)
-// or numbers (category N) are considered valid characters. They are mapped to
-// lower case, and included in the output. All other runes are considered
-// invalid characters. Invalid characters that precede the first valid character,
-// as well as invalid character that follow the last valid character
-// are dropped completely. All other sequences of invalid characters
-// between two valid characters are replaced with a single dash character '-'.
-//
-// SanitizedAnchorName exposes this functionality, and can be used to
-// create compatible links to the anchor names generated by blackfriday.
-// This algorithm is also implemented in a small standalone package at
-// github.com/shurcooL/sanitized_anchor_name. It can be useful for clients
-// that want a small package and don't need full functionality of blackfriday.
-package blackfriday
-
-// NOTE: Keep Sanitized Anchor Name algorithm in sync with package
-// github.com/shurcooL/sanitized_anchor_name.
-// Otherwise, users of sanitized_anchor_name will get anchor names
-// that are incompatible with those generated by blackfriday.
diff --git a/vendor/github.com/russross/blackfriday/v2/entities.go b/vendor/github.com/russross/blackfriday/v2/entities.go
deleted file mode 100644
index a2c3edb..0000000
--- a/vendor/github.com/russross/blackfriday/v2/entities.go
+++ /dev/null
@@ -1,2236 +0,0 @@
-package blackfriday
-
-// Extracted from https://html.spec.whatwg.org/multipage/entities.json
-var entities = map[string]bool{
- "Æ": true,
- "Æ": true,
- "&": true,
- "&": true,
- "Á": true,
- "Á": true,
- "Ă": true,
- "Â": true,
- "Â": true,
- "А": true,
- "𝔄": true,
- "À": true,
- "À": true,
- "Α": true,
- "Ā": true,
- "⩓": true,
- "Ą": true,
- "𝔸": true,
- "⁡": true,
- "Å": true,
- "Å": true,
- "𝒜": true,
- "≔": true,
- "Ã": true,
- "Ã": true,
- "Ä": true,
- "Ä": true,
- "∖": true,
- "⫧": true,
- "⌆": true,
- "Б": true,
- "∵": true,
- "ℬ": true,
- "Β": true,
- "𝔅": true,
- "𝔹": true,
- "˘": true,
- "ℬ": true,
- "≎": true,
- "Ч": true,
- "©": true,
- "©": true,
- "Ć": true,
- "⋒": true,
- "ⅅ": true,
- "ℭ": true,
- "Č": true,
- "Ç": true,
- "Ç": true,
- "Ĉ": true,
- "∰": true,
- "Ċ": true,
- "¸": true,
- "·": true,
- "ℭ": true,
- "Χ": true,
- "⊙": true,
- "⊖": true,
- "⊕": true,
- "⊗": true,
- "∲": true,
- "”": true,
- "’": true,
- "∷": true,
- "⩴": true,
- "≡": true,
- "∯": true,
- "∮": true,
- "ℂ": true,
- "∐": true,
- "∳": true,
- "⨯": true,
- "𝒞": true,
- "⋓": true,
- "≍": true,
- "ⅅ": true,
- "⤑": true,
- "Ђ": true,
- "Ѕ": true,
- "Џ": true,
- "‡": true,
- "↡": true,
- "⫤": true,
- "Ď": true,
- "Д": true,
- "∇": true,
- "Δ": true,
- "𝔇": true,
- "´": true,
- "˙": true,
- "˝": true,
- "`": true,
- "˜": true,
- "⋄": true,
- "ⅆ": true,
- "𝔻": true,
- "¨": true,
- "⃜": true,
- "≐": true,
- "∯": true,
- "¨": true,
- "⇓": true,
- "⇐": true,
- "⇔": true,
- "⫤": true,
- "⟸": true,
- "⟺": true,
- "⟹": true,
- "⇒": true,
- "⊨": true,
- "⇑": true,
- "⇕": true,
- "∥": true,
- "↓": true,
- "⤓": true,
- "⇵": true,
- "̑": true,
- "⥐": true,
- "⥞": true,
- "↽": true,
- "⥖": true,
- "⥟": true,
- "⇁": true,
- "⥗": true,
- "⊤": true,
- "↧": true,
- "⇓": true,
- "𝒟": true,
- "Đ": true,
- "Ŋ": true,
- "Ð": true,
- "Ð": true,
- "É": true,
- "É": true,
- "Ě": true,
- "Ê": true,
- "Ê": true,
- "Э": true,
- "Ė": true,
- "𝔈": true,
- "È": true,
- "È": true,
- "∈": true,
- "Ē": true,
- "◻": true,
- "▫": true,
- "Ę": true,
- "𝔼": true,
- "Ε": true,
- "⩵": true,
- "≂": true,
- "⇌": true,
- "ℰ": true,
- "⩳": true,
- "Η": true,
- "Ë": true,
- "Ë": true,
- "∃": true,
- "ⅇ": true,
- "Ф": true,
- "𝔉": true,
- "◼": true,
- "▪": true,
- "𝔽": true,
- "∀": true,
- "ℱ": true,
- "ℱ": true,
- "Ѓ": true,
- ">": true,
- ">": true,
- "Γ": true,
- "Ϝ": true,
- "Ğ": true,
- "Ģ": true,
- "Ĝ": true,
- "Г": true,
- "Ġ": true,
- "𝔊": true,
- "⋙": true,
- "𝔾": true,
- "≥": true,
- "⋛": true,
- "≧": true,
- "⪢": true,
- "≷": true,
- "⩾": true,
- "≳": true,
- "𝒢": true,
- "≫": true,
- "Ъ": true,
- "ˇ": true,
- "^": true,
- "Ĥ": true,
- "ℌ": true,
- "ℋ": true,
- "ℍ": true,
- "─": true,
- "ℋ": true,
- "Ħ": true,
- "≎": true,
- "≏": true,
- "Е": true,
- "IJ": true,
- "Ё": true,
- "Í": true,
- "Í": true,
- "Î": true,
- "Î": true,
- "И": true,
- "İ": true,
- "ℑ": true,
- "Ì": true,
- "Ì": true,
- "ℑ": true,
- "Ī": true,
- "ⅈ": true,
- "⇒": true,
- "∬": true,
- "∫": true,
- "⋂": true,
- "⁣": true,
- "⁢": true,
- "Į": true,
- "𝕀": true,
- "Ι": true,
- "ℐ": true,
- "Ĩ": true,
- "І": true,
- "Ï": true,
- "Ï": true,
- "Ĵ": true,
- "Й": true,
- "𝔍": true,
- "𝕁": true,
- "𝒥": true,
- "Ј": true,
- "Є": true,
- "Х": true,
- "Ќ": true,
- "Κ": true,
- "Ķ": true,
- "К": true,
- "𝔎": true,
- "𝕂": true,
- "𝒦": true,
- "Љ": true,
- "<": true,
- "<": true,
- "Ĺ": true,
- "Λ": true,
- "⟪": true,
- "ℒ": true,
- "↞": true,
- "Ľ": true,
- "Ļ": true,
- "Л": true,
- "⟨": true,
- "←": true,
- "⇤": true,
- "⇆": true,
- "⌈": true,
- "⟦": true,
- "⥡": true,
- "⇃": true,
- "⥙": true,
- "⌊": true,
- "↔": true,
- "⥎": true,
- "⊣": true,
- "↤": true,
- "⥚": true,
- "⊲": true,
- "⧏": true,
- "⊴": true,
- "⥑": true,
- "⥠": true,
- "↿": true,
- "⥘": true,
- "↼": true,
- "⥒": true,
- "⇐": true,
- "⇔": true,
- "⋚": true,
- "≦": true,
- "≶": true,
- "⪡": true,
- "⩽": true,
- "≲": true,
- "𝔏": true,
- "⋘": true,
- "⇚": true,
- "Ŀ": true,
- "⟵": true,
- "⟷": true,
- "⟶": true,
- "⟸": true,
- "⟺": true,
- "⟹": true,
- "𝕃": true,
- "↙": true,
- "↘": true,
- "ℒ": true,
- "↰": true,
- "Ł": true,
- "≪": true,
- "⤅": true,
- "М": true,
- " ": true,
- "ℳ": true,
- "𝔐": true,
- "∓": true,
- "𝕄": true,
- "ℳ": true,
- "Μ": true,
- "Њ": true,
- "Ń": true,
- "Ň": true,
- "Ņ": true,
- "Н": true,
- "​": true,
- "​": true,
- "​": true,
- "​": true,
- "≫": true,
- "≪": true,
- "
": true,
- "𝔑": true,
- "⁠": true,
- " ": true,
- "ℕ": true,
- "⫬": true,
- "≢": true,
- "≭": true,
- "∦": true,
- "∉": true,
- "≠": true,
- "≂̸": true,
- "∄": true,
- "≯": true,
- "≱": true,
- "≧̸": true,
- "≫̸": true,
- "≹": true,
- "⩾̸": true,
- "≵": true,
- "≎̸": true,
- "≏̸": true,
- "⋪": true,
- "⧏̸": true,
- "⋬": true,
- "≮": true,
- "≰": true,
- "≸": true,
- "≪̸": true,
- "⩽̸": true,
- "≴": true,
- "⪢̸": true,
- "⪡̸": true,
- "⊀": true,
- "⪯̸": true,
- "⋠": true,
- "∌": true,
- "⋫": true,
- "⧐̸": true,
- "⋭": true,
- "⊏̸": true,
- "⋢": true,
- "⊐̸": true,
- "⋣": true,
- "⊂⃒": true,
- "⊈": true,
- "⊁": true,
- "⪰̸": true,
- "⋡": true,
- "≿̸": true,
- "⊃⃒": true,
- "⊉": true,
- "≁": true,
- "≄": true,
- "≇": true,
- "≉": true,
- "∤": true,
- "𝒩": true,
- "Ñ": true,
- "Ñ": true,
- "Ν": true,
- "Œ": true,
- "Ó": true,
- "Ó": true,
- "Ô": true,
- "Ô": true,
- "О": true,
- "Ő": true,
- "𝔒": true,
- "Ò": true,
- "Ò": true,
- "Ō": true,
- "Ω": true,
- "Ο": true,
- "𝕆": true,
- "“": true,
- "‘": true,
- "⩔": true,
- "𝒪": true,
- "Ø": true,
- "Ø": true,
- "Õ": true,
- "Õ": true,
- "⨷": true,
- "Ö": true,
- "Ö": true,
- "‾": true,
- "⏞": true,
- "⎴": true,
- "⏜": true,
- "∂": true,
- "П": true,
- "𝔓": true,
- "Φ": true,
- "Π": true,
- "±": true,
- "ℌ": true,
- "ℙ": true,
- "⪻": true,
- "≺": true,
- "⪯": true,
- "≼": true,
- "≾": true,
- "″": true,
- "∏": true,
- "∷": true,
- "∝": true,
- "𝒫": true,
- "Ψ": true,
- """: true,
- """: true,
- "𝔔": true,
- "ℚ": true,
- "𝒬": true,
- "⤐": true,
- "®": true,
- "®": true,
- "Ŕ": true,
- "⟫": true,
- "↠": true,
- "⤖": true,
- "Ř": true,
- "Ŗ": true,
- "Р": true,
- "ℜ": true,
- "∋": true,
- "⇋": true,
- "⥯": true,
- "ℜ": true,
- "Ρ": true,
- "⟩": true,
- "→": true,
- "⇥": true,
- "⇄": true,
- "⌉": true,
- "⟧": true,
- "⥝": true,
- "⇂": true,
- "⥕": true,
- "⌋": true,
- "⊢": true,
- "↦": true,
- "⥛": true,
- "⊳": true,
- "⧐": true,
- "⊵": true,
- "⥏": true,
- "⥜": true,
- "↾": true,
- "⥔": true,
- "⇀": true,
- "⥓": true,
- "⇒": true,
- "ℝ": true,
- "⥰": true,
- "⇛": true,
- "ℛ": true,
- "↱": true,
- "⧴": true,
- "Щ": true,
- "Ш": true,
- "Ь": true,
- "Ś": true,
- "⪼": true,
- "Š": true,
- "Ş": true,
- "Ŝ": true,
- "С": true,
- "𝔖": true,
- "↓": true,
- "←": true,
- "→": true,
- "↑": true,
- "Σ": true,
- "∘": true,
- "𝕊": true,
- "√": true,
- "□": true,
- "⊓": true,
- "⊏": true,
- "⊑": true,
- "⊐": true,
- "⊒": true,
- "⊔": true,
- "𝒮": true,
- "⋆": true,
- "⋐": true,
- "⋐": true,
- "⊆": true,
- "≻": true,
- "⪰": true,
- "≽": true,
- "≿": true,
- "∋": true,
- "∑": true,
- "⋑": true,
- "⊃": true,
- "⊇": true,
- "⋑": true,
- "Þ": true,
- "Þ": true,
- "™": true,
- "Ћ": true,
- "Ц": true,
- "	": true,
- "Τ": true,
- "Ť": true,
- "Ţ": true,
- "Т": true,
- "𝔗": true,
- "∴": true,
- "Θ": true,
- "  ": true,
- " ": true,
- "∼": true,
- "≃": true,
- "≅": true,
- "≈": true,
- "𝕋": true,
- "⃛": true,
- "𝒯": true,
- "Ŧ": true,
- "Ú": true,
- "Ú": true,
- "↟": true,
- "⥉": true,
- "Ў": true,
- "Ŭ": true,
- "Û": true,
- "Û": true,
- "У": true,
- "Ű": true,
- "𝔘": true,
- "Ù": true,
- "Ù": true,
- "Ū": true,
- "_": true,
- "⏟": true,
- "⎵": true,
- "⏝": true,
- "⋃": true,
- "⊎": true,
- "Ų": true,
- "𝕌": true,
- "↑": true,
- "⤒": true,
- "⇅": true,
- "↕": true,
- "⥮": true,
- "⊥": true,
- "↥": true,
- "⇑": true,
- "⇕": true,
- "↖": true,
- "↗": true,
- "ϒ": true,
- "Υ": true,
- "Ů": true,
- "𝒰": true,
- "Ũ": true,
- "Ü": true,
- "Ü": true,
- "⊫": true,
- "⫫": true,
- "В": true,
- "⊩": true,
- "⫦": true,
- "⋁": true,
- "‖": true,
- "‖": true,
- "∣": true,
- "|": true,
- "❘": true,
- "≀": true,
- " ": true,
- "𝔙": true,
- "𝕍": true,
- "𝒱": true,
- "⊪": true,
- "Ŵ": true,
- "⋀": true,
- "𝔚": true,
- "𝕎": true,
- "𝒲": true,
- "𝔛": true,
- "Ξ": true,
- "𝕏": true,
- "𝒳": true,
- "Я": true,
- "Ї": true,
- "Ю": true,
- "Ý": true,
- "Ý": true,
- "Ŷ": true,
- "Ы": true,
- "𝔜": true,
- "𝕐": true,
- "𝒴": true,
- "Ÿ": true,
- "Ж": true,
- "Ź": true,
- "Ž": true,
- "З": true,
- "Ż": true,
- "​": true,
- "Ζ": true,
- "ℨ": true,
- "ℤ": true,
- "𝒵": true,
- "á": true,
- "á": true,
- "ă": true,
- "∾": true,
- "∾̳": true,
- "∿": true,
- "â": true,
- "â": true,
- "´": true,
- "´": true,
- "а": true,
- "æ": true,
- "æ": true,
- "⁡": true,
- "𝔞": true,
- "à": true,
- "à": true,
- "ℵ": true,
- "ℵ": true,
- "α": true,
- "ā": true,
- "⨿": true,
- "&": true,
- "&": true,
- "∧": true,
- "⩕": true,
- "⩜": true,
- "⩘": true,
- "⩚": true,
- "∠": true,
- "⦤": true,
- "∠": true,
- "∡": true,
- "⦨": true,
- "⦩": true,
- "⦪": true,
- "⦫": true,
- "⦬": true,
- "⦭": true,
- "⦮": true,
- "⦯": true,
- "∟": true,
- "⊾": true,
- "⦝": true,
- "∢": true,
- "Å": true,
- "⍼": true,
- "ą": true,
- "𝕒": true,
- "≈": true,
- "⩰": true,
- "⩯": true,
- "≊": true,
- "≋": true,
- "'": true,
- "≈": true,
- "≊": true,
- "å": true,
- "å": true,
- "𝒶": true,
- "*": true,
- "≈": true,
- "≍": true,
- "ã": true,
- "ã": true,
- "ä": true,
- "ä": true,
- "∳": true,
- "⨑": true,
- "⫭": true,
- "≌": true,
- "϶": true,
- "‵": true,
- "∽": true,
- "⋍": true,
- "⊽": true,
- "⌅": true,
- "⌅": true,
- "⎵": true,
- "⎶": true,
- "≌": true,
- "б": true,
- "„": true,
- "∵": true,
- "∵": true,
- "⦰": true,
- "϶": true,
- "ℬ": true,
- "β": true,
- "ℶ": true,
- "≬": true,
- "𝔟": true,
- "⋂": true,
- "◯": true,
- "⋃": true,
- "⨀": true,
- "⨁": true,
- "⨂": true,
- "⨆": true,
- "★": true,
- "▽": true,
- "△": true,
- "⨄": true,
- "⋁": true,
- "⋀": true,
- "⤍": true,
- "⧫": true,
- "▪": true,
- "▴": true,
- "▾": true,
- "◂": true,
- "▸": true,
- "␣": true,
- "▒": true,
- "░": true,
- "▓": true,
- "█": true,
- "=⃥": true,
- "≡⃥": true,
- "⌐": true,
- "𝕓": true,
- "⊥": true,
- "⊥": true,
- "⋈": true,
- "╗": true,
- "╔": true,
- "╖": true,
- "╓": true,
- "═": true,
- "╦": true,
- "╩": true,
- "╤": true,
- "╧": true,
- "╝": true,
- "╚": true,
- "╜": true,
- "╙": true,
- "║": true,
- "╬": true,
- "╣": true,
- "╠": true,
- "╫": true,
- "╢": true,
- "╟": true,
- "⧉": true,
- "╕": true,
- "╒": true,
- "┐": true,
- "┌": true,
- "─": true,
- "╥": true,
- "╨": true,
- "┬": true,
- "┴": true,
- "⊟": true,
- "⊞": true,
- "⊠": true,
- "╛": true,
- "╘": true,
- "┘": true,
- "└": true,
- "│": true,
- "╪": true,
- "╡": true,
- "╞": true,
- "┼": true,
- "┤": true,
- "├": true,
- "‵": true,
- "˘": true,
- "¦": true,
- "¦": true,
- "𝒷": true,
- "⁏": true,
- "∽": true,
- "⋍": true,
- "\": true,
- "⧅": true,
- "⟈": true,
- "•": true,
- "•": true,
- "≎": true,
- "⪮": true,
- "≏": true,
- "≏": true,
- "ć": true,
- "∩": true,
- "⩄": true,
- "⩉": true,
- "⩋": true,
- "⩇": true,
- "⩀": true,
- "∩︀": true,
- "⁁": true,
- "ˇ": true,
- "⩍": true,
- "č": true,
- "ç": true,
- "ç": true,
- "ĉ": true,
- "⩌": true,
- "⩐": true,
- "ċ": true,
- "¸": true,
- "¸": true,
- "⦲": true,
- "¢": true,
- "¢": true,
- "·": true,
- "𝔠": true,
- "ч": true,
- "✓": true,
- "✓": true,
- "χ": true,
- "○": true,
- "⧃": true,
- "ˆ": true,
- "≗": true,
- "↺": true,
- "↻": true,
- "®": true,
- "Ⓢ": true,
- "⊛": true,
- "⊚": true,
- "⊝": true,
- "≗": true,
- "⨐": true,
- "⫯": true,
- "⧂": true,
- "♣": true,
- "♣": true,
- ":": true,
- "≔": true,
- "≔": true,
- ",": true,
- "@": true,
- "∁": true,
- "∘": true,
- "∁": true,
- "ℂ": true,
- "≅": true,
- "⩭": true,
- "∮": true,
- "𝕔": true,
- "∐": true,
- "©": true,
- "©": true,
- "℗": true,
- "↵": true,
- "✗": true,
- "𝒸": true,
- "⫏": true,
- "⫑": true,
- "⫐": true,
- "⫒": true,
- "⋯": true,
- "⤸": true,
- "⤵": true,
- "⋞": true,
- "⋟": true,
- "↶": true,
- "⤽": true,
- "∪": true,
- "⩈": true,
- "⩆": true,
- "⩊": true,
- "⊍": true,
- "⩅": true,
- "∪︀": true,
- "↷": true,
- "⤼": true,
- "⋞": true,
- "⋟": true,
- "⋎": true,
- "⋏": true,
- "¤": true,
- "¤": true,
- "↶": true,
- "↷": true,
- "⋎": true,
- "⋏": true,
- "∲": true,
- "∱": true,
- "⌭": true,
- "⇓": true,
- "⥥": true,
- "†": true,
- "ℸ": true,
- "↓": true,
- "‐": true,
- "⊣": true,
- "⤏": true,
- "˝": true,
- "ď": true,
- "д": true,
- "ⅆ": true,
- "‡": true,
- "⇊": true,
- "⩷": true,
- "°": true,
- "°": true,
- "δ": true,
- "⦱": true,
- "⥿": true,
- "𝔡": true,
- "⇃": true,
- "⇂": true,
- "⋄": true,
- "⋄": true,
- "♦": true,
- "♦": true,
- "¨": true,
- "ϝ": true,
- "⋲": true,
- "÷": true,
- "÷": true,
- "÷": true,
- "⋇": true,
- "⋇": true,
- "ђ": true,
- "⌞": true,
- "⌍": true,
- "$": true,
- "𝕕": true,
- "˙": true,
- "≐": true,
- "≑": true,
- "∸": true,
- "∔": true,
- "⊡": true,
- "⌆": true,
- "↓": true,
- "⇊": true,
- "⇃": true,
- "⇂": true,
- "⤐": true,
- "⌟": true,
- "⌌": true,
- "𝒹": true,
- "ѕ": true,
- "⧶": true,
- "đ": true,
- "⋱": true,
- "▿": true,
- "▾": true,
- "⇵": true,
- "⥯": true,
- "⦦": true,
- "џ": true,
- "⟿": true,
- "⩷": true,
- "≑": true,
- "é": true,
- "é": true,
- "⩮": true,
- "ě": true,
- "≖": true,
- "ê": true,
- "ê": true,
- "≕": true,
- "э": true,
- "ė": true,
- "ⅇ": true,
- "≒": true,
- "𝔢": true,
- "⪚": true,
- "è": true,
- "è": true,
- "⪖": true,
- "⪘": true,
- "⪙": true,
- "⏧": true,
- "ℓ": true,
- "⪕": true,
- "⪗": true,
- "ē": true,
- "∅": true,
- "∅": true,
- "∅": true,
- " ": true,
- " ": true,
- " ": true,
- "ŋ": true,
- " ": true,
- "ę": true,
- "𝕖": true,
- "⋕": true,
- "⧣": true,
- "⩱": true,
- "ε": true,
- "ε": true,
- "ϵ": true,
- "≖": true,
- "≕": true,
- "≂": true,
- "⪖": true,
- "⪕": true,
- "=": true,
- "≟": true,
- "≡": true,
- "⩸": true,
- "⧥": true,
- "≓": true,
- "⥱": true,
- "ℯ": true,
- "≐": true,
- "≂": true,
- "η": true,
- "ð": true,
- "ð": true,
- "ë": true,
- "ë": true,
- "€": true,
- "!": true,
- "∃": true,
- "ℰ": true,
- "ⅇ": true,
- "≒": true,
- "ф": true,
- "♀": true,
- "ffi": true,
- "ff": true,
- "ffl": true,
- "𝔣": true,
- "fi": true,
- "fj": true,
- "♭": true,
- "fl": true,
- "▱": true,
- "ƒ": true,
- "𝕗": true,
- "∀": true,
- "⋔": true,
- "⫙": true,
- "⨍": true,
- "½": true,
- "½": true,
- "⅓": true,
- "¼": true,
- "¼": true,
- "⅕": true,
- "⅙": true,
- "⅛": true,
- "⅔": true,
- "⅖": true,
- "¾": true,
- "¾": true,
- "⅗": true,
- "⅜": true,
- "⅘": true,
- "⅚": true,
- "⅝": true,
- "⅞": true,
- "⁄": true,
- "⌢": true,
- "𝒻": true,
- "≧": true,
- "⪌": true,
- "ǵ": true,
- "γ": true,
- "ϝ": true,
- "⪆": true,
- "ğ": true,
- "ĝ": true,
- "г": true,
- "ġ": true,
- "≥": true,
- "⋛": true,
- "≥": true,
- "≧": true,
- "⩾": true,
- "⩾": true,
- "⪩": true,
- "⪀": true,
- "⪂": true,
- "⪄": true,
- "⋛︀": true,
- "⪔": true,
- "𝔤": true,
- "≫": true,
- "⋙": true,
- "ℷ": true,
- "ѓ": true,
- "≷": true,
- "⪒": true,
- "⪥": true,
- "⪤": true,
- "≩": true,
- "⪊": true,
- "⪊": true,
- "⪈": true,
- "⪈": true,
- "≩": true,
- "⋧": true,
- "𝕘": true,
- "`": true,
- "ℊ": true,
- "≳": true,
- "⪎": true,
- "⪐": true,
- ">": true,
- ">": true,
- "⪧": true,
- "⩺": true,
- "⋗": true,
- "⦕": true,
- "⩼": true,
- "⪆": true,
- "⥸": true,
- "⋗": true,
- "⋛": true,
- "⪌": true,
- "≷": true,
- "≳": true,
- "≩︀": true,
- "≩︀": true,
- "⇔": true,
- " ": true,
- "½": true,
- "ℋ": true,
- "ъ": true,
- "↔": true,
- "⥈": true,
- "↭": true,
- "ℏ": true,
- "ĥ": true,
- "♥": true,
- "♥": true,
- "…": true,
- "⊹": true,
- "𝔥": true,
- "⤥": true,
- "⤦": true,
- "⇿": true,
- "∻": true,
- "↩": true,
- "↪": true,
- "𝕙": true,
- "―": true,
- "𝒽": true,
- "ℏ": true,
- "ħ": true,
- "⁃": true,
- "‐": true,
- "í": true,
- "í": true,
- "⁣": true,
- "î": true,
- "î": true,
- "и": true,
- "е": true,
- "¡": true,
- "¡": true,
- "⇔": true,
- "𝔦": true,
- "ì": true,
- "ì": true,
- "ⅈ": true,
- "⨌": true,
- "∭": true,
- "⧜": true,
- "℩": true,
- "ij": true,
- "ī": true,
- "ℑ": true,
- "ℐ": true,
- "ℑ": true,
- "ı": true,
- "⊷": true,
- "Ƶ": true,
- "∈": true,
- "℅": true,
- "∞": true,
- "⧝": true,
- "ı": true,
- "∫": true,
- "⊺": true,
- "ℤ": true,
- "⊺": true,
- "⨗": true,
- "⨼": true,
- "ё": true,
- "į": true,
- "𝕚": true,
- "ι": true,
- "⨼": true,
- "¿": true,
- "¿": true,
- "𝒾": true,
- "∈": true,
- "⋹": true,
- "⋵": true,
- "⋴": true,
- "⋳": true,
- "∈": true,
- "⁢": true,
- "ĩ": true,
- "і": true,
- "ï": true,
- "ï": true,
- "ĵ": true,
- "й": true,
- "𝔧": true,
- "ȷ": true,
- "𝕛": true,
- "𝒿": true,
- "ј": true,
- "є": true,
- "κ": true,
- "ϰ": true,
- "ķ": true,
- "к": true,
- "𝔨": true,
- "ĸ": true,
- "х": true,
- "ќ": true,
- "𝕜": true,
- "𝓀": true,
- "⇚": true,
- "⇐": true,
- "⤛": true,
- "⤎": true,
- "≦": true,
- "⪋": true,
- "⥢": true,
- "ĺ": true,
- "⦴": true,
- "ℒ": true,
- "λ": true,
- "〈": true,
- "⦑": true,
- "⟨": true,
- "⪅": true,
- "«": true,
- "«": true,
- "←": true,
- "⇤": true,
- "⤟": true,
- "⤝": true,
- "↩": true,
- "↫": true,
- "⤹": true,
- "⥳": true,
- "↢": true,
- "⪫": true,
- "⤙": true,
- "⪭": true,
- "⪭︀": true,
- "⤌": true,
- "❲": true,
- "{": true,
- "[": true,
- "⦋": true,
- "⦏": true,
- "⦍": true,
- "ľ": true,
- "ļ": true,
- "⌈": true,
- "{": true,
- "л": true,
- "⤶": true,
- "“": true,
- "„": true,
- "⥧": true,
- "⥋": true,
- "↲": true,
- "≤": true,
- "←": true,
- "↢": true,
- "↽": true,
- "↼": true,
- "⇇": true,
- "↔": true,
- "⇆": true,
- "⇋": true,
- "↭": true,
- "⋋": true,
- "⋚": true,
- "≤": true,
- "≦": true,
- "⩽": true,
- "⩽": true,
- "⪨": true,
- "⩿": true,
- "⪁": true,
- "⪃": true,
- "⋚︀": true,
- "⪓": true,
- "⪅": true,
- "⋖": true,
- "⋚": true,
- "⪋": true,
- "≶": true,
- "≲": true,
- "⥼": true,
- "⌊": true,
- "𝔩": true,
- "≶": true,
- "⪑": true,
- "↽": true,
- "↼": true,
- "⥪": true,
- "▄": true,
- "љ": true,
- "≪": true,
- "⇇": true,
- "⌞": true,
- "⥫": true,
- "◺": true,
- "ŀ": true,
- "⎰": true,
- "⎰": true,
- "≨": true,
- "⪉": true,
- "⪉": true,
- "⪇": true,
- "⪇": true,
- "≨": true,
- "⋦": true,
- "⟬": true,
- "⇽": true,
- "⟦": true,
- "⟵": true,
- "⟷": true,
- "⟼": true,
- "⟶": true,
- "↫": true,
- "↬": true,
- "⦅": true,
- "𝕝": true,
- "⨭": true,
- "⨴": true,
- "∗": true,
- "_": true,
- "◊": true,
- "◊": true,
- "⧫": true,
- "(": true,
- "⦓": true,
- "⇆": true,
- "⌟": true,
- "⇋": true,
- "⥭": true,
- "": true,
- "⊿": true,
- "‹": true,
- "𝓁": true,
- "↰": true,
- "≲": true,
- "⪍": true,
- "⪏": true,
- "[": true,
- "‘": true,
- "‚": true,
- "ł": true,
- "<": true,
- "<": true,
- "⪦": true,
- "⩹": true,
- "⋖": true,
- "⋋": true,
- "⋉": true,
- "⥶": true,
- "⩻": true,
- "⦖": true,
- "◃": true,
- "⊴": true,
- "◂": true,
- "⥊": true,
- "⥦": true,
- "≨︀": true,
- "≨︀": true,
- "∺": true,
- "¯": true,
- "¯": true,
- "♂": true,
- "✠": true,
- "✠": true,
- "↦": true,
- "↦": true,
- "↧": true,
- "↤": true,
- "↥": true,
- "▮": true,
- "⨩": true,
- "м": true,
- "—": true,
- "∡": true,
- "𝔪": true,
- "℧": true,
- "µ": true,
- "µ": true,
- "∣": true,
- "*": true,
- "⫰": true,
- "·": true,
- "·": true,
- "−": true,
- "⊟": true,
- "∸": true,
- "⨪": true,
- "⫛": true,
- "…": true,
- "∓": true,
- "⊧": true,
- "𝕞": true,
- "∓": true,
- "𝓂": true,
- "∾": true,
- "μ": true,
- "⊸": true,
- "⊸": true,
- "⋙̸": true,
- "≫⃒": true,
- "≫̸": true,
- "⇍": true,
- "⇎": true,
- "⋘̸": true,
- "≪⃒": true,
- "≪̸": true,
- "⇏": true,
- "⊯": true,
- "⊮": true,
- "∇": true,
- "ń": true,
- "∠⃒": true,
- "≉": true,
- "⩰̸": true,
- "≋̸": true,
- "ʼn": true,
- "≉": true,
- "♮": true,
- "♮": true,
- "ℕ": true,
- " ": true,
- " ": true,
- "≎̸": true,
- "≏̸": true,
- "⩃": true,
- "ň": true,
- "ņ": true,
- "≇": true,
- "⩭̸": true,
- "⩂": true,
- "н": true,
- "–": true,
- "≠": true,
- "⇗": true,
- "⤤": true,
- "↗": true,
- "↗": true,
- "≐̸": true,
- "≢": true,
- "⤨": true,
- "≂̸": true,
- "∄": true,
- "∄": true,
- "𝔫": true,
- "≧̸": true,
- "≱": true,
- "≱": true,
- "≧̸": true,
- "⩾̸": true,
- "⩾̸": true,
- "≵": true,
- "≯": true,
- "≯": true,
- "⇎": true,
- "↮": true,
- "⫲": true,
- "∋": true,
- "⋼": true,
- "⋺": true,
- "∋": true,
- "њ": true,
- "⇍": true,
- "≦̸": true,
- "↚": true,
- "‥": true,
- "≰": true,
- "↚": true,
- "↮": true,
- "≰": true,
- "≦̸": true,
- "⩽̸": true,
- "⩽̸": true,
- "≮": true,
- "≴": true,
- "≮": true,
- "⋪": true,
- "⋬": true,
- "∤": true,
- "𝕟": true,
- "¬": true,
- "¬": true,
- "∉": true,
- "⋹̸": true,
- "⋵̸": true,
- "∉": true,
- "⋷": true,
- "⋶": true,
- "∌": true,
- "∌": true,
- "⋾": true,
- "⋽": true,
- "∦": true,
- "∦": true,
- "⫽⃥": true,
- "∂̸": true,
- "⨔": true,
- "⊀": true,
- "⋠": true,
- "⪯̸": true,
- "⊀": true,
- "⪯̸": true,
- "⇏": true,
- "↛": true,
- "⤳̸": true,
- "↝̸": true,
- "↛": true,
- "⋫": true,
- "⋭": true,
- "⊁": true,
- "⋡": true,
- "⪰̸": true,
- "𝓃": true,
- "∤": true,
- "∦": true,
- "≁": true,
- "≄": true,
- "≄": true,
- "∤": true,
- "∦": true,
- "⋢": true,
- "⋣": true,
- "⊄": true,
- "⫅̸": true,
- "⊈": true,
- "⊂⃒": true,
- "⊈": true,
- "⫅̸": true,
- "⊁": true,
- "⪰̸": true,
- "⊅": true,
- "⫆̸": true,
- "⊉": true,
- "⊃⃒": true,
- "⊉": true,
- "⫆̸": true,
- "≹": true,
- "ñ": true,
- "ñ": true,
- "≸": true,
- "⋪": true,
- "⋬": true,
- "⋫": true,
- "⋭": true,
- "ν": true,
- "#": true,
- "№": true,
- " ": true,
- "⊭": true,
- "⤄": true,
- "≍⃒": true,
- "⊬": true,
- "≥⃒": true,
- ">⃒": true,
- "⧞": true,
- "⤂": true,
- "≤⃒": true,
- "<⃒": true,
- "⊴⃒": true,
- "⤃": true,
- "⊵⃒": true,
- "∼⃒": true,
- "⇖": true,
- "⤣": true,
- "↖": true,
- "↖": true,
- "⤧": true,
- "Ⓢ": true,
- "ó": true,
- "ó": true,
- "⊛": true,
- "⊚": true,
- "ô": true,
- "ô": true,
- "о": true,
- "⊝": true,
- "ő": true,
- "⨸": true,
- "⊙": true,
- "⦼": true,
- "œ": true,
- "⦿": true,
- "𝔬": true,
- "˛": true,
- "ò": true,
- "ò": true,
- "⧁": true,
- "⦵": true,
- "Ω": true,
- "∮": true,
- "↺": true,
- "⦾": true,
- "⦻": true,
- "‾": true,
- "⧀": true,
- "ō": true,
- "ω": true,
- "ο": true,
- "⦶": true,
- "⊖": true,
- "𝕠": true,
- "⦷": true,
- "⦹": true,
- "⊕": true,
- "∨": true,
- "↻": true,
- "⩝": true,
- "ℴ": true,
- "ℴ": true,
- "ª": true,
- "ª": true,
- "º": true,
- "º": true,
- "⊶": true,
- "⩖": true,
- "⩗": true,
- "⩛": true,
- "ℴ": true,
- "ø": true,
- "ø": true,
- "⊘": true,
- "õ": true,
- "õ": true,
- "⊗": true,
- "⨶": true,
- "ö": true,
- "ö": true,
- "⌽": true,
- "∥": true,
- "¶": true,
- "¶": true,
- "∥": true,
- "⫳": true,
- "⫽": true,
- "∂": true,
- "п": true,
- "%": true,
- ".": true,
- "‰": true,
- "⊥": true,
- "‱": true,
- "𝔭": true,
- "φ": true,
- "ϕ": true,
- "ℳ": true,
- "☎": true,
- "π": true,
- "⋔": true,
- "ϖ": true,
- "ℏ": true,
- "ℎ": true,
- "ℏ": true,
- "+": true,
- "⨣": true,
- "⊞": true,
- "⨢": true,
- "∔": true,
- "⨥": true,
- "⩲": true,
- "±": true,
- "±": true,
- "⨦": true,
- "⨧": true,
- "±": true,
- "⨕": true,
- "𝕡": true,
- "£": true,
- "£": true,
- "≺": true,
- "⪳": true,
- "⪷": true,
- "≼": true,
- "⪯": true,
- "≺": true,
- "⪷": true,
- "≼": true,
- "⪯": true,
- "⪹": true,
- "⪵": true,
- "⋨": true,
- "≾": true,
- "′": true,
- "ℙ": true,
- "⪵": true,
- "⪹": true,
- "⋨": true,
- "∏": true,
- "⌮": true,
- "⌒": true,
- "⌓": true,
- "∝": true,
- "∝": true,
- "≾": true,
- "⊰": true,
- "𝓅": true,
- "ψ": true,
- " ": true,
- "𝔮": true,
- "⨌": true,
- "𝕢": true,
- "⁗": true,
- "𝓆": true,
- "ℍ": true,
- "⨖": true,
- "?": true,
- "≟": true,
- """: true,
- """: true,
- "⇛": true,
- "⇒": true,
- "⤜": true,
- "⤏": true,
- "⥤": true,
- "∽̱": true,
- "ŕ": true,
- "√": true,
- "⦳": true,
- "〉": true,
- "⦒": true,
- "⦥": true,
- "⟩": true,
- "»": true,
- "»": true,
- "→": true,
- "⥵": true,
- "⇥": true,
- "⤠": true,
- "⤳": true,
- "⤞": true,
- "↪": true,
- "↬": true,
- "⥅": true,
- "⥴": true,
- "↣": true,
- "↝": true,
- "⤚": true,
- "∶": true,
- "ℚ": true,
- "⤍": true,
- "❳": true,
- "}": true,
- "]": true,
- "⦌": true,
- "⦎": true,
- "⦐": true,
- "ř": true,
- "ŗ": true,
- "⌉": true,
- "}": true,
- "р": true,
- "⤷": true,
- "⥩": true,
- "”": true,
- "”": true,
- "↳": true,
- "ℜ": true,
- "ℛ": true,
- "ℜ": true,
- "ℝ": true,
- "▭": true,
- "®": true,
- "®": true,
- "⥽": true,
- "⌋": true,
- "𝔯": true,
- "⇁": true,
- "⇀": true,
- "⥬": true,
- "ρ": true,
- "ϱ": true,
- "→": true,
- "↣": true,
- "⇁": true,
- "⇀": true,
- "⇄": true,
- "⇌": true,
- "⇉": true,
- "↝": true,
- "⋌": true,
- "˚": true,
- "≓": true,
- "⇄": true,
- "⇌": true,
- "": true,
- "⎱": true,
- "⎱": true,
- "⫮": true,
- "⟭": true,
- "⇾": true,
- "⟧": true,
- "⦆": true,
- "𝕣": true,
- "⨮": true,
- "⨵": true,
- ")": true,
- "⦔": true,
- "⨒": true,
- "⇉": true,
- "›": true,
- "𝓇": true,
- "↱": true,
- "]": true,
- "’": true,
- "’": true,
- "⋌": true,
- "⋊": true,
- "▹": true,
- "⊵": true,
- "▸": true,
- "⧎": true,
- "⥨": true,
- "℞": true,
- "ś": true,
- "‚": true,
- "≻": true,
- "⪴": true,
- "⪸": true,
- "š": true,
- "≽": true,
- "⪰": true,
- "ş": true,
- "ŝ": true,
- "⪶": true,
- "⪺": true,
- "⋩": true,
- "⨓": true,
- "≿": true,
- "с": true,
- "⋅": true,
- "⊡": true,
- "⩦": true,
- "⇘": true,
- "⤥": true,
- "↘": true,
- "↘": true,
- "§": true,
- "§": true,
- ";": true,
- "⤩": true,
- "∖": true,
- "∖": true,
- "✶": true,
- "𝔰": true,
- "⌢": true,
- "♯": true,
- "щ": true,
- "ш": true,
- "∣": true,
- "∥": true,
- "­": true,
- "": true,
- "σ": true,
- "ς": true,
- "ς": true,
- "∼": true,
- "⩪": true,
- "≃": true,
- "≃": true,
- "⪞": true,
- "⪠": true,
- "⪝": true,
- "⪟": true,
- "≆": true,
- "⨤": true,
- "⥲": true,
- "←": true,
- "∖": true,
- "⨳": true,
- "⧤": true,
- "∣": true,
- "⌣": true,
- "⪪": true,
- "⪬": true,
- "⪬︀": true,
- "ь": true,
- "/": true,
- "⧄": true,
- "⌿": true,
- "𝕤": true,
- "♠": true,
- "♠": true,
- "∥": true,
- "⊓": true,
- "⊓︀": true,
- "⊔": true,
- "⊔︀": true,
- "⊏": true,
- "⊑": true,
- "⊏": true,
- "⊑": true,
- "⊐": true,
- "⊒": true,
- "⊐": true,
- "⊒": true,
- "□": true,
- "□": true,
- "▪": true,
- "▪": true,
- "→": true,
- "𝓈": true,
- "∖": true,
- "⌣": true,
- "⋆": true,
- "☆": true,
- "★": true,
- "ϵ": true,
- "ϕ": true,
- "¯": true,
- "⊂": true,
- "⫅": true,
- "⪽": true,
- "⊆": true,
- "⫃": true,
- "⫁": true,
- "⫋": true,
- "⊊": true,
- "⪿": true,
- "⥹": true,
- "⊂": true,
- "⊆": true,
- "⫅": true,
- "⊊": true,
- "⫋": true,
- "⫇": true,
- "⫕": true,
- "⫓": true,
- "≻": true,
- "⪸": true,
- "≽": true,
- "⪰": true,
- "⪺": true,
- "⪶": true,
- "⋩": true,
- "≿": true,
- "∑": true,
- "♪": true,
- "¹": true,
- "¹": true,
- "²": true,
- "²": true,
- "³": true,
- "³": true,
- "⊃": true,
- "⫆": true,
- "⪾": true,
- "⫘": true,
- "⊇": true,
- "⫄": true,
- "⟉": true,
- "⫗": true,
- "⥻": true,
- "⫂": true,
- "⫌": true,
- "⊋": true,
- "⫀": true,
- "⊃": true,
- "⊇": true,
- "⫆": true,
- "⊋": true,
- "⫌": true,
- "⫈": true,
- "⫔": true,
- "⫖": true,
- "⇙": true,
- "⤦": true,
- "↙": true,
- "↙": true,
- "⤪": true,
- "ß": true,
- "ß": true,
- "⌖": true,
- "τ": true,
- "⎴": true,
- "ť": true,
- "ţ": true,
- "т": true,
- "⃛": true,
- "⌕": true,
- "𝔱": true,
- "∴": true,
- "∴": true,
- "θ": true,
- "ϑ": true,
- "ϑ": true,
- "≈": true,
- "∼": true,
- " ": true,
- "≈": true,
- "∼": true,
- "þ": true,
- "þ": true,
- "˜": true,
- "×": true,
- "×": true,
- "⊠": true,
- "⨱": true,
- "⨰": true,
- "∭": true,
- "⤨": true,
- "⊤": true,
- "⌶": true,
- "⫱": true,
- "𝕥": true,
- "⫚": true,
- "⤩": true,
- "‴": true,
- "™": true,
- "▵": true,
- "▿": true,
- "◃": true,
- "⊴": true,
- "≜": true,
- "▹": true,
- "⊵": true,
- "◬": true,
- "≜": true,
- "⨺": true,
- "⨹": true,
- "⧍": true,
- "⨻": true,
- "⏢": true,
- "𝓉": true,
- "ц": true,
- "ћ": true,
- "ŧ": true,
- "≬": true,
- "↞": true,
- "↠": true,
- "⇑": true,
- "⥣": true,
- "ú": true,
- "ú": true,
- "↑": true,
- "ў": true,
- "ŭ": true,
- "û": true,
- "û": true,
- "у": true,
- "⇅": true,
- "ű": true,
- "⥮": true,
- "⥾": true,
- "𝔲": true,
- "ù": true,
- "ù": true,
- "↿": true,
- "↾": true,
- "▀": true,
- "⌜": true,
- "⌜": true,
- "⌏": true,
- "◸": true,
- "ū": true,
- "¨": true,
- "¨": true,
- "ų": true,
- "𝕦": true,
- "↑": true,
- "↕": true,
- "↿": true,
- "↾": true,
- "⊎": true,
- "υ": true,
- "ϒ": true,
- "υ": true,
- "⇈": true,
- "⌝": true,
- "⌝": true,
- "⌎": true,
- "ů": true,
- "◹": true,
- "𝓊": true,
- "⋰": true,
- "ũ": true,
- "▵": true,
- "▴": true,
- "⇈": true,
- "ü": true,
- "ü": true,
- "⦧": true,
- "⇕": true,
- "⫨": true,
- "⫩": true,
- "⊨": true,
- "⦜": true,
- "ϵ": true,
- "ϰ": true,
- "∅": true,
- "ϕ": true,
- "ϖ": true,
- "∝": true,
- "↕": true,
- "ϱ": true,
- "ς": true,
- "⊊︀": true,
- "⫋︀": true,
- "⊋︀": true,
- "⫌︀": true,
- "ϑ": true,
- "⊲": true,
- "⊳": true,
- "в": true,
- "⊢": true,
- "∨": true,
- "⊻": true,
- "≚": true,
- "⋮": true,
- "|": true,
- "|": true,
- "𝔳": true,
- "⊲": true,
- "⊂⃒": true,
- "⊃⃒": true,
- "𝕧": true,
- "∝": true,
- "⊳": true,
- "𝓋": true,
- "⫋︀": true,
- "⊊︀": true,
- "⫌︀": true,
- "⊋︀": true,
- "⦚": true,
- "ŵ": true,
- "⩟": true,
- "∧": true,
- "≙": true,
- "℘": true,
- "𝔴": true,
- "𝕨": true,
- "℘": true,
- "≀": true,
- "≀": true,
- "𝓌": true,
- "⋂": true,
- "◯": true,
- "⋃": true,
- "▽": true,
- "𝔵": true,
- "⟺": true,
- "⟷": true,
- "ξ": true,
- "⟸": true,
- "⟵": true,
- "⟼": true,
- "⋻": true,
- "⨀": true,
- "𝕩": true,
- "⨁": true,
- "⨂": true,
- "⟹": true,
- "⟶": true,
- "𝓍": true,
- "⨆": true,
- "⨄": true,
- "△": true,
- "⋁": true,
- "⋀": true,
- "ý": true,
- "ý": true,
- "я": true,
- "ŷ": true,
- "ы": true,
- "¥": true,
- "¥": true,
- "𝔶": true,
- "ї": true,
- "𝕪": true,
- "𝓎": true,
- "ю": true,
- "ÿ": true,
- "ÿ": true,
- "ź": true,
- "ž": true,
- "з": true,
- "ż": true,
- "ℨ": true,
- "ζ": true,
- "𝔷": true,
- "ж": true,
- "⇝": true,
- "𝕫": true,
- "𝓏": true,
- "": true,
- "": true,
-}
diff --git a/vendor/github.com/russross/blackfriday/v2/esc.go b/vendor/github.com/russross/blackfriday/v2/esc.go
deleted file mode 100644
index 6ab6010..0000000
--- a/vendor/github.com/russross/blackfriday/v2/esc.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package blackfriday
-
-import (
- "html"
- "io"
-)
-
-var htmlEscaper = [256][]byte{
- '&': []byte("&"),
- '<': []byte("<"),
- '>': []byte(">"),
- '"': []byte("""),
-}
-
-func escapeHTML(w io.Writer, s []byte) {
- escapeEntities(w, s, false)
-}
-
-func escapeAllHTML(w io.Writer, s []byte) {
- escapeEntities(w, s, true)
-}
-
-func escapeEntities(w io.Writer, s []byte, escapeValidEntities bool) {
- var start, end int
- for end < len(s) {
- escSeq := htmlEscaper[s[end]]
- if escSeq != nil {
- isEntity, entityEnd := nodeIsEntity(s, end)
- if isEntity && !escapeValidEntities {
- w.Write(s[start : entityEnd+1])
- start = entityEnd + 1
- } else {
- w.Write(s[start:end])
- w.Write(escSeq)
- start = end + 1
- }
- }
- end++
- }
- if start < len(s) && end <= len(s) {
- w.Write(s[start:end])
- }
-}
-
-func nodeIsEntity(s []byte, end int) (isEntity bool, endEntityPos int) {
- isEntity = false
- endEntityPos = end + 1
-
- if s[end] == '&' {
- for endEntityPos < len(s) {
- if s[endEntityPos] == ';' {
- if entities[string(s[end:endEntityPos+1])] {
- isEntity = true
- break
- }
- }
- if !isalnum(s[endEntityPos]) && s[endEntityPos] != '&' && s[endEntityPos] != '#' {
- break
- }
- endEntityPos++
- }
- }
-
- return isEntity, endEntityPos
-}
-
-func escLink(w io.Writer, text []byte) {
- unesc := html.UnescapeString(string(text))
- escapeHTML(w, []byte(unesc))
-}
diff --git a/vendor/github.com/russross/blackfriday/v2/html.go b/vendor/github.com/russross/blackfriday/v2/html.go
deleted file mode 100644
index cb4f26e..0000000
--- a/vendor/github.com/russross/blackfriday/v2/html.go
+++ /dev/null
@@ -1,952 +0,0 @@
-//
-// Blackfriday Markdown Processor
-// Available at http://github.com/russross/blackfriday
-//
-// Copyright © 2011 Russ Ross .
-// Distributed under the Simplified BSD License.
-// See README.md for details.
-//
-
-//
-//
-// HTML rendering backend
-//
-//
-
-package blackfriday
-
-import (
- "bytes"
- "fmt"
- "io"
- "regexp"
- "strings"
-)
-
-// HTMLFlags control optional behavior of HTML renderer.
-type HTMLFlags int
-
-// HTML renderer configuration options.
-const (
- HTMLFlagsNone HTMLFlags = 0
- SkipHTML HTMLFlags = 1 << iota // Skip preformatted HTML blocks
- SkipImages // Skip embedded images
- SkipLinks // Skip all links
- Safelink // Only link to trusted protocols
- NofollowLinks // Only link with rel="nofollow"
- NoreferrerLinks // Only link with rel="noreferrer"
- NoopenerLinks // Only link with rel="noopener"
- HrefTargetBlank // Add a blank target
- CompletePage // Generate a complete HTML page
- UseXHTML // Generate XHTML output instead of HTML
- FootnoteReturnLinks // Generate a link at the end of a footnote to return to the source
- Smartypants // Enable smart punctuation substitutions
- SmartypantsFractions // Enable smart fractions (with Smartypants)
- SmartypantsDashes // Enable smart dashes (with Smartypants)
- SmartypantsLatexDashes // Enable LaTeX-style dashes (with Smartypants)
- SmartypantsAngledQuotes // Enable angled double quotes (with Smartypants) for double quotes rendering
- SmartypantsQuotesNBSP // Enable « French guillemets » (with Smartypants)
- TOC // Generate a table of contents
-)
-
-var (
- htmlTagRe = regexp.MustCompile("(?i)^" + htmlTag)
-)
-
-const (
- htmlTag = "(?:" + openTag + "|" + closeTag + "|" + htmlComment + "|" +
- processingInstruction + "|" + declaration + "|" + cdata + ")"
- closeTag = "" + tagName + "\\s*[>]"
- openTag = "<" + tagName + attribute + "*" + "\\s*/?>"
- attribute = "(?:" + "\\s+" + attributeName + attributeValueSpec + "?)"
- attributeValue = "(?:" + unquotedValue + "|" + singleQuotedValue + "|" + doubleQuotedValue + ")"
- attributeValueSpec = "(?:" + "\\s*=" + "\\s*" + attributeValue + ")"
- attributeName = "[a-zA-Z_:][a-zA-Z0-9:._-]*"
- cdata = ""
- declaration = "]*>"
- doubleQuotedValue = "\"[^\"]*\""
- htmlComment = "|"
- processingInstruction = "[<][?].*?[?][>]"
- singleQuotedValue = "'[^']*'"
- tagName = "[A-Za-z][A-Za-z0-9-]*"
- unquotedValue = "[^\"'=<>`\\x00-\\x20]+"
-)
-
-// HTMLRendererParameters is a collection of supplementary parameters tweaking
-// the behavior of various parts of HTML renderer.
-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 tag for a footnote return link, if the
- // HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string
- // [return] is used.
- FootnoteReturnLinkContents string
- // If set, add this text to the front of each Heading ID, to ensure
- // uniqueness.
- HeadingIDPrefix string
- // If set, add this text to the back of each Heading ID, to ensure uniqueness.
- HeadingIDSuffix string
- // Increase heading levels: if the offset is 1, becomes etc.
- // Negative offset is also valid.
- // Resulting levels are clipped between 1 and 6.
- HeadingLevelOffset int
-
- Title string // Document title (used if CompletePage is set)
- CSS string // Optional CSS file URL (used if CompletePage is set)
- Icon string // Optional icon file URL (used if CompletePage is set)
-
- Flags HTMLFlags // Flags allow customizing this renderer's behavior
-}
-
-// HTMLRenderer is a type that implements the Renderer interface for HTML output.
-//
-// Do not create this directly, instead use the NewHTMLRenderer function.
-type HTMLRenderer struct {
- HTMLRendererParameters
-
- closeTag string // how to end singleton tags: either " />" or ">"
-
- // Track heading IDs to prevent ID collision in a single generation.
- headingIDs map[string]int
-
- lastOutputLen int
- disableTags int
-
- sr *SPRenderer
-}
-
-const (
- xhtmlClose = " />"
- htmlClose = ">"
-)
-
-// NewHTMLRenderer creates and configures an HTMLRenderer object, which
-// satisfies the Renderer interface.
-func NewHTMLRenderer(params HTMLRendererParameters) *HTMLRenderer {
- // configure the rendering engine
- closeTag := htmlClose
- if params.Flags&UseXHTML != 0 {
- closeTag = xhtmlClose
- }
-
- if params.FootnoteReturnLinkContents == "" {
- // U+FE0E is VARIATION SELECTOR-15.
- // It suppresses automatic emoji presentation of the preceding
- // U+21A9 LEFTWARDS ARROW WITH HOOK on iOS and iPadOS.
- params.FootnoteReturnLinkContents = "↩\ufe0e "
- }
-
- return &HTMLRenderer{
- HTMLRendererParameters: params,
-
- closeTag: closeTag,
- headingIDs: make(map[string]int),
-
- sr: NewSmartypantsRenderer(params.Flags),
- }
-}
-
-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 skipSpace(tag []byte, i int) int {
- for i < len(tag) && isspace(tag[i]) {
- i++
- }
- return i
-}
-
-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 (r *HTMLRenderer) ensureUniqueHeadingID(id string) string {
- for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] {
- tmp := fmt.Sprintf("%s-%d", id, count+1)
-
- if _, tmpFound := r.headingIDs[tmp]; !tmpFound {
- r.headingIDs[id] = count + 1
- id = tmp
- } else {
- id = id + "-1"
- }
- }
-
- if _, found := r.headingIDs[id]; !found {
- r.headingIDs[id] = 0
- }
-
- return id
-}
-
-func (r *HTMLRenderer) addAbsPrefix(link []byte) []byte {
- if r.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' {
- newDest := r.AbsolutePrefix
- if link[0] != '/' {
- newDest += "/"
- }
- newDest += string(link)
- return []byte(newDest)
- }
- return link
-}
-
-func appendLinkAttrs(attrs []string, flags HTMLFlags, link []byte) []string {
- if isRelativeLink(link) {
- return attrs
- }
- val := []string{}
- if flags&NofollowLinks != 0 {
- val = append(val, "nofollow")
- }
- if flags&NoreferrerLinks != 0 {
- val = append(val, "noreferrer")
- }
- if flags&NoopenerLinks != 0 {
- val = append(val, "noopener")
- }
- if flags&HrefTargetBlank != 0 {
- attrs = append(attrs, "target=\"_blank\"")
- }
- if len(val) == 0 {
- return attrs
- }
- attr := fmt.Sprintf("rel=%q", strings.Join(val, " "))
- return append(attrs, attr)
-}
-
-func isMailto(link []byte) bool {
- return bytes.HasPrefix(link, []byte("mailto:"))
-}
-
-func needSkipLink(flags HTMLFlags, dest []byte) bool {
- if flags&SkipLinks != 0 {
- return true
- }
- return flags&Safelink != 0 && !isSafeLink(dest) && !isMailto(dest)
-}
-
-func isSmartypantable(node *Node) bool {
- pt := node.Parent.Type
- return pt != Link && pt != CodeBlock && pt != Code
-}
-
-func appendLanguageAttr(attrs []string, info []byte) []string {
- if len(info) == 0 {
- return attrs
- }
- endOfLang := bytes.IndexAny(info, "\t ")
- if endOfLang < 0 {
- endOfLang = len(info)
- }
- return append(attrs, fmt.Sprintf("class=\"language-%s\"", info[:endOfLang]))
-}
-
-func (r *HTMLRenderer) tag(w io.Writer, name []byte, attrs []string) {
- w.Write(name)
- if len(attrs) > 0 {
- w.Write(spaceBytes)
- w.Write([]byte(strings.Join(attrs, " ")))
- }
- w.Write(gtBytes)
- r.lastOutputLen = 1
-}
-
-func footnoteRef(prefix string, node *Node) []byte {
- urlFrag := prefix + string(slugify(node.Destination))
- anchor := fmt.Sprintf(`%d `, urlFrag, node.NoteID)
- return []byte(fmt.Sprintf(``, urlFrag, anchor))
-}
-
-func footnoteItem(prefix string, slug []byte) []byte {
- return []byte(fmt.Sprintf(` `, prefix, slug))
-}
-
-func footnoteReturnLink(prefix, returnLink string, slug []byte) []byte {
- const format = ` `
- return []byte(fmt.Sprintf(format, prefix, slug, returnLink))
-}
-
-func itemOpenCR(node *Node) bool {
- if node.Prev == nil {
- return false
- }
- ld := node.Parent.ListData
- return !ld.Tight && ld.ListFlags&ListTypeDefinition == 0
-}
-
-func skipParagraphTags(node *Node) bool {
- grandparent := node.Parent.Parent
- if grandparent == nil || grandparent.Type != List {
- return false
- }
- tightOrTerm := grandparent.Tight || node.Parent.ListFlags&ListTypeTerm != 0
- return grandparent.Type == List && tightOrTerm
-}
-
-func cellAlignment(align CellAlignFlags) string {
- switch align {
- case TableAlignmentLeft:
- return "left"
- case TableAlignmentRight:
- return "right"
- case TableAlignmentCenter:
- return "center"
- default:
- return ""
- }
-}
-
-func (r *HTMLRenderer) out(w io.Writer, text []byte) {
- if r.disableTags > 0 {
- w.Write(htmlTagRe.ReplaceAll(text, []byte{}))
- } else {
- w.Write(text)
- }
- r.lastOutputLen = len(text)
-}
-
-func (r *HTMLRenderer) cr(w io.Writer) {
- if r.lastOutputLen > 0 {
- r.out(w, nlBytes)
- }
-}
-
-var (
- nlBytes = []byte{'\n'}
- gtBytes = []byte{'>'}
- spaceBytes = []byte{' '}
-)
-
-var (
- brTag = []byte(" ")
- brXHTMLTag = []byte(" ")
- emTag = []byte("")
- emCloseTag = []byte(" ")
- strongTag = []byte("")
- strongCloseTag = []byte(" ")
- delTag = []byte("")
- delCloseTag = []byte("")
- ttTag = []byte("")
- ttCloseTag = []byte(" ")
- aTag = []byte("")
- preTag = []byte("")
- preCloseTag = []byte(" ")
- codeTag = []byte("")
- codeCloseTag = []byte("
")
- pTag = []byte("")
- pCloseTag = []byte("
")
- blockquoteTag = []byte("")
- blockquoteCloseTag = []byte(" ")
- hrTag = []byte(" ")
- hrXHTMLTag = []byte(" ")
- ulTag = []byte("")
- ulCloseTag = []byte(" ")
- olTag = []byte("")
- olCloseTag = []byte(" ")
- dlTag = []byte("")
- dlCloseTag = []byte(" ")
- liTag = []byte("")
- liCloseTag = []byte(" ")
- ddTag = []byte("")
- ddCloseTag = []byte(" ")
- dtTag = []byte("")
- dtCloseTag = []byte(" ")
- tableTag = []byte(" ")
- tableCloseTag = []byte("
")
- tdTag = []byte("")
- thTag = []byte(" ")
- theadTag = []byte("")
- theadCloseTag = []byte(" ")
- tbodyTag = []byte(" ")
- tbodyCloseTag = []byte(" ")
- trTag = []byte("")
- trCloseTag = []byte(" ")
- h1Tag = []byte("")
- h2Tag = []byte("")
- h3Tag = []byte("")
- h4Tag = []byte("")
- h5Tag = []byte("")
- h6Tag = []byte("")
-
- footnotesDivBytes = []byte("\n\n")
-)
-
-func headingTagsFromLevel(level int) ([]byte, []byte) {
- if level <= 1 {
- return h1Tag, h1CloseTag
- }
- switch level {
- case 2:
- return h2Tag, h2CloseTag
- case 3:
- return h3Tag, h3CloseTag
- case 4:
- return h4Tag, h4CloseTag
- case 5:
- return h5Tag, h5CloseTag
- }
- return h6Tag, h6CloseTag
-}
-
-func (r *HTMLRenderer) outHRTag(w io.Writer) {
- if r.Flags&UseXHTML == 0 {
- r.out(w, hrTag)
- } else {
- r.out(w, hrXHTMLTag)
- }
-}
-
-// RenderNode is a default renderer of a single node of a syntax tree. For
-// block nodes it will be called twice: first time with entering=true, second
-// time with entering=false, so that it could know when it's working on an open
-// tag and when on close. It writes the result to w.
-//
-// The return value is a way to tell the calling walker to adjust its walk
-// pattern: e.g. it can terminate the traversal by returning Terminate. Or it
-// can ask the walker to skip a subtree of this node by returning SkipChildren.
-// The typical behavior is to return GoToNext, which asks for the usual
-// traversal to the next node.
-func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkStatus {
- attrs := []string{}
- switch node.Type {
- case Text:
- if r.Flags&Smartypants != 0 {
- var tmp bytes.Buffer
- escapeHTML(&tmp, node.Literal)
- r.sr.Process(w, tmp.Bytes())
- } else {
- if node.Parent.Type == Link {
- escLink(w, node.Literal)
- } else {
- escapeHTML(w, node.Literal)
- }
- }
- case Softbreak:
- r.cr(w)
- // TODO: make it configurable via out(renderer.softbreak)
- case Hardbreak:
- if r.Flags&UseXHTML == 0 {
- r.out(w, brTag)
- } else {
- r.out(w, brXHTMLTag)
- }
- r.cr(w)
- case Emph:
- if entering {
- r.out(w, emTag)
- } else {
- r.out(w, emCloseTag)
- }
- case Strong:
- if entering {
- r.out(w, strongTag)
- } else {
- r.out(w, strongCloseTag)
- }
- case Del:
- if entering {
- r.out(w, delTag)
- } else {
- r.out(w, delCloseTag)
- }
- case HTMLSpan:
- if r.Flags&SkipHTML != 0 {
- break
- }
- r.out(w, node.Literal)
- case Link:
- // mark it but don't link it if it is not a safe link: no smartypants
- dest := node.LinkData.Destination
- if needSkipLink(r.Flags, dest) {
- if entering {
- r.out(w, ttTag)
- } else {
- r.out(w, ttCloseTag)
- }
- } else {
- if entering {
- dest = r.addAbsPrefix(dest)
- var hrefBuf bytes.Buffer
- hrefBuf.WriteString("href=\"")
- escLink(&hrefBuf, dest)
- hrefBuf.WriteByte('"')
- attrs = append(attrs, hrefBuf.String())
- if node.NoteID != 0 {
- r.out(w, footnoteRef(r.FootnoteAnchorPrefix, node))
- break
- }
- attrs = appendLinkAttrs(attrs, r.Flags, dest)
- if len(node.LinkData.Title) > 0 {
- var titleBuff bytes.Buffer
- titleBuff.WriteString("title=\"")
- escapeHTML(&titleBuff, node.LinkData.Title)
- titleBuff.WriteByte('"')
- attrs = append(attrs, titleBuff.String())
- }
- r.tag(w, aTag, attrs)
- } else {
- if node.NoteID != 0 {
- break
- }
- r.out(w, aCloseTag)
- }
- }
- case Image:
- if r.Flags&SkipImages != 0 {
- return SkipChildren
- }
- if entering {
- dest := node.LinkData.Destination
- dest = r.addAbsPrefix(dest)
- if r.disableTags == 0 {
- //if options.safe && potentiallyUnsafe(dest) {
- //out(w, ` `))
- }
- }
- case Code:
- r.out(w, codeTag)
- escapeAllHTML(w, node.Literal)
- r.out(w, codeCloseTag)
- case Document:
- break
- case Paragraph:
- if skipParagraphTags(node) {
- break
- }
- if entering {
- // TODO: untangle this clusterfuck about when the newlines need
- // to be added and when not.
- if node.Prev != nil {
- switch node.Prev.Type {
- case HTMLBlock, List, Paragraph, Heading, CodeBlock, BlockQuote, HorizontalRule:
- r.cr(w)
- }
- }
- if node.Parent.Type == BlockQuote && node.Prev == nil {
- r.cr(w)
- }
- r.out(w, pTag)
- } else {
- r.out(w, pCloseTag)
- if !(node.Parent.Type == Item && node.Next == nil) {
- r.cr(w)
- }
- }
- case BlockQuote:
- if entering {
- r.cr(w)
- r.out(w, blockquoteTag)
- } else {
- r.out(w, blockquoteCloseTag)
- r.cr(w)
- }
- case HTMLBlock:
- if r.Flags&SkipHTML != 0 {
- break
- }
- r.cr(w)
- r.out(w, node.Literal)
- r.cr(w)
- case Heading:
- headingLevel := r.HTMLRendererParameters.HeadingLevelOffset + node.Level
- openTag, closeTag := headingTagsFromLevel(headingLevel)
- if entering {
- if node.IsTitleblock {
- attrs = append(attrs, `class="title"`)
- }
- if node.HeadingID != "" {
- id := r.ensureUniqueHeadingID(node.HeadingID)
- if r.HeadingIDPrefix != "" {
- id = r.HeadingIDPrefix + id
- }
- if r.HeadingIDSuffix != "" {
- id = id + r.HeadingIDSuffix
- }
- attrs = append(attrs, fmt.Sprintf(`id="%s"`, id))
- }
- r.cr(w)
- r.tag(w, openTag, attrs)
- } else {
- r.out(w, closeTag)
- if !(node.Parent.Type == Item && node.Next == nil) {
- r.cr(w)
- }
- }
- case HorizontalRule:
- r.cr(w)
- r.outHRTag(w)
- r.cr(w)
- case List:
- openTag := ulTag
- closeTag := ulCloseTag
- if node.ListFlags&ListTypeOrdered != 0 {
- openTag = olTag
- closeTag = olCloseTag
- }
- if node.ListFlags&ListTypeDefinition != 0 {
- openTag = dlTag
- closeTag = dlCloseTag
- }
- if entering {
- if node.IsFootnotesList {
- r.out(w, footnotesDivBytes)
- r.outHRTag(w)
- r.cr(w)
- }
- r.cr(w)
- if node.Parent.Type == Item && node.Parent.Parent.Tight {
- r.cr(w)
- }
- r.tag(w, openTag[:len(openTag)-1], attrs)
- r.cr(w)
- } else {
- r.out(w, closeTag)
- //cr(w)
- //if node.parent.Type != Item {
- // cr(w)
- //}
- if node.Parent.Type == Item && node.Next != nil {
- r.cr(w)
- }
- if node.Parent.Type == Document || node.Parent.Type == BlockQuote {
- r.cr(w)
- }
- if node.IsFootnotesList {
- r.out(w, footnotesCloseDivBytes)
- }
- }
- case Item:
- openTag := liTag
- closeTag := liCloseTag
- if node.ListFlags&ListTypeDefinition != 0 {
- openTag = ddTag
- closeTag = ddCloseTag
- }
- if node.ListFlags&ListTypeTerm != 0 {
- openTag = dtTag
- closeTag = dtCloseTag
- }
- if entering {
- if itemOpenCR(node) {
- r.cr(w)
- }
- if node.ListData.RefLink != nil {
- slug := slugify(node.ListData.RefLink)
- r.out(w, footnoteItem(r.FootnoteAnchorPrefix, slug))
- break
- }
- r.out(w, openTag)
- } else {
- if node.ListData.RefLink != nil {
- slug := slugify(node.ListData.RefLink)
- if r.Flags&FootnoteReturnLinks != 0 {
- r.out(w, footnoteReturnLink(r.FootnoteAnchorPrefix, r.FootnoteReturnLinkContents, slug))
- }
- }
- r.out(w, closeTag)
- r.cr(w)
- }
- case CodeBlock:
- attrs = appendLanguageAttr(attrs, node.Info)
- r.cr(w)
- r.out(w, preTag)
- r.tag(w, codeTag[:len(codeTag)-1], attrs)
- escapeAllHTML(w, node.Literal)
- r.out(w, codeCloseTag)
- r.out(w, preCloseTag)
- if node.Parent.Type != Item {
- r.cr(w)
- }
- case Table:
- if entering {
- r.cr(w)
- r.out(w, tableTag)
- } else {
- r.out(w, tableCloseTag)
- r.cr(w)
- }
- case TableCell:
- openTag := tdTag
- closeTag := tdCloseTag
- if node.IsHeader {
- openTag = thTag
- closeTag = thCloseTag
- }
- if entering {
- align := cellAlignment(node.Align)
- if align != "" {
- attrs = append(attrs, fmt.Sprintf(`align="%s"`, align))
- }
- if node.Prev == nil {
- r.cr(w)
- }
- r.tag(w, openTag, attrs)
- } else {
- r.out(w, closeTag)
- r.cr(w)
- }
- case TableHead:
- if entering {
- r.cr(w)
- r.out(w, theadTag)
- } else {
- r.out(w, theadCloseTag)
- r.cr(w)
- }
- case TableBody:
- if entering {
- r.cr(w)
- r.out(w, tbodyTag)
- // XXX: this is to adhere to a rather silly test. Should fix test.
- if node.FirstChild == nil {
- r.cr(w)
- }
- } else {
- r.out(w, tbodyCloseTag)
- r.cr(w)
- }
- case TableRow:
- if entering {
- r.cr(w)
- r.out(w, trTag)
- } else {
- r.out(w, trCloseTag)
- r.cr(w)
- }
- default:
- panic("Unknown node type " + node.Type.String())
- }
- return GoToNext
-}
-
-// RenderHeader writes HTML document preamble and TOC if requested.
-func (r *HTMLRenderer) RenderHeader(w io.Writer, ast *Node) {
- r.writeDocumentHeader(w)
- if r.Flags&TOC != 0 {
- r.writeTOC(w, ast)
- }
-}
-
-// RenderFooter writes HTML document footer.
-func (r *HTMLRenderer) RenderFooter(w io.Writer, ast *Node) {
- if r.Flags&CompletePage == 0 {
- return
- }
- io.WriteString(w, "\n