Skip to content

Latest commit

 

History

History
825 lines (604 loc) · 21.4 KB

syntax.md

File metadata and controls

825 lines (604 loc) · 21.4 KB

(example_syntax)=

The MyST Syntax Guide

{sub-ref}today | {sub-ref}wordcount-minutes min read

As a base, MyST adheres to the CommonMark specification. For this, it uses the markdown-it-py parser, which is a well-structured markdown parser for Python that is CommonMark-compliant and also extensible.

MyST adds several new syntax options to CommonMark in order to be used with Sphinx, the documentation generation engine used extensively in the Python ecosystem.

Below is a summary of the syntax 'tokens' parsed, and further details of a few major extensions from the CommonMark flavor of markdown.

:::{seealso}

  • For an introduction to writing Directives and Roles with MyST markdown, see {ref}intro/writing.
  • Check out the MyST-Markdown VS Code extension, for MyST extended syntax highlighting. :::

MyST builds on the tokens defined by markdown-it, to extend the syntax described in the CommonMark Spec, which the parser is tested against.

% TODO link to markdown-it documentation

(syntax/directives)=

Directives - a block-level extension point

Directives syntax is defined with triple-backticks and curly-brackets. It is effectively a code block with curly brackets around the language, and a directive name in place of a language name. It is similar to how RMarkdown defines "runnable cells". Here is the basic structure:

---
header-rows: 1
---
* - MyST
  - reStructuredText
* - ````md
    ```{directivename} arguments
    ---
    key1: val1
    key2: val2
    ---
    This is
    directive content
    ```
    ````
  - ```rst
    .. directivename:: arguments
       :key1: val1
       :key2: val2

       This is
       directive content
    ```

For example, the following code:

```{admonition} This is my admonition
This is my note
```

Will generate this admonition:

This is my note

Parameterizing directives

For directives that take parameters as input, there are two ways to parameterize them. In each case, the options themselves are given as key: value pairs. An example of each is shown below:

Using YAML frontmatter. A block of YAML front-matter just after the first line of the directive will be parsed as options for the directive. This needs to be surrounded by --- lines. Everything in between will be parsed by YAML and passed as keyword arguments to your directive. For example:

```{code-block} python
---
lineno-start: 10
emphasize-lines: 1, 3
caption: |
    This is my
    multi-line caption. It is *pretty nifty* ;-)
---
a = 2
print('my 1st line')
print(f'my {a}nd line')
```
---
lineno-start: 10
emphasize-lines: 1, 3
caption: |
    This is my
    multi-line caption. It is *pretty nifty* ;-)
---
a = 2
print('my 1st line')
print(f'my {a}nd line')

Short-hand options with : characters. If you only need one or two options for your directive and wish to save lines, you may also specify directive options as a collection of lines just after the first line of the directive, each preceding with :. Then the leading : is removed from each line, and the rest is parsed as YAML.

For example:

```{code-block} python
:lineno-start: 10
:emphasize-lines: 1, 3

a = 2
print('my 1st line')
print(f'my {a}nd line')
```

(syntax/directives/parsing)=

How directives parse content

Some directives parse the content that is in their content block. MyST parses this content as Markdown.

This means that MyST markdown can be written in the content areas of any directives written in MyST markdown. For example:

