From 26fb0b56e6c4f97b3245323a0553f5aff0b8d1b7 Mon Sep 17 00:00:00 2001 From: yuin Date: Wed, 18 Dec 2019 15:46:54 +0900 Subject: [PATCH] Fixes gohugoio/hugo#6626 --- README.md | 77 +++++++++++++++++++++++++++++++++++---------- _test/extra.txt | 8 +++++ parser/delimiter.go | 21 +++++++------ 3 files changed, 81 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index d98ba47..9e61344 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,15 @@ if err := goldmark.Convert(source, &buf, parser.WithContext(ctx)); err != nil { | Functional option | Type | Description | | ----------------- | ---- | ----------- | -| `parser.WithContext` | A parser.Context | Context for the parsing phase. | +| `parser.WithContext` | A `parser.Context` | Context for the parsing phase. | + +Context options +---------------------- + +| Functional option | Type | Description | +| ----------------- | ---- | ----------- | +| `parser.WithIDs` | A `parser.IDs` | `IDs` allows you to change logics that are related to element id(ex: Auto heading id generation). | + Custom parser and renderer -------------------------- @@ -130,6 +138,7 @@ Parser and Renderer options | `parser.WithBlockParsers` | A `util.PrioritizedSlice` whose elements are `parser.BlockParser` | Parsers for parsing block level elements. | | `parser.WithInlineParsers` | A `util.PrioritizedSlice` whose elements are `parser.InlineParser` | Parsers for parsing inline level elements. | | `parser.WithParagraphTransformers` | A `util.PrioritizedSlice` whose elements are `parser.ParagraphTransformer` | Transformers for transforming paragraph nodes. | +| `parser.WithASTTransformers` | A `util.PrioritizedSlice` whose elements are `parser.ASTTransformer` | Transformers for transforming an AST. | | `parser.WithAutoHeadingID` | `-` | Enables auto heading ids. | | `parser.WithAttribute` | `-` | Enables custom attributes. Currently only headings supports attributes. | @@ -217,21 +226,6 @@ markdown := goldmark.New( ) ``` - - -Create extensions --------------------- -**TODO** - -See `extension` directory for examples of extensions. - -Summary: - -1. Define AST Node as a struct in which `ast.BaseBlock` or `ast.BaseInline` is embedded. -2. Write a parser that implements `parser.BlockParser` or `parser.InlineParser`. -3. Write a renderer that implements `renderer.NodeRenderer`. -4. Define your goldmark extension that implements `goldmark.Extender`. - Security -------------------- By default, goldmark does not render raw HTML and potentially dangerous URLs. @@ -285,6 +279,57 @@ Extensions for the goldmark markdown parser. - [goldmark-mathjax](https://github.com/litao91/goldmark-mathjax): Mathjax support for goldmark markdown parser +goldmark internal(for extension developers) +---------------------------------------------- +### Overview +goldmark's Markdown processing is outlined as a bellow diagram. + +``` + + | + V + +-------- parser.Parser --------------------------- + | 1. Parse block elements into AST + | 1. If a parsed block is a paragraph, apply + | ast.ParagraphTransformer + | 2. Traverse AST and parse blocks. + | 1. Process delimiters(emphasis) at the end of + | block parsing + | 3. Apply parser.ASTTransformers to AST + | + V + + | + V + +------- renderer.Renderer ------------------------ + | 1. Traverse AST and apply renderer.NodeRenderer + | corespond to the node type + + | + V + +``` + +### Parsing +Markdown documents are read through `text.Reader` interface. + +AST nodes do not have concrete text. AST nodes have segment information of the documents. It is represented by `text.Segment` . + +`text.Segment` has 3 attributes: `Start`, `End`, `Padding` . + + +**TODO** + +See `extension` directory for examples of extensions. + +Summary: + +1. Define AST Node as a struct in which `ast.BaseBlock` or `ast.BaseInline` is embedded. +2. Write a parser that implements `parser.BlockParser` or `parser.InlineParser`. +3. Write a renderer that implements `renderer.NodeRenderer`. +4. Define your goldmark extension that implements `goldmark.Extender`. + + Donation -------------------- BTC: 1NEDSyUmo4SMTDP83JJQSWi1MvQUGGNMZB diff --git a/_test/extra.txt b/_test/extra.txt index 74ac61f..c0472de 100644 --- a/_test/extra.txt +++ b/_test/extra.txt @@ -55,3 +55,11 @@ testtest

testatest

//= = = = = = = = = = = = = = = = = = = = = = = =// + + +5 +//- - - - - - - - -// +_**TL/DR** - [Go see summary.](#my-summary-area)_ +//- - - - - - - - -// +

TL/DR - Go see summary.

+//= = = = = = = = = = = = = = = = = = = = = = = =// diff --git a/parser/delimiter.go b/parser/delimiter.go index 0cdaab3..50aa7bd 100644 --- a/parser/delimiter.go +++ b/parser/delimiter.go @@ -156,20 +156,23 @@ func ScanDelimiter(line []byte, before rune, min int, processor DelimiterProcess // If you implement an inline parser that can have other inline nodes as // children, you should call this function when nesting span has closed. func ProcessDelimiters(bottom ast.Node, pc Context) { - if pc.LastDelimiter() == nil { + lastDelimiter := pc.LastDelimiter() + if lastDelimiter == nil { return } var closer *Delimiter if bottom != nil { - for c := pc.LastDelimiter().PreviousSibling(); c != nil; { - if d, ok := c.(*Delimiter); ok { - closer = d - } - prev := c.PreviousSibling() - if prev == bottom { - break + if bottom != lastDelimiter { + for c := lastDelimiter.PreviousSibling(); c != nil; { + if d, ok := c.(*Delimiter); ok { + closer = d + } + prev := c.PreviousSibling() + if prev == bottom { + break + } + c = prev } - c = prev } } else { closer = pc.FirstDelimiter()