• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
12 #include <base/strings/string_util.h>
13 #include <brillo/strings/string_utils.h>
14 
15 using std::string;
16 using std::vector;
17 
18 namespace chromeos_dbus_bindings {
19 
IndentedText()20 IndentedText::IndentedText() : offset_(0) {}
21 
AddBlankLine()22 void IndentedText::AddBlankLine() {
23   AddLine("");
24 }
25 
AddBlock(const IndentedText & block)26 void IndentedText::AddBlock(const IndentedText& block) {
27   AddBlockWithOffset(block, 0);
28 }
29 
AddBlockWithOffset(const IndentedText & block,size_t shift)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 
AddLine(const std::string & line)36 void IndentedText::AddLine(const std::string& line) {
37   AddLineWithOffset(line, 0);
38 }
39 
AddLineWithOffset(const std::string & line,size_t shift)40 void IndentedText::AddLineWithOffset(const std::string& line, size_t shift) {
41   contents_.emplace_back(line, shift + offset_);
42 }
43 
AddLineAndPushOffsetTo(const std::string & line,size_t occurrence,char c)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 
AddComments(const std::string & doc_string)58 void IndentedText::AddComments(const std::string& doc_string) {
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 = brillo::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 (base::StartsWith(line, trim_prefix,
80                            base::CompareCase::INSENSITIVE_ASCII)) {
81         line = line.substr(trim_prefix.length());
82       } else {
83         base::TrimWhitespaceASCII(line, base::TRIM_LEADING, &line);
84       }
85       lines_out.push_back(line);
86     }
87   }
88 
89   // We already eliminated all empty lines at the beginning of the comment
90   // block. Now remove the trailing empty lines.
91   while (!lines_out.empty() && lines_out.back().empty())
92     lines_out.pop_back();
93 
94   for (const string& line : lines_out) {
95     const bool all_whitespace = (line.find_first_not_of(" \t") == string::npos);
96     if (all_whitespace) {
97       AddLine("//");
98     } else {
99       AddLine("// " + line);
100     }
101   }
102 }
103 
GetContents() const104 string IndentedText::GetContents() const {
105   string output;
106   for (const string& line : GetLines()) {
107     output.append(line);
108     output.append("\n");
109   }
110   return output;
111 }
112 
GetLines() const113 std::vector<std::string> IndentedText::GetLines() const {
114   vector<string> result;
115   for (const auto& member : contents_) {
116     const string& line = member.first;
117     size_t shift = line.empty() ? 0 : member.second;
118     string indent(shift, ' ');
119     result.push_back(indent + line);
120   }
121   return result;
122 }
123 
PushOffset(size_t shift)124 void IndentedText::PushOffset(size_t shift) {
125   offset_ += shift;
126   offset_history_.push_back(shift);
127 }
128 
PopOffset()129 void IndentedText::PopOffset() {
130   CHECK(!offset_history_.empty());
131   offset_ -= offset_history_.back();
132   offset_history_.pop_back();
133 }
134 
Reset()135 void IndentedText::Reset() {
136   offset_ = 0;
137   offset_history_.clear();
138   contents_.clear();
139 }
140 
141 }  // namespace chromeos_dbus_bindings
142