Skip to content

Commit 1ac97a3

Browse files
committed
fix(md077): reject a configured indent of 0
An indent of 0 asks for continuation content at the list marker's own column, which is not continuation content at all: it ends the list item. The requirement was accepted, so correctly indented bodies were reported as "Continuation line over-indented (expected 0, found 2)" and `fix` would have dissolved the list the rule exists to keep consistent. It is now rejected at parse time with an explanation, and MD077 falls back to its defaults.
1 parent cba175c commit 1ac97a3

1 file changed

Lines changed: 39 additions & 5 deletions

File tree

src/rules/md077_list_continuation_indent/md077_config.rs

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::ContinuationStyle;
22
use crate::rule_config_serde::RuleConfig;
3-
use serde::{Deserialize, Serialize};
3+
use serde::{Deserialize, Deserializer, Serialize};
44

55
/// Configuration for MD077 (List continuation content indentation)
66
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
@@ -10,13 +10,30 @@ pub struct MD077Config {
1010
#[serde(default)]
1111
pub style: ContinuationStyle,
1212
/// Fixed continuation indent relative to the list marker, e.g. `4` for
13-
/// MkDocs-style documents. When set, overrides the content-column-derived
14-
/// requirement (`content_col`, or `max(content_col, 4)` under the MkDocs
15-
/// flavor). `None` keeps the default content-column behavior.
16-
#[serde(default)]
13+
/// MkDocs-style documents. When set, it replaces the content-column-derived
14+
/// requirement, except that under a flavor requiring strict list indentation
15+
/// it may only raise the 4-space minimum, never lower it. `None` keeps the
16+
/// default content-column behavior.
17+
#[serde(default, deserialize_with = "deserialize_indent")]
1718
pub indent: Option<usize>,
1819
}
1920

21+
/// Rejects `indent = 0`. A continuation at the marker column is not continuation
22+
/// content at all: it ends the list item, so requiring it would make `fix`
23+
/// dissolve the list it is meant to keep consistent.
24+
fn deserialize_indent<'de, D>(deserializer: D) -> Result<Option<usize>, D::Error>
25+
where
26+
D: Deserializer<'de>,
27+
{
28+
match Option::<usize>::deserialize(deserializer)? {
29+
Some(0) => Err(serde::de::Error::custom(
30+
"Invalid indent 0: continuation content at the list marker's own column \
31+
leaves the list item. Use 1 or greater.",
32+
)),
33+
other => Ok(other),
34+
}
35+
}
36+
2037
impl RuleConfig for MD077Config {
2138
const RULE_NAME: &'static str = "MD077";
2239
}
@@ -60,4 +77,21 @@ mod tests {
6077
assert_eq!(parsed.style, ContinuationStyle::Aligned);
6178
assert_eq!(parsed.indent, Some(4));
6279
}
80+
81+
#[test]
82+
fn rejects_zero_indent() {
83+
let err = toml::from_str::<MD077Config>("indent = 0").unwrap_err().to_string();
84+
assert!(
85+
err.contains("leaves the list item"),
86+
"zero must be rejected with an explanation, got: {err}"
87+
);
88+
// Control: the neighbouring value parses, so the rejection is about 0
89+
// and not about the key being unreadable.
90+
assert_eq!(toml::from_str::<MD077Config>("indent = 1").unwrap().indent, Some(1));
91+
}
92+
93+
#[test]
94+
fn rejects_negative_indent() {
95+
assert!(toml::from_str::<MD077Config>("indent = -1").is_err());
96+
}
6397
}

0 commit comments

Comments
 (0)