kadircet created this revision.
kadircet added a reviewer: sammccall.
Herald added subscribers: cfe-commits, usaxena95, arphaman, jkorous, MaskRay, 
ilya-biryukov.
Herald added a project: clang.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D71422

Files:
  clang-tools-extra/clangd/FormattedString.cpp
  clang-tools-extra/clangd/FormattedString.h
  clang-tools-extra/clangd/unittests/FormattedStringTests.cpp

Index: clang-tools-extra/clangd/unittests/FormattedStringTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/FormattedStringTests.cpp
+++ clang-tools-extra/clangd/unittests/FormattedStringTests.cpp
@@ -120,16 +120,23 @@
   D.addParagraph().appendText("foo");
   D.addCodeBlock("test");
   D.addParagraph().appendText("bar");
+  D.addBulletList().addItem().addParagraph().appendText("item");
+  D.addParagraph().appendText("baz");
   EXPECT_EQ(D.asMarkdown(), R"md(foo
 ```cpp
 test
 ```
-bar)md");
+bar
+- item
+
+baz)md");
   EXPECT_EQ(D.asPlainText(), R"pt(foo
 
 test
 
-bar)pt");
+bar
+- item
+baz)pt");
 }
 
 TEST(Document, Spacer) {
@@ -173,6 +180,71 @@
 foo)pt");
 }
 
+TEST(BulletList, Render) {
+  BulletList L;
+  // Flat list
+  L.addItem().addParagraph().appendText("foo");
+  EXPECT_EQ(L.asMarkdown(), "- foo");
+  EXPECT_EQ(L.asPlainText(), "- foo");
+
+  L.addItem().addParagraph().appendText("bar");
+  EXPECT_EQ(L.asMarkdown(), R"md(- foo
+- bar)md");
+  EXPECT_EQ(L.asPlainText(), R"pt(- foo
+- bar)pt");
+
+  // Nested list, with a single item.
+  Document &D = L.addItem();
+  // First item with foo\nbaz
+  D.addParagraph().appendText("foo");
+  D.addParagraph().appendText("baz");
+
+  // Nest one level.
+  Document &Inner = D.addBulletList().addItem();
+  Inner.addParagraph().appendText("foo");
+
+  // Nest one more level.
+  BulletList &InnerList = Inner.addBulletList();
+  // Single item, baz\nbaz
+  Document &DeepDoc = InnerList.addItem();
+  DeepDoc.addParagraph().appendText("baz");
+  DeepDoc.addParagraph().appendText("baz");
+  EXPECT_EQ(L.asMarkdown(), R"md(- foo
+- bar
+- foo
+  baz
+  - foo
+    - baz
+      baz)md");
+  EXPECT_EQ(L.asPlainText(), R"pt(- foo
+- bar
+- foo
+  baz
+  - foo
+    - baz
+      baz)pt");
+
+  // Termination
+  Inner.addParagraph().appendText("after");
+  EXPECT_EQ(L.asMarkdown(), R"md(- foo
+- bar
+- foo
+  baz
+  - foo
+    - baz
+      baz
+    
+    after)md");
+  EXPECT_EQ(L.asPlainText(), R"pt(- foo
+- bar
+- foo
+  baz
+  - foo
+    - baz
+      baz
+    after)pt");
+}
+
 } // namespace
 } // namespace markup
 } // namespace clangd
Index: clang-tools-extra/clangd/FormattedString.h
===================================================================
--- clang-tools-extra/clangd/FormattedString.h
+++ clang-tools-extra/clangd/FormattedString.h
@@ -62,6 +62,19 @@
   std::vector<Chunk> Chunks;
 };
 
