Skip to content

Commit

Permalink
User friendly blockquote title
Browse files Browse the repository at this point in the history
- Instead of the not so nice Github Alerts notations
  • Loading branch information
prokod committed Dec 12, 2024
1 parent 7206729 commit 24b2a74
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 22 deletions.
56 changes: 49 additions & 7 deletions renderer/blockquote.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package renderer
import (
"fmt"
"regexp"
"strings"

"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/renderer"
Expand All @@ -12,14 +13,16 @@ import (

type ConfluenceBlockQuoteRenderer struct {
html.Config
LevelMap BlockQuoteLevelMap
LevelMap BlockQuoteLevelMap
BlockQuoteNode ast.Node
}

// NewConfluenceRenderer creates a new instance of the ConfluenceRenderer
func NewConfluenceBlockQuoteRenderer(opts ...html.Option) renderer.NodeRenderer {
return &ConfluenceBlockQuoteRenderer{
Config: html.NewConfig(),
LevelMap: nil,
Config: html.NewConfig(),
LevelMap: nil,
BlockQuoteNode: nil,
}
}

Expand All @@ -39,6 +42,14 @@ const (
None
)

// Define BlockQuoteClassifierType enum
type BlockQuoteClassifierType int

const (
Legacy BlockQuoteClassifierType = iota
GHAlerts
)

func (t BlockQuoteType) String() string {
return []string{"info", "note", "warning", "tip", "none"}[t]
}
Expand Down Expand Up @@ -93,8 +104,10 @@ func (classifier BlockQuoteClassifier) ClassifyingBlockQuote(literal string) Blo
}

// ParseBlockQuoteType parses the first line of a blockquote and returns its type
func ParseBlockQuoteType(node ast.Node, source []byte) BlockQuoteType {
func ParseBlockQuoteType(node ast.Node, source []byte) (BlockQuoteType, BlockQuoteClassifierType, ast.Node) {
var t = None
var ct = Legacy
var context ast.Node = nil
var legacyClassifier = LegacyBlockQuoteClassifier()
var ghAlertsClassifier = GHAlertsBlockQuoteClassifier()

Expand Down Expand Up @@ -126,6 +139,8 @@ func ParseBlockQuoteType(node ast.Node, source []byte) BlockQuoteType {
rightTextNode := rightNode.(*ast.Text)
if string(n.Value(source)) == "[" && string(rightTextNode.Value(source)) == "]" {
t = ghAlertsClassifier.ClassifyingBlockQuote(string(midTextNode.Value(source)))
ct = GHAlerts
context = midNode
}
}
}
Expand All @@ -150,7 +165,27 @@ func ParseBlockQuoteType(node ast.Node, source []byte) BlockQuoteType {
return ast.WalkContinue, nil
})

return t
return t, ct, context
}

// Helper function to update the source in place
func ghaAlertsUpdateSourceInPlace(source []byte, node ast.Node, value string) {
leftNode := node.PreviousSibling().(*ast.Text)
midNode := node.(*ast.Text)
rightNode := node.NextSibling().(*ast.Text)

title := string(midNode.Value(source))
sanitizedTitle := strings.Replace(strings.ToLower(title), "!", "", -1)
capitalizedValue := strings.ToUpper(sanitizedTitle[:1]) + sanitizedTitle[1:]
if value != "" {
capitalizedValue = strings.ToUpper(value[:1]) + value[1:]
}

// Modify the source byte slice directly
copy(source[leftNode.Segment.Start:leftNode.Segment.Stop], []byte(" "))
format := fmt.Sprintf("%%-%ds", len(title))
copy(source[midNode.Segment.Start:midNode.Segment.Stop], []byte(fmt.Sprintf(format, capitalizedValue)))
copy(source[rightNode.Segment.Start:rightNode.Segment.Stop], []byte(" "))
}

// GenerateBlockQuoteLevel walks a given node and returns a map of blockquote levels
Expand Down Expand Up @@ -184,17 +219,24 @@ func (r *ConfluenceBlockQuoteRenderer) renderBlockQuote(writer util.BufWriter, s
r.LevelMap = GenerateBlockQuoteLevel(node)
}

quoteType := ParseBlockQuoteType(node, source)
quoteType, classifierType, blockQuoteCtxNode := ParseBlockQuoteType(node, source)
quoteLevel := r.LevelMap.Level(node)

