Skip to content

Commit

Permalink
adjust scaladoc and manual for new rst extension registration - #56
Browse files Browse the repository at this point in the history
  • Loading branch information
jenshalm committed Jul 19, 2018
1 parent b7233fe commit 1458cdc
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 132 deletions.
31 changes: 4 additions & 27 deletions core/src/main/scala/laika/parse/rst/ReStructuredText.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,38 +41,15 @@ import laika.tree.Paths.Path
* }}}
*
* reStructuredText has several types of extension points that are fully supported by Laika.
* In contrast to the original Python implementation, the API has been redesigned to be a more
* idiomatic, concise and type-safe Scala DSL.
*
* The following extension types are available:
*
* - Block Directives - an extension hook for adding new block level elements to
* reStructuredText markup. Use the `withBlockDirectives` method of this class to
* add directive implementations to the parser. Specification entry:
* [[http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#directives]]
*
* - Substitution Definitions - an extension hook for adding new span level elements to
* reStructuredText markup that can be used by substitution references (like `|subst|`).
* Use the `withSpanDirectives` method of this class to
* add directive implementations to the parser that can be used as substitution definitions.
* Specification entry:
* [[http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#substitution-definitions]]
*
* - Interpreted Text Roles - an extension hook for adding new dynamic span level elements to
* reStructuredText markup. In contrast to substitution definitions the implementation of a text
* role uses the text from the occurrences in the markup referring to the role as input.
* Use the `withTextRoles` method of this class to
* add custom text role implementations to the parser that can be referred to by interpreted text.
* Specification entry:
* [[http://docutils.sourceforge.net/docs/ref/rst/directives.html#custom-interpreted-text-roles]]
*
* For more information on how to implement and register those see [[laika.parse.rst.ext.RstExtensionRegistry]].
*
* In addition to the standard reStructuredText directives, the API also supports a custom directive
* type unique to Laika. They represent a library-wide extension mechanism and allow you to implement
* tags which can be used in any of the supported markup formats or in templates. If you need this
* level of flexibility, it is recommended to use the Laika directives, if you want to stay compatible
* with the reStructuredText reference parser, you should pick the standard directives.
*
* Laika directives can be registered with the `DirectiveSupport` extension bundle.
* Laika directives can be registered with the [[laika.directive.DirectiveRegistry]] extension bundle.
* The DSLs for creating directives are similar, but still different,
* due to differences in the feature set of the two variants. The Laika directives try to avoid some
* of the unnecessary complexities of reStructuredText directives.
Expand Down Expand Up @@ -129,7 +106,7 @@ class ReStructuredText private (rawContent: Boolean = false) extends ParserFacto

}

/** The default reStructuredText parser configuration, without any directives or text roles installed.
/** The default reStructuredText parser configuration.
*
* @author Jens Halm
*/
Expand Down
43 changes: 28 additions & 15 deletions core/src/main/scala/laika/parse/rst/ext/Directives.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package laika.parse.rst.ext

import laika.parse.core.markup.RecursiveParsers
import laika.parse.rst.ext.TextRoles.RoleDirectivePart
import laika.tree.Elements._
import laika.util.Builders._
import laika.util.~
Expand Down Expand Up @@ -73,12 +72,18 @@ import laika.util.~
* options: Options = NoOpt) extends Block
* with BlockContainer[Note]
*
* val rst = ReStructuredText withBlockDirectives
* BlockDirective("note") {
* (argument(withWS = true) ~ blockContent)(Note(_,_))
* }
* object MyDirectives extends RstExtensionRegistry {
* val blockDirectives = Seq(
* BlockDirective("note") {
* (argument(withWS = true) ~ blockContent)(Note(_,_))
* }
* )
* val spanDirectives = Nil
* val textRoles = Nil
* )
*
* Transform from rst to HTML fromFile "hello.rst" toFile "hello.html"
* Transform from ReStructuredText to HTML using
* MyDirectives fromFile "hello.rst" toFile "hello.html"
* }}}
*
* The `argument()` method specifies a required argument of type `String` (since no conversion
Expand Down Expand Up @@ -109,10 +114,14 @@ import laika.util.~
* options: Options = NoOpt) extends Block
* with BlockContainer[Message]
*
* val rst = ReStructuredText withBlockDirectives (
* BlockDirective("message") {
* (argument(nonNegativeInt) ~ blockContent)(Message(_,_))
* }
* object MyDirectives extends RstExtensionRegistry {
* val blockDirectives = Seq(
* BlockDirective("message") {
* (argument(nonNegativeInt) ~ blockContent)(Message(_,_))
* }
* )
* val spanDirectives = Nil
* val textRoles = Nil
* )
* }}}
*
Expand All @@ -132,11 +141,15 @@ import laika.util.~
* options: Options = NoOpt) extends Block
* with BlockContainer[Message]
*
* val rst = ReStructuredText withBlockDirectives (
* BlockDirective("message") {
* (optArgument(nonNegativeInt) ~ blockContent)(Message(_,_))
* }
* )
* object MyDirectives extends RstExtensionRegistry {
* val blockDirectives = Seq(
* BlockDirective("message") {
* (optArgument(nonNegativeInt) ~ blockContent)(Message(_,_))
* }
* )
* val spanDirectives = Nil
* val textRoles = Nil
* }
* }}}
*
* The argument may be missing, but if it is present it has to pass the specified validator.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import laika.util.~

