cmDocumentationFormatter.cxx 4.9 KB

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