if quoteLevel == 0 && entering && quoteType != None {
r.BlockQuoteNode = node

prefix := fmt.Sprintf("<ac:structured-macro ac:name=\"%s\"><ac:parameter ac:name=\"icon\">true</ac:parameter><ac:rich-text-body>\n", quoteType)
if _, err := writer.Write([]byte(prefix)); err != nil {
return ast.WalkStop, err
}
if classifierType == GHAlerts {
// Using quoteType as value like so: ghaAlertsUpdateSourceInPlace(source, blockQuoteCtxNode, quoteType.String())
// Will result in the blockquote title replaced by the blockquote type
ghaAlertsUpdateSourceInPlace(source, blockQuoteCtxNode, "")
}
return ast.WalkContinue, nil
}
if quoteLevel == 0 && !entering && quoteType != None {
if quoteLevel == 0 && !entering && node == r.BlockQuoteNode {
suffix := "</ac:rich-text-body></ac:structured-macro>\n"
if _, err := writer.Write([]byte(suffix)); err != nil {
return ast.WalkStop, err
Expand Down
10 changes: 5 additions & 5 deletions testdata/quotes-droph1.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,38 +48,38 @@ <h2 id="Simple-Blockquote">Simple Blockquote</h2>
<h2 id="GH-Alerts-Heading">GH Alerts Heading</h2>
<h3 id="Note-Type-Alert-Heading">Note Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!NOTE]</p>
<p> Note </p>
<ul>
<li>Note bullet 1</li>
<li>Note bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="Tip-Type-Alert-Heading">Tip Type Alert Heading</h3>
<ac:structured-macro ac:name="tip"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!TIP]</p>
<p> Tip </p>
<ul>
<li>Tip bullet 1</li>
<li>Tip bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="Warning-Type-Alert-Heading">Warning Type Alert Heading</h3>
<ac:structured-macro ac:name="note"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!WARNING]</p>
<p> Warning </p>
<ul>
<li>Warning bullet 1</li>
<li>Warning bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="Important/Caution-Type-Alert-Heading">Important/Caution Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!IMPORTANT]</p>
<p> Important </p>
<ul>
<li>Important bullet 1</li>
<li>Important bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<ac:structured-macro ac:name="warning"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!CAUTION]</p>
<p> Caution </p>
<ul>
<li>Important bullet 1</li>
<li>Important bullet 2</li>
Expand Down
10 changes: 5 additions & 5 deletions testdata/quotes-stripnewlines.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,38 +46,38 @@ <h2 id="Simple-Blockquote">Simple Blockquote</h2>
<h2 id="GH-Alerts-Heading">GH Alerts Heading</h2>
<h3 id="Note-Type-Alert-Heading">Note Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!NOTE]</p>
<p> Note </p>
<ul>
<li>Note bullet 1</li>
<li>Note bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="Tip-Type-Alert-Heading">Tip Type Alert Heading</h3>
<ac:structured-macro ac:name="tip"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!TIP]</p>
<p> Tip </p>
<ul>
<li>Tip bullet 1</li>
<li>Tip bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="Warning-Type-Alert-Heading">Warning Type Alert Heading</h3>
<ac:structured-macro ac:name="note"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!WARNING]</p>
<p> Warning </p>
<ul>
<li>Warning bullet 1</li>
<li>Warning bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="Important/Caution-Type-Alert-Heading">Important/Caution Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!IMPORTANT]</p>
<p> Important </p>
<ul>
<li>Important bullet 1</li>
<li>Important bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<ac:structured-macro ac:name="warning"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!CAUTION]</p>
<p> Caution </p>
<ul>
<li>Important bullet 1</li>
<li>Important bullet 2</li>
Expand Down
10 changes: 5 additions & 5 deletions testdata/quotes.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,38 +49,38 @@ <h2 id="Simple-Blockquote">Simple Blockquote</h2>
<h2 id="GH-Alerts-Heading">GH Alerts Heading</h2>
<h3 id="Note-Type-Alert-Heading">Note Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!NOTE]</p>
<p> Note </p>
<ul>
<li>Note bullet 1</li>
<li>Note bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="Tip-Type-Alert-Heading">Tip Type Alert Heading</h3>
<ac:structured-macro ac:name="tip"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!TIP]</p>
<p> Tip </p>
<ul>
<li>Tip bullet 1</li>
<li>Tip bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="Warning-Type-Alert-Heading">Warning Type Alert Heading</h3>
<ac:structured-macro ac:name="note"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!WARNING]</p>
<p> Warning </p>
<ul>
<li>Warning bullet 1</li>
<li>Warning bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<h3 id="Important/Caution-Type-Alert-Heading">Important/Caution Type Alert Heading</h3>
<ac:structured-macro ac:name="info"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!IMPORTANT]</p>
<p> Important </p>
<ul>
<li>Important bullet 1</li>
<li>Important bullet 2</li>
</ul>
</ac:rich-text-body></ac:structured-macro>
<ac:structured-macro ac:name="warning"><ac:parameter ac:name="icon">true</ac:parameter><ac:rich-text-body>
<p>[!CAUTION]</p>
<p> Caution </p>
<ul>
<li>Important bullet 1</li>
<li>Important bullet 2</li>
Expand Down

0 comments on commit 24b2a74

Please sign in to comment.