Paul Stewart | b9b3f9d | 2014-09-10 15:12:39 -0700 | [diff] [blame] | 1 | // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "chromeos-dbus-bindings/indented_text.h" |
| 6 | |
| 7 | #include <string> |
| 8 | #include <utility> |
| 9 | #include <vector> |
| 10 | |
| 11 | #include <base/logging.h> |
Alex Vakulenko | 0a86514 | 2014-11-26 08:44:50 -0800 | [diff] [blame] | 12 | #include <base/strings/string_util.h> |
Alex Vakulenko | 4f3c05e | 2014-11-12 15:01:46 -0800 | [diff] [blame] | 13 | #include <chromeos/strings/string_utils.h> |
Paul Stewart | b9b3f9d | 2014-09-10 15:12:39 -0700 | [diff] [blame] | 14 | |
| 15 | using std::string; |
| 16 | using std::vector; |
| 17 | |
| 18 | namespace chromeos_dbus_bindings { |
| 19 | |
| 20 | IndentedText::IndentedText() : offset_(0) {} |
| 21 | |
Paul Stewart | 8d62c29 | 2014-10-01 05:40:57 -0700 | [diff] [blame] | 22 | void IndentedText::AddBlankLine() { |
| 23 | AddLine(""); |
| 24 | } |
| 25 | |
Paul Stewart | b9b3f9d | 2014-09-10 15:12:39 -0700 | [diff] [blame] | 26 | void IndentedText::AddBlock(const IndentedText& block) { |
| 27 | AddBlockWithOffset(block, 0); |
| 28 | } |
| 29 | |
| 30 | void IndentedText::AddBlockWithOffset(const IndentedText& block, size_t shift) { |
| 31 | for (const auto& member : block.contents_) { |
| 32 | AddLineWithOffset(member.first, member.second + shift); |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | void IndentedText::AddLine(const std::string& line) { |
| 37 | AddLineWithOffset(line, 0); |
| 38 | } |
| 39 | |
| 40 | void IndentedText::AddLineWithOffset(const std::string& line, size_t shift) { |
| 41 | contents_.emplace_back(line, shift + offset_); |
| 42 | } |
| 43 | |
Alex Vakulenko | 99e8fb0 | 2014-12-01 17:22:03 -0800 | [diff] [blame^] | 44 | void IndentedText::AddLineAndPushOffsetTo(const std::string& line, |
| 45 | size_t occurrence, |
| 46 | char c) { |
| 47 | AddLine(line); |
| 48 | size_t pos = 0; |
| 49 | while (occurrence > 0) { |
| 50 | pos = line.find(c, pos); |
| 51 | CHECK(pos != string::npos); |
| 52 | pos++; |
| 53 | occurrence--; |
| 54 | } |
| 55 | PushOffset(pos); |
| 56 | } |
| 57 | |
Alex Vakulenko | 4f3c05e | 2014-11-12 15:01:46 -0800 | [diff] [blame] | 58 | void IndentedText::AddComments(const std::string& doc_string) { |
Alex Vakulenko | 0a86514 | 2014-11-26 08:44:50 -0800 | [diff] [blame] | 59 | // Try to retain indentation in the comments. Find the first non-empty line |
| 60 | // of the comment and find its whitespace indentation prefix. |
| 61 | // For all subsequent lines, remove the same whitespace prefix as found |
| 62 | // at the first line of the comment but keep any additional spaces to |
| 63 | // maintain the comment layout. |
| 64 | auto lines = chromeos::string_utils::Split(doc_string, '\n', false, false); |
| 65 | vector<string> lines_out; |
| 66 | lines_out.reserve(lines.size()); |
| 67 | bool first_nonempty_found = false; |
| 68 | std::string trim_prefix; |
| 69 | for (string line : lines) { |
| 70 | base::TrimWhitespaceASCII(line, base::TRIM_TRAILING, &line); |
| 71 | if (!first_nonempty_found) { |
| 72 | size_t pos = line.find_first_not_of(" \t"); |
| 73 | if (pos != std::string::npos) { |
| 74 | first_nonempty_found = true; |
| 75 | trim_prefix = line.substr(0, pos); |
| 76 | lines_out.push_back(line.substr(pos)); |
| 77 | } |
| 78 | } else { |
| 79 | if (StartsWithASCII(line, trim_prefix, false)) { |
| 80 | line = line.substr(trim_prefix.length()); |
| 81 | } else { |
| 82 | base::TrimWhitespaceASCII(line, base::TRIM_LEADING, &line); |
| 83 | } |
| 84 | lines_out.push_back(line); |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | // We already eliminated all empty lines at the beginning of the comment |
| 89 | // block. Now remove the trailing empty lines. |
| 90 | while (!lines_out.empty() && lines_out.back().empty()) |
| 91 | lines_out.pop_back(); |
| 92 | |
| 93 | for (const string& line : lines_out) { |
| 94 | const bool all_whitespace = (line.find_first_not_of(" \t") == string::npos); |
| 95 | if (all_whitespace) { |
| 96 | AddLine("//"); |
| 97 | } else { |
| 98 | AddLine("// " + line); |
| 99 | } |
Alex Vakulenko | 4f3c05e | 2014-11-12 15:01:46 -0800 | [diff] [blame] | 100 | } |
| 101 | } |
| 102 | |
Paul Stewart | b9b3f9d | 2014-09-10 15:12:39 -0700 | [diff] [blame] | 103 | string IndentedText::GetContents() const { |
| 104 | string output; |
| 105 | for (const auto& member : contents_) { |
Paul Stewart | 8d62c29 | 2014-10-01 05:40:57 -0700 | [diff] [blame] | 106 | const string& line = member.first; |
| 107 | size_t shift = line.empty() ? 0 : member.second; |
| 108 | string indent(shift, ' '); |
| 109 | output.append(indent + line + "\n"); |
Paul Stewart | b9b3f9d | 2014-09-10 15:12:39 -0700 | [diff] [blame] | 110 | } |
| 111 | return output; |
| 112 | } |
| 113 | |
| 114 | void IndentedText::PushOffset(size_t shift) { |
| 115 | offset_ += shift; |
| 116 | offset_history_.push_back(shift); |
| 117 | } |
| 118 | |
| 119 | void IndentedText::PopOffset() { |
| 120 | CHECK(!offset_history_.empty()); |
| 121 | offset_ -= offset_history_.back(); |
| 122 | offset_history_.pop_back(); |
| 123 | } |
| 124 | |
| 125 | void IndentedText::Reset() { |
| 126 | offset_ = 0; |
| 127 | offset_history_.clear(); |
| 128 | contents_.clear(); |
| 129 | } |
| 130 | |
| 131 | } // namespace chromeos_dbus_bindings |