1 //===--- Markup.h -------------------------------------------*- C++-*------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // A model of formatted text that can be rendered to plaintext or markdown. 10 // 11 //===----------------------------------------------------------------------===// 12 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_MARKUP_H 13 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_MARKUP_H 14 15 #include "llvm/Support/raw_ostream.h" 16 #include <cstddef> 17 #include <memory> 18 #include <string> 19 #include <vector> 20 21 namespace clang { 22 namespace clangd { 23 namespace markup { 24 25 /// Holds text and knows how to lay it out. Multiple blocks can be grouped to 26 /// form a document. Blocks include their own trailing newlines, container 27 /// should trim them if need be. 28 class Block { 29 public: 30 virtual void renderMarkdown(llvm::raw_ostream &OS) const = 0; 31 virtual void renderPlainText(llvm::raw_ostream &OS) const = 0; 32 virtual std::unique_ptr<Block> clone() const = 0; 33 std::string asMarkdown() const; 34 std::string asPlainText() const; 35 isRuler()36 virtual bool isRuler() const { return false; } 37 virtual ~Block() = default; 38 }; 39 40 /// Represents parts of the markup that can contain strings, like inline code, 41 /// code block or plain text. 42 /// One must introduce different paragraphs to create separate blocks. 43 class Paragraph : public Block { 44 public: 45 void renderMarkdown(llvm::raw_ostream &OS) const override; 46 void renderPlainText(llvm::raw_ostream &OS) const override; 47 std::unique_ptr<Block> clone() const override; 48 49 /// Append plain text to the end of the string. 50 Paragraph &appendText(llvm::StringRef Text); 51 52 /// Append inline code, this translates to the ` block in markdown. 53 /// \p Preserve indicates the code span must be apparent even in plaintext. 54 Paragraph &appendCode(llvm::StringRef Code, bool Preserve = false); 55 56 /// Ensure there is space between the surrounding chunks. 57 /// Has no effect at the beginning or end of a paragraph. 58 Paragraph &appendSpace(); 59 60 private: 61 struct Chunk { 62 enum { 63 PlainText, 64 InlineCode, 65 } Kind = PlainText; 66 // Preserve chunk markers in plaintext. 67 bool Preserve = false; 68 std::string Contents; 69 // Whether this chunk should be surrounded by whitespace. 70 // Consecutive SpaceAfter and SpaceBefore will be collapsed into one space. 71 // Code spans don't usually set this: their spaces belong "inside" the span. 72 bool SpaceBefore = false; 73 bool SpaceAfter = false; 74 }; 75 std::vector<Chunk> Chunks; 76 }; 77 78 /// Represents a sequence of one or more documents. Knows how to print them in a 79 /// list like format, e.g. by prepending with "- " and indentation. 80 class BulletList : public Block { 81 public: 82 void renderMarkdown(llvm::raw_ostream &OS) const override; 83 void renderPlainText(llvm::raw_ostream &OS) const override; 84 std::unique_ptr<Block> clone() const override; 85 86 class Document &addItem(); 87 88 private: 89 std::vector<class Document> Items; 90 }; 91 92 /// A format-agnostic representation for structured text. Allows rendering into 93 /// markdown and plaintext. 94 class Document { 95 public: 96 Document() = default; Document(const Document & Other)97 Document(const Document &Other) { *this = Other; } 98 Document &operator=(const Document &); 99 Document(Document &&) = default; 100 Document &operator=(Document &&) = default; 101 102 void append(Document Other); 103 104 /// Adds a semantical block that will be separate from others. 105 Paragraph &addParagraph(); 106 /// Inserts a horizontal separator to the document. 107 void addRuler(); 108 /// Adds a block of code. This translates to a ``` block in markdown. In plain 109 /// text representation, the code block will be surrounded by newlines. 110 void addCodeBlock(std::string Code, std::string Language = "cpp"); 111 /// Heading is a special type of paragraph that will be prepended with \p 112 /// Level many '#'s in markdown. 113 Paragraph &addHeading(size_t Level); 114 115 BulletList &addBulletList(); 116 117 /// Doesn't contain any trailing newlines. 118 /// We try to make the markdown human-readable, e.g. avoid extra escaping. 119 /// At least one client (coc.nvim) displays the markdown verbatim! 120 std::string asMarkdown() const; 121 /// Doesn't contain any trailing newlines. 122 std::string asPlainText() const; 123 124 private: 125 std::vector<std::unique_ptr<Block>> Children; 126 }; 127 } // namespace markup 128 } // namespace clangd 129 } // namespace clang 130 131 #endif 132