cmDocumentationFormatter.cxx 4.9 KB

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