Repository: getnikola/nikola

Issue:
 ReST plugin strips single title
I've noticed that if I have a .rst post which has one header, that one will be removed from the output. So if I have two pages:

Page 1:

```
Test
====

This is a test.
```

Page 2:

```
Test
====

This is a test.

Test2
=====

This is another test.
```

Then I would expect that Page 1 looks like Page 2 with the second section removed, but it ends up being just "This is a test." for Page 1 with the section header removed. I don't know why this is the default behavior, but I noticed it can be changed by modifying the ReST plugin by replacing

``` .py
return pub.writer.parts['docinfo'] + pub.writer.parts['fragment'], pub.document.reporter.max_level, pub.settings.record_dependencies
```

with

``` .py
return pub.writer.parts['html_title'] + pub.writer.parts['docinfo'] + pub.writer.parts['fragment'], pub.document.reporter.max_level, pub.settings.record_dependencies
```

at the end of `rst2html`.

I guess changing the default is not a good idea, but would it be acceptable to add an option to force inclusion of the HTML title?



Discussion:
This is a rather problematic thing. You see, the first paragraph is considered the document title by reST. We accept that as a way of specifying the title of the entire post.

If we display that, people who use this format will have their post titles duplicated. Doing this in config might be problematic for people with mixed styles — and the Pelican support (which does not exist yet…) would actually require that. I think this can be made a bit smarter, but we need to know whether or not the document title was used. But then we’d need to tell the compiler that.

That's true, but even if I create a post with two headers:

```
Test
====

Test
-----

This is a test.
```

it will also result in just "This is a test.". (I think I even tried three different levels; they all went away.)

What about adding support for setting this via metadata? I.e. I could write:

```
.. title: This is a title.
.. show_all_titles: True

Test
====

This is a test.
```

And it will include the title. Would that be an acceptable solution?

(This could also be combined with a global variable which is by default `False`, and if the setting is specified in a post it will override the global behavior. But I'm already happy enough about being able to control this per post/page.)

Your first thing is probably caused by subtitles also being a reST feature.

A best implementation is a silent one that does the right thing: it knows where the title came from. But this might require a change of things, because we’d need to tell `compile_html` about that.

Hmm, extracting that from the metadata and passing it on to `compile_html` is kind of more challenging; adding a new argument breaks compile plugins not delivered with Nikola. I guess that's not an option :)

Another possibility would be adding a new function to `PageCompiler`, like `compile_html_new`, which accepts one more argument, and then by default calls the old `compile_html` with less arguments, except for the ReST plugin, where it passes the parameters on. That's backwards compatible, but kind of sucks (the `PageCompiler` interface gets more messy).

The third option is to implement a global setting only. That doesn't require more information to be passed to `compile_html`. It has the drawback that you cannot toggle the setting per post, though. (For me that's fine, but as you mentioned it, for others it might not be.)

Or is there another (halfway clean) option?

(Ok, another solution is to create my own ReST plugin which re-uses most of Nikola's ReST plugin's code and changes this bit. This is what I'm doing now, until this issue gets resolved in one way or another.)

Another solution is to make the rest plugin not use the DocTitle transform.


Resolving patch:
diff --git a/nikola/plugins/compile/rest/__init__.py b/nikola/plugins/compile/rest/__init__.py
--- a/nikola/plugins/compile/rest/__init__.py
+++ b/nikola/plugins/compile/rest/__init__.py
@@ -82,7 +82,8 @@ def compile_html_string(self, data, source_path=None, is_two_file=True):
         }
 
         output, error_level, deps = rst2html(
-            data, settings_overrides=settings_overrides, logger=self.logger, source_path=source_path, l_add_ln=add_ln, transforms=self.site.rst_transforms)
+            data, settings_overrides=settings_overrides, logger=self.logger, source_path=source_path, l_add_ln=add_ln, transforms=self.site.rst_transforms,
+            no_title_transform=self.site.config.get('NO_DOCUTILS_TITLE_TRANSFORM', False))
         if not isinstance(output, unicode_str):
             # To prevent some weird bugs here or there.
             # Original issue: empty files.  `output` became a bytestring.
@@ -178,11 +179,15 @@ class NikolaReader(docutils.readers.standalone.Reader):
     def __init__(self, *args, **kwargs):
         """Initialize the reader."""
         self.transforms = kwargs.pop('transforms', [])
+        self.no_title_transform = kwargs.pop('no_title_transform', False)
         docutils.readers.standalone.Reader.__init__(self, *args, **kwargs)
 
     def get_transforms(self):
         """Get docutils transforms."""
-        return docutils.readers.standalone.Reader(self).get_transforms() + self.transforms
+        transforms = docutils.readers.standalone.Reader(self).get_transforms() + self.transforms
+        if self.no_title_transform:
+            transforms = [t for t in transforms if str(t) != "<class 'docutils.transforms.frontmatter.DocTitle'>"]
+        return transforms
 
     def new_document(self):
         """Create and return a new empty document tree (root node)."""
@@ -247,7 +252,8 @@ def rst2html(source, source_path=None, source_class=docutils.io.StringInput,
              parser=None, parser_name='restructuredtext', writer=None,
              writer_name='html', settings=None, settings_spec=None,
              settings_overrides=None, config_section=None,
-             enable_exit_status=None, logger=None, l_add_ln=0, transforms=None):
+             enable_exit_status=None, logger=None, l_add_ln=0, transforms=None,
+             no_title_transform=False):
     """Set up & run a ``Publisher``, and return a dictionary of document parts.
 
     Dictionary keys are the names of parts, and values are Unicode strings;
@@ -265,7 +271,7 @@ def rst2html(source, source_path=None, source_class=docutils.io.StringInput,
              reStructuredText syntax errors.
     """
     if reader is None:
-        reader = NikolaReader(transforms=transforms)
+        reader = NikolaReader(transforms=transforms, no_title_transform=no_title_transform)
         # For our custom logging, we have special needs and special settings we
         # specify here.
         # logger    a logger from Nikola


Test patch: