Index: clang-tools-extra/clang-doc/Generators.h =================================================================== --- clang-tools-extra/clang-doc/Generators.h +++ clang-tools-extra/clang-doc/Generators.h @@ -27,6 +27,7 @@ // Write out the decl info in the specified format. virtual llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) = 0; + virtual bool createResources(ClangDocContext CDCtx) = 0; }; typedef llvm::Registry GeneratorRegistry; Index: clang-tools-extra/clang-doc/HTMLGenerator.cpp =================================================================== --- clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -34,6 +34,7 @@ TAG_UL, TAG_LI, TAG_A, + TAG_LINK, }; HTMLTag() = default; @@ -114,6 +115,7 @@ bool HTMLTag::IsSelfClosing() const { switch (Value) { case HTMLTag::TAG_META: + case HTMLTag::TAG_LINK: return true; case HTMLTag::TAG_TITLE: case HTMLTag::TAG_DIV: @@ -137,6 +139,7 @@ case HTMLTag::TAG_H3: case HTMLTag::TAG_LI: case HTMLTag::TAG_A: + case HTMLTag::TAG_LINK: return true; case HTMLTag::TAG_DIV: case HTMLTag::TAG_P: @@ -167,6 +170,8 @@ return llvm::SmallString<16>("li"); case HTMLTag::TAG_A: return llvm::SmallString<16>("a"); + case HTMLTag::TAG_LINK: + return llvm::SmallString<16>("link"); } } @@ -546,6 +551,7 @@ static const char *Format; llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override; + bool createResources(ClangDocContext CDCtx) override; }; const char *HTMLGenerator::Format = "html"; @@ -592,12 +598,40 @@ 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)); 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"; + 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; + } + return true; +} + static GeneratorRegistry::Add HTML(HTMLGenerator::Format, "Generator for HTML output."); Index: clang-tools-extra/clang-doc/MDGenerator.cpp =================================================================== --- clang-tools-extra/clang-doc/MDGenerator.cpp +++ clang-tools-extra/clang-doc/MDGenerator.cpp @@ -255,6 +255,7 @@ static const char *Format; llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override; + bool createResources(ClangDocContext CDCtx) override { return true; } }; const char *MDGenerator::Format = "md"; Index: clang-tools-extra/clang-doc/Representation.h =================================================================== --- clang-tools-extra/clang-doc/Representation.h +++ clang-tools-extra/clang-doc/Representation.h @@ -349,6 +349,8 @@ struct ClangDocContext { tooling::ExecutionContext *ECtx; bool PublicOnly; + std::string OutDirectory; + std::string ClangDocPath; }; } // namespace doc Index: clang-tools-extra/clang-doc/Serialize.cpp =================================================================== --- clang-tools-extra/clang-doc/Serialize.cpp +++ clang-tools-extra/clang-doc/Serialize.cpp @@ -44,7 +44,6 @@ // } llvm::SmallString<128> getInfoRelativePath(const llvm::SmallVectorImpl &Namespaces) { - std::error_code OK; llvm::SmallString<128> Path; for (auto R = Namespaces.rbegin(), E = Namespaces.rend(); R != E; ++R) llvm::sys::path::append(Path, R->Name); Index: clang-tools-extra/clang-doc/YAMLGenerator.cpp =================================================================== --- clang-tools-extra/clang-doc/YAMLGenerator.cpp +++ clang-tools-extra/clang-doc/YAMLGenerator.cpp @@ -244,6 +244,7 @@ static const char *Format; llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS) override; + bool createResources(ClangDocContext CDCtx) override { return true; } }; const char *YAMLGenerator::Format = "yaml"; Index: clang-tools-extra/clang-doc/stylesheets/clang-doc-default-stylesheet.css =================================================================== --- /dev/null +++ clang-tools-extra/clang-doc/stylesheets/clang-doc-default-stylesheet.css @@ -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; +} Index: clang-tools-extra/clang-doc/tool/CMakeLists.txt =================================================================== --- clang-tools-extra/clang-doc/tool/CMakeLists.txt +++ clang-tools-extra/clang-doc/tool/CMakeLists.txt @@ -14,4 +14,7 @@ clangTooling clangToolingCore ) - \ No newline at end of file + +install(FILES ../stylesheets/clang-doc-default-stylesheet.css + DESTINATION share/clang + COMPONENT clang-doc) Index: clang-tools-extra/clang-doc/tool/ClangDocMain.cpp =================================================================== --- clang-tools-extra/clang-doc/tool/ClangDocMain.cpp +++ clang-tools-extra/clang-doc/tool/ClangDocMain.cpp @@ -91,6 +91,15 @@ llvm_unreachable("Unknown OutputFormatTy"); } +// This function isn't referenced outside its translation unit, but it +// can't use the "static" keyword because its address is used for +// GetMainExecutable (since some platforms don't support taking the +// address of main, and some platforms can't implement GetMainExecutable +// without being given the address of a function in the main executable). +std::string GetExecutablePath(const char *Argv0, void *MainAddr) { + return llvm::sys::fs::getMainExecutable(Argv0, MainAddr); +} + bool CreateDirectory(const Twine &DirName, bool ClearDirectory = false) { std::error_code OK; llvm::SmallString<128> DocsRootPath; @@ -129,7 +138,6 @@ StringRef RelativePath, StringRef Name, StringRef Ext) { - std::error_code OK; llvm::SmallString<128> Path; llvm::sys::path::native(Root, Path); llvm::sys::path::append(Path, RelativePath); @@ -195,8 +203,10 @@ // 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}; + PublicOnly, OutDirectory, ClangDocPath}; auto Err = Exec->get()->execute(doc::newMapperActionFactory(CDCtx), ArgAdjuster); if (Err) { @@ -239,5 +249,8 @@ llvm::errs() << toString(std::move(Err)) << "\n"; } + if (!G->get()->createResources(CDCtx)) + return 1; + return 0; } Index: clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp =================================================================== --- clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp +++ clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp @@ -43,6 +43,7 @@ std::string Expected = R"raw( namespace Namespace +

namespace Namespace

Namespaces

@@ -100,6 +101,7 @@ std::string Expected = R"raw( class r +

class r

@@ -157,6 +159,7 @@ std::string Expected = R"raw( +

f

@@ -194,6 +197,7 @@ std::string Expected = R"raw( +

enum class e

    @@ -254,6 +258,7 @@ std::string Expected = R"raw( +

    f