Index: clang-tools-extra/trunk/clang-doc/Generators.h =================================================================== --- clang-tools-extra/trunk/clang-doc/Generators.h +++ clang-tools-extra/trunk/clang-doc/Generators.h @@ -26,7 +26,8 @@ virtual ~Generator() = default; // Write out the decl info in the specified format. - virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) = 0; + virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) = 0; virtual bool createResources(ClangDocContext CDCtx) = 0; }; Index: clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp =================================================================== --- clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp +++ clang-tools-extra/trunk/clang-doc/HTMLGenerator.cpp @@ -222,6 +222,21 @@ // HTML generation +std::vector> +genStylesheetsHTML(StringRef InfoPath, const ClangDocContext &CDCtx) { + std::vector> Out; + for (const auto &FilePath : CDCtx.UserStylesheets) { + auto LinkNode = llvm::make_unique(HTMLTag::TAG_LINK); + LinkNode->Attributes.try_emplace("rel", "stylesheet"); + SmallString<128> StylesheetPath = computeRelativePath("", InfoPath); + llvm::sys::path::append(StylesheetPath, + llvm::sys::path::filename(FilePath)); + LinkNode->Attributes.try_emplace("href", StylesheetPath); + Out.emplace_back(std::move(LinkNode)); + } + return Out; +} + static std::unique_ptr genLink(const Twine &Text, const Twine &Link) { auto LinkNode = llvm::make_unique(HTMLTag::TAG_A, Text); LinkNode->Attributes.try_emplace("href", Link.str()); @@ -529,13 +544,15 @@ public: static const char *Format; - llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override; + llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) override; bool createResources(ClangDocContext CDCtx) override; }; const char *HTMLGenerator::Format = "html"; -llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) { +llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) { HTMLFile F; auto MetaNode = llvm::make_unique(HTMLTag::TAG_META); @@ -577,12 +594,9 @@ F.Children.emplace_back( llvm::make_unique(HTMLTag::TAG_TITLE, InfoTitle)); - auto LinkNode = llvm::make_unique(HTMLTag::TAG_LINK); - LinkNode->Attributes.try_emplace("rel", "stylesheet"); - SmallString<128> StylesheetPath = computeRelativePath("", I->Path); - llvm::sys::path::append(StylesheetPath, "clang-doc-default-stylesheet.css"); - LinkNode->Attributes.try_emplace("href", StylesheetPath); - F.Children.emplace_back(std::move(LinkNode)); + std::vector> StylesheetsNodes = + genStylesheetsHTML(I->Path, CDCtx); + AppendVector(std::move(StylesheetsNodes), F.Children); F.Children.emplace_back(std::move(MainContentNode)); F.Render(OS); @@ -591,22 +605,22 @@ bool HTMLGenerator::createResources(ClangDocContext CDCtx) { llvm::outs() << "Generating stylesheet for docs...\n"; - llvm::SmallString<128> StylesheetPathWrite; - llvm::sys::path::native(CDCtx.OutDirectory, StylesheetPathWrite); - llvm::sys::path::append(StylesheetPathWrite, - "clang-doc-default-stylesheet.css"); - llvm::SmallString<128> StylesheetPathRead; - llvm::sys::path::native(CDCtx.ClangDocPath, StylesheetPathRead); - StylesheetPathRead = llvm::sys::path::parent_path(StylesheetPathRead); - llvm::sys::path::append(StylesheetPathRead, "..", "share", "clang", - "clang-doc-default-stylesheet.css"); - std::error_code OK; - std::error_code FileErr = - llvm::sys::fs::copy_file(StylesheetPathRead, StylesheetPathWrite); - if (FileErr != OK) { - llvm::errs() << "Error creating stylesheet file: " << FileErr.message() - << "\n"; - return false; + 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; + } } return true; } Index: clang-tools-extra/trunk/clang-doc/MDGenerator.cpp =================================================================== --- clang-tools-extra/trunk/clang-doc/MDGenerator.cpp +++ clang-tools-extra/trunk/clang-doc/MDGenerator.cpp @@ -250,13 +250,15 @@ public: static const char *Format; - llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override; + 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"; -llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) { +llvm::Error MDGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) { switch (I->IT) { case InfoType::IT_namespace: genMarkdown(*static_cast(I), OS); Index: clang-tools-extra/trunk/clang-doc/Representation.h =================================================================== --- clang-tools-extra/trunk/clang-doc/Representation.h +++ clang-tools-extra/trunk/clang-doc/Representation.h @@ -350,7 +350,7 @@ tooling::ExecutionContext *ECtx; bool PublicOnly; std::string OutDirectory; - std::string ClangDocPath; + std::vector UserStylesheets; }; } // namespace doc Index: clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp =================================================================== --- clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp +++ clang-tools-extra/trunk/clang-doc/YAMLGenerator.cpp @@ -243,13 +243,15 @@ public: static const char *Format; - llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override; + 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"; -llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) { +llvm::Error YAMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS, + const ClangDocContext &CDCtx) { llvm::yaml::Output InfoYAML(OS); switch (I->IT) { case InfoType::IT_namespace: Index: clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp =================================================================== --- clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp +++ clang-tools-extra/trunk/clang-doc/tool/ClangDocMain.cpp @@ -62,6 +62,11 @@ llvm::cl::desc("Use only doxygen-style comments to generate docs."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory)); +static llvm::cl::list UserStylesheets( + "stylesheets", llvm::cl::CommaSeparated, + llvm::cl::desc("CSS stylesheets to extend the default styles."), + llvm::cl::cat(ClangDocCategory)); + enum OutputFormatTy { md, yaml, @@ -201,12 +206,26 @@ tooling::ArgumentInsertPosition::END), ArgAdjuster); + clang::doc::ClangDocContext CDCtx = { + Exec->get()->getExecutionContext(), + PublicOnly, + OutDirectory, + {UserStylesheets.begin(), UserStylesheets.end()}}; + + if (Format == "html") { + void *MainAddr = (void *)(intptr_t)GetExecutablePath; + std::string ClangDocPath = GetExecutablePath(argv[0], MainAddr); + llvm::SmallString<128> DefaultStylesheet; + llvm::sys::path::native(ClangDocPath, DefaultStylesheet); + DefaultStylesheet = llvm::sys::path::parent_path(DefaultStylesheet); + llvm::sys::path::append(DefaultStylesheet, + "../share/clang/clang-doc-default-stylesheet.css"); + CDCtx.UserStylesheets.insert(CDCtx.UserStylesheets.begin(), + DefaultStylesheet.str()); + } + // Mapping phase llvm::outs() << "Mapping decls...\n"; - void *MainAddr = (void *)(intptr_t)GetExecutablePath; - std::string ClangDocPath = GetExecutablePath(argv[0], MainAddr); - clang::doc::ClangDocContext CDCtx = {Exec->get()->getExecutionContext(), - PublicOnly, OutDirectory, ClangDocPath}; auto Err = Exec->get()->execute(doc::newMapperActionFactory(CDCtx), ArgAdjuster); if (Err) { @@ -245,7 +264,7 @@ continue; } - if (auto Err = G->get()->generateDocForInfo(I, InfoOS)) + if (auto Err = G->get()->generateDocForInfo(I, InfoOS, CDCtx)) llvm::errs() << toString(std::move(Err)) << "\n"; } Index: clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp +++ clang-tools-extra/trunk/unittests/clang-doc/HTMLGeneratorTest.cpp @@ -21,6 +21,16 @@ return std::move(G.get()); } +ClangDocContext +getClangDocContext(std::vector UserStylesheets = {}) { + ClangDocContext CDCtx; + CDCtx.UserStylesheets = {UserStylesheets.begin(), UserStylesheets.end()}; + CDCtx.UserStylesheets.insert( + CDCtx.UserStylesheets.begin(), + "../share/clang/clang-doc-default-stylesheet.css"); + return CDCtx; +} + TEST(HTMLGeneratorTest, emitNamespaceHTML) { NamespaceInfo I; I.Name = "Namespace"; @@ -38,12 +48,14 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + ClangDocContext CDCtx = getClangDocContext({"user-provided-stylesheet.css"}); + auto Err = G->generateDocForInfo(&I, Actual, CDCtx); assert(!Err); std::string Expected = R"raw( namespace Namespace +

