diff --git a/zbook_backend/markdown/admonition/extend.go b/zbook_backend/markdown/admonition/extend.go index 8fce607..0abb3f5 100644 --- a/zbook_backend/markdown/admonition/extend.go +++ b/zbook_backend/markdown/admonition/extend.go @@ -7,40 +7,49 @@ import ( "github.com/yuin/goldmark/util" ) -// This extender allows you to use admonitions in markdown +// Extender allows you to use admonitions in markdown with different triggers. // -// Admonitions are a markdown extension that allows you to style markdown as -// nice boxes with a title. This is done by way of wrapping other elements in -// divs with classes starting with "adm-" +// Admonitions are a markdown extension that styles markdown as +// boxes with titles, triggered by characters like '!' or '?' // // !!!note This is the title {.some-additional-class} -// This is the admonition +// This is the admonition content // -// ## with a header +// Example with a different trigger: +// ???note Another type of admonition // -// !!!danger Nesting is possible! -// ```R -// X <- as.data.table(iris) -// X[Species != "virginica", mean(Sepal.Length), Species] -// ``` -// !!! -// !!! +// You can now pass multiple trigger characters to support different +// types of admonitions. type Extender struct { - priority int // optional int != 0. the priority value for parser and renderer. Defaults to 100. + priority int // optional int != 0. the priority value for parser and renderer. Defaults to 100. + triggerChars []byte // list of trigger characters (e.g., '!', '?') } -// This implements the Extend method for goldmark-admonitions.Extender +// NewExtender creates an Extender with specified trigger characters and priority. +func NewExtender(priority int, triggerChars []byte) *Extender { + return &Extender{ + priority: priority, + triggerChars: triggerChars, + } +} + +// Extend adds block parsers and node renderers to the markdown instance. func (e *Extender) Extend(md goldmark.Markdown) { priority := 100 - if e.priority != 0 { priority = e.priority } - md.Parser().AddOptions( - parser.WithBlockParsers( - util.Prioritized(&admonitionParser{}, priority), - ), - ) + + // Add a parser for each trigger character + for _, char := range e.triggerChars { + md.Parser().AddOptions( + parser.WithBlockParsers( + util.Prioritized(NewAdmonitionParser(char), priority), + ), + ) + } + + // Add the renderer md.Renderer().AddOptions( renderer.WithNodeRenderers( util.Prioritized(&Renderer{}, priority), diff --git a/zbook_backend/markdown/admonition/parser.go b/zbook_backend/markdown/admonition/parser.go index dd69eac..5562743 100644 --- a/zbook_backend/markdown/admonition/parser.go +++ b/zbook_backend/markdown/admonition/parser.go @@ -11,21 +11,21 @@ import ( ) type admonitionParser struct { + triggerChar byte // The character that triggers the admonition, e.g., '!' or '?' } -var defaultAdmonitionParser = &admonitionParser{} - -// NewAdmonitionParser returns a new BlockParser that -// parses admonition blocks. -func NewAdmonitionParser() parser.BlockParser { - return defaultAdmonitionParser +// NewAdmonitionParser creates a new admonition parser with a specified trigger character. +func NewAdmonitionParser(char byte) parser.BlockParser { + return &admonitionParser{ + triggerChar: char, + } } type admonitionData struct { ID string // The ID of the admonition. This enables nested admonitions with indentation - char byte // Currently, this is always "!" + char byte // Trigger character, e.g., '!' or '?' indent int // The indentation of the opening (and closing) tags (!!!{}) - length int // The length of the admonition, e.g. is it !!! or !!!!? + length int // The length of the admonition, e.g. is it !!! or ??? node ast.Node // The node of the admonition contentIndent int // The indentation of the content relative to the previous admonition block. The first line of the content is taken as its indentation. If you want an admonition with just a code block you need to use backticks contentHasStarted bool // Only used as an indicator if contentIndent has been set already @@ -34,13 +34,13 @@ type admonitionData struct { var admonitionInfoKey = parser.NewContextKey() func (b *admonitionParser) Trigger() []byte { - return []byte{'!'} + return []byte{b.triggerChar} } func (b *admonitionParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) { line, _ := reader.PeekLine() pos := pc.BlockOffset() - if pos < 0 || line[pos] != '!' { + if pos < 0 || line[pos] != b.triggerChar { return nil, parser.NoChildren } findent := pos @@ -108,6 +108,12 @@ func (b *admonitionParser) Open(parent ast.Node, reader text.Reader, pc parser.C if close, _ := hasClosingTag(line, w, pos, fdata); w < fdata.indent || close { return node, parser.NoChildren } + indentClose := + !util.IsBlank(line) && + (w < fdata.indent || (w == fdata.indent && w <= fdata.contentIndent)) // mydebug:warning,这里w < fdata.contentIndent 修改添加= + if indentClose { + return node, parser.NoChildren + } return node, parser.HasChildren } diff --git a/zbook_backend/markdown/render/config.go b/zbook_backend/markdown/render/config.go index 150def7..9a818ce 100644 --- a/zbook_backend/markdown/render/config.go +++ b/zbook_backend/markdown/render/config.go @@ -1,7 +1,6 @@ package render import ( - // admonitions "github.com/stefanfritsch/goldmark-admonitions" "github.com/yuin/goldmark" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/parser" @@ -23,7 +22,7 @@ func GetMarkdownConfig() goldmark.Markdown { ), goldmark.WithExtensions(extension.GFM), goldmark.WithExtensions( - &admonitions.Extender{}, + admonitions.NewExtender(100, []byte{'!', '?'}), ), goldmark.WithExtensions(extension.NewCJK(extension.WithEastAsianLineBreaks(), extension.WithEscapedSpace())), goldmark.WithExtensions(