mdbook_numbering/
config.rs

1use serde::de::IgnoredAny;
2use serde::{Deserialize, Serialize};
3
4/// The numbering style to be used by the `mdbook-numbering` preprocessor.
5///
6/// Should be placed under the `numbering-style` field
7/// in the `[preprocessor.numbering]` section in `book.toml`.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9#[non_exhaustive]
10#[serde(rename_all = "kebab-case")]
11#[serde(deny_unknown_fields)]
12pub enum NumberingStyle {
13    /// There should be no more than one top heading (the heading with the highest level)
14    /// in the chapter, and it should has the same level as the chapter numbering.
15    ///
16    /// For example, if the numbering of the chapter is `1.2.3`, the top heading in the chapter
17    /// should be level 3 (i.e., `### Chapter 1.2.3`).
18    ///
19    /// This is the default behavior of `mdbook-numbering`. And it works well with [mdbook-pdf]
20    /// in regard to generating the table of contents.
21    ///
22    /// [mdbook-pdf]: https://github.com/HollowMan6/mdbook-pdf
23    Consecutive,
24    /// There should be no more than one top heading (the heading with the highest level)
25    /// in the chapter, and it should be level 1 (i.e., `# Chapter 1.2.3`),
26    /// regardless of the chapter numbering.
27    ///
28    /// This style is more flexible, but may lead to inconsistent heading levels across chapters.
29    /// And using it you may get a flat table of contents when generating PDF with [mdbook-pdf].
30    ///
31    /// By the way, this is how [the documentation of mdbook] is structured.
32    ///
33    /// [mdbook-pdf]: https://github.com/HollowMan6/mdbook-pdf
34    /// [the documentation of mdbook]: https://github.com/rust-lang/mdBook/tree/master/guide
35    Top,
36    // Future numbering styles can be added here.
37}
38
39impl NumberingStyle {
40    /// Create a new `NumberingStyle` with default value.
41    pub const fn new() -> Self {
42        Self::Consecutive
43    }
44}
45
46impl Default for NumberingStyle {
47    fn default() -> Self {
48        Self::new()
49    }
50}
51
52fn bool_true() -> bool {
53    true
54}
55
56/// Configuration for heading numbering style.
57///
58/// Should be placed under the `heading` field
59/// in the `[preprocessor.numbering]` section in `book.toml`.
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
61#[non_exhaustive]
62#[serde(rename_all = "kebab-case")]
63#[serde(deny_unknown_fields)]
64pub struct HeadingConfig {
65    /// Whether to enable heading numbering.
66    #[serde(default = "bool_true")]
67    pub enable: bool,
68    /// Whether to treat warnings as errors.
69    #[serde(default)]
70    pub numbering_style: NumberingStyle,
71    // Future configuration options can be added here.
72}
73
74impl HeadingConfig {
75    /// Create a new `HeadingConfig` with default values.
76    pub const fn new() -> Self {
77        Self {
78            enable: true,
79            numbering_style: NumberingStyle::new(),
80        }
81    }
82}
83
84impl Default for HeadingConfig {
85    fn default() -> Self {
86        Self::new()
87    }
88}
89
90/// Configuration for code block line numbering.
91///
92/// Should be placed under the `code` field
93/// in the `[preprocessor.numbering]` section in `book.toml`.
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
95#[non_exhaustive]
96#[serde(rename_all = "kebab-case")]
97#[serde(deny_unknown_fields)]
98pub struct CodeConfig {
99    /// Whether to enable code numbering.
100    #[serde(default = "bool_true")]
101    pub enable: bool,
102    // Future configuration options can be added here.
103}
104
105impl CodeConfig {
106    /// Create a new `CodeConfig` with default values.
107    pub const fn new() -> Self {
108        Self { enable: true }
109    }
110}
111
112impl Default for CodeConfig {
113    fn default() -> Self {
114        Self::new()
115    }
116}
117
118/// Configuration for the `mdbook-numbering` preprocessor.
119///
120/// Should be placed under the `[preprocessor.numbering]` section in `book.toml`.
121#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
122#[non_exhaustive]
123#[serde(rename_all = "kebab-case")]
124#[serde(deny_unknown_fields)]
125pub struct NumberingConfig {
126    /// Those preprocessors that `mdbook-numbering` should run after.
127    #[serde(default, skip_serializing)]
128    pub after: IgnoredAny,
129    /// Those preprocessors that `mdbook-numbering` should run before.
130    #[serde(default, skip_serializing)]
131    pub before: IgnoredAny,
132    /// Configuration for line numbering in code blocks.
133    #[serde(default)]
134    pub code: CodeConfig,
135    /// Placeholder to ignore unused fields.
136    #[serde(default, skip_serializing)]
137    pub command: IgnoredAny,
138    /// Configuration for heading numbering.
139    #[serde(default)]
140    pub heading: HeadingConfig,
141    /// Placeholder to ignore unused fields.
142    #[serde(default, skip_serializing)]
143    pub optional: IgnoredAny,
144    /// Placeholder to ignore unused fields.
145    #[serde(default, skip_serializing)]
146    pub renderers: IgnoredAny,
147    // Future configuration options can be added here.
148}
149
150impl NumberingConfig {
151    /// Create a new `NumberingConfig` with default values.
152    pub const fn new() -> Self {
153        Self {
154            after: IgnoredAny,
155            before: IgnoredAny,
156            code: CodeConfig::new(),
157            command: IgnoredAny,
158            heading: HeadingConfig::new(),
159            optional: IgnoredAny,
160            renderers: IgnoredAny,
161        }
162    }
163}
164
165impl Default for NumberingConfig {
166    fn default() -> Self {
167        Self::new()
168    }
169}
170
171impl PartialEq for NumberingConfig {
172    fn eq(&self, other: &Self) -> bool {
173        self.code == other.code && self.heading == other.heading
174    }
175}
176impl Eq for NumberingConfig {}