diff --git a/.gitignore b/.gitignore index f8804fc..1d5dc4c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ bin/*.n -bin/*.js* \ No newline at end of file +bin/*.js* diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b0c6000 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +LIB_NAME=comark +LIB_FILE=$(LIB_NAME).zip + +upload: + haxelib submit comark.zip + +lib: $(LIB_FILE) clean + +$(LIB_FILE): haxelib.json src/*/* + -mkdir temp + cp haxelib.json temp/ + cp -R src/comark temp/ + cd temp; zip -X -r $(LIB_FILE) .; mv $(LIB_FILE) ../ + +clean: + -rm -rf temp + diff --git a/bin/tests/github.txt b/bin/tests/github.txt new file mode 100644 index 0000000..7a09d0e --- /dev/null +++ b/bin/tests/github.txt @@ -0,0 +1,43 @@ +--- +title: CommonMark Github flavour Spec +author: +- ConstNW +version: 0.1 +date: 2014-10-29 +... + + +# Strike + + +. +~~foo~~ +. +

foo

+. + +# No Strike + +. +~~foo +. +

~~foo

+. + +# Hashtag + +. +#hashtag +. +

#hashtag

+. + +. +#hash tag +. +

#hash tag

+. + + + +# Appendix diff --git a/bin/tests/spec.txt b/bin/tests/spec.txt index 0307df1..2459321 100644 --- a/bin/tests/spec.txt +++ b/bin/tests/spec.txt @@ -2,8 +2,8 @@ title: CommonMark Spec author: - John MacFarlane -version: 1 -date: 2014-09-06 +version: 0.6 +date: 2014-10-26 ... # Introduction @@ -192,10 +192,10 @@ In the examples, the `→` character is used to represent tabs. # Preprocessing A [line](#line) -is a sequence of zero or more characters followed by a line -ending (CR, LF, or CRLF) or by the end of -file. +is a sequence of zero or more [characters](#character) followed by a +line ending (CR, LF, or CRLF) or by the end of file. +A [character](#character) is a unicode code point. This spec does not specify an encoding; it thinks of lines as composed of characters rather than bytes. A conforming parser may be limited to a certain encoding. @@ -377,16 +377,18 @@ Spaces are allowed at the end:
. -However, no other characters may occur at the end or the -beginning: +However, no other characters may occur in the line: . _ _ _ _ a a------ + +---a--- .

_ _ _ _ a

a------

+

---a---

. It is required that all of the non-space characters be the same. @@ -426,8 +428,11 @@ bar

bar

