Skip to content

Commit 81eb086

Browse files
feat: add support for nested sections
1 parent 2150227 commit 81eb086

File tree

2 files changed

+74
-31
lines changed

2 files changed

+74
-31
lines changed

Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,11 @@ case-insensitive = ["unicase"]
4040
# [[A]]
4141
# Key=value
4242
brackets-in-section-names = []
43+
# Allow parsing of nested sections
44+
#
45+
# For example:
46+
# [Section][Subsection]
47+
# key=value
48+
#
49+
# That appears in KDE Configuration files
50+
nested-sections = []

src/lib.rs

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@
4444
4545
use std::{
4646
borrow::Cow,
47-
char,
48-
error,
47+
char, error,
4948
fmt::{self, Display},
5049
fs::{File, OpenOptions},
5150
io::{self, Read, Seek, SeekFrom, Write},
@@ -300,53 +299,79 @@ impl Default for WriteOption {
300299
}
301300
}
302301

302+
#[cfg(all(feature = "case-insensitive", not(feature = "nested-sections")))]
303+
pub type SectionKey = Option<UniCase<String>>;
304+
#[cfg(all(feature = "case-insensitive", feature = "nested-sections"))]
305+
pub type SectionKey = Option<Vec<UniCase<String>>>;
306+
#[cfg(all(not(feature = "case-insensitive"), not(feature = "nested-sections")))]
307+
pub type SectionKey = Option<String>;
308+
#[cfg(all(not(feature = "case-insensitive"), feature = "nested-sections"))]
309+
pub type SectionKey = Option<Vec<String>>;
310+
303311
cfg_if! {
304312
if #[cfg(feature = "case-insensitive")] {
305-
/// Internal storage of section's key
306-
pub type SectionKey = Option<UniCase<String>>;
307-
/// Internal storage of property's key
308313
pub type PropertyKey = UniCase<String>;
309-
310314
macro_rules! property_get_key {
311315
($s:expr) => {
312316
&UniCase::from($s)
313317
};
314318
}
315-
316319
macro_rules! property_insert_key {
317320
($s:expr) => {
318321
UniCase::from($s)
319322
};
320323
}
321-
322-
macro_rules! section_key {
323-
($s:expr) => {
324-
$s.map(|s| UniCase::from(s.into()))
325-
};
326-
}
327-
328324
} else {
329-
/// Internal storage of section's key
330-
pub type SectionKey = Option<String>;
331-
/// Internal storage of property's key
332325
pub type PropertyKey = String;
333-
334326
macro_rules! property_get_key {
335327
($s:expr) => {
336328
$s
337329
};
338330
}
339-
340331
macro_rules! property_insert_key {
341332
($s:expr) => {
342333
$s
343334
};
344335
}
336+
}
337+
}
345338

346-
macro_rules! section_key {
347-
($s:expr) => {
348-
$s.map(Into::into)
349-
};
339+
cfg_if! {
340+
if #[cfg(feature = "case-insensitive")] {
341+
cfg_if! {
342+
if #[cfg(feature = "nested-sections")] {
343+
macro_rules! section_key {
344+
($s:expr) => {
345+
$s.map(|s| {
346+
s.split("][")
347+
.map(|part| UniCase::from(part.to_string()))
348+
.collect::<Vec<_>>()
349+
})
350+
};
351+
}
352+
} else {
353+
macro_rules! section_key {
354+
($s:expr) => {
355+
$s.map(|s| UniCase::from(s.into()))
356+
};
357+
}
358+
}
359+
}
360+
} else {
361+
cfg_if! {
362+
if #[cfg(feature = "nested-sections")] {
363+
macro_rules! section_key {
364+
($s:expr) => {
365+
$s.map(|s| s.split("][").map(Into::into).collect::<Vec<_>>())
366+
};
367+
}
368+
} else {
369+
macro_rules! section_key {
370+
($s:expr) => {
371+
$s.map(Into::into)
372+
};
373+
}
374+
}
350375
}
351376
}
352377
}
@@ -764,8 +789,19 @@ impl Ini {
764789
}
765790

766791
/// Iterate with sections
767-
pub fn sections(&self) -> impl DoubleEndedIterator<Item = Option<&str>> {
768-
self.sections.keys().map(|s| s.as_ref().map(AsRef::as_ref))
792+
pub fn sections(&self) -> impl DoubleEndedIterator<Item = Option<String>> + '_ {
793+
self.sections.keys().map(|key| {
794+
key.as_ref().map(|parts| {
795+
#[cfg(feature = "nested-sections")]
796+
{
797+
parts.join("][")
798+
}
799+
#[cfg(not(feature = "nested-sections"))]
800+
{
801+
parts.clone()
802+
}
803+
})
804+
})
769805
}
770806

771807
/// Set key-value to a section
@@ -959,12 +995,11 @@ impl Ini {
959995
}
960996

961997
if let Some(ref section) = *section {
962-
write!(
963-
writer,
964-
"[{}]{}",
965-
escape_str(&section[..], opt.escape_policy),
966-
opt.line_separator
967-
)?;
998+
#[cfg(feature = "nested-sections")]
999+
let section_str = format!("[{}]", parts.join("]["));
1000+
#[cfg(not(feature = "nested-sections"))]
1001+
let section_str = format!("[{}]", escape_str(section, opt.escape_policy));
1002+
write!(writer, "{}{}", section_str, opt.line_separator)?;
9681003
}
9691004
for (k, v) in props.iter() {
9701005
let k_str = escape_str(k, opt.escape_policy);

0 commit comments

Comments
 (0)