Skip to content

Commit

Permalink
✨ NEW: Add myst_title_to_header configuration (#492)
Browse files Browse the repository at this point in the history
Setting `myst_title_to_header = True` allows for the value of a `title` key,
in the Markdown front-matter, to be treated as the initial H1 header
(the value will be parsed as Markdown).
  • Loading branch information
chrisjsewell committed Jan 9, 2022
1 parent 74e91e6 commit 574b525
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 1 deletion.
3 changes: 3 additions & 0 deletions docs/sphinx/reference.md
Expand Up @@ -32,6 +32,9 @@ To do so, use the keywords beginning `myst_`.
* - `myst_linkify_fuzzy_links`
- `True`
- If `False`, only links that contain a scheme (such as `http`) will be recognised as external links.
* - `myst_title_to_header`
- `False`
- If `True`, the `title` key of a document front-matter is converted to a header at the top of the document.
* - `myst_heading_anchors`
- `None`
- Enable auto-generated heading anchors, up to a maximum level, [see here](syntax/header-anchors) for details.
Expand Down
20 changes: 19 additions & 1 deletion docs/syntax/syntax.md
Expand Up @@ -398,9 +398,27 @@ This is a YAML block at the start of the document, as used for example in

:::{seealso}
Top-matter is also used for the [substitution syntax extension](syntax/substitutions),
and can be used to store information for blog posting (see [ablog's myst-parser support](https://ablog.readthedocs.io/manual/markdown/)).
and can be used to store information for blog posting (see [ablog's myst-parser support](https://ablog.readthedocs.io/en/latest/manual/markdown/)).
:::

### Setting a title

If `myst_title_to_header` is set to `True`, and a `title` key is present in the front matter,
then the title will be used as the document's header (parsed as Markdown.
For example:

```md
---
title: My Title with *emphasis*
---
```

would be equivalent to:

```md
# My Title with *emphasis*
```

(syntax/html_meta)=

### Setting HTML Metadata
Expand Down
3 changes: 3 additions & 0 deletions myst_parser/docutils_renderer.py
Expand Up @@ -831,6 +831,9 @@ def render_front_matter(self, token: SyntaxTreeNode) -> None:
)
)

if data.get("title") and self.md_config.title_to_header:
self.nested_render_text(f"# {data['title']}", 0)

def dict_to_fm_field_list(
self, data: Dict[str, Any], language_code: str, line: int = 0
) -> nodes.field_list:
Expand Down
9 changes: 9 additions & 0 deletions myst_parser/main.py
@@ -1,3 +1,6 @@
"""This module holds the global configuration for the parser ``MdParserConfig``,
and the ``create_md_parser`` function, which creates a parser from the config.
"""
from typing import Any, Callable, Dict, Iterable, Optional, Sequence, Tuple, Union, cast

import attr
Expand Down Expand Up @@ -146,6 +149,12 @@ def check_extensions(self, attribute, value):
metadata={"help": "Add line numbers to code blocks with these languages"},
)

title_to_header: bool = attr.ib(
default=False,
validator=instance_of(bool),
metadata={"help": "Convert a `title` field in the top-matter to a H1 header"},
)

heading_anchors: Optional[int] = attr.ib(
default=None,
validator=optional(in_([1, 2, 3, 4, 5, 6, 7])),
Expand Down
26 changes: 26 additions & 0 deletions tests/test_renderers/fixtures/myst-config.txt
@@ -0,0 +1,26 @@
[title-to-header] --myst-title-to-header="yes"
.
---
title: "The title *nested syntax*"
---

# Other header
.
<document source="<string>">
<docinfo>
<field classes="title">
<field_name>
title
<field_body>
<paragraph>
<literal>
The title *nested syntax*
<section ids="the-title-nested-syntax" names="the\ title\ nested\ syntax">
<title>
The title
<emphasis>
nested syntax
<section ids="other-header" names="other\ header">
<title>
Other header
.
1 change: 1 addition & 0 deletions tests/test_renderers/test_error_reporting.py
@@ -1,3 +1,4 @@
"""Tests of the warning reporting for different MyST Markdown inputs."""
from io import StringIO
from pathlib import Path

Expand Down
34 changes: 34 additions & 0 deletions tests/test_renderers/test_myst_config.py
@@ -0,0 +1,34 @@
"""Test (docutils) parsing with different ``MdParserConfig`` options set."""
import shlex
from io import StringIO
from pathlib import Path

from docutils.core import Publisher, publish_doctree
from pytest_param_files import with_parameters

from myst_parser.docutils_ import Parser

FIXTURE_PATH = Path(__file__).parent.joinpath("fixtures")


@with_parameters(FIXTURE_PATH / "myst-config.txt")
def test_cmdline(file_params):
"""The description is parsed as a docutils commandline"""
pub = Publisher(parser=Parser())
option_parser = pub.setup_option_parser()
try:
settings = option_parser.parse_args(
shlex.split(file_params.description)
).__dict__
except Exception as err:
raise AssertionError(
f"Failed to parse commandline: {file_params.description}\n{err}"
)
report_stream = StringIO()
settings["warning_stream"] = report_stream
doctree = publish_doctree(
file_params.content,
parser=Parser(),
settings_overrides=settings,
)
file_params.assert_expected(doctree.pformat(), rstrip_lines=True)

0 comments on commit 574b525

Please sign in to comment.