From 1db3327e18fcf5297f9368d0f310812153ab2325 Mon Sep 17 00:00:00 2001 From: Changkun Ou Date: Mon, 2 May 2022 08:44:55 +0200 Subject: [PATCH] vendor: update --- pdfgen.go | 9 +- .../goldmark/extension/definition_list.go | 270 ------- .../yuin/goldmark/extension/footnote.go | 687 ------------------ .../github.com/yuin/goldmark/extension/gfm.go | 18 - .../yuin/goldmark/extension/linkify.go | 318 -------- .../yuin/goldmark/extension/strikethrough.go | 116 --- .../yuin/goldmark/extension/table.go | 552 -------------- .../yuin/goldmark/extension/tasklist.go | 115 --- .../yuin/goldmark/extension/typographer.go | 339 --------- vendor/modules.txt | 1 - 10 files changed, 2 insertions(+), 2423 deletions(-) delete mode 100644 vendor/github.com/yuin/goldmark/extension/definition_list.go delete mode 100644 vendor/github.com/yuin/goldmark/extension/footnote.go delete mode 100644 vendor/github.com/yuin/goldmark/extension/gfm.go delete mode 100644 vendor/github.com/yuin/goldmark/extension/linkify.go delete mode 100644 vendor/github.com/yuin/goldmark/extension/strikethrough.go delete mode 100644 vendor/github.com/yuin/goldmark/extension/table.go delete mode 100644 vendor/github.com/yuin/goldmark/extension/tasklist.go delete mode 100644 vendor/github.com/yuin/goldmark/extension/typographer.go diff --git a/pdfgen.go b/pdfgen.go index 2e6de80..90981cf 100644 --- a/pdfgen.go +++ b/pdfgen.go @@ -16,8 +16,7 @@ import ( "time" "github.com/yuin/goldmark" - "github.com/yuin/goldmark-meta" - "github.com/yuin/goldmark/extension" + meta "github.com/yuin/goldmark-meta" "github.com/yuin/goldmark/parser" "gopkg.in/yaml.v3" "mvdan.cc/xurls/v2" @@ -29,10 +28,6 @@ func init() { md = goldmark.New( goldmark.WithExtensions( meta.Meta, - extension.Table, - ), - goldmark.WithParserOptions( - parser.WithAutoHeadingID(), ), ) } @@ -249,7 +244,7 @@ func parseReferences(b []byte) string { ## References - [@ou2022bench]: Changkun Ou. 2020. Conduct Reliable Benchmarking in Go. TalkGo Meetup. Virtual Event. March 26. https://golang.design/s/gobench + [^ou2022bench]: Changkun Ou. 2020. Conduct Reliable Benchmarking in Go. TalkGo Meetup. Virtual Event. March 26. https://golang.design/s/gobench `) } diff --git a/vendor/github.com/yuin/goldmark/extension/definition_list.go b/vendor/github.com/yuin/goldmark/extension/definition_list.go deleted file mode 100644 index d2f5fec..0000000 --- a/vendor/github.com/yuin/goldmark/extension/definition_list.go +++ /dev/null @@ -1,270 +0,0 @@ -package extension - -import ( - "github.com/yuin/goldmark" - gast "github.com/yuin/goldmark/ast" - "github.com/yuin/goldmark/extension/ast" - "github.com/yuin/goldmark/parser" - "github.com/yuin/goldmark/renderer" - "github.com/yuin/goldmark/renderer/html" - "github.com/yuin/goldmark/text" - "github.com/yuin/goldmark/util" -) - -type definitionListParser struct { -} - -var defaultDefinitionListParser = &definitionListParser{} - -// NewDefinitionListParser return a new parser.BlockParser that -// can parse PHP Markdown Extra Definition lists. -func NewDefinitionListParser() parser.BlockParser { - return defaultDefinitionListParser -} - -func (b *definitionListParser) Trigger() []byte { - return []byte{':'} -} - -func (b *definitionListParser) Open(parent gast.Node, reader text.Reader, pc parser.Context) (gast.Node, parser.State) { - if _, ok := parent.(*ast.DefinitionList); ok { - return nil, parser.NoChildren - } - line, _ := reader.PeekLine() - pos := pc.BlockOffset() - indent := pc.BlockIndent() - if pos < 0 || line[pos] != ':' || indent != 0 { - return nil, parser.NoChildren - } - - last := parent.LastChild() - // need 1 or more spaces after ':' - w, _ := util.IndentWidth(line[pos+1:], pos+1) - if w < 1 { - return nil, parser.NoChildren - } - if w >= 8 { // starts with indented code - w = 5 - } - w += pos + 1 /* 1 = ':' */ - - para, lastIsParagraph := last.(*gast.Paragraph) - var list *ast.DefinitionList - status := parser.HasChildren - var ok bool - if lastIsParagraph { - list, ok = last.PreviousSibling().(*ast.DefinitionList) - if ok { // is not first item - list.Offset = w - list.TemporaryParagraph = para - } else { // is first item - list = ast.NewDefinitionList(w, para) - status |= parser.RequireParagraph - } - } else if list, ok = last.(*ast.DefinitionList); ok { // multiple description - list.Offset = w - list.TemporaryParagraph = nil - } else { - return nil, parser.NoChildren - } - - return list, status -} - -func (b *definitionListParser) Continue(node gast.Node, reader text.Reader, pc parser.Context) parser.State { - line, _ := reader.PeekLine() - if util.IsBlank(line) { - return parser.Continue | parser.HasChildren - } - list, _ := node.(*ast.DefinitionList) - w, _ := util.IndentWidth(line, reader.LineOffset()) - if w < list.Offset { - return parser.Close - } - pos, padding := util.IndentPosition(line, reader.LineOffset(), list.Offset) - reader.AdvanceAndSetPadding(pos, padding) - return parser.Continue | parser.HasChildren -} - -func (b *definitionListParser) Close(node gast.Node, reader text.Reader, pc parser.Context) { - // nothing to do -} - -func (b *definitionListParser) CanInterruptParagraph() bool { - return true -} - -func (b *definitionListParser) CanAcceptIndentedLine() bool { - return false -} - -type definitionDescriptionParser struct { -} - -var defaultDefinitionDescriptionParser = &definitionDescriptionParser{} - -// NewDefinitionDescriptionParser return a new parser.BlockParser that -// can parse definition description starts with ':'. -func NewDefinitionDescriptionParser() parser.BlockParser { - return defaultDefinitionDescriptionParser -} - -func (b *definitionDescriptionParser) Trigger() []byte { - return []byte{':'} -} - -func (b *definitionDescriptionParser) Open(parent gast.Node, reader text.Reader, pc parser.Context) (gast.Node, parser.State) { - line, _ := reader.PeekLine() - pos := pc.BlockOffset() - indent := pc.BlockIndent() - if pos < 0 || line[pos] != ':' || indent != 0 { - return nil, parser.NoChildren - } - list, _ := parent.(*ast.DefinitionList) - if list == nil { - return nil, parser.NoChildren - } - para := list.TemporaryParagraph - list.TemporaryParagraph = nil - if para != nil { - lines := para.Lines() - l := lines.Len() - for i := 0; i < l; i++ { - term := ast.NewDefinitionTerm() - segment := lines.At(i) - term.Lines().Append(segment.TrimRightSpace(reader.Source())) - list.AppendChild(list, term) - } - para.Parent().RemoveChild(para.Parent(), para) - } - cpos, padding := util.IndentPosition(line[pos+1:], pos+1, list.Offset-pos-1) - reader.AdvanceAndSetPadding(cpos+1, padding) - - return ast.NewDefinitionDescription(), parser.HasChildren -} - -func (b *definitionDescriptionParser) Continue(node gast.Node, reader text.Reader, pc parser.Context) parser.State { - // definitionListParser detects end of the description. - // so this method will never be called. - return parser.Continue | parser.HasChildren -} - -func (b *definitionDescriptionParser) Close(node gast.Node, reader text.Reader, pc parser.Context) { - desc := node.(*ast.DefinitionDescription) - desc.IsTight = !desc.HasBlankPreviousLines() - if desc.IsTight { - for gc := desc.FirstChild(); gc != nil; gc = gc.NextSibling() { - paragraph, ok := gc.(*gast.Paragraph) - if ok { - textBlock := gast.NewTextBlock() - textBlock.SetLines(paragraph.Lines()) - desc.ReplaceChild(desc, paragraph, textBlock) - } - } - } -} - -func (b *definitionDescriptionParser) CanInterruptParagraph() bool { - return true -} - -func (b *definitionDescriptionParser) CanAcceptIndentedLine() bool { - return false -} - -// DefinitionListHTMLRenderer is a renderer.NodeRenderer implementation that -// renders DefinitionList nodes. -type DefinitionListHTMLRenderer struct { - html.Config -} - -// NewDefinitionListHTMLRenderer returns a new DefinitionListHTMLRenderer. -func NewDefinitionListHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { - r := &DefinitionListHTMLRenderer{ - Config: html.NewConfig(), - } - for _, opt := range opts { - opt.SetHTMLOption(&r.Config) - } - return r -} - -// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. -func (r *DefinitionListHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { - reg.Register(ast.KindDefinitionList, r.renderDefinitionList) - reg.Register(ast.KindDefinitionTerm, r.renderDefinitionTerm) - reg.Register(ast.KindDefinitionDescription, r.renderDefinitionDescription) -} - -// DefinitionListAttributeFilter defines attribute names which dl elements can have. -var DefinitionListAttributeFilter = html.GlobalAttributeFilter - -func (r *DefinitionListHTMLRenderer) renderDefinitionList(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { - if entering { - if n.Attributes() != nil { - _, _ = w.WriteString("\n") - } else { - _, _ = w.WriteString("
\n") - } - } else { - _, _ = w.WriteString("
\n") - } - return gast.WalkContinue, nil -} - -// DefinitionTermAttributeFilter defines attribute names which dd elements can have. -var DefinitionTermAttributeFilter = html.GlobalAttributeFilter - -func (r *DefinitionListHTMLRenderer) renderDefinitionTerm(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { - if entering { - if n.Attributes() != nil { - _, _ = w.WriteString("') - } else { - _, _ = w.WriteString("
") - } - } else { - _, _ = w.WriteString("
\n") - } - return gast.WalkContinue, nil -} - -// DefinitionDescriptionAttributeFilter defines attribute names which dd elements can have. -var DefinitionDescriptionAttributeFilter = html.GlobalAttributeFilter - -func (r *DefinitionListHTMLRenderer) renderDefinitionDescription(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { - if entering { - n := node.(*ast.DefinitionDescription) - _, _ = w.WriteString("") - } else { - _, _ = w.WriteString(">\n") - } - } else { - _, _ = w.WriteString("\n") - } - return gast.WalkContinue, nil -} - -type definitionList struct { -} - -// DefinitionList is an extension that allow you to use PHP Markdown Extra Definition lists. -var DefinitionList = &definitionList{} - -func (e *definitionList) Extend(m goldmark.Markdown) { - m.Parser().AddOptions(parser.WithBlockParsers( - util.Prioritized(NewDefinitionListParser(), 101), - util.Prioritized(NewDefinitionDescriptionParser(), 102), - )) - m.Renderer().AddOptions(renderer.WithNodeRenderers( - util.Prioritized(NewDefinitionListHTMLRenderer(), 500), - )) -} diff --git a/vendor/github.com/yuin/goldmark/extension/footnote.go b/vendor/github.com/yuin/goldmark/extension/footnote.go deleted file mode 100644 index 09b6fa8..0000000 --- a/vendor/github.com/yuin/goldmark/extension/footnote.go +++ /dev/null @@ -1,687 +0,0 @@ -package extension - -import ( - "bytes" - "fmt" - "strconv" - - "github.com/yuin/goldmark" - gast "github.com/yuin/goldmark/ast" - "github.com/yuin/goldmark/extension/ast" - "github.com/yuin/goldmark/parser" - "github.com/yuin/goldmark/renderer" - "github.com/yuin/goldmark/renderer/html" - "github.com/yuin/goldmark/text" - "github.com/yuin/goldmark/util" -) - -var footnoteListKey = parser.NewContextKey() -var footnoteLinkListKey = parser.NewContextKey() - -type footnoteBlockParser struct { -} - -var defaultFootnoteBlockParser = &footnoteBlockParser{} - -// NewFootnoteBlockParser returns a new parser.BlockParser that can parse -// footnotes of the Markdown(PHP Markdown Extra) text. -func NewFootnoteBlockParser() parser.BlockParser { - return defaultFootnoteBlockParser -} - -func (b *footnoteBlockParser) Trigger() []byte { - return []byte{'['} -} - -func (b *footnoteBlockParser) Open(parent gast.Node, reader text.Reader, pc parser.Context) (gast.Node, parser.State) { - line, segment := reader.PeekLine() - pos := pc.BlockOffset() - if pos < 0 || line[pos] != '[' { - return nil, parser.NoChildren - } - pos++ - if pos > len(line)-1 || line[pos] != '^' { - return nil, parser.NoChildren - } - open := pos + 1 - closes := 0 - closure := util.FindClosure(line[pos+1:], '[', ']', false, false) - closes = pos + 1 + closure - next := closes + 1 - if closure > -1 { - if next >= len(line) || line[next] != ':' { - return nil, parser.NoChildren - } - } else { - return nil, parser.NoChildren - } - padding := segment.Padding - label := reader.Value(text.NewSegment(segment.Start+open-padding, segment.Start+closes-padding)) - if util.IsBlank(label) { - return nil, parser.NoChildren - } - item := ast.NewFootnote(label) - - pos = next + 1 - padding - if pos >= len(line) { - reader.Advance(pos) - return item, parser.NoChildren - } - reader.AdvanceAndSetPadding(pos, padding) - return item, parser.HasChildren -} - -func (b *footnoteBlockParser) Continue(node gast.Node, reader text.Reader, pc parser.Context) parser.State { - line, _ := reader.PeekLine() - if util.IsBlank(line) { - return parser.Continue | parser.HasChildren - } - childpos, padding := util.IndentPosition(line, reader.LineOffset(), 4) - if childpos < 0 { - return parser.Close - } - reader.AdvanceAndSetPadding(childpos, padding) - return parser.Continue | parser.HasChildren -} - -func (b *footnoteBlockParser) Close(node gast.Node, reader text.Reader, pc parser.Context) { - var list *ast.FootnoteList - if tlist := pc.Get(footnoteListKey); tlist != nil { - list = tlist.(*ast.FootnoteList) - } else { - list = ast.NewFootnoteList() - pc.Set(footnoteListKey, list) - node.Parent().InsertBefore(node.Parent(), node, list) - } - node.Parent().RemoveChild(node.Parent(), node) - list.AppendChild(list, node) -} - -func (b *footnoteBlockParser) CanInterruptParagraph() bool { - return true -} - -func (b *footnoteBlockParser) CanAcceptIndentedLine() bool { - return false -} - -type footnoteParser struct { -} - -var defaultFootnoteParser = &footnoteParser{} - -// NewFootnoteParser returns a new parser.InlineParser that can parse -// footnote links of the Markdown(PHP Markdown Extra) text. -func NewFootnoteParser() parser.InlineParser { - return defaultFootnoteParser -} - -func (s *footnoteParser) Trigger() []byte { - // footnote syntax probably conflict with the image syntax. - // So we need trigger this parser with '!'. - return []byte{'!', '['} -} - -func (s *footnoteParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node { - line, segment := block.PeekLine() - pos := 1 - if len(line) > 0 && line[0] == '!' { - pos++ - } - if pos >= len(line) || line[pos] != '^' { - return nil - } - pos++ - if pos >= len(line) { - return nil - } - open := pos - closure := util.FindClosure(line[pos:], '[', ']', false, false) - if closure < 0 { - return nil - } - closes := pos + closure - value := block.Value(text.NewSegment(segment.Start+open, segment.Start+closes)) - block.Advance(closes + 1) - - var list *ast.FootnoteList - if tlist := pc.Get(footnoteListKey); tlist != nil { - list = tlist.(*ast.FootnoteList) - } - if list == nil { - return nil - } - index := 0 - for def := list.FirstChild(); def != nil; def = def.NextSibling() { - d := def.(*ast.Footnote) - if bytes.Equal(d.Ref, value) { - if d.Index < 0 { - list.Count += 1 - d.Index = list.Count - } - index = d.Index - break - } - } - if index == 0 { - return nil - } - - fnlink := ast.NewFootnoteLink(index) - var fnlist []*ast.FootnoteLink - if tmp := pc.Get(footnoteLinkListKey); tmp != nil { - fnlist = tmp.([]*ast.FootnoteLink) - } else { - fnlist = []*ast.FootnoteLink{} - pc.Set(footnoteLinkListKey, fnlist) - } - pc.Set(footnoteLinkListKey, append(fnlist, fnlink)) - if line[0] == '!' { - parent.AppendChild(parent, gast.NewTextSegment(text.NewSegment(segment.Start, segment.Start+1))) - } - - return fnlink -} - -type footnoteASTTransformer struct { -} - -var defaultFootnoteASTTransformer = &footnoteASTTransformer{} - -// NewFootnoteASTTransformer returns a new parser.ASTTransformer that -// insert a footnote list to the last of the document. -func NewFootnoteASTTransformer() parser.ASTTransformer { - return defaultFootnoteASTTransformer -} - -func (a *footnoteASTTransformer) Transform(node *gast.Document, reader text.Reader, pc parser.Context) { - var list *ast.FootnoteList - var fnlist []*ast.FootnoteLink - if tmp := pc.Get(footnoteListKey); tmp != nil { - list = tmp.(*ast.FootnoteList) - } - if tmp := pc.Get(footnoteLinkListKey); tmp != nil { - fnlist = tmp.([]*ast.FootnoteLink) - } - - pc.Set(footnoteListKey, nil) - pc.Set(footnoteLinkListKey, nil) - - if list == nil { - return - } - - counter := map[int]int{} - if fnlist != nil { - for _, fnlink := range fnlist { - if fnlink.Index >= 0 { - counter[fnlink.Index]++ - } - } - refCounter := map[int]int{} - for _, fnlink := range fnlist { - fnlink.RefCount = counter[fnlink.Index] - if _, ok := refCounter[fnlink.Index]; !ok { - refCounter[fnlink.Index] = 0 - } - fnlink.RefIndex = refCounter[fnlink.Index] - refCounter[fnlink.Index]++ - } - } - for footnote := list.FirstChild(); footnote != nil; { - var container gast.Node = footnote - next := footnote.NextSibling() - if fc := container.LastChild(); fc != nil && gast.IsParagraph(fc) { - container = fc - } - fn := footnote.(*ast.Footnote) - index := fn.Index - if index < 0 { - list.RemoveChild(list, footnote) - } else { - refCount := counter[index] - backLink := ast.NewFootnoteBacklink(index) - backLink.RefCount = refCount - backLink.RefIndex = 0 - container.AppendChild(container, backLink) - if refCount > 1 { - for i := 1; i < refCount; i++ { - backLink := ast.NewFootnoteBacklink(index) - backLink.RefCount = refCount - backLink.RefIndex = i - container.AppendChild(container, backLink) - } - } - } - footnote = next - } - list.SortChildren(func(n1, n2 gast.Node) int { - if n1.(*ast.Footnote).Index < n2.(*ast.Footnote).Index { - return -1 - } - return 1 - }) - if list.Count <= 0 { - list.Parent().RemoveChild(list.Parent(), list) - return - } - - node.AppendChild(node, list) -} - -// FootnoteConfig holds configuration values for the footnote extension. -// -// Link* and Backlink* configurations have some variables: -// Occurrances of “^^” in the string will be replaced by the -// corresponding footnote number in the HTML output. -// Occurrances of “%%” will be replaced by a number for the -// reference (footnotes can have multiple references). -type FootnoteConfig struct { - html.Config - - // IDPrefix is a prefix for the id attributes generated by footnotes. - IDPrefix []byte - - // IDPrefix is a function that determines the id attribute for given Node. - IDPrefixFunction func(gast.Node) []byte - - // LinkTitle is an optional title attribute for footnote links. - LinkTitle []byte - - // BacklinkTitle is an optional title attribute for footnote backlinks. - BacklinkTitle []byte - - // LinkClass is a class for footnote links. - LinkClass []byte - - // BacklinkClass is a class for footnote backlinks. - BacklinkClass []byte - - // BacklinkHTML is an HTML content for footnote backlinks. - BacklinkHTML []byte -} - -// FootnoteOption interface is a functional option interface for the extension. -type FootnoteOption interface { - renderer.Option - // SetFootnoteOption sets given option to the extension. - SetFootnoteOption(*FootnoteConfig) -} - -// NewFootnoteConfig returns a new Config with defaults. -func NewFootnoteConfig() FootnoteConfig { - return FootnoteConfig{ - Config: html.NewConfig(), - LinkTitle: []byte(""), - BacklinkTitle: []byte(""), - LinkClass: []byte("footnote-ref"), - BacklinkClass: []byte("footnote-backref"), - BacklinkHTML: []byte("↩︎"), - } -} - -// SetOption implements renderer.SetOptioner. -func (c *FootnoteConfig) SetOption(name renderer.OptionName, value interface{}) { - switch name { - case optFootnoteIDPrefixFunction: - c.IDPrefixFunction = value.(func(gast.Node) []byte) - case optFootnoteIDPrefix: - c.IDPrefix = value.([]byte) - case optFootnoteLinkTitle: - c.LinkTitle = value.([]byte) - case optFootnoteBacklinkTitle: - c.BacklinkTitle = value.([]byte) - case optFootnoteLinkClass: - c.LinkClass = value.([]byte) - case optFootnoteBacklinkClass: - c.BacklinkClass = value.([]byte) - case optFootnoteBacklinkHTML: - c.BacklinkHTML = value.([]byte) - default: - c.Config.SetOption(name, value) - } -} - -type withFootnoteHTMLOptions struct { - value []html.Option -} - -func (o *withFootnoteHTMLOptions) SetConfig(c *renderer.Config) { - if o.value != nil { - for _, v := range o.value { - v.(renderer.Option).SetConfig(c) - } - } -} - -func (o *withFootnoteHTMLOptions) SetFootnoteOption(c *FootnoteConfig) { - if o.value != nil { - for _, v := range o.value { - v.SetHTMLOption(&c.Config) - } - } -} - -// WithFootnoteHTMLOptions is functional option that wraps goldmark HTMLRenderer options. -func WithFootnoteHTMLOptions(opts ...html.Option) FootnoteOption { - return &withFootnoteHTMLOptions{opts} -} - -const optFootnoteIDPrefix renderer.OptionName = "FootnoteIDPrefix" - -type withFootnoteIDPrefix struct { - value []byte -} - -func (o *withFootnoteIDPrefix) SetConfig(c *renderer.Config) { - c.Options[optFootnoteIDPrefix] = o.value -} - -func (o *withFootnoteIDPrefix) SetFootnoteOption(c *FootnoteConfig) { - c.IDPrefix = o.value -} - -// WithFootnoteIDPrefix is a functional option that is a prefix for the id attributes generated by footnotes. -func WithFootnoteIDPrefix(a []byte) FootnoteOption { - return &withFootnoteIDPrefix{a} -} - -const optFootnoteIDPrefixFunction renderer.OptionName = "FootnoteIDPrefixFunction" - -type withFootnoteIDPrefixFunction struct { - value func(gast.Node) []byte -} - -func (o *withFootnoteIDPrefixFunction) SetConfig(c *renderer.Config) { - c.Options[optFootnoteIDPrefixFunction] = o.value -} - -func (o *withFootnoteIDPrefixFunction) SetFootnoteOption(c *FootnoteConfig) { - c.IDPrefixFunction = o.value -} - -// WithFootnoteIDPrefixFunction is a functional option that is a prefix for the id attributes generated by footnotes. -func WithFootnoteIDPrefixFunction(a func(gast.Node) []byte) FootnoteOption { - return &withFootnoteIDPrefixFunction{a} -} - -const optFootnoteLinkTitle renderer.OptionName = "FootnoteLinkTitle" - -type withFootnoteLinkTitle struct { - value []byte -} - -func (o *withFootnoteLinkTitle) SetConfig(c *renderer.Config) { - c.Options[optFootnoteLinkTitle] = o.value -} - -func (o *withFootnoteLinkTitle) SetFootnoteOption(c *FootnoteConfig) { - c.LinkTitle = o.value -} - -// WithFootnoteLinkTitle is a functional option that is an optional title attribute for footnote links. -func WithFootnoteLinkTitle(a []byte) FootnoteOption { - return &withFootnoteLinkTitle{a} -} - -const optFootnoteBacklinkTitle renderer.OptionName = "FootnoteBacklinkTitle" - -type withFootnoteBacklinkTitle struct { - value []byte -} - -func (o *withFootnoteBacklinkTitle) SetConfig(c *renderer.Config) { - c.Options[optFootnoteBacklinkTitle] = o.value -} - -func (o *withFootnoteBacklinkTitle) SetFootnoteOption(c *FootnoteConfig) { - c.BacklinkTitle = o.value -} - -// WithFootnoteBacklinkTitle is a functional option that is an optional title attribute for footnote backlinks. -func WithFootnoteBacklinkTitle(a []byte) FootnoteOption { - return &withFootnoteBacklinkTitle{a} -} - -const optFootnoteLinkClass renderer.OptionName = "FootnoteLinkClass" - -type withFootnoteLinkClass struct { - value []byte -} - -func (o *withFootnoteLinkClass) SetConfig(c *renderer.Config) { - c.Options[optFootnoteLinkClass] = o.value -} - -func (o *withFootnoteLinkClass) SetFootnoteOption(c *FootnoteConfig) { - c.LinkClass = o.value -} - -// WithFootnoteLinkClass is a functional option that is a class for footnote links. -func WithFootnoteLinkClass(a []byte) FootnoteOption { - return &withFootnoteLinkClass{a} -} - -const optFootnoteBacklinkClass renderer.OptionName = "FootnoteBacklinkClass" - -type withFootnoteBacklinkClass struct { - value []byte -} - -func (o *withFootnoteBacklinkClass) SetConfig(c *renderer.Config) { - c.Options[optFootnoteBacklinkClass] = o.value -} - -func (o *withFootnoteBacklinkClass) SetFootnoteOption(c *FootnoteConfig) { - c.BacklinkClass = o.value -} - -// WithFootnoteBacklinkClass is a functional option that is a class for footnote backlinks. -func WithFootnoteBacklinkClass(a []byte) FootnoteOption { - return &withFootnoteBacklinkClass{a} -} - -const optFootnoteBacklinkHTML renderer.OptionName = "FootnoteBacklinkHTML" - -type withFootnoteBacklinkHTML struct { - value []byte -} - -func (o *withFootnoteBacklinkHTML) SetConfig(c *renderer.Config) { - c.Options[optFootnoteBacklinkHTML] = o.value -} - -func (o *withFootnoteBacklinkHTML) SetFootnoteOption(c *FootnoteConfig) { - c.BacklinkHTML = o.value -} - -// WithFootnoteBacklinkHTML is an HTML content for footnote backlinks. -func WithFootnoteBacklinkHTML(a []byte) FootnoteOption { - return &withFootnoteBacklinkHTML{a} -} - -// FootnoteHTMLRenderer is a renderer.NodeRenderer implementation that -// renders FootnoteLink nodes. -type FootnoteHTMLRenderer struct { - FootnoteConfig -} - -// NewFootnoteHTMLRenderer returns a new FootnoteHTMLRenderer. -func NewFootnoteHTMLRenderer(opts ...FootnoteOption) renderer.NodeRenderer { - r := &FootnoteHTMLRenderer{ - FootnoteConfig: NewFootnoteConfig(), - } - for _, opt := range opts { - opt.SetFootnoteOption(&r.FootnoteConfig) - } - return r -} - -// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. -func (r *FootnoteHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { - reg.Register(ast.KindFootnoteLink, r.renderFootnoteLink) - reg.Register(ast.KindFootnoteBacklink, r.renderFootnoteBacklink) - reg.Register(ast.KindFootnote, r.renderFootnote) - reg.Register(ast.KindFootnoteList, r.renderFootnoteList) -} - -func (r *FootnoteHTMLRenderer) renderFootnoteLink(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { - if entering { - n := node.(*ast.FootnoteLink) - is := strconv.Itoa(n.Index) - _, _ = w.WriteString(``) - - _, _ = w.WriteString(is) - _, _ = w.WriteString(``) - } - return gast.WalkContinue, nil -} - -func (r *FootnoteHTMLRenderer) renderFootnoteBacklink(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { - if entering { - n := node.(*ast.FootnoteBacklink) - is := strconv.Itoa(n.Index) - _, _ = w.WriteString(` `) - _, _ = w.Write(applyFootnoteTemplate(r.FootnoteConfig.BacklinkHTML, n.Index, n.RefCount)) - _, _ = w.WriteString(``) - } - return gast.WalkContinue, nil -} - -func (r *FootnoteHTMLRenderer) renderFootnote(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { - n := node.(*ast.Footnote) - is := strconv.Itoa(n.Index) - if entering { - _, _ = w.WriteString(`
  • \n") - } else { - _, _ = w.WriteString("
  • \n") - } - return gast.WalkContinue, nil -} - -func (r *FootnoteHTMLRenderer) renderFootnoteList(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { - if entering { - _, _ = w.WriteString(`
    ') - if r.Config.XHTML { - _, _ = w.WriteString("\n
    \n") - } else { - _, _ = w.WriteString("\n
    \n") - } - _, _ = w.WriteString("
      \n") - } else { - _, _ = w.WriteString("
    \n") - _, _ = w.WriteString("
    \n") - } - return gast.WalkContinue, nil -} - -func (r *FootnoteHTMLRenderer) idPrefix(node gast.Node) []byte { - if r.FootnoteConfig.IDPrefix != nil { - return r.FootnoteConfig.IDPrefix - } - if r.FootnoteConfig.IDPrefixFunction != nil { - return r.FootnoteConfig.IDPrefixFunction(node) - } - return []byte("") -} - -func applyFootnoteTemplate(b []byte, index, refCount int) []byte { - fast := true - for i, c := range b { - if i != 0 { - if b[i-1] == '^' && c == '^' { - fast = false - break - } - if b[i-1] == '%' && c == '%' { - fast = false - break - } - } - } - if fast { - return b - } - is := []byte(strconv.Itoa(index)) - rs := []byte(strconv.Itoa(refCount)) - ret := bytes.Replace(b, []byte("^^"), is, -1) - return bytes.Replace(ret, []byte("%%"), rs, -1) -} - -type footnote struct { - options []FootnoteOption -} - -// Footnote is an extension that allow you to use PHP Markdown Extra Footnotes. -var Footnote = &footnote{ - options: []FootnoteOption{}, -} - -// NewFootnote returns a new extension with given options. -func NewFootnote(opts ...FootnoteOption) goldmark.Extender { - return &footnote{ - options: opts, - } -} - -func (e *footnote) Extend(m goldmark.Markdown) { - m.Parser().AddOptions( - parser.WithBlockParsers( - util.Prioritized(NewFootnoteBlockParser(), 999), - ), - parser.WithInlineParsers( - util.Prioritized(NewFootnoteParser(), 101), - ), - parser.WithASTTransformers( - util.Prioritized(NewFootnoteASTTransformer(), 999), - ), - ) - m.Renderer().AddOptions(renderer.WithNodeRenderers( - util.Prioritized(NewFootnoteHTMLRenderer(e.options...), 500), - )) -} diff --git a/vendor/github.com/yuin/goldmark/extension/gfm.go b/vendor/github.com/yuin/goldmark/extension/gfm.go deleted file mode 100644 index a570fbd..0000000 --- a/vendor/github.com/yuin/goldmark/extension/gfm.go +++ /dev/null @@ -1,18 +0,0 @@ -package extension - -import ( - "github.com/yuin/goldmark" -) - -type gfm struct { -} - -// GFM is an extension that provides Github Flavored markdown functionalities. -var GFM = &gfm{} - -func (e *gfm) Extend(m goldmark.Markdown) { - Linkify.Extend(m) - Table.Extend(m) - Strikethrough.Extend(m) - TaskList.Extend(m) -} diff --git a/vendor/github.com/yuin/goldmark/extension/linkify.go b/vendor/github.com/yuin/goldmark/extension/linkify.go deleted file mode 100644 index 2f046eb..0000000 --- a/vendor/github.com/yuin/goldmark/extension/linkify.go +++ /dev/null @@ -1,318 +0,0 @@ -package extension - -import ( - "bytes" - "regexp" - - "github.com/yuin/goldmark" - "github.com/yuin/goldmark/ast" - "github.com/yuin/goldmark/parser" - "github.com/yuin/goldmark/text" - "github.com/yuin/goldmark/util" -) - -var wwwURLRegxp = regexp.MustCompile(`^www\.[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-z]+(?:[/#?][-a-zA-Z0-9@:%_\+.~#!?&/=\(\);,'">\^{}\[\]` + "`" + `]*)?`) - -var urlRegexp = regexp.MustCompile(`^(?:http|https|ftp)://[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-z]+(?::\d+)?(?:[/#?][-a-zA-Z0-9@:%_+.~#$!?&/=\(\);,'">\^{}\[\]` + "`" + `]*)?`) - -// An LinkifyConfig struct is a data structure that holds configuration of the -// Linkify extension. -type LinkifyConfig struct { - AllowedProtocols [][]byte - URLRegexp *regexp.Regexp - WWWRegexp *regexp.Regexp - EmailRegexp *regexp.Regexp -} - -const ( - optLinkifyAllowedProtocols parser.OptionName = "LinkifyAllowedProtocols" - optLinkifyURLRegexp parser.OptionName = "LinkifyURLRegexp" - optLinkifyWWWRegexp parser.OptionName = "LinkifyWWWRegexp" - optLinkifyEmailRegexp parser.OptionName = "LinkifyEmailRegexp" -) - -// SetOption implements SetOptioner. -func (c *LinkifyConfig) SetOption(name parser.OptionName, value interface{}) { - switch name { - case optLinkifyAllowedProtocols: - c.AllowedProtocols = value.([][]byte) - case optLinkifyURLRegexp: - c.URLRegexp = value.(*regexp.Regexp) - case optLinkifyWWWRegexp: - c.WWWRegexp = value.(*regexp.Regexp) - case optLinkifyEmailRegexp: - c.EmailRegexp = value.(*regexp.Regexp) - } -} - -// A LinkifyOption interface sets options for the LinkifyOption. -type LinkifyOption interface { - parser.Option - SetLinkifyOption(*LinkifyConfig) -} - -type withLinkifyAllowedProtocols struct { - value [][]byte -} - -func (o *withLinkifyAllowedProtocols) SetParserOption(c *parser.Config) { - c.Options[optLinkifyAllowedProtocols] = o.value -} - -func (o *withLinkifyAllowedProtocols) SetLinkifyOption(p *LinkifyConfig) { - p.AllowedProtocols = o.value -} - -// WithLinkifyAllowedProtocols is a functional option that specify allowed -// protocols in autolinks. Each protocol must end with ':' like -// 'http:' . -func WithLinkifyAllowedProtocols(value [][]byte) LinkifyOption { - return &withLinkifyAllowedProtocols{ - value: value, - } -} - -type withLinkifyURLRegexp struct { - value *regexp.Regexp -} - -func (o *withLinkifyURLRegexp) SetParserOption(c *parser.Config) { - c.Options[optLinkifyURLRegexp] = o.value -} - -func (o *withLinkifyURLRegexp) SetLinkifyOption(p *LinkifyConfig) { - p.URLRegexp = o.value -} - -// WithLinkifyURLRegexp is a functional option that specify -// a pattern of the URL including a protocol. -func WithLinkifyURLRegexp(value *regexp.Regexp) LinkifyOption { - return &withLinkifyURLRegexp{ - value: value, - } -} - -// WithLinkifyWWWRegexp is a functional option that specify -// a pattern of the URL without a protocol. -// This pattern must start with 'www.' . -type withLinkifyWWWRegexp struct { - value *regexp.Regexp -} - -func (o *withLinkifyWWWRegexp) SetParserOption(c *parser.Config) { - c.Options[optLinkifyWWWRegexp] = o.value -} - -func (o *withLinkifyWWWRegexp) SetLinkifyOption(p *LinkifyConfig) { - p.WWWRegexp = o.value -} - -func WithLinkifyWWWRegexp(value *regexp.Regexp) LinkifyOption { - return &withLinkifyWWWRegexp{ - value: value, - } -} - -// WithLinkifyWWWRegexp is a functional otpion that specify -// a pattern of the email address. -type withLinkifyEmailRegexp struct { - value *regexp.Regexp -} - -func (o *withLinkifyEmailRegexp) SetParserOption(c *parser.Config) { - c.Options[optLinkifyEmailRegexp] = o.value -} - -func (o *withLinkifyEmailRegexp) SetLinkifyOption(p *LinkifyConfig) { - p.EmailRegexp = o.value -} - -func WithLinkifyEmailRegexp(value *regexp.Regexp) LinkifyOption { - return &withLinkifyEmailRegexp{ - value: value, - } -} - -type linkifyParser struct { - LinkifyConfig -} - -// NewLinkifyParser return a new InlineParser can parse -// text that seems like a URL. -func NewLinkifyParser(opts ...LinkifyOption) parser.InlineParser { - p := &linkifyParser{ - LinkifyConfig: LinkifyConfig{ - AllowedProtocols: nil, - URLRegexp: urlRegexp, - WWWRegexp: wwwURLRegxp, - }, - } - for _, o := range opts { - o.SetLinkifyOption(&p.LinkifyConfig) - } - return p -} - -func (s *linkifyParser) Trigger() []byte { - // ' ' indicates any white spaces and a line head - return []byte{' ', '*', '_', '~', '('} -} - -var ( - protoHTTP = []byte("http:") - protoHTTPS = []byte("https:") - protoFTP = []byte("ftp:") - domainWWW = []byte("www.") -) - -func (s *linkifyParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node { - if pc.IsInLinkLabel() { - return nil - } - line, segment := block.PeekLine() - consumes := 0 - start := segment.Start - c := line[0] - // advance if current position is not a line head. - if c == ' ' || c == '*' || c == '_' || c == '~' || c == '(' { - consumes++ - start++ - line = line[1:] - } - - var m []int - var protocol []byte - var typ ast.AutoLinkType = ast.AutoLinkURL - if s.LinkifyConfig.AllowedProtocols == nil { - if bytes.HasPrefix(line, protoHTTP) || bytes.HasPrefix(line, protoHTTPS) || bytes.HasPrefix(line, protoFTP) { - m = s.LinkifyConfig.URLRegexp.FindSubmatchIndex(line) - } - } else { - for _, prefix := range s.LinkifyConfig.AllowedProtocols { - if bytes.HasPrefix(line, prefix) { - m = s.LinkifyConfig.URLRegexp.FindSubmatchIndex(line) - break - } - } - } - if m == nil && bytes.HasPrefix(line, domainWWW) { - m = s.LinkifyConfig.WWWRegexp.FindSubmatchIndex(line) - protocol = []byte("http") - } - if m != nil && m[0] != 0 { - m = nil - } - if m != nil && m[0] == 0 { - lastChar := line[m[1]-1] - if lastChar == '.' { - m[1]-- - } else if lastChar == ')' { - closing := 0 - for i := m[1] - 1; i >= m[0]; i-- { - if line[i] == ')' { - closing++ - } else if line[i] == '(' { - closing-- - } - } - if closing > 0 { - m[1] -= closing - } - } else if lastChar == ';' { - i := m[1] - 2 - for ; i >= m[0]; i-- { - if util.IsAlphaNumeric(line[i]) { - continue - } - break - } - if i != m[1]-2 { - if line[i] == '&' { - m[1] -= m[1] - i - } - } - } - } - if m == nil { - if len(line) > 0 && util.IsPunct(line[0]) { - return nil - } - typ = ast.AutoLinkEmail - stop := -1 - if s.LinkifyConfig.EmailRegexp == nil { - stop = util.FindEmailIndex(line) - } else { - m := s.LinkifyConfig.EmailRegexp.FindSubmatchIndex(line) - if m != nil && m[0] == 0 { - stop = m[1] - } - } - if stop < 0 { - return nil - } - at := bytes.IndexByte(line, '@') - m = []int{0, stop, at, stop - 1} - if m == nil || bytes.IndexByte(line[m[2]:m[3]], '.') < 0 { - return nil - } - lastChar := line[m[1]-1] - if lastChar == '.' { - m[1]-- - } - if m[1] < len(line) { - nextChar := line[m[1]] - if nextChar == '-' || nextChar == '_' { - return nil - } - } - } - if m == nil { - return nil - } - if consumes != 0 { - s := segment.WithStop(segment.Start + 1) - ast.MergeOrAppendTextSegment(parent, s) - } - i := m[1] - 1 - for ; i > 0; i-- { - c := line[i] - switch c { - case '?', '!', '.', ',', ':', '*', '_', '~': - default: - goto endfor - } - } -endfor: - i++ - consumes += i - block.Advance(consumes) - n := ast.NewTextSegment(text.NewSegment(start, start+i)) - link := ast.NewAutoLink(typ, n) - link.Protocol = protocol - return link -} - -func (s *linkifyParser) CloseBlock(parent ast.Node, pc parser.Context) { - // nothing to do -} - -type linkify struct { - options []LinkifyOption -} - -// Linkify is an extension that allow you to parse text that seems like a URL. -var Linkify = &linkify{} - -func NewLinkify(opts ...LinkifyOption) goldmark.Extender { - return &linkify{ - options: opts, - } -} - -func (e *linkify) Extend(m goldmark.Markdown) { - m.Parser().AddOptions( - parser.WithInlineParsers( - util.Prioritized(NewLinkifyParser(e.options...), 999), - ), - ) -} diff --git a/vendor/github.com/yuin/goldmark/extension/strikethrough.go b/vendor/github.com/yuin/goldmark/extension/strikethrough.go deleted file mode 100644 index 1b629ad..0000000 --- a/vendor/github.com/yuin/goldmark/extension/strikethrough.go +++ /dev/null @@ -1,116 +0,0 @@ -package extension - -import ( - "github.com/yuin/goldmark" - gast "github.com/yuin/goldmark/ast" - "github.com/yuin/goldmark/extension/ast" - "github.com/yuin/goldmark/parser" - "github.com/yuin/goldmark/renderer" - "github.com/yuin/goldmark/renderer/html" - "github.com/yuin/goldmark/text" - "github.com/yuin/goldmark/util" -) - -type strikethroughDelimiterProcessor struct { -} - -func (p *strikethroughDelimiterProcessor) IsDelimiter(b byte) bool { - return b == '~' -} - -func (p *strikethroughDelimiterProcessor) CanOpenCloser(opener, closer *parser.Delimiter) bool { - return opener.Char == closer.Char -} - -func (p *strikethroughDelimiterProcessor) OnMatch(consumes int) gast.Node { - return ast.NewStrikethrough() -} - -var defaultStrikethroughDelimiterProcessor = &strikethroughDelimiterProcessor{} - -type strikethroughParser struct { -} - -var defaultStrikethroughParser = &strikethroughParser{} - -// NewStrikethroughParser return a new InlineParser that parses -// strikethrough expressions. -func NewStrikethroughParser() parser.InlineParser { - return defaultStrikethroughParser -} - -func (s *strikethroughParser) Trigger() []byte { - return []byte{'~'} -} - -func (s *strikethroughParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node { - before := block.PrecendingCharacter() - line, segment := block.PeekLine() - node := parser.ScanDelimiter(line, before, 2, defaultStrikethroughDelimiterProcessor) - if node == nil { - return nil - } - node.Segment = segment.WithStop(segment.Start + node.OriginalLength) - block.Advance(node.OriginalLength) - pc.PushDelimiter(node) - return node -} - -func (s *strikethroughParser) CloseBlock(parent gast.Node, pc parser.Context) { - // nothing to do -} - -// StrikethroughHTMLRenderer is a renderer.NodeRenderer implementation that -// renders Strikethrough nodes. -type StrikethroughHTMLRenderer struct { - html.Config -} - -// NewStrikethroughHTMLRenderer returns a new StrikethroughHTMLRenderer. -func NewStrikethroughHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { - r := &StrikethroughHTMLRenderer{ - Config: html.NewConfig(), - } - for _, opt := range opts { - opt.SetHTMLOption(&r.Config) - } - return r -} - -// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. -func (r *StrikethroughHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { - reg.Register(ast.KindStrikethrough, r.renderStrikethrough) -} - -// StrikethroughAttributeFilter defines attribute names which dd elements can have. -var StrikethroughAttributeFilter = html.GlobalAttributeFilter - -func (r *StrikethroughHTMLRenderer) renderStrikethrough(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { - if entering { - if n.Attributes() != nil { - _, _ = w.WriteString("') - } else { - _, _ = w.WriteString("") - } - } else { - _, _ = w.WriteString("") - } - return gast.WalkContinue, nil -} - -type strikethrough struct { -} - -// Strikethrough is an extension that allow you to use strikethrough expression like '~~text~~' . -var Strikethrough = &strikethrough{} - -func (e *strikethrough) Extend(m goldmark.Markdown) { - m.Parser().AddOptions(parser.WithInlineParsers( - util.Prioritized(NewStrikethroughParser(), 500), - )) - m.Renderer().AddOptions(renderer.WithNodeRenderers( - util.Prioritized(NewStrikethroughHTMLRenderer(), 500), - )) -} diff --git a/vendor/github.com/yuin/goldmark/extension/table.go b/vendor/github.com/yuin/goldmark/extension/table.go deleted file mode 100644 index c637b99..0000000 --- a/vendor/github.com/yuin/goldmark/extension/table.go +++ /dev/null @@ -1,552 +0,0 @@ -package extension - -import ( - "bytes" - "fmt" - "regexp" - - "github.com/yuin/goldmark" - gast "github.com/yuin/goldmark/ast" - "github.com/yuin/goldmark/extension/ast" - "github.com/yuin/goldmark/parser" - "github.com/yuin/goldmark/renderer" - "github.com/yuin/goldmark/renderer/html" - "github.com/yuin/goldmark/text" - "github.com/yuin/goldmark/util" -) - -var escapedPipeCellListKey = parser.NewContextKey() - -type escapedPipeCell struct { - Cell *ast.TableCell - Pos []int - Transformed bool -} - -// TableCellAlignMethod indicates how are table cells aligned in HTML format.indicates how are table cells aligned in HTML format. -type TableCellAlignMethod int - -const ( - // TableCellAlignDefault renders alignments by default method. - // With XHTML, alignments are rendered as an align attribute. - // With HTML5, alignments are rendered as a style attribute. - TableCellAlignDefault TableCellAlignMethod = iota - - // TableCellAlignAttribute renders alignments as an align attribute. - TableCellAlignAttribute - - // TableCellAlignStyle renders alignments as a style attribute. - TableCellAlignStyle - - // TableCellAlignNone does not care about alignments. - // If you using classes or other styles, you can add these attributes - // in an ASTTransformer. - TableCellAlignNone -) - -// TableConfig struct holds options for the extension. -type TableConfig struct { - html.Config - - // TableCellAlignMethod indicates how are table celss aligned. - TableCellAlignMethod TableCellAlignMethod -} - -// TableOption interface is a functional option interface for the extension. -type TableOption interface { - renderer.Option - // SetTableOption sets given option to the extension. - SetTableOption(*TableConfig) -} - -// NewTableConfig returns a new Config with defaults. -func NewTableConfig() TableConfig { - return TableConfig{ - Config: html.NewConfig(), - TableCellAlignMethod: TableCellAlignDefault, - } -} - -// SetOption implements renderer.SetOptioner. -func (c *TableConfig) SetOption(name renderer.OptionName, value interface{}) { - switch name { - case optTableCellAlignMethod: - c.TableCellAlignMethod = value.(TableCellAlignMethod) - default: - c.Config.SetOption(name, value) - } -} - -type withTableHTMLOptions struct { - value []html.Option -} - -func (o *withTableHTMLOptions) SetConfig(c *renderer.Config) { - if o.value != nil { - for _, v := range o.value { - v.(renderer.Option).SetConfig(c) - } - } -} - -func (o *withTableHTMLOptions) SetTableOption(c *TableConfig) { - if o.value != nil { - for _, v := range o.value { - v.SetHTMLOption(&c.Config) - } - } -} - -// WithTableHTMLOptions is functional option that wraps goldmark HTMLRenderer options. -func WithTableHTMLOptions(opts ...html.Option) TableOption { - return &withTableHTMLOptions{opts} -} - -const optTableCellAlignMethod renderer.OptionName = "TableTableCellAlignMethod" - -type withTableCellAlignMethod struct { - value TableCellAlignMethod -} - -func (o *withTableCellAlignMethod) SetConfig(c *renderer.Config) { - c.Options[optTableCellAlignMethod] = o.value -} - -func (o *withTableCellAlignMethod) SetTableOption(c *TableConfig) { - c.TableCellAlignMethod = o.value -} - -// WithTableCellAlignMethod is a functional option that indicates how are table cells aligned in HTML format. -func WithTableCellAlignMethod(a TableCellAlignMethod) TableOption { - return &withTableCellAlignMethod{a} -} - -func isTableDelim(bs []byte) bool { - for _, b := range bs { - if !(util.IsSpace(b) || b == '-' || b == '|' || b == ':') { - return false - } - } - return true -} - -var tableDelimLeft = regexp.MustCompile(`^\s*\:\-+\s*$`) -var tableDelimRight = regexp.MustCompile(`^\s*\-+\:\s*$`) -var tableDelimCenter = regexp.MustCompile(`^\s*\:\-+\:\s*$`) -var tableDelimNone = regexp.MustCompile(`^\s*\-+\s*$`) - -type tableParagraphTransformer struct { -} - -var defaultTableParagraphTransformer = &tableParagraphTransformer{} - -// NewTableParagraphTransformer returns a new ParagraphTransformer -// that can transform paragraphs into tables. -func NewTableParagraphTransformer() parser.ParagraphTransformer { - return defaultTableParagraphTransformer -} - -func (b *tableParagraphTransformer) Transform(node *gast.Paragraph, reader text.Reader, pc parser.Context) { - lines := node.Lines() - if lines.Len() < 2 { - return - } - for i := 1; i < lines.Len(); i++ { - alignments := b.parseDelimiter(lines.At(i), reader) - if alignments == nil { - continue - } - header := b.parseRow(lines.At(i-1), alignments, true, reader, pc) - if header == nil || len(alignments) != header.ChildCount() { - return - } - table := ast.NewTable() - table.Alignments = alignments - table.AppendChild(table, ast.NewTableHeader(header)) - for j := i + 1; j < lines.Len(); j++ { - table.AppendChild(table, b.parseRow(lines.At(j), alignments, false, reader, pc)) - } - node.Lines().SetSliced(0, i-1) - node.Parent().InsertAfter(node.Parent(), node, table) - if node.Lines().Len() == 0 { - node.Parent().RemoveChild(node.Parent(), node) - } else { - last := node.Lines().At(i - 2) - last.Stop = last.Stop - 1 // trim last newline(\n) - node.Lines().Set(i-2, last) - } - } -} - -func (b *tableParagraphTransformer) parseRow(segment text.Segment, alignments []ast.Alignment, isHeader bool, reader text.Reader, pc parser.Context) *ast.TableRow { - source := reader.Source() - line := segment.Value(source) - pos := 0 - pos += util.TrimLeftSpaceLength(line) - limit := len(line) - limit -= util.TrimRightSpaceLength(line) - row := ast.NewTableRow(alignments) - if len(line) > 0 && line[pos] == '|' { - pos++ - } - if len(line) > 0 && line[limit-1] == '|' { - limit-- - } - i := 0 - for ; pos < limit; i++ { - alignment := ast.AlignNone - if i >= len(alignments) { - if !isHeader { - return row - } - } else { - alignment = alignments[i] - } - - var escapedCell *escapedPipeCell - node := ast.NewTableCell() - node.Alignment = alignment - hasBacktick := false - closure := pos - for ; closure < limit; closure++ { - if line[closure] == '`' { - hasBacktick = true - } - if line[closure] == '|' { - if closure == 0 || line[closure-1] != '\\' { - break - } else if hasBacktick { - if escapedCell == nil { - escapedCell = &escapedPipeCell{node, []int{}, false} - escapedList := pc.ComputeIfAbsent(escapedPipeCellListKey, - func() interface{} { - return []*escapedPipeCell{} - }).([]*escapedPipeCell) - escapedList = append(escapedList, escapedCell) - pc.Set(escapedPipeCellListKey, escapedList) - } - escapedCell.Pos = append(escapedCell.Pos, segment.Start+closure-1) - } - } - } - seg := text.NewSegment(segment.Start+pos, segment.Start+closure) - seg = seg.TrimLeftSpace(source) - seg = seg.TrimRightSpace(source) - node.Lines().Append(seg) - row.AppendChild(row, node) - pos = closure + 1 - } - for ; i < len(alignments); i++ { - row.AppendChild(row, ast.NewTableCell()) - } - return row -} - -func (b *tableParagraphTransformer) parseDelimiter(segment text.Segment, reader text.Reader) []ast.Alignment { - line := segment.Value(reader.Source()) - if !isTableDelim(line) { - return nil - } - cols := bytes.Split(line, []byte{'|'}) - if util.IsBlank(cols[0]) { - cols = cols[1:] - } - if len(cols) > 0 && util.IsBlank(cols[len(cols)-1]) { - cols = cols[:len(cols)-1] - } - - var alignments []ast.Alignment - for _, col := range cols { - if tableDelimLeft.Match(col) { - alignments = append(alignments, ast.AlignLeft) - } else if tableDelimRight.Match(col) { - alignments = append(alignments, ast.AlignRight) - } else if tableDelimCenter.Match(col) { - alignments = append(alignments, ast.AlignCenter) - } else if tableDelimNone.Match(col) { - alignments = append(alignments, ast.AlignNone) - } else { - return nil - } - } - return alignments -} - -type tableASTTransformer struct { -} - -var defaultTableASTTransformer = &tableASTTransformer{} - -// NewTableASTTransformer returns a parser.ASTTransformer for tables. -func NewTableASTTransformer() parser.ASTTransformer { - return defaultTableASTTransformer -} - -func (a *tableASTTransformer) Transform(node *gast.Document, reader text.Reader, pc parser.Context) { - lst := pc.Get(escapedPipeCellListKey) - if lst == nil { - return - } - pc.Set(escapedPipeCellListKey, nil) - for _, v := range lst.([]*escapedPipeCell) { - if v.Transformed { - continue - } - _ = gast.Walk(v.Cell, func(n gast.Node, entering bool) (gast.WalkStatus, error) { - if !entering || n.Kind() != gast.KindCodeSpan { - return gast.WalkContinue, nil - } - - for c := n.FirstChild(); c != nil; { - next := c.NextSibling() - if c.Kind() != gast.KindText { - c = next - continue - } - parent := c.Parent() - ts := &c.(*gast.Text).Segment - n := c - for _, v := range lst.([]*escapedPipeCell) { - for _, pos := range v.Pos { - if ts.Start <= pos && pos < ts.Stop { - segment := n.(*gast.Text).Segment - n1 := gast.NewRawTextSegment(segment.WithStop(pos)) - n2 := gast.NewRawTextSegment(segment.WithStart(pos + 1)) - parent.InsertAfter(parent, n, n1) - parent.InsertAfter(parent, n1, n2) - parent.RemoveChild(parent, n) - n = n2 - v.Transformed = true - } - } - } - c = next - } - return gast.WalkContinue, nil - }) - } -} - -// TableHTMLRenderer is a renderer.NodeRenderer implementation that -// renders Table nodes. -type TableHTMLRenderer struct { - TableConfig -} - -// NewTableHTMLRenderer returns a new TableHTMLRenderer. -func NewTableHTMLRenderer(opts ...TableOption) renderer.NodeRenderer { - r := &TableHTMLRenderer{ - TableConfig: NewTableConfig(), - } - for _, opt := range opts { - opt.SetTableOption(&r.TableConfig) - } - return r -} - -// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. -func (r *TableHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { - reg.Register(ast.KindTable, r.renderTable) - reg.Register(ast.KindTableHeader, r.renderTableHeader) - reg.Register(ast.KindTableRow, r.renderTableRow) - reg.Register(ast.KindTableCell, r.renderTableCell) -} - -// TableAttributeFilter defines attribute names which table elements can have. -var TableAttributeFilter = html.GlobalAttributeFilter.Extend( - []byte("align"), // [Deprecated] - []byte("bgcolor"), // [Deprecated] - []byte("border"), // [Deprecated] - []byte("cellpadding"), // [Deprecated] - []byte("cellspacing"), // [Deprecated] - []byte("frame"), // [Deprecated] - []byte("rules"), // [Deprecated] - []byte("summary"), // [Deprecated] - []byte("width"), // [Deprecated] -) - -func (r *TableHTMLRenderer) renderTable(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { - if entering { - _, _ = w.WriteString("\n") - } else { - _, _ = w.WriteString("\n") - } - return gast.WalkContinue, nil -} - -// TableHeaderAttributeFilter defines attribute names which elements can have. -var TableHeaderAttributeFilter = html.GlobalAttributeFilter.Extend( - []byte("align"), // [Deprecated since HTML4] [Obsolete since HTML5] - []byte("bgcolor"), // [Not Standardized] - []byte("char"), // [Deprecated since HTML4] [Obsolete since HTML5] - []byte("charoff"), // [Deprecated since HTML4] [Obsolete since HTML5] - []byte("valign"), // [Deprecated since HTML4] [Obsolete since HTML5] -) - -func (r *TableHTMLRenderer) renderTableHeader(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { - if entering { - _, _ = w.WriteString("\n") - _, _ = w.WriteString("\n") // Header has no separate handle - } else { - _, _ = w.WriteString("\n") - _, _ = w.WriteString("\n") - if n.NextSibling() != nil { - _, _ = w.WriteString("\n") - } - } - return gast.WalkContinue, nil -} - -// TableRowAttributeFilter defines attribute names which elements can have. -var TableRowAttributeFilter = html.GlobalAttributeFilter.Extend( - []byte("align"), // [Obsolete since HTML5] - []byte("bgcolor"), // [Obsolete since HTML5] - []byte("char"), // [Obsolete since HTML5] - []byte("charoff"), // [Obsolete since HTML5] - []byte("valign"), // [Obsolete since HTML5] -) - -func (r *TableHTMLRenderer) renderTableRow(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { - if entering { - _, _ = w.WriteString("\n") - } else { - _, _ = w.WriteString("\n") - if n.Parent().LastChild() == n { - _, _ = w.WriteString("\n") - } - } - return gast.WalkContinue, nil -} - -// TableThCellAttributeFilter defines attribute names which table cells can have. -var TableThCellAttributeFilter = html.GlobalAttributeFilter.Extend( - []byte("abbr"), // [OK] Contains a short abbreviated description of the cell's content [NOT OK in ] - - []byte("align"), // [Obsolete since HTML5] - []byte("axis"), // [Obsolete since HTML5] - []byte("bgcolor"), // [Not Standardized] - []byte("char"), // [Obsolete since HTML5] - []byte("charoff"), // [Obsolete since HTML5] - - []byte("colspan"), // [OK] Number of columns that the cell is to span - []byte("headers"), // [OK] This attribute contains a list of space-separated strings, each corresponding to the id attribute of the elements that apply to this element - - []byte("height"), // [Deprecated since HTML4] [Obsolete since HTML5] - - []byte("rowspan"), // [OK] Number of rows that the cell is to span - []byte("scope"), // [OK] This enumerated attribute defines the cells that the header (defined in the ) element relates to [NOT OK in ] - - []byte("valign"), // [Obsolete since HTML5] - []byte("width"), // [Deprecated since HTML4] [Obsolete since HTML5] -) - -// TableTdCellAttributeFilter defines attribute names which table cells can have. -var TableTdCellAttributeFilter = html.GlobalAttributeFilter.Extend( - []byte("abbr"), // [Obsolete since HTML5] [OK in ] - []byte("align"), // [Obsolete since HTML5] - []byte("axis"), // [Obsolete since HTML5] - []byte("bgcolor"), // [Not Standardized] - []byte("char"), // [Obsolete since HTML5] - []byte("charoff"), // [Obsolete since HTML5] - - []byte("colspan"), // [OK] Number of columns that the cell is to span - []byte("headers"), // [OK] This attribute contains a list of space-separated strings, each corresponding to the id attribute of the elements that apply to this element - - []byte("height"), // [Deprecated since HTML4] [Obsolete since HTML5] - - []byte("rowspan"), // [OK] Number of rows that the cell is to span - - []byte("scope"), // [Obsolete since HTML5] [OK in ] - []byte("valign"), // [Obsolete since HTML5] - []byte("width"), // [Deprecated since HTML4] [Obsolete since HTML5] -) - -func (r *TableHTMLRenderer) renderTableCell(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { - n := node.(*ast.TableCell) - tag := "td" - if n.Parent().Kind() == ast.KindTableHeader { - tag = "th" - } - if entering { - fmt.Fprintf(w, "<%s", tag) - if n.Alignment != ast.AlignNone { - amethod := r.TableConfig.TableCellAlignMethod - if amethod == TableCellAlignDefault { - if r.Config.XHTML { - amethod = TableCellAlignAttribute - } else { - amethod = TableCellAlignStyle - } - } - switch amethod { - case TableCellAlignAttribute: - if _, ok := n.AttributeString("align"); !ok { // Skip align render if overridden - fmt.Fprintf(w, ` align="%s"`, n.Alignment.String()) - } - case TableCellAlignStyle: - v, ok := n.AttributeString("style") - var cob util.CopyOnWriteBuffer - if ok { - cob = util.NewCopyOnWriteBuffer(v.([]byte)) - cob.AppendByte(';') - } - style := fmt.Sprintf("text-align:%s", n.Alignment.String()) - cob.AppendString(style) - n.SetAttributeString("style", cob.Bytes()) - } - } - if n.Attributes() != nil { - if tag == "td" { - html.RenderAttributes(w, n, TableTdCellAttributeFilter) // - } else { - html.RenderAttributes(w, n, TableThCellAttributeFilter) // - } - } - _ = w.WriteByte('>') - } else { - fmt.Fprintf(w, "\n", tag) - } - return gast.WalkContinue, nil -} - -type table struct { - options []TableOption -} - -// Table is an extension that allow you to use GFM tables . -var Table = &table{ - options: []TableOption{}, -} - -// NewTable returns a new extension with given options. -func NewTable(opts ...TableOption) goldmark.Extender { - return &table{ - options: opts, - } -} - -func (e *table) Extend(m goldmark.Markdown) { - m.Parser().AddOptions( - parser.WithParagraphTransformers( - util.Prioritized(NewTableParagraphTransformer(), 200), - ), - parser.WithASTTransformers( - util.Prioritized(defaultTableASTTransformer, 0), - ), - ) - m.Renderer().AddOptions(renderer.WithNodeRenderers( - util.Prioritized(NewTableHTMLRenderer(e.options...), 500), - )) -} diff --git a/vendor/github.com/yuin/goldmark/extension/tasklist.go b/vendor/github.com/yuin/goldmark/extension/tasklist.go deleted file mode 100644 index 1f3e52c..0000000 --- a/vendor/github.com/yuin/goldmark/extension/tasklist.go +++ /dev/null @@ -1,115 +0,0 @@ -package extension - -import ( - "github.com/yuin/goldmark" - gast "github.com/yuin/goldmark/ast" - "github.com/yuin/goldmark/extension/ast" - "github.com/yuin/goldmark/parser" - "github.com/yuin/goldmark/renderer" - "github.com/yuin/goldmark/renderer/html" - "github.com/yuin/goldmark/text" - "github.com/yuin/goldmark/util" - "regexp" -) - -var taskListRegexp = regexp.MustCompile(`^\[([\sxX])\]\s*`) - -type taskCheckBoxParser struct { -} - -var defaultTaskCheckBoxParser = &taskCheckBoxParser{} - -// NewTaskCheckBoxParser returns a new InlineParser that can parse -// checkboxes in list items. -// This parser must take precedence over the parser.LinkParser. -func NewTaskCheckBoxParser() parser.InlineParser { - return defaultTaskCheckBoxParser -} - -func (s *taskCheckBoxParser) Trigger() []byte { - return []byte{'['} -} - -func (s *taskCheckBoxParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node { - // Given AST structure must be like - // - List - // - ListItem : parent.Parent - // - TextBlock : parent - // (current line) - if parent.Parent() == nil || parent.Parent().FirstChild() != parent { - return nil - } - - if _, ok := parent.Parent().(*gast.ListItem); !ok { - return nil - } - line, _ := block.PeekLine() - m := taskListRegexp.FindSubmatchIndex(line) - if m == nil { - return nil - } - value := line[m[2]:m[3]][0] - block.Advance(m[1]) - checked := value == 'x' || value == 'X' - return ast.NewTaskCheckBox(checked) -} - -func (s *taskCheckBoxParser) CloseBlock(parent gast.Node, pc parser.Context) { - // nothing to do -} - -// TaskCheckBoxHTMLRenderer is a renderer.NodeRenderer implementation that -// renders checkboxes in list items. -type TaskCheckBoxHTMLRenderer struct { - html.Config -} - -// NewTaskCheckBoxHTMLRenderer returns a new TaskCheckBoxHTMLRenderer. -func NewTaskCheckBoxHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { - r := &TaskCheckBoxHTMLRenderer{ - Config: html.NewConfig(), - } - for _, opt := range opts { - opt.SetHTMLOption(&r.Config) - } - return r -} - -// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. -func (r *TaskCheckBoxHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { - reg.Register(ast.KindTaskCheckBox, r.renderTaskCheckBox) -} - -func (r *TaskCheckBoxHTMLRenderer) renderTaskCheckBox(w util.BufWriter, source []byte, node gast.Node, entering bool) (gast.WalkStatus, error) { - if !entering { - return gast.WalkContinue, nil - } - n := node.(*ast.TaskCheckBox) - - if n.IsChecked { - w.WriteString(` ") - } else { - w.WriteString("> ") - } - return gast.WalkContinue, nil -} - -type taskList struct { -} - -// TaskList is an extension that allow you to use GFM task lists. -var TaskList = &taskList{} - -func (e *taskList) Extend(m goldmark.Markdown) { - m.Parser().AddOptions(parser.WithInlineParsers( - util.Prioritized(NewTaskCheckBoxParser(), 0), - )) - m.Renderer().AddOptions(renderer.WithNodeRenderers( - util.Prioritized(NewTaskCheckBoxHTMLRenderer(), 500), - )) -} diff --git a/vendor/github.com/yuin/goldmark/extension/typographer.go b/vendor/github.com/yuin/goldmark/extension/typographer.go deleted file mode 100644 index f56c06f..0000000 --- a/vendor/github.com/yuin/goldmark/extension/typographer.go +++ /dev/null @@ -1,339 +0,0 @@ -package extension - -import ( - "unicode" - - "github.com/yuin/goldmark" - gast "github.com/yuin/goldmark/ast" - "github.com/yuin/goldmark/parser" - "github.com/yuin/goldmark/text" - "github.com/yuin/goldmark/util" -) - -var uncloseCounterKey = parser.NewContextKey() - -type unclosedCounter struct { - Single int - Double int -} - -func (u *unclosedCounter) Reset() { - u.Single = 0 - u.Double = 0 -} - -func getUnclosedCounter(pc parser.Context) *unclosedCounter { - v := pc.Get(uncloseCounterKey) - if v == nil { - v = &unclosedCounter{} - pc.Set(uncloseCounterKey, v) - } - return v.(*unclosedCounter) -} - -// TypographicPunctuation is a key of the punctuations that can be replaced with -// typographic entities. -type TypographicPunctuation int - -const ( - // LeftSingleQuote is ' - LeftSingleQuote TypographicPunctuation = iota + 1 - // RightSingleQuote is ' - RightSingleQuote - // LeftDoubleQuote is " - LeftDoubleQuote - // RightDoubleQuote is " - RightDoubleQuote - // EnDash is -- - EnDash - // EmDash is --- - EmDash - // Ellipsis is ... - Ellipsis - // LeftAngleQuote is << - LeftAngleQuote - // RightAngleQuote is >> - RightAngleQuote - // Apostrophe is ' - Apostrophe - - typographicPunctuationMax -) - -// An TypographerConfig struct is a data structure that holds configuration of the -// Typographer extension. -type TypographerConfig struct { - Substitutions [][]byte -} - -func newDefaultSubstitutions() [][]byte { - replacements := make([][]byte, typographicPunctuationMax) - replacements[LeftSingleQuote] = []byte("‘") - replacements[RightSingleQuote] = []byte("’") - replacements[LeftDoubleQuote] = []byte("“") - replacements[RightDoubleQuote] = []byte("”") - replacements[EnDash] = []byte("–") - replacements[EmDash] = []byte("—") - replacements[Ellipsis] = []byte("…") - replacements[LeftAngleQuote] = []byte("«") - replacements[RightAngleQuote] = []byte("»") - replacements[Apostrophe] = []byte("’") - - return replacements -} - -// SetOption implements SetOptioner. -func (b *TypographerConfig) SetOption(name parser.OptionName, value interface{}) { - switch name { - case optTypographicSubstitutions: - b.Substitutions = value.([][]byte) - } -} - -// A TypographerOption interface sets options for the TypographerParser. -type TypographerOption interface { - parser.Option - SetTypographerOption(*TypographerConfig) -} - -const optTypographicSubstitutions parser.OptionName = "TypographicSubstitutions" - -// TypographicSubstitutions is a list of the substitutions for the Typographer extension. -type TypographicSubstitutions map[TypographicPunctuation][]byte - -type withTypographicSubstitutions struct { - value [][]byte -} - -func (o *withTypographicSubstitutions) SetParserOption(c *parser.Config) { - c.Options[optTypographicSubstitutions] = o.value -} - -func (o *withTypographicSubstitutions) SetTypographerOption(p *TypographerConfig) { - p.Substitutions = o.value -} - -// WithTypographicSubstitutions is a functional otpion that specify replacement text -// for punctuations. -func WithTypographicSubstitutions(values map[TypographicPunctuation][]byte) TypographerOption { - replacements := newDefaultSubstitutions() - for k, v := range values { - replacements[k] = v - } - - return &withTypographicSubstitutions{replacements} -} - -type typographerDelimiterProcessor struct { -} - -func (p *typographerDelimiterProcessor) IsDelimiter(b byte) bool { - return b == '\'' || b == '"' -} - -func (p *typographerDelimiterProcessor) CanOpenCloser(opener, closer *parser.Delimiter) bool { - return opener.Char == closer.Char -} - -func (p *typographerDelimiterProcessor) OnMatch(consumes int) gast.Node { - return nil -} - -var defaultTypographerDelimiterProcessor = &typographerDelimiterProcessor{} - -type typographerParser struct { - TypographerConfig -} - -// NewTypographerParser return a new InlineParser that parses -// typographer expressions. -func NewTypographerParser(opts ...TypographerOption) parser.InlineParser { - p := &typographerParser{ - TypographerConfig: TypographerConfig{ - Substitutions: newDefaultSubstitutions(), - }, - } - for _, o := range opts { - o.SetTypographerOption(&p.TypographerConfig) - } - return p -} - -func (s *typographerParser) Trigger() []byte { - return []byte{'\'', '"', '-', '.', ',', '<', '>', '*', '['} -} - -func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node { - line, _ := block.PeekLine() - c := line[0] - if len(line) > 2 { - if c == '-' { - if s.Substitutions[EmDash] != nil && line[1] == '-' && line[2] == '-' { // --- - node := gast.NewString(s.Substitutions[EmDash]) - node.SetCode(true) - block.Advance(3) - return node - } - } else if c == '.' { - if s.Substitutions[Ellipsis] != nil && line[1] == '.' && line[2] == '.' { // ... - node := gast.NewString(s.Substitutions[Ellipsis]) - node.SetCode(true) - block.Advance(3) - return node - } - return nil - } - } - if len(line) > 1 { - if c == '<' { - if s.Substitutions[LeftAngleQuote] != nil && line[1] == '<' { // << - node := gast.NewString(s.Substitutions[LeftAngleQuote]) - node.SetCode(true) - block.Advance(2) - return node - } - return nil - } else if c == '>' { - if s.Substitutions[RightAngleQuote] != nil && line[1] == '>' { // >> - node := gast.NewString(s.Substitutions[RightAngleQuote]) - node.SetCode(true) - block.Advance(2) - return node - } - return nil - } else if s.Substitutions[EnDash] != nil && c == '-' && line[1] == '-' { // -- - node := gast.NewString(s.Substitutions[EnDash]) - node.SetCode(true) - block.Advance(2) - return node - } - } - if c == '\'' || c == '"' { - before := block.PrecendingCharacter() - d := parser.ScanDelimiter(line, before, 1, defaultTypographerDelimiterProcessor) - if d == nil { - return nil - } - counter := getUnclosedCounter(pc) - if c == '\'' { - if s.Substitutions[Apostrophe] != nil { - // Handle decade abbrevations such as '90s - if d.CanOpen && !d.CanClose && len(line) > 3 && util.IsNumeric(line[1]) && util.IsNumeric(line[2]) && line[3] == 's' { - after := rune(' ') - if len(line) > 4 { - after = util.ToRune(line, 4) - } - if len(line) == 3 || util.IsSpaceRune(after) || util.IsPunctRune(after) { - node := gast.NewString(s.Substitutions[Apostrophe]) - node.SetCode(true) - block.Advance(1) - return node - } - } - // special cases: 'twas, 'em, 'net - if len(line) > 1 && (unicode.IsPunct(before) || unicode.IsSpace(before)) && (line[1] == 't' || line[1] == 'e' || line[1] == 'n' || line[1] == 'l') { - node := gast.NewString(s.Substitutions[Apostrophe]) - node.SetCode(true) - block.Advance(1) - return node - } - // Convert normal apostrophes. This is probably more flexible than necessary but - // converts any apostrophe in between two alphanumerics. - if len(line) > 1 && (unicode.IsDigit(before) || unicode.IsLetter(before)) && (unicode.IsLetter(util.ToRune(line, 1))) { - node := gast.NewString(s.Substitutions[Apostrophe]) - node.SetCode(true) - block.Advance(1) - return node - } - } - if s.Substitutions[LeftSingleQuote] != nil && d.CanOpen && !d.CanClose { - nt := LeftSingleQuote - // special cases: Alice's, I'm, Don't, You'd - if len(line) > 1 && (line[1] == 's' || line[1] == 'm' || line[1] == 't' || line[1] == 'd') && (len(line) < 3 || util.IsPunct(line[2]) || util.IsSpace(line[2])) { - nt = RightSingleQuote - } - // special cases: I've, I'll, You're - if len(line) > 2 && ((line[1] == 'v' && line[2] == 'e') || (line[1] == 'l' && line[2] == 'l') || (line[1] == 'r' && line[2] == 'e')) && (len(line) < 4 || util.IsPunct(line[3]) || util.IsSpace(line[3])) { - nt = RightSingleQuote - } - if nt == LeftSingleQuote { - counter.Single++ - } - - node := gast.NewString(s.Substitutions[nt]) - node.SetCode(true) - block.Advance(1) - return node - } - if s.Substitutions[RightSingleQuote] != nil { - // plural possesives and abbreviations: Smiths', doin' - if len(line) > 1 && unicode.IsSpace(util.ToRune(line, 0)) || unicode.IsPunct(util.ToRune(line, 0)) && (len(line) > 2 && !unicode.IsDigit(util.ToRune(line, 1))) { - node := gast.NewString(s.Substitutions[RightSingleQuote]) - node.SetCode(true) - block.Advance(1) - return node - } - } - if s.Substitutions[RightSingleQuote] != nil && counter.Single > 0 { - isClose := d.CanClose && !d.CanOpen - maybeClose := d.CanClose && d.CanOpen && len(line) > 1 && unicode.IsPunct(util.ToRune(line, 1)) && (len(line) == 2 || (len(line) > 2 && util.IsPunct(line[2]) || util.IsSpace(line[2]))) - if isClose || maybeClose { - node := gast.NewString(s.Substitutions[RightSingleQuote]) - node.SetCode(true) - block.Advance(1) - counter.Single-- - return node - } - } - } - if c == '"' { - if s.Substitutions[LeftDoubleQuote] != nil && d.CanOpen && !d.CanClose { - node := gast.NewString(s.Substitutions[LeftDoubleQuote]) - node.SetCode(true) - block.Advance(1) - counter.Double++ - return node - } - if s.Substitutions[RightDoubleQuote] != nil && counter.Double > 0 { - isClose := d.CanClose && !d.CanOpen - maybeClose := d.CanClose && d.CanOpen && len(line) > 1 && (unicode.IsPunct(util.ToRune(line, 1))) && (len(line) == 2 || (len(line) > 2 && util.IsPunct(line[2]) || util.IsSpace(line[2]))) - if isClose || maybeClose { - // special case: "Monitor 21"" - if len(line) > 1 && line[1] == '"' && unicode.IsDigit(before) { - return nil - } - node := gast.NewString(s.Substitutions[RightDoubleQuote]) - node.SetCode(true) - block.Advance(1) - counter.Double-- - return node - } - } - } - } - return nil -} - -func (s *typographerParser) CloseBlock(parent gast.Node, pc parser.Context) { - getUnclosedCounter(pc).Reset() -} - -type typographer struct { - options []TypographerOption -} - -// Typographer is an extension that replaces punctuations with typographic entities. -var Typographer = &typographer{} - -// NewTypographer returns a new Extender that replaces punctuations with typographic entities. -func NewTypographer(opts ...TypographerOption) goldmark.Extender { - return &typographer{ - options: opts, - } -} - -func (e *typographer) Extend(m goldmark.Markdown) { - m.Parser().AddOptions(parser.WithInlineParsers( - util.Prioritized(NewTypographerParser(e.options...), 9999), - )) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 0bef97d..58e97e4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -2,7 +2,6 @@ ## explicit; go 1.18 github.com/yuin/goldmark github.com/yuin/goldmark/ast -github.com/yuin/goldmark/extension github.com/yuin/goldmark/extension/ast github.com/yuin/goldmark/parser github.com/yuin/goldmark/renderer