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