From 429e25864b86b7b5976348860a302c2843687ef4 Mon Sep 17 00:00:00 2001
From: hmhealey <harrisonmhealey@gmail.com>
Date: Thu, 8 Oct 2015 18:18:51 -0400
Subject: Modified markdown lexer to not break up words written in snake_case

---
 web/react/utils/markdown.jsx | 38 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

(limited to 'web/react/utils/markdown.jsx')

diff --git a/web/react/utils/markdown.jsx b/web/react/utils/markdown.jsx
index 26587dd6e..4fb4c6089 100644
--- a/web/react/utils/markdown.jsx
+++ b/web/react/utils/markdown.jsx
@@ -6,7 +6,31 @@ const Utils = require('./utils.jsx');
 
 const marked = require('marked');
 
-export class MattermostMarkdownRenderer extends marked.Renderer {
+class MattermostInlineLexer extends marked.InlineLexer {
+    constructor(links, options) {
+        super(links, options);
+
+        // modified version of the regex that doesn't break up words in snake_case
+        // the original is /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
+        this.rules.text = /^[\s\S]+?(?=__|\b_|[\\<!\[*`]| {2,}\n|$)/;
+    }
+}
+
+class MattermostParser extends marked.Parser {
+    parse(src) {
+        this.inline = new MattermostInlineLexer(src.links, this.options, this.renderer);
+        this.tokens = src.reverse();
+
+        var out = '';
+        while (this.next()) {
+            out += this.tok();
+        }
+
+        return out;
+    }
+}
+
+class MattermostMarkdownRenderer extends marked.Renderer {
     constructor(options, formattingOptions = {}) {
         super(options);
 
@@ -78,3 +102,15 @@ export class MattermostMarkdownRenderer extends marked.Renderer {
         return TextFormatting.doFormatText(txt, this.formattingOptions);
     }
 }
+
+export function format(text, options) {
+    const markdownOptions = {
+        renderer: new MattermostMarkdownRenderer(null, options),
+        sanitize: true
+    };
+
+    const tokens = marked.lexer(text, markdownOptions);
+
+    return new MattermostParser(markdownOptions).parse(tokens);
+}
+
-- 
cgit v1.2.3-1-g7c22


From 0356130ca6d4e3457769946d7dbf383ffe291098 Mon Sep 17 00:00:00 2001
From: hmhealey <harrisonmhealey@gmail.com>
Date: Wed, 28 Oct 2015 14:21:47 -0400
Subject: Updated markdown regexes to better handle underscores and links

---
 web/react/utils/markdown.jsx | 52 +++++++++++++++++++++++++++++---------------
 1 file changed, 34 insertions(+), 18 deletions(-)

(limited to 'web/react/utils/markdown.jsx')

diff --git a/web/react/utils/markdown.jsx b/web/react/utils/markdown.jsx
index 4fb4c6089..e34f3d00a 100644
--- a/web/react/utils/markdown.jsx
+++ b/web/react/utils/markdown.jsx
@@ -10,9 +10,21 @@ class MattermostInlineLexer extends marked.InlineLexer {
     constructor(links, options) {
         super(links, options);
 
-        // modified version of the regex that doesn't break up words in snake_case
-        // the original is /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
-        this.rules.text = /^[\s\S]+?(?=__|\b_|[\\<!\[*`]| {2,}\n|$)/;
+        this.rules = Object.assign({}, this.rules);
+
+        // modified version of the regex that doesn't break up words in snake_case,
+        // allows for links starting with www, and allows links succounded by parentheses
+        // the original is /^[\s\S]+?(?=[\\<!\[_*`~]|https?:\/\/| {2,}\n|$)/
+        this.rules.text = /^[\s\S]+?(?=[^\w\/]_|[\\<!\[*`~]|https?:\/\/|www\.|\(| {2,}\n|$)/;
+
+        // modified version of the regex that allows links starting with www and those surrounded
+        // by parentheses
+        // the original is /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/
+        this.rules.url = /^(\(?(?:https?:\/\/|www\.)[^\s<.][^\s<]*[^<.,:;"'\]\s])/;
+
+        // modified version of the regex that allows <links> starting with www.
+        // the original is /^<([^ >]+(@|:\/)[^ >]+)>/
+        this.rules.autolink = /^<((?:[^ >]+(@|:\/)|www\.)[^ >]+)>/;
     }
 }
 
@@ -56,8 +68,20 @@ class MattermostMarkdownRenderer extends marked.Renderer {
 
     link(href, title, text) {
         let outHref = href;
+        let outText = text;
+        let prefix = '';
+        let suffix = '';
+
+        // some links like https://en.wikipedia.org/wiki/Rendering_(computer_graphics) contain brackets
+        // and we try our best to differentiate those from ones just wrapped in brackets when autolinking
+        if (outHref.startsWith('(') && outHref.endsWith(')') && text === outHref) {
+            prefix = '(';
+            suffix = ')';
+            outText = text.substring(1, text.length - 1);
+            outHref = outHref.substring(1, outHref.length - 1);
+        }
 
-        if (!(/^(mailto|https?|ftp)/.test(outHref))) {
+        if (!(/[a-z+.-]+:/i).test(outHref)) {
             outHref = `http://${outHref}`;
         }
 
@@ -72,26 +96,17 @@ class MattermostMarkdownRenderer extends marked.Renderer {
             output += ' target="_blank">';
         }
 
-        output += text + '</a>';
+        output += outText + '</a>';
 
-        return output;
+        return prefix + output + suffix;
     }
 
     paragraph(text) {
-        let outText = text;
-
-        // required so markdown does not strip '_' from @user_names
-        outText = TextFormatting.doFormatMentions(text);
-
-        if (!('emoticons' in this.options) || this.options.emoticon) {
-            outText = TextFormatting.doFormatEmoticons(outText);
-        }
-
         if (this.formattingOptions.singleline) {
-            return `<p class="markdown__paragraph-inline">${outText}</p>`;
+            return `<p class="markdown__paragraph-inline">${text}</p>`;
         }
 
-        return super.paragraph(outText);
+        return super.paragraph(text);
     }
 
     table(header, body) {
@@ -106,7 +121,8 @@ class MattermostMarkdownRenderer extends marked.Renderer {
 export function format(text, options) {
     const markdownOptions = {
         renderer: new MattermostMarkdownRenderer(null, options),
-        sanitize: true
+        sanitize: true,
+        gfm: true
     };
 
     const tokens = marked.lexer(text, markdownOptions);
-- 
cgit v1.2.3-1-g7c22

