Author: diegoastiazaran Date: Tue Aug 6 11:31:46 2019 New Revision: 368070
URL: http://llvm.org/viewvc/llvm-project?rev=368070&view=rev Log: [clang-doc] Add index in each info html file An index structure is created while generating the output file for each info. This structure is parsed to JSON and written to a file in the output directory. The html for the index is not rendered by clang-doc. A Javascript file is included in the output directory, this will the JSON file and insert HTML elements into the file. Differential Revision: https://reviews.llvm.org/D65690 Added: clang-tools-extra/trunk/clang-doc/assets/ clang-tools-extra/trunk/clang-doc/assets/clang-doc-default-stylesheet.css clang-tools-extra/trunk/clang-doc/assets/index.js clang-tools-extra/trunk/unittests/clang-doc/GeneratorTest.cpp Removed: clang-tools-extra/trunk/clang-doc/stylesheets/ Modified: clang-tools-extra/trunk/clang-doc/Generators.cpp clang-tools-extra/trunk/clang-doc/Generators.h clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp clang-tools-extra/trunk/clang-doc/MDGenerator.cpp clang-tools-extra/trunk/clang-doc/Representation.cpp clang-tools-extra/trunk/clang-doc/Representation.h clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp Modified: clang-tools-extra/trunk/clang-doc/Generators.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Generators.cpp?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/clang-doc/Generators.cpp (original) +++ clang-tools-extra/trunk/clang-doc/Generators.cpp Tue Aug 6 11:31:46 2019 @@ -57,6 +57,57 @@ std::string getTagType(TagTypeKind AS) { llvm_unreachable("Unknown TagTypeKind"); } +bool Generator::createResources(ClangDocContext &CDCtx) { return true; } + +// A function to add a reference to Info in Idx. +// Given an Info X with the following namespaces: [B,A]; a reference to X will +// be added in the children of a reference to B, which should be also a child of +// a reference to A, where A is a child of Idx. +// Idx +// |-- A +// |--B +// |--X +// If the references to the namespaces do not exist, they will be created. If +// the references already exist, the same one will be used. +void Generator::addInfoToIndex(Index &Idx, const doc::Info *Info) { + // Index pointer that will be moving through Idx until the first parent + // namespace of Info (where the reference has to be inserted) is found. + Index *I = &Idx; + // The Namespace vector includes the upper-most namespace at the end so the + // loop will start from the end to find each of the namespaces. + for (const auto &R : llvm::reverse(Info->Namespace)) { + // Look for the current namespace in the children of the index I is + // pointing. + auto It = std::find(I->Children.begin(), I->Children.end(), R.USR); + if (It != I->Children.end()) { + // If it is found, just change I to point the namespace refererence found. + I = &*It; + } else { + // If it is not found a new reference is created + I->Children.emplace_back(R.USR, R.Name, R.RefType, R.Path); + // I is updated with the reference of the new namespace reference + I = &I->Children.back(); + } + } + // Look for Info in the vector where it is supposed to be; it could already + // exist if it is a parent namespace of an Info already passed to this + // function. + auto It = std::find(I->Children.begin(), I->Children.end(), Info->USR); + if (It == I->Children.end()) { + // If it is not in the vector it is inserted + I->Children.emplace_back(Info->USR, Info->extractName(), Info->IT, + Info->Path); + } else { + // If it not in the vector we only check if Path and Name are not empty + // because if the Info was included by a namespace it may not have those + // values. + if (It->Path.empty()) + It->Path = Info->Path; + if (It->Name.empty()) + It->Name = Info->extractName(); + } +} + // This anchor is used to force the linker to link in the generated object file // and thus register the generators. extern volatile int YAMLGeneratorAnchorSource; Modified: clang-tools-extra/trunk/clang-doc/Generators.h URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Generators.h?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/clang-doc/Generators.h (original) +++ clang-tools-extra/trunk/clang-doc/Generators.h Tue Aug 6 11:31:46 2019 @@ -28,7 +28,13 @@ public: // Write out the decl info in the specified format. virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, const ClangDocContext &CDCtx) = 0; - virtual bool createResources(ClangDocContext CDCtx) = 0; + // This function writes a file with the index previously constructed. + // It can be overwritten by any of the inherited generators. + // If the override method wants to run this it should call + // Generator::createResources(CDCtx); + virtual bool createResources(ClangDocContext &CDCtx); + + static void addInfoToIndex(Index &Idx, const doc::Info *Info); }; typedef llvm::Registry<Generator> GeneratorRegistry; Modified: clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp (original) +++ clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp Tue Aug 6 11:31:46 2019 @@ -11,7 +11,9 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" #include <string> using namespace llvm; @@ -25,17 +27,19 @@ class HTMLTag { public: // Any other tag can be added if required enum TagType { - TAG_META, - TAG_TITLE, + TAG_A, TAG_DIV, TAG_H1, TAG_H2, TAG_H3, - TAG_P, - TAG_UL, TAG_LI, - TAG_A, TAG_LINK, + TAG_META, + TAG_P, + TAG_SCRIPT, + TAG_SPAN, + TAG_TITLE, + TAG_UL, }; HTMLTag() = default; @@ -106,15 +110,17 @@ bool HTMLTag::IsSelfClosing() const { case HTMLTag::TAG_META: case HTMLTag::TAG_LINK: return true; - case HTMLTag::TAG_TITLE: + case HTMLTag::TAG_A: case HTMLTag::TAG_DIV: case HTMLTag::TAG_H1: case HTMLTag::TAG_H2: case HTMLTag::TAG_H3: + case HTMLTag::TAG_LI: case HTMLTag::TAG_P: + case HTMLTag::TAG_SCRIPT: + case HTMLTag::TAG_SPAN: + case HTMLTag::TAG_TITLE: case HTMLTag::TAG_UL: - case HTMLTag::TAG_LI: - case HTMLTag::TAG_A: return false; } llvm_unreachable("Unhandled HTMLTag::TagType"); @@ -122,10 +128,8 @@ bool HTMLTag::IsSelfClosing() const { llvm::SmallString<16> HTMLTag::ToString() const { switch (Value) { - case HTMLTag::TAG_META: - return llvm::SmallString<16>("meta"); - case HTMLTag::TAG_TITLE: - return llvm::SmallString<16>("title"); + case HTMLTag::TAG_A: + return llvm::SmallString<16>("a"); case HTMLTag::TAG_DIV: return llvm::SmallString<16>("div"); case HTMLTag::TAG_H1: @@ -134,16 +138,22 @@ llvm::SmallString<16> HTMLTag::ToString( return llvm::SmallString<16>("h2"); case HTMLTag::TAG_H3: return llvm::SmallString<16>("h3"); - case HTMLTag::TAG_P: - return llvm::SmallString<16>("p"); - case HTMLTag::TAG_UL: - return llvm::SmallString<16>("ul"); case HTMLTag::TAG_LI: return llvm::SmallString<16>("li"); - case HTMLTag::TAG_A: - return llvm::SmallString<16>("a"); case HTMLTag::TAG_LINK: return llvm::SmallString<16>("link"); + case HTMLTag::TAG_META: + return llvm::SmallString<16>("meta"); + case HTMLTag::TAG_P: + return llvm::SmallString<16>("p"); + case HTMLTag::TAG_SCRIPT: + return llvm::SmallString<16>("script"); + case HTMLTag::TAG_SPAN: + return llvm::SmallString<16>("span"); + case HTMLTag::TAG_TITLE: + return llvm::SmallString<16>("title"); + case HTMLTag::TAG_UL: + return llvm::SmallString<16>("ul"); } llvm_unreachable("Unhandled HTMLTag::TagType"); } @@ -222,7 +232,7 @@ static SmallString<128> computeRelativeP // HTML generation -std::vector<std::unique_ptr<TagNode>> +static std::vector<std::unique_ptr<TagNode>> genStylesheetsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) { std::vector<std::unique_ptr<TagNode>> Out; for (const auto &FilePath : CDCtx.UserStylesheets) { @@ -239,6 +249,19 @@ genStylesheetsHTML(StringRef InfoPath, c return Out; } +static std::vector<std::unique_ptr<TagNode>> +genJsScriptsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) { + std::vector<std::unique_ptr<TagNode>> Out; + for (const auto &FilePath : CDCtx.JsScripts) { + auto ScriptNode = llvm::make_unique<TagNode>(HTMLTag::TAG_SCRIPT); + SmallString<128> ScriptPath = computeRelativePath("", InfoPath); + llvm::sys::path::append(ScriptPath, llvm::sys::path::filename(FilePath)); + ScriptNode->Attributes.try_emplace("src", ScriptPath); + Out.emplace_back(std::move(ScriptNode)); + } + return Out; +} + static std::unique_ptr<TagNode> genLink(const Twine &Text, const Twine &Link) { auto LinkNode = llvm::make_unique<TagNode>(HTMLTag::TAG_A, Text); LinkNode->Attributes.try_emplace("href", Link.str()); @@ -362,6 +385,28 @@ static std::unique_ptr<TagNode> writeFil "Defined at line " + std::to_string(L.LineNumber) + " of " + L.Filename); } +static std::vector<std::unique_ptr<TagNode>> +genCommonFileNodes(StringRef Title, StringRef InfoPath, + const ClangDocContext &CDCtx) { + std::vector<std::unique_ptr<TagNode>> Out; + auto MetaNode = llvm::make_unique<TagNode>(HTMLTag::TAG_META); + MetaNode->Attributes.try_emplace("charset", "utf-8"); + Out.emplace_back(std::move(MetaNode)); + Out.emplace_back(llvm::make_unique<TagNode>(HTMLTag::TAG_TITLE, Title)); + std::vector<std::unique_ptr<TagNode>> StylesheetsNodes = + genStylesheetsHTML(InfoPath, CDCtx); + AppendVector(std::move(StylesheetsNodes), Out); + std::vector<std::unique_ptr<TagNode>> JsNodes = + genJsScriptsHTML(InfoPath, CDCtx); + AppendVector(std::move(JsNodes), Out); + // An empty <div> is generated but the index will be then rendered here + auto IndexNode = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV); + IndexNode->Attributes.try_emplace("id", "index"); + IndexNode->Attributes.try_emplace("path", InfoPath); + Out.emplace_back(std::move(IndexNode)); + return Out; +} + static std::unique_ptr<HTMLNode> genHTML(const CommentInfo &I) { if (I.Kind == "FullComment") { auto FullComment = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV); @@ -550,7 +595,7 @@ public: llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, const ClangDocContext &CDCtx) override; - bool createResources(ClangDocContext CDCtx) override; + bool createResources(ClangDocContext &CDCtx) override; }; const char *HTMLGenerator::Format = "html"; @@ -558,13 +603,7 @@ const char *HTMLGenerator::Format = "htm llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, const ClangDocContext &CDCtx) { HTMLFile F; - - auto MetaNode = llvm::make_unique<TagNode>(HTMLTag::TAG_META); - MetaNode->Attributes.try_emplace("charset", "utf-8"); - F.Children.emplace_back(std::move(MetaNode)); - std::string InfoTitle; - Info CastedInfo; auto MainContentNode = llvm::make_unique<TagNode>(HTMLTag::TAG_DIV); switch (I->IT) { case InfoType::IT_namespace: { @@ -596,39 +635,91 @@ llvm::Error HTMLGenerator::generateDocFo llvm::inconvertibleErrorCode()); } - F.Children.emplace_back( - llvm::make_unique<TagNode>(HTMLTag::TAG_TITLE, InfoTitle)); - std::vector<std::unique_ptr<TagNode>> StylesheetsNodes = - genStylesheetsHTML(I->Path, CDCtx); - AppendVector(std::move(StylesheetsNodes), F.Children); + std::vector<std::unique_ptr<TagNode>> BasicNodes = + genCommonFileNodes(InfoTitle, I->Path, CDCtx); + AppendVector(std::move(BasicNodes), F.Children); F.Children.emplace_back(std::move(MainContentNode)); F.Render(OS); return llvm::Error::success(); } -bool HTMLGenerator::createResources(ClangDocContext CDCtx) { - llvm::outs() << "Generating stylesheet for docs...\n"; - for (const auto &FilePath : CDCtx.UserStylesheets) { - llvm::SmallString<128> StylesheetPathWrite; - llvm::sys::path::native(CDCtx.OutDirectory, StylesheetPathWrite); - llvm::sys::path::append(StylesheetPathWrite, - llvm::sys::path::filename(FilePath)); - llvm::SmallString<128> StylesheetPathRead; - llvm::sys::path::native(FilePath, StylesheetPathRead); - std::error_code OK; - std::error_code FileErr = - llvm::sys::fs::copy_file(StylesheetPathRead, StylesheetPathWrite); - if (FileErr != OK) { - llvm::errs() << "Error creating stylesheet file " - << llvm::sys::path::filename(FilePath) << ": " - << FileErr.message() << "\n"; - return false; - } +static std::string getRefType(InfoType IT) { + switch (IT) { + case InfoType::IT_default: + return "default"; + case InfoType::IT_namespace: + return "namespace"; + case InfoType::IT_record: + return "record"; + case InfoType::IT_function: + return "function"; + case InfoType::IT_enum: + return "enum"; + } + llvm_unreachable("Unknown InfoType"); +} + +static bool SerializeIndex(ClangDocContext &CDCtx) { + std::error_code OK; + std::error_code FileErr; + llvm::SmallString<128> FilePath; + llvm::sys::path::native(CDCtx.OutDirectory, FilePath); + llvm::sys::path::append(FilePath, "index_json.js"); + llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::F_None); + if (FileErr != OK) { + llvm::errs() << "Error creating index file: " << FileErr.message() << "\n"; + return false; + } + CDCtx.Idx.sort(); + llvm::json::OStream J(OS, 2); + std::function<void(Index)> IndexToJSON = [&](Index I) { + J.object([&] { + J.attribute("USR", toHex(llvm::toStringRef(I.USR))); + J.attribute("Name", I.Name); + J.attribute("RefType", getRefType(I.RefType)); + J.attribute("Path", I.Path); + J.attributeArray("Children", [&] { + for (const Index &C : I.Children) + IndexToJSON(C); + }); + }); + }; + OS << "var JsonIndex = `\n"; + IndexToJSON(CDCtx.Idx); + OS << "`;\n"; + return true; +} + +static bool CopyFile(StringRef FilePath, StringRef OutDirectory) { + llvm::SmallString<128> PathWrite; + llvm::sys::path::native(OutDirectory, PathWrite); + llvm::sys::path::append(PathWrite, llvm::sys::path::filename(FilePath)); + llvm::SmallString<128> PathRead; + llvm::sys::path::native(FilePath, PathRead); + std::error_code OK; + std::error_code FileErr = llvm::sys::fs::copy_file(PathRead, PathWrite); + if (FileErr != OK) { + llvm::errs() << "Error creating file " + << llvm::sys::path::filename(FilePath) << ": " + << FileErr.message() << "\n"; + return false; } return true; } +bool HTMLGenerator::createResources(ClangDocContext &CDCtx) { + if (!SerializeIndex(CDCtx)) + return false; + for (const auto &FilePath : CDCtx.UserStylesheets) + if (!CopyFile(FilePath, CDCtx.OutDirectory)) + return false; + for (const auto &FilePath : CDCtx.FilesToCopy) + if (!CopyFile(FilePath, CDCtx.OutDirectory)) + return false; + return true; +} + static GeneratorRegistry::Add<HTMLGenerator> HTML(HTMLGenerator::Format, "Generator for HTML output."); Modified: clang-tools-extra/trunk/clang-doc/MDGenerator.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/MDGenerator.cpp?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/clang-doc/MDGenerator.cpp (original) +++ clang-tools-extra/trunk/clang-doc/MDGenerator.cpp Tue Aug 6 11:31:46 2019 @@ -252,7 +252,6 @@ public: llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, const ClangDocContext &CDCtx) override; - bool createResources(ClangDocContext CDCtx) override { return true; } }; const char *MDGenerator::Format = "md"; Modified: clang-tools-extra/trunk/clang-doc/Representation.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.cpp?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/clang-doc/Representation.cpp (original) +++ clang-tools-extra/trunk/clang-doc/Representation.cpp Tue Aug 6 11:31:46 2019 @@ -197,7 +197,7 @@ void FunctionInfo::merge(FunctionInfo && SymbolInfo::merge(std::move(Other)); } -llvm::SmallString<16> Info::extractName() { +llvm::SmallString<16> Info::extractName() const { if (!Name.empty()) return Name; @@ -229,5 +229,11 @@ llvm::SmallString<16> Info::extractName( return llvm::SmallString<16>(""); } +void Index::sort() { + std::sort(Children.begin(), Children.end()); + for (auto &C : Children) + C.sort(); +} + } // namespace doc } // namespace clang Modified: clang-tools-extra/trunk/clang-doc/Representation.h URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/Representation.h?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/clang-doc/Representation.h (original) +++ clang-tools-extra/trunk/clang-doc/Representation.h Tue Aug 6 11:31:46 2019 @@ -249,7 +249,7 @@ struct Info { void mergeBase(Info &&I); bool mergeable(const Info &Other); - llvm::SmallString<16> extractName(); + llvm::SmallString<16> extractName() const; // Returns a reference to the parent scope (that is, the immediate parent // namespace or class in which this decl resides). @@ -348,6 +348,19 @@ struct EnumInfo : public SymbolInfo { llvm::SmallVector<SmallString<16>, 4> Members; // List of enum members. }; +struct Index : public Reference { + Index() = default; + Index(SymbolID USR, StringRef Name, InfoType IT, StringRef Path) + : Reference(USR, Name, IT, Path) {} + // This is used to look for a USR in a vector of Indexes using std::find + bool operator==(const SymbolID &Other) const { return USR == Other; } + bool operator<(const Index &Other) const { return Name < Other.Name; } + + std::vector<Index> Children; + + void sort(); +}; + // TODO: Add functionality to include separate markdown pages. // A standalone function to call to merge a vector of infos into one. @@ -357,10 +370,24 @@ llvm::Expected<std::unique_ptr<Info>> mergeInfos(std::vector<std::unique_ptr<Info>> &Values); struct ClangDocContext { + ClangDocContext() = default; + ClangDocContext(tooling::ExecutionContext *ECtx, bool PublicOnly, + StringRef OutDirectory, + std::vector<std::string> UserStylesheets, + std::vector<std::string> JsScripts) + : ECtx(ECtx), PublicOnly(PublicOnly), OutDirectory(OutDirectory), + UserStylesheets(UserStylesheets), JsScripts(JsScripts) {} tooling::ExecutionContext *ECtx; bool PublicOnly; std::string OutDirectory; + // Path of CSS stylesheets that will be copied to OutDirectory and used to + // style all HTML files. std::vector<std::string> UserStylesheets; + // JavaScript files that will be imported in allHTML file. + std::vector<std::string> JsScripts; + // Other files that should be copied to OutDirectory, besides UserStylesheets. + std::vector<std::string> FilesToCopy; + Index Idx; }; } // namespace doc Modified: clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp (original) +++ clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp Tue Aug 6 11:31:46 2019 @@ -246,7 +246,6 @@ public: llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, const ClangDocContext &CDCtx) override; - bool createResources(ClangDocContext CDCtx) override { return true; } }; const char *YAMLGenerator::Format = "yaml"; Added: clang-tools-extra/trunk/clang-doc/assets/clang-doc-default-stylesheet.css URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/assets/clang-doc-default-stylesheet.css?rev=368070&view=auto ============================================================================== --- clang-tools-extra/trunk/clang-doc/assets/clang-doc-default-stylesheet.css (added) +++ clang-tools-extra/trunk/clang-doc/assets/clang-doc-default-stylesheet.css Tue Aug 6 11:31:46 2019 @@ -0,0 +1,205 @@ +body,div { + margin: 0; + padding: 0; +} + +body[no-overflow] { + overflow: hidden; +} + +li>p:first-child { + margin-top: 0; +} + +li>p:last-child { + margin-bottom: 0; +} + +html { + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +*,*::before,*::after { + -webkit-box-sizing: inherit; + box-sizing: inherit; +} + +body,html { + color: #202124; + font: 400 16px/24px Roboto,sans-serif; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + height: 100%; + margin: 36px; + -webkit-text-size-adjust: 100%; + -moz-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; + text-size-adjust: 100%; +} + +body[devsite-framebox] { + overflow: hidden; + padding: 20px; +} + +body[sitemask--active] { + overflow: hidden; +} + +p { + margin: 16px 0; + padding: 0; +} + +:link,:visited { + color: #039be5; + outline: 0; + text-decoration: none; +} + +ul { + margin: 0; + padding-left: 40px; +} + +ul { + list-style: disc outside; +} + +li,li p { + margin: 12px 0; + padding: 0; +} + +*[visually-hidden] { + opacity: 0 !important; + pointer-events: none !important; + visibility: hidden !important; +} + +*[hidden] { + display: none !important; +} + +[render-hidden] { + display: inline !important; + position: absolute !important; + visibility: hidden !important; +} + +*[no-scroll] { + overflow: hidden; +} + +@supports (display: flex) { + body[ready] .devsite-wrapper { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + } +} + +@media screen and (max-width: 840px) { + body[devsite-book-nav--open] { + overflow: hidden; + } +} + +h1,h2,h3,h4,h5,h6 { + overflow: hidden; + padding: 0; + text-overflow: ellipsis; +} + +h1 { + color: #80868b; + font: 300 34px/40px Roboto,sans-serif; + letter-spacing: -0.01em; + margin: 40px 0 20px; +} + +[layout=docs] h2 { + border-bottom: 1px solid #e8eaed; + padding-bottom: 3px; +} + +h2 { + font: 300 24px/32px Roboto,sans-serif; + letter-spacing: -0.01em; + margin: 40px 0 20px; +} + +h3 { + font: 400 20px/32px Roboto,sans-serif; + margin: 32px 0 16px; +} + +h4,h5,h6 { + margin: 32px 0 16px; +} + +h4 { + font: 500 16px/24px Roboto,sans-serif; +} + +h5 { + font: 700 14px/24px Roboto,sans-serif; +} + +h6 { + font: 500 14px/24px Roboto,sans-serif; +} + +h1+h1,h1+h2,h1+h3,h1+h4,h1+h5,h1+h6,h2+h1,h2+h2,h2+h3,h2+h4,h2+h5,h2+h6,h3+h1,h3+h2,h3+h3,h3+h4,h3+h5,h3+h6,h4+h1,h4+h2,h4+h3,h4+h4,h4+h5,h4+h6,h5+h1,h5+h2,h5+h3,h5+h4,h5+h5,h5+h6,h6+h1,h6+h2,h6+h3,h6+h4,h6+h5,h6+h6 { + margin-top: 0; +} + +@media screen and (max-width: 600px) { + h1 { + font: 300 24px/32px Roboto,sans-serif; + } +} + +[scrollbars]::-webkit-scrollbar { + height: 8px; + width: 8px; +} + +[scrollbars]::-webkit-scrollbar-thumb { + background: rgba(128,134,139,.26); + border-radius: 8px; +} + +[no-horizontal-scrollbars]::-webkit-scrollbar { + height: 0; + width: 0; +} + +[scrollbars]::-webkit-scrollbar-corner { + background: 0; +} + +[background] h2 { + color: #fff; +} + +@media print { + body, html, :link, :visited, h1, h2, h3, h4, h5, h6 { + color: #000 !important; + padding-left: 0 !important; + padding-right: 0 !important; + } + + :link, :visited { + text-decoration: underline; + } +} + +@page { + margin: .75in; +} Added: clang-tools-extra/trunk/clang-doc/assets/index.js URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/assets/index.js?rev=368070&view=auto ============================================================================== --- clang-tools-extra/trunk/clang-doc/assets/index.js (added) +++ clang-tools-extra/trunk/clang-doc/assets/index.js Tue Aug 6 11:31:46 2019 @@ -0,0 +1,81 @@ +// Append using posix-style a file name or directory to Base +function append(Base, New) { + if (!New) + return Base; + if (Base) + Base += "/"; + Base += New; + return Base; +} + +// Get relative path to access FilePath from CurrentDirectory +function computeRelativePath(FilePath, CurrentDirectory) { + var Path = FilePath; + while (Path) { + if (CurrentDirectory == Path) + return FilePath.substring(Path.length + 1); + Path = Path.substring(0, Path.lastIndexOf("/")); + } + + var Dir = CurrentDirectory; + var Result = ""; + while (Dir) { + if (Dir == FilePath) + break; + Dir = Dir.substring(0, Dir.lastIndexOf("/")); + Result = append(Result, "..") + } + Result = append(Result, FilePath.substring(Dir.length)) + return Result; +} + +function genLink(Ref, CurrentDirectory) { + var Path = computeRelativePath(Ref.Path, CurrentDirectory); + Path = append(Path, Ref.Name + ".html") + ANode = document.createElement("a"); + ANode.setAttribute("href", Path); + var TextNode = document.createTextNode(Ref.Name); + ANode.appendChild(TextNode); + return ANode; +} + +function genHTMLOfIndex(Index, CurrentDirectory) { + // Out will store the HTML elements that Index requires to be generated + var Out = []; + if (Index.Name) { + var SpanNode = document.createElement("span"); + var TextNode = document.createTextNode(Index.Name); + SpanNode.appendChild(genLink(Index, CurrentDirectory)); + Out.push(SpanNode); + } + if (Index.Children.length == 0) + return Out; + var UlNode = document.createElement("ul"); + for (Child of Index.Children) { + var LiNode = document.createElement("li"); + ChildNodes = genHTMLOfIndex(Child, CurrentDirectory); + for (Node of ChildNodes) + LiNode.appendChild(Node); + UlNode.appendChild(LiNode); + } + Out.push(UlNode); + return Out; +} + +function createIndex(Index) { + // Get the DOM element where the index will be created + var IndexDiv = document.getElementById("index"); + // Get the relative path of this file + CurrentDirectory = IndexDiv.getAttribute("path"); + var IndexNodes = genHTMLOfIndex(Index, CurrentDirectory); + for (Node of IndexNodes) + IndexDiv.appendChild(Node); +} + +// Runs after DOM loads +document.addEventListener("DOMContentLoaded", function() { + // JsonIndex is a variable from another file that contains the index + // in JSON format + var Index = JSON.parse(JsonIndex); + createIndex(Index); +}); Modified: clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt (original) +++ clang-tools-extra/trunk/clang-doc/tool/CMakeLists.txt Tue Aug 6 11:31:46 2019 @@ -15,6 +15,10 @@ target_link_libraries(clang-doc clangToolingCore ) -install(FILES ../stylesheets/clang-doc-default-stylesheet.css +install(FILES ../assets/clang-doc-default-stylesheet.css + DESTINATION share/clang + COMPONENT clang-doc) + +install(FILES ../assets/index.js DESTINATION share/clang COMPONENT clang-doc) Modified: clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp (original) +++ clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp Tue Aug 6 11:31:46 2019 @@ -215,18 +215,26 @@ int main(int argc, const char **argv) { Exec->get()->getExecutionContext(), PublicOnly, OutDirectory, - {UserStylesheets.begin(), UserStylesheets.end()}}; + {UserStylesheets.begin(), UserStylesheets.end()}, + {"index.js", "index_json.js"}}; if (Format == "html") { void *MainAddr = (void *)(intptr_t)GetExecutablePath; std::string ClangDocPath = GetExecutablePath(argv[0], MainAddr); + llvm::SmallString<128> AssetsPath; + llvm::sys::path::native(ClangDocPath, AssetsPath); + AssetsPath = llvm::sys::path::parent_path(AssetsPath); + llvm::sys::path::append(AssetsPath, "..", "share", "clang"); llvm::SmallString<128> DefaultStylesheet; - llvm::sys::path::native(ClangDocPath, DefaultStylesheet); - DefaultStylesheet = llvm::sys::path::parent_path(DefaultStylesheet); + llvm::sys::path::native(AssetsPath, DefaultStylesheet); llvm::sys::path::append(DefaultStylesheet, - "../share/clang/clang-doc-default-stylesheet.css"); + "clang-doc-default-stylesheet.css"); + llvm::SmallString<128> IndexJS; + llvm::sys::path::native(AssetsPath, IndexJS); + llvm::sys::path::append(IndexJS, "index.js"); CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), DefaultStylesheet.str()); + CDCtx.FilesToCopy.emplace_back(IndexJS.str()); } // Mapping phase @@ -276,10 +284,14 @@ int main(int argc, const char **argv) { continue; } + // Add a reference to this Info in the Index + clang::doc::Generator::addInfoToIndex(CDCtx.Idx, I); + if (auto Err = G->get()->generateDocForInfo(I, InfoOS, CDCtx)) llvm::errs() << toString(std::move(Err)) << "\n"; } + llvm::outs() << "Generating assets for docs...\n"; if (!G->get()->createResources(CDCtx)) return 1; Modified: clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt (original) +++ clang-tools-extra/trunk/unittests/clang-doc/CMakeLists.txt Tue Aug 6 11:31:46 2019 @@ -12,6 +12,7 @@ include_directories( add_extra_unittest(ClangDocTests BitcodeTest.cpp ClangDocTest.cpp + GeneratorTest.cpp HTMLGeneratorTest.cpp MDGeneratorTest.cpp MergeTest.cpp Modified: clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp (original) +++ clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.cpp Tue Aug 6 11:31:46 2019 @@ -63,6 +63,7 @@ void CheckCommentInfo(CommentInfo &Expec void CheckReference(Reference &Expected, Reference &Actual) { EXPECT_EQ(Expected.Name, Actual.Name); EXPECT_EQ(Expected.RefType, Actual.RefType); + EXPECT_EQ(Expected.Path, Actual.Path); } void CheckTypeInfo(TypeInfo *Expected, TypeInfo *Actual) { @@ -180,5 +181,12 @@ void CheckRecordInfo(RecordInfo *Expecte CheckEnumInfo(&Expected->ChildEnums[Idx], &Actual->ChildEnums[Idx]); } +void CheckIndex(Index &Expected, Index &Actual) { + CheckReference(Expected, Actual); + ASSERT_EQ(Expected.Children.size(), Actual.Children.size()); + for (size_t Idx = 0; Idx < Actual.Children.size(); ++Idx) + CheckIndex(Expected.Children[Idx], Actual.Children[Idx]); +} + } // namespace doc } // namespace clang Modified: clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h (original) +++ clang-tools-extra/trunk/unittests/clang-doc/ClangDocTest.h Tue Aug 6 11:31:46 2019 @@ -44,6 +44,8 @@ void CheckEnumInfo(EnumInfo *Expected, E void CheckNamespaceInfo(NamespaceInfo *Expected, NamespaceInfo *Actual); void CheckRecordInfo(RecordInfo *Expected, RecordInfo *Actual); +void CheckIndex(Index &Expected, Index &Actual); + } // namespace doc } // namespace clang Added: clang-tools-extra/trunk/unittests/clang-doc/GeneratorTest.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/GeneratorTest.cpp?rev=368070&view=auto ============================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/GeneratorTest.cpp (added) +++ clang-tools-extra/trunk/unittests/clang-doc/GeneratorTest.cpp Tue Aug 6 11:31:46 2019 @@ -0,0 +1,74 @@ +//===-- clang-doc/GeneratorTest.cpp ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ClangDocTest.h" +#include "Generators.h" +#include "Representation.h" +#include "Serialize.h" +#include "gtest/gtest.h" + +namespace clang { +namespace doc { + +TEST(GeneratorTest, emitIndex) { + Index Idx; + auto InfoA = llvm::make_unique<Info>(); + InfoA->Name = "A"; + InfoA->USR = serialize::hashUSR("1"); + Generator::addInfoToIndex(Idx, InfoA.get()); + auto InfoC = llvm::make_unique<Info>(); + InfoC->Name = "C"; + InfoC->USR = serialize::hashUSR("3"); + Reference RefB = Reference("B"); + RefB.USR = serialize::hashUSR("2"); + InfoC->Namespace = {std::move(RefB)}; + Generator::addInfoToIndex(Idx, InfoC.get()); + auto InfoD = llvm::make_unique<Info>(); + InfoD->Name = "D"; + InfoD->USR = serialize::hashUSR("4"); + auto InfoF = llvm::make_unique<Info>(); + InfoF->Name = "F"; + InfoF->USR = serialize::hashUSR("6"); + Reference RefD = Reference("D"); + RefD.USR = serialize::hashUSR("4"); + Reference RefE = Reference("E"); + RefE.USR = serialize::hashUSR("5"); + InfoF->Namespace = {std::move(RefE), std::move(RefD)}; + Generator::addInfoToIndex(Idx, InfoF.get()); + auto InfoG = llvm::make_unique<Info>(InfoType::IT_namespace); + Generator::addInfoToIndex(Idx, InfoG.get()); + + Index ExpectedIdx; + Index IndexA; + IndexA.Name = "A"; + ExpectedIdx.Children.emplace_back(std::move(IndexA)); + Index IndexB; + IndexB.Name = "B"; + Index IndexC; + IndexC.Name = "C"; + IndexB.Children.emplace_back(std::move(IndexC)); + ExpectedIdx.Children.emplace_back(std::move(IndexB)); + Index IndexD; + IndexD.Name = "D"; + Index IndexE; + IndexE.Name = "E"; + Index IndexF; + IndexF.Name = "F"; + IndexE.Children.emplace_back(std::move(IndexF)); + IndexD.Children.emplace_back(std::move(IndexE)); + ExpectedIdx.Children.emplace_back(std::move(IndexD)); + Index IndexG; + IndexG.Name = "GlobalNamespace"; + IndexG.RefType = InfoType::IT_namespace; + ExpectedIdx.Children.emplace_back(std::move(IndexG)); + + CheckIndex(ExpectedIdx, Idx); +} + +} // namespace doc +} // namespace clang Modified: clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp?rev=368070&r1=368069&r2=368070&view=diff ============================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp (original) +++ clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp Tue Aug 6 11:31:46 2019 @@ -28,6 +28,7 @@ getClangDocContext(std::vector<std::stri CDCtx.UserStylesheets.insert( CDCtx.UserStylesheets.begin(), "../share/clang/clang-doc-default-stylesheet.css"); + CDCtx.JsScripts.emplace_back("index.js"); return CDCtx; } @@ -56,6 +57,8 @@ TEST(HTMLGeneratorTest, emitNamespaceHTM <title>namespace Namespace</title> <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/> <link rel="stylesheet" href="user-provided-stylesheet.css"/> +<script src="index.js"></script> +<div id="index" path=""></div> <div> <h1>namespace Namespace</h1> <h2>Namespaces</h2> @@ -114,6 +117,8 @@ TEST(HTMLGeneratorTest, emitRecordHTML) <meta charset="utf-8"/> <title>class r</title> <link rel="stylesheet" href="../../../clang-doc-default-stylesheet.css"/> +<script src="../../../index.js"></script> +<div id="index" path="X/Y/Z"></div> <div> <h1>class r</h1> <p>Defined at line 10 of test.cpp</p> @@ -175,6 +180,8 @@ TEST(HTMLGeneratorTest, emitFunctionHTML <meta charset="utf-8"/> <title></title> <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/> +<script src="index.js"></script> +<div id="index" path=""></div> <div> <h3>f</h3> <p> @@ -212,6 +219,8 @@ TEST(HTMLGeneratorTest, emitEnumHTML) { <meta charset="utf-8"/> <title></title> <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/> +<script src="index.js"></script> +<div id="index" path=""></div> <div> <h3>enum class e</h3> <ul> @@ -281,6 +290,8 @@ TEST(HTMLGeneratorTest, emitCommentHTML) <meta charset="utf-8"/> <title></title> <link rel="stylesheet" href="clang-doc-default-stylesheet.css"/> +<script src="index.js"></script> +<div id="index" path=""></div> <div> <h3>f</h3> <p>void f(int I, int J)</p> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits