mirror of https://github.com/kdl-org/kdl-rs.git
feat: control format of multi-line strings
This commit is contained in:
parent
268f3a2d00
commit
1aaa178d00
53
src/entry.rs
53
src/entry.rs
|
|
@ -169,6 +169,59 @@ impl KdlEntry {
|
|||
}
|
||||
}
|
||||
|
||||
/// Auto-formats this entry with multiline string handling.
|
||||
pub(crate) fn autoformat_with_multiline(
|
||||
&mut self,
|
||||
expand: crate::fmt::MultilineStringExpansion,
|
||||
) {
|
||||
use crate::fmt::MultilineStringExpansion::*;
|
||||
|
||||
let should_preserve_repr = match expand {
|
||||
Never => false,
|
||||
Always => {
|
||||
if let Some(s) = self.value.as_string() {
|
||||
if s.contains('\n') {
|
||||
// Convert to multiline format
|
||||
let multiline = format!("\"\"\"\n{}\n\"\"\"", s);
|
||||
#[cfg(feature = "v1")]
|
||||
self.ensure_v2();
|
||||
self.format = Some(KdlEntryFormat {
|
||||
value_repr: multiline,
|
||||
leading: " ".into(),
|
||||
..Default::default()
|
||||
});
|
||||
if let Some(name) = &mut self.name {
|
||||
name.autoformat();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
TripleQuotes => self
|
||||
.format
|
||||
.as_ref()
|
||||
.is_some_and(|f| f.value_repr.starts_with("\"\"\"")),
|
||||
};
|
||||
|
||||
if should_preserve_repr {
|
||||
#[cfg(feature = "v1")]
|
||||
self.ensure_v2();
|
||||
self.format = self.format.take().map(|f| KdlEntryFormat {
|
||||
value_repr: f.value_repr,
|
||||
leading: " ".into(),
|
||||
..Default::default()
|
||||
});
|
||||
} else {
|
||||
self.autoformat();
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(name) = &mut self.name {
|
||||
name.autoformat();
|
||||
}
|
||||
}
|
||||
|
||||
/// Auto-formats this entry.
|
||||
pub fn autoformat(&mut self) {
|
||||
// TODO once MSRV allows (1.80.0):
|
||||
|
|
|
|||
24
src/fmt.rs
24
src/fmt.rs
|
|
@ -1,5 +1,17 @@
|
|||
use std::fmt::Write as _;
|
||||
|
||||
/// Controls how multiline strings are handled during formatting.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub enum MultilineStringExpansion {
|
||||
/// Keep strings as-is (current behavior).
|
||||
#[default]
|
||||
Never,
|
||||
/// Convert any string with `\n` to `"""..."""` syntax.
|
||||
Always,
|
||||
/// Only preserve existing `"""..."""` syntax.
|
||||
TripleQuotes,
|
||||
}
|
||||
|
||||
/// Formatting configuration for use with [`KdlDocument::autoformat_config`](`crate::KdlDocument::autoformat_config`)
|
||||
/// and [`KdlNode::autoformat_config`](`crate::KdlNode::autoformat_config`).
|
||||
#[non_exhaustive]
|
||||
|
|
@ -18,6 +30,9 @@ pub struct FormatConfig<'a> {
|
|||
|
||||
/// Whether to keep individual entry formatting.
|
||||
pub entry_autoformate_keep: bool,
|
||||
|
||||
/// How to handle multiline strings during formatting.
|
||||
pub expand_multiline: MultilineStringExpansion,
|
||||
}
|
||||
|
||||
/// See field documentation for defaults.
|
||||
|
|
@ -48,6 +63,7 @@ impl<'a> FormatConfigBuilder<'a> {
|
|||
indent: " ",
|
||||
no_comments: false,
|
||||
entry_autoformate_keep: false,
|
||||
expand_multiline: MultilineStringExpansion::Never,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -105,6 +121,13 @@ impl<'a> FormatConfigBuilder<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
/// How to handle multiline strings during formatting.
|
||||
/// Defaults to `Never` iff not specified.
|
||||
pub const fn expand_multiline(mut self, expand_multiline: MultilineStringExpansion) -> Self {
|
||||
self.0.expand_multiline = expand_multiline;
|
||||
self
|
||||
}
|
||||
|
||||
/// Builds the [`FormatConfig`].
|
||||
pub const fn build(self) -> FormatConfig<'a> {
|
||||
self.0
|
||||
|
|
@ -168,6 +191,7 @@ mod test {
|
|||
indent: " \t",
|
||||
no_comments: true,
|
||||
entry_autoformate_keep: false,
|
||||
expand_multiline: MultilineStringExpansion::Never,
|
||||
}
|
||||
));
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -311,8 +311,10 @@ impl KdlNode {
|
|||
for entry in &mut self.entries {
|
||||
if config.entry_autoformate_keep {
|
||||
entry.keep_format();
|
||||
entry.autoformat();
|
||||
} else {
|
||||
entry.autoformat_with_multiline(config.expand_multiline);
|
||||
}
|
||||
entry.autoformat();
|
||||
}
|
||||
if let Some(children) = self.children.as_mut() {
|
||||
children.autoformat_config(&FormatConfig {
|
||||
|
|
|
|||
|
|
@ -24,3 +24,96 @@ fn build_and_format() {
|
|||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiline_string_never() -> miette::Result<()> {
|
||||
let input = r#"multi """
|
||||
a
|
||||
b
|
||||
c
|
||||
"""
|
||||
multi-explicit "a\nb\nc""#;
|
||||
|
||||
let mut doc: KdlDocument = input.parse()?;
|
||||
doc.autoformat();
|
||||
|
||||
let output = doc.to_string();
|
||||
assert_eq!(
|
||||
output,
|
||||
"multi \"a\\nb\\nc\"\nmulti-explicit \"a\\nb\\nc\"\n"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiline_string_triple_quotes() -> miette::Result<()> {
|
||||
let input = r#"multi """
|
||||
a
|
||||
b
|
||||
c
|
||||
"""
|
||||
multi-explicit "a\nb\nc""#;
|
||||
|
||||
let mut doc: KdlDocument = input.parse()?;
|
||||
doc.autoformat_config(
|
||||
&kdl::FormatConfig::builder()
|
||||
.expand_multiline(kdl::MultilineStringExpansion::TripleQuotes)
|
||||
.build(),
|
||||
);
|
||||
|
||||
let output = doc.to_string();
|
||||
assert!(output.contains("multi \"\"\""));
|
||||
assert!(output.contains("multi-explicit \"a\\nb\\nc\""));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiline_string_always() -> miette::Result<()> {
|
||||
let input = r#"multi """
|
||||
a
|
||||
b
|
||||
c
|
||||
"""
|
||||
multi-explicit "a\nb\nc""#;
|
||||
|
||||
let mut doc: KdlDocument = input.parse()?;
|
||||
doc.autoformat_config(
|
||||
&kdl::FormatConfig::builder()
|
||||
.expand_multiline(kdl::MultilineStringExpansion::Always)
|
||||
.build(),
|
||||
);
|
||||
|
||||
let output = doc.to_string();
|
||||
assert!(output.contains("multi \"\"\""));
|
||||
assert!(output.contains("multi-explicit \"\"\""));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiline_string_nested_triple_quotes() -> miette::Result<()> {
|
||||
let input = r#"some-node {
|
||||
multi """
|
||||
a
|
||||
b
|
||||
c
|
||||
"""
|
||||
explicit "a\nb\nc"
|
||||
}"#;
|
||||
|
||||
let mut doc: KdlDocument = input.parse()?;
|
||||
doc.autoformat_config(
|
||||
&kdl::FormatConfig::builder()
|
||||
.expand_multiline(kdl::MultilineStringExpansion::TripleQuotes)
|
||||
.build(),
|
||||
);
|
||||
|
||||
let output = doc.to_string();
|
||||
// Multiline string should be preserved
|
||||
assert!(output.contains("multi \"\"\""));
|
||||
// Regular string should be normalized
|
||||
assert!(output.contains("explicit \"a\\nb\\nc\""));
|
||||
// Indentation should be normalized to 4 spaces
|
||||
assert!(output.contains(" multi"));
|
||||
assert!(output.contains(" explicit"));
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue