The core of the Laika toolkit does not depend on sbt in any way, and therefore comes with a plugin that provides the glue necessary to expose Laika's feature set as sbt tasks and settings.

This chapter only covers the topics which are specific to using Laika with sbt, while most other parts of the manual apply to both embedded use and sbt plugin.

Adding the Plugin to the Build

Laika's sbt plugin requires sbt 0.13.x.

First add the plugin to project/plugins.sbt:

addSbtPlugin("org.planet42" % "laika-sbt" % "0.6.0")

If you want to install it globally, add the line above to ~/.sbt/0.13/plugins/build.sbt instead.

Then, in your project's build.sbt, simply import the default settings:

LaikaPlugin.defaults

You can now add content to the directory src/docs inside your project and run laika:site from within sbt to generate the site in target/docs/site. See the following sections for details.

Editing Content

Laika expects the site content to be organized in a directory. By default this is src/docs. In contrast to several similar tools content in Laika is hierarchical. Subdirectories can contain markup files, too, and the hierarchy can get visualized in a table of contents. Furthermore you can also specify additional directories to be merged into the main directory, which allows to keep reusable templates and styles (other tools would call it "themes") in a separate place.

The directories can contain different types of files:

  • All of the supported text markup formats (currently this is Markdown and reStructuredText). The default parser of the plugin allows to use both formats in the same document tree (including cross linking between the two formats) and recognizes them by the file suffix (.md or .markdown for Markdown and .rst for reStructuredText).

  • A configuration file directory.conf which allows to specify the document order for navigation, the directory title, autonumbering options and other settings.

  • A template file default.template.<format> that gets applied to all markup files in this directory (and its subdirectories unless overridden). The suffix may be any output format in Laika that supports templating, currently this is .html for HTML output and .fo for PDF or XSL-FO output. A very basic HTML template may look like this:

    <html>
      <head>
        <title>{{document.title}}</title>
      </head>
      <body>
        <div class="content">
          {{document.content}}
        </div>
      </body>
    </html>

    The two placeholders enclosed in double curly braces will be replaced with the title and content of the parsed markup document.

  • Other static files that simply get copied to the target directory.

For more details on the template engine, see the chapter Templates.

For features like titles, sections, cross-linking, auto-numbering, document order and tables of content, see the chapter Document Structure.

For details about Markdown and reStructuredText see the chapter Supported Markup.

For details about rendering see the chapter Supported Output Formats.

Laika Tasks for sbt

Laika currently supports the following sbt tasks:

  • laika:site Processes all files from the source directories and renders the result to target/docs/site (unless overridden). By default only HTML output gets rendered by this task. You can add API documentation for a Scala project with the includeAPI setting and a PDF file rendered from the same markup sources with the includePDF setting.

  • laika:packageSite
    Packages the site into a zip file inside the target/docs directory. Depends on the laika:site task.

  • laika:clean
    Deletes the contents of Laika's target directory only. Alternatively you can also run the global clean task which will delete content generated by Laika together with the target directories of other tasks.

  • laika:generate Generates the output format specified as arguments to this task. For example laika:generate html pdf generates an HTML site as well as a PDF file from the parsed source markup. The markup will only get parsed once, therefore this task is very efficient for producing multiple output formats. The formats supported as arguments to this task are html, pdf, xslfo and prettyPrint. If you only want to generate one output format there are shortcut tasks for each of them: (laika:html, laika:pdf, laika:xslfo, laika:prettyPrint)

The next version of the plugin will add support for epub (0.7 release).

The default settings for these tasks should be sufficient for many use cases. The following sections show how you can override the defaults.

Basic Settings

The basic structure of a build with custom Laika settings looks like this:

import LaikaKeys._

name := "..."

organization := "..."

version := "0.1"

LaikaPlugin.defaults

<key> in Laika := <value>

<key> in Laika := <value>

[...]

Where <key> is one of the setting keys listed below.

All keys for the Laika plugin are scoped to the Laika configuration, as the keys are a mix of reused built-in keys and custom Laika keys.

