From 484f988f32cb91a8502e26fc1d03f5e86edaee11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20R=C3=BCger?= Date: Fri, 19 May 2023 18:47:55 +0200 Subject: [PATCH] Move drop-h1 to the renderer This is more reliable than a regular expression. --- README.md | 2 +- main.go | 8 +++--- pkg/mark/markdown.go | 53 +++++++++++++++++++++++++++------------ pkg/mark/markdown_test.go | 2 +- 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 599b497..206fc0e 100644 --- a/README.md +++ b/README.md @@ -667,7 +667,7 @@ GLOBAL OPTIONS: --compile-only show resulting HTML and don't update Confluence page content. (default: false) [$MARK_COMPILE_ONLY] --dry-run resolve page and ancestry, show resulting HTML and exit. (default: false) [$MARK_DRY_RUN] --edit-lock, -k lock page editing to current user only to prevent accidental manual edits over Confluence Web UI. (default: false) [$MARK_EDIT_LOCK] - --drop-h1, --h1_drop don't include H1 headings in Confluence output. (default: false) [$MARK_H1_DROP] + --drop-h1, --h1_drop don't include the first H1 heading in Confluence output. (default: false) [$MARK_H1_DROP] --title-from-h1, --h1_title extract page title from a leading H1 heading. If no H1 heading on a page exists, then title must be set in the page metadata. (default: false) [$MARK_H1_TITLE] --minor-edit don't send notifications while updating Confluence page. (default: false) [$MARK_MINOR_EDIT] --color value display logs in color. Possible values: auto, never. (default: "auto") [$MARK_COLOR] diff --git a/main.go b/main.go index ab32b98..b6d8d0a 100644 --- a/main.go +++ b/main.go @@ -58,7 +58,7 @@ var flags = []cli.Flag{ Name: "drop-h1", Value: false, Aliases: []string{"h1_drop"}, - Usage: "don't include H1 headings in Confluence output.", + Usage: "don't include the first H1 heading in Confluence output.", EnvVars: []string{"MARK_H1_DROP"}, }), altsrc.NewBoolFlag(&cli.BoolFlag{ @@ -361,10 +361,9 @@ func processFile( log.Info( "the leading H1 heading will be excluded from the Confluence output", ) - markdown = mark.DropDocumentLeadingH1(markdown) } - html, _ := mark.CompileMarkdown(markdown, stdlib, file, cCtx.String("mermaid-provider")) + html, _ := mark.CompileMarkdown(markdown, stdlib, file, cCtx.String("mermaid-provider"), cCtx.Bool("drop-h1")) fmt.Println(html) os.Exit(0) } @@ -438,10 +437,9 @@ func processFile( log.Info( "the leading H1 heading will be excluded from the Confluence output", ) - markdown = mark.DropDocumentLeadingH1(markdown) } - html, inlineAttachments := mark.CompileMarkdown(markdown, stdlib, file, cCtx.String("mermaid-provider")) + html, inlineAttachments := mark.CompileMarkdown(markdown, stdlib, file, cCtx.String("mermaid-provider"), cCtx.Bool("drop-h1")) // Resolve attachements detected from markdown _, err = mark.ResolveAttachments( diff --git a/pkg/mark/markdown.go b/pkg/mark/markdown.go index 7119396..298fd79 100644 --- a/pkg/mark/markdown.go +++ b/pkg/mark/markdown.go @@ -53,17 +53,19 @@ type ConfluenceRenderer struct { Stdlib *stdlib.Lib Path string MermaidProvider string + DropFirstH1 bool LevelMap BlockQuoteLevelMap Attachments []Attachment } // NewConfluenceRenderer creates a new instance of the ConfluenceRenderer -func NewConfluenceRenderer(stdlib *stdlib.Lib, path string, mermaidProvider string, opts ...html.Option) renderer.NodeRenderer { +func NewConfluenceRenderer(stdlib *stdlib.Lib, path string, mermaidProvider string, dropFirstH1 bool, opts ...html.Option) renderer.NodeRenderer { return &ConfluenceRenderer{ Config: html.NewConfig(), Stdlib: stdlib, Path: path, MermaidProvider: mermaidProvider, + DropFirstH1: dropFirstH1, LevelMap: nil, Attachments: []Attachment{}, } @@ -73,7 +75,7 @@ func NewConfluenceRenderer(stdlib *stdlib.Lib, path string, mermaidProvider stri func (r *ConfluenceRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { // blocks // reg.Register(ast.KindDocument, r.renderNode) - // reg.Register(ast.KindHeading, r.renderNode) + reg.Register(ast.KindHeading, r.renderHeading) reg.Register(ast.KindBlockquote, r.renderBlockQuote) reg.Register(ast.KindCodeBlock, r.renderCodeBlock) reg.Register(ast.KindFencedCodeBlock, r.renderFencedCodeBlock) @@ -95,6 +97,37 @@ func (r *ConfluenceRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegister // reg.Register(ast.KindString, r.renderNode) } +func (r *ConfluenceRenderer) renderHeading(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.Heading) + + // If this is the first h1 heading of the document and we want to drop it, let's not render it at all. + if n.Level == 1 && r.DropFirstH1 { + if !entering { + r.DropFirstH1 = false + } + return ast.WalkSkipChildren, nil + } + + return r.goldmarkRenderHeading(w, source, node, entering) +} + +func (r *ConfluenceRenderer) goldmarkRenderHeading(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + n := node.(*ast.Heading) + if entering { + _, _ = w.WriteString("') + } else { + _, _ = w.WriteString("\n") + } + return ast.WalkContinue, nil +} + func ParseLanguage(lang string) string { // lang takes the following form: language? "collapse"? ("title"? *)? // let's split it by spaces @@ -612,10 +645,10 @@ func (r *ConfluenceRenderer) goldmarkRenderHTMLBlock(w util.BufWriter, source [] return ast.WalkContinue, nil } -func CompileMarkdown(markdown []byte, stdlib *stdlib.Lib, path string, mermaidProvider string) (string, []Attachment) { +func CompileMarkdown(markdown []byte, stdlib *stdlib.Lib, path string, mermaidProvider string, dropFirstH1 bool) (string, []Attachment) { log.Tracef(nil, "rendering markdown:\n%s", string(markdown)) - confluenceRenderer := NewConfluenceRenderer(stdlib, path, mermaidProvider) + confluenceRenderer := NewConfluenceRenderer(stdlib, path, mermaidProvider, dropFirstH1) converter := goldmark.New( goldmark.WithExtensions( @@ -657,18 +690,6 @@ func CompileMarkdown(markdown []byte, stdlib *stdlib.Lib, path string, mermaidPr } -// DropDocumentLeadingH1 will drop leading H1 headings to prevent -// duplication of or visual conflict with page titles. -// NOTE: This is intended only to operate on the whole markdown document. -// Operating on individual lines will clear them if the begin with `#`. -func DropDocumentLeadingH1( - markdown []byte, -) []byte { - h1 := regexp.MustCompile(`^#[^#].*\n`) - markdown = h1.ReplaceAll(markdown, []byte("")) - return markdown -} - // ExtractDocumentLeadingH1 will extract leading H1 heading func ExtractDocumentLeadingH1(markdown []byte) string { h1 := regexp.MustCompile(`#[^#]\s*(.*)\s*\n`) diff --git a/pkg/mark/markdown_test.go b/pkg/mark/markdown_test.go index 269d27f..e833251 100644 --- a/pkg/mark/markdown_test.go +++ b/pkg/mark/markdown_test.go @@ -36,7 +36,7 @@ func TestCompileMarkdown(t *testing.T) { if err != nil { panic(err) } - actual, _ := CompileMarkdown(markdown, lib, filename, "") + actual, _ := CompileMarkdown(markdown, lib, filename, "", false) test.EqualValues(string(html), actual, filename+" vs "+htmlname) } }