diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 1541e17d0..ea96385a1 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -366,7 +366,28 @@ bool WriteDoubleQuotedString(ostream_wrapper& out, const char* str, std::size_t bool WriteLiteralString(ostream_wrapper& out, const char* str, std::size_t size, std::size_t indent) { - out << "|\n"; + // depending on the numbers of new lines at the end of the string + // we need to use 'clip (-)', 'strip (default)' or 'keep' (+) annotation. + // if there is no newline at the end, we need 'clip' + // if there is single new line at the end, we need 'strip' + // otherwise 'keep' + // + // see YAML spec 1.2 chapter '8.1.1.2 Block Chomping Indicator' for more information + // https://yaml.org/spec/1.2.2/#8112-block-chomping-indicator + + + // The chomping depends on the number of new lines. + // The output following this 'WriteLiteralString' call will add an additional '\n', + // because of this we need to remove one in the case of 'strip' and 'keep'. + if (size == 0 || str[size-1] != '\n') { // clip + out << "|-\n"; + } else if (size == 1 || str[size-2] != '\n') { // strip + out << "|\n"; + size -= 1; + } else { // 'keep' + out << "|+\n"; + size -= 1; + } int codePoint; for (const char* i = str; GetNextCodePointAndAdvance(codePoint, i, str + size);) { diff --git a/test/integration/emitter_test.cpp b/test/integration/emitter_test.cpp index f1472d6f3..64cc999e6 100644 --- a/test/integration/emitter_test.cpp +++ b/test/integration/emitter_test.cpp @@ -101,7 +101,7 @@ TEST_F(EmitterTest, StringFormat) { out << "string"; out << EndSeq; - ExpectEmit("- 'string'\n- \"string\"\n- |\n string"); + ExpectEmit("- 'string'\n- \"string\"\n- |-\n string"); } TEST_F(EmitterTest, IntBase) { @@ -409,7 +409,7 @@ TEST_F(EmitterTest, ScalarFormat) { "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit " "double-quoted scalar\"\n- \"auto-detected\\ndouble-quoted " "scalar\"\n- a " - "non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n " + "non-\"auto-detected\" double-quoted scalar\n- |-\n literal scalar\n " " " "that may span\n many, many\n lines and have \"whatever\" " "crazy\tsymbols that we like"); @@ -424,18 +424,34 @@ TEST_F(EmitterTest, LiteralWithoutTrailingSpaces) { out << YAML::EndMap; ExpectEmit( - "key: |\n" + "key: |-\n" " expect that with two newlines\n\n" " no spaces are emitted in the empty line"); } +TEST_F(EmitterTest, LiteralWithAndWithoutTrailingEmptyLines) { + out << BeginSeq; + out << Literal << "A\nB"; + out << Literal << "A\nB\n"; + out << Literal << "A\nB\n\n\n"; + out << "something"; + out << EndSeq; + + ExpectEmit( + "- |-\n A\n B\n" + "- |\n A\n B\n" + "- |+\n A\n B\n\n\n" + "- something"); +} + + TEST_F(EmitterTest, AutoLongKeyScalar) { out << BeginMap; out << Key << Literal << "multi-line\nscalar"; out << Value << "and its value"; out << EndMap; - ExpectEmit("? |\n multi-line\n scalar\n: and its value"); + ExpectEmit("? |-\n multi-line\n scalar\n: and its value"); } TEST_F(EmitterTest, LongKeyFlowMap) { @@ -717,7 +733,7 @@ TEST_F(EmitterTest, ComplexDoc) { "given: Dorothy\n family: Gale\nitems:\n - part_no: A4786\n " "descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n - " "part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: " - "100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado " + "100.27\n quantity: 1\nbill-to: &id001\n street: |-\n 123 Tornado " "Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: " "*id001"); }