diff --git a/plugin/markdown/parser/tag.go b/plugin/markdown/parser/tag.go index 22ad4f7a4..bc46280ff 100644 --- a/plugin/markdown/parser/tag.go +++ b/plugin/markdown/parser/tag.go @@ -47,6 +47,17 @@ func isValidTagRune(r rune) bool { return true } + // Allow marks (non-spacing, spacing combining, enclosing) + // This covers variation selectors (e.g. VS16 \uFE0F) and combining marks (e.g. Keycap \u20E3, accents) + if unicode.IsMark(r) { + return true + } + + // Allow Zero Width Joiner (ZWJ) for emoji sequences + if r == '\u200D' { + return true + } + // Allow specific ASCII symbols for tag structure // Underscore: word separation (snake_case) // Hyphen: word separation (kebab-case) diff --git a/plugin/markdown/parser/tag_test.go b/plugin/markdown/parser/tag_test.go index a6015f4d1..ecb41f577 100644 --- a/plugin/markdown/parser/tag_test.go +++ b/plugin/markdown/parser/tag_test.go @@ -174,6 +174,18 @@ func TestTagParser(t *testing.T) { expectedTag: "test🚀", shouldParse: true, }, + { + name: "emoji with VS16", + input: "#test👁️", // Eye + VS16 + expectedTag: "test👁️", + shouldParse: true, + }, + { + name: "emoji with ZWJ sequence", + input: "#family👨‍👩‍👧‍👦", // Family ZWJ sequence + expectedTag: "family👨‍👩‍👧‍👦", + shouldParse: true, + }, } for _, tt := range tests {