Object

laika.rst.ext

Directives

Related Doc: package ext

Permalink

object Directives

API for creating directives, the extension mechanism of reStructuredText. The API did not aim to mimic the API of the original Python reference implementation. Instead the goal was to create an API that is idiomatic Scala, fully typesafe and as concise as possible. Yet it should be flexible enough to semantically support the options of the Python directives, so that ideally most existing Python directives could theoretically get ported to Laika.

Entry points are the BlockDirective and SpanDirective objects. The Python reference parser does not make this distinction on the API level, but does this internally based on the context a directive is parsed in. Since Laika APIs are typesafe, the distinction is necessary since block level and span level directives create different types of document tree nodes. A SpanDirective can only be used in a substitution definition which can then be used within flow elements. A BlockDirective can be used directly in any location other block level content like paragraphs or lists can be used.

A directive may consist of any combination of arguments, fields and body elements:

.. myDirective:: arg1 arg2
 :field1: value1
 :field2: value2

 This is the body of the directive. It may consist of any standard or custom
 block-level and inline markup.

In the example above arg1 and arg2 are arguments, field1 and field2 are fields, and followed by body elements after a blank line. If there are no arguments or fields the blank line may be omitted. For the full specification, see http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#directives.

For each of these directive elements, the API offers a method to specify whether the element is required or optional, and an optional function to convert or validate the parsed value.

Consider the following simple example of a directive with just one argument and a body:

.. note:: This is the title

 This is the body of the note.

The implementation of this directive could look like this:

case class Note (title: String,
                 content: Seq[Block],
                 options: Options = NoOpt) extends Block
                                           with BlockContainer[Note]

object MyDirectives extends RstExtensionRegistry {
  val blockDirectives = Seq(
    BlockDirective("note") {
      (argument(withWS = true) ~ blockContent)(Note(_,_))
    }
  )
  val spanDirectives = Nil
  val textRoles = Nil
)

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 function was supplied). We need to set the withWS flag to true as an argument cannot have whitespace per default. The blockContent method specifies standard block content (any block-level elements that are supported in normal blocks, too) which results in a parsed value of type Seq[Block]. Finally you need to provide a function that accepts the results of the specified directive elements as parameters (of the corresponding type). Here we created a case class with a matching signature so can pass it directly as the target function. For a block directive the final result has to be of type Block which the Note class satisfies. Finally the directive gets registered with the ReStructuredText parser.

If any conversion or validation is required on the individual parts of the directive they can be passed to the corresponding function:

def nonNegativeInt (value: String) =
  try {
    val num = value.toInt
    Either.cond(num >= 0, num, s"not a positive int: $num")
  }
  catch {
    case e: NumberFormatException => Left(s"not a number: $value")
  }

case class Message (severity: Int,
                    content: Seq[Block],
                    options: Options = NoOpt) extends Block
                                              with BlockContainer[Message]

object MyDirectives extends RstExtensionRegistry {
  val blockDirectives = Seq(
    BlockDirective("message") {
      (argument(nonNegativeInt) ~ blockContent)(Message(_,_))
    }
  )
  val spanDirectives = Nil
  val textRoles = Nil
)

The function has to provide an Either[String, T] as a result. A Left result will be interpreted as an error by the parser with the string being used as the message and an instance of InvalidBlock containing the validator message and the raw source of the directive will be inserted into the document tree. In this case the final function (Message) will never be invoked. A Right result will be used as an argument to the final function. Note how the case class now expects an Int as the first parameter.

Finally arguments and fields can also be optional. In case they are missing, the directive is still considered valid and None will be passed to your function:

case class Message (severity: Option[Int],
                    content: Seq[Block],
                    options: Options = NoOpt) extends Block
                                              with BlockContainer[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.

In case of multiple arguments, the order you specify them is also the order in which they are parsed from the directive markup, with the only exception being that required arguments will always be parsed before optional ones, and arguments with whitespace need to come last.

Linear Supertypes
AnyRef, Any
Ordering
  1. Alphabetic
  2. By Inheritance
Inherited
  1. Directives
  2. AnyRef
  3. Any
  1. Hide All
  2. Show All
Visibility
  1. Public
  2. All

Type Members

  1. class Directive[E <: Element] extends RstExtension[DirectivePart[E]]

    Permalink

    Represents a single directive implementation.

  2. trait DirectiveParser extends AnyRef

    Permalink

    API to implement by the actual directive parser.

    API to implement by the actual directive parser. The methods of this trait correspond to the methods of the Parts object, only differing in return type.

  3. abstract class DirectivePart[+A] extends (DirectiveParser) ⇒ Result[A]

    Permalink

    Represents a single part (argument, field or body) of a directive.

  4. type DirectivePartBuilder[E] = (RecursiveParsers) ⇒ DirectivePart[E]

    Permalink

Value Members

  1. final def !=(arg0: Any): Boolean

    Permalink
    Definition Classes
    AnyRef → Any
  2. final def ##(): Int

    Permalink
    Definition Classes
    AnyRef → Any
  3. final def ==(arg0: Any): Boolean

    Permalink
    Definition Classes
    AnyRef → Any
  4. object BlockDirective

    Permalink

    API entry point for setting up a block directive.

  5. implicit object CanBuildDirectivePart extends CanBuild[DirectivePart]

    Permalink

    Type class required for using the generic Builders API with directives.

  6. object Parts extends Implicits

    Permalink

    The public user API for specifying the required and optional parts of a directive (arguments, fields or body) together with optional converter/validator functions.

  7. object SpanDirective

    Permalink

    API entry point for setting up a span directive that can be used in substitution definitions.

  8. final def asInstanceOf[T0]: T0

    Permalink
    Definition Classes
    Any
  9. def clone(): AnyRef

    Permalink
    Attributes
    protected[java.lang]
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  10. final def eq(arg0: AnyRef): Boolean

    Permalink
    Definition Classes
    AnyRef
  11. def equals(arg0: Any): Boolean

    Permalink
    Definition Classes
    AnyRef → Any
  12. def finalize(): Unit

    Permalink
    Attributes
    protected[java.lang]
    Definition Classes
    AnyRef
    Annotations
    @throws( classOf[java.lang.Throwable] )
  13. final def getClass(): Class[_]

    Permalink
    Definition Classes
    AnyRef → Any
  14. def hashCode(): Int

    Permalink
    Definition Classes
    AnyRef → Any
  15. final def isInstanceOf[T0]: Boolean

    Permalink
    Definition Classes
    Any
  16. final def ne(arg0: AnyRef): Boolean

    Permalink
    Definition Classes
    AnyRef
  17. final def notify(): Unit

    Permalink
    Definition Classes
    AnyRef
  18. final def notifyAll(): Unit

    Permalink
    Definition Classes
    AnyRef
  19. final def synchronized[T0](arg0: ⇒ T0): T0

    Permalink
    Definition Classes
    AnyRef
  20. def toString(): String

    Permalink
    Definition Classes
    AnyRef → Any
  21. final def wait(): Unit

    Permalink
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  22. final def wait(arg0: Long, arg1: Int): Unit

    Permalink
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )
  23. final def wait(arg0: Long): Unit

    Permalink
    Definition Classes
    AnyRef
    Annotations
    @throws( ... )

Inherited from AnyRef

Inherited from Any

Ungrouped