Skip to content

Commit 8893b3b

Browse files
Merge pull request #60173 from apple/QuietMisdreavus/markup-gfm-updates
[Markup] add support for swift-cmark's inline attributes
2 parents a613bce + fe14235 commit 8893b3b

File tree

9 files changed

+151
-13
lines changed

9 files changed

+151
-13
lines changed

bindings/xml/comment-xml-schema.rng

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,13 @@
959959
<param name="pattern">.*\S.*</param>
960960
</data>
961961
</element>
962+
<element name="InlineAttributes">
963+
<attribute name="attributes"/>
964+
<!-- Non-empty text content. -->
965+
<data type="string">
966+
<param name="pattern">.*\S.*</param>
967+
</data>
968+
</element>
962969
</choice>
963970
</define>
964971

include/swift/Markup/AST.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,36 @@ class Image final : public InlineContent,
589589
}
590590
};
591591

592+
class InlineAttributes final : public InlineContent, private llvm::TrailingObjects<Image, MarkupASTNode *> {
593+
friend TrailingObjects;
594+
595+
// Note that inline attributes are like links, in that there are child inline nodes that are
596+
// collectively styled by the attribute text. The child nodes are the text that should be
597+
// displayed.
598+
599+
size_t NumChildren;
600+
StringRef Attributes;
601+
602+
InlineAttributes(StringRef Attributes, ArrayRef<MarkupASTNode *> Children);
603+
604+
public:
605+
static InlineAttributes *create(MarkupContext &MC, StringRef Attributes, ArrayRef<MarkupASTNode *> Children);
606+
607+
StringRef getAttributes() const { return Attributes; }
608+
609+
ArrayRef<MarkupASTNode *> getChildren() {
610+
return {getTrailingObjects<MarkupASTNode *>(), NumChildren};
611+
}
612+
613+
ArrayRef<const MarkupASTNode *> getChildren() const {
614+
return {getTrailingObjects<MarkupASTNode *>(), NumChildren};
615+
}
616+
617+
static bool classof(const MarkupASTNode *N) {
618+
return N->getKind() == ASTNodeKind::InlineAttributes;
619+
}
620+
};
621+
592622
#pragma mark Private Extensions
593623

594624
class PrivateExtension : public MarkupASTNode {

include/swift/Markup/ASTNodes.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ ABSTRACT_MARKUP_AST_NODE(InlineContent, MarkupASTNode)
4040
MARKUP_AST_NODE(Strong, InlineContent)
4141
MARKUP_AST_NODE(Link, InlineContent)
4242
MARKUP_AST_NODE(Image, InlineContent)
43-
MARKUP_AST_NODE_RANGE(Inline, Text, Image)
43+
MARKUP_AST_NODE(InlineAttributes, InlineContent)
44+
MARKUP_AST_NODE_RANGE(Inline, Text, InlineAttributes)
4445

4546
/// Private Markdown Extensions - these should not be implemented in the
4647
/// underlying cmark parser.

lib/Frontend/PrintingDiagnosticConsumer.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,15 @@ namespace {
142142
}
143143
}
144144