namespace Namespace

Namespaces

@@ -95,7 +107,8 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + ClangDocContext CDCtx = getClangDocContext(); + auto Err = G->generateDocForInfo(&I, Actual, CDCtx); assert(!Err); SmallString<16> PathToF; llvm::sys::path::native("../../../path/to/F.html", PathToF); @@ -161,7 +174,8 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + ClangDocContext CDCtx = getClangDocContext(); + auto Err = G->generateDocForInfo(&I, Actual, CDCtx); assert(!Err); SmallString<16> PathToFloat; llvm::sys::path::native("path/to/float.html", PathToFloat); @@ -203,7 +217,8 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + ClangDocContext CDCtx = getClangDocContext(); + auto Err = G->generateDocForInfo(&I, Actual, CDCtx); assert(!Err); std::string Expected = R"raw( @@ -271,7 +286,8 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + ClangDocContext CDCtx = getClangDocContext(); + auto Err = G->generateDocForInfo(&I, Actual, CDCtx); assert(!Err); std::string Expected = R"raw( Index: clang-tools-extra/trunk/unittests/clang-doc/MDGeneratorTest.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/MDGeneratorTest.cpp +++ clang-tools-extra/trunk/unittests/clang-doc/MDGeneratorTest.cpp @@ -38,7 +38,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(# namespace Namespace @@ -101,7 +101,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(# class r @@ -162,7 +162,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(### f @@ -190,7 +190,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(| enum class e | @@ -320,7 +320,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(### f Index: clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp +++ clang-tools-extra/trunk/unittests/clang-doc/YAMLGeneratorTest.cpp @@ -40,7 +40,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(--- @@ -94,7 +94,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(--- @@ -158,7 +158,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(--- @@ -206,7 +206,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(--- @@ -343,7 +343,7 @@ assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - auto Err = G->generateDocForInfo(&I, Actual); + auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext()); assert(!Err); std::string Expected = R"raw(---