dsl

object dsl extends Combinators

Provides the basic building blocks for defining directives, Laika's extension mechanism for creating custom tags for both, templates or text markup.

This object is used as part of the concrete objects Blocks.dsl, Spans.dsl and Templates.dsl respectively.

It contains several simple combinators that allow to specify the expected attributes and body elements of the directive, optional converters for these elements and the function responsible for producing the final node element.

In contrast to custom tag hooks in other template engines the result of a directive is not a string. In the same way as markup documents get transformed into a tree of elements before rendering, a directive produces a node of the tree to render. As a result, the directive can be used independent from the output format.

Entry points of the API are the Templates, Blocks and Spans objects for the three different directive types.

A directive may consist of any combination of attributes and body elements:

@:myDirective { arg1 = value1, arg2 = 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 attributes, followed by a body element enclosed in curly braces.

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

Consider the following simple example of a directive with just one argument and a body, for specifying a specially formatted inline note:

@: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 DirectiveRegistry {
  val blockDirectives = Seq(
    Blocks.create("note") {
      (defaultAttribute.as[String], parsedBody).mapN(Note(_,_))
    }
  )
  val spanDirectives = Seq()
}

val transformer = Transformer.from(Markdown).to(HTML).using(MyDirectives)

The defaultAttribute combinator specifies a required attribute of type String and without a name. The parsedBody combinator specifies standard block content (any block elements that are supported in normal markup, 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 Markdown parser. It can be registered for a reStructuredText parser, too, without any changes.

If any conversion of attributes is required it can be performed with the as[T] method:

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

val blockDirectives = Seq(
  Blocks.create("message") {
    (defaultAttribute.as[Int], blockContent).mapN(Message(_,_))
  }
)

In the example above the built-in Int decoder gets passed to the defaultAttribute combinator, but you can easily create and use your own instances of ConfigDecoder[T].

If required attributes or bodies are missing or any type conversion fails, an instance of InvalidBlock containing the error 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.

Finally attributes 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: Int,
                    content: Seq[Block],
                    options: Options = NoOpt) extends Block
                                              with BlockContainer[Message]

val blockDirectives = Seq(
  Blocks.create("message") {
    (defaultAttribute.as[Int].optional, blockContent).mapN {
      (severity, content) => Message(severity.getOrElse(0), content)
    }
  }
)

The attribute may be missing, but if it is present it has to pass the specified validator.

class Object
trait Matchable
class Any
dsl.type

Type members

Inherited classlikes

class AttributePart[T](key: AttributeKey, decoder: ConfigDecoder[T], isInherited: Boolean, requiredMsg: => String) extends DirectivePart[T]
Inherited from:
Combinators
class PositionalAttributes[T](decoder: ConfigDecoder[T]) extends DirectivePart[Seq[T]]
Inherited from:
Combinators
class SeparatedBodyPart[T](directives: Seq[SeparatorDirective[T]]) extends DirectivePart[Multipart[T]]
Inherited from:
Combinators

Value members

Inherited methods

A combinator that captures all attributes in a directive declaration.

A combinator that captures all attributes in a directive declaration.

This is useful when a directive implementation allows the use of any arbitrary attribute name, but leaves the burden of validation to the implementor of the directive. This part does not provide automatic error handling for missing required attributes for example.

Inherited from:
Combinators

Specifies a required attribute from the HOCON section of the directive.

Specifies a required attribute from the HOCON section of the directive.

Value parameters:
key

the key that must be used in markup or templates

Returns:

a directive part that can be combined with further parts

Inherited from:
Combinators
def attribute(position: Int): AttributePart[ConfigValue]

Specifies a required attribute from the positional attribute section of the directive.

Specifies a required attribute from the positional attribute section of the directive.

Value parameters:
position

the position within the attribute list

Returns:

a directive part that can be combined with further parts

Inherited from:
Combinators

Indicates that access to the document cursor is required. This may be required if the directive relies on information from the document structure, its title or the parent tree it is contained in.

Indicates that access to the document cursor is required. This may be required if the directive relies on information from the document structure, its title or the parent tree it is contained in.

Inherited from:
Combinators
def empty[T](result: T): DirectivePart[T]

Specifies an empty directive that does not accept any attributes or body elements.

Specifies an empty directive that does not accept any attributes or body elements.

Value parameters:
result

the fixed result each empty directive will produce

Returns:

a directive part that usually won't be combined with other parts

Inherited from:
Combinators
def parsedBody[T](parser: Parser => Parser[T]): DirectivePart[T]

Specifies a required body part with a custom parser.

Specifies a required body part with a custom parser.

The provided parser factory function has to accept a parameter for an instance providing access to the default parser for blocks and spans with all user and theme extensions installed.

This is useful for situations where some custom parsing logic has to be combined with the standard block/span parsing rules.

This is a fairly rare requirement, and most likely used the zero-param parsedBody method will suffice in most cases.

Returns:

a directive part that can be combined with further parts

Inherited from:
Combinators

Specifies a required body part parsed as spans or blocks, depending on the type of directive.

Specifies a required body part parsed as spans or blocks, depending on the type of directive.

Returns:

a directive part that can be combined with further parts

Inherited from:
Combinators

A combinator that captures all positional attributes in a directive declaration.

A combinator that captures all positional attributes in a directive declaration.

This is useful when the positional attributes represent a flexible, comma-separated list of values. Using as on the directive decodes '''all''' attributes as the same type. To decode with different types, use the combinators for individual positional attributes, e.g. attribute(0).

Inherited from:
Combinators
def rawBody: DirectivePart[String]

Specifies a required body part.

Specifies a required body part.

Returns:

a directive part that can be combined with further parts

Inherited from:
Combinators
def separatedBody[T](separators: Seq[SeparatorDirective[T]]): DirectivePart[Multipart[T]]

Specifies a required body part divided by separator directives.

Specifies a required body part divided by separator directives.

It is recommended that all separators extend a sealed trait, if the directive supports more than one separator kind. The separators need to be immediate children in the body element of the parent directive.

Value parameters:
separators

all separator directives accepted as children of this directive.

Returns:

a directive part that can be combined with further parts

Inherited from:
Combinators

Indicates that access to the source of the directive is required. This may be required if the directive needs to produce instances of InvalidElement for error scenarios, which requires passing the source.

Indicates that access to the source of the directive is required. This may be required if the directive needs to produce instances of InvalidElement for error scenarios, which requires passing the source.

This should normally be a rare requirement, as it is more convenient to use evalMap on the directive builder and pass simple strings describing any error and let the library insert the corresponding source.

Inherited from:
Combinators