| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 | 
							- /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 
-    file Copyright.txt or https://cmake.org/licensing for details.  */
 
- #include "cmDocumentationFormatter.h"
 
- #include <algorithm> // IWYU pragma: keep
 
- #include <cassert>
 
- #include <iomanip>
 
- #include <ostream>
 
- #include <string>
 
- #include <vector>
 
- #include "cmDocumentationEntry.h"
 
- #include "cmDocumentationSection.h"
 
- namespace {
 
- const char* skipSpaces(const char* ptr)
 
- {
 
-   assert(ptr);
 
-   for (; *ptr == ' '; ++ptr) {
 
-     ;
 
-   }
 
-   return ptr;
 
- }
 
- const char* skipToSpace(const char* ptr)
 
- {
 
-   assert(ptr);
 
-   for (; *ptr && (*ptr != '\n') && (*ptr != ' '); ++ptr) {
 
-     ;
 
-   }
 
-   return ptr;
 
- }
 
- }
 
- void cmDocumentationFormatter::PrintFormatted(std::ostream& os,
 
-                                               std::string const& text) const
 
- {
 
-   if (text.empty()) {
 
-     return;
 
-   }
 
-   struct Buffer
 
-   {
 
-     // clang-format off
 
-     using PrinterFn = void (cmDocumentationFormatter::*)(
 
-         std::ostream&, std::string const&
 
-       ) const;
 
-     // clang-format on
 
-     std::string collected;
 
-     const PrinterFn printer;
 
-   };
 
-   // const auto NORMAL_IDX = 0u;
 
-   const auto PREFORMATTED_IDX = 1u;
 
-   const auto HANDLERS_SIZE = 2u;
 
-   Buffer buffers[HANDLERS_SIZE] = {
 
-     { {}, &cmDocumentationFormatter::PrintParagraph },
 
-     { {}, &cmDocumentationFormatter::PrintPreformatted }
 
-   };
 
-   const auto padding = std::string(this->TextIndent, ' ');
 
-   for (std::size_t pos = 0u, eol = 0u; pos < text.size(); pos = eol) {
 
-     const auto current_idx = std::size_t(text[pos] == ' ');
 
-     // size_t(!bool(current_idx))
 
-     const auto other_idx = current_idx ^ 1u;
 
-     // Flush the other buffer if anything has been collected
 
-     if (!buffers[other_idx].collected.empty()) {
 
-       // NOTE Whatever the other index is, the current buffered
 
-       // string expected to be empty.
 
-       assert(buffers[current_idx].collected.empty());
 
-       (this->*buffers[other_idx].printer)(os, buffers[other_idx].collected);
 
-       buffers[other_idx].collected.clear();
 
-     }
 
-     // ATTENTION The previous implementation had called `PrintParagraph()`
 
-     // **for every processed (char by char) input line**.
 
-     // The method unconditionally append the `\n' character after the
 
-     // printed text. To keep the backward-compatible behavior it's needed to
 
-     // add the '\n' character to the previously collected line...
 
-     if (!buffers[current_idx].collected.empty() &&
 
-         current_idx != PREFORMATTED_IDX) {
 
-       buffers[current_idx].collected += '\n';
 
-     }
 
-     // Lookup EOL
 
-     eol = text.find('\n', pos);
 
-     if (current_idx == PREFORMATTED_IDX) {
 
-       buffers[current_idx].collected.append(padding);
 
-     }
 
-     buffers[current_idx].collected.append(
 
-       text, pos, eol == std::string::npos ? eol : ++eol - pos);
 
-   }
 
-   for (auto& buf : buffers) {
 
-     if (!buf.collected.empty()) {
 
-       (this->*buf.printer)(os, buf.collected);
 
-     }
 
-   }
 
- }
 
- void cmDocumentationFormatter::PrintPreformatted(std::ostream& os,
 
-                                                  std::string const& text) const
 
- {
 
-   os << text << '\n';
 
- }
 
- void cmDocumentationFormatter::PrintParagraph(std::ostream& os,
 
-                                               std::string const& text) const
 
- {
 
-   if (this->TextIndent) {
 
-     os << std::string(this->TextIndent, ' ');
 
-   }
 
-   this->PrintColumn(os, text);
 
-   os << '\n';
 
- }
 
