mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-09 01:29:52 +00:00
[clang-doc] Add option for user provided stylesheets
An option has been added to clang-doc to provide a list of css stylesheets that the user wants to use for the generated html docs. Depends on D64539. Differential Revision: https://reviews.llvm.org/D64938 llvm-svn: 367072
This commit is contained in:
parent
fc8c65b2e1
commit
acd35f6c5e
@ -26,7 +26,8 @@ public:
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -222,6 +222,21 @@ static SmallString<128> computeRelativePath(StringRef FilePath,
|
||||
|
||||
// HTML generation
|
||||
|
||||
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) {
|
||||
auto LinkNode = llvm::make_unique<TagNode>(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<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());
|
||||
@ -529,13 +544,15 @@ class HTMLGenerator : public Generator {
|
||||
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<TagNode>(HTMLTag::TAG_META);
|
||||
@ -577,12 +594,9 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
|
||||
|
||||
F.Children.emplace_back(
|
||||
llvm::make_unique<TagNode>(HTMLTag::TAG_TITLE, InfoTitle));
|
||||
auto LinkNode = llvm::make_unique<TagNode>(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<std::unique_ptr<TagNode>> 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 @@ llvm::Error HTMLGenerator::generateDocForInfo(Info *I, llvm::raw_ostream &OS) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -250,13 +250,15 @@ class MDGenerator : public Generator {
|
||||
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<clang::doc::NamespaceInfo *>(I), OS);
|
||||
|
@ -350,7 +350,7 @@ struct ClangDocContext {
|
||||
tooling::ExecutionContext *ECtx;
|
||||
bool PublicOnly;
|
||||
std::string OutDirectory;
|
||||
std::string ClangDocPath;
|
||||
std::vector<std::string> UserStylesheets;
|
||||
};
|
||||
|
||||
} // namespace doc
|
||||
|
@ -243,13 +243,15 @@ class YAMLGenerator : public Generator {
|
||||
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:
|
||||
|
@ -62,6 +62,11 @@ static llvm::cl::opt<bool> DoxygenOnly(
|
||||
llvm::cl::desc("Use only doxygen-style comments to generate docs."),
|
||||
llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
|
||||
|
||||
static llvm::cl::list<std::string> 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 @@ int main(int argc, const char **argv) {
|
||||
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 @@ int main(int argc, const char **argv) {
|
||||
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";
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,16 @@ std::unique_ptr<Generator> getHTMLGenerator() {
|
||||
return std::move(G.get());
|
||||
}
|
||||
|
||||
ClangDocContext
|
||||
getClangDocContext(std::vector<std::string> 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 @@ TEST(HTMLGeneratorTest, emitNamespaceHTML) {
|
||||
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(<!DOCTYPE html>
|
||||
<meta charset="utf-8"/>
|
||||
<title>namespace Namespace</title>
|
||||
<link rel="stylesheet" href="clang-doc-default-stylesheet.css"/>
|
||||
<link rel="stylesheet" href="user-provided-stylesheet.css"/>
|
||||
<div>
|
||||
<h1>namespace Namespace</h1>
|
||||
<h2>Namespaces</h2>
|
||||
@ -95,7 +107,8 @@ TEST(HTMLGeneratorTest, emitRecordHTML) {
|
||||
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 @@ TEST(HTMLGeneratorTest, emitFunctionHTML) {
|
||||
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 @@ TEST(HTMLGeneratorTest, emitEnumHTML) {
|
||||
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(<!DOCTYPE html>
|
||||
<meta charset="utf-8"/>
|
||||
@ -271,7 +286,8 @@ TEST(HTMLGeneratorTest, emitCommentHTML) {
|
||||
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(<!DOCTYPE html>
|
||||
<meta charset="utf-8"/>
|
||||
|
@ -38,7 +38,7 @@ TEST(MDGeneratorTest, emitNamespaceMD) {
|
||||
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 @@ TEST(MDGeneratorTest, emitRecordMD) {
|
||||
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 @@ TEST(MDGeneratorTest, emitFunctionMD) {
|
||||
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 @@ TEST(MDGeneratorTest, emitEnumMD) {
|
||||
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 @@ TEST(MDGeneratorTest, emitCommentMD) {
|
||||
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
|
||||
|
@ -40,7 +40,7 @@ TEST(YAMLGeneratorTest, emitNamespaceYAML) {
|
||||
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 @@ TEST(YAMLGeneratorTest, emitRecordYAML) {
|
||||
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 @@ TEST(YAMLGeneratorTest, emitFunctionYAML) {
|
||||
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 @@ TEST(YAMLGeneratorTest, emitEnumYAML) {
|
||||
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 @@ TEST(YAMLGeneratorTest, emitCommentYAML) {
|
||||
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(---
|
||||
|
Loading…
Reference in New Issue
Block a user