Home | History | Annotate | Download | only in chromeos-dbus-bindings
      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 
     20 IndentedText::IndentedText() : offset_(0) {}
     21 
     22 void IndentedText::AddBlankLine() {
     23   AddLine("");
     24 }
     25 
     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 
     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 
     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 
    104 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 
    113 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 
    124 void IndentedText::PushOffset(size_t shift) {
    125   offset_ += shift;
    126   offset_history_.push_back(shift);
    127 }
    128 
    129 void IndentedText::PopOffset() {
    130   CHECK(!offset_history_.empty());
    131   offset_ -= offset_history_.back();
    132   offset_history_.pop_back();
    133 }
    134 
    135 void IndentedText::Reset() {
    136   offset_ = 0;
    137   offset_history_.clear();
    138   contents_.clear();
    139 }
    140 
    141 }  // namespace chromeos_dbus_bindings
    142