145+
void visitInlineAttributes(const InlineAttributes *A) {
146+
print("^[");
147+
for (const auto *Child : A->getChildren())
148+
visit(Child);
149+
print("](");
150+
print(A->getAttributes());
151+
print(")");
152+
}
153+
145154
void visitBlockQuote(const BlockQuote *BQ) {
146155
indent();
147156
printNewline();

lib/IDE/CommentConversion.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,18 @@ struct CommentToXMLConverter {
7272
llvm_unreachable("Can't print a swift::markup::Document as XML directly");
7373
}
7474

75+
void printInlineAttributes(const InlineAttributes *A) {
76+
OS << "<InlineAttributes attributes=\"";
77+
appendWithXMLEscaping(OS, A->getAttributes());
78+
OS << "\">";
79+
80+
for (const auto *N : A->getChildren()) {
81+
printASTNode(N);
82+
}
83+
84+
OS << "</InlineAttributes>";
85+
}
86+
7587
void printBlockQuote(const BlockQuote *BQ) {
7688
for (const auto *N : BQ->getChildren())
7789
printASTNode(N);
@@ -638,6 +650,12 @@ class DoxygenConverter : public MarkupASTVisitor<DoxygenConverter> {
638650
visit(Child);
639651
}
640652

653+
void visitInlineAttributes(const InlineAttributes *A) {
654+
// attributed strings don't have an analogue in Doxygen, so just print out the text
655+
for (const auto *Child : A->getChildren())
656+
visit(Child);
657+
}
658+
641659
void visitBlockQuote(const BlockQuote *BQ) {
642660
print("<blockquote>");
643661
printNewline();

lib/Markup/AST.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ Paragraph *Paragraph::create(MarkupContext &MC,
157157
return new (Mem) Paragraph(Children);
158158
}
159159

160+
InlineAttributes::InlineAttributes(StringRef Attributes, ArrayRef<MarkupASTNode *> Children) : InlineContent(ASTNodeKind::InlineAttributes), NumChildren(Children.size()), Attributes(Attributes) {
161+
std::uninitialized_copy(Children.begin(), Children.end(), getTrailingObjects<MarkupASTNode *>());
162+
}
163+
164+
InlineAttributes *InlineAttributes::create(MarkupContext &MC, StringRef Attributes, ArrayRef<MarkupASTNode *> Children) {
165+
void *Mem = MC.allocate(totalSizeToAlloc<MarkupASTNode *>(Children.size()), alignof(InlineAttributes));
166+
StringRef AttrsCopy = MC.allocateCopy(Attributes);
167+
return new (Mem) InlineAttributes(AttrsCopy, Children);
168+
}
169+
160170
HRule *HRule::create(MarkupContext &MC) {
161171
void *Mem = MC.allocate(sizeof(HRule), alignof(HRule));
162172
return new (Mem) HRule();
@@ -408,6 +418,14 @@ void swift::markup::dump(const MarkupASTNode *Node, llvm::raw_ostream &OS,
408418
dumpChildren(Node->getChildren(), OS, indent + 1);
409419
break;
410420
}
421+
case swift::markup::ASTNodeKind::InlineAttributes: {
422+
auto A = cast<InlineAttributes>(Node);
423+
OS << "Attribute:";
424+
OS << " Attributes=" << A->getAttributes();
425+
OS << " Children=" << Node->getChildren().size();
426+
dumpChildren(Node->getChildren(), OS, indent + 1);
427+
break;
428+
}
411429
case swift::markup::ASTNodeKind::BlockQuote: {
412430
OS << "BlockQuote: Children=" << Node->getChildren().size();
413431
dumpChildren(Node->getChildren(), OS, indent + 1);

lib/Markup/Markup.cpp

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ ParseResult<Strong> parseStrong(MarkupContext &MC, ParseState State) {
137137
}
138138

139139
ParseResult<Header> parseHeader(MarkupContext &MC, ParseState State) {
140-
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HEADER
140+
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HEADING
141141
&& State.Event == CMARK_EVENT_ENTER);
142142
auto Level = cmark_node_get_header_level(State.Node);
143143
SmallVector<MarkupASTNode *, 2> Children;
@@ -149,19 +149,19 @@ ParseResult<Header> parseHeader(MarkupContext &MC, ParseState State) {
149149
}
150150

151151
ParseResult<HRule> parseHRule(MarkupContext &MC, ParseState State) {
152-
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HRULE
152+
assert(cmark_node_get_type(State.Node) == CMARK_NODE_THEMATIC_BREAK
153153
&& State.Event == CMARK_EVENT_ENTER);
154154
return { HRule::create(MC), State.next() };
155155
}
156156

157157
ParseResult<HTML> parseHTML(MarkupContext &MC, ParseState State) {
158-
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HTML
158+
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HTML_BLOCK
159159
&& State.Event == CMARK_EVENT_ENTER);
160160
return {HTML::create(MC, getLiteralContent(MC, State.Node)), State.next()};
161161
}
162162

163163
ParseResult<InlineHTML> parseInlineHTML(MarkupContext &MC, ParseState State) {
164-
assert(cmark_node_get_type(State.Node) == CMARK_NODE_INLINE_HTML
164+
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HTML_INLINE
165165
&& State.Event == CMARK_EVENT_ENTER);
166166
return {InlineHTML::create(MC, getLiteralContent(MC, State.Node)),
167167
State.next()};
@@ -216,6 +216,15 @@ ParseResult<Link> parseLink(MarkupContext &MC, ParseState State) {
216216
return { Link::create(MC, Destination, Children), ResultState.next() };
217217
}
218218

219+
ParseResult<InlineAttributes> parseAttribute(MarkupContext &MC, ParseState State) {
220+
assert(cmark_node_get_type(State.Node) == CMARK_NODE_ATTRIBUTE && State.Event == CMARK_EVENT_ENTER);
221+
std::string Attributes(cmark_node_get_attributes(State.Node));
222+
SmallVector<MarkupASTNode *, 2> Children;
223+
auto ResultState = parseChildren(MC, State, Children);
224+
assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT);
225+
return { InlineAttributes::create(MC, Attributes, Children), ResultState.next() };
226+
}
227+
219228
ParseResult<List> parseList(MarkupContext &MC, ParseState State) {
220229
assert(cmark_node_get_type(State.Node) == CMARK_NODE_LIST
221230
&& State.Event == CMARK_EVENT_ENTER);
@@ -245,6 +254,13 @@ ParseResult<MarkupASTNode> parseElement(MarkupContext &MC, ParseState State) {
245254
case CMARK_NODE_DOCUMENT: {
246255
llvm_unreachable("Markup documents cannot be nested");
247256
}
257+
case CMARK_NODE_FOOTNOTE_REFERENCE:
258+
case CMARK_NODE_FOOTNOTE_DEFINITION: {
259+
llvm_unreachable("Footnotes are not currently parsed by swiftMarkup");
260+
}
261+
case CMARK_NODE_ATTRIBUTE: {
262+
return parseAttribute(MC, State);
263+
}
248264
case CMARK_NODE_BLOCK_QUOTE: {
249265
return parseBlockQuote(MC, State);
250266
}
@@ -257,21 +273,18 @@ ParseResult<MarkupASTNode> parseElement(MarkupContext &MC, ParseState State) {
257273
case CMARK_NODE_EMPH: {
258274
return parseEmphasis(MC, State);
259275
}
260-
case CMARK_NODE_HEADER: {
276+
case CMARK_NODE_HEADING: {
261277
return parseHeader(MC, State);
262278
}
263-
case CMARK_NODE_HRULE: {
264-
return parseHRule(MC, State);
265-
}
266-
case CMARK_NODE_HTML: {
279+
case CMARK_NODE_HTML_BLOCK: {
267280
return parseHTML(MC, State);
268281
}
282+
case CMARK_NODE_HTML_INLINE: {
283+
return parseInlineHTML(MC, State);
284+
}
269285
case CMARK_NODE_IMAGE: {
270286
return parseImage(MC, State);
271287
}
272-
case CMARK_NODE_INLINE_HTML: {
273-
return parseInlineHTML(MC, State);
274-
}
275288
case CMARK_NODE_ITEM: {
276289
return parseItem(MC, State);
277290
}
@@ -296,6 +309,9 @@ ParseResult<MarkupASTNode> parseElement(MarkupContext &MC, ParseState State) {
296309
case CMARK_NODE_TEXT: {
297310
return parseText(MC, State);
298311
}
312+
case CMARK_NODE_THEMATIC_BREAK: {
313+
return parseHRule(MC, State);
314+
}
299315
default: {
300316
llvm_unreachable("Can't parse a Markup node of type 'None'");
301317
}

test/Inputs/comment_to_something_conversion.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,15 @@ public enum A012_AttachToEntities {
6262
// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:@M@comment_to_xml@objc(cs)ATXHeaders(im)f0</USR><Declaration>@objc public func f0()</Declaration><CommentParts><Discussion><rawHTML><![CDATA[<h1>]]></rawHTML>LEVEL ONE<rawHTML><![CDATA[</h1>]]></rawHTML><rawHTML><![CDATA[<h2>]]></rawHTML>LEVEL TWO<rawHTML><![CDATA[</h2>]]></rawHTML></Discussion></CommentParts></Function>]
6363
}
6464

65+
@objc public class Attributes {
66+
// CHECK: {{.*}}DocCommentAsXML=none
67+
/// Here is an attribute:
68+
///
69+
/// ^[Attribute text](string: "attributed")
70+
@objc public func f0() {}
71+
// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:@M@comment_to_xml@objc(cs)Attributes(im)f0</USR><Declaration>@objc public func f0()</Declaration><CommentParts><Abstract><Para>Here is an attribute:</Para></Abstract><Discussion><Para><InlineAttributes attributes="string: &quot;attributed&quot;">Attribute text</InlineAttributes></Para></Discussion></CommentParts></Function>]
72+
}
73+
6574
@objc public class AutomaticLink {
6675
// CHECK: {{.*}}DocCommentAsXML=none
6776
/// And now for a URL.
@@ -198,6 +207,18 @@ public enum A012_AttachToEntities {
198207
// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f4()</Name><USR>c:@M@comment_to_xml@objc(cs)EmptyComments(im)f4</USR><Declaration>@objc public func f4()</Declaration><CommentParts><Abstract><Para>Aaa.</Para></Abstract></CommentParts></Function>]
199208
}
200209

210+
@objc public class Footnotes {
211+
// CHECK: {{.*}}DocCommentAsXML=none
212+
/// Has some footnotes.
213+
///
214+
/// Footnotes aren't handled by swiftMarkup yet[^footnote], but they may in the future.
215+
///
216+
/// [^footnote]: Footnotes aren't parsed by default in swift-cmark, and swiftMarkup doesn't
217+
/// enable the feature.
218+
@objc public func f0() {}
219+
// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:@M@comment_to_xml@objc(cs)Footnotes(im)f0</USR><Declaration>@objc public func f0()</Declaration><CommentParts><Abstract><Para>Has some footnotes.</Para></Abstract><Discussion><Para>Footnotes aren’t handled by swiftMarkup yet[^footnote], but they may in the future.</Para><Para>[^footnote]: Footnotes aren’t parsed by default in swift-cmark, and swiftMarkup doesn’t enable the feature.</Para></Discussion></CommentParts></Function>]
220+
}
221+
201222
@objc public class HasThrowingFunction {
202223
// CHECK: {{.*}}DocCommentAsXML=none
203224

test/PrintAsObjC/Inputs/comments-expected-output.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ SWIFT_CLASS("_TtC8comments10ATXHeaders")
3232
@end
3333

3434

35+
SWIFT_CLASS("_TtC8comments10Attributes")
36+
@interface Attributes
37+
/// Here is an attribute:
38+
/// Attribute text
39+
- (void)f0;
40+
@end
41+
42+
3543
SWIFT_CLASS("_TtC8comments13AutomaticLink")
3644
@interface AutomaticLink
3745
/// And now for a URL.
@@ -185,6 +193,16 @@ SWIFT_CLASS("_TtC8comments13EmptyComments")
185193
@end
186194

187195

196+
SWIFT_CLASS("_TtC8comments9Footnotes")
197+
@interface Footnotes
198+
/// Has some footnotes.
199+
/// Footnotes aren’t handled by swiftMarkup yet[^footnote], but they may in the future.
200+
/// [^footnote]: Footnotes aren’t parsed by default in swift-cmark, and swiftMarkup doesn’t
201+
/// enable the feature.
202+
- (void)f0;
203+
@end
204+
205+
188206
SWIFT_CLASS("_TtC8comments19HasThrowingFunction")
189207
@interface HasThrowingFunction
190208
/// Might throw something.

0 commit comments

Comments
 (0)