1
0

cmDocumentationFormatter.cxx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmDocumentationFormatter.h"
  4. #include "cmDocumentationEntry.h"
  5. #include "cmDocumentationSection.h"
  6. #include <iomanip>
  7. #include <ostream>
  8. #include <string.h>
  9. #include <string>
  10. #include <vector>
  11. cmDocumentationFormatter::cmDocumentationFormatter() = default;
  12. cmDocumentationFormatter::~cmDocumentationFormatter() = default;
  13. void cmDocumentationFormatter::PrintFormatted(std::ostream& os,
  14. const char* text)
  15. {
  16. if (!text) {
  17. return;
  18. }
  19. const char* ptr = text;
  20. while (*ptr) {
  21. // Any ptrs starting in a space are treated as preformatted text.
  22. std::string preformatted;
  23. while (*ptr == ' ') {
  24. for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) {
  25. preformatted.append(1, ch);
  26. }
  27. if (*ptr) {
  28. ++ptr;
  29. preformatted.append(1, '\n');
  30. }
  31. }
  32. if (!preformatted.empty()) {
  33. this->PrintPreformatted(os, preformatted.c_str());
  34. }
  35. // Other ptrs are treated as paragraphs.
  36. std::string paragraph;
  37. for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) {
  38. paragraph.append(1, ch);
  39. }
  40. if (*ptr) {
  41. ++ptr;
  42. paragraph.append(1, '\n');
  43. }
  44. if (!paragraph.empty()) {
  45. this->PrintParagraph(os, paragraph.c_str());
  46. }
  47. }
  48. }
  49. void cmDocumentationFormatter::PrintPreformatted(std::ostream& os,
  50. const char* text)
  51. {
  52. bool newline = true;
  53. for (const char* ptr = text; *ptr; ++ptr) {
  54. if (newline && *ptr != '\n') {
  55. os << this->TextIndent;
  56. newline = false;
  57. }
  58. os << *ptr;
  59. if (*ptr == '\n') {
  60. newline = true;
  61. }
  62. }
  63. os << "\n";
  64. }
  65. void cmDocumentationFormatter::PrintParagraph(std::ostream& os,
  66. const char* text)
  67. {
  68. os << this->TextIndent;
  69. this->PrintColumn(os, text);
  70. os << "\n";
  71. }
  72. void cmDocumentationFormatter::SetIndent(const char* indent)
  73. {
  74. this->TextIndent = indent;
  75. }
  76. void cmDocumentationFormatter::PrintColumn(std::ostream& os, const char* text)
  77. {
  78. // Print text arranged in an indented column of fixed width.
  79. const char* l = text;
  80. long column = 0;
  81. bool newSentence = false;
  82. bool firstLine = true;
  83. int width = this->TextWidth - static_cast<int>(strlen(this->TextIndent));
  84. // Loop until the end of the text.
  85. while (*l) {
  86. // Parse the next word.
  87. const char* r = l;
  88. while (*r && (*r != '\n') && (*r != ' ')) {
  89. ++r;
  90. }
  91. // Does it fit on this line?
  92. if (r - l < (width - column - (newSentence ? 1 : 0))) {
  93. // Word fits on this line.
  94. if (r > l) {
  95. if (column) {
  96. // Not first word on line. Separate from the previous word
  97. // by a space, or two if this is a new sentence.
  98. if (newSentence) {
  99. os << " ";
  100. column += 2;
  101. } else {
  102. os << " ";
  103. column += 1;
  104. }
  105. } else {
  106. // First word on line. Print indentation unless this is the
  107. // first line.
  108. os << (firstLine ? "" : this->TextIndent);
  109. }
  110. // Print the word.
  111. os.write(l, static_cast<long>(r - l));
  112. newSentence = (*(r - 1) == '.');
  113. }
  114. if (*r == '\n') {
  115. // Text provided a newline. Start a new line.
  116. os << "\n";
  117. ++r;
  118. column = 0;
  119. firstLine = false;
  120. } else {
  121. // No provided newline. Continue this line.
  122. column += static_cast<long>(r - l);
  123. }
  124. } else {
  125. // Word does not fit on this line. Start a new line.
  126. os << "\n";
  127. firstLine = false;
  128. if (r > l) {
  129. os << this->TextIndent;
  130. os.write(l, static_cast<long>(r - l));
  131. column = static_cast<long>(r - l);
  132. newSentence = (*(r - 1) == '.');
  133. } else {
  134. column = 0;
  135. }
  136. }
  137. // Move to beginning of next word. Skip over whitespace.
  138. l = r;
  139. while (*l == ' ') {
  140. ++l;
  141. }
  142. }
  143. }
  144. void cmDocumentationFormatter::PrintSection(
  145. std::ostream& os, cmDocumentationSection const& section)
  146. {
  147. os << section.GetName() << "\n";
  148. const std::vector<cmDocumentationEntry>& entries = section.GetEntries();
  149. for (cmDocumentationEntry const& entry : entries) {
  150. if (!entry.Name.empty()) {
  151. os << std::setw(2) << std::left << entry.CustomNamePrefix << entry.Name;
  152. this->TextIndent = " ";
  153. int align = static_cast<int>(strlen(this->TextIndent)) - 4;
  154. for (int i = static_cast<int>(entry.Name.size()); i < align; ++i) {
  155. os << " ";
  156. }
  157. if (entry.Name.size() > strlen(this->TextIndent) - 4) {
  158. os << "\n";
  159. os.write(this->TextIndent, strlen(this->TextIndent) - 2);
  160. }
  161. os << "= ";
  162. this->PrintColumn(os, entry.Brief.c_str());
  163. os << "\n";
  164. } else {
  165. os << "\n";
  166. this->TextIndent = "";
  167. this->PrintFormatted(os, entry.Brief.c_str());
  168. }
  169. }
  170. os << "\n";
  171. }