diff --git a/common/markdown_parser/constants.ts b/common/markdown_parser/constants.ts index f976b23e..8475048b 100644 --- a/common/markdown_parser/constants.ts +++ b/common/markdown_parser/constants.ts @@ -1,5 +1,5 @@ export const wikiLinkRegex = /(!?\[\[)([^\]\|]+)(?:\|([^\]]+))?(\]\])/g; // [fullMatch, firstMark, url, alias, lastMark] export const mdLinkRegex = /!?\[(?[^\]]*)\]\((?<url>.+)\)/g; // [fullMatch, alias, url] export const tagRegex = - /#[^\d\s!@#$%^&*(),.?":{}|<>\\][^\s!@#$%^&*(),.?":{}|<>\\]*/; + /#(?:(?:\d*[^\d\s!@#$%^&*(),.?":{}|<>\\][^\s!@#$%^&*(),.?":{}|<>\\]*)|(?:"[^"\n]+")|(?:<[^>\n]+>))/; export const pWikiLinkRegex = new RegExp("^" + wikiLinkRegex.source); // Modified regex used only in parser diff --git a/common/markdown_parser/parser.test.ts b/common/markdown_parser/parser.test.ts index 3709242a..00606d3f 100644 --- a/common/markdown_parser/parser.test.ts +++ b/common/markdown_parser/parser.test.ts @@ -162,3 +162,40 @@ Deno.test("Test lua directive parser", () => { const simpleExample = `Simple \${{a=}}`; console.log(JSON.stringify(parseMarkdown(simpleExample), null, 2)); }); + +const hashtagSample = ` +Hashtags, e.g. #mytag but ignore in code \`#mytag\`. +They can contain slashes like #level/beginner, single quotes, and dashes: #Mike's-idea. +Can be just #a single letter. +But no other #interpunction: #exclamation! #question? +There are two ways to make #"tag with spaces and <angle>" #<tag with spaces and "quote"> +These cannot span #"multiple +lines" +#no#spacing also works. +Hashtags can start with number if there's something after it: #3dprint #15-52_Trip-to-NYC. +But magazine issue #123 is not a hashtag. +Should support other languages, like #żółć or #井号 +`; + +Deno.test("Test hashtag parser", () => { + const tree = parseMarkdown(hashtagSample); + const hashtags = collectNodesOfType(tree, "Hashtag"); + assertEquals(hashtags.length, 15); + + assertEquals(hashtags[0].children![0].text, "#mytag"); + assertEquals(hashtags[1].children![0].text, "#level/beginner"); + assertEquals(hashtags[2].children![0].text, "#Mike's-idea"); + assertEquals(hashtags[2].children![0].text, "#a"); + assertEquals(hashtags[3].children![0].text, "#interpunction"); + assertEquals(hashtags[4].children![0].text, "#exclamation"); + assertEquals(hashtags[5].children![0].text, "#question"); + assertEquals(hashtags[6].children![0].text, '#"tag with spaces and <angle>"'); + assertEquals(hashtags[7].children![0].text, '#<tag with spaces and "quote">'); + // multiple lines not allowed + assertEquals(hashtags[8].children![0].text, "#no"); + assertEquals(hashtags[9].children![0].text, "#spacing"); + assertEquals(hashtags[10].children![0].text, "#3dprint"); + assertEquals(hashtags[11].children![0].text, "#15-52_Trip-to-NYC"); + assertEquals(hashtags[12].children![0].text, "#żółć"); + assertEquals(hashtags[13].children![0].text, "#井号"); +}); diff --git a/website/Markdown/Extensions.md b/website/Markdown/Extensions.md index b030c612..91441a29 100644 --- a/website/Markdown/Extensions.md +++ b/website/Markdown/Extensions.md @@ -10,7 +10,7 @@ In addition to supporting [[Markdown/Basics|markdown basics]] as standardized by * [[Transclusions]] syntax * [[Markdown/Anchors]] * [[Markdown/Admonitions]] -* Hashtags, e.g. `#mytag`. +* [[Markdown/Hashtags]] * [[Markdown/Command links]] syntax * [Tables](https://www.markdownguide.org/extended-syntax/#tables) * [Task lists](https://www.markdownguide.org/extended-syntax/#task-lists) diff --git a/website/Markdown/Hashtags.md b/website/Markdown/Hashtags.md new file mode 100644 index 00000000..4cdcaf42 --- /dev/null +++ b/website/Markdown/Hashtags.md @@ -0,0 +1,16 @@ +#level/beginner + +These can be used in text to assign an [[Objects#tag]] #like-this. If hashtags are the only content of first paragraph, they are applied to the entire page. + +Hashtags can contain letters, dashes, underscores and other characters, but not: +- Whitespace (space, newline etc.) +- Characters from this list `!@#$%^&*(),.?":{}|<>\` +- Consist of digits only #123 (but #3dprint is recognised) + +If you need your tags to contain these characters, you have to surround the tag content with either: +- Double quotes `#"tag in quotes"` #“tag in quotes” +- Angle brackets #<tag in angle> #<tag in angle> + +```query +tag where page = @page.name +``` \ No newline at end of file