A way to replace/override files in the InputTreeBuilder
?
#253
-
In the sbt-https-org plugin, which requires the sbt-typelevel plugin, we currently provide a default template like so: laikaInputs ~= {
_.delegate
.addStream(
IO.blocking(getClass.getResourceAsStream("default.template.html")),
DefaultTemplatePath.forHTML
)
}, Now, I'd like to add a default template in the sbt-typelevel plugin as well via the same sbt setting. However, that means that when the sbt-http4s-org plugin adds its own default template there will be two in the virtual tree, and it will fail because of the duplicate paths. Is there a way that to override the sbt-typelevel template with the sbt-http4s-org template? This is also relevant if a project is using one of these plugins but they want to override the default template with one provided in their own documentation sources. Thanks! (Btw, I am aware of |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 7 replies
-
I'd recommend not to pre-populate The more natural way to pre-populate something in a library or plugin would be to package it as a theme. This way anything added in user land automatically does obtain the override semantics. It's also less error-prone for users as most Laika keys remain empty (e.g. they can use The way this can be done is actually quite convenient, apart from the minor annoyance that you'd need to keep an extension method in the plugin for now that will later be added to Laika 0.19: object TypelevelHeliumExtensions extends ThemeProvider {
def build[F[_]: Sync]: Resource[F, Theme[F]] = ThemeBuilder[F]("Typelevel Helium Extensions")
.addInputs(InputTree[F].addStream(/* your templates */)
.addExtensions(/* GitHubFlavor, Syntax Highlighting */)
.build
}
// method will be added in Laika 0.19, for now it needs to sit inside the plugin
implicit class ThemeProviderOps(provider: ThemeProvider) {
def extend(extensions: ThemeProvider): ThemeProvider = new ThemeProvider {
def build[F[_] : Sync] = for {
base <- provider.build
ext <- extensions.build
} yield {
def overrideInputs[F[_]](base: InputTree[F], overrides: InputTree[F]): InputTree[F] = {
val overridePaths = overrides.allPaths.toSet
val filteredBaseInputs = InputTree(
textInputs = base.textInputs.filterNot(in => overridePaths.contains(in.path)),
binaryInputs = base.binaryInputs.filterNot(in => overridePaths.contains(in.path)),
parsedResults = base.parsedResults.filterNot(in => overridePaths.contains(in.path)),
sourcePaths = base.sourcePaths
)
overrides ++ filteredBaseInputs
}
new Theme[F] {
override def inputs: InputTree[F] = overrideInputs(base.inputs, ext.inputs)
override def extensions: Seq[ExtensionBundle] = base.extensions ++ ext.extensions
override def treeProcessor: Format => TreeProcessor[F] = fmt =>
base.treeProcessor(fmt).andThen(ext.treeProcessor(fmt))
}
}
}
} You can then define the theme setting like this: laikaTheme := tlSiteHeliumConfig.value.build.extend(TypelevelHeliumExtensions), Note that the code is untested in this form, but assembled from bits and pieces which are tested, so it'll probably work. I'd also love to address the classpath issue, but I'd need to run some tests myself before I might come up with an idea. |
Beta Was this translation helpful? Give feedback.
I'd recommend not to pre-populate
laikaInputs
in any way. The reason is that it is kind of reserved for "user land". Even if we'd find a way to make it work for the base case (one plugin overriding another), it would still break for users who browse the Laika docs and find out that they can put a default template into the root directory. They would still get a duplicate path error and this is intentional (to avoid silent errors or non-determinism when users define ambiguous inputs).The more natural way to pre-populate something in a library or plugin would be to package it as a theme. This way anything added in user land automatically does obtain the override semantics. It's also less er…