9 #include "clang/Basic/CharInfo.h" 10 #include "llvm/ADT/ArrayRef.h" 11 #include "llvm/ADT/STLExtras.h" 12 #include "llvm/ADT/SmallVector.h" 13 #include "llvm/ADT/StringExtras.h" 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/Support/ErrorHandling.h" 16 #include "llvm/Support/FormatVariadic.h" 17 #include "llvm/Support/raw_ostream.h" 31 std::string renderText(llvm::StringRef Input) {
34 R
"txt(!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~)txt"; 37 for (
size_t From = 0; From < Input.size();) {
38 size_t Next = Input.find_first_of(Punctuation, From);
39 R += Input.substr(From, Next - From);
40 if (Next == llvm::StringRef::npos)
52 std::string renderInlineBlock(llvm::StringRef Input) {
55 for (
size_t From = 0; From < Input.size();) {
56 size_t Next = Input.find(
"`", From);
57 R += Input.substr(From, Next - From);
58 if (Next == llvm::StringRef::npos)
66 if (llvm::StringRef(R).startswith(
"`") || llvm::StringRef(R).endswith(
"`"))
67 return "` " + std::move(R) +
" `";
71 if (llvm::StringRef(R).startswith(
" ") && llvm::StringRef(R).endswith(
" "))
72 return "` " + std::move(R) +
" `";
73 return "`" + std::move(R) +
"`";
79 std::string getMarkerForCodeBlock(llvm::StringRef Input) {
82 unsigned MaxBackticks = 0;
83 unsigned Backticks = 0;
84 for (
char C : Input) {
89 MaxBackticks = std::max(MaxBackticks, Backticks);
92 MaxBackticks = std::max(Backticks, MaxBackticks);
94 return std::string(std::max(3u, MaxBackticks + 1),
'`');
98 std::string canonicalizeSpaces(std::string Input) {
101 auto WritePtr = Input.begin();
102 llvm::SmallVector<llvm::StringRef, 4> Words;
103 llvm::SplitString(Input, Words);
107 for (llvm::StringRef
Word : Words) {
108 if (WritePtr > Input.begin())
110 llvm::for_each(
Word, [&WritePtr](
const char C) { *WritePtr++ = C; });
113 Input.resize(WritePtr - Input.begin());
117 std::string renderBlocks(llvm::ArrayRef<std::unique_ptr<Block>> Children,
118 void (Block::*RenderFunc)(llvm::raw_ostream &)
const) {
120 llvm::raw_string_ostream OS(R);
124 [](
const std::unique_ptr<Block> &C) {
return C->isRuler(); });
125 auto Last = llvm::find_if(
126 llvm::reverse(Children),
127 [](
const std::unique_ptr<Block> &C) {
return !C->isRuler(); });
128 Children = Children.drop_back(Children.end() - Last.base());
130 bool LastBlockWasRuler =
true;
131 for (
const auto &C : Children) {
132 if (C->isRuler() && LastBlockWasRuler)
134 LastBlockWasRuler = C->isRuler();
135 ((*C).*RenderFunc)(OS);
140 std::string AdjustedResult;
141 llvm::StringRef TrimmedText(OS.str());
142 TrimmedText = TrimmedText.trim();
144 llvm::copy_if(TrimmedText, std::back_inserter(AdjustedResult),
145 [&TrimmedText](
const char &C) {
146 return !llvm::StringRef(TrimmedText.data(),
147 &C - TrimmedText.data() + 1)
152 return AdjustedResult;
158 class Ruler :
public Block {
160 void renderMarkdown(llvm::raw_ostream &OS)
const override {
165 void renderPlainText(llvm::raw_ostream &OS)
const override { OS <<
'\n'; }
166 bool isRuler()
const override {
return true; }
169 class CodeBlock :
public Block {
171 void renderMarkdown(llvm::raw_ostream &OS)
const override {
172 std::string Marker = getMarkerForCodeBlock(
Contents);
174 OS << Marker << Language <<
'\n' <<
Contents <<
'\n' << Marker <<
'\n';
177 void renderPlainText(llvm::raw_ostream &OS)
const override {
182 CodeBlock(std::string
Contents, std::string Language)
183 : Contents(std::move(Contents)), Language(std::move(Language)) {}
187 std::string Language;
192 std::string indentLines(llvm::StringRef Input) {
193 assert(!Input.endswith(
"\n") &&
"Input should've been trimmed.");
194 std::string IndentedR;
196 IndentedR.reserve(Input.size() + Input.count(
'\n') * 2);
197 for (
char C : Input) {
200 IndentedR.append(
" ");
205 class Heading :
public Paragraph {
207 Heading(
size_t Level) : Level(Level) {}
208 void renderMarkdown(llvm::raw_ostream &OS)
const override {
209 OS << std::string(Level,
'#') <<
' ';
221 llvm::raw_string_ostream OS(R);
223 return llvm::StringRef(OS.str()).trim().str();
228 llvm::raw_string_ostream OS(R);
230 return llvm::StringRef(OS.str()).trim().str();
234 llvm::StringRef Sep =
"";
235 for (
auto &C : Chunks) {
239 OS << renderText(C.Contents);
241 case Chunk::InlineCode:
242 OS << renderInlineBlock(C.Contents);
254 llvm::StringRef Sep =
"";
255 for (
auto &C : Chunks) {
256 OS << Sep << C.Contents;
263 for (
auto &D : Items) {
266 OS <<
"- " << indentLines(D.asMarkdown()) <<
'\n';
273 for (
auto &D : Items) {
276 OS <<
"- " << indentLines(D.asPlainText()) <<
'\n';
281 Text = canonicalizeSpaces(std::move(Text));
284 Chunks.emplace_back();
285 Chunk &C = Chunks.back();
286 C.Contents = std::move(Text);
292 Code = canonicalizeSpaces(std::move(Code));
295 Chunks.emplace_back();
296 Chunk &C = Chunks.back();
297 C.Contents = std::move(Code);
298 C.Kind = Chunk::InlineCode;
303 Items.emplace_back();
308 Children.push_back(std::make_unique<Paragraph>());
309 return *
static_cast<Paragraph *
>(Children.back().get());
315 Children.emplace_back(
316 std::make_unique<CodeBlock>(std::move(Code), std::move(Language)));
328 Children.emplace_back(std::make_unique<BulletList>());
329 return *
static_cast<BulletList *
>(Children.back().get());
334 Children.emplace_back(std::make_unique<Heading>(Level));
335 return *
static_cast<Paragraph *
>(Children.back().get());
void renderMarkdown(llvm::raw_ostream &OS) const override
Paragraph & appendCode(std::string Code)
Append inline code, this translates to the ` block in markdown.
std::string asMarkdown() const
Doesn't contain any trailing newlines.
class Document & addItem()
virtual void renderPlainText(llvm::raw_ostream &OS) const =0
std::string asPlainText() const
void addCodeBlock(std::string Code, std::string Language="cpp")
Adds a block of code.
Paragraph & appendText(std::string Text)
Append plain text to the end of the string.
std::string asMarkdown() const
std::vector< std::unique_ptr< HTMLNode > > Children
void renderPlainText(llvm::raw_ostream &OS) const override
void renderMarkdown(llvm::raw_ostream &OS) const override
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::string asPlainText() const
Doesn't contain any trailing newlines.
BulletList & addBulletList()
void addRuler()
Inserts a horizontal separator to the document.
Paragraph & addHeading(size_t Level)
Heading is a special type of paragraph that will be prepended with Level many '#'s in markdown...
Paragraph & addParagraph()
Adds a semantical block that will be separate from others.
void renderPlainText(llvm::raw_ostream &OS) const override
virtual void renderMarkdown(llvm::raw_ostream &OS) const =0