[PATCH] [YAMLIO] Make line-wrapping configurable and test it.

Justin Bogner mail at justinbogner.com
Thu May 28 16:48:14 PDT 2015


Frederic Riss <friss at apple.com> writes:
> Hi bogner,
>
> We would wrap flow mappings and sequences when they go over a hardcoded 70
> characters limit. Make the wrapping column configurable (and default to 70
> co the change should be NFC for current users). Passing 0 allows to completely
> suppress the wrapping which makes it easier to handle in tools like FileCheck.

LGTM, with a minor comment.

> http://reviews.llvm.org/D10109
>
> Files:
>   docs/YamlIO.rst
>   include/llvm/Support/YAMLTraits.h
>   lib/Support/YAMLTraits.cpp
>   unittests/Support/YAMLIOTest.cpp
>
> EMAIL PREFERENCES
>   http://reviews.llvm.org/settings/panel/emailpreferences/
>
> Index: docs/YamlIO.rst
> ===================================================================
> --- docs/YamlIO.rst
> +++ docs/YamlIO.rst
> @@ -798,6 +798,7 @@
>        static const bool flow = true;
>      }
>  
> +Flow mappings are subject to line wrapping according to the Output object configuration.
>  
>  Sequence
>  ========
> @@ -845,6 +846,7 @@
>  structures, then when converted to YAML, a flow sequence of integers 
>  will be used (e.g. [ 10, -3, 4 ]).
>  
> +Flow sequences are subject to line wrapping according to the Output object configuration.

Could you subject these lines to line wrapping? ;)

