Skip to content

Commit 3982bb4

Browse files
authored
Merge pull request #28612 from owenv/terminal_md_viewer
2 parents bd62d5a + d68089d commit 3982bb4

File tree

6 files changed

+352
-95
lines changed

6 files changed

+352
-95
lines changed

include/swift/Markup/Markup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class MarkupContext final {
6060
LineList getLineList(swift::RawComment RC);
6161
};
6262

63+
Document *parseDocument(MarkupContext &MC, StringRef String);
6364
Document *parseDocument(MarkupContext &MC, LineList &LL);
6465

6566
} // namespace markup

lib/Frontend/PrintingDiagnosticConsumer.cpp

Lines changed: 190 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/AST/DiagnosticEngine.h"
1919
#include "swift/Basic/LLVM.h"
2020
#include "swift/Basic/SourceManager.h"
21+
#include "swift/Markup/Markup.h"
2122
#include "llvm/ADT/SmallString.h"
2223
#include "llvm/ADT/StringRef.h"
2324
#include "llvm/ADT/Twine.h"
@@ -28,6 +29,7 @@
2829
#include <algorithm>
2930

3031
using namespace swift;
32+
using namespace swift::markup;
3133

3234
namespace {
3335
class ColoredStream : public raw_ostream {
@@ -85,6 +87,190 @@ namespace {
8587
size_t preferred_buffer_size() const override { return 0; }
8688
};
8789

90+
// MARK: Markdown Printing
91+
class TerminalMarkupPrinter : public MarkupASTVisitor<TerminalMarkupPrinter> {
92+
llvm::raw_ostream &OS;
93+
unsigned Indent;
94+
unsigned ShouldBold;
95+
96+
void indent(unsigned Amount = 2) { Indent += Amount; }
97+
98+
void dedent(unsigned Amount = 2) {
99+
assert(Indent >= Amount && "dedent without matching indent");
100+
Indent -= Amount;
101+
}
102+
103+
void bold() {
104+
++ShouldBold;
105+
updateFormatting();
106+
}
107+
108+
void unbold() {
109+
assert(ShouldBold > 0 && "unbolded without matching bold");
110+
--ShouldBold;
111+
updateFormatting();
112+
}
113+
114+
void updateFormatting() {
115+
OS.resetColor();
116+
if (ShouldBold > 0)
117+
OS.changeColor(raw_ostream::Colors::SAVEDCOLOR, true);
118+
}
119+
120+
void print(StringRef Str) {
121+
for (auto c : Str) {
122+
OS << c;
123+
if (c == '\n')
124+
for (unsigned i = 0; i < Indent; ++i)
125+
OS << ' ';
126+
}
127+
}
128+
129+
public:
130+
TerminalMarkupPrinter(llvm::raw_ostream &OS)
131+
: OS(OS), Indent(0), ShouldBold(0) {}
132+
133+
void printNewline() { print("\n"); }
134+
135+
void visitDocument(const Document *D) {
136+
for (const auto *Child : D->getChildren()) {
137+
if (Child->getKind() == ASTNodeKind::Paragraph) {
138+
// Add a newline before top-level paragraphs
139+
printNewline();
140+
}
141+
visit(Child);
142+
}
143+
}
144+
145+
void visitBlockQuote(const BlockQuote *BQ) {
146+
indent();
147+
printNewline();
148+
for (const auto *Child : BQ->getChildren())
149+
visit(Child);
150+
dedent();
151+
}
152+
153+
void visitList(const List *BL) {
154+
indent();
155+
printNewline();
156+
for (const auto *Child : BL->getChildren())
157+
visit(Child);
158+
dedent();
159+
}
160+
161+
void visitItem(const Item *I) {
162+
print("- ");
163+
for (const auto *N : I->getChildren())
164+
visit(N);
165+
}
166+
167+
void visitCodeBlock(const CodeBlock *CB) {
168+
indent();
169+
printNewline();
170+
print(CB->getLiteralContent());
171+
dedent();
172+
}
173+
174+
void visitCode(const Code *C) {
175+
print("'");
176+
print(C->getLiteralContent());
177+
print("'");
178+
}
179+
180+
void visitHTML(const HTML *H) { print(H->getLiteralContent()); }
181+
182+
void visitInlineHTML(const InlineHTML *IH) {
183+
print(IH->getLiteralContent());
184+
}
185+
186+
void visitSoftBreak(const SoftBreak *SB) { printNewline(); }
187+
188+
void visitLineBreak(const LineBreak *LB) {
189+
printNewline();
190+
printNewline();
191+
}
192+
193+
void visitLink(const Link *L) {
194+
print("[");
195+
for (const auto *Child : L->getChildren())
196+
visit(Child);
197+
print("](");
198+
print(L->getDestination());
199+
print(")");
200+
}
201+
202+
void visitImage(const Image *I) { llvm_unreachable("unsupported"); }
203+
204+
void visitParagraph(const Paragraph *P) {
205+
for (const auto *Child : P->getChildren())
206+
visit(Child);
207+
printNewline();
208+
}
209+
210+
// TODO: add raw_ostream support for italics ANSI codes in LLVM.
211+
void visitEmphasis(const Emphasis *E) {
212+
for (const auto *Child : E->getChildren())
213+
visit(Child);
214+
}
215+
216+
void visitStrong(const Strong *E) {
217+
bold();
218+
for (const auto *Child : E->getChildren())
219+
visit(Child);
220+
unbold();
221+
}
222+
223+
void visitHRule(const HRule *HR) {
224+
print("--------------");
225+
printNewline();
226+
}
227+
228+
void visitHeader(const Header *H) {
229+
bold();
230+
for (const auto *Child : H->getChildren())
231+
visit(Child);
232+
unbold();
233+
printNewline();
234+
}
235+
236+
void visitText(const Text *T) { print(T->getLiteralContent()); }
237+
238+
void visitPrivateExtension(const PrivateExtension *PE) {
239+
llvm_unreachable("unsupported");
240+
}
241+
242+
void visitParamField(const ParamField *PF) {
243+
llvm_unreachable("unsupported");
244+
}
245+
246+
void visitReturnField(const ReturnsField *RF) {
247+
llvm_unreachable("unsupported");
248+
}
249+
250+
void visitThrowField(const ThrowsField *TF) {
251+
llvm_unreachable("unsupported");
252+
}
253+
254+
#define MARKUP_SIMPLE_FIELD(Id, Keyword, XMLKind) \
255+
void visit##Id(const Id *Field) { llvm_unreachable("unsupported"); }
256+
#include "swift/Markup/SimpleFields.def"
257+
};
258+
259+
static void printMarkdown(StringRef Content, raw_ostream &Out,
260+
bool UseColor) {
261+
markup::MarkupContext ctx;
262+
auto document = markup::parseDocument(ctx, Content);
263+
if (UseColor) {
264+
ColoredStream stream{Out};
265+
TerminalMarkupPrinter printer(stream);
266+
printer.visit(document);
267+
} else {
268+
NoColorStream stream{Out};
269+
TerminalMarkupPrinter printer(stream);
270+
printer.visit(document);
271+
}
272+
}
273+
88274
// MARK: Experimental diagnostic printing.
89275

90276
static void printDiagnosticKind(DiagnosticKind kind, raw_ostream &out) {
@@ -716,8 +902,10 @@ void PrintingDiagnosticConsumer::handleDiagnostic(SourceManager &SM,
716902
printDiagnostic(SM, Info);
717903

718904
for (auto path : Info.EducationalNotePaths) {
719-
if (auto buffer = SM.getFileSystem()->getBufferForFile(path))
720-
Stream << buffer->get()->getBuffer() << "\n";
905+
if (auto buffer = SM.getFileSystem()->getBufferForFile(path)) {
906+
printMarkdown(buffer->get()->getBuffer(), Stream, ForceColors);
907+
Stream << "\n";
908+
}
721909
}
722910

723911
for (auto ChildInfo : Info.ChildDiagnosticInfo) {

0 commit comments

Comments
 (0)