我目前正在玩 Hakyll 和 Pandoc。
我想从 Markdown 源(包括 LaTeX 中的内联数学)创建一个静态 HTML 网站。使用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
但是,我想使用Hakyllpandoc-katex
中的过滤器并获得与上述命令完全相同的结果(目前),即我想使用 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 的弃用版本。显然,writerStandalone
在早期版本的 Pandoc 中有一个选项,但它不再存在(尽管命令行工具仍然有 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
建议s 应该是文件名,但对于我上下文中的Identifier
某些s(例如对于字段;参见变量),将文件名作为键是没有意义的。我想我误解了这种类型的用途。我应该如何看待这些s?Item
author
authorItem
Item
- 有没有办法获取
Context
命令行工具在进行转换时使用的?默认设置Context
似乎比我的快速草稿复杂得多,例如,它从 Markdown 文件的元数据中读取摘要,并将每个段落放在单独的<p> ... </p>
HTML 标记之间。我知道有一个metadataField :: Context a
,但它似乎不是我想要的。
除了这些具体问题之外,一般问题是:
- 我这样做对吗?或者是否有一种更简单的方法来完成我尝试做的事情(即使用 Hakyll 复制 Haskell 中初始 pandoc shell 命令的输出)?
最好的方法可能是使用
writerTemplate
Pandoc传递WriterOptions
默认模板,如下所示compileDefaultTemplate
:另请参阅pandoc 问题 #10209,它指出了类似的方法。
附带问题:
Item
indeed 主要用于绑定到站点树中的文件路径的内容。有时,使用虚假路径作为标识符是有意义的 — 例如,在使用规则合成某些内容时create
。但是,这通常不是人们为了设置上下文字段而想要做的事情,因为可能有更直接的方法可以做到这一点。(特别是,如果与此答案不同,您使用的是 Hakyll 的模板,则不必明确定义包含在源文件的元数据标头中的字段,因为 HakylldefaultContext
已经通过包含 来涵盖了这一点metadataField
。)虽然 Pandoc 提供了操作其自身元数据的方法(我自己从未使用过;
Text.Pandoc.Writers.Shared
可能是开始浏览的好地方),但 Pandoc 和 Hakyll 的模板系统看起来相似但又有区别,特别是 Hakyll 的Context
类型与 Pandoc 对应类型不同。最后要说的是,值得一提的是,如果您完全无法在 Hakyll 中重现 Pandoc 的输出,那么最后的办法就是设置
unixFilter
一个可以运行命令行 Pandoc 的编译器。