>  
>  Utility Macros
>  --------------
> @@ -908,22 +910,26 @@
>  
>  The llvm::yaml::Output class is used to generate a YAML document from your 
>  in-memory data structures, using traits defined on your data types.  
> -To instantiate an Output object you need an llvm::raw_ostream, and optionally 
> -a context pointer:
> +To instantiate an Output object you need an llvm::raw_ostream, an optional 
> +context pointer and an optional wrapping column:
>  
>  .. code-block:: c++
>  
>        class Output : public IO {
>        public:
> -        Output(llvm::raw_ostream &, void *context=NULL);
> +        Output(llvm::raw_ostream &, void *context = NULL, int WrapColumn = 70);
>      
>  Once you have an Output object, you can use the C++ stream operator on it
>  to write your native data as YAML. One thing to recall is that a YAML file
>  can contain multiple "documents".  If the top level data structure you are
>  streaming as YAML is a mapping, scalar, or sequence, then Output assumes you
>  are generating one document and wraps the mapping output 
>  with  "``---``" and trailing "``...``".  
>  
> +The WrapColumn parameter will cause the flow mappings and sequences to
> +line-wrap when they go over the supplied column. Pass 0 to completely
> +suppress the wrapping.
> +
>  .. code-block:: c++
>     
>      using llvm::yaml::Output;
> Index: include/llvm/Support/YAMLTraits.h
> ===================================================================
> --- include/llvm/Support/YAMLTraits.h
> +++ include/llvm/Support/YAMLTraits.h
> @@ -1114,7 +1114,7 @@
>  ///
>  class Output : public IO {
>  public:
> -  Output(llvm::raw_ostream &, void *Ctxt=nullptr);
> +  Output(llvm::raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70);
>    ~Output() override;
>  
>    bool outputting() override;
> @@ -1170,6 +1170,7 @@
>    };
>  
>    llvm::raw_ostream       &Out;
> +  int                      WrapColumn;
>    SmallVector<InState, 8>  StateStack;
>    int                      Column;
>    int                      ColumnAtFlowStart;
> Index: lib/Support/YAMLTraits.cpp
> ===================================================================
> --- lib/Support/YAMLTraits.cpp
> +++ lib/Support/YAMLTraits.cpp
> @@ -404,9 +404,10 @@
>  //  Output
>  //===----------------------------------------------------------------------===//
>  
> -Output::Output(raw_ostream &yout, void *context)
> +Output::Output(raw_ostream &yout, void *context, int WrapColumn)
>      : IO(context),
>        Out(yout),
> +      WrapColumn(WrapColumn),
>        Column(0),
>        ColumnAtFlowStart(0),
>        ColumnAtMapFlowStart(0),
> @@ -529,7 +530,7 @@
>  bool Output::preflightFlowElement(unsigned, void *&) {
>    if (NeedFlowSequenceComma)
>      output(", ");
> -  if (Column > 70) {
> +  if (WrapColumn && Column > WrapColumn) {
>      output("\n");
>      for (int i = 0; i < ColumnAtFlowStart; ++i)
>        output(" ");
> @@ -720,7 +721,7 @@
>  void Output::flowKey(StringRef Key) {
>    if (StateStack.back() == inFlowMapOtherKey)
>      output(", ");
> -  if (Column > 70) {
> +  if (WrapColumn && Column > WrapColumn) {
>      output("\n");
>      for (int I = 0; I < ColumnAtMapFlowStart; ++I)
>        output(" ");
> Index: unittests/Support/YAMLIOTest.cpp
> ===================================================================
> --- unittests/Support/YAMLIOTest.cpp
> +++ unittests/Support/YAMLIOTest.cpp
> @@ -2074,3 +2074,123 @@
>    EXPECT_FALSE(yin.error());
>    EXPECT_TRUE(seq.empty());
>  }
> +
> +struct FlowMap {
> +  llvm::StringRef str1, str2, str3;
> +  FlowMap(llvm::StringRef str1, llvm::StringRef str2, llvm::StringRef str3)
> +    : str1(str1), str2(str2), str3(str3) {}
> +};
> +
> +namespace llvm {
> +namespace yaml {
> +  template <>
> +  struct MappingTraits<FlowMap> {
> +    static void mapping(IO &io, FlowMap &fm) {
> +      io.mapRequired("str1", fm.str1);
> +      io.mapRequired("str2", fm.str2);
> +      io.mapRequired("str3", fm.str3);
> +    }
> +
> +    static const bool flow = true;
> +  };
> +}
> +}
> +
> +struct FlowSeq {
> +  llvm::StringRef str;
> +  FlowSeq(llvm::StringRef S) : str(S) {}
> +  FlowSeq() = default;
> +};
> +
> +template <>
> +struct ScalarTraits<FlowSeq> {
> +  static void output(const FlowSeq &value, void*, llvm::raw_ostream &out) {
> +    out << value.str;
> +  }
> +  static StringRef input(StringRef scalar, void*, FlowSeq &value) {
> +    value.str = scalar;
> +    return "";
> +  }
> +
> +  static bool mustQuote(StringRef S) { return false; }
> +};
> +
> +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FlowSeq)
> +
> +TEST(YAMLIO, TestWrapFlow) {
> +  std::string out;
> +  llvm::raw_string_ostream ostr(out);
> +  FlowMap Map("This is str1", "This is str2", "This is str3");
> +  std::vector<FlowSeq> Seq;
> +  Seq.emplace_back("This is str1");
> +  Seq.emplace_back("This is str2");
> +  Seq.emplace_back("This is str3");
> +
> +  {
> +    // 20 is just bellow the total length of the first mapping field.
> +    // We should wreap at every element.
> +    Output yout(ostr, nullptr, 15);
> +
> +    yout << Map;
> +    ostr.flush();
> +    EXPECT_EQ(out,
> +              "---\n"
> +              "{ str1: This is str1, \n"
> +              "  str2: This is str2, \n"
> +              "  str3: This is str3 }\n"
> +              "...\n");
> +    out.clear();
> +
> +    yout << Seq;
> +    ostr.flush();
> +    EXPECT_EQ(out,
> +              "---\n"
> +              "[ This is str1, \n"
> +              "  This is str2, \n"
> +              "  This is str3 ]\n"
> +              "...\n");
> +    out.clear();
> +  }
> +  {
> +    // 25 will allow the second field to be output on the first line.
> +    Output yout(ostr, nullptr, 25);
> +
> +    yout << Map;
> +    ostr.flush();
> +    EXPECT_EQ(out,
> +              "---\n"
> +              "{ str1: This is str1, str2: This is str2, \n"
> +              "  str3: This is str3 }\n"
> +              "...\n");
> +    out.clear();
> +
> +    yout << Seq;
> +    ostr.flush();
> +    EXPECT_EQ(out,
> +              "---\n"
> +              "[ This is str1, This is str2, \n"
> +              "  This is str3 ]\n"
> +              "...\n");
> +    out.clear();
> +  }
> +  {
> +    // 0 means no wrapping.
> +    Output yout(ostr, nullptr, 0);
> +
> +    yout << Map;
> +    ostr.flush();
> +    EXPECT_EQ(out,
> +              "---\n"
> +              "{ str1: This is str1, str2: This is str2, str3: This is str3 }\n"
> +              "...\n");
> +    out.clear();
> +
> +    yout << Seq;
> +    ostr.flush();
> +    EXPECT_EQ(out,
> +              "---\n"
> +              "[ This is str1, This is str2, This is str3 ]\n"
> +              "...\n");
> +    out.clear();
> +  }
> +}



More information about the llvm-commits mailing list