Feature/themed blocks (#223)

* Allow themed blocks

* add macro code for themed blocks
This commit is contained in:
Stephan Hradek 2023-01-03 18:53:41 +01:00 committed by GitHub
parent 0b745c25e4
commit f4bbbb19ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 42 deletions

View File

@ -177,10 +177,30 @@ And you can also add a title:
...
```
You can collapse or have a title without language or any mix, but the language
must stay in the front _if it is given_:
Or linenumbers, by giving the first number
[<language>] ["collapse"] ["title" <your title>]
```bash 1 collapse title Some long long bash function
...
some long bash code block
...
```
And even themes
```bash 1 collapse midnight title Some long long bash function
...
some long bash code block
...
```
Please note that, if you want to have a code block without a language
use `-` as the first character, if you want to have the other goodies
``` - 1 collapse midnight title Some long long code
...
some long code block
...
```
[Code Block Macro]: https://confluence.atlassian.com/doc/code-block-macro-139390.html

View File

@ -8,6 +8,13 @@ import (
bf "github.com/kovetskiy/blackfriday/v2"
"github.com/kovetskiy/mark/pkg/mark/stdlib"
"github.com/reconquest/pkg/log"
"fmt"
)
var reBlockDetails = regexp.MustCompile(
// (<Lang>|-) (collapse|<theme>|\d)* (title <title>)?
`^(?:(\w*)|-)\s*\b(\S.*?\S?)??\s*(?:\btitle\s+(\S.*\S?))?$`,
)
type ConfluenceRenderer struct {
@ -16,45 +23,41 @@ type ConfluenceRenderer struct {
Stdlib *stdlib.Lib
}
func ParseLanguage(lang string) string {
// lang takes the following form: language? "collapse"? ("title"? <any string>*)?
// let's split it by spaces
paramlist := strings.Fields(lang)
// get the word in question, aka the first one
first := lang
if len(paramlist) > 0 {
first = paramlist[0]
}
if first == "collapse" || first == "title" {
// collapsing or including a title without a language
return ""
}
// the default case with language being the first one
return first
}
func ParseTitle(lang string) string {
index := strings.Index(lang, "title")
if index >= 0 {
// it's found, check if title is given and return it
start := index + 6
if len(lang) > start {
return lang[start:]
}
}
return ""
}
func (renderer ConfluenceRenderer) RenderNode(
writer io.Writer,
node *bf.Node,
entering bool,
) bf.WalkStatus {
if node.Type == bf.CodeBlock {
lang := string(node.Info)
groups:= reBlockDetails.FindStringSubmatch(string(node.Info))
linenumbers := false
firstline := 0
theme := ""
collapse := false
lang := ""
var options []string
title := ""
if len(groups) > 0 {
lang, options, title = groups[1], strings.Fields(groups[2]), groups[3]
for _, option := range options {
if option == "collapse" {
collapse = true
continue
}
if option == "nocollapse" {
collapse = false
continue
}
var i int
if _, err := fmt.Sscanf(option, "%d", &i); err == nil {
linenumbers = i > 0
firstline = i
continue
}
theme = option
}
}
renderer.Stdlib.Templates.ExecuteTemplate(
writer,
"ac:code",
@ -62,11 +65,17 @@ func (renderer ConfluenceRenderer) RenderNode(
Language string
Collapse bool
Title string
Theme string
Linenumbers bool
Firstline int
Text string
}{
ParseLanguage(lang),
strings.Contains(lang, "collapse"),
ParseTitle(lang),
lang,
collapse,
title,
theme,
linenumbers,
firstline,
strings.TrimSuffix(string(node.Literal), "\n"),
},
)

View File

@ -110,6 +110,9 @@ func templates(api *confluence.API) (*template.Template, error) {
/**/ `{{ if eq .Language "mermaid" }}<ac:parameter ac:name="showSource">true</ac:parameter>{{printf "\n"}}{{ else }}`,
/**/ `<ac:parameter ac:name="language">{{ .Language }}</ac:parameter>{{printf "\n"}}{{ end }}`,
/**/ `<ac:parameter ac:name="collapse">{{ .Collapse }}</ac:parameter>{{printf "\n"}}`,
/**/ `{{ if .Theme }}<ac:parameter ac:name="theme">{{ .Theme }}</ac:parameter>{{printf "\n"}}{{ end }}`,
/**/ `{{ if .Linenumbers }}<ac:parameter ac:name="linenumbers">{{ .Linenumbers }}</ac:parameter>{{printf "\n"}}{{ end }}`,
/**/ `{{ if .Firstline }}<ac:parameter ac:name="firstline">{{ .Firstline }}</ac:parameter>{{printf "\n"}}{{ end }}`,
/**/ `{{ if .Title }}<ac:parameter ac:name="title">{{ .Title }}</ac:parameter>{{printf "\n"}}{{ end }}`,
/**/ `<ac:plain-text-body><![CDATA[{{ .Text | cdata }}]]></ac:plain-text-body>{{printf "\n"}}`,
`</ac:structured-macro>{{printf "\n"}}`,