diff --git a/md2html/md2html.c b/md2html/md2html.c
index c959bfc1..a69bb354 100644
--- a/md2html/md2html.c
+++ b/md2html/md2html.c
@@ -220,6 +220,8 @@ static const CMDLINE_OPTION cmdline_options[] = {
{ 0, "funderline", '_', 0 },
{ 0, "fverbatim-entities", 'E', 0 },
{ 0, "fwiki-links", 'K', 0 },
+ { 0, "fmention-links", 'M', 0 },
+
{ 0, "fno-html-blocks", 'F', 0 },
{ 0, "fno-html-spans", 'G', 0 },
@@ -269,6 +271,7 @@ usage(void)
" --ftasklists Enable task lists\n"
" --funderline Enable underline spans\n"
" --fwiki-links Enable wiki links\n"
+ " --fmention-links Enable mention links\n"
"\n"
"Markdown suppression options:\n"
" --fno-html-blocks\n"
@@ -335,6 +338,7 @@ cmdline_callback(int opt, char const* value, void* data)
case 'K': parser_flags |= MD_FLAG_WIKILINKS; break;
case 'X': parser_flags |= MD_FLAG_TASKLISTS; break;
case '_': parser_flags |= MD_FLAG_UNDERLINE; break;
+ case 'M': parser_flags |= MD_FLAG_MENTIONS; break;
default:
fprintf(stderr, "Illegal option: %s\n", value);
diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh
index c00b36a9..f93ac350 100755
--- a/scripts/run-tests.sh
+++ b/scripts/run-tests.sh
@@ -70,6 +70,10 @@ echo
echo "Underline extension:"
$PYTHON "$TEST_DIR/spec_tests.py" -s "$TEST_DIR/underline.txt" -p "$PROGRAM --funderline"
+echo
+echo "Mention links extension:"
+$PYTHON "$TEST_DIR/spec_tests.py" -s "$TEST_DIR/mention-links.txt" -p "$PROGRAM --fmention-links"
+
echo
echo "Pathological input:"
$PYTHON "$TEST_DIR/pathological_tests.py" -p "$PROGRAM"
diff --git a/src/md4c-html.c b/src/md4c-html.c
index d604aecb..833cc2a6 100644
--- a/src/md4c-html.c
+++ b/src/md4c-html.c
@@ -265,6 +265,13 @@ render_attribute(MD_HTML* r, const MD_ATTRIBUTE* attr,
}
}
+static void
+render_mention_link(MD_HTML* r, const MD_SPAN_MENTION_DETAIL* det)
+{
+ RENDER_VERBATIM(r, "text, det->size, render_html_escaped);
+ RENDER_VERBATIM(r, "\">");
+}
static void
render_open_ol_block(MD_HTML* r, const MD_BLOCK_OL_DETAIL* det)
@@ -466,6 +473,7 @@ enter_span_callback(MD_SPANTYPE type, void* detail, void* userdata)
case MD_SPAN_LATEXMATH: RENDER_VERBATIM(r, ""); break;
case MD_SPAN_LATEXMATH_DISPLAY: RENDER_VERBATIM(r, ""); break;
case MD_SPAN_WIKILINK: render_open_wikilink_span(r, (MD_SPAN_WIKILINK_DETAIL*) detail); break;
+ case MD_SPAN_MENTION: render_mention_link(r, (MD_SPAN_MENTION_DETAIL*) detail); break;
}
return 0;
@@ -495,6 +503,7 @@ leave_span_callback(MD_SPANTYPE type, void* detail, void* userdata)
case MD_SPAN_LATEXMATH: /*fall through*/
case MD_SPAN_LATEXMATH_DISPLAY: RENDER_VERBATIM(r, ""); break;
case MD_SPAN_WIKILINK: RENDER_VERBATIM(r, ""); break;
+ case MD_SPAN_MENTION: RENDER_VERBATIM(r, ""); break;
}
return 0;
diff --git a/src/md4c.c b/src/md4c.c
index 40066b2d..a52a4ccc 100644
--- a/src/md4c.c
+++ b/src/md4c.c
@@ -2709,7 +2709,7 @@ md_build_mark_char_map(MD_CTX* ctx)
if(ctx->parser.flags & MD_FLAG_LATEXMATHSPANS)
ctx->mark_char_map['$'] = 1;
- if(ctx->parser.flags & MD_FLAG_PERMISSIVEEMAILAUTOLINKS)
+ if ((ctx->parser.flags & MD_FLAG_MENTIONS) || (ctx->parser.flags & MD_FLAG_PERMISSIVEEMAILAUTOLINKS))
ctx->mark_char_map['@'] = 1;
if(ctx->parser.flags & MD_FLAG_PERMISSIVEURLAUTOLINKS)
@@ -3190,9 +3190,26 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
continue;
}
+ /* A potential mention link. */
/* A potential permissive e-mail autolink. */
if(ch == _T('@')) {
- if(line->beg + 1 <= off && ISALNUM(off-1) &&
+ if( (ctx->parser.flags & MD_FLAG_MENTIONS) && (line->beg == off || (CH(off-1) == _T(' '))) )
+ {
+ OFF index = off + 1;
+ if (index == line->end || CH(index) == ' ') {
+ off++;
+ continue;
+ }
+ while (index <= line->end)
+ {
+ if (!(ISALNUM(index) || (CH(index) == '_')))
+ break;
+ index++;
+ }
+ PUSH_MARK('@', off, index, MD_MARK_RESOLVED);
+ off = index;
+ }
+ else if(line->beg + 1 <= off && ISALNUM(off-1) &&
off + 3 < line->end && ISALNUM(off+1))
{
PUSH_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER);
@@ -4291,6 +4308,7 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
MD_FALLTHROUGH();
case '@': /* Permissive e-mail autolink. */
+ /* Mention link */
case ':': /* Permissive URL autolink. */
case '.': /* Permissive WWW autolink. */
{
@@ -4299,6 +4317,17 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
const CHAR* dest = STR(opener->end);
SZ dest_size = closer->beg - opener->end;
+ MD_SPAN_MENTION_DETAIL det;
+ if (CH(mark->beg) == '@')
+ {
+ det.text = (char *) ctx->text + mark->beg + 1;
+ det.size = mark->end - mark->beg - 1;
+ MD_ENTER_SPAN(MD_SPAN_MENTION, &det);
+ MD_TEXT(text_type, STR(mark->beg), mark->end - mark->beg);
+ MD_LEAVE_SPAN(MD_SPAN_MENTION, &det);
+ break;
+ }
+
/* For permissive auto-links we do not know closer mark
* position at the time of md_collect_marks(), therefore
* it can be out-of-order in ctx->marks[].
diff --git a/src/md4c.h b/src/md4c.h
index 95f78f9b..521e14bd 100644
--- a/src/md4c.h
+++ b/src/md4c.h
@@ -145,7 +145,9 @@ typedef enum MD_SPANTYPE {
/* ...
* Note: Recognized only when MD_FLAG_UNDERLINE is enabled. */
- MD_SPAN_U
+ MD_SPAN_U,
+
+ MD_SPAN_MENTION
} MD_SPANTYPE;
/* Text is the actual textual contents of span. */
@@ -297,6 +299,12 @@ typedef struct MD_SPAN_WIKILINK {
MD_ATTRIBUTE target;
} MD_SPAN_WIKILINK_DETAIL;
+/* Detailed info for MD_SPAN_MENTION. */
+typedef struct MD_SPAN_MENTION {
+ unsigned char size;
+ MD_CHAR* text;
+} MD_SPAN_MENTION_DETAIL;
+
/* Flags specifying extensions/deviations from CommonMark specification.
*
* By default (when MD_PARSER::flags == 0), we follow CommonMark specification.
@@ -316,6 +324,7 @@ typedef struct MD_SPAN_WIKILINK {
#define MD_FLAG_LATEXMATHSPANS 0x1000 /* Enable $ and $$ containing LaTeX equations. */
#define MD_FLAG_WIKILINKS 0x2000 /* Enable wiki links extension. */
#define MD_FLAG_UNDERLINE 0x4000 /* Enable underline extension (and disables '_' for normal emphasis). */
+#define MD_FLAG_MENTIONS 0x8000 /* Enable mention links extension. */
#define MD_FLAG_PERMISSIVEAUTOLINKS (MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS | MD_FLAG_PERMISSIVEWWWAUTOLINKS)
#define MD_FLAG_NOHTML (MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS)
diff --git a/test/mention-links.txt b/test/mention-links.txt
new file mode 100644
index 00000000..27e33d9a
--- /dev/null
+++ b/test/mention-links.txt
@@ -0,0 +1,29 @@
+# Mention links
+
+With the flag `MD_FLAG_MENTIONS`, MD4C enables extension for recognition of mention (@) style links.
+
+A link ends when a non-alphanumeric character is hit. The only such character allowed is an underscore.
+
+```````````````````````````````` example
+someone said @me said such and such.
+.
+
someone said @me said such and such.
+````````````````````````````````
+
+```````````````````````````````` example
+@me said such and such.
+.
+@me said such and such.
+````````````````````````````````
+
+```````````````````````````````` example
+An empty at character is not recognized as a mention:
+
+@
+
+@
+.
+An empty at character is not recognized as a mention:
+@
+@
+````````````````````````````````
\ No newline at end of file