我目前正在与 Hakyll 和 Pandoc 一起玩。
我想从 Markdown 源代码创建一个静态 HTML 网站,包括 LaTeX 中的内联数学。使用 pandoc-katex 我可以使用以下命令进行转换:
$ pandoc -f markdown -t html --filter pandoc-katex --css "https://cdn.jsdelivr.net/npm/katex@$(pandoc-katex --katex-version)/dist/katex.min.css" --css "https://pandoc.org/demo/pandoc.css" --standalone -o output.html input.md
但是,我想在
Hakyll中使用
pandoc-katex
过滤器并获得与上面命令(目前)相同的结果 exact,即我想使用 Pandoc 的标准 HTML 模板,使其加载两个 CSS文件并以与上述命令相同的方式处理 input.md
中的任何可用元数据是的。
我导出的标准 HTML 模板如下:
$ pandoc -D html > default-template.html
使用
pandocCompilerWithTransformM
,我能够使用
pandoc-katex
过滤器:katexCompiler = pandocCompilerWithTransformM defaultHakyllReaderOptions (defaultHakyllWriterOptions) katexFilter
where katexFilter = recompilingUnsafeCompiler
. runIOorExplode
. applyFilters noEngine def [JSONFilter "pandoc-katex"] []
在 Hakyll 中使用这个编译器,我只能得到 HTML 文件的正文部分。我在网上搜索了此问题的解决方案,但我找到的所有信息似乎都涉及已弃用的 Pandoc 版本。显然在早期版本的 Pandoc 中有一个
writerStandalone
选项,但它
不再存在(尽管命令行工具 仍然有
opStandalone
并且上面使用的 --standalone
参数显然有效)。我目前所做的是,我使用 loadAndApplyTemplate "templates/default-template.html" myCtx
应用默认模板,然后尝试手动复制
myCtx
中的默认上下文。这显然不应该这样做。这是我尝试的一个最小的例子(抱歉,它仍然有点长 - 这正是问题所在):
{-# LANGUAGE OverloadedStrings #-}
import Text.Pandoc
import Text.Pandoc.Filter
import Text.Pandoc.Scripting
import Hakyll
css1Item = Item (fromFilePath "css/katex.min.css") "https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css"
css2Item = Item (fromFilePath "css/pandoc.css") "https://pandoc.org/demo/pandoc.css"
authorItem = Item (fromFilePath "general") "Jon Doe"
stylesString = "/* 15 lines of CSS */"
myCtx :: Context String
myCtx = dateField "date" "%B %e, %Y"
<> constField "pagetitle" "My Title"
<> constField "styles.html" stylesString
<> listCtx "author" [authorItem]
<> listCtx "author-meta" [authorItem]
<> listCtx "css" [css1Item, css2Item]
<> listCtx "header-includes" []
<> listCtx "include-before" []
<> listCtx "include-after" []
<> defaultContext
listCtx :: String -> [Item String] -> Context String
listCtx name lst = listField name ctx (return $ lst)
where ctx = field name (return . itemBody)
katexCompiler = pandocCompilerWithTransformM defaultHakyllReaderOptions (defaultHakyllWriterOptions) katexFilter
where katexFilter = recompilingUnsafeCompiler
. runIOorExplode
. applyFilters noEngine def [JSONFilter "pandoc-katex"] []
main :: IO ()
main = hakyll $ do
match "templates/default-template.html" $ compile templateBodyCompiler
match "input.md" $ do
route $ setExtension ".html"
compile $ katexCompiler
>>= loadAndApplyTemplate "templates/default-template.html" myCtx
我有两个具体问题:
Item
Identifier
类型的键与值相关联。 Identifier
的构造函数建议 Identifier
应该是文件名,但对于我上下文中的某些 Item
(例如,对于 author
字段;请参阅变量 authorItem
),有一个文件名称作为键没有意义。我想我误解了这种类型的目的。我该如何看待这些Item
?有没有办法获得命令行工具在进行转换时使用的Context
Context
似乎比我的快速草稿涉及更多,例如它从 Markdown 文件的元数据中读取摘要,并将每个段落放在单独的 <p> ... </p>
HTML 标签之间。我知道有一个metadataField :: Context a
,但它似乎不是我想要的。
我这样做是否正确,或者是否有一种更简单的方法来完成我尝试做的事情(即使用 Hakyll 在 Haskell 中复制初始 pandoc shell 命令的输出)?
writerTemplate
WriterOptions
来传递默认模板,如
compileDefaultTemplate
:所示
main :: IO ()
main = do
pandocTmpl <- runIoOrExplode $ compileDefaultTemplate "html"
let katexOpts = defaultHakyllWriterOptions
{ writerTemplate = Just pandocTmpl
, writerHTMLMathMethod = KaTeX defaultKaTeXURL
-- And whatever else you need.
}
katexCompiler = pandocCompilerWith defaultHakyllReaderOptions katexOpts
hakyll $ do
-- etc.
match "input.md" $ do
route $ setExtension ".html"
compile katexCompiler
另请参阅pandoc Issue #10209附带问题:
我应该如何看待这些
Item
?
Item
确实主要用于绑定到站点树中的文件路径的内容。有时,使用假路径作为标识符是有意义的 - 例如,当使用
create
规则合成某些内容时。然而,这通常不是人们为了设置上下文字段而想要做的事情,因为可能有更直接的方法来做到这一点。 (特别要注意的是,原则上您不必显式定义源文件的元数据标头中包含的字段,因为 Hakyll 的
defaultContext
已经通过包含 metadataField
涵盖了这一点。)有没有办法获得命令行工具在进行转换时使用的
Context
?
虽然 Pandoc 提供了操作其自身元数据的方法(我自己从未使用过;
可能是一个开始浏览的好地方),但重要的是要强调 Pandoc 和 Hakyll 的模板系统看起来相似,但是不同,特别是 Hakyll 的
Context
类型与其 Pandoc 对应类型不同。
最后一点,值得一提的是,如果您完全陷入尝试在 Hakyll 中重现 Pandoc 的输出的情况,最后的选择是使用 设置一个编译器,该编译器可以运行到命令行潘多克。