Skip to main content

rumdl_lib/rules/md046_code_block_style/
md046_config.rs

1use crate::rule_config_serde::RuleConfig;
2use serde::ser::Serializer;
3use serde::{Deserialize, Serialize};
4use std::fmt;
5
6/// The style for code blocks (MD046)
7#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
8pub enum CodeBlockStyle {
9    /// Consistent with the first code block style found
10    #[default]
11    Consistent,
12    /// Indented code blocks (4 spaces)
13    Indented,
14    /// Fenced code blocks (``` or ~~~)
15    Fenced,
16}
17
18impl fmt::Display for CodeBlockStyle {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        match self {
21            CodeBlockStyle::Fenced => write!(f, "fenced"),
22            CodeBlockStyle::Indented => write!(f, "indented"),
23            CodeBlockStyle::Consistent => write!(f, "consistent"),
24        }
25    }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
29pub struct MD046Config {
30    #[serde(
31        default = "default_style",
32        serialize_with = "serialize_style",
33        deserialize_with = "deserialize_style"
34    )]
35    pub style: CodeBlockStyle,
36}
37
38impl Default for MD046Config {
39    fn default() -> Self {
40        Self { style: default_style() }
41    }
42}
43
44fn default_style() -> CodeBlockStyle {
45    CodeBlockStyle::Consistent
46}
47
48fn deserialize_style<'de, D>(deserializer: D) -> Result<CodeBlockStyle, D::Error>
49where
50    D: serde::Deserializer<'de>,
51{
52    let s = String::deserialize(deserializer)?;
53    match s.trim().to_ascii_lowercase().as_str() {
54        "fenced" => Ok(CodeBlockStyle::Fenced),
55        "indented" => Ok(CodeBlockStyle::Indented),
56        "consistent" => Ok(CodeBlockStyle::Consistent),
57        _ => Err(serde::de::Error::custom(format!(
58            "Invalid code block style: {s}. Valid options: fenced, indented, consistent"
59        ))),
60    }
61}
62
63fn serialize_style<S>(style: &CodeBlockStyle, serializer: S) -> Result<S::Ok, S::Error>
64where
65    S: Serializer,
66{
67    serializer.serialize_str(&style.to_string())
68}
69
70impl RuleConfig for MD046Config {
71    const RULE_NAME: &'static str = "MD046";
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    #[test]
79    fn test_style_is_case_insensitive() {
80        let config: MD046Config = toml::from_str(r#"style = "Fenced""#).unwrap();
81        assert_eq!(config.style, CodeBlockStyle::Fenced);
82
83        let config: MD046Config = toml::from_str(r#"style = "INDENTED""#).unwrap();
84        assert_eq!(config.style, CodeBlockStyle::Indented);
85
86        let config: MD046Config = toml::from_str(r#"style = "Consistent""#).unwrap();
87        assert_eq!(config.style, CodeBlockStyle::Consistent);
88    }
89}