From 08d28822e811665c40e5726e5aa68b7c449c7d85 Mon Sep 17 00:00:00 2001 From: Chris Sewell Date: Fri, 7 Jan 2022 00:42:23 +0100 Subject: [PATCH 1/4] PoP Set title in front-matter --- myst_parser/docutils_renderer.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/myst_parser/docutils_renderer.py b/myst_parser/docutils_renderer.py index 9caf091c..297d0983 100644 --- a/myst_parser/docutils_renderer.py +++ b/myst_parser/docutils_renderer.py @@ -748,6 +748,9 @@ def render_front_matter(self, token: SyntaxTreeNode) -> None: else: data = deepcopy(token.content) + if data.get("title"): + self.nested_render_text(f"# {data.pop('title')}", 0) + substitutions = data.pop("substitutions", {}) html_meta = data.pop("html_meta", {}) From 98dd111894ed42650b6be2ea3c468ef495446ace Mon Sep 17 00:00:00 2001 From: Chris Sewell Date: Sun, 9 Jan 2022 11:03:36 +0100 Subject: [PATCH 2/4] add config and test --- myst_parser/docutils_renderer.py | 6 ++-- myst_parser/main.py | 10 ++++++ tests/test_renderers/fixtures/myst-config.txt | 26 ++++++++++++++ tests/test_renderers/test_error_reporting.py | 1 + tests/test_renderers/test_myst_config.py | 34 +++++++++++++++++++ 5 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 tests/test_renderers/fixtures/myst-config.txt create mode 100644 tests/test_renderers/test_myst_config.py diff --git a/myst_parser/docutils_renderer.py b/myst_parser/docutils_renderer.py index 297d0983..d94c4419 100644 --- a/myst_parser/docutils_renderer.py +++ b/myst_parser/docutils_renderer.py @@ -748,9 +748,6 @@ def render_front_matter(self, token: SyntaxTreeNode) -> None: else: data = deepcopy(token.content) - if data.get("title"): - self.nested_render_text(f"# {data.pop('title')}", 0) - substitutions = data.pop("substitutions", {}) html_meta = data.pop("html_meta", {}) @@ -788,6 +785,9 @@ def render_front_matter(self, token: SyntaxTreeNode) -> None: ) ) + if data.get("title") and self.config.get("myst_title_to_header", False): + 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: diff --git a/myst_parser/main.py b/myst_parser/main.py index 30f98cc6..2bac9d95 100644 --- a/myst_parser/main.py +++ b/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 @@ -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])), @@ -307,6 +316,7 @@ def create_md_parser( "myst_footnote_transition": config.footnote_transition, "myst_number_code_blocks": config.number_code_blocks, "myst_highlight_code_blocks": config.highlight_code_blocks, + "myst_title_to_header": config.title_to_header, } ) diff --git a/tests/test_renderers/fixtures/myst-config.txt b/tests/test_renderers/fixtures/myst-config.txt new file mode 100644 index 00000000..ef4a81f6 --- /dev/null +++ b/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 +. + + + + + title + + + + The title *nested syntax* +
+ + The title + <emphasis> + nested syntax + <section ids="other-header" names="other\ header"> + <title> + Other header +. diff --git a/tests/test_renderers/test_error_reporting.py b/tests/test_renderers/test_error_reporting.py index daa677e8..e6cfa6f0 100644 --- a/tests/test_renderers/test_error_reporting.py +++ b/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 diff --git a/tests/test_renderers/test_myst_config.py b/tests/test_renderers/test_myst_config.py new file mode 100644 index 00000000..24af9afc --- /dev/null +++ b/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) From 01c13e5f042b482584af17f145de0bd2fc9e438c Mon Sep 17 00:00:00 2001 From: Chris Sewell <chrisj_sewell@hotmail.com> Date: Sun, 9 Jan 2022 11:19:31 +0100 Subject: [PATCH 3/4] Add documentation --- docs/sphinx/reference.md | 3 +++ docs/syntax/syntax.md | 20 +++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/sphinx/reference.md b/docs/sphinx/reference.md index 5d3235c8..74b0c89f 100644 --- a/docs/sphinx/reference.md +++ b/docs/sphinx/reference.md @@ -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. diff --git a/docs/syntax/syntax.md b/docs/syntax/syntax.md index df27ea8c..05f5efe5 100644 --- a/docs/syntax/syntax.md +++ b/docs/syntax/syntax.md @@ -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 From 706e0894393b9528dffcd73b12ca11ed3568afb8 Mon Sep 17 00:00:00 2001 From: Chris Sewell <chrisj_sewell@hotmail.com> Date: Sun, 9 Jan 2022 18:01:44 +0100 Subject: [PATCH 4/4] apply update fix --- myst_parser/docutils_renderer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/myst_parser/docutils_renderer.py b/myst_parser/docutils_renderer.py index 65862372..eba7718b 100644 --- a/myst_parser/docutils_renderer.py +++ b/myst_parser/docutils_renderer.py @@ -831,7 +831,7 @@ def render_front_matter(self, token: SyntaxTreeNode) -> None: ) ) - if data.get("title") and self.config.get("myst_title_to_header", False): + 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(