1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index 64221d32db8c..f7e01f4ccf32 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -1629,9 +1629,10 @@ markup::Document HoverInfo::present() const {
// If the backtick at `Offset` starts a probable quoted range, return the range
// (including the quotes).
-std::optional<llvm::StringRef> getBacktickQuoteRange(llvm::StringRef Line,
- unsigned Offset) {
- assert(Line[Offset] == '`');
+std::optional<llvm::StringRef>
+getBacktickQuoteRange(llvm::StringRef Line, unsigned Offset,
+ llvm::StringRef Quote = "`") {
+ assert(Line.substr(Offset, Quote.size()) == Quote);
// The open-quote is usually preceded by whitespace.
llvm::StringRef Prefix = Line.substr(0, Offset);
@@ -1640,21 +1641,21 @@ std::optional<llvm::StringRef> getBacktickQuoteRange(llvm::StringRef Line,
return std::nullopt;
// The quoted string must be nonempty and usually has no leading/trailing ws.
- auto Next = Line.find('`', Offset + 1);
+ auto Next = Line.find(Quote, Offset + Quote.size());
if (Next == llvm::StringRef::npos)
return std::nullopt;
- llvm::StringRef Contents = Line.slice(Offset + 1, Next);
+ llvm::StringRef Contents = Line.slice(Offset + Quote.size(), Next);
if (Contents.empty() || isWhitespace(Contents.front()) ||
isWhitespace(Contents.back()))
return std::nullopt;
// The close-quote is usually followed by whitespace or punctuation.
- llvm::StringRef Suffix = Line.substr(Next + 1);
+ llvm::StringRef Suffix = Line.substr(Next + Quote.size());
constexpr llvm::StringLiteral AfterEndChars = " \t)=.,;:";
if (!Suffix.empty() && !AfterEndChars.contains(Suffix.front()))
return std::nullopt;
- return Line.slice(Offset, Next + 1);
+ return Line.slice(Offset, Next + Quote.size());
}
void parseDocumentationLine(llvm::StringRef Line, markup::Paragraph &Out) {
@@ -1668,6 +1669,24 @@ void parseDocumentationLine(llvm::StringRef Line, markup::Paragraph &Out) {
return parseDocumentationLine(Line.substr(I + Range->size()), Out);
}
break;
+ case '\\':
+ Out.appendText(Line.substr(0, I));
+ Out.appendText(Line.substr(I + 1, 1));
+ return parseDocumentationLine(Line.substr(I + 2), Out);
+ case '*':
+ if (Line[I + 1] == '*') {
+ if (auto Range = getBacktickQuoteRange(Line, I, "**")) {
+ Out.appendText(Line.substr(0, I));
+ Out.appendBoldText(Range->trim("**"));
+ return parseDocumentationLine(Line.substr(I + Range->size()), Out);
+ }
+ }
+ if (auto Range = getBacktickQuoteRange(Line, I, "*")) {
+ Out.appendText(Line.substr(0, I));
+ Out.appendItalicText(Range->trim("*"));
+ return parseDocumentationLine(Line.substr(I + Range->size()), Out);
+ }
+ break;
}
}
Out.appendText(Line).appendSpace();
diff --git a/clang-tools-extra/clangd/support/Markup.cpp b/clang-tools-extra/clangd/support/Markup.cpp
index 4d17a2bf2b2b..3de3478661f0 100644
--- a/clang-tools-extra/clangd/support/Markup.cpp
+++ b/clang-tools-extra/clangd/support/Markup.cpp
@@ -164,6 +164,14 @@ std::string renderText(llvm::StringRef Input, bool StartsLine) {
return R;
}
+std::string renderBoldText(llvm::StringRef Input, bool StartsLine) {
+ return "**" + renderText(Input, StartsLine) + "**";
+}
+
+std::string renderItalicText(llvm::StringRef Input, bool StartsLine) {
+ return "*" + renderText(Input, StartsLine) + "*";
+}
+
/// Renders \p Input as an inline block of code in markdown. The returned value
/// is surrounded by backticks and the inner contents are properly escaped.
std::string renderInlineBlock(llvm::StringRef Input) {
@@ -354,6 +362,12 @@ void Paragraph::renderMarkdown(llvm::raw_ostream &OS) const {
case Chunk::InlineCode:
OS << renderInlineBlock(C.Contents);
break;
+ case Chunk::BoldText:
+ OS << renderBoldText(C.Contents, !HasChunks);
+ break;
+ case Chunk::ItalicText:
+ OS << renderItalicText(C.Contents, !HasChunks);
+ break;
}
HasChunks = true;
NeedsSpace = C.SpaceAfter;
@@ -449,6 +463,32 @@ Paragraph &Paragraph::appendCode(llvm::StringRef Code, bool Preserve) {
return *this;
}
+Paragraph &Paragraph::appendBoldText(llvm::StringRef Text) {
+ std::string Norm = canonicalizeSpaces(Text);
+ if (Norm.empty())
+ return *this;
+ Chunks.emplace_back();
+ Chunk &C = Chunks.back();
+ C.Contents = std::move(Norm);
+ C.Kind = Chunk::BoldText;
+ C.SpaceBefore = llvm::isSpace(Text.front());
+ C.SpaceAfter = llvm::isSpace(Text.back());
+ return *this;
+}
+
+Paragraph &Paragraph::appendItalicText(llvm::StringRef Text) {
+ std::string Norm = canonicalizeSpaces(Text);
+ if (Norm.empty())
+ return *this;
+ Chunks.emplace_back();
+ Chunk &C = Chunks.back();
+ C.Contents = std::move(Norm);
+ C.Kind = Chunk::ItalicText;
+ C.SpaceBefore = llvm::isSpace(Text.front());
+ C.SpaceAfter = llvm::isSpace(Text.back());
+ return *this;
+}
+
std::unique_ptr<Block> BulletList::clone() const {
return std::make_unique<BulletList>(*this);
}
diff --git a/clang-tools-extra/clangd/support/Markup.h b/clang-tools-extra/clangd/support/Markup.h
index 3a869c49a2cb..eb2c5a35de97 100644
--- a/clang-tools-extra/clangd/support/Markup.h
+++ b/clang-tools-extra/clangd/support/Markup.h
@@ -53,6 +53,12 @@ public:
/// \p Preserve indicates the code span must be apparent even in plaintext.
Paragraph &appendCode(llvm::StringRef Code, bool Preserve = false);
+ /// Append bold text to the end of the string.
+ Paragraph &appendBoldText(llvm::StringRef Text);
+
+ /// Append italic text to the end of the string.
+ Paragraph &appendItalicText(llvm::StringRef Text);
+
/// Ensure there is space between the surrounding chunks.
/// Has no effect at the beginning or end of a paragraph.
Paragraph &appendSpace();
@@ -62,6 +68,8 @@ private:
enum {
PlainText,
InlineCode,
+ BoldText,
+ ItalicText,
} Kind = PlainText;
// Preserve chunk markers in plaintext.
bool Preserve = false;
|