feat(markdown): mask spoilers (#820)

This commit is contained in:
ayn2op 2026-07-30 14:32:26 -04:00 • committed by GitHub
parent d13ce0ea4a
commit ec0e68ef54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 50 additions and 2 deletions

View file

@ -65,8 +65,9 @@ type (
}
MarkdownConfig struct {
Enabled bool `toml:"enabled"`
Theme string `toml:"theme"`
Enabled bool `toml:"enabled"`
MaskSpoilers bool `toml:"mask_spoilers"`
Theme string `toml:"theme"`
}
HelpConfig struct {

View file

@ -28,6 +28,8 @@ max_height = 10
[markdown]
# Whether to parse and render markdown in messages or not.
enabled = true
# Replace spoiler contents with a placeholder.
mask_spoilers = false
# Theme for fenced code blocks. Available themes: https://xyproto.github.io/splash/docs
theme = "monokai"

View file

@ -118,6 +118,12 @@ func (r *Renderer) RenderLines(source []byte, node ast.Node, base tcell.Style) [
builder.NewLine()
}
case *discordmd.Inline:
if r.cfg.Markdown.MaskSpoilers && node.Attr&discordmd.AttrSpoiler != 0 {
if entering {
builder.Write("[spoiler]", currentStyle())
}
return ast.WalkSkipChildren, nil
}
if entering {
pushStyle(applyInlineAttr(currentStyle(), node.Attr, linkDepth > 0))
} else {

View file

@ -0,0 +1,39 @@
package markdown
import (
"strings"
"testing"
"github.com/ayn2op/discordo/internal/config"
"github.com/ayn2op/ningen/v3/discordmd"
"github.com/gdamore/tcell/v3"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/text"
)
func TestRendererMasksSpoilers(t *testing.T) {
source := []byte("before ||secret|| after")
node := parser.NewParser(
parser.WithBlockParsers(discordmd.BlockParsers()...),
parser.WithInlineParsers(discordmd.InlineParserWithLink()...),
).Parse(text.NewReader(source))
for _, test := range []struct {
mask bool
want string
}{
{true, "before [spoiler] after"},
{false, "before secret after"},
} {
lines := NewRenderer(&config.Config{Markdown: config.MarkdownConfig{MaskSpoilers: test.mask}}).RenderLines(source, node, tcell.StyleDefault)
var got strings.Builder
for _, line := range lines {
for _, segment := range line {
got.WriteString(segment.Text)
}
}
if got.String() != test.want {
t.Fatalf("mask=%t: got %q, want %q", test.mask, got.String(), test.want)
}
}
}