// 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 #include #include #include #include #include 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 = brillo::string_utils::Split(doc_string, "\n", false, false); vector 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::StartsWithASCII(line, trim_prefix, false)) { 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 IndentedText::GetLines() const { vector 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