From d386be1a495a54ff13b5ba880a47016a090150be Mon Sep 17 00:00:00 2001 From: Garrett Berg Date: Sun, 13 Aug 2017 16:15:15 -0600 Subject: [PATCH] add pretty_string_literal to be able to disable literal strings --- src/ser.rs | 79 ++++++++++++++++++++++++++++++++++++++++++------- tests/pretty.rs | 44 ++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 11 deletions(-) diff --git a/src/ser.rs b/src/ser.rs index 3c4c220..ef037ed 100644 --- a/src/ser.rs +++ b/src/ser.rs @@ -169,9 +169,19 @@ impl ArraySettings { #[doc(hidden)] #[derive(Debug, Default, Clone)] -/// String settings. Currently empty but may contain settings -/// eventually. -struct StringSettings(); +/// String settings +struct StringSettings { + /// Whether to use literal strings when possible + literal: bool, +} + +impl StringSettings { + fn pretty() -> StringSettings { + StringSettings { + literal: true, + } + } +} #[derive(Debug, Default, Clone)] #[doc(hidden)] @@ -259,7 +269,7 @@ impl<'a> Serializer<'a> { state: State::End, settings: Rc::new(Settings { array: Some(ArraySettings::pretty()), - string: Some(StringSettings()), + string: Some(StringSettings::pretty()), }), } } @@ -289,13 +299,56 @@ impl<'a> Serializer<'a> { /// ``` pub fn pretty_string(&mut self, value: bool) -> &mut Self { Rc::get_mut(&mut self.settings).unwrap().string = if value { - Some(StringSettings()) + Some(StringSettings::pretty()) } else { None }; self } + /// Enable or Disable Literal strings for pretty strings + /// + /// If enabled, literal strings will be used when possible and strings with + /// one or more newlines will use triple quotes (i.e.: `'''` or `"""`) + /// + /// If disabled, literal strings will NEVER be used and strings with one or + /// more newlines will use `"""` + /// + /// # Examples + /// + /// Instead of: + /// + /// ```toml,ignore + /// single = "no newlines" + /// text = "\nfoo\nbar\n" + /// ``` + /// + /// You will have: + /// + /// ```toml,ignore + /// single = "no newlines" + /// text = """ + /// foo + /// bar + /// """ + /// ``` + pub fn pretty_string_literal(&mut self, value: bool) -> &mut Self { + let use_default = if let &mut Some(ref mut s) = &mut Rc::get_mut(&mut self.settings) + .unwrap().string { + s.literal = value; + false + } else { + true + }; + + if use_default { + let mut string = StringSettings::pretty(); + string.literal = value; + Rc::get_mut(&mut self.settings).unwrap().string = Some(string); + } + self + } + /// Enable or Disable pretty arrays /// /// If enabled, arrays will always have each item on their own line. @@ -548,7 +601,11 @@ impl<'a> Serializer<'a> { } let repr = if !is_key && self.settings.string.is_some() { - do_pretty(value) + match (&self.settings.string, do_pretty(value)) { + (&Some(StringSettings { literal: false, .. }), Repr::Literal(_, ty)) => + Repr::Std(ty), + (_, r @ _) => r, + } } else { Repr::Std(Type::OnelineSingle) }; @@ -569,8 +626,11 @@ impl<'a> Serializer<'a> { Repr::Std(ty) => { match ty { Type::NewlineTripple => self.dst.push_str("\"\"\"\n"), - Type::OnelineSingle => self.dst.push('"'), - _ => unreachable!(), + // note: OnelineTripple can happen if do_pretty wants to do + // '''it's one line''' + // but settings.string.literal == false + Type::OnelineSingle | + Type::OnelineTripple => self.dst.push('"'), } for ch in value.chars() { match ch { @@ -593,8 +653,7 @@ impl<'a> Serializer<'a> { } match ty { Type::NewlineTripple => self.dst.push_str("\"\"\""), - Type::OnelineSingle => self.dst.push('"'), - _ => unreachable!(), + Type::OnelineSingle | Type::OnelineTripple => self.dst.push('"'), } }, } diff --git a/tests/pretty.rs b/tests/pretty.rs index 3a9777c..ce906d9 100644 --- a/tests/pretty.rs +++ b/tests/pretty.rs @@ -198,7 +198,7 @@ text = """ this is the first line. This has a ''' in it and \"\"\" cuz it's tricky yo Also ' and \" because why not -this is the third line +this is the fourth line """ "##; @@ -260,3 +260,45 @@ fn table_array() { println!("\nRESULT:\n{}", result); assert_eq!(toml, &result); } + +// FIXME: add the `glass` line to this. Unfortunately there seems to +// be an issue with the deserialization module that treats the first \n +// as a real newline in that case (not cool) +const PRETTY_TRICKY_NON_LITERAL: &'static str = r##"[example] +f = "\f" +plain = """ +This has a couple of lines +Because it likes to. +""" +r = "\r" +r_newline = """ +\r +""" +single = "this is a single line but has '' cuz it's tricky" +single_tricky = "single line with ''' in it" +tabs = """ +this is pretty standard +\texcept for some \ttabs right here +""" +text = """ +this is the first line. +This has a ''' in it and \"\"\" cuz it's tricky yo +Also ' and \" because why not +this is the fourth line +""" +"##; + +#[test] +fn pretty_tricky_non_literal() { + let toml = PRETTY_TRICKY_NON_LITERAL; + let value: toml::Value = toml::from_str(toml).unwrap(); + let mut result = String::with_capacity(128); + { + let mut serializer = toml::Serializer::pretty(&mut result); + serializer.pretty_string_literal(false); + value.serialize(&mut serializer).unwrap(); + } + println!("EXPECTED:\n{}", toml); + println!("\nRESULT:\n{}", result); + assert_eq!(toml, &result); +}