import scala.collection.mutable.ListBuffer

/** Provides the parsers for all types of explicit block elements.
* In reStructuredText an explicit block element starts with `.. `,
/** Provides the parsers for all types of extensions (directives and text roles).
* In reStructuredText an explicit block element for an extension starts with `.. `,
* followed by a block where the second and subsequent lines are indented.
*
* @author Jens Halm
Expand Down Expand Up @@ -60,7 +60,7 @@ class RstExtensionParsers(recParsers: RecursiveParsers,
*
* See [[http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#substitution-definitions]].
*/
lazy val substitutionDefinition: Parser[Block] = { // TODO - move
lazy val substitutionDefinition: Parser[Block] = {
val text = not(ws take 1) ~> escapedText(delimitedBy('|','\n').keepDelimiter.nonEmpty)
val prefix = '|' ~> text <~ not(lookBehind(1, ' ')) ~ '|'

Expand All @@ -70,7 +70,7 @@ class RstExtensionParsers(recParsers: RecursiveParsers,
case name ~ content => SubstitutionDefinition(name, content)
}
}
private lazy val spanDirectiveParser: Parser[Span] = directive(spanDirectives.get) // TODO - move
private lazy val spanDirectiveParser: Parser[Span] = directive(spanDirectives.get)

private def replaceInvalidDirective (block: Block): Block = block match {
case InvalidDirective(msg, source, _) => InvalidBlock(SystemMessage(laika.tree.Elements.Error, msg), LiteralBlock(source))
Expand All @@ -81,7 +81,7 @@ class RstExtensionParsers(recParsers: RecursiveParsers,
*
* See [[http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#directives]].
*/
lazy val blockDirective: Parser[Block] = directive(blockDirectives.get) ^^ replaceInvalidDirective // TODO - move
lazy val blockDirective: Parser[Block] = directive(blockDirectives.get) ^^ replaceInvalidDirective


private def directive [E](provider: String => Option[DirectivePart[E]]): Parser[E] = {
Expand Down Expand Up @@ -116,7 +116,7 @@ class RstExtensionParsers(recParsers: RecursiveParsers,
*
* See [[http://docutils.sourceforge.net/docs/ref/rst/directives.html#custom-interpreted-text-roles]].
*/
lazy val roleDirective: Parser[Block] = { // TODO - move
lazy val roleDirective: Parser[Block] = {

val nameParser = "role::" ~ ws ~> simpleRefName ~ opt('(' ~> simpleRefName <~ ')')

Expand Down
78 changes: 60 additions & 18 deletions core/src/main/scala/laika/parse/rst/ext/RstExtensionSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,31 @@ object RstExtension {

}

/** In contrast to the original Python implementation, the API has been redesigned to be a more
* idiomatic, concise and type-safe Scala DSL.
*
* The following extension types are available:
*
* - Block Directives - an extension hook for adding new block level elements to
* reStructuredText markup. Use the `blockDirectives` method of this class to
* add directive implementations to the parser. Specification entry:
* [[http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#directives]]
*
* - Substitution Definitions - an extension hook for adding new span level elements to
* reStructuredText markup that can be used by substitution references (like `|subst|`).
* Use the `spanDirectives` method of this class to
* add directive implementations to the parser that can be used as substitution definitions.
* Specification entry:
* [[http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#substitution-definitions]]
*
* - Interpreted Text Roles - an extension hook for adding new dynamic span level elements to
* reStructuredText markup. In contrast to substitution definitions the implementation of a text
* role uses the text from the occurrences in the markup referring to the role as input.
* Use the `textRoles` method of this class to
* add custom text role implementations to the parser that can be referred to by interpreted text.
* Specification entry:
* [[http://docutils.sourceforge.net/docs/ref/rst/directives.html#custom-interpreted-text-roles]]
*/
trait RstExtensionRegistry extends ExtensionBundle {

override val useInStrictMode: Boolean = true
Expand All @@ -87,13 +112,19 @@ trait RstExtensionRegistry extends ExtensionBundle {
* Example:
*
* {{{
* val rst = ReStructuredText withSpanDirectives (
* SpanDirective("replace") {
* spanContent map SpanSequence
* }
* )
* object MyDirectives extends RstExtensionRegistry {
* val spanDirectives = Seq(
* SpanDirective("replace") {
* spanContent map SpanSequence
* }
* )
* val blockDirectives = Seq()
* val textRoles = Seq()
* }
*
* Transform from rst to HTML fromFile "hello.rst" toFile "hello.html"
* Transform.from(ReStructuredText).to(HTML)
* .using(MyDirectives)
* .fromFile("hello.rst").toFile("hello.html")
* }}}
*
* For more details on implementing directives see [[Directives]].
Expand All @@ -107,13 +138,19 @@ trait RstExtensionRegistry extends ExtensionBundle {
* {{{
* case class Note (title: String, content: Seq[Block]) extends Block with BlockContainer[Note]
*
* val rst = ReStructuredText withBlockDirectives (
* BlockDirective("note") {
* (argument() ~ blockContent)(Note)
* }
* )
* object MyDirectives extends RstExtensionRegistry {
* val blockDirectives = Seq(
* BlockDirective("note") {
* (argument() ~ blockContent)(Note)
* }
* )
* val spanDirectives = Seq()
* val textRoles = Seq()
* }
*
* Transform from rst to HTML fromFile "hello.rst" toFile "hello.html"
* Transform.from(ReStructuredText).to(HTML)
* .using(MyDirectives)
* .fromFile("hello.rst").toFile("hello.html")
* }}}
*
* For more details on implementing directives see [[Directives]].
Expand All @@ -126,13 +163,18 @@ trait RstExtensionRegistry extends ExtensionBundle {
* Example:
*
* {{{
* val rst = ReStructuredText withTextRoles (
* TextRole("link", "http://www.our-server.com/tickets/")(field("base-url")) {
* (base, text) => Link(List(Text(text)), base + text)
* }
* )
* val textRole = TextRole("link", "http://www.company.com/main/")(field("base-url")) {
* (base, text) => Link(List(Text(text)), base + text)
* }
*
* object MyDirectives extends RstExtensionRegistry {
* val textRoles = Seq(textRole)
* val spanDirectives = Seq()
* val blockDirectives = Seq()
* }
*
* Transform from rst to HTML fromFile "hello.rst" toFile "hello.html"
* Transform from ReStructuredText to HTML using
* MyDirectives fromFile "hello.rst" toFile "hello.html"
* }}}
*
* For more details on implementing directives see [[TextRoles]].
Expand Down
11 changes: 9 additions & 2 deletions core/src/main/scala/laika/parse/rst/ext/StandardTextRoles.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@ import laika.tree.Elements._
* through the API when creating a parser instance:
*
* {{{
* Parse as ReStructuredText.withDefaultTextRole("my-role-name")
* object RstExtensions extends RstExtensionRegistry {
* val blockDirectives = Nil
* val spanDirectives = Nil
* val textRoles = Nil
* override val defaultTextRole = "my-role-name"
* }
*
* val transformer = Transform from ReStructuredText to HTML using RstExtensions
* }}}
*
* See [[http://docutils.sourceforge.net/docs/ref/rst/roles.html]] for details.
Expand Down Expand Up @@ -96,7 +103,7 @@ class StandardTextRoles {
TextRole("sup", NoOpt:Options)(classOption)((opt, text) => Text(text, opt + Styles("superscript")))

/** The standard title-reference text role, the default text role in reStructuredText unless overridden
* with `ReStructuredText.withDefaultTextRole`.
* with `RstExtensionRegistry.defaultTextRole`.
*/
lazy val titleRef: TextRole =
TextRole("title-reference", NoOpt:Options)(classOption)((opt, text) => Emphasized(List(Text(text)), opt + Styles("title-reference")))
Expand Down
23 changes: 14 additions & 9 deletions core/src/main/scala/laika/parse/rst/ext/TextRoles.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,23 @@ import laika.util.~
*
* Before such a role directive can be used, an implementation has to be provided
* for the base role with the name `link`. For more details on implementing directives
* see [[laika.parse.rst.Directives]].
* see [[laika.parse.rst.ext.Directives]].
*
* The implementation of the `link` text role could look like this:
*
* {{{
* val rst = ReStructuredText withTextRoles (
* TextRole("link", "http://www.company.com/main/")(field("base-url")) {
* (base, text) => Link(List(Text(text)), base + text)
* }
* )
*
* Transform from rst to HTML fromFile "hello.rst" toFile "hello.html"
* val textRole = TextRole("link", "http://www.company.com/main/")(field("base-url")) {
* (base, text) => Link(List(Text(text)), base + text)
* }
*
* object MyDirectives extends RstExtensionRegistry {
* val textRoles = Seq(textRole)
* val spanDirectives = Seq()
* val blockDirectives = Seq()
* }
*
* Transform from ReStructuredText to HTML using
* MyDirectives fromFile "hello.rst" toFile "hello.html"
* }}}
*
* We specify the name of the role to be `link`, and the default value the URL provided as the
Expand All @@ -88,7 +93,7 @@ import laika.util.~
*
* If you need to define more fields or body content they can be added with the `~` combinator
* just like with normal directives. Likewise you can specify validators and converters for
* fields and body values like documented in [[laika.parse.rst.Directives]].
* fields and body values like documented in [[laika.parse.rst.ext.Directives]].
*
* Our example role can then be used in the following ways:
*
Expand Down

0 comments on commit 1458cdc

Please sign in to comment.