Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/mdbook-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ pub struct HtmlConfig {
pub preferred_dark_theme: Option<String>,
/// Supports smart quotes, apostrophes, ellipsis, en-dash, and em-dash.
pub smart_punctuation: bool,
/// Support for definition lists.
pub definition_lists: bool,
/// Should mathjax be enabled?
pub mathjax_support: bool,
/// Additional CSS stylesheets to include in the rendered page's `<head>`.
Expand Down Expand Up @@ -501,6 +503,7 @@ impl Default for HtmlConfig {
default_theme: None,
preferred_dark_theme: None,
smart_punctuation: true,
definition_lists: true,
mathjax_support: false,
additional_css: Vec::new(),
additional_js: Vec::new(),
Expand Down
41 changes: 40 additions & 1 deletion crates/mdbook-html/front-end/css/general.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ h2:target::before,
h3:target::before,
h4:target::before,
h5:target::before,
h6:target::before {
h6:target::before,
dt:target::before {
display: inline-block;
content: "»";
margin-inline-start: -30px;
Expand Down Expand Up @@ -285,3 +286,41 @@ sup {
fill: currentColor;
margin-bottom: -0.1em;
}

dt {
font-weight: bold;
margin-top: 0.5em;
margin-bottom: 0.1em;
}

/* This uses a CSS counter to add numbers to definitions, but only if there is
more than one definition. */
dl, dt {
counter-reset: dd-counter;
}

/* When there is more than one definition, increment the counter. The first
selector selects the first definition, and the second one selects definitions
2 and beyond.*/
dd:has(+ dd), dd + dd {
counter-increment: dd-counter;
/* Use flex display to help with positioning the numbers when there is a p
tag inside the definition. */
display: flex;
align-items: flex-start;
}

/* Shows the counter for definitions. The first selector selects the first
definition, and the second one selections definitions 2 and beyond.*/
dd:has(+ dd)::before, dd + dd::before {
content: counter(dd-counter) ". ";
font-weight: 600;
display: inline-block;
margin-right: 0.5em;
}

dd > p {
/* For loose definitions that have a p tag inside, don't add a bunch of
space before the definition. */
margin-top: 0;
}
1 change: 1 addition & 0 deletions crates/mdbook-html/src/html/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl<'a> HtmlRenderOptions<'a> {
) -> HtmlRenderOptions<'a> {
let mut markdown_options = MarkdownOptions::default();
markdown_options.smart_punctuation = config.smart_punctuation;
markdown_options.definition_lists = config.definition_lists;
HtmlRenderOptions {
markdown_options,
path,
Expand Down
10 changes: 6 additions & 4 deletions crates/mdbook-html/src/html/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -818,12 +818,14 @@ where
}

/// This is used after parsing is complete to add a unique `id` attribute
/// to all header elements, and to also add an `<a>` tag so that clicking
/// the header will set the current URL to that header's fragment.
/// to all header and dt elements, and to also add an `<a>` tag so that
/// clicking the element will set the current URL to that element's
/// fragment.
fn add_header_links(&mut self) {
let mut id_counter = HashSet::new();
let headings =
self.node_ids_for_tag(&|name| matches!(name, "h1" | "h2" | "h3" | "h4" | "h5" | "h6"));
let headings = self.node_ids_for_tag(&|name| {
matches!(name, "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "dt")
});
for heading in headings {
let node = self.tree.get(heading).unwrap();
let el = node.value().as_element().unwrap();
Expand Down
8 changes: 8 additions & 0 deletions crates/mdbook-markdown/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ pub struct MarkdownOptions {
///
/// This is `true` by default.
pub smart_punctuation: bool,
/// Enables definition lists.
///
/// This is `true` by default.
pub definition_lists: bool,
}

impl Default for MarkdownOptions {
fn default() -> MarkdownOptions {
MarkdownOptions {
smart_punctuation: true,
definition_lists: true,
}
}
}
Expand All @@ -45,5 +50,8 @@ pub fn new_cmark_parser<'text>(text: &'text str, options: &MarkdownOptions) -> P
if options.smart_punctuation {
opts.insert(Options::ENABLE_SMART_PUNCTUATION);
}
if options.definition_lists {
opts.insert(Options::ENABLE_DEFINITION_LIST);
}
Parser::new_ext(text, opts)
}
2 changes: 2 additions & 0 deletions guide/src/format/configuration/renderers.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ theme = "my-theme"
default-theme = "light"
preferred-dark-theme = "navy"
smart-punctuation = true
definition-lists = true
mathjax-support = false
additional-css = ["custom.css", "custom2.css"]
additional-js = ["custom.js"]
Expand Down Expand Up @@ -125,6 +126,7 @@ The following configuration options are available:
- **smart-punctuation:** Converts quotes to curly quotes, `...` to `…`, `--` to en-dash, and `---` to em-dash.
See [Smart Punctuation](../markdown.md#smart-punctuation).
Defaults to `true`.
- **definition-lists:** Enables [definition lists](../markdown.md#definition-lists). Defaults to `true`.
- **mathjax-support:** Adds support for [MathJax](../mathjax.md). Defaults to
`false`.
- **additional-css:** If you need to slightly change the appearance of your book
Expand Down
30 changes: 30 additions & 0 deletions guide/src/format/markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,33 @@ Example:
This makes the level 1 heading with the content `Example heading`, ID `first`, and classes `class1` and `class2`. Note that the attributes should be space-separated.

More information can be found in the [heading attrs spec page](https://github.com/raphlinus/pulldown-cmark/blob/master/pulldown-cmark/specs/heading_attrs.txt).

### Definition lists

Definition lists can be used for things like glossary entries. The term is listed on a line by itself, followed by one or more definitions. Each definition must begin with a `:` (after 0-2 spaces).

Example:

```md
term A
: This is a definition of term A. Text
can span multiple lines.

term B
: This is a definition of term B.
: This has more than one definition.
```

This will render as:

term A
: This is a definition of term A. Text
can span multiple lines.

term B
: This is a definition of term B.
: This has more than one definition.

Terms are clickable just like headers, which will set the browser's URL to point directly to that term.

See the [definition lists spec](https://github.com/pulldown-cmark/pulldown-cmark/blob/HEAD/pulldown-cmark/specs/definition_lists.txt) for more information on the specifics of the syntax. See the [Wikipedia guidelines for glossaries](https://en.wikipedia.org/wiki/Wikipedia:Manual_of_Style/Glossaries#General_guidelines_for_writing_glossaries) for some guidelines on how to write a glossary.
13 changes: 13 additions & 0 deletions tests/testsuite/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,16 @@ fn smart_punctuation() {
fn basic_markdown() {
BookTest::from_dir("markdown/basic_markdown").check_all_main_files();
}

#[test]
fn definition_lists() {
BookTest::from_dir("markdown/definition_lists")
.check_all_main_files()
.run("build", |cmd| {
cmd.env("MDBOOK_OUTPUT__HTML__DEFINITION_LISTS", "false");
})
.check_main_file(
"book/definition_lists.html",
file!["markdown/definition_lists/expected_disabled/definition_lists.html"],
);
}
2 changes: 2 additions & 0 deletions tests/testsuite/markdown/definition_lists/book.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[book]
title = "definition_lists"
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<h1 id="definition-lists"><a class="header" href="#definition-lists">Definition Lists</a></h1>
<dl>
<dt id="apple"><a class="header" href="#apple">apple</a></dt>
<dd>red fruit</dd>
<dt id="orange"><a class="header" href="#orange">orange</a></dt>
<dd>orange fruit</dd>
<dt id="apple-1"><a class="header" href="#apple-1">apple</a></dt>
<dd>red fruit</dd>
<dd>computer company</dd>
<dt id="orange-1"><a class="header" href="#orange-1">orange</a></dt>
<dd>orange fruit</dd>
<dd>telecom company</dd>
<dt id="term"><a class="header" href="#term">term</a></dt>
<dd>
<ol>
<li>
<p>Para one</p>
<p>Para two</p>
</li>
</ol>
</dd>
</dl>
<h2 id="term-with-link"><a class="header" href="#term-with-link">Term with link</a></h2>
<dl>
<dt id="apple-2"><a class="header" href="#apple-2"><a href="some-page.html#apple">apple</a></a></dt>
<dd>red fruit</dd>
</dl>
<h2 id="multi-line-term"><a class="header" href="#multi-line-term">Multi-line term</a></h2>
<dl>
<dt id="a-bc"><a class="header" href="#a-bc">a
b<br>c</a></dt>
<dd>
<p>foo</p>
</dd>
</dl>
<h2 id="nested"><a class="header" href="#nested">Nested</a></h2>
<dl>
<dt id="level-one"><a class="header" href="#level-one">level one</a></dt>
<dd>
<dl>
<dt id="l1-level-two"><a class="header" href="#l1-level-two">l1
level two</a></dt>
<dd>
<dl>
<dt id="l2-level-three"><a class="header" href="#l2-level-three">l2
level three</a></dt>
<dd>l3</dd>
</dl>
</dd>
</dl>
</dd>
<dt id="level-one-1"><a class="header" href="#level-one-1">level one</a></dt>
<dd>l1</dd>
</dl>
<h2 id="loose"><a class="header" href="#loose">Loose</a></h2>
<dl>
<dt id="apple-3"><a class="header" href="#apple-3">apple</a></dt>
<dd>
<p>red fruit</p>
</dd>
<dd>
<p>computer company</p>
</dd>
<dt id="orange-2"><a class="header" href="#orange-2">orange</a></dt>
<dd>
<p>orange fruit</p>
</dd>
</dl>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<h1 id="definition-lists"><a class="header" href="#definition-lists">Definition Lists</a></h1>
<p>apple
: red fruit</p>
<p>orange
: orange fruit</p>
<p>apple
: red fruit
: computer company</p>
<p>orange
: orange fruit
: telecom company</p>
<p>term
: 1. Para one</p>
<pre><code> Para two
</code></pre>
<h2 id="term-with-link"><a class="header" href="#term-with-link">Term with link</a></h2>
<p><a href="some-page.html#apple">apple</a>
: red fruit</p>
<h2 id="multi-line-term"><a class="header" href="#multi-line-term">Multi-line term</a></h2>
<p>a
b<br>c</p>
<p>: foo</p>
<h2 id="nested"><a class="header" href="#nested">Nested</a></h2>
<p>level one
: l1
level two
: l2
level three
: l3</p>
<p>level one
: l1</p>
<h2 id="loose"><a class="header" href="#loose">Loose</a></h2>
<p>apple</p>
<p>: red fruit
: computer company</p>
<p>orange</p>
<p>: orange fruit</p>
3 changes: 3 additions & 0 deletions tests/testsuite/markdown/definition_lists/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Summary

- [Definition lists](./definition_lists.md)
56 changes: 56 additions & 0 deletions tests/testsuite/markdown/definition_lists/src/definition_lists.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Definition Lists

apple
: red fruit

orange
: orange fruit

apple
: red fruit
: computer company

orange
: orange fruit
: telecom company

term
: 1. Para one

Para two

## Term with link

[apple](some-page.md#apple)
: red fruit

## Multi-line term

a
b\
c

: foo

## Nested

level one
: l1
level two
: l2
level three
: l3

level one
: l1

## Loose

apple

: red fruit
: computer company

orange

: orange fruit
Loading