cmDocumentationFormatter.cxx 5.0 KB

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