| // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromeos-dbus-bindings/indented_text.h" |
| |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/check.h> |
| #include <base/logging.h> |
| #include <base/strings/string_split.h> |
| #include <base/strings/string_util.h> |
| |
| using std::string; |
| using std::vector; |
| |
| namespace chromeos_dbus_bindings { |
| |
| IndentedText::IndentedText() : offset_(0) {} |
| |
| void IndentedText::AddBlankLine() { |
| AddLine(""); |
| } |
| |
| void IndentedText::AddBlock(const IndentedText& block) { |
| AddBlockWithOffset(block, 0); |
| } |
| |
| void IndentedText::AddBlockWithOffset(const IndentedText& block, size_t shift) { |
| for (const auto& member : block.contents_) { |
| AddLineWithOffset(member.first, member.second + shift); |
| } |
| } |
| |
| void IndentedText::AddLine(const std::string& line) { |
| AddLineWithOffset(line, 0); |
| } |
| |
| void IndentedText::AddLineWithOffset(const std::string& line, size_t shift) { |
| contents_.emplace_back(line, shift + offset_); |
| } |
| |
| void IndentedText::AddLineAndPushOffsetTo(const std::string& line, |
| size_t occurrence, |
| char c) { |
| AddLine(line); |
| size_t pos = 0; |
| while (occurrence > 0) { |
| pos = line.find(c, pos); |
| CHECK(pos != string::npos); |
| pos++; |
| occurrence--; |
| } |
| PushOffset(pos); |
| } |
| |
| void IndentedText::AddComments(const std::string& doc_string) { |
| // Try to retain indentation in the comments. Find the first non-empty line |
| // of the comment and find its whitespace indentation prefix. |
| // For all subsequent lines, remove the same whitespace prefix as found |
| // at the first line of the comment but keep any additional spaces to |
| // maintain the comment layout. |
| auto lines = base::SplitString(doc_string, "\n", base::KEEP_WHITESPACE, |
| base::SPLIT_WANT_ALL); |
| vector<string> lines_out; |
| lines_out.reserve(lines.size()); |
| bool first_nonempty_found = false; |
| std::string trim_prefix; |
| for (string line : lines) { |
| base::TrimWhitespaceASCII(line, base::TRIM_TRAILING, &line); |
| if (!first_nonempty_found) { |
| size_t pos = line.find_first_not_of(" \t"); |
| if (pos != std::string::npos) { |
| first_nonempty_found = true; |
| trim_prefix = line.substr(0, pos); |
| lines_out.push_back(line.substr(pos)); |
| } |
| } else { |
| if (base::StartsWith(line, trim_prefix, |
| base::CompareCase::INSENSITIVE_ASCII)) { |
| line = line.substr(trim_prefix.length()); |
| } else { |
| base::TrimWhitespaceASCII(line, base::TRIM_LEADING, &line); |
| } |
| lines_out.push_back(line); |
| } |
| } |
| |
| // We already eliminated all empty lines at the beginning of the comment |
| // block. Now remove the trailing empty lines. |
| while (!lines_out.empty() && lines_out.back().empty()) |
| lines_out.pop_back(); |
| |
| for (const string& line : lines_out) { |
| const bool all_whitespace = (line.find_first_not_of(" \t") == string::npos); |
| if (all_whitespace) { |
| AddLine("//"); |
| } else { |
| AddLine("// " + line); |
| } |
| } |
| } |
| |
| string IndentedText::GetContents() const { |
| string output; |
| for (const string& line : GetLines()) { |
| output.append(line); |
| output.append("\n"); |
| } |
| return output; |
| } |
| |
| std::vector<std::string> IndentedText::GetLines() const { |
| vector<string> result; |
| for (const auto& member : contents_) { |
| const string& line = member.first; |
| size_t shift = line.empty() ? 0 : member.second; |
| string indent(shift, ' '); |
| result.push_back(indent + line); |
| } |
| return result; |
| } |
| |
| void IndentedText::PushOffset(size_t shift) { |
| offset_ += shift; |
| offset_history_.push_back(shift); |
| } |
| |
| void IndentedText::PopOffset() { |
| CHECK(!offset_history_.empty()); |
| offset_ -= offset_history_.back(); |
| offset_history_.pop_back(); |
| } |
| |
| void IndentedText::Reset() { |
| offset_ = 0; |
| offset_history_.clear(); |
| contents_.clear(); |
| } |
| |
| } // namespace chromeos_dbus_bindings |