mirror of
				https://github.com/kovetskiy/mark.git
				synced 2025-10-31 11:47:37 +08:00 
			
		
		
		
	feat: Support page inclusion macro
Also generalize the ac_tag_parser a bit and support <ri:* /> tags as well
This commit is contained in:
		
							parent
							
								
									943a356508
								
							
						
					
					
						commit
						1285947ab3
					
				| @ -371,6 +371,10 @@ By default, mark provides several built-in templates and macros: | ||||
| 
 | ||||
|   See: https://confluence.atlassian.com/doc/blog-posts-macro-139470.html | ||||
| 
 | ||||
| * template: `ac:include` to include a page | ||||
|   - Page: the page to be included | ||||
|   - Space: the space the page is in (optional, otherwise same space) | ||||
| 
 | ||||
| * macro `@{...}` to mention user by name specified in the braces. | ||||
| 
 | ||||
| ## Template & Macros Usecases | ||||
|  | ||||
| @ -6,6 +6,7 @@ import ( | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	cparser "github.com/kovetskiy/mark/pkg/mark/parser" | ||||
| 	"github.com/kovetskiy/mark/pkg/mark/stdlib" | ||||
| 	"github.com/reconquest/pkg/log" | ||||
| 	"github.com/yuin/goldmark" | ||||
| @ -450,7 +451,7 @@ func CompileMarkdown(markdown []byte, stdlib *stdlib.Lib) string { | ||||
| 	converter.Parser().AddOptions(parser.WithInlineParsers( | ||||
| 		// Must be registered with a higher priority than goldmark's linkParser to make sure goldmark doesn't parse | ||||
| 		// the <ac:*/> tags. | ||||
| 		util.Prioritized(NewACTagParser(), 199), | ||||
| 		util.Prioritized(cparser.NewConfluenceTagParser(), 199), | ||||
| 	)) | ||||
| 
 | ||||
| 	converter.Renderer().AddOptions(renderer.WithNodeRenderers( | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| package mark | ||||
| package parser | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| @ -9,25 +9,25 @@ import ( | ||||
| 	"regexp" | ||||
| ) | ||||
| 
 | ||||
| // NewACTagParser returns an inline parser that parses <ac:* /> tags to ensure that Confluence specific tags are parsed | ||||
| // NewConfluenceTagParser returns an inline parser that parses <ac:* /> and <ri:* /> tags to ensure that Confluence specific tags are parsed | ||||
| // as ast.KindRawHtml so they are not escaped at render time. The parser must be registered with a higher priority | ||||
| // than goldmark's linkParser. Otherwise, the linkParser would parse the <ac:* /> tags. | ||||
| func NewACTagParser() parser.InlineParser { | ||||
| 	return &acTagParser{} | ||||
| func NewConfluenceTagParser() parser.InlineParser { | ||||
| 	return &confluenceTagParser{} | ||||
| } | ||||
| 
 | ||||
| var _ parser.InlineParser = (*acTagParser)(nil) | ||||
| var _ parser.InlineParser = (*confluenceTagParser)(nil) | ||||
| 
 | ||||
| // acTagParser is a stripped down version of goldmark's rawHTMLParser. | ||||
| // confluenceTagParser is a stripped down version of goldmark's rawHTMLParser. | ||||
| // See: https://github.com/yuin/goldmark/blob/master/parser/raw_html.go | ||||
| type acTagParser struct { | ||||
| type confluenceTagParser struct { | ||||
| } | ||||
| 
 | ||||
| func (s *acTagParser) Trigger() []byte { | ||||
| func (s *confluenceTagParser) Trigger() []byte { | ||||
| 	return []byte{'<'} | ||||
| } | ||||
| 
 | ||||
| func (s *acTagParser) Parse(_ ast.Node, block text.Reader, pc parser.Context) ast.Node { | ||||
| func (s *confluenceTagParser) Parse(_ ast.Node, block text.Reader, pc parser.Context) ast.Node { | ||||
| 	line, _ := block.PeekLine() | ||||
| 	if len(line) > 1 && util.IsAlphaNumeric(line[1]) { | ||||
| 		return s.parseMultiLineRegexp(openTagRegexp, block, pc) | ||||
| @ -48,15 +48,15 @@ var tagnamePattern = `([A-Za-z][A-Za-z0-9-]*)` | ||||
| 
 | ||||
| var attributePattern = `(?:[\r\n \t]+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:[\r\n \t]*=[\r\n \t]*(?:[^\"'=<>` + "`" + `\x00-\x20]+|'[^']*'|"[^"]*"))?)` | ||||
| 
 | ||||
| // Only match <ac:*/> tags | ||||
| var openTagRegexp = regexp.MustCompile("^<ac:" + tagnamePattern + attributePattern + `*[ \t]*/?>`) | ||||
| // Only match <ac:*/> and <ri:*/> tags | ||||
| var openTagRegexp = regexp.MustCompile("^<(ac|ri):" + tagnamePattern + attributePattern + `*[ \t]*/?>`) | ||||
| var closeTagRegexp = regexp.MustCompile("^</ac:" + tagnamePattern + `\s*>`) | ||||
| 
 | ||||
| var openCDATA = []byte("<![CDATA[") | ||||
| var closeCDATA = []byte("]]>") | ||||
| var closeDecl = []byte(">") | ||||
| 
 | ||||
| func (s *acTagParser) parseUntil(block text.Reader, closer []byte, _ parser.Context) ast.Node { | ||||
| func (s *confluenceTagParser) parseUntil(block text.Reader, closer []byte, _ parser.Context) ast.Node { | ||||
| 	savedLine, savedSegment := block.Position() | ||||
| 	node := ast.NewRawHTML() | ||||
| 	for { | ||||
| @ -77,7 +77,7 @@ func (s *acTagParser) parseUntil(block text.Reader, closer []byte, _ parser.Cont | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (s *acTagParser) parseMultiLineRegexp(reg *regexp.Regexp, block text.Reader, _ parser.Context) ast.Node { | ||||
| func (s *confluenceTagParser) parseMultiLineRegexp(reg *regexp.Regexp, block text.Reader, _ parser.Context) ast.Node { | ||||
| 	sline, ssegment := block.Position() | ||||
| 	if block.Match(reg) { | ||||
| 		node := ast.NewRawHTML() | ||||
| @ -261,6 +261,18 @@ func templates(api *confluence.API) (*template.Template, error) { | ||||
| 			`</ac:structured-macro>{{printf "\n"}}`, | ||||
| 		), | ||||
| 
 | ||||
| 		/* https://confluence.atlassian.com/conf59/include-page-macro-792499125.html */ | ||||
| 
 | ||||
| 		`ac:include`: text( | ||||
| 			`<ac:structured-macro ac:name="include">{{printf "\n"}}`, | ||||
| 			`<ac:parameter ac:name="">{{printf "\n"}}`, | ||||
| 			`<ac:link>{{printf "\n"}}`, | ||||
| 			`<ri:page ri:content-title="{{ .Page }}" {{if .Space }}ri:space-key="{{ .Space }}"{{end}}/>{{printf "\n"}}`, | ||||
| 			`</ac:link>{{printf "\n"}}`, | ||||
| 			`</ac:parameter>{{printf "\n"}}`, | ||||
| 			`</ac:structured-macro>{{printf "\n"}}`, | ||||
| 		), | ||||
| 
 | ||||
| 		// TODO(seletskiy): more templates here | ||||
| 	} { | ||||
| 		templates, err = templates.New(name).Parse(body) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Manuel Rüger
						Manuel Rüger