. -Note, however, that this is a setext header, not a paragraph followed -by a horizontal rule: +If a line of dashes that meets the above conditions for being a +horizontal rule could also be interpreted as the underline of a [setext +header](#setext-header), the interpretation as a +[setext-header](#setext-header) takes precedence. Thus, for example, +this is a setext header, not a paragraph followed by a horizontal rule: . Foo @@ -474,11 +479,11 @@ consists of a string of characters, parsed as inline content, between an opening sequence of 1--6 unescaped `#` characters and an optional closing sequence of any number of `#` characters. The opening sequence of `#` characters cannot be followed directly by a nonspace character. -The closing `#` characters may be followed by spaces only. The opening -`#` character may be indented 0-3 spaces. The raw contents of the -header are stripped of leading and trailing spaces before being parsed -as inline content. The header level is equal to the number of `#` -characters in the opening sequence. +The optional closing sequence of `#`s must be preceded by a space and may be +followed by spaces only. The opening `#` character may be indented 0-3 +spaces. The raw contents of the header are stripped of leading and +trailing spaces before being parsed as inline content. The header level +is equal to the number of `#` characters in the opening sequence. Simple headers: @@ -609,16 +614,24 @@ header:

foo ### b

. +The closing sequence must be preceded by a space: + +. +# foo# +. +

foo#

+. + Backslash-escaped `#` characters do not count as part of the closing sequence: . ### foo \### -## foo \#\## +## foo #\## # foo \# . -

foo #

-

foo ##

+

foo ###

+

foo ###

foo #

. @@ -662,7 +675,10 @@ ATX headers can be empty: A [setext header](#setext-header) consists of a line of text, containing at least one nonspace character, with no more than 3 spaces indentation, followed by a [setext header -underline](#setext-header-underline). A [setext header +underline](#setext-header-underline). The line of text must be +one that, were it not followed by the setext header underline, +would be interpreted as part of a paragraph: it cannot be a code +block, header, blockquote, horizontal rule, or list. A [setext header underline](#setext-header-underline) is a sequence of `=` characters or a sequence of `-` characters, with no more than 3 spaces indentation and any number of trailing @@ -807,7 +823,8 @@ of dashes"/>

of dashes"/>

. -The setext header underline cannot be a lazy line: +The setext header underline cannot be a [lazy continuation +line](#lazy-continuation-line) in a list item or block quote: . > Foo @@ -819,6 +836,16 @@ The setext header underline cannot be a lazy line:
. +. +- Foo +--- +. + +
+. + A setext header cannot interrupt a paragraph: . @@ -863,6 +890,56 @@ Setext headers cannot be empty:

====

. +Setext header text lines must not be interpretable as block +constructs other than paragraphs. So, the line of dashes +in these examples gets interpreted as a horizontal rule: + +. +--- +--- +. +
+
+. + +. +- foo +----- +. + +
+. + +. + foo +--- +. +
foo
+
+
+. + +. +> foo +----- +. +
+

foo

+
+
+. + +If you want a header with `> foo` as its literal text, you can +use backslash escapes: + +. +\> foo +------ +. +

> foo

+. ## Indented code blocks @@ -1058,7 +1135,7 @@ a blank line either before or after. The content of a code fence is treated as literal text, not parsed as inlines. The first word of the info string is typically used to specify the language of the code sample, and rendered in the `class` -attribute of the `pre` tag. However, this spec does not mandate any +attribute of the `code` tag. However, this spec does not mandate any particular treatment of the info string. Here is a simple example with backticks: @@ -1232,6 +1309,40 @@ aaa . +Closing fences may be indented by 0-3 spaces, and their indentation +need not match that of the opening fence: + +. +``` +aaa + ``` +. +
aaa
+
+. + +. + ``` +aaa + ``` +. +
aaa
+
+. + +This is not a closing fence, because it is indented 4 spaces: + +. +``` +aaa + ``` +. +
aaa
+    ```
+
+. + + Code fences (opening and closing) cannot contain internal spaces: . @@ -1355,8 +1466,8 @@ name is one of the following (case-insensitive): `output`, `col`, `p`, `colgroup`, `pre`, `dd`, `progress`, `div`, `section`, `dl`, `table`, `td`, `dt`, `tbody`, `embed`, `textarea`, `fieldset`, `tfoot`, `figcaption`, `th`, `figure`, `thead`, `footer`, -`footer`, `tr`, `form`, `ul`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, -`video`, `script`, `style`. +`tr`, `form`, `ul`, `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `video`, +`script`, `style`. An [HTML block](#html-block) begins with an [HTML block tag](#html-block-tag), [HTML comment](#html-comment), @@ -1401,7 +1512,7 @@ okay. . -Here we have two code blocks with a Markdown paragraph between them: +Here we have two HTML blocks with a Markdown paragraph between them: .
@@ -1447,11 +1558,11 @@ A processing instruction: . '; ?> . '; ?> . @@ -1682,7 +1793,7 @@ them. [Foo bar] . -

Foo bar

+

Foo bar

. The title may be omitted: @@ -1745,7 +1856,7 @@ case-insensitive (see [matches](#matches)). [αγω] . -

αγω

+

αγω

. Here is a link reference definition with no corresponding link. @@ -1946,8 +2057,8 @@ bbb . Final spaces are stripped before inline parsing, so a paragraph -that ends with two or more spaces will not end with a hard line -break: +that ends with two or more spaces will not end with a [hard line +break](#hard-line-break): . aaa @@ -1994,11 +2105,11 @@ form of the definition is: > transforming X in such-and-such a way is a container of type Y > with these blocks as its content. -So, we explain what counts as a block quote or list item by -explaining how these can be *generated* from their contents. -This should suffice to define the syntax, although it does not -give a recipe for *parsing* these constructions. (A recipe is -provided below in the section entitled [A parsing strategy].) +So, we explain what counts as a block quote or list item by explaining +how these can be *generated* from their contents. This should suffice +to define the syntax, although it does not give a recipe for *parsing* +these constructions. (A recipe is provided below in the section entitled +[A parsing strategy](#appendix-a-a-parsing-strategy).) ## Block quotes @@ -2010,9 +2121,9 @@ The following rules define [block quotes](#block-quote): 1. **Basic case.** If a string of lines *Ls* constitute a sequence - of blocks *Bs*, then the result of appending a [block quote marker] - to the beginning of each line in *Ls* is a [block quote](#block-quote) - containing *Bs*. + of blocks *Bs*, then the result of prepending a [block quote + marker](#block-quote-marker) to the beginning of each line in *Ls* + is a [block quote](#block-quote) containing *Bs*. 2. **Laziness.** If a string of lines *Ls* constitute a [block quote](#block-quote) with contents *Bs*, then the result of deleting @@ -2375,7 +2486,8 @@ An [ordered list marker](#ordered-list-marker) is a sequence of one of more digits (`0-9`), followed by either a `.` character or a `)` character. -The following rules define [list items](#list-item): +The following rules define [list items](#list-item): 1. **Basic case.** If a sequence of lines *Ls* constitute a sequence of blocks *Bs* starting with a non-space character and not separated @@ -2826,9 +2938,11 @@ Four spaces indent gives a code block: some or all of the indentation from one or more lines in which the next non-space character after the indentation is [paragraph continuation text](#paragraph-continuation-text) is a - list item with the same contents and attributes. + list item with the same contents and attributes. -Here is an example with lazy continuation lines: +Here is an example with [lazy continuation +lines](#lazy-continuation-line): . 1. A paragraph @@ -3005,6 +3119,21 @@ A list item may be empty: . +A list item can contain a header: + +. +- # Foo +- Bar + --- + baz +. + +. + ### Motivation John Gruber's Markdown spec says the following about list items: @@ -3210,12 +3339,12 @@ of an [ordered list](#ordered-list) is determined by the list number of its initial list item. The numbers of subsequent list items are disregarded. -A list is [loose](#loose) if it any of its constituent list items are -separated by blank lines, or if any of its constituent list items -directly contain two block-level elements with a blank line between -them. Otherwise a list is [tight](#tight). (The difference in HTML output -is that paragraphs in a loose with are wrapped in `

` tags, while -paragraphs in a tight list are not.) +A list is [loose](#loose) if it any of its constituent +list items are separated by blank lines, or if any of its constituent +list items directly contain two block-level elements with a blank line +between them. Otherwise a list is [tight](#tight). +(The difference in HTML output is that paragraphs in a loose list are +wrapped in `

` tags, while paragraphs in a tight list are not.) Changing the bullet or ordered list delimiter starts a new list: @@ -3247,6 +3376,87 @@ Changing the bullet or ordered list delimiter starts a new list: . +In CommonMark, a list can interrupt a paragraph. That is, +no blank line is needed to separate a paragraph from a following +list: + +. +Foo +- bar +- baz +. +

Foo

+ +. + +`Markdown.pl` does not allow this, through fear of triggering a list +via a numeral in a hard-wrapped line: + +. +The number of windows in my house is +14. The number of doors is 6. +. +

The number of windows in my house is

+
    +
  1. The number of doors is 6.
  2. +
+. + +Oddly, `Markdown.pl` *does* allow a blockquote to interrupt a paragraph, +even though the same considerations might apply. We think that the two +cases should be treated the same. Here are two reasons for allowing +lists to interrupt paragraphs: + +First, it is natural and not uncommon for people to start lists without +blank lines: + + I need to buy + - new shoes + - a coat + - a plane ticket + +Second, we are attracted to a + +> [principle of uniformity](#principle-of-uniformity): id="principle-of-uniformity"> if a span of text has a certain +> meaning, it will continue to have the same meaning when put into a list +> item. + +(Indeed, the spec for [list items](#list-item) presupposes this.) +This principle implies that if + + * I need to buy + - new shoes + - a coat + - a plane ticket + +is a list item containing a paragraph followed by a nested sublist, +as all Markdown implementations agree it is (though the paragraph +may be rendered without `

` tags, since the list is "tight"), +then + + I need to buy + - new shoes + - a coat + - a plane ticket + +by itself should be a paragraph followed by a nested sublist. + +Our adherence to the [principle of uniformity](#principle-of-uniformity) +thus inclines us to think that there are two coherent packages: + +1. Require blank lines before *all* lists and blockquotes, + including lists that occur as sublists inside other list items. + +2. Require blank lines in none of these places. + +[reStructuredText](http://docutils.sourceforge.net/rst.html) takes +the first approach, for which there is much to be said. But the second +seems more consistent with established practice with Markdown. + There can be blank lines between items, but two blank lines end a list: @@ -3463,8 +3673,8 @@ This is a tight list, because the blank lines are in a code block: . This is a tight list, because the blank line is between two -paragraphs of a sublist. So the inner list is loose while -the other list is tight: +paragraphs of a sublist. So the sublist is loose while +the outer list is tight: . - a @@ -3650,7 +3860,8 @@ If a backslash is itself escaped, the following character is not:

\emphasis

. -A backslash at the end of the line is a hard line break: +A backslash at the end of the line is a [hard line +break](#hard-line-break): . foo\ @@ -3686,9 +3897,9 @@ raw HTML: . . - + . -

http://google.com?find=\*

+

http://example.com?find=\*

. . @@ -3727,47 +3938,65 @@ foo ## Entities -Entities are parsed as entities, not as literal text, in all contexts -except code spans and code blocks. Three kinds of entities are recognized. +With the goal of making this standard as HTML-agnostic as possible, all +valid HTML entities in any context are recognized as such and +converted into unicode characters before they are stored in the AST. + +This allows implementations that target HTML output to trivially escape +the entities when generating HTML, and simplifies the job of +implementations targetting other languages, as these will only need to +handle the unicode chars and need not be HTML-entity aware. [Named entities](#name-entities) consist of `&` -+ a string of 2-32 alphanumerics beginning with a letter + `;`. ++ any of the valid HTML5 entity names + `;`. The +[following document](http://www.whatwg.org/specs/web-apps/current-work/multipage/entities.json) +is used as an authoritative source of the valid entity names and their +corresponding codepoints. + +Conforming implementations that target HTML don't need to generate +entities for all the valid named entities that exist, with the exception +of `"` (`"`), `&` (`&`), `<` (`<`) and `>` (`>`), which +always need to be written as entities for security reasons. .   & © Æ Ď ¾ ℋ ⅆ ∲ . -

  & © Æ Ď ¾ ℋ ⅆ ∲

+

  & © Æ Ď ¾ ℋ ⅆ ∲

. [Decimal entities](#decimal-entities) -consist of `&#` + a string of 1--8 arabic digits + `;`. +consist of `&#` + a string of 1--8 arabic digits + `;`. Again, these +entities need to be recognised and tranformed into their corresponding +UTF8 codepoints. Invalid Unicode codepoints will be written as the +"unknown codepoint" character (`0xFFFD`) . - # Ӓ Ϡ � +# Ӓ Ϡ � . -

 # Ӓ Ϡ �

+

# Ӓ Ϡ �

. [Hexadecimal entities](#hexadecimal-entities) consist of `&#` + either `X` or `x` + a string of 1-8 hexadecimal digits -+ `;`. ++ `;`. They will also be parsed and turned into their corresponding UTF8 values in the AST. . - " ആ ಫ +" ആ ಫ . -

 " ആ ಫ

+

" ആ ಫ

. Here are some nonentities: . -  &x; &#; &#x; � &ThisIsWayTooLongToBeAnEntityIsntIt; &hi?; +  &x; &#; &#x; &ThisIsWayTooLongToBeAnEntityIsntIt; &hi?; . -

&nbsp &x; &#; &#x; &#123456789; &ThisIsWayTooLongToBeAnEntityIsntIt; &hi?;

+

&nbsp &x; &#; &#x; &ThisIsWayTooLongToBeAnEntityIsntIt; &hi?;

. Although HTML5 does accept some entities without a trailing semicolon -(such as `©`), these are not recognized as entities here: +(such as `©`), these are not recognized as entities here, because it +makes the grammar too ambiguous: . © @@ -3775,13 +4004,13 @@ Although HTML5 does accept some entities without a trailing semicolon

&copy

. -On the other hand, many strings that are not on the list of HTML5 -named entities are recognized as entities here: +Strings that are not on the list of HTML5 named entities are not +recognized as entities either: . &MadeUpEntity; . -

&MadeUpEntity;

+

&MadeUpEntity;

. Entities are recognized in any context besides code spans or @@ -3797,7 +4026,7 @@ code blocks, including raw HTML, URLs, [link titles](#link-title), and . [foo](/föö "föö") . -

foo

+

foo

. . @@ -3805,7 +4034,7 @@ code blocks, including raw HTML, URLs, [link titles](#link-title), and [foo]: /föö "föö" . -

foo

+

foo

. . @@ -3813,7 +4042,7 @@ code blocks, including raw HTML, URLs, [link titles](#link-title), and foo ``` . -
foo
+
foo
 
. @@ -3946,7 +4175,7 @@ But this is a link: . ` . -

http://foo.bar.`baz`

+

http://foo.bar.`baz`

. And this is an HTML tag: @@ -4024,15 +4253,15 @@ for efficient parsing strategies that do not backtrack: (a) it is not part of a sequence of four or more unescaped `*`s, (b) it is not followed by whitespace, and (c) either it is not followed by a `*` character or it is - followed immediately by strong emphasis. + followed immediately by emphasis or strong emphasis. 2. A single `_` character [can open emphasis](#can-open-emphasis) iff (a) it is not part of a sequence of four or more unescaped `_`s, (b) it is not followed by whitespace, - (c) is is not preceded by an ASCII alphanumeric character, and + (c) it is not preceded by an ASCII alphanumeric character, and (d) either it is not followed by a `_` character or it is - followed immediately by strong emphasis. + followed immediately by emphasis or strong emphasis. 3. A single `*` character [can close emphasis](#can-close-emphasis) iff @@ -4077,16 +4306,42 @@ for efficient parsing strategies that do not backtrack: (c) it is not followed by an ASCII alphanumeric character. 9. Emphasis begins with a delimiter that [can open - emphasis](#can-open-emphasis) and includes inlines parsed - sequentially until a delimiter that [can close + emphasis](#can-open-emphasis) and ends with a delimiter that [can close emphasis](#can-close-emphasis), and that uses the same - character (`_` or `*`) as the opening delimiter, is reached. + character (`_` or `*`) as the opening delimiter. The inlines + between the open delimiter and the closing delimiter are the + contents of the emphasis inline. 10. Strong emphasis begins with a delimiter that [can open strong - emphasis](#can-open-strong-emphasis) and includes inlines parsed - sequentially until a delimiter that [can close strong - emphasis](#can-close-strong-emphasis), and that uses the - same character (`_` or `*`) as the opening delimiter, is reached. + emphasis](#can-open-strong-emphasis) and ends with a delimiter that + [can close strong emphasis](#can-close-strong-emphasis), and that uses the + same character (`_` or `*`) as the opening delimiter. The inlines + between the open delimiter and the closing delimiter are the + contents of the strong emphasis inline. + +Where rules 1--10 above are compatible with multiple parsings, +the following principles resolve ambiguity: + +11. An interpretation `...` is always preferred to + `...`. + +12. An interpretation `...` is always + preferred to `..`. + +13. Earlier closings are preferred to later closings. Thus, + when two potential emphasis or strong emphasis spans overlap, + the first takes precedence: for example, `*foo _bar* baz_` + is parsed as `foo _bar baz_` rather than + `*foo bar* baz`. For the same reason, + `**foo*bar**` is parsed as `foobar*` + rather than `foo*bar`. + +14. Inline code spans, links, images, and HTML tags group more tightly + than emphasis. So, when there is a choice between an interpretation + that contains one of these elements and one that does not, the + former always wins. Thus, for example, `*[foo*](bar)` is + parsed as `*foo*` rather than as + `[foo](bar)`. These rules can be illustrated through a series of examples. @@ -4334,6 +4589,32 @@ __this is a double underscore (`__`)__

this is a double underscore (__)

. +Or use the other emphasis character: + +. +*_* +. +

_

+. + +. +_*_ +. +

*

+. + +. +*__* +. +

__

+. + +. +_**_ +. +

**

+. + `*` delimiters allow intra-word emphasis; `_` delimiters do not: . @@ -4509,6 +4790,36 @@ __foo _bar_ baz__

foo bar baz

. +. +**foo, *bar*, baz** +. +

foo, bar, baz

+. + +. +__foo, _bar_, baz__ +. +

foo, bar, baz

+. + +But note: + +. +*foo**bar**baz* +. +

foobarbaz

+. + +. +**foo*bar*baz** +. +

foobarbaz**

+. + +The difference is that in the two preceding cases, +the internal delimiters [can close emphasis](#can-close-emphasis), +while in the cases with spaces, they cannot. + Note that you cannot nest emphasis directly inside emphasis using the same delimeter, or strong emphasis directly inside strong emphasis: @@ -4561,6 +4872,18 @@ similarly for `_` and `__`):

foo*

. +. +***foo* bar*** +. +

foo bar*

+. + +. +***foo** bar*** +. +

foo bar**

+. + The following contains no strong emphasis, because the opening delimiter is closed by the first `*` before `bar`: @@ -4578,7 +4901,7 @@ However, a string of four or more `****` can never close emphasis:

*foo****

. -Note that there are some asymmetries here: +We retain symmetry in these cases: . *foo** @@ -4586,7 +4909,7 @@ Note that there are some asymmetries here: **foo* .

foo*

-

**foo*

+

*foo

. . @@ -4595,17 +4918,11 @@ Note that there are some asymmetries here: **foo* bar* .

foo bar

-

**foo* bar*

+

foo bar

. More cases with mismatched delimiters: -. -**foo* bar* -. -

**foo* bar*

-. - . *bar*** . @@ -4615,7 +4932,7 @@ More cases with mismatched delimiters: . ***foo* . -

***foo*

+

**foo

. . @@ -4627,7 +4944,7 @@ More cases with mismatched delimiters: . ***foo** . -

***foo**

+

*foo

. . @@ -4636,6 +4953,46 @@ More cases with mismatched delimiters:

***foo bar

. +The following cases illustrate rule 13: + +. +*foo _bar* baz_ +. +

foo _bar baz_

+. + +. +**foo bar* baz** +. +

foo bar baz*

+. + +The following cases illustrate rule 14: + +. +*[foo*](bar) +. +

*foo*

+. + +. +*![foo*](bar) +. +

*foo*

+. + +. +* +. +

*

+. + +. +*a`a*` +. +

*aa*

+. + ## Links A link contains a [link label](#link-label) (the visible text), @@ -4743,7 +5100,7 @@ braces: . [link]() . -

link

+

link

. The destination cannot contain line breaks, even with pointy braces: @@ -4794,12 +5151,15 @@ in Markdown:

link

. -URL-escaping and entities should be left alone inside the destination: +URL-escaping should be left alone inside the destination, as all +URL-escaped characters are also valid URL characters. HTML entities in +the destination will be parsed into their UTF-8 codepoints, as usual, and +optionally URL-escaped when written as HTML. . [link](foo%20bä) . -

link

+

link

. Note that, because titles can often be parsed as destinations, @@ -4809,7 +5169,7 @@ get unexpected results: . [link]("title") . -

link

+

link

. Titles may be in single quotes, double quotes, or parentheses: @@ -5479,9 +5839,9 @@ spec](http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-m Examples of email autolinks: . - + . -

foo@bar.baz.com

+

foo@bar.example.com

. . @@ -5523,15 +5883,15 @@ These are not autolinks: . . -http://google.com +http://example.com . -

http://google.com

+

http://example.com

. . -foo@bar.baz.com +foo@bar.example.com . -

foo@bar.baz.com

+

foo@bar.example.com

. ## Raw HTML @@ -5771,7 +6131,8 @@ Backslash escapes do not work in HTML attributes: ## Hard line breaks A line break (not in a code span or HTML tag) that is preceded -by two or more spaces is parsed as a linebreak (rendered +by two or more spaces is parsed as a [hard line +break](#hard-line-break) (rendered in HTML as a `
` tag): . @@ -6121,5 +6482,3 @@ an `emph`. The document can be rendered as HTML, or in any other format, given an appropriate renderer. - - diff --git a/comark-client.hxml b/comark-js.hxml similarity index 100% rename from comark-client.hxml rename to comark-js.hxml diff --git a/comark-client.hxproj b/comark-js.hxproj similarity index 100% rename from comark-client.hxproj rename to comark-js.hxproj diff --git a/comark.zip b/comark.zip new file mode 100644 index 0000000..04eb2b9 Binary files /dev/null and b/comark.zip differ diff --git a/haxelib.json b/haxelib.json index 2677503..bc19904 100644 --- a/haxelib.json +++ b/haxelib.json @@ -4,8 +4,8 @@ "tags": ["cross","utility"], "description": "Comark is CommonMark (Markdown) library.", "contributors": ["constnw"], - "releasenote": "Github Flavor added", - "version": "0.0.2", + "releasenote": "Updated to CommonMark spec v0.6", + "version": "0.0.3", "url": "http://github.com/constnw/comark/", "dependencies": { diff --git a/src/comark/DocParser.hx b/src/comark/DocParser.hx index ec2b19d..152959c 100644 --- a/src/comark/DocParser.hx +++ b/src/comark/DocParser.hx @@ -17,9 +17,6 @@ class DocParser static var HTMLBLOCKOPEN = "<(?:" + BLOCKTAGNAME + "[\\s/>]" + "|" + "/" + BLOCKTAGNAME + "[\\s>]" + "|" + "[?!])"; static var reHtmlBlockOpen = new EReg('^' + HTMLBLOCKOPEN, 'i'); - public static var ESCAPABLE = '[!"#$%&\'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]'; - public static var reAllEscapedChar = new EReg('\\\\(' + ESCAPABLE + ')', 'g'); - var doc : BlockElement; var tip : BlockElement; @@ -54,7 +51,7 @@ class DocParser var i = 0; do incorporateLine(lines[i], i+1) while ( len > ++i ); - while ( tip != null ) finalize(tip, len - 1); + while ( tip != null ) { finalize(tip, len - 1); } processInlines(doc); @@ -254,7 +251,10 @@ class DocParser // remove trailing ###s: var s = ln.substr(offset); - container.strings = [~/(?:(\\#) *#*| *#+) *$/.replace(s, '$1')]; + container.strings = [ + ~/ +#+ *$/.replace( + ~/^ *#+ *$/.replace(s, ''), '') + ]; break; } else if ( erCode.match(ln.substr(first_nonspace)) ) @@ -455,7 +455,7 @@ class DocParser case 'FencedCode': // first line becomes info string - block.info = unescape(block.strings[0].trim()); + block.info = InlineParser.unescapeString(block.strings[0].trim()); if ( block.strings.length == 1 ) block.string_content = ''; else @@ -579,14 +579,6 @@ class DocParser lastStop = offset + 1; return result; }); - - /* - return text.replace(reAllTab, function(match, offset) { - var result = ' '.slice((offset - lastStop) % 4); - lastStop = offset + 1; - return result; - }); - */ } // Attempt to match a regex in string s at offset offset. @@ -694,9 +686,6 @@ class DocParser // Returns true if block type can accept lines of text. function acceptsLines( block_type : String ) : Bool return ( block_type == 'Paragraph' || block_type == 'IndentedCode' || block_type == 'FencedCode' ); - // Replace backslash escapes with literal characters. - function unescape( s ) return reAllEscapedChar.replace(s, '$1'); - // Returns true if string contains only space characters. function isBlank(s) return ~/^\s*$/.match(s); @@ -713,4 +702,12 @@ class DocParser else return false; } +/* + breakOutOfLists: breakOutOfLists, + addLine: addLine, + addChild: addChild, + incorporateLine: incorporateLine, + finalize: finalize, + processInlines: processInlines, +*/ } \ No newline at end of file diff --git a/src/comark/EntityToChar.hx b/src/comark/EntityToChar.hx new file mode 100644 index 0000000..6271523 --- /dev/null +++ b/src/comark/EntityToChar.hx @@ -0,0 +1,2213 @@ +package comark; + +/** + * ... + * @author Const + */ +class EntityToChar +{ + static var entities = { + AAacute: 'Á', + aacute: 'á', + Abreve: 'Ă', + abreve: 'ă', + ac: '∾', + acd: '∿', + acE: '∾', + Acirc: 'Â', + acirc: 'â', + acute: '´', + Acy: 'А', + acy: 'а', + AElig: 'Æ', + aelig: 'æ', + af: '⁡', + Afr: '𝔄', + afr: '𝔞', + Agrave: 'À', + agrave: 'à', + alefsym: 'ℵ', + aleph: 'ℵ', + Alpha: 'Α', + alpha: 'α', + Amacr: 'Ā', + amacr: 'ā', + amalg: '⨿', + amp: '&', + AMP: '&', + andand: '⩕', + And: '⩓', + and: '∧', + andd: '⩜', + andslope: '⩘', + andv: '⩚', + ang: '∠', + ange: '⦤', + angle: '∠', + angmsdaa: '⦨', + angmsdab: '⦩', + angmsdac: '⦪', + angmsdad: '⦫', + angmsdae: '⦬', + angmsdaf: '⦭', + angmsdag: '⦮', + angmsdah: '⦯', + angmsd: '∡', + angrt: '∟', + angrtvb: '⊾', + angrtvbd: '⦝', + angsph: '∢', + angst: 'Å', + angzarr: '⍼', + Aogon: 'Ą', + aogon: 'ą', + Aopf: '𝔸', + aopf: '𝕒', + apacir: '⩯', + ap: '≈', + apE: '⩰', + ape: '≊', + apid: '≋', + apos: '\'', + ApplyFunction: '⁡', + approx: '≈', + approxeq: '≊', + Aring: 'Å', + aring: 'å', + Ascr: '𝒜', + ascr: '𝒶', + Assign: '≔', + ast: '*', + asymp: '≈', + asympeq: '≍', + Atilde: 'Ã', + atilde: 'ã', + Auml: 'Ä', + auml: 'ä', + awconint: '∳', + awint: '⨑', + backcong: '≌', + backepsilon: '϶', + backprime: '‵', + backsim: '∽', + backsimeq: '⋍', + Backslash: '∖', + Barv: '⫧', + barvee: '⊽', + barwed: '⌅', + Barwed: '⌆', + barwedge: '⌅', + bbrk: '⎵', + bbrktbrk: '⎶', + bcong: '≌', + Bcy: 'Б', + bcy: 'б', + bdquo: '„', + becaus: '∵', + because: '∵', + Because: '∵', + bemptyv: '⦰', + bepsi: '϶', + bernou: 'ℬ', + Bernoullis: 'ℬ', + Beta: 'Β', + beta: 'β', + beth: 'ℶ', + between: '≬', + Bfr: '𝔅', + bfr: '𝔟', + bigcap: '⋂', + bigcirc: '◯', + bigcup: '⋃', + bigodot: '⨀', + bigoplus: '⨁', + bigotimes: '⨂', + bigsqcup: '⨆', + bigstar: '★', + bigtriangledown: '▽', + bigtriangleup: '△', + biguplus: '⨄', + bigvee: '⋁', + bigwedge: '⋀', + bkarow: '⤍', + blacklozenge: '⧫', + blacksquare: '▪', + blacktriangle: '▴', + blacktriangledown: '▾', + blacktriangleleft: '◂', + blacktriangleright: '▸', + blank: '␣', + blk12: '▒', + blk14: '░', + blk34: '▓', + block: '█', + bne: '=', + bnequiv: '≡', + bNot: '⫭', + bnot: '⌐', + Bopf: '𝔹', + bopf: '𝕓', + bot: '⊥', + bottom: '⊥', + bowtie: '⋈', + boxbox: '⧉', + boxdl: '┐', + boxdL: '╕', + boxDl: '╖', + boxDL: '╗', + boxdr: '┌', + boxdR: '╒', + boxDr: '╓', + boxDR: '╔', + boxh: '─', + boxH: '═', + boxhd: '┬', + boxHd: '╤', + boxhD: '╥', + boxHD: '╦', + boxhu: '┴', + boxHu: '╧', + boxhU: '╨', + boxHU: '╩', + boxminus: '⊟', + boxplus: '⊞', + boxtimes: '⊠', + boxul: '┘', + boxuL: '╛', + boxUl: '╜', + boxUL: '╝', + boxur: '└', + boxuR: '╘', + boxUr: '╙', + boxUR: '╚', + boxv: '│', + boxV: '║', + boxvh: '┼', + boxvH: '╪', + boxVh: '╫', + boxVH: '╬', + boxvl: '┤', + boxvL: '╡', + boxVl: '╢', + boxVL: '╣', + boxvr: '├', + boxvR: '╞', + boxVr: '╟', + boxVR: '╠', + bprime: '‵', + breve: '˘', + Breve: '˘', + brvbar: '¦', + bscr: '𝒷', + Bscr: 'ℬ', + bsemi: '⁏', + bsim: '∽', + bsime: '⋍', + bsolb: '⧅', + bsol: '\\', + bsolhsub: '⟈', + bull: '•', + bullet: '•', + bump: '≎', + bumpE: '⪮', + bumpe: '≏', + Bumpeq: '≎', + bumpeq: '≏', + Cacute: 'Ć', + cacute: 'ć', + capand: '⩄', + capbrcup: '⩉', + capcap: '⩋', + cap: '∩', + Cap: '⋒', + capcup: '⩇', + capdot: '⩀', + CapitalDifferentialD: 'ⅅ', + caps: '∩', + caret: '⁁', + caron: 'ˇ', + Cayleys: 'ℭ', + ccaps: '⩍', + Ccaron: 'Č', + ccaron: 'č', + Ccedil: 'Ç', + ccedil: 'ç', + Ccirc: 'Ĉ', + ccirc: 'ĉ', + Cconint: '∰', + ccups: '⩌', + ccupssm: '⩐', + Cdot: 'Ċ', + cdot: 'ċ', + cedil: '¸', + Cedilla: '¸', + cemptyv: '⦲', + cent: '¢', + centerdot: '·', + CenterDot: '·', + cfr: '𝔠', + Cfr: 'ℭ', + CHcy: 'Ч', + chcy: 'ч', + check: '✓', + checkmark: '✓', + Chi: 'Χ', + chi: 'χ', + circ: 'ˆ', + circeq: '≗', + circlearrowleft: '↺', + circlearrowright: '↻', + circledast: '⊛', + circledcirc: '⊚', + circleddash: '⊝', + CircleDot: '⊙', + circledR: '®', + circledS: 'Ⓢ', + CircleMinus: '⊖', + CirclePlus: '⊕', + CircleTimes: '⊗', + cir: '○', + cirE: '⧃', + cire: '≗', + cirfnint: '⨐', + cirmid: '⫯', + cirscir: '⧂', + ClockwiseContourIntegral: '∲', + CloseCurlyDoubleQuote: '”', + CloseCurlyQuote: '’', + clubs: '♣', + clubsuit: '♣', + colon: ':', + Colon: '∷', + Colone: '⩴', + colone: '≔', + coloneq: '≔', + comma: ',', + commat: '@', + comp: '∁', + compfn: '∘', + complement: '∁', + complexes: 'ℂ', + cong: '≅', + congdot: '⩭', + Congruent: '≡', + conint: '∮', + Conint: '∯', + ContourIntegral: '∮', + copf: '𝕔', + Copf: 'ℂ', + coprod: '∐', + Coproduct: '∐', + copy: '©', + COPY: '©', + copysr: '℗', + CounterClockwiseContourIntegral: '∳', + crarr: '↵', + cross: '✗', + Cross: '⨯', + Cscr: '𝒞', + cscr: '𝒸', + csub: '⫏', + csube: '⫑', + csup: '⫐', + csupe: '⫒', + ctdot: '⋯', + cudarrl: '⤸', + cudarrr: '⤵', + cuepr: '⋞', + cuesc: '⋟', + cularr: '↶', + cularrp: '⤽', + cupbrcap: '⩈', + cupcap: '⩆', + CupCap: '≍', + cup: '∪', + Cup: '⋓', + cupcup: '⩊', + cupdot: '⊍', + cupor: '⩅', + cups: '∪', + curarr: '↷', + curarrm: '⤼', + curlyeqprec: '⋞', + curlyeqsucc: '⋟', + curlyvee: '⋎', + curlywedge: '⋏', + curren: '¤', + curvearrowleft: '↶', + curvearrowright: '↷', + cuvee: '⋎', + cuwed: '⋏', + cwconint: '∲', + cwint: '∱', + cylcty: '⌭', + dagger: '†', + Dagger: '‡', + daleth: 'ℸ', + darr: '↓', + Darr: '↡', + dArr: '⇓', + dash: '‐', + Dashv: '⫤', + dashv: '⊣', + dbkarow: '⤏', + dblac: '˝', + Dcaron: 'Ď', + dcaron: 'ď', + Dcy: 'Д', + dcy: 'д', + ddagger: '‡', + ddarr: '⇊', + DD: 'ⅅ', + dd: 'ⅆ', + DDotrahd: '⤑', + ddotseq: '⩷', + deg: '°', + Del: '∇', + Delta: 'Δ', + delta: 'δ', + demptyv: '⦱', + dfisht: '⥿', + Dfr: '𝔇', + dfr: '𝔡', + dHar: '⥥', + dharl: '⇃', + dharr: '⇂', + DiacriticalAcute: '´', + DiacriticalDot: '˙', + DiacriticalDoubleAcute: '˝', + DiacriticalGrave: '`', + DiacriticalTilde: '˜', + diam: '⋄', + diamond: '⋄', + Diamond: '⋄', + diamondsuit: '♦', + diams: '♦', + die: '¨', + DifferentialD: 'ⅆ', + digamma: 'ϝ', + disin: '⋲', + div: '÷', + divide: '÷', + divideontimes: '⋇', + divonx: '⋇', + DJcy: 'Ђ', + djcy: 'ђ', + dlcorn: '⌞', + dlcrop: '⌍', + dollar: '$', + Dopf: '𝔻', + dopf: '𝕕', + Dot: '¨', + dot: '˙', + DotDot: '⃜', + doteq: '≐', + doteqdot: '≑', + DotEqual: '≐', + dotminus: '∸', + dotplus: '∔', + dotsquare: '⊡', + doublebarwedge: '⌆', + DoubleContourIntegral: '∯', + DoubleDot: '¨', + DoubleDownArrow: '⇓', + DoubleLeftArrow: '⇐', + DoubleLeftRightArrow: '⇔', + DoubleLeftTee: '⫤', + DoubleLongLeftArrow: '⟸', + DoubleLongLeftRightArrow: '⟺', + DoubleLongRightArrow: '⟹', + DoubleRightArrow: '⇒', + DoubleRightTee: '⊨', + DoubleUpArrow: '⇑', + DoubleUpDownArrow: '⇕', + DoubleVerticalBar: '∥', + DownArrowBar: '⤓', + downarrow: '↓', + DownArrow: '↓', + Downarrow: '⇓', + DownArrowUpArrow: '⇵', + DownBreve: '̑', + downdownarrows: '⇊', + downharpoonleft: '⇃', + downharpoonright: '⇂', + DownLeftRightVector: '⥐', + DownLeftTeeVector: '⥞', + DownLeftVectorBar: '⥖', + DownLeftVector: '↽', + DownRightTeeVector: '⥟', + DownRightVectorBar: '⥗', + DownRightVector: '⇁', + DownTeeArrow: '↧', + DownTee: '⊤', + drbkarow: '⤐', + drcorn: '⌟', + drcrop: '⌌', + Dscr: '𝒟', + dscr: '𝒹', + DScy: 'Ѕ', + dscy: 'ѕ', + dsol: '⧶', + Dstrok: 'Đ', + dstrok: 'đ', + dtdot: '⋱', + dtri: '▿', + dtrif: '▾', + duarr: '⇵', + duhar: '⥯', + dwangle: '⦦', + DZcy: 'Џ', + dzcy: 'џ', + dzigrarr: '⟿', + Eacute: 'É', + eacute: 'é', + easter: '⩮', + Ecaron: 'Ě', + ecaron: 'ě', + Ecirc: 'Ê', + ecirc: 'ê', + ecir: '≖', + ecolon: '≕', + Ecy: 'Э', + ecy: 'э', + eDDot: '⩷', + Edot: 'Ė', + edot: 'ė', + eDot: '≑', + ee: 'ⅇ', + efDot: '≒', + Efr: '𝔈', + efr: '𝔢', + eg: '⪚', + Egrave: 'È', + egrave: 'è', + egs: '⪖', + egsdot: '⪘', + el: '⪙', + Element: '∈', + elinters: '⏧', + ell: 'ℓ', + els: '⪕', + elsdot: '⪗', + Emacr: 'Ē', + emacr: 'ē', + empty: '∅', + emptyset: '∅', + EmptySmallSquare: '◻', + emptyv: '∅', + EmptyVerySmallSquare: '▫', + emsp13: ' ', + emsp14: ' ', + emsp: ' ', + ENG: 'Ŋ', + eng: 'ŋ', + ensp: ' ', + Eogon: 'Ę', + eogon: 'ę', + Eopf: '𝔼', + eopf: '𝕖', + epar: '⋕', + eparsl: '⧣', + eplus: '⩱', + epsi: 'ε', + Epsilon: 'Ε', + epsilon: 'ε', + epsiv: 'ϵ', + eqcirc: '≖', + eqcolon: '≕', + eqsim: '≂', + eqslantgtr: '⪖', + eqslantless: '⪕', + Equal: '⩵', + equals: '=', + EqualTilde: '≂', + equest: '≟', + Equilibrium: '⇌', + equiv: '≡', + equivDD: '⩸', + eqvparsl: '⧥', + erarr: '⥱', + erDot: '≓', + escr: 'ℯ', + Escr: 'ℰ', + esdot: '≐', + Esim: '⩳', + esim: '≂', + Eta: 'Η', + eta: 'η', + ETH: 'Ð', + eth: 'ð', + Euml: 'Ë', + euml: 'ë', + euro: '€', + excl: '!', + exist: '∃', + Exists: '∃', + expectation: 'ℰ', + exponentiale: 'ⅇ', + ExponentialE: 'ⅇ', + fallingdotseq: '≒', + Fcy: 'Ф', + fcy: 'ф', + female: '♀', + ffilig: 'ffi', + fflig: 'ff', + ffllig: 'ffl', + Ffr: '𝔉', + ffr: '𝔣', + filig: 'fi', + FilledSmallSquare: '◼', + FilledVerySmallSquare: '▪', + fjlig: 'f', + flat: '♭', + fllig: 'fl', + fltns: '▱', + fnof: 'ƒ', + Fopf: '𝔽', + fopf: '𝕗', + forall: '∀', + ForAll: '∀', + fork: '⋔', + forkv: '⫙', + Fouriertrf: 'ℱ', + fpartint: '⨍', + frac12: '½', + frac13: '⅓', + frac14: '¼', + frac15: '⅕', + frac16: '⅙', + frac18: '⅛', + frac23: '⅔', + frac25: '⅖', + frac34: '¾', + frac35: '⅗', + frac38: '⅜', + frac45: '⅘', + frac56: '⅚', + frac58: '⅝', + frac78: '⅞', + frasl: '⁄', + frown: '⌢', + fscr: '𝒻', + Fscr: 'ℱ', + gacute: 'ǵ', + Gamma: 'Γ', + gamma: 'γ', + Gammad: 'Ϝ', + gammad: 'ϝ', + gap: '⪆', + Gbreve: 'Ğ', + gbreve: 'ğ', + Gcedil: 'Ģ', + Gcirc: 'Ĝ', + gcirc: 'ĝ', + Gcy: 'Г', + gcy: 'г', + Gdot: 'Ġ', + gdot: 'ġ', + ge: '≥', + gE: '≧', + gEl: '⪌', + gel: '⋛', + geq: '≥', + geqq: '≧', + geqslant: '⩾', + gescc: '⪩', + ges: '⩾', + gesdot: '⪀', + gesdoto: '⪂', + gesdotol: '⪄', + gesl: '⋛', + gesles: '⪔', + Gfr: '𝔊', + gfr: '𝔤', + gg: '≫', + Gg: '⋙', + ggg: '⋙', + gimel: 'ℷ', + GJcy: 'Ѓ', + gjcy: 'ѓ', + gla: '⪥', + gl: '≷', + glE: '⪒', + glj: '⪤', + gnap: '⪊', + gnapprox: '⪊', + gne: '⪈', + gnE: '≩', + gneq: '⪈', + gneqq: '≩', + gnsim: '⋧', + Gopf: '𝔾', + gopf: '𝕘', + grave: '`', + GreaterEqual: '≥', + GreaterEqualLess: '⋛', + GreaterFullEqual: '≧', + GreaterGreater: '⪢', + GreaterLess: '≷', + GreaterSlantEqual: '⩾', + GreaterTilde: '≳', + Gscr: '𝒢', + gscr: 'ℊ', + gsim: '≳', + gsime: '⪎', + gsiml: '⪐', + gtcc: '⪧', + gtcir: '⩺', + gt: '>', + GT: '>', + Gt: '≫', + gtdot: '⋗', + gtlPar: '⦕', + gtquest: '⩼', + gtrapprox: '⪆', + gtrarr: '⥸', + gtrdot: '⋗', + gtreqless: '⋛', + gtreqqless: '⪌', + gtrless: '≷', + gtrsim: '≳', + gvertneqq: '≩', + gvnE: '≩', + Hacek: 'ˇ', + hairsp: ' ', + half: '½', + hamilt: 'ℋ', + HARDcy: 'Ъ', + hardcy: 'ъ', + harrcir: '⥈', + harr: '↔', + hArr: '⇔', + harrw: '↭', + Hat: '^', + hbar: 'ℏ', + Hcirc: 'Ĥ', + hcirc: 'ĥ', + hearts: '♥', + heartsuit: '♥', + hellip: '…', + hercon: '⊹', + hfr: '𝔥', + Hfr: 'ℌ', + HilbertSpace: 'ℋ', + hksearow: '⤥', + hkswarow: '⤦', + hoarr: '⇿', + homtht: '∻', + hookleftarrow: '↩', + hookrightarrow: '↪', + hopf: '𝕙', + Hopf: 'ℍ', + horbar: '―', + HorizontalLine: '─', + hscr: '𝒽', + Hscr: 'ℋ', + hslash: 'ℏ', + Hstrok: 'Ħ', + hstrok: 'ħ', + HumpDownHump: '≎', + HumpEqual: '≏', + hybull: '⁃', + hyphen: '‐', + Iacute: 'Í', + iacute: 'í', + ic: '⁣', + Icirc: 'Î', + icirc: 'î', + Icy: 'И', + icy: 'и', + Idot: 'İ', + IEcy: 'Е', + iecy: 'е', + iexcl: '¡', + iff: '⇔', + ifr: '𝔦', + Ifr: 'ℑ', + Igrave: 'Ì', + igrave: 'ì', + ii: 'ⅈ', + iiiint: '⨌', + iiint: '∭', + iinfin: '⧜', + iiota: '℩', + IJlig: 'IJ', + ijlig: 'ij', + Imacr: 'Ī', + imacr: 'ī', + image: 'ℑ', + ImaginaryI: 'ⅈ', + imagline: 'ℐ', + imagpart: 'ℑ', + imath: 'ı', + Im: 'ℑ', + imof: '⊷', + imped: 'Ƶ', + Implies: '⇒', + incare: '℅', + "in": '∈', + infin: '∞', + infintie: '⧝', + inodot: 'ı', + intcal: '⊺', + int: '∫', + Int: '∬', + integers: 'ℤ', + Integral: '∫', + intercal: '⊺', + Intersection: '⋂', + intlarhk: '⨗', + intprod: '⨼', + InvisibleComma: '⁣', + InvisibleTimes: '⁢', + IOcy: 'Ё', + iocy: 'ё', + Iogon: 'Į', + iogon: 'į', + Iopf: '𝕀', + iopf: '𝕚', + Iota: 'Ι', + iota: 'ι', + iprod: '⨼', + iquest: '¿', + iscr: '𝒾', + Iscr: 'ℐ', + isin: '∈', + isindot: '⋵', + isinE: '⋹', + isins: '⋴', + isinsv: '⋳', + isinv: '∈', + it: '⁢', + Itilde: 'Ĩ', + itilde: 'ĩ', + Iukcy: 'І', + iukcy: 'і', + Iuml: 'Ï', + iuml: 'ï', + Jcirc: 'Ĵ', + jcirc: 'ĵ', + Jcy: 'Й', + jcy: 'й', + Jfr: '𝔍', + jfr: '𝔧', + jmath: 'ȷ', + Jopf: '𝕁', + jopf: '𝕛', + Jscr: '𝒥', + jscr: '𝒿', + Jsercy: 'Ј', + jsercy: 'ј', + Jukcy: 'Є', + jukcy: 'є', + Kappa: 'Κ', + kappa: 'κ', + kappav: 'ϰ', + Kcedil: 'Ķ', + kcedil: 'ķ', + Kcy: 'К', + kcy: 'к', + Kfr: '𝔎', + kfr: '𝔨', + kgreen: 'ĸ', + KHcy: 'Х', + khcy: 'х', + KJcy: 'Ќ', + kjcy: 'ќ', + Kopf: '𝕂', + kopf: '𝕜', + Kscr: '𝒦', + kscr: '𝓀', + lAarr: '⇚', + Lacute: 'Ĺ', + lacute: 'ĺ', + laemptyv: '⦴', + lagran: 'ℒ', + Lambda: 'Λ', + lambda: 'λ', + lang: '⟨', + Lang: '⟪', + langd: '⦑', + langle: '⟨', + lap: '⪅', + Laplacetrf: 'ℒ', + laquo: '«', + larrb: '⇤', + larrbfs: '⤟', + larr: '←', + Larr: '↞', + lArr: '⇐', + larrfs: '⤝', + larrhk: '↩', + larrlp: '↫', + larrpl: '⤹', + larrsim: '⥳', + larrtl: '↢', + latail: '⤙', + lAtail: '⤛', + lat: '⪫', + late: '⪭', + lates: '⪭', + lbarr: '⤌', + lBarr: '⤎', + lbbrk: '❲', + lbrace: '{', + lbrack: '[', + lbrke: '⦋', + lbrksld: '⦏', + lbrkslu: '⦍', + Lcaron: 'Ľ', + lcaron: 'ľ', + Lcedil: 'Ļ', + lcedil: 'ļ', + lceil: '⌈', + lcub: '{', + Lcy: 'Л', + lcy: 'л', + ldca: '⤶', + ldquo: '“', + ldquor: '„', + ldrdhar: '⥧', + ldrushar: '⥋', + ldsh: '↲', + le: '≤', + lE: '≦', + LeftAngleBracket: '⟨', + LeftArrowBar: '⇤', + leftarrow: '←', + LeftArrow: '←', + Leftarrow: '⇐', + LeftArrowRightArrow: '⇆', + leftarrowtail: '↢', + LeftCeiling: '⌈', + LeftDoubleBracket: '⟦', + LeftDownTeeVector: '⥡', + LeftDownVectorBar: '⥙', + LeftDownVector: '⇃', + LeftFloor: '⌊', + leftharpoondown: '↽', + leftharpoonup: '↼', + leftleftarrows: '⇇', + leftrightarrow: '↔', + LeftRightArrow: '↔', + Leftrightarrow: '⇔', + leftrightarrows: '⇆', + leftrightharpoons: '⇋', + leftrightsquigarrow: '↭', + LeftRightVector: '⥎', + LeftTeeArrow: '↤', + LeftTee: '⊣', + LeftTeeVector: '⥚', + leftthreetimes: '⋋', + LeftTriangleBar: '⧏', + LeftTriangle: '⊲', + LeftTriangleEqual: '⊴', + LeftUpDownVector: '⥑', + LeftUpTeeVector: '⥠', + LeftUpVectorBar: '⥘', + LeftUpVector: '↿', + LeftVectorBar: '⥒', + LeftVector: '↼', + lEg: '⪋', + leg: '⋚', + leq: '≤', + leqq: '≦', + leqslant: '⩽', + lescc: '⪨', + les: '⩽', + lesdot: '⩿', + lesdoto: '⪁', + lesdotor: '⪃', + lesg: '⋚', + lesges: '⪓', + lessapprox: '⪅', + lessdot: '⋖', + lesseqgtr: '⋚', + lesseqqgtr: '⪋', + LessEqualGreater: '⋚', + LessFullEqual: '≦', + LessGreater: '≶', + lessgtr: '≶', + LessLess: '⪡', + lesssim: '≲', + LessSlantEqual: '⩽', + LessTilde: '≲', + lfisht: '⥼', + lfloor: '⌊', + Lfr: '𝔏', + lfr: '𝔩', + lg: '≶', + lgE: '⪑', + lHar: '⥢', + lhard: '↽', + lharu: '↼', + lharul: '⥪', + lhblk: '▄', + LJcy: 'Љ', + ljcy: 'љ', + llarr: '⇇', + ll: '≪', + Ll: '⋘', + llcorner: '⌞', + Lleftarrow: '⇚', + llhard: '⥫', + lltri: '◺', + Lmidot: 'Ŀ', + lmidot: 'ŀ', + lmoustache: '⎰', + lmoust: '⎰', + lnap: '⪉', + lnapprox: '⪉', + lne: '⪇', + lnE: '≨', + lneq: '⪇', + lneqq: '≨', + lnsim: '⋦', + loang: '⟬', + loarr: '⇽', + lobrk: '⟦', + longleftarrow: '⟵', + LongLeftArrow: '⟵', + Longleftarrow: '⟸', + longleftrightarrow: '⟷', + LongLeftRightArrow: '⟷', + Longleftrightarrow: '⟺', + longmapsto: '⟼', + longrightarrow: '⟶', + LongRightArrow: '⟶', + Longrightarrow: '⟹', + looparrowleft: '↫', + looparrowright: '↬', + lopar: '⦅', + Lopf: '𝕃', + lopf: '𝕝', + loplus: '⨭', + lotimes: '⨴', + lowast: '∗', + lowbar: '_', + LowerLeftArrow: '↙', + LowerRightArrow: '↘', + loz: '◊', + lozenge: '◊', + lozf: '⧫', + lpar: '(', + lparlt: '⦓', + lrarr: '⇆', + lrcorner: '⌟', + lrhar: '⇋', + lrhard: '⥭', + lrm: '‎', + lrtri: '⊿', + lsaquo: '‹', + lscr: '𝓁', + Lscr: 'ℒ', + lsh: '↰', + Lsh: '↰', + lsim: '≲', + lsime: '⪍', + lsimg: '⪏', + lsqb: '[', + lsquo: '‘', + lsquor: '‚', + Lstrok: 'Ł', + lstrok: 'ł', + ltcc: '⪦', + ltcir: '⩹', + lt: '<', + LT: '<', + Lt: '≪', + ltdot: '⋖', + lthree: '⋋', + ltimes: '⋉', + ltlarr: '⥶', + ltquest: '⩻', + ltri: '◃', + ltrie: '⊴', + ltrif: '◂', + ltrPar: '⦖', + lurdshar: '⥊', + luruhar: '⥦', + lvertneqq: '≨', + lvnE: '≨', + macr: '¯', + male: '♂', + malt: '✠', + maltese: '✠', + Map: '⤅', + map: '↦', + mapsto: '↦', + mapstodown: '↧', + mapstoleft: '↤', + mapstoup: '↥', + marker: '▮', + mcomma: '⨩', + Mcy: 'М', + mcy: 'м', + mdash: '—', + mDDot: '∺', + measuredangle: '∡', + MediumSpace: ' ', + Mellintrf: 'ℳ', + Mfr: '𝔐', + mfr: '𝔪', + mho: '℧', + micro: 'µ', + midast: '*', + midcir: '⫰', + mid: '∣', + middot: '·', + minusb: '⊟', + minus: '−', + minusd: '∸', + minusdu: '⨪', + MinusPlus: '∓', + mlcp: '⫛', + mldr: '…', + mnplus: '∓', + models: '⊧', + Mopf: '𝕄', + mopf: '𝕞', + mp: '∓', + mscr: '𝓂', + Mscr: 'ℳ', + mstpos: '∾', + Mu: 'Μ', + mu: 'μ', + multimap: '⊸', + mumap: '⊸', + nabla: '∇', + Nacute: 'Ń', + nacute: 'ń', + nang: '∠', + nap: '≉', + napE: '⩰', + napid: '≋', + napos: 'ʼn', + napprox: '≉', + natural: '♮', + naturals: 'ℕ', + natur: '♮', + nbsp: ' ', + nbump: '≎', + nbumpe: '≏', + ncap: '⩃', + Ncaron: 'Ň', + ncaron: 'ň', + Ncedil: 'Ņ', + ncedil: 'ņ', + ncong: '≇', + ncongdot: '⩭', + ncup: '⩂', + Ncy: 'Н', + ncy: 'н', + ndash: '–', + nearhk: '⤤', + nearr: '↗', + neArr: '⇗', + nearrow: '↗', + ne: '≠', + nedot: '≐', + NegativeMediumSpace: '​', + NegativeThickSpace: '​', + NegativeThinSpace: '​', + NegativeVeryThinSpace: '​', + nequiv: '≢', + nesear: '⤨', + nesim: '≂', + NestedGreaterGreater: '≫', + NestedLessLess: '≪', + NewLine: '\n', + nexist: '∄', + nexists: '∄', + Nfr: '𝔑', + nfr: '𝔫', + ngE: '≧', + nge: '≱', + ngeq: '≱', + ngeqq: '≧', + ngeqslant: '⩾', + nges: '⩾', + nGg: '⋙', + ngsim: '≵', + nGt: '≫', + ngt: '≯', + ngtr: '≯', + nGtv: '≫', + nharr: '↮', + nhArr: '⇎', + nhpar: '⫲', + ni: '∋', + nis: '⋼', + nisd: '⋺', + niv: '∋', + NJcy: 'Њ', + njcy: 'њ', + nlarr: '↚', + nlArr: '⇍', + nldr: '‥', + nlE: '≦', + nle: '≰', + nleftarrow: '↚', + nLeftarrow: '⇍', + nleftrightarrow: '↮', + nLeftrightarrow: '⇎', + nleq: '≰', + nleqq: '≦', + nleqslant: '⩽', + nles: '⩽', + nless: '≮', + nLl: '⋘', + nlsim: '≴', + nLt: '≪', + nlt: '≮', + nltri: '⋪', + nltrie: '⋬', + nLtv: '≪', + nmid: '∤', + NoBreak: '⁠', + NonBreakingSpace: ' ', + nopf: '𝕟', + Nopf: 'ℕ', + Not: '⫬', + not: '¬', + NotCongruent: '≢', + NotCupCap: '≭', + NotDoubleVerticalBar: '∦', + NotElement: '∉', + NotEqual: '≠', + NotEqualTilde: '≂', + NotExists: '∄', + NotGreater: '≯', + NotGreaterEqual: '≱', + NotGreaterFullEqual: '≧', + NotGreaterGreater: '≫', + NotGreaterLess: '≹', + NotGreaterSlantEqual: '⩾', + NotGreaterTilde: '≵', + NotHumpDownHump: '≎', + NotHumpEqual: '≏', + notin: '∉', + notindot: '⋵', + notinE: '⋹', + notinva: '∉', + notinvb: '⋷', + notinvc: '⋶', + NotLeftTriangleBar: '⧏', + NotLeftTriangle: '⋪', + NotLeftTriangleEqual: '⋬', + NotLess: '≮', + NotLessEqual: '≰', + NotLessGreater: '≸', + NotLessLess: '≪', + NotLessSlantEqual: '⩽', + NotLessTilde: '≴', + NotNestedGreaterGreater: '⪢', + NotNestedLessLess: '⪡', + notni: '∌', + notniva: '∌', + notnivb: '⋾', + notnivc: '⋽', + NotPrecedes: '⊀', + NotPrecedesEqual: '⪯', + NotPrecedesSlantEqual: '⋠', + NotReverseElement: '∌', + NotRightTriangleBar: '⧐', + NotRightTriangle: '⋫', + NotRightTriangleEqual: '⋭', + NotSquareSubset: '⊏', + NotSquareSubsetEqual: '⋢', + NotSquareSuperset: '⊐', + NotSquareSupersetEqual: '⋣', + NotSubset: '⊂', + NotSubsetEqual: '⊈', + NotSucceeds: '⊁', + NotSucceedsEqual: '⪰', + NotSucceedsSlantEqual: '⋡', + NotSucceedsTilde: '≿', + NotSuperset: '⊃', + NotSupersetEqual: '⊉', + NotTilde: '≁', + NotTildeEqual: '≄', + NotTildeFullEqual: '≇', + NotTildeTilde: '≉', + NotVerticalBar: '∤', + nparallel: '∦', + npar: '∦', + nparsl: '⫽', + npart: '∂', + npolint: '⨔', + npr: '⊀', + nprcue: '⋠', + nprec: '⊀', + npreceq: '⪯', + npre: '⪯', + nrarrc: '⤳', + nrarr: '↛', + nrArr: '⇏', + nrarrw: '↝', + nrightarrow: '↛', + nRightarrow: '⇏', + nrtri: '⋫', + nrtrie: '⋭', + nsc: '⊁', + nsccue: '⋡', + nsce: '⪰', + Nscr: '𝒩', + nscr: '𝓃', + nshortmid: '∤', + nshortparallel: '∦', + nsim: '≁', + nsime: '≄', + nsimeq: '≄', + nsmid: '∤', + nspar: '∦', + nsqsube: '⋢', + nsqsupe: '⋣', + nsub: '⊄', + nsubE: '⫅', + nsube: '⊈', + nsubset: '⊂', + nsubseteq: '⊈', + nsubseteqq: '⫅', + nsucc: '⊁', + nsucceq: '⪰', + nsup: '⊅', + nsupE: '⫆', + nsupe: '⊉', + nsupset: '⊃', + nsupseteq: '⊉', + nsupseteqq: '⫆', + ntgl: '≹', + Ntilde: 'Ñ', + ntilde: 'ñ', + ntlg: '≸', + ntriangleleft: '⋪', + ntrianglelefteq: '⋬', + ntriangleright: '⋫', + ntrianglerighteq: '⋭', + Nu: 'Ν', + nu: 'ν', + num: '#', + numero: '№', + numsp: ' ', + nvap: '≍', + nvdash: '⊬', + nvDash: '⊭', + nVdash: '⊮', + nVDash: '⊯', + nvge: '≥', + nvgt: '>', + nvHarr: '⤄', + nvinfin: '⧞', + nvlArr: '⤂', + nvle: '≤', + nvlt: '>', + nvltrie: '⊴', + nvrArr: '⤃', + nvrtrie: '⊵', + nvsim: '∼', + nwarhk: '⤣', + nwarr: '↖', + nwArr: '⇖', + nwarrow: '↖', + nwnear: '⤧', + Oacute: 'Ó', + oacute: 'ó', + oast: '⊛', + Ocirc: 'Ô', + ocirc: 'ô', + ocir: '⊚', + Ocy: 'О', + ocy: 'о', + odash: '⊝', + Odblac: 'Ő', + odblac: 'ő', + odiv: '⨸', + odot: '⊙', + odsold: '⦼', + OElig: 'Œ', + oelig: 'œ', + ofcir: '⦿', + Ofr: '𝔒', + ofr: '𝔬', + ogon: '˛', + Ograve: 'Ò', + ograve: 'ò', + ogt: '⧁', + ohbar: '⦵', + ohm: 'Ω', + oint: '∮', + olarr: '↺', + olcir: '⦾', + olcross: '⦻', + oline: '‾', + olt: '⧀', + Omacr: 'Ō', + omacr: 'ō', + Omega: 'Ω', + omega: 'ω', + Omicron: 'Ο', + omicron: 'ο', + omid: '⦶', + ominus: '⊖', + Oopf: '𝕆', + oopf: '𝕠', + opar: '⦷', + OpenCurlyDoubleQuote: '“', + OpenCurlyQuote: '‘', + operp: '⦹', + oplus: '⊕', + orarr: '↻', + Or: '⩔', + or: '∨', + ord: '⩝', + order: 'ℴ', + orderof: 'ℴ', + ordf: 'ª', + ordm: 'º', + origof: '⊶', + oror: '⩖', + orslope: '⩗', + orv: '⩛', + oS: 'Ⓢ', + Oscr: '𝒪', + oscr: 'ℴ', + Oslash: 'Ø', + oslash: 'ø', + osol: '⊘', + Otilde: 'Õ', + otilde: 'õ', + otimesas: '⨶', + Otimes: '⨷', + otimes: '⊗', + Ouml: 'Ö', + ouml: 'ö', + ovbar: '⌽', + OverBar: '‾', + OverBrace: '⏞', + OverBracket: '⎴', + OverParenthesis: '⏜', + para: '¶', + parallel: '∥', + par: '∥', + parsim: '⫳', + parsl: '⫽', + part: '∂', + PartialD: '∂', + Pcy: 'П', + pcy: 'п', + percnt: '%', + period: '.', + permil: '‰', + perp: '⊥', + pertenk: '‱', + Pfr: '𝔓', + pfr: '𝔭', + Phi: 'Φ', + phi: 'φ', + phiv: 'ϕ', + phmmat: 'ℳ', + phone: '☎', + Pi: 'Π', + pi: 'π', + pitchfork: '⋔', + piv: 'ϖ', + planck: 'ℏ', + planckh: 'ℎ', + plankv: 'ℏ', + plusacir: '⨣', + plusb: '⊞', + pluscir: '⨢', + plus: '+', + plusdo: '∔', + plusdu: '⨥', + pluse: '⩲', + PlusMinus: '±', + plusmn: '±', + plussim: '⨦', + plustwo: '⨧', + pm: '±', + Poincareplane: 'ℌ', + pointint: '⨕', + popf: '𝕡', + Popf: 'ℙ', + pound: '£', + prap: '⪷', + Pr: '⪻', + pr: '≺', + prcue: '≼', + precapprox: '⪷', + prec: '≺', + preccurlyeq: '≼', + Precedes: '≺', + PrecedesEqual: '⪯', + PrecedesSlantEqual: '≼', + PrecedesTilde: '≾', + preceq: '⪯', + precnapprox: '⪹', + precneqq: '⪵', + precnsim: '⋨', + pre: '⪯', + prE: '⪳', + precsim: '≾', + prime: '′', + Prime: '″', + primes: 'ℙ', + prnap: '⪹', + prnE: '⪵', + prnsim: '⋨', + prod: '∏', + Product: '∏', + profalar: '⌮', + profline: '⌒', + profsurf: '⌓', + prop: '∝', + Proportional: '∝', + Proportion: '∷', + propto: '∝', + prsim: '≾', + prurel: '⊰', + Pscr: '𝒫', + pscr: '𝓅', + Psi: 'Ψ', + psi: 'ψ', + puncsp: ' ', + Qfr: '𝔔', + qfr: '𝔮', + qint: '⨌', + qopf: '𝕢', + Qopf: 'ℚ', + qprime: '⁗', + Qscr: '𝒬', + qscr: '𝓆', + quaternions: 'ℍ', + quatint: '⨖', + quest: '?', + questeq: '≟', + quot: '"', + QUOT: '"', + rAarr: '⇛', + race: '∽', + Racute: 'Ŕ', + racute: 'ŕ', + radic: '√', + raemptyv: '⦳', + rang: '⟩', + Rang: '⟫', + rangd: '⦒', + range: '⦥', + rangle: '⟩', + raquo: '»', + rarrap: '⥵', + rarrb: '⇥', + rarrbfs: '⤠', + rarrc: '⤳', + rarr: '→', + Rarr: '↠', + rArr: '⇒', + rarrfs: '⤞', + rarrhk: '↪', + rarrlp: '↬', + rarrpl: '⥅', + rarrsim: '⥴', + Rarrtl: '⤖', + rarrtl: '↣', + rarrw: '↝', + ratail: '⤚', + rAtail: '⤜', + ratio: '∶', + rationals: 'ℚ', + rbarr: '⤍', + rBarr: '⤏', + RBarr: '⤐', + rbbrk: '❳', + rbrace: '}', + rbrack: ']', + rbrke: '⦌', + rbrksld: '⦎', + rbrkslu: '⦐', + Rcaron: 'Ř', + rcaron: 'ř', + Rcedil: 'Ŗ', + rcedil: 'ŗ', + rceil: '⌉', + rcub: '}', + Rcy: 'Р', + rcy: 'р', + rdca: '⤷', + rdldhar: '⥩', + rdquo: '”', + rdquor: '”', + rdsh: '↳', + real: 'ℜ', + realine: 'ℛ', + realpart: 'ℜ', + reals: 'ℝ', + Re: 'ℜ', + rect: '▭', + reg: '®', + REG: '®', + ReverseElement: '∋', + ReverseEquilibrium: '⇋', + ReverseUpEquilibrium: '⥯', + rfisht: '⥽', + rfloor: '⌋', + rfr: '𝔯', + Rfr: 'ℜ', + rHar: '⥤', + rhard: '⇁', + rharu: '⇀', + rharul: '⥬', + Rho: 'Ρ', + rho: 'ρ', + rhov: 'ϱ', + RightAngleBracket: '⟩', + RightArrowBar: '⇥', + rightarrow: '→', + RightArrow: '→', + Rightarrow: '⇒', + RightArrowLeftArrow: '⇄', + rightarrowtail: '↣', + RightCeiling: '⌉', + RightDoubleBracket: '⟧', + RightDownTeeVector: '⥝', + RightDownVectorBar: '⥕', + RightDownVector: '⇂', + RightFloor: '⌋', + rightharpoondown: '⇁', + rightharpoonup: '⇀', + rightleftarrows: '⇄', + rightleftharpoons: '⇌', + rightrightarrows: '⇉', + rightsquigarrow: '↝', + RightTeeArrow: '↦', + RightTee: '⊢', + RightTeeVector: '⥛', + rightthreetimes: '⋌', + RightTriangleBar: '⧐', + RightTriangle: '⊳', + RightTriangleEqual: '⊵', + RightUpDownVector: '⥏', + RightUpTeeVector: '⥜', + RightUpVectorBar: '⥔', + RightUpVector: '↾', + RightVectorBar: '⥓', + RightVector: '⇀', + ring: '˚', + risingdotseq: '≓', + rlarr: '⇄', + rlhar: '⇌', + rlm: '‏', + rmoustache: '⎱', + rmoust: '⎱', + rnmid: '⫮', + roang: '⟭', + roarr: '⇾', + robrk: '⟧', + ropar: '⦆', + ropf: '𝕣', + Ropf: 'ℝ', + roplus: '⨮', + rotimes: '⨵', + RoundImplies: '⥰', + rpar: ')', + rpargt: '⦔', + rppolint: '⨒', + rrarr: '⇉', + Rrightarrow: '⇛', + rsaquo: '›', + rscr: '𝓇', + Rscr: 'ℛ', + rsh: '↱', + Rsh: '↱', + rsqb: ']', + rsquo: '’', + rsquor: '’', + rthree: '⋌', + rtimes: '⋊', + rtri: '▹', + rtrie: '⊵', + rtrif: '▸', + rtriltri: '⧎', + RuleDelayed: '⧴', + ruluhar: '⥨', + rx: '℞', + Sacute: 'Ś', + sacute: 'ś', + sbquo: '‚', + scap: '⪸', + Scaron: 'Š', + scaron: 'š', + Sc: '⪼', + sc: '≻', + sccue: '≽', + sce: '⪰', + scE: '⪴', + Scedil: 'Ş', + scedil: 'ş', + Scirc: 'Ŝ', + scirc: 'ŝ', + scnap: '⪺', + scnE: '⪶', + scnsim: '⋩', + scpolint: '⨓', + scsim: '≿', + Scy: 'С', + scy: 'с', + sdotb: '⊡', + sdot: '⋅', + sdote: '⩦', + searhk: '⤥', + searr: '↘', + seArr: '⇘', + searrow: '↘', + sect: '§', + semi: ';', + seswar: '⤩', + setminus: '∖', + setmn: '∖', + sext: '✶', + Sfr: '𝔖', + sfr: '𝔰', + sfrown: '⌢', + sharp: '♯', + SHCHcy: 'Щ', + shchcy: 'щ', + SHcy: 'Ш', + shcy: 'ш', + ShortDownArrow: '↓', + ShortLeftArrow: '←', + shortmid: '∣', + shortparallel: '∥', + ShortRightArrow: '→', + ShortUpArrow: '↑', + shy: '­', + Sigma: 'Σ', + sigma: 'σ', + sigmaf: 'ς', + sigmav: 'ς', + sim: '∼', + simdot: '⩪', + sime: '≃', + simeq: '≃', + simg: '⪞', + simgE: '⪠', + siml: '⪝', + simlE: '⪟', + simne: '≆', + simplus: '⨤', + simrarr: '⥲', + slarr: '←', + SmallCircle: '∘', + smallsetminus: '∖', + smashp: '⨳', + smeparsl: '⧤', + smid: '∣', + smile: '⌣', + smt: '⪪', + smte: '⪬', + smtes: '⪬', + SOFTcy: 'Ь', + softcy: 'ь', + solbar: '⌿', + solb: '⧄', + sol: '/', + Sopf: '𝕊', + sopf: '𝕤', + spades: '♠', + spadesuit: '♠', + spar: '∥', + sqcap: '⊓', + sqcaps: '⊓', + sqcup: '⊔', + sqcups: '⊔', + Sqrt: '√', + sqsub: '⊏', + sqsube: '⊑', + sqsubset: '⊏', + sqsubseteq: '⊑', + sqsup: '⊐', + sqsupe: '⊒', + sqsupset: '⊐', + sqsupseteq: '⊒', + square: '□', + Square: '□', + SquareIntersection: '⊓', + SquareSubset: '⊏', + SquareSubsetEqual: '⊑', + SquareSuperset: '⊐', + SquareSupersetEqual: '⊒', + SquareUnion: '⊔', + squarf: '▪', + squ: '□', + squf: '▪', + srarr: '→', + Sscr: '𝒮', + sscr: '𝓈', + ssetmn: '∖', + ssmile: '⌣', + sstarf: '⋆', + Star: '⋆', + star: '☆', + starf: '★', + straightepsilon: 'ϵ', + straightphi: 'ϕ', + strns: '¯', + sub: '⊂', + Sub: '⋐', + subdot: '⪽', + subE: '⫅', + sube: '⊆', + subedot: '⫃', + submult: '⫁', + subnE: '⫋', + subne: '⊊', + subplus: '⪿', + subrarr: '⥹', + subset: '⊂', + Subset: '⋐', + subseteq: '⊆', + subseteqq: '⫅', + SubsetEqual: '⊆', + subsetneq: '⊊', + subsetneqq: '⫋', + subsim: '⫇', + subsub: '⫕', + subsup: '⫓', + succapprox: '⪸', + succ: '≻', + succcurlyeq: '≽', + Succeeds: '≻', + SucceedsEqual: '⪰', + SucceedsSlantEqual: '≽', + SucceedsTilde: '≿', + succeq: '⪰', + succnapprox: '⪺', + succneqq: '⪶', + succnsim: '⋩', + succsim: '≿', + SuchThat: '∋', + sum: '∑', + Sum: '∑', + sung: '♪', + sup1: '¹', + sup2: '²', + sup3: '³', + sup: '⊃', + Sup: '⋑', + supdot: '⪾', + supdsub: '⫘', + supE: '⫆', + supe: '⊇', + supedot: '⫄', + Superset: '⊃', + SupersetEqual: '⊇', + suphsol: '⟉', + suphsub: '⫗', + suplarr: '⥻', + supmult: '⫂', + supnE: '⫌', + supne: '⊋', + supplus: '⫀', + supset: '⊃', + Supset: '⋑', + supseteq: '⊇', + supseteqq: '⫆', + supsetneq: '⊋', + supsetneqq: '⫌', + supsim: '⫈', + supsub: '⫔', + supsup: '⫖', + swarhk: '⤦', + swarr: '↙', + swArr: '⇙', + swarrow: '↙', + swnwar: '⤪', + szlig: 'ß', + Tab: ' ', + target: '⌖', + Tau: 'Τ', + tau: 'τ', + tbrk: '⎴', + Tcaron: 'Ť', + tcaron: 'ť', + Tcedil: 'Ţ', + tcedil: 'ţ', + Tcy: 'Т', + tcy: 'т', + tdot: '⃛', + telrec: '⌕', + Tfr: '𝔗', + tfr: '𝔱', + there4: '∴', + therefore: '∴', + Therefore: '∴', + Theta: 'Θ', + theta: 'θ', + thetasym: 'ϑ', + thetav: 'ϑ', + thickapprox: '≈', + thicksim: '∼', + ThickSpace: ' ', + ThinSpace: ' ', + thinsp: ' ', + thkap: '≈', + thksim: '∼', + THORN: 'Þ', + thorn: 'þ', + tilde: '˜', + Tilde: '∼', + TildeEqual: '≃', + TildeFullEqual: '≅', + TildeTilde: '≈', + timesbar: '⨱', + timesb: '⊠', + times: '×', + timesd: '⨰', + tint: '∭', + toea: '⤨', + topbot: '⌶', + topcir: '⫱', + top: '⊤', + Topf: '𝕋', + topf: '𝕥', + topfork: '⫚', + tosa: '⤩', + tprime: '‴', + trade: '™', + TRADE: '™', + triangle: '▵', + triangledown: '▿', + triangleleft: '◃', + trianglelefteq: '⊴', + triangleq: '≜', + triangleright: '▹', + trianglerighteq: '⊵', + tridot: '◬', + trie: '≜', + triminus: '⨺', + TripleDot: '⃛', + triplus: '⨹', + trisb: '⧍', + tritime: '⨻', + trpezium: '⏢', + Tscr: '𝒯', + tscr: '𝓉', + TScy: 'Ц', + tscy: 'ц', + TSHcy: 'Ћ', + tshcy: 'ћ', + Tstrok: 'Ŧ', + tstrok: 'ŧ', + twixt: '≬', + twoheadleftarrow: '↞', + twoheadrightarrow: '↠', + Uacute: 'Ú', + uacute: 'ú', + uarr: '↑', + Uarr: '↟', + uArr: '⇑', + Uarrocir: '⥉', + Ubrcy: 'Ў', + ubrcy: 'ў', + Ubreve: 'Ŭ', + ubreve: 'ŭ', + Ucirc: 'Û', + ucirc: 'û', + Ucy: 'У', + ucy: 'у', + udarr: '⇅', + Udblac: 'Ű', + udblac: 'ű', + udhar: '⥮', + ufisht: '⥾', + Ufr: '𝔘', + ufr: '𝔲', + Ugrave: 'Ù', + ugrave: 'ù', + uHar: '⥣', + uharl: '↿', + uharr: '↾', + uhblk: '▀', + ulcorn: '⌜', + ulcorner: '⌜', + ulcrop: '⌏', + ultri: '◸', + Umacr: 'Ū', + umacr: 'ū', + uml: '¨', + UnderBar: '_', + UnderBrace: '⏟', + UnderBracket: '⎵', + UnderParenthesis: '⏝', + Union: '⋃', + UnionPlus: '⊎', + Uogon: 'Ų', + uogon: 'ų', + Uopf: '𝕌', + uopf: '𝕦', + UpArrowBar: '⤒', + uparrow: '↑', + UpArrow: '↑', + Uparrow: '⇑', + UpArrowDownArrow: '⇅', + updownarrow: '↕', + UpDownArrow: '↕', + Updownarrow: '⇕', + UpEquilibrium: '⥮', + upharpoonleft: '↿', + upharpoonright: '↾', + uplus: '⊎', + UpperLeftArrow: '↖', + UpperRightArrow: '↗', + upsi: 'υ', + Upsi: 'ϒ', + upsih: 'ϒ', + Upsilon: 'Υ', + upsilon: 'υ', + UpTeeArrow: '↥', + UpTee: '⊥', + upuparrows: '⇈', + urcorn: '⌝', + urcorner: '⌝', + urcrop: '⌎', + Uring: 'Ů', + uring: 'ů', + urtri: '◹', + Uscr: '𝒰', + uscr: '𝓊', + utdot: '⋰', + Utilde: 'Ũ', + utilde: 'ũ', + utri: '▵', + utrif: '▴', + uuarr: '⇈', + Uuml: 'Ü', + uuml: 'ü', + uwangle: '⦧', + vangrt: '⦜', + varepsilon: 'ϵ', + varkappa: 'ϰ', + varnothing: '∅', + varphi: 'ϕ', + varpi: 'ϖ', + varpropto: '∝', + varr: '↕', + vArr: '⇕', + varrho: 'ϱ', + varsigma: 'ς', + varsubsetneq: '⊊', + varsubsetneqq: '⫋', + varsupsetneq: '⊋', + varsupsetneqq: '⫌', + vartheta: 'ϑ', + vartriangleleft: '⊲', + vartriangleright: '⊳', + vBar: '⫨', + Vbar: '⫫', + vBarv: '⫩', + Vcy: 'В', + vcy: 'в', + vdash: '⊢', + vDash: '⊨', + Vdash: '⊩', + VDash: '⊫', + Vdashl: '⫦', + veebar: '⊻', + vee: '∨', + Vee: '⋁', + veeeq: '≚', + vellip: '⋮', + verbar: '|', + Verbar: '‖', + vert: '|', + Vert: '‖', + VerticalBar: '∣', + VerticalLine: '|', + VerticalSeparator: '❘', + VerticalTilde: '≀', + VeryThinSpace: ' ', + Vfr: '𝔙', + vfr: '𝔳', + vltri: '⊲', + vnsub: '⊂', + vnsup: '⊃', + Vopf: '𝕍', + vopf: '𝕧', + vprop: '∝', + vrtri: '⊳', + Vscr: '𝒱', + vscr: '𝓋', + vsubnE: '⫋', + vsubne: '⊊', + vsupnE: '⫌', + vsupne: '⊋', + Vvdash: '⊪', + vzigzag: '⦚', + Wcirc: 'Ŵ', + wcirc: 'ŵ', + wedbar: '⩟', + wedge: '∧', + Wedge: '⋀', + wedgeq: '≙', + weierp: '℘', + Wfr: '𝔚', + wfr: '𝔴', + Wopf: '𝕎', + wopf: '𝕨', + wp: '℘', + wr: '≀', + wreath: '≀', + Wscr: '𝒲', + wscr: '𝓌', + xcap: '⋂', + xcirc: '◯', + xcup: '⋃', + xdtri: '▽', + Xfr: '𝔛', + xfr: '𝔵', + xharr: '⟷', + xhArr: '⟺', + Xi: 'Ξ', + xi: 'ξ', + xlarr: '⟵', + xlArr: '⟸', + xmap: '⟼', + xnis: '⋻', + xodot: '⨀', + Xopf: '𝕏', + xopf: '𝕩', + xoplus: '⨁', + xotime: '⨂', + xrarr: '⟶', + xrArr: '⟹', + Xscr: '𝒳', + xscr: '𝓍', + xsqcup: '⨆', + xuplus: '⨄', + xutri: '△', + xvee: '⋁', + xwedge: '⋀', + Yacute: 'Ý', + yacute: 'ý', + YAcy: 'Я', + yacy: 'я', + Ycirc: 'Ŷ', + ycirc: 'ŷ', + Ycy: 'Ы', + ycy: 'ы', + yen: '¥', + Yfr: '𝔜', + yfr: '𝔶', + YIcy: 'Ї', + yicy: 'ї', + Yopf: '𝕐', + yopf: '𝕪', + Yscr: '𝒴', + yscr: '𝓎', + YUcy: 'Ю', + yucy: 'ю', + yuml: 'ÿ', + Yuml: 'Ÿ', + Zacute: 'Ź', + zacute: 'ź', + Zcaron: 'Ž', + zcaron: 'ž', + Zcy: 'З', + zcy: 'з', + Zdot: 'Ż', + zdot: 'ż', + zeetrf: 'ℨ', + ZeroWidthSpace: '​', + Zeta: 'Ζ', + zeta: 'ζ', + zfr: '𝔷', + Zfr: 'ℨ', + ZHcy: 'Ж', + zhcy: 'ж', + zigrarr: '⇝', + zopf: '𝕫', + Zopf: 'ℤ', + Zscr: '𝒵', + zscr: '𝓏', + zwj: '‍', + zwnj: '‌' + }; + + inline public static function entityToCharEr( er : EReg ) return entityToChar(er.matched(0)); + public static function entityToChar( m : String ) + { + var isNumeric = ~/^&#/.match(m); + var isHex = ~/^&#[Xx]/.match(m); + var uchar; + + if ( isNumeric ) + { + var num; + if ( isHex ) num = Std.parseInt('0x' + m.substr(3, m.length - 4)); + else num = Std.parseInt(m.substr(2, m.length - 3)); + + uchar = fromCodePoint([num]); + } + else + { + uchar = Reflect.field(entities, m.substr(1, m.length - 2)); + } + + return uchar != null ? uchar : m; + } + + public static function fromCodePoint( args : Array ) + { + var MAX_SIZE = 0x4000; + var codeUnits = []; + var highSurrogate; + var lowSurrogate; + var index = -1; + var length = args.length; + + if ( length < 1 ) + return ''; + + var result = ''; + + while ( ++index < length ) + { + var codePoint = args[index]; + if ( + !Math.isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity` + codePoint < 0 || // not a valid Unicode code point + codePoint > 0x10FFFF || // not a valid Unicode code point + Math.floor(codePoint) != codePoint // not an integer + ) + { + return String.fromCharCode(0xFFFD); + } + + if ( codePoint <= 0xFFFF ) + { + // BMP code point + codeUnits.push(codePoint); + } + else + { + // Astral code point; split in surrogate halves + // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + codePoint -= 0x10000; + highSurrogate = (codePoint >> 10) + 0xD800; + lowSurrogate = (codePoint % 0x400) + 0xDC00; + codeUnits.push(highSurrogate); + codeUnits.push(lowSurrogate); + } + + if ( index + 1 == length || codeUnits.length > MAX_SIZE ) + { + for( cu in codeUnits ) + result += String.fromCharCode(cu); + codeUnits = []; + } + } + + return result; + } +} \ No newline at end of file diff --git a/src/comark/GithubInlineParser.hx b/src/comark/GithubInlineParser.hx index c11ae81..1218c78 100644 --- a/src/comark/GithubInlineParser.hx +++ b/src/comark/GithubInlineParser.hx @@ -12,31 +12,32 @@ class GithubInlineParser extends InlineParser public function new( ) { super(); - - reMain = ~/^(?:[\n`\[\]\\!<&*_~]|[^\n`\[\]\\!<&*_~]+)/m; + //~/^(?:[\n`\[\]\\!<&*_]|[^\n`\[\]\\!<&*_]+)/m; + reMain = //~/^(?:[\n`\[\]\\!<&*_~]|[^\n`\[\]\\!<&*_~]+)/m; + ~/^(?:[_*`\n]+|[\[\]\\!<&*_]|(?: *[^\n `\[\]\\!<&*_~]+)+|[ \n]+)/m; } - override function applyParsers( c : String, inlines : Array ) : Int + override function applyParsers( c : Int, inlines : Array ) : Bool { return switch( c ) { - case '~': parseStrike(inlines); - case '#': parseHashtag(inlines); + case '~'.code: parseStrike(inlines); + case '#'.code: parseHashtag(inlines); case _: super.applyParsers(c, inlines); } } - - function parseStrike( inlines : Array ) : Int + function parseStrike( inlines : Array ) : Bool { var startpos : Int = this.pos; - var c : String; + var c : Int; var first_close : Int = 0; - var nxt : String = this.peek(); - if ( nxt == '~' ) c = nxt; + + var nxt : Int = this.peek(); + if ( nxt == '~'.code ) c = nxt; else - return 0; + return false; // Get opening delimiters. var res = this.scanDelims(c); @@ -54,12 +55,13 @@ class GithubInlineParser extends InlineParser var delimpos = inlines.length - 1; if ( !res.can_open || numdelims != 2 ) - return 0; + return false; // We started with ~~ while ( true ) { res = this.scanDelims(c); + if ( res.numdelims >= 2 && res.can_close ) { this.pos += 2; @@ -68,19 +70,19 @@ class GithubInlineParser extends InlineParser inlines.splice(delimpos + 1, inlines.length); break; } - else if ( this.parseInline(inlines) == 0 ) + else if( !this.parseInline(inlines) ) break; } - return (this.pos - startpos); + return (this.pos != startpos); } - function parseHashtag( inlines : Array ) : Int + function parseHashtag( inlines : Array ) : Bool { // Entity var prev = subject.charAt(pos - 1); if ( pos > 0 && prev != ' ' ) - return 0; + return false; var startpos : Int = this.pos; this.pos++; @@ -93,12 +95,12 @@ class GithubInlineParser extends InlineParser //title: m, label: [ { t: 'Str', c: '#$m' } ], }); - return m.length; + return true; } else { this.pos = startpos; - return 0; + return false; } } } \ No newline at end of file diff --git a/src/comark/GithubMarkdown.hx b/src/comark/GithubMarkdown.hx index 65634b5..4f56060 100644 --- a/src/comark/GithubMarkdown.hx +++ b/src/comark/GithubMarkdown.hx @@ -7,11 +7,14 @@ package comark; class GithubMarkdown extends Markdown { - public function new( ) + public function new( ?header_start : Int = 1, ?allow_html : Bool = false ) { super(); render = new GithubHtmlRenderer(); parser = new GithubDocParser(); + + render.header_start = header_start; + render.allow_html = allow_html; } } \ No newline at end of file diff --git a/src/comark/HtmlRenderer.hx b/src/comark/HtmlRenderer.hx index badd80f..4d711f2 100644 --- a/src/comark/HtmlRenderer.hx +++ b/src/comark/HtmlRenderer.hx @@ -9,18 +9,25 @@ using StringTools; class HtmlRenderer { + public var header_start : Int; + public var allow_html : Bool; + // default options: var blocksep : String; // '\n', // space between blocks var innersep : String; // '\n', // space between block container tag and contents var softbreak: String; // '\n', // by default, soft breaks are rendered as newlines in HTML // set to "
" to make them hard breaks // set to " " if you want to ignore line wrapping in source + //var asd : String; public function new( ) { blocksep = '\n'; innersep = '\n'; softbreak = '\n'; + + header_start = 1; + allow_html = true; } public function render( block : BlockElement ) return renderBlock(block); @@ -66,10 +73,7 @@ class HtmlRenderer return inTags('strong', [], renderInlines(inlineHtml.childs)); case 'Html': - return inlineHtml.c; - - case 'Entity': - return inlineHtml.c; + return allow_html ? inlineHtml.c : escape(inlineHtml.c); case 'Link': attrs = [['href', escape(inlineHtml.destination, true)]]; @@ -143,7 +147,7 @@ class HtmlRenderer return inTags(tag, attr, innersep + renderBlocks(block.children, block.tight) + innersep); case 'ATXHeader', 'SetextHeader': - tag = 'h' + block.level; + tag = 'h' + Std.int(Math.min(6, header_start - 1 + block.level)); return inTags(tag, [], renderInlines(block.inline_content)); case 'IndentedCode': @@ -156,7 +160,7 @@ class HtmlRenderer return inTags('pre', [], inTags('code', attr, escape(block.string_content))); case 'HtmlBlock': - return block.string_content; + return allow_html ? block.string_content : escape(block.string_content); case 'ReferenceDef': return ""; @@ -196,3 +200,35 @@ class HtmlRenderer return r; } } + +/* +// The HtmlRenderer object. +function HtmlRenderer(){ + return { + // default options: + blocksep: '\n', // space between blocks + innersep: '\n', // space between block container tag and contents + softbreak: '\n', // by default, soft breaks are rendered as newlines in HTML + // set to "
" to make them hard breaks + // set to " " if you want to ignore line wrapping in source + escape: function(s, preserve_entities) { + if (preserve_entities) { + return s.replace(/[&](?![#](x[a-f0-9]{1,8}|[0-9]{1,8});|[a-z][a-z0-9]{1,31};)/gi,'&') + .replace(/[<]/g,'<') + .replace(/[>]/g,'>') + .replace(/["]/g,'"'); + } else { + return s.replace(/[&]/g,'&') + .replace(/[<]/g,'<') + .replace(/[>]/g,'>') + .replace(/["]/g,'"'); + } + }, + renderInline: renderInline, + renderInlines: renderInlines, + renderBlock: renderBlock, + renderBlocks: renderBlocks, + render: renderBlock + }; +} +*/ diff --git a/src/comark/InlineElement.hx b/src/comark/InlineElement.hx index 2c6000e..dda6897 100644 --- a/src/comark/InlineElement.hx +++ b/src/comark/InlineElement.hx @@ -12,4 +12,5 @@ typedef InlineElement = { @:optional var childs : Array; @:optional var label : Array; + //@:optional var childs : Array; }; \ No newline at end of file diff --git a/src/comark/InlineParser.hx b/src/comark/InlineParser.hx index ba99bd7..e06dfa1 100644 --- a/src/comark/InlineParser.hx +++ b/src/comark/InlineParser.hx @@ -7,9 +7,30 @@ import haxe.ds.StringMap; using StringTools; +typedef EmphasisOpener = { + var cc : Int; // cc, + var numdelims : Int; // numdelims, + var pos : Int; // inlines.length - 1, + var previous : EmphasisOpener; // this.emphasis_openers +}; class InlineParser { + inline static var C_NEWLINE = 10; + inline static var C_SPACE = 32; + inline static var C_ASTERISK = 42; + inline static var C_UNDERSCORE = 95; + inline static var C_BACKTICK = 96; + inline static var C_OPEN_BRACKET = 91; + inline static var C_CLOSE_BRACKET = 93; + inline static var C_LESSTHAN = 60; + inline static var C_GREATERTHAN = 62; + inline static var C_BANG = 33; + inline static var C_BACKSLASH = 92; + inline static var C_AMPERSAND = 38; + inline static var C_OPEN_PAREN = 40; + inline static var C_COLON = 58; + static var TAGNAME = '[A-Za-z][A-Za-z0-9]*'; static var ATTRIBUTENAME = '[a-zA-Z_:][a-zA-Z0-9:._-]*'; static var UNQUOTEDVALUE = "[^\"'=<>`\\x00-\\x20]+"; @@ -27,14 +48,20 @@ class InlineParser static var HTMLTAG = "(?:" + OPENTAG + "|" + CLOSETAG + "|" + HTMLCOMMENT + "|" + PROCESSINGINSTRUCTION + "|" + DECLARATION + "|" + CDATA + ")"; public static var reHtmlTag = new EReg('^' + HTMLTAG, 'i'); + public static var ESCAPABLE = '[!"#$%&\'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]'; + public static var reAllEscapedChar = new EReg('\\\\(' + ESCAPABLE + ')', 'g'); // Matches a character with a special meaning in markdown, // or a string of non-special characters. var reMain : EReg; - static var reEscapable = new EReg(DocParser.ESCAPABLE, ''); + static var reEscapable = new EReg(ESCAPABLE, ''); + + static var ENTITY = "&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});"; + static var reEntity = new EReg(ENTITY, 'gi'); + static var reEntityHere = new EReg('^' + ENTITY, 'i'); - static var ESCAPED_CHAR = '\\\\' + DocParser.ESCAPABLE; + static var ESCAPED_CHAR = '\\\\' + ESCAPABLE; static var reLinkDestinationBraces = new EReg('^(?:[<](?:[^<>\\n\\\\\\x00]' + '|' + ESCAPED_CHAR + '|' + '\\\\)*[>])', ''); static var REG_CHAR = '[^\\\\()\\x00-\\x20]'; @@ -50,12 +77,14 @@ class InlineParser var subject : String; var label_nest_level : Int; //0, // used by parseLinkLabel method + var emphasis_openers : EmphasisOpener; // used by parseEmphasis method var pos : Int; // 0, var refmap : StringMap; // { }, public function new( ) { - reMain = ~/^(?:[\n`\[\]\\!<&*_]|[^\n`\[\]\\!<&*_]+)/m; + reMain = // ~/^(?:[\n`\[\]\\!<&*_]|[^\n`\[\]\\!<&*_]+)/m; + ~/^(?:[_*`\n]+|[\[\]\\!<&*_]|(?: *[^\n `\[\]\\!<&*_]+)+|[ \n]+)/m; subject = ''; label_nest_level = 0; @@ -63,6 +92,8 @@ class InlineParser refmap = new StringMap(); } + // Parse s as a list of inlines, using refmap to resolve references. + // parseInlines public function parse( s : String, refmap : StringMap ) : Array { this.subject = s; @@ -70,7 +101,7 @@ class InlineParser this.refmap = refmap != null ? refmap : new StringMap(); var inlines : Array = []; - while ( parseInline(inlines) > 0 ) { } + while ( parseInline(inlines) ) { } return inlines; } @@ -80,29 +111,55 @@ class InlineParser // number of characters parsed (possibly 0). - // Parse the next inline element in subject, advancing subject position - // and adding the result to 'inlines'. - function parseInline( inlines : Array ) : Int + // Parse the next inline element in subject, advancing subject position. + // On success, add the result to the inlines list, and return true. + // On failure, return false. + function parseInline( inlines : Array ) : Bool { + var startpos = this.pos; + var origlen = inlines.length; + var c = peek(); + if ( c == -1 ) + return false; + + var res : Bool = applyParsers(c, inlines); + if ( !res ) + { + pos += 1; + inlines.push({ + t: 'Str', + c: EntityToChar.fromCodePoint([c]) + }); + } - var res : Int = applyParsers(c, inlines); - return res > 0 ? res : parseString(inlines); + return true; + // return res > 0 ? res : parseString(inlines); } - function applyParsers( c : String, inlines : Array ) : Int + function applyParsers( c : Int, inlines : Array ) : Bool { return switch( c ) { - case '\n': parseNewline(inlines); - case '\\': parseEscaped(inlines); - case '`': parseBackticks(inlines); - case '*', '_': parseEmphasis(inlines); - case '[': parseLink(inlines); - case '!': parseImage(inlines); - case '<': var res = parseAutolink(inlines); res > 0 ? res : parseHtmlTag(inlines); - case '&': parseEntity(inlines); - case _: 0; + case C_NEWLINE, + C_SPACE: parseNewline(inlines); + + case C_BACKSLASH: parseBackslash(inlines); + + case C_BACKTICK: parseBackticks(inlines); + + case C_ASTERISK, + C_UNDERSCORE: parseEmphasis(c, inlines); + + case C_OPEN_BRACKET: parseLink(inlines); + + case C_BANG: parseImage(inlines); + + case C_LESSTHAN: parseAutolink(inlines) || parseHtmlTag(inlines); + + case C_AMPERSAND: parseEntity(inlines); + + case _: parseString(inlines); } } @@ -124,12 +181,10 @@ class InlineParser if ( matchChars == 0 ) return 0; - - rawlabel = this.subject.substr(0, matchChars); // colon: - if ( this.peek() == ':' ) + if ( this.peek() == C_COLON ) { this.pos++; } @@ -141,7 +196,7 @@ class InlineParser // link url this.spnl(); - + dest = this.parseLinkDestination(); if ( dest == null || dest.length == 0 ) { @@ -175,9 +230,22 @@ class InlineParser } // Parse a newline. - // If it was preceded by two spaces, return a hard line break; otherwise a soft line break. - function parseNewline( inlines : Array ) : Int + // If it was preceded by two spaces, return a hard line break; + // otherwise a soft line break. + function parseNewline( inlines : Array ) : Bool { + var m : String = match(~/^ *\n/); + + if ( m == null ) + return false; + + if ( m.length > 2 ) + inlines.push( { t: 'Hardbreak' } ); + else + inlines.push( { t: 'Softbreak' } ); + + return true; + /* if ( this.peek() == '\n') { pos++; @@ -198,48 +266,48 @@ class InlineParser return 1; } else return 0; + */ } // Parse a backslash-escaped special character, adding either the escaped // character, a hard line break (if the backslash is followed by a newline), // or a literal backslash to the 'inlines' list. - function parseEscaped( inlines : Array ) : Int + function parseBackslash( inlines : Array ) : Bool { var subj = this.subject; var pos = this.pos; - if ( subj.charAt(pos) == '\\' ) + if ( subj.charCodeAt(pos) == C_BACKSLASH ) { if ( subj.charAt(pos + 1) == '\n' ) { inlines.push({ t: 'Hardbreak' }); this.pos = this.pos + 2; - return 2; } else if ( reEscapable.match(subj.charAt(pos + 1)) ) { inlines.push({ t: 'Str', c: subj.charAt(pos + 1) }); this.pos = this.pos + 2; - return 2; } else { this.pos++; inlines.push({t: 'Str', c: '\\'}); - return 1; } + + return true; } - else return 0; + else return false; } // Attempt to parse backticks, adding either a backtick code span or a // literal sequence of backticks to the 'inlines' list. - function parseBackticks( inlines : Array ) : Int + function parseBackticks( inlines : Array ) : Bool { var startpos = this.pos; var ticks = this.match(~/^`+/); if ( ticks == null ) - return 0; + return false; var afterOpenTicks = this.pos; var foundCode = false; @@ -252,174 +320,122 @@ class InlineParser t: 'Code', c: ~/[ \n]+/g.replace(subject.substring(afterOpenTicks, this.pos - ticks.length), ' ').trim() }); - return (this.pos - startpos); + return true; } } // If we got here, we didn't match a closing backtick sequence. - inlines.push({ t: 'Str', c: ticks }); this.pos = afterOpenTicks; - - return (this.pos - startpos); + inlines.push({ t: 'Str', c: ticks }); + return true; } - // Attempt to parse emphasis or strong emphasis in an efficient way, with no backtracking. - function parseEmphasis( inlines : Array ) : Int + // Attempt to parse emphasis or strong emphasis. + function parseEmphasis( cc : Int, inlines : Array ) : Bool { var startpos = this.pos; - var c ; - var first_close = 0; - var nxt = this.peek(); - if (nxt == '*' || nxt == '_') c = nxt; - else - return 0; - - var numdelims; - var delimpos; - - // Get opening delimiters. - var res = this.scanDelims(c); - numdelims = res.numdelims; - this.pos += numdelims; - - // We provisionally add a literal string. If we match appropriate - // closing delimiters, we'll change this to Strong or Emph. - inlines.push({ - t: 'Str', - c: this.subject.substr(this.pos - numdelims, numdelims) - }); - // Record the position of this opening delimiter: - delimpos = inlines.length - 1; + var res = scanDelims(cc); + var numdelims = res.numdelims; - if ( !res.can_open || numdelims == 0 ) - return 0; - - var first_close_delims = 0; + if ( numdelims == 0 ) + { + this.pos = startpos; + return false; + } - switch ( numdelims ) + if ( res.can_close ) { - case 1: // we started with * or _ - while ( true ) - { - res = this.scanDelims(c); - if ( res.numdelims >= 1 && res.can_close ) - { - this.pos += 1; - // Convert the inline at delimpos, currently a string with the delim, - // into an Emph whose contents are the succeeding inlines - inlines[delimpos].t = 'Emph'; - inlines[delimpos].childs = inlines.slice(delimpos + 1, inlines.length); - inlines.splice(delimpos + 1, inlines.length); - break; - } - else if ( this.parseInline(inlines) == 0 ) - break; - } - return (this.pos - startpos); - - case 2: // We started with ** or __ - while ( true ) - { - res = this.scanDelims(c); - if ( res.numdelims >= 2 && res.can_close ) - { - this.pos += 2; - inlines[delimpos].t = 'Strong'; - inlines[delimpos].childs = inlines.slice(delimpos + 1, inlines.length); - inlines.splice(delimpos + 1, inlines.length); - break; - } - else if ( this.parseInline(inlines) == 0 ) - break; - } - return (this.pos - startpos); - - case 3: // We started with *** or ___ - while ( true ) + // Walk the stack and find a matching opener, if possible + var opener = this.emphasis_openers; + while ( opener != null ) + { + // we have a match! + if ( opener.cc == cc ) { - res = this.scanDelims(c); - if ( res.numdelims >= 1 && res.numdelims <= 3 && res.can_close && res.numdelims != first_close_delims ) + // all openers used + if ( opener.numdelims <= numdelims ) { - if ( first_close_delims == 1 && numdelims > 2 ) res.numdelims = 2; - else if ( first_close_delims == 2 ) res.numdelims = 1; - else if ( res.numdelims == 3 ) + this.pos += opener.numdelims; + var X : Dynamic -> Dynamic = null; + switch ( opener.numdelims ) { - // If we opened with ***, then we interpret *** as ** followed by * - // giving us - res.numdelims = 1; + case 3: X = function(x) { return makeStrong([makeEmph(x)]); }; + case 2: X = makeStrong; + case 1, _: X = makeEmph; } - this.pos += res.numdelims; - if (first_close > 0) - { - // if we've already passed the first closer: - inlines[delimpos].t = first_close_delims == 1 ? 'Strong' : 'Emph'; - inlines[delimpos].childs = ([{ - t: first_close_delims == 1 ? 'Emph' : 'Strong', - childs: inlines.slice(delimpos + 1, first_close) - }] : Array ) - .concat(inlines.slice(first_close + 1)); - - inlines.splice(delimpos + 1, inlines.length); - break; - } - else - { - // this is the first closer; for now, add literal string; - // we'll change this when he hit the second closer - inlines.push({ - t: 'Str', - c: this.subject.substr(this.pos - res.numdelims, this.pos) - }); - first_close = inlines.length - 1; - first_close_delims = res.numdelims; - } + inlines[opener.pos] = X(inlines.slice(opener.pos + 1)); + inlines.splice(opener.pos + 1, inlines.length - (opener.pos + 1)); + + // Remove entries after this, to prevent overlapping nesting: + this.emphasis_openers = opener.previous; + return true; } - else - { - // parse another inline element, til we hit the end - if ( this.parseInline(inlines) == 0 ) - break; + // only some openers used + else if ( opener.numdelims > numdelims ) + { + this.pos += numdelims; + opener.numdelims -= numdelims; + + inlines[opener.pos].c = inlines[opener.pos].c.substr(0, opener.numdelims); + + var X : Dynamic -> Dynamic = numdelims == 2 ? makeStrong : makeEmph; + + inlines[opener.pos + 1] = X(inlines.slice(opener.pos + 1)); + inlines.splice(opener.pos + 2, inlines.length - (opener.pos + 2)); + + // Remove entries after this, to prevent overlapping nesting: + this.emphasis_openers = opener; + return true; } } - return (this.pos - startpos); - - case _: - //return res; - return 0; + opener = opener.previous; + } } - return 0; + // If we're here, we didn't match a closer. + this.pos += numdelims; + inlines.push(makeStr(this.subject.substring(startpos, startpos + numdelims))); + + if ( res.can_open ) + { + // Add entry to stack for this opener + this.emphasis_openers = { + cc: cc, + numdelims: numdelims, + pos: inlines.length - 1, + previous: this.emphasis_openers + }; + } + + return true; } // Attempt to parse an image. If the opening '!' is not followed // by a link, add a literal '!' to inlines. - function parseImage( inlines : Array ) + function parseImage( inlines : Array ) : Bool { if ( this.match(~/^!/) != null ) { - var n = this.parseLink(inlines); - if ( n == 0 ) - { - inlines.push({ t: 'Str', c: '!' }); - return 1; - } - else if ( inlines[inlines.length - 1] != null && inlines[inlines.length - 1].t == 'Link' ) + var link = parseLink(inlines); + if ( link ) { + // if ( inlines[inlines.length - 1] != null && inlines[inlines.length - 1].t == 'Link' ) inlines[inlines.length - 1].t = 'Image'; - return n+1; + return true; } else - throw "Shouldn't happen"; - + { + inlines.push({ t: 'Str', c: '!' }); + return true; + } } - else return 0; + else return false; } - // Attempt to parse a link. If successful, add the link to - // inlines. - function parseLink( inlines : Array ) : Int + // Attempt to parse a link. If successful, add the link to inlines. + function parseLink( inlines : Array ) : Bool { var startpos = this.pos; var reflabel : String; @@ -429,14 +445,14 @@ class InlineParser n = this.parseLinkLabel(); if ( n == 0 ) - return 0; + return false; var afterlabel = this.pos; var rawlabel = this.subject.substr(startpos, n); // if we got this far, we've parsed a label. // Try to parse an explicit link: [label](url "title") - if ( this.peek() == '(' ) + if ( this.peek() == C_OPEN_PAREN ) { this.pos++; if ( this.spnl() && @@ -451,18 +467,18 @@ class InlineParser if ( title == null ) title = ''; - inlines.push( { + inlines.push({ t: 'Link', destination: dest, title: title, label: parseRawLabel(rawlabel) }); - return this.pos - startpos; + return true; } else { this.pos = startpos; - return 0; + return false; } } @@ -470,6 +486,7 @@ class InlineParser // first, see if there's another label var savepos = this.pos; this.spnl(); + var beforelabel = this.pos; n = this.parseLinkLabel(); if ( n == 2 ) @@ -497,17 +514,17 @@ class InlineParser title: link.title, label: parseRawLabel(rawlabel) }); - return this.pos - startpos; + return true; } else { this.pos = startpos; - return 0; + return false; } // Nothing worked, rewind: this.pos = startpos; - return 0; + return false; } // Attempt to parse link title (sans quotes), returning the string @@ -517,7 +534,7 @@ class InlineParser var title = this.match(reLinkTitle); if ( title != null ) // chop off quotes from title and unescape: - return unescape(title.substr(1, title.length - 2)); + return unescapeString(title.substr(1, title.length - 2)); else return null; } @@ -529,21 +546,29 @@ class InlineParser var res = this.match(reLinkDestinationBraces); if ( res != null ) // chop off surrounding <..>: - return unescape(res.substr(1, res.length - 2)); + return fixEncode( + unescape( + unescapeString(res.substr(1, res.length - 2)) + ).urlEncode() + ); else { res = this.match(reLinkDestination); if ( res != null ) - return unescape(res); + return fixEncode( + unescape( + unescapeString(res) + ).urlEncode() + ); else return null; } } // Attempt to parse a link label, returning number of characters parsed. - function parseLinkLabel( ) + function parseLinkLabel( ) : Int { - if ( this.peek() != '[' ) + if ( this.peek() != C_OPEN_BRACKET ) return 0; var startpos = this.pos; @@ -563,29 +588,27 @@ class InlineParser this.pos++; // advance past [ var c; - while ( (c = this.peek()) != null && (c != ']' || nest_level > 0) ) + while ( (c = this.peek()) != -1 && (c != C_CLOSE_BRACKET || nest_level > 0) ) { switch (c) { - case '`': this.parseBackticks([]); - case '<': this.parseAutolink([]) > 0 || this.parseHtmlTag([]) > 0 || this.parseString([]) > 0; - case '[': // nested [] + case C_BACKTICK: this.parseBackticks([]); + case C_LESSTHAN: if ( !(this.parseAutolink([]) || this.parseHtmlTag([])) ) this.pos++; + case C_OPEN_BRACKET: // nested [] nest_level++; this.pos++; - case ']': // nested [] + case C_CLOSE_BRACKET: // nested [] nest_level--; this.pos++; - case '\\': - this.parseEscaped([]); + case C_BACKSLASH: this.parseBackslash([]); - default: - this.parseString([]); + case _: this.parseString([]); } } - if ( c == ']' ) + if ( c == C_CLOSE_BRACKET ) { this.label_nest_level = 0; this.pos++; // advance past ] @@ -593,7 +616,7 @@ class InlineParser } else { - if ( c == null ) + if ( c == -1 ) this.label_nest_level = nest_level; this.pos = startpos; @@ -611,34 +634,42 @@ class InlineParser } // Attempt to parse an entity, adding to inlines if successful. - function parseEntity( inlines : Array ) + function parseEntity( inlines : Array ) : Bool { var m; - if ( (m = this.match(~/^&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});/i)) != null ) + /* + if ((m = this.match(reEntityHere))) { + inlines.push({ t: 'Str', c: entityToChar(m) }); + return true; + } else { + return false; + } + */ + if ( (m = this.match(reEntityHere)) != null ) { - inlines.push({ t: 'Entity', c: m }); - return m.length; + inlines.push({ t: 'Str', c: EntityToChar.entityToChar(m) }); + return true; } else - return 0; + return false; } // Parse a run of ordinary characters, or a single character with // a special meaning in markdown, as a plain string, adding to inlines. - function parseString( inlines : Array ) : Int + function parseString( inlines : Array ) : Bool { var m; if ( (m = this.match(reMain)) != null ) { inlines.push({ t: 'Str', c: m }); - return m.length; + return true; } else - return 0; + return false; } // Attempt to parse an autolink (URL or email in pointy brackets). - function parseAutolink( inlines : Array ) : Int + function parseAutolink( inlines : Array ) : Bool { var erMail = ~/^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/; var erLink = ~/^<(?:coap|doi|javascript|aaa|aaas|about|acap|cap|cid|crid|data|dav|dict|dns|file|ftp|geo|go|gopher|h323|http|https|iax|icap|im|imap|info|ipp|iris|iris.beep|iris.xpc|iris.xpcs|iris.lwz|ldap|mailto|mid|msrp|msrps|mtqp|mupdate|news|nfs|ni|nih|nntp|opaquelocktoken|pop|pres|rtsp|service|session|shttp|sieve|sip|sips|sms|snmp|soap.beep|soap.beeps|tag|tel|telnet|tftp|thismessage|tn3270|tip|tv|urn|vemmi|ws|wss|xcon|xcon-userid|xmlrpc.beep|xmlrpc.beeps|xmpp|z39.50r|z39.50s|adiumxtra|afp|afs|aim|apt|attachment|aw|beshare|bitcoin|bolo|callto|chrome|chrome-extension|com-eventbrite-attendee|content|cvs|dlna-playsingle|dlna-playcontainer|dtn|dvb|ed2k|facetime|feed|finger|fish|gg|git|gizmoproject|gtalk|hcp|icon|ipn|irc|irc6|ircs|itms|jar|jms|keyparc|lastfm|ldaps|magnet|maps|market|message|mms|ms-help|msnim|mumble|mvn|notes|oid|palm|paparazzi|platform|proxy|psyc|query|res|resource|rmi|rsync|rtmp|secondlife|sftp|sgn|skype|smb|soldat|spotify|ssh|steam|svn|teamspeak|things|udp|unreal|ut2004|ventrilo|view-source|webcal|wtai|wyciwyg|xfire|xri|ymsgr):[^<>\x00-\x20]*>/i; @@ -648,50 +679,58 @@ class InlineParser if ( (m = this.match(erMail)) != null ) { // email autolink - //dest = m.substr(1,-1); dest = m.substr(1, m.length - 2); inlines.push( { t: 'Link', label: [{ t: 'Str', c: dest }], - destination: 'mailto:' + dest + destination: 'mailto:' + fixEncode(unescape(dest).urlEncode()) }); - return m.length; + return true; } else if ( (m = this.match(erLink)) != null ) { - //dest = m.substr(1, -1); dest = m.substr(1, m.length - 2); - inlines.push( { + + inlines.push({ t: 'Link', label: [{ t: 'Str', c: dest }], - destination: dest + destination: fixEncode(unescape(dest).urlEncode()) }); - return m.length; + return true; } else - return 0; + return false; } // Attempt to parse a raw HTML tag. - function parseHtmlTag(inlines : Array ) : Int + function parseHtmlTag(inlines : Array ) : Bool { var m = this.match(reHtmlTag); if ( m != null ) { inlines.push({ t: 'Html', c: m }); - return m.length; + return true; } else - return 0; + return false; } // Replace backslash escapes with literal characters. - function unescape( s : String ) : String return DocParser.reAllEscapedChar.replace(s, '$1'); + function unescape( s : String ) : String + { + return s.replace('%20', ' '); // reAllEscapedChar.replace(s, '$1'); + } + + // Replace entities and backslash escapes with literal characters. + inline public static function unescapeString( s : String ) : String + { + return reEntity.map(reAllEscapedChar.replace(s, '$1'), EntityToChar.entityToCharEr); + } // Returns the character at the current subject position, or null if // there are no more characters. - function peek( ) return pos == subject.length ? null : subject.charAt(pos); // ] || null; + function peek( ) : Int return pos == subject.length ? -1 : subject.charCodeAt(pos); // ] || null; // Parse zero or more space characters, including at most one newline function spnl( ) : Bool @@ -720,13 +759,14 @@ class InlineParser // the number of delimiters and whether they are positioned such that // they can open and/or close emphasis or strong emphasis. A utility // function for strong/emph parsing. - function scanDelims( c ) + function scanDelims( c : Int ) { - var numdelims = 0; - var first_close_delims = 0; - var char_before; - var char_after; - var startpos = this.pos; + var numdelims : Int = 0; + var first_close_delims : Int = 0; + var char_before : String; + var char_after : String; + var c_after : Int; + var startpos : Int = this.pos; char_before = this.pos == 0 ? '\n' : this.subject.charAt(this.pos - 1); @@ -736,13 +776,13 @@ class InlineParser this.pos++; } - char_after = this.peek(); - if( char_after == null ) char_after = '\n'; + c_after = this.peek(); + char_after = c_after == -1 ? '\n' : EntityToChar.fromCodePoint([c_after]); var can_open = numdelims > 0 && numdelims <= 3 && !(~/\s/.match(char_after)); var can_close = numdelims > 0 && numdelims <= 3 && !(~/\s/.match(char_before)); - if ( c == '_' ) + if ( c == C_UNDERSCORE ) { can_open = can_open && !((~/[a-z0-9]/i).match(char_before)); can_close = can_close && !((~/[a-z0-9]/i).match(char_after)); @@ -755,4 +795,51 @@ class InlineParser can_close: can_close }; } + + inline public function fixEncode( s : String ) : String return s + .replace('%2F', '/') + .replace('%28', '(') + .replace('%29', ')') + .replace('%2A', '*') + .replace('%3A', ':') + .replace('%3F', '?') + .replace('%3D', '=') + .replace('%26', '&') + .replace('%40', '@') + .replace('%2B', '+') + ; + + + inline public static function makeEmph( ils : Array ) : InlineElement return { t: 'Emph', childs: ils }; + inline public static function makeStrong( ils : Array ) : InlineElement return { t: 'Strong', childs: ils }; + inline public static function makeStr( s : String ) : InlineElement return { t: 'Str', c: s }; + +/* + subject: '', + label_nest_level: 0, // used by parseLinkLabel method + pos: 0, + refmap: {}, + + match: match, + peek: peek, + spnl: spnl, + + parseBackticks: parseBackticks, + parseEscaped: parseEscaped, + parseAutolink: parseAutolink, + parseHtmlTag: parseHtmlTag, + scanDelims: scanDelims, + parseEmphasis: parseEmphasis, + parseLinkTitle: parseLinkTitle, + parseLinkDestination: parseLinkDestination, + parseLinkLabel: parseLinkLabel, + parseLink: parseLink, + parseEntity: parseEntity, + parseString: parseString, + parseNewline: parseNewline, + parseImage: parseImage, + parseReference: parseReference, + parseInline: parseInline, + parse: parseInlines +*/ } \ No newline at end of file diff --git a/src/comark/Markdown.hx b/src/comark/Markdown.hx index c7c5541..116665c 100644 --- a/src/comark/Markdown.hx +++ b/src/comark/Markdown.hx @@ -4,12 +4,11 @@ */ package comark; - class Markdown { var render : HtmlRenderer; var parser : DocParser; - + public function new( ) { render = new HtmlRenderer(); diff --git a/test/Main.hx b/test/Main.hx index 04dea14..15e51c0 100644 --- a/test/Main.hx +++ b/test/Main.hx @@ -20,6 +20,8 @@ class Main { var r : TestRunner; var files : Array; + var spec : String; + var specG : String; public function new( ) { @@ -32,13 +34,24 @@ class Main files = []; #if neko - var spec = File.getContent('tests/spec.txt'); + spec = File.getContent('tests/spec.txt'); + specG = File.getContent('tests/github.txt'); #elseif js LoadResources.loadFile('spec.txt', 'bin/tests/spec.txt'); - var spec = Resource.getString('spec.txt'); + LoadResources.loadFile('github.txt', 'bin/tests/github.txt'); + + spec = Resource.getString('spec.txt'); + specG = Resource.getString('github.txt'); #else #error #end + process(spec); + process(spec, true); + process(specG, true, false); + } + + function process( spec : String, github : Bool = false, skipUtf8 : Bool = true ) + { var lines = spec.split('\n'); var eStart : EReg = ~/^\.$/; @@ -53,6 +66,7 @@ class Main var markdown = ''; var html = ''; + //var secLevel = 0; var sec var header = ''; for ( l in lines ) @@ -69,15 +83,26 @@ class Main else if ( stage == 0 ) { example++; -#if neko - if ( example == 2 ) { } // UTF german - else if ( example == 110 ) { } // UTF greek - else if ( example == 349 ) { } // UTF russian - else -#end - if ( example == 25 ) { } // Github Flavour #hashtag + + var md = ~/␣/g.replace(~/→/g.replace(markdown, '\t'), ' '); + files.push(md); + + if ( false ) { } + else if ( skipUtf8 && example == 2 ) { } // UTF german + else if ( skipUtf8 && example == 120 ) { } // UTF greek + else if ( skipUtf8 && example == 234 ) { } // UTF magic - Decimal entities + else if ( skipUtf8 && example == 235 ) { } // UTF magic - Hexadecimal entities + else if ( skipUtf8 && example == 377 ) { } // UTF russian + + else if ( github && example == 25 ) { } // Github Flavour #hashtag + else - r.add(new StringTest(new GithubMarkdown(), ~/␣/g.replace(~/→/g.replace(markdown, '\t'), ' '), html, header, example, exampleLine)); + { + if ( github ) + r.add(new StringTest(new GithubMarkdown(1, true), md, html, header, example, exampleLine)); + else + r.add(new StringTest(new Markdown(), md, html, header, example, exampleLine)); + } markdown = ''; html = ''; @@ -94,8 +119,44 @@ class Main } } + + public function run( ) : Void + { +#if debug + r.run(); +#else + bench(); +#end + } + +#if !debug + function bench( ) : Void + { + var start1 = t(); + for( i in 0...5 ) + for ( f in files ) var out = new comark.Markdown().parse(f); + var end1 = t(); + + var start2 = t(); + for( i in 0...5 ) + for ( f in files ) var out = new mdcebe.Markdown().parse(f); + var end2 = t(); + + var start3 = t(); + for( i in 0...5 ) + for ( f in files ) var out = markdown.Markdown.markdownToHtml(f); + var end3 = t(); + + trace([end1 - start1, end2 - start2, end3 - start3]); + } +#end - public function run( ) : Void r.run(); + inline static function t( ) return +#if neko + Sys.time(); +#elseif js + Date.now().getTime(); +#end static function main() new Main().run(); } diff --git a/test/StringTest.hx b/test/StringTest.hx index a015c7e..9ddb58d 100644 --- a/test/StringTest.hx +++ b/test/StringTest.hx @@ -3,13 +3,17 @@ * @author ... */ +package ; + import comark.Markdown; + class StringTest extends haxe.unit.TestCase { public static var PATH = ''; var md : Markdown; + //var name : String; var src : String; var res : String; @@ -21,6 +25,7 @@ class StringTest extends haxe.unit.TestCase public function new( md : Markdown, src : String, res : String, header : String, num : Int, line : Int ) { this.md = md; + //this.name = name; super(); @@ -33,6 +38,7 @@ class StringTest extends haxe.unit.TestCase } public function testCoversion( ) : Void assertEquals(res, md.parse(src)); + //public function testCoversion( ) : Void assertEquals(src, md.parse(src)); override public function setup( ) : Void {