If you don't want to specify the Laika configuration with every setting you can also use an alternative syntax:

inConfig(Laika)(Seq(
  <key> := <value>,
  <key> := <value>
))

The downside of this syntax is that you cannot use blank lines between settings (in .sbt files).

The following list shows the names, types and default values of the basic settings:

  • sourceDirectories - Seq[File] - default Seq("src/docs")
    Specifies one or more source directories to process. All specified directories can contain any of the supported file types and will get merged into a tree with a single root.

  • target - File - default target/docs
    Specifies the directory where the plugin should generate the site. This key also has separate values scoped to the individual tasks: target in site (default target/docs/site), target in copyAPI (default target/docs/site/api) and target in packageSite (default target/docs).

  • excludeFilter - FileFilter - default HiddenFileFilter
    Specifies files to exclude from processing. Note that Laika ignores any includeFilter you set, as the tool needs more than a simple yes/no decision for deciding how to process files. If a simple exclusion filter is not sufficient, you can specify a docTypeMatcher as explained in Settings for Customization Hooks.

  • includeAPI - Boolean - default false
    Indicates whether generated scaladoc APIs should be included when running the laika:site task. The folder for the API can be set with target in copyAPI (default target/docs/site/api).

  • includePDF - Boolean - default false Indicates whether a generated PDF file should be included when running the laika:site task. The file name for the PDF can be set with artifact in pdf (default target/docs/site/<noduleName>-<version>.pdf).

  • encoding - String - default UTF-8
    Specifies the character encoding for input and output.

  • strict - Boolean - default false
    Indicates whether all Laika-specific extensions to the text markup formats should be disabled. When strict is set to true, features like configuration headers in markup files or Laika directives are no longer available.

  • rawContent - Boolean - default false
    Indicates whether raw content like embedded verbatim HTML is supported in text markup. Setting this flag to true has different effects for the two supported markup formats: In Markdown it enables support for raw HTML interspersed with text markup like specified in the original Markdown syntax description, in reStructuredText it enables the standard raw directive which allows to embed content in any target format (although in the context of this plugin only HTML would make sense).

  • logMessageLevel - Option[MessageLevel] - default Some(Warning)
    Specifies the log level for problems found in markup files, like unresolved link references or directives. For most of these errors the parser recovers and includes the illegal node as plain text in the output, but in most cases you want to fix these issues and these logs help with that. Info and Debug levels are currently not used by Laika.

  • renderMessageLevel - Option[MessageLevel] - default None
    In addition to just logging errors, illegal nodes can also be rendered to the target HTML, so you can see them in context. The messages are rendered with a span with two classes: system-message and the second specifying the level (error, warning, etc.), so you can add CSS to easily identify these nodes in the page.

  • parallel - Boolean - default true
    Indicates whether the parsers and renderers should be processed in parallel. If set to true, there is only a short synchronization step between parsing and rendering where things like cross references get resolved. Most of the heavy work before and after that can be done for all input and output files in parallel.

Settings for Customization Hooks

Laika allows to easily add custom logic to the processing of documents. When all you need to adjust is the processing of one or more particular nodes types, a simple partial function allows to do that while still benefiting from the defaults for all other node types.

When working with the document tree (the internal AST representing the document structure), it is most comfortable to add the following imports to the build:

import laika.tree.Documents._
import laika.tree.Elements._

Custom Renderers

A custom renderer allows to override the generated output for one or more specific node types, while falling back to the default renderers for all other node types.

The siteRenderers setting is of type Seq[HTMLWriter => RenderFunction] where RenderFunction is a type alias for PartialFunction[Element,Unit]. Element is the base trait for all nodes in a document tree. By default the siteRenderers setting is empty, meaning Laika will use the default renderers for all node types.

The following simple example shows how you can add a style to the renderer for the <em> tag:

siteRenderers in Laika += siteRenderer { out => {
  case Emphasized(content, _) => 
      out << """<em class="big">""" << content << "</em>" 
}}