+/// Prints a list of documents while prepending "- " marker. Also indents the
+/// documents.
+class BulletList : public Block {
+public:
+  void renderMarkdown(llvm::raw_ostream &OS) const override;
+  void renderPlainText(llvm::raw_ostream &OS) const override;
+
+  class Document &addItem();
+
+private:
+  std::vector<class Document> Documents;
+};
+
 /// A format-agnostic representation for structured text. Allows rendering into
 /// markdown and plaintext.
 class Document {
@@ -74,13 +87,20 @@
   /// text representation, the code block will be surrounded by newlines.
   void addCodeBlock(std::string Code, std::string Language = "cpp");
 
+  BulletList &addBulletList();
+
   std::string asMarkdown() const;
   std::string asPlainText() const;
 
+  /// Causes every line of the document to be indented by 2 spaces. Except the
+  /// first line, it is containers responsibility to adjust padding for first
+  /// line.
+  void indent() { Indent = true; }
+
 private:
   std::vector<std::unique_ptr<Block>> Children;
+  bool Indent = false;
 };
-
 } // namespace markup
 } // namespace clangd
 } // namespace clang
Index: clang-tools-extra/clangd/FormattedString.cpp
===================================================================
--- clang-tools-extra/clangd/FormattedString.cpp
+++ clang-tools-extra/clangd/FormattedString.cpp
@@ -115,12 +115,28 @@
 }
 
 std::string renderBlocks(llvm::ArrayRef<std::unique_ptr<Block>> Children,
-                         void (Block::*RenderFunc)(llvm::raw_ostream &) const) {
+                         void (Block::*RenderFunc)(llvm::raw_ostream &) const,
+                         bool Indent) {
   std::string R;
   llvm::raw_string_ostream OS(R);
   for (auto &C : Children)
     ((*C).*RenderFunc)(OS);
-  return llvm::StringRef(OS.str()).trim().str();
+  llvm::StringRef Trimmed(OS.str());
+  Trimmed = Trimmed.trim();
+  if (!Indent)
+    return Trimmed.str();
+
+  // Instead of doing this we might prefer passing Indent to children to get rid
+  // of the copies, if it turns out to be a bottleneck.
+  std::string IndentedR;
+  // We'll add 2 spaces after each new line.
+  IndentedR.reserve(Trimmed.size() + Trimmed.count('\n') * 2);
+  for (char C : Trimmed) {
+    IndentedR += C;
+    if (C == '\n')
+      IndentedR.append("  ");
+  }
+  return IndentedR;
 }
 
 // Puts a vertical space between blocks inside a document.
@@ -194,6 +210,18 @@
   OS << '\n';
 }
 
+void BulletList::renderMarkdown(llvm::raw_ostream &OS) const {
+  for (auto &D : Documents)
+    OS << "- " + D.asMarkdown() << '\n';
+  // We need a new line after list to terminate it in markdown.
+  OS << '\n';
+}
+
+void BulletList::renderPlainText(llvm::raw_ostream &OS) const {
+  for (auto &D : Documents)
+    OS << "- " + D.asPlainText() << '\n';
+}
+
 Paragraph &Paragraph::appendText(std::string Text) {
   Text = canonicalizeSpaces(std::move(Text));
   if (Text.empty())
@@ -216,6 +244,12 @@
   return *this;
 }
 
+class Document &BulletList::addItem() {
+  Documents.emplace_back();
+  Documents.back().indent();
+  return Documents.back();
+}
+
 Paragraph &Document::addParagraph() {
   Children.push_back(std::make_unique<Paragraph>());
   return *static_cast<Paragraph *>(Children.back().get());
@@ -229,11 +263,16 @@
 }
 
 std::string Document::asMarkdown() const {
-  return renderBlocks(Children, &Block::renderMarkdown);
+  return renderBlocks(Children, &Block::renderMarkdown, Indent);
 }
 
 std::string Document::asPlainText() const {
-  return renderBlocks(Children, &Block::renderPlainText);
+  return renderBlocks(Children, &Block::renderPlainText, Indent);
+}
+
+BulletList &Document::addBulletList() {
+  Children.emplace_back(std::make_unique<BulletList>());
+  return *static_cast<BulletList *>(Children.back().get());
 }
 } // namespace markup
 } // namespace clangd
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to