all: Vendor with Godeps & GO15EXPERIMENT
Use godeps to vendor dependencies and the normal go toolchain, with GO15VENDOREXPERIMENT=1 set to properly vendor dependencies for reproducible builds.
This commit is contained in:
parent
71e83d6f59
commit
4e6d69e744
55
Godeps/Godeps.json
generated
Normal file
55
Godeps/Godeps.json
generated
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"ImportPath": "github.com/derekparker/delve",
|
||||
"GoVersion": "go1.5.1",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/cpuguy83/go-md2man/md2man",
|
||||
"Comment": "v1.0.4",
|
||||
"Rev": "71acacd42f85e5e82f70a55327789582a5200a90"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/davecheney/profile",
|
||||
"Rev": "c29d1a1565bca9fbeed5eed0e5d52ba78469a16b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/inconshreveable/mousetrap",
|
||||
"Rev": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/peterh/liner",
|
||||
"Rev": "941195f85dd7a23971a3d55142972d396278ddcf"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/russross/blackfriday",
|
||||
"Comment": "v1.3",
|
||||
"Rev": "8cec3a854e68dba10faabbe31c089abf4a3e57a6"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/shurcooL/sanitized_anchor_name",
|
||||
"Rev": "244f5ac324cb97e1987ef901a0081a77bfd8e845"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/spf13/cobra",
|
||||
"Rev": "53d96508f5c9311f5dade714e1de7bd6a9d2af4a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/spf13/pflag",
|
||||
"Rev": "b084184666e02084b8ccb9b704bf0d79c466eb1d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/sys/unix",
|
||||
"Rev": "342d6a85aa15bcd2ec54803cdffe90d52b6f35a7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/check.v1",
|
||||
"Rev": "11d3bc7aa68e238947792f30573146a3231fc0f1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/yaml.v2",
|
||||
"Rev": "53feefa2559fb8dfa8d81baad31be332c97d6c77"
|
||||
}
|
||||
]
|
||||
}
|
||||
5
Godeps/Readme
generated
Normal file
5
Godeps/Readme
generated
Normal file
@ -0,0 +1,5 @@
|
||||
This directory tree is generated automatically by godep.
|
||||
|
||||
Please do not edit.
|
||||
|
||||
See https://github.com/tools/godep for more information.
|
||||
15
Makefile
15
Makefile
@ -23,28 +23,19 @@ endif
|
||||
endif
|
||||
endif
|
||||
|
||||
deps: check-cert
|
||||
ifeq "$(SKIP_DEPS)" ""
|
||||
go get -u github.com/peterh/liner
|
||||
go get -u github.com/spf13/cobra
|
||||
go get -u golang.org/x/sys/unix
|
||||
go get -u github.com/davecheney/profile
|
||||
go get -u gopkg.in/yaml.v2
|
||||
endif
|
||||
|
||||
build: deps
|
||||
build: check-cert
|
||||
go build $(FLAGS) github.com/derekparker/delve/cmd/dlv
|
||||
ifeq "$(UNAME)" "Darwin"
|
||||
codesign -s $(CERT) ./dlv
|
||||
endif
|
||||
|
||||
install: deps
|
||||
install: check-cert
|
||||
go install $(FLAGS) github.com/derekparker/delve/cmd/dlv
|
||||
ifeq "$(UNAME)" "Darwin"
|
||||
codesign -s $(CERT) $(GOPATH)/bin/dlv
|
||||
endif
|
||||
|
||||
test: deps
|
||||
test: check-cert
|
||||
ifeq "$(UNAME)" "Darwin"
|
||||
ifeq "$(TRAVIS)" "true"
|
||||
sudo -E go test -v ./...
|
||||
|
||||
19
vendor/github.com/cpuguy83/go-md2man/md2man/md2man.go
generated
vendored
Normal file
19
vendor/github.com/cpuguy83/go-md2man/md2man/md2man.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
package md2man
|
||||
|
||||
import (
|
||||
"github.com/russross/blackfriday"
|
||||
)
|
||||
|
||||
func Render(doc []byte) []byte {
|
||||
renderer := RoffRenderer(0)
|
||||
extensions := 0
|
||||
extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
|
||||
extensions |= blackfriday.EXTENSION_TABLES
|
||||
extensions |= blackfriday.EXTENSION_FENCED_CODE
|
||||
extensions |= blackfriday.EXTENSION_AUTOLINK
|
||||
extensions |= blackfriday.EXTENSION_SPACE_HEADERS
|
||||
extensions |= blackfriday.EXTENSION_FOOTNOTES
|
||||
extensions |= blackfriday.EXTENSION_TITLEBLOCK
|
||||
|
||||
return blackfriday.Markdown(doc, renderer, extensions)
|
||||
}
|
||||
269
vendor/github.com/cpuguy83/go-md2man/md2man/roff.go
generated
vendored
Normal file
269
vendor/github.com/cpuguy83/go-md2man/md2man/roff.go
generated
vendored
Normal file
@ -0,0 +1,269 @@
|
||||
package md2man
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html"
|
||||
"strings"
|
||||
|
||||
"github.com/russross/blackfriday"
|
||||
)
|
||||
|
||||
type roffRenderer struct{}
|
||||
|
||||
func RoffRenderer(flags int) blackfriday.Renderer {
|
||||
return &roffRenderer{}
|
||||
}
|
||||
|
||||
func (r *roffRenderer) GetFlags() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (r *roffRenderer) TitleBlock(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString(".TH ")
|
||||
|
||||
splitText := bytes.Split(text, []byte("\n"))
|
||||
for i, line := range splitText {
|
||||
line = bytes.TrimPrefix(line, []byte("% "))
|
||||
if i == 0 {
|
||||
line = bytes.Replace(line, []byte("("), []byte("\" \""), 1)
|
||||
line = bytes.Replace(line, []byte(")"), []byte("\" \""), 1)
|
||||
}
|
||||
line = append([]byte("\""), line...)
|
||||
line = append(line, []byte("\" ")...)
|
||||
out.Write(line)
|
||||
}
|
||||
|
||||
out.WriteString(" \"\"\n")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string) {
|
||||
out.WriteString("\n.PP\n.RS\n\n.nf\n")
|
||||
escapeSpecialChars(out, text)
|
||||
out.WriteString("\n.fi\n.RE\n")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) BlockQuote(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("\n.PP\n.RS\n")
|
||||
out.Write(text)
|
||||
out.WriteString("\n.RE\n")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) BlockHtml(out *bytes.Buffer, text []byte) {
|
||||
out.Write(text)
|
||||
}
|
||||
|
||||
func (r *roffRenderer) Header(out *bytes.Buffer, text func() bool, level int, id string) {
|
||||
marker := out.Len()
|
||||
|
||||
switch {
|
||||
case marker == 0:
|
||||
// This is the doc header
|
||||
out.WriteString(".TH ")
|
||||
case level == 1:
|
||||
out.WriteString("\n\n.SH ")
|
||||
case level == 2:
|
||||
out.WriteString("\n.SH ")
|
||||
default:
|
||||
out.WriteString("\n.SS ")
|
||||
}
|
||||
|
||||
if !text() {
|
||||
out.Truncate(marker)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (r *roffRenderer) HRule(out *bytes.Buffer) {
|
||||
out.WriteString("\n.ti 0\n\\l'\\n(.lu'\n")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) List(out *bytes.Buffer, text func() bool, flags int) {
|
||||
marker := out.Len()
|
||||
out.WriteString(".IP ")
|
||||
if flags&blackfriday.LIST_TYPE_ORDERED != 0 {
|
||||
out.WriteString("\\(bu 2")
|
||||
} else {
|
||||
out.WriteString("\\n+[step" + string(flags) + "]")
|
||||
}
|
||||
out.WriteString("\n")
|
||||
if !text() {
|
||||
out.Truncate(marker)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (r *roffRenderer) ListItem(out *bytes.Buffer, text []byte, flags int) {
|
||||
out.WriteString("\n\\item ")
|
||||
out.Write(text)
|
||||
}
|
||||
|
||||
func (r *roffRenderer) Paragraph(out *bytes.Buffer, text func() bool) {
|
||||
marker := out.Len()
|
||||
out.WriteString("\n.PP\n")
|
||||
if !text() {
|
||||
out.Truncate(marker)
|
||||
return
|
||||
}
|
||||
if marker != 0 {
|
||||
out.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This might now work
|
||||
func (r *roffRenderer) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
|
||||
out.WriteString(".TS\nallbox;\n")
|
||||
|
||||
out.Write(header)
|
||||
out.Write(body)
|
||||
out.WriteString("\n.TE\n")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) TableRow(out *bytes.Buffer, text []byte) {
|
||||
if out.Len() > 0 {
|
||||
out.WriteString("\n")
|
||||
}
|
||||
out.Write(text)
|
||||
out.WriteString("\n")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
|
||||
if out.Len() > 0 {
|
||||
out.WriteString(" ")
|
||||
}
|
||||
out.Write(text)
|
||||
out.WriteString(" ")
|
||||
}
|
||||
|
||||
// TODO: This is probably broken
|
||||
func (r *roffRenderer) TableCell(out *bytes.Buffer, text []byte, align int) {
|
||||
if out.Len() > 0 {
|
||||
out.WriteString("\t")
|
||||
}
|
||||
out.Write(text)
|
||||
out.WriteString("\t")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) Footnotes(out *bytes.Buffer, text func() bool) {
|
||||
|
||||
}
|
||||
|
||||
func (r *roffRenderer) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
|
||||
|
||||
}
|
||||
|
||||
func (r *roffRenderer) AutoLink(out *bytes.Buffer, link []byte, kind int) {
|
||||
out.WriteString("\n\\[la]")
|
||||
out.Write(link)
|
||||
out.WriteString("\\[ra]")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) CodeSpan(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("\\fB\\fC")
|
||||
escapeSpecialChars(out, text)
|
||||
out.WriteString("\\fR")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) DoubleEmphasis(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("\\fB")
|
||||
out.Write(text)
|
||||
out.WriteString("\\fP")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) Emphasis(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("\\fI")
|
||||
out.Write(text)
|
||||
out.WriteString("\\fP")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
||||
}
|
||||
|
||||
func (r *roffRenderer) LineBreak(out *bytes.Buffer) {
|
||||
out.WriteString("\n.br\n")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
|
||||
r.AutoLink(out, link, 0)
|
||||
}
|
||||
|
||||
func (r *roffRenderer) RawHtmlTag(out *bytes.Buffer, tag []byte) {
|
||||
out.Write(tag)
|
||||
}
|
||||
|
||||
func (r *roffRenderer) TripleEmphasis(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("\\s+2")
|
||||
out.Write(text)
|
||||
out.WriteString("\\s-2")
|
||||
}
|
||||
|
||||
func (r *roffRenderer) StrikeThrough(out *bytes.Buffer, text []byte) {
|
||||
}
|
||||
|
||||
func (r *roffRenderer) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
|
||||
|
||||
}
|
||||
|
||||
func (r *roffRenderer) Entity(out *bytes.Buffer, entity []byte) {
|
||||
out.WriteString(html.UnescapeString(string(entity)))
|
||||
}
|
||||
|
||||
func processFooterText(text []byte) []byte {
|
||||
text = bytes.TrimPrefix(text, []byte("% "))
|
||||
newText := []byte{}
|
||||
textArr := strings.Split(string(text), ") ")
|
||||
|
||||
for i, w := range textArr {
|
||||
if i == 0 {
|
||||
w = strings.Replace(w, "(", "\" \"", 1)
|
||||
w = fmt.Sprintf("\"%s\"", w)
|
||||
} else {
|
||||
w = fmt.Sprintf(" \"%s\"", w)
|
||||
}
|
||||
newText = append(newText, []byte(w)...)
|
||||
}
|
||||
newText = append(newText, []byte(" \"\"")...)
|
||||
|
||||
return newText
|
||||
}
|
||||
|
||||
func (r *roffRenderer) NormalText(out *bytes.Buffer, text []byte) {
|
||||
escapeSpecialChars(out, text)
|
||||
}
|
||||
|
||||
func (r *roffRenderer) DocumentHeader(out *bytes.Buffer) {
|
||||
}
|
||||
|
||||
func (r *roffRenderer) DocumentFooter(out *bytes.Buffer) {
|
||||
}
|
||||
|
||||
func needsBackslash(c byte) bool {
|
||||
for _, r := range []byte("-_&\\~") {
|
||||
if c == r {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func escapeSpecialChars(out *bytes.Buffer, text []byte) {
|
||||
for i := 0; i < len(text); i++ {
|
||||
// directly copy normal characters
|
||||
org := i
|
||||
|
||||
for i < len(text) && !needsBackslash(text[i]) {
|
||||
i++
|
||||
}
|
||||
if i > org {
|
||||
out.Write(text[org:i])
|
||||
}
|
||||
|
||||
// escape a character
|
||||
if i >= len(text) {
|
||||
break
|
||||
}
|
||||
out.WriteByte('\\')
|
||||
out.WriteByte(text[i])
|
||||
}
|
||||
}
|
||||
1
vendor/github.com/davecheney/profile/AUTHORS
generated
vendored
Normal file
1
vendor/github.com/davecheney/profile/AUTHORS
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
Dave Cheney <dave@cheney.net>
|
||||
24
vendor/github.com/davecheney/profile/LICENSE
generated
vendored
Normal file
24
vendor/github.com/davecheney/profile/LICENSE
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
Copyright (c) 2013 Dave Cheney. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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
|
||||
OWNER 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.
|
||||
50
vendor/github.com/davecheney/profile/README.md
generated
vendored
Normal file
50
vendor/github.com/davecheney/profile/README.md
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
profile
|
||||
=======
|
||||
|
||||
Simple profiling support package for Go
|
||||
|
||||
installation
|
||||
------------
|
||||
|
||||
go get github.com/davecheney/profile
|
||||
|
||||
usage
|
||||
-----
|
||||
|
||||
Enabling profiling in your application is as simple as one line at the top of your main function
|
||||
|
||||
```go
|
||||
import "github.com/davecheney/profile"
|
||||
|
||||
func main() {
|
||||
defer profile.Start(profile.CPUProfile).Stop()
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
options
|
||||
-------
|
||||
|
||||
What to profile is controlled by the \*profile.Config value passed to profile.Start. A nil
|
||||
Config is the same as choosing all the defaults. By default no profiles are enabled.
|
||||
|
||||
```go
|
||||
import "github.com/davecheney/profile"
|
||||
|
||||
func main() {
|
||||
cfg := profile.Config{
|
||||
MemProfile: true,
|
||||
ProfilePath: ".", // store profiles in current directory
|
||||
NoShutdownHook: true, // do not hook SIGINT
|
||||
}
|
||||
|
||||
// p.Stop() must be called before the program exits to
|
||||
// ensure profiling information is written to disk.
|
||||
p := profile.Start(&cfg)
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Several convenience package level values are provided for cpu, memory, and block (contention) profiling.
|
||||
|
||||
For more complex options, consult the [documentation](http://godoc.org/github.com/davecheney/profile) on the profile.Config type. Enabling more than one profile at once may cause your results to be less reliable as profiling itself is not without overhead.
|
||||
169
vendor/github.com/davecheney/profile/profile.go
generated
vendored
Normal file
169
vendor/github.com/davecheney/profile/profile.go
generated
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
// Package profile provides a simple way to manage runtime/pprof
|
||||
// profiling of your Go application.
|
||||
package profile
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
)
|
||||
|
||||
// Config controls the operation of the profile package.
|
||||
type Config struct {
|
||||
// Quiet suppresses informational messages during profiling.
|
||||
Quiet bool
|
||||
|
||||
// CPUProfile controls if cpu profiling will be enabled.
|
||||
// It defaults to false.
|
||||
CPUProfile bool
|
||||
|
||||
// MemProfile controls if memory profiling will be enabled.
|
||||
// It defaults to false.
|
||||
MemProfile bool
|
||||
|
||||
// BlockProfile controls if block (contention) profiling will
|
||||
// be enabled.
|
||||
// It defaults to false.
|
||||
BlockProfile bool
|
||||
|
||||
// ProfilePath controls the base path where various profiling
|
||||
// files are written. If blank, the base path will be generated
|
||||
// by ioutil.TempDir.
|
||||
ProfilePath string
|
||||
|
||||
// NoShutdownHook controls whether the profiling package should
|
||||
// hook SIGINT to write profiles cleanly.
|
||||
// Programs with more sophisticated signal handling should set
|
||||
// this to true and ensure the Stop() function returned from Start()
|
||||
// is called during shutdown.
|
||||
NoShutdownHook bool
|
||||
}
|
||||
|
||||
var zeroConfig Config
|
||||
|
||||
const memProfileRate = 4096
|
||||
|
||||
func defaultConfig() *Config { return &zeroConfig }
|
||||
|
||||
var (
|
||||
CPUProfile = &Config{
|
||||
CPUProfile: true,
|
||||
}
|
||||
|
||||
MemProfile = &Config{
|
||||
MemProfile: true,
|
||||
}
|
||||
|
||||
BlockProfile = &Config{
|
||||
BlockProfile: true,
|
||||
}
|
||||
)
|
||||
|
||||
type profile struct {
|
||||
path string
|
||||
*Config
|
||||
closers []func()
|
||||
}
|
||||
|
||||
func (p *profile) Stop() {
|
||||
for _, c := range p.closers {
|
||||
c()
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts a new profiling session configured using *Config.
|
||||
// The caller should call the Stop method on the value returned
|
||||
// to cleanly stop profiling.
|
||||
// Passing a nil *Config is the same as passing a *Config with
|
||||
// defaults chosen.
|
||||
func Start(cfg *Config) interface {
|
||||
Stop()
|
||||
} {
|
||||
if cfg == nil {
|
||||
cfg = defaultConfig()
|
||||
}
|
||||
path := cfg.ProfilePath
|
||||
var err error
|
||||
if path == "" {
|
||||
path, err = ioutil.TempDir("", "profile")
|
||||
} else {
|
||||
err = os.MkdirAll(path, 0777)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("profile: could not create initial output directory: %v", err)
|
||||
}
|
||||
prof := &profile{
|
||||
path: path,
|
||||
Config: cfg,
|
||||
}
|
||||
|
||||
if prof.CPUProfile {
|
||||
fn := filepath.Join(prof.path, "cpu.pprof")
|
||||
f, err := os.Create(fn)
|
||||
if err != nil {
|
||||
log.Fatalf("profile: could not create cpu profile %q: %v", fn, err)
|
||||
}
|
||||
if !prof.Quiet {
|
||||
log.Printf("profile: cpu profiling enabled, %s", fn)
|
||||
}
|
||||
pprof.StartCPUProfile(f)
|
||||
prof.closers = append(prof.closers, func() {
|
||||
pprof.StopCPUProfile()
|
||||
f.Close()
|
||||
})
|
||||
}
|
||||
|
||||
if prof.MemProfile {
|
||||
fn := filepath.Join(prof.path, "mem.pprof")
|
||||
f, err := os.Create(fn)
|
||||
if err != nil {
|
||||
log.Fatalf("profile: could not create memory profile %q: %v", fn, err)
|
||||
}
|
||||
old := runtime.MemProfileRate
|
||||
runtime.MemProfileRate = memProfileRate
|
||||
if !prof.Quiet {
|
||||
log.Printf("profile: memory profiling enabled, %s", fn)
|
||||
}
|
||||
prof.closers = append(prof.closers, func() {
|
||||
pprof.Lookup("heap").WriteTo(f, 0)
|
||||
f.Close()
|
||||
runtime.MemProfileRate = old
|
||||
})
|
||||
}
|
||||
|
||||
if prof.BlockProfile {
|
||||
fn := filepath.Join(prof.path, "block.pprof")
|
||||
f, err := os.Create(fn)
|
||||
if err != nil {
|
||||
log.Fatalf("profile: could not create block profile %q: %v", fn, err)
|
||||
}
|
||||
runtime.SetBlockProfileRate(1)
|
||||
if !prof.Quiet {
|
||||
log.Printf("profile: block profiling enabled, %s", fn)
|
||||
}
|
||||
prof.closers = append(prof.closers, func() {
|
||||
pprof.Lookup("block").WriteTo(f, 0)
|
||||
f.Close()
|
||||
runtime.SetBlockProfileRate(0)
|
||||
})
|
||||
}
|
||||
|
||||
if !prof.NoShutdownHook {
|
||||
go func() {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
<-c
|
||||
|
||||
log.Println("profile: caught interrupt, stopping profiles")
|
||||
prof.Stop()
|
||||
|
||||
os.Exit(0)
|
||||
}()
|
||||
}
|
||||
|
||||
return prof
|
||||
}
|
||||
11
vendor/github.com/davecheney/profile/profile_test.go
generated
vendored
Normal file
11
vendor/github.com/davecheney/profile/profile_test.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
package profile_test
|
||||
|
||||
import (
|
||||
"github.com/davecheney/profile"
|
||||
)
|
||||
|
||||
func ExampleStart() {
|
||||
// start a simple CPU profile and register
|
||||
// a defer to Stop (flush) the profiling data.
|
||||
defer profile.Start(profile.CPUProfile).Stop()
|
||||
}
|
||||
13
vendor/github.com/inconshreveable/mousetrap/LICENSE
generated
vendored
Normal file
13
vendor/github.com/inconshreveable/mousetrap/LICENSE
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
Copyright 2014 Alan Shreve
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
23
vendor/github.com/inconshreveable/mousetrap/README.md
generated
vendored
Normal file
23
vendor/github.com/inconshreveable/mousetrap/README.md
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# mousetrap
|
||||
|
||||
mousetrap is a tiny library that answers a single question.
|
||||
|
||||
On a Windows machine, was the process invoked by someone double clicking on
|
||||
the executable file while browsing in explorer?
|
||||
|
||||
### Motivation
|
||||
|
||||
Windows developers unfamiliar with command line tools will often "double-click"
|
||||
the executable for a tool. Because most CLI tools print the help and then exit
|
||||
when invoked without arguments, this is often very frustrating for those users.
|
||||
|
||||
mousetrap provides a way to detect these invocations so that you can provide
|
||||
more helpful behavior and instructions on how to run the CLI tool. To see what
|
||||
this looks like, both from an organizational and a technical perspective, see
|
||||
https://inconshreveable.com/09-09-2014/sweat-the-small-stuff/
|
||||
|
||||
### The interface
|
||||
|
||||
The library exposes a single interface:
|
||||
|
||||
func StartedByExplorer() (bool)
|
||||
15
vendor/github.com/inconshreveable/mousetrap/trap_others.go
generated
vendored
Normal file
15
vendor/github.com/inconshreveable/mousetrap/trap_others.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// +build !windows
|
||||
|
||||
package mousetrap
|
||||
|
||||
// StartedByExplorer returns true if the program was invoked by the user
|
||||
// double-clicking on the executable from explorer.exe
|
||||
//
|
||||
// It is conservative and returns false if any of the internal calls fail.
|
||||
// It does not guarantee that the program was run from a terminal. It only can tell you
|
||||
// whether it was launched from explorer.exe
|
||||
//
|
||||
// On non-Windows platforms, it always returns false.
|
||||
func StartedByExplorer() bool {
|
||||
return false
|
||||
}
|
||||
98
vendor/github.com/inconshreveable/mousetrap/trap_windows.go
generated
vendored
Normal file
98
vendor/github.com/inconshreveable/mousetrap/trap_windows.go
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
// +build windows
|
||||
// +build !go1.4
|
||||
|
||||
package mousetrap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// defined by the Win32 API
|
||||
th32cs_snapprocess uintptr = 0x2
|
||||
)
|
||||
|
||||
var (
|
||||
kernel = syscall.MustLoadDLL("kernel32.dll")
|
||||
CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot")
|
||||
Process32First = kernel.MustFindProc("Process32FirstW")
|
||||
Process32Next = kernel.MustFindProc("Process32NextW")
|
||||
)
|
||||
|
||||
// ProcessEntry32 structure defined by the Win32 API
|
||||
type processEntry32 struct {
|
||||
dwSize uint32
|
||||
cntUsage uint32
|
||||
th32ProcessID uint32
|
||||
th32DefaultHeapID int
|
||||
th32ModuleID uint32
|
||||
cntThreads uint32
|
||||
th32ParentProcessID uint32
|
||||
pcPriClassBase int32
|
||||
dwFlags uint32
|
||||
szExeFile [syscall.MAX_PATH]uint16
|
||||
}
|
||||
|
||||
func getProcessEntry(pid int) (pe *processEntry32, err error) {
|
||||
snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0))
|
||||
if snapshot == uintptr(syscall.InvalidHandle) {
|
||||
err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1)
|
||||
return
|
||||
}
|
||||
defer syscall.CloseHandle(syscall.Handle(snapshot))
|
||||
|
||||
var processEntry processEntry32
|
||||
processEntry.dwSize = uint32(unsafe.Sizeof(processEntry))
|
||||
ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
|
||||
if ok == 0 {
|
||||
err = fmt.Errorf("Process32First: %v", e1)
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
if processEntry.th32ProcessID == uint32(pid) {
|
||||
pe = &processEntry
|
||||
return
|
||||
}
|
||||
|
||||
ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry)))
|
||||
if ok == 0 {
|
||||
err = fmt.Errorf("Process32Next: %v", e1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getppid() (pid int, err error) {
|
||||
pe, err := getProcessEntry(os.Getpid())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pid = int(pe.th32ParentProcessID)
|
||||
return
|
||||
}
|
||||
|
||||
// StartedByExplorer returns true if the program was invoked by the user double-clicking
|
||||
// on the executable from explorer.exe
|
||||
//
|
||||
// It is conservative and returns false if any of the internal calls fail.
|
||||
// It does not guarantee that the program was run from a terminal. It only can tell you
|
||||
// whether it was launched from explorer.exe
|
||||
func StartedByExplorer() bool {
|
||||
ppid, err := getppid()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
pe, err := getProcessEntry(ppid)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
name := syscall.UTF16ToString(pe.szExeFile[:])
|
||||
return name == "explorer.exe"
|
||||
}
|
||||
46
vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go
generated
vendored
Normal file
46
vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
// +build windows
|
||||
// +build go1.4
|
||||
|
||||
package mousetrap
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) {
|
||||
snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer syscall.CloseHandle(snapshot)
|
||||
var procEntry syscall.ProcessEntry32
|
||||
procEntry.Size = uint32(unsafe.Sizeof(procEntry))
|
||||
if err = syscall.Process32First(snapshot, &procEntry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for {
|
||||
if procEntry.ProcessID == uint32(pid) {
|
||||
return &procEntry, nil
|
||||
}
|
||||
err = syscall.Process32Next(snapshot, &procEntry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StartedByExplorer returns true if the program was invoked by the user double-clicking
|
||||
// on the executable from explorer.exe
|
||||
//
|
||||
// It is conservative and returns false if any of the internal calls fail.
|
||||
// It does not guarantee that the program was run from a terminal. It only can tell you
|
||||
// whether it was launched from explorer.exe
|
||||
func StartedByExplorer() bool {
|
||||
pe, err := getProcessEntry(os.Getppid())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:])
|
||||
}
|
||||
21
vendor/github.com/peterh/liner/COPYING
generated
vendored
Normal file
21
vendor/github.com/peterh/liner/COPYING
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
Copyright © 2012 Peter Harris
|
||||
|
||||
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 (including the next
|
||||
paragraph) 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.
|
||||
|
||||
99
vendor/github.com/peterh/liner/README.md
generated
vendored
Normal file
99
vendor/github.com/peterh/liner/README.md
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
Liner
|
||||
=====
|
||||
|
||||
Liner is a command line editor with history. It was inspired by linenoise;
|
||||
everything Unix-like is a VT100 (or is trying very hard to be). If your
|
||||
terminal is not pretending to be a VT100, change it. Liner also support
|
||||
Windows.
|
||||
|
||||
Liner is released under the X11 license (which is similar to the new BSD
|
||||
license).
|
||||
|
||||
Line Editing
|
||||
------------
|
||||
|
||||
The following line editing commands are supported on platforms and terminals
|
||||
that Liner supports:
|
||||
|
||||
Keystroke | Action
|
||||
--------- | ------
|
||||
Ctrl-A, Home | Move cursor to beginning of line
|
||||
Ctrl-E, End | Move cursor to end of line
|
||||
Ctrl-B, Left | Move cursor one character left
|
||||
Ctrl-F, Right| Move cursor one character right
|
||||
Ctrl-Left, Alt-B | Move cursor to previous word
|
||||
Ctrl-Right, Alt-F | Move cursor to next word
|
||||
Ctrl-D, Del | (if line is *not* empty) Delete character under cursor
|
||||
Ctrl-D | (if line *is* empty) End of File - usually quits application
|
||||
Ctrl-C | Reset input (create new empty prompt)
|
||||
Ctrl-L | Clear screen (line is unmodified)
|
||||
Ctrl-T | Transpose previous character with current character
|
||||
Ctrl-H, BackSpace | Delete character before cursor
|
||||
Ctrl-W | Delete word leading up to cursor
|
||||
Ctrl-K | Delete from cursor to end of line
|
||||
Ctrl-U | Delete from start of line to cursor
|
||||
Ctrl-P, Up | Previous match from history
|
||||
Ctrl-N, Down | Next match from history
|
||||
Ctrl-R | Reverse Search history (Ctrl-S forward, Ctrl-G cancel)
|
||||
Ctrl-Y | Paste from Yank buffer (Alt-Y to paste next yank instead)
|
||||
Tab | Next completion
|
||||
Shift-Tab | (after Tab) Previous completion
|
||||
|
||||
Getting started
|
||||
-----------------
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/peterh/liner"
|
||||
)
|
||||
|
||||
var (
|
||||
history_fn = "/tmp/.liner_history"
|
||||
names = []string{"john", "james", "mary", "nancy"}
|
||||
)
|
||||
|
||||
func main() {
|
||||
line := liner.NewLiner()
|
||||
defer line.Close()
|
||||
|
||||
line.SetCtrlCAborts(true)
|
||||
|
||||
line.SetCompleter(func(line string) (c []string) {
|
||||
for _, n := range names {
|
||||
if strings.HasPrefix(n, strings.ToLower(line)) {
|
||||
c = append(c, n)
|
||||
}
|
||||
}
|
||||
return
|
||||
})
|
||||
|
||||
if f, err := os.Open(history_fn); err == nil {
|
||||
line.ReadHistory(f)
|
||||
f.Close()
|
||||
}
|
||||
|
||||
if name, err := line.Prompt("What is your name? "); err == nil {
|
||||
log.Print("Got: ", name)
|
||||
line.AppendHistory(name)
|
||||
} else if err == liner.ErrPromptAborted {
|
||||
log.Print("Aborted")
|
||||
} else {
|
||||
log.Print("Error reading line: ", err)
|
||||
}
|
||||
|
||||
if f, err := os.Create(history_fn); err != nil {
|
||||
log.Print("Error writing history file: ", err)
|
||||
} else {
|
||||
line.WriteHistory(f)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For documentation, see http://godoc.org/github.com/peterh/liner
|
||||
39
vendor/github.com/peterh/liner/bsdinput.go
generated
vendored
Normal file
39
vendor/github.com/peterh/liner/bsdinput.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
// +build openbsd freebsd netbsd
|
||||
|
||||
package liner
|
||||
|
||||
import "syscall"
|
||||
|
||||
const (
|
||||
getTermios = syscall.TIOCGETA
|
||||
setTermios = syscall.TIOCSETA
|
||||
)
|
||||
|
||||
const (
|
||||
// Input flags
|
||||
inpck = 0x010
|
||||
istrip = 0x020
|
||||
icrnl = 0x100
|
||||
ixon = 0x200
|
||||
|
||||
// Output flags
|
||||
opost = 0x1
|
||||
|
||||
// Control flags
|
||||
cs8 = 0x300
|
||||
|
||||
// Local flags
|
||||
isig = 0x080
|
||||
icanon = 0x100
|
||||
iexten = 0x400
|
||||
)
|
||||
|
||||
type termios struct {
|
||||
Iflag uint32
|
||||
Oflag uint32
|
||||
Cflag uint32
|
||||
Lflag uint32
|
||||
Cc [20]byte
|
||||
Ispeed int32
|
||||
Ospeed int32
|
||||
}
|
||||
219
vendor/github.com/peterh/liner/common.go
generated
vendored
Normal file
219
vendor/github.com/peterh/liner/common.go
generated
vendored
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
Package liner implements a simple command line editor, inspired by linenoise
|
||||
(https://github.com/antirez/linenoise/). This package supports WIN32 in
|
||||
addition to the xterm codes supported by everything else.
|
||||
*/
|
||||
package liner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"container/ring"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type commonState struct {
|
||||
terminalSupported bool
|
||||
outputRedirected bool
|
||||
inputRedirected bool
|
||||
history []string
|
||||
historyMutex sync.RWMutex
|
||||
completer WordCompleter
|
||||
columns int
|
||||
killRing *ring.Ring
|
||||
ctrlCAborts bool
|
||||
r *bufio.Reader
|
||||
tabStyle TabStyle
|
||||
}
|
||||
|
||||
// TabStyle is used to select how tab completions are displayed.
|
||||
type TabStyle int
|
||||
|
||||
// Two tab styles are currently available:
|
||||
//
|
||||
// TabCircular cycles through each completion item and displays it directly on
|
||||
// the prompt
|
||||
//
|
||||
// TabPrints prints the list of completion items to the screen after a second
|
||||
// tab key is pressed. This behaves similar to GNU readline and BASH (which
|
||||
// uses readline)
|
||||
const (
|
||||
TabCircular TabStyle = iota
|
||||
TabPrints
|
||||
)
|
||||
|
||||
// ErrPromptAborted is returned from Prompt or PasswordPrompt when the user presses Ctrl-C
|
||||
// if SetCtrlCAborts(true) has been called on the State
|
||||
var ErrPromptAborted = errors.New("prompt aborted")
|
||||
|
||||
// ErrNotTerminalOutput is returned from Prompt or PasswordPrompt if the
|
||||
// platform is normally supported, but stdout has been redirected
|
||||
var ErrNotTerminalOutput = errors.New("standard output is not a terminal")
|
||||
|
||||
// Max elements to save on the killring
|
||||
const KillRingMax = 60
|
||||
|
||||
// HistoryLimit is the maximum number of entries saved in the scrollback history.
|
||||
const HistoryLimit = 1000
|
||||
|
||||
// ReadHistory reads scrollback history from r. Returns the number of lines
|
||||
// read, and any read error (except io.EOF).
|
||||
func (s *State) ReadHistory(r io.Reader) (num int, err error) {
|
||||
s.historyMutex.Lock()
|
||||
defer s.historyMutex.Unlock()
|
||||
|
||||
in := bufio.NewReader(r)
|
||||
num = 0
|
||||
for {
|
||||
line, part, err := in.ReadLine()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return num, err
|
||||
}
|
||||
if part {
|
||||
return num, fmt.Errorf("line %d is too long", num+1)
|
||||
}
|
||||
if !utf8.Valid(line) {
|
||||
return num, fmt.Errorf("invalid string at line %d", num+1)
|
||||
}
|
||||
num++
|
||||
s.history = append(s.history, string(line))
|
||||
if len(s.history) > HistoryLimit {
|
||||
s.history = s.history[1:]
|
||||
}
|
||||
}
|
||||
return num, nil
|
||||
}
|
||||
|
||||
// WriteHistory writes scrollback history to w. Returns the number of lines
|
||||
// successfully written, and any write error.
|
||||
//
|
||||
// Unlike the rest of liner's API, WriteHistory is safe to call
|
||||
// from another goroutine while Prompt is in progress.
|
||||
// This exception is to facilitate the saving of the history buffer
|
||||
// during an unexpected exit (for example, due to Ctrl-C being invoked)
|
||||
func (s *State) WriteHistory(w io.Writer) (num int, err error) {
|
||||
s.historyMutex.RLock()
|
||||
defer s.historyMutex.RUnlock()
|
||||
|
||||
for _, item := range s.history {
|
||||
_, err := fmt.Fprintln(w, item)
|
||||
if err != nil {
|
||||
return num, err
|
||||
}
|
||||
num++
|
||||
}
|
||||
return num, nil
|
||||
}
|
||||
|
||||
// AppendHistory appends an entry to the scrollback history. AppendHistory
|
||||
// should be called iff Prompt returns a valid command.
|
||||
func (s *State) AppendHistory(item string) {
|
||||
s.historyMutex.Lock()
|
||||
defer s.historyMutex.Unlock()
|
||||
|
||||
if len(s.history) > 0 {
|
||||
if item == s.history[len(s.history)-1] {
|
||||
return
|
||||
}
|
||||
}
|
||||
s.history = append(s.history, item)
|
||||
if len(s.history) > HistoryLimit {
|
||||
s.history = s.history[1:]
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the history lines starting with prefix
|
||||
func (s *State) getHistoryByPrefix(prefix string) (ph []string) {
|
||||
for _, h := range s.history {
|
||||
if strings.HasPrefix(h, prefix) {
|
||||
ph = append(ph, h)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Returns the history lines matching the inteligent search
|
||||
func (s *State) getHistoryByPattern(pattern string) (ph []string, pos []int) {
|
||||
if pattern == "" {
|
||||
return
|
||||
}
|
||||
for _, h := range s.history {
|
||||
if i := strings.Index(h, pattern); i >= 0 {
|
||||
ph = append(ph, h)
|
||||
pos = append(pos, i)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Completer takes the currently edited line content at the left of the cursor
|
||||
// and returns a list of completion candidates.
|
||||
// If the line is "Hello, wo!!!" and the cursor is before the first '!', "Hello, wo" is passed
|
||||
// to the completer which may return {"Hello, world", "Hello, Word"} to have "Hello, world!!!".
|
||||
type Completer func(line string) []string
|
||||
|
||||
// WordCompleter takes the currently edited line with the cursor position and
|
||||
// returns the completion candidates for the partial word to be completed.
|
||||
// If the line is "Hello, wo!!!" and the cursor is before the first '!', ("Hello, wo!!!", 9) is passed
|
||||
// to the completer which may returns ("Hello, ", {"world", "Word"}, "!!!") to have "Hello, world!!!".
|
||||
type WordCompleter func(line string, pos int) (head string, completions []string, tail string)
|
||||
|
||||
// SetCompleter sets the completion function that Liner will call to
|
||||
// fetch completion candidates when the user presses tab.
|
||||
func (s *State) SetCompleter(f Completer) {
|
||||
if f == nil {
|
||||
s.completer = nil
|
||||
return
|
||||
}
|
||||
s.completer = func(line string, pos int) (string, []string, string) {
|
||||
return "", f(line[:pos]), line[pos:]
|
||||
}
|
||||
}
|
||||
|
||||
// SetWordCompleter sets the completion function that Liner will call to
|
||||
// fetch completion candidates when the user presses tab.
|
||||
func (s *State) SetWordCompleter(f WordCompleter) {
|
||||
s.completer = f
|
||||
}
|
||||
|
||||
// SetTabCompletionStyle sets the behvavior when the Tab key is pressed
|
||||
// for auto-completion. TabCircular is the default behavior and cycles
|
||||
// through the list of candidates at the prompt. TabPrints will print
|
||||
// the available completion candidates to the screen similar to BASH
|
||||
// and GNU Readline
|
||||
func (s *State) SetTabCompletionStyle(tabStyle TabStyle) {
|
||||
s.tabStyle = tabStyle
|
||||
}
|
||||
|
||||
// ModeApplier is the interface that wraps a representation of the terminal
|
||||
// mode. ApplyMode sets the terminal to this mode.
|
||||
type ModeApplier interface {
|
||||
ApplyMode() error
|
||||
}
|
||||
|
||||
// SetCtrlCAborts sets whether Prompt on a supported terminal will return an
|
||||
// ErrPromptAborted when Ctrl-C is pressed. The default is false (will not
|
||||
// return when Ctrl-C is pressed). Unsupported terminals typically raise SIGINT
|
||||
// (and Prompt does not return) regardless of the value passed to SetCtrlCAborts.
|
||||
func (s *State) SetCtrlCAborts(aborts bool) {
|
||||
s.ctrlCAborts = aborts
|
||||
}
|
||||
|
||||
func (s *State) promptUnsupported(p string) (string, error) {
|
||||
if !s.inputRedirected || !s.terminalSupported {
|
||||
fmt.Print(p)
|
||||
}
|
||||
linebuf, _, err := s.r.ReadLine()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bytes.TrimSpace(linebuf)), nil
|
||||
}
|
||||
57
vendor/github.com/peterh/liner/fallbackinput.go
generated
vendored
Normal file
57
vendor/github.com/peterh/liner/fallbackinput.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
// +build !windows,!linux,!darwin,!openbsd,!freebsd,!netbsd
|
||||
|
||||
package liner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
// State represents an open terminal
|
||||
type State struct {
|
||||
commonState
|
||||
}
|
||||
|
||||
// Prompt displays p, and then waits for user input. Prompt does not support
|
||||
// line editing on this operating system.
|
||||
func (s *State) Prompt(p string) (string, error) {
|
||||
return s.promptUnsupported(p)
|
||||
}
|
||||
|
||||
// PasswordPrompt is not supported in this OS.
|
||||
func (s *State) PasswordPrompt(p string) (string, error) {
|
||||
return "", errors.New("liner: function not supported in this terminal")
|
||||
}
|
||||
|
||||
// NewLiner initializes a new *State
|
||||
//
|
||||
// Note that this operating system uses a fallback mode without line
|
||||
// editing. Patches welcome.
|
||||
func NewLiner() *State {
|
||||
var s State
|
||||
s.r = bufio.NewReader(os.Stdin)
|
||||
return &s
|
||||
}
|
||||
|
||||
// Close returns the terminal to its previous mode
|
||||
func (s *State) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TerminalSupported returns false because line editing is not
|
||||
// supported on this platform.
|
||||
func TerminalSupported() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type noopMode struct{}
|
||||
|
||||
func (n noopMode) ApplyMode() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TerminalMode returns a noop InputModeSetter on this platform.
|
||||
func TerminalMode() (ModeApplier, error) {
|
||||
return noopMode{}, nil
|
||||
}
|
||||
368
vendor/github.com/peterh/liner/input.go
generated
vendored
Normal file
368
vendor/github.com/peterh/liner/input.go
generated
vendored
Normal file
@ -0,0 +1,368 @@
|
||||
// +build linux darwin openbsd freebsd netbsd
|
||||
|
||||
package liner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type nexter struct {
|
||||
r rune
|
||||
err error
|
||||
}
|
||||
|
||||
// State represents an open terminal
|
||||
type State struct {
|
||||
commonState
|
||||
origMode termios
|
||||
defaultMode termios
|
||||
next <-chan nexter
|
||||
winch chan os.Signal
|
||||
pending []rune
|
||||
useCHA bool
|
||||
}
|
||||
|
||||
// NewLiner initializes a new *State, and sets the terminal into raw mode. To
|
||||
// restore the terminal to its previous state, call State.Close().
|
||||
//
|
||||
// Note if you are still using Go 1.0: NewLiner handles SIGWINCH, so it will
|
||||
// leak a channel every time you call it. Therefore, it is recommened that you
|
||||
// upgrade to a newer release of Go, or ensure that NewLiner is only called
|
||||
// once.
|
||||
func NewLiner() *State {
|
||||
var s State
|
||||
s.r = bufio.NewReader(os.Stdin)
|
||||
|
||||
s.terminalSupported = TerminalSupported()
|
||||
if m, err := TerminalMode(); err == nil {
|
||||
s.origMode = *m.(*termios)
|
||||
} else {
|
||||
s.inputRedirected = true
|
||||
}
|
||||
if _, err := getMode(syscall.Stdout); err != 0 {
|
||||
s.outputRedirected = true
|
||||
}
|
||||
if s.inputRedirected && s.outputRedirected {
|
||||
s.terminalSupported = false
|
||||
}
|
||||
if s.terminalSupported && !s.inputRedirected && !s.outputRedirected {
|
||||
mode := s.origMode
|
||||
mode.Iflag &^= icrnl | inpck | istrip | ixon
|
||||
mode.Cflag |= cs8
|
||||
mode.Lflag &^= syscall.ECHO | icanon | iexten
|
||||
mode.ApplyMode()
|
||||
|
||||
winch := make(chan os.Signal, 1)
|
||||
signal.Notify(winch, syscall.SIGWINCH)
|
||||
s.winch = winch
|
||||
|
||||
s.checkOutput()
|
||||
}
|
||||
|
||||
if !s.outputRedirected {
|
||||
s.getColumns()
|
||||
s.outputRedirected = s.columns <= 0
|
||||
}
|
||||
|
||||
return &s
|
||||
}
|
||||
|
||||
var errTimedOut = errors.New("timeout")
|
||||
|
||||
func (s *State) startPrompt() {
|
||||
if s.terminalSupported {
|
||||
if m, err := TerminalMode(); err == nil {
|
||||
s.defaultMode = *m.(*termios)
|
||||
mode := s.defaultMode
|
||||
mode.Lflag &^= isig
|
||||
mode.ApplyMode()
|
||||
}
|
||||
}
|
||||
s.restartPrompt()
|
||||
}
|
||||
|
||||
func (s *State) restartPrompt() {
|
||||
next := make(chan nexter)
|
||||
go func() {
|
||||
for {
|
||||
var n nexter
|
||||
n.r, _, n.err = s.r.ReadRune()
|
||||
next <- n
|
||||
// Shut down nexter loop when an end condition has been reached
|
||||
if n.err != nil || n.r == '\n' || n.r == '\r' || n.r == ctrlC || n.r == ctrlD {
|
||||
close(next)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
s.next = next
|
||||
}
|
||||
|
||||
func (s *State) stopPrompt() {
|
||||
if s.terminalSupported {
|
||||
s.defaultMode.ApplyMode()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) nextPending(timeout <-chan time.Time) (rune, error) {
|
||||
select {
|
||||
case thing, ok := <-s.next:
|
||||
if !ok {
|
||||
return 0, errors.New("liner: internal error")
|
||||
}
|
||||
if thing.err != nil {
|
||||
return 0, thing.err
|
||||
}
|
||||
s.pending = append(s.pending, thing.r)
|
||||
return thing.r, nil
|
||||
case <-timeout:
|
||||
rv := s.pending[0]
|
||||
s.pending = s.pending[1:]
|
||||
return rv, errTimedOut
|
||||
}
|
||||
// not reached
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (s *State) readNext() (interface{}, error) {
|
||||
if len(s.pending) > 0 {
|
||||
rv := s.pending[0]
|
||||
s.pending = s.pending[1:]
|
||||
return rv, nil
|
||||
}
|
||||
var r rune
|
||||
select {
|
||||
case thing, ok := <-s.next:
|
||||
if !ok {
|
||||
return 0, errors.New("liner: internal error")
|
||||
}
|
||||
if thing.err != nil {
|
||||
return nil, thing.err
|
||||
}
|
||||
r = thing.r
|
||||
case <-s.winch:
|
||||
s.getColumns()
|
||||
return winch, nil
|
||||
}
|
||||
if r != esc {
|
||||
return r, nil
|
||||
}
|
||||
s.pending = append(s.pending, r)
|
||||
|
||||
// Wait at most 50 ms for the rest of the escape sequence
|
||||
// If nothing else arrives, it was an actual press of the esc key
|
||||
timeout := time.After(50 * time.Millisecond)
|
||||
flag, err := s.nextPending(timeout)
|
||||
if err != nil {
|
||||
if err == errTimedOut {
|
||||
return flag, nil
|
||||
}
|
||||
return unknown, err
|
||||
}
|
||||
|
||||
switch flag {
|
||||
case '[':
|
||||
code, err := s.nextPending(timeout)
|
||||
if err != nil {
|
||||
if err == errTimedOut {
|
||||
return code, nil
|
||||
}
|
||||
return unknown, err
|
||||
}
|
||||
switch code {
|
||||
case 'A':
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
return up, nil
|
||||
case 'B':
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
return down, nil
|
||||
case 'C':
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
return right, nil
|
||||
case 'D':
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
return left, nil
|
||||
case 'F':
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
return end, nil
|
||||
case 'H':
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
return home, nil
|
||||
case 'Z':
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
return shiftTab, nil
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
num := []rune{code}
|
||||
for {
|
||||
code, err := s.nextPending(timeout)
|
||||
if err != nil {
|
||||
if err == errTimedOut {
|
||||
return code, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
switch code {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
num = append(num, code)
|
||||
case ';':
|
||||
// Modifier code to follow
|
||||
// This only supports Ctrl-left and Ctrl-right for now
|
||||
x, _ := strconv.ParseInt(string(num), 10, 32)
|
||||
if x != 1 {
|
||||
// Can't be left or right
|
||||
rv := s.pending[0]
|
||||
s.pending = s.pending[1:]
|
||||
return rv, nil
|
||||
}
|
||||
num = num[:0]
|
||||
for {
|
||||
code, err = s.nextPending(timeout)
|
||||
if err != nil {
|
||||
if err == errTimedOut {
|
||||
rv := s.pending[0]
|
||||
s.pending = s.pending[1:]
|
||||
return rv, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
switch code {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
num = append(num, code)
|
||||
case 'C', 'D':
|
||||
// right, left
|
||||
mod, _ := strconv.ParseInt(string(num), 10, 32)
|
||||
if mod != 5 {
|
||||
// Not bare Ctrl
|
||||
rv := s.pending[0]
|
||||
s.pending = s.pending[1:]
|
||||
return rv, nil
|
||||
}
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
if code == 'C' {
|
||||
return wordRight, nil
|
||||
}
|
||||
return wordLeft, nil
|
||||
default:
|
||||
// Not left or right
|
||||
rv := s.pending[0]
|
||||
s.pending = s.pending[1:]
|
||||
return rv, nil
|
||||
}
|
||||
}
|
||||
case '~':
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
x, _ := strconv.ParseInt(string(num), 10, 32)
|
||||
switch x {
|
||||
case 2:
|
||||
return insert, nil
|
||||
case 3:
|
||||
return del, nil
|
||||
case 5:
|
||||
return pageUp, nil
|
||||
case 6:
|
||||
return pageDown, nil
|
||||
case 7:
|
||||
return home, nil
|
||||
case 8:
|
||||
return end, nil
|
||||
case 15:
|
||||
return f5, nil
|
||||
case 17:
|
||||
return f6, nil
|
||||
case 18:
|
||||
return f7, nil
|
||||
case 19:
|
||||
return f8, nil
|
||||
case 20:
|
||||
return f9, nil
|
||||
case 21:
|
||||
return f10, nil
|
||||
case 23:
|
||||
return f11, nil
|
||||
case 24:
|
||||
return f12, nil
|
||||
default:
|
||||
return unknown, nil
|
||||
}
|
||||
default:
|
||||
// unrecognized escape code
|
||||
rv := s.pending[0]
|
||||
s.pending = s.pending[1:]
|
||||
return rv, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case 'O':
|
||||
code, err := s.nextPending(timeout)
|
||||
if err != nil {
|
||||
if err == errTimedOut {
|
||||
return code, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
switch code {
|
||||
case 'c':
|
||||
return wordRight, nil
|
||||
case 'd':
|
||||
return wordLeft, nil
|
||||
case 'H':
|
||||
return home, nil
|
||||
case 'F':
|
||||
return end, nil
|
||||
case 'P':
|
||||
return f1, nil
|
||||
case 'Q':
|
||||
return f2, nil
|
||||
case 'R':
|
||||
return f3, nil
|
||||
case 'S':
|
||||
return f4, nil
|
||||
default:
|
||||
return unknown, nil
|
||||
}
|
||||
case 'b':
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
return altB, nil
|
||||
case 'f':
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
return altF, nil
|
||||
case 'y':
|
||||
s.pending = s.pending[:0] // escape code complete
|
||||
return altY, nil
|
||||
default:
|
||||
rv := s.pending[0]
|
||||
s.pending = s.pending[1:]
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
// not reached
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Close returns the terminal to its previous mode
|
||||
func (s *State) Close() error {
|
||||
stopSignal(s.winch)
|
||||
if !s.inputRedirected {
|
||||
s.origMode.ApplyMode()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TerminalSupported returns true if the current terminal supports
|
||||
// line editing features, and false if liner will use the 'dumb'
|
||||
// fallback for input.
|
||||
// Note that TerminalSupported does not check all factors that may
|
||||
// cause liner to not fully support the terminal (such as stdin redirection)
|
||||
func TerminalSupported() bool {
|
||||
bad := map[string]bool{"": true, "dumb": true, "cons25": true}
|
||||
return !bad[strings.ToLower(os.Getenv("TERM"))]
|
||||
}
|
||||
39
vendor/github.com/peterh/liner/input_darwin.go
generated
vendored
Normal file
39
vendor/github.com/peterh/liner/input_darwin.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
// +build darwin
|
||||
|
||||
package liner
|
||||
|
||||
import "syscall"
|
||||
|
||||
const (
|
||||
getTermios = syscall.TIOCGETA
|
||||
setTermios = syscall.TIOCSETA
|
||||
)
|
||||
|
||||
const (
|
||||
// Input flags
|
||||
inpck = 0x010
|
||||
istrip = 0x020
|
||||
icrnl = 0x100
|
||||
ixon = 0x200
|
||||
|
||||
// Output flags
|
||||
opost = 0x1
|
||||
|
||||
// Control flags
|
||||
cs8 = 0x300
|
||||
|
||||
// Local flags
|
||||
isig = 0x080
|
||||
icanon = 0x100
|
||||
iexten = 0x400
|
||||
)
|
||||
|
||||
type termios struct {
|
||||
Iflag uintptr
|
||||
Oflag uintptr
|
||||
Cflag uintptr
|
||||
Lflag uintptr
|
||||
Cc [20]byte
|
||||
Ispeed uintptr
|
||||
Ospeed uintptr
|
||||
}
|
||||
26
vendor/github.com/peterh/liner/input_linux.go
generated
vendored
Normal file
26
vendor/github.com/peterh/liner/input_linux.go
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// +build linux
|
||||
|
||||
package liner
|
||||
|
||||
import "syscall"
|
||||
|
||||
const (
|
||||
getTermios = syscall.TCGETS
|
||||
setTermios = syscall.TCSETS
|
||||
)
|
||||
|
||||
const (
|
||||
icrnl = syscall.ICRNL
|
||||
inpck = syscall.INPCK
|
||||
istrip = syscall.ISTRIP
|
||||
ixon = syscall.IXON
|
||||
opost = syscall.OPOST
|
||||
cs8 = syscall.CS8
|
||||
isig = syscall.ISIG
|
||||
icanon = syscall.ICANON
|
||||
iexten = syscall.IEXTEN
|
||||
)
|
||||
|
||||
type termios struct {
|
||||
syscall.Termios
|
||||
}
|
||||
61
vendor/github.com/peterh/liner/input_test.go
generated
vendored
Normal file
61
vendor/github.com/peterh/liner/input_test.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
// +build !windows
|
||||
|
||||
package liner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func (s *State) expectRune(t *testing.T, r rune) {
|
||||
item, err := s.readNext()
|
||||
if err != nil {
|
||||
t.Fatalf("Expected rune '%c', got error %s\n", r, err)
|
||||
}
|
||||
if v, ok := item.(rune); !ok {
|
||||
t.Fatalf("Expected rune '%c', got non-rune %v\n", r, v)
|
||||
} else {
|
||||
if v != r {
|
||||
t.Fatalf("Expected rune '%c', got rune '%c'\n", r, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) expectAction(t *testing.T, a action) {
|
||||
item, err := s.readNext()
|
||||
if err != nil {
|
||||
t.Fatalf("Expected Action %d, got error %s\n", a, err)
|
||||
}
|
||||
if v, ok := item.(action); !ok {
|
||||
t.Fatalf("Expected Action %d, got non-Action %v\n", a, v)
|
||||
} else {
|
||||
if v != a {
|
||||
t.Fatalf("Expected Action %d, got Action %d\n", a, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTypes(t *testing.T) {
|
||||
input := []byte{'A', 27, 'B', 27, 91, 68, 27, '[', '1', ';', '5', 'D', 'e'}
|
||||
var s State
|
||||
s.r = bufio.NewReader(bytes.NewBuffer(input))
|
||||
|
||||
next := make(chan nexter)
|
||||
go func() {
|
||||
for {
|
||||
var n nexter
|
||||
n.r, _, n.err = s.r.ReadRune()
|
||||
next <- n
|
||||
}
|
||||
}()
|
||||
s.next = next
|
||||
|
||||
s.expectRune(t, 'A')
|
||||
s.expectRune(t, 27)
|
||||
s.expectRune(t, 'B')
|
||||
s.expectAction(t, left)
|
||||
s.expectAction(t, wordLeft)
|
||||
|
||||
s.expectRune(t, 'e')
|
||||
}
|
||||
321
vendor/github.com/peterh/liner/input_windows.go
generated
vendored
Normal file
321
vendor/github.com/peterh/liner/input_windows.go
generated
vendored
Normal file
@ -0,0 +1,321 @@
|
||||
package liner
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
procGetStdHandle = kernel32.NewProc("GetStdHandle")
|
||||
procReadConsoleInput = kernel32.NewProc("ReadConsoleInputW")
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
|
||||
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
|
||||
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
|
||||
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
|
||||
)
|
||||
|
||||
// These names are from the Win32 api, so they use underscores (contrary to
|
||||
// what golint suggests)
|
||||
const (
|
||||
std_input_handle = uint32(-10 & 0xFFFFFFFF)
|
||||
std_output_handle = uint32(-11 & 0xFFFFFFFF)
|
||||
std_error_handle = uint32(-12 & 0xFFFFFFFF)
|
||||
invalid_handle_value = ^uintptr(0)
|
||||
)
|
||||
|
||||
type inputMode uint32
|
||||
|
||||
// State represents an open terminal
|
||||
type State struct {
|
||||
commonState
|
||||
handle syscall.Handle
|
||||
hOut syscall.Handle
|
||||
origMode inputMode
|
||||
defaultMode inputMode
|
||||
key interface{}
|
||||
repeat uint16
|
||||
}
|
||||
|
||||
const (
|
||||
enableEchoInput = 0x4
|
||||
enableInsertMode = 0x20
|
||||
enableLineInput = 0x2
|
||||
enableMouseInput = 0x10
|
||||
enableProcessedInput = 0x1
|
||||
enableQuickEditMode = 0x40
|
||||
enableWindowInput = 0x8
|
||||
)
|
||||
|
||||
// NewLiner initializes a new *State, and sets the terminal into raw mode. To
|
||||
// restore the terminal to its previous state, call State.Close().
|
||||
func NewLiner() *State {
|
||||
var s State
|
||||
hIn, _, _ := procGetStdHandle.Call(uintptr(std_input_handle))
|
||||
s.handle = syscall.Handle(hIn)
|
||||
hOut, _, _ := procGetStdHandle.Call(uintptr(std_output_handle))
|
||||
s.hOut = syscall.Handle(hOut)
|
||||
|
||||
s.terminalSupported = true
|
||||
if m, err := TerminalMode(); err == nil {
|
||||
s.origMode = m.(inputMode)
|
||||
mode := s.origMode
|
||||
mode &^= enableEchoInput
|
||||
mode &^= enableInsertMode
|
||||
mode &^= enableLineInput
|
||||
mode &^= enableMouseInput
|
||||
mode |= enableWindowInput
|
||||
mode.ApplyMode()
|
||||
} else {
|
||||
s.inputRedirected = true
|
||||
s.r = bufio.NewReader(os.Stdin)
|
||||
}
|
||||
|
||||
s.getColumns()
|
||||
s.outputRedirected = s.columns <= 0
|
||||
|
||||
return &s
|
||||
}
|
||||
|
||||
// These names are from the Win32 api, so they use underscores (contrary to
|
||||
// what golint suggests)
|
||||
const (
|
||||
focus_event = 0x0010
|
||||
key_event = 0x0001
|
||||
menu_event = 0x0008
|
||||
mouse_event = 0x0002
|
||||
window_buffer_size_event = 0x0004
|
||||
)
|
||||
|
||||
type input_record struct {
|
||||
eventType uint16
|
||||
pad uint16
|
||||
blob [16]byte
|
||||
}
|
||||
|
||||
type key_event_record struct {
|
||||
KeyDown int32
|
||||
RepeatCount uint16
|
||||
VirtualKeyCode uint16
|
||||
VirtualScanCode uint16
|
||||
Char int16
|
||||
ControlKeyState uint32
|
||||
}
|
||||
|
||||
// These names are from the Win32 api, so they use underscores (contrary to
|
||||
// what golint suggests)
|
||||
const (
|
||||
vk_tab = 0x09
|
||||
vk_prior = 0x21
|
||||
vk_next = 0x22
|
||||
vk_end = 0x23
|
||||
vk_home = 0x24
|
||||
vk_left = 0x25
|
||||
vk_up = 0x26
|
||||
vk_right = 0x27
|
||||
vk_down = 0x28
|
||||
vk_insert = 0x2d
|
||||
vk_delete = 0x2e
|
||||
vk_f1 = 0x70
|
||||
vk_f2 = 0x71
|
||||
vk_f3 = 0x72
|
||||
vk_f4 = 0x73
|
||||
vk_f5 = 0x74
|
||||
vk_f6 = 0x75
|
||||
vk_f7 = 0x76
|
||||
vk_f8 = 0x77
|
||||
vk_f9 = 0x78
|
||||
vk_f10 = 0x79
|
||||
vk_f11 = 0x7a
|
||||
vk_f12 = 0x7b
|
||||
bKey = 0x42
|
||||
fKey = 0x46
|
||||
yKey = 0x59
|
||||
)
|
||||
|
||||
const (
|
||||
shiftPressed = 0x0010
|
||||
leftAltPressed = 0x0002
|
||||
leftCtrlPressed = 0x0008
|
||||
rightAltPressed = 0x0001
|
||||
rightCtrlPressed = 0x0004
|
||||
|
||||
modKeys = shiftPressed | leftAltPressed | rightAltPressed | leftCtrlPressed | rightCtrlPressed
|
||||
)
|
||||
|
||||
func (s *State) readNext() (interface{}, error) {
|
||||
if s.repeat > 0 {
|
||||
s.repeat--
|
||||
return s.key, nil
|
||||
}
|
||||
|
||||
var input input_record
|
||||
pbuf := uintptr(unsafe.Pointer(&input))
|
||||
var rv uint32
|
||||
prv := uintptr(unsafe.Pointer(&rv))
|
||||
|
||||
for {
|
||||
ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv)
|
||||
|
||||
if ok == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if input.eventType == window_buffer_size_event {
|
||||
xy := (*coord)(unsafe.Pointer(&input.blob[0]))
|
||||
s.columns = int(xy.x)
|
||||
return winch, nil
|
||||
}
|
||||
if input.eventType != key_event {
|
||||
continue
|
||||
}
|
||||
ke := (*key_event_record)(unsafe.Pointer(&input.blob[0]))
|
||||
if ke.KeyDown == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if ke.VirtualKeyCode == vk_tab && ke.ControlKeyState&modKeys == shiftPressed {
|
||||
s.key = shiftTab
|
||||
} else if ke.VirtualKeyCode == bKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
|
||||
ke.ControlKeyState&modKeys == rightAltPressed) {
|
||||
s.key = altB
|
||||
} else if ke.VirtualKeyCode == fKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
|
||||
ke.ControlKeyState&modKeys == rightAltPressed) {
|
||||
s.key = altF
|
||||
} else if ke.VirtualKeyCode == yKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
|
||||
ke.ControlKeyState&modKeys == rightAltPressed) {
|
||||
s.key = altY
|
||||
} else if ke.Char > 0 {
|
||||
s.key = rune(ke.Char)
|
||||
} else {
|
||||
switch ke.VirtualKeyCode {
|
||||
case vk_prior:
|
||||
s.key = pageUp
|
||||
case vk_next:
|
||||
s.key = pageDown
|
||||
case vk_end:
|
||||
s.key = end
|
||||
case vk_home:
|
||||
s.key = home
|
||||
case vk_left:
|
||||
s.key = left
|
||||
if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 {
|
||||
if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) {
|
||||
s.key = wordLeft
|
||||
}
|
||||
}
|
||||
case vk_right:
|
||||
s.key = right
|
||||
if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 {
|
||||
if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) {
|
||||
s.key = wordRight
|
||||
}
|
||||
}
|
||||
case vk_up:
|
||||
s.key = up
|
||||
case vk_down:
|
||||
s.key = down
|
||||
case vk_insert:
|
||||
s.key = insert
|
||||
case vk_delete:
|
||||
s.key = del
|
||||
case vk_f1:
|
||||
s.key = f1
|
||||
case vk_f2:
|
||||
s.key = f2
|
||||
case vk_f3:
|
||||
s.key = f3
|
||||
case vk_f4:
|
||||
s.key = f4
|
||||
case vk_f5:
|
||||
s.key = f5
|
||||
case vk_f6:
|
||||
s.key = f6
|
||||
case vk_f7:
|
||||
s.key = f7
|
||||
case vk_f8:
|
||||
s.key = f8
|
||||
case vk_f9:
|
||||
s.key = f9
|
||||
case vk_f10:
|
||||
s.key = f10
|
||||
case vk_f11:
|
||||
s.key = f11
|
||||
case vk_f12:
|
||||
s.key = f12
|
||||
default:
|
||||
// Eat modifier keys
|
||||
// TODO: return Action(Unknown) if the key isn't a
|
||||
// modifier.
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if ke.RepeatCount > 1 {
|
||||
s.repeat = ke.RepeatCount - 1
|
||||
}
|
||||
return s.key, nil
|
||||
}
|
||||
return unknown, nil
|
||||
}
|
||||
|
||||
// Close returns the terminal to its previous mode
|
||||
func (s *State) Close() error {
|
||||
s.origMode.ApplyMode()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *State) startPrompt() {
|
||||
if m, err := TerminalMode(); err == nil {
|
||||
s.defaultMode = m.(inputMode)
|
||||
mode := s.defaultMode
|
||||
mode &^= enableProcessedInput
|
||||
mode.ApplyMode()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) restartPrompt() {
|
||||
}
|
||||
|
||||
func (s *State) stopPrompt() {
|
||||
s.defaultMode.ApplyMode()
|
||||
}
|
||||
|
||||
// TerminalSupported returns true because line editing is always
|
||||
// supported on Windows.
|
||||
func TerminalSupported() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (mode inputMode) ApplyMode() error {
|
||||
hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle))
|
||||
if hIn == invalid_handle_value || hIn == 0 {
|
||||
return err
|
||||
}
|
||||
ok, _, err := procSetConsoleMode.Call(hIn, uintptr(mode))
|
||||
if ok != 0 {
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// TerminalMode returns the current terminal input mode as an InputModeSetter.
|
||||
//
|
||||
// This function is provided for convenience, and should
|
||||
// not be necessary for most users of liner.
|
||||
func TerminalMode() (ModeApplier, error) {
|
||||
var mode inputMode
|
||||
hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle))
|
||||
if hIn == invalid_handle_value || hIn == 0 {
|
||||
return nil, err
|
||||
}
|
||||
ok, _, err := procGetConsoleMode.Call(hIn, uintptr(unsafe.Pointer(&mode)))
|
||||
if ok != 0 {
|
||||
err = nil
|
||||
}
|
||||
return mode, err
|
||||
}
|
||||
884
vendor/github.com/peterh/liner/line.go
generated
vendored
Normal file
884
vendor/github.com/peterh/liner/line.go
generated
vendored
Normal file
@ -0,0 +1,884 @@
|
||||
// +build windows linux darwin openbsd freebsd netbsd
|
||||
|
||||
package liner
|
||||
|
||||
import (
|
||||
"container/ring"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type action int
|
||||
|
||||
const (
|
||||
left action = iota
|
||||
right
|
||||
up
|
||||
down
|
||||
home
|
||||
end
|
||||
insert
|
||||
del
|
||||
pageUp
|
||||
pageDown
|
||||
f1
|
||||
f2
|
||||
f3
|
||||
f4
|
||||
f5
|
||||
f6
|
||||
f7
|
||||
f8
|
||||
f9
|
||||
f10
|
||||
f11
|
||||
f12
|
||||
altB
|
||||
altF
|
||||
altY
|
||||
shiftTab
|
||||
wordLeft
|
||||
wordRight
|
||||
winch
|
||||
unknown
|
||||
)
|
||||
|
||||
const (
|
||||
ctrlA = 1
|
||||
ctrlB = 2
|
||||
ctrlC = 3
|
||||
ctrlD = 4
|
||||
ctrlE = 5
|
||||
ctrlF = 6
|
||||
ctrlG = 7
|
||||
ctrlH = 8
|
||||
tab = 9
|
||||
lf = 10
|
||||
ctrlK = 11
|
||||
ctrlL = 12
|
||||
cr = 13
|
||||
ctrlN = 14
|
||||
ctrlO = 15
|
||||
ctrlP = 16
|
||||
ctrlQ = 17
|
||||
ctrlR = 18
|
||||
ctrlS = 19
|
||||
ctrlT = 20
|
||||
ctrlU = 21
|
||||
ctrlV = 22
|
||||
ctrlW = 23
|
||||
ctrlX = 24
|
||||
ctrlY = 25
|
||||
ctrlZ = 26
|
||||
esc = 27
|
||||
bs = 127
|
||||
)
|
||||
|
||||
const (
|
||||
beep = "\a"
|
||||
)
|
||||
|
||||
type tabDirection int
|
||||
|
||||
const (
|
||||
tabForward tabDirection = iota
|
||||
tabReverse
|
||||
)
|
||||
|
||||
func (s *State) refresh(prompt []rune, buf []rune, pos int) error {
|
||||
s.cursorPos(0)
|
||||
_, err := fmt.Print(string(prompt))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pLen := countGlyphs(prompt)
|
||||
bLen := countGlyphs(buf)
|
||||
pos = countGlyphs(buf[:pos])
|
||||
if pLen+bLen < s.columns {
|
||||
_, err = fmt.Print(string(buf))
|
||||
s.eraseLine()
|
||||
s.cursorPos(pLen + pos)
|
||||
} else {
|
||||
// Find space available
|
||||
space := s.columns - pLen
|
||||
space-- // space for cursor
|
||||
start := pos - space/2
|
||||
end := start + space
|
||||
if end > bLen {
|
||||
end = bLen
|
||||
start = end - space
|
||||
}
|
||||
if start < 0 {
|
||||
start = 0
|
||||
end = space
|
||||
}
|
||||
pos -= start
|
||||
|
||||
// Leave space for markers
|
||||
if start > 0 {
|
||||
start++
|
||||
}
|
||||
if end < bLen {
|
||||
end--
|
||||
}
|
||||
startRune := len(getPrefixGlyphs(buf, start))
|
||||
line := getPrefixGlyphs(buf[startRune:], end-start)
|
||||
|
||||
// Output
|
||||
if start > 0 {
|
||||
fmt.Print("{")
|
||||
}
|
||||
fmt.Print(string(line))
|
||||
if end < bLen {
|
||||
fmt.Print("}")
|
||||
}
|
||||
|
||||
// Set cursor position
|
||||
s.eraseLine()
|
||||
s.cursorPos(pLen + pos)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func longestCommonPrefix(strs []string) string {
|
||||
if len(strs) == 0 {
|
||||
return ""
|
||||
}
|
||||
longest := strs[0]
|
||||
|
||||
for _, str := range strs[1:] {
|
||||
for !strings.HasPrefix(str, longest) {
|
||||
longest = longest[:len(longest)-1]
|
||||
}
|
||||
}
|
||||
// Remove trailing partial runes
|
||||
longest = strings.TrimRight(longest, "\uFFFD")
|
||||
return longest
|
||||
}
|
||||
|
||||
func (s *State) circularTabs(items []string) func(tabDirection) (string, error) {
|
||||
item := -1
|
||||
return func(direction tabDirection) (string, error) {
|
||||
if direction == tabForward {
|
||||
if item < len(items)-1 {
|
||||
item++
|
||||
} else {
|
||||
item = 0
|
||||
}
|
||||
} else if direction == tabReverse {
|
||||
if item > 0 {
|
||||
item--
|
||||
} else {
|
||||
item = len(items) - 1
|
||||
}
|
||||
}
|
||||
return items[item], nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) printedTabs(items []string) func(tabDirection) (string, error) {
|
||||
numTabs := 1
|
||||
prefix := longestCommonPrefix(items)
|
||||
return func(direction tabDirection) (string, error) {
|
||||
if len(items) == 1 {
|
||||
return items[0], nil
|
||||
}
|
||||
|
||||
if numTabs == 2 {
|
||||
if len(items) > 100 {
|
||||
fmt.Printf("\nDisplay all %d possibilities? (y or n) ", len(items))
|
||||
for {
|
||||
next, err := s.readNext()
|
||||
if err != nil {
|
||||
return prefix, err
|
||||
}
|
||||
|
||||
if key, ok := next.(rune); ok {
|
||||
if unicode.ToLower(key) == 'n' {
|
||||
return prefix, nil
|
||||
} else if unicode.ToLower(key) == 'y' {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println("")
|
||||
maxWidth := 0
|
||||
for _, item := range items {
|
||||
if len(item) >= maxWidth {
|
||||
maxWidth = len(item) + 1
|
||||
}
|
||||
}
|
||||
|
||||
numColumns := s.columns / maxWidth
|
||||
numRows := len(items) / numColumns
|
||||
if len(items)%numColumns > 0 {
|
||||
numRows++
|
||||
}
|
||||
|
||||
if len(items) <= numColumns {
|
||||
maxWidth = 0
|
||||
}
|
||||
for i := 0; i < numRows; i++ {
|
||||
for j := 0; j < numColumns*numRows; j += numRows {
|
||||
if i+j < len(items) {
|
||||
if maxWidth > 0 {
|
||||
fmt.Printf("%-*s", maxWidth, items[i+j])
|
||||
} else {
|
||||
fmt.Printf("%v ", items[i+j])
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
} else {
|
||||
numTabs++
|
||||
}
|
||||
return prefix, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) tabComplete(p []rune, line []rune, pos int) ([]rune, int, interface{}, error) {
|
||||
if s.completer == nil {
|
||||
return line, pos, rune(esc), nil
|
||||
}
|
||||
head, list, tail := s.completer(string(line), pos)
|
||||
if len(list) <= 0 {
|
||||
return line, pos, rune(esc), nil
|
||||
}
|
||||
hl := utf8.RuneCountInString(head)
|
||||
if len(list) == 1 {
|
||||
s.refresh(p, []rune(head+list[0]+tail), hl+utf8.RuneCountInString(list[0]))
|
||||
return []rune(head + list[0] + tail), hl + utf8.RuneCountInString(list[0]), rune(esc), nil
|
||||
}
|
||||
|
||||
direction := tabForward
|
||||
tabPrinter := s.circularTabs(list)
|
||||
if s.tabStyle == TabPrints {
|
||||
tabPrinter = s.printedTabs(list)
|
||||
}
|
||||
|
||||
for {
|
||||
pick, err := tabPrinter(direction)
|
||||
if err != nil {
|
||||
return line, pos, rune(esc), err
|
||||
}
|
||||
s.refresh(p, []rune(head+pick+tail), hl+utf8.RuneCountInString(pick))
|
||||
|
||||
next, err := s.readNext()
|
||||
if err != nil {
|
||||
return line, pos, rune(esc), err
|
||||
}
|
||||
if key, ok := next.(rune); ok {
|
||||
if key == tab {
|
||||
direction = tabForward
|
||||
continue
|
||||
}
|
||||
if key == esc {
|
||||
return line, pos, rune(esc), nil
|
||||
}
|
||||
}
|
||||
if a, ok := next.(action); ok && a == shiftTab {
|
||||
direction = tabReverse
|
||||
continue
|
||||
}
|
||||
return []rune(head + pick + tail), hl + utf8.RuneCountInString(pick), next, nil
|
||||
}
|
||||
// Not reached
|
||||
return line, pos, rune(esc), nil
|
||||
}
|
||||
|
||||
// reverse intelligent search, implements a bash-like history search.
|
||||
func (s *State) reverseISearch(origLine []rune, origPos int) ([]rune, int, interface{}, error) {
|
||||
p := "(reverse-i-search)`': "
|
||||
s.refresh([]rune(p), origLine, origPos)
|
||||
|
||||
line := []rune{}
|
||||
pos := 0
|
||||
foundLine := string(origLine)
|
||||
foundPos := origPos
|
||||
|
||||
getLine := func() ([]rune, []rune, int) {
|
||||
search := string(line)
|
||||
prompt := "(reverse-i-search)`%s': "
|
||||
return []rune(fmt.Sprintf(prompt, search)), []rune(foundLine), foundPos
|
||||
}
|
||||
|
||||
history, positions := s.getHistoryByPattern(string(line))
|
||||
historyPos := len(history) - 1
|
||||
|
||||
for {
|
||||
next, err := s.readNext()
|
||||
if err != nil {
|
||||
return []rune(foundLine), foundPos, rune(esc), err
|
||||
}
|
||||
|
||||
switch v := next.(type) {
|
||||
case rune:
|
||||
switch v {
|
||||
case ctrlR: // Search backwards
|
||||
if historyPos > 0 && historyPos < len(history) {
|
||||
historyPos--
|
||||
foundLine = history[historyPos]
|
||||
foundPos = positions[historyPos]
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case ctrlS: // Search forward
|
||||
if historyPos < len(history)-1 && historyPos >= 0 {
|
||||
historyPos++
|
||||
foundLine = history[historyPos]
|
||||
foundPos = positions[historyPos]
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case ctrlH, bs: // Backspace
|
||||
if pos <= 0 {
|
||||
fmt.Print(beep)
|
||||
} else {
|
||||
n := len(getSuffixGlyphs(line[:pos], 1))
|
||||
line = append(line[:pos-n], line[pos:]...)
|
||||
pos -= n
|
||||
|
||||
// For each char deleted, display the last matching line of history
|
||||
history, positions := s.getHistoryByPattern(string(line))
|
||||
historyPos = len(history) - 1
|
||||
if len(history) > 0 {
|
||||
foundLine = history[historyPos]
|
||||
foundPos = positions[historyPos]
|
||||
} else {
|
||||
foundLine = ""
|
||||
foundPos = 0
|
||||
}
|
||||
}
|
||||
case ctrlG: // Cancel
|
||||
return origLine, origPos, rune(esc), err
|
||||
|
||||
case tab, cr, lf, ctrlA, ctrlB, ctrlD, ctrlE, ctrlF, ctrlK,
|
||||
ctrlL, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ:
|
||||
fallthrough
|
||||
case 0, ctrlC, esc, 28, 29, 30, 31:
|
||||
return []rune(foundLine), foundPos, next, err
|
||||
default:
|
||||
line = append(line[:pos], append([]rune{v}, line[pos:]...)...)
|
||||
pos++
|
||||
|
||||
// For each keystroke typed, display the last matching line of history
|
||||
history, positions = s.getHistoryByPattern(string(line))
|
||||
historyPos = len(history) - 1
|
||||
if len(history) > 0 {
|
||||
foundLine = history[historyPos]
|
||||
foundPos = positions[historyPos]
|
||||
} else {
|
||||
foundLine = ""
|
||||
foundPos = 0
|
||||
}
|
||||
}
|
||||
case action:
|
||||
return []rune(foundLine), foundPos, next, err
|
||||
}
|
||||
s.refresh(getLine())
|
||||
}
|
||||
}
|
||||
|
||||
// addToKillRing adds some text to the kill ring. If mode is 0 it adds it to a
|
||||
// new node in the end of the kill ring, and move the current pointer to the new
|
||||
// node. If mode is 1 or 2 it appends or prepends the text to the current entry
|
||||
// of the killRing.
|
||||
func (s *State) addToKillRing(text []rune, mode int) {
|
||||
// Don't use the same underlying array as text
|
||||
killLine := make([]rune, len(text))
|
||||
copy(killLine, text)
|
||||
|
||||
// Point killRing to a newNode, procedure depends on the killring state and
|
||||
// append mode.
|
||||
if mode == 0 { // Add new node to killRing
|
||||
if s.killRing == nil { // if killring is empty, create a new one
|
||||
s.killRing = ring.New(1)
|
||||
} else if s.killRing.Len() >= KillRingMax { // if killring is "full"
|
||||
s.killRing = s.killRing.Next()
|
||||
} else { // Normal case
|
||||
s.killRing.Link(ring.New(1))
|
||||
s.killRing = s.killRing.Next()
|
||||
}
|
||||
} else {
|
||||
if s.killRing == nil { // if killring is empty, create a new one
|
||||
s.killRing = ring.New(1)
|
||||
s.killRing.Value = []rune{}
|
||||
}
|
||||
if mode == 1 { // Append to last entry
|
||||
killLine = append(s.killRing.Value.([]rune), killLine...)
|
||||
} else if mode == 2 { // Prepend to last entry
|
||||
killLine = append(killLine, s.killRing.Value.([]rune)...)
|
||||
}
|
||||
}
|
||||
|
||||
// Save text in the current killring node
|
||||
s.killRing.Value = killLine
|
||||
}
|
||||
|
||||
func (s *State) yank(p []rune, text []rune, pos int) ([]rune, int, interface{}, error) {
|
||||
if s.killRing == nil {
|
||||
return text, pos, rune(esc), nil
|
||||
}
|
||||
|
||||
lineStart := text[:pos]
|
||||
lineEnd := text[pos:]
|
||||
var line []rune
|
||||
|
||||
for {
|
||||
value := s.killRing.Value.([]rune)
|
||||
line = make([]rune, 0)
|
||||
line = append(line, lineStart...)
|
||||
line = append(line, value...)
|
||||
line = append(line, lineEnd...)
|
||||
|
||||
pos = len(lineStart) + len(value)
|
||||
s.refresh(p, line, pos)
|
||||
|
||||
next, err := s.readNext()
|
||||
if err != nil {
|
||||
return line, pos, next, err
|
||||
}
|
||||
|
||||
switch v := next.(type) {
|
||||
case rune:
|
||||
return line, pos, next, nil
|
||||
case action:
|
||||
switch v {
|
||||
case altY:
|
||||
s.killRing = s.killRing.Prev()
|
||||
default:
|
||||
return line, pos, next, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return line, pos, esc, nil
|
||||
}
|
||||
|
||||
// Prompt displays p and returns a line of user input, not including a trailing
|
||||
// newline character. An io.EOF error is returned if the user signals end-of-file
|
||||
// by pressing Ctrl-D. Prompt allows line editing if the terminal supports it.
|
||||
func (s *State) Prompt(prompt string) (string, error) {
|
||||
if s.inputRedirected || !s.terminalSupported {
|
||||
return s.promptUnsupported(prompt)
|
||||
}
|
||||
if s.outputRedirected {
|
||||
return "", ErrNotTerminalOutput
|
||||
}
|
||||
|
||||
s.historyMutex.RLock()
|
||||
defer s.historyMutex.RUnlock()
|
||||
|
||||
s.startPrompt()
|
||||
defer s.stopPrompt()
|
||||
s.getColumns()
|
||||
|
||||
fmt.Print(prompt)
|
||||
p := []rune(prompt)
|
||||
var line []rune
|
||||
pos := 0
|
||||
historyEnd := ""
|
||||
prefixHistory := s.getHistoryByPrefix(string(line))
|
||||
historyPos := len(prefixHistory)
|
||||
historyAction := false // used to mark history related actions
|
||||
killAction := 0 // used to mark kill related actions
|
||||
mainLoop:
|
||||
for {
|
||||
next, err := s.readNext()
|
||||
haveNext:
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
historyAction = false
|
||||
switch v := next.(type) {
|
||||
case rune:
|
||||
switch v {
|
||||
case cr, lf:
|
||||
fmt.Println()
|
||||
break mainLoop
|
||||
case ctrlA: // Start of line
|
||||
pos = 0
|
||||
s.refresh(p, line, pos)
|
||||
case ctrlE: // End of line
|
||||
pos = len(line)
|
||||
s.refresh(p, line, pos)
|
||||
case ctrlB: // left
|
||||
if pos > 0 {
|
||||
pos -= len(getSuffixGlyphs(line[:pos], 1))
|
||||
s.refresh(p, line, pos)
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case ctrlF: // right
|
||||
if pos < len(line) {
|
||||
pos += len(getPrefixGlyphs(line[pos:], 1))
|
||||
s.refresh(p, line, pos)
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case ctrlD: // del
|
||||
if pos == 0 && len(line) == 0 {
|
||||
// exit
|
||||
return "", io.EOF
|
||||
}
|
||||
|
||||
// ctrlD is a potential EOF, so the rune reader shuts down.
|
||||
// Therefore, if it isn't actually an EOF, we must re-startPrompt.
|
||||
s.restartPrompt()
|
||||
|
||||
if pos >= len(line) {
|
||||
fmt.Print(beep)
|
||||
} else {
|
||||
n := len(getPrefixGlyphs(line[pos:], 1))
|
||||
line = append(line[:pos], line[pos+n:]...)
|
||||
s.refresh(p, line, pos)
|
||||
}
|
||||
case ctrlK: // delete remainder of line
|
||||
if pos >= len(line) {
|
||||
fmt.Print(beep)
|
||||
} else {
|
||||
if killAction > 0 {
|
||||
s.addToKillRing(line[pos:], 1) // Add in apend mode
|
||||
} else {
|
||||
s.addToKillRing(line[pos:], 0) // Add in normal mode
|
||||
}
|
||||
|
||||
killAction = 2 // Mark that there was a kill action
|
||||
line = line[:pos]
|
||||
s.refresh(p, line, pos)
|
||||
}
|
||||
case ctrlP: // up
|
||||
historyAction = true
|
||||
if historyPos > 0 {
|
||||
if historyPos == len(prefixHistory) {
|
||||
historyEnd = string(line)
|
||||
}
|
||||
historyPos--
|
||||
line = []rune(prefixHistory[historyPos])
|
||||
pos = len(line)
|
||||
s.refresh(p, line, pos)
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case ctrlN: // down
|
||||
historyAction = true
|
||||
if historyPos < len(prefixHistory) {
|
||||
historyPos++
|
||||
if historyPos == len(prefixHistory) {
|
||||
line = []rune(historyEnd)
|
||||
} else {
|
||||
line = []rune(prefixHistory[historyPos])
|
||||
}
|
||||
pos = len(line)
|
||||
s.refresh(p, line, pos)
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case ctrlT: // transpose prev glyph with glyph under cursor
|
||||
if len(line) < 2 || pos < 1 {
|
||||
fmt.Print(beep)
|
||||
} else {
|
||||
if pos == len(line) {
|
||||
pos -= len(getSuffixGlyphs(line, 1))
|
||||
}
|
||||
prev := getSuffixGlyphs(line[:pos], 1)
|
||||
next := getPrefixGlyphs(line[pos:], 1)
|
||||
scratch := make([]rune, len(prev))
|
||||
copy(scratch, prev)
|
||||
copy(line[pos-len(prev):], next)
|
||||
copy(line[pos-len(prev)+len(next):], scratch)
|
||||
pos += len(next)
|
||||
s.refresh(p, line, pos)
|
||||
}
|
||||
case ctrlL: // clear screen
|
||||
s.eraseScreen()
|
||||
s.refresh(p, line, pos)
|
||||
case ctrlC: // reset
|
||||
fmt.Println("^C")
|
||||
if s.ctrlCAborts {
|
||||
return "", ErrPromptAborted
|
||||
}
|
||||
line = line[:0]
|
||||
pos = 0
|
||||
fmt.Print(prompt)
|
||||
s.restartPrompt()
|
||||
case ctrlH, bs: // Backspace
|
||||
if pos <= 0 {
|
||||
fmt.Print(beep)
|
||||
} else {
|
||||
n := len(getSuffixGlyphs(line[:pos], 1))
|
||||
line = append(line[:pos-n], line[pos:]...)
|
||||
pos -= n
|
||||
s.refresh(p, line, pos)
|
||||
}
|
||||
case ctrlU: // Erase line before cursor
|
||||
if killAction > 0 {
|
||||
s.addToKillRing(line[:pos], 2) // Add in prepend mode
|
||||
} else {
|
||||
s.addToKillRing(line[:pos], 0) // Add in normal mode
|
||||
}
|
||||
|
||||
killAction = 2 // Mark that there was some killing
|
||||
line = line[pos:]
|
||||
pos = 0
|
||||
s.refresh(p, line, pos)
|
||||
case ctrlW: // Erase word
|
||||
if pos == 0 {
|
||||
fmt.Print(beep)
|
||||
break
|
||||
}
|
||||
// Remove whitespace to the left
|
||||
var buf []rune // Store the deleted chars in a buffer
|
||||
for {
|
||||
if pos == 0 || !unicode.IsSpace(line[pos-1]) {
|
||||
break
|
||||
}
|
||||
buf = append(buf, line[pos-1])
|
||||
line = append(line[:pos-1], line[pos:]...)
|
||||
pos--
|
||||
}
|
||||
// Remove non-whitespace to the left
|
||||
for {
|
||||
if pos == 0 || unicode.IsSpace(line[pos-1]) {
|
||||
break
|
||||
}
|
||||
buf = append(buf, line[pos-1])
|
||||
line = append(line[:pos-1], line[pos:]...)
|
||||
pos--
|
||||
}
|
||||
// Invert the buffer and save the result on the killRing
|
||||
var newBuf []rune
|
||||
for i := len(buf) - 1; i >= 0; i-- {
|
||||
newBuf = append(newBuf, buf[i])
|
||||
}
|
||||
if killAction > 0 {
|
||||
s.addToKillRing(newBuf, 2) // Add in prepend mode
|
||||
} else {
|
||||
s.addToKillRing(newBuf, 0) // Add in normal mode
|
||||
}
|
||||
killAction = 2 // Mark that there was some killing
|
||||
|
||||
s.refresh(p, line, pos)
|
||||
case ctrlY: // Paste from Yank buffer
|
||||
line, pos, next, err = s.yank(p, line, pos)
|
||||
goto haveNext
|
||||
case ctrlR: // Reverse Search
|
||||
line, pos, next, err = s.reverseISearch(line, pos)
|
||||
s.refresh(p, line, pos)
|
||||
goto haveNext
|
||||
case tab: // Tab completion
|
||||
line, pos, next, err = s.tabComplete(p, line, pos)
|
||||
goto haveNext
|
||||
// Catch keys that do nothing, but you don't want them to beep
|
||||
case esc:
|
||||
// DO NOTHING
|
||||
// Unused keys
|
||||
case ctrlG, ctrlO, ctrlQ, ctrlS, ctrlV, ctrlX, ctrlZ:
|
||||
fallthrough
|
||||
// Catch unhandled control codes (anything <= 31)
|
||||
case 0, 28, 29, 30, 31:
|
||||
fmt.Print(beep)
|
||||
default:
|
||||
if pos == len(line) && len(p)+len(line) < s.columns-1 {
|
||||
line = append(line, v)
|
||||
fmt.Printf("%c", v)
|
||||
pos++
|
||||
} else {
|
||||
line = append(line[:pos], append([]rune{v}, line[pos:]...)...)
|
||||
pos++
|
||||
s.refresh(p, line, pos)
|
||||
}
|
||||
}
|
||||
case action:
|
||||
switch v {
|
||||
case del:
|
||||
if pos >= len(line) {
|
||||
fmt.Print(beep)
|
||||
} else {
|
||||
n := len(getPrefixGlyphs(line[pos:], 1))
|
||||
line = append(line[:pos], line[pos+n:]...)
|
||||
}
|
||||
case left:
|
||||
if pos > 0 {
|
||||
pos -= len(getSuffixGlyphs(line[:pos], 1))
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case wordLeft, altB:
|
||||
if pos > 0 {
|
||||
var spaceHere, spaceLeft, leftKnown bool
|
||||
for {
|
||||
pos--
|
||||
if pos == 0 {
|
||||
break
|
||||
}
|
||||
if leftKnown {
|
||||
spaceHere = spaceLeft
|
||||
} else {
|
||||
spaceHere = unicode.IsSpace(line[pos])
|
||||
}
|
||||
spaceLeft, leftKnown = unicode.IsSpace(line[pos-1]), true
|
||||
if !spaceHere && spaceLeft {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case right:
|
||||
if pos < len(line) {
|
||||
pos += len(getPrefixGlyphs(line[pos:], 1))
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case wordRight, altF:
|
||||
if pos < len(line) {
|
||||
var spaceHere, spaceLeft, hereKnown bool
|
||||
for {
|
||||
pos++
|
||||
if pos == len(line) {
|
||||
break
|
||||
}
|
||||
if hereKnown {
|
||||
spaceLeft = spaceHere
|
||||
} else {
|
||||
spaceLeft = unicode.IsSpace(line[pos-1])
|
||||
}
|
||||
spaceHere, hereKnown = unicode.IsSpace(line[pos]), true
|
||||
if spaceHere && !spaceLeft {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case up:
|
||||
historyAction = true
|
||||
if historyPos > 0 {
|
||||
if historyPos == len(prefixHistory) {
|
||||
historyEnd = string(line)
|
||||
}
|
||||
historyPos--
|
||||
line = []rune(prefixHistory[historyPos])
|
||||
pos = len(line)
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case down:
|
||||
historyAction = true
|
||||
if historyPos < len(prefixHistory) {
|
||||
historyPos++
|
||||
if historyPos == len(prefixHistory) {
|
||||
line = []rune(historyEnd)
|
||||
} else {
|
||||
line = []rune(prefixHistory[historyPos])
|
||||
}
|
||||
pos = len(line)
|
||||
} else {
|
||||
fmt.Print(beep)
|
||||
}
|
||||
case home: // Start of line
|
||||
pos = 0
|
||||
case end: // End of line
|
||||
pos = len(line)
|
||||
}
|
||||
s.refresh(p, line, pos)
|
||||
}
|
||||
if !historyAction {
|
||||
prefixHistory = s.getHistoryByPrefix(string(line))
|
||||
historyPos = len(prefixHistory)
|
||||
}
|
||||
if killAction > 0 {
|
||||
killAction--
|
||||
}
|
||||
}
|
||||
return string(line), nil
|
||||
}
|
||||
|
||||
// PasswordPrompt displays p, and then waits for user input. The input typed by
|
||||
// the user is not displayed in the terminal.
|
||||
func (s *State) PasswordPrompt(prompt string) (string, error) {
|
||||
if !s.terminalSupported {
|
||||
return "", errors.New("liner: function not supported in this terminal")
|
||||
}
|
||||
if s.inputRedirected {
|
||||
return s.promptUnsupported(prompt)
|
||||
}
|
||||
if s.outputRedirected {
|
||||
return "", ErrNotTerminalOutput
|
||||
}
|
||||
|
||||
s.startPrompt()
|
||||
defer s.stopPrompt()
|
||||
s.getColumns()
|
||||
|
||||
fmt.Print(prompt)
|
||||
p := []rune(prompt)
|
||||
var line []rune
|
||||
pos := 0
|
||||
|
||||
mainLoop:
|
||||
for {
|
||||
next, err := s.readNext()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
switch v := next.(type) {
|
||||
case rune:
|
||||
switch v {
|
||||
case cr, lf:
|
||||
fmt.Println()
|
||||
break mainLoop
|
||||
case ctrlD: // del
|
||||
if pos == 0 && len(line) == 0 {
|
||||
// exit
|
||||
return "", io.EOF
|
||||
}
|
||||
|
||||
// ctrlD is a potential EOF, so the rune reader shuts down.
|
||||
// Therefore, if it isn't actually an EOF, we must re-startPrompt.
|
||||
s.restartPrompt()
|
||||
case ctrlL: // clear screen
|
||||
s.eraseScreen()
|
||||
s.refresh(p, []rune{}, 0)
|
||||
case ctrlH, bs: // Backspace
|
||||
if pos <= 0 {
|
||||
fmt.Print(beep)
|
||||
} else {
|
||||
n := len(getSuffixGlyphs(line[:pos], 1))
|
||||
line = append(line[:pos-n], line[pos:]...)
|
||||
pos -= n
|
||||
}
|
||||
case ctrlC:
|
||||
fmt.Println("^C")
|
||||
if s.ctrlCAborts {
|
||||
return "", ErrPromptAborted
|
||||
}
|
||||
line = line[:0]
|
||||
pos = 0
|
||||
fmt.Print(prompt)
|
||||
s.restartPrompt()
|
||||
// Unused keys
|
||||
case esc, tab, ctrlA, ctrlB, ctrlE, ctrlF, ctrlG, ctrlK, ctrlN, ctrlO, ctrlP, ctrlQ, ctrlR, ctrlS,
|
||||
ctrlT, ctrlU, ctrlV, ctrlW, ctrlX, ctrlY, ctrlZ:
|
||||
fallthrough
|
||||
// Catch unhandled control codes (anything <= 31)
|
||||
case 0, 28, 29, 30, 31:
|
||||
fmt.Print(beep)
|
||||
default:
|
||||
line = append(line[:pos], append([]rune{v}, line[pos:]...)...)
|
||||
pos++
|
||||
}
|
||||
}
|
||||
}
|
||||
return string(line), nil
|
||||
}
|
||||
90
vendor/github.com/peterh/liner/line_test.go
generated
vendored
Normal file
90
vendor/github.com/peterh/liner/line_test.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
package liner
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAppend(t *testing.T) {
|
||||
var s State
|
||||
s.AppendHistory("foo")
|
||||
s.AppendHistory("bar")
|
||||
|
||||
var out bytes.Buffer
|
||||
num, err := s.WriteHistory(&out)
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error writing history", err)
|
||||
}
|
||||
if num != 2 {
|
||||
t.Fatalf("Expected 2 history entries, got %d", num)
|
||||
}
|
||||
|
||||
s.AppendHistory("baz")
|
||||
num, err = s.WriteHistory(&out)
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error writing history", err)
|
||||
}
|
||||
if num != 3 {
|
||||
t.Fatalf("Expected 3 history entries, got %d", num)
|
||||
}
|
||||
|
||||
s.AppendHistory("baz")
|
||||
num, err = s.WriteHistory(&out)
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error writing history", err)
|
||||
}
|
||||
if num != 3 {
|
||||
t.Fatalf("Expected 3 history entries after duplicate append, got %d", num)
|
||||
}
|
||||
|
||||
s.AppendHistory("baz")
|
||||
|
||||
}
|
||||
|
||||
func TestHistory(t *testing.T) {
|
||||
input := `foo
|
||||
bar
|
||||
baz
|
||||
quux
|
||||
dingle`
|
||||
|
||||
var s State
|
||||
num, err := s.ReadHistory(strings.NewReader(input))
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error reading history", err)
|
||||
}
|
||||
if num != 5 {
|
||||
t.Fatal("Wrong number of history entries read")
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
num, err = s.WriteHistory(&out)
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error writing history", err)
|
||||
}
|
||||
if num != 5 {
|
||||
t.Fatal("Wrong number of history entries written")
|
||||
}
|
||||
if strings.TrimSpace(out.String()) != input {
|
||||
t.Fatal("Round-trip failure")
|
||||
}
|
||||
|
||||
// Test reading with a trailing newline present
|
||||
var s2 State
|
||||
num, err = s2.ReadHistory(&out)
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error reading history the 2nd time", err)
|
||||
}
|
||||
if num != 5 {
|
||||
t.Fatal("Wrong number of history entries read the 2nd time")
|
||||
}
|
||||
|
||||
num, err = s.ReadHistory(strings.NewReader(input + "\n\xff"))
|
||||
if err == nil {
|
||||
t.Fatal("Unexpected success reading corrupted history", err)
|
||||
}
|
||||
if num != 5 {
|
||||
t.Fatal("Wrong number of history entries read the 3rd time")
|
||||
}
|
||||
}
|
||||
63
vendor/github.com/peterh/liner/output.go
generated
vendored
Normal file
63
vendor/github.com/peterh/liner/output.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
// +build linux darwin openbsd freebsd netbsd
|
||||
|
||||
package liner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (s *State) cursorPos(x int) {
|
||||
if s.useCHA {
|
||||
// 'G' is "Cursor Character Absolute (CHA)"
|
||||
fmt.Printf("\x1b[%dG", x+1)
|
||||
} else {
|
||||
// 'C' is "Cursor Forward (CUF)"
|
||||
fmt.Print("\r")
|
||||
if x > 0 {
|
||||
fmt.Printf("\x1b[%dC", x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) eraseLine() {
|
||||
fmt.Print("\x1b[0K")
|
||||
}
|
||||
|
||||
func (s *State) eraseScreen() {
|
||||
fmt.Print("\x1b[H\x1b[2J")
|
||||
}
|
||||
|
||||
type winSize struct {
|
||||
row, col uint16
|
||||
xpixel, ypixel uint16
|
||||
}
|
||||
|
||||
func (s *State) getColumns() {
|
||||
var ws winSize
|
||||
ok, _, _ := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdout),
|
||||
syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws)))
|
||||
if ok < 0 {
|
||||
s.columns = 80
|
||||
}
|
||||
s.columns = int(ws.col)
|
||||
}
|
||||
|
||||
func (s *State) checkOutput() {
|
||||
// xterm is known to support CHA
|
||||
if strings.Contains(strings.ToLower(os.Getenv("TERM")), "xterm") {
|
||||
s.useCHA = true
|
||||
return
|
||||
}
|
||||
|
||||
// The test for functional ANSI CHA is unreliable (eg the Windows
|
||||
// telnet command does not support reading the cursor position with
|
||||
// an ANSI DSR request, despite setting TERM=ansi)
|
||||
|
||||
// Assume CHA isn't supported (which should be safe, although it
|
||||
// does result in occasional visible cursor jitter)
|
||||
s.useCHA = false
|
||||
}
|
||||
54
vendor/github.com/peterh/liner/output_windows.go
generated
vendored
Normal file
54
vendor/github.com/peterh/liner/output_windows.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
package liner
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type coord struct {
|
||||
x, y int16
|
||||
}
|
||||
type smallRect struct {
|
||||
left, top, right, bottom int16
|
||||
}
|
||||
|
||||
type consoleScreenBufferInfo struct {
|
||||
dwSize coord
|
||||
dwCursorPosition coord
|
||||
wAttributes int16
|
||||
srWindow smallRect
|
||||
dwMaximumWindowSize coord
|
||||
}
|
||||
|
||||
func (s *State) cursorPos(x int) {
|
||||
var sbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
|
||||
procSetConsoleCursorPosition.Call(uintptr(s.hOut),
|
||||
uintptr(int(x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16))
|
||||
}
|
||||
|
||||
func (s *State) eraseLine() {
|
||||
var sbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
|
||||
var numWritten uint32
|
||||
procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '),
|
||||
uintptr(sbi.dwSize.x-sbi.dwCursorPosition.x),
|
||||
uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16),
|
||||
uintptr(unsafe.Pointer(&numWritten)))
|
||||
}
|
||||
|
||||
func (s *State) eraseScreen() {
|
||||
var sbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
|
||||
var numWritten uint32
|
||||
procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '),
|
||||
uintptr(sbi.dwSize.x)*uintptr(sbi.dwSize.y),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&numWritten)))
|
||||
procSetConsoleCursorPosition.Call(uintptr(s.hOut), 0)
|
||||
}
|
||||
|
||||
func (s *State) getColumns() {
|
||||
var sbi consoleScreenBufferInfo
|
||||
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
|
||||
s.columns = int(sbi.dwSize.x)
|
||||
}
|
||||
37
vendor/github.com/peterh/liner/prefix_test.go
generated
vendored
Normal file
37
vendor/github.com/peterh/liner/prefix_test.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// +build windows linux darwin openbsd freebsd netbsd
|
||||
|
||||
package liner
|
||||
|
||||
import "testing"
|
||||
|
||||
type testItem struct {
|
||||
list []string
|
||||
prefix string
|
||||
}
|
||||
|
||||
func TestPrefix(t *testing.T) {
|
||||
list := []testItem{
|
||||
{[]string{"food", "foot"}, "foo"},
|
||||
{[]string{"foo", "foot"}, "foo"},
|
||||
{[]string{"food", "foo"}, "foo"},
|
||||
{[]string{"food", "foe", "foot"}, "fo"},
|
||||
{[]string{"food", "foot", "barbeque"}, ""},
|
||||
{[]string{"cafeteria", "café"}, "caf"},
|
||||
{[]string{"cafe", "café"}, "caf"},
|
||||
{[]string{"cafè", "café"}, "caf"},
|
||||
{[]string{"cafés", "café"}, "café"},
|
||||
{[]string{"áéíóú", "áéíóú"}, "áéíóú"},
|
||||
{[]string{"éclairs", "éclairs"}, "éclairs"},
|
||||
{[]string{"éclairs are the best", "éclairs are great", "éclairs"}, "éclairs"},
|
||||
{[]string{"éclair", "éclairs"}, "éclair"},
|
||||
{[]string{"éclairs", "éclair"}, "éclair"},
|
||||
{[]string{"éclair", "élan"}, "é"},
|
||||
}
|
||||
|
||||
for _, test := range list {
|
||||
lcp := longestCommonPrefix(test.list)
|
||||
if lcp != test.prefix {
|
||||
t.Errorf("%s != %s for %+v", lcp, test.prefix, test.list)
|
||||
}
|
||||
}
|
||||
}
|
||||
44
vendor/github.com/peterh/liner/race_test.go
generated
vendored
Normal file
44
vendor/github.com/peterh/liner/race_test.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// +build race
|
||||
|
||||
package liner
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestWriteHistory(t *testing.T) {
|
||||
oldout := os.Stdout
|
||||
defer func() { os.Stdout = oldout }()
|
||||
oldin := os.Stdout
|
||||
defer func() { os.Stdin = oldin }()
|
||||
|
||||
newinr, newinw, err := os.Pipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
os.Stdin = newinr
|
||||
newoutr, newoutw, err := os.Pipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer newoutr.Close()
|
||||
os.Stdout = newoutw
|
||||
|
||||
var wait sync.WaitGroup
|
||||
wait.Add(1)
|
||||
s := NewLiner()
|
||||
go func() {
|
||||
s.AppendHistory("foo")
|
||||
s.AppendHistory("bar")
|
||||
s.Prompt("")
|
||||
wait.Done()
|
||||
}()
|
||||
|
||||
s.WriteHistory(ioutil.Discard)
|
||||
|
||||
newinw.Close()
|
||||
wait.Wait()
|
||||
}
|
||||
12
vendor/github.com/peterh/liner/signal.go
generated
vendored
Normal file
12
vendor/github.com/peterh/liner/signal.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// +build go1.1,!windows
|
||||
|
||||
package liner
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
)
|
||||
|
||||
func stopSignal(c chan<- os.Signal) {
|
||||
signal.Stop(c)
|
||||
}
|
||||
11
vendor/github.com/peterh/liner/signal_legacy.go
generated
vendored
Normal file
11
vendor/github.com/peterh/liner/signal_legacy.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
// +build !go1.1,!windows
|
||||
|
||||
package liner
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func stopSignal(c chan<- os.Signal) {
|
||||
// signal.Stop does not exist before Go 1.1
|
||||
}
|
||||
37
vendor/github.com/peterh/liner/unixmode.go
generated
vendored
Normal file
37
vendor/github.com/peterh/liner/unixmode.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// +build linux darwin freebsd openbsd netbsd
|
||||
|
||||
package liner
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func (mode *termios) ApplyMode() error {
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdin), setTermios, uintptr(unsafe.Pointer(mode)))
|
||||
|
||||
if errno != 0 {
|
||||
return errno
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TerminalMode returns the current terminal input mode as an InputModeSetter.
|
||||
//
|
||||
// This function is provided for convenience, and should
|
||||
// not be necessary for most users of liner.
|
||||
func TerminalMode() (ModeApplier, error) {
|
||||
mode, errno := getMode(syscall.Stdin)
|
||||
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
}
|
||||
return mode, nil
|
||||
}
|
||||
|
||||
func getMode(handle int) (*termios, syscall.Errno) {
|
||||
var mode termios
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(handle), getTermios, uintptr(unsafe.Pointer(&mode)))
|
||||
|
||||
return &mode, errno
|
||||
}
|
||||
60
vendor/github.com/peterh/liner/width.go
generated
vendored
Normal file
60
vendor/github.com/peterh/liner/width.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
package liner
|
||||
|
||||
import "unicode"
|
||||
|
||||
// These character classes are mostly zero width (when combined).
|
||||
// A few might not be, depending on the user's font. Fixing this
|
||||
// is non-trivial, given that some terminals don't support
|
||||
// ANSI DSR/CPR
|
||||
var zeroWidth = []*unicode.RangeTable{
|
||||
unicode.Mn,
|
||||
unicode.Me,
|
||||
unicode.Cc,
|
||||
unicode.Cf,
|
||||
}
|
||||
|
||||
var doubleWidth = []*unicode.RangeTable{
|
||||
unicode.Han,
|
||||
unicode.Hangul,
|
||||
unicode.Hiragana,
|
||||
unicode.Katakana,
|
||||
}
|
||||
|
||||
// countGlyphs considers zero-width characters to be zero glyphs wide,
|
||||
// and members of Chinese, Japanese, and Korean scripts to be 2 glyphs wide.
|
||||
func countGlyphs(s []rune) int {
|
||||
n := 0
|
||||
for _, r := range s {
|
||||
switch {
|
||||
case unicode.IsOneOf(zeroWidth, r):
|
||||
case unicode.IsOneOf(doubleWidth, r):
|
||||
n += 2
|
||||
default:
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func getPrefixGlyphs(s []rune, num int) []rune {
|
||||
p := 0
|
||||
for n := 0; n < num && p < len(s); p++ {
|
||||
if !unicode.IsOneOf(zeroWidth, s[p]) {
|
||||
n++
|
||||
}
|
||||
}
|
||||
for p < len(s) && unicode.IsOneOf(zeroWidth, s[p]) {
|
||||
p++
|
||||
}
|
||||
return s[:p]
|
||||
}
|
||||
|
||||
func getSuffixGlyphs(s []rune, num int) []rune {
|
||||
p := len(s)
|
||||
for n := 0; n < num && p > 0; p-- {
|
||||
if !unicode.IsOneOf(zeroWidth, s[p-1]) {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return s[p:]
|
||||
}
|
||||
102
vendor/github.com/peterh/liner/width_test.go
generated
vendored
Normal file
102
vendor/github.com/peterh/liner/width_test.go
generated
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
package liner
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func accent(in []rune) []rune {
|
||||
var out []rune
|
||||
for _, r := range in {
|
||||
out = append(out, r)
|
||||
out = append(out, '\u0301')
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type testCase struct {
|
||||
s []rune
|
||||
glyphs int
|
||||
}
|
||||
|
||||
var testCases = []testCase{
|
||||
{[]rune("query"), 5},
|
||||
{[]rune("私"), 2},
|
||||
{[]rune("hello世界"), 9},
|
||||
}
|
||||
|
||||
func TestCountGlyphs(t *testing.T) {
|
||||
for _, testCase := range testCases {
|
||||
count := countGlyphs(testCase.s)
|
||||
if count != testCase.glyphs {
|
||||
t.Errorf("ASCII count incorrect. %d != %d", count, testCase.glyphs)
|
||||
}
|
||||
count = countGlyphs(accent(testCase.s))
|
||||
if count != testCase.glyphs {
|
||||
t.Errorf("Accent count incorrect. %d != %d", count, testCase.glyphs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func compare(a, b []rune, name string, t *testing.T) {
|
||||
if len(a) != len(b) {
|
||||
t.Errorf(`"%s" != "%s" in %s"`, string(a), string(b), name)
|
||||
return
|
||||
}
|
||||
for i := range a {
|
||||
if a[i] != b[i] {
|
||||
t.Errorf(`"%s" != "%s" in %s"`, string(a), string(b), name)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrefixGlyphs(t *testing.T) {
|
||||
for _, testCase := range testCases {
|
||||
for i := 0; i <= len(testCase.s); i++ {
|
||||
iter := strconv.Itoa(i)
|
||||
out := getPrefixGlyphs(testCase.s, i)
|
||||
compare(out, testCase.s[:i], "ascii prefix "+iter, t)
|
||||
out = getPrefixGlyphs(accent(testCase.s), i)
|
||||
compare(out, accent(testCase.s[:i]), "accent prefix "+iter, t)
|
||||
}
|
||||
out := getPrefixGlyphs(testCase.s, 999)
|
||||
compare(out, testCase.s, "ascii prefix overflow", t)
|
||||
out = getPrefixGlyphs(accent(testCase.s), 999)
|
||||
compare(out, accent(testCase.s), "accent prefix overflow", t)
|
||||
|
||||
out = getPrefixGlyphs(testCase.s, -3)
|
||||
if len(out) != 0 {
|
||||
t.Error("ascii prefix negative")
|
||||
}
|
||||
out = getPrefixGlyphs(accent(testCase.s), -3)
|
||||
if len(out) != 0 {
|
||||
t.Error("accent prefix negative")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSuffixGlyphs(t *testing.T) {
|
||||
for _, testCase := range testCases {
|
||||
for i := 0; i <= len(testCase.s); i++ {
|
||||
iter := strconv.Itoa(i)
|
||||
out := getSuffixGlyphs(testCase.s, i)
|
||||
compare(out, testCase.s[len(testCase.s)-i:], "ascii suffix "+iter, t)
|
||||
out = getSuffixGlyphs(accent(testCase.s), i)
|
||||
compare(out, accent(testCase.s[len(testCase.s)-i:]), "accent suffix "+iter, t)
|
||||
}
|
||||
out := getSuffixGlyphs(testCase.s, 999)
|
||||
compare(out, testCase.s, "ascii suffix overflow", t)
|
||||
out = getSuffixGlyphs(accent(testCase.s), 999)
|
||||
compare(out, accent(testCase.s), "accent suffix overflow", t)
|
||||
|
||||
out = getSuffixGlyphs(testCase.s, -3)
|
||||
if len(out) != 0 {
|
||||
t.Error("ascii suffix negative")
|
||||
}
|
||||
out = getSuffixGlyphs(accent(testCase.s), -3)
|
||||
if len(out) != 0 {
|
||||
t.Error("accent suffix negative")
|
||||
}
|
||||
}
|
||||
}
|
||||
8
vendor/github.com/russross/blackfriday/.gitignore
generated
vendored
Normal file
8
vendor/github.com/russross/blackfriday/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
*.out
|
||||
*.swp
|
||||
*.8
|
||||
*.6
|
||||
_obj
|
||||
_test*
|
||||
markdown
|
||||
tags
|
||||
17
vendor/github.com/russross/blackfriday/.travis.yml
generated
vendored
Normal file
17
vendor/github.com/russross/blackfriday/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# Travis CI (http://travis-ci.org/) is a continuous integration service for
|
||||
# open source projects. This file configures it to run unit tests for
|
||||
# blackfriday.
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
|
||||
install:
|
||||
- go get -d -t -v ./...
|
||||
- go build -v ./...
|
||||
|
||||
script:
|
||||
- go test -v ./...
|
||||
246
vendor/github.com/russross/blackfriday/README.md
generated
vendored
Normal file
246
vendor/github.com/russross/blackfriday/README.md
generated
vendored
Normal file
@ -0,0 +1,246 @@
|
||||
Blackfriday [](https://travis-ci.org/russross/blackfriday)
|
||||
===========
|
||||
|
||||
Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It
|
||||
is paranoid about its input (so you can safely feed it user-supplied
|
||||
data), it is fast, it supports common extensions (tables, smart
|
||||
punctuation substitutions, etc.), and it is safe for all utf-8
|
||||
(unicode) input.
|
||||
|
||||
HTML output is currently supported, along with Smartypants
|
||||
extensions. An experimental LaTeX output engine is also included.
|
||||
|
||||
It started as a translation from C of [Sundown][3].
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Blackfriday is compatible with Go 1. If you are using an older
|
||||
release of Go, consider using v1.1 of blackfriday, which was based
|
||||
on the last stable release of Go prior to Go 1. You can find it as a
|
||||
tagged commit on github.
|
||||
|
||||
With Go 1 and git installed:
|
||||
|
||||
go get github.com/russross/blackfriday
|
||||
|
||||
will download, compile, and install the package into your `$GOPATH`
|
||||
directory hierarchy. Alternatively, you can achieve the same if you
|
||||
import it into a project:
|
||||
|
||||
import "github.com/russross/blackfriday"
|
||||
|
||||
and `go get` without parameters.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
For basic usage, it is as simple as getting your input into a byte
|
||||
slice and calling:
|
||||
|
||||
output := blackfriday.MarkdownBasic(input)
|
||||
|
||||
This renders it with no extensions enabled. To get a more useful
|
||||
feature set, use this instead:
|
||||
|
||||
output := blackfriday.MarkdownCommon(input)
|
||||
|
||||
### Sanitize untrusted content
|
||||
|
||||
Blackfriday itself does nothing to protect against malicious content. If you are
|
||||
dealing with user-supplied markdown, we recommend running blackfriday's output
|
||||
through HTML sanitizer such as
|
||||
[Bluemonday](https://github.com/microcosm-cc/bluemonday).
|
||||
|
||||
Here's an example of simple usage of blackfriday together with bluemonday:
|
||||
|
||||
``` go
|
||||
import (
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
"github.com/russross/blackfriday"
|
||||
)
|
||||
|
||||
// ...
|
||||
unsafe := blackfriday.MarkdownCommon(input)
|
||||
html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
|
||||
```
|
||||
|
||||
### Custom options
|
||||
|
||||
If you want to customize the set of options, first get a renderer
|
||||
(currently either the HTML or LaTeX output engines), then use it to
|
||||
call the more general `Markdown` function. For examples, see the
|
||||
implementations of `MarkdownBasic` and `MarkdownCommon` in
|
||||
`markdown.go`.
|
||||
|
||||
You can also check out `blackfriday-tool` for a more complete example
|
||||
of how to use it. Download and install it using:
|
||||
|
||||
go get github.com/russross/blackfriday-tool
|
||||
|
||||
This is a simple command-line tool that allows you to process a
|
||||
markdown file using a standalone program. You can also browse the
|
||||
source directly on github if you are just looking for some example
|
||||
code:
|
||||
|
||||
* <http://github.com/russross/blackfriday-tool>
|
||||
|
||||
Note that if you have not already done so, installing
|
||||
`blackfriday-tool` will be sufficient to download and install
|
||||
blackfriday in addition to the tool itself. The tool binary will be
|
||||
installed in `$GOPATH/bin`. This is a statically-linked binary that
|
||||
can be copied to wherever you need it without worrying about
|
||||
dependencies and library versions.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
All features of Sundown are supported, including:
|
||||
|
||||
* **Compatibility**. The Markdown v1.0.3 test suite passes with
|
||||
the `--tidy` option. Without `--tidy`, the differences are
|
||||
mostly in whitespace and entity escaping, where blackfriday is
|
||||
more consistent and cleaner.
|
||||
|
||||
* **Common extensions**, including table support, fenced code
|
||||
blocks, autolinks, strikethroughs, non-strict emphasis, etc.
|
||||
|
||||
* **Safety**. Blackfriday is paranoid when parsing, making it safe
|
||||
to feed untrusted user input without fear of bad things
|
||||
happening. The test suite stress tests this and there are no
|
||||
known inputs that make it crash. If you find one, please let me
|
||||
know and send me the input that does it.
|
||||
|
||||
NOTE: "safety" in this context means *runtime safety only*. In order to
|
||||
protect yourself agains JavaScript injection in untrusted content, see
|
||||
[this example](https://github.com/russross/blackfriday#sanitize-untrusted-content).
|
||||
|
||||
* **Fast processing**. It is fast enough to render on-demand in
|
||||
most web applications without having to cache the output.
|
||||
|
||||
* **Thread safety**. You can run multiple parsers in different
|
||||
goroutines without ill effect. There is no dependence on global
|
||||
shared state.
|
||||
|
||||
* **Minimal dependencies**. Blackfriday only depends on standard
|
||||
library packages in Go. The source code is pretty
|
||||
self-contained, so it is easy to add to any project, including
|
||||
Google App Engine projects.
|
||||
|
||||
* **Standards compliant**. Output successfully validates using the
|
||||
W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.
|
||||
|
||||
|
||||
Extensions
|
||||
----------
|
||||
|
||||
In addition to the standard markdown syntax, this package
|
||||
implements the following extensions:
|
||||
|
||||
* **Intra-word emphasis supression**. The `_` character is
|
||||
commonly used inside words when discussing code, so having
|
||||
markdown interpret it as an emphasis command is usually the
|
||||
wrong thing. Blackfriday lets you treat all emphasis markers as
|
||||
normal characters when they occur inside a word.
|
||||
|
||||
* **Tables**. Tables can be created by drawing them in the input
|
||||
using a simple syntax:
|
||||
|
||||
```
|
||||
Name | Age
|
||||
--------|------
|
||||
Bob | 27
|
||||
Alice | 23
|
||||
```
|
||||
|
||||
* **Fenced code blocks**. In addition to the normal 4-space
|
||||
indentation to mark code blocks, you can explicitly mark them
|
||||
and supply a language (to make syntax highlighting simple). Just
|
||||
mark it like this:
|
||||
|
||||
``` go
|
||||
func getTrue() bool {
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
You can use 3 or more backticks to mark the beginning of the
|
||||
block, and the same number to mark the end of the block.
|
||||
|
||||
* **Autolinking**. Blackfriday can find URLs that have not been
|
||||
explicitly marked as links and turn them into links.
|
||||
|
||||
* **Strikethrough**. Use two tildes (`~~`) to mark text that
|
||||
should be crossed out.
|
||||
|
||||
* **Hard line breaks**. With this extension enabled (it is off by
|
||||
default in the `MarkdownBasic` and `MarkdownCommon` convenience
|
||||
functions), newlines in the input translate into line breaks in
|
||||
the output.
|
||||
|
||||
* **Smart quotes**. Smartypants-style punctuation substitution is
|
||||
supported, turning normal double- and single-quote marks into
|
||||
curly quotes, etc.
|
||||
|
||||
* **LaTeX-style dash parsing** is an additional option, where `--`
|
||||
is translated into `–`, and `---` is translated into
|
||||
`—`. This differs from most smartypants processors, which
|
||||
turn a single hyphen into an ndash and a double hyphen into an
|
||||
mdash.
|
||||
|
||||
* **Smart fractions**, where anything that looks like a fraction
|
||||
is translated into suitable HTML (instead of just a few special
|
||||
cases like most smartypant processors). For example, `4/5`
|
||||
becomes `<sup>4</sup>⁄<sub>5</sub>`, which renders as
|
||||
<sup>4</sup>⁄<sub>5</sub>.
|
||||
|
||||
|
||||
Other renderers
|
||||
---------------
|
||||
|
||||
Blackfriday is structured to allow alternative rendering engines. Here
|
||||
are a few of note:
|
||||
|
||||
* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/github_flavored_markdown):
|
||||
provides a GitHub Flavored Markdown renderer with fenced code block
|
||||
highlighting, clickable header anchor links.
|
||||
|
||||
It's not customizable, and its goal is to produce HTML output
|
||||
equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode),
|
||||
except the rendering is performed locally.
|
||||
|
||||
* [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt,
|
||||
but for markdown.
|
||||
|
||||
* LaTeX output: renders output as LaTeX. This is currently part of the
|
||||
main Blackfriday repository, but may be split into its own project
|
||||
in the future. If you are interested in owning and maintaining the
|
||||
LaTeX output component, please be in touch.
|
||||
|
||||
It renders some basic documents, but is only experimental at this
|
||||
point. In particular, it does not do any inline escaping, so input
|
||||
that happens to look like LaTeX code will be passed through without
|
||||
modification.
|
||||
|
||||
|
||||
Todo
|
||||
----
|
||||
|
||||
* More unit testing
|
||||
* Improve unicode support. It does not understand all unicode
|
||||
rules (about what constitutes a letter, a punctuation symbol,
|
||||
etc.), so it may fail to detect word boundaries correctly in
|
||||
some instances. It is safe on all utf-8 input.
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
[Blackfriday is distributed under the Simplified BSD License](LICENSE.txt)
|
||||
|
||||
|
||||
[1]: http://daringfireball.net/projects/markdown/ "Markdown"
|
||||
[2]: http://golang.org/ "Go Language"
|
||||
[3]: https://github.com/vmg/sundown "Sundown"
|
||||
1389
vendor/github.com/russross/blackfriday/block.go
generated
vendored
Normal file
1389
vendor/github.com/russross/blackfriday/block.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1407
vendor/github.com/russross/blackfriday/block_test.go
generated
vendored
Normal file
1407
vendor/github.com/russross/blackfriday/block_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
948
vendor/github.com/russross/blackfriday/html.go
generated
vendored
Normal file
948
vendor/github.com/russross/blackfriday/html.go
generated
vendored
Normal file
@ -0,0 +1,948 @@
|
||||
//
|
||||
// Blackfriday Markdown Processor
|
||||
// Available at http://github.com/russross/blackfriday
|
||||
//
|
||||
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
||||
// Distributed under the Simplified BSD License.
|
||||
// See README.md for details.
|
||||
//
|
||||
|
||||
//
|
||||
//
|
||||
// HTML rendering backend
|
||||
//
|
||||
//
|
||||
|
||||
package blackfriday
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Html renderer configuration options.
|
||||
const (
|
||||
HTML_SKIP_HTML = 1 << iota // skip preformatted HTML blocks
|
||||
HTML_SKIP_STYLE // skip embedded <style> elements
|
||||
HTML_SKIP_IMAGES // skip embedded images
|
||||
HTML_SKIP_LINKS // skip all links
|
||||
HTML_SAFELINK // only link to trusted protocols
|
||||
HTML_NOFOLLOW_LINKS // only link with rel="nofollow"
|
||||
HTML_NOREFERRER_LINKS // only link with rel="noreferrer"
|
||||
HTML_HREF_TARGET_BLANK // add a blank target
|
||||
HTML_TOC // generate a table of contents
|
||||
HTML_OMIT_CONTENTS // skip the main contents (for a standalone table of contents)
|
||||
HTML_COMPLETE_PAGE // generate a complete HTML page
|
||||
HTML_USE_XHTML // generate XHTML output instead of HTML
|
||||
HTML_USE_SMARTYPANTS // enable smart punctuation substitutions
|
||||
HTML_SMARTYPANTS_FRACTIONS // enable smart fractions (with HTML_USE_SMARTYPANTS)
|
||||
HTML_SMARTYPANTS_LATEX_DASHES // enable LaTeX-style dashes (with HTML_USE_SMARTYPANTS)
|
||||
HTML_SMARTYPANTS_ANGLED_QUOTES // enable angled double quotes (with HTML_USE_SMARTYPANTS) for double quotes rendering
|
||||
HTML_FOOTNOTE_RETURN_LINKS // generate a link at the end of a footnote to return to the source
|
||||
)
|
||||
|
||||
var (
|
||||
alignments = []string{
|
||||
"left",
|
||||
"right",
|
||||
"center",
|
||||
}
|
||||
|
||||
// TODO: improve this regexp to catch all possible entities:
|
||||
htmlEntity = regexp.MustCompile(`&[a-z]{2,5};`)
|
||||
)
|
||||
|
||||
type HtmlRendererParameters struct {
|
||||
// Prepend this text to each relative URL.
|
||||
AbsolutePrefix string
|
||||
// Add this text to each footnote anchor, to ensure uniqueness.
|
||||
FootnoteAnchorPrefix string
|
||||
// Show this text inside the <a> tag for a footnote return link, if the
|
||||
// HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string
|
||||
// <sup>[return]</sup> is used.
|
||||
FootnoteReturnLinkContents string
|
||||
// If set, add this text to the front of each Header ID, to ensure
|
||||
// uniqueness.
|
||||
HeaderIDPrefix string
|
||||
// If set, add this text to the back of each Header ID, to ensure uniqueness.
|
||||
HeaderIDSuffix string
|
||||
}
|
||||
|
||||
// Html is a type that implements the Renderer interface for HTML output.
|
||||
//
|
||||
// Do not create this directly, instead use the HtmlRenderer function.
|
||||
type Html struct {
|
||||
flags int // HTML_* options
|
||||
closeTag string // how to end singleton tags: either " />" or ">"
|
||||
title string // document title
|
||||
css string // optional css file url (used with HTML_COMPLETE_PAGE)
|
||||
|
||||
parameters HtmlRendererParameters
|
||||
|
||||
// table of contents data
|
||||
tocMarker int
|
||||
headerCount int
|
||||
currentLevel int
|
||||
toc *bytes.Buffer
|
||||
|
||||
// Track header IDs to prevent ID collision in a single generation.
|
||||
headerIDs map[string]int
|
||||
|
||||
smartypants *smartypantsRenderer
|
||||
}
|
||||
|
||||
const (
|
||||
xhtmlClose = " />"
|
||||
htmlClose = ">"
|
||||
)
|
||||
|
||||
// HtmlRenderer creates and configures an Html object, which
|
||||
// satisfies the Renderer interface.
|
||||
//
|
||||
// flags is a set of HTML_* options ORed together.
|
||||
// title is the title of the document, and css is a URL for the document's
|
||||
// stylesheet.
|
||||
// title and css are only used when HTML_COMPLETE_PAGE is selected.
|
||||
func HtmlRenderer(flags int, title string, css string) Renderer {
|
||||
return HtmlRendererWithParameters(flags, title, css, HtmlRendererParameters{})
|
||||
}
|
||||
|
||||
func HtmlRendererWithParameters(flags int, title string,
|
||||
css string, renderParameters HtmlRendererParameters) Renderer {
|
||||
// configure the rendering engine
|
||||
closeTag := htmlClose
|
||||
if flags&HTML_USE_XHTML != 0 {
|
||||
closeTag = xhtmlClose
|
||||
}
|
||||
|
||||
if renderParameters.FootnoteReturnLinkContents == "" {
|
||||
renderParameters.FootnoteReturnLinkContents = `<sup>[return]</sup>`
|
||||
}
|
||||
|
||||
return &Html{
|
||||
flags: flags,
|
||||
closeTag: closeTag,
|
||||
title: title,
|
||||
css: css,
|
||||
parameters: renderParameters,
|
||||
|
||||
headerCount: 0,
|
||||
currentLevel: 0,
|
||||
toc: new(bytes.Buffer),
|
||||
|
||||
headerIDs: make(map[string]int),
|
||||
|
||||
smartypants: smartypants(flags),
|
||||
}
|
||||
}
|
||||
|
||||
// Using if statements is a bit faster than a switch statement. As the compiler
|
||||
// improves, this should be unnecessary this is only worthwhile because
|
||||
// attrEscape is the single largest CPU user in normal use.
|
||||
// Also tried using map, but that gave a ~3x slowdown.
|
||||
func escapeSingleChar(char byte) (string, bool) {
|
||||
if char == '"' {
|
||||
return """, true
|
||||
}
|
||||
if char == '&' {
|
||||
return "&", true
|
||||
}
|
||||
if char == '<' {
|
||||
return "<", true
|
||||
}
|
||||
if char == '>' {
|
||||
return ">", true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
func attrEscape(out *bytes.Buffer, src []byte) {
|
||||
org := 0
|
||||
for i, ch := range src {
|
||||
if entity, ok := escapeSingleChar(ch); ok {
|
||||
if i > org {
|
||||
// copy all the normal characters since the last escape
|
||||
out.Write(src[org:i])
|
||||
}
|
||||
org = i + 1
|
||||
out.WriteString(entity)
|
||||
}
|
||||
}
|
||||
if org < len(src) {
|
||||
out.Write(src[org:])
|
||||
}
|
||||
}
|
||||
|
||||
func entityEscapeWithSkip(out *bytes.Buffer, src []byte, skipRanges [][]int) {
|
||||
end := 0
|
||||
for _, rang := range skipRanges {
|
||||
attrEscape(out, src[end:rang[0]])
|
||||
out.Write(src[rang[0]:rang[1]])
|
||||
end = rang[1]
|
||||
}
|
||||
attrEscape(out, src[end:])
|
||||
}
|
||||
|
||||
func (options *Html) GetFlags() int {
|
||||
return options.flags
|
||||
}
|
||||
|
||||
func (options *Html) TitleBlock(out *bytes.Buffer, text []byte) {
|
||||
text = bytes.TrimPrefix(text, []byte("% "))
|
||||
text = bytes.Replace(text, []byte("\n% "), []byte("\n"), -1)
|
||||
out.WriteString("<h1 class=\"title\">")
|
||||
out.Write(text)
|
||||
out.WriteString("\n</h1>")
|
||||
}
|
||||
|
||||
func (options *Html) Header(out *bytes.Buffer, text func() bool, level int, id string) {
|
||||
marker := out.Len()
|
||||
doubleSpace(out)
|
||||
|
||||
if id == "" && options.flags&HTML_TOC != 0 {
|
||||
id = fmt.Sprintf("toc_%d", options.headerCount)
|
||||
}
|
||||
|
||||
if id != "" {
|
||||
id = options.ensureUniqueHeaderID(id)
|
||||
|
||||
if options.parameters.HeaderIDPrefix != "" {
|
||||
id = options.parameters.HeaderIDPrefix + id
|
||||
}
|
||||
|
||||
if options.parameters.HeaderIDSuffix != "" {
|
||||
id = id + options.parameters.HeaderIDSuffix
|
||||
}
|
||||
|
||||
out.WriteString(fmt.Sprintf("<h%d id=\"%s\">", level, id))
|
||||
} else {
|
||||
out.WriteString(fmt.Sprintf("<h%d>", level))
|
||||
}
|
||||
|
||||
tocMarker := out.Len()
|
||||
if !text() {
|
||||
out.Truncate(marker)
|
||||
return
|
||||
}
|
||||
|
||||
// are we building a table of contents?
|
||||
if options.flags&HTML_TOC != 0 {
|
||||
options.TocHeaderWithAnchor(out.Bytes()[tocMarker:], level, id)
|
||||
}
|
||||
|
||||
out.WriteString(fmt.Sprintf("</h%d>\n", level))
|
||||
}
|
||||
|
||||
func (options *Html) BlockHtml(out *bytes.Buffer, text []byte) {
|
||||
if options.flags&HTML_SKIP_HTML != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
doubleSpace(out)
|
||||
out.Write(text)
|
||||
out.WriteByte('\n')
|
||||
}
|
||||
|
||||
func (options *Html) HRule(out *bytes.Buffer) {
|
||||
doubleSpace(out)
|
||||
out.WriteString("<hr")
|
||||
out.WriteString(options.closeTag)
|
||||
out.WriteByte('\n')
|
||||
}
|
||||
|
||||
func (options *Html) BlockCode(out *bytes.Buffer, text []byte, lang string) {
|
||||
doubleSpace(out)
|
||||
|
||||
// parse out the language names/classes
|
||||
count := 0
|
||||
for _, elt := range strings.Fields(lang) {
|
||||
if elt[0] == '.' {
|
||||
elt = elt[1:]
|
||||
}
|
||||
if len(elt) == 0 {
|
||||
continue
|
||||
}
|
||||
if count == 0 {
|
||||
out.WriteString("<pre><code class=\"language-")
|
||||
} else {
|
||||
out.WriteByte(' ')
|
||||
}
|
||||
attrEscape(out, []byte(elt))
|
||||
count++
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
out.WriteString("<pre><code>")
|
||||
} else {
|
||||
out.WriteString("\">")
|
||||
}
|
||||
|
||||
attrEscape(out, text)
|
||||
out.WriteString("</code></pre>\n")
|
||||
}
|
||||
|
||||
func (options *Html) BlockQuote(out *bytes.Buffer, text []byte) {
|
||||
doubleSpace(out)
|
||||
out.WriteString("<blockquote>\n")
|
||||
out.Write(text)
|
||||
out.WriteString("</blockquote>\n")
|
||||
}
|
||||
|
||||
func (options *Html) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
|
||||
doubleSpace(out)
|
||||
out.WriteString("<table>\n<thead>\n")
|
||||
out.Write(header)
|
||||
out.WriteString("</thead>\n\n<tbody>\n")
|
||||
out.Write(body)
|
||||
out.WriteString("</tbody>\n</table>\n")
|
||||
}
|
||||
|
||||
func (options *Html) TableRow(out *bytes.Buffer, text []byte) {
|
||||
doubleSpace(out)
|
||||
out.WriteString("<tr>\n")
|
||||
out.Write(text)
|
||||
out.WriteString("\n</tr>\n")
|
||||
}
|
||||
|
||||
func (options *Html) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
|
||||
doubleSpace(out)
|
||||
switch align {
|
||||
case TABLE_ALIGNMENT_LEFT:
|
||||
out.WriteString("<th align=\"left\">")
|
||||
case TABLE_ALIGNMENT_RIGHT:
|
||||
out.WriteString("<th align=\"right\">")
|
||||
case TABLE_ALIGNMENT_CENTER:
|
||||
out.WriteString("<th align=\"center\">")
|
||||
default:
|
||||
out.WriteString("<th>")
|
||||
}
|
||||
|
||||
out.Write(text)
|
||||
out.WriteString("</th>")
|
||||
}
|
||||
|
||||
func (options *Html) TableCell(out *bytes.Buffer, text []byte, align int) {
|
||||
doubleSpace(out)
|
||||
switch align {
|
||||
case TABLE_ALIGNMENT_LEFT:
|
||||
out.WriteString("<td align=\"left\">")
|
||||
case TABLE_ALIGNMENT_RIGHT:
|
||||
out.WriteString("<td align=\"right\">")
|
||||
case TABLE_ALIGNMENT_CENTER:
|
||||
out.WriteString("<td align=\"center\">")
|
||||
default:
|
||||
out.WriteString("<td>")
|
||||
}
|
||||
|
||||
out.Write(text)
|
||||
out.WriteString("</td>")
|
||||
}
|
||||
|
||||
func (options *Html) Footnotes(out *bytes.Buffer, text func() bool) {
|
||||
out.WriteString("<div class=\"footnotes\">\n")
|
||||
options.HRule(out)
|
||||
options.List(out, text, LIST_TYPE_ORDERED)
|
||||
out.WriteString("</div>\n")
|
||||
}
|
||||
|
||||
func (options *Html) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
|
||||
if flags&LIST_ITEM_CONTAINS_BLOCK != 0 || flags&LIST_ITEM_BEGINNING_OF_LIST != 0 {
|
||||
doubleSpace(out)
|
||||
}
|
||||
slug := slugify(name)
|
||||
out.WriteString(`<li id="`)
|
||||
out.WriteString(`fn:`)
|
||||
out.WriteString(options.parameters.FootnoteAnchorPrefix)
|
||||
out.Write(slug)
|
||||
out.WriteString(`">`)
|
||||
out.Write(text)
|
||||
if options.flags&HTML_FOOTNOTE_RETURN_LINKS != 0 {
|
||||
out.WriteString(` <a class="footnote-return" href="#`)
|
||||
out.WriteString(`fnref:`)
|
||||
out.WriteString(options.parameters.FootnoteAnchorPrefix)
|
||||
out.Write(slug)
|
||||
out.WriteString(`">`)
|
||||
out.WriteString(options.parameters.FootnoteReturnLinkContents)
|
||||
out.WriteString(`</a>`)
|
||||
}
|
||||
out.WriteString("</li>\n")
|
||||
}
|
||||
|
||||
func (options *Html) List(out *bytes.Buffer, text func() bool, flags int) {
|
||||
marker := out.Len()
|
||||
doubleSpace(out)
|
||||
|
||||
if flags&LIST_TYPE_DEFINITION != 0 {
|
||||
out.WriteString("<dl>")
|
||||
} else if flags&LIST_TYPE_ORDERED != 0 {
|
||||
out.WriteString("<ol>")
|
||||
} else {
|
||||
out.WriteString("<ul>")
|
||||
}
|
||||
if !text() {
|
||||
out.Truncate(marker)
|
||||
return
|
||||
}
|
||||
if flags&LIST_TYPE_DEFINITION != 0 {
|
||||
out.WriteString("</dl>\n")
|
||||
} else if flags&LIST_TYPE_ORDERED != 0 {
|
||||
out.WriteString("</ol>\n")
|
||||
} else {
|
||||
out.WriteString("</ul>\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (options *Html) ListItem(out *bytes.Buffer, text []byte, flags int) {
|
||||
if (flags&LIST_ITEM_CONTAINS_BLOCK != 0 && flags&LIST_TYPE_DEFINITION == 0) ||
|
||||
flags&LIST_ITEM_BEGINNING_OF_LIST != 0 {
|
||||
doubleSpace(out)
|
||||
}
|
||||
if flags&LIST_TYPE_TERM != 0 {
|
||||
out.WriteString("<dt>")
|
||||
} else if flags&LIST_TYPE_DEFINITION != 0 {
|
||||
out.WriteString("<dd>")
|
||||
} else {
|
||||
out.WriteString("<li>")
|
||||
}
|
||||
out.Write(text)
|
||||
if flags&LIST_TYPE_TERM != 0 {
|
||||
out.WriteString("</dt>\n")
|
||||
} else if flags&LIST_TYPE_DEFINITION != 0 {
|
||||
out.WriteString("</dd>\n")
|
||||
} else {
|
||||
out.WriteString("</li>\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (options *Html) Paragraph(out *bytes.Buffer, text func() bool) {
|
||||
marker := out.Len()
|
||||
doubleSpace(out)
|
||||
|
||||
out.WriteString("<p>")
|
||||
if !text() {
|
||||
out.Truncate(marker)
|
||||
return
|
||||
}
|
||||
out.WriteString("</p>\n")
|
||||
}
|
||||
|
||||
func (options *Html) AutoLink(out *bytes.Buffer, link []byte, kind int) {
|
||||
skipRanges := htmlEntity.FindAllIndex(link, -1)
|
||||
if options.flags&HTML_SAFELINK != 0 && !isSafeLink(link) && kind != LINK_TYPE_EMAIL {
|
||||
// mark it but don't link it if it is not a safe link: no smartypants
|
||||
out.WriteString("<tt>")
|
||||
entityEscapeWithSkip(out, link, skipRanges)
|
||||
out.WriteString("</tt>")
|
||||
return
|
||||
}
|
||||
|
||||
out.WriteString("<a href=\"")
|
||||
if kind == LINK_TYPE_EMAIL {
|
||||
out.WriteString("mailto:")
|
||||
} else {
|
||||
options.maybeWriteAbsolutePrefix(out, link)
|
||||
}
|
||||
|
||||
entityEscapeWithSkip(out, link, skipRanges)
|
||||
|
||||
var relAttrs []string
|
||||
if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) {
|
||||
relAttrs = append(relAttrs, "nofollow")
|
||||
}
|
||||
if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) {
|
||||
relAttrs = append(relAttrs, "noreferrer")
|
||||
}
|
||||
if len(relAttrs) > 0 {
|
||||
out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
|
||||
}
|
||||
|
||||
// blank target only add to external link
|
||||
if options.flags&HTML_HREF_TARGET_BLANK != 0 && !isRelativeLink(link) {
|
||||
out.WriteString("\" target=\"_blank")
|
||||
}
|
||||
|
||||
out.WriteString("\">")
|
||||
|
||||
// Pretty print: if we get an email address as
|
||||
// an actual URI, e.g. `mailto:foo@bar.com`, we don't
|
||||
// want to print the `mailto:` prefix
|
||||
switch {
|
||||
case bytes.HasPrefix(link, []byte("mailto://")):
|
||||
attrEscape(out, link[len("mailto://"):])
|
||||
case bytes.HasPrefix(link, []byte("mailto:")):
|
||||
attrEscape(out, link[len("mailto:"):])
|
||||
default:
|
||||
entityEscapeWithSkip(out, link, skipRanges)
|
||||
}
|
||||
|
||||
out.WriteString("</a>")
|
||||
}
|
||||
|
||||
func (options *Html) CodeSpan(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("<code>")
|
||||
attrEscape(out, text)
|
||||
out.WriteString("</code>")
|
||||
}
|
||||
|
||||
func (options *Html) DoubleEmphasis(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("<strong>")
|
||||
out.Write(text)
|
||||
out.WriteString("</strong>")
|
||||
}
|
||||
|
||||
func (options *Html) Emphasis(out *bytes.Buffer, text []byte) {
|
||||
if len(text) == 0 {
|
||||
return
|
||||
}
|
||||
out.WriteString("<em>")
|
||||
out.Write(text)
|
||||
out.WriteString("</em>")
|
||||
}
|
||||
|
||||
func (options *Html) maybeWriteAbsolutePrefix(out *bytes.Buffer, link []byte) {
|
||||
if options.parameters.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' {
|
||||
out.WriteString(options.parameters.AbsolutePrefix)
|
||||
if link[0] != '/' {
|
||||
out.WriteByte('/')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (options *Html) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
||||
if options.flags&HTML_SKIP_IMAGES != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
out.WriteString("<img src=\"")
|
||||
options.maybeWriteAbsolutePrefix(out, link)
|
||||
attrEscape(out, link)
|
||||
out.WriteString("\" alt=\"")
|
||||
if len(alt) > 0 {
|
||||
attrEscape(out, alt)
|
||||
}
|
||||
if len(title) > 0 {
|
||||
out.WriteString("\" title=\"")
|
||||
attrEscape(out, title)
|
||||
}
|
||||
|
||||
out.WriteByte('"')
|
||||
out.WriteString(options.closeTag)
|
||||
}
|
||||
|
||||
func (options *Html) LineBreak(out *bytes.Buffer) {
|
||||
out.WriteString("<br")
|
||||
out.WriteString(options.closeTag)
|
||||
out.WriteByte('\n')
|
||||
}
|
||||
|
||||
func (options *Html) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
|
||||
if options.flags&HTML_SKIP_LINKS != 0 {
|
||||
// write the link text out but don't link it, just mark it with typewriter font
|
||||
out.WriteString("<tt>")
|
||||
attrEscape(out, content)
|
||||
out.WriteString("</tt>")
|
||||
return
|
||||
}
|
||||
|
||||
if options.flags&HTML_SAFELINK != 0 && !isSafeLink(link) {
|
||||
// write the link text out but don't link it, just mark it with typewriter font
|
||||
out.WriteString("<tt>")
|
||||
attrEscape(out, content)
|
||||
out.WriteString("</tt>")
|
||||
return
|
||||
}
|
||||
|
||||
out.WriteString("<a href=\"")
|
||||
options.maybeWriteAbsolutePrefix(out, link)
|
||||
attrEscape(out, link)
|
||||
if len(title) > 0 {
|
||||
out.WriteString("\" title=\"")
|
||||
attrEscape(out, title)
|
||||
}
|
||||
var relAttrs []string
|
||||
if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) {
|
||||
relAttrs = append(relAttrs, "nofollow")
|
||||
}
|
||||
if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) {
|
||||
relAttrs = append(relAttrs, "noreferrer")
|
||||
}
|
||||
if len(relAttrs) > 0 {
|
||||
out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
|
||||
}
|
||||
|
||||
// blank target only add to external link
|
||||
if options.flags&HTML_HREF_TARGET_BLANK != 0 && !isRelativeLink(link) {
|
||||
out.WriteString("\" target=\"_blank")
|
||||
}
|
||||
|
||||
out.WriteString("\">")
|
||||
out.Write(content)
|
||||
out.WriteString("</a>")
|
||||
return
|
||||
}
|
||||
|
||||
func (options *Html) RawHtmlTag(out *bytes.Buffer, text []byte) {
|
||||
if options.flags&HTML_SKIP_HTML != 0 {
|
||||
return
|
||||
}
|
||||
if options.flags&HTML_SKIP_STYLE != 0 && isHtmlTag(text, "style") {
|
||||
return
|
||||
}
|
||||
if options.flags&HTML_SKIP_LINKS != 0 && isHtmlTag(text, "a") {
|
||||
return
|
||||
}
|
||||
if options.flags&HTML_SKIP_IMAGES != 0 && isHtmlTag(text, "img") {
|
||||
return
|
||||
}
|
||||
out.Write(text)
|
||||
}
|
||||
|
||||
func (options *Html) TripleEmphasis(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("<strong><em>")
|
||||
out.Write(text)
|
||||
out.WriteString("</em></strong>")
|
||||
}
|
||||
|
||||
func (options *Html) StrikeThrough(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("<del>")
|
||||
out.Write(text)
|
||||
out.WriteString("</del>")
|
||||
}
|
||||
|
||||
func (options *Html) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
|
||||
slug := slugify(ref)
|
||||
out.WriteString(`<sup class="footnote-ref" id="`)
|
||||
out.WriteString(`fnref:`)
|
||||
out.WriteString(options.parameters.FootnoteAnchorPrefix)
|
||||
out.Write(slug)
|
||||
out.WriteString(`"><a rel="footnote" href="#`)
|
||||
out.WriteString(`fn:`)
|
||||
out.WriteString(options.parameters.FootnoteAnchorPrefix)
|
||||
out.Write(slug)
|
||||
out.WriteString(`">`)
|
||||
out.WriteString(strconv.Itoa(id))
|
||||
out.WriteString(`</a></sup>`)
|
||||
}
|
||||
|
||||
func (options *Html) Entity(out *bytes.Buffer, entity []byte) {
|
||||
out.Write(entity)
|
||||
}
|
||||
|
||||
func (options *Html) NormalText(out *bytes.Buffer, text []byte) {
|
||||
if options.flags&HTML_USE_SMARTYPANTS != 0 {
|
||||
options.Smartypants(out, text)
|
||||
} else {
|
||||
attrEscape(out, text)
|
||||
}
|
||||
}
|
||||
|
||||
func (options *Html) Smartypants(out *bytes.Buffer, text []byte) {
|
||||
smrt := smartypantsData{false, false}
|
||||
|
||||
// first do normal entity escaping
|
||||
var escaped bytes.Buffer
|
||||
attrEscape(&escaped, text)
|
||||
text = escaped.Bytes()
|
||||
|
||||
mark := 0
|
||||
for i := 0; i < len(text); i++ {
|
||||
if action := options.smartypants[text[i]]; action != nil {
|
||||
if i > mark {
|
||||
out.Write(text[mark:i])
|
||||
}
|
||||
|
||||
previousChar := byte(0)
|
||||
if i > 0 {
|
||||
previousChar = text[i-1]
|
||||
}
|
||||
i += action(out, &smrt, previousChar, text[i:])
|
||||
mark = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
if mark < len(text) {
|
||||
out.Write(text[mark:])
|
||||
}
|
||||
}
|
||||
|
||||
func (options *Html) DocumentHeader(out *bytes.Buffer) {
|
||||
if options.flags&HTML_COMPLETE_PAGE == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ending := ""
|
||||
if options.flags&HTML_USE_XHTML != 0 {
|
||||
out.WriteString("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ")
|
||||
out.WriteString("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n")
|
||||
out.WriteString("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n")
|
||||
ending = " /"
|
||||
} else {
|
||||
out.WriteString("<!DOCTYPE html>\n")
|
||||
out.WriteString("<html>\n")
|
||||
}
|
||||
out.WriteString("<head>\n")
|
||||
out.WriteString(" <title>")
|
||||
options.NormalText(out, []byte(options.title))
|
||||
out.WriteString("</title>\n")
|
||||
out.WriteString(" <meta name=\"GENERATOR\" content=\"Blackfriday Markdown Processor v")
|
||||
out.WriteString(VERSION)
|
||||
out.WriteString("\"")
|
||||
out.WriteString(ending)
|
||||
out.WriteString(">\n")
|
||||
out.WriteString(" <meta charset=\"utf-8\"")
|
||||
out.WriteString(ending)
|
||||
out.WriteString(">\n")
|
||||
if options.css != "" {
|
||||
out.WriteString(" <link rel=\"stylesheet\" type=\"text/css\" href=\"")
|
||||
attrEscape(out, []byte(options.css))
|
||||
out.WriteString("\"")
|
||||
out.WriteString(ending)
|
||||
out.WriteString(">\n")
|
||||
}
|
||||
out.WriteString("</head>\n")
|
||||
out.WriteString("<body>\n")
|
||||
|
||||
options.tocMarker = out.Len()
|
||||
}
|
||||
|
||||
func (options *Html) DocumentFooter(out *bytes.Buffer) {
|
||||
// finalize and insert the table of contents
|
||||
if options.flags&HTML_TOC != 0 {
|
||||
options.TocFinalize()
|
||||
|
||||
// now we have to insert the table of contents into the document
|
||||
var temp bytes.Buffer
|
||||
|
||||
// start by making a copy of everything after the document header
|
||||
temp.Write(out.Bytes()[options.tocMarker:])
|
||||
|
||||
// now clear the copied material from the main output buffer
|
||||
out.Truncate(options.tocMarker)
|
||||
|
||||
// corner case spacing issue
|
||||
if options.flags&HTML_COMPLETE_PAGE != 0 {
|
||||
out.WriteByte('\n')
|
||||
}
|
||||
|
||||
// insert the table of contents
|
||||
out.WriteString("<nav>\n")
|
||||
out.Write(options.toc.Bytes())
|
||||
out.WriteString("</nav>\n")
|
||||
|
||||
// corner case spacing issue
|
||||
if options.flags&HTML_COMPLETE_PAGE == 0 && options.flags&HTML_OMIT_CONTENTS == 0 {
|
||||
out.WriteByte('\n')
|
||||
}
|
||||
|
||||
// write out everything that came after it
|
||||
if options.flags&HTML_OMIT_CONTENTS == 0 {
|
||||
out.Write(temp.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
if options.flags&HTML_COMPLETE_PAGE != 0 {
|
||||
out.WriteString("\n</body>\n")
|
||||
out.WriteString("</html>\n")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (options *Html) TocHeaderWithAnchor(text []byte, level int, anchor string) {
|
||||
for level > options.currentLevel {
|
||||
switch {
|
||||
case bytes.HasSuffix(options.toc.Bytes(), []byte("</li>\n")):
|
||||
// this sublist can nest underneath a header
|
||||
size := options.toc.Len()
|
||||
options.toc.Truncate(size - len("</li>\n"))
|
||||
|
||||
case options.currentLevel > 0:
|
||||
options.toc.WriteString("<li>")
|
||||
}
|
||||
if options.toc.Len() > 0 {
|
||||
options.toc.WriteByte('\n')
|
||||
}
|
||||
options.toc.WriteString("<ul>\n")
|
||||
options.currentLevel++
|
||||
}
|
||||
|
||||
for level < options.currentLevel {
|
||||
options.toc.WriteString("</ul>")
|
||||
if options.currentLevel > 1 {
|
||||
options.toc.WriteString("</li>\n")
|
||||
}
|
||||
options.currentLevel--
|
||||
}
|
||||
|
||||
options.toc.WriteString("<li><a href=\"#")
|
||||
if anchor != "" {
|
||||
options.toc.WriteString(anchor)
|
||||
} else {
|
||||
options.toc.WriteString("toc_")
|
||||
options.toc.WriteString(strconv.Itoa(options.headerCount))
|
||||
}
|
||||
options.toc.WriteString("\">")
|
||||
options.headerCount++
|
||||
|
||||
options.toc.Write(text)
|
||||
|
||||
options.toc.WriteString("</a></li>\n")
|
||||
}
|
||||
|
||||
func (options *Html) TocHeader(text []byte, level int) {
|
||||
options.TocHeaderWithAnchor(text, level, "")
|
||||
}
|
||||
|
||||
func (options *Html) TocFinalize() {
|
||||
for options.currentLevel > 1 {
|
||||
options.toc.WriteString("</ul></li>\n")
|
||||
options.currentLevel--
|
||||
}
|
||||
|
||||
if options.currentLevel > 0 {
|
||||
options.toc.WriteString("</ul>\n")
|
||||
}
|
||||
}
|
||||
|
||||
func isHtmlTag(tag []byte, tagname string) bool {
|
||||
found, _ := findHtmlTagPos(tag, tagname)
|
||||
return found
|
||||
}
|
||||
|
||||
// Look for a character, but ignore it when it's in any kind of quotes, it
|
||||
// might be JavaScript
|
||||
func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int {
|
||||
inSingleQuote := false
|
||||
inDoubleQuote := false
|
||||
inGraveQuote := false
|
||||
i := start
|
||||
for i < len(html) {
|
||||
switch {
|
||||
case html[i] == char && !inSingleQuote && !inDoubleQuote && !inGraveQuote:
|
||||
return i
|
||||
case html[i] == '\'':
|
||||
inSingleQuote = !inSingleQuote
|
||||
case html[i] == '"':
|
||||
inDoubleQuote = !inDoubleQuote
|
||||
case html[i] == '`':
|
||||
inGraveQuote = !inGraveQuote
|
||||
}
|
||||
i++
|
||||
}
|
||||
return start
|
||||
}
|
||||
|
||||
func findHtmlTagPos(tag []byte, tagname string) (bool, int) {
|
||||
i := 0
|
||||
if i < len(tag) && tag[0] != '<' {
|
||||
return false, -1
|
||||
}
|
||||
i++
|
||||
i = skipSpace(tag, i)
|
||||
|
||||
if i < len(tag) && tag[i] == '/' {
|
||||
i++
|
||||
}
|
||||
|
||||
i = skipSpace(tag, i)
|
||||
j := 0
|
||||
for ; i < len(tag); i, j = i+1, j+1 {
|
||||
if j >= len(tagname) {
|
||||
break
|
||||
}
|
||||
|
||||
if strings.ToLower(string(tag[i]))[0] != tagname[j] {
|
||||
return false, -1
|
||||
}
|
||||
}
|
||||
|
||||
if i == len(tag) {
|
||||
return false, -1
|
||||
}
|
||||
|
||||
rightAngle := skipUntilCharIgnoreQuotes(tag, i, '>')
|
||||
if rightAngle > i {
|
||||
return true, rightAngle
|
||||
}
|
||||
|
||||
return false, -1
|
||||
}
|
||||
|
||||
func skipUntilChar(text []byte, start int, char byte) int {
|
||||
i := start
|
||||
for i < len(text) && text[i] != char {
|
||||
i++
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func skipSpace(tag []byte, i int) int {
|
||||
for i < len(tag) && isspace(tag[i]) {
|
||||
i++
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func skipChar(data []byte, start int, char byte) int {
|
||||
i := start
|
||||
for i < len(data) && data[i] == char {
|
||||
i++
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func doubleSpace(out *bytes.Buffer) {
|
||||
if out.Len() > 0 {
|
||||
out.WriteByte('\n')
|
||||
}
|
||||
}
|
||||
|
||||
func isRelativeLink(link []byte) (yes bool) {
|
||||
// a tag begin with '#'
|
||||
if link[0] == '#' {
|
||||
return true
|
||||
}
|
||||
|
||||
// link begin with '/' but not '//', the second maybe a protocol relative link
|
||||
if len(link) >= 2 && link[0] == '/' && link[1] != '/' {
|
||||
return true
|
||||
}
|
||||
|
||||
// only the root '/'
|
||||
if len(link) == 1 && link[0] == '/' {
|
||||
return true
|
||||
}
|
||||
|
||||
// current directory : begin with "./"
|
||||
if bytes.HasPrefix(link, []byte("./")) {
|
||||
return true
|
||||
}
|
||||
|
||||
// parent directory : begin with "../"
|
||||
if bytes.HasPrefix(link, []byte("../")) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (options *Html) ensureUniqueHeaderID(id string) string {
|
||||
for count, found := options.headerIDs[id]; found; count, found = options.headerIDs[id] {
|
||||
tmp := fmt.Sprintf("%s-%d", id, count+1)
|
||||
|
||||
if _, tmpFound := options.headerIDs[tmp]; !tmpFound {
|
||||
options.headerIDs[id] = count + 1
|
||||
id = tmp
|
||||
} else {
|
||||
id = id + "-1"
|
||||
}
|
||||
}
|
||||
|
||||
if _, found := options.headerIDs[id]; !found {
|
||||
options.headerIDs[id] = 0
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
1103
vendor/github.com/russross/blackfriday/inline.go
generated
vendored
Normal file
1103
vendor/github.com/russross/blackfriday/inline.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1016
vendor/github.com/russross/blackfriday/inline_test.go
generated
vendored
Normal file
1016
vendor/github.com/russross/blackfriday/inline_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
332
vendor/github.com/russross/blackfriday/latex.go
generated
vendored
Normal file
332
vendor/github.com/russross/blackfriday/latex.go
generated
vendored
Normal file
@ -0,0 +1,332 @@
|
||||
//
|
||||
// Blackfriday Markdown Processor
|
||||
// Available at http://github.com/russross/blackfriday
|
||||
//
|
||||
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
||||
// Distributed under the Simplified BSD License.
|
||||
// See README.md for details.
|
||||
//
|
||||
|
||||
//
|
||||
//
|
||||
// LaTeX rendering backend
|
||||
//
|
||||
//
|
||||
|
||||
package blackfriday
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// Latex is a type that implements the Renderer interface for LaTeX output.
|
||||
//
|
||||
// Do not create this directly, instead use the LatexRenderer function.
|
||||
type Latex struct {
|
||||
}
|
||||
|
||||
// LatexRenderer creates and configures a Latex object, which
|
||||
// satisfies the Renderer interface.
|
||||
//
|
||||
// flags is a set of LATEX_* options ORed together (currently no such options
|
||||
// are defined).
|
||||
func LatexRenderer(flags int) Renderer {
|
||||
return &Latex{}
|
||||
}
|
||||
|
||||
func (options *Latex) GetFlags() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// render code chunks using verbatim, or listings if we have a language
|
||||
func (options *Latex) BlockCode(out *bytes.Buffer, text []byte, lang string) {
|
||||
if lang == "" {
|
||||
out.WriteString("\n\\begin{verbatim}\n")
|
||||
} else {
|
||||
out.WriteString("\n\\begin{lstlisting}[language=")
|
||||
out.WriteString(lang)
|
||||
out.WriteString("]\n")
|
||||
}
|
||||
out.Write(text)
|
||||
if lang == "" {
|
||||
out.WriteString("\n\\end{verbatim}\n")
|
||||
} else {
|
||||
out.WriteString("\n\\end{lstlisting}\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (options *Latex) TitleBlock(out *bytes.Buffer, text []byte) {
|
||||
|
||||
}
|
||||
|
||||
func (options *Latex) BlockQuote(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("\n\\begin{quotation}\n")
|
||||
out.Write(text)
|
||||
out.WriteString("\n\\end{quotation}\n")
|
||||
}
|
||||
|
||||
func (options *Latex) BlockHtml(out *bytes.Buffer, text []byte) {
|
||||
// a pretty lame thing to do...
|
||||
out.WriteString("\n\\begin{verbatim}\n")
|
||||
out.Write(text)
|
||||
out.WriteString("\n\\end{verbatim}\n")
|
||||
}
|
||||
|
||||
func (options *Latex) Header(out *bytes.Buffer, text func() bool, level int, id string) {
|
||||
marker := out.Len()
|
||||
|
||||
switch level {
|
||||
case 1:
|
||||
out.WriteString("\n\\section{")
|
||||
case 2:
|
||||
out.WriteString("\n\\subsection{")
|
||||
case 3:
|
||||
out.WriteString("\n\\subsubsection{")
|
||||
case 4:
|
||||
out.WriteString("\n\\paragraph{")
|
||||
case 5:
|
||||
out.WriteString("\n\\subparagraph{")
|
||||
case 6:
|
||||
out.WriteString("\n\\textbf{")
|
||||
}
|
||||
if !text() {
|
||||
out.Truncate(marker)
|
||||
return
|
||||
}
|
||||
out.WriteString("}\n")
|
||||
}
|
||||
|
||||
func (options *Latex) HRule(out *bytes.Buffer) {
|
||||
out.WriteString("\n\\HRule\n")
|
||||
}
|
||||
|
||||
func (options *Latex) List(out *bytes.Buffer, text func() bool, flags int) {
|
||||
marker := out.Len()
|
||||
if flags&LIST_TYPE_ORDERED != 0 {
|
||||
out.WriteString("\n\\begin{enumerate}\n")
|
||||
} else {
|
||||
out.WriteString("\n\\begin{itemize}\n")
|
||||
}
|
||||
if !text() {
|
||||
out.Truncate(marker)
|
||||
return
|
||||
}
|
||||
if flags&LIST_TYPE_ORDERED != 0 {
|
||||
out.WriteString("\n\\end{enumerate}\n")
|
||||
} else {
|
||||
out.WriteString("\n\\end{itemize}\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (options *Latex) ListItem(out *bytes.Buffer, text []byte, flags int) {
|
||||
out.WriteString("\n\\item ")
|
||||
out.Write(text)
|
||||
}
|
||||
|
||||
func (options *Latex) Paragraph(out *bytes.Buffer, text func() bool) {
|
||||
marker := out.Len()
|
||||
out.WriteString("\n")
|
||||
if !text() {
|
||||
out.Truncate(marker)
|
||||
return
|
||||
}
|
||||
out.WriteString("\n")
|
||||
}
|
||||
|
||||
func (options *Latex) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
|
||||
out.WriteString("\n\\begin{tabular}{")
|
||||
for _, elt := range columnData {
|
||||
switch elt {
|
||||
case TABLE_ALIGNMENT_LEFT:
|
||||
out.WriteByte('l')
|
||||
case TABLE_ALIGNMENT_RIGHT:
|
||||
out.WriteByte('r')
|
||||
default:
|
||||
out.WriteByte('c')
|
||||
}
|
||||
}
|
||||
out.WriteString("}\n")
|
||||
out.Write(header)
|
||||
out.WriteString(" \\\\\n\\hline\n")
|
||||
out.Write(body)
|
||||
out.WriteString("\n\\end{tabular}\n")
|
||||
}
|
||||
|
||||
func (options *Latex) TableRow(out *bytes.Buffer, text []byte) {
|
||||
if out.Len() > 0 {
|
||||
out.WriteString(" \\\\\n")
|
||||
}
|
||||
out.Write(text)
|
||||
}
|
||||
|
||||
func (options *Latex) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
|
||||
if out.Len() > 0 {
|
||||
out.WriteString(" & ")
|
||||
}
|
||||
out.Write(text)
|
||||
}
|
||||
|
||||
func (options *Latex) TableCell(out *bytes.Buffer, text []byte, align int) {
|
||||
if out.Len() > 0 {
|
||||
out.WriteString(" & ")
|
||||
}
|
||||
out.Write(text)
|
||||
}
|
||||
|
||||
// TODO: this
|
||||
func (options *Latex) Footnotes(out *bytes.Buffer, text func() bool) {
|
||||
|
||||
}
|
||||
|
||||
func (options *Latex) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
|
||||
|
||||
}
|
||||
|
||||
func (options *Latex) AutoLink(out *bytes.Buffer, link []byte, kind int) {
|
||||
out.WriteString("\\href{")
|
||||
if kind == LINK_TYPE_EMAIL {
|
||||
out.WriteString("mailto:")
|
||||
}
|
||||
out.Write(link)
|
||||
out.WriteString("}{")
|
||||
out.Write(link)
|
||||
out.WriteString("}")
|
||||
}
|
||||
|
||||
func (options *Latex) CodeSpan(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("\\texttt{")
|
||||
escapeSpecialChars(out, text)
|
||||
out.WriteString("}")
|
||||
}
|
||||
|
||||
func (options *Latex) DoubleEmphasis(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("\\textbf{")
|
||||
out.Write(text)
|
||||
out.WriteString("}")
|
||||
}
|
||||
|
||||
func (options *Latex) Emphasis(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("\\textit{")
|
||||
out.Write(text)
|
||||
out.WriteString("}")
|
||||
}
|
||||
|
||||
func (options *Latex) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
||||
if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) {
|
||||
// treat it like a link
|
||||
out.WriteString("\\href{")
|
||||
out.Write(link)
|
||||
out.WriteString("}{")
|
||||
out.Write(alt)
|
||||
out.WriteString("}")
|
||||
} else {
|
||||
out.WriteString("\\includegraphics{")
|
||||
out.Write(link)
|
||||
out.WriteString("}")
|
||||
}
|
||||
}
|
||||
|
||||
func (options *Latex) LineBreak(out *bytes.Buffer) {
|
||||
out.WriteString(" \\\\\n")
|
||||
}
|
||||
|
||||
func (options *Latex) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
|
||||
out.WriteString("\\href{")
|
||||
out.Write(link)
|
||||
out.WriteString("}{")
|
||||
out.Write(content)
|
||||
out.WriteString("}")
|
||||
}
|
||||
|
||||
func (options *Latex) RawHtmlTag(out *bytes.Buffer, tag []byte) {
|
||||
}
|
||||
|
||||
func (options *Latex) TripleEmphasis(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("\\textbf{\\textit{")
|
||||
out.Write(text)
|
||||
out.WriteString("}}")
|
||||
}
|
||||
|
||||
func (options *Latex) StrikeThrough(out *bytes.Buffer, text []byte) {
|
||||
out.WriteString("\\sout{")
|
||||
out.Write(text)
|
||||
out.WriteString("}")
|
||||
}
|
||||
|
||||
// TODO: this
|
||||
func (options *Latex) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
|
||||
|
||||
}
|
||||
|
||||
func needsBackslash(c byte) bool {
|
||||
for _, r := range []byte("_{}%$&\\~#") {
|
||||
if c == r {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func escapeSpecialChars(out *bytes.Buffer, text []byte) {
|
||||
for i := 0; i < len(text); i++ {
|
||||
// directly copy normal characters
|
||||
org := i
|
||||
|
||||
for i < len(text) && !needsBackslash(text[i]) {
|
||||
i++
|
||||
}
|
||||
if i > org {
|
||||
out.Write(text[org:i])
|
||||
}
|
||||
|
||||
// escape a character
|
||||
if i >= len(text) {
|
||||
break
|
||||
}
|
||||
out.WriteByte('\\')
|
||||
out.WriteByte(text[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (options *Latex) Entity(out *bytes.Buffer, entity []byte) {
|
||||
// TODO: convert this into a unicode character or something
|
||||
out.Write(entity)
|
||||
}
|
||||
|
||||
func (options *Latex) NormalText(out *bytes.Buffer, text []byte) {
|
||||
escapeSpecialChars(out, text)
|
||||
}
|
||||
|
||||
// header and footer
|
||||
func (options *Latex) DocumentHeader(out *bytes.Buffer) {
|
||||
out.WriteString("\\documentclass{article}\n")
|
||||
out.WriteString("\n")
|
||||
out.WriteString("\\usepackage{graphicx}\n")
|
||||
out.WriteString("\\usepackage{listings}\n")
|
||||
out.WriteString("\\usepackage[margin=1in]{geometry}\n")
|
||||
out.WriteString("\\usepackage[utf8]{inputenc}\n")
|
||||
out.WriteString("\\usepackage{verbatim}\n")
|
||||
out.WriteString("\\usepackage[normalem]{ulem}\n")
|
||||
out.WriteString("\\usepackage{hyperref}\n")
|
||||
out.WriteString("\n")
|
||||
out.WriteString("\\hypersetup{colorlinks,%\n")
|
||||
out.WriteString(" citecolor=black,%\n")
|
||||
out.WriteString(" filecolor=black,%\n")
|
||||
out.WriteString(" linkcolor=black,%\n")
|
||||
out.WriteString(" urlcolor=black,%\n")
|
||||
out.WriteString(" pdfstartview=FitH,%\n")
|
||||
out.WriteString(" breaklinks=true,%\n")
|
||||
out.WriteString(" pdfauthor={Blackfriday Markdown Processor v")
|
||||
out.WriteString(VERSION)
|
||||
out.WriteString("}}\n")
|
||||
out.WriteString("\n")
|
||||
out.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n")
|
||||
out.WriteString("\\addtolength{\\parskip}{0.5\\baselineskip}\n")
|
||||
out.WriteString("\\parindent=0pt\n")
|
||||
out.WriteString("\n")
|
||||
out.WriteString("\\begin{document}\n")
|
||||
}
|
||||
|
||||
func (options *Latex) DocumentFooter(out *bytes.Buffer) {
|
||||
out.WriteString("\n\\end{document}\n")
|
||||
}
|
||||
919
vendor/github.com/russross/blackfriday/markdown.go
generated
vendored
Normal file
919
vendor/github.com/russross/blackfriday/markdown.go
generated
vendored
Normal file
@ -0,0 +1,919 @@
|
||||
//
|
||||
// Blackfriday Markdown Processor
|
||||
// Available at http://github.com/russross/blackfriday
|
||||
//
|
||||
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
||||
// Distributed under the Simplified BSD License.
|
||||
// See README.md for details.
|
||||
//
|
||||
|
||||
//
|
||||
//
|
||||
// Markdown parsing and processing
|
||||
//
|
||||
//
|
||||
|
||||
// Blackfriday markdown processor.
|
||||
//
|
||||
// Translates plain text with simple formatting rules into HTML or LaTeX.
|
||||
package blackfriday
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const VERSION = "1.1"
|
||||
|
||||
// These are the supported markdown parsing extensions.
|
||||
// OR these values together to select multiple extensions.
|
||||
const (
|
||||
EXTENSION_NO_INTRA_EMPHASIS = 1 << iota // ignore emphasis markers inside words
|
||||
EXTENSION_TABLES // render tables
|
||||
EXTENSION_FENCED_CODE // render fenced code blocks
|
||||
EXTENSION_AUTOLINK // detect embedded URLs that are not explicitly marked
|
||||
EXTENSION_STRIKETHROUGH // strikethrough text using ~~test~~
|
||||
EXTENSION_LAX_HTML_BLOCKS // loosen up HTML block parsing rules
|
||||
EXTENSION_SPACE_HEADERS // be strict about prefix header rules
|
||||
EXTENSION_HARD_LINE_BREAK // translate newlines into line breaks
|
||||
EXTENSION_TAB_SIZE_EIGHT // expand tabs to eight spaces instead of four
|
||||
EXTENSION_FOOTNOTES // Pandoc-style footnotes
|
||||
EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block
|
||||
EXTENSION_HEADER_IDS // specify header IDs with {#id}
|
||||
EXTENSION_TITLEBLOCK // Titleblock ala pandoc
|
||||
EXTENSION_AUTO_HEADER_IDS // Create the header ID from the text
|
||||
EXTENSION_BACKSLASH_LINE_BREAK // translate trailing backslashes into line breaks
|
||||
EXTENSION_DEFINITION_LISTS // render definition lists
|
||||
|
||||
commonHtmlFlags = 0 |
|
||||
HTML_USE_XHTML |
|
||||
HTML_USE_SMARTYPANTS |
|
||||
HTML_SMARTYPANTS_FRACTIONS |
|
||||
HTML_SMARTYPANTS_LATEX_DASHES
|
||||
|
||||
commonExtensions = 0 |
|
||||
EXTENSION_NO_INTRA_EMPHASIS |
|
||||
EXTENSION_TABLES |
|
||||
EXTENSION_FENCED_CODE |
|
||||
EXTENSION_AUTOLINK |
|
||||
EXTENSION_STRIKETHROUGH |
|
||||
EXTENSION_SPACE_HEADERS |
|
||||
EXTENSION_HEADER_IDS |
|
||||
EXTENSION_BACKSLASH_LINE_BREAK |
|
||||
EXTENSION_DEFINITION_LISTS
|
||||
)
|
||||
|
||||
// These are the possible flag values for the link renderer.
|
||||
// Only a single one of these values will be used; they are not ORed together.
|
||||
// These are mostly of interest if you are writing a new output format.
|
||||
const (
|
||||
LINK_TYPE_NOT_AUTOLINK = iota
|
||||
LINK_TYPE_NORMAL
|
||||
LINK_TYPE_EMAIL
|
||||
)
|
||||
|
||||
// These are the possible flag values for the ListItem renderer.
|
||||
// Multiple flag values may be ORed together.
|
||||
// These are mostly of interest if you are writing a new output format.
|
||||
const (
|
||||
LIST_TYPE_ORDERED = 1 << iota
|
||||
LIST_TYPE_DEFINITION
|
||||
LIST_TYPE_TERM
|
||||
LIST_ITEM_CONTAINS_BLOCK
|
||||
LIST_ITEM_BEGINNING_OF_LIST
|
||||
LIST_ITEM_END_OF_LIST
|
||||
)
|
||||
|
||||
// These are the possible flag values for the table cell renderer.
|
||||
// Only a single one of these values will be used; they are not ORed together.
|
||||
// These are mostly of interest if you are writing a new output format.
|
||||
const (
|
||||
TABLE_ALIGNMENT_LEFT = 1 << iota
|
||||
TABLE_ALIGNMENT_RIGHT
|
||||
TABLE_ALIGNMENT_CENTER = (TABLE_ALIGNMENT_LEFT | TABLE_ALIGNMENT_RIGHT)
|
||||
)
|
||||
|
||||
// The size of a tab stop.
|
||||
const (
|
||||
TAB_SIZE_DEFAULT = 4
|
||||
TAB_SIZE_EIGHT = 8
|
||||
)
|
||||
|
||||
// These are the tags that are recognized as HTML block tags.
|
||||
// Any of these can be included in markdown text without special escaping.
|
||||
var blockTags = map[string]bool{
|
||||
"p": true,
|
||||
"dl": true,
|
||||
"h1": true,
|
||||
"h2": true,
|
||||
"h3": true,
|
||||
"h4": true,
|
||||
"h5": true,
|
||||
"h6": true,
|
||||
"ol": true,
|
||||
"ul": true,
|
||||
"del": true,
|
||||
"div": true,
|
||||
"ins": true,
|
||||
"pre": true,
|
||||
"form": true,
|
||||
"math": true,
|
||||
"table": true,
|
||||
"iframe": true,
|
||||
"script": true,
|
||||
"fieldset": true,
|
||||
"noscript": true,
|
||||
"blockquote": true,
|
||||
|
||||
// HTML5
|
||||
"video": true,
|
||||
"aside": true,
|
||||
"canvas": true,
|
||||
"figure": true,
|
||||
"footer": true,
|
||||
"header": true,
|
||||
"hgroup": true,
|
||||
"output": true,
|
||||
"article": true,
|
||||
"section": true,
|
||||
"progress": true,
|
||||
"figcaption": true,
|
||||
}
|
||||
|
||||
// Renderer is the rendering interface.
|
||||
// This is mostly of interest if you are implementing a new rendering format.
|
||||
//
|
||||
// When a byte slice is provided, it contains the (rendered) contents of the
|
||||
// element.
|
||||
//
|
||||
// When a callback is provided instead, it will write the contents of the
|
||||
// respective element directly to the output buffer and return true on success.
|
||||
// If the callback returns false, the rendering function should reset the
|
||||
// output buffer as though it had never been called.
|
||||
//
|
||||
// Currently Html and Latex implementations are provided
|
||||
type Renderer interface {
|
||||
// block-level callbacks
|
||||
BlockCode(out *bytes.Buffer, text []byte, lang string)
|
||||
BlockQuote(out *bytes.Buffer, text []byte)
|
||||
BlockHtml(out *bytes.Buffer, text []byte)
|
||||
Header(out *bytes.Buffer, text func() bool, level int, id string)
|
||||
HRule(out *bytes.Buffer)
|
||||
List(out *bytes.Buffer, text func() bool, flags int)
|
||||
ListItem(out *bytes.Buffer, text []byte, flags int)
|
||||
Paragraph(out *bytes.Buffer, text func() bool)
|
||||
Table(out *bytes.Buffer, header []byte, body []byte, columnData []int)
|
||||
TableRow(out *bytes.Buffer, text []byte)
|
||||
TableHeaderCell(out *bytes.Buffer, text []byte, flags int)
|
||||
TableCell(out *bytes.Buffer, text []byte, flags int)
|
||||
Footnotes(out *bytes.Buffer, text func() bool)
|
||||
FootnoteItem(out *bytes.Buffer, name, text []byte, flags int)
|
||||
TitleBlock(out *bytes.Buffer, text []byte)
|
||||
|
||||
// Span-level callbacks
|
||||
AutoLink(out *bytes.Buffer, link []byte, kind int)
|
||||
CodeSpan(out *bytes.Buffer, text []byte)
|
||||
DoubleEmphasis(out *bytes.Buffer, text []byte)
|
||||
Emphasis(out *bytes.Buffer, text []byte)
|
||||
Image(out *bytes.Buffer, link []byte, title []byte, alt []byte)
|
||||
LineBreak(out *bytes.Buffer)
|
||||
Link(out *bytes.Buffer, link []byte, title []byte, content []byte)
|
||||
RawHtmlTag(out *bytes.Buffer, tag []byte)
|
||||
TripleEmphasis(out *bytes.Buffer, text []byte)
|
||||
StrikeThrough(out *bytes.Buffer, text []byte)
|
||||
FootnoteRef(out *bytes.Buffer, ref []byte, id int)
|
||||
|
||||
// Low-level callbacks
|
||||
Entity(out *bytes.Buffer, entity []byte)
|
||||
NormalText(out *bytes.Buffer, text []byte)
|
||||
|
||||
// Header and footer
|
||||
DocumentHeader(out *bytes.Buffer)
|
||||
DocumentFooter(out *bytes.Buffer)
|
||||
|
||||
GetFlags() int
|
||||
}
|
||||
|
||||
// Callback functions for inline parsing. One such function is defined
|
||||
// for each character that triggers a response when parsing inline data.
|
||||
type inlineParser func(p *parser, out *bytes.Buffer, data []byte, offset int) int
|
||||
|
||||
// Parser holds runtime state used by the parser.
|
||||
// This is constructed by the Markdown function.
|
||||
type parser struct {
|
||||
r Renderer
|
||||
refOverride ReferenceOverrideFunc
|
||||
refs map[string]*reference
|
||||
inlineCallback [256]inlineParser
|
||||
flags int
|
||||
nesting int
|
||||
maxNesting int
|
||||
insideLink bool
|
||||
|
||||
// Footnotes need to be ordered as well as available to quickly check for
|
||||
// presence. If a ref is also a footnote, it's stored both in refs and here
|
||||
// in notes. Slice is nil if footnotes not enabled.
|
||||
notes []*reference
|
||||
}
|
||||
|
||||
func (p *parser) getRef(refid string) (ref *reference, found bool) {
|
||||
if p.refOverride != nil {
|
||||
r, overridden := p.refOverride(refid)
|
||||
if overridden {
|
||||
if r == nil {
|
||||
return nil, false
|
||||
}
|
||||
return &reference{
|
||||
link: []byte(r.Link),
|
||||
title: []byte(r.Title),
|
||||
noteId: 0,
|
||||
hasBlock: false,
|
||||
text: []byte(r.Text)}, true
|
||||
}
|
||||
}
|
||||
// refs are case insensitive
|
||||
ref, found = p.refs[strings.ToLower(refid)]
|
||||
return ref, found
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Public interface
|
||||
//
|
||||
//
|
||||
|
||||
// Reference represents the details of a link.
|
||||
// See the documentation in Options for more details on use-case.
|
||||
type Reference struct {
|
||||
// Link is usually the URL the reference points to.
|
||||
Link string
|
||||
// Title is the alternate text describing the link in more detail.
|
||||
Title string
|
||||
// Text is the optional text to override the ref with if the syntax used was
|
||||
// [refid][]
|
||||
Text string
|
||||
}
|
||||
|
||||
// ReferenceOverrideFunc is expected to be called with a reference string and
|
||||
// return either a valid Reference type that the reference string maps to or
|
||||
// nil. If overridden is false, the default reference logic will be executed.
|
||||
// See the documentation in Options for more details on use-case.
|
||||
type ReferenceOverrideFunc func(reference string) (ref *Reference, overridden bool)
|
||||
|
||||
// Options represents configurable overrides and callbacks (in addition to the
|
||||
// extension flag set) for configuring a Markdown parse.
|
||||
type Options struct {
|
||||
// Extensions is a flag set of bit-wise ORed extension bits. See the
|
||||
// EXTENSION_* flags defined in this package.
|
||||
Extensions int
|
||||
|
||||
// ReferenceOverride is an optional function callback that is called every
|
||||
// time a reference is resolved.
|
||||
//
|
||||
// In Markdown, the link reference syntax can be made to resolve a link to
|
||||
// a reference instead of an inline URL, in one of the following ways:
|
||||
//
|
||||
// * [link text][refid]
|
||||
// * [refid][]
|
||||
//
|
||||
// Usually, the refid is defined at the bottom of the Markdown document. If
|
||||
// this override function is provided, the refid is passed to the override
|
||||
// function first, before consulting the defined refids at the bottom. If
|
||||
// the override function indicates an override did not occur, the refids at
|
||||
// the bottom will be used to fill in the link details.
|
||||
ReferenceOverride ReferenceOverrideFunc
|
||||
}
|
||||
|
||||
// MarkdownBasic is a convenience function for simple rendering.
|
||||
// It processes markdown input with no extensions enabled.
|
||||
func MarkdownBasic(input []byte) []byte {
|
||||
// set up the HTML renderer
|
||||
htmlFlags := HTML_USE_XHTML
|
||||
renderer := HtmlRenderer(htmlFlags, "", "")
|
||||
|
||||
// set up the parser
|
||||
return MarkdownOptions(input, renderer, Options{Extensions: 0})
|
||||
}
|
||||
|
||||
// Call Markdown with most useful extensions enabled
|
||||
// MarkdownCommon is a convenience function for simple rendering.
|
||||
// It processes markdown input with common extensions enabled, including:
|
||||
//
|
||||
// * Smartypants processing with smart fractions and LaTeX dashes
|
||||
//
|
||||
// * Intra-word emphasis suppression
|
||||
//
|
||||
// * Tables
|
||||
//
|
||||
// * Fenced code blocks
|
||||
//
|
||||
// * Autolinking
|
||||
//
|
||||
// * Strikethrough support
|
||||
//
|
||||
// * Strict header parsing
|
||||
//
|
||||
// * Custom Header IDs
|
||||
func MarkdownCommon(input []byte) []byte {
|
||||
// set up the HTML renderer
|
||||
renderer := HtmlRenderer(commonHtmlFlags, "", "")
|
||||
return MarkdownOptions(input, renderer, Options{
|
||||
Extensions: commonExtensions})
|
||||
}
|
||||
|
||||
// Markdown is the main rendering function.
|
||||
// It parses and renders a block of markdown-encoded text.
|
||||
// The supplied Renderer is used to format the output, and extensions dictates
|
||||
// which non-standard extensions are enabled.
|
||||
//
|
||||
// To use the supplied Html or LaTeX renderers, see HtmlRenderer and
|
||||
// LatexRenderer, respectively.
|
||||
func Markdown(input []byte, renderer Renderer, extensions int) []byte {
|
||||
return MarkdownOptions(input, renderer, Options{
|
||||
Extensions: extensions})
|
||||
}
|
||||
|
||||
// MarkdownOptions is just like Markdown but takes additional options through
|
||||
// the Options struct.
|
||||
func MarkdownOptions(input []byte, renderer Renderer, opts Options) []byte {
|
||||
// no point in parsing if we can't render
|
||||
if renderer == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
extensions := opts.Extensions
|
||||
|
||||
// fill in the render structure
|
||||
p := new(parser)
|
||||
p.r = renderer
|
||||
p.flags = extensions
|
||||
p.refOverride = opts.ReferenceOverride
|
||||
p.refs = make(map[string]*reference)
|
||||
p.maxNesting = 16
|
||||
p.insideLink = false
|
||||
|
||||
// register inline parsers
|
||||
p.inlineCallback['*'] = emphasis
|
||||
p.inlineCallback['_'] = emphasis
|
||||
if extensions&EXTENSION_STRIKETHROUGH != 0 {
|
||||
p.inlineCallback['~'] = emphasis
|
||||
}
|
||||
p.inlineCallback['`'] = codeSpan
|
||||
p.inlineCallback['\n'] = lineBreak
|
||||
p.inlineCallback['['] = link
|
||||
p.inlineCallback['<'] = leftAngle
|
||||
p.inlineCallback['\\'] = escape
|
||||
p.inlineCallback['&'] = entity
|
||||
|
||||
if extensions&EXTENSION_AUTOLINK != 0 {
|
||||
p.inlineCallback[':'] = autoLink
|
||||
}
|
||||
|
||||
if extensions&EXTENSION_FOOTNOTES != 0 {
|
||||
p.notes = make([]*reference, 0)
|
||||
}
|
||||
|
||||
first := firstPass(p, input)
|
||||
second := secondPass(p, first)
|
||||
return second
|
||||
}
|
||||
|
||||
// first pass:
|
||||
// - extract references
|
||||
// - expand tabs
|
||||
// - normalize newlines
|
||||
// - copy everything else
|
||||
// - add missing newlines before fenced code blocks
|
||||
func firstPass(p *parser, input []byte) []byte {
|
||||
var out bytes.Buffer
|
||||
tabSize := TAB_SIZE_DEFAULT
|
||||
if p.flags&EXTENSION_TAB_SIZE_EIGHT != 0 {
|
||||
tabSize = TAB_SIZE_EIGHT
|
||||
}
|
||||
beg, end := 0, 0
|
||||
lastLineWasBlank := false
|
||||
lastFencedCodeBlockEnd := 0
|
||||
for beg < len(input) { // iterate over lines
|
||||
if end = isReference(p, input[beg:], tabSize); end > 0 {
|
||||
beg += end
|
||||
} else { // skip to the next line
|
||||
end = beg
|
||||
for end < len(input) && input[end] != '\n' && input[end] != '\r' {
|
||||
end++
|
||||
}
|
||||
|
||||
if p.flags&EXTENSION_FENCED_CODE != 0 {
|
||||
// when last line was none blank and a fenced code block comes after
|
||||
if beg >= lastFencedCodeBlockEnd {
|
||||
if i := p.fencedCode(&out, input[beg:], false); i > 0 {
|
||||
if !lastLineWasBlank {
|
||||
out.WriteByte('\n') // need to inject additional linebreak
|
||||
}
|
||||
lastFencedCodeBlockEnd = beg + i
|
||||
}
|
||||
}
|
||||
lastLineWasBlank = end == beg
|
||||
}
|
||||
|
||||
// add the line body if present
|
||||
if end > beg {
|
||||
if end < lastFencedCodeBlockEnd { // Do not expand tabs while inside fenced code blocks.
|
||||
out.Write(input[beg:end])
|
||||
} else {
|
||||
expandTabs(&out, input[beg:end], tabSize)
|
||||
}
|
||||
}
|
||||
out.WriteByte('\n')
|
||||
|
||||
if end < len(input) && input[end] == '\r' {
|
||||
end++
|
||||
}
|
||||
if end < len(input) && input[end] == '\n' {
|
||||
end++
|
||||
}
|
||||
|
||||
beg = end
|
||||
}
|
||||
}
|
||||
|
||||
// empty input?
|
||||
if out.Len() == 0 {
|
||||
out.WriteByte('\n')
|
||||
}
|
||||
|
||||
return out.Bytes()
|
||||
}
|
||||
|
||||
// second pass: actual rendering
|
||||
func secondPass(p *parser, input []byte) []byte {
|
||||
var output bytes.Buffer
|
||||
|
||||
p.r.DocumentHeader(&output)
|
||||
p.block(&output, input)
|
||||
|
||||
if p.flags&EXTENSION_FOOTNOTES != 0 && len(p.notes) > 0 {
|
||||
p.r.Footnotes(&output, func() bool {
|
||||
flags := LIST_ITEM_BEGINNING_OF_LIST
|
||||
for _, ref := range p.notes {
|
||||
var buf bytes.Buffer
|
||||
if ref.hasBlock {
|
||||
flags |= LIST_ITEM_CONTAINS_BLOCK
|
||||
p.block(&buf, ref.title)
|
||||
} else {
|
||||
p.inline(&buf, ref.title)
|
||||
}
|
||||
p.r.FootnoteItem(&output, ref.link, buf.Bytes(), flags)
|
||||
flags &^= LIST_ITEM_BEGINNING_OF_LIST | LIST_ITEM_CONTAINS_BLOCK
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
p.r.DocumentFooter(&output)
|
||||
|
||||
if p.nesting != 0 {
|
||||
panic("Nesting level did not end at zero")
|
||||
}
|
||||
|
||||
return output.Bytes()
|
||||
}
|
||||
|
||||
//
|
||||
// Link references
|
||||
//
|
||||
// This section implements support for references that (usually) appear
|
||||
// as footnotes in a document, and can be referenced anywhere in the document.
|
||||
// The basic format is:
|
||||
//
|
||||
// [1]: http://www.google.com/ "Google"
|
||||
// [2]: http://www.github.com/ "Github"
|
||||
//
|
||||
// Anywhere in the document, the reference can be linked by referring to its
|
||||
// label, i.e., 1 and 2 in this example, as in:
|
||||
//
|
||||
// This library is hosted on [Github][2], a git hosting site.
|
||||
//
|
||||
// Actual footnotes as specified in Pandoc and supported by some other Markdown
|
||||
// libraries such as php-markdown are also taken care of. They look like this:
|
||||
//
|
||||
// This sentence needs a bit of further explanation.[^note]
|
||||
//
|
||||
// [^note]: This is the explanation.
|
||||
//
|
||||
// Footnotes should be placed at the end of the document in an ordered list.
|
||||
// Inline footnotes such as:
|
||||
//
|
||||
// Inline footnotes^[Not supported.] also exist.
|
||||
//
|
||||
// are not yet supported.
|
||||
|
||||
// References are parsed and stored in this struct.
|
||||
type reference struct {
|
||||
link []byte
|
||||
title []byte
|
||||
noteId int // 0 if not a footnote ref
|
||||
hasBlock bool
|
||||
text []byte
|
||||
}
|
||||
|
||||
// Check whether or not data starts with a reference link.
|
||||
// If so, it is parsed and stored in the list of references
|
||||
// (in the render struct).
|
||||
// Returns the number of bytes to skip to move past it,
|
||||
// or zero if the first line is not a reference.
|
||||
func isReference(p *parser, data []byte, tabSize int) int {
|
||||
// up to 3 optional leading spaces
|
||||
if len(data) < 4 {
|
||||
return 0
|
||||
}
|
||||
i := 0
|
||||
for i < 3 && data[i] == ' ' {
|
||||
i++
|
||||
}
|
||||
|
||||
noteId := 0
|
||||
|
||||
// id part: anything but a newline between brackets
|
||||
if data[i] != '[' {
|
||||
return 0
|
||||
}
|
||||
i++
|
||||
if p.flags&EXTENSION_FOOTNOTES != 0 {
|
||||
if i < len(data) && data[i] == '^' {
|
||||
// we can set it to anything here because the proper noteIds will
|
||||
// be assigned later during the second pass. It just has to be != 0
|
||||
noteId = 1
|
||||
i++
|
||||
}
|
||||
}
|
||||
idOffset := i
|
||||
for i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != ']' {
|
||||
i++
|
||||
}
|
||||
if i >= len(data) || data[i] != ']' {
|
||||
return 0
|
||||
}
|
||||
idEnd := i
|
||||
|
||||
// spacer: colon (space | tab)* newline? (space | tab)*
|
||||
i++
|
||||
if i >= len(data) || data[i] != ':' {
|
||||
return 0
|
||||
}
|
||||
i++
|
||||
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
|
||||
i++
|
||||
}
|
||||
if i < len(data) && (data[i] == '\n' || data[i] == '\r') {
|
||||
i++
|
||||
if i < len(data) && data[i] == '\n' && data[i-1] == '\r' {
|
||||
i++
|
||||
}
|
||||
}
|
||||
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
|
||||
i++
|
||||
}
|
||||
if i >= len(data) {
|
||||
return 0
|
||||
}
|
||||
|
||||
var (
|
||||
linkOffset, linkEnd int
|
||||
titleOffset, titleEnd int
|
||||
lineEnd int
|
||||
raw []byte
|
||||
hasBlock bool
|
||||
)
|
||||
|
||||
if p.flags&EXTENSION_FOOTNOTES != 0 && noteId != 0 {
|
||||
linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize)
|
||||
lineEnd = linkEnd
|
||||
} else {
|
||||
linkOffset, linkEnd, titleOffset, titleEnd, lineEnd = scanLinkRef(p, data, i)
|
||||
}
|
||||
if lineEnd == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// a valid ref has been found
|
||||
|
||||
ref := &reference{
|
||||
noteId: noteId,
|
||||
hasBlock: hasBlock,
|
||||
}
|
||||
|
||||
if noteId > 0 {
|
||||
// reusing the link field for the id since footnotes don't have links
|
||||
ref.link = data[idOffset:idEnd]
|
||||
// if footnote, it's not really a title, it's the contained text
|
||||
ref.title = raw
|
||||
} else {
|
||||
ref.link = data[linkOffset:linkEnd]
|
||||
ref.title = data[titleOffset:titleEnd]
|
||||
}
|
||||
|
||||
// id matches are case-insensitive
|
||||
id := string(bytes.ToLower(data[idOffset:idEnd]))
|
||||
|
||||
p.refs[id] = ref
|
||||
|
||||
return lineEnd
|
||||
}
|
||||
|
||||
func scanLinkRef(p *parser, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) {
|
||||
// link: whitespace-free sequence, optionally between angle brackets
|
||||
if data[i] == '<' {
|
||||
i++
|
||||
}
|
||||
linkOffset = i
|
||||
for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' {
|
||||
i++
|
||||
}
|
||||
if i == len(data) {
|
||||
return
|
||||
}
|
||||
linkEnd = i
|
||||
if data[linkOffset] == '<' && data[linkEnd-1] == '>' {
|
||||
linkOffset++
|
||||
linkEnd--
|
||||
}
|
||||
|
||||
// optional spacer: (space | tab)* (newline | '\'' | '"' | '(' )
|
||||
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
|
||||
i++
|
||||
}
|
||||
if i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(' {
|
||||
return
|
||||
}
|
||||
|
||||
// compute end-of-line
|
||||
if i >= len(data) || data[i] == '\r' || data[i] == '\n' {
|
||||
lineEnd = i
|
||||
}
|
||||
if i+1 < len(data) && data[i] == '\r' && data[i+1] == '\n' {
|
||||
lineEnd++
|
||||
}
|
||||
|
||||
// optional (space|tab)* spacer after a newline
|
||||
if lineEnd > 0 {
|
||||
i = lineEnd + 1
|
||||
for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// optional title: any non-newline sequence enclosed in '"() alone on its line
|
||||
if i+1 < len(data) && (data[i] == '\'' || data[i] == '"' || data[i] == '(') {
|
||||
i++
|
||||
titleOffset = i
|
||||
|
||||
// look for EOL
|
||||
for i < len(data) && data[i] != '\n' && data[i] != '\r' {
|
||||
i++
|
||||
}
|
||||
if i+1 < len(data) && data[i] == '\n' && data[i+1] == '\r' {
|
||||
titleEnd = i + 1
|
||||
} else {
|
||||
titleEnd = i
|
||||
}
|
||||
|
||||
// step back
|
||||
i--
|
||||
for i > titleOffset && (data[i] == ' ' || data[i] == '\t') {
|
||||
i--
|
||||
}
|
||||
if i > titleOffset && (data[i] == '\'' || data[i] == '"' || data[i] == ')') {
|
||||
lineEnd = titleEnd
|
||||
titleEnd = i
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// The first bit of this logic is the same as (*parser).listItem, but the rest
|
||||
// is much simpler. This function simply finds the entire block and shifts it
|
||||
// over by one tab if it is indeed a block (just returns the line if it's not).
|
||||
// blockEnd is the end of the section in the input buffer, and contents is the
|
||||
// extracted text that was shifted over one tab. It will need to be rendered at
|
||||
// the end of the document.
|
||||
func scanFootnote(p *parser, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) {
|
||||
if i == 0 || len(data) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// skip leading whitespace on first line
|
||||
for i < len(data) && data[i] == ' ' {
|
||||
i++
|
||||
}
|
||||
|
||||
blockStart = i
|
||||
|
||||
// find the end of the line
|
||||
blockEnd = i
|
||||
for i < len(data) && data[i-1] != '\n' {
|
||||
i++
|
||||
}
|
||||
|
||||
// get working buffer
|
||||
var raw bytes.Buffer
|
||||
|
||||
// put the first line into the working buffer
|
||||
raw.Write(data[blockEnd:i])
|
||||
blockEnd = i
|
||||
|
||||
// process the following lines
|
||||
containsBlankLine := false
|
||||
|
||||
gatherLines:
|
||||
for blockEnd < len(data) {
|
||||
i++
|
||||
|
||||
// find the end of this line
|
||||
for i < len(data) && data[i-1] != '\n' {
|
||||
i++
|
||||
}
|
||||
|
||||
// if it is an empty line, guess that it is part of this item
|
||||
// and move on to the next line
|
||||
if p.isEmpty(data[blockEnd:i]) > 0 {
|
||||
containsBlankLine = true
|
||||
blockEnd = i
|
||||
continue
|
||||
}
|
||||
|
||||
n := 0
|
||||
if n = isIndented(data[blockEnd:i], indentSize); n == 0 {
|
||||
// this is the end of the block.
|
||||
// we don't want to include this last line in the index.
|
||||
break gatherLines
|
||||
}
|
||||
|
||||
// if there were blank lines before this one, insert a new one now
|
||||
if containsBlankLine {
|
||||
raw.WriteByte('\n')
|
||||
containsBlankLine = false
|
||||
}
|
||||
|
||||
// get rid of that first tab, write to buffer
|
||||
raw.Write(data[blockEnd+n : i])
|
||||
hasBlock = true
|
||||
|
||||
blockEnd = i
|
||||
}
|
||||
|
||||
if data[blockEnd-1] != '\n' {
|
||||
raw.WriteByte('\n')
|
||||
}
|
||||
|
||||
contents = raw.Bytes()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Miscellaneous helper functions
|
||||
//
|
||||
//
|
||||
|
||||
// Test if a character is a punctuation symbol.
|
||||
// Taken from a private function in regexp in the stdlib.
|
||||
func ispunct(c byte) bool {
|
||||
for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") {
|
||||
if c == r {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Test if a character is a whitespace character.
|
||||
func isspace(c byte) bool {
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'
|
||||
}
|
||||
|
||||
// Test if a character is letter.
|
||||
func isletter(c byte) bool {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|
||||
}
|
||||
|
||||
// Test if a character is a letter or a digit.
|
||||
// TODO: check when this is looking for ASCII alnum and when it should use unicode
|
||||
func isalnum(c byte) bool {
|
||||
return (c >= '0' && c <= '9') || isletter(c)
|
||||
}
|
||||
|
||||
// Replace tab characters with spaces, aligning to the next TAB_SIZE column.
|
||||
// always ends output with a newline
|
||||
func expandTabs(out *bytes.Buffer, line []byte, tabSize int) {
|
||||
// first, check for common cases: no tabs, or only tabs at beginning of line
|
||||
i, prefix := 0, 0
|
||||
slowcase := false
|
||||
for i = 0; i < len(line); i++ {
|
||||
if line[i] == '\t' {
|
||||
if prefix == i {
|
||||
prefix++
|
||||
} else {
|
||||
slowcase = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no need to decode runes if all tabs are at the beginning of the line
|
||||
if !slowcase {
|
||||
for i = 0; i < prefix*tabSize; i++ {
|
||||
out.WriteByte(' ')
|
||||
}
|
||||
out.Write(line[prefix:])
|
||||
return
|
||||
}
|
||||
|
||||
// the slow case: we need to count runes to figure out how
|
||||
// many spaces to insert for each tab
|
||||
column := 0
|
||||
i = 0
|
||||
for i < len(line) {
|
||||
start := i
|
||||
for i < len(line) && line[i] != '\t' {
|
||||
_, size := utf8.DecodeRune(line[i:])
|
||||
i += size
|
||||
column++
|
||||
}
|
||||
|
||||
if i > start {
|
||||
out.Write(line[start:i])
|
||||
}
|
||||
|
||||
if i >= len(line) {
|
||||
break
|
||||
}
|
||||
|
||||
for {
|
||||
out.WriteByte(' ')
|
||||
column++
|
||||
if column%tabSize == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// Find if a line counts as indented or not.
|
||||
// Returns number of characters the indent is (0 = not indented).
|
||||
func isIndented(data []byte, indentSize int) int {
|
||||
if len(data) == 0 {
|
||||
return 0
|
||||
}
|
||||
if data[0] == '\t' {
|
||||
return 1
|
||||
}
|
||||
if len(data) < indentSize {
|
||||
return 0
|
||||
}
|
||||
for i := 0; i < indentSize; i++ {
|
||||
if data[i] != ' ' {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return indentSize
|
||||
}
|
||||
|
||||
// Create a url-safe slug for fragments
|
||||
func slugify(in []byte) []byte {
|
||||
if len(in) == 0 {
|
||||
return in
|
||||
}
|
||||
out := make([]byte, 0, len(in))
|
||||
sym := false
|
||||
|
||||
for _, ch := range in {
|
||||
if isalnum(ch) {
|
||||
sym = false
|
||||
out = append(out, ch)
|
||||
} else if sym {
|
||||
continue
|
||||
} else {
|
||||
out = append(out, '-')
|
||||
sym = true
|
||||
}
|
||||
}
|
||||
var a, b int
|
||||
var ch byte
|
||||
for a, ch = range out {
|
||||
if ch != '-' {
|
||||
break
|
||||
}
|
||||
}
|
||||
for b = len(out) - 1; b > 0; b-- {
|
||||
if out[b] != '-' {
|
||||
break
|
||||
}
|
||||
}
|
||||
return out[a : b+1]
|
||||
}
|
||||
128
vendor/github.com/russross/blackfriday/ref_test.go
generated
vendored
Normal file
128
vendor/github.com/russross/blackfriday/ref_test.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
//
|
||||
// Blackfriday Markdown Processor
|
||||
// Available at http://github.com/russross/blackfriday
|
||||
//
|
||||
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
||||
// Distributed under the Simplified BSD License.
|
||||
// See README.md for details.
|
||||
//
|
||||
|
||||
//
|
||||
// Markdown 1.0.3 reference tests
|
||||
//
|
||||
|
||||
package blackfriday
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func runMarkdownReference(input string, flag int) string {
|
||||
renderer := HtmlRenderer(0, "", "")
|
||||
return string(Markdown([]byte(input), renderer, flag))
|
||||
}
|
||||
|
||||
func doTestsReference(t *testing.T, files []string, flag int) {
|
||||
// catch and report panics
|
||||
var candidate string
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
t.Errorf("\npanic while processing [%#v]\n", candidate)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, basename := range files {
|
||||
filename := filepath.Join("testdata", basename+".text")
|
||||
inputBytes, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
|
||||
continue
|
||||
}
|
||||
input := string(inputBytes)
|
||||
|
||||
filename = filepath.Join("testdata", basename+".html")
|
||||
expectedBytes, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
|
||||
continue
|
||||
}
|
||||
expected := string(expectedBytes)
|
||||
|
||||
// fmt.Fprintf(os.Stderr, "processing %s ...", filename)
|
||||
actual := string(runMarkdownReference(input, flag))
|
||||
if actual != expected {
|
||||
t.Errorf("\n [%#v]\nExpected[%#v]\nActual [%#v]",
|
||||
basename+".text", expected, actual)
|
||||
}
|
||||
// fmt.Fprintf(os.Stderr, " ok\n")
|
||||
|
||||
// now test every prefix of every input to check for
|
||||
// bounds checking
|
||||
if !testing.Short() {
|
||||
start, max := 0, len(input)
|
||||
for end := start + 1; end <= max; end++ {
|
||||
candidate = input[start:end]
|
||||
// fmt.Fprintf(os.Stderr, " %s %d:%d/%d\n", filename, start, end, max)
|
||||
_ = runMarkdownReference(candidate, flag)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReference(t *testing.T) {
|
||||
files := []string{
|
||||
"Amps and angle encoding",
|
||||
"Auto links",
|
||||
"Backslash escapes",
|
||||
"Blockquotes with code blocks",
|
||||
"Code Blocks",
|
||||
"Code Spans",
|
||||
"Hard-wrapped paragraphs with list-like lines",
|
||||
"Horizontal rules",
|
||||
"Inline HTML (Advanced)",
|
||||
"Inline HTML (Simple)",
|
||||
"Inline HTML comments",
|
||||
"Links, inline style",
|
||||
"Links, reference style",
|
||||
"Links, shortcut references",
|
||||
"Literal quotes in titles",
|
||||
"Markdown Documentation - Basics",
|
||||
"Markdown Documentation - Syntax",
|
||||
"Nested blockquotes",
|
||||
"Ordered and unordered lists",
|
||||
"Strong and em together",
|
||||
"Tabs",
|
||||
"Tidyness",
|
||||
}
|
||||
doTestsReference(t, files, 0)
|
||||
}
|
||||
|
||||
func TestReference_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) {
|
||||
files := []string{
|
||||
"Amps and angle encoding",
|
||||
"Auto links",
|
||||
"Backslash escapes",
|
||||
"Blockquotes with code blocks",
|
||||
"Code Blocks",
|
||||
"Code Spans",
|
||||
"Hard-wrapped paragraphs with list-like lines no empty line before block",
|
||||
"Horizontal rules",
|
||||
"Inline HTML (Advanced)",
|
||||
"Inline HTML (Simple)",
|
||||
"Inline HTML comments",
|
||||
"Links, inline style",
|
||||
"Links, reference style",
|
||||
"Links, shortcut references",
|
||||
"Literal quotes in titles",
|
||||
"Markdown Documentation - Basics",
|
||||
"Markdown Documentation - Syntax",
|
||||
"Nested blockquotes",
|
||||
"Ordered and unordered lists",
|
||||
"Strong and em together",
|
||||
"Tabs",
|
||||
"Tidyness",
|
||||
}
|
||||
doTestsReference(t, files, EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK)
|
||||
}
|
||||
398
vendor/github.com/russross/blackfriday/smartypants.go
generated
vendored
Normal file
398
vendor/github.com/russross/blackfriday/smartypants.go
generated
vendored
Normal file
@ -0,0 +1,398 @@
|
||||
//
|
||||
// Blackfriday Markdown Processor
|
||||
// Available at http://github.com/russross/blackfriday
|
||||
//
|
||||
// Copyright © 2011 Russ Ross <russ@russross.com>.
|
||||
// Distributed under the Simplified BSD License.
|
||||
// See README.md for details.
|
||||
//
|
||||
|
||||
//
|
||||
//
|
||||
// SmartyPants rendering
|
||||
//
|
||||
//
|
||||
|
||||
package blackfriday
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type smartypantsData struct {
|
||||
inSingleQuote bool
|
||||
inDoubleQuote bool
|
||||
}
|
||||
|
||||
func wordBoundary(c byte) bool {
|
||||
return c == 0 || isspace(c) || ispunct(c)
|
||||
}
|
||||
|
||||
func tolower(c byte) byte {
|
||||
if c >= 'A' && c <= 'Z' {
|
||||
return c - 'A' + 'a'
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func isdigit(c byte) bool {
|
||||
return c >= '0' && c <= '9'
|
||||
}
|
||||
|
||||
func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool) bool {
|
||||
// edge of the buffer is likely to be a tag that we don't get to see,
|
||||
// so we treat it like text sometimes
|
||||
|
||||
// enumerate all sixteen possibilities for (previousChar, nextChar)
|
||||
// each can be one of {0, space, punct, other}
|
||||
switch {
|
||||
case previousChar == 0 && nextChar == 0:
|
||||
// context is not any help here, so toggle
|
||||
*isOpen = !*isOpen
|
||||
case isspace(previousChar) && nextChar == 0:
|
||||
// [ "] might be [ "<code>foo...]
|
||||
*isOpen = true
|
||||
case ispunct(previousChar) && nextChar == 0:
|
||||
// [!"] hmm... could be [Run!"] or [("<code>...]
|
||||
*isOpen = false
|
||||
case /* isnormal(previousChar) && */ nextChar == 0:
|
||||
// [a"] is probably a close
|
||||
*isOpen = false
|
||||
case previousChar == 0 && isspace(nextChar):
|
||||
// [" ] might be [...foo</code>" ]
|
||||
*isOpen = false
|
||||
case isspace(previousChar) && isspace(nextChar):
|
||||
// [ " ] context is not any help here, so toggle
|
||||
*isOpen = !*isOpen
|
||||
case ispunct(previousChar) && isspace(nextChar):
|
||||
// [!" ] is probably a close
|
||||
*isOpen = false
|
||||
case /* isnormal(previousChar) && */ isspace(nextChar):
|
||||
// [a" ] this is one of the easy cases
|
||||
*isOpen = false
|
||||
case previousChar == 0 && ispunct(nextChar):
|
||||
// ["!] hmm... could be ["$1.95] or [</code>"!...]
|
||||
*isOpen = false
|
||||
case isspace(previousChar) && ispunct(nextChar):
|
||||
// [ "!] looks more like [ "$1.95]
|
||||
*isOpen = true
|
||||
case ispunct(previousChar) && ispunct(nextChar):
|
||||
// [!"!] context is not any help here, so toggle
|
||||
*isOpen = !*isOpen
|
||||
case /* isnormal(previousChar) && */ ispunct(nextChar):
|
||||
// [a"!] is probably a close
|
||||
*isOpen = false
|
||||
case previousChar == 0 /* && isnormal(nextChar) */ :
|
||||
// ["a] is probably an open
|
||||
*isOpen = true
|
||||
case isspace(previousChar) /* && isnormal(nextChar) */ :
|
||||
// [ "a] this is one of the easy cases
|
||||
*isOpen = true
|
||||
case ispunct(previousChar) /* && isnormal(nextChar) */ :
|
||||
// [!"a] is probably an open
|
||||
*isOpen = true
|
||||
default:
|
||||
// [a'b] maybe a contraction?
|
||||
*isOpen = false
|
||||
}
|
||||
|
||||
out.WriteByte('&')
|
||||
if *isOpen {
|
||||
out.WriteByte('l')
|
||||
} else {
|
||||
out.WriteByte('r')
|
||||
}
|
||||
out.WriteByte(quote)
|
||||
out.WriteString("quo;")
|
||||
return true
|
||||
}
|
||||
|
||||
func smartSingleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
if len(text) >= 2 {
|
||||
t1 := tolower(text[1])
|
||||
|
||||
if t1 == '\'' {
|
||||
nextChar := byte(0)
|
||||
if len(text) >= 3 {
|
||||
nextChar = text[2]
|
||||
}
|
||||
if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
if (t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && (len(text) < 3 || wordBoundary(text[2])) {
|
||||
out.WriteString("’")
|
||||
return 0
|
||||
}
|
||||
|
||||
if len(text) >= 3 {
|
||||
t2 := tolower(text[2])
|
||||
|
||||
if ((t1 == 'r' && t2 == 'e') || (t1 == 'l' && t2 == 'l') || (t1 == 'v' && t2 == 'e')) &&
|
||||
(len(text) < 4 || wordBoundary(text[3])) {
|
||||
out.WriteString("’")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nextChar := byte(0)
|
||||
if len(text) > 1 {
|
||||
nextChar = text[1]
|
||||
}
|
||||
if smartQuoteHelper(out, previousChar, nextChar, 's', &smrt.inSingleQuote) {
|
||||
return 0
|
||||
}
|
||||
|
||||
out.WriteByte(text[0])
|
||||
return 0
|
||||
}
|
||||
|
||||
func smartParens(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
if len(text) >= 3 {
|
||||
t1 := tolower(text[1])
|
||||
t2 := tolower(text[2])
|
||||
|
||||
if t1 == 'c' && t2 == ')' {
|
||||
out.WriteString("©")
|
||||
return 2
|
||||
}
|
||||
|
||||
if t1 == 'r' && t2 == ')' {
|
||||
out.WriteString("®")
|
||||
return 2
|
||||
}
|
||||
|
||||
if len(text) >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')' {
|
||||
out.WriteString("™")
|
||||
return 3
|
||||
}
|
||||
}
|
||||
|
||||
out.WriteByte(text[0])
|
||||
return 0
|
||||
}
|
||||
|
||||
func smartDash(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
if len(text) >= 2 {
|
||||
if text[1] == '-' {
|
||||
out.WriteString("—")
|
||||
return 1
|
||||
}
|
||||
|
||||
if wordBoundary(previousChar) && wordBoundary(text[1]) {
|
||||
out.WriteString("–")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
out.WriteByte(text[0])
|
||||
return 0
|
||||
}
|
||||
|
||||
func smartDashLatex(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
if len(text) >= 3 && text[1] == '-' && text[2] == '-' {
|
||||
out.WriteString("—")
|
||||
return 2
|
||||
}
|
||||
if len(text) >= 2 && text[1] == '-' {
|
||||
out.WriteString("–")
|
||||
return 1
|
||||
}
|
||||
|
||||
out.WriteByte(text[0])
|
||||
return 0
|
||||
}
|
||||
|
||||
func smartAmpVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int {
|
||||
if bytes.HasPrefix(text, []byte(""")) {
|
||||
nextChar := byte(0)
|
||||
if len(text) >= 7 {
|
||||
nextChar = text[6]
|
||||
}
|
||||
if smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) {
|
||||
return 5
|
||||
}
|
||||
}
|
||||
|
||||
if bytes.HasPrefix(text, []byte("�")) {
|
||||
return 3
|
||||
}
|
||||
|
||||
out.WriteByte('&')
|
||||
return 0
|
||||
}
|
||||
|
||||
func smartAmp(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
return smartAmpVariant(out, smrt, previousChar, text, 'd')
|
||||
}
|
||||
|
||||
func smartAmpAngledQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
return smartAmpVariant(out, smrt, previousChar, text, 'a')
|
||||
}
|
||||
|
||||
func smartPeriod(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
if len(text) >= 3 && text[1] == '.' && text[2] == '.' {
|
||||
out.WriteString("…")
|
||||
return 2
|
||||
}
|
||||
|
||||
if len(text) >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.' {
|
||||
out.WriteString("…")
|
||||
return 4
|
||||
}
|
||||
|
||||
out.WriteByte(text[0])
|
||||
return 0
|
||||
}
|
||||
|
||||
func smartBacktick(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
if len(text) >= 2 && text[1] == '`' {
|
||||
nextChar := byte(0)
|
||||
if len(text) >= 3 {
|
||||
nextChar = text[2]
|
||||
}
|
||||
if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
out.WriteByte(text[0])
|
||||
return 0
|
||||
}
|
||||
|
||||
func smartNumberGeneric(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
|
||||
// is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b
|
||||
// note: check for regular slash (/) or fraction slash (⁄, 0x2044, or 0xe2 81 84 in utf-8)
|
||||
// and avoid changing dates like 1/23/2005 into fractions.
|
||||
numEnd := 0
|
||||
for len(text) > numEnd && isdigit(text[numEnd]) {
|
||||
numEnd++
|
||||
}
|
||||
if numEnd == 0 {
|
||||
out.WriteByte(text[0])
|
||||
return 0
|
||||
}
|
||||
denStart := numEnd + 1
|
||||
if len(text) > numEnd+3 && text[numEnd] == 0xe2 && text[numEnd+1] == 0x81 && text[numEnd+2] == 0x84 {
|
||||
denStart = numEnd + 3
|
||||
} else if len(text) < numEnd+2 || text[numEnd] != '/' {
|
||||
out.WriteByte(text[0])
|
||||
return 0
|
||||
}
|
||||
denEnd := denStart
|
||||
for len(text) > denEnd && isdigit(text[denEnd]) {
|
||||
denEnd++
|
||||
}
|
||||
if denEnd == denStart {
|
||||
out.WriteByte(text[0])
|
||||
return 0
|
||||
}
|
||||
if len(text) == denEnd || wordBoundary(text[denEnd]) && text[denEnd] != '/' {
|
||||
out.WriteString("<sup>")
|
||||
out.Write(text[:numEnd])
|
||||
out.WriteString("</sup>⁄<sub>")
|
||||
out.Write(text[denStart:denEnd])
|
||||
out.WriteString("</sub>")
|
||||
return denEnd - 1
|
||||
}
|
||||
}
|
||||
|
||||
out.WriteByte(text[0])
|
||||
return 0
|
||||
}
|
||||
|
||||
func smartNumber(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
|
||||
if text[0] == '1' && text[1] == '/' && text[2] == '2' {
|
||||
if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' {
|
||||
out.WriteString("½")
|
||||
return 2
|
||||
}
|
||||
}
|
||||
|
||||
if text[0] == '1' && text[1] == '/' && text[2] == '4' {
|
||||
if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h') {
|
||||
out.WriteString("¼")
|
||||
return 2
|
||||
}
|
||||
}
|
||||
|
||||
if text[0] == '3' && text[1] == '/' && text[2] == '4' {
|
||||
if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's') {
|
||||
out.WriteString("¾")
|
||||
return 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out.WriteByte(text[0])
|
||||
return 0
|
||||
}
|
||||
|
||||
func smartDoubleQuoteVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int {
|
||||
nextChar := byte(0)
|
||||
if len(text) > 1 {
|
||||
nextChar = text[1]
|
||||
}
|
||||
if !smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) {
|
||||
out.WriteString(""")
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func smartDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'd')
|
||||
}
|
||||
|
||||
func smartAngledDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'a')
|
||||
}
|
||||
|
||||
func smartLeftAngle(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
|
||||
i := 0
|
||||
|
||||
for i < len(text) && text[i] != '>' {
|
||||
i++
|
||||
}
|
||||
|
||||
out.Write(text[:i+1])
|
||||
return i
|
||||
}
|
||||
|
||||
type smartCallback func(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int
|
||||
|
||||
type smartypantsRenderer [256]smartCallback
|
||||
|
||||
func smartypants(flags int) *smartypantsRenderer {
|
||||
r := new(smartypantsRenderer)
|
||||
if flags&HTML_SMARTYPANTS_ANGLED_QUOTES == 0 {
|
||||
r['"'] = smartDoubleQuote
|
||||
r['&'] = smartAmp
|
||||
} else {
|
||||
r['"'] = smartAngledDoubleQuote
|
||||
r['&'] = smartAmpAngledQuote
|
||||
}
|
||||
r['\''] = smartSingleQuote
|
||||
r['('] = smartParens
|
||||
if flags&HTML_SMARTYPANTS_LATEX_DASHES == 0 {
|
||||
r['-'] = smartDash
|
||||
} else {
|
||||
r['-'] = smartDashLatex
|
||||
}
|
||||
r['.'] = smartPeriod
|
||||
if flags&HTML_SMARTYPANTS_FRACTIONS == 0 {
|
||||
r['1'] = smartNumber
|
||||
r['3'] = smartNumber
|
||||
} else {
|
||||
for ch := '1'; ch <= '9'; ch++ {
|
||||
r[ch] = smartNumberGeneric
|
||||
}
|
||||
}
|
||||
r['<'] = smartLeftAngle
|
||||
r['`'] = smartBacktick
|
||||
return r
|
||||
}
|
||||
17
vendor/github.com/russross/blackfriday/testdata/Amps and angle encoding.html
generated
vendored
Normal file
17
vendor/github.com/russross/blackfriday/testdata/Amps and angle encoding.html
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<p>AT&T has an ampersand in their name.</p>
|
||||
|
||||
<p>AT&T is another way to write it.</p>
|
||||
|
||||
<p>This & that.</p>
|
||||
|
||||
<p>4 < 5.</p>
|
||||
|
||||
<p>6 > 5.</p>
|
||||
|
||||
<p>Here's a <a href="http://example.com/?foo=1&bar=2">link</a> with an ampersand in the URL.</p>
|
||||
|
||||
<p>Here's a link with an amersand in the link text: <a href="http://att.com/" title="AT&T">AT&T</a>.</p>
|
||||
|
||||
<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>
|
||||
|
||||
<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>
|
||||
21
vendor/github.com/russross/blackfriday/testdata/Amps and angle encoding.text
generated
vendored
Normal file
21
vendor/github.com/russross/blackfriday/testdata/Amps and angle encoding.text
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
AT&T has an ampersand in their name.
|
||||
|
||||
AT&T is another way to write it.
|
||||
|
||||
This & that.
|
||||
|
||||
4 < 5.
|
||||
|
||||
6 > 5.
|
||||
|
||||
Here's a [link] [1] with an ampersand in the URL.
|
||||
|
||||
Here's a link with an amersand in the link text: [AT&T] [2].
|
||||
|
||||
Here's an inline [link](/script?foo=1&bar=2).
|
||||
|
||||
Here's an inline [link](</script?foo=1&bar=2>).
|
||||
|
||||
|
||||
[1]: http://example.com/?foo=1&bar=2
|
||||
[2]: http://att.com/ "AT&T"
|
||||
18
vendor/github.com/russross/blackfriday/testdata/Auto links.html
generated
vendored
Normal file
18
vendor/github.com/russross/blackfriday/testdata/Auto links.html
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<p>Link: <a href="http://example.com/">http://example.com/</a>.</p>
|
||||
|
||||
<p>With an ampersand: <a href="http://example.com/?foo=1&bar=2">http://example.com/?foo=1&bar=2</a></p>
|
||||
|
||||
<ul>
|
||||
<li>In a list?</li>
|
||||
<li><a href="http://example.com/">http://example.com/</a></li>
|
||||
<li>It should.</li>
|
||||
</ul>
|
||||
|
||||
<blockquote>
|
||||
<p>Blockquoted: <a href="http://example.com/">http://example.com/</a></p>
|
||||
</blockquote>
|
||||
|
||||
<p>Auto-links should not occur here: <code><http://example.com/></code></p>
|
||||
|
||||
<pre><code>or here: <http://example.com/>
|
||||
</code></pre>
|
||||
13
vendor/github.com/russross/blackfriday/testdata/Auto links.text
generated
vendored
Normal file
13
vendor/github.com/russross/blackfriday/testdata/Auto links.text
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
Link: <http://example.com/>.
|
||||
|
||||
With an ampersand: <http://example.com/?foo=1&bar=2>
|
||||
|
||||
* In a list?
|
||||
* <http://example.com/>
|
||||
* It should.
|
||||
|
||||
> Blockquoted: <http://example.com/>
|
||||
|
||||
Auto-links should not occur here: `<http://example.com/>`
|
||||
|
||||
or here: <http://example.com/>
|
||||
123
vendor/github.com/russross/blackfriday/testdata/Backslash escapes.html
generated
vendored
Normal file
123
vendor/github.com/russross/blackfriday/testdata/Backslash escapes.html
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
<p>These should all get escaped:</p>
|
||||
|
||||
<p>Backslash: \</p>
|
||||
|
||||
<p>Backtick: `</p>
|
||||
|
||||
<p>Asterisk: *</p>
|
||||
|
||||
<p>Underscore: _</p>
|
||||
|
||||
<p>Left brace: {</p>
|
||||
|
||||
<p>Right brace: }</p>
|
||||
|
||||
<p>Left bracket: [</p>
|
||||
|
||||
<p>Right bracket: ]</p>
|
||||
|
||||
<p>Left paren: (</p>
|
||||
|
||||
<p>Right paren: )</p>
|
||||
|
||||
<p>Greater-than: ></p>
|
||||
|
||||
<p>Hash: #</p>
|
||||
|
||||
<p>Period: .</p>
|
||||
|
||||
<p>Bang: !</p>
|
||||
|
||||
<p>Plus: +</p>
|
||||
|
||||
<p>Minus: -</p>
|
||||
|
||||
<p>Tilde: ~</p>
|
||||
|
||||
<p>These should not, because they occur within a code block:</p>
|
||||
|
||||
<pre><code>Backslash: \\
|
||||
|
||||
Backtick: \`
|
||||
|
||||
Asterisk: \*
|
||||
|
||||
Underscore: \_
|
||||
|
||||
Left brace: \{
|
||||
|
||||
Right brace: \}
|
||||
|
||||
Left bracket: \[
|
||||
|
||||
Right bracket: \]
|
||||
|
||||
Left paren: \(
|
||||
|
||||
Right paren: \)
|
||||
|
||||
Greater-than: \>
|
||||
|
||||
Hash: \#
|
||||
|
||||
Period: \.
|
||||
|
||||
Bang: \!
|
||||
|
||||
Plus: \+
|
||||
|
||||
Minus: \-
|
||||
|
||||
Tilde: \~
|
||||
</code></pre>
|
||||
|
||||
<p>Nor should these, which occur in code spans:</p>
|
||||
|
||||
<p>Backslash: <code>\\</code></p>
|
||||
|
||||
<p>Backtick: <code>\`</code></p>
|
||||
|
||||
<p>Asterisk: <code>\*</code></p>
|
||||
|
||||
<p>Underscore: <code>\_</code></p>
|
||||
|
||||
<p>Left brace: <code>\{</code></p>
|
||||
|
||||
<p>Right brace: <code>\}</code></p>
|
||||
|
||||
<p>Left bracket: <code>\[</code></p>
|
||||
|
||||
<p>Right bracket: <code>\]</code></p>
|
||||
|
||||
<p>Left paren: <code>\(</code></p>
|
||||
|
||||
<p>Right paren: <code>\)</code></p>
|
||||
|
||||
<p>Greater-than: <code>\></code></p>
|
||||
|
||||
<p>Hash: <code>\#</code></p>
|
||||
|
||||
<p>Period: <code>\.</code></p>
|
||||
|
||||
<p>Bang: <code>\!</code></p>
|
||||
|
||||
<p>Plus: <code>\+</code></p>
|
||||
|
||||
<p>Minus: <code>\-</code></p>
|
||||
|
||||
<p>Tilde: <code>\~</code></p>
|
||||
|
||||
<p>These should get escaped, even though they're matching pairs for
|
||||
other Markdown constructs:</p>
|
||||
|
||||
<p>*asterisks*</p>
|
||||
|
||||
<p>_underscores_</p>
|
||||
|
||||
<p>`backticks`</p>
|
||||
|
||||
<p>This is a code span with a literal backslash-backtick sequence: <code>\`</code></p>
|
||||
|
||||
<p>This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.</p>
|
||||
|
||||
<p>This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.</p>
|
||||
126
vendor/github.com/russross/blackfriday/testdata/Backslash escapes.text
generated
vendored
Normal file
126
vendor/github.com/russross/blackfriday/testdata/Backslash escapes.text
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
These should all get escaped:
|
||||
|
||||
Backslash: \\
|
||||
|
||||
Backtick: \`
|
||||
|
||||
Asterisk: \*
|
||||
|
||||
Underscore: \_
|
||||
|
||||
Left brace: \{
|
||||
|
||||
Right brace: \}
|
||||
|
||||
Left bracket: \[
|
||||
|
||||
Right bracket: \]
|
||||
|
||||
Left paren: \(
|
||||
|
||||
Right paren: \)
|
||||
|
||||
Greater-than: \>
|
||||
|
||||
Hash: \#
|
||||
|
||||
Period: \.
|
||||
|
||||
Bang: \!
|
||||
|
||||
Plus: \+
|
||||
|
||||
Minus: \-
|
||||
|
||||
Tilde: \~
|
||||
|
||||
|
||||
|
||||
These should not, because they occur within a code block:
|
||||
|
||||
Backslash: \\
|
||||
|
||||
Backtick: \`
|
||||
|
||||
Asterisk: \*
|
||||
|
||||
Underscore: \_
|
||||
|
||||
Left brace: \{
|
||||
|
||||
Right brace: \}
|
||||
|
||||
Left bracket: \[
|
||||
|
||||
Right bracket: \]
|
||||
|
||||
Left paren: \(
|
||||
|
||||
Right paren: \)
|
||||
|
||||
Greater-than: \>
|
||||
|
||||
Hash: \#
|
||||
|
||||
Period: \.
|
||||
|
||||
Bang: \!
|
||||
|
||||
Plus: \+
|
||||
|
||||
Minus: \-
|
||||
|
||||
Tilde: \~
|
||||
|
||||
|
||||
Nor should these, which occur in code spans:
|
||||
|
||||
Backslash: `\\`
|
||||
|
||||
Backtick: `` \` ``
|
||||
|
||||
Asterisk: `\*`
|
||||
|
||||
Underscore: `\_`
|
||||
|
||||
Left brace: `\{`
|
||||
|
||||
Right brace: `\}`
|
||||
|
||||
Left bracket: `\[`
|
||||
|
||||
Right bracket: `\]`
|
||||
|
||||
Left paren: `\(`
|
||||
|
||||
Right paren: `\)`
|
||||
|
||||
Greater-than: `\>`
|
||||
|
||||
Hash: `\#`
|
||||
|
||||
Period: `\.`
|
||||
|
||||
Bang: `\!`
|
||||
|
||||
Plus: `\+`
|
||||
|
||||
Minus: `\-`
|
||||
|
||||
Tilde: `\~`
|
||||
|
||||
|
||||
These should get escaped, even though they're matching pairs for
|
||||
other Markdown constructs:
|
||||
|
||||
\*asterisks\*
|
||||
|
||||
\_underscores\_
|
||||
|
||||
\`backticks\`
|
||||
|
||||
This is a code span with a literal backslash-backtick sequence: `` \` ``
|
||||
|
||||
This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.
|
||||
|
||||
This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.
|
||||
15
vendor/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html
generated
vendored
Normal file
15
vendor/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<blockquote>
|
||||
<p>Example:</p>
|
||||
|
||||
<pre><code>sub status {
|
||||
print "working";
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<p>Or:</p>
|
||||
|
||||
<pre><code>sub status {
|
||||
return "working";
|
||||
}
|
||||
</code></pre>
|
||||
</blockquote>
|
||||
11
vendor/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text
generated
vendored
Normal file
11
vendor/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
> Example:
|
||||
>
|
||||
> sub status {
|
||||
> print "working";
|
||||
> }
|
||||
>
|
||||
> Or:
|
||||
>
|
||||
> sub status {
|
||||
> return "working";
|
||||
> }
|
||||
18
vendor/github.com/russross/blackfriday/testdata/Code Blocks.html
generated
vendored
Normal file
18
vendor/github.com/russross/blackfriday/testdata/Code Blocks.html
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<pre><code>code block on the first line
|
||||
</code></pre>
|
||||
|
||||
<p>Regular text.</p>
|
||||
|
||||
<pre><code>code block indented by spaces
|
||||
</code></pre>
|
||||
|
||||
<p>Regular text.</p>
|
||||
|
||||
<pre><code>the lines in this block
|
||||
all contain trailing spaces
|
||||
</code></pre>
|
||||
|
||||
<p>Regular Text.</p>
|
||||
|
||||
<pre><code>code block on the last line
|
||||
</code></pre>
|
||||
14
vendor/github.com/russross/blackfriday/testdata/Code Blocks.text
generated
vendored
Normal file
14
vendor/github.com/russross/blackfriday/testdata/Code Blocks.text
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
code block on the first line
|
||||
|
||||
Regular text.
|
||||
|
||||
code block indented by spaces
|
||||
|
||||
Regular text.
|
||||
|
||||
the lines in this block
|
||||
all contain trailing spaces
|
||||
|
||||
Regular Text.
|
||||
|
||||
code block on the last line
|
||||
5
vendor/github.com/russross/blackfriday/testdata/Code Spans.html
generated
vendored
Normal file
5
vendor/github.com/russross/blackfriday/testdata/Code Spans.html
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
<p><code><test a="</code> content of attribute <code>"></code></p>
|
||||
|
||||
<p>Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span></p>
|
||||
|
||||
<p>Here's how you put <code>`backticks`</code> in a code span.</p>
|
||||
6
vendor/github.com/russross/blackfriday/testdata/Code Spans.text
generated
vendored
Normal file
6
vendor/github.com/russross/blackfriday/testdata/Code Spans.text
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
`<test a="` content of attribute `">`
|
||||
|
||||
Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span>
|
||||
|
||||
Here's how you put `` `backticks` `` in a code span.
|
||||
|
||||
14
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html
generated
vendored
Normal file
14
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<p>In Markdown 1.0.0 and earlier. Version</p>
|
||||
|
||||
<ol>
|
||||
<li>This line turns into a list item.
|
||||
Because a hard-wrapped line in the
|
||||
middle of a paragraph looked like a
|
||||
list item.</li>
|
||||
</ol>
|
||||
|
||||
<p>Here's one with a bullet.</p>
|
||||
|
||||
<ul>
|
||||
<li>criminey.</li>
|
||||
</ul>
|
||||
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text
generated
vendored
Normal file
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
In Markdown 1.0.0 and earlier. Version
|
||||
8. This line turns into a list item.
|
||||
Because a hard-wrapped line in the
|
||||
middle of a paragraph looked like a
|
||||
list item.
|
||||
|
||||
Here's one with a bullet.
|
||||
* criminey.
|
||||
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html
generated
vendored
Normal file
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
<p>In Markdown 1.0.0 and earlier. Version
|
||||
8. This line turns into a list item.
|
||||
Because a hard-wrapped line in the
|
||||
middle of a paragraph looked like a
|
||||
list item.</p>
|
||||
|
||||
<p>Here's one with a bullet.
|
||||
* criminey.</p>
|
||||
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text
generated
vendored
Normal file
8
vendor/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
In Markdown 1.0.0 and earlier. Version
|
||||
8. This line turns into a list item.
|
||||
Because a hard-wrapped line in the
|
||||
middle of a paragraph looked like a
|
||||
list item.
|
||||
|
||||
Here's one with a bullet.
|
||||
* criminey.
|
||||
71
vendor/github.com/russross/blackfriday/testdata/Horizontal rules.html
generated
vendored
Normal file
71
vendor/github.com/russross/blackfriday/testdata/Horizontal rules.html
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
<p>Dashes:</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<pre><code>---
|
||||
</code></pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<pre><code>- - -
|
||||
</code></pre>
|
||||
|
||||
<p>Asterisks:</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<pre><code>***
|
||||
</code></pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<pre><code>* * *
|
||||
</code></pre>
|
||||
|
||||
<p>Underscores:</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<pre><code>___
|
||||
</code></pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr>
|
||||
|
||||
<pre><code>_ _ _
|
||||
</code></pre>
|
||||
67
vendor/github.com/russross/blackfriday/testdata/Horizontal rules.text
generated
vendored
Normal file
67
vendor/github.com/russross/blackfriday/testdata/Horizontal rules.text
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
Dashes:
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
- - -
|
||||
|
||||
- - -
|
||||
|
||||
- - -
|
||||
|
||||
- - -
|
||||
|
||||
- - -
|
||||
|
||||
|
||||
Asterisks:
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
|
||||
Underscores:
|
||||
|
||||
___
|
||||
|
||||
___
|
||||
|
||||
___
|
||||
|
||||
___
|
||||
|
||||
___
|
||||
|
||||
_ _ _
|
||||
|
||||
_ _ _
|
||||
|
||||
_ _ _
|
||||
|
||||
_ _ _
|
||||
|
||||
_ _ _
|
||||
15
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html
generated
vendored
Normal file
15
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<p>Simple block on one line:</p>
|
||||
|
||||
<div>foo</div>
|
||||
|
||||
<p>And nested without indentation:</p>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
<div style=">"/>
|
||||
</div>
|
||||
<div>bar</div>
|
||||
</div>
|
||||
15
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text
generated
vendored
Normal file
15
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
Simple block on one line:
|
||||
|
||||
<div>foo</div>
|
||||
|
||||
And nested without indentation:
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
<div style=">"/>
|
||||
</div>
|
||||
<div>bar</div>
|
||||
</div>
|
||||
72
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html
generated
vendored
Normal file
72
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
<p>Here's a simple block:</p>
|
||||
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
|
||||
<p>This should be a code block, though:</p>
|
||||
|
||||
<pre><code><div>
|
||||
foo
|
||||
</div>
|
||||
</code></pre>
|
||||
|
||||
<p>As should this:</p>
|
||||
|
||||
<pre><code><div>foo</div>
|
||||
</code></pre>
|
||||
|
||||
<p>Now, nested:</p>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>This should just be an HTML comment:</p>
|
||||
|
||||
<!-- Comment -->
|
||||
|
||||
<p>Multiline:</p>
|
||||
|
||||
<!--
|
||||
Blah
|
||||
Blah
|
||||
-->
|
||||
|
||||
<p>Code block:</p>
|
||||
|
||||
<pre><code><!-- Comment -->
|
||||
</code></pre>
|
||||
|
||||
<p>Just plain comment, with trailing spaces on the line:</p>
|
||||
|
||||
<!-- foo -->
|
||||
|
||||
<p>Code:</p>
|
||||
|
||||
<pre><code><hr />
|
||||
</code></pre>
|
||||
|
||||
<p>Hr's:</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<hr/>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr>
|
||||
|
||||
<hr/>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr class="foo" id="bar" />
|
||||
|
||||
<hr class="foo" id="bar"/>
|
||||
|
||||
<hr class="foo" id="bar" >
|
||||
69
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text
generated
vendored
Normal file
69
vendor/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
Here's a simple block:
|
||||
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
|
||||
This should be a code block, though:
|
||||
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
|
||||
As should this:
|
||||
|
||||
<div>foo</div>
|
||||
|
||||
Now, nested:
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
foo
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
This should just be an HTML comment:
|
||||
|
||||
<!-- Comment -->
|
||||
|
||||
Multiline:
|
||||
|
||||
<!--
|
||||
Blah
|
||||
Blah
|
||||
-->
|
||||
|
||||
Code block:
|
||||
|
||||
<!-- Comment -->
|
||||
|
||||
Just plain comment, with trailing spaces on the line:
|
||||
|
||||
<!-- foo -->
|
||||
|
||||
Code:
|
||||
|
||||
<hr />
|
||||
|
||||
Hr's:
|
||||
|
||||
<hr>
|
||||
|
||||
<hr/>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr>
|
||||
|
||||
<hr/>
|
||||
|
||||
<hr />
|
||||
|
||||
<hr class="foo" id="bar" />
|
||||
|
||||
<hr class="foo" id="bar"/>
|
||||
|
||||
<hr class="foo" id="bar" >
|
||||
|
||||
13
vendor/github.com/russross/blackfriday/testdata/Inline HTML comments.html
generated
vendored
Normal file
13
vendor/github.com/russross/blackfriday/testdata/Inline HTML comments.html
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<p>Paragraph one.</p>
|
||||
|
||||
<!-- This is a simple comment -->
|
||||
|
||||
<!--
|
||||
This is another comment.
|
||||
-->
|
||||
|
||||
<p>Paragraph two.</p>
|
||||
|
||||
<!-- one comment block -- -- with two comments -->
|
||||
|
||||
<p>The end.</p>
|
||||
13
vendor/github.com/russross/blackfriday/testdata/Inline HTML comments.text
generated
vendored
Normal file
13
vendor/github.com/russross/blackfriday/testdata/Inline HTML comments.text
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
Paragraph one.
|
||||
|
||||
<!-- This is a simple comment -->
|
||||
|
||||
<!--
|
||||
This is another comment.
|
||||
-->
|
||||
|
||||
Paragraph two.
|
||||
|
||||
<!-- one comment block -- -- with two comments -->
|
||||
|
||||
The end.
|
||||
11
vendor/github.com/russross/blackfriday/testdata/Links, inline style.html
generated
vendored
Normal file
11
vendor/github.com/russross/blackfriday/testdata/Links, inline style.html
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<p>Just a <a href="/url/">URL</a>.</p>
|
||||
|
||||
<p><a href="/url/" title="title">URL and title</a>.</p>
|
||||
|
||||
<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>
|
||||
|
||||
<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>
|
||||
|
||||
<p><a href="/url/" title="title has spaces afterward">URL and title</a>.</p>
|
||||
|
||||
<p>[Empty]().</p>
|
||||
12
vendor/github.com/russross/blackfriday/testdata/Links, inline style.text
generated
vendored
Normal file
12
vendor/github.com/russross/blackfriday/testdata/Links, inline style.text
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
Just a [URL](/url/).
|
||||
|
||||
[URL and title](/url/ "title").
|
||||
|
||||
[URL and title](/url/ "title preceded by two spaces").
|
||||
|
||||
[URL and title](/url/ "title preceded by a tab").
|
||||
|
||||
[URL and title](/url/ "title has spaces afterward" ).
|
||||
|
||||
|
||||
[Empty]().
|
||||
52
vendor/github.com/russross/blackfriday/testdata/Links, reference style.html
generated
vendored
Normal file
52
vendor/github.com/russross/blackfriday/testdata/Links, reference style.html
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
<p>Foo <a href="/url/" title="Title">bar</a>.</p>
|
||||
|
||||
<p>Foo <a href="/url/" title="Title">bar</a>.</p>
|
||||
|
||||
<p>Foo <a href="/url/" title="Title">bar</a>.</p>
|
||||
|
||||
<p>With <a href="/url/">embedded [brackets]</a>.</p>
|
||||
|
||||
<p>Indented <a href="/url">once</a>.</p>
|
||||
|
||||
<p>Indented <a href="/url">twice</a>.</p>
|
||||
|
||||
<p>Indented <a href="/url">thrice</a>.</p>
|
||||
|
||||
<p>Indented [four][] times.</p>
|
||||
|
||||
<pre><code>[four]: /url
|
||||
</code></pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<p><a href="foo">this</a> should work</p>
|
||||
|
||||
<p>So should <a href="foo">this</a>.</p>
|
||||
|
||||
<p>And <a href="foo">this</a>.</p>
|
||||
|
||||
<p>And <a href="foo">this</a>.</p>
|
||||
|
||||
<p>And <a href="foo">this</a>.</p>
|
||||
|
||||
<p>But not [that] [].</p>
|
||||
|
||||
<p>Nor [that][].</p>
|
||||
|
||||
<p>Nor [that].</p>
|
||||
|
||||
<p>[Something in brackets like <a href="foo">this</a> should work]</p>
|
||||
|
||||
<p>[Same with <a href="foo">this</a>.]</p>
|
||||
|
||||
<p>In this case, <a href="/somethingelse/">this</a> points to something else.</p>
|
||||
|
||||
<p>Backslashing should suppress [this] and [this].</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Here's one where the <a href="/url/">link
|
||||
breaks</a> across lines.</p>
|
||||
|
||||
<p>Here's another where the <a href="/url/">link
|
||||
breaks</a> across lines, but with a line-ending space.</p>
|
||||
71
vendor/github.com/russross/blackfriday/testdata/Links, reference style.text
generated
vendored
Normal file
71
vendor/github.com/russross/blackfriday/testdata/Links, reference style.text
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
Foo [bar] [1].
|
||||
|
||||
Foo [bar][1].
|
||||
|
||||
Foo [bar]
|
||||
[1].
|
||||
|
||||
[1]: /url/ "Title"
|
||||
|
||||
|
||||
With [embedded [brackets]] [b].
|
||||
|
||||
|
||||
Indented [once][].
|
||||
|
||||
Indented [twice][].
|
||||
|
||||
Indented [thrice][].
|
||||
|
||||
Indented [four][] times.
|
||||
|
||||
[once]: /url
|
||||
|
||||
[twice]: /url
|
||||
|
||||
[thrice]: /url
|
||||
|
||||
[four]: /url
|
||||
|
||||
|
||||
[b]: /url/
|
||||
|
||||
* * *
|
||||
|
||||
[this] [this] should work
|
||||
|
||||
So should [this][this].
|
||||
|
||||
And [this] [].
|
||||
|
||||
And [this][].
|
||||
|
||||
And [this].
|
||||
|
||||
But not [that] [].
|
||||
|
||||
Nor [that][].
|
||||
|
||||
Nor [that].
|
||||
|
||||
[Something in brackets like [this][] should work]
|
||||
|
||||
[Same with [this].]
|
||||
|
||||
In this case, [this](/somethingelse/) points to something else.
|
||||
|
||||
Backslashing should suppress \[this] and [this\].
|
||||
|
||||
[this]: foo
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
Here's one where the [link
|
||||
breaks] across lines.
|
||||
|
||||
Here's another where the [link
|
||||
breaks] across lines, but with a line-ending space.
|
||||
|
||||
|
||||
[link breaks]: /url/
|
||||
9
vendor/github.com/russross/blackfriday/testdata/Links, shortcut references.html
generated
vendored
Normal file
9
vendor/github.com/russross/blackfriday/testdata/Links, shortcut references.html
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<p>This is the <a href="/simple">simple case</a>.</p>
|
||||
|
||||
<p>This one has a <a href="/foo">line
|
||||
break</a>.</p>
|
||||
|
||||
<p>This one has a <a href="/foo">line
|
||||
break</a> with a line-ending space.</p>
|
||||
|
||||
<p><a href="/that">this</a> and the <a href="/other">other</a></p>
|
||||
20
vendor/github.com/russross/blackfriday/testdata/Links, shortcut references.text
generated
vendored
Normal file
20
vendor/github.com/russross/blackfriday/testdata/Links, shortcut references.text
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
This is the [simple case].
|
||||
|
||||
[simple case]: /simple
|
||||
|
||||
|
||||
|
||||
This one has a [line
|
||||
break].
|
||||
|
||||
This one has a [line
|
||||
break] with a line-ending space.
|
||||
|
||||
[line break]: /foo
|
||||
|
||||
|
||||
[this] [that] and the [other]
|
||||
|
||||
[this]: /this
|
||||
[that]: /that
|
||||
[other]: /other
|
||||
3
vendor/github.com/russross/blackfriday/testdata/Literal quotes in titles.html
generated
vendored
Normal file
3
vendor/github.com/russross/blackfriday/testdata/Literal quotes in titles.html
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>
|
||||
|
||||
<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>
|
||||
7
vendor/github.com/russross/blackfriday/testdata/Literal quotes in titles.text
generated
vendored
Normal file
7
vendor/github.com/russross/blackfriday/testdata/Literal quotes in titles.text
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
Foo [bar][].
|
||||
|
||||
Foo [bar](/url/ "Title with "quotes" inside").
|
||||
|
||||
|
||||
[bar]: /url/ "Title with "quotes" inside"
|
||||
|
||||
314
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html
generated
vendored
Normal file
314
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html
generated
vendored
Normal file
@ -0,0 +1,314 @@
|
||||
<h1>Markdown: Basics</h1>
|
||||
|
||||
<ul id="ProjectSubmenu">
|
||||
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||
<li><a class="selected" title="Markdown Basics">Basics</a></li>
|
||||
<li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Getting the Gist of Markdown's Formatting Syntax</h2>
|
||||
|
||||
<p>This page offers a brief overview of what it's like to use Markdown.
|
||||
The <a href="/projects/markdown/syntax" title="Markdown Syntax">syntax page</a> provides complete, detailed documentation for
|
||||
every feature, but Markdown should be very easy to pick up simply by
|
||||
looking at a few examples of it in action. The examples on this page
|
||||
are written in a before/after style, showing example syntax and the
|
||||
HTML output produced by Markdown.</p>
|
||||
|
||||
<p>It's also helpful to simply try Markdown out; the <a href="/projects/markdown/dingus" title="Markdown Dingus">Dingus</a> is a
|
||||
web application that allows you type your own Markdown-formatted text
|
||||
and translate it to XHTML.</p>
|
||||
|
||||
<p><strong>Note:</strong> This document is itself written using Markdown; you
|
||||
can <a href="/projects/markdown/basics.text">see the source for it by adding '.text' to the URL</a>.</p>
|
||||
|
||||
<h2>Paragraphs, Headers, Blockquotes</h2>
|
||||
|
||||
<p>A paragraph is simply one or more consecutive lines of text, separated
|
||||
by one or more blank lines. (A blank line is any line that looks like a
|
||||
blank line -- a line containing nothing spaces or tabs is considered
|
||||
blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
|
||||
|
||||
<p>Markdown offers two styles of headers: <em>Setext</em> and <em>atx</em>.
|
||||
Setext-style headers for <code><h1></code> and <code><h2></code> are created by
|
||||
"underlining" with equal signs (<code>=</code>) and hyphens (<code>-</code>), respectively.
|
||||
To create an atx-style header, you put 1-6 hash marks (<code>#</code>) at the
|
||||
beginning of the line -- the number of hashes equals the resulting
|
||||
HTML header level.</p>
|
||||
|
||||
<p>Blockquotes are indicated using email-style '<code>></code>' angle brackets.</p>
|
||||
|
||||
<p>Markdown:</p>
|
||||
|
||||
<pre><code>A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><h1>A First Level Header</h1>
|
||||
|
||||
<h2>A Second Level Header</h2>
|
||||
|
||||
<p>Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.</p>
|
||||
|
||||
<p>The quick brown fox jumped over the lazy
|
||||
dog's back.</p>
|
||||
|
||||
<h3>Header 3</h3>
|
||||
|
||||
<blockquote>
|
||||
<p>This is a blockquote.</p>
|
||||
|
||||
<p>This is the second paragraph in the blockquote.</p>
|
||||
|
||||
<h2>This is an H2 in a blockquote</h2>
|
||||
</blockquote>
|
||||
</code></pre>
|
||||
|
||||
<h3>Phrase Emphasis</h3>
|
||||
|
||||
<p>Markdown uses asterisks and underscores to indicate spans of emphasis.</p>
|
||||
|
||||
<p>Markdown:</p>
|
||||
|
||||
<pre><code>Some of these words *are emphasized*.
|
||||
Some of these words _are emphasized also_.
|
||||
|
||||
Use two asterisks for **strong emphasis**.
|
||||
Or, if you prefer, __use two underscores instead__.
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>Some of these words <em>are emphasized</em>.
|
||||
Some of these words <em>are emphasized also</em>.</p>
|
||||
|
||||
<p>Use two asterisks for <strong>strong emphasis</strong>.
|
||||
Or, if you prefer, <strong>use two underscores instead</strong>.</p>
|
||||
</code></pre>
|
||||
|
||||
<h2>Lists</h2>
|
||||
|
||||
<p>Unordered (bulleted) lists use asterisks, pluses, and hyphens (<code>*</code>,
|
||||
<code>+</code>, and <code>-</code>) as list markers. These three markers are
|
||||
interchangable; this:</p>
|
||||
|
||||
<pre><code>* Candy.
|
||||
* Gum.
|
||||
* Booze.
|
||||
</code></pre>
|
||||
|
||||
<p>this:</p>
|
||||
|
||||
<pre><code>+ Candy.
|
||||
+ Gum.
|
||||
+ Booze.
|
||||
</code></pre>
|
||||
|
||||
<p>and this:</p>
|
||||
|
||||
<pre><code>- Candy.
|
||||
- Gum.
|
||||
- Booze.
|
||||
</code></pre>
|
||||
|
||||
<p>all produce the same output:</p>
|
||||
|
||||
<pre><code><ul>
|
||||
<li>Candy.</li>
|
||||
<li>Gum.</li>
|
||||
<li>Booze.</li>
|
||||
</ul>
|
||||
</code></pre>
|
||||
|
||||
<p>Ordered (numbered) lists use regular numbers, followed by periods, as
|
||||
list markers:</p>
|
||||
|
||||
<pre><code>1. Red
|
||||
2. Green
|
||||
3. Blue
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><ol>
|
||||
<li>Red</li>
|
||||
<li>Green</li>
|
||||
<li>Blue</li>
|
||||
</ol>
|
||||
</code></pre>
|
||||
|
||||
<p>If you put blank lines between items, you'll get <code><p></code> tags for the
|
||||
list item text. You can create multi-paragraph list items by indenting
|
||||
the paragraphs by 4 spaces or 1 tab:</p>
|
||||
|
||||
<pre><code>* A list item.
|
||||
|
||||
With multiple paragraphs.
|
||||
|
||||
* Another item in the list.
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><ul>
|
||||
<li><p>A list item.</p>
|
||||
<p>With multiple paragraphs.</p></li>
|
||||
<li><p>Another item in the list.</p></li>
|
||||
</ul>
|
||||
</code></pre>
|
||||
|
||||
<h3>Links</h3>
|
||||
|
||||
<p>Markdown supports two styles for creating links: <em>inline</em> and
|
||||
<em>reference</em>. With both styles, you use square brackets to delimit the
|
||||
text you want to turn into a link.</p>
|
||||
|
||||
<p>Inline-style links use parentheses immediately after the link text.
|
||||
For example:</p>
|
||||
|
||||
<pre><code>This is an [example link](http://example.com/).
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>This is an <a href="http://example.com/">
|
||||
example link</a>.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>Optionally, you may include a title attribute in the parentheses:</p>
|
||||
|
||||
<pre><code>This is an [example link](http://example.com/ "With a Title").
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>This is an <a href="http://example.com/" title="With a Title">
|
||||
example link</a>.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>Reference-style links allow you to refer to your links by names, which
|
||||
you define elsewhere in your document:</p>
|
||||
|
||||
<pre><code>I get 10 times more traffic from [Google][1] than from
|
||||
[Yahoo][2] or [MSN][3].
|
||||
|
||||
[1]: http://google.com/ "Google"
|
||||
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[3]: http://search.msn.com/ "MSN Search"
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>I get 10 times more traffic from <a href="http://google.com/"
|
||||
title="Google">Google</a> than from <a href="http://search.yahoo.com/"
|
||||
title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
|
||||
title="MSN Search">MSN</a>.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>The title attribute is optional. Link names may contain letters,
|
||||
numbers and spaces, but are <em>not</em> case sensitive:</p>
|
||||
|
||||
<pre><code>I start my morning with a cup of coffee and
|
||||
[The New York Times][NY Times].
|
||||
|
||||
[ny times]: http://www.nytimes.com/
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>I start my morning with a cup of coffee and
|
||||
<a href="http://www.nytimes.com/">The New York Times</a>.</p>
|
||||
</code></pre>
|
||||
|
||||
<h3>Images</h3>
|
||||
|
||||
<p>Image syntax is very much like link syntax.</p>
|
||||
|
||||
<p>Inline (titles are optional):</p>
|
||||
|
||||
<pre><code>
|
||||
</code></pre>
|
||||
|
||||
<p>Reference-style:</p>
|
||||
|
||||
<pre><code>![alt text][id]
|
||||
|
||||
[id]: /path/to/img.jpg "Title"
|
||||
</code></pre>
|
||||
|
||||
<p>Both of the above examples produce the same output:</p>
|
||||
|
||||
<pre><code><img src="/path/to/img.jpg" alt="alt text" title="Title" />
|
||||
</code></pre>
|
||||
|
||||
<h3>Code</h3>
|
||||
|
||||
<p>In a regular paragraph, you can create code span by wrapping text in
|
||||
backtick quotes. Any ampersands (<code>&</code>) and angle brackets (<code><</code> or
|
||||
<code>></code>) will automatically be translated into HTML entities. This makes
|
||||
it easy to use Markdown to write about HTML example code:</p>
|
||||
|
||||
<pre><code>I strongly recommend against using any `<blink>` tags.
|
||||
|
||||
I wish SmartyPants used named entities like `&mdash;`
|
||||
instead of decimal-encoded entites like `&#8212;`.
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>I strongly recommend against using any
|
||||
<code>&lt;blink&gt;</code> tags.</p>
|
||||
|
||||
<p>I wish SmartyPants used named entities like
|
||||
<code>&amp;mdash;</code> instead of decimal-encoded
|
||||
entites like <code>&amp;#8212;</code>.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>To specify an entire block of pre-formatted code, indent every line of
|
||||
the block by 4 spaces or 1 tab. Just like with code spans, <code>&</code>, <code><</code>,
|
||||
and <code>></code> characters will be escaped automatically.</p>
|
||||
|
||||
<p>Markdown:</p>
|
||||
|
||||
<pre><code>If you want your page to validate under XHTML 1.0 Strict,
|
||||
you've got to put paragraph tags in your blockquotes:
|
||||
|
||||
<blockquote>
|
||||
<p>For example.</p>
|
||||
</blockquote>
|
||||
</code></pre>
|
||||
|
||||
<p>Output:</p>
|
||||
|
||||
<pre><code><p>If you want your page to validate under XHTML 1.0 Strict,
|
||||
you've got to put paragraph tags in your blockquotes:</p>
|
||||
|
||||
<pre><code>&lt;blockquote&gt;
|
||||
&lt;p&gt;For example.&lt;/p&gt;
|
||||
&lt;/blockquote&gt;
|
||||
</code></pre>
|
||||
</code></pre>
|
||||
306
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text
generated
vendored
Normal file
306
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text
generated
vendored
Normal file
@ -0,0 +1,306 @@
|
||||
Markdown: Basics
|
||||
================
|
||||
|
||||
<ul id="ProjectSubmenu">
|
||||
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||
<li><a class="selected" title="Markdown Basics">Basics</a></li>
|
||||
<li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
Getting the Gist of Markdown's Formatting Syntax
|
||||
------------------------------------------------
|
||||
|
||||
This page offers a brief overview of what it's like to use Markdown.
|
||||
The [syntax page] [s] provides complete, detailed documentation for
|
||||
every feature, but Markdown should be very easy to pick up simply by
|
||||
looking at a few examples of it in action. The examples on this page
|
||||
are written in a before/after style, showing example syntax and the
|
||||
HTML output produced by Markdown.
|
||||
|
||||
It's also helpful to simply try Markdown out; the [Dingus] [d] is a
|
||||
web application that allows you type your own Markdown-formatted text
|
||||
and translate it to XHTML.
|
||||
|
||||
**Note:** This document is itself written using Markdown; you
|
||||
can [see the source for it by adding '.text' to the URL] [src].
|
||||
|
||||
[s]: /projects/markdown/syntax "Markdown Syntax"
|
||||
[d]: /projects/markdown/dingus "Markdown Dingus"
|
||||
[src]: /projects/markdown/basics.text
|
||||
|
||||
|
||||
## Paragraphs, Headers, Blockquotes ##
|
||||
|
||||
A paragraph is simply one or more consecutive lines of text, separated
|
||||
by one or more blank lines. (A blank line is any line that looks like a
|
||||
blank line -- a line containing nothing spaces or tabs is considered
|
||||
blank.) Normal paragraphs should not be intended with spaces or tabs.
|
||||
|
||||
Markdown offers two styles of headers: *Setext* and *atx*.
|
||||
Setext-style headers for `<h1>` and `<h2>` are created by
|
||||
"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
|
||||
To create an atx-style header, you put 1-6 hash marks (`#`) at the
|
||||
beginning of the line -- the number of hashes equals the resulting
|
||||
HTML header level.
|
||||
|
||||
Blockquotes are indicated using email-style '`>`' angle brackets.
|
||||
|
||||
Markdown:
|
||||
|
||||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
<h1>A First Level Header</h1>
|
||||
|
||||
<h2>A Second Level Header</h2>
|
||||
|
||||
<p>Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.</p>
|
||||
|
||||
<p>The quick brown fox jumped over the lazy
|
||||
dog's back.</p>
|
||||
|
||||
<h3>Header 3</h3>
|
||||
|
||||
<blockquote>
|
||||
<p>This is a blockquote.</p>
|
||||
|
||||
<p>This is the second paragraph in the blockquote.</p>
|
||||
|
||||
<h2>This is an H2 in a blockquote</h2>
|
||||
</blockquote>
|
||||
|
||||
|
||||
|
||||
### Phrase Emphasis ###
|
||||
|
||||
Markdown uses asterisks and underscores to indicate spans of emphasis.
|
||||
|
||||
Markdown:
|
||||
|
||||
Some of these words *are emphasized*.
|
||||
Some of these words _are emphasized also_.
|
||||
|
||||
Use two asterisks for **strong emphasis**.
|
||||
Or, if you prefer, __use two underscores instead__.
|
||||
|
||||
Output:
|
||||
|
||||
<p>Some of these words <em>are emphasized</em>.
|
||||
Some of these words <em>are emphasized also</em>.</p>
|
||||
|
||||
<p>Use two asterisks for <strong>strong emphasis</strong>.
|
||||
Or, if you prefer, <strong>use two underscores instead</strong>.</p>
|
||||
|
||||
|
||||
|
||||
## Lists ##
|
||||
|
||||
Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
|
||||
`+`, and `-`) as list markers. These three markers are
|
||||
interchangable; this:
|
||||
|
||||
* Candy.
|
||||
* Gum.
|
||||
* Booze.
|
||||
|
||||
this:
|
||||
|
||||
+ Candy.
|
||||
+ Gum.
|
||||
+ Booze.
|
||||
|
||||
and this:
|
||||
|
||||
- Candy.
|
||||
- Gum.
|
||||
- Booze.
|
||||
|
||||
all produce the same output:
|
||||
|
||||
<ul>
|
||||
<li>Candy.</li>
|
||||
<li>Gum.</li>
|
||||
<li>Booze.</li>
|
||||
</ul>
|
||||
|
||||
Ordered (numbered) lists use regular numbers, followed by periods, as
|
||||
list markers:
|
||||
|
||||
1. Red
|
||||
2. Green
|
||||
3. Blue
|
||||
|
||||
Output:
|
||||
|
||||
<ol>
|
||||
<li>Red</li>
|
||||
<li>Green</li>
|
||||
<li>Blue</li>
|
||||
</ol>
|
||||
|
||||
If you put blank lines between items, you'll get `<p>` tags for the
|
||||
list item text. You can create multi-paragraph list items by indenting
|
||||
the paragraphs by 4 spaces or 1 tab:
|
||||
|
||||
* A list item.
|
||||
|
||||
With multiple paragraphs.
|
||||
|
||||
* Another item in the list.
|
||||
|
||||
Output:
|
||||
|
||||
<ul>
|
||||
<li><p>A list item.</p>
|
||||
<p>With multiple paragraphs.</p></li>
|
||||
<li><p>Another item in the list.</p></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
### Links ###
|
||||
|
||||
Markdown supports two styles for creating links: *inline* and
|
||||
*reference*. With both styles, you use square brackets to delimit the
|
||||
text you want to turn into a link.
|
||||
|
||||
Inline-style links use parentheses immediately after the link text.
|
||||
For example:
|
||||
|
||||
This is an [example link](http://example.com/).
|
||||
|
||||
Output:
|
||||
|
||||
<p>This is an <a href="http://example.com/">
|
||||
example link</a>.</p>
|
||||
|
||||
Optionally, you may include a title attribute in the parentheses:
|
||||
|
||||
This is an [example link](http://example.com/ "With a Title").
|
||||
|
||||
Output:
|
||||
|
||||
<p>This is an <a href="http://example.com/" title="With a Title">
|
||||
example link</a>.</p>
|
||||
|
||||
Reference-style links allow you to refer to your links by names, which
|
||||
you define elsewhere in your document:
|
||||
|
||||
I get 10 times more traffic from [Google][1] than from
|
||||
[Yahoo][2] or [MSN][3].
|
||||
|
||||
[1]: http://google.com/ "Google"
|
||||
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[3]: http://search.msn.com/ "MSN Search"
|
||||
|
||||
Output:
|
||||
|
||||
<p>I get 10 times more traffic from <a href="http://google.com/"
|
||||
title="Google">Google</a> than from <a href="http://search.yahoo.com/"
|
||||
title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
|
||||
title="MSN Search">MSN</a>.</p>
|
||||
|
||||
The title attribute is optional. Link names may contain letters,
|
||||
numbers and spaces, but are *not* case sensitive:
|
||||
|
||||
I start my morning with a cup of coffee and
|
||||
[The New York Times][NY Times].
|
||||
|
||||
[ny times]: http://www.nytimes.com/
|
||||
|
||||
Output:
|
||||
|
||||
<p>I start my morning with a cup of coffee and
|
||||
<a href="http://www.nytimes.com/">The New York Times</a>.</p>
|
||||
|
||||
|
||||
### Images ###
|
||||
|
||||
Image syntax is very much like link syntax.
|
||||
|
||||
Inline (titles are optional):
|
||||
|
||||

|
||||
|
||||
Reference-style:
|
||||
|
||||
![alt text][id]
|
||||
|
||||
[id]: /path/to/img.jpg "Title"
|
||||
|
||||
Both of the above examples produce the same output:
|
||||
|
||||
<img src="/path/to/img.jpg" alt="alt text" title="Title" />
|
||||
|
||||
|
||||
|
||||
### Code ###
|
||||
|
||||
In a regular paragraph, you can create code span by wrapping text in
|
||||
backtick quotes. Any ampersands (`&`) and angle brackets (`<` or
|
||||
`>`) will automatically be translated into HTML entities. This makes
|
||||
it easy to use Markdown to write about HTML example code:
|
||||
|
||||
I strongly recommend against using any `<blink>` tags.
|
||||
|
||||
I wish SmartyPants used named entities like `—`
|
||||
instead of decimal-encoded entites like `—`.
|
||||
|
||||
Output:
|
||||
|
||||
<p>I strongly recommend against using any
|
||||
<code><blink></code> tags.</p>
|
||||
|
||||
<p>I wish SmartyPants used named entities like
|
||||
<code>&mdash;</code> instead of decimal-encoded
|
||||
entites like <code>&#8212;</code>.</p>
|
||||
|
||||
|
||||
To specify an entire block of pre-formatted code, indent every line of
|
||||
the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`,
|
||||
and `>` characters will be escaped automatically.
|
||||
|
||||
Markdown:
|
||||
|
||||
If you want your page to validate under XHTML 1.0 Strict,
|
||||
you've got to put paragraph tags in your blockquotes:
|
||||
|
||||
<blockquote>
|
||||
<p>For example.</p>
|
||||
</blockquote>
|
||||
|
||||
Output:
|
||||
|
||||
<p>If you want your page to validate under XHTML 1.0 Strict,
|
||||
you've got to put paragraph tags in your blockquotes:</p>
|
||||
|
||||
<pre><code><blockquote>
|
||||
<p>For example.</p>
|
||||
</blockquote>
|
||||
</code></pre>
|
||||
946
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html
generated
vendored
Normal file
946
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html
generated
vendored
Normal file
@ -0,0 +1,946 @@
|
||||
<h1>Markdown: Syntax</h1>
|
||||
|
||||
<ul id="ProjectSubmenu">
|
||||
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||
<li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
|
||||
<li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||
</ul>
|
||||
|
||||
<ul>
|
||||
<li><a href="#overview">Overview</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="#philosophy">Philosophy</a></li>
|
||||
<li><a href="#html">Inline HTML</a></li>
|
||||
<li><a href="#autoescape">Automatic Escaping for Special Characters</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#block">Block Elements</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="#p">Paragraphs and Line Breaks</a></li>
|
||||
<li><a href="#header">Headers</a></li>
|
||||
<li><a href="#blockquote">Blockquotes</a></li>
|
||||
<li><a href="#list">Lists</a></li>
|
||||
<li><a href="#precode">Code Blocks</a></li>
|
||||
<li><a href="#hr">Horizontal Rules</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#span">Span Elements</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="#link">Links</a></li>
|
||||
<li><a href="#em">Emphasis</a></li>
|
||||
<li><a href="#code">Code</a></li>
|
||||
<li><a href="#img">Images</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#misc">Miscellaneous</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="#backslash">Backslash Escapes</a></li>
|
||||
<li><a href="#autolink">Automatic Links</a></li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
|
||||
<p><strong>Note:</strong> This document is itself written using Markdown; you
|
||||
can <a href="/projects/markdown/syntax.text">see the source for it by adding '.text' to the URL</a>.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2 id="overview">Overview</h2>
|
||||
|
||||
<h3 id="philosophy">Philosophy</h3>
|
||||
|
||||
<p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</p>
|
||||
|
||||
<p>Readability, however, is emphasized above all else. A Markdown-formatted
|
||||
document should be publishable as-is, as plain text, without looking
|
||||
like it's been marked up with tags or formatting instructions. While
|
||||
Markdown's syntax has been influenced by several existing text-to-HTML
|
||||
filters -- including <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a>, <a href="http://www.aaronsw.com/2002/atx/">atx</a>, <a href="http://textism.com/tools/textile/">Textile</a>, <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>,
|
||||
<a href="http://www.triptico.com/software/grutatxt.html">Grutatext</a>, and <a href="http://ettext.taint.org/doc/">EtText</a> -- the single biggest source of
|
||||
inspiration for Markdown's syntax is the format of plain text email.</p>
|
||||
|
||||
<p>To this end, Markdown's syntax is comprised entirely of punctuation
|
||||
characters, which punctuation characters have been carefully chosen so
|
||||
as to look like what they mean. E.g., asterisks around a word actually
|
||||
look like *emphasis*. Markdown lists look like, well, lists. Even
|
||||
blockquotes look like quoted passages of text, assuming you've ever
|
||||
used email.</p>
|
||||
|
||||
<h3 id="html">Inline HTML</h3>
|
||||
|
||||
<p>Markdown's syntax is intended for one purpose: to be used as a
|
||||
format for <em>writing</em> for the web.</p>
|
||||
|
||||
<p>Markdown is not a replacement for HTML, or even close to it. Its
|
||||
syntax is very small, corresponding only to a very small subset of
|
||||
HTML tags. The idea is <em>not</em> to create a syntax that makes it easier
|
||||
to insert HTML tags. In my opinion, HTML tags are already easy to
|
||||
insert. The idea for Markdown is to make it easy to read, write, and
|
||||
edit prose. HTML is a <em>publishing</em> format; Markdown is a <em>writing</em>
|
||||
format. Thus, Markdown's formatting syntax only addresses issues that
|
||||
can be conveyed in plain text.</p>
|
||||
|
||||
<p>For any markup that is not covered by Markdown's syntax, you simply
|
||||
use HTML itself. There's no need to preface it or delimit it to
|
||||
indicate that you're switching from Markdown to HTML; you just use
|
||||
the tags.</p>
|
||||
|
||||
<p>The only restrictions are that block-level HTML elements -- e.g. <code><div></code>,
|
||||
<code><table></code>, <code><pre></code>, <code><p></code>, etc. -- must be separated from surrounding
|
||||
content by blank lines, and the start and end tags of the block should
|
||||
not be indented with tabs or spaces. Markdown is smart enough not
|
||||
to add extra (unwanted) <code><p></code> tags around HTML block-level tags.</p>
|
||||
|
||||
<p>For example, to add an HTML table to a Markdown article:</p>
|
||||
|
||||
<pre><code>This is a regular paragraph.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Foo</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
This is another regular paragraph.
|
||||
</code></pre>
|
||||
|
||||
<p>Note that Markdown formatting syntax is not processed within block-level
|
||||
HTML tags. E.g., you can't use Markdown-style <code>*emphasis*</code> inside an
|
||||
HTML block.</p>
|
||||
|
||||
<p>Span-level HTML tags -- e.g. <code><span></code>, <code><cite></code>, or <code><del></code> -- can be
|
||||
used anywhere in a Markdown paragraph, list item, or header. If you
|
||||
want, you can even use HTML tags instead of Markdown formatting; e.g. if
|
||||
you'd prefer to use HTML <code><a></code> or <code><img></code> tags instead of Markdown's
|
||||
link or image syntax, go right ahead.</p>
|
||||
|
||||
<p>Unlike block-level HTML tags, Markdown syntax <em>is</em> processed within
|
||||
span-level tags.</p>
|
||||
|
||||
<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
|
||||
|
||||
<p>In HTML, there are two characters that demand special treatment: <code><</code>
|
||||
and <code>&</code>. Left angle brackets are used to start tags; ampersands are
|
||||
used to denote HTML entities. If you want to use them as literal
|
||||
characters, you must escape them as entities, e.g. <code>&lt;</code>, and
|
||||
<code>&amp;</code>.</p>
|
||||
|
||||
<p>Ampersands in particular are bedeviling for web writers. If you want to
|
||||
write about 'AT&T', you need to write '<code>AT&amp;T</code>'. You even need to
|
||||
escape ampersands within URLs. Thus, if you want to link to:</p>
|
||||
|
||||
<pre><code>http://images.google.com/images?num=30&q=larry+bird
|
||||
</code></pre>
|
||||
|
||||
<p>you need to encode the URL as:</p>
|
||||
|
||||
<pre><code>http://images.google.com/images?num=30&amp;q=larry+bird
|
||||
</code></pre>
|
||||
|
||||
<p>in your anchor tag <code>href</code> attribute. Needless to say, this is easy to
|
||||
forget, and is probably the single most common source of HTML validation
|
||||
errors in otherwise well-marked-up web sites.</p>
|
||||
|
||||
<p>Markdown allows you to use these characters naturally, taking care of
|
||||
all the necessary escaping for you. If you use an ampersand as part of
|
||||
an HTML entity, it remains unchanged; otherwise it will be translated
|
||||
into <code>&amp;</code>.</p>
|
||||
|
||||
<p>So, if you want to include a copyright symbol in your article, you can write:</p>
|
||||
|
||||
<pre><code>&copy;
|
||||
</code></pre>
|
||||
|
||||
<p>and Markdown will leave it alone. But if you write:</p>
|
||||
|
||||
<pre><code>AT&T
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown will translate it to:</p>
|
||||
|
||||
<pre><code>AT&amp;T
|
||||
</code></pre>
|
||||
|
||||
<p>Similarly, because Markdown supports <a href="#html">inline HTML</a>, if you use
|
||||
angle brackets as delimiters for HTML tags, Markdown will treat them as
|
||||
such. But if you write:</p>
|
||||
|
||||
<pre><code>4 < 5
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown will translate it to:</p>
|
||||
|
||||
<pre><code>4 &lt; 5
|
||||
</code></pre>
|
||||
|
||||
<p>However, inside Markdown code spans and blocks, angle brackets and
|
||||
ampersands are <em>always</em> encoded automatically. This makes it easy to use
|
||||
Markdown to write about HTML code. (As opposed to raw HTML, which is a
|
||||
terrible format for writing about HTML syntax, because every single <code><</code>
|
||||
and <code>&</code> in your example code needs to be escaped.)</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2 id="block">Block Elements</h2>
|
||||
|
||||
<h3 id="p">Paragraphs and Line Breaks</h3>
|
||||
|
||||
<p>A paragraph is simply one or more consecutive lines of text, separated
|
||||
by one or more blank lines. (A blank line is any line that looks like a
|
||||
blank line -- a line containing nothing but spaces or tabs is considered
|
||||
blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
|
||||
|
||||
<p>The implication of the "one or more consecutive lines of text" rule is
|
||||
that Markdown supports "hard-wrapped" text paragraphs. This differs
|
||||
significantly from most other text-to-HTML formatters (including Movable
|
||||
Type's "Convert Line Breaks" option) which translate every line break
|
||||
character in a paragraph into a <code><br /></code> tag.</p>
|
||||
|
||||
<p>When you <em>do</em> want to insert a <code><br /></code> break tag using Markdown, you
|
||||
end a line with two or more spaces, then type return.</p>
|
||||
|
||||
<p>Yes, this takes a tad more effort to create a <code><br /></code>, but a simplistic
|
||||
"every line break is a <code><br /></code>" rule wouldn't work for Markdown.
|
||||
Markdown's email-style <a href="#blockquote">blockquoting</a> and multi-paragraph <a href="#list">list items</a>
|
||||
work best -- and look better -- when you format them with hard breaks.</p>
|
||||
|
||||
<h3 id="header">Headers</h3>
|
||||
|
||||
<p>Markdown supports two styles of headers, <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a> and <a href="http://www.aaronsw.com/2002/atx/">atx</a>.</p>
|
||||
|
||||
<p>Setext-style headers are "underlined" using equal signs (for first-level
|
||||
headers) and dashes (for second-level headers). For example:</p>
|
||||
|
||||
<pre><code>This is an H1
|
||||
=============
|
||||
|
||||
This is an H2
|
||||
-------------
|
||||
</code></pre>
|
||||
|
||||
<p>Any number of underlining <code>=</code>'s or <code>-</code>'s will work.</p>
|
||||
|
||||
<p>Atx-style headers use 1-6 hash characters at the start of the line,
|
||||
corresponding to header levels 1-6. For example:</p>
|
||||
|
||||
<pre><code># This is an H1
|
||||
|
||||
## This is an H2
|
||||
|
||||
###### This is an H6
|
||||
</code></pre>
|
||||
|
||||
<p>Optionally, you may "close" atx-style headers. This is purely
|
||||
cosmetic -- you can use this if you think it looks better. The
|
||||
closing hashes don't even need to match the number of hashes
|
||||
used to open the header. (The number of opening hashes
|
||||
determines the header level.) :</p>
|
||||
|
||||
<pre><code># This is an H1 #
|
||||
|
||||
## This is an H2 ##
|
||||
|
||||
### This is an H3 ######
|
||||
</code></pre>
|
||||
|
||||
<h3 id="blockquote">Blockquotes</h3>
|
||||
|
||||
<p>Markdown uses email-style <code>></code> characters for blockquoting. If you're
|
||||
familiar with quoting passages of text in an email message, then you
|
||||
know how to create a blockquote in Markdown. It looks best if you hard
|
||||
wrap the text and put a <code>></code> before every line:</p>
|
||||
|
||||
<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
>
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
> id sem consectetuer libero luctus adipiscing.
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown allows you to be lazy and only put the <code>></code> before the first
|
||||
line of a hard-wrapped paragraph:</p>
|
||||
|
||||
<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
id sem consectetuer libero luctus adipiscing.
|
||||
</code></pre>
|
||||
|
||||
<p>Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
|
||||
adding additional levels of <code>></code>:</p>
|
||||
|
||||
<pre><code>> This is the first level of quoting.
|
||||
>
|
||||
> > This is nested blockquote.
|
||||
>
|
||||
> Back to the first level.
|
||||
</code></pre>
|
||||
|
||||
<p>Blockquotes can contain other Markdown elements, including headers, lists,
|
||||
and code blocks:</p>
|
||||
|
||||
<pre><code>> ## This is a header.
|
||||
>
|
||||
> 1. This is the first list item.
|
||||
> 2. This is the second list item.
|
||||
>
|
||||
> Here's some example code:
|
||||
>
|
||||
> return shell_exec("echo $input | $markdown_script");
|
||||
</code></pre>
|
||||
|
||||
<p>Any decent text editor should make email-style quoting easy. For
|
||||
example, with BBEdit, you can make a selection and choose Increase
|
||||
Quote Level from the Text menu.</p>
|
||||
|
||||
<h3 id="list">Lists</h3>
|
||||
|
||||
<p>Markdown supports ordered (numbered) and unordered (bulleted) lists.</p>
|
||||
|
||||
<p>Unordered lists use asterisks, pluses, and hyphens -- interchangably
|
||||
-- as list markers:</p>
|
||||
|
||||
<pre><code>* Red
|
||||
* Green
|
||||
* Blue
|
||||
</code></pre>
|
||||
|
||||
<p>is equivalent to:</p>
|
||||
|
||||
<pre><code>+ Red
|
||||
+ Green
|
||||
+ Blue
|
||||
</code></pre>
|
||||
|
||||
<p>and:</p>
|
||||
|
||||
<pre><code>- Red
|
||||
- Green
|
||||
- Blue
|
||||
</code></pre>
|
||||
|
||||
<p>Ordered lists use numbers followed by periods:</p>
|
||||
|
||||
<pre><code>1. Bird
|
||||
2. McHale
|
||||
3. Parish
|
||||
</code></pre>
|
||||
|
||||
<p>It's important to note that the actual numbers you use to mark the
|
||||
list have no effect on the HTML output Markdown produces. The HTML
|
||||
Markdown produces from the above list is:</p>
|
||||
|
||||
<pre><code><ol>
|
||||
<li>Bird</li>
|
||||
<li>McHale</li>
|
||||
<li>Parish</li>
|
||||
</ol>
|
||||
</code></pre>
|
||||
|
||||
<p>If you instead wrote the list in Markdown like this:</p>
|
||||
|
||||
<pre><code>1. Bird
|
||||
1. McHale
|
||||
1. Parish
|
||||
</code></pre>
|
||||
|
||||
<p>or even:</p>
|
||||
|
||||
<pre><code>3. Bird
|
||||
1. McHale
|
||||
8. Parish
|
||||
</code></pre>
|
||||
|
||||
<p>you'd get the exact same HTML output. The point is, if you want to,
|
||||
you can use ordinal numbers in your ordered Markdown lists, so that
|
||||
the numbers in your source match the numbers in your published HTML.
|
||||
But if you want to be lazy, you don't have to.</p>
|
||||
|
||||
<p>If you do use lazy list numbering, however, you should still start the
|
||||
list with the number 1. At some point in the future, Markdown may support
|
||||
starting ordered lists at an arbitrary number.</p>
|
||||
|
||||
<p>List markers typically start at the left margin, but may be indented by
|
||||
up to three spaces. List markers must be followed by one or more spaces
|
||||
or a tab.</p>
|
||||
|
||||
<p>To make lists look nice, you can wrap items with hanging indents:</p>
|
||||
|
||||
<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
</code></pre>
|
||||
|
||||
<p>But if you want to be lazy, you don't have to:</p>
|
||||
|
||||
<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
</code></pre>
|
||||
|
||||
<p>If list items are separated by blank lines, Markdown will wrap the
|
||||
items in <code><p></code> tags in the HTML output. For example, this input:</p>
|
||||
|
||||
<pre><code>* Bird
|
||||
* Magic
|
||||
</code></pre>
|
||||
|
||||
<p>will turn into:</p>
|
||||
|
||||
<pre><code><ul>
|
||||
<li>Bird</li>
|
||||
<li>Magic</li>
|
||||
</ul>
|
||||
</code></pre>
|
||||
|
||||
<p>But this:</p>
|
||||
|
||||
<pre><code>* Bird
|
||||
|
||||
* Magic
|
||||
</code></pre>
|
||||
|
||||
<p>will turn into:</p>
|
||||
|
||||
<pre><code><ul>
|
||||
<li><p>Bird</p></li>
|
||||
<li><p>Magic</p></li>
|
||||
</ul>
|
||||
</code></pre>
|
||||
|
||||
<p>List items may consist of multiple paragraphs. Each subsequent
|
||||
paragraph in a list item must be intended by either 4 spaces
|
||||
or one tab:</p>
|
||||
|
||||
<pre><code>1. This is a list item with two paragraphs. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
|
||||
mi posuere lectus.
|
||||
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet
|
||||
vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
|
||||
sit amet velit.
|
||||
|
||||
2. Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
</code></pre>
|
||||
|
||||
<p>It looks nice if you indent every line of the subsequent
|
||||
paragraphs, but here again, Markdown will allow you to be
|
||||
lazy:</p>
|
||||
|
||||
<pre><code>* This is a list item with two paragraphs.
|
||||
|
||||
This is the second paragraph in the list item. You're
|
||||
only required to indent the first line. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit.
|
||||
|
||||
* Another item in the same list.
|
||||
</code></pre>
|
||||
|
||||
<p>To put a blockquote within a list item, the blockquote's <code>></code>
|
||||
delimiters need to be indented:</p>
|
||||
|
||||
<pre><code>* A list item with a blockquote:
|
||||
|
||||
> This is a blockquote
|
||||
> inside a list item.
|
||||
</code></pre>
|
||||
|
||||
<p>To put a code block within a list item, the code block needs
|
||||
to be indented <em>twice</em> -- 8 spaces or two tabs:</p>
|
||||
|
||||
<pre><code>* A list item with a code block:
|
||||
|
||||
<code goes here>
|
||||
</code></pre>
|
||||
|
||||
<p>It's worth noting that it's possible to trigger an ordered list by
|
||||
accident, by writing something like this:</p>
|
||||
|
||||
<pre><code>1986. What a great season.
|
||||
</code></pre>
|
||||
|
||||
<p>In other words, a <em>number-period-space</em> sequence at the beginning of a
|
||||
line. To avoid this, you can backslash-escape the period:</p>
|
||||
|
||||
<pre><code>1986\. What a great season.
|
||||
</code></pre>
|
||||
|
||||
<h3 id="precode">Code Blocks</h3>
|
||||
|
||||
<p>Pre-formatted code blocks are used for writing about programming or
|
||||
markup source code. Rather than forming normal paragraphs, the lines
|
||||
of a code block are interpreted literally. Markdown wraps a code block
|
||||
in both <code><pre></code> and <code><code></code> tags.</p>
|
||||
|
||||
<p>To produce a code block in Markdown, simply indent every line of the
|
||||
block by at least 4 spaces or 1 tab. For example, given this input:</p>
|
||||
|
||||
<pre><code>This is a normal paragraph:
|
||||
|
||||
This is a code block.
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown will generate:</p>
|
||||
|
||||
<pre><code><p>This is a normal paragraph:</p>
|
||||
|
||||
<pre><code>This is a code block.
|
||||
</code></pre>
|
||||
</code></pre>
|
||||
|
||||
<p>One level of indentation -- 4 spaces or 1 tab -- is removed from each
|
||||
line of the code block. For example, this:</p>
|
||||
|
||||
<pre><code>Here is an example of AppleScript:
|
||||
|
||||
tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
</code></pre>
|
||||
|
||||
<p>will turn into:</p>
|
||||
|
||||
<pre><code><p>Here is an example of AppleScript:</p>
|
||||
|
||||
<pre><code>tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
</code></pre>
|
||||
</code></pre>
|
||||
|
||||
<p>A code block continues until it reaches a line that is not indented
|
||||
(or the end of the article).</p>
|
||||
|
||||
<p>Within a code block, ampersands (<code>&</code>) and angle brackets (<code><</code> and <code>></code>)
|
||||
are automatically converted into HTML entities. This makes it very
|
||||
easy to include example HTML source code using Markdown -- just paste
|
||||
it and indent it, and Markdown will handle the hassle of encoding the
|
||||
ampersands and angle brackets. For example, this:</p>
|
||||
|
||||
<pre><code> <div class="footer">
|
||||
&copy; 2004 Foo Corporation
|
||||
</div>
|
||||
</code></pre>
|
||||
|
||||
<p>will turn into:</p>
|
||||
|
||||
<pre><code><pre><code>&lt;div class="footer"&gt;
|
||||
&amp;copy; 2004 Foo Corporation
|
||||
&lt;/div&gt;
|
||||
</code></pre>
|
||||
</code></pre>
|
||||
|
||||
<p>Regular Markdown syntax is not processed within code blocks. E.g.,
|
||||
asterisks are just literal asterisks within a code block. This means
|
||||
it's also easy to use Markdown to write about Markdown's own syntax.</p>
|
||||
|
||||
<h3 id="hr">Horizontal Rules</h3>
|
||||
|
||||
<p>You can produce a horizontal rule tag (<code><hr /></code>) by placing three or
|
||||
more hyphens, asterisks, or underscores on a line by themselves. If you
|
||||
wish, you may use spaces between the hyphens or asterisks. Each of the
|
||||
following lines will produce a horizontal rule:</p>
|
||||
|
||||
<pre><code>* * *
|
||||
|
||||
***
|
||||
|
||||
*****
|
||||
|
||||
- - -
|
||||
|
||||
---------------------------------------
|
||||
|
||||
_ _ _
|
||||
</code></pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2 id="span">Span Elements</h2>
|
||||
|
||||
<h3 id="link">Links</h3>
|
||||
|
||||
<p>Markdown supports two style of links: <em>inline</em> and <em>reference</em>.</p>
|
||||
|
||||
<p>In both styles, the link text is delimited by [square brackets].</p>
|
||||
|
||||
<p>To create an inline link, use a set of regular parentheses immediately
|
||||
after the link text's closing square bracket. Inside the parentheses,
|
||||
put the URL where you want the link to point, along with an <em>optional</em>
|
||||
title for the link, surrounded in quotes. For example:</p>
|
||||
|
||||
<pre><code>This is [an example](http://example.com/ "Title") inline link.
|
||||
|
||||
[This link](http://example.net/) has no title attribute.
|
||||
</code></pre>
|
||||
|
||||
<p>Will produce:</p>
|
||||
|
||||
<pre><code><p>This is <a href="http://example.com/" title="Title">
|
||||
an example</a> inline link.</p>
|
||||
|
||||
<p><a href="http://example.net/">This link</a> has no
|
||||
title attribute.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>If you're referring to a local resource on the same server, you can
|
||||
use relative paths:</p>
|
||||
|
||||
<pre><code>See my [About](/about/) page for details.
|
||||
</code></pre>
|
||||
|
||||
<p>Reference-style links use a second set of square brackets, inside
|
||||
which you place a label of your choosing to identify the link:</p>
|
||||
|
||||
<pre><code>This is [an example][id] reference-style link.
|
||||
</code></pre>
|
||||
|
||||
<p>You can optionally use a space to separate the sets of brackets:</p>
|
||||
|
||||
<pre><code>This is [an example] [id] reference-style link.
|
||||
</code></pre>
|
||||
|
||||
<p>Then, anywhere in the document, you define your link label like this,
|
||||
on a line by itself:</p>
|
||||
|
||||
<pre><code>[id]: http://example.com/ "Optional Title Here"
|
||||
</code></pre>
|
||||
|
||||
<p>That is:</p>
|
||||
|
||||
<ul>
|
||||
<li>Square brackets containing the link identifier (optionally
|
||||
indented from the left margin using up to three spaces);</li>
|
||||
<li>followed by a colon;</li>
|
||||
<li>followed by one or more spaces (or tabs);</li>
|
||||
<li>followed by the URL for the link;</li>
|
||||
<li>optionally followed by a title attribute for the link, enclosed
|
||||
in double or single quotes.</li>
|
||||
</ul>
|
||||
|
||||
<p>The link URL may, optionally, be surrounded by angle brackets:</p>
|
||||
|
||||
<pre><code>[id]: <http://example.com/> "Optional Title Here"
|
||||
</code></pre>
|
||||
|
||||
<p>You can put the title attribute on the next line and use extra spaces
|
||||
or tabs for padding, which tends to look better with longer URLs:</p>
|
||||
|
||||
<pre><code>[id]: http://example.com/longish/path/to/resource/here
|
||||
"Optional Title Here"
|
||||
</code></pre>
|
||||
|
||||
<p>Link definitions are only used for creating links during Markdown
|
||||
processing, and are stripped from your document in the HTML output.</p>
|
||||
|
||||
<p>Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are <em>not</em> case sensitive. E.g. these two links:</p>
|
||||
|
||||
<pre><code>[link text][a]
|
||||
[link text][A]
|
||||
</code></pre>
|
||||
|
||||
<p>are equivalent.</p>
|
||||
|
||||
<p>The <em>implicit link name</em> shortcut allows you to omit the name of the
|
||||
link, in which case the link text itself is used as the name.
|
||||
Just use an empty set of square brackets -- e.g., to link the word
|
||||
"Google" to the google.com web site, you could simply write:</p>
|
||||
|
||||
<pre><code>[Google][]
|
||||
</code></pre>
|
||||
|
||||
<p>And then define the link:</p>
|
||||
|
||||
<pre><code>[Google]: http://google.com/
|
||||
</code></pre>
|
||||
|
||||
<p>Because link names may contain spaces, this shortcut even works for
|
||||
multiple words in the link text:</p>
|
||||
|
||||
<pre><code>Visit [Daring Fireball][] for more information.
|
||||
</code></pre>
|
||||
|
||||
<p>And then define the link:</p>
|
||||
|
||||
<pre><code>[Daring Fireball]: http://daringfireball.net/
|
||||
</code></pre>
|
||||
|
||||
<p>Link definitions can be placed anywhere in your Markdown document. I
|
||||
tend to put them immediately after each paragraph in which they're
|
||||
used, but if you want, you can put them all at the end of your
|
||||
document, sort of like footnotes.</p>
|
||||
|
||||
<p>Here's an example of reference links in action:</p>
|
||||
|
||||
<pre><code>I get 10 times more traffic from [Google] [1] than from
|
||||
[Yahoo] [2] or [MSN] [3].
|
||||
|
||||
[1]: http://google.com/ "Google"
|
||||
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[3]: http://search.msn.com/ "MSN Search"
|
||||
</code></pre>
|
||||
|
||||
<p>Using the implicit link name shortcut, you could instead write:</p>
|
||||
|
||||
<pre><code>I get 10 times more traffic from [Google][] than from
|
||||
[Yahoo][] or [MSN][].
|
||||
|
||||
[google]: http://google.com/ "Google"
|
||||
[yahoo]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[msn]: http://search.msn.com/ "MSN Search"
|
||||
</code></pre>
|
||||
|
||||
<p>Both of the above examples will produce the following HTML output:</p>
|
||||
|
||||
<pre><code><p>I get 10 times more traffic from <a href="http://google.com/"
|
||||
title="Google">Google</a> than from
|
||||
<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
|
||||
or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>For comparison, here is the same paragraph written using
|
||||
Markdown's inline link style:</p>
|
||||
|
||||
<pre><code>I get 10 times more traffic from [Google](http://google.com/ "Google")
|
||||
than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
|
||||
[MSN](http://search.msn.com/ "MSN Search").
|
||||
</code></pre>
|
||||
|
||||
<p>The point of reference-style links is not that they're easier to
|
||||
write. The point is that with reference-style links, your document
|
||||
source is vastly more readable. Compare the above examples: using
|
||||
reference-style links, the paragraph itself is only 81 characters
|
||||
long; with inline-style links, it's 176 characters; and as raw HTML,
|
||||
it's 234 characters. In the raw HTML, there's more markup than there
|
||||
is text.</p>
|
||||
|
||||
<p>With Markdown's reference-style links, a source document much more
|
||||
closely resembles the final output, as rendered in a browser. By
|
||||
allowing you to move the markup-related metadata out of the paragraph,
|
||||
you can add links without interrupting the narrative flow of your
|
||||
prose.</p>
|
||||
|
||||
<h3 id="em">Emphasis</h3>
|
||||
|
||||
<p>Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of
|
||||
emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an
|
||||
HTML <code><em></code> tag; double <code>*</code>'s or <code>_</code>'s will be wrapped with an HTML
|
||||
<code><strong></code> tag. E.g., this input:</p>
|
||||
|
||||
<pre><code>*single asterisks*
|
||||
|
||||
_single underscores_
|
||||
|
||||
**double asterisks**
|
||||
|
||||
__double underscores__
|
||||
</code></pre>
|
||||
|
||||
<p>will produce:</p>
|
||||
|
||||
<pre><code><em>single asterisks</em>
|
||||
|
||||
<em>single underscores</em>
|
||||
|
||||
<strong>double asterisks</strong>
|
||||
|
||||
<strong>double underscores</strong>
|
||||
</code></pre>
|
||||
|
||||
<p>You can use whichever style you prefer; the lone restriction is that
|
||||
the same character must be used to open and close an emphasis span.</p>
|
||||
|
||||
<p>Emphasis can be used in the middle of a word:</p>
|
||||
|
||||
<pre><code>un*fucking*believable
|
||||
</code></pre>
|
||||
|
||||
<p>But if you surround an <code>*</code> or <code>_</code> with spaces, it'll be treated as a
|
||||
literal asterisk or underscore.</p>
|
||||
|
||||
<p>To produce a literal asterisk or underscore at a position where it
|
||||
would otherwise be used as an emphasis delimiter, you can backslash
|
||||
escape it:</p>
|
||||
|
||||
<pre><code>\*this text is surrounded by literal asterisks\*
|
||||
</code></pre>
|
||||
|
||||
<h3 id="code">Code</h3>
|
||||
|
||||
<p>To indicate a span of code, wrap it with backtick quotes (<code>`</code>).
|
||||
Unlike a pre-formatted code block, a code span indicates code within a
|
||||
normal paragraph. For example:</p>
|
||||
|
||||
<pre><code>Use the `printf()` function.
|
||||
</code></pre>
|
||||
|
||||
<p>will produce:</p>
|
||||
|
||||
<pre><code><p>Use the <code>printf()</code> function.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>To include a literal backtick character within a code span, you can use
|
||||
multiple backticks as the opening and closing delimiters:</p>
|
||||
|
||||
<pre><code>``There is a literal backtick (`) here.``
|
||||
</code></pre>
|
||||
|
||||
<p>which will produce this:</p>
|
||||
|
||||
<pre><code><p><code>There is a literal backtick (`) here.</code></p>
|
||||
</code></pre>
|
||||
|
||||
<p>The backtick delimiters surrounding a code span may include spaces --
|
||||
one after the opening, one before the closing. This allows you to place
|
||||
literal backtick characters at the beginning or end of a code span:</p>
|
||||
|
||||
<pre><code>A single backtick in a code span: `` ` ``
|
||||
|
||||
A backtick-delimited string in a code span: `` `foo` ``
|
||||
</code></pre>
|
||||
|
||||
<p>will produce:</p>
|
||||
|
||||
<pre><code><p>A single backtick in a code span: <code>`</code></p>
|
||||
|
||||
<p>A backtick-delimited string in a code span: <code>`foo`</code></p>
|
||||
</code></pre>
|
||||
|
||||
<p>With a code span, ampersands and angle brackets are encoded as HTML
|
||||
entities automatically, which makes it easy to include example HTML
|
||||
tags. Markdown will turn this:</p>
|
||||
|
||||
<pre><code>Please don't use any `<blink>` tags.
|
||||
</code></pre>
|
||||
|
||||
<p>into:</p>
|
||||
|
||||
<pre><code><p>Please don't use any <code>&lt;blink&gt;</code> tags.</p>
|
||||
</code></pre>
|
||||
|
||||
<p>You can write this:</p>
|
||||
|
||||
<pre><code>`&#8212;` is the decimal-encoded equivalent of `&mdash;`.
|
||||
</code></pre>
|
||||
|
||||
<p>to produce:</p>
|
||||
|
||||
<pre><code><p><code>&amp;#8212;</code> is the decimal-encoded
|
||||
equivalent of <code>&amp;mdash;</code>.</p>
|
||||
</code></pre>
|
||||
|
||||
<h3 id="img">Images</h3>
|
||||
|
||||
<p>Admittedly, it's fairly difficult to devise a "natural" syntax for
|
||||
placing images into a plain text document format.</p>
|
||||
|
||||
<p>Markdown uses an image syntax that is intended to resemble the syntax
|
||||
for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
|
||||
|
||||
<p>Inline image syntax looks like this:</p>
|
||||
|
||||
<pre><code>
|
||||
|
||||

|
||||
</code></pre>
|
||||
|
||||
<p>That is:</p>
|
||||
|
||||
<ul>
|
||||
<li>An exclamation mark: <code>!</code>;</li>
|
||||
<li>followed by a set of square brackets, containing the <code>alt</code>
|
||||
attribute text for the image;</li>
|
||||
<li>followed by a set of parentheses, containing the URL or path to
|
||||
the image, and an optional <code>title</code> attribute enclosed in double
|
||||
or single quotes.</li>
|
||||
</ul>
|
||||
|
||||
<p>Reference-style image syntax looks like this:</p>
|
||||
|
||||
<pre><code>![Alt text][id]
|
||||
</code></pre>
|
||||
|
||||
<p>Where "id" is the name of a defined image reference. Image references
|
||||
are defined using syntax identical to link references:</p>
|
||||
|
||||
<pre><code>[id]: url/to/image "Optional title attribute"
|
||||
</code></pre>
|
||||
|
||||
<p>As of this writing, Markdown has no syntax for specifying the
|
||||
dimensions of an image; if this is important to you, you can simply
|
||||
use regular HTML <code><img></code> tags.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2 id="misc">Miscellaneous</h2>
|
||||
|
||||
<h3 id="autolink">Automatic Links</h3>
|
||||
|
||||
<p>Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:</p>
|
||||
|
||||
<pre><code><http://example.com/>
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown will turn this into:</p>
|
||||
|
||||
<pre><code><a href="http://example.com/">http://example.com/</a>
|
||||
</code></pre>
|
||||
|
||||
<p>Automatic links for email addresses work similarly, except that
|
||||
Markdown will also perform a bit of randomized decimal and hex
|
||||
entity-encoding to help obscure your address from address-harvesting
|
||||
spambots. For example, Markdown will turn this:</p>
|
||||
|
||||
<pre><code><address@example.com>
|
||||
</code></pre>
|
||||
|
||||
<p>into something like this:</p>
|
||||
|
||||
<pre><code><a href="&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:&#x61;&#x64;&#x64;&#x72;&#x65;
|
||||
&#115;&#115;&#64;&#101;&#120;&#x61;&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;
|
||||
&#109;">&#x61;&#x64;&#x64;&#x72;&#x65;&#115;&#115;&#64;&#101;&#120;&#x61;
|
||||
&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;&#109;</a>
|
||||
</code></pre>
|
||||
|
||||
<p>which will render in a browser as a clickable link to "address@example.com".</p>
|
||||
|
||||
<p>(This sort of entity-encoding trick will indeed fool many, if not
|
||||
most, address-harvesting bots, but it definitely won't fool all of
|
||||
them. It's better than nothing, but an address published in this way
|
||||
will probably eventually start receiving spam.)</p>
|
||||
|
||||
<h3 id="backslash">Backslash Escapes</h3>
|
||||
|
||||
<p>Markdown allows you to use backslash escapes to generate literal
|
||||
characters which would otherwise have special meaning in Markdown's
|
||||
formatting syntax. For example, if you wanted to surround a word with
|
||||
literal asterisks (instead of an HTML <code><em></code> tag), you can backslashes
|
||||
before the asterisks, like this:</p>
|
||||
|
||||
<pre><code>\*literal asterisks\*
|
||||
</code></pre>
|
||||
|
||||
<p>Markdown provides backslash escapes for the following characters:</p>
|
||||
|
||||
<pre><code>\ backslash
|
||||
` backtick
|
||||
* asterisk
|
||||
_ underscore
|
||||
{} curly braces
|
||||
[] square brackets
|
||||
() parentheses
|
||||
# hash mark
|
||||
+ plus sign
|
||||
- minus sign (hyphen)
|
||||
. dot
|
||||
! exclamation mark
|
||||
</code></pre>
|
||||
888
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text
generated
vendored
Normal file
888
vendor/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text
generated
vendored
Normal file
@ -0,0 +1,888 @@
|
||||
Markdown: Syntax
|
||||
================
|
||||
|
||||
<ul id="ProjectSubmenu">
|
||||
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||
<li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
|
||||
<li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
* [Overview](#overview)
|
||||
* [Philosophy](#philosophy)
|
||||
* [Inline HTML](#html)
|
||||
* [Automatic Escaping for Special Characters](#autoescape)
|
||||
* [Block Elements](#block)
|
||||
* [Paragraphs and Line Breaks](#p)
|
||||
* [Headers](#header)
|
||||
* [Blockquotes](#blockquote)
|
||||
* [Lists](#list)
|
||||
* [Code Blocks](#precode)
|
||||
* [Horizontal Rules](#hr)
|
||||
* [Span Elements](#span)
|
||||
* [Links](#link)
|
||||
* [Emphasis](#em)
|
||||
* [Code](#code)
|
||||
* [Images](#img)
|
||||
* [Miscellaneous](#misc)
|
||||
* [Backslash Escapes](#backslash)
|
||||
* [Automatic Links](#autolink)
|
||||
|
||||
|
||||
**Note:** This document is itself written using Markdown; you
|
||||
can [see the source for it by adding '.text' to the URL][src].
|
||||
|
||||
[src]: /projects/markdown/syntax.text
|
||||
|
||||
* * *
|
||||
|
||||
<h2 id="overview">Overview</h2>
|
||||
|
||||
<h3 id="philosophy">Philosophy</h3>
|
||||
|
||||
Markdown is intended to be as easy-to-read and easy-to-write as is feasible.
|
||||
|
||||
Readability, however, is emphasized above all else. A Markdown-formatted
|
||||
document should be publishable as-is, as plain text, without looking
|
||||
like it's been marked up with tags or formatting instructions. While
|
||||
Markdown's syntax has been influenced by several existing text-to-HTML
|
||||
filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4],
|
||||
[Grutatext] [5], and [EtText] [6] -- the single biggest source of
|
||||
inspiration for Markdown's syntax is the format of plain text email.
|
||||
|
||||
[1]: http://docutils.sourceforge.net/mirror/setext.html
|
||||
[2]: http://www.aaronsw.com/2002/atx/
|
||||
[3]: http://textism.com/tools/textile/
|
||||
[4]: http://docutils.sourceforge.net/rst.html
|
||||
[5]: http://www.triptico.com/software/grutatxt.html
|
||||
[6]: http://ettext.taint.org/doc/
|
||||
|
||||
To this end, Markdown's syntax is comprised entirely of punctuation
|
||||
characters, which punctuation characters have been carefully chosen so
|
||||
as to look like what they mean. E.g., asterisks around a word actually
|
||||
look like \*emphasis\*. Markdown lists look like, well, lists. Even
|
||||
blockquotes look like quoted passages of text, assuming you've ever
|
||||
used email.
|
||||
|
||||
|
||||
|
||||
<h3 id="html">Inline HTML</h3>
|
||||
|
||||
Markdown's syntax is intended for one purpose: to be used as a
|
||||
format for *writing* for the web.
|
||||
|
||||
Markdown is not a replacement for HTML, or even close to it. Its
|
||||
syntax is very small, corresponding only to a very small subset of
|
||||
HTML tags. The idea is *not* to create a syntax that makes it easier
|
||||
to insert HTML tags. In my opinion, HTML tags are already easy to
|
||||
insert. The idea for Markdown is to make it easy to read, write, and
|
||||
edit prose. HTML is a *publishing* format; Markdown is a *writing*
|
||||
format. Thus, Markdown's formatting syntax only addresses issues that
|
||||
can be conveyed in plain text.
|
||||
|
||||
For any markup that is not covered by Markdown's syntax, you simply
|
||||
use HTML itself. There's no need to preface it or delimit it to
|
||||
indicate that you're switching from Markdown to HTML; you just use
|
||||
the tags.
|
||||
|
||||
The only restrictions are that block-level HTML elements -- e.g. `<div>`,
|
||||
`<table>`, `<pre>`, `<p>`, etc. -- must be separated from surrounding
|
||||
content by blank lines, and the start and end tags of the block should
|
||||
not be indented with tabs or spaces. Markdown is smart enough not
|
||||
to add extra (unwanted) `<p>` tags around HTML block-level tags.
|
||||
|
||||
For example, to add an HTML table to a Markdown article:
|
||||
|
||||
This is a regular paragraph.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Foo</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
This is another regular paragraph.
|
||||
|
||||
Note that Markdown formatting syntax is not processed within block-level
|
||||
HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an
|
||||
HTML block.
|
||||
|
||||
Span-level HTML tags -- e.g. `<span>`, `<cite>`, or `<del>` -- can be
|
||||
used anywhere in a Markdown paragraph, list item, or header. If you
|
||||
want, you can even use HTML tags instead of Markdown formatting; e.g. if
|
||||
you'd prefer to use HTML `<a>` or `<img>` tags instead of Markdown's
|
||||
link or image syntax, go right ahead.
|
||||
|
||||
Unlike block-level HTML tags, Markdown syntax *is* processed within
|
||||
span-level tags.
|
||||
|
||||
|
||||
<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
|
||||
|
||||
In HTML, there are two characters that demand special treatment: `<`
|
||||
and `&`. Left angle brackets are used to start tags; ampersands are
|
||||
used to denote HTML entities. If you want to use them as literal
|
||||
characters, you must escape them as entities, e.g. `<`, and
|
||||
`&`.
|
||||
|
||||
Ampersands in particular are bedeviling for web writers. If you want to
|
||||
write about 'AT&T', you need to write '`AT&T`'. You even need to
|
||||
escape ampersands within URLs. Thus, if you want to link to:
|
||||
|
||||
http://images.google.com/images?num=30&q=larry+bird
|
||||
|
||||
you need to encode the URL as:
|
||||
|
||||
http://images.google.com/images?num=30&q=larry+bird
|
||||
|
||||
in your anchor tag `href` attribute. Needless to say, this is easy to
|
||||
forget, and is probably the single most common source of HTML validation
|
||||
errors in otherwise well-marked-up web sites.
|
||||
|
||||
Markdown allows you to use these characters naturally, taking care of
|
||||
all the necessary escaping for you. If you use an ampersand as part of
|
||||
an HTML entity, it remains unchanged; otherwise it will be translated
|
||||
into `&`.
|
||||
|
||||
So, if you want to include a copyright symbol in your article, you can write:
|
||||
|
||||
©
|
||||
|
||||
and Markdown will leave it alone. But if you write:
|
||||
|
||||
AT&T
|
||||
|
||||
Markdown will translate it to:
|
||||
|
||||
AT&T
|
||||
|
||||
Similarly, because Markdown supports [inline HTML](#html), if you use
|
||||
angle brackets as delimiters for HTML tags, Markdown will treat them as
|
||||
such. But if you write:
|
||||
|
||||
4 < 5
|
||||
|
||||
Markdown will translate it to:
|
||||
|
||||
4 < 5
|
||||
|
||||
However, inside Markdown code spans and blocks, angle brackets and
|
||||
ampersands are *always* encoded automatically. This makes it easy to use
|
||||
Markdown to write about HTML code. (As opposed to raw HTML, which is a
|
||||
terrible format for writing about HTML syntax, because every single `<`
|
||||
and `&` in your example code needs to be escaped.)
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
|
||||
<h2 id="block">Block Elements</h2>
|
||||
|
||||
|
||||
<h3 id="p">Paragraphs and Line Breaks</h3>
|
||||
|
||||
A paragraph is simply one or more consecutive lines of text, separated
|
||||
by one or more blank lines. (A blank line is any line that looks like a
|
||||
blank line -- a line containing nothing but spaces or tabs is considered
|
||||
blank.) Normal paragraphs should not be intended with spaces or tabs.
|
||||
|
||||
The implication of the "one or more consecutive lines of text" rule is
|
||||
that Markdown supports "hard-wrapped" text paragraphs. This differs
|
||||
significantly from most other text-to-HTML formatters (including Movable
|
||||
Type's "Convert Line Breaks" option) which translate every line break
|
||||
character in a paragraph into a `<br />` tag.
|
||||
|
||||
When you *do* want to insert a `<br />` break tag using Markdown, you
|
||||
end a line with two or more spaces, then type return.
|
||||
|
||||
Yes, this takes a tad more effort to create a `<br />`, but a simplistic
|
||||
"every line break is a `<br />`" rule wouldn't work for Markdown.
|
||||
Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l]
|
||||
work best -- and look better -- when you format them with hard breaks.
|
||||
|
||||
[bq]: #blockquote
|
||||
[l]: #list
|
||||
|
||||
|
||||
|
||||
<h3 id="header">Headers</h3>
|
||||
|
||||
Markdown supports two styles of headers, [Setext] [1] and [atx] [2].
|
||||
|
||||
Setext-style headers are "underlined" using equal signs (for first-level
|
||||
headers) and dashes (for second-level headers). For example:
|
||||
|
||||
This is an H1
|
||||
=============
|
||||
|
||||
This is an H2
|
||||
-------------
|
||||
|
||||
Any number of underlining `=`'s or `-`'s will work.
|
||||
|
||||
Atx-style headers use 1-6 hash characters at the start of the line,
|
||||
corresponding to header levels 1-6. For example:
|
||||
|
||||
# This is an H1
|
||||
|
||||
## This is an H2
|
||||
|
||||
###### This is an H6
|
||||
|
||||
Optionally, you may "close" atx-style headers. This is purely
|
||||
cosmetic -- you can use this if you think it looks better. The
|
||||
closing hashes don't even need to match the number of hashes
|
||||
used to open the header. (The number of opening hashes
|
||||
determines the header level.) :
|
||||
|
||||
# This is an H1 #
|
||||
|
||||
## This is an H2 ##
|
||||
|
||||
### This is an H3 ######
|
||||
|
||||
|
||||
<h3 id="blockquote">Blockquotes</h3>
|
||||
|
||||
Markdown uses email-style `>` characters for blockquoting. If you're
|
||||
familiar with quoting passages of text in an email message, then you
|
||||
know how to create a blockquote in Markdown. It looks best if you hard
|
||||
wrap the text and put a `>` before every line:
|
||||
|
||||
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
>
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
> id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
Markdown allows you to be lazy and only put the `>` before the first
|
||||
line of a hard-wrapped paragraph:
|
||||
|
||||
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
|
||||
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
|
||||
|
||||
> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
|
||||
id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
|
||||
adding additional levels of `>`:
|
||||
|
||||
> This is the first level of quoting.
|
||||
>
|
||||
> > This is nested blockquote.
|
||||
>
|
||||
> Back to the first level.
|
||||
|
||||
Blockquotes can contain other Markdown elements, including headers, lists,
|
||||
and code blocks:
|
||||
|
||||
> ## This is a header.
|
||||
>
|
||||
> 1. This is the first list item.
|
||||
> 2. This is the second list item.
|
||||
>
|
||||
> Here's some example code:
|
||||
>
|
||||
> return shell_exec("echo $input | $markdown_script");
|
||||
|
||||
Any decent text editor should make email-style quoting easy. For
|
||||
example, with BBEdit, you can make a selection and choose Increase
|
||||
Quote Level from the Text menu.
|
||||
|
||||
|
||||
<h3 id="list">Lists</h3>
|
||||
|
||||
Markdown supports ordered (numbered) and unordered (bulleted) lists.
|
||||
|
||||
Unordered lists use asterisks, pluses, and hyphens -- interchangably
|
||||
-- as list markers:
|
||||
|
||||
* Red
|
||||
* Green
|
||||
* Blue
|
||||
|
||||
is equivalent to:
|
||||
|
||||
+ Red
|
||||
+ Green
|
||||
+ Blue
|
||||
|
||||
and:
|
||||
|
||||
- Red
|
||||
- Green
|
||||
- Blue
|
||||
|
||||
Ordered lists use numbers followed by periods:
|
||||
|
||||
1. Bird
|
||||
2. McHale
|
||||
3. Parish
|
||||
|
||||
It's important to note that the actual numbers you use to mark the
|
||||
list have no effect on the HTML output Markdown produces. The HTML
|
||||
Markdown produces from the above list is:
|
||||
|
||||
<ol>
|
||||
<li>Bird</li>
|
||||
<li>McHale</li>
|
||||
<li>Parish</li>
|
||||
</ol>
|
||||
|
||||
If you instead wrote the list in Markdown like this:
|
||||
|
||||
1. Bird
|
||||
1. McHale
|
||||
1. Parish
|
||||
|
||||
or even:
|
||||
|
||||
3. Bird
|
||||
1. McHale
|
||||
8. Parish
|
||||
|
||||
you'd get the exact same HTML output. The point is, if you want to,
|
||||
you can use ordinal numbers in your ordered Markdown lists, so that
|
||||
the numbers in your source match the numbers in your published HTML.
|
||||
But if you want to be lazy, you don't have to.
|
||||
|
||||
If you do use lazy list numbering, however, you should still start the
|
||||
list with the number 1. At some point in the future, Markdown may support
|
||||
starting ordered lists at an arbitrary number.
|
||||
|
||||
List markers typically start at the left margin, but may be indented by
|
||||
up to three spaces. List markers must be followed by one or more spaces
|
||||
or a tab.
|
||||
|
||||
To make lists look nice, you can wrap items with hanging indents:
|
||||
|
||||
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
But if you want to be lazy, you don't have to:
|
||||
|
||||
* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
|
||||
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
|
||||
viverra nec, fringilla in, laoreet vitae, risus.
|
||||
* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
|
||||
Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
If list items are separated by blank lines, Markdown will wrap the
|
||||
items in `<p>` tags in the HTML output. For example, this input:
|
||||
|
||||
* Bird
|
||||
* Magic
|
||||
|
||||
will turn into:
|
||||
|
||||
<ul>
|
||||
<li>Bird</li>
|
||||
<li>Magic</li>
|
||||
</ul>
|
||||
|
||||
But this:
|
||||
|
||||
* Bird
|
||||
|
||||
* Magic
|
||||
|
||||
will turn into:
|
||||
|
||||
<ul>
|
||||
<li><p>Bird</p></li>
|
||||
<li><p>Magic</p></li>
|
||||
</ul>
|
||||
|
||||
List items may consist of multiple paragraphs. Each subsequent
|
||||
paragraph in a list item must be intended by either 4 spaces
|
||||
or one tab:
|
||||
|
||||
1. This is a list item with two paragraphs. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
|
||||
mi posuere lectus.
|
||||
|
||||
Vestibulum enim wisi, viverra nec, fringilla in, laoreet
|
||||
vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
|
||||
sit amet velit.
|
||||
|
||||
2. Suspendisse id sem consectetuer libero luctus adipiscing.
|
||||
|
||||
It looks nice if you indent every line of the subsequent
|
||||
paragraphs, but here again, Markdown will allow you to be
|
||||
lazy:
|
||||
|
||||
* This is a list item with two paragraphs.
|
||||
|
||||
This is the second paragraph in the list item. You're
|
||||
only required to indent the first line. Lorem ipsum dolor
|
||||
sit amet, consectetuer adipiscing elit.
|
||||
|
||||
* Another item in the same list.
|
||||
|
||||
To put a blockquote within a list item, the blockquote's `>`
|
||||
delimiters need to be indented:
|
||||
|
||||
* A list item with a blockquote:
|
||||
|
||||
> This is a blockquote
|
||||
> inside a list item.
|
||||
|
||||
To put a code block within a list item, the code block needs
|
||||
to be indented *twice* -- 8 spaces or two tabs:
|
||||
|
||||
* A list item with a code block:
|
||||
|
||||
<code goes here>
|
||||
|
||||
|
||||
It's worth noting that it's possible to trigger an ordered list by
|
||||
accident, by writing something like this:
|
||||
|
||||
1986. What a great season.
|
||||
|
||||
In other words, a *number-period-space* sequence at the beginning of a
|
||||
line. To avoid this, you can backslash-escape the period:
|
||||
|
||||
1986\. What a great season.
|
||||
|
||||
|
||||
|
||||
<h3 id="precode">Code Blocks</h3>
|
||||
|
||||
Pre-formatted code blocks are used for writing about programming or
|
||||
markup source code. Rather than forming normal paragraphs, the lines
|
||||
of a code block are interpreted literally. Markdown wraps a code block
|
||||
in both `<pre>` and `<code>` tags.
|
||||
|
||||
To produce a code block in Markdown, simply indent every line of the
|
||||
block by at least 4 spaces or 1 tab. For example, given this input:
|
||||
|
||||
This is a normal paragraph:
|
||||
|
||||
This is a code block.
|
||||
|
||||
Markdown will generate:
|
||||
|
||||
<p>This is a normal paragraph:</p>
|
||||
|
||||
<pre><code>This is a code block.
|
||||
</code></pre>
|
||||
|
||||
One level of indentation -- 4 spaces or 1 tab -- is removed from each
|
||||
line of the code block. For example, this:
|
||||
|
||||
Here is an example of AppleScript:
|
||||
|
||||
tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
|
||||
will turn into:
|
||||
|
||||
<p>Here is an example of AppleScript:</p>
|
||||
|
||||
<pre><code>tell application "Foo"
|
||||
beep
|
||||
end tell
|
||||
</code></pre>
|
||||
|
||||
A code block continues until it reaches a line that is not indented
|
||||
(or the end of the article).
|
||||
|
||||
Within a code block, ampersands (`&`) and angle brackets (`<` and `>`)
|
||||
are automatically converted into HTML entities. This makes it very
|
||||
easy to include example HTML source code using Markdown -- just paste
|
||||
it and indent it, and Markdown will handle the hassle of encoding the
|
||||
ampersands and angle brackets. For example, this:
|
||||
|
||||
<div class="footer">
|
||||
© 2004 Foo Corporation
|
||||
</div>
|
||||
|
||||
will turn into:
|
||||
|
||||
<pre><code><div class="footer">
|
||||
&copy; 2004 Foo Corporation
|
||||
</div>
|
||||
</code></pre>
|
||||
|
||||
Regular Markdown syntax is not processed within code blocks. E.g.,
|
||||
asterisks are just literal asterisks within a code block. This means
|
||||
it's also easy to use Markdown to write about Markdown's own syntax.
|
||||
|
||||
|
||||
|
||||
<h3 id="hr">Horizontal Rules</h3>
|
||||
|
||||
You can produce a horizontal rule tag (`<hr />`) by placing three or
|
||||
more hyphens, asterisks, or underscores on a line by themselves. If you
|
||||
wish, you may use spaces between the hyphens or asterisks. Each of the
|
||||
following lines will produce a horizontal rule:
|
||||
|
||||
* * *
|
||||
|
||||
***
|
||||
|
||||
*****
|
||||
|
||||
- - -
|
||||
|
||||
---------------------------------------
|
||||
|
||||
_ _ _
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
<h2 id="span">Span Elements</h2>
|
||||
|
||||
<h3 id="link">Links</h3>
|
||||
|
||||
Markdown supports two style of links: *inline* and *reference*.
|
||||
|
||||
In both styles, the link text is delimited by [square brackets].
|
||||
|
||||
To create an inline link, use a set of regular parentheses immediately
|
||||
after the link text's closing square bracket. Inside the parentheses,
|
||||
put the URL where you want the link to point, along with an *optional*
|
||||
title for the link, surrounded in quotes. For example:
|
||||
|
||||
This is [an example](http://example.com/ "Title") inline link.
|
||||
|
||||
[This link](http://example.net/) has no title attribute.
|
||||
|
||||
Will produce:
|
||||
|
||||
<p>This is <a href="http://example.com/" title="Title">
|
||||
an example</a> inline link.</p>
|
||||
|
||||
<p><a href="http://example.net/">This link</a> has no
|
||||
title attribute.</p>
|
||||
|
||||
If you're referring to a local resource on the same server, you can
|
||||
use relative paths:
|
||||
|
||||
See my [About](/about/) page for details.
|
||||
|
||||
Reference-style links use a second set of square brackets, inside
|
||||
which you place a label of your choosing to identify the link:
|
||||
|
||||
This is [an example][id] reference-style link.
|
||||
|
||||
You can optionally use a space to separate the sets of brackets:
|
||||
|
||||
This is [an example] [id] reference-style link.
|
||||
|
||||
Then, anywhere in the document, you define your link label like this,
|
||||
on a line by itself:
|
||||
|
||||
[id]: http://example.com/ "Optional Title Here"
|
||||
|
||||
That is:
|
||||
|
||||
* Square brackets containing the link identifier (optionally
|
||||
indented from the left margin using up to three spaces);
|
||||
* followed by a colon;
|
||||
* followed by one or more spaces (or tabs);
|
||||
* followed by the URL for the link;
|
||||
* optionally followed by a title attribute for the link, enclosed
|
||||
in double or single quotes.
|
||||
|
||||
The link URL may, optionally, be surrounded by angle brackets:
|
||||
|
||||
[id]: <http://example.com/> "Optional Title Here"
|
||||
|
||||
You can put the title attribute on the next line and use extra spaces
|
||||
or tabs for padding, which tends to look better with longer URLs:
|
||||
|
||||
[id]: http://example.com/longish/path/to/resource/here
|
||||
"Optional Title Here"
|
||||
|
||||
Link definitions are only used for creating links during Markdown
|
||||
processing, and are stripped from your document in the HTML output.
|
||||
|
||||
Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are *not* case sensitive. E.g. these two links:
|
||||
|
||||
[link text][a]
|
||||
[link text][A]
|
||||
|
||||
are equivalent.
|
||||
|
||||
The *implicit link name* shortcut allows you to omit the name of the
|
||||
link, in which case the link text itself is used as the name.
|
||||
Just use an empty set of square brackets -- e.g., to link the word
|
||||
"Google" to the google.com web site, you could simply write:
|
||||
|
||||
[Google][]
|
||||
|
||||
And then define the link:
|
||||
|
||||
[Google]: http://google.com/
|
||||
|
||||
Because link names may contain spaces, this shortcut even works for
|
||||
multiple words in the link text:
|
||||
|
||||
Visit [Daring Fireball][] for more information.
|
||||
|
||||
And then define the link:
|
||||
|
||||
[Daring Fireball]: http://daringfireball.net/
|
||||
|
||||
Link definitions can be placed anywhere in your Markdown document. I
|
||||
tend to put them immediately after each paragraph in which they're
|
||||
used, but if you want, you can put them all at the end of your
|
||||
document, sort of like footnotes.
|
||||
|
||||
Here's an example of reference links in action:
|
||||
|
||||
I get 10 times more traffic from [Google] [1] than from
|
||||
[Yahoo] [2] or [MSN] [3].
|
||||
|
||||
[1]: http://google.com/ "Google"
|
||||
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[3]: http://search.msn.com/ "MSN Search"
|
||||
|
||||
Using the implicit link name shortcut, you could instead write:
|
||||
|
||||
I get 10 times more traffic from [Google][] than from
|
||||
[Yahoo][] or [MSN][].
|
||||
|
||||
[google]: http://google.com/ "Google"
|
||||
[yahoo]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[msn]: http://search.msn.com/ "MSN Search"
|
||||
|
||||
Both of the above examples will produce the following HTML output:
|
||||
|
||||
<p>I get 10 times more traffic from <a href="http://google.com/"
|
||||
title="Google">Google</a> than from
|
||||
<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
|
||||
or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
|
||||
|
||||
For comparison, here is the same paragraph written using
|
||||
Markdown's inline link style:
|
||||
|
||||
I get 10 times more traffic from [Google](http://google.com/ "Google")
|
||||
than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
|
||||
[MSN](http://search.msn.com/ "MSN Search").
|
||||
|
||||
The point of reference-style links is not that they're easier to
|
||||
write. The point is that with reference-style links, your document
|
||||
source is vastly more readable. Compare the above examples: using
|
||||
reference-style links, the paragraph itself is only 81 characters
|
||||
long; with inline-style links, it's 176 characters; and as raw HTML,
|
||||
it's 234 characters. In the raw HTML, there's more markup than there
|
||||
is text.
|
||||
|
||||
With Markdown's reference-style links, a source document much more
|
||||
closely resembles the final output, as rendered in a browser. By
|
||||
allowing you to move the markup-related metadata out of the paragraph,
|
||||
you can add links without interrupting the narrative flow of your
|
||||
prose.
|
||||
|
||||
|
||||
<h3 id="em">Emphasis</h3>
|
||||
|
||||
Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
|
||||
emphasis. Text wrapped with one `*` or `_` will be wrapped with an
|
||||
HTML `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML
|
||||
`<strong>` tag. E.g., this input:
|
||||
|
||||
*single asterisks*
|
||||
|
||||
_single underscores_
|
||||
|
||||
**double asterisks**
|
||||
|
||||
__double underscores__
|
||||
|
||||
will produce:
|
||||
|
||||
<em>single asterisks</em>
|
||||
|
||||
<em>single underscores</em>
|
||||
|
||||
<strong>double asterisks</strong>
|
||||
|
||||
<strong>double underscores</strong>
|
||||
|
||||
You can use whichever style you prefer; the lone restriction is that
|
||||
the same character must be used to open and close an emphasis span.
|
||||
|
||||
Emphasis can be used in the middle of a word:
|
||||
|
||||
un*fucking*believable
|
||||
|
||||
But if you surround an `*` or `_` with spaces, it'll be treated as a
|
||||
literal asterisk or underscore.
|
||||
|
||||
To produce a literal asterisk or underscore at a position where it
|
||||
would otherwise be used as an emphasis delimiter, you can backslash
|
||||
escape it:
|
||||
|
||||
\*this text is surrounded by literal asterisks\*
|
||||
|
||||
|
||||
|
||||
<h3 id="code">Code</h3>
|
||||
|
||||
To indicate a span of code, wrap it with backtick quotes (`` ` ``).
|
||||
Unlike a pre-formatted code block, a code span indicates code within a
|
||||
normal paragraph. For example:
|
||||
|
||||
Use the `printf()` function.
|
||||
|
||||
will produce:
|
||||
|
||||
<p>Use the <code>printf()</code> function.</p>
|
||||
|
||||
To include a literal backtick character within a code span, you can use
|
||||
multiple backticks as the opening and closing delimiters:
|
||||
|
||||
``There is a literal backtick (`) here.``
|
||||
|
||||
which will produce this:
|
||||
|
||||
<p><code>There is a literal backtick (`) here.</code></p>
|
||||
|
||||
The backtick delimiters surrounding a code span may include spaces --
|
||||
one after the opening, one before the closing. This allows you to place
|
||||
literal backtick characters at the beginning or end of a code span:
|
||||
|
||||
A single backtick in a code span: `` ` ``
|
||||
|
||||
A backtick-delimited string in a code span: `` `foo` ``
|
||||
|
||||
will produce:
|
||||
|
||||
<p>A single backtick in a code span: <code>`</code></p>
|
||||
|
||||
<p>A backtick-delimited string in a code span: <code>`foo`</code></p>
|
||||
|
||||
With a code span, ampersands and angle brackets are encoded as HTML
|
||||
entities automatically, which makes it easy to include example HTML
|
||||
tags. Markdown will turn this:
|
||||
|
||||
Please don't use any `<blink>` tags.
|
||||
|
||||
into:
|
||||
|
||||
<p>Please don't use any <code><blink></code> tags.</p>
|
||||
|
||||
You can write this:
|
||||
|
||||
`—` is the decimal-encoded equivalent of `—`.
|
||||
|
||||
to produce:
|
||||
|
||||
<p><code>&#8212;</code> is the decimal-encoded
|
||||
equivalent of <code>&mdash;</code>.</p>
|
||||
|
||||
|
||||
|
||||
<h3 id="img">Images</h3>
|
||||
|
||||
Admittedly, it's fairly difficult to devise a "natural" syntax for
|
||||
placing images into a plain text document format.
|
||||
|
||||
Markdown uses an image syntax that is intended to resemble the syntax
|
||||
for links, allowing for two styles: *inline* and *reference*.
|
||||
|
||||
Inline image syntax looks like this:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
That is:
|
||||
|
||||
* An exclamation mark: `!`;
|
||||
* followed by a set of square brackets, containing the `alt`
|
||||
attribute text for the image;
|
||||
* followed by a set of parentheses, containing the URL or path to
|
||||
the image, and an optional `title` attribute enclosed in double
|
||||
or single quotes.
|
||||
|
||||
Reference-style image syntax looks like this:
|
||||
|
||||
![Alt text][id]
|
||||
|
||||
Where "id" is the name of a defined image reference. Image references
|
||||
are defined using syntax identical to link references:
|
||||
|
||||
[id]: url/to/image "Optional title attribute"
|
||||
|
||||
As of this writing, Markdown has no syntax for specifying the
|
||||
dimensions of an image; if this is important to you, you can simply
|
||||
use regular HTML `<img>` tags.
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
|
||||
<h2 id="misc">Miscellaneous</h2>
|
||||
|
||||
<h3 id="autolink">Automatic Links</h3>
|
||||
|
||||
Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:
|
||||
|
||||
<http://example.com/>
|
||||
|
||||
Markdown will turn this into:
|
||||
|
||||
<a href="http://example.com/">http://example.com/</a>
|
||||
|
||||
Automatic links for email addresses work similarly, except that
|
||||
Markdown will also perform a bit of randomized decimal and hex
|
||||
entity-encoding to help obscure your address from address-harvesting
|
||||
spambots. For example, Markdown will turn this:
|
||||
|
||||
<address@example.com>
|
||||
|
||||
into something like this:
|
||||
|
||||
<a href="mailto:addre
|
||||
ss@example.co
|
||||
m">address@exa
|
||||
mple.com</a>
|
||||
|
||||
which will render in a browser as a clickable link to "address@example.com".
|
||||
|
||||
(This sort of entity-encoding trick will indeed fool many, if not
|
||||
most, address-harvesting bots, but it definitely won't fool all of
|
||||
them. It's better than nothing, but an address published in this way
|
||||
will probably eventually start receiving spam.)
|
||||
|
||||
|
||||
|
||||
<h3 id="backslash">Backslash Escapes</h3>
|
||||
|
||||
Markdown allows you to use backslash escapes to generate literal
|
||||
characters which would otherwise have special meaning in Markdown's
|
||||
formatting syntax. For example, if you wanted to surround a word with
|
||||
literal asterisks (instead of an HTML `<em>` tag), you can backslashes
|
||||
before the asterisks, like this:
|
||||
|
||||
\*literal asterisks\*
|
||||
|
||||
Markdown provides backslash escapes for the following characters:
|
||||
|
||||
\ backslash
|
||||
` backtick
|
||||
* asterisk
|
||||
_ underscore
|
||||
{} curly braces
|
||||
[] square brackets
|
||||
() parentheses
|
||||
# hash mark
|
||||
+ plus sign
|
||||
- minus sign (hyphen)
|
||||
. dot
|
||||
! exclamation mark
|
||||
|
||||
9
vendor/github.com/russross/blackfriday/testdata/Nested blockquotes.html
generated
vendored
Normal file
9
vendor/github.com/russross/blackfriday/testdata/Nested blockquotes.html
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<blockquote>
|
||||
<p>foo</p>
|
||||
|
||||
<blockquote>
|
||||
<p>bar</p>
|
||||
</blockquote>
|
||||
|
||||
<p>foo</p>
|
||||
</blockquote>
|
||||
5
vendor/github.com/russross/blackfriday/testdata/Nested blockquotes.text
generated
vendored
Normal file
5
vendor/github.com/russross/blackfriday/testdata/Nested blockquotes.text
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
> foo
|
||||
>
|
||||
> > bar
|
||||
>
|
||||
> foo
|
||||
166
vendor/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html
generated
vendored
Normal file
166
vendor/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
<h2>Unordered</h2>
|
||||
|
||||
<p>Asterisks tight:</p>
|
||||
|
||||
<ul>
|
||||
<li>asterisk 1</li>
|
||||
<li>asterisk 2</li>
|
||||
<li>asterisk 3</li>
|
||||
</ul>
|
||||
|
||||
<p>Asterisks loose:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>asterisk 1</p></li>
|
||||
|
||||
<li><p>asterisk 2</p></li>
|
||||
|
||||
<li><p>asterisk 3</p></li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Pluses tight:</p>
|
||||
|
||||
<ul>
|
||||
<li>Plus 1</li>
|
||||
<li>Plus 2</li>
|
||||
<li>Plus 3</li>
|
||||
</ul>
|
||||
|
||||
<p>Pluses loose:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>Plus 1</p></li>
|
||||
|
||||
<li><p>Plus 2</p></li>
|
||||
|
||||
<li><p>Plus 3</p></li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<p>Minuses tight:</p>
|
||||
|
||||
<ul>
|
||||
<li>Minus 1</li>
|
||||
<li>Minus 2</li>
|
||||
<li>Minus 3</li>
|
||||
</ul>
|
||||
|
||||
<p>Minuses loose:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>Minus 1</p></li>
|
||||
|
||||
<li><p>Minus 2</p></li>
|
||||
|
||||
<li><p>Minus 3</p></li>
|
||||
</ul>
|
||||
|
||||
<h2>Ordered</h2>
|
||||
|
||||
<p>Tight:</p>
|
||||
|
||||
<ol>
|
||||
<li>First</li>
|
||||
<li>Second</li>
|
||||
<li>Third</li>
|
||||
</ol>
|
||||
|
||||
<p>and:</p>
|
||||
|
||||
<ol>
|
||||
<li>One</li>
|
||||
<li>Two</li>
|
||||
<li>Three</li>
|
||||
</ol>
|
||||
|
||||
<p>Loose using tabs:</p>
|
||||
|
||||
<ol>
|
||||
<li><p>First</p></li>
|
||||
|
||||
<li><p>Second</p></li>
|
||||
|
||||
<li><p>Third</p></li>
|
||||
</ol>
|
||||
|
||||
<p>and using spaces:</p>
|
||||
|
||||
<ol>
|
||||
<li><p>One</p></li>
|
||||
|
||||
<li><p>Two</p></li>
|
||||
|
||||
<li><p>Three</p></li>
|
||||
</ol>
|
||||
|
||||
<p>Multiple paragraphs:</p>
|
||||
|
||||
<ol>
|
||||
<li><p>Item 1, graf one.</p>
|
||||
|
||||
<p>Item 2. graf two. The quick brown fox jumped over the lazy dog's
|
||||
back.</p></li>
|
||||
|
||||
<li><p>Item 2.</p></li>
|
||||
|
||||
<li><p>Item 3.</p></li>
|
||||
</ol>
|
||||
|
||||
<h2>Nested</h2>
|
||||
|
||||
<ul>
|
||||
<li>Tab
|
||||
|
||||
<ul>
|
||||
<li>Tab
|
||||
|
||||
<ul>
|
||||
<li>Tab</li>
|
||||
</ul></li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
|
||||
<p>Here's another:</p>
|
||||
|
||||
<ol>
|
||||
<li>First</li>
|
||||
<li>Second:
|
||||
|
||||
<ul>
|
||||
<li>Fee</li>
|
||||
<li>Fie</li>
|
||||
<li>Foe</li>
|
||||
</ul></li>
|
||||
<li>Third</li>
|
||||
</ol>
|
||||
|
||||
<p>Same thing but with paragraphs:</p>
|
||||
|
||||
<ol>
|
||||
<li><p>First</p></li>
|
||||
|
||||
<li><p>Second:</p>
|
||||
|
||||
<ul>
|
||||
<li>Fee</li>
|
||||
<li>Fie</li>
|
||||
<li>Foe</li>
|
||||
</ul></li>
|
||||
|
||||
<li><p>Third</p></li>
|
||||
</ol>
|
||||
|
||||
<p>This was an error in Markdown 1.0.1:</p>
|
||||
|
||||
<ul>
|
||||
<li><p>this</p>
|
||||
|
||||
<ul>
|
||||
<li>sub</li>
|
||||
</ul>
|
||||
|
||||
<p>that</p></li>
|
||||
</ul>
|
||||
131
vendor/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text
generated
vendored
Normal file
131
vendor/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text
generated
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
## Unordered
|
||||
|
||||
Asterisks tight:
|
||||
|
||||
* asterisk 1
|
||||
* asterisk 2
|
||||
* asterisk 3
|
||||
|
||||
|
||||
Asterisks loose:
|
||||
|
||||
* asterisk 1
|
||||
|
||||
* asterisk 2
|
||||
|
||||
* asterisk 3
|
||||
|
||||
* * *
|
||||
|
||||
Pluses tight:
|
||||
|
||||
+ Plus 1
|
||||
+ Plus 2
|
||||
+ Plus 3
|
||||
|
||||
|
||||
Pluses loose:
|
||||
|
||||
+ Plus 1
|
||||
|
||||
+ Plus 2
|
||||
|
||||
+ Plus 3
|
||||
|
||||
* * *
|
||||
|
||||
|
||||
Minuses tight:
|
||||
|
||||
- Minus 1
|
||||
- Minus 2
|
||||
- Minus 3
|
||||
|
||||
|
||||
Minuses loose:
|
||||
|
||||
- Minus 1
|
||||
|
||||
- Minus 2
|
||||
|
||||
- Minus 3
|
||||
|
||||
|
||||
## Ordered
|
||||
|
||||
Tight:
|
||||
|
||||
1. First
|
||||
2. Second
|
||||
3. Third
|
||||
|
||||
and:
|
||||
|
||||
1. One
|
||||
2. Two
|
||||
3. Three
|
||||
|
||||
|
||||
Loose using tabs:
|
||||
|
||||
1. First
|
||||
|
||||
2. Second
|
||||
|
||||
3. Third
|
||||
|
||||
and using spaces:
|
||||
|
||||
1. One
|
||||
|
||||
2. Two
|
||||
|
||||
3. Three
|
||||
|
||||
Multiple paragraphs:
|
||||
|
||||
1. Item 1, graf one.
|
||||
|
||||
Item 2. graf two. The quick brown fox jumped over the lazy dog's
|
||||
back.
|
||||
|
||||
2. Item 2.
|
||||
|
||||
3. Item 3.
|
||||
|
||||
|
||||
|
||||
## Nested
|
||||
|
||||
* Tab
|
||||
* Tab
|
||||
* Tab
|
||||
|
||||
Here's another:
|
||||
|
||||
1. First
|
||||
2. Second:
|
||||
* Fee
|
||||
* Fie
|
||||
* Foe
|
||||
3. Third
|
||||
|
||||
Same thing but with paragraphs:
|
||||
|
||||
1. First
|
||||
|
||||
2. Second:
|
||||
* Fee
|
||||
* Fie
|
||||
* Foe
|
||||
|
||||
3. Third
|
||||
|
||||
|
||||
This was an error in Markdown 1.0.1:
|
||||
|
||||
* this
|
||||
|
||||
* sub
|
||||
|
||||
that
|
||||
7
vendor/github.com/russross/blackfriday/testdata/Strong and em together.html
generated
vendored
Normal file
7
vendor/github.com/russross/blackfriday/testdata/Strong and em together.html
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
<p><strong><em>This is strong and em.</em></strong></p>
|
||||
|
||||
<p>So is <strong><em>this</em></strong> word.</p>
|
||||
|
||||
<p><strong><em>This is strong and em.</em></strong></p>
|
||||
|
||||
<p>So is <strong><em>this</em></strong> word.</p>
|
||||
7
vendor/github.com/russross/blackfriday/testdata/Strong and em together.text
generated
vendored
Normal file
7
vendor/github.com/russross/blackfriday/testdata/Strong and em together.text
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
***This is strong and em.***
|
||||
|
||||
So is ***this*** word.
|
||||
|
||||
___This is strong and em.___
|
||||
|
||||
So is ___this___ word.
|
||||
26
vendor/github.com/russross/blackfriday/testdata/Tabs.html
generated
vendored
Normal file
26
vendor/github.com/russross/blackfriday/testdata/Tabs.html
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<ul>
|
||||
<li><p>this is a list item
|
||||
indented with tabs</p></li>
|
||||
|
||||
<li><p>this is a list item
|
||||
indented with spaces</p></li>
|
||||
</ul>
|
||||
|
||||
<p>Code:</p>
|
||||
|
||||
<pre><code>this code block is indented by one tab
|
||||
</code></pre>
|
||||
|
||||
<p>And:</p>
|
||||
|
||||
<pre><code> this code block is indented by two tabs
|
||||
</code></pre>
|
||||
|
||||
<p>And:</p>
|
||||
|
||||
<pre><code>+ this is an example list item
|
||||
indented with tabs
|
||||
|
||||
+ this is an example list item
|
||||
indented with spaces
|
||||
</code></pre>
|
||||
21
vendor/github.com/russross/blackfriday/testdata/Tabs.text
generated
vendored
Normal file
21
vendor/github.com/russross/blackfriday/testdata/Tabs.text
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
+ this is a list item
|
||||
indented with tabs
|
||||
|
||||
+ this is a list item
|
||||
indented with spaces
|
||||
|
||||
Code:
|
||||
|
||||
this code block is indented by one tab
|
||||
|
||||
And:
|
||||
|
||||
this code block is indented by two tabs
|
||||
|
||||
And:
|
||||
|
||||
+ this is an example list item
|
||||
indented with tabs
|
||||
|
||||
+ this is an example list item
|
||||
indented with spaces
|
||||
9
vendor/github.com/russross/blackfriday/testdata/Tidyness.html
generated
vendored
Normal file
9
vendor/github.com/russross/blackfriday/testdata/Tidyness.html
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<blockquote>
|
||||
<p>A list within a blockquote:</p>
|
||||
|
||||
<ul>
|
||||
<li>asterisk 1</li>
|
||||
<li>asterisk 2</li>
|
||||
<li>asterisk 3</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
5
vendor/github.com/russross/blackfriday/testdata/Tidyness.text
generated
vendored
Normal file
5
vendor/github.com/russross/blackfriday/testdata/Tidyness.text
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
> A list within a blockquote:
|
||||
>
|
||||
> * asterisk 1
|
||||
> * asterisk 2
|
||||
> * asterisk 3
|
||||
10
vendor/github.com/shurcooL/sanitized_anchor_name/.travis.yml
generated
vendored
Normal file
10
vendor/github.com/shurcooL/sanitized_anchor_name/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.5
|
||||
install:
|
||||
- go get golang.org/x/tools/cmd/vet
|
||||
script:
|
||||
- go get -t -v ./...
|
||||
- diff -u <(echo -n) <(gofmt -d ./)
|
||||
- go tool vet ./
|
||||
- go test -v -race ./...
|
||||
31
vendor/github.com/shurcooL/sanitized_anchor_name/README.md
generated
vendored
Normal file
31
vendor/github.com/shurcooL/sanitized_anchor_name/README.md
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
# sanitized_anchor_name [](https://travis-ci.org/shurcooL/sanitized_anchor_name) [](https://godoc.org/github.com/shurcooL/sanitized_anchor_name)
|
||||
|
||||
Package sanitized_anchor_name provides a func to create sanitized anchor names.
|
||||
|
||||
Its logic can be reused by multiple packages to create interoperable anchor names and links to those anchors.
|
||||
|
||||
At this time, it does not try to ensure that generated anchor names are unique, that responsibility falls on the caller.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
```bash
|
||||
go get -u github.com/shurcooL/sanitized_anchor_name
|
||||
```
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
```Go
|
||||
anchorName := sanitized_anchor_name.Create("This is a header")
|
||||
|
||||
fmt.Println(anchorName)
|
||||
|
||||
// Output:
|
||||
// this-is-a-header
|
||||
```
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
- [MIT License](http://opensource.org/licenses/mit-license.php)
|
||||
29
vendor/github.com/shurcooL/sanitized_anchor_name/main.go
generated
vendored
Normal file
29
vendor/github.com/shurcooL/sanitized_anchor_name/main.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// Package sanitized_anchor_name provides a func to create sanitized anchor names.
|
||||
//
|
||||
// Its logic can be reused by multiple packages to create interoperable anchor names
|
||||
// and links to those anchors.
|
||||
//
|
||||
// At this time, it does not try to ensure that generated anchor names
|
||||
// are unique, that responsibility falls on the caller.
|
||||
package sanitized_anchor_name
|
||||
|
||||
import "unicode"
|
||||
|
||||
// Create returns a sanitized anchor name for the given text.
|
||||
func Create(text string) string {
|
||||
var anchorName []rune
|
||||
var futureDash = false
|
||||
for _, r := range []rune(text) {
|
||||
switch {
|
||||
case unicode.IsLetter(r) || unicode.IsNumber(r):
|
||||
if futureDash && len(anchorName) > 0 {
|
||||
anchorName = append(anchorName, '-')
|
||||
}
|
||||
futureDash = false
|
||||
anchorName = append(anchorName, unicode.ToLower(r))
|
||||
default:
|
||||
futureDash = true
|
||||
}
|
||||
}
|
||||
return string(anchorName)
|
||||
}
|
||||
35
vendor/github.com/shurcooL/sanitized_anchor_name/main_test.go
generated
vendored
Normal file
35
vendor/github.com/shurcooL/sanitized_anchor_name/main_test.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
package sanitized_anchor_name_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/shurcooL/sanitized_anchor_name"
|
||||
)
|
||||
|
||||
func ExampleCreate() {
|
||||
anchorName := sanitized_anchor_name.Create("This is a header")
|
||||
|
||||
fmt.Println(anchorName)
|
||||
|
||||
// Output:
|
||||
// this-is-a-header
|
||||
}
|
||||
|
||||
func ExampleCreate2() {
|
||||
fmt.Println(sanitized_anchor_name.Create("This is a header"))
|
||||
fmt.Println(sanitized_anchor_name.Create("This is also a header"))
|
||||
fmt.Println(sanitized_anchor_name.Create("main.go"))
|
||||
fmt.Println(sanitized_anchor_name.Create("Article 123"))
|
||||
fmt.Println(sanitized_anchor_name.Create("<- Let's try this, shall we?"))
|
||||
fmt.Printf("%q\n", sanitized_anchor_name.Create(" "))
|
||||
fmt.Println(sanitized_anchor_name.Create("Hello, 世界"))
|
||||
|
||||
// Output:
|
||||
// this-is-a-header
|
||||
// this-is-also-a-header
|
||||
// main-go
|
||||
// article-123
|
||||
// let-s-try-this-shall-we
|
||||
// ""
|
||||
// hello-世界
|
||||
}
|
||||
24
vendor/github.com/spf13/cobra/.gitignore
generated
vendored
Normal file
24
vendor/github.com/spf13/cobra/.gitignore
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
|
||||
cobra.test
|
||||
9
vendor/github.com/spf13/cobra/.travis.yml
generated
vendored
Normal file
9
vendor/github.com/spf13/cobra/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.3.3
|
||||
- 1.4.2
|
||||
- 1.5.1
|
||||
- tip
|
||||
script:
|
||||
- go test ./...
|
||||
- go build
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user