diff --git a/saphyr/src/emitter.rs b/saphyr/src/emitter.rs index 3653f56..6e98ba8 100644 --- a/saphyr/src/emitter.rs +++ b/saphyr/src/emitter.rs @@ -171,7 +171,7 @@ impl<'a> YamlEmitter<'a> { /// emitter.dump(&parsed[0]).unwrap(); /// assert_eq!(output.as_str(), "\ /// --- - /// foo: | + /// foo: |- /// bar! /// bar! /// baz: 42"); @@ -219,15 +219,7 @@ impl<'a> YamlEmitter<'a> { && v.contains('\n') && char_traits::is_valid_literal_block_scalar(v) { - write!(self.writer, "|")?; - self.level += 1; - for line in v.lines() { - writeln!(self.writer)?; - self.write_indent()?; - // It's literal text, so don't escape special chars. - write!(self.writer, "{line}")?; - } - self.level -= 1; + self.emit_literal_block(v)?; } else if need_quotes(v) { escape_str(self.writer, v)?; } else { @@ -260,6 +252,26 @@ impl<'a> YamlEmitter<'a> { } } + fn emit_literal_block(&mut self, v: &str) -> EmitResult { + let ends_with_newline = v.ends_with('\n'); + if ends_with_newline { + self.writer.write_str("|")?; + } else { + self.writer.write_str("|-")?; + } + + self.level += 1; + // lines() will omit the last line if it is empty. + for line in v.lines() { + writeln!(self.writer)?; + self.write_indent()?; + // It's literal text, so don't escape special chars. + self.writer.write_str(line)?; + } + self.level -= 1; + Ok(()) + } + fn emit_array(&mut self, v: &[Yaml]) -> EmitResult { if v.is_empty() { write!(self.writer, "[]")?; diff --git a/saphyr/tests/test_round_trip.rs b/saphyr/tests/test_round_trip.rs index e4ada73..8280f22 100644 --- a/saphyr/tests/test_round_trip.rs +++ b/saphyr/tests/test_round_trip.rs @@ -11,6 +11,19 @@ fn roundtrip(original: &Yaml) { assert_eq!(documents[0], *original); } +fn roundtrip_multiline(original: &Yaml) { + let mut emitted = String::new(); + let mut emitter = YamlEmitter::new(&mut emitted); + emitter.multiline_strings(true); + emitter.dump(original).unwrap(); + + let documents = Yaml::load_from_str(&emitted).unwrap(); + println!("emitted {emitted}"); + + assert_eq!(documents.len(), 1); + assert_eq!(documents[0], *original); +} + fn double_roundtrip(original: &str) { let parsed = Yaml::load_from_str(original).unwrap(); @@ -75,3 +88,27 @@ fn test_crlf() { let y = Yaml::Array(vec![Yaml::String("\r\n".to_owned())]); roundtrip(&y); } + +#[test] +fn test_multiline_noline() { + let y = Yaml::Array(vec![Yaml::String("a".to_owned())]); + roundtrip_multiline(&y); +} + +#[test] +fn test_multiline_inner_newline() { + let y = Yaml::Array(vec![Yaml::String("a\nb".to_owned())]); + roundtrip_multiline(&y); +} + +#[test] +fn test_multiline_trailing_newline() { + let y = Yaml::Array(vec![Yaml::String("a\n".to_owned())]); + roundtrip_multiline(&y); +} + +#[test] +fn test_multiline_leading_newline() { + let y = Yaml::Array(vec![Yaml::String("\na".to_owned())]); + roundtrip_multiline(&y); +}