/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <folly/String.h>
+#include <boost/regex.hpp>
#include <folly/Format.h>
#include <folly/ScopeGuard.h>
} // namespace detail
+std::string stripLeftMargin(std::string s) {
+ using namespace boost;
+ static const auto kPre = regex(R"(\A[ \t]*\n)");
+ static const auto kPost = regex(R"([ \t]+\z)");
+ static const auto kScan = regex(R"(^[ \t]*(?=\S))");
+ s = regex_replace(s, kPre, "");
+ s = regex_replace(s, kPost, "");
+ const auto sentinel = std::numeric_limits<size_t>::max();
+ auto indent = sentinel;
+ sregex_iterator it(s.cbegin(), s.cend(), kScan);
+ sregex_iterator itend;
+ for (; it != itend; ++it) {
+ indent = std::min<size_t>(indent, it->length());
+ }
+ indent = indent == sentinel ? 0 : indent;
+ s = regex_replace(s, regex(sformat(R"(^[ \t]{{0,{0}}})", indent)), "");
+ return s;
+}
+
} // namespace folly
#ifdef FOLLY_DEFINED_DMGL
/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
return ltrimWhitespace(sp);
}
+/**
+ * Strips the leading and the trailing whitespace-only lines. Then looks for
+ * the least indented non-whitespace-only line and removes its amount of
+ * leading whitespace from every line. Assumes leading whitespace is either all
+ * spaces or all tabs.
+ *
+ * Purpose: including a multiline string literal in source code, indented to
+ * the level expected from context.
+ */
+std::string stripLeftMargin(std::string s);
+
/**
* Fast, in-place lowercasing of ASCII alphabetic characters in strings.
* Leaves all other characters unchanged, including those with the 0x80
/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <folly/String.h>
+#include <boost/regex.hpp>
#include <gtest/gtest.h>
using namespace folly;
EXPECT_EQ("", rtrimWhitespace("\r "));
}
+TEST(String, stripLeftMargin_empty) {
+ auto input = R"TEXT(
+ )TEXT";
+ auto expected = "";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_one_line) {
+ auto input = R"TEXT(
+ hi there bob!
+ )TEXT";
+ auto expected = "hi there bob!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_two_lines) {
+ auto input = R"TEXT(
+ hi there bob!
+ nice weather today!
+ )TEXT";
+ auto expected = "hi there bob!\nnice weather today!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_three_lines_uneven) {
+ auto input = R"TEXT(
+ hi there bob!
+ nice weather today!
+ so long!
+ )TEXT";
+ auto expected = " hi there bob!\nnice weather today!\n so long!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_preceding_blank_lines) {
+ auto input = R"TEXT(
+
+
+ hi there bob!
+ )TEXT";
+ auto expected = "\n\nhi there bob!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_succeeding_blank_lines) {
+ auto input = R"TEXT(
+ hi there bob!
+
+
+ )TEXT";
+ auto expected = "hi there bob!\n\n\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_interstitial_undented_whiteline) {
+ // using ~ as a marker
+ string input = R"TEXT(
+ hi there bob!
+ ~
+ so long!
+ )TEXT";
+ input = boost::regex_replace(input, boost::regex(" +~"), "");
+ EXPECT_EQ("\n hi there bob!\n\n so long!\n ", input);
+ auto expected = "hi there bob!\n\nso long!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_interstitial_dedented_whiteline) {
+ // using ~ as a marker
+ string input = R"TEXT(
+ hi there bob!
+ ~
+ so long!
+ )TEXT";
+ input = boost::regex_replace(input, boost::regex("~"), "");
+ EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
+ auto expected = "hi there bob!\n\nso long!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_interstitial_equidented_whiteline) {
+ // using ~ as a marker
+ string input = R"TEXT(
+ hi there bob!
+ ~
+ so long!
+ )TEXT";
+ input = boost::regex_replace(input, boost::regex("~"), "");
+ EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
+ auto expected = "hi there bob!\n\nso long!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_interstitial_indented_whiteline) {
+ // using ~ as a marker
+ string input = R"TEXT(
+ hi there bob!
+ ~
+ so long!
+ )TEXT";
+ input = boost::regex_replace(input, boost::regex("~"), "");
+ EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
+ auto expected = "hi there bob!\n \nso long!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
const folly::StringPiece kTestUTF8 = "This is \U0001F602 stuff!";
TEST(UTF8StringPiece, valid_utf8) {