1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! Pre-processing utilities for normalizing fenced code block delimiters.
//!
//! `compress_fences` reduces safe outer delimiters to three backticks while
//! preserving nested fence-like content whose marker runs are literal text.
//! The local `FENCE_RE` defines which delimiter lines this module can
//! normalize, while `FenceTracker` provides the depth-aware structural Markdown
//! fence semantics shared with wrapping; its `observe_source_fence` supplies the
//! structural marker parse so this module never re-runs `wrap::is_fence`.
//! `attach_orphan_specifiers` then finds orphaned fence specifier lines and
//! attaches them to the following fence, preserving the retained indentation
//! and normalized language specifier.
use LazyLock;
use Regex;
use crateFenceTracker;
use attach_to_next_fence;
pub use compress_fences;
/// Parses a complete fence delimiter, retaining indentation, marker, and language specifier.
static FENCE_RE: = lazy_regex!;
/// Recognises standalone language-specifier lines eligible for fence attachment.
static ORPHAN_LANG_RE: = lazy_regex!;
/// Determine whether a language specifier denotes an absent language.
///
/// A language is absent when it is empty or the case-insensitive string `null`, with surrounding
/// whitespace ignored.
///
/// # Examples
///
/// ```rust,ignore
/// use mdtablefix::fences::is_null_lang;
/// assert!(is_null_lang(""));
/// assert!(is_null_lang("NULL"));
/// assert!(is_null_lang(" null "));
/// assert!(!is_null_lang("rust"));
/// ```
/// Normalize a potential language specifier.
///
/// Returns the cleaned specifier in lowercase and the leading indentation
/// captured from the original line.
///
/// # Examples
///
/// ```rust,ignore
/// use mdtablefix::fences::normalize_specifier;
/// let (spec, indent) = normalize_specifier(" TOML, Ini");
/// assert_eq!(spec, "toml,ini");
/// assert_eq!(indent, " ");
/// ```
/// Attach orphaned language specifiers to opening fences.
///
/// After compressing fences, a language may appear on its own line directly
/// before a fence. This function removes that line and applies the specifier
/// to the following opening fence, dropping any intervening blank lines when
/// attachment succeeds. When the fence is unindented, the specifier's
/// indentation is used. If the specifier's indentation extends the fence's, the
/// deeper indentation is retained.
///
/// Specifiers containing spaces are accepted and normalized. Fences labelled
/// `null` are normalized to empty by `compress_fences`, so only empty languages
/// are treated as absent.
///
/// # Examples
///
/// ```
/// use mdtablefix::fences::{attach_orphan_specifiers, compress_fences};
/// let lines = vec![
/// "Rust".to_string(),
/// "```".to_string(),
/// "fn main() {}".to_string(),
/// "```".to_string(),
/// ];
/// let fixed = attach_orphan_specifiers(&compress_fences(&lines));
/// assert_eq!(fixed[0], "```rust");
/// ```