diff --git a/Cargo.lock b/Cargo.lock index b96baab078..b20ac59832 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2545,6 +2545,7 @@ dependencies = [ "itertools", "libcst", "once_cell", + "regex", "ruff", "ruff_cli", "rustpython-common", diff --git a/crates/ruff_dev/Cargo.toml b/crates/ruff_dev/Cargo.toml index 4114f59ca4..5dcec1a767 100644 --- a/crates/ruff_dev/Cargo.toml +++ b/crates/ruff_dev/Cargo.toml @@ -10,6 +10,7 @@ clap = { workspace = true } itertools = { workspace = true } libcst = { workspace = true } once_cell = { workspace = true } +regex.workspace = true ruff = { path = "../ruff" } ruff_cli = { path = "../ruff_cli" } rustpython-common = { workspace = true } diff --git a/crates/ruff_dev/src/generate_docs.rs b/crates/ruff_dev/src/generate_docs.rs index 528f2a9a42..c75c9f67df 100644 --- a/crates/ruff_dev/src/generate_docs.rs +++ b/crates/ruff_dev/src/generate_docs.rs @@ -4,6 +4,7 @@ use std::fs; use anyhow::Result; +use regex::{Captures, Regex}; use ruff::registry::{Linter, Rule, RuleNamespace}; use ruff::settings::options::Options; use ruff::settings::options_base::ConfigurationOptions; @@ -56,6 +57,21 @@ fn process_documentation(documentation: &str, out: &mut String) { let mut in_options = false; let mut after = String::new(); + // HACK: This is an ugly regex hack that's necessary because mkdocs uses + // a non-CommonMark-compliant Markdown parser, which doesn't support code + // tags in link definitions + // (see https://github.com/Python-Markdown/markdown/issues/280). + let documentation = Regex::new(r"\[`(.*?)`\]($|[^\[])").unwrap().replace_all( + documentation, + |caps: &Captures| { + format!( + "[`{option}`][{option}]{sep}", + option = &caps[1], + sep = &caps[2] + ) + }, + ); + for line in documentation.split_inclusive('\n') { if line.starts_with("## ") { in_options = line == "## Options\n"; @@ -69,8 +85,8 @@ fn process_documentation(documentation: &str, out: &mut String) { ); let anchor = option.rsplit('.').next().unwrap(); - out.push_str(&format!("* [`{option}`]\n")); - after.push_str(&format!("[`{option}`]: ../../settings#{anchor}")); + out.push_str(&format!("* [`{option}`][{option}]\n")); + after.push_str(&format!("[{option}]: ../../settings#{anchor}")); continue; } @@ -83,3 +99,39 @@ fn process_documentation(documentation: &str, out: &mut String) { out.push_str(&after); } } + +#[cfg(test)] +mod tests { + use super::process_documentation; + + #[test] + fn test_process_documentation() { + let mut out = String::new(); + process_documentation( + " +See also [`mccabe.max-complexity`]. +Something [`else`][other]. + +## Options + +* `mccabe.max-complexity` + +[other]: http://example.com.", + &mut out, + ); + assert_eq!( + out, + " +See also [`mccabe.max-complexity`][mccabe.max-complexity]. +Something [`else`][other]. + +## Options + +* [`mccabe.max-complexity`][mccabe.max-complexity] + +[other]: http://example.com. + +[mccabe.max-complexity]: ../../settings#max-complexity" + ); + } +}