For more details see the chapter Customizing Renderers.

There are similar settings for customizing renderers of other output formats.

The foRenderers setting is of type Seq[FOWriter => RenderFunction] and can be used to modify the output of the XSL-FO and PDF renderers (the latter uses XSL-FO as an interim format). In most cases it is more convenient to style a PDF with Laika's CSS support.

Finally the prettyPrintRenderers setting is of type Seq[TextWriter => RenderFunction] and can be used to adjust pretty print output, which shows a textual representation of the document tree model and is primarily useful for debugging purposes. Adjusting this renderer should rarely be required.

Custom Rewrite Rules

When customizing renderers you have to repeat the step for each output format (subsequent versions will add support for PDF and epub). A rewrite rule lets you express a transformation of a node inside the document tree before rendering, so it would have an effect on all output formats.

The rewriteRules setting is of type Seq[DocumentContext => RewriteRule] where RewriteRule is a type alias for PartialFunction[Element,Option[Element]]. By default this setting is empty, meaning Laika will only use the built-in rewrite rules like those for resolving link references.

If the partial function is not defined for a particular element the old element is kept in the tree. If it returns Some(Element) this element replaces the old one. If the function returns None the old element is removed from the tree.

The following (somewhat contrived, but simple) example shows how to turn each Emphasized node into a Strong node:

rewriteRules in Laika += rewriteRule { 
  case Emphasized(content, opts) => Some(Strong(content, opts))
}

For more details see the chapter Document Tree Rewriting.

Custom Document Type Matcher

A document type matcher categorizes an input document based on its path. It is a function that takes a Path instance (from the Laika API, not sbt.Path) and returns the matching DocumentType with valid values being one of the following objects:

Markup, Template, Dynamic, Static, Config, Ignored

These values correspond to the descriptions provided in Document Types.

The setting is of type Option[Path => DocumentType] and the default is None, which means that the built-in DefaultDocumentTypeMatcher will be used. Its naming conventions will probably be sufficient in almost all use cases. The matcher will only be used for inputs which make it past the excludeFilter.

Settings for Directives

Directives are Laika's extension hook for both, templates and text markup. They allow to add new tag-like constructs without touching the existing parsers.

Laika supports two flavors of directives, one compatible with the reStructuredText specification and the other with a Laika-specific syntax.

The reStructuredText variant is supported for full compatibility with the reStructuredText specification and reuse of existing reStructuredText files making use of some of the standard directives. Laika supports almost all of the directives defined in the specification. Use the keys rstSpanDirectives or rstBlockDirectives for adding custom implementations to the built-in ones. For more details on this directive type see Extending reStructuredText.

The Laika variant is more flexible, as it can be used in template files as well as Markdown and reStructuredText markup. It is also somewhat simpler in syntax and configuration while offering the same functionality. It comes with a small set of predefined directives in this syntax. Use the keys spanDirectives, blockDirectives or templateDirectives for adding custom implementations. For more details on this directive type see Directives.

The examples in the two chapters linked above show how to implement a directive and register it either for use in sbt or in embedded mode.

Using Laika for GitHub Pages

If you want to generate the site and push it up to the gh-pages branch of your GitHub repository in one go, you can combine Laika and the sbt-ghpages plugin.

Add the sbt-ghpages plugin to project/plugins.sbt:

resolvers += "jgit-repo" at "http://download.eclipse.org/jgit/maven"

addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.5.2")

Configure the plugins in build.sbt:

import LaikaKeys._
import GhPagesKeys._

LaikaPlugin.defaults

ghpages.settings

git.remoteRepo := "git@github.com:{your username}/{your project}.git"

git.gitCurrentBranch := "master"

mappings in synchLocal := (mappings in LaikaKeys.site in Laika).value

It is the last line that connects the two plugins, but there is no need to understand how that line works.

Finally run the task ghpages-push-site. This will also trigger the Laika transformation if the site output is not up-to-date.