kadircet updated this revision to Diff 234059.
kadircet marked 2 inline comments as done.
kadircet added a comment.

- Move indentation logic into bulletlist.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D71422/new/

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
@@ -186,6 +186,71 @@
   EXPECT_EQ(D.asPlainText(), ExpectedPlainText);
 }
 
+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;
 };
 
+/// Represents a sequence of one or more documents. Knows how to print them in a
+/// list like format, e.g. by prepending with "- " and indentation.
+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,14 @@
   /// 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;
 
 private:
   std::vector<std::unique_ptr<Block>> Children;
 };
-
 } // 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
@@ -150,6 +150,20 @@
   std::string Contents;
   std::string Language;
 };
+
+// Inserts two spaces after each `\n` to indent each line. First line is not
+// indented.
+std::string indentLines(llvm::StringRef Input) {
+  std::string IndentedR;
+  // We'll add 2 spaces after each new line.
+  IndentedR.reserve(Input.size() + Input.count('\n') * 2);
+  for (char C : Input) {
+    IndentedR += C;
+    if (C == '\n')
+      IndentedR.append("  ");
+  }
+  return IndentedR;
+}
 } // namespace
 
 std::string Block::asMarkdown() const {
@@ -194,6 +208,24 @@
   OS << '\n';
 }
 
+void BulletList::renderMarkdown(llvm::raw_ostream &OS) const {
+  for (auto &D : Documents) {
+    // 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.
+    OS << "- " << indentLines(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) {
+    // 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.
+    OS << "- " << indentLines(D.asPlainText()) << '\n';
+  }
+}
+
 Paragraph &Paragraph::appendText(std::string Text) {
   Text = canonicalizeSpaces(std::move(Text));
   if (Text.empty())
@@ -216,6 +248,11 @@
   return *this;
 }
 
+class Document &BulletList::addItem() {
+  Documents.emplace_back();
+  return Documents.back();
+}
+
 Paragraph &Document::addParagraph() {
   Children.push_back(std::make_unique<Paragraph>());
   return *static_cast<Paragraph *>(Children.back().get());
@@ -235,6 +272,11 @@
 std::string Document::asPlainText() const {
   return renderBlocks(Children, &Block::renderPlainText);
 }
+
+BulletList &Document::addBulletList() {
+  Children.emplace_back(std::make_unique<BulletList>());
+  return *static_cast<BulletList *>(Children.back().get());
+}
 } // namespace markup
 } // namespace clangd
 } // namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to