Fix some vet errors, Improve attributes on ATXHeadings

This commit is contained in:
yuin 2019-05-16 12:37:49 +09:00
parent e481813300
commit 1963434c50
10 changed files with 2190 additions and 2153 deletions

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Yusuke Inuzuka
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -4,6 +4,7 @@ goldmark
[![http://godoc.org/github.com/yuin/goldmark](https://godoc.org/github.com/yuin/goldmark?status.svg)](http://godoc.org/github.com/yuin/goldmark) [![http://godoc.org/github.com/yuin/goldmark](https://godoc.org/github.com/yuin/goldmark?status.svg)](http://godoc.org/github.com/yuin/goldmark)
[![https://travis-ci.org/yuin/goldmark](https://travis-ci.org/yuin/goldmark.svg)](https://travis-ci.org/yuin/goldmark) [![https://travis-ci.org/yuin/goldmark](https://travis-ci.org/yuin/goldmark.svg)](https://travis-ci.org/yuin/goldmark)
[![https://coveralls.io/r/yuin/goldmark](https://coveralls.io/repos/yuin/goldmark/badge.svg)](https://coveralls.io/r/yuin/goldmark) [![https://coveralls.io/r/yuin/goldmark](https://coveralls.io/repos/yuin/goldmark/badge.svg)](https://coveralls.io/r/yuin/goldmark)
[![https://goreportcard.com/report/github.com/yuin/goldmark](https://goreportcard.com/badge/github.com/yuin/goldmark)](https://goreportcard.com/report/github.com/yuin/goldmark)
> A markdown parser written in Go. Easy to extend, standard compliant, well structured. > A markdown parser written in Go. Easy to extend, standard compliant, well structured.
@ -128,10 +129,17 @@ Parser and Renderer options
Currently only headings support attributes. Currently only headings support attributes.
**Attributes are being discussed in the
[CommonMark fourum](https://talk.commonmark.org/t/consistent-attribute-syntax/272).
This syntax possibly changes in the future. **
#### Headings #### Headings
``` ```
## heading ## {#id .className attrName=attrValue class="class1 class2"} ## heading ## {#id .className attrName=attrValue class="class1 class2"}
## heading {#id .className attrName=attrValue class="class1 class2"}
``` ```
``` ```

View file

@ -167,10 +167,14 @@ func (b *atxHeadingParser) Continue(node ast.Node, reader text.Reader, pc Contex
} }
func (b *atxHeadingParser) Close(node ast.Node, reader text.Reader, pc Context) { func (b *atxHeadingParser) Close(node ast.Node, reader text.Reader, pc Context) {
if !b.AutoHeadingID { if b.Attribute {
return _, ok := node.AttributeString("id")
if !ok {
parseLastLineAttributes(node, reader, pc)
} }
if !b.Attribute { }
if b.AutoHeadingID {
_, ok := node.AttributeString("id") _, ok := node.AttributeString("id")
if !ok { if !ok {
generateAutoHeadingID(node.(*ast.Heading), reader, pc) generateAutoHeadingID(node.(*ast.Heading), reader, pc)
@ -196,3 +200,18 @@ func generateAutoHeadingID(node *ast.Heading, reader text.Reader, pc Context) {
headingID := pc.IDs().Generate(line, attrAutoHeadingIDPrefix) headingID := pc.IDs().Generate(line, attrAutoHeadingIDPrefix)
node.SetAttribute(attrNameID, headingID) node.SetAttribute(attrNameID, headingID)
} }
func parseLastLineAttributes(node ast.Node, reader text.Reader, pc Context) {
lastIndex := node.Lines().Len() - 1
lastLine := node.Lines().At(lastIndex)
line := lastLine.Value(reader.Source())
indicies := util.FindAttributeIndiciesReverse(line, true)
if indicies != nil {
for _, index := range indicies {
node.SetAttribute(line[index[0]:index[1]], line[index[2]:index[3]])
}
lastLine.Stop = lastLine.Start + indicies[0][0] - 1
lastLine.TrimRightSpace(reader.Source())
node.Lines().Set(lastIndex, lastLine)
}
}

View file

@ -106,7 +106,7 @@ var defaultListParser = &listParser{}
// NewListParser returns a new BlockParser that // NewListParser returns a new BlockParser that
// parses lists. // parses lists.
// This parser must take predecence over the ListItemParser. // This parser must take precedence over the ListItemParser.
func NewListParser() BlockParser { func NewListParser() BlockParser {
return defaultListParser return defaultListParser
} }
@ -157,7 +157,7 @@ func (b *listParser) Continue(node ast.Node, reader text.Reader, pc Context) Sta
} }
return Continue | HasChildren return Continue | HasChildren
} }
// Themantic Breaks take predecence over lists // Themantic Breaks take precedence over lists
if isThemanticBreak(line) { if isThemanticBreak(line) {
isHeading := false isHeading := false
last := pc.LastOpenedBlock().Node last := pc.LastOpenedBlock().Node

View file

@ -114,7 +114,7 @@ func (s *ids) Put(value []byte) {
s.values[util.BytesToReadOnlyString(value)] = true s.values[util.BytesToReadOnlyString(value)] = true
} }
// ContextKey is a key that is used to set arbitary values to the context. // ContextKey is a key that is used to set arbitrary values to the context.
type ContextKey int type ContextKey int
// ContextKeyMax is a maximum value of the ContextKey. // ContextKeyMax is a maximum value of the ContextKey.
@ -629,7 +629,7 @@ func (o *withOption) SetParserOption(c *Config) {
} }
// WithOption is a functional option that allow you to set // WithOption is a functional option that allow you to set
// an arbitary option to the parser. // an arbitrary option to the parser.
func WithOption(name OptionName, value interface{}) Option { func WithOption(name OptionName, value interface{}) Option {
return &withOption{name, value} return &withOption{name, value}
} }

View file

@ -97,18 +97,7 @@ func (b *setextHeadingParser) Close(node ast.Node, reader text.Reader, pc Contex
} }
if b.Attribute { if b.Attribute {
lastIndex := node.Lines().Len() - 1 parseLastLineAttributes(node, reader, pc)
lastLine := node.Lines().At(lastIndex)
line := lastLine.Value(reader.Source())
indicies := util.FindAttributeIndiciesReverse(line, true)
if indicies != nil {
for _, index := range indicies {
node.SetAttribute(line[index[0]:index[1]], line[index[2]:index[3]])
}
lastLine.Stop = lastLine.Start + indicies[0][0] - 1
lastLine.TrimRightSpace(reader.Source())
node.Lines().Set(lastIndex, lastLine)
}
} }
if b.AutoHeadingID { if b.AutoHeadingID {

View file

@ -608,7 +608,7 @@ func (d *defaultWriter) Write(writer util.BufWriter, source []byte) {
} }
escaped = false escaped = false
} }
d.RawWrite(writer, source[n:len(source)]) d.RawWrite(writer, source[n:])
} }
// DefaultWriter is a default implementation of the Writer. // DefaultWriter is a default implementation of the Writer.

View file

@ -57,7 +57,7 @@ func (o *withOption) SetConfig(c *Config) {
} }
// WithOption is a functional option that allow you to set // WithOption is a functional option that allow you to set
// an arbitary option to the parser. // an arbitrary option to the parser.
func WithOption(name OptionName, value interface{}) Option { func WithOption(name OptionName, value interface{}) Option {
return &withOption{name, value} return &withOption{name, value}
} }

File diff suppressed because it is too large Load diff

View file

@ -411,7 +411,7 @@ func EscapeHTML(v []byte) []byte {
} }
} }
if cob.IsCopied() { if cob.IsCopied() {
cob.Write(v[n:len(v)]) cob.Write(v[n:])
} }
return cob.Bytes() return cob.Bytes()
} }
@ -433,7 +433,7 @@ func UnescapePunctuations(source []byte) []byte {
i++ i++
} }
if cob.IsCopied() { if cob.IsCopied() {
cob.Write(source[n:len(source)]) cob.Write(source[n:])
} }
return cob.Bytes() return cob.Bytes()
} }
@ -482,7 +482,7 @@ func ResolveNumericReferences(source []byte) []byte {
} }
} }
if cob.IsCopied() { if cob.IsCopied() {
cob.Write(source[n:len(source)]) cob.Write(source[n:])
} }
return cob.Bytes() return cob.Bytes()
} }
@ -515,7 +515,7 @@ func ResolveEntityNames(source []byte) []byte {
} }
} }
if cob.IsCopied() { if cob.IsCopied() {
cob.Write(source[n:len(source)]) cob.Write(source[n:])
} }
return cob.Bytes() return cob.Bytes()
} }
@ -567,7 +567,7 @@ func URLEscape(v []byte, resolveReference bool) []byte {
n = i n = i
} }
if cob.IsCopied() { if cob.IsCopied() {
cob.Write(v[n:len(v)]) cob.Write(v[n:])
} }
return cob.Bytes() return cob.Bytes()
} }
@ -612,7 +612,7 @@ retry:
goto retry goto retry
} }
// FindAttributeIndex searchs // FindAttributeIndex searches
// - #id // - #id
// - .class // - .class
// - attr=value // - attr=value
@ -858,9 +858,9 @@ type BufWriter interface {
WriteString(s string) (int, error) WriteString(s string) (int, error)
} }
// A PrioritizedValue struct holds pair of an arbitary value and a priority. // A PrioritizedValue struct holds pair of an arbitrary value and a priority.
type PrioritizedValue struct { type PrioritizedValue struct {
// Value is an arbitary value that you want to prioritize. // Value is an arbitrary value that you want to prioritize.
Value interface{} Value interface{}
// Priority is a priority of the value. // Priority is a priority of the value.
Priority int Priority int