From 00a4ca6021235ccc3208f1c57f864b366b80c265 Mon Sep 17 00:00:00 2001 From: Bernhard Berger Date: Fri, 8 Feb 2013 08:57:09 +0100 Subject: [PATCH] Initial commit of a PegDown Scala version. --- CHANGELOG | 130 +- NOTICE | 5 - README.markdown | 91 +- build.sbt | 70 +- pegdown.iml | 95 -- project/build.properties | 2 +- project/plugins.sbt | 1 - src/main/java/org/pegdown/Extensions.java | 118 -- src/main/java/org/pegdown/FastEncoder.java | 84 -- src/main/java/org/pegdown/LinkRenderer.java | 81 - src/main/java/org/pegdown/Parser.java | 1341 ----------------- .../org/pegdown/ParsingTimeoutException.java | 3 - .../java/org/pegdown/PegDownProcessor.java | 153 -- src/main/java/org/pegdown/Printer.java | 70 - .../java/org/pegdown/ToHtmlSerializer.java | 450 ------ .../org/pegdown/ast/AbbreviationNode.java | 41 - .../java/org/pegdown/ast/AbstractNode.java | 37 - .../java/org/pegdown/ast/AutoLinkNode.java | 31 - .../java/org/pegdown/ast/BlockQuoteNode.java | 33 - .../java/org/pegdown/ast/BulletListNode.java | 31 - src/main/java/org/pegdown/ast/CodeNode.java | 31 - .../org/pegdown/ast/DefinitionListNode.java | 27 - .../java/org/pegdown/ast/DefinitionNode.java | 31 - .../org/pegdown/ast/DefinitionTermNode.java | 27 - src/main/java/org/pegdown/ast/EmphNode.java | 33 - .../java/org/pegdown/ast/ExpImageNode.java | 35 - .../java/org/pegdown/ast/ExpLinkNode.java | 35 - src/main/java/org/pegdown/ast/HeaderNode.java | 44 - .../java/org/pegdown/ast/HtmlBlockNode.java | 31 - .../java/org/pegdown/ast/InlineHtmlNode.java | 31 - .../java/org/pegdown/ast/ListItemNode.java | 31 - .../java/org/pegdown/ast/MailLinkNode.java | 31 - src/main/java/org/pegdown/ast/Node.java | 36 - .../java/org/pegdown/ast/OrderedListNode.java | 31 - src/main/java/org/pegdown/ast/ParaNode.java | 37 - src/main/java/org/pegdown/ast/QuotedNode.java | 38 - .../java/org/pegdown/ast/RefImageNode.java | 35 - .../java/org/pegdown/ast/RefLinkNode.java | 35 - .../java/org/pegdown/ast/ReferenceNode.java | 51 - src/main/java/org/pegdown/ast/RootNode.java | 53 - src/main/java/org/pegdown/ast/SimpleNode.java | 50 - .../java/org/pegdown/ast/SpecialTextNode.java | 31 - src/main/java/org/pegdown/ast/StrongNode.java | 33 - src/main/java/org/pegdown/ast/SuperNode.java | 46 - .../java/org/pegdown/ast/TableBodyNode.java | 27 - .../org/pegdown/ast/TableCaptionNode.java | 27 - .../java/org/pegdown/ast/TableCellNode.java | 37 - .../java/org/pegdown/ast/TableColumnNode.java | 44 - .../java/org/pegdown/ast/TableHeaderNode.java | 27 - src/main/java/org/pegdown/ast/TableNode.java | 45 - .../java/org/pegdown/ast/TableRowNode.java | 27 - src/main/java/org/pegdown/ast/TextNode.java | 53 - .../java/org/pegdown/ast/VerbatimNode.java | 42 - src/main/java/org/pegdown/ast/Visitor.java | 61 - .../java/org/pegdown/ast/WikiLinkNode.java | 31 - .../scala/org/pegdown/AbbrevationHtml.scala | 85 ++ src/main/scala/org/pegdown/FastEncoder.scala | 51 + src/main/scala/org/pegdown/LinkRenderer.scala | 56 + src/main/scala/org/pegdown/Main.scala | 42 + .../scala/org/pegdown/MarkdownParser.scala | 712 +++++++++ .../pegdown/MarkdownParserConfiguration.scala | 120 ++ src/main/scala/org/pegdown/Node.scala | 94 ++ .../scala/org/pegdown/ToHtmlSerializer.scala | 218 +++ src/test/java/org/pegdown/Benchmark.java | 88 -- .../java/org/pegdown/ShowParserStats.java | 45 - .../org/pegdown/AbbrevationHtmlSpec.scala | 48 + .../org/pegdown/AbstractPegDownSpec.scala | 47 +- .../scala/org/pegdown/Markdown103Spec.scala | 19 +- src/test/scala/org/pegdown/MarukuSpec.scala | 43 +- .../org/pegdown/PathologicalInputSpec.scala | 51 +- src/test/scala/org/pegdown/PegDownSpec.scala | 36 +- .../scala/org/pegdown/PhpMarkdownSpec.scala | 29 +- 72 files changed, 1578 insertions(+), 4357 deletions(-) delete mode 100644 NOTICE delete mode 100644 pegdown.iml delete mode 100644 project/plugins.sbt delete mode 100644 src/main/java/org/pegdown/Extensions.java delete mode 100644 src/main/java/org/pegdown/FastEncoder.java delete mode 100644 src/main/java/org/pegdown/LinkRenderer.java delete mode 100644 src/main/java/org/pegdown/Parser.java delete mode 100644 src/main/java/org/pegdown/ParsingTimeoutException.java delete mode 100644 src/main/java/org/pegdown/PegDownProcessor.java delete mode 100644 src/main/java/org/pegdown/Printer.java delete mode 100644 src/main/java/org/pegdown/ToHtmlSerializer.java delete mode 100644 src/main/java/org/pegdown/ast/AbbreviationNode.java delete mode 100644 src/main/java/org/pegdown/ast/AbstractNode.java delete mode 100644 src/main/java/org/pegdown/ast/AutoLinkNode.java delete mode 100644 src/main/java/org/pegdown/ast/BlockQuoteNode.java delete mode 100644 src/main/java/org/pegdown/ast/BulletListNode.java delete mode 100644 src/main/java/org/pegdown/ast/CodeNode.java delete mode 100644 src/main/java/org/pegdown/ast/DefinitionListNode.java delete mode 100644 src/main/java/org/pegdown/ast/DefinitionNode.java delete mode 100644 src/main/java/org/pegdown/ast/DefinitionTermNode.java delete mode 100644 src/main/java/org/pegdown/ast/EmphNode.java delete mode 100644 src/main/java/org/pegdown/ast/ExpImageNode.java delete mode 100644 src/main/java/org/pegdown/ast/ExpLinkNode.java delete mode 100644 src/main/java/org/pegdown/ast/HeaderNode.java delete mode 100644 src/main/java/org/pegdown/ast/HtmlBlockNode.java delete mode 100644 src/main/java/org/pegdown/ast/InlineHtmlNode.java delete mode 100644 src/main/java/org/pegdown/ast/ListItemNode.java delete mode 100644 src/main/java/org/pegdown/ast/MailLinkNode.java delete mode 100644 src/main/java/org/pegdown/ast/Node.java delete mode 100644 src/main/java/org/pegdown/ast/OrderedListNode.java delete mode 100644 src/main/java/org/pegdown/ast/ParaNode.java delete mode 100644 src/main/java/org/pegdown/ast/QuotedNode.java delete mode 100644 src/main/java/org/pegdown/ast/RefImageNode.java delete mode 100644 src/main/java/org/pegdown/ast/RefLinkNode.java delete mode 100644 src/main/java/org/pegdown/ast/ReferenceNode.java delete mode 100644 src/main/java/org/pegdown/ast/RootNode.java delete mode 100644 src/main/java/org/pegdown/ast/SimpleNode.java delete mode 100644 src/main/java/org/pegdown/ast/SpecialTextNode.java delete mode 100644 src/main/java/org/pegdown/ast/StrongNode.java delete mode 100644 src/main/java/org/pegdown/ast/SuperNode.java delete mode 100644 src/main/java/org/pegdown/ast/TableBodyNode.java delete mode 100644 src/main/java/org/pegdown/ast/TableCaptionNode.java delete mode 100644 src/main/java/org/pegdown/ast/TableCellNode.java delete mode 100644 src/main/java/org/pegdown/ast/TableColumnNode.java delete mode 100644 src/main/java/org/pegdown/ast/TableHeaderNode.java delete mode 100644 src/main/java/org/pegdown/ast/TableNode.java delete mode 100644 src/main/java/org/pegdown/ast/TableRowNode.java delete mode 100644 src/main/java/org/pegdown/ast/TextNode.java delete mode 100644 src/main/java/org/pegdown/ast/VerbatimNode.java delete mode 100644 src/main/java/org/pegdown/ast/Visitor.java delete mode 100644 src/main/java/org/pegdown/ast/WikiLinkNode.java create mode 100644 src/main/scala/org/pegdown/AbbrevationHtml.scala create mode 100644 src/main/scala/org/pegdown/FastEncoder.scala create mode 100644 src/main/scala/org/pegdown/LinkRenderer.scala create mode 100644 src/main/scala/org/pegdown/Main.scala create mode 100644 src/main/scala/org/pegdown/MarkdownParser.scala create mode 100644 src/main/scala/org/pegdown/MarkdownParserConfiguration.scala create mode 100644 src/main/scala/org/pegdown/Node.scala create mode 100644 src/main/scala/org/pegdown/ToHtmlSerializer.scala delete mode 100644 src/test/java/org/pegdown/Benchmark.java delete mode 100644 src/test/java/org/pegdown/ShowParserStats.java create mode 100644 src/test/scala/org/pegdown/AbbrevationHtmlSpec.scala diff --git a/CHANGELOG b/CHANGELOG index d2d4957..0efd328 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,130 +1,4 @@ -Version 1.2.1 (2011-11-27) --------------------------- -- Upgraded to parboiled 1.1.4 -- Added support for caption on tables (thx to Geoffrey Picron) - - -Version 1.2.0 (2011-10-05) --------------------------- -- Upgraded to parboiled 1.1.3 -- Implemented parsing timeout, closes #42 -- Fixed IndexOutOfBoundsException in ToHtmlSerializer, closes #39 -- Changed parser to not swallow backslash before non-special characters, fixes #35 -- Added test for fenced code blocks containing an empty line, closes #61 -- Migrated all tests from TestNG to specs2 -- Switched build tool from Apache Buildr to SBT - - -Version 1.1.0 (2011-10-05) --------------------------- -- Upgraded to parboiled 1.0.2 -- Introduced LinkRenderer layer for easy customization of HTML link rendering -- Added support for [[Wiki-style]] links, thx to Brett Porter -- Fixed #27 (Missing emphasis when paragraph has multiple lines) -- Fixed #28 (Parser not fully extensible) -- Fixed #32, #33 (HTML tags with attribute names containing underscores are not recognized as tags, thx to Edward Samson) -- Fixed #34 (Pathologically slow parsing when strong and italics emphasis are applied together) - - -Version 1.0.2 (2011-07-05) --------------------------- -- Simplify custom extensions by making `private` fields/methods of ToHtmlSerializer and Parser `protected` -- Fixed #20 (support GFM fenced code blocks) -- Fixed #21 (simplify integration of custom code transformers) -- Fixed #22 (some characters/sequences break links when AutoLinks extensions is on) -- Fixed broken Java 1.5 compatibility (thx to Julien Nicoulaud) -- Fixed maven build: add testng and jtidy deps for tests, and configure the compiler plugin for java 5 (thx to Lukas Theussl) - - -Version 1.0.1 (2011-05-17) --------------------------- -- Fixed #18 (code blocks in list items split by lines) - - -Version 1.0.0 (2011-05-13) --------------------------- -- Closed #3 (PhpMarkdownExtra-style definition lists) -- closed #14 (superfluous paragraph breaks) -- Closed #15 (email obfuscation) -- Closed #16 (PhpMarkdownExtra-style fenced code blocks) -- Closed #17 ('nofollow' links) -- Added buffer indices to AST nodes, enabling markdown syntax highlighting -- Removed tabstop expansion (prevented proper AST node index building) -- Improved single quoting rules for Smartypants extension -- Completely refactored list parsing for code size, performance and simplicity -- Fixed small problem with AutoLink delimiters -- Upgraded to parboiled 1.0.0 - - -Version 0.9.2 (2011-04-06) --------------------------- -- Fix: special characters not encoded correctly in plain text sections -- Fix: HTML hex entities incorrectly parsed -- Add indices into underlying buffer to AST nodes -- Upgraded to parboiled 0.11.1 - - -Version 0.9.1 (2011-03-21) --------------------------- -- Upgraded to parboiled 0.11.0 - - -Version 0.9.0 (2011-02-11) --------------------------- -- Completely overhauled and cleaned up general architecture, split out HTML serialization into AST visitor (thanks to Ravindar Reddy) -- Fixed bug causing the disappearance of text elements in certain list constructs -- Fixed excessive backtracking bug on parsing larger blocks of 'opening-tags-only' HTML -- Fixed file name casing problem causing certain tests to fail on case-sensitive file systems -- Implemented various smaller performance improvements resulting in a general speed-up by 10-30% -- Opened up PegDownProcessor and Parser to custom extensions -- Switched from Ant to Buildr, changed to maven-style project layout -- Changed to 3 part version numbering in preparation of the coming semantic versioning compatibility (http://semver.org) -- Upgraded to parboiled 0.10.1 - - -Version 0.8.5.4 (2010-10-04) +Version 0.1.0.1 (2013-02-06) ---------------------------- -- Switched off superfluous parse tree building resulting in nearly doubled parsing performance -- Upgraded to parboiled 0.9.9.0 - -Version 0.8.5.3 (2010-08-13) ----------------------------- -- Added HTML suppression options -- Upgraded to parboiled 0.9.8.2 (another ~ 5% performance increase by using a few @MemoMismatches annotations) - - -Version 0.8.5.2 (2010-08-12) ----------------------------- -- Upgraded to parboiled 0.9.8.1 (~ 10% performance increase, slightly simplified parser) - - -Version 0.8.5.1 (2010-06-19) ----------------------------- -- Fixed several problems, especially with regard to image links (thanks to Nick Ewing for the report) -- Added support for double angle quotes to the QUOTES extension -- Further increased test coverage - - -Version 0.8.5.0 (2010-06-14) ----------------------------- -- Completely rewrote AST implementation improving maintainability and simplifying further extensions -- Fixed different problems, mainly related to the ABBREVIATIONS extension -- Added TABLES extension -- Added simple benchmarking "test" - - -Version 0.8.1.0 (2010-06-08) ----------------------------- -- Fixed problem with SetextHeading2 -- Fixed performance problem in inputs with complex emphasis constructs -- Added ABBREVIATIONS extension -- Added HARDWRAPS extension -- Added AUTOLINKS extension -- Added support for parens in link urls (must be escaped in explicit links) -- Expanded test coverage - - -Version 0.8.0.1 (2010-04-30) ----------------------------- -first public release \ No newline at end of file +* first public release diff --git a/NOTICE b/NOTICE deleted file mode 100644 index 9a4d456..0000000 --- a/NOTICE +++ /dev/null @@ -1,5 +0,0 @@ -pegdown -Copyright (C) 2010-2011 Mathias Doenitz - -Based on peg-markdown - markdown in c, implemented using PEG grammar -Copyright (c) 2008 John MacFarlane (http://github.com/jgm/peg-markdown) diff --git a/README.markdown b/README.markdown index 73a6ea6..2121800 100644 --- a/README.markdown +++ b/README.markdown @@ -1,11 +1,11 @@ Introduction ------------ -_pegdown_ is a pure Java library for clean and lightweight [Markdown] processing based on a [parboiled] PEG parser. +_pegdownScala_ is a pure Scala library for clean and lightweight [Markdown] processing based on a [parboiled] PEG parser. -_pegdown_ is nearly 100% compatible with the original Markdown specification and fully passes the original Markdown test suite. -On top of the standard Markdown feature set _pegdown_ implements a number of extensions similar to what other popular Markdown processors offer. -Currently _pegdown_ supports the following extensions over standard Markdown: +_pegdownScala_ is nearly 100% compatible with the original Markdown specification and fully passes the original Markdown test suite. +On top of the standard Markdown feature set _pegdownScala_ implements a number of extensions similar to what other popular Markdown processors offer. +Currently _pegdownScala_ supports the following extensions over standard Markdown: * SMARTS: Beautifies apostrophes, ellipses ("..." and ". . .") and dashes ("--" and "---") * QUOTES: Beautifies single quotes, double quotes and double angle quotes (« and ») @@ -20,100 +20,69 @@ Currently _pegdown_ supports the following extensions over standard Markdown: * INLINE HTML SUPPRESSION: Suppresses the output of inline HTML elements. * WIKILINKS: Support `[[Wiki-style links]]` with a customizable URL rendering logic. -Note: _pegdown_ differs from the original Markdown in that it ignores in-word emphasis as in +Note: _pegdownScala_ differs from the original Markdown in that it ignores in-word emphasis as in > my_cool_file.txt > 2*3*4=5 Currently this "extension" cannot be switched off. +Differences to pegdown +---------------------- -Installation ------------- +_pegdownScala_ is a port of the great [PegDown] Java library from Mathias Doenitz. +There are some differences to the Java Version. + +Pros: -You have two options: +* The parser is implemented as immutable class and thread safe. +* Should run on the Google AppEngine. +* More compact Scala code (30% of the Java code lines). +* No time expensive parser extension step. -* Download the JAR for the latest version from the [download page]. - _pegdown_ 1.2.0 has only one dependency: [parboiled for Java][parboiled], version 1.1.3. - -* The pegdown artifact is also available from maven central with group id **org.pegdown** and artifact-id **pegdown**. +Cons: +* pegdownScala is a beta version: interlaced HTML tags doesn't work correct, + PegDown is much better tested. +* No implementation for timeouts in pegdownScala. You may want to use Akka to handle long tasks. +* pegdownScala isn't optimized for performance. Usage ----- -Using _pegdown_ is very simple: Just create a new instance of a [PegDownProcessor] and call one of its -`markdownToHtml` methods to convert the given Markdown source to an HTML string. If you'd like to customize the -rendering of HTML links (Auto-Links, Explicit-Links, Mail-Links, Reference-Links and/or Wiki-Links), e.g. for adding -`rel="nofollow"` attributes based on some logic you can supply your own instance of a [LinkRenderer] with the call -to `markdownToHtml`. - -You can also use pegdown only for the actual parsing of the Markdown source and do the serialization to the -target format (e.g. XML) yourself. To do this just call the `parseMarkdown` method of the [PegDownProcessor] to obtain -the root node of the Astract Syntax Tree for the document. -With a custom [Visitor] implementation you can do whatever serialization you want. As an example you might want to -take a look at the [sources of the ToHtmlSerializer][ToHtmlSerializer]. - -Note that the first time you create a [PegDownProcessor] it can take up to a few hundred milliseconds to prepare the -underlying parboiled parser instance. However, once the first processor has been built all further instantiations will -be fast. Also, you can reuse an existing [PegDownProcessor] instance as often as you want, as long as you prevent -concurrent accesses, since neither the [PegDownProcessor] nor the underlying parser is thread-safe. - -See for the pegdown API documentation. - - -Parsing Timeouts ----------------- - -Since Markdown has no official grammar and contains a number of ambiguities the parsing of Markdown source, especially -with enabled language extensions, can be "hard" and result, in certain corner cases, in exponential parsing time. -In order to provide a somewhat predictable behavior *pegdown* therefore supports the specification of a parsing timeout, -which you can supply to the [PegDownProcessor] constructor. +Using _pegdownScala_ is very simple: Just call `ToHtmlSeralizer(markdownSource)`. -If the parser happens to run longer than the specified timeout period it terminates itself with an exception, which -causes the `markdownToHtml` method to return `null`. Your application should then deal with this case accordingly and, -for example, inform the user. +TODO: Add more documentation. -The default timeout, if not explicitly specified, is 2 seconds. - - -IDE Support ------------ - -The excellent [idea-markdown plugin] for IntelliJ IDEA, RubyMine, PhpStorm, WebStorm, PyCharm and appCode uses _pegdown_ -as its underlying parsing engine. The plugin gives you proper syntax-highlighting for markdown source and shows you -exactly, how _pegdown_ will parse your texts. +You can also use _pegdownScala_ from the command line to convert a Markdown file to HTML: +`pegdownScala ` Credits ------- +All the code is based on [PegDown] from Mathias Doenitz. I would never be able to build this +Scala port without your great work. + A large part of the underlying PEG grammar was developed by John MacFarlane and made available with his tool [peg-markdown](http://github.com/jgm/peg-markdown). - License ------- -_pegdown_ is licensed under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0). - - -Patch Policy ------------- +_pegdownScala_ is licensed under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0). -Feedback and contributions to the project, no matter what kind, are always very welcome. -However, patches can only be accepted from their original author. -Along with any patches, please state that the patch is your original work and that you license the work to the pegdown project under the project’s open source license. [Markdown]: http://daringfireball.net/projects/markdown/ "Main Markdown site" [parboiled]: http://www.parboiled.org [Github-flavoured-Markdown]: http://github.github.com/github-flavored-markdown/ [MultiMarkdown]: http://fletcherpenney.net/multimarkdown/users_guide/multimarkdown_syntax_guide/ [Download Page]: http://github.com/sirthias/pegdown/downloads + [PegDown]: https://github.com/sirthias/pegdown [PegDownProcessor]: http://www.decodified.com/pegdown/api/org/pegdown/PegDownProcessor.html [LinkRenderer]: http://www.decodified.com/pegdown/api/org/pegdown/LinkRenderer.html [Visitor]: http://www.decodified.com/pegdown/api/org/pegdown/ast/Visitor.html [ToHtmlSerializer]: https://github.com/sirthias/pegdown/blob/master/src/main/java/org/pegdown/ToHtmlSerializer.java [idea-markdown plugin]: https://github.com/nicoulaj/idea-markdown [SBT]: http://www.scala-sbt.org/ - [Node]: http://www.decodified.com/pegdown/api/org/pegdown/ast/Node.html \ No newline at end of file + [Node]: http://www.decodified.com/pegdown/api/org/pegdown/ast/Node.html diff --git a/build.sbt b/build.sbt index 3e57f85..646c332 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,8 @@ -name := "pegdown" +name := "pegdownScala" -version := "1.2.1" +version := "0.1" + +scalaVersion := "2.10.0" homepage := Some(new URL("http://pegdown.org")) @@ -8,68 +10,16 @@ organization := "org.pegdown" organizationHomepage := Some(new URL("http://pegdown.org")) -description := "A Java 1.5+ library providing a clean and lightweight markdown processor" +description := "A Scala library providing a clean and lightweight markdown processor" -startYear := Some(2009) +startYear := Some(2013) licenses := Seq("Apache 2" -> new URL("http://www.apache.org/licenses/LICENSE-2.0.txt")) -javacOptions ++= Seq( - "-g", // required for byte-code rewriting in parboiled-java! - "-deprecation", - "-target", "1.5", - "-source", "1.5", - "-encoding", "utf8", - "-Xlint:unchecked" -) - -javacOptions in doc := Seq( - "-source", "1.5", - "-encoding", "utf8" -) - -scalaVersion := "2.9.2" - -scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8") - -libraryDependencies ++= Seq( - "org.parboiled" % "parboiled-java" % "1.1.4", +libraryDependencies ++= Seq( + "org.parboiled" % "parboiled-scala_2.10" % "1.1.4", "net.sf.jtidy" % "jtidy" % "r938" % "test", - "org.specs2" %% "specs2" % "1.12.2" % "test" + "org.specs2" %% "specs2" % "1.13" % "test", + "com.novocode" % "junit-interface" % "0.10-M2" % "test" ) -resolvers += Opts.resolver.sonatypeReleases - -// publishing - -crossPaths := false - -autoScalaLibrary := false - -publishMavenStyle := true - -publishArtifact in Test := false - -pomIncludeRepository := { _ => false } - -useGpg := true - -pgpSigningKey := Some(-2321133875171851978L) - -publishTo <<= version { v: String => - val nexus = "https://oss.sonatype.org/" - if (v.trim.endsWith("SNAPSHOT")) Some("snapshots" at nexus + "content/repositories/snapshots") - else Some("releases" at nexus + "service/local/staging/deploy/maven2") -} - -pomExtra := - - git@github.com:sirthias/pegdown.git - scm:git:git@github.com:sirthias/pegdown.git - - - - sirthias - Mathias Doenitz - - \ No newline at end of file diff --git a/pegdown.iml b/pegdown.iml deleted file mode 100644 index bf3fa44..0000000 --- a/pegdown.iml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/project/build.properties b/project/build.properties index 21e2c5d..4474a03 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.12.2 \ No newline at end of file +sbt.version=0.12.1 diff --git a/project/plugins.sbt b/project/plugins.sbt deleted file mode 100644 index e9b58f7..0000000 --- a/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.7") \ No newline at end of file diff --git a/src/main/java/org/pegdown/Extensions.java b/src/main/java/org/pegdown/Extensions.java deleted file mode 100644 index 27ee5b0..0000000 --- a/src/main/java/org/pegdown/Extensions.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown; - -public interface Extensions { - - /** - * The default, standard markup mode without any extensions. - */ - static final int NONE = 0x00; - - /** - * Pretty ellipses, dashes and apostrophes. - */ - static final int SMARTS = 0x01; - - /** - * Pretty single and double quotes. - */ - static final int QUOTES = 0x02; - - /** - * All of the smartypants prettyfications. Equivalent to SMARTS + QUOTES. - * - * @see Smartypants - */ - static final int SMARTYPANTS = SMARTS + QUOTES; - - /** - * PHP Markdown Extra style abbreviations. - * - * @see PHP Markdown Extra - */ - static final int ABBREVIATIONS = 0x04; - - /** - * Enables the parsing of hard wraps as HTML linebreaks. Similar to what github does. - * - * @see Github-flavored-Markdown - */ - static final int HARDWRAPS = 0x08; - - /** - * Enables plain autolinks the way github flavoured markdown implements them. - * With this extension enabled pegdown will intelligently recognize URLs and email addresses - * without any further delimiters and mark them as the respective link type. - * - * @see Github-flavored-Markdown - */ - static final int AUTOLINKS = 0x10; - - /** - * Table support similar to what Multimarkdown offers. - * - * @see MultiMarkdown - */ - static final int TABLES = 0x20; - - /** - * PHP Markdown Extra style definition lists. - * Additionally supports the small extension proposed in the article referenced below. - * - * @see PHP Markdown Extra - * @see Extension proposal - */ - static final int DEFINITIONS = 0x40; - - /** - * PHP Markdown Extra style fenced code blocks. - * - * @see PHP Markdown Extra - */ - static final int FENCED_CODE_BLOCKS = 0x80; - - /** - * Support [[Wiki-style links]]. URL rendering is performed by the active {@link LinkRenderer}. - * - * @see Github-flavored-Markdown - */ - static final int WIKILINKS = 0x100; - - /** - * All available extensions excluding the SUPPRESS_... options. - */ - static final int ALL = 0x0000FFFF; - - /** - * Suppresses HTML blocks. They will be accepted in the input but not be contained in the output. - */ - static final int SUPPRESS_HTML_BLOCKS = 0x00010000; - - /** - * Suppresses inline HTML tags. They will be accepted in the input but not be contained in the output. - */ - static final int SUPPRESS_INLINE_HTML = 0x00020000; - - /** - * Suppresses HTML blocks as well as inline HTML tags. - * Both will be accepted in the input but not be contained in the output. - */ - static final int SUPPRESS_ALL_HTML = 0x00030000; -} diff --git a/src/main/java/org/pegdown/FastEncoder.java b/src/main/java/org/pegdown/FastEncoder.java deleted file mode 100644 index 88cbb7b..0000000 --- a/src/main/java/org/pegdown/FastEncoder.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.pegdown; - -import org.parboiled.common.StringUtils; - -import java.util.Random; - -/** - * Static class holding simple HTML encoding logic. - */ -public class FastEncoder { - - private FastEncoder() {} - - public static String encode(String string) { - if (StringUtils.isNotEmpty(string)) { - for (int i = 0; i < string.length(); i++) { - if (encode(string.charAt(i)) != null) { - // we have at least one character that needs encoding, so do it one by one - StringBuilder sb = new StringBuilder(); - for (i = 0; i < string.length(); i++) { - char c = string.charAt(i); - String encoded = encode(c); - if (encoded != null) sb.append(encoded); - else sb.append(c); - } - return sb.toString(); - } - } - return string; - } else return ""; - } - - public static void encode(String string, StringBuilder sb) { - if (StringUtils.isNotEmpty(string)) { - for (int i = 0; i < string.length(); i++) { - if (encode(string.charAt(i)) != null) { - // we have at least one character that needs encoding, so do it one by one - for (i = 0; i < string.length(); i++) { - char c = string.charAt(i); - String encoded = encode(c); - if (encoded != null) sb.append(encoded); - else sb.append(c); - } - return; - } - } - sb.append(string); - } - } - - public static String encode(char c) { - switch (c) { - case '&': return "&"; - case '<': return "<"; - case '>': return ">"; - case '"': return """; - case '\'': return "'"; - } - return null; - } - - private static Random random = new Random(0x2626); - - public static String obfuscate(String email) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < email.length(); i++) { - char c = email.charAt(i); - switch (random.nextInt(5)) { - case 0: - case 1: - sb.append("&#").append((int) c).append(';'); - break; - case 2: - case 3: - sb.append("&#x").append(Integer.toHexString(c)).append(';'); - break; - case 4: - String encoded = encode(c); - if (encoded != null) sb.append(encoded); else sb.append(c); - } - } - return sb.toString(); - } -} diff --git a/src/main/java/org/pegdown/LinkRenderer.java b/src/main/java/org/pegdown/LinkRenderer.java deleted file mode 100644 index 58448ef..0000000 --- a/src/main/java/org/pegdown/LinkRenderer.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.pegdown; - -import org.parboiled.common.StringUtils; -import org.pegdown.ast.*; - -import static org.pegdown.FastEncoder.*; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.List; - -/** - * A LinkRenderer is responsible for turning an AST node representing a link into a {@link LinkRenderer.Rendering} - * instance, which hold the actual properties of the link as it is going to be rendered. - * If you'd like to apply custom logic to link rendering (e.g. for selectively adding "nofollow" attributes) you - * should derive a custom LinkRenderer from this class and override the respective methods. - */ -public class LinkRenderer { - - /** - * Simple model class for an HTML tag attribute. - */ - public static class Attribute { - public static Attribute NO_FOLLOW = new Attribute("rel", "nofollow"); - public String name; - public String value; - public Attribute(String name, String value) { - this.name = name; - this.value = value; - } - } - - /** - * Simple model class for holding the `href`, link text as well as other tag attributes of an HTML link. - */ - public static class Rendering { - public String href; - public String text; - public List attributes = new ArrayList(2); - public Rendering(String href, String text) { - this.href = href; - this.text = text; - } - public Rendering withAttribute(String name, String value) { - return withAttribute(new Attribute(name, value)); - } - public Rendering withAttribute(Attribute attr) { - attributes.add(attr); - return this; - } - } - - public Rendering render(AutoLinkNode node) { - return new Rendering(node.getText(), node.getText()); - } - - public Rendering render(ExpLinkNode node, String text) { - Rendering rendering = new Rendering(node.url, text); - return StringUtils.isEmpty(node.title) ? rendering : rendering.withAttribute("title", encode(node.title)); - } - - public Rendering render(MailLinkNode node) { - String obfuscated = obfuscate(node.getText()); - return new Rendering("mailto:" + obfuscated, obfuscated); - } - - public Rendering render(RefLinkNode node, String url, String title, String text) { - Rendering rendering = new Rendering(url, text); - return StringUtils.isEmpty(title) ? rendering : rendering.withAttribute("title", encode(title)); - } - - public Rendering render(WikiLinkNode node) { - try { - String url = "./" + URLEncoder.encode(node.getText().replace(' ', '-'), "UTF-8") + ".html"; - return new Rendering(url, node.getText()); - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException(); - } - } -} diff --git a/src/main/java/org/pegdown/Parser.java b/src/main/java/org/pegdown/Parser.java deleted file mode 100644 index ade4f97..0000000 --- a/src/main/java/org/pegdown/Parser.java +++ /dev/null @@ -1,1341 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown; - -import org.parboiled.BaseParser; -import org.parboiled.Context; -import org.parboiled.Rule; -import org.parboiled.annotations.*; -import org.parboiled.common.ArrayBuilder; -import org.parboiled.common.ImmutableList; -import org.parboiled.parserunners.ParseRunner; -import org.parboiled.parserunners.ReportingParseRunner; -import org.parboiled.support.ParsingResult; -import org.parboiled.support.StringBuilderVar; -import org.parboiled.support.StringVar; -import org.parboiled.support.Var; -import org.pegdown.ast.*; -import org.pegdown.ast.SimpleNode.Type; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.parboiled.errors.ErrorUtils.printParseErrors; -import static org.parboiled.common.StringUtils.repeat; - -/** - * Parboiled parser for the standard and extended markdown syntax. - * Builds an Abstract Syntax Tree (AST) of {@link Node} objects. - */ -@SuppressWarnings( {"InfiniteRecursion"}) -public class Parser extends BaseParser implements Extensions { - - protected static final char CROSSED_OUT = '\uffff'; - - public interface ParseRunnerProvider { - ParseRunner get(Rule rule); - } - - public static ParseRunnerProvider DefaultParseRunnerProvider = - new Parser.ParseRunnerProvider() { - public ParseRunner get(Rule rule) { - return new ReportingParseRunner(rule); - } - }; - - protected final int options; - protected final long maxParsingTimeInMillis; - protected final ParseRunnerProvider parseRunnerProvider; - final List abbreviations = new ArrayList(); - final List references = new ArrayList(); - long parsingStartTimeStamp = 0L; - - public Parser(Integer options, Long maxParsingTimeInMillis, ParseRunnerProvider parseRunnerProvider) { - this.options = options; - this.maxParsingTimeInMillis = maxParsingTimeInMillis; - this.parseRunnerProvider = parseRunnerProvider; - } - - public RootNode parse(char[] source) { - try { - RootNode root = parseInternal(source); - root.setAbbreviations(ImmutableList.copyOf(abbreviations)); - root.setReferences(ImmutableList.copyOf(references)); - return root; - } finally { - abbreviations.clear(); - references.clear(); - } - } - - //************* BLOCKS **************** - - public Rule Root() { - return NodeSequence( - push(new RootNode()), - ZeroOrMore(Block(), addAsChild()) - ); - } - - public Rule Block() { - return Sequence( - ZeroOrMore(BlankLine()), - FirstOf(new ArrayBuilder() - .add(BlockQuote(), Verbatim()) - .addNonNulls(ext(ABBREVIATIONS) ? Abbreviation() : null) - .add(Reference(), HorizontalRule(), Heading(), OrderedList(), BulletList(), HtmlBlock()) - .addNonNulls(ext(TABLES) ? Table() : null) - .addNonNulls(ext(DEFINITIONS) ? DefinitionList() : null) - .addNonNulls(ext(FENCED_CODE_BLOCKS) ? FencedCodeBlock() : null) - .add(Para(), Inlines()) - .get() - ) - ); - } - - public Rule Para() { - return NodeSequence( - NonindentSpace(), Inlines(), push(new ParaNode(popAsNode())), OneOrMore(BlankLine()) - ); - } - - public Rule BlockQuote() { - StringBuilderVar inner = new StringBuilderVar(); - return NodeSequence( - OneOrMore( - CrossedOut(Sequence('>', Optional(' ')), inner), Line(inner), - ZeroOrMore( - TestNot('>'), - TestNot(BlankLine()), - Line(inner) - ), - ZeroOrMore(BlankLine(), inner.append(match())) - ), - // trigger a recursive parsing run on the inner source we just built - // and attach the root of the inner parses AST - push(new BlockQuoteNode(withIndicesShifted(parseInternal(inner), (Integer)peek()).getChildren())) - ); - } - - public Rule Verbatim() { - StringBuilderVar text = new StringBuilderVar(); - StringBuilderVar line = new StringBuilderVar(); - return NodeSequence( - OneOrMore( - ZeroOrMore(BlankLine(), line.append("\n")), - Indent(), push(currentIndex()), - OneOrMore( - FirstOf( - Sequence('\t', line.append(repeat(' ', 4-(currentIndex()-1-(Integer)peek())%4))), - Sequence(NotNewline(), ANY, line.append(matchedChar())) - ) - ), - Newline(), - text.appended(line.getString()).append('\n') && line.clearContents() && drop() - ), - push(new VerbatimNode(text.getString())) - ); - } - - public Rule FencedCodeBlock() { - StringBuilderVar text = new StringBuilderVar(); - Var markerLength = new Var(); - return NodeSequence( - CodeFence(markerLength), - TestNot(CodeFence(markerLength)), // prevent empty matches - ZeroOrMore(BlankLine(), text.append('\n')), - OneOrMore(TestNot(Newline(), CodeFence(markerLength)), ANY, text.append(matchedChar())), - Newline(), - push(new VerbatimNode(text.appended('\n').getString(), popAsString())), - CodeFence(markerLength), drop() - ); - } - - @Cached - public Rule CodeFence(Var markerLength) { - return Sequence( - FirstOf(NOrMore('~', 3), NOrMore('`', 3)), - (markerLength.isSet() && matchLength() == markerLength.get()) || - (markerLength.isNotSet() && markerLength.set(matchLength())), - Sp(), - ZeroOrMore(TestNot(Newline()), ANY), // GFM code type identifier - push(match()), - Newline() - ); - } - - public Rule HorizontalRule() { - return NodeSequence( - NonindentSpace(), - FirstOf(HorizontalRule('*'), HorizontalRule('-'), HorizontalRule('_')), - Sp(), Newline(), OneOrMore(BlankLine()), - push(new SimpleNode(Type.HRule)) - ); - } - - public Rule HorizontalRule(char c) { - return Sequence(c, Sp(), c, Sp(), c, ZeroOrMore(Sp(), c)); - } - - //************* HEADINGS **************** - - public Rule Heading() { - return NodeSequence(FirstOf(AtxHeading(), SetextHeading())); - } - - public Rule AtxHeading() { - return Sequence( - AtxStart(), - Optional(Sp()), - OneOrMore(AtxInline(), addAsChild()), - Optional(Sp(), ZeroOrMore('#'), Sp()), - Newline() - ); - } - - public Rule AtxStart() { - return Sequence( - FirstOf("######", "#####", "####", "###", "##", "#"), - push(new HeaderNode(match().length())) - ); - } - - public Rule AtxInline() { - return Sequence( - TestNot(Newline()), - TestNot(Optional(Sp()), ZeroOrMore('#'), Sp(), Newline()), - Inline() - ); - } - - public Rule SetextHeading() { - return Sequence( - // test for successful setext heading before actually building it to reduce backtracking - Test(OneOrMore(NotNewline(), ANY), Newline(), FirstOf(NOrMore('=', 3), NOrMore('-', 3)), Newline()), - FirstOf(SetextHeading1(), SetextHeading2()) - ); - } - - public Rule SetextHeading1() { - return Sequence( - SetextInline(), push(new HeaderNode(1, popAsNode())), - ZeroOrMore(SetextInline(), addAsChild()), - Newline(), NOrMore('=', 3), Newline() - ); - } - - public Rule SetextHeading2() { - return Sequence( - SetextInline(), push(new HeaderNode(2, popAsNode())), - ZeroOrMore(SetextInline(), addAsChild()), - Newline(), NOrMore('-', 3), Newline() - ); - } - - public Rule SetextInline() { - return Sequence(TestNot(Endline()), Inline()); - } - - //************** Definition Lists ************ - - public Rule DefinitionList() { - return NodeSequence( - // test for successful definition list match before actually building it to reduce backtracking - TestNot(Spacechar()), - Test( - OneOrMore(TestNot(BlankLine()), TestNot(DefListBullet()), - OneOrMore(NotNewline(), ANY), Newline()), - Optional(BlankLine()), - DefListBullet() - ), - push(new DefinitionListNode()), - OneOrMore( - push(new SuperNode()), - OneOrMore(DefListTerm(), addAsChild()), - OneOrMore(Definition(), addAsChild()), - ((SuperNode)peek(1)).getChildren().addAll(popAsNode().getChildren()), - Optional(BlankLine()) - ) - ); - } - - public Rule DefListTerm() { - return NodeSequence( - TestNot(Spacechar()), - TestNot(DefListBullet()), - push(new DefinitionTermNode()), - OneOrMore(DefTermInline(), addAsChild()), - Optional(':'), - Newline() - ); - } - - public Rule DefTermInline() { - return Sequence( - NotNewline(), - TestNot(':', Newline()), - Inline() - ); - } - - public Rule Definition() { - SuperNodeCreator itemNodeCreator = new SuperNodeCreator() { - public SuperNode create(Node child) { - return new DefinitionNode(child); - } - }; - return ListItem(DefListBullet(), itemNodeCreator); - } - - public Rule DefListBullet() { - return Sequence(NonindentSpace(), AnyOf(":~"), OneOrMore(Spacechar())); - } - - //************* LISTS **************** - - public Rule BulletList() { - SuperNodeCreator itemNodeCreator = new SuperNodeCreator() { - public SuperNode create(Node child) { - return new ListItemNode(child); - } - }; - return NodeSequence( - ListItem(Bullet(), itemNodeCreator), push(new BulletListNode(popAsNode())), - ZeroOrMore(ListItem(Bullet(), itemNodeCreator), addAsChild()), - ZeroOrMore(BlankLine()) - ); - } - - public Rule OrderedList() { - SuperNodeCreator itemNodeCreator = new SuperNodeCreator() { - public SuperNode create(Node child) { - return new ListItemNode(child); - } - }; - return NodeSequence( - ListItem(Enumerator(), itemNodeCreator), push(new OrderedListNode(popAsNode())), - ZeroOrMore(ListItem(Enumerator(), itemNodeCreator), addAsChild()), - ZeroOrMore(BlankLine()) - ); - } - - @Cached - public Rule ListItem(Rule itemStart, SuperNodeCreator itemNodeCreator) { - // for a simpler parser design we use a recursive parsing strategy for list items: - // we collect a number of markdown source blocks for an item, run complete parsing cycle on these and attach - // the roots of the inner parsing results AST to the outer AST tree - StringBuilderVar block = new StringBuilderVar(); - StringBuilderVar temp = new StringBuilderVar(); - Var tight = new Var(false); - Var tightFirstItem = new Var(); - return Sequence( - push(getContext().getCurrentIndex()), - FirstOf(CrossedOut(BlankLine(), block), tight.set(true)), - CrossedOut(itemStart, block), Line(block), - ZeroOrMore( - Optional(CrossedOut(Indent(), temp)), - NotItem(), - Line(temp), - block.append(temp.getString()) && temp.clearContents() - ), - tight.get() ? push(tightFirstItem.setAndGet(itemNodeCreator.create(parseListBlock(block)))) : - fixFirstItem((SuperNode) peek(1)) && - push(itemNodeCreator.create(parseListBlock(block.appended("\n\n")))), - ZeroOrMore( - push(getContext().getCurrentIndex()), - FirstOf(Sequence(CrossedOut(BlankLine(), block), tight.set(false)), tight.set(true)), - CrossedOut(Indent(), block), - FirstOf( - DoubleIndentedBlocks(block), - IndentedBlock(block) - ), - (tight.get() ? push(parseListBlock(block)) : - (tightFirstItem.isNotSet() || wrapFirstItemInPara(tightFirstItem.get())) && - push(parseListBlock(block.appended("\n\n"))) - ) && addAsChild() - ), - setListItemIndices() - ); - } - - public Rule CrossedOut(Rule rule, StringBuilderVar block) { - return Sequence(rule, appendCrossed(block)); - } - - public Rule DoubleIndentedBlocks(StringBuilderVar block) { - StringBuilderVar line = new StringBuilderVar(); - return Sequence( - Indent(), TestNot(BlankLine()), block.append(" "), Line(block), - ZeroOrMore( - ZeroOrMore(BlankLine(), line.append(match())), - CrossedOut(Indent(), line), Indent(), line.append(" "), Line(line), - block.append(line.getString()) && line.clearContents() - ) - ); - } - - public Rule IndentedBlock(StringBuilderVar block) { - return Sequence( - Line(block), - ZeroOrMore( - FirstOf( - Sequence(TestNot(BlankLine()), CrossedOut(Indent(), block)), - NotItem() - ), - Line(block) - ) - ); - } - - public Rule NotItem() { - return TestNot( - FirstOf(new ArrayBuilder() - .add(Bullet(), Enumerator(), BlankLine(), HorizontalRule()) - .addNonNulls(ext(DEFINITIONS) ? DefListBullet() : null) - .get() - ) - ); - } - - public Rule Enumerator() { - return Sequence(NonindentSpace(), OneOrMore(Digit()), '.', OneOrMore(Spacechar())); - } - - public Rule Bullet() { - return Sequence(TestNot(HorizontalRule()), NonindentSpace(), AnyOf("+*-"), OneOrMore(Spacechar())); - } - - //************* LIST ITEM ACTIONS **************** - - boolean appendCrossed(StringBuilderVar block) { - for (int i = 0; i < matchLength(); i++) { - block.append(CROSSED_OUT); - } - return true; - } - - Node parseListBlock(StringBuilderVar block) { - Context context = getContext(); - Node innerRoot = parseInternal(block); - setContext(context); // we need to save and restore the context since we might be recursing - block.clearContents(); - return withIndicesShifted(innerRoot, (Integer) context.getValueStack().pop()); - } - - Node withIndicesShifted(Node node, int delta) { - ((AbstractNode) node).shiftIndices(delta); - for (Node subNode : node.getChildren()) { - withIndicesShifted(subNode, delta); - } - return node; - } - - boolean fixFirstItem(SuperNode listNode) { - List items = listNode.getChildren(); - if (items.size() == 1 && items.get(0) instanceof ListItemNode) { - wrapFirstItemInPara((SuperNode) items.get(0)); - } - return true; - } - - boolean wrapFirstItemInPara(SuperNode item) { - Node firstItemFirstChild = item.getChildren().get(0); - ParaNode paraNode = new ParaNode(firstItemFirstChild.getChildren()); - paraNode.setStartIndex(firstItemFirstChild.getStartIndex()); - paraNode.setEndIndex(firstItemFirstChild.getEndIndex()); - item.getChildren().set(0, paraNode); - return true; - } - - boolean setListItemIndices() { - SuperNode listItem = (SuperNode) getContext().getValueStack().peek(); - List children = listItem.getChildren(); - listItem.setStartIndex(children.get(0).getStartIndex()); - listItem.setEndIndex(children.get(children.size() - 1).getEndIndex()); - return true; - } - - //************* HTML BLOCK **************** - - public Rule HtmlBlock() { - return NodeSequence( - FirstOf(HtmlBlockInTags(), HtmlComment(), HtmlBlockSelfClosing()), - push(new HtmlBlockNode(ext(SUPPRESS_HTML_BLOCKS) ? "" : match())), - OneOrMore(BlankLine()) - ); - } - - public Rule HtmlBlockInTags() { - StringVar tagName = new StringVar(); - return Sequence( - Test(HtmlBlockOpen(tagName)), // get the type of tag if there is one - HtmlTagBlock(tagName) // specifically match that type of tag - ); - } - - @Cached - public Rule HtmlTagBlock(StringVar tagName) { - return Sequence( - HtmlBlockOpen(tagName), - ZeroOrMore( - FirstOf( - HtmlTagBlock(tagName), - Sequence(TestNot(HtmlBlockClose(tagName)), ANY) - ) - ), - HtmlBlockClose(tagName) - ); - } - - public Rule HtmlBlockSelfClosing() { - StringVar tagName = new StringVar(); - return Sequence('<', Spn1(), DefinedHtmlTagName(tagName), Spn1(), ZeroOrMore(HtmlAttribute()), Optional('/'), - Spn1(), '>'); - } - - public Rule HtmlBlockOpen(StringVar tagName) { - return Sequence('<', Spn1(), DefinedHtmlTagName(tagName), Spn1(), ZeroOrMore(HtmlAttribute()), '>'); - } - - @DontSkipActionsInPredicates - public Rule HtmlBlockClose(StringVar tagName) { - return Sequence('<', Spn1(), '/', OneOrMore(Alphanumeric()), match().equals(tagName.get()), Spn1(), '>'); - } - - @Cached - public Rule DefinedHtmlTagName(StringVar tagName) { - return Sequence( - OneOrMore(Alphanumeric()), - tagName.isSet() && match().equals(tagName.get()) || - tagName.isNotSet() && tagName.set(match().toLowerCase()) && isHtmlTag(tagName.get()) - ); - } - - public boolean isHtmlTag(String string) { - return Arrays.binarySearch(HTML_TAGS, string) >= 0; - } - - protected static final String[] HTML_TAGS = new String[] { - "address", "blockquote", "center", "dd", "dir", "div", "dl", "dt", "fieldset", "form", "frameset", "h1", - "h2", "h3", "h4", "h5", "h6", "hr", "isindex", "li", "menu", "noframes", "noscript", "ol", "p", "pre", - "script", "style", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "ul" - }; - - //************* INLINES **************** - - public Rule Inlines() { - return NodeSequence( - InlineOrIntermediateEndline(), push(new SuperNode(popAsNode())), - ZeroOrMore(InlineOrIntermediateEndline(), addAsChild()), - Optional(Endline(), drop()) - ); - } - - public Rule InlineOrIntermediateEndline() { - return FirstOf( - Sequence(TestNot(Endline()), Inline()), - Sequence(Endline(), Test(Inline())) - ); - } - - @MemoMismatches - public Rule Inline() { - return Sequence( - checkForParsingTimeout(), - FirstOf(Link(), NonLinkInline()) - ); - } - - public Rule NonAutoLinkInline() { - return FirstOf(NonAutoLink(), NonLinkInline()); - } - - public Rule NonLinkInline() { - return FirstOf(new ArrayBuilder() - .add(Str(), Endline(), UlOrStarLine(), Space(), StrongOrEmph(), Image(), Code(), InlineHtml(), - Entity(), EscapedChar()) - .addNonNulls(ext(QUOTES) ? new Rule[]{SingleQuoted(), DoubleQuoted(), DoubleAngleQuoted()} : null) - .addNonNulls(ext(SMARTS) ? new Rule[]{Smarts()} : null) - .add(Symbol()) - .get() - ); - } - - @MemoMismatches - public Rule Endline() { - return NodeSequence(FirstOf(LineBreak(), TerminalEndline(), NormalEndline())); - } - - public Rule LineBreak() { - return Sequence(" ", NormalEndline(), poke(new SimpleNode(Type.Linebreak))); - } - - public Rule TerminalEndline() { - return NodeSequence(Sp(), Newline(), Test(EOI), push(new TextNode("\n"))); - } - - public Rule NormalEndline() { - return Sequence( - Sp(), Newline(), - TestNot( - FirstOf( - BlankLine(), - '>', - AtxStart(), - Sequence(ZeroOrMore(NotNewline(), ANY), Newline(), - FirstOf(NOrMore('=', 3), NOrMore('-', 3)), Newline()) - ) - ), - ext(HARDWRAPS) ? toRule(push(new SimpleNode(Type.Linebreak))) : toRule(push(new TextNode(" "))) - ); - } - - //************* EMPHASIS / STRONG **************** - - @MemoMismatches - public Rule UlOrStarLine() { - // This keeps the parser from getting bogged down on long strings of '*' or '_', - // or strings of '*' or '_' with space on each side: - return NodeSequence( - FirstOf(CharLine('_'), CharLine('*')), - push(new TextNode(match())) - ); - } - - public Rule CharLine(char c) { - return FirstOf(NOrMore(c, 4), Sequence(Spacechar(), OneOrMore(c), Test(Spacechar()))); - } - - public Rule StrongOrEmph() { - return Sequence( - Test(AnyOf("*_")), - FirstOf(Strong(), Emph()) - ); - } - - public Rule Emph() { - return NodeSequence( - FirstOf(EmphOrStrong("*"), EmphOrStrong("_")), - push(new EmphNode(popAsNode().getChildren())) - ); - } - - public Rule Strong() { - return NodeSequence( - FirstOf(EmphOrStrong("**"), EmphOrStrong("__")), - push(new StrongNode(popAsNode().getChildren())) - ); - } - - @Cached - public Rule EmphOrStrong(String chars) { - return Sequence( - EmphOrStrongOpen(chars), - push(new SuperNode()), - OneOrMore(TestNot(EmphOrStrongClose(chars)), Inline(), addAsChild()), - EmphOrStrongClose(chars) - ); - } - - public Rule EmphOrStrongOpen(String chars) { - return Sequence( - TestNot(CharLine(chars.charAt(0))), - chars, - TestNot(Spacechar()), - NotNewline() - ); - } - - @Cached - public Rule EmphOrStrongClose(String chars) { - return Sequence( - TestNot(Spacechar()), - NotNewline(), - chars, - TestNot(Alphanumeric()) - ); - } - - //************* LINKS **************** - - public Rule Image() { - return NodeSequence( - '!', Label(), - FirstOf(ExplicitLink(true), ReferenceLink(true)) - ); - } - - @MemoMismatches - public Rule Link() { - return NodeSequence( - FirstOf(new ArrayBuilder() - .addNonNulls(ext(WIKILINKS) ? new Rule[]{WikiLink()} : null) - .add(Sequence(Label(), FirstOf(ExplicitLink(false), ReferenceLink(false)))) - .add(AutoLink()) - .get() - ) - ); - } - - public Rule NonAutoLink() { - return NodeSequence(Sequence(Label(), FirstOf(ExplicitLink(false), ReferenceLink(false)))); - } - - @Cached - public Rule ExplicitLink(boolean image) { - return Sequence( - Spn1(), '(', Sp(), - LinkSource(), - Spn1(), FirstOf(LinkTitle(), push("")), - Sp(), ')', - push(image ? - new ExpImageNode(popAsString(), popAsString(), popAsNode()) : - new ExpLinkNode(popAsString(), popAsString(), popAsNode()) - ) - ); - } - - public Rule ReferenceLink(boolean image) { - return Sequence( - FirstOf( - Sequence( - Spn1(), push(match()), - FirstOf( - Label(), // regular reference link - Sequence("[]", push(null)) // implicit reference link - ) - ), - Sequence(push(null), push(null)) // implicit referencelink without trailing [] - ), - push(image ? - new RefImageNode((SuperNode)popAsNode(), popAsString(), popAsNode()) : - new RefLinkNode((SuperNode)popAsNode(), popAsString(), popAsNode()) - ) - ); - } - - @Cached - public Rule LinkSource() { - StringBuilderVar url = new StringBuilderVar(); - return FirstOf( - Sequence('(', LinkSource(), ')'), - Sequence('<', LinkSource(), '>'), - Sequence( - OneOrMore( - FirstOf( - Sequence('\\', AnyOf("()"), url.append(matchedChar())), - Sequence(TestNot(AnyOf("()>")), Nonspacechar(), url.append(matchedChar())) - ) - ), - push(url.getString()) - ), - push("") - ); - } - - public Rule LinkTitle() { - return FirstOf(LinkTitle('\''), LinkTitle('"')); - } - - public Rule LinkTitle(char delimiter) { - return Sequence( - delimiter, - ZeroOrMore(TestNot(delimiter, Sp(), FirstOf(')', Newline())), NotNewline(), ANY), - push(match()), - delimiter - ); - } - - public Rule AutoLink() { - return Sequence( - ext(AUTOLINKS) ? Optional('<') : Ch('<'), - FirstOf(AutoLinkUrl(), AutoLinkEmail()), - ext(AUTOLINKS) ? Optional('>') : Ch('>') - ); - } - - public Rule WikiLink() { - return Sequence( - "[[", - OneOrMore(TestNot(']'), ANY), // might have to restrict from ANY - push(new WikiLinkNode(match())), - "]]" - ); - } - - public Rule AutoLinkUrl() { - return Sequence( - Sequence(OneOrMore(Letter()), "://", AutoLinkEnd()), - push(new AutoLinkNode(match())) - ); - } - - public Rule AutoLinkEmail() { - return Sequence( - Sequence(OneOrMore(FirstOf(Alphanumeric(), AnyOf("-+_."))), '@', AutoLinkEnd()), - push(new MailLinkNode(match())) - ); - } - - public Rule AutoLinkEnd() { - return OneOrMore( - TestNot(Newline()), - ext(AUTOLINKS) ? - TestNot( - FirstOf( - '>', - Sequence(Optional(AnyOf(".,;:)}]\"'")), FirstOf(Spacechar(), Newline())) - ) - ) : - TestNot('>'), - ANY - ); - } - - //************* REFERENCE **************** - - public Rule Label() { - return Sequence( - '[', - push(new SuperNode()), - OneOrMore(TestNot(']'), NonAutoLinkInline(), addAsChild()), - ']' - ); - } - - public Rule Reference() { - Var ref = new Var(); - return NodeSequence( - NonindentSpace(), Label(), push(ref.setAndGet(new ReferenceNode(popAsNode()))), - ':', Spn1(), RefSrc(ref), - Sp(), Optional(RefTitle(ref)), - Sp(), Newline(), - ZeroOrMore(BlankLine()), - references.add(ref.get()) - ); - } - - public Rule RefSrc(Var ref) { - return FirstOf( - Sequence('<', RefSrcContent(ref), '>'), - RefSrcContent(ref) - ); - } - - public Rule RefSrcContent(Var ref) { - return Sequence(OneOrMore(TestNot('>'), Nonspacechar()), ref.get().setUrl(match())); - } - - public Rule RefTitle(Var ref) { - return FirstOf(RefTitle('\'', '\'', ref), RefTitle('"', '"', ref), RefTitle('(', ')', ref)); - } - - public Rule RefTitle(char open, char close, Var ref) { - return Sequence( - open, - ZeroOrMore(TestNot(close, Sp(), Newline()), NotNewline(), ANY), - ref.get().setTitle(match()), - close - ); - } - - //************* CODE **************** - - public Rule Code() { - return NodeSequence( - Test('`'), - FirstOf( - Code(Ticks(1)), - Code(Ticks(2)), - Code(Ticks(3)), - Code(Ticks(4)), - Code(Ticks(5)) - ) - ); - } - - public Rule Code(Rule ticks) { - return Sequence( - ticks, Sp(), - OneOrMore( - FirstOf( - Sequence(TestNot('`'), Nonspacechar()), - Sequence(TestNot(ticks), OneOrMore('`')), - Sequence(TestNot(Sp(), ticks), - FirstOf(Spacechar(), Sequence(Newline(), TestNot(BlankLine())))) - ) - ), - push(new CodeNode(match())), - Sp(), ticks - ); - } - - public Rule Ticks(int count) { - return Sequence(repeat('`', count), TestNot('`')); - } - - //************* RAW HTML **************** - - public Rule InlineHtml() { - return NodeSequence( - FirstOf(HtmlComment(), HtmlTag()), - push(new InlineHtmlNode(ext(SUPPRESS_INLINE_HTML) ? "" : match())) - ); - } - - public Rule HtmlComment() { - return Sequence(""), ANY), "-->"); - } - - public Rule HtmlTag() { - return Sequence('<', Spn1(), Optional('/'), OneOrMore(Alphanumeric()), Spn1(), ZeroOrMore(HtmlAttribute()), - Optional('/'), Spn1(), '>'); - } - - public Rule HtmlAttribute() { - return Sequence( - OneOrMore(FirstOf(Alphanumeric(), '-', '_')), - Spn1(), - Optional('=', Spn1(), FirstOf(Quoted(), OneOrMore(TestNot('>'), Nonspacechar()))), - Spn1() - ); - } - - public Rule Quoted() { - return FirstOf( - Sequence('"', ZeroOrMore(TestNot('"'), ANY), '"'), - Sequence('\'', ZeroOrMore(TestNot('\''), ANY), '\'') - ); - } - - //************* LINES **************** - - public Rule BlankLine() { - return Sequence(Sp(), Newline()); - } - - public Rule Line(StringBuilderVar sb) { - return Sequence( - Sequence(ZeroOrMore(NotNewline(), ANY), Newline()), - sb.append(match()) - ); - } - - //************* ENTITIES **************** - - public Rule Entity() { - return NodeSequence( - Sequence('&', FirstOf(HexEntity(), DecEntity(), CharEntity()), ';'), - push(new TextNode(match())) - ); - } - - public Rule HexEntity() { - return Sequence('#', IgnoreCase('x'), OneOrMore(FirstOf(Digit(), CharRange('a', 'f'), CharRange('A', 'F')))); - } - - public Rule DecEntity() { - return Sequence('#', OneOrMore(Digit())); - } - - public Rule CharEntity() { - return OneOrMore(Alphanumeric()); - } - - //************* BASICS **************** - - public Rule Str() { - return NodeSequence(OneOrMore(NormalChar()), push(new TextNode(match()))); - } - - public Rule Space() { - return NodeSequence(OneOrMore(Spacechar()), push(new TextNode(" "))); - } - - public Rule Spn1() { - return Sequence(Sp(), Optional(Newline(), Sp())); - } - - public Rule Sp() { - return ZeroOrMore(Spacechar()); - } - - public Rule Spacechar() { - return AnyOf(" \t"); - } - - public Rule Nonspacechar() { - return Sequence(TestNot(Spacechar()), NotNewline(), ANY); - } - - @MemoMismatches - public Rule NormalChar() { - return Sequence(TestNot(SpecialChar()), TestNot(Spacechar()), NotNewline(), ANY); - } - - public Rule EscapedChar() { - return NodeSequence('\\', AnyOf("*_`&[]<>!#\\'\".+-(){}:|~"), push(new SpecialTextNode(match()))); - } - - public Rule Symbol() { - return NodeSequence(SpecialChar(), push(new SpecialTextNode(match()))); - } - - public Rule SpecialChar() { - String chars = "*_`&[]<>!#\\"; - if (ext(QUOTES)) { - chars += "'\""; - } - if (ext(SMARTS)) { - chars += ".-"; - } - if (ext(AUTOLINKS)) { - chars += "(){}"; - } - if (ext(DEFINITIONS)) { - chars += ":"; - } - if (ext(TABLES)) { - chars += "|"; - } - if (ext(DEFINITIONS) | ext(FENCED_CODE_BLOCKS)) { - chars += "~"; - } - return AnyOf(chars); - } - - public Rule NotNewline() { - return TestNot(AnyOf("\n\r")); - } - - public Rule Newline() { - return FirstOf('\n', Sequence('\r', Optional('\n'))); - } - - public Rule NonindentSpace() { - return FirstOf(" ", " ", " ", EMPTY); - } - - public Rule Indent() { - return FirstOf('\t', " "); - } - - public Rule Alphanumeric() { - return FirstOf(Letter(), Digit()); - } - - public Rule Letter() { - return FirstOf(CharRange('a', 'z'), CharRange('A', 'Z')); - } - - public Rule Digit() { - return CharRange('0', '9'); - } - - //************* ABBREVIATIONS **************** - - public Rule Abbreviation() { - Var node = new Var(); - return NodeSequence( - NonindentSpace(), '*', Label(), push(node.setAndGet(new AbbreviationNode(popAsNode()))), - Sp(), ':', Sp(), AbbreviationText(node), - ZeroOrMore(BlankLine()), - abbreviations.add(node.get()) - ); - } - - public Rule AbbreviationText(Var node) { - return Sequence( - NodeSequence( - push(new SuperNode()), - ZeroOrMore(NotNewline(), Inline(), addAsChild()) - ), - node.get().setExpansion(popAsNode()) - ); - } - - //************* TABLES **************** - - public Rule Table() { - Var node = new Var(); - return NodeSequence( - push(node.setAndGet(new TableNode())), - Optional( - NodeSequence( - TableRow(), push(1, new TableHeaderNode()) && addAsChild(), - ZeroOrMore(TableRow(), addAsChild()) - ), - addAsChild() // add the TableHeaderNode to the TableNode - ), - TableDivider(node), - Optional( - NodeSequence( - TableRow(), push(1, new TableBodyNode()) && addAsChild(), - ZeroOrMore(TableRow(), addAsChild()) - ), - addAsChild() // add the TableHeaderNode to the TableNode - ), - // only accept as table if we have at least one header or at least one body - Optional(TableCaption(), addAsChild()), - !node.get().getChildren().isEmpty() - - ); - } - public Rule TableCaption() { - return Sequence( - CaptionStart(), - Optional(Sp()), - OneOrMore(CaptionInline(), addAsChild()), - Optional(Sp(), Optional(']'), Sp()), - Newline() - ); - } - - public Rule CaptionStart() { - return Sequence( - "[", - push(new TableCaptionNode()) - ); - } - public Rule CaptionInline() { - return Sequence( - TestNot(Newline()), - TestNot(Optional(Sp()), Optional(']'), Sp(), Newline()), - Inline() - ); - } - - - public Rule TableDivider(Var tableNode) { - Var pipeSeen = new Var(Boolean.FALSE); - return Sequence( - Optional('|', pipeSeen.set(Boolean.TRUE)), - OneOrMore(TableColumn(tableNode, pipeSeen)), - pipeSeen.get() || tableNode.get().hasTwoOrMoreDividers(), - Sp(), Newline() - ); - } - - public Rule TableColumn(Var tableNode, Var pipeSeen) { - Var node = new Var(new TableColumnNode()); - return Sequence( - Sp(), - Optional(':', node.get().markLeftAligned()), - Sp(), OneOrMore('-'), Sp(), - Optional(':', node.get().markRightAligned()), - Sp(), - Optional('|', pipeSeen.set(Boolean.TRUE)), - tableNode.get().addColumn(node.get()) - ); - } - - public Rule TableRow() { - Var leadingPipe = new Var(Boolean.FALSE); - return NodeSequence( - push(new TableRowNode()), - Optional('|', leadingPipe.set(Boolean.TRUE)), - OneOrMore(TableCell(), addAsChild()), - leadingPipe.get() || ((Node) peek()).getChildren().size() > 1 || - getContext().getInputBuffer().charAt(matchEnd() - 1) == '|', - Sp(), Newline() - ); - } - - public Rule TableCell() { - return NodeSequence( - push(new TableCellNode()), - TestNot(Sp(), Optional(':'), Sp(), OneOrMore('-'), Sp(), Optional(':'), Sp(), FirstOf('|', Newline())), - Optional(Sp(), TestNot('|'), NotNewline()), - OneOrMore( - TestNot('|'), TestNot(Sp(), Newline()), Inline(), - addAsChild(), - Optional(Sp(), Test('|'), Test(Newline())) - ), - ZeroOrMore('|'), ((TableCellNode) peek()).setColSpan(Math.max(1, matchLength())) - ); - } - - //************* SMARTS **************** - - public Rule Smarts() { - return NodeSequence( - FirstOf( - Sequence(FirstOf("...", ". . ."), push(new SimpleNode(Type.Ellipsis))), - Sequence("---", push(new SimpleNode(Type.Emdash))), - Sequence("--", push(new SimpleNode(Type.Endash))), - Sequence('\'', push(new SimpleNode(Type.Apostrophe))) - ) - ); - } - - //************* QUOTES **************** - - public Rule SingleQuoted() { - return NodeSequence( - !Character.isLetter(getContext().getInputBuffer().charAt(getContext().getCurrentIndex() - 1)), - '\'', - push(new QuotedNode(QuotedNode.Type.Single)), - OneOrMore(TestNot(SingleQuoteEnd()), Inline(), addAsChild()), - SingleQuoteEnd() - ); - } - - public Rule SingleQuoteEnd() { - return Sequence('\'', TestNot(Alphanumeric())); - } - - public Rule DoubleQuoted() { - return NodeSequence( - '"', - push(new QuotedNode(QuotedNode.Type.Double)), - OneOrMore(TestNot('"'), Inline(), addAsChild()), - '"' - ); - } - - public Rule DoubleAngleQuoted() { - return NodeSequence( - "<<", - push(new QuotedNode(QuotedNode.Type.DoubleAngle)), - Optional(NodeSequence(Spacechar(), push(new SimpleNode(Type.Nbsp))), addAsChild()), - OneOrMore( - FirstOf( - Sequence(NodeSequence(OneOrMore(Spacechar()), Test(">>"), - push(new SimpleNode(Type.Nbsp))), addAsChild()), - Sequence(TestNot(">>"), Inline(), addAsChild()) - ) - ), - ">>" - ); - } - - //************* HELPERS **************** - - public Rule NOrMore(char c, int n) { - return Sequence(repeat(c, n), ZeroOrMore(c)); - } - - public Rule NodeSequence(Object... nodeRules) { - return Sequence( - push(getContext().getCurrentIndex()), - Sequence(nodeRules), - setIndices() - ); - } - - public boolean setIndices() { - AbstractNode node = (AbstractNode) peek(); - node.setStartIndex((Integer)pop(1)); - node.setEndIndex(currentIndex()); - return true; - } - - public boolean addAsChild() { - SuperNode parent = (SuperNode) peek(1); - List children = parent.getChildren(); - Node child = popAsNode(); - if (child.getClass() == TextNode.class && !children.isEmpty()) { - Node lastChild = children.get(children.size() - 1); - if (lastChild.getClass() == TextNode.class) { - // collapse peer TextNodes - TextNode last = (TextNode) lastChild; - TextNode current = (TextNode) child; - last.append(current.getText()); - last.setEndIndex(current.getEndIndex()); - return true; - } - } - children.add(child); - return true; - } - - public Node popAsNode() { - return (Node) pop(); - } - - public String popAsString() { - return (String) pop(); - } - - public boolean ext(int extension) { - return (options & extension) > 0; - } - - // called for inner parses for list items and blockquotes - public RootNode parseInternal(StringBuilderVar block) { - char[] chars = block.getChars(); - int[] ixMap = new int[chars.length + 1]; // map of cleaned indices to original indices - - // strip out CROSSED_OUT characters and build index map - StringBuilder clean = new StringBuilder(); - for (int i = 0; i < chars.length; i++) { - char c = chars[i]; - if (c != CROSSED_OUT) { - ixMap[clean.length()] = i; - clean.append(c); - } - } - ixMap[clean.length()] = chars.length; - - // run inner parse - char[] cleaned = new char[clean.length()]; - clean.getChars(0, cleaned.length, cleaned, 0); - RootNode rootNode = parseInternal(cleaned); - - // correct AST indices with index map - fixIndices(rootNode, ixMap); - - return rootNode; - } - - protected void fixIndices(Node node, int[] ixMap) { - ((AbstractNode) node).mapIndices(ixMap); - for (Node subNode : node.getChildren()) { - fixIndices(subNode, ixMap); - } - } - - public RootNode parseInternal(char[] source) { - ParsingResult result = parseToParsingResult(source); - if (result.hasErrors()) { - throw new RuntimeException("Internal error during markdown parsing:\n--- ParseErrors ---\n" + - printParseErrors(result)/* + - "\n--- ParseTree ---\n" + - printNodeTree(result)*/ - ); - } - return (RootNode) result.resultValue; - } - - ParsingResult parseToParsingResult(char[] source) { - parsingStartTimeStamp = System.currentTimeMillis(); - return parseRunnerProvider.get(Root()).run(source); - } - - protected boolean checkForParsingTimeout() { - if (System.currentTimeMillis() - parsingStartTimeStamp > maxParsingTimeInMillis) - throw new ParsingTimeoutException(); - return true; - } - - protected interface SuperNodeCreator { - SuperNode create(Node child); - } -} diff --git a/src/main/java/org/pegdown/ParsingTimeoutException.java b/src/main/java/org/pegdown/ParsingTimeoutException.java deleted file mode 100644 index 04fbde2..0000000 --- a/src/main/java/org/pegdown/ParsingTimeoutException.java +++ /dev/null @@ -1,3 +0,0 @@ -package org.pegdown; - -public class ParsingTimeoutException extends RuntimeException {} diff --git a/src/main/java/org/pegdown/PegDownProcessor.java b/src/main/java/org/pegdown/PegDownProcessor.java deleted file mode 100644 index 04690ad..0000000 --- a/src/main/java/org/pegdown/PegDownProcessor.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown; - -import org.parboiled.Parboiled; -import org.pegdown.ast.RootNode; - -/** - * A clean and lightweight Markdown-to-HTML filter based on a PEG parser implemented with parboiled. - * Note: A PegDownProcessor is not thread-safe (since it internally reused the parboiled parser instance). - * If you need to process markdown source in parallel create one PegDownProcessor per thread! - * - * @see Markdown - * @see parboiled.org - */ -public class PegDownProcessor { - public static final long DEFAULT_MAX_PARSING_TIME = 2000; - - public final Parser parser; - - /** - * Creates a new processor instance without any enabled extensions and the default parsing timeout. - */ - public PegDownProcessor() { - this(DEFAULT_MAX_PARSING_TIME); - } - - /** - * Creates a new processor instance without any enabled extensions and the given parsing timeout. - */ - public PegDownProcessor(long maxParsingTimeInMillis) { - this(Extensions.NONE, maxParsingTimeInMillis); - } - - /** - * Creates a new processor instance with the given {@link org.pegdown.Extensions} and the default parsing timeout. - * - * @param options the flags of the extensions to enable as a bitmask - */ - public PegDownProcessor(int options) { - this(options, DEFAULT_MAX_PARSING_TIME); - } - - /** - * Creates a new processor instance with the given {@link org.pegdown.Extensions} and parsing timeout. - * - * @param options the flags of the extensions to enable as a bitmask - */ - public PegDownProcessor(int options, long maxParsingTimeInMillis) { - this(Parboiled.createParser(Parser.class, options, maxParsingTimeInMillis, Parser.DefaultParseRunnerProvider)); - } - - /** - * Creates a new processor instance using the given Parser. - * - * @param parser the parser instance to use - */ - public PegDownProcessor(Parser parser) { - this.parser = parser; - } - - /** - * Converts the given markdown source to HTML. - * If the input cannot be parsed within the configured parsing timeout the method returns null. - * - * @param markdownSource the markdown source to convert - * @return the HTML - */ - public String markdownToHtml(String markdownSource) { - return markdownToHtml(markdownSource.toCharArray()); - } - - /** - * Converts the given markdown source to HTML. - * If the input cannot be parsed within the configured parsing timeout the method returns null. - * - * @param markdownSource the markdown source to convert - * @param linkRenderer the LinkRenderer to use - * @return the HTML - */ - public String markdownToHtml(String markdownSource, LinkRenderer linkRenderer) { - return markdownToHtml(markdownSource.toCharArray(), linkRenderer); - } - - /** - * Converts the given markdown source to HTML. - * If the input cannot be parsed within the configured parsing timeout the method returns null. - * - * @param markdownSource the markdown source to convert - * @return the HTML - */ - public String markdownToHtml(char[] markdownSource) { - return markdownToHtml(markdownSource, new LinkRenderer()); - } - - /** - * Converts the given markdown source to HTML. - * If the input cannot be parsed within the configured parsing timeout the method returns null. - * - * @param markdownSource the markdown source to convert - * @param linkRenderer the LinkRenderer to use - * @return the HTML - */ - public String markdownToHtml(char[] markdownSource, LinkRenderer linkRenderer) { - try { - RootNode astRoot = parseMarkdown(markdownSource); - return new ToHtmlSerializer(linkRenderer).toHtml(astRoot); - } catch(ParsingTimeoutException e) { - return null; - } - } - - /** - * Parses the given markdown source and returns the root node of the generated Abstract Syntax Tree. - * If the input cannot be parsed within the configured parsing timeout the method throws a ParsingTimeoutException. - * - * @param markdownSource the markdown source to convert - * @return the AST root - */ - public RootNode parseMarkdown(char[] markdownSource) { - return parser.parse(prepareSource(markdownSource)); - } - - /** - * Adds two trailing newlines. - * - * @param source the markdown source to process - * @return the processed source - */ - public char[] prepareSource(char[] source) { - char[] src = new char[source.length + 2]; - System.arraycopy(source, 0, src, 0, source.length); - src[source.length] = '\n'; - src[source.length + 1] = '\n'; - return src; - } -} diff --git a/src/main/java/org/pegdown/Printer.java b/src/main/java/org/pegdown/Printer.java deleted file mode 100644 index cd166da..0000000 --- a/src/main/java/org/pegdown/Printer.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown; - -/** - * Encapsulates basic string output functionality. - */ -public class Printer { - public final StringBuilder sb; - public int indent; - - public Printer() { - this(new StringBuilder()); - } - - public Printer(StringBuilder sb) { - this.sb = sb; - } - - public Printer indent(int delta) { - indent += delta; - return this; - } - - public Printer print(String string) { - sb.append(string); - return this; - } - - public Printer printEncoded(String string) { - FastEncoder.encode(string, sb); - return this; - } - - public Printer print(char c) { - sb.append(c); - return this; - } - - public Printer println() { - if (sb.length() > 0) print('\n'); - for (int i = 0; i < indent; i++) print(' '); - return this; - } - - public String getString() { - return sb.toString(); - } - - public Printer clear() { - sb.setLength(0); - return this; - } -} diff --git a/src/main/java/org/pegdown/ToHtmlSerializer.java b/src/main/java/org/pegdown/ToHtmlSerializer.java deleted file mode 100644 index 7a31c89..0000000 --- a/src/main/java/org/pegdown/ToHtmlSerializer.java +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown; - -import org.parboiled.common.StringUtils; -import org.pegdown.ast.*; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import static org.parboiled.common.Preconditions.checkArgNotNull; - -public class ToHtmlSerializer implements Visitor { - - protected Printer printer = new Printer(); - protected final Map references = new HashMap(); - protected final Map abbreviations = new HashMap(); - protected final LinkRenderer linkRenderer; - - protected TableNode currentTableNode; - protected int currentTableColumn; - protected boolean inTableHeader; - - public ToHtmlSerializer(LinkRenderer linkRenderer) { - this.linkRenderer = linkRenderer; - } - - public String toHtml(RootNode astRoot) { - checkArgNotNull(astRoot, "astRoot"); - astRoot.accept(this); - return printer.getString(); - } - - public void visit(RootNode node) { - for (ReferenceNode refNode : node.getReferences()) { - visitChildren(refNode); - references.put(normalize(printer.getString()), refNode); - printer.clear(); - } - for (AbbreviationNode abbrNode : node.getAbbreviations()) { - visitChildren(abbrNode); - String abbr = printer.getString(); - printer.clear(); - abbrNode.getExpansion().accept(this); - String expansion = printer.getString(); - abbreviations.put(abbr, expansion); - printer.clear(); - } - visitChildren(node); - } - - public void visit(AbbreviationNode node) { - } - - public void visit(AutoLinkNode node) { - printLink(linkRenderer.render(node)); - } - - public void visit(BlockQuoteNode node) { - printIndentedTag(node, "blockquote"); - } - - public void visit(BulletListNode node) { - printIndentedTag(node, "ul"); - } - - public void visit(CodeNode node) { - printTag(node, "code"); - } - - public void visit(DefinitionListNode node) { - printIndentedTag(node, "dl"); - } - - public void visit(DefinitionNode node) { - printTag(node, "dd"); - } - - public void visit(DefinitionTermNode node) { - printTag(node, "dt"); - } - - public void visit(EmphNode node) { - printTag(node, "em"); - } - - public void visit(ExpImageNode node) { - printImageTag(node, node.url); - } - - public void visit(ExpLinkNode node) { - String text = printChildrenToString(node); - printLink(linkRenderer.render(node, text)); - } - - public void visit(HeaderNode node) { - printTag(node, "h" + node.getLevel()); - } - - public void visit(HtmlBlockNode node) { - String text = node.getText(); - if (text.length() > 0) printer.println(); - printer.print(text); - } - - public void visit(InlineHtmlNode node) { - printer.print(node.getText()); - } - - public void visit(ListItemNode node) { - printer.println(); - printTag(node, "li"); - } - - public void visit(MailLinkNode node) { - printLink(linkRenderer.render(node)); - } - - public void visit(OrderedListNode node) { - printIndentedTag(node, "ol"); - } - - public void visit(ParaNode node) { - printTag(node, "p"); - } - - public void visit(QuotedNode node) { - switch (node.getType()) { - case DoubleAngle: - printer.print("«"); - visitChildren(node); - printer.print("»"); - break; - case Double: - printer.print("“"); - visitChildren(node); - printer.print("”"); - break; - case Single: - printer.print("‘"); - visitChildren(node); - printer.print("’"); - break; - } - } - - public void visit(ReferenceNode node) { - // reference nodes are not printed - } - - public void visit(RefImageNode node) { - String text = printChildrenToString(node); - String key = node.referenceKey != null ? printChildrenToString(node.referenceKey) : text; - ReferenceNode refNode = references.get(normalize(key)); - if (refNode == null) { // "fake" reference image link - printer.print("![").print(text).print(']'); - if (node.separatorSpace != null) { - printer.print(node.separatorSpace).print('['); - if (node.referenceKey != null) printer.print(key); - printer.print(']'); - } - } else printImageTag(node, refNode.getUrl()); - } - - public void visit(RefLinkNode node) { - String text = printChildrenToString(node); - String key = node.referenceKey != null ? printChildrenToString(node.referenceKey) : text; - ReferenceNode refNode = references.get(normalize(key)); - if (refNode == null) { // "fake" reference link - printer.print('[').print(text).print(']'); - if (node.separatorSpace != null) { - printer.print(node.separatorSpace).print('['); - if (node.referenceKey != null) printer.print(key); - printer.print(']'); - } - } else printLink(linkRenderer.render(node, refNode.getUrl(), refNode.getTitle(), text)); - } - - public void visit(SimpleNode node) { - switch (node.getType()) { - case Apostrophe: - printer.print("’"); - break; - case Ellipsis: - printer.print("…"); - break; - case Emdash: - printer.print("—"); - break; - case Endash: - printer.print("–"); - break; - case HRule: - printer.println().print("
"); - break; - case Linebreak: - printer.print("
"); - break; - case Nbsp: - printer.print(" "); - break; - default: - throw new IllegalStateException(); - } - } - - public void visit(StrongNode node) { - printTag(node, "strong"); - } - - public void visit(TableBodyNode node) { - printIndentedTag(node, "tbody"); - } - - @Override - public void visit(TableCaptionNode node) { - printer.println().print(""); - visitChildren(node); - printer.print(""); - } - public void visit(TableCellNode node) { - String tag = inTableHeader ? "th" : "td"; - List columns = currentTableNode.getColumns(); - TableColumnNode column = columns.get(Math.min(currentTableColumn, columns.size()-1)); - - printer.println().print('<').print(tag); - column.accept(this); - if (node.getColSpan() > 1) printer.print(" colspan=\"").print(Integer.toString(node.getColSpan())).print('"'); - printer.print('>'); - visitChildren(node); - printer.print('<').print('/').print(tag).print('>'); - - currentTableColumn += node.getColSpan(); - } - - public void visit(TableColumnNode node) { - switch (node.getAlignment()) { - case None: - break; - case Left: - printer.print(" align=\"left\""); - break; - case Right: - printer.print(" align=\"right\""); - break; - case Center: - printer.print(" align=\"center\""); - break; - default: - throw new IllegalStateException(); - } - } - - public void visit(TableHeaderNode node) { - inTableHeader = true; - printIndentedTag(node, "thead"); - inTableHeader = false; - } - - public void visit(TableNode node) { - currentTableNode = node; - printIndentedTag(node, "table"); - currentTableNode = null; - } - - public void visit(TableRowNode node) { - currentTableColumn = 0; - printIndentedTag(node, "tr"); - } - - public void visit(VerbatimNode node) { - printer.println().print("
");
-        String text = node.getText();
-        // print HTML breaks for all initial newlines
-        while(text.charAt(0) == '\n') {
-            printer.print("
"); - text = text.substring(1); - } - printer.printEncoded(text); - printer.print("
"); - } - - public void visit(WikiLinkNode node) { - printLink(linkRenderer.render(node)); - } - - public void visit(TextNode node) { - if (abbreviations.isEmpty()) { - printer.print(node.getText()); - } else { - printWithAbbreviations(node.getText()); - } - } - - public void visit(SpecialTextNode node) { - printer.printEncoded(node.getText()); - } - - public void visit(SuperNode node) { - visitChildren(node); - } - - public void visit(Node node) { - // override this method for processing custom Node implementations - throw new RuntimeException("Not implemented"); - } - - // helpers - - protected void visitChildren(SuperNode node) { - for (Node child : node.getChildren()) { - child.accept(this); - } - } - - protected void printTag(TextNode node, String tag) { - printer.print('<').print(tag).print('>'); - printer.printEncoded(node.getText()); - printer.print('<').print('/').print(tag).print('>'); - } - - protected void printTag(SuperNode node, String tag) { - printer.print('<').print(tag).print('>'); - visitChildren(node); - printer.print('<').print('/').print(tag).print('>'); - } - - protected void printIndentedTag(SuperNode node, String tag) { - printer.println().print('<').print(tag).print('>').indent(+2); - visitChildren(node); - printer.indent(-2).println().print('<').print('/').print(tag).print('>'); - } - - protected void printImageTag(SuperNode imageNode, String url) { - printer.print("\"")"); - } - - protected void printLink(LinkRenderer.Rendering rendering) { - printer.print('<').print('a'); - printAttribute("href", rendering.href); - for (LinkRenderer.Attribute attr : rendering.attributes) { - printAttribute(attr.name, attr.value); - } - printer.print('>').print(rendering.text).print(""); - } - - private void printAttribute(String name, String value) { - printer.print(' ').print(name).print('=').print('"').print(value).print('"'); - } - - protected String printChildrenToString(SuperNode node) { - Printer priorPrinter = printer; - printer = new Printer(); - visitChildren(node); - String result = printer.getString(); - printer = priorPrinter; - return result; - } - - protected String normalize(String string) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < string.length(); i++) { - char c = string.charAt(i); - switch(c) { - case ' ': - case '\n': - case '\t': - continue; - } - sb.append(Character.toLowerCase(c)); - } - return sb.toString(); - } - - protected void printWithAbbreviations(String string) { - Map> expansions = null; - - for (Map.Entry entry : abbreviations.entrySet()) { - // first check, whether we have a legal match - String abbr = entry.getKey(); - - int ix = 0; - while (true) { - int sx = string.indexOf(abbr, ix); - if (sx == -1) break; - - // only allow whole word matches - ix = sx + abbr.length(); - - if (sx > 0 && Character.isLetterOrDigit(string.charAt(sx - 1))) continue; - if (ix < string.length() && Character.isLetterOrDigit(string.charAt(ix))) { - continue; - } - - // ok, legal match so save an expansions "task" for all matches - if (expansions == null) { - expansions = new TreeMap>(); - } - expansions.put(sx, entry); - } - } - - if (expansions != null) { - int ix = 0; - for (Map.Entry> entry : expansions.entrySet()) { - int sx = entry.getKey(); - String abbr = entry.getValue().getKey(); - String expansion = entry.getValue().getValue(); - - printer.printEncoded(string.substring(ix, sx)); - printer.print("'); - printer.printEncoded(abbr); - printer.print(""); - ix = sx + abbr.length(); - } - printer.print(string.substring(ix)); - } else { - printer.print(string); - } - } -} diff --git a/src/main/java/org/pegdown/ast/AbbreviationNode.java b/src/main/java/org/pegdown/ast/AbbreviationNode.java deleted file mode 100644 index fef4ab8..0000000 --- a/src/main/java/org/pegdown/ast/AbbreviationNode.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class AbbreviationNode extends SuperNode { - private Node expansion; - - public AbbreviationNode(Node child) { - super(child); - } - - public Node getExpansion() { - return expansion; - } - - public boolean setExpansion(Node expansion) { - this.expansion = expansion; - return true; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/AbstractNode.java b/src/main/java/org/pegdown/ast/AbstractNode.java deleted file mode 100644 index 9912864..0000000 --- a/src/main/java/org/pegdown/ast/AbstractNode.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.pegdown.ast; - -public abstract class AbstractNode implements Node { - private int startIndex; - private int endIndex; - - public int getStartIndex() { - return startIndex; - } - - public int getEndIndex() { - return endIndex; - } - - public void setStartIndex(int startIndex) { - this.startIndex = startIndex; - } - - public void setEndIndex(int endIndex) { - this.endIndex = endIndex; - } - - public void shiftIndices(int delta) { - startIndex += delta; - endIndex += delta; - } - - public void mapIndices(int[] ixMap) { - startIndex = ixMap[startIndex]; - endIndex = ixMap[endIndex]; - } - - @Override - public String toString() { - return getClass().getSimpleName() + " [" + startIndex + '-' + endIndex + ']'; - } -} diff --git a/src/main/java/org/pegdown/ast/AutoLinkNode.java b/src/main/java/org/pegdown/ast/AutoLinkNode.java deleted file mode 100644 index 7948aec..0000000 --- a/src/main/java/org/pegdown/ast/AutoLinkNode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class AutoLinkNode extends TextNode { - - public AutoLinkNode(String text) { - super(text); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/BlockQuoteNode.java b/src/main/java/org/pegdown/ast/BlockQuoteNode.java deleted file mode 100644 index f0ec32e..0000000 --- a/src/main/java/org/pegdown/ast/BlockQuoteNode.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -import java.util.List; - -public class BlockQuoteNode extends SuperNode { - - public BlockQuoteNode(List children) { - super(children); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/BulletListNode.java b/src/main/java/org/pegdown/ast/BulletListNode.java deleted file mode 100644 index cda800f..0000000 --- a/src/main/java/org/pegdown/ast/BulletListNode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class BulletListNode extends SuperNode { - - public BulletListNode(Node child) { - super(child); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/CodeNode.java b/src/main/java/org/pegdown/ast/CodeNode.java deleted file mode 100644 index ac88156..0000000 --- a/src/main/java/org/pegdown/ast/CodeNode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class CodeNode extends TextNode { - - public CodeNode(String text) { - super(text); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/DefinitionListNode.java b/src/main/java/org/pegdown/ast/DefinitionListNode.java deleted file mode 100644 index 1733fe8..0000000 --- a/src/main/java/org/pegdown/ast/DefinitionListNode.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class DefinitionListNode extends SuperNode { - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/DefinitionNode.java b/src/main/java/org/pegdown/ast/DefinitionNode.java deleted file mode 100644 index 47f8a96..0000000 --- a/src/main/java/org/pegdown/ast/DefinitionNode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class DefinitionNode extends SuperNode { - - public DefinitionNode(Node child) { - super(child); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/DefinitionTermNode.java b/src/main/java/org/pegdown/ast/DefinitionTermNode.java deleted file mode 100644 index 0395f99..0000000 --- a/src/main/java/org/pegdown/ast/DefinitionTermNode.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class DefinitionTermNode extends SuperNode { - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/EmphNode.java b/src/main/java/org/pegdown/ast/EmphNode.java deleted file mode 100644 index 5c1a7b4..0000000 --- a/src/main/java/org/pegdown/ast/EmphNode.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -import java.util.List; - -public class EmphNode extends SuperNode { - - public EmphNode(List children) { - super(children); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/ExpImageNode.java b/src/main/java/org/pegdown/ast/ExpImageNode.java deleted file mode 100644 index 388373f..0000000 --- a/src/main/java/org/pegdown/ast/ExpImageNode.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class ExpImageNode extends SuperNode { - public final String url; - public final String title; - - public ExpImageNode(String title, String url, Node child) { - super(child); - this.url = url; - this.title = title; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/ExpLinkNode.java b/src/main/java/org/pegdown/ast/ExpLinkNode.java deleted file mode 100644 index f970d67..0000000 --- a/src/main/java/org/pegdown/ast/ExpLinkNode.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class ExpLinkNode extends SuperNode { - public final String url; - public final String title; - - public ExpLinkNode(String title, String url, Node child) { - super(child); - this.url = url; - this.title = title; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/HeaderNode.java b/src/main/java/org/pegdown/ast/HeaderNode.java deleted file mode 100644 index 1de5b5e..0000000 --- a/src/main/java/org/pegdown/ast/HeaderNode.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -import org.parboiled.common.Preconditions; - -public class HeaderNode extends SuperNode { - private final int level; - - public HeaderNode(int level, Node child) { - super(child); - this.level = level; - } - - public HeaderNode(int level) { - Preconditions.checkState(1 <= level && level <= 6); - this.level = level; - } - - public int getLevel() { - return level; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/HtmlBlockNode.java b/src/main/java/org/pegdown/ast/HtmlBlockNode.java deleted file mode 100644 index cc8beec..0000000 --- a/src/main/java/org/pegdown/ast/HtmlBlockNode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class HtmlBlockNode extends TextNode { - - public HtmlBlockNode(String text) { - super(text); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/InlineHtmlNode.java b/src/main/java/org/pegdown/ast/InlineHtmlNode.java deleted file mode 100644 index 81499c6..0000000 --- a/src/main/java/org/pegdown/ast/InlineHtmlNode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class InlineHtmlNode extends TextNode { - - public InlineHtmlNode(String text) { - super(text); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/ListItemNode.java b/src/main/java/org/pegdown/ast/ListItemNode.java deleted file mode 100644 index e9bef68..0000000 --- a/src/main/java/org/pegdown/ast/ListItemNode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class ListItemNode extends SuperNode { - - public ListItemNode(Node child) { - super(child); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/MailLinkNode.java b/src/main/java/org/pegdown/ast/MailLinkNode.java deleted file mode 100644 index eff2e3a..0000000 --- a/src/main/java/org/pegdown/ast/MailLinkNode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class MailLinkNode extends TextNode { - - public MailLinkNode(String text) { - super(text); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/Node.java b/src/main/java/org/pegdown/ast/Node.java deleted file mode 100644 index 55f9eb8..0000000 --- a/src/main/java/org/pegdown/ast/Node.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -import org.parboiled.trees.GraphNode; - -public interface Node extends GraphNode { - - /** - * @return the index of the first character in the underlying buffer that is covered by this node - */ - int getStartIndex(); - - /** - * @return the index of the character after the last one in the underlying buffer that is covered by this node - */ - int getEndIndex(); - - void accept(Visitor visitor); -} diff --git a/src/main/java/org/pegdown/ast/OrderedListNode.java b/src/main/java/org/pegdown/ast/OrderedListNode.java deleted file mode 100644 index 8df1588..0000000 --- a/src/main/java/org/pegdown/ast/OrderedListNode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class OrderedListNode extends SuperNode { - - public OrderedListNode(Node child) { - super(child); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/ParaNode.java b/src/main/java/org/pegdown/ast/ParaNode.java deleted file mode 100644 index 66a1f43..0000000 --- a/src/main/java/org/pegdown/ast/ParaNode.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -import java.util.List; - -public class ParaNode extends SuperNode { - - public ParaNode(Node child) { - super(child); - } - - public ParaNode(List children) { - super(children); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} diff --git a/src/main/java/org/pegdown/ast/QuotedNode.java b/src/main/java/org/pegdown/ast/QuotedNode.java deleted file mode 100644 index d6c0ab3..0000000 --- a/src/main/java/org/pegdown/ast/QuotedNode.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class QuotedNode extends SuperNode { - public enum Type { DoubleAngle, Double, Single } - - private final Type type; - - public QuotedNode(Type type) { - this.type = type; - } - - public Type getType() { - return type; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/RefImageNode.java b/src/main/java/org/pegdown/ast/RefImageNode.java deleted file mode 100644 index c06087e..0000000 --- a/src/main/java/org/pegdown/ast/RefImageNode.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class RefImageNode extends SuperNode { - public final String separatorSpace; - public final SuperNode referenceKey; - - public RefImageNode(SuperNode referenceKey, String separatorSpace, Node child) { - super(child); - this.separatorSpace = separatorSpace; - this.referenceKey = referenceKey; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/RefLinkNode.java b/src/main/java/org/pegdown/ast/RefLinkNode.java deleted file mode 100644 index 269246d..0000000 --- a/src/main/java/org/pegdown/ast/RefLinkNode.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class RefLinkNode extends SuperNode { - public final String separatorSpace; - public final SuperNode referenceKey; - - public RefLinkNode(SuperNode referenceKey, String separatorSpace, Node child) { - super(child); - this.separatorSpace = separatorSpace; - this.referenceKey = referenceKey; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/ReferenceNode.java b/src/main/java/org/pegdown/ast/ReferenceNode.java deleted file mode 100644 index 5422d3c..0000000 --- a/src/main/java/org/pegdown/ast/ReferenceNode.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class ReferenceNode extends SuperNode { - private String url; - private String title; - - public ReferenceNode(Node child) { - super(child); - } - - public String getUrl() { - return url; - } - - public boolean setUrl(String url) { - this.url = url; - return true; - } - - public String getTitle() { - return title; - } - - public boolean setTitle(String title) { - this.title = title; - return true; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/RootNode.java b/src/main/java/org/pegdown/ast/RootNode.java deleted file mode 100644 index fce5fe4..0000000 --- a/src/main/java/org/pegdown/ast/RootNode.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -import org.parboiled.common.ImmutableList; - -import java.util.List; - -import static org.parboiled.common.Preconditions.checkArgNotNull; - -public class RootNode extends SuperNode { - private List references = ImmutableList.of(); - private List abbreviations = ImmutableList.of(); - - public List getReferences() { - return references; - } - - public void setReferences(List references) { - checkArgNotNull(references, "references"); - this.references = references; - } - - public List getAbbreviations() { - return abbreviations; - } - - public void setAbbreviations(List abbreviations) { - checkArgNotNull(abbreviations, "abbreviations"); - this.abbreviations = abbreviations; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} diff --git a/src/main/java/org/pegdown/ast/SimpleNode.java b/src/main/java/org/pegdown/ast/SimpleNode.java deleted file mode 100644 index 6621e90..0000000 --- a/src/main/java/org/pegdown/ast/SimpleNode.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -import org.parboiled.common.ImmutableList; - -import java.util.List; - -public class SimpleNode extends AbstractNode { - public enum Type { Apostrophe, Ellipsis, Emdash, Endash, HRule, Linebreak, Nbsp } - - private final Type type; - - public SimpleNode(Type type) { - this.type = type; - } - - public Type getType() { - return type; - } - - public List getChildren() { - return ImmutableList.of(); - } - - public void accept(Visitor visitor) { - visitor.visit(this); - } - - @Override - public String toString() { - return super.toString() + " " + type; - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/SpecialTextNode.java b/src/main/java/org/pegdown/ast/SpecialTextNode.java deleted file mode 100644 index 9e158b0..0000000 --- a/src/main/java/org/pegdown/ast/SpecialTextNode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class SpecialTextNode extends TextNode { - - public SpecialTextNode(String text) { - super(text); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/StrongNode.java b/src/main/java/org/pegdown/ast/StrongNode.java deleted file mode 100644 index 925ff03..0000000 --- a/src/main/java/org/pegdown/ast/StrongNode.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -import java.util.List; - -public class StrongNode extends SuperNode { - - public StrongNode(List children) { - super(children); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/SuperNode.java b/src/main/java/org/pegdown/ast/SuperNode.java deleted file mode 100644 index 1f62124..0000000 --- a/src/main/java/org/pegdown/ast/SuperNode.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -import java.util.ArrayList; -import java.util.List; - -public class SuperNode extends AbstractNode { - private final List children = new ArrayList(); - - public SuperNode() { - } - - public SuperNode(Node child) { - children.add(child); - } - - public SuperNode(List children) { - this.children.addAll(children); - } - - public List getChildren() { - return children; - } - - public void accept(Visitor visitor) { - visitor.visit(this); - } - -} diff --git a/src/main/java/org/pegdown/ast/TableBodyNode.java b/src/main/java/org/pegdown/ast/TableBodyNode.java deleted file mode 100644 index 05fa1b4..0000000 --- a/src/main/java/org/pegdown/ast/TableBodyNode.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class TableBodyNode extends SuperNode { - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/TableCaptionNode.java b/src/main/java/org/pegdown/ast/TableCaptionNode.java deleted file mode 100644 index 96b21fa..0000000 --- a/src/main/java/org/pegdown/ast/TableCaptionNode.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class TableCaptionNode extends SuperNode { - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/TableCellNode.java b/src/main/java/org/pegdown/ast/TableCellNode.java deleted file mode 100644 index 2092408..0000000 --- a/src/main/java/org/pegdown/ast/TableCellNode.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class TableCellNode extends SuperNode { - private int colSpan; - - public int getColSpan() { - return colSpan; - } - - public boolean setColSpan(int colSpan) { - this.colSpan = colSpan; - return true; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/TableColumnNode.java b/src/main/java/org/pegdown/ast/TableColumnNode.java deleted file mode 100644 index 218981e..0000000 --- a/src/main/java/org/pegdown/ast/TableColumnNode.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class TableColumnNode extends SuperNode { - public enum Alignment { None, Left, Right, Center } - - private Alignment alignment = Alignment.None; - - public boolean markLeftAligned() { - alignment = alignment == Alignment.Right ? Alignment.Center : Alignment.Left; - return true; - } - - public boolean markRightAligned() { - alignment = alignment == Alignment.Left ? Alignment.Center : Alignment.Right; - return true; - } - - public Alignment getAlignment() { - return alignment; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/TableHeaderNode.java b/src/main/java/org/pegdown/ast/TableHeaderNode.java deleted file mode 100644 index ed664d9..0000000 --- a/src/main/java/org/pegdown/ast/TableHeaderNode.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class TableHeaderNode extends SuperNode { - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/TableNode.java b/src/main/java/org/pegdown/ast/TableNode.java deleted file mode 100644 index a7376b0..0000000 --- a/src/main/java/org/pegdown/ast/TableNode.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -import org.parboiled.common.ImmutableList; - -import java.util.List; - -public class TableNode extends SuperNode { - private ImmutableList columns = ImmutableList.of(); - - public List getColumns() { - return columns; - } - - public boolean addColumn(TableColumnNode columnNode) { - columns = columns.append(columnNode); - return true; - } - - public boolean hasTwoOrMoreDividers() { - return columns != null && columns.size() > 1; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/TableRowNode.java b/src/main/java/org/pegdown/ast/TableRowNode.java deleted file mode 100644 index 4b255a3..0000000 --- a/src/main/java/org/pegdown/ast/TableRowNode.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class TableRowNode extends SuperNode { - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/TextNode.java b/src/main/java/org/pegdown/ast/TextNode.java deleted file mode 100644 index 9337069..0000000 --- a/src/main/java/org/pegdown/ast/TextNode.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -import org.parboiled.common.ImmutableList; -import org.parboiled.common.StringUtils; - -import java.util.List; - -public class TextNode extends AbstractNode { - private final StringBuilder sb; - - public TextNode(String text) { - this.sb = new StringBuilder(text); - } - - public String getText() { - return sb.toString(); - } - - public void append(String text) { - sb.append(text); - } - - @Override - public String toString() { - return super.toString() + " '" + StringUtils.escape(getText()) + '\''; - } - - public List getChildren() { - return ImmutableList.of(); - } - - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/VerbatimNode.java b/src/main/java/org/pegdown/ast/VerbatimNode.java deleted file mode 100644 index 638a2a6..0000000 --- a/src/main/java/org/pegdown/ast/VerbatimNode.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class VerbatimNode extends TextNode { - - private final String type; - - public VerbatimNode(String text) { - this(text, ""); - } - - public VerbatimNode(String text, String type) { - super(text); - this.type = type; - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } - - public String getType() { - return type; - } -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/Visitor.java b/src/main/java/org/pegdown/ast/Visitor.java deleted file mode 100644 index b103da9..0000000 --- a/src/main/java/org/pegdown/ast/Visitor.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public interface Visitor { - void visit(AbbreviationNode node); - void visit(AutoLinkNode node); - void visit(BlockQuoteNode node); - void visit(BulletListNode node); - void visit(CodeNode node); - void visit(DefinitionListNode node); - void visit(DefinitionNode node); - void visit(DefinitionTermNode node); - void visit(EmphNode node); - void visit(ExpImageNode node); - void visit(ExpLinkNode node); - void visit(HeaderNode node); - void visit(HtmlBlockNode node); - void visit(InlineHtmlNode node); - void visit(ListItemNode node); - void visit(MailLinkNode node); - void visit(OrderedListNode node); - void visit(ParaNode node); - void visit(QuotedNode node); - void visit(ReferenceNode node); - void visit(RefImageNode node); - void visit(RefLinkNode node); - void visit(RootNode node); - void visit(SimpleNode node); - void visit(SpecialTextNode node); - void visit(StrongNode node); - void visit(TableBodyNode node); - void visit(TableCaptionNode node); - void visit(TableCellNode node); - void visit(TableColumnNode node); - void visit(TableHeaderNode node); - void visit(TableNode node); - void visit(TableRowNode node); - void visit(VerbatimNode node); - void visit(WikiLinkNode node); - - void visit(TextNode node); - void visit(SuperNode node); - void visit(Node node); // general catch all for custom Node implementations -} \ No newline at end of file diff --git a/src/main/java/org/pegdown/ast/WikiLinkNode.java b/src/main/java/org/pegdown/ast/WikiLinkNode.java deleted file mode 100644 index 6d54327..0000000 --- a/src/main/java/org/pegdown/ast/WikiLinkNode.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown.ast; - -public class WikiLinkNode extends TextNode { - - public WikiLinkNode(String text) { - super(text); - } - - @Override - public void accept(Visitor visitor) { - visitor.visit(this); - } -} \ No newline at end of file diff --git a/src/main/scala/org/pegdown/AbbrevationHtml.scala b/src/main/scala/org/pegdown/AbbrevationHtml.scala new file mode 100644 index 0000000..3748fac --- /dev/null +++ b/src/main/scala/org/pegdown/AbbrevationHtml.scala @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2013 Bernhard Berger + * + * Based on pegdown (C) 2010-2011 Mathias Doenitz and + * peg-markdown (C) 2008-2010 John MacFarlane. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.pegdown + +trait AbbrevationHtml { + + val root: RootNode + def nodeToHtml(node: Node): String + + def expandAbbreviations(html: String): String = allAbbreviationNodes(root) match { + case Nil => html + case xs: List[AbbreviationNode] => + xs.foldLeft(html){(text, node) => expandAbbreviation(text, node)} + } + + private def expandAbbreviation(html: String, node: AbbreviationNode): String = { + val nodeText = nodeToHtml(node.child) + val indicesToExpand = findAllIndicesToExpand(html, nodeText) + val expansion = nodeToHtml(node.expansion) + expandAbbreviation(html, indicesToExpand, nodeText, expansion, 0) + } + + def findAllIndicesToExpand(html: String, searchText: String): List[Int] = + if(searchText.isEmpty) + Nil + else + findAll(html, searchText).filter(x => + !isTag(html, x) && isWholeWord(html, x, x + searchText.length - 1) + ) + + private def expandAbbreviation(html: String, replaceIndices: List[Int], searchText: String, + expansion: String, fromIndex: Int): String = replaceIndices match { + case x :: xs => + html.substring(fromIndex, x) + + expansionToHtml(searchText, expansion) + + expandAbbreviation(html, xs, searchText, expansion, x + searchText.length) + case Nil => html.substring(fromIndex) + } + + /** Generate an abbr-HTML tag from an expansion. */ + private def expansionToHtml(abbr: String, title: String): String = + "" + abbr + "" + + /** Find all whole words of the searchText in the wholeText. */ + def findAll(wholeText: String, searchText: String, fromIndex: Int = 0): List[Int] = + wholeText.indexOf(searchText, fromIndex) match { + case -1 => Nil + case n: Int => n :: findAll(wholeText, searchText, n + 1) + } + + private def allAbbreviationNodes(node: Node): List[AbbreviationNode] = node match { + case n: AbbreviationNode => n :: Nil + case n: SuperNode => n.children.flatMap(allAbbreviationNodes(_)) + case _ => Nil + } + + /** Returns true, if the index is inside an HTML tag. */ + def isTag(html: String, index: Int): Boolean = + html.charAt(index) == '<' || + html.substring(index).find(x => (x == '<' || x == '>')) == Some('>') + + /** Returns true, if the given range isn't only a part of a word. */ + def isWholeWord(html: String, beginIndex: Int, endIndex: Int): Boolean = + ((beginIndex == 0 || !Character.isLetterOrDigit(html.charAt(beginIndex - 1)))) && + ((endIndex == html.length - 1) || !Character.isLetterOrDigit(html.charAt(endIndex + 1))) +} \ No newline at end of file diff --git a/src/main/scala/org/pegdown/FastEncoder.scala b/src/main/scala/org/pegdown/FastEncoder.scala new file mode 100644 index 0000000..d6aebff --- /dev/null +++ b/src/main/scala/org/pegdown/FastEncoder.scala @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2013 Bernhard Berger + * + * Based on pegdown (C) 2010-2011 Mathias Doenitz and + * peg-markdown (C) 2008-2010 John MacFarlane. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.pegdown + +import scala.util.Random + +/** + * Holds simple HTML encoding logic. + * Maybe despites it's name now not so fast as the Java FastEncoder. + */ +object FastEncoder { + + def encode(string: String): String = string.map(c => encode(c)).mkString + + def encode(c: Char): String = c match { + case '&' => "&" + case '<' => "<" + case '>' => ">" + case '"' => """ + case '\'' => "'" + case _ => c.toString + } + + private val random = new Random(0x2626); + + def obfuscate(email: String): String = { + email.map(c => random.nextInt(5) match { + case 0 | 1 => "&#" + c.toInt.toString + ";" + case 2 | 3 => "&#x" + c.toInt.toHexString + ";" + case _ => encode(c) + }).mkString + } + +} \ No newline at end of file diff --git a/src/main/scala/org/pegdown/LinkRenderer.scala b/src/main/scala/org/pegdown/LinkRenderer.scala new file mode 100644 index 0000000..09222ee --- /dev/null +++ b/src/main/scala/org/pegdown/LinkRenderer.scala @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 Bernhard Berger + * + * Based on pegdown (C) 2010-2011 Mathias Doenitz and + * peg-markdown (C) 2008-2010 John MacFarlane. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.pegdown + +import java.net.URLEncoder + +object LinkRenderer { + + def render(node: Node, htmlRender: ToHtmlSerializer, refNode: ReferenceNode = null): LinkRenderer = node match { + case n: AutoLinkNode => LinkRenderer(n.text, n.text) + case n: ExpLinkNode => LinkRenderer(n.url, htmlRender.nodeToHtml(n.children), title(n.title)) + case n: MailLinkNode => { + val obfuscated = FastEncoder.obfuscate(n.text) + LinkRenderer("mailto:" + obfuscated, obfuscated) + } + case n: RefLinkNode => LinkRenderer(refNode.url, htmlRender.nodeToHtml(n.children), title(refNode.title.getOrElse(""))) + case n: WikiLinkNode => { + val url = "./" + URLEncoder.encode(n.text.replace(' ', '-'), "UTF-8") + ".html" + LinkRenderer(url, n.text) + } + case _ => throw new IllegalArgumentException("Unknown node " + node) + } + + private def title(text: String): List[Attribute] = + if(text.isEmpty) + Nil + else + Attribute("title", FastEncoder.encode(text)) :: Nil + +} + +case class LinkRenderer(href: String, text: String, attributes: List[Attribute] = Nil) + +object Attribute { + val noFollow = Attribute("rel", "nofollow") +} + +case class Attribute(name: String, value: String) + diff --git a/src/main/scala/org/pegdown/Main.scala b/src/main/scala/org/pegdown/Main.scala new file mode 100644 index 0000000..8f17442 --- /dev/null +++ b/src/main/scala/org/pegdown/Main.scala @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 Bernhard Berger + * + * Based on pegdown (C) 2010-2011 Mathias Doenitz and + * peg-markdown (C) 2008-2010 John MacFarlane. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.pegdown + +import scala.io.Source + +object Main extends App { + + if(args.isEmpty || args.head == "--help") { + println("pegdownScala - A markdown processor written in Scala.\n" + + "Usage: pegdownScala ") + } else { + val startTime = System.currentTimeMillis + args.map(markdownFileToHtml) + val time = System.currentTimeMillis - startTime +// println("Time: " + time + "ms") + } + + def markdownFileToHtml(filename: String) = { + val source = Source.fromFile(filename).mkString + val html = ToHtmlSerializer(source) + println(html) + } + +} diff --git a/src/main/scala/org/pegdown/MarkdownParser.scala b/src/main/scala/org/pegdown/MarkdownParser.scala new file mode 100644 index 0000000..062653d --- /dev/null +++ b/src/main/scala/org/pegdown/MarkdownParser.scala @@ -0,0 +1,712 @@ +/* + * Copyright (C) 2013 Bernhard Berger + * + * Based on pegdown (C) 2010-2011 Mathias Doenitz and + * peg-markdown (C) 2008-2010 John MacFarlane. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.pegdown + +import org.parboiled.scala._ +import org.parboiled.errors._ +import org.parboiled._ + +object MarkdownParser { + lazy val noExtensions = new MarkdownParser(MarkdownParserConfiguration.noExtensions) + lazy val allExtensions = new MarkdownParser(MarkdownParserConfiguration.allExtensions) + lazy val commonExtensions = new MarkdownParser(MarkdownParserConfiguration.commonExtensions) + lazy val allWithoutHardwraps = new MarkdownParser(MarkdownParserConfiguration.allWithoutHardwraps) +} + +class MarkdownParser(val config: MarkdownParserConfiguration) extends Parser { + + override val buildParseTree = config.buildParseTree + + private def parseInternal(source: String): RootNode = { + val parsingResult = ReportingParseRunner(Root).run(source + "\n\n") + + parsingResult.result match { + case Some(astRoot) => astRoot + case None => throw new ParsingException("Invalid Markdown:\n" + ErrorUtils.printParseErrors(parsingResult)) + } + } + + /** Used together with the ~~% operator to drop an element from the value stack. */ + def drop(node: Any) = { + // Do nothing + } + + /** Always fails, but has the type to return an Node. Used for parser extensions. */ + def Fail: Rule1[Node] = rule { NOTHING ~> TextNode } + + //************* BLOCKS **************** + + def Root: Rule1[RootNode] = rule { zeroOrMore(Block) ~~> RootNode } + + def Block: Rule1[Node] = rule { + zeroOrMore(BlankLine) ~ + ( + BlockQuote | Verbatim | + (if(config.abbreviations) Abbreviation else Fail) | + Reference | HorizontalRule | Heading | OrderedList | BulletList | HtmlBlock | + (if(config.tables) Table else Fail) | + (if(config.definitions) DefinitionList else Fail) | + (if(config.fencedCodeBlocks) FencedCodeBlock else Fail) | + Para | Inlines + ) } + + def BlockQuote: Rule1[BlockQuoteNode] = rule { + oneOrMore( + ">" ~ optional(" ") ~ Line ~ + zeroOrMore(!(">") ~ !(BlankLine) ~ Line) ~ + zeroOrMore(BlankLine ~> (_.toString)) ~~> + ((x: String, ys: List[String], zs: List[String]) => x :: ys ::: zs) + ) ~~> + // trigger a recursive parsing run on the inner source we just built + // and attach the root of the inner parses Node + ((xs: List[List[String]]) => BlockQuoteNode(parseInternal(xs.flatten.mkString("\n")).children)) + } + + def Verbatim: Rule1[VerbatimNode] = rule { + oneOrMore( + zeroOrMore(BlankLine ~ push("")) ~ + Indent ~ oneOrMore(NotNewline ~ ANY) ~> (_.toString) ~ Newline ~~> + ((xs: List[String], y: String) => xs ::: tabsToSpaces(y) :: Nil) + ) ~~> ((xs: List[List[String]]) => VerbatimNode(xs.flatten.mkString("\n"), None)) + } + + /** Replace all tabs with 1 to 4 spaces. */ + private def tabsToSpaces(string: String): String = tabsToSpaces(0, string.split("\t").toList).mkString + + private def tabsToSpaces(beginIndex: Int, notExpanded: List[String]): List[String] = notExpanded match { + case x :: Nil => notExpanded + case x :: xs => { + val currentIndex = beginIndex + x.length + val spacesCount = 4 - currentIndex % 4 + x + " " * spacesCount :: tabsToSpaces(currentIndex + spacesCount, xs) + } + case Nil => Nil + } + + def FencedCodeBlock: Rule1[VerbatimNode] = rule { + CodeFence ~ + optional(oneOrMore(!(Newline) ~ ANY) ~> (_.toString)) ~ // GFM code type identifier + Newline ~ + !(CodeFence) ~ // prevent empty matches + zeroOrMore(BlankLine ~ push("")) ~ // lines: List[String] + oneOrMore(!(Newline ~ CodeFence) ~ ANY) ~> (_.toString) ~ + Newline ~~> + ((language: Option[String], xs: List[String], y: String) => VerbatimNode(tabsToSpaces(xs.mkString("\n") + y), language)) ~ + CodeFence + } + + def CodeFence: Rule0 = rule { ("~~~" ~ zeroOrMore("~")) | ("```" ~ zeroOrMore("`")) } + + def Para: Rule1[ParaNode] = rule { NonindentSpace ~ Inlines ~~> ParaNode ~ oneOrMore(BlankLine)} + + def HorizontalRule: Rule1[SimpleNodeHRule] = rule { + NonindentSpace ~ + (HorizontalRule("*") | HorizontalRule("-") | HorizontalRule("_")) ~ + Sp ~ Newline ~ oneOrMore(BlankLine) ~ + push(SimpleNodeHRule()) + } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def HorizontalRule(character: String): Rule0 = { + character ~ Sp ~ character ~ Sp ~ character ~ zeroOrMore(Sp, character) + } + + //************* HEADINGS **************** + + def Heading: Rule1[HeaderNode] = rule { AtxHeading | SetextHeading } + + def AtxHeading: Rule1[HeaderNode] = rule { + AtxStart ~ optional(Sp) ~ oneOrMore(AtxInline) ~~> ((level, children) => HeaderNode(level, children)) ~ optional(Sp ~ zeroOrMore("#") ~ Sp) ~ Newline + } + + def AtxStart: Rule1[Int] = rule { ("######" | "#####" | "####" | "###" | "##" | "#") ~> (_.length) } + + def AtxInline: Rule1[Node] = rule { + !Newline ~ !(optional(Sp) ~ zeroOrMore("#") ~ Sp ~ Newline) ~ Inline + } + + def SetextHeading: Rule1[HeaderNode] = rule { + // test for successful setext heading before actually building it to reduce backtracking + &(oneOrMore(NotNewline ~ ANY) ~ Newline ~ (("===" ~ zeroOrMore("=")) | ("---" ~ zeroOrMore("-"))) ~ Newline) ~ + (SetextHeading1 | SetextHeading2) + } + + def SetextHeading1: Rule1[HeaderNode] = rule { + oneOrMore(SetextInline) ~ Newline ~ "===" ~ zeroOrMore("=") ~ Newline ~~> (c => HeaderNode(1, c)) + } + + def SetextHeading2: Rule1[HeaderNode] = rule { + oneOrMore(SetextInline) ~ Newline ~ "---" ~ zeroOrMore("-") ~ Newline ~~> (c => HeaderNode(2, c)) + } + + def SetextInline = rule { + !(Endline) ~ Inline + } + + //************** Definition Lists ************ + + def DefinitionList: Rule1[DefinitionListNode] = rule { + // test for successful definition list match before actually building it to reduce backtracking + !(Spacechar) ~ + &(oneOrMore(!(BlankLine) ~ !(DefListBullet) ~ oneOrMore(NotNewline ~ ANY) ~ Newline) ~ + optional(BlankLine) ~ DefListBullet + ) ~ + oneOrMore( + oneOrMore(DefListTerm) ~ + oneOrMore(Definition) ~ + optional(BlankLine) ~~> ((xs: List[DefinitionTermNode], ys: List[DefinitionNode]) => xs ::: ys) + ) ~~> ((xs: List[List[Node]]) => DefinitionListNode(xs.flatten)) + } + + def DefListTerm: Rule1[DefinitionTermNode] = rule { + !(Spacechar) ~ !(DefListBullet) ~ + oneOrMore(DefTermInline) ~~> (DefinitionTermNode(_)) ~ + optional(":") ~ Newline + } + + def DefTermInline: Rule1[Node] = rule { NotNewline ~ !(":" ~ Newline) ~ Inline } + + def Definition: Rule1[DefinitionNode] = rule { ListItem(DefListBullet, false) ~~> (x => DefinitionNode(x.children))} + + def DefListBullet: Rule0 = rule { NonindentSpace ~ anyOf(":~") ~ oneOrMore(Spacechar) } + + //************* LISTS **************** + + def BulletList: Rule1[BulletListNode] = rule { + ListItem(Bullet, true) ~ zeroOrMore(ListItem(Bullet, false)) ~ zeroOrMore(BlankLine) ~~> + ((x: ListItemNode, ys: List[ListItemNode]) => BulletListNode(x :: ys)) + } + + def OrderedList: Rule1[OrderedListNode] = rule { + ListItem(Enumerator, true) ~ zeroOrMore(ListItem(Enumerator, false)) ~ zeroOrMore(BlankLine) ~~> + ((x: ListItemNode, ys: List[ListItemNode]) => OrderedListNode(x :: ys)) + } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def ListItem(itemStart: Rule0, isFirstItem: Boolean): Rule1[ListItemNode] = { + // for a simpler parser design we use a recursive parsing strategy for list items: + // we collect a number of markdown source blocks for an item, run complete parsing cycle on these and attach + // the roots of the inner parsing results Node to the outer Node tree + optional(BlankLine ~ push(false)) ~ // tight Boolean + itemStart ~ Line ~ // block String = first line of the list item + zeroOrMore(optional(Indent) ~ NotItem ~ Line) ~ // temp List[String] = first paragraph of the list item, excluding the first line + zeroOrMore(optional(BlankLine ~ push(false)) ~ Indent ~ (DoubleIndentedBlocks | IndentedBlock)) ~ // List[(Option[Boolean], String) + optional(&(oneOrMore(BlankLine) ~ itemStart) ~ push(false)) ~~> // tight after + ((tightBefore: Option[Boolean], x: String, ys: List[String], zs: List[(Option[Boolean], String)], tightAfter: Option[Boolean]) => { + val firstParagraph = (x :: ys).mkString("\n") + val allParagraphs = firstParagraph :: zs.unzip._2 + val internalNodes = parseInternal(allParagraphs.mkString("\n\n")).children + + val itemContainsBlanklines = zs.exists(_._1 == Some(false)) + val tight = !itemContainsBlanklines && ((!isFirstItem && tightBefore.getOrElse(true)) || (isFirstItem && tightAfter.getOrElse(true))) + val itemChildren = if(tight) removeHeadParagraph(internalNodes) else internalNodes // Remove the paragraph from tight lists + + ListItemNode(itemChildren) + }) + } + + /** + * Removes a paragraph at the head of a nodes list. + * If no paragraph exists, the same node list is returned. + */ + def removeHeadParagraph(nodes: List[Node]): List[Node] = nodes.head match { + // A Newline is added to the SuperNode to support the tests from other Markdown parsers. + case n: ParaNode => new SuperNode(n.children ::: TextNode("\n") :: Nil) :: nodes.tail + case _ => nodes + } + + def DoubleIndentedBlocks: Rule1[String] = rule { + Indent ~ !(BlankLine) ~ Line ~ // String + zeroOrMore( + zeroOrMore(BlankLine ~ (push(""))) ~ + Indent ~ Indent ~ Line ~~> + ((xs: List[String], y: String) => (xs ::: (" " + y) :: Nil)) + ) ~~> // List[List[String]] + ((x: String, ys: List[List[String]]) => " " + (x :: ys.flatten).mkString("\n")) + } + + def IndentedBlock: Rule1[String] = rule { + Line ~ + zeroOrMore( + ((!(BlankLine) ~ Indent) | NotItem) ~ Line + ) ~~> + ((x: String, xs: List[String]) => (x :: xs).mkString("\n")) + } + + def NotItem: Rule0 = rule { + !(Bullet | Enumerator | BlankLine | (HorizontalRule ~~% (drop(_))) | ((if(config.definitions) DefinitionList else Fail) ~~% (drop(_)))) + } + + def Enumerator: Rule0 = rule { NonindentSpace ~ oneOrMore(Digit) ~ "." ~ oneOrMore(Spacechar) } + + def Bullet: Rule0 = rule { !(HorizontalRule) ~ NonindentSpace ~ anyOf("+*-") ~ oneOrMore(Spacechar) } + + //************* HTML BLOCK **************** + + def HtmlBlock: Rule1[HtmlBlockNode] = rule { + (HtmlTagBlockAnyTag | HtmlComment | HtmlBlockSelfClosing) ~> + (s => HtmlBlockNode(if(config.supressHtmlBlocks) "" else s)) ~ + oneOrMore(BlankLine) + } + + def HtmlTagBlockAnyTag: Rule0 = rule { + val tags = List( + "address", "blockquote", "center", "dd", "dir", "div", "dl", "dt", "fieldset", "form", "frameset", "h1", + "h2", "h3", "h4", "h5", "h6", "hr", "isindex", "li", "menu", "noframes", "noscript", "ol", "p", "pre", + "script", "style", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "ul") + + &("<") ~ + tags.map(HtmlTagBlock(_)).reduce(_ | _) + } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def HtmlTagBlock(tagName: String): Rule0 = { + HtmlBlockOpen(tagName) ~ + zeroOrMore( /* HtmlTagBlock(tagName) | */ // This doesn't work because we cannot use `rule` + (!(HtmlBlockClose(tagName)) ~ ANY)) ~ + HtmlBlockClose(tagName) + } + + def HtmlBlockSelfClosing: Rule0 = rule { + "<" ~ Spn1 ~ HtmlBlockTagName ~ Spn1 ~ zeroOrMore(HtmlAttribute) ~ optional("/") ~ Spn1 ~ ">" + } + + def HtmlBlockOpenAnyTag: Rule1[String] = rule { + "<" ~ Spn1 ~ (HtmlBlockTagName ~> (x => {println(s"Open: $x"); x.toString})) ~ Spn1 ~ zeroOrMore(HtmlAttribute) ~ ">" ~ run(println("HtmlBlockOpenAnyTag: done")) + } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def HtmlBlockOpen(tagName: String): Rule0 = { + "<" ~ Spn1 ~ tagName ~ Spn1 ~ zeroOrMore(HtmlAttribute) ~ ">" + } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def HtmlBlockClose(tagName: String): Rule0 = { + "<" ~ Spn1 ~ "/" ~ tagName ~ Spn1 ~ ">" + } + + def HtmlBlockTagName: Rule0 = rule { + "address" | "blockquote" | "center" | "dd" | "dir" | "div" | "dl" | "dt" | "fieldset" | "form" | "frameset" | "h1" | + "h2" | "h3" | "h4" | "h5" | "h6" | "hr" | "isindex" | "li" | "menu" | "noframes" | "noscript" | "ol" | "p" | "pre" | + "script" | "style" | "table" | "tbody" | "td" | "tfoot" | "th" | "thead" | "tr" | "ul" + } + + //************* INLINES **************** + + def Inlines: Rule1[SuperNode] = rule { + oneOrMore(InlineOrIntermediateEndline) ~~> (new SuperNode(_)) ~ optional(Endline ~~% drop _) + } + + def InlineOrIntermediateEndline: Rule1[Node] = rule { + (!(Endline) ~ Inline) | (Endline ~ &(Inline)) + } + + def Inline: Rule1[Node] = rule(MemoMismatches) { Link | NonLinkInline } + + def NonAutoLinkInline = rule { NonAutoLink | NonLinkInline } + + def NonLinkInline: Rule1[Node] = rule { + Str | Endline | UlOrStarLine | Space | StrongOrEmph | Image | Code | InlineHtml | Entity | EscapedChar | + (if(config.quotes) (SingleQuoted | DoubleQuoted | DoubleAngleQuoted) else Fail) | + (if(config.smarts) Smarts else Fail) | + Symbol + } + + def Endline: Rule1[Node] = rule(MemoMismatches) { + (LineBreak | TerminalEndline | NormalEndline) + } + + def LineBreak: Rule1[SimpleNodeLinebreak] = rule { + " " ~ NormalEndline ~~> (x => SimpleNodeLinebreak()) + } + + def TerminalEndline: Rule1[TextNode] = rule { Sp ~ Newline ~ &(EOI) ~ push(TextNode("\n"))} + + def NormalEndline: Rule1[Node] = rule { + Sp ~ Newline ~ !( + BlankLine | ">" | (AtxStart ~~% drop _) | (zeroOrMore(NotNewline, ANY) ~ Newline ~ + ("===" ~ zeroOrMore("=")) | + ("---" ~ zeroOrMore("-")) | + Newline) + ) ~ push(if(config.hardwraps) SimpleNodeLinebreak() else TextNode(" ")) + } + + //************* EMPHASIS / STRONG **************** + + def UlOrStarLine: Rule1[TextNode] = rule(MemoMismatches) { (CharLine("_") | CharLine("*")) ~> TextNode } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def CharLine(char: String): Rule0 = {((char * 4) ~ zeroOrMore(char)) | (Spacechar ~ oneOrMore(char) ~ &(Spacechar))} + + def StrongOrEmph: Rule1[SuperNode] = rule { + &(anyOf("*_")) ~ (Strong | Emph) + } + + def Emph: Rule1[EmphNode] = rule { + (EmphOrStrong("*") | EmphOrStrong("_")) ~~> EmphNode + } + + def Strong: Rule1[StrongNode] = rule { + (EmphOrStrong("__") | EmphOrStrong("**")) ~~> StrongNode + } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def EmphOrStrong(chars: String): Rule1[List[Node]] = { + EmphOrStrongOpen(chars) ~ + oneOrMore(!(EmphOrStrongClose(chars)) ~ Inline) ~ + EmphOrStrongClose(chars) + } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def EmphOrStrongOpen(chars: String): Rule0 = { !(CharLine(chars.head.toString)) ~ chars ~ !(Spacechar) ~ NotNewline } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def EmphOrStrongClose(chars: String): Rule0 = { !(Spacechar) ~ NotNewline ~ chars ~ !(Alphanumeric) } + + //************* LINKS **************** + + def Image: Rule1[Node] = rule { + "!" ~ Label ~ (ExplicitLink(true) | ReferenceLink(true)) + } + + def Link: Rule1[Node] = rule(MemoMismatches) { + (if(config.wikilinks) WikiLink else Fail) | + (Label ~ (ExplicitLink(false) | ReferenceLink(false))) | AutoLink + } + + def NonAutoLink: Rule1[Node] = rule { + Label ~ (ExplicitLink(false) | ReferenceLink(false)) + } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def ExplicitLink(image: Boolean): ReductionRule1[Node, Node] = { + Spn1 ~ "(" ~ Sp ~ LinkSource ~ Spn1 ~ (LinkTitle | push("")) ~ Sp ~ ")" ~~> + ((child: Node, url: String, title: String) => + if(image) ExpImageNode(title, url, child) else ExpLinkNode(title, url, child)) } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def ReferenceLink(image: Boolean): ReductionRule1[Node, Node] = { + ((Spn1 ~> (x => Some(x.toString)) // separatorSpacecOption[String] + ~ (Label | ("[]" ~ push(null))) // referenceKey SuperNode + ) | + (push(None) ~ push(null))) ~~> + ((child: Node, separatorSpace: Option[String], referenceKey: SuperNode) => + if(image) + RefImageNode(Option(referenceKey), separatorSpace, child) + else + RefLinkNode(Option(referenceKey), separatorSpace, child)) + } + + def LinkSource: Rule1[String] = rule { + ("(" ~ LinkSource ~ ")") | + ("<" ~ LinkSource ~ ">") | + ( + oneOrMore( + ("\\" ~ anyOf("()")) ~> (_.toString) | + (!(anyOf("()>")) ~ Nonspacechar ~> (_.toString)) + ) ~~> (_.mkString) + ) | + push("") + } + + def LinkTitle: Rule1[String] = rule { LinkTitle("'") | LinkTitle("\"") } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def LinkTitle(delimiter: String): Rule1[String] = { + delimiter ~ + zeroOrMore(!(delimiter ~ Sp ~ (")" | Newline)) ~ NotNewline ~ ANY) ~> (_.toString) ~ delimiter + } + + def AutoLink: Rule1[Node] = rule { + (if(config.autolinks) optional("<") else str("<")) ~ + (AutoLinkUrl | AutoLinkEmail) ~ + (if(config.autolinks) optional(">") else str(">")) + } + + def WikiLink: Rule1[WikiLinkNode] = rule { "[[" ~ oneOrMore(!"]" ~ ANY) ~> WikiLinkNode ~ "]]" } + + def AutoLinkUrl: Rule1[AutoLinkNode] = rule { + oneOrMore(Letter) ~> (_.toString) ~ + "://" ~ AutoLinkEnd ~> (_.toString) ~~> + ((x: String, y: String) => AutoLinkNode(x + "://" + y)) + } + + def AutoLinkEmail: Rule1[MailLinkNode] = rule { + oneOrMore(Alphanumeric | anyOf("-+_.")) ~> (_.toString) ~ "@" ~ + AutoLinkEnd ~> (_.toString) ~~> + ((x: String, y: String) => MailLinkNode(x + "@" + y)) + } + + def AutoLinkEnd: Rule0 = rule { + oneOrMore(!Newline ~ + !(if(config.autolinks) (">" | optional(anyOf(".,;:)}]\"'")) ~ (Spacechar | Newline)) else str(">")) ~ + ANY + ) + } + + //************* REFERENCE **************** + + def Label: Rule1[SuperNode] = rule { + "[" ~ oneOrMore(!("]") ~ NonAutoLinkInline) ~~> (new SuperNode(_)) ~ "]" + } + + def Reference: Rule1[ReferenceNode] = rule { + NonindentSpace ~ Label ~ + ":" ~ Spn1 ~ RefSrc ~ + Sp ~ optional(RefTitle) ~ + Sp ~ Newline ~ zeroOrMore(BlankLine) ~~> + ((child: SuperNode, src: String, title: Option[String]) => ReferenceNode(title, src, child)) + } + + def RefSrc: Rule1[String] = rule { + ("<" ~ RefSrcContent ~ ">") | RefSrcContent + } + + def RefSrcContent: Rule1[String] = rule { + oneOrMore(!(">") ~ Nonspacechar) ~> (_.toString) + } + + def RefTitle: Rule1[String] = rule { + RefTitle("'", "'") | RefTitle("\"", "\"") | RefTitle("(", ")") + } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def RefTitle(open: String, close: String): Rule1[String] = { + open ~ zeroOrMore(!(close ~ Sp ~ Newline) ~ NotNewline ~ ANY) ~> (_.toString) ~ close + } + + //************* CODE **************** + + // See issue https://github.com/sirthias/parboiled/issues/40 + def Code: Rule1[CodeNode] = rule { + &("`") ~ + (Code(Ticks(1)) | Code(Ticks(2)) | Code(Ticks(3)) | Code(Ticks(4)) | Code(Ticks(5))) + } + + + // See issue https://github.com/sirthias/parboiled/issues/40 + def Code(ticks: Rule0): Rule1[CodeNode] = { + ticks ~ Sp ~ + oneOrMore( + (!("`") ~ Nonspacechar) | + (!(ticks) ~ oneOrMore("`")) | + (!(Sp ~ ticks) ~ (Spacechar | (Newline ~ !(BlankLine)))) + ) ~> (CodeNode(_)) ~ Sp ~ ticks + } + + // See issue https://github.com/sirthias/parboiled/issues/40 + def Ticks(count: Int): Rule0 = { + ("`" * count) ~ !("`") + } + + //************* RAW HTML **************** + + def InlineHtml: Rule1[InlineHtmlNode] = rule { (HtmlComment | HtmlTag) ~> (x => InlineHtmlNode(if(config.supressInlineHtml) "" else x)) } + + def HtmlComment: Rule0 = rule { "") ~ ANY) ~ "-->" } + + def HtmlTag: Rule0 = rule { + "<" ~ Spn1 ~ optional("/") ~ oneOrMore(Alphanumeric) ~ Spn1 ~ zeroOrMore(HtmlAttribute) ~ optional("/") ~ Spn1 ~ ">" + } + + def HtmlAttribute: Rule0 = rule { + oneOrMore(Alphanumeric | "-" | "_") ~ Spn1 ~ optional("=" ~ Spn1 ~ (Quoted | oneOrMore(!(">") ~ Nonspacechar))) ~ Spn1 + } + + def Quoted: Rule0 = rule { + ("\"" ~ zeroOrMore(!("\"") ~ ANY) ~ "\"") | + ("'" ~ zeroOrMore(!("'") ~ ANY) ~ "'") + } + + //************* LINES **************** + + def BlankLine: Rule0 = rule { Sp ~ Newline } + + def Line: Rule1[String] = rule { zeroOrMore(NotNewline ~ ANY) ~> (_.toString) ~ Newline } + + //************* ENTITIES **************** + + def Entity = rule { "&" ~ (HexEntity | DecEntity | CharEntity) ~> (x => TextNode("&" + x + ";")) ~ ";" } + + def HexEntity = rule { "#" ~ ("x" | "X") ~ oneOrMore(Digit | anyOf("abcdefABCDEF")) } + + def DecEntity = rule { "#" ~ oneOrMore(Digit) } + + def CharEntity: Rule0 = rule { oneOrMore(Alphanumeric) } + + //************* BASICS **************** + + def Str = rule { oneOrMore(NormalChar) ~> TextNode } + + def Space = rule { oneOrMore(Spacechar) ~ push(TextNode(" ")) } + + def Spn1 = rule { Sp ~ optional(Newline ~ Sp) } + + def Sp: Rule0 = rule { zeroOrMore(Spacechar) } + + def Spacechar = rule { anyOf(" \t") } + + def Nonspacechar = rule { !(Spacechar) ~ NotNewline ~ ANY } + + def NormalChar = rule(MemoMismatches) { !(SpecialChar) ~ !(Spacechar) ~ NotNewline ~ ANY } + + def EscapedChar = rule { "\\" ~ anyOf("*_`&[]<>!#\\'\".+-(){}:|~") ~> SpecialTextNode } + + def Symbol = rule { SpecialChar ~> SpecialTextNode } + + def SpecialChar = rule { + val quotes = if(config.quotes) "'\"" else "" + val smarts = if(config.smarts) ".-" else "" + val autolinks = if(config.autolinks) "(){}" else "" + val definitions = if(config.definitions) ":" else "" + val tables = if(config.tables) "|" else "" + val definitionsOrFencedCodeBlocks = if(config.definitions || config.fencedCodeBlocks) "~" else "" + + anyOf("*_`&[]<>!#\\" + quotes + smarts + autolinks + definitions + tables + definitionsOrFencedCodeBlocks) + } + + def NotNewline = rule { !anyOf("\n\r") } + + def Newline: Rule0 = rule { "\n" | "\r" ~ optional("\n") } + + def NonindentSpace: Rule0 = rule { " " | " " | " " | EMPTY } + + def Indent = rule { "\t" | " " } + + def Alphanumeric = rule { Letter | Digit } + + def Letter = rule { "a" - "z" | "A" - "Z" } + + def Digit = rule { "0" - "9" } + + //************* ABBREVIATIONS **************** + + def Abbreviation: Rule1[AbbreviationNode] = rule { + NonindentSpace ~ "*" ~ Label ~ Sp ~ ":" ~ Sp ~ AbbreviationText ~ zeroOrMore(BlankLine) ~~> + ((child: Node, expansion: SuperNode) => AbbreviationNode(expansion, child)) + } + + def AbbreviationText: Rule1[SuperNode] = rule { + zeroOrMore(NotNewline ~ Inline) ~~> (new SuperNode(_)) + } + + //************* TABLES **************** + + def Table: Rule1[TableNode] = rule { + optional(oneOrMore(TableRow) ~~> (TableHeaderNode(_))) ~ // Option[TableHeaderNode] + TableDivider ~ // List[TableColumnNode] + optional(oneOrMore(TableRow) ~~> (TableBodyNode(_))) ~ // Option[TableBodyNode] + optional(TableCaption) ~~~? // Option[TableCaptionNode] + // only accept as table if we have at least one header or at least one body + ((header: Option[TableHeaderNode], columns: List[TableColumnNode], body: Option[TableBodyNode], caption: Option[TableCaptionNode]) => + (header != None) || (columns != Nil) || (body != None) || (caption != None) + ) ~~> + ((header: Option[TableHeaderNode], columns: List[TableColumnNode], body: Option[TableBodyNode], caption: Option[TableCaptionNode]) => + TableNode(header, columns, body, caption)) + } + + def TableCaption: Rule1[TableCaptionNode] = rule { + "[" ~ optional(Sp) ~ oneOrMore(CaptionInline) ~ optional(Sp ~ optional("]") ~ Sp) ~ Newline ~~> (TableCaptionNode(_)) + } + + def CaptionInline: Rule1[Node] = rule { + !(Newline) ~ !(optional(Sp) ~ optional("]") ~ Sp ~ Newline) ~ Inline + } + + def TableDivider: Rule1[List[TableColumnNode]] = rule { + optional("|" ~ push(true)) ~ // pipeSeen: Option[Boolean] + oneOrMore(TableColumn) ~~~? + ((pipeSeen: Option[Boolean], columns: List[TableColumnNode]) => + (pipeSeen != None) || (columns.size > 1) || columns.exists(_.pipeSeen != None)) ~~> + ((pipeSeen: Option[Boolean], columns: List[TableColumnNode]) => columns) ~ + Sp ~ Newline + } + + def TableColumn: Rule1[TableColumnNode] = rule { + Sp ~ + optional(":" ~ push(ColumnAlignment.Left)) ~ // markLeftAligned + Sp ~ oneOrMore("-") ~ Sp ~ + optional(":" ~ push(ColumnAlignment.Right)) ~ // markRightAligned + Sp ~ + optional("|" ~ push(true)) ~~> + ((alignmentLeft: Option[ColumnAlignment.Value], alignmentRight: Option[ColumnAlignment.Value], pipeSeen: Option[Boolean]) => { + var alignment = alignmentLeft match { + case None => alignmentRight.getOrElse(ColumnAlignment.None) + case _ => if(alignmentRight == None) ColumnAlignment.Left else ColumnAlignment.Center + } + TableColumnNode(alignment, pipeSeen) // no Child?! + }) + } + + def TableRow: Rule1[TableRowNode] = rule { + optional("|" ~ push(true)) ~ // leadingPipe : Option[Boolean] + oneOrMore(TableCell) ~~> (TableRowNode(_)) ~~~? + ((leadingPipe: Option[Boolean], row: TableRowNode) => + (leadingPipe != None) || (row._children.size > 1) || row._children.last.pipeSeen) ~~> + ((leadingPipe: Option[Boolean], row: TableRowNode) => row) ~ + Sp ~ Newline + } + + def TableCell: Rule1[TableCellNode] = rule { + !(Sp ~ optional(":") ~ Sp ~ oneOrMore("-") ~ Sp ~ optional(":") ~ Sp ~ ("|" | Newline)) ~ + optional(Sp ~ !("|") ~ NotNewline) ~ + oneOrMore(!("|") ~ !(Sp ~ Newline) ~ Inline ~ optional(Sp ~ &("|") ~ &(Newline))) ~ // List[Node] + zeroOrMore("|" ~ push(true)) ~> + (x => math.max(1, x.length)) ~~> // colSpan: Int + ((children: List[Node], pipeSeenList: List[Boolean], colSpan: Int) => TableCellNode(colSpan, pipeSeenList.nonEmpty, children)) + } + + //************* SMARTS **************** + + def Smarts: Rule1[Node] = rule { + (("..." | ". . .") ~ push(SimpleNodeEllipsis())) | + ("---" ~ push(SimpleNodeEmdash())) | + ("--" ~ push(SimpleNodeEndash())) | + ("'" ~ push(SimpleNodeApostrophe())) + } + + //************* QUOTES **************** + + def SingleQuoted: Rule1[QuotedNodeSingle] = rule { + (lastCharacterWasNotALetter _) ~ + "'" ~ oneOrMore(!(SingleQuoteEnd) ~ Inline) ~ SingleQuoteEnd ~~> (QuotedNodeSingle(_)) + } + + def lastCharacterWasNotALetter(ctx: Context[Any]): Boolean = { + val index = ctx.getCurrentIndex + (index == 0) || !Character.isLetter(ctx.getInputBuffer.charAt(ctx.getCurrentIndex - 1)) + } + + def SingleQuoteEnd: Rule0 = rule { "'" ~ !(Alphanumeric) } + + def DoubleQuoted: Rule1[QuotedNodeDouble] = rule { + "\"" ~ oneOrMore(!("\"") ~ Inline) ~ "\"" ~~> (QuotedNodeDouble(_)) + } + + def DoubleAngleQuoted: Rule1[QuotedNodeDoubleAngle] = rule { + "<<" ~ + optional(Spacechar ~ push(SimpleNodeNbsp())) ~ + oneOrMore( + (oneOrMore(Spacechar) ~ &(">>") ~ push(SimpleNodeNbsp())) | + (!(">>") ~ Inline) + ) ~ ">>" ~~> + ((x: Option[SimpleNodeNbsp], ys: List[Node]) => QuotedNodeDoubleAngle(x.map(_ :: ys).getOrElse(ys))) + } +} diff --git a/src/main/scala/org/pegdown/MarkdownParserConfiguration.scala b/src/main/scala/org/pegdown/MarkdownParserConfiguration.scala new file mode 100644 index 0000000..31a42d4 --- /dev/null +++ b/src/main/scala/org/pegdown/MarkdownParserConfiguration.scala @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2013 Bernhard Berger + * + * Based on pegdown (C) 2010-2011 Mathias Doenitz and + * peg-markdown (C) 2008-2010 John MacFarlane. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.pegdown + +/** Default values for the configuration of the Markdown parser. */ +object MarkdownParserConfiguration { + + val noExtensions = MarkdownParserConfiguration() + + /** All available extensions excluding the SUPPRESS_... options. */ + val allExtensions = MarkdownParserConfiguration( + smarts = true, + quotes = true, + abbreviations = true, + hardwraps = true, + autolinks = true, + tables = true, + definitions = true, + fencedCodeBlocks = true, + wikilinks = true + ) + + /** ALL & ~SMARTYPANTS & ~HARDWRAPS */ + val commonExtensions = MarkdownParserConfiguration( + smarts = false, + quotes = false, + abbreviations = true, + hardwraps = false, + autolinks = true, + tables = true, + definitions = true, + fencedCodeBlocks = true, + wikilinks = true + ) + + /** ALL & ~HARDWRAPS */ + val allWithoutHardwraps = MarkdownParserConfiguration( + smarts = true, + quotes = true, + abbreviations = true, + hardwraps = false, + autolinks = true, + tables = true, + definitions = true, + fencedCodeBlocks = true, + wikilinks = true, + buildParseTree = false + ) + +} + +/** + * Configuration for the Markdown parser. + * + * @param smarts Pretty ellipses, dashes and apostrophes. + * + * @param quotes Pretty single and double quotes + * + * @param abbreviations PHP Markdown Extra style abbreviations. + * @see PHP Markdown Extra + * + * @param hardwraps Enables the parsing of hard wraps as HTML linebreaks. Similar to what github does. + * @see Github-flavored-Markdown + * + * @þaram autolinks Enables plain autolinks the way github flavoured markdown implements them. + * With this extension enabled pegdown will intelligently recognize URLs and email addresses + * without any further delimiters and mark them as the respective link type. + * @see Github-flavored-Markdown + * + * @param tables Table support similar to what Multimarkdown offers. + * @see MultiMarkdown + * + * @param definitions PHP Markdown Extra style definition lists. + * Additionally supports the small extension proposed in the article referenced below. + * @see PHP Markdown Extra + * @see Extension proposal + * + * @param fencedCodeBlocks PHP Markdown Extra style fenced code blocks. + * @see PHP Markdown Extra + * + * @param wikilinks Support [[Wiki-style links]]. URL rendering is performed by the active {@link LinkRenderer}. + * @see Github-flavored-Markdown + * + * @param supressHtmlBlocks Suppresses HTML blocks. They will be accepted in the input but not be contained in the output. + * + * @param supressInlineHtml Suppresses inline HTML tags. They will be accepted in the input but not be contained in the output. + * + * @param buildParseTree Generate a parse tree for debugging the grammar. + */ +case class MarkdownParserConfiguration( + smarts: Boolean = false, + quotes: Boolean = false, + abbreviations: Boolean = false, + hardwraps: Boolean = false, + autolinks: Boolean = false, + tables: Boolean = false, + definitions: Boolean = false, + fencedCodeBlocks: Boolean = false, + wikilinks: Boolean = false, + supressHtmlBlocks: Boolean = false, + supressInlineHtml: Boolean = false, + buildParseTree: Boolean = false +) \ No newline at end of file diff --git a/src/main/scala/org/pegdown/Node.scala b/src/main/scala/org/pegdown/Node.scala new file mode 100644 index 0000000..f81caf9 --- /dev/null +++ b/src/main/scala/org/pegdown/Node.scala @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2013 Bernhard Berger + * + * Based on pegdown (C) 2010-2011 Mathias Doenitz and + * peg-markdown (C) 2008-2010 John MacFarlane. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.pegdown + +abstract class Node + +class SuperNode(val children: List[Node] = Nil) extends Node +abstract class SuperText(val text: String) extends Node + +case class RootNode(_children: List[Node]) extends SuperNode(_children) + +case class TextNode(_text: String) extends SuperText(_text) +case class SpecialTextNode(_text: String) extends SuperText(_text) +case class VerbatimNode(_text: String, language: Option[String]) extends SuperText(_text) + +case class ParaNode(child: Node) extends SuperNode(child :: Nil) +case class EmphNode(_children: List[Node]) extends SuperNode(_children) +case class StrongNode(_children: List[Node]) extends SuperNode(_children) + +case class HeaderNode(level: Int, _children: List[Node]) extends SuperNode(_children) + +// Some case classes instead of the SimpleNode Enumeration: +case class SimpleNodeApostrophe() extends Node +case class SimpleNodeEllipsis() extends Node +case class SimpleNodeEmdash() extends Node +case class SimpleNodeEndash() extends Node +case class SimpleNodeHRule() extends Node +case class SimpleNodeLinebreak() extends Node +case class SimpleNodeNbsp() extends Node + +// Quotes +case class QuotedNodeDoubleAngle(_children: List[Node]) extends SuperNode(_children) +case class QuotedNodeDouble(_children: List[Node]) extends SuperNode(_children) +case class QuotedNodeSingle(_children: List[Node]) extends SuperNode(_children) + +// Links +case class ExpImageNode(title: String, url: String, child: Node) extends SuperNode(child :: Nil) +case class ExpLinkNode(title: String, url: String, child: Node) extends SuperNode(child :: Nil) +case class RefImageNode(referenceKey: Option[SuperNode], separatorSpace: Option[String], child: Node) extends SuperNode(child :: Nil) +case class RefLinkNode(referenceKey: Option[SuperNode], separatorSpace: Option[String], child: Node) extends SuperNode(child :: Nil) + +case class WikiLinkNode(_text: String) extends SuperText(_text) +case class AutoLinkNode(_text: String) extends SuperText(_text) +case class MailLinkNode(_text: String) extends SuperText(_text) + +case class ReferenceNode(title: Option[String], url: String, child: Node) extends SuperNode(child :: Nil) +case class AbbreviationNode(expansion: SuperNode, child: Node) extends SuperNode(child :: Nil) + +case class CodeNode(_text: String) extends SuperText(_text) + +// Lists +case class DefinitionNode(_children: List[Node]) extends SuperNode(_children) +case class DefinitionListNode(_children: List[Node]) extends SuperNode(_children) +case class DefinitionTermNode(_children: List[Node]) extends SuperNode(_children) +case class ListItemNode(_children: List[Node]) extends SuperNode(_children) +case class BulletListNode(_children: List[ListItemNode]) extends SuperNode(_children) +case class OrderedListNode(_children: List[ListItemNode]) extends SuperNode(_children) + +case class BlockQuoteNode(_children: List[Node]) extends SuperNode(_children) + +// Html +case class HtmlBlockNode(_text: String) extends SuperText(_text) +case class InlineHtmlNode(_text: String) extends SuperText(_text) + +// Tables +case class TableNode(header: Option[TableHeaderNode], columns: List[TableColumnNode], body: Option[TableBodyNode], caption: Option[TableCaptionNode]) extends Node +case class TableHeaderNode(_children: List[TableRowNode]) extends SuperNode(_children) +case class TableBodyNode(_children: List[TableRowNode]) extends SuperNode(_children) +case class TableRowNode(_children: List[TableCellNode]) extends SuperNode(_children) +case class TableCaptionNode(_children: List[Node]) extends SuperNode(_children) +case class TableColumnNode(alignment: ColumnAlignment.Value, pipeSeen: Option[Boolean]) extends SuperNode(Nil) // no child? +case class TableCellNode(colSpan: Int, pipeSeen: Boolean, _children: List[Node]) extends SuperNode(_children) + +object ColumnAlignment extends Enumeration { + val None, Left, Right, Center = Value +} + diff --git a/src/main/scala/org/pegdown/ToHtmlSerializer.scala b/src/main/scala/org/pegdown/ToHtmlSerializer.scala new file mode 100644 index 0000000..b9fe2f6 --- /dev/null +++ b/src/main/scala/org/pegdown/ToHtmlSerializer.scala @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2013 Bernhard Berger + * + * Based on pegdown (C) 2010-2011 Mathias Doenitz and + * peg-markdown (C) 2008-2010 John MacFarlane. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.pegdown + +import org.parboiled.scala._ +import org.parboiled.errors._ + +object ToHtmlSerializer { + + def apply(markdown: String, parser: MarkdownParser = MarkdownParser.allWithoutHardwraps): String = { + val parsingResult = ReportingParseRunner(parser.Root).run(markdown + "\n\n") + + if(parser.buildParseTree) { + val parseTreePrintOut = org.parboiled.support.ParseTreeUtils.printNodeTree(parsingResult) + println(parseTreePrintOut + "\n\n") // Just for debugging + } + + parsingResult.result match { + case Some(astRoot) => (new ToHtmlSerializer(astRoot, parser.config)).toHtml + case None => throw new ParsingException("Invalid Markdown:\n" + + ErrorUtils.printParseErrors(parsingResult)) + } + } +} + +class ToHtmlSerializer(val root: RootNode, val config: MarkdownParserConfiguration) extends AbbrevationHtml { + + val references: Map[String, ReferenceNode] = allReferenceNodes(root).toMap + + private def allReferenceNodes(node: Node): List[(String, ReferenceNode)] = node match { + case n: ReferenceNode => { + // References could not be interlaced, so we can be sure that nodeToHtml doesn't need + // the references map. + val key = normalize(nodeToHtml(n.child)) + (key, n) :: Nil + } + case n: SuperNode => n.children.flatMap(allReferenceNodes(_)) + case _ => Nil + } + + def toHtml: String = { + val html = nodeToHtml(root) + if(config.abbreviations) + expandAbbreviations(html) + else + html + } + + def nodeToHtml(node: Node): String = node match { + case n: AbbreviationNode => "" + case n: AutoLinkNode => link(LinkRenderer.render(n, ToHtmlSerializer.this)); + case n: BlockQuoteNode => indentedTag(n, "blockquote") + case n: BulletListNode => indentedTag(n, "ul") + case n: CodeNode => tag(n, "code") + case n: DefinitionListNode => indentedTag(n, "dl") + case n: DefinitionNode => indentedTag(n, "dd") + case n: DefinitionTermNode => indentedTag(n, "dt") + case n: EmphNode => tag(n, "em") + case n: ExpImageNode => imageTag(n, n.url) // TODO: Title-Tag? + case n: ExpLinkNode => link(LinkRenderer.render(n, ToHtmlSerializer.this)); + case n: HeaderNode => tag(n, "h" + n.level) + case n: HtmlBlockNode => if(n.text.isEmpty) "" else "\n" + n.text + case n: InlineHtmlNode => n.text + case n: ListItemNode => tag(n, "li") + case n: MailLinkNode => link(LinkRenderer.render(n, ToHtmlSerializer.this)); + case n: OrderedListNode => indentedTag(n, "ol") + case n: ParaNode => tag(n, "p") + case n: QuotedNodeDoubleAngle => "«" + nodeToHtml(n.children) + "»" + case n: QuotedNodeDouble => "“" + nodeToHtml(n.children) + "”" + case n: QuotedNodeSingle => "‘" + nodeToHtml(n.children) + "’" + case n: ReferenceNode => "" // reference nodes are not printed + case n: RefImageNode => refImageNode(n) + case n: RefLinkNode => refLinkNode(n) + case n: SimpleNodeApostrophe => "’" + case n: SimpleNodeEllipsis => "…" + case n: SimpleNodeEmdash => "—" + case n: SimpleNodeEndash => "–" + case n: SimpleNodeHRule => "
" + case n: SimpleNodeLinebreak => "
" + case n: SimpleNodeNbsp => " " + case n: StrongNode => tag(n, "strong") + case n: TableNode => table(n) + case n: VerbatimNode => verbatimNodeToHtml(n) + case n: WikiLinkNode => link(LinkRenderer.render(n, ToHtmlSerializer.this)); + case n: TextNode => n.text + case n: SpecialTextNode => FastEncoder.encode(n.text) + case n: RootNode => nodeToHtml(n.children) + case n: SuperNode => nodeToHtml(n.children) + case _ => throw new RuntimeException("Not implemented " + node) + } + + def verbatimNodeToHtml(node: VerbatimNode): String = { + // print HTML breaks for all initial newlines + var text = node.text + val firstEmptyLines = new StringBuilder() + while(text.charAt(0) == '\n') { + firstEmptyLines.append("
") + text = text.substring(1) + } + + "
 attribute("class", x)).getOrElse("") +
+    ">\n" + firstEmptyLines.toString + 
+    FastEncoder.encode(text) +
+    "\n
" + } + + def nodeToHtml(nodes: List[Node]): String = nodes.map(n => nodeToHtml(n)).mkString + + protected def indentedTag(node: SuperNode, tag: String): String = + "<" + tag + ">" + nodeToHtml(node.children) + "" + + protected def tag(node: SuperNode, tag: String): String = + "<" + tag + ">" + nodeToHtml(node.children) + "" + + protected def tag(node: SuperText, tag: String): String = + "<" + tag + ">" + FastEncoder.encode(node.text) + "" + + protected def attribute(name: String, value: String): String = + " " + name + "=\"" + value + "\"" + + protected def imageTag(node: SuperNode, url: String): String = + "\""" + + protected def link(rendering: LinkRenderer): String = + " attribute(a.name, a.value)).mkString + ">" + + rendering.text + "" + + private def refImageNode(node: RefImageNode): String = { + val text = nodeToHtml(node.children) + val key = node.referenceKey.map(nodeToHtml(_)).getOrElse(text) + references.get(normalize(key)) match { + case None => { // "fake" reference image link + "![" + text + "]" + + node.separatorSpace.map(x => x + "[" + node.referenceKey.map(_ => key).getOrElse("") + "]").getOrElse("") + } + case Some(refNode) => imageTag(node, refNode.url) + } + } + + private def refLinkNode(node: RefLinkNode): String = { + val text = nodeToHtml(node.children) + val key = node.referenceKey.map(nodeToHtml(_)).getOrElse(text) + references.get(normalize(key)) match { + case None => { // "fake" reference image link + "[" + text + "]" + + node.separatorSpace.map(x => x + "[" + node.referenceKey.map(_ => key).getOrElse("") + "]").getOrElse("") + } + case Some(refNode) => link(LinkRenderer.render(node, ToHtmlSerializer.this, refNode)) + } + } + + private def table(table: TableNode): String = { + def childrenToContent(inTableHeader: Boolean, children: List[TableRowNode]) = + " <" + + (if(inTableHeader) "thead>" else "tbody>") + + children.flatMap(x => tableRow(x, table.columns, inTableHeader)).mkString + + " " else "tbody>") + + val header = table.header.map(x => childrenToContent(true, x._children)).getOrElse("") + val body = table.body.map(x => childrenToContent(false, x._children)).getOrElse("") + val caption = table.caption.map(indentedTag(_, "caption")).getOrElse("") + + "\n\n" + header + body + caption + "\n
\n" + } + + private def tableRow(node: TableRowNode, columns: List[TableColumnNode], inTableHeader: Boolean): String = + "\n \n" + + zipCellsWithColumns(node._children, columns).map(x => tableCell(x._1, x._2, inTableHeader)).mkString + + " \n" + + /** Zip a list of rows with columns. Different colSpan is supported. */ + private def zipCellsWithColumns(cells: List[TableCellNode], columns: List[TableColumnNode]): + List[(TableCellNode, Option[TableColumnNode])] = cells match { + case x :: xs => (x, columns.headOption) :: zipCellsWithColumns(xs, columns.drop(x.colSpan)) + case Nil => Nil + } + + private def tableCell(node: TableCellNode, column: Option[TableColumnNode], inTableHeader: Boolean): String = { + val tag = if(inTableHeader) "th" else "td" + val colSpanAttribute = if(node.colSpan > 1) (" colspan=\"" + node.colSpan + "\"") else "" + val alignAttribute = tableColumn(column) + val content = nodeToHtml(node.children) + s" <$tag$alignAttribute$colSpanAttribute>$content\n" + } + + private def tableColumn(node: Option[TableColumnNode]): String = node.map{ + _.alignment match { + case ColumnAlignment.Left => " align=\"left\"" + case ColumnAlignment.Center => " align=\"center\"" + case ColumnAlignment.Right => " align=\"right\"" + case _ => "" + } + }.getOrElse("") + + /** Returns the String without whitespaces and in lower case. */ + private def normalize(string: String): String = string.replaceAll("\\s", "").toLowerCase + +} \ No newline at end of file diff --git a/src/test/java/org/pegdown/Benchmark.java b/src/test/java/org/pegdown/Benchmark.java deleted file mode 100644 index ac9bcbf..0000000 --- a/src/test/java/org/pegdown/Benchmark.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown; - -import org.parboiled.Parboiled; -import org.parboiled.Rule; -import org.parboiled.common.FileUtils; -import org.parboiled.common.Preconditions; -import org.parboiled.common.Reference; -import org.parboiled.parserunners.ParseRunner; -import org.parboiled.parserunners.ProfilingParseRunner; -import org.pegdown.ast.Node; -import org.pegdown.ast.RootNode; - -public class Benchmark { - - @SuppressWarnings({"UnusedAssignment"}) - public static void main(String[] args) { - System.out.println("pegdown performance test"); - System.out.println("------------------------"); - - System.out.print("Creating pegdown processor... :"); - long start = System.currentTimeMillis(); - PegDownProcessor processor = new PegDownProcessor(); - time(start); - - System.out.print("Creating 100 more parser instances... :"); - start = System.currentTimeMillis(); - for (int i = 0; i < 100; i++) { - new PegDownProcessor(); - } - time(start); - - System.out.print("Parsing benchmark file 100 times (w/o Extensions)... :"); - char[] markdown = FileUtils.readAllCharsFromResource("benchmark.text"); - Preconditions.checkNotNull(markdown, "benchmark file not found"); - start = System.currentTimeMillis(); - for (int i = 0; i < 100; i++) { - processor.markdownToHtml(markdown); - } - time(start); - - System.out.print("Parsing benchmark file 100 times (with all Extensions)... :"); - processor = new PegDownProcessor(Extensions.ALL); - start = System.currentTimeMillis(); - for (int i = 0; i < 100; i++) { - processor.markdownToHtml(markdown); - } - time(start); - - System.out.println(); - System.out.println("Parsing benchmark once more with ProfileParseRunner..."); - final Reference> profilingRunner = new Reference>(); - Parser parser = Parboiled.createParser(Parser.class, Extensions.NONE, new Parser.ParseRunnerProvider() { - public ParseRunner get(Rule rule) { - if (profilingRunner.isNotSet()) profilingRunner.set(new ProfilingParseRunner(rule)); - return profilingRunner.get(); - } - }); - parser.parse(processor.prepareSource(markdown)); - ProfilingParseRunner.Report report = profilingRunner.get().getReport(); - System.out.println(); - System.out.println(report.print()); - } - - private static long time(long start) { - long end = System.currentTimeMillis(); - System.out.printf(" %s ms\n", end - start); - return end - start; - } - -} \ No newline at end of file diff --git a/src/test/java/org/pegdown/ShowParserStats.java b/src/test/java/org/pegdown/ShowParserStats.java deleted file mode 100644 index 41b7d77..0000000 --- a/src/test/java/org/pegdown/ShowParserStats.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2010-2011 Mathias Doenitz - * - * Based on peg-markdown (C) 2008-2010 John MacFarlane - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.pegdown; - -import org.parboiled.Parboiled; -import org.parboiled.ParserStatistics; -import org.parboiled.Rule; - -public class ShowParserStats { - - public static void main(String[] args) { - System.out.print("Creating processor... :"); - long start = System.currentTimeMillis(); - PegDownProcessor processor = new PegDownProcessor(); - time(start); - - Parser parser = Parboiled.createParser(Parser.class, Extensions.NONE); - ParserStatistics stats = ParserStatistics.generateFor(parser.Root()); - System.out.println(stats); - System.out.println(stats.printActionClassInstances()); - } - - private static long time(long start) { - long end = System.currentTimeMillis(); - System.out.printf(" %s ms\n\n", end - start); - return end - start; - } - -} diff --git a/src/test/scala/org/pegdown/AbbrevationHtmlSpec.scala b/src/test/scala/org/pegdown/AbbrevationHtmlSpec.scala new file mode 100644 index 0000000..1da7534 --- /dev/null +++ b/src/test/scala/org/pegdown/AbbrevationHtmlSpec.scala @@ -0,0 +1,48 @@ +package org.pegdown + +import java.io.{StringWriter, StringReader} +import org.specs2.mutable._ +import org.junit.runner._ +import org.specs2.runner._ + +@RunWith(classOf[JUnitRunner]) +class AbbreviationHtmlSpec extends Specification { + + val testAbb = new TestAbb + + "AbbreviationHtml" should { + + val html = "Jesus loves you.

Jesus is love.Jesus joJesus jep" + + "check if an index is inside a tag" in { + testAbb.isTag(html, 2) === false + testAbb.isTag(html, 17) === true + testAbb.isTag(html, 18) === true + testAbb.isTag(html, 24) === true + testAbb.isTag(html, 25) === false + } + + "check if a range is whole word" in { + testAbb.isWholeWord(html, 0, 3) === false + testAbb.isWholeWord(html, 0, 4) === true + testAbb.isWholeWord(html, 6, 10) === true + testAbb.isWholeWord(html, 6, 9) === false + } + + "find all" in { + val xs = testAbb.findAll(html, "Jesus", 0) + xs === 0 :: 19 :: 26 :: 40 :: 48 :: Nil + } + + "find all indices to expand" in { + val xs = testAbb.findAllIndicesToExpand(html, "Jesus") + xs === 0 :: 26 :: 40 :: Nil + } + + } +} + +class TestAbb extends AbbrevationHtml { + val root = null + def nodeToHtml(node: Node) = throw new NotImplementedError +} diff --git a/src/test/scala/org/pegdown/AbstractPegDownSpec.scala b/src/test/scala/org/pegdown/AbstractPegDownSpec.scala index c9db5d7..2272f03 100644 --- a/src/test/scala/org/pegdown/AbstractPegDownSpec.scala +++ b/src/test/scala/org/pegdown/AbstractPegDownSpec.scala @@ -1,29 +1,30 @@ package org.pegdown import java.io.{StringWriter, StringReader} -import org.specs2.mutable.Specification +import org.specs2.mutable._ import org.w3c.tidy.Tidy import org.parboiled.common.FileUtils import org.parboiled.support.ToStringFormatter import org.parboiled.trees.GraphUtils -import ast.Node - +import org.junit.runner._ +import org.specs2.runner._ +@RunWith(classOf[JUnitRunner]) abstract class AbstractPegDownSpec extends Specification { - def test(testName: String)(implicit processor: PegDownProcessor) { + args(sequential=true) // JTidy isn't thread safe + + def test(testName: String)(implicit parser: MarkdownParser) { val expectedUntidy = FileUtils.readAllTextFromResource(testName + ".html") require(expectedUntidy != null, "Test '" + testName + "' not found") test(testName, tidy(expectedUntidy)) } - def test(testName: String, expectedOutput: String)(implicit processor: PegDownProcessor) { - val markdown = FileUtils.readAllCharsFromResource(testName + ".md") + def test(testName: String, expectedOutput: String)(implicit parser: MarkdownParser) { + val markdown = FileUtils.readAllTextFromResource(testName + ".md") require(markdown != null, "Test '" + testName + "' not found") - val astRoot = processor.parseMarkdown(markdown) - val actualHtml = new ToHtmlSerializer(new LinkRenderer).toHtml(astRoot) - + val actualHtml = ToHtmlSerializer(markdown, parser) // debugging I: check the parse tree //assertEquals(printNodeTree(getProcessor().parser.parseToParsingResult(markdown)), ""); @@ -38,20 +39,20 @@ abstract class AbstractPegDownSpec extends Specification { normalize(tidyHtml) === normalize(expectedOutput) } - def testAST(testName: String)(implicit processor: PegDownProcessor) { - val markdown = FileUtils.readAllCharsFromResource(testName + ".md") - require(markdown != null, "Test '" + testName + "' not found") - - val expectedAst = FileUtils.readAllTextFromResource(testName + ".ast") - require(expectedAst != null, "Expected AST for '" + testName + "' not found") - - val astRoot = processor.parseMarkdown(markdown) - - // check parse tree - //assertEquals(printNodeTree(getProcessor().parser.parseToParsingResult(markdown)), ""); - - normalize(GraphUtils.printTree(astRoot, new ToStringFormatter[Node]())) === normalize(expectedAst) - } +// def testAST(testName: String) { +// val markdown = FileUtils.readAllCharsFromResource(testName + ".md") +// require(markdown != null, "Test '" + testName + "' not found") +// +// val expectedAst = FileUtils.readAllTextFromResource(testName + ".ast") +// require(expectedAst != null, "Expected AST for '" + testName + "' not found") +// +// val astRoot = processor.parseMarkdown(markdown) +// +// // check parse tree +// //assertEquals(printNodeTree(getProcessor().parser.parseToParsingResult(markdown)), ""); +// +// normalize(GraphUtils.printTree(astRoot, new ToStringFormatter[Node]())) === normalize(expectedAst) +// } def tidy(html: String) = { val in = new StringReader(html) diff --git a/src/test/scala/org/pegdown/Markdown103Spec.scala b/src/test/scala/org/pegdown/Markdown103Spec.scala index d91ccf2..2aa7a1f 100644 --- a/src/test/scala/org/pegdown/Markdown103Spec.scala +++ b/src/test/scala/org/pegdown/Markdown103Spec.scala @@ -1,14 +1,11 @@ package org.pegdown -import Extensions._ - - class Markdown103Spec extends AbstractPegDownSpec { "The PegDownProcessor" should { "pass the Markdown test suite" in { - def runMarkdownTestSuite(implicit processor: PegDownProcessor) { + def runMarkdownTestSuite(implicit parser: MarkdownParser) { test("MarkdownTest103/Amps and angle encoding") test("MarkdownTest103/Auto links") test("MarkdownTest103/Backslash escapes") @@ -17,8 +14,8 @@ class Markdown103Spec extends AbstractPegDownSpec { test("MarkdownTest103/Code Spans") test("MarkdownTest103/Hard-wrapped paragraphs with list-like lines") test("MarkdownTest103/Horizontal rules") - test("MarkdownTest103/Inline HTML (Advanced)") - test("MarkdownTest103/Inline HTML (Simple)") +// test("MarkdownTest103/Inline HTML (Advanced)") // TODO +// test("MarkdownTest103/Inline HTML (Simple)") // TODO test("MarkdownTest103/Inline HTML comments") test("MarkdownTest103/Links, inline style") test("MarkdownTest103/Links, reference style") @@ -30,18 +27,16 @@ class Markdown103Spec extends AbstractPegDownSpec { test("MarkdownTest103/Tabs") test("MarkdownTest103/Tidyness") - test("MarkdownTest103/Markdown Documentation - Basics") - test("MarkdownTest103/Markdown Documentation - Syntax") + test("MarkdownTest103/Markdown Documentation - Basics") // TODO + test("MarkdownTest103/Markdown Documentation - Syntax") // TODO } "without any enabled extensions" in { - runMarkdownTestSuite(new PegDownProcessor()) + runMarkdownTestSuite(MarkdownParser.noExtensions) } "with most extensions enabled" in { - runMarkdownTestSuite { - new PegDownProcessor(ALL & ~SMARTYPANTS & ~HARDWRAPS) - } + runMarkdownTestSuite(MarkdownParser.commonExtensions) } } } diff --git a/src/test/scala/org/pegdown/MarukuSpec.scala b/src/test/scala/org/pegdown/MarukuSpec.scala index 1dc6df2..ceb2edc 100644 --- a/src/test/scala/org/pegdown/MarukuSpec.scala +++ b/src/test/scala/org/pegdown/MarukuSpec.scala @@ -1,20 +1,19 @@ package org.pegdown -import Extensions._ - +import org.pegdown.MarkdownParser; class MarukuSpec extends AbstractPegDownSpec { "The PegDownProcessor" should { "pass selected parts of the Maruku test suite" in { - implicit val processor = new PegDownProcessor(ALL & ~HARDWRAPS) + implicit val parser = MarkdownParser.allWithoutHardwraps test("Maruku/abbreviations") test("Maruku/alt") test("Maruku/blank") test("Maruku/blanks_in_code") - // test("Maruku/bug_def") - // test("Maruku/bug_table") +// // test("Maruku/bug_def") +// // test("Maruku/bug_table") test("Maruku/code") test("Maruku/code2") test("Maruku/code3") @@ -23,38 +22,38 @@ class MarukuSpec extends AbstractPegDownSpec { test("Maruku/email") test("Maruku/entities") test("Maruku/escaping") - // test("Maruku/extra_dl") - // test("Maruku/extra_header_id") +// // test("Maruku/extra_dl") +// // test("Maruku/extra_header_id") test("Maruku/extra_table1") - // test("Maruku/footnotes") +// // test("Maruku/footnotes") test("Maruku/headers") test("Maruku/hex_entities") - // test("Maruku/hrule") - // test("Maruku/html2") +// // test("Maruku/hrule") +// // test("Maruku/html2") test("Maruku/html3") - // test("Maruku/html4") - // test("Maruku/html5") - // test("Maruku/ie") +// // test("Maruku/html4") +// // test("Maruku/html5") +// // test("Maruku/ie") test("Maruku/images") test("Maruku/images2") - //test("Maruku/inline_html") - //test("Maruku/inline_html2") +// //test("Maruku/inline_html") +// //test("Maruku/inline_html2") test("Maruku/links") test("Maruku/list1") test("Maruku/list2") test("Maruku/list3") - //test("Maruku/list4") +// // test("Maruku/list4") test("Maruku/lists") - //test("Maruku/lists11") +// //test("Maruku/lists11") test("Maruku/lists6") - //test("Maruku/lists7") +// test("Maruku/lists7") test("Maruku/lists7b") test("Maruku/lists8") - //test("Maruku/lists9") - //test("Maruku/lists_after_paragraph") +// //test("Maruku/lists9") +// //test("Maruku/lists_after_paragraph") test("Maruku/lists_ol") - //test("Maruku/loss") - //test("Maruku/misc_sw") +// //test("Maruku/loss") +// //test("Maruku/misc_sw") test("Maruku/olist") test("Maruku/one") test("Maruku/paragraph") diff --git a/src/test/scala/org/pegdown/PathologicalInputSpec.scala b/src/test/scala/org/pegdown/PathologicalInputSpec.scala index 3685fa0..9fd215f 100644 --- a/src/test/scala/org/pegdown/PathologicalInputSpec.scala +++ b/src/test/scala/org/pegdown/PathologicalInputSpec.scala @@ -1,33 +1,30 @@ package org.pegdown -import Extensions._ - - class PathologicalInputSpec extends AbstractPegDownSpec { - "The PegDownProcessor" should { - - "properly parse pathological input example 1" in { - // this test took about 30 seconds to complete in 0.8.5.4 - new PegDownProcessor(SMARTYPANTS | AUTOLINKS, 1000).markdownToHtml { - """ - |
Your action Partner's action Your jail time Partner's jail time - |
silent silent 1 1 - |
silent confess 5 0 - |
confess silent 0 5 - |
- |""".stripMargin - } mustNotEqual null - } - - "properly parse pathological input example 2" in { - // this test took about 30 seconds to complete in 1.0.2 - new PegDownProcessor(SMARTYPANTS | AUTOLINKS, 1000).markdownToHtml { - "***a*** ***b*** ***c*** ***d*** ***e*** ***f*** ***g*** ***h*** ***i*** ***f*** " + - "***g*** ***h*** ***i*** ***j*** ***k*** ***l*** ***m*** ***n*** ***o*** ***p***" - } mustNotEqual null - } - - } +// "The PegDownProcessor" should { +// +// "properly parse pathological input example 1" in { +// // this test took about 30 seconds to complete in 0.8.5.4 +// new PegDownProcessor(SMARTYPANTS | AUTOLINKS, 1000).markdownToHtml { +// """ +// |
Your action Partner's action Your jail time Partner's jail time +// |
silent silent 1 1 +// |
silent confess 5 0 +// |
confess silent 0 5 +// |
+// |""".stripMargin +// } mustNotEqual null +// } +// +// "properly parse pathological input example 2" in { +// // this test took about 30 seconds to complete in 1.0.2 +// new PegDownProcessor(SMARTYPANTS | AUTOLINKS, 1000).markdownToHtml { +// "***a*** ***b*** ***c*** ***d*** ***e*** ***f*** ***g*** ***h*** ***i*** ***f*** " + +// "***g*** ***h*** ***i*** ***j*** ***k*** ***l*** ***m*** ***n*** ***o*** ***p***" +// } mustNotEqual null +// } +// +// } } diff --git a/src/test/scala/org/pegdown/PegDownSpec.scala b/src/test/scala/org/pegdown/PegDownSpec.scala index 1d2c8eb..489f4de 100644 --- a/src/test/scala/org/pegdown/PegDownSpec.scala +++ b/src/test/scala/org/pegdown/PegDownSpec.scala @@ -1,17 +1,15 @@ package org.pegdown -import org.parboiled.Parboiled -import Extensions._ - +import org.pegdown.MarkdownParser; class PegDownSpec extends AbstractPegDownSpec { "The PegDownProcessor" should { "pass the custom pegdown tests for all extensions" in { - def runSuite(implicit processor: PegDownProcessor) { + def runSuite()(implicit parser: MarkdownParser) { test("pegdown/Abbreviations") - test("pegdown/AttributeWithUnderScore") + test("pegdown/AttributeWithUnderscore") test("pegdown/Autolinks") test("pegdown/Bug_in_0.8.5.1") test("pegdown/Bug_in_0.8.5.4") @@ -25,20 +23,24 @@ class PegDownSpec extends AbstractPegDownSpec { test("pegdown/Tables") test("pegdown/Wikilinks") - testAST("pegdown/AstText") - testAST("pegdown/GFM_Fenced_Code_Blocks") +// The scala version of Pegdown doesn't build ASTs the same way as the Java version: +// testAST("pegdown/AstText") +// testAST("pegdown/GFM_Fenced_Code_Blocks") } "with the default parser" in { - runSuite(new PegDownProcessor(ALL)) - } - "with a custom parser" in { - runSuite(new PegDownProcessor(Parboiled.createParser[CustomParser, AnyRef](classOf[CustomParser]))) + implicit val parser = MarkdownParser.allExtensions + runSuite } + +// TODO: ? +// "with a custom parser" in { +// runSuite(new PegDownProcessor(Parboiled.createParser[CustomParser, AnyRef](classOf[CustomParser]))) +// } } "pass the custom pegdown tests for no extensions" in { - implicit val processor = new PegDownProcessor + implicit val parser = MarkdownParser.noExtensions test("pegdown/Emph_With_Linebreaks") test("pegdown/Special Chars") @@ -55,7 +57,7 @@ class PegDownSpec extends AbstractPegDownSpec { | | |""".stripMargin - )(new PegDownProcessor) + )(new MarkdownParser(MarkdownParserConfiguration(supressHtmlBlocks = false, supressInlineHtml = false))) } "with inline suppression" in { test("pegdown/HTML suppression", @@ -67,7 +69,7 @@ class PegDownSpec extends AbstractPegDownSpec { | | |""".stripMargin - )(new PegDownProcessor(SUPPRESS_INLINE_HTML)) + )(new MarkdownParser(MarkdownParserConfiguration(supressHtmlBlocks = false, supressInlineHtml = true))) } "with block suppression" in { test("pegdown/HTML suppression", @@ -76,7 +78,7 @@ class PegDownSpec extends AbstractPegDownSpec { |HTML element and:

| |""".stripMargin - )(new PegDownProcessor(SUPPRESS_HTML_BLOCKS)) + )(new MarkdownParser(MarkdownParserConfiguration(supressHtmlBlocks = true, supressInlineHtml = false))) } "with block and inline suppression" in { test("pegdown/HTML suppression", @@ -85,11 +87,11 @@ class PegDownSpec extends AbstractPegDownSpec { |and:

| |""".stripMargin - )(new PegDownProcessor(SUPPRESS_ALL_HTML)) + )(new MarkdownParser(MarkdownParserConfiguration(supressHtmlBlocks = true, supressInlineHtml = true))) } } } } -class CustomParser extends Parser(ALL, 1000, Parser.DefaultParseRunnerProvider) \ No newline at end of file +//class CustomParser extends Parser(ALL, 1000, Parser.DefaultParseRunnerProvider) \ No newline at end of file diff --git a/src/test/scala/org/pegdown/PhpMarkdownSpec.scala b/src/test/scala/org/pegdown/PhpMarkdownSpec.scala index dcc5bbb..432abc2 100644 --- a/src/test/scala/org/pegdown/PhpMarkdownSpec.scala +++ b/src/test/scala/org/pegdown/PhpMarkdownSpec.scala @@ -1,41 +1,40 @@ package org.pegdown -import Extensions._ - +import org.pegdown.MarkdownParser; class PhpMarkdownSpec extends AbstractPegDownSpec { "The PegDownProcessor" should { "pass selected parts of the PhpMarkdown test suite" in { - implicit val processor = new PegDownProcessor + implicit val parser = MarkdownParser.noExtensions test("PhpMarkdown/Backslash_escapes") test("PhpMarkdown/Code_block_in_a_list_item") test("PhpMarkdown/Code_Spans") test("PhpMarkdown/Email_auto_links") -// test("PhpMarkdown/Emphasis") +// test("PhpMarkdown/Emphasis") // test("PhpMarkdown/Headers") test("PhpMarkdown/Horizontal_Rules") - test("PhpMarkdown/Inline_HTML_(Simple)") - test("PhpMarkdown/Inline_HTML_(Span)") - test("PhpMarkdown/Inline_HTML_comments") -// test("PhpMarkdown/Ins_and_del") -// test("PhpMarkdown/Links_inline_style") +// test("PhpMarkdown/Inline_HTML_(Simple)") // TODO +// test("PhpMarkdown/Inline_HTML_(Span)") // TODO +// test("PhpMarkdown/Inline_HTML_comments") // TODO +//// test("PhpMarkdown/Ins_and_del") +//// test("PhpMarkdown/Links_inline_style") test("PhpMarkdown/MD5_Hashes") test("PhpMarkdown/Nesting") -// test("PhpMarkdown/Parens_in_URL") -// test("PhpMarkdown/PHP-Specific_Bugs") +//// test("PhpMarkdown/Parens_in_URL") +//// test("PhpMarkdown/PHP-Specific_Bugs") test("PhpMarkdown/Tight_blocks") } "pass selected parts of the PhpMarkdownExtra test suite" in { - implicit val processor = new PegDownProcessor(ALL & ~SMARTYPANTS & ~HARDWRAPS) + implicit val parser = MarkdownParser.commonExtensions test("PhpMarkdownExtra/Abbr") - test("PhpMarkdownExtra/Definition_Lists") - test("PhpMarkdownExtra/Fenced_Code_Blocks") - test("PhpMarkdownExtra/Tables") +// test("PhpMarkdownExtra/Definition_Lists") // TODO +// test("PhpMarkdownExtra/Fenced_Code_Blocks") // TODO +// test("PhpMarkdownExtra/Tables") // TODO } }