Skip to content

Commit a4e2061

Browse files
ImUrXehuss
authored andcommitted
Add working heading extension
1 parent 4f1b5ea commit a4e2061

File tree

3 files changed

+30
-3
lines changed

3 files changed

+30
-3
lines changed

guide/src/format/markdown.md

+11
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,14 @@ To enable it, see the [`output.html.curly-quotes`] config option.
220220
[tables]: https://github.github.com/gfm/#tables-extension-
221221
[task list extension]: https://github.github.com/gfm/#task-list-items-extension-
222222
[`output.html.curly-quotes`]: configuration/renderers.md#html-renderer-options
223+
224+
### Heading attributes { #headingattributes .class1 .class2 }
225+
226+
Headings can have a custom ID and classes. This let's you maintain the same ID even if you change the heading's text, it also let's you add multiple classes in the heading.
227+
228+
Example:
229+
```md
230+
# Example heading { #first .class1 .class2 }
231+
```
232+
233+
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.

src/renderer/html_handlebars/hbs_renderer.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -789,8 +789,10 @@ fn make_data(
789789
/// Goes through the rendered HTML, making sure all header tags have
790790
/// an anchor respectively so people can link to sections directly.
791791
fn build_header_links(html: &str) -> String {
792-
static BUILD_HEADER_LINKS: Lazy<Regex> =
793-
Lazy::new(|| Regex::new(r"<h(\d)>(.*?)</h\d>").unwrap());
792+
static BUILD_HEADER_LINKS: Lazy<Regex> = Lazy::new(|| {
793+
Regex::new(r#"<h(\d)(?: id="([^"]+)")?(?: class="([^"]+)")?>(.*?)</h\d>"#).unwrap()
794+
});
795+
static IGNORE_CLASS: &'static [&str] = &["menu-title"];
794796

795797
let mut id_counter = HashMap::new();
796798

@@ -800,7 +802,20 @@ fn build_header_links(html: &str) -> String {
800802
.parse()
801803
.expect("Regex should ensure we only ever get numbers here");
802804

803-
insert_link_into_header(level, &caps[2], &mut id_counter)
805+
// Ignore .menu-title because now it's getting detected by the regex.
806+
if let Some(classes) = caps.get(3) {
807+
for class in classes.as_str().split(" ") {
808+
if IGNORE_CLASS.contains(&class) {
809+
return caps[0].to_string();
810+
}
811+
}
812+
}
813+
814+
insert_link_into_header(
815+
level,
816+
caps.get(2).map(|x| x.as_str()).unwrap_or(&caps[4]),
817+
&mut id_counter,
818+
)
804819
})
805820
.into_owned()
806821
}

src/utils/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ pub fn new_cmark_parser(text: &str, curly_quotes: bool) -> Parser<'_, '_> {
183183
opts.insert(Options::ENABLE_FOOTNOTES);
184184
opts.insert(Options::ENABLE_STRIKETHROUGH);
185185
opts.insert(Options::ENABLE_TASKLISTS);
186+
opts.insert(Options::ENABLE_HEADING_ATTRIBUTES);
186187
if curly_quotes {
187188
opts.insert(Options::ENABLE_SMART_PUNCTUATION);
188189
}

0 commit comments

Comments
 (0)