- void cmDocumentationFormatter::PrintColumn(std::ostream& os,
 
-                                            std::string const& text) const
 
- {
 
-   // Print text arranged in an indented column of fixed width.
 
-   bool newSentence = false;
 
-   bool firstLine = true;
 
-   assert(this->TextIndent < this->TextWidth);
 
-   const std::ptrdiff_t width = this->TextWidth - this->TextIndent;
 
-   std::ptrdiff_t column = 0;
 
-   const auto padding = std::string(this->TextIndent, ' ');
 
-   // Loop until the end of the text.
 
-   for (const char *l = text.c_str(), *r = skipToSpace(text.c_str()); *l;
 
-        l = skipSpaces(r), r = skipToSpace(l)) {
 
-     // Does it fit on this line?
 
-     if (r - l < width - column - std::ptrdiff_t(newSentence)) {
 
-       // Word fits on this line.
 
-       if (r > l) {
 
-         if (column) {
 
-           // Not first word on line.  Separate from the previous word
 
-           // by a space, or two if this is a new sentence.
 
-           os << &("  "[std::size_t(!newSentence)]);
 
-           column += 1u + std::ptrdiff_t(newSentence);
 
-         } else if (!firstLine && this->TextIndent) {
 
-           // First word on line.  Print indentation unless this is the
 
-           // first line.
 
-           os << padding;
 
-         }
 
-         // Print the word.
 
-         os.write(l, r - l);
 
-         newSentence = (*(r - 1) == '.');
 
-       }
 
-       if (*r == '\n') {
 
-         // Text provided a newline.  Start a new line.
 
-         os << '\n';
 
-         ++r;
 
-         column = 0;
 
-         firstLine = false;
 
-       } else {
 
-         // No provided newline.  Continue this line.
 
-         column += r - l;
 
-       }
 
-     } else {
 
-       // Word does not fit on this line.  Start a new line.
 
-       os << '\n';
 
-       firstLine = false;
 
-       if (r > l) {
 
-         os << padding;
 
-         os.write(l, r - l);
 
-         column = r - l;
 
-         newSentence = (*(r - 1) == '.');
 
-       } else {
 
-         column = 0;
 
-       }
 
-     }
 
-     // Move to beginning of next word.  Skip over whitespace.
 
-   }
 
- }
 
- void cmDocumentationFormatter::PrintSection(
 
-   std::ostream& os, cmDocumentationSection const& section)
 
- {
 
-   const std::size_t PREFIX_SIZE =
 
-     sizeof(cmDocumentationEntry::CustomNamePrefix) + 1u;
 
-   // length of the "= " literal (see below)
 
-   const std::size_t SUFFIX_SIZE = 2u;
 
-   // legacy magic number ;-)
 
-   const std::size_t NAME_SIZE = 29u;
 
-   const std::size_t PADDING_SIZE = PREFIX_SIZE + SUFFIX_SIZE;
 
-   const std::size_t TITLE_SIZE = NAME_SIZE + PADDING_SIZE;
 
-   const auto savedIndent = this->TextIndent;
 
-   os << section.GetName() << '\n';
 
-   for (cmDocumentationEntry const& entry : section.GetEntries()) {
 
-     if (!entry.Name.empty()) {
 
-       this->TextIndent = TITLE_SIZE;
 
-       os << std::setw(PREFIX_SIZE) << std::left << entry.CustomNamePrefix
 
-          << std::setw(int(std::max(NAME_SIZE, entry.Name.size())))
 
-          << entry.Name;
 
-       if (entry.Name.size() > NAME_SIZE) {
 
-         os << '\n' << std::setw(int(this->TextIndent - PREFIX_SIZE)) << ' ';
 
-       }
 
-       os << "= ";
 
-       this->PrintColumn(os, entry.Brief);
 
-       os << '\n';
 
-     } else {
 
-       os << '\n';
 
-       this->TextIndent = 0u;
 
-       this->PrintFormatted(os, entry.Brief);
 
-     }
 
-   }
 
-   os << '\n';
 
-   this->TextIndent = savedIndent;
 
- }
 
 
  |