summaryrefslogtreecommitdiff
path: root/public/vendor/codemirror/mode/markdown
diff options
context:
space:
mode:
authorWu Cheng-Han2015-05-04 15:53:29 +0800
committerWu Cheng-Han2015-05-04 15:53:29 +0800
commit4b0ca55eb79e963523eb6c8197825e9e8ae904e2 (patch)
tree574f3923af77b37b41dbf1b00bcd7827ef724a28 /public/vendor/codemirror/mode/markdown
parent61eb11d23c65c9e5c493c67d055f785cbec139e2 (diff)
First commit, version 0.2.7
Diffstat (limited to 'public/vendor/codemirror/mode/markdown')
-rwxr-xr-xpublic/vendor/codemirror/mode/markdown/index.html359
-rwxr-xr-xpublic/vendor/codemirror/mode/markdown/markdown.js767
-rwxr-xr-xpublic/vendor/codemirror/mode/markdown/test.js754
3 files changed, 1880 insertions, 0 deletions
diff --git a/public/vendor/codemirror/mode/markdown/index.html b/public/vendor/codemirror/mode/markdown/index.html
new file mode 100755
index 00000000..c3bb8df9
--- /dev/null
+++ b/public/vendor/codemirror/mode/markdown/index.html
@@ -0,0 +1,359 @@
+<!doctype html>
+
+<title>CodeMirror: Markdown mode</title>
+<meta charset="utf-8"/>
+<link rel=stylesheet href="../../doc/docs.css">
+
+<link rel="stylesheet" href="../../lib/codemirror.css">
+<script src="../../lib/codemirror.js"></script>
+<script src="../../addon/edit/continuelist.js"></script>
+<script src="../xml/xml.js"></script>
+<script src="markdown.js"></script>
+<style type="text/css">
+ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
+ .cm-s-default .cm-trailing-space-a:before,
+ .cm-s-default .cm-trailing-space-b:before {position: absolute; content: "\00B7"; color: #777;}
+ .cm-s-default .cm-trailing-space-new-line:before {position: absolute; content: "\21B5"; color: #777;}
+ </style>
+<div id=nav>
+ <a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
+
+ <ul>
+ <li><a href="../../index.html">Home</a>
+ <li><a href="../../doc/manual.html">Manual</a>
+ <li><a href="https://github.com/codemirror/codemirror">Code</a>
+ </ul>
+ <ul>
+ <li><a href="../index.html">Language modes</a>
+ <li><a class=active href="#">Markdown</a>
+ </ul>
+</div>
+
+<article>
+<h2>Markdown mode</h2>
+<form><textarea id="code" name="code">
+Markdown: Basics
+================
+
+&lt;ul id="ProjectSubmenu"&gt;
+ &lt;li&gt;&lt;a href="/projects/markdown/" title="Markdown Project Page"&gt;Main&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a class="selected" title="Markdown Basics"&gt;Basics&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="/projects/markdown/syntax" title="Markdown Syntax Documentation"&gt;Syntax&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="/projects/markdown/license" title="Pricing and License Information"&gt;License&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href="/projects/markdown/dingus" title="Online Markdown Web Form"&gt;Dingus&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+
+Getting the Gist of Markdown's Formatting Syntax
+------------------------------------------------
+
+This page offers a brief overview of what it's like to use Markdown.
+The [syntax page] [s] provides complete, detailed documentation for
+every feature, but Markdown should be very easy to pick up simply by
+looking at a few examples of it in action. The examples on this page
+are written in a before/after style, showing example syntax and the
+HTML output produced by Markdown.
+
+It's also helpful to simply try Markdown out; the [Dingus] [d] is a
+web application that allows you type your own Markdown-formatted text
+and translate it to XHTML.
+
+**Note:** This document is itself written using Markdown; you
+can [see the source for it by adding '.text' to the URL] [src].
+
+ [s]: /projects/markdown/syntax "Markdown Syntax"
+ [d]: /projects/markdown/dingus "Markdown Dingus"
+ [src]: /projects/markdown/basics.text
+
+
+## Paragraphs, Headers, Blockquotes ##
+
+A paragraph is simply one or more consecutive lines of text, separated
+by one or more blank lines. (A blank line is any line that looks like
+a blank line -- a line containing nothing but spaces or tabs is
+considered blank.) Normal paragraphs should not be indented with
+spaces or tabs.
+
+Markdown offers two styles of headers: *Setext* and *atx*.
+Setext-style headers for `&lt;h1&gt;` and `&lt;h2&gt;` are created by
+"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
+To create an atx-style header, you put 1-6 hash marks (`#`) at the
+beginning of the line -- the number of hashes equals the resulting
+HTML header level.
+
+Blockquotes are indicated using email-style '`&gt;`' angle brackets.
+
+Markdown:
+
+ A First Level Header
+ ====================
+
+ A Second Level Header
+ ---------------------
+
+ Now is the time for all good men to come to
+ the aid of their country. This is just a
+ regular paragraph.
+
+ The quick brown fox jumped over the lazy
+ dog's back.
+
+ ### Header 3
+
+ &gt; This is a blockquote.
+ &gt;
+ &gt; This is the second paragraph in the blockquote.
+ &gt;
+ &gt; ## This is an H2 in a blockquote
+
+
+Output:
+
+ &lt;h1&gt;A First Level Header&lt;/h1&gt;
+
+ &lt;h2&gt;A Second Level Header&lt;/h2&gt;
+
+ &lt;p&gt;Now is the time for all good men to come to
+ the aid of their country. This is just a
+ regular paragraph.&lt;/p&gt;
+
+ &lt;p&gt;The quick brown fox jumped over the lazy
+ dog's back.&lt;/p&gt;
+
+ &lt;h3&gt;Header 3&lt;/h3&gt;
+
+ &lt;blockquote&gt;
+ &lt;p&gt;This is a blockquote.&lt;/p&gt;
+
+ &lt;p&gt;This is the second paragraph in the blockquote.&lt;/p&gt;
+
+ &lt;h2&gt;This is an H2 in a blockquote&lt;/h2&gt;
+ &lt;/blockquote&gt;
+
+
+
+### Phrase Emphasis ###
+
+Markdown uses asterisks and underscores to indicate spans of emphasis.
+
+Markdown:
+
+ Some of these words *are emphasized*.
+ Some of these words _are emphasized also_.
+
+ Use two asterisks for **strong emphasis**.
+ Or, if you prefer, __use two underscores instead__.
+
+Output:
+
+ &lt;p&gt;Some of these words &lt;em&gt;are emphasized&lt;/em&gt;.
+ Some of these words &lt;em&gt;are emphasized also&lt;/em&gt;.&lt;/p&gt;
+
+ &lt;p&gt;Use two asterisks for &lt;strong&gt;strong emphasis&lt;/strong&gt;.
+ Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;/p&gt;
+
+
+
+## Lists ##
+
+Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
+`+`, and `-`) as list markers. These three markers are
+interchangable; this:
+
+ * Candy.
+ * Gum.
+ * Booze.
+
+this:
+
+ + Candy.
+ + Gum.
+ + Booze.
+
+and this:
+
+ - Candy.
+ - Gum.
+ - Booze.
+
+all produce the same output:
+
+ &lt;ul&gt;
+ &lt;li&gt;Candy.&lt;/li&gt;
+ &lt;li&gt;Gum.&lt;/li&gt;
+ &lt;li&gt;Booze.&lt;/li&gt;
+ &lt;/ul&gt;
+
+Ordered (numbered) lists use regular numbers, followed by periods, as
+list markers:
+
+ 1. Red
+ 2. Green
+ 3. Blue
+
+Output:
+
+ &lt;ol&gt;
+ &lt;li&gt;Red&lt;/li&gt;
+ &lt;li&gt;Green&lt;/li&gt;
+ &lt;li&gt;Blue&lt;/li&gt;
+ &lt;/ol&gt;
+
+If you put blank lines between items, you'll get `&lt;p&gt;` tags for the
+list item text. You can create multi-paragraph list items by indenting
+the paragraphs by 4 spaces or 1 tab:
+
+ * A list item.
+
+ With multiple paragraphs.
+
+ * Another item in the list.
+
+Output:
+
+ &lt;ul&gt;
+ &lt;li&gt;&lt;p&gt;A list item.&lt;/p&gt;
+ &lt;p&gt;With multiple paragraphs.&lt;/p&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;p&gt;Another item in the list.&lt;/p&gt;&lt;/li&gt;
+ &lt;/ul&gt;
+
+
+
+### Links ###
+
+Markdown supports two styles for creating links: *inline* and
+*reference*. With both styles, you use square brackets to delimit the
+text you want to turn into a link.
+
+Inline-style links use parentheses immediately after the link text.
+For example:
+
+ This is an [example link](http://example.com/).
+
+Output:
+
+ &lt;p&gt;This is an &lt;a href="http://example.com/"&gt;
+ example link&lt;/a&gt;.&lt;/p&gt;
+
+Optionally, you may include a title attribute in the parentheses:
+
+ This is an [example link](http://example.com/ "With a Title").
+
+Output:
+
+ &lt;p&gt;This is an &lt;a href="http://example.com/" title="With a Title"&gt;
+ example link&lt;/a&gt;.&lt;/p&gt;
+
+Reference-style links allow you to refer to your links by names, which
+you define elsewhere in your document:
+
+ I get 10 times more traffic from [Google][1] than from
+ [Yahoo][2] or [MSN][3].
+
+ [1]: http://google.com/ "Google"
+ [2]: http://search.yahoo.com/ "Yahoo Search"
+ [3]: http://search.msn.com/ "MSN Search"
+
+Output:
+
+ &lt;p&gt;I get 10 times more traffic from &lt;a href="http://google.com/"
+ title="Google"&gt;Google&lt;/a&gt; than from &lt;a href="http://search.yahoo.com/"
+ title="Yahoo Search"&gt;Yahoo&lt;/a&gt; or &lt;a href="http://search.msn.com/"
+ title="MSN Search"&gt;MSN&lt;/a&gt;.&lt;/p&gt;
+
+The title attribute is optional. Link names may contain letters,
+numbers and spaces, but are *not* case sensitive:
+
+ I start my morning with a cup of coffee and
+ [The New York Times][NY Times].
+
+ [ny times]: http://www.nytimes.com/
+
+Output:
+
+ &lt;p&gt;I start my morning with a cup of coffee and
+ &lt;a href="http://www.nytimes.com/"&gt;The New York Times&lt;/a&gt;.&lt;/p&gt;
+
+
+### Images ###
+
+Image syntax is very much like link syntax.
+
+Inline (titles are optional):
+
+ ![alt text](/path/to/img.jpg "Title")
+
+Reference-style:
+
+ ![alt text][id]
+
+ [id]: /path/to/img.jpg "Title"
+
+Both of the above examples produce the same output:
+
+ &lt;img src="/path/to/img.jpg" alt="alt text" title="Title" /&gt;
+
+
+
+### Code ###
+
+In a regular paragraph, you can create code span by wrapping text in
+backtick quotes. Any ampersands (`&amp;`) and angle brackets (`&lt;` or
+`&gt;`) will automatically be translated into HTML entities. This makes
+it easy to use Markdown to write about HTML example code:
+
+ I strongly recommend against using any `&lt;blink&gt;` tags.
+
+ I wish SmartyPants used named entities like `&amp;mdash;`
+ instead of decimal-encoded entites like `&amp;#8212;`.
+
+Output:
+
+ &lt;p&gt;I strongly recommend against using any
+ &lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
+
+ &lt;p&gt;I wish SmartyPants used named entities like
+ &lt;code&gt;&amp;amp;mdash;&lt;/code&gt; instead of decimal-encoded
+ entites like &lt;code&gt;&amp;amp;#8212;&lt;/code&gt;.&lt;/p&gt;
+
+
+To specify an entire block of pre-formatted code, indent every line of
+the block by 4 spaces or 1 tab. Just like with code spans, `&amp;`, `&lt;`,
+and `&gt;` characters will be escaped automatically.
+
+Markdown:
+
+ If you want your page to validate under XHTML 1.0 Strict,
+ you've got to put paragraph tags in your blockquotes:
+
+ &lt;blockquote&gt;
+ &lt;p&gt;For example.&lt;/p&gt;
+ &lt;/blockquote&gt;
+
+Output:
+
+ &lt;p&gt;If you want your page to validate under XHTML 1.0 Strict,
+ you've got to put paragraph tags in your blockquotes:&lt;/p&gt;
+
+ &lt;pre&gt;&lt;code&gt;&amp;lt;blockquote&amp;gt;
+ &amp;lt;p&amp;gt;For example.&amp;lt;/p&amp;gt;
+ &amp;lt;/blockquote&amp;gt;
+ &lt;/code&gt;&lt;/pre&gt;
+</textarea></form>
+
+ <script>
+ var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
+ mode: 'markdown',
+ lineNumbers: true,
+ theme: "default",
+ extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}
+ });
+ </script>
+
+ <p>Optionally depends on the XML mode for properly highlighted inline XML blocks.</p>
+
+ <p><strong>MIME types defined:</strong> <code>text/x-markdown</code>.</p>
+
+ <p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#markdown_*">normal</a>, <a href="../../test/index.html#verbose,markdown_*">verbose</a>.</p>
+
+ </article>
diff --git a/public/vendor/codemirror/mode/markdown/markdown.js b/public/vendor/codemirror/mode/markdown/markdown.js
new file mode 100755
index 00000000..bc5314fc
--- /dev/null
+++ b/public/vendor/codemirror/mode/markdown/markdown.js
@@ -0,0 +1,767 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
+ mod(require("../../lib/codemirror"), require("../xml/xml"), require("../meta"));
+ else if (typeof define == "function" && define.amd) // AMD
+ define(["../../lib/codemirror", "../xml/xml", "../meta"], mod);
+ else // Plain browser env
+ mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
+
+ var htmlFound = CodeMirror.modes.hasOwnProperty("xml");
+ var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: "xml", htmlMode: true} : "text/plain");
+
+ function getMode(name) {
+ if (CodeMirror.findModeByName) {
+ var found = CodeMirror.findModeByName(name);
+ if (found) name = found.mime || found.mimes[0];
+ }
+ var mode = CodeMirror.getMode(cmCfg, name);
+ return mode.name == "null" ? null : mode;
+ }
+
+ // Should characters that affect highlighting be highlighted separate?
+ // Does not include characters that will be output (such as `1.` and `-` for lists)
+ if (modeCfg.highlightFormatting === undefined)
+ modeCfg.highlightFormatting = false;
+
+ // Maximum number of nested blockquotes. Set to 0 for infinite nesting.
+ // Excess `>` will emit `error` token.
+ if (modeCfg.maxBlockquoteDepth === undefined)
+ modeCfg.maxBlockquoteDepth = 0;
+
+ // Should underscores in words open/close em/strong?
+ if (modeCfg.underscoresBreakWords === undefined)
+ modeCfg.underscoresBreakWords = true;
+
+ // Turn on fenced code blocks? ("```" to start/end)
+ if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false;
+
+ // Turn on task lists? ("- [ ] " and "- [x] ")
+ if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
+
+ // Turn on strikethrough syntax
+ if (modeCfg.strikethrough === undefined)
+ modeCfg.strikethrough = false;
+
+ var codeDepth = 0;
+
+ var header = 'header'
+ , code = 'comment'
+ , quote = 'quote'
+ , list1 = 'variable-2'
+ , list2 = 'variable-3'
+ , list3 = 'keyword'
+ , hr = 'hr'
+ , image = 'tag'
+ , formatting = 'formatting'
+ , linkinline = 'link'
+ , linkemail = 'link'
+ , linktext = 'link'
+ , linkhref = 'string'
+ , em = 'em'
+ , strong = 'strong'
+ , strikethrough = 'strikethrough';
+
+ var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
+ , ulRE = /^[*\-+]\s+/
+ , olRE = /^[0-9]+\.\s+/
+ , taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE
+ , atxHeaderRE = /^#+ ?/
+ , setextHeaderRE = /^(?:\={1,}|-{1,})$/
+ , textRE = /^[^#!\[\]*_\\<>` "'(~]+/;
+
+ function switchInline(stream, state, f) {
+ state.f = state.inline = f;
+ return f(stream, state);
+ }
+
+ function switchBlock(stream, state, f) {
+ state.f = state.block = f;
+ return f(stream, state);
+ }
+
+
+ // Blocks
+
+ function blankLine(state) {
+ // Reset linkTitle state
+ state.linkTitle = false;
+ // Reset EM state
+ state.em = false;
+ // Reset STRONG state
+ state.strong = false;
+ // Reset strikethrough state
+ state.strikethrough = false;
+ // Reset state.quote
+ state.quote = 0;
+ if (!htmlFound && state.f == htmlBlock) {
+ state.f = inlineNormal;
+ state.block = blockNormal;
+ }
+ // Reset state.trailingSpace
+ state.trailingSpace = 0;
+ state.trailingSpaceNewLine = false;
+ // Mark this line as blank
+ state.thisLineHasContent = false;
+ return null;
+ }
+
+ function blockNormal(stream, state) {
+
+ var sol = stream.sol();
+
+ var prevLineIsList = state.list !== false;
+ if (prevLineIsList) {
+ if (state.indentationDiff >= 0) { // Continued list
+ if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
+ state.indentation -= state.indentationDiff;
+ }
+ state.list = null;
+ } else if (state.indentation > 0) {
+ state.list = null;
+ state.listDepth = Math.floor(state.indentation / 4);
+ } else { // No longer a list
+ state.list = false;
+ state.listDepth = 0;
+ }
+ }
+
+ var match = null;
+ if (state.indentationDiff >= 4) {
+ state.indentation -= 4;
+ stream.skipToEnd();
+ return code;
+ } else if (stream.eatSpace()) {
+ return null;
+ } else if (match = stream.match(atxHeaderRE)) {
+ state.header = Math.min(6, match[0].indexOf(" ") !== -1 ? match[0].length - 1 : match[0].length);
+ if (modeCfg.highlightFormatting) state.formatting = "header";
+ state.f = state.inline;
+ return getType(state);
+ } else if (state.prevLineHasContent && (match = stream.match(setextHeaderRE))) {
+ state.header = match[0].charAt(0) == '=' ? 1 : 2;
+ if (modeCfg.highlightFormatting) state.formatting = "header";
+ state.f = state.inline;
+ return getType(state);
+ } else if (stream.eat('>')) {
+ state.indentation++;
+ state.quote = sol ? 1 : state.quote + 1;
+ if (modeCfg.highlightFormatting) state.formatting = "quote";
+ stream.eatSpace();
+ return getType(state);
+ } else if (stream.peek() === '[') {
+ return switchInline(stream, state, footnoteLink);
+ } else if (stream.match(hrRE, true)) {
+ return hr;
+ } else if ((!state.prevLineHasContent || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) {
+ var listType = null;
+ if (stream.match(ulRE, true)) {
+ listType = 'ul';
+ } else {
+ stream.match(olRE, true);
+ listType = 'ol';
+ }
+ state.indentation += 4;
+ state.list = true;
+ state.listDepth++;
+ if (modeCfg.taskLists && stream.match(taskListRE, false)) {
+ state.taskList = true;
+ }
+ state.f = state.inline;
+ if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType];
+ return getType(state);
+ } else if (modeCfg.fencedCodeBlocks && stream.match(/^```[ \t]*([\w+#]*)/, true)) {
+ // try switching mode
+ state.localMode = getMode(RegExp.$1);
+ if (state.localMode) state.localState = state.localMode.startState();
+ state.f = state.block = local;
+ if (modeCfg.highlightFormatting) state.formatting = "code-block";
+ state.code = true;
+ return getType(state);
+ }
+
+ return switchInline(stream, state, state.inline);
+ }
+
+ function htmlBlock(stream, state) {
+ var style = htmlMode.token(stream, state.htmlState);
+ if ((htmlFound && state.htmlState.tagStart === null && !state.htmlState.context) ||
+ (state.md_inside && stream.current().indexOf(">") > -1)) {
+ state.f = inlineNormal;
+ state.block = blockNormal;
+ state.htmlState = null;
+ }
+ return style;
+ }
+
+ function local(stream, state) {
+ if (stream.sol() && stream.match("```", false)) {
+ state.localMode = state.localState = null;
+ state.f = state.block = leavingLocal;
+ return null;
+ } else if (state.localMode) {
+ return state.localMode.token(stream, state.localState);
+ } else {
+ stream.skipToEnd();
+ return code;
+ }
+ }
+
+ function leavingLocal(stream, state) {
+ stream.match("```");
+ state.block = blockNormal;
+ state.f = inlineNormal;
+ if (modeCfg.highlightFormatting) state.formatting = "code-block";
+ state.code = true;
+ var returnType = getType(state);
+ state.code = false;
+ return returnType;
+ }
+
+ // Inline
+ function getType(state) {
+ var styles = [];
+
+ if (state.formatting) {
+ styles.push(formatting);
+
+ if (typeof state.formatting === "string") state.formatting = [state.formatting];
+
+ for (var i = 0; i < state.formatting.length; i++) {
+ styles.push(formatting + "-" + state.formatting[i]);
+
+ if (state.formatting[i] === "header") {
+ styles.push(formatting + "-" + state.formatting[i] + "-" + state.header);
+ }
+
+ // Add `formatting-quote` and `formatting-quote-#` for blockquotes
+ // Add `error` instead if the maximum blockquote nesting depth is passed
+ if (state.formatting[i] === "quote") {
+ if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
+ styles.push(formatting + "-" + state.formatting[i] + "-" + state.quote);
+ } else {
+ styles.push("error");
+ }
+ }
+ }
+ }
+
+ if (state.taskOpen) {
+ styles.push("meta");
+ return styles.length ? styles.join(' ') : null;
+ }
+ if (state.taskClosed) {
+ styles.push("property");
+ return styles.length ? styles.join(' ') : null;
+ }
+
+ if (state.linkHref) {
+ styles.push(linkhref);
+ return styles.length ? styles.join(' ') : null;
+ }
+
+ if (state.strong) { styles.push(strong); }
+ if (state.em) { styles.push(em); }
+ if (state.strikethrough) { styles.push(strikethrough); }
+
+ if (state.linkText) { styles.push(linktext); }
+
+ if (state.code) { styles.push(code); }
+
+ if (state.header) { styles.push(header); styles.push(header + "-" + state.header); }
+
+ if (state.quote) {
+ styles.push(quote);
+
+ // Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth
+ if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
+ styles.push(quote + "-" + state.quote);
+ } else {
+ styles.push(quote + "-" + modeCfg.maxBlockquoteDepth);
+ }
+ }
+
+ if (state.list !== false) {
+ var listMod = (state.listDepth - 1) % 3;
+ if (!listMod) {
+ styles.push(list1);
+ } else if (listMod === 1) {
+ styles.push(list2);
+ } else {
+ styles.push(list3);
+ }
+ }
+
+ if (state.trailingSpaceNewLine) {
+ styles.push("trailing-space-new-line");
+ } else if (state.trailingSpace) {
+ styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b"));
+ }
+
+ return styles.length ? styles.join(' ') : null;
+ }
+
+ function handleText(stream, state) {
+ if (stream.match(textRE, true)) {
+ return getType(state);
+ }
+ return undefined;
+ }
+
+ function inlineNormal(stream, state) {
+ var style = state.text(stream, state);
+ if (typeof style !== 'undefined')
+ return style;
+
+ if (state.list) { // List marker (*, +, -, 1., etc)
+ state.list = null;
+ return getType(state);
+ }
+
+ if (state.taskList) {
+ var taskOpen = stream.match(taskListRE, true)[1] !== "x";
+ if (taskOpen) state.taskOpen = true;
+ else state.taskClosed = true;
+ if (modeCfg.highlightFormatting) state.formatting = "task";
+ state.taskList = false;
+ return getType(state);
+ }
+
+ state.taskOpen = false;
+ state.taskClosed = false;
+
+ if (state.header && stream.match(/^#+$/, true)) {
+ if (modeCfg.highlightFormatting) state.formatting = "header";
+ return getType(state);
+ }
+
+ // Get sol() value now, before character is consumed
+ var sol = stream.sol();
+
+ var ch = stream.next();
+
+ if (ch === '\\') {
+ stream.next();
+ if (modeCfg.highlightFormatting) {
+ var type = getType(state);
+ return type ? type + " formatting-escape" : "formatting-escape";
+ }
+ }
+
+ // Matches link titles present on next line
+ if (state.linkTitle) {
+ state.linkTitle = false;
+ var matchCh = ch;
+ if (ch === '(') {
+ matchCh = ')';
+ }
+ matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
+ var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
+ if (stream.match(new RegExp(regex), true)) {
+ return linkhref;
+ }
+ }
+
+ // If this block is changed, it may need to be updated in GFM mode
+ if (ch === '`') {
+ var previousFormatting = state.formatting;
+ if (modeCfg.highlightFormatting) state.formatting = "code";
+ var t = getType(state);
+ var before = stream.pos;
+ stream.eatWhile('`');
+ var difference = 1 + stream.pos - before;
+ if (!state.code) {
+ codeDepth = difference;
+ state.code = true;
+ return getType(state);
+ } else {
+ if (difference === codeDepth) { // Must be exact
+ state.code = false;
+ return t;
+ }
+ state.formatting = previousFormatting;
+ return getType(state);
+ }
+ } else if (state.code) {
+ return getType(state);
+ }
+
+ if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
+ stream.match(/\[[^\]]*\]/);
+ state.inline = state.f = linkHref;
+ return image;
+ }
+
+ if (ch === '[' && stream.match(/.*\](\(.*\)| ?\[.*\])/, false)) {
+ state.linkText = true;
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ return getType(state);
+ }
+
+ if (ch === ']' && state.linkText && stream.match(/\(.*\)| ?\[.*\]/, false)) {
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ var type = getType(state);
+ state.linkText = false;
+ state.inline = state.f = linkHref;
+ return type;
+ }
+
+ if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) {
+ state.f = state.inline = linkInline;
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ var type = getType(state);
+ if (type){
+ type += " ";
+ } else {
+ type = "";
+ }
+ return type + linkinline;
+ }
+
+ if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) {
+ state.f = state.inline = linkInline;
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ var type = getType(state);
+ if (type){
+ type += " ";
+ } else {
+ type = "";
+ }
+ return type + linkemail;
+ }
+
+ if (ch === '<' && stream.match(/^\w/, false)) {
+ if (stream.string.indexOf(">") != -1) {
+ var atts = stream.string.substring(1,stream.string.indexOf(">"));
+ if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) {
+ state.md_inside = true;
+ }
+ }
+ stream.backUp(1);
+ state.htmlState = CodeMirror.startState(htmlMode);
+ return switchBlock(stream, state, htmlBlock);
+ }
+
+ if (ch === '<' && stream.match(/^\/\w*?>/)) {
+ state.md_inside = false;
+ return "tag";
+ }
+
+ var ignoreUnderscore = false;
+ if (!modeCfg.underscoresBreakWords) {
+ if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) {
+ var prevPos = stream.pos - 2;
+ if (prevPos >= 0) {
+ var prevCh = stream.string.charAt(prevPos);
+ if (prevCh !== '_' && prevCh.match(/(\w)/, false)) {
+ ignoreUnderscore = true;
+ }
+ }
+ }
+ }
+ if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {
+ if (sol && stream.peek() === ' ') {
+ // Do nothing, surrounded by newline and space
+ } else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
+ if (modeCfg.highlightFormatting) state.formatting = "strong";
+ var t = getType(state);
+ state.strong = false;
+ return t;
+ } else if (!state.strong && stream.eat(ch)) { // Add STRONG
+ state.strong = ch;
+ if (modeCfg.highlightFormatting) state.formatting = "strong";
+ return getType(state);
+ } else if (state.em === ch) { // Remove EM
+ if (modeCfg.highlightFormatting) state.formatting = "em";
+ var t = getType(state);
+ state.em = false;
+ return t;
+ } else if (!state.em) { // Add EM
+ state.em = ch;
+ if (modeCfg.highlightFormatting) state.formatting = "em";
+ return getType(state);
+ }
+ } else if (ch === ' ') {
+ if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
+ if (stream.peek() === ' ') { // Surrounded by spaces, ignore
+ return getType(state);
+ } else { // Not surrounded by spaces, back up pointer
+ stream.backUp(1);
+ }
+ }
+ }
+
+ if (modeCfg.strikethrough) {
+ if (ch === '~' && stream.eatWhile(ch)) {
+ if (state.strikethrough) {// Remove strikethrough
+ if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
+ var t = getType(state);
+ state.strikethrough = false;
+ return t;
+ } else if (stream.match(/^[^\s]/, false)) {// Add strikethrough
+ state.strikethrough = true;
+ if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
+ return getType(state);
+ }
+ } else if (ch === ' ') {
+ if (stream.match(/^~~/, true)) { // Probably surrounded by space
+ if (stream.peek() === ' ') { // Surrounded by spaces, ignore
+ return getType(state);
+ } else { // Not surrounded by spaces, back up pointer
+ stream.backUp(2);
+ }
+ }
+ }
+ }
+
+ if (ch === ' ') {
+ if (stream.match(/ +$/, false)) {
+ state.trailingSpace++;
+ } else if (state.trailingSpace) {
+ state.trailingSpaceNewLine = true;
+ }
+ }
+
+ return getType(state);
+ }
+
+ function linkInline(stream, state) {
+ var ch = stream.next();
+
+ if (ch === ">") {
+ state.f = state.inline = inlineNormal;
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ var type = getType(state);
+ if (type){
+ type += " ";
+ } else {
+ type = "";
+ }
+ return type + linkinline;
+ }
+
+ stream.match(/^[^>]+/, true);
+
+ return linkinline;
+ }
+
+ function linkHref(stream, state) {
+ // Check if space, and return NULL if so (to avoid marking the space)
+ if(stream.eatSpace()){
+ return null;
+ }
+ var ch = stream.next();
+ if (ch === '(' || ch === '[') {
+ state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]");
+ if (modeCfg.highlightFormatting) state.formatting = "link-string";
+ state.linkHref = true;
+ return getType(state);
+ }
+ return 'error';
+ }
+
+ function getLinkHrefInside(endChar) {
+ return function(stream, state) {
+ var ch = stream.next();
+
+ if (ch === endChar) {
+ state.f = state.inline = inlineNormal;
+ if (modeCfg.highlightFormatting) state.formatting = "link-string";
+ var returnState = getType(state);
+ state.linkHref = false;
+ return returnState;
+ }
+
+ if (stream.match(inlineRE(endChar), true)) {
+ stream.backUp(1);
+ }
+
+ state.linkHref = true;
+ return getType(state);
+ };
+ }
+
+ function footnoteLink(stream, state) {
+ if (stream.match(/^[^\]]*\]:/, false)) {
+ state.f = footnoteLinkInside;
+ stream.next(); // Consume [
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ state.linkText = true;
+ return getType(state);
+ }
+ return switchInline(stream, state, inlineNormal);
+ }
+
+ function footnoteLinkInside(stream, state) {
+ if (stream.match(/^\]:/, true)) {
+ state.f = state.inline = footnoteUrl;
+ if (modeCfg.highlightFormatting) state.formatting = "link";
+ var returnType = getType(state);
+ state.linkText = false;
+ return returnType;
+ }
+
+ stream.match(/^[^\]]+/, true);
+
+ return linktext;
+ }
+
+ function footnoteUrl(stream, state) {
+ // Check if space, and return NULL if so (to avoid marking the space)
+ if(stream.eatSpace()){
+ return null;
+ }
+ // Match URL
+ stream.match(/^[^\s]+/, true);
+ // Check for link title
+ if (stream.peek() === undefined) { // End of line, set flag to check next line
+ state.linkTitle = true;
+ } else { // More content on line, check if link title
+ stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true);
+ }
+ state.f = state.inline = inlineNormal;
+ return linkhref;
+ }
+
+ var savedInlineRE = [];
+ function inlineRE(endChar) {
+ if (!savedInlineRE[endChar]) {
+ // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)
+ endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
+ // Match any non-endChar, escaped character, as well as the closing
+ // endChar.
+ savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')');
+ }
+ return savedInlineRE[endChar];
+ }
+
+ var mode = {
+ startState: function() {
+ return {
+ f: blockNormal,
+
+ prevLineHasContent: false,
+ thisLineHasContent: false,
+
+ block: blockNormal,
+ htmlState: null,
+ indentation: 0,
+
+ inline: inlineNormal,
+ text: handleText,
+
+ formatting: false,
+ linkText: false,
+ linkHref: false,
+ linkTitle: false,
+ em: false,
+ strong: false,
+ header: 0,
+ taskList: false,
+ list: false,
+ listDepth: 0,
+ quote: 0,
+ trailingSpace: 0,
+ trailingSpaceNewLine: false,
+ strikethrough: false
+ };
+ },
+
+ copyState: function(s) {
+ return {
+ f: s.f,
+
+ prevLineHasContent: s.prevLineHasContent,
+ thisLineHasContent: s.thisLineHasContent,
+
+ block: s.block,
+ htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState),
+ indentation: s.indentation,
+
+ localMode: s.localMode,
+ localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
+
+ inline: s.inline,
+ text: s.text,
+ formatting: false,
+ linkTitle: s.linkTitle,
+ em: s.em,
+ strong: s.strong,
+ strikethrough: s.strikethrough,
+ header: s.header,
+ taskList: s.taskList,
+ list: s.list,
+ listDepth: s.listDepth,
+ quote: s.quote,
+ trailingSpace: s.trailingSpace,
+ trailingSpaceNewLine: s.trailingSpaceNewLine,
+ md_inside: s.md_inside
+ };
+ },
+
+ token: function(stream, state) {
+
+ // Reset state.formatting
+ state.formatting = false;
+
+ if (stream.sol()) {
+ var forceBlankLine = !!state.header;
+
+ // Reset state.header
+ state.header = 0;
+
+ if (stream.match(/^\s*$/, true) || forceBlankLine) {
+ state.prevLineHasContent = false;
+ blankLine(state);
+ return forceBlankLine ? this.token(stream, state) : null;
+ } else {
+ state.prevLineHasContent = state.thisLineHasContent;
+ state.thisLineHasContent = true;
+ }
+
+ // Reset state.taskList
+ state.taskList = false;
+
+ // Reset state.code
+ state.code = false;
+
+ // Reset state.trailingSpace
+ state.trailingSpace = 0;
+ state.trailingSpaceNewLine = false;
+
+ state.f = state.block;
+ var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
+ var difference = Math.floor((indentation - state.indentation) / 4) * 4;
+ if (difference > 4) difference = 4;
+ var adjustedIndentation = state.indentation + difference;
+ state.indentationDiff = adjustedIndentation - state.indentation;
+ state.indentation = adjustedIndentation;
+ if (indentation > 0) return null;
+ }
+ return state.f(stream, state);
+ },
+
+ innerMode: function(state) {
+ if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode};
+ if (state.localState) return {state: state.localState, mode: state.localMode};
+ return {state: state, mode: mode};
+ },
+
+ blankLine: blankLine,
+
+ getType: getType,
+
+ fold: "markdown"
+ };
+ return mode;
+}, "xml");
+
+CodeMirror.defineMIME("text/x-markdown", "markdown");
+
+});
diff --git a/public/vendor/codemirror/mode/markdown/test.js b/public/vendor/codemirror/mode/markdown/test.js
new file mode 100755
index 00000000..7bc687f0
--- /dev/null
+++ b/public/vendor/codemirror/mode/markdown/test.js
@@ -0,0 +1,754 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function() {
+ var mode = CodeMirror.getMode({tabSize: 4}, "markdown");
+ function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
+ var modeHighlightFormatting = CodeMirror.getMode({tabSize: 4}, {name: "markdown", highlightFormatting: true});
+ function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); }
+
+ FT("formatting_emAsterisk",
+ "[em&formatting&formatting-em *][em foo][em&formatting&formatting-em *]");
+
+ FT("formatting_emUnderscore",
+ "[em&formatting&formatting-em _][em foo][em&formatting&formatting-em _]");
+
+ FT("formatting_strongAsterisk",
+ "[strong&formatting&formatting-strong **][strong foo][strong&formatting&formatting-strong **]");
+
+ FT("formatting_strongUnderscore",
+ "[strong&formatting&formatting-strong __][strong foo][strong&formatting&formatting-strong __]");
+
+ FT("formatting_codeBackticks",
+ "[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]");
+
+ FT("formatting_doubleBackticks",
+ "[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]");
+
+ FT("formatting_atxHeader",
+ "[header&header-1&formatting&formatting-header&formatting-header-1 # ][header&header-1 foo # bar ][header&header-1&formatting&formatting-header&formatting-header-1 #]");
+
+ FT("formatting_setextHeader",
+ "foo",
+ "[header&header-1&formatting&formatting-header&formatting-header-1 =]");
+
+ FT("formatting_blockquote",
+ "[quote&quote-1&formatting&formatting-quote&formatting-quote-1 > ][quote&quote-1 foo]");
+
+ FT("formatting_list",
+ "[variable-2&formatting&formatting-list&formatting-list-ul - ][variable-2 foo]");
+ FT("formatting_list",
+ "[variable-2&formatting&formatting-list&formatting-list-ol 1. ][variable-2 foo]");
+
+ FT("formatting_link",
+ "[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string (][string http://example.com/][string&formatting&formatting-link-string )]");
+
+ FT("formatting_linkReference",
+ "[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string [][string bar][string&formatting&formatting-link-string ]]]",
+ "[link&formatting&formatting-link [][link bar][link&formatting&formatting-link ]]:] [string http://example.com/]");
+
+ FT("formatting_linkWeb",
+ "[link&formatting&formatting-link <][link http://example.com/][link&formatting&formatting-link >]");
+
+ FT("formatting_linkEmail",
+ "[link&formatting&formatting-link <][link user@example.com][link&formatting&formatting-link >]");
+
+ FT("formatting_escape",
+ "[formatting-escape \\*]");
+
+ MT("plainText",
+ "foo");
+
+ // Don't style single trailing space
+ MT("trailingSpace1",
+ "foo ");
+
+ // Two or more trailing spaces should be styled with line break character
+ MT("trailingSpace2",
+ "foo[trailing-space-a ][trailing-space-new-line ]");
+
+ MT("trailingSpace3",
+ "foo[trailing-space-a ][trailing-space-b ][trailing-space-new-line ]");
+
+ MT("trailingSpace4",
+ "foo[trailing-space-a ][trailing-space-b ][trailing-space-a ][trailing-space-new-line ]");
+
+ // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
+ MT("codeBlocksUsing4Spaces",
+ " [comment foo]");
+
+ // Code blocks using 4 spaces with internal indentation
+ MT("codeBlocksUsing4SpacesIndentation",
+ " [comment bar]",
+ " [comment hello]",
+ " [comment world]",
+ " [comment foo]",
+ "bar");
+
+ // Code blocks using 4 spaces with internal indentation
+ MT("codeBlocksUsing4SpacesIndentation",
+ " foo",
+ " [comment bar]",
+ " [comment hello]",
+ " [comment world]");
+
+ // Code blocks should end even after extra indented lines
+ MT("codeBlocksWithTrailingIndentedLine",
+ " [comment foo]",
+ " [comment bar]",
+ " [comment baz]",
+ " ",
+ "hello");
+
+ // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
+ MT("codeBlocksUsing1Tab",
+ "\t[comment foo]");
+
+ // Inline code using backticks
+ MT("inlineCodeUsingBackticks",
+ "foo [comment `bar`]");
+
+ // Block code using single backtick (shouldn't work)
+ MT("blockCodeSingleBacktick",
+ "[comment `]",
+ "foo",
+ "[comment `]");
+
+ // Unclosed backticks
+ // Instead of simply marking as CODE, it would be nice to have an
+ // incomplete flag for CODE, that is styled slightly different.
+ MT("unclosedBackticks",
+ "foo [comment `bar]");
+
+ // Per documentation: "To include a literal backtick character within a
+ // code span, you can use multiple backticks as the opening and closing
+ // delimiters"
+ MT("doubleBackticks",
+ "[comment ``foo ` bar``]");
+
+ // Tests based on Dingus
+ // http://daringfireball.net/projects/markdown/dingus
+ //
+ // Multiple backticks within an inline code block
+ MT("consecutiveBackticks",
+ "[comment `foo```bar`]");
+
+ // Multiple backticks within an inline code block with a second code block
+ MT("consecutiveBackticks",
+ "[comment `foo```bar`] hello [comment `world`]");
+
+ // Unclosed with several different groups of backticks
+ MT("unclosedBackticks",
+ "[comment ``foo ``` bar` hello]");
+
+ // Closed with several different groups of backticks
+ MT("closedBackticks",
+ "[comment ``foo ``` bar` hello``] world");
+
+ // atx headers
+ // http://daringfireball.net/projects/markdown/syntax#header
+
+ MT("atxH1",
+ "[header&header-1 # foo]");
+
+ MT("atxH2",
+ "[header&header-2 ## foo]");
+
+ MT("atxH3",
+ "[header&header-3 ### foo]");
+
+ MT("atxH4",
+ "[header&header-4 #### foo]");
+
+ MT("atxH5",
+ "[header&header-5 ##### foo]");
+
+ MT("atxH6",
+ "[header&header-6 ###### foo]");
+
+ // H6 - 7x '#' should still be H6, per Dingus
+ // http://daringfireball.net/projects/markdown/dingus
+ MT("atxH6NotH7",
+ "[header&header-6 ####### foo]");
+
+ // Inline styles should be parsed inside headers
+ MT("atxH1inline",
+ "[header&header-1 # foo ][header&header-1&em *bar*]");
+
+ // Setext headers - H1, H2
+ // Per documentation, "Any number of underlining =’s or -’s will work."
+ // http://daringfireball.net/projects/markdown/syntax#header
+ // Ideally, the text would be marked as `header` as well, but this is
+ // not really feasible at the moment. So, instead, we're testing against
+ // what works today, to avoid any regressions.
+ //
+ // Check if single underlining = works
+ MT("setextH1",
+ "foo",
+ "[header&header-1 =]");
+
+ // Check if 3+ ='s work
+ MT("setextH1",
+ "foo",
+ "[header&header-1 ===]");
+
+ // Check if single underlining - works
+ MT("setextH2",
+ "foo",
+ "[header&header-2 -]");
+
+ // Check if 3+ -'s work
+ MT("setextH2",
+ "foo",
+ "[header&header-2 ---]");
+
+ // Single-line blockquote with trailing space
+ MT("blockquoteSpace",
+ "[quote&quote-1 > foo]");
+
+ // Single-line blockquote
+ MT("blockquoteNoSpace",
+ "[quote&quote-1 >foo]");
+
+ // No blank line before blockquote
+ MT("blockquoteNoBlankLine",
+ "foo",
+ "[quote&quote-1 > bar]");
+
+ // Nested blockquote
+ MT("blockquoteSpace",
+ "[quote&quote-1 > foo]",
+ "[quote&quote-1 >][quote&quote-2 > foo]",
+ "[quote&quote-1 >][quote&quote-2 >][quote&quote-3 > foo]");
+
+ // Single-line blockquote followed by normal paragraph
+ MT("blockquoteThenParagraph",
+ "[quote&quote-1 >foo]",
+ "",
+ "bar");
+
+ // Multi-line blockquote (lazy mode)
+ MT("multiBlockquoteLazy",
+ "[quote&quote-1 >foo]",
+ "[quote&quote-1 bar]");
+
+ // Multi-line blockquote followed by normal paragraph (lazy mode)
+ MT("multiBlockquoteLazyThenParagraph",
+ "[quote&quote-1 >foo]",
+ "[quote&quote-1 bar]",
+ "",
+ "hello");
+
+ // Multi-line blockquote (non-lazy mode)
+ MT("multiBlockquote",
+ "[quote&quote-1 >foo]",
+ "[quote&quote-1 >bar]");
+
+ // Multi-line blockquote followed by normal paragraph (non-lazy mode)
+ MT("multiBlockquoteThenParagraph",
+ "[quote&quote-1 >foo]",
+ "[quote&quote-1 >bar]",
+ "",
+ "hello");
+
+ // Check list types
+
+ MT("listAsterisk",
+ "foo",
+ "bar",
+ "",
+ "[variable-2 * foo]",
+ "[variable-2 * bar]");
+
+ MT("listPlus",
+ "foo",
+ "bar",
+ "",
+ "[variable-2 + foo]",
+ "[variable-2 + bar]");
+
+ MT("listDash",
+ "foo",
+ "bar",
+ "",
+ "[variable-2 - foo]",
+ "[variable-2 - bar]");
+
+ MT("listNumber",
+ "foo",
+ "bar",
+ "",
+ "[variable-2 1. foo]",
+ "[variable-2 2. bar]");
+
+ // Lists require a preceding blank line (per Dingus)
+ MT("listBogus",
+ "foo",
+ "1. bar",
+ "2. hello");
+
+ // List after header
+ MT("listAfterHeader",
+ "[header&header-1 # foo]",
+ "[variable-2 - bar]");
+
+ // Formatting in lists (*)
+ MT("listAsteriskFormatting",
+ "[variable-2 * ][variable-2&em *foo*][variable-2 bar]",
+ "[variable-2 * ][variable-2&strong **foo**][variable-2 bar]",
+ "[variable-2 * ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
+ "[variable-2 * ][variable-2&comment `foo`][variable-2 bar]");
+
+ // Formatting in lists (+)
+ MT("listPlusFormatting",
+ "[variable-2 + ][variable-2&em *foo*][variable-2 bar]",
+ "[variable-2 + ][variable-2&strong **foo**][variable-2 bar]",
+ "[variable-2 + ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
+ "[variable-2 + ][variable-2&comment `foo`][variable-2 bar]");
+
+ // Formatting in lists (-)
+ MT("listDashFormatting",
+ "[variable-2 - ][variable-2&em *foo*][variable-2 bar]",
+ "[variable-2 - ][variable-2&strong **foo**][variable-2 bar]",
+ "[variable-2 - ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
+ "[variable-2 - ][variable-2&comment `foo`][variable-2 bar]");
+
+ // Formatting in lists (1.)
+ MT("listNumberFormatting",
+ "[variable-2 1. ][variable-2&em *foo*][variable-2 bar]",
+ "[variable-2 2. ][variable-2&strong **foo**][variable-2 bar]",
+ "[variable-2 3. ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
+ "[variable-2 4. ][variable-2&comment `foo`][variable-2 bar]");
+
+ // Paragraph lists
+ MT("listParagraph",
+ "[variable-2 * foo]",
+ "",
+ "[variable-2 * bar]");
+
+ // Multi-paragraph lists
+ //
+ // 4 spaces
+ MT("listMultiParagraph",
+ "[variable-2 * foo]",
+ "",
+ "[variable-2 * bar]",
+ "",
+ " [variable-2 hello]");
+
+ // 4 spaces, extra blank lines (should still be list, per Dingus)
+ MT("listMultiParagraphExtra",
+ "[variable-2 * foo]",
+ "",
+ "[variable-2 * bar]",
+ "",
+ "",
+ " [variable-2 hello]");
+
+ // 4 spaces, plus 1 space (should still be list, per Dingus)
+ MT("listMultiParagraphExtraSpace",
+ "[variable-2 * foo]",
+ "",
+ "[variable-2 * bar]",
+ "",
+ " [variable-2 hello]",
+ "",
+ " [variable-2 world]");
+
+ // 1 tab
+ MT("listTab",
+ "[variable-2 * foo]",
+ "",
+ "[variable-2 * bar]",
+ "",
+ "\t[variable-2 hello]");
+
+ // No indent
+ MT("listNoIndent",
+ "[variable-2 * foo]",
+ "",
+ "[variable-2 * bar]",
+ "",
+ "hello");
+
+ // Blockquote
+ MT("blockquote",
+ "[variable-2 * foo]",
+ "",
+ "[variable-2 * bar]",
+ "",
+ " [variable-2&quote&quote-1 > hello]");
+
+ // Code block
+ MT("blockquoteCode",
+ "[variable-2 * foo]",
+ "",
+ "[variable-2 * bar]",
+ "",
+ " [comment > hello]",
+ "",
+ " [variable-2 world]");
+
+ // Code block followed by text
+ MT("blockquoteCodeText",
+ "[variable-2 * foo]",
+ "",
+ " [variable-2 bar]",
+ "",
+ " [comment hello]",
+ "",
+ " [variable-2 world]");
+
+ // Nested list
+
+ MT("listAsteriskNested",
+ "[variable-2 * foo]",
+ "",
+ " [variable-3 * bar]");
+
+ MT("listPlusNested",
+ "[variable-2 + foo]",
+ "",
+ " [variable-3 + bar]");
+
+ MT("listDashNested",
+ "[variable-2 - foo]",
+ "",
+ " [variable-3 - bar]");
+
+ MT("listNumberNested",
+ "[variable-2 1. foo]",
+ "",
+ " [variable-3 2. bar]");
+
+ MT("listMixed",
+ "[variable-2 * foo]",
+ "",
+ " [variable-3 + bar]",
+ "",
+ " [keyword - hello]",
+ "",
+ " [variable-2 1. world]");
+
+ MT("listBlockquote",
+ "[variable-2 * foo]",
+ "",
+ " [variable-3 + bar]",
+ "",
+ " [quote&quote-1&variable-3 > hello]");
+
+ MT("listCode",
+ "[variable-2 * foo]",
+ "",
+ " [variable-3 + bar]",
+ "",
+ " [comment hello]");
+
+ // Code with internal indentation
+ MT("listCodeIndentation",
+ "[variable-2 * foo]",
+ "",
+ " [comment bar]",
+ " [comment hello]",
+ " [comment world]",
+ " [comment foo]",
+ " [variable-2 bar]");
+
+ // List nesting edge cases
+ MT("listNested",
+ "[variable-2 * foo]",
+ "",
+ " [variable-3 * bar]",
+ "",
+ " [variable-2 hello]"
+ );
+ MT("listNested",
+ "[variable-2 * foo]",
+ "",
+ " [variable-3 * bar]",
+ "",
+ " [variable-3 * foo]"
+ );
+
+ // Code followed by text
+ MT("listCodeText",
+ "[variable-2 * foo]",
+ "",
+ " [comment bar]",
+ "",
+ "hello");
+
+ // Following tests directly from official Markdown documentation
+ // http://daringfireball.net/projects/markdown/syntax#hr
+
+ MT("hrSpace",
+ "[hr * * *]");
+
+ MT("hr",
+ "[hr ***]");
+
+ MT("hrLong",
+ "[hr *****]");
+
+ MT("hrSpaceDash",
+ "[hr - - -]");
+
+ MT("hrDashLong",
+ "[hr ---------------------------------------]");
+
+ // Inline link with title
+ MT("linkTitle",
+ "[link [[foo]]][string (http://example.com/ \"bar\")] hello");
+
+ // Inline link without title
+ MT("linkNoTitle",
+ "[link [[foo]]][string (http://example.com/)] bar");
+
+ // Inline link with image
+ MT("linkImage",
+ "[link [[][tag ![[foo]]][string (http://example.com/)][link ]]][string (http://example.com/)] bar");
+
+ // Inline link with Em
+ MT("linkEm",
+ "[link [[][link&em *foo*][link ]]][string (http://example.com/)] bar");
+
+ // Inline link with Strong
+ MT("linkStrong",
+ "[link [[][link&strong **foo**][link ]]][string (http://example.com/)] bar");
+
+ // Inline link with EmStrong
+ MT("linkEmStrong",
+ "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string (http://example.com/)] bar");
+
+ // Image with title
+ MT("imageTitle",
+ "[tag ![[foo]]][string (http://example.com/ \"bar\")] hello");
+
+ // Image without title
+ MT("imageNoTitle",
+ "[tag ![[foo]]][string (http://example.com/)] bar");
+
+ // Image with asterisks
+ MT("imageAsterisks",
+ "[tag ![[*foo*]]][string (http://example.com/)] bar");
+
+ // Not a link. Should be normal text due to square brackets being used
+ // regularly in text, especially in quoted material, and no space is allowed
+ // between square brackets and parentheses (per Dingus).
+ MT("notALink",
+ "[[foo]] (bar)");
+
+ // Reference-style links
+ MT("linkReference",
+ "[link [[foo]]][string [[bar]]] hello");
+
+ // Reference-style links with Em
+ MT("linkReferenceEm",
+ "[link [[][link&em *foo*][link ]]][string [[bar]]] hello");
+
+ // Reference-style links with Strong
+ MT("linkReferenceStrong",
+ "[link [[][link&strong **foo**][link ]]][string [[bar]]] hello");
+
+ // Reference-style links with EmStrong
+ MT("linkReferenceEmStrong",
+ "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string [[bar]]] hello");
+
+ // Reference-style links with optional space separator (per docuentation)
+ // "You can optionally use a space to separate the sets of brackets"
+ MT("linkReferenceSpace",
+ "[link [[foo]]] [string [[bar]]] hello");
+
+ // Should only allow a single space ("...use *a* space...")
+ MT("linkReferenceDoubleSpace",
+ "[[foo]] [[bar]] hello");
+
+ // Reference-style links with implicit link name
+ MT("linkImplicit",
+ "[link [[foo]]][string [[]]] hello");
+
+ // @todo It would be nice if, at some point, the document was actually
+ // checked to see if the referenced link exists
+
+ // Link label, for reference-style links (taken from documentation)
+
+ MT("labelNoTitle",
+ "[link [[foo]]:] [string http://example.com/]");
+
+ MT("labelIndented",
+ " [link [[foo]]:] [string http://example.com/]");
+
+ MT("labelSpaceTitle",
+ "[link [[foo bar]]:] [string http://example.com/ \"hello\"]");
+
+ MT("labelDoubleTitle",
+ "[link [[foo bar]]:] [string http://example.com/ \"hello\"] \"world\"");
+
+ MT("labelTitleDoubleQuotes",
+ "[link [[foo]]:] [string http://example.com/ \"bar\"]");
+
+ MT("labelTitleSingleQuotes",
+ "[link [[foo]]:] [string http://example.com/ 'bar']");
+
+ MT("labelTitleParenthese",
+ "[link [[foo]]:] [string http://example.com/ (bar)]");
+
+ MT("labelTitleInvalid",
+ "[link [[foo]]:] [string http://example.com/] bar");
+
+ MT("labelLinkAngleBrackets",
+ "[link [[foo]]:] [string <http://example.com/> \"bar\"]");
+
+ MT("labelTitleNextDoubleQuotes",
+ "[link [[foo]]:] [string http://example.com/]",
+ "[string \"bar\"] hello");
+
+ MT("labelTitleNextSingleQuotes",
+ "[link [[foo]]:] [string http://example.com/]",
+ "[string 'bar'] hello");
+
+ MT("labelTitleNextParenthese",
+ "[link [[foo]]:] [string http://example.com/]",
+ "[string (bar)] hello");
+
+ MT("labelTitleNextMixed",
+ "[link [[foo]]:] [string http://example.com/]",
+ "(bar\" hello");
+
+ MT("linkWeb",
+ "[link <http://example.com/>] foo");
+
+ MT("linkWebDouble",
+ "[link <http://example.com/>] foo [link <http://example.com/>]");
+
+ MT("linkEmail",
+ "[link <user@example.com>] foo");
+
+ MT("linkEmailDouble",
+ "[link <user@example.com>] foo [link <user@example.com>]");
+
+ MT("emAsterisk",
+ "[em *foo*] bar");
+
+ MT("emUnderscore",
+ "[em _foo_] bar");
+
+ MT("emInWordAsterisk",
+ "foo[em *bar*]hello");
+
+ MT("emInWordUnderscore",
+ "foo[em _bar_]hello");
+
+ // Per documentation: "...surround an * or _ with spaces, it’ll be
+ // treated as a literal asterisk or underscore."
+
+ MT("emEscapedBySpaceIn",
+ "foo [em _bar _ hello_] world");
+
+ MT("emEscapedBySpaceOut",
+ "foo _ bar[em _hello_]world");
+
+ MT("emEscapedByNewline",
+ "foo",
+ "_ bar[em _hello_]world");
+
+ // Unclosed emphasis characters
+ // Instead of simply marking as EM / STRONG, it would be nice to have an
+ // incomplete flag for EM and STRONG, that is styled slightly different.
+ MT("emIncompleteAsterisk",
+ "foo [em *bar]");
+
+ MT("emIncompleteUnderscore",
+ "foo [em _bar]");
+
+ MT("strongAsterisk",
+ "[strong **foo**] bar");
+
+ MT("strongUnderscore",
+ "[strong __foo__] bar");
+
+ MT("emStrongAsterisk",
+ "[em *foo][em&strong **bar*][strong hello**] world");
+
+ MT("emStrongUnderscore",
+ "[em _foo][em&strong __bar_][strong hello__] world");
+
+ // "...same character must be used to open and close an emphasis span.""
+ MT("emStrongMixed",
+ "[em _foo][em&strong **bar*hello__ world]");
+
+ MT("emStrongMixed",
+ "[em *foo][em&strong __bar_hello** world]");
+
+ // These characters should be escaped:
+ // \ backslash
+ // ` backtick
+ // * asterisk
+ // _ underscore
+ // {} curly braces
+ // [] square brackets
+ // () parentheses
+ // # hash mark
+ // + plus sign
+ // - minus sign (hyphen)
+ // . dot
+ // ! exclamation mark
+
+ MT("escapeBacktick",
+ "foo \\`bar\\`");
+
+ MT("doubleEscapeBacktick",
+ "foo \\\\[comment `bar\\\\`]");
+
+ MT("escapeAsterisk",
+ "foo \\*bar\\*");
+
+ MT("doubleEscapeAsterisk",
+ "foo \\\\[em *bar\\\\*]");
+
+ MT("escapeUnderscore",
+ "foo \\_bar\\_");
+
+ MT("doubleEscapeUnderscore",
+ "foo \\\\[em _bar\\\\_]");
+
+ MT("escapeHash",
+ "\\# foo");
+
+ MT("doubleEscapeHash",
+ "\\\\# foo");
+
+ MT("escapeNewline",
+ "\\",
+ "[em *foo*]");
+
+
+ // Tests to make sure GFM-specific things aren't getting through
+
+ MT("taskList",
+ "[variable-2 * [ ]] bar]");
+
+ MT("fencedCodeBlocks",
+ "[comment ```]",
+ "foo",
+ "[comment ```]");
+
+ // Tests that require XML mode
+
+ MT("xmlMode",
+ "[tag&bracket <][tag div][tag&bracket >]",
+ "*foo*",
+ "[tag&bracket <][tag http://github.com][tag&bracket />]",
+ "[tag&bracket </][tag div][tag&bracket >]",
+ "[link <http://github.com/>]");
+
+ MT("xmlModeWithMarkdownInside",
+ "[tag&bracket <][tag div] [attribute markdown]=[string 1][tag&bracket >]",
+ "[em *foo*]",
+ "[link <http://github.com/>]",
+ "[tag </div>]",
+ "[link <http://github.com/>]",
+ "[tag&bracket <][tag div][tag&bracket >]",
+ "[tag&bracket </][tag div][tag&bracket >]");
+
+})();