[clang-tools-extra] a000f2e - [clangd] Introduce bulletlists
Kadir Cetinkaya via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 7 06:24:04 PST 2020
Author: Kadir Cetinkaya
Date: 2020-01-07T15:21:11+01:00
New Revision: a000f2e53f5c3433608f6097c3f4096e313b5f56
URL: https://github.com/llvm/llvm-project/commit/a000f2e53f5c3433608f6097c3f4096e313b5f56
DIFF: https://github.com/llvm/llvm-project/commit/a000f2e53f5c3433608f6097c3f4096e313b5f56.diff
LOG: [clangd] Introduce bulletlists
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D71422
Added:
Modified:
clang-tools-extra/clangd/FormattedString.cpp
clang-tools-extra/clangd/FormattedString.h
clang-tools-extra/clangd/unittests/FormattedStringTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/FormattedString.cpp b/clang-tools-extra/clangd/FormattedString.cpp
index a7a63a476c3c..cfa1210a2ee6 100644
--- a/clang-tools-extra/clangd/FormattedString.cpp
+++ b/clang-tools-extra/clangd/FormattedString.cpp
@@ -149,6 +149,21 @@ class CodeBlock : public Block {
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) {
+ assert(!Input.endswith("\n") && "Input should've been trimmed.");
+ 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 {
@@ -193,6 +208,24 @@ void Paragraph::renderPlainText(llvm::raw_ostream &OS) const {
OS << '\n';
}
+void BulletList::renderMarkdown(llvm::raw_ostream &OS) const {
+ for (auto &D : Items) {
+ // 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 : Items) {
+ // 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())
@@ -215,6 +248,11 @@ Paragraph &Paragraph::appendCode(std::string Code) {
return *this;
}
+class Document &BulletList::addItem() {
+ Items.emplace_back();
+ return Items.back();
+}
+
Paragraph &Document::addParagraph() {
Children.push_back(std::make_unique<Paragraph>());
return *static_cast<Paragraph *>(Children.back().get());
@@ -234,6 +272,11 @@ std::string Document::asMarkdown() const {
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
diff --git a/clang-tools-extra/clangd/FormattedString.h b/clang-tools-extra/clangd/FormattedString.h
index 4ded2fdee315..2d1f681e7ebe 100644
--- a/clang-tools-extra/clangd/FormattedString.h
+++ b/clang-tools-extra/clangd/FormattedString.h
@@ -62,6 +62,19 @@ class Paragraph : public Block {
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> Items;
+};
+
/// A format-agnostic representation for structured text. Allows rendering into
/// markdown and plaintext.
class Document {
@@ -74,13 +87,16 @@ class Document {
/// text representation, the code block will be surrounded by newlines.
void addCodeBlock(std::string Code, std::string Language = "cpp");
+ BulletList &addBulletList();
+
+ /// Doesn't contain any trailing newlines.
std::string asMarkdown() const;
+ /// Doesn't contain any trailing newlines.
std::string asPlainText() const;
private:
std::vector<std::unique_ptr<Block>> Children;
};
-
} // namespace markup
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp b/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp
index 06f43d390349..3093ba2ce50d 100644
--- a/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp
@@ -186,6 +186,71 @@ foo)pt";
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
More information about the cfe-commits
mailing list