```{admonition} My markdown link
Here is [markdown link syntax](https://jupyter.org)
```
Here is [markdown link syntax](https://jupyter.org)

As a short-hand for directives that require no arguments, and when no parameter options are used (see below), you may start the content directly after the directive name.

```{note} Notes require **no** arguments, so content can start here.
```

For special cases, MySt also offers the eval-rst directive. This will parse the content as ReStructuredText:

```{eval-rst}
.. figure:: img/fun-fish.png
  :width: 100px
  :name: rst-fun-fish

  Party time!

A reference from inside: :ref:`rst-fun-fish`

A reference from outside: :ref:`syntax/directives/parsing`
```
.. figure:: img/fun-fish.png
  :width: 100px
  :name: rst-fun-fish

  Party time!

A reference from inside: :ref:`rst-fun-fish`

A reference from outside: :ref:`syntax/directives/parsing`

Note how the text is integrated into the rest of the document, so we can also reference party fish anywhere else in the documentation.

Nesting directives

You can nest directives by ensuring that the tick-lines corresponding to the outermost directive are longer than the tick-lines for the inner directives. For example, nest a warning inside a note block like so:

````{note}
The next info should be nested
```{warning}
Here's my warning
```
````

Here's how it looks rendered:

The next info should be nested
```{warning}
Here's my warning
```

You can indent inner-code fences, so long as they aren't indented by more than 3 spaces. Otherwise, they will be rendered as "raw code" blocks:

````{note}
The warning block will be properly-parsed

   ```{warning}
   Here's my warning
   ```

But the next block will be parsed as raw text

    ```{warning}
    Here's my raw text warning that isn't parsed...
    ```
````
The warning block will be properly-parsed

   ```{warning}
   Here's my warning
   ```

But the next block will be parsed as raw text

    ```{warning}
    Here's my raw text warning that isn't parsed...
    ```

This can really be abused if you'd like ;-)

The next info should be nested
`````{warning}
Here's my warning
````{admonition} Yep another admonition
```python
# All this fuss was about this boring python?!
print('yep!')
```
````
`````

Markdown-friendly directives

Want to use syntax that renders correctly in standard Markdown editors? See the extended syntax option.

:::{note}
This text is **standard** _Markdown_
:::

:::{note} This text is standard Markdown :::

(syntax/roles)=

Roles - an in-line extension point

Roles are similar to directives - they allow you to define arbitrary new functionality, but they are used in-line. To define an in-line role, use the following form:

---
header-rows: 1
---
* - MyST
  - reStructuredText
* - ````md
    {role-name}`role content`
    ````
  - ```rst
    :role-name:`role content`
    ```

For example, the following code:

Since Pythagoras, we know that {math}`a^2 + b^2 = c^2`

Becomes:

Since Pythagoras, we know that {math}a^2 + b^2 = c^2

You can use roles to do things like reference equations and other items in your book. For example:

```{math} e^{i\pi} + 1 = 0
---
label: euler
---
```

Euler's identity, equation {math:numref}`euler`, was elected one of the
most beautiful mathematical formulas.

Becomes:

---
label: euler
---

Euler's identity, equation {math:numref}euler, was elected one of the most beautiful mathematical formulas.

How roles parse content

The content of roles is parsed differently depending on the role that you've used. Some roles expect inputs that will be used to change functionality. For example, the ref role will assume that input content is a reference to some other part of the site. However, other roles may use the MyST parser to parse the input as content.

Some roles also extend their functionality depending on the content that you pass. For example, following the ref example above, if you pass a string like this: Content to display <myref>, then the ref will display Content to display and use myref as the reference to look up.

How roles parse this content depends on the author that created the role.

(syntax/roles/special)=

(extra-markdown-syntax)=

Extra markdown syntax

In addition to roles and directives, MyST supports extra markdown syntax that doesn't exist in CommonMark. In most cases, these are syntactic short-cuts to calling roles and directives. We'll cover some common ones below.

This table describes the rST and MyST equivalents:

---
header-rows: 1
---
* - Type
  - MyST
  - reStructuredText
* - Front matter
  - ```md
    ---
    key: val
    ---
    ```
  - ```md
    :key: val
    ```
* - Comments
  - `% comment`
  - `.. comment`
* - Targets
  - `(mytarget)=`
  - `.. _mytarget:`

(syntax/frontmatter)=

Front Matter

This is a YAML block at the start of the document, as used for example in jekyll.

:::{seealso} Top-matter is also used for the substitution syntax extension, and can be used to store information for blog posting (see ablog's myst-parser support). :::

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:

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

would be equivalent to:

# My Title with *emphasis*

(syntax/html_meta)=

Setting HTML Metadata

The front-matter can contain the special key html_meta; a dict with data to add to the generated HTML as <meta> elements. This is equivalent to using the RST meta directive.

HTML metadata can also be added globally in the conf.py via the myst_html_meta variable, in which case it will be added to all MyST documents. For each document, the myst_html_meta dict will be updated by the document level front-matter html_meta, with the front-matter taking precedence.

:::{tabbed} Sphinx Configuration

language = "en"
myst_html_meta = {
    "description lang=en": "metadata description",
    "description lang=fr": "description des métadonnées",
    "keywords": "Sphinx, MyST",
    "property=og:locale":  "en_US"
}

:::

:::{tabbed} MyST Front-Matter

---
html_meta:
  "description lang=en": "metadata description"
  "description lang=fr": "description des métadonnées"
  "keywords": "Sphinx, MyST"
  "property=og:locale": "en_US"
---

:::

:::{tabbed} RestructuredText

.. meta::
   :description lang=en: metadata description
   :description lang=fr: description des métadonnées
   :keywords: Sphinx, MyST
   :property=og:locale: en_US

:::

:::{tabbed} HTML Output

<html lang="en">
  <head>
    <meta content="metadata description" lang="en" name="description" xml:lang="en" />
    <meta content="description des métadonnées" lang="fr" name="description" xml:lang="fr" />
    <meta name="keywords" content="Sphinx, MyST">
    <meta content="en_US" property="og:locale" />

:::

(syntax/comments)=

Comments

You may add comments by putting the % character at the beginning of a line. This will prevent the line from being parsed into the output document.

For example, this code:

% my comment

Is below, but it won't be parsed into the document.

% my comment

Since comments are a block-level entity, they will terminate the previous block.
In practical terms, this means that the following lines
will be broken up into two paragraphs, resulting in a new line between them:

```
a line
% a comment
another line
```

a line
% a comment
another line

(syntax/blockbreaks)=

Block Breaks

You may add a block break by putting +++ at the beginning of a line. This constuct's intended use case is for mapping to cell based document formats, like jupyter notebooks, to indicate a new text cell. It will not show up in the rendered text, but is stored in the internal document structure for use by developers.

For example, this code:

+++ some text

Is below, but it won't be parsed into the document.

+++

(syntax/referencing)=

Markdown Links and Referencing

Markdown links are of the form: [text](link).

If you set the configuration myst_all_links_external = True (False by default), then all links will be treated simply as "external" links. For example, in HTML outputs, [text](link) will be rendered as <a href="link">text</a>.

Otherwise, links will only be treated as "external" links if they are prefixed with a scheme, configured with myst_url_schemes (by default, http, https, ftp, or mailto). For example, [example.com](https://example.com) becomes example.com.

:::{note} The text will be parsed as nested Markdown, for example [here's some *emphasised text*](https://example.com) will be parsed as here's some emphasised text. :::

For "internal" links, myst-parser in Sphinx will attempt to resolve the reference to either a relative document path, or a cross-reference to a target (see ):

  • [this doc](syntax.md) will link to a rendered source document: this doc
    • This is similar to {doc}`this doc <syntax>`; {doc}this doc <syntax>, but allows for document extensions, and parses nested Markdown text.
  • [example text](example.txt) will link to a non-source (downloadable) file: example text
    • The linked document itself will be copied to the build directory.
    • This is similar to {download}`example text <example.txt>`; {download}example text <example.txt>, but parses nested Markdown text.
  • [reference](syntax/referencing) will link to an internal cross-reference: reference
    • This is similar to {any}`reference <syntax/referencing>`; {any}reference <syntax/referencing>, but parses nested Markdown text.
    • You can limit the scope of the cross-reference to specific sphinx domains, by using the myst_ref_domains configuration. For example, myst_ref_domains = ("std", "py") will only allow cross-references to std and py domains.

Additionally, only if are enabled, then internal links to document headers can be used. For example [a header](syntax.md#markdown-links-and-referencing) will link to a header anchor: a header.

(syntax/targets)=

Targets and Cross-Referencing

Targets are used to define custom anchors that you can refer to elsewhere in your documentation. They generally go before section titles so that you can easily refer to them.

:::{tip}

If you'd like to automatically generate targets for each of your section headers, check out the section of extended syntaxes.

:::

Target headers are defined with this syntax:

(header_target)=

They can then be referred to with the ref inline role:

{ref}`header_target`

By default, the reference will use the text of the target (such as the section title), but also you can directly specify the text:

{ref}`my text <header_target>`

For example, see this ref: {ref}syntax/targets, and here's a ref back to the top of this page: {ref}my text <example_syntax>.

Alternatively using the markdown syntax:

[my text](header_target)

is equivalent to using the any inline role:

{any}`my text <header_target>`

but can also accept "nested" syntax (like bold text) and will recognise document paths that include extensions (e.g. syntax/syntax or syntax/syntax.md)

Using the same example, see this ref: , here is a reference back to the top of this page: my text with nested $\alpha$ syntax, and here is a reference to another page ([](../sphinx/intro.md)): .

If you wish to have the target's title inserted into your text, you can
leave the "text" section of the markdown link empty. For example, this
markdown: `[](syntax.md)` will result in: [](syntax.md).

(syntax/code-blocks)=

Code blocks

Code blocks contain a language identifier, which is used to determine the language of the code. This language is used to determine the syntax highlighting, using an available pygments lexer.

```python
from a import b
c = "string"
```
from a import b
c = "string"

You can create and register your own lexer, using the pygments.lexers entry point, or within a sphinx extension, with the app.add_lexer method.

Using the myst_number_code_blocks configuration option, you can also control whether code blocks are numbered by line. For example, using myst_number_code_blocks = ["typescript"]:

type MyBool = true | false;

interface User {
  name: string;
  id: number;
}

Show backticks inside raw markdown blocks

If you'd like to show backticks inside of your markdown, you can do so by nesting them in backticks of a greater length. Markdown will treat the outer-most backticks as the edges of the "raw" block and everything inside will show up. For example:

`` `hi` `` will be rendered as: `hi`

and

````
```
hi
```
````

will be rendered as:

```
hi
```

Tables

Tables can be written using the standard Github Flavoured Markdown syntax:

| foo | bar |
| --- | --- |
| baz | bim |
foo bar
baz bim

Cells in a column can be aligned using the : character:

| left | center | right |
| :--- | :----: | ----: |
| a    | b      | c     |
left center right
a b c

:::{note}

Text is aligned by assigning text-left, text-center, or text-right to the cell. It is then necessary for the theme you are using to include the appropriate css styling.

<table class="colwidths-auto table">
  <thead>
    <tr><th class="text-left head"><p>left</p></th></tr>
  </thead>
  <tbody>
    <tr><td class="text-left"><p>a</p></td></tr>
  </tbody>
</table>

:::

Images

MyST provides a few different syntaxes for including images in your documentation.

The standard Markdown syntax is:

![fishy](img/fun-fish.png)

fishy

But you can also enable extended image syntaxes, to control attributes like width and captions. See the extended image syntax guide.

(syntax/footnotes)=

Footnotes

Footnotes use the pandoc specification. Their labels start with ^ and can then be any alpha-numeric string (no spaces), which is case-insensitive.

  • If the label is an integer, then it will always use that integer for the rendered label (i.e. they are manually numbered).
  • For any other labels, they will be auto-numbered in the order which they are referenced, skipping any manually numbered labels.

All footnote definitions are collected, and displayed at the bottom of the page (in the order they are referenced). Note that un-referenced footnote definitions will not be displayed.

- This is a manually-numbered footnote reference.[^3]
- This is an auto-numbered footnote reference.[^myref]

[^myref]: This is an auto-numbered footnote definition.
[^3]: This is a manually-numbered footnote definition.
  • This is a manually-numbered footnote reference.1
  • This is an auto-numbered footnote reference.2

Any preceding text after a footnote definitions, which is indented by four or more spaces, will also be included in the footnote definition, and the text is rendered as MyST Markdown, e.g.

A longer footnote definition.[^mylongdef]

[^mylongdef]: This is the _**footnote definition**_.

    That continues for all indented lines

    - even other block elements

    Plus any preceding unindented lines,
that are not separated by a blank line

This is not part of the footnote.

A longer footnote definition.3

This is not part of the footnote.

Although footnote references can be used just fine within directives, e.g.[^myref],
it it recommended that footnote definitions are not set within directives,
unless they will only be referenced within that same directive:

```md
[^other]

[^other]: A definition within a directive
```

[^other]

[^other]: A definition within a directive

This is because, in the current implementation, they may not be available to reference in text above that particular directive.

By default, a transition line (with a footnotes class) will be placed before any footnotes. This can be turned off by adding myst_footnote_transition = False to the config file.

Footnotes

  1. This is a manually-numbered footnote definition.

  2. This is an auto-numbered footnote definition.

  3. This is the footnote definition.

    That continues for all indented lines

    • even other block elements

    Plus any preceding unindented lines, that are not separated by a blank line