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

Summary:
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.

Reviewers: bogner

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D10109

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238584 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Frederic Riss 2015-05-29 17:56:28 +00:00
parent 82fdcc0e7f
commit 9282af9d6c
4 changed files with 137 additions and 7 deletions

View File

@ -798,6 +798,8 @@ add "static const bool flow = true;". For instance:
static const bool flow = true;
}
Flow mappings are subject to line wrapping according to the Output object
configuration.
Sequence
========
@ -845,6 +847,8 @@ With the above, if you used MyList as the data type in your native data
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.
Utility Macros
--------------
@ -908,14 +912,14 @@ Output
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
@ -924,6 +928,10 @@ 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;

View File

@ -1114,7 +1114,7 @@ private:
///
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 @@ private:
};
llvm::raw_ostream &Out;
int WrapColumn;
SmallVector<InState, 8> StateStack;
int Column;
int ColumnAtFlowStart;

View File

@ -404,9 +404,10 @@ bool Input::canElideEmptySequence() {
// 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 @@ void Output::endFlowSequence() {
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::paddedKey(StringRef key) {
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(" ");

View File

@ -2074,3 +2074,123 @@ TEST(YAMLIO, TestEmptyStringSucceedsForSequence) {
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();
}
}