jgm / pandoc

Universal markup converter
https://pandoc.org
Other
34.69k stars 3.39k forks source link

Allow testing metadata values in templates #3697

Open iandol opened 7 years ago

iandol commented 7 years ago

I was wondering if the ability to test values could be added to the template language, so we could do something like:

$if(documentclass!='memoir')$
$if(linestretch)$
\usepackage{setspace}
\setstretch{$linestretch$}
$endif$
$endif$

This would give us a bit more flexibility in making templates...

tarleb commented 7 years ago

Instead of changing the pandoc templating engine, one could extend lua scripting to the point that scripts get control over how the document is rendered. This would allow users to use a lua templating engine of their chosing, e.g. luastache. Performance would be worse, but users would gain a lot of freedom this way. As a side effect, it would become possible to write a full-blown static site generator with nothing but pandoc and lua scripts.

jgm commented 7 years ago

+++ Albert Krewinkel [May 26 17 02:11 ]:

Instead of changing the pandoc templating engine, one could extend lua scripting to the point that scripts get control over how the document is rendered. This would allow users to use a lua templating engine of their chosing, e.g. [1]luastache. Performance would be worse, but users

It's already possible, with custom lua writers. Just don't specify -s, and have the custom writer do your templating.

tarleb commented 7 years ago

Wouldn't that require users to re-implement any writer they'd want to use in lua? The scripting-idea might be blinding me.

Disregarding the issue at hand, how do you feel about allowing a script parameter? I imagine it to just pass all other options on to the script, execute the script, and exit afterwards.

jgm commented 7 years ago

@tarleb I may have misunderstood your original idea. Yes, I was talking about a case where the whole writer is implemented in lua.

But actually, the sort of thing you have in mind -- rendering with a pandoc writer, but using an external program to do the templating -- is already possible with pandoc.

Create a template with:

$meta-json$
$body$

and call pandoc with this template. Pipe the result through a lua (perl/ruby/python/whatever) program that reads a JSON object from the input stream, reads the rest of the input stream as a string, parses the JSON, and populates a template.

That said, I'd certainly consider proposals to streamline this sort of thing with lua scripting.

jgm commented 7 years ago

On this general subject, I've often considering moving to a more standard templating system, like hastache (Haskell's mustache implementation). I always get hung up on a few missing features, e.g. if I recall correctly, hastache has nothing corresponding to our $for(var)$...$sep$...$endfor$ (i.e., nothing corresponding to the $sep$ part). hastache would give us partials (a frequent request) but not the sort of equality tests requested here.

On the equality tests: one difficulty is that a variable in pandoc's template system needn't be a string -- it can be a list, a boolean, an object with fields. One could, I suppose, do a string equality test on the result of rendering the variable (which will be a string). I know that if we implemented this feature, the next request would be to support boolean combinations of tests...

Maybe there are other templating systems that we should consider.

jgm commented 7 years ago

Btw @tarleb you might be interested in my lua implementation of pandoc-style templates, here: https://github.com/jgm/lcmark

tarleb commented 7 years ago

Oh wow, that $meta-json$\n$body$ approach is awesome.

Thanks for the lcmark link; I don't know how I had missed that project till now. :open_mouth:

iandol commented 7 years ago

So it appears such {{logic-less templating systems}} cannot perform a simple boolean test, or they requires a separate view methods system to enable the "logic".

What about using Lua itself as the templating language? Something like: https://github.com/dannote/lua-template/ or https://john.nachtimwald.com/2014/08/06/using-lua-as-a-templating-engine/ or https://github.com/bungle/lua-resty-template which do allow logic by running lua code directly.

iandol commented 7 years ago

Here is a SO page with quite a few alternatives to hastache:

https://stackoverflow.com/questions/5770168/templating-packages-for-haskell

Some examples:

http://www.haskell.org/haskellwiki/HStringTemplate

https://wiki.haskell.org/Bravo

jgm commented 7 years ago

Bravo compiles the templates at compile time. We need run-time.

I've used HStringTemplate in gitit. It is powerful, but behaves a bit surprisingly sometimes. I also don't know how well maintained it is -- it only has 5 commits since 2014.

jgm commented 7 years ago

Using lua, and perhaps automatically providing a simple template engine like https://github.com/dannote/lua-template, might make sense, actually. [Update: https://github.com/leafo/etlua looks like a good option. It's just one lua file with no dependencies, and it seems to do sandboxing.]

Ideally everything could be sandboxed, so that only the lua functions we explicitly provide can be used. Users should be able to be confident that using a template won't cause IO operations other than the reading of subtemplates (partials).

@tarleb raised the possibility of adding this to the lua scripting functionality, but I'm thinking it might make more sense to support these as first-class templates. We could integrate this smoothly by saying that if a template path ends in .etlua (or something), it is treated as a lua template. This would allow the old templates to be used. But at some point we might want to replace all the default templates with lua templates; we could then also provide an automated tool to convert, which people could use for their custom templates.

jgm commented 7 years ago

Of course one problem with lua templates is that they'd have to be run in the IO monad. Currently we have templates that will work in a pure context.