mirror of
https://github.com/yuin/goldmark
synced 2025-03-04 23:04:52 +00:00
Fix some vet errors, Improve attributes on ATXHeadings
This commit is contained in:
parent
e481813300
commit
1963434c50
10 changed files with 2190 additions and 2153 deletions
21
LICENSE
Normal file
21
LICENSE
Normal 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.
|
||||||
|
|
@ -4,6 +4,7 @@ goldmark
|
||||||
[](http://godoc.org/github.com/yuin/goldmark)
|
[](http://godoc.org/github.com/yuin/goldmark)
|
||||||
[](https://travis-ci.org/yuin/goldmark)
|
[](https://travis-ci.org/yuin/goldmark)
|
||||||
[](https://coveralls.io/r/yuin/goldmark)
|
[](https://coveralls.io/r/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"}
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
16
util/util.go
16
util/util.go
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue