Repository: getnikola/nikola

Issue:
dispatch PANDOC_OPTIONS base on input extensions
<!--
Before creating an issue:
* make sure you are using an up-to-date version of Nikola
* search for existing issues that might be related

Describe your requested features as precisely as possible. -->

# Summary

Currently, `COMPILERS` only has a key `pandoc`, and `PANDOC_OPTIONS` is set for all the extensions specified there. The proposed feature simply suggests to have configurable dispatch logic to allow multiple extensions calling pandoc with a different set of `PANDOC_OPTIONS`.

# Example use case

My personal use for this would be to convert one of my site currently using `.md` and `.markdown` to mean a different target format. Both will be converted to HTML, but one of them is slideshow, another is normal "article"/post.

Another possible use case is, if one want to specify markdown extensions in pandoc, say `-t markdown+...-...`, then `COMPILERS['pandoc'] = ['.rst', '.md']` won't work with `PANDOC_OPTIONS = ['-t', 'markdown+...-...']` because that would be wrong input format for `.rst`.

# Suggested implementation

Probably the natural way is to promote

```py
PANDOC_OPTIONS: Union[list, Dict[str, list]]
```

where the keys are those in `COMPILERS['pandoc']`.

If it makes sense I can send a PR doing that. It seems that it only requires changes in <https://github.com/getnikola/nikola/blob/master/nikola/plugins/compile/pandoc.py#L52-L56>, is it true?


Discussion:
Please implement this. No changes other than `pandoc.py` should be necessary.
There's one thing I don't understand and missed last time I looked:

```py
self.config_dependencies = [str(site.config['PANDOC_OPTIONS'])]
```

What's this `self.config_dependencies` doing here? Turning it into a string is strange here. Is it just for something like logging?
`self.config_dependencies` is used to figure out if a post needs updating due to config changes. PANDOC_OPTIONS should be placed there — maybe doing it directly (without `str`) would work. It’s easy to test: if it doesn’t work, you’d (a) get an exception, (b) fail to get a rebuild when you change PANDOC_OPTIONS, (c) get a rebuild when you didn’t change anything (run `nikola build` twice+ in a row to test).

Resolving patch:
diff --git a/nikola/plugins/compile/pandoc.py b/nikola/plugins/compile/pandoc.py
--- a/nikola/plugins/compile/pandoc.py
+++ b/nikola/plugins/compile/pandoc.py
@@ -33,6 +33,8 @@
 import io
 import os
 import subprocess
+from typing import List
+from pathlib import Path
 
 from nikola.plugin_categories import PageCompiler
 from nikola.utils import req_missing, makedirs, write_metadata
@@ -49,11 +51,30 @@ def set_site(self, site):
         self.config_dependencies = [str(site.config['PANDOC_OPTIONS'])]
         super().set_site(site)
 
+    def _get_pandoc_options(self, source: str) -> List[str]:
+        """Obtain pandoc args from config depending on type and file extensions."""
+        # Union[List[str], Dict[str, List[str]]]
+        config_options = self.site.config['PANDOC_OPTIONS']
+        type_ = type(config_options)
+        if type_ is list:
+            pandoc_options = config_options
+        elif type_ is dict:
+            ext = Path(source).suffix
+            try:
+                pandoc_options = config_options[ext]
+            except KeyError:
+                self.logger.warn('Setting PANDOC_OPTIONS to [], because extension {} is not defined in PANDOC_OPTIONS: {}.'.format(ext, config_options))
+                pandoc_options = []
+        else:
+            self.logger.warn('Setting PANDOC_OPTIONS to [], because PANDOC_OPTIONS is expected to be of type Union[List[str], Dict[str, List[str]]] but this is not: {}'.format(config_options))
+            pandoc_options = []
+        return pandoc_options
+
     def compile(self, source, dest, is_two_file=True, post=None, lang=None):
         """Compile the source file into HTML and save as dest."""
         makedirs(os.path.dirname(dest))
         try:
-            subprocess.check_call(['pandoc', '-o', dest, source] + self.site.config['PANDOC_OPTIONS'])
+            subprocess.check_call(['pandoc', '-o', dest, source] + self._get_pandoc_options(source))
             with open(dest, 'r', encoding='utf-8-sig') as inf:
                 output, shortcode_deps = self.site.apply_shortcodes(inf.read())
             with open(dest, 'w', encoding='utf-8') as outf:


Test patch:
diff --git a/tests/test_plugins.py b/tests/test_plugins.py
--- a/tests/test_plugins.py
+++ b/tests/test_plugins.py
@@ -14,3 +14,7 @@ def test_command_version():
 
 def test_importing_plugin_task_galleries():
     import nikola.plugins.task.galleries  # NOQA
+
+
+def test_importing_plugin_compile_pandoc():
+    import nikola.plugins.compile.pandoc  # NOQA