1515#include " Headers.h"
1616#include " IncludeCleaner.h"
1717#include " ParsedAST.h"
18+ #include " Protocol.h"
1819#include " Selection.h"
1920#include " SourceCode.h"
2021#include " clang-include-cleaner/Analysis.h"
@@ -960,42 +961,6 @@ std::optional<HoverInfo> getHoverContents(const Attr *A, ParsedAST &AST) {
960961 return HI;
961962}
962963
963- bool isParagraphBreak (llvm::StringRef Rest) {
964- return Rest.ltrim (" \t " ).starts_with (" \n " );
965- }
966-
967- bool punctuationIndicatesLineBreak (llvm::StringRef Line) {
968- constexpr llvm::StringLiteral Punctuation = R"txt( .:,;!?)txt" ;
969-
970- Line = Line.rtrim ();
971- return !Line.empty () && Punctuation.contains (Line.back ());
972- }
973-
974- bool isHardLineBreakIndicator (llvm::StringRef Rest) {
975- // '-'/'*' md list, '@'/'\' documentation command, '>' md blockquote,
976- // '#' headings, '`' code blocks
977- constexpr llvm::StringLiteral LinebreakIndicators = R"txt( -*@\>#`)txt" ;
978-
979- Rest = Rest.ltrim (" \t " );
980- if (Rest.empty ())
981- return false ;
982-
983- if (LinebreakIndicators.contains (Rest.front ()))
984- return true ;
985-
986- if (llvm::isDigit (Rest.front ())) {
987- llvm::StringRef AfterDigit = Rest.drop_while (llvm::isDigit);
988- if (AfterDigit.starts_with (" ." ) || AfterDigit.starts_with (" )" ))
989- return true ;
990- }
991- return false ;
992- }
993-
994- bool isHardLineBreakAfter (llvm::StringRef Line, llvm::StringRef Rest) {
995- // Should we also consider whether Line is short?
996- return punctuationIndicatesLineBreak (Line) || isHardLineBreakIndicator (Rest);
997- }
998-
999964void addLayoutInfo (const NamedDecl &ND, HoverInfo &HI) {
1000965 if (ND.isInvalidDecl ())
1001966 return ;
@@ -1570,6 +1535,26 @@ markup::Document HoverInfo::present() const {
15701535 return Output;
15711536}
15721537
1538+ std::string HoverInfo::present (MarkupKind Kind) const {
1539+ if (Kind == MarkupKind::Markdown) {
1540+ const Config &Cfg = Config::current ();
1541+ if ((Cfg.Documentation .CommentFormat ==
1542+ Config::CommentFormatPolicy::Markdown) ||
1543+ (Cfg.Documentation .CommentFormat ==
1544+ Config::CommentFormatPolicy::Doxygen))
1545+ // If the user prefers Markdown, we use the present() method to generate
1546+ // the Markdown output.
1547+ return present ().asMarkdown ();
1548+ if (Cfg.Documentation .CommentFormat ==
1549+ Config::CommentFormatPolicy::PlainText)
1550+ // If the user prefers plain text, we use the present() method to generate
1551+ // the plain text output.
1552+ return present ().asEscapedMarkdown ();
1553+ }
1554+
1555+ return present ().asPlainText ();
1556+ }
1557+
15731558// If the backtick at `Offset` starts a probable quoted range, return the range
15741559// (including the quotes).
15751560std::optional<llvm::StringRef> getBacktickQuoteRange (llvm::StringRef Line,
@@ -1583,9 +1568,14 @@ std::optional<llvm::StringRef> getBacktickQuoteRange(llvm::StringRef Line,
15831568 return std::nullopt ;
15841569
15851570 // The quoted string must be nonempty and usually has no leading/trailing ws.
1586- auto Next = Line.find ( ' ` ' , Offset + 1 );
1571+ auto Next = Line.find_first_of ( " ` \n " , Offset + 1 );
15871572 if (Next == llvm::StringRef::npos)
15881573 return std::nullopt ;
1574+
1575+ // There should be no newline in the quoted string.
1576+ if (Line[Next] == ' \n ' )
1577+ return std::nullopt ;
1578+
15891579 llvm::StringRef Contents = Line.slice (Offset + 1 , Next);
15901580 if (Contents.empty () || isWhitespace (Contents.front ()) ||
15911581 isWhitespace (Contents.back ()))
@@ -1600,51 +1590,40 @@ std::optional<llvm::StringRef> getBacktickQuoteRange(llvm::StringRef Line,
16001590 return Line.slice (Offset, Next + 1 );
16011591}
16021592
1603- void parseDocumentationLine (llvm::StringRef Line , markup::Paragraph &Out) {
1593+ void parseDocumentationParagraph (llvm::StringRef Text , markup::Paragraph &Out) {
16041594 // Probably this is appendText(Line), but scan for something interesting.
1605- for (unsigned I = 0 ; I < Line .size (); ++I) {
1606- switch (Line [I]) {
1595+ for (unsigned I = 0 ; I < Text .size (); ++I) {
1596+ switch (Text [I]) {
16071597 case ' `' :
1608- if (auto Range = getBacktickQuoteRange (Line , I)) {
1609- Out.appendText (Line .substr (0 , I));
1598+ if (auto Range = getBacktickQuoteRange (Text , I)) {
1599+ Out.appendText (Text .substr (0 , I));
16101600 Out.appendCode (Range->trim (" `" ), /* Preserve=*/ true );
1611- return parseDocumentationLine (Line .substr (I + Range->size ()), Out);
1601+ return parseDocumentationParagraph (Text .substr (I + Range->size ()), Out);
16121602 }
16131603 break ;
16141604 }
16151605 }
1616- Out.appendText (Line). appendSpace ( );
1606+ Out.appendText (Text );
16171607}
16181608
16191609void parseDocumentation (llvm::StringRef Input, markup::Document &Output) {
1620- std::vector<llvm::StringRef> ParagraphLines;
1621- auto FlushParagraph = [&] {
1622- if (ParagraphLines.empty ())
1623- return ;
1624- auto &P = Output.addParagraph ();
1625- for (llvm::StringRef Line : ParagraphLines)
1626- parseDocumentationLine (Line, P);
1627- ParagraphLines.clear ();
1628- };
1629-
1630- llvm::StringRef Line, Rest;
1631- for (std::tie (Line, Rest) = Input.split (' \n ' );
1632- !(Line.empty () && Rest.empty ());
1633- std::tie (Line, Rest) = Rest.split (' \n ' )) {
1634-
1635- // After a linebreak remove spaces to avoid 4 space markdown code blocks.
1636- // FIXME: make FlushParagraph handle this.
1637- Line = Line.ltrim ();
1638- if (!Line.empty ())
1639- ParagraphLines.push_back (Line);
1640-
1641- if (isParagraphBreak (Rest) || isHardLineBreakAfter (Line, Rest)) {
1642- FlushParagraph ();
1643- }
1610+ // A documentation string is treated as a sequence of paragraphs,
1611+ // where the paragraphs are seperated by at least one empty line
1612+ // (meaning 2 consecutive newline characters).
1613+ // Possible leading empty lines (introduced by an odd number > 1 of
1614+ // empty lines between 2 paragraphs) will be removed later in the Markup
1615+ // renderer.
1616+ llvm::StringRef Paragraph, Rest;
1617+ for (std::tie (Paragraph, Rest) = Input.split (" \n\n " );
1618+ !(Paragraph.empty () && Rest.empty ());
1619+ std::tie (Paragraph, Rest) = Rest.split (" \n\n " )) {
1620+
1621+ // The Paragraph will be empty if there is an even number of newline
1622+ // characters between two paragraphs, so we skip it.
1623+ if (!Paragraph.empty ())
1624+ parseDocumentationParagraph (Paragraph, Output.addParagraph ());
16441625 }
1645- FlushParagraph ();
16461626}
1647-
16481627llvm::raw_ostream &operator <<(llvm::raw_ostream &OS,
16491628 const HoverInfo::PrintedType &T) {
16501629 OS << T.Type ;
0 commit comments