else
return genLink(Type.Name, "#" + JumpToSection.getValue());
}
- llvm::SmallString<128> Path =
- computeRelativePath(Type.Path, CurrentDirectory);
- llvm::sys::path::append(Path, Type.Name + ".html");
+ llvm::SmallString<64> Path = Type.getRelativeFilePath(CurrentDirectory);
+ llvm::sys::path::append(Path, Type.getFileBaseName() + ".html");
+
// Paths in HTML must be in posix-style
llvm::sys::path::native(Path, llvm::sys::path::Style::posix);
if (JumpToSection)
if (!I.Description.empty())
Out.emplace_back(genHTML(I.Description));
+ llvm::SmallString<64> BasePath = I.getRelativeFilePath("");
+
std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
- genReferencesBlock(I.ChildNamespaces, "Namespaces", I.Path);
+ genReferencesBlock(I.ChildNamespaces, "Namespaces", BasePath);
AppendVector(std::move(ChildNamespaces), Out);
std::vector<std::unique_ptr<TagNode>> ChildRecords =
- genReferencesBlock(I.ChildRecords, "Records", I.Path);
+ genReferencesBlock(I.ChildRecords, "Records", BasePath);
AppendVector(std::move(ChildRecords), Out);
std::vector<std::unique_ptr<TagNode>> ChildFunctions =
- genFunctionsBlock(I.ChildFunctions, CDCtx, I.Path);
+ genFunctionsBlock(I.ChildFunctions, CDCtx, BasePath);
AppendVector(std::move(ChildFunctions), Out);
std::vector<std::unique_ptr<TagNode>> ChildEnums =
genEnumsBlock(I.ChildEnums, CDCtx);
"unexpected info type");
}
- HTMLFile F =
- genInfoFile(InfoTitle, I->Path, MainContentNodes, InfoIndex, CDCtx);
+ HTMLFile F = genInfoFile(InfoTitle, I->getRelativeFilePath(""),
+ MainContentNodes, InfoIndex, CDCtx);
F.Render(OS);
return llvm::Error::success();
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.attribute("Path", I.getRelativeFilePath(""));
J.attributeArray("Children", [&] {
for (const Index &C : I.Children)
IndexToJSON(C);
OS << std::string(Num, '#') + " " + Text << "\n\n";
}
-static void writeFileDefinition(const Location &L, raw_ostream &OS) {
- OS << genItalic("Defined at line " + std::to_string(L.LineNumber) + " of " +
- L.Filename)
- << "\n\n";
+static void writeFileDefinition(const ClangDocContext &CDCtx, const Location &L,
+ raw_ostream &OS) {
+
+ if (!CDCtx.RepositoryUrl) {
+ OS << "*Defined at " << L.Filename << "#" << std::to_string(L.LineNumber)
+ << "*";
+ } else {
+ OS << "*Defined at [" << L.Filename << "#" << std::to_string(L.LineNumber)
+ << "](" << StringRef{CDCtx.RepositoryUrl.getValue()}
+ << llvm::sys::path::relative_path(L.Filename) << "#"
+ << std::to_string(L.LineNumber) << ")"
+ << "*";
+ }
+ OS << "\n\n";
}
static void writeDescription(const CommentInfo &I, raw_ostream &OS) {
}
}
-static void genMarkdown(const EnumInfo &I, llvm::raw_ostream &OS) {
+static void writeNameLink(const StringRef &CurrentPath, const Reference &R,
+ llvm::raw_ostream &OS) {
+ llvm::SmallString<64> Path = R.getRelativeFilePath(CurrentPath);
+ // Paths in Markdown use POSIX separators.
+ llvm::sys::path::native(Path, llvm::sys::path::Style::posix);
+ llvm::sys::path::append(Path, llvm::sys::path::Style::posix,
+ R.getFileBaseName() + ".md");
+ OS << "[" << R.Name << "](" << Path << ")";
+}
+
+static void genMarkdown(const ClangDocContext &CDCtx, const EnumInfo &I,
+ llvm::raw_ostream &OS) {
if (I.Scoped)
writeLine("| enum class " + I.Name + " |", OS);
else
Members << "| " << N << " |\n";
writeLine(Members.str(), OS);
if (I.DefLoc)
- writeFileDefinition(I.DefLoc.getValue(), OS);
+ writeFileDefinition(CDCtx, I.DefLoc.getValue(), OS);
for (const auto &C : I.Description)
writeDescription(C, OS);
}
-static void genMarkdown(const FunctionInfo &I, llvm::raw_ostream &OS) {
+static void genMarkdown(const ClangDocContext &CDCtx, const FunctionInfo &I,
+ llvm::raw_ostream &OS) {
std::string Buffer;
llvm::raw_string_ostream Stream(Buffer);
bool First = true;
Stream.str() + ")"),
OS);
if (I.DefLoc)
- writeFileDefinition(I.DefLoc.getValue(), OS);
+ writeFileDefinition(CDCtx, I.DefLoc.getValue(), OS);
for (const auto &C : I.Description)
writeDescription(C, OS);
}
-static void genMarkdown(const NamespaceInfo &I, llvm::raw_ostream &OS) {
+static void genMarkdown(const ClangDocContext &CDCtx, const NamespaceInfo &I,
+ llvm::raw_ostream &OS) {
if (I.Name == "")
writeHeader("Global Namespace", 1, OS);
else
writeNewLine(OS);
}
+ llvm::SmallString<64> BasePath = I.getRelativeFilePath("");
+
if (!I.ChildNamespaces.empty()) {
writeHeader("Namespaces", 2, OS);
- for (const auto &R : I.ChildNamespaces)
- writeLine(R.Name, OS);
+ for (const auto &R : I.ChildNamespaces) {
+ OS << "* ";
+ writeNameLink(BasePath, R, OS);
+ OS << "\n";
+ }
writeNewLine(OS);
}
+
if (!I.ChildRecords.empty()) {
writeHeader("Records", 2, OS);
- for (const auto &R : I.ChildRecords)
- writeLine(R.Name, OS);
+ for (const auto &R : I.ChildRecords) {
+ OS << "* ";
+ writeNameLink(BasePath, R, OS);
+ OS << "\n";
+ }
writeNewLine(OS);
}
+
if (!I.ChildFunctions.empty()) {
writeHeader("Functions", 2, OS);
for (const auto &F : I.ChildFunctions)
- genMarkdown(F, OS);
+ genMarkdown(CDCtx, F, OS);
writeNewLine(OS);
}
if (!I.ChildEnums.empty()) {
writeHeader("Enums", 2, OS);
for (const auto &E : I.ChildEnums)
- genMarkdown(E, OS);
+ genMarkdown(CDCtx, E, OS);
writeNewLine(OS);
}
}
-static void genMarkdown(const RecordInfo &I, llvm::raw_ostream &OS) {
+static void genMarkdown(const ClangDocContext &CDCtx, const RecordInfo &I,
+ llvm::raw_ostream &OS) {
writeHeader(getTagType(I.TagType) + " " + I.Name, 1, OS);
if (I.DefLoc)
- writeFileDefinition(I.DefLoc.getValue(), OS);
+ writeFileDefinition(CDCtx, I.DefLoc.getValue(), OS);
if (!I.Description.empty()) {
for (const auto &C : I.Description)
if (!I.ChildFunctions.empty()) {
writeHeader("Functions", 2, OS);
for (const auto &F : I.ChildFunctions)
- genMarkdown(F, OS);
+ genMarkdown(CDCtx, F, OS);
writeNewLine(OS);
}
if (!I.ChildEnums.empty()) {
writeHeader("Enums", 2, OS);
for (const auto &E : I.ChildEnums)
- genMarkdown(E, OS);
+ genMarkdown(CDCtx, E, OS);
writeNewLine(OS);
}
}
+static void serializeReference(llvm::raw_fd_ostream &OS, Index &I, int Level) {
+ // Write out the heading level starting at ##
+ OS << "##" << std::string(Level, '#') << " ";
+ writeNameLink("", I, OS);
+ OS << "\n";
+}
+
+static llvm::Error serializeIndex(ClangDocContext &CDCtx) {
+ std::error_code FileErr;
+ llvm::SmallString<128> FilePath;
+ llvm::sys::path::native(CDCtx.OutDirectory, FilePath);
+ llvm::sys::path::append(FilePath, "all_files.md");
+ llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_None);
+ if (FileErr)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "error creating index file: " +
+ FileErr.message());
+
+ CDCtx.Idx.sort();
+ OS << "# All Files";
+ if (!CDCtx.ProjectName.empty())
+ OS << " for " << CDCtx.ProjectName;
+ OS << "\n\n";
+
+ for (auto C : CDCtx.Idx.Children)
+ serializeReference(OS, C, 0);
+
+ return llvm::Error::success();
+}
+
+static llvm::Error genIndex(ClangDocContext &CDCtx) {
+ std::error_code FileErr;
+ llvm::SmallString<128> FilePath;
+ llvm::sys::path::native(CDCtx.OutDirectory, FilePath);
+ llvm::sys::path::append(FilePath, "index.md");
+ llvm::raw_fd_ostream OS(FilePath, FileErr, llvm::sys::fs::OF_None);
+ if (FileErr)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "error creating index file: " +
+ FileErr.message());
+ CDCtx.Idx.sort();
+ OS << "# " << CDCtx.ProjectName << " C/C++ Reference\n\n";
+ for (auto C : CDCtx.Idx.Children) {
+ if (!C.Children.empty()) {
+ const char *Type;
+ switch (C.RefType) {
+ case InfoType::IT_namespace:
+ Type = "Namespace";
+ break;
+ case InfoType::IT_record:
+ Type = "Type";
+ break;
+ case InfoType::IT_enum:
+ Type = "Enum";
+ break;
+ case InfoType::IT_function:
+ Type = "Function";
+ break;
+ case InfoType::IT_default:
+ Type = "Other";
+ }
+ OS << "* " << Type << ": [" << C.Name << "](";
+ if (!C.Path.empty())
+ OS << C.Path << "/";
+ OS << C.Name << ")\n";
+ }
+ }
+ return llvm::Error::success();
+}
/// Generator for Markdown documentation.
class MDGenerator : public Generator {
public:
llvm::Error generateDocForInfo(Info *I, llvm::raw_ostream &OS,
const ClangDocContext &CDCtx) override;
+ llvm::Error createResources(ClangDocContext &CDCtx) override;
};
const char *MDGenerator::Format = "md";
const ClangDocContext &CDCtx) {
switch (I->IT) {
case InfoType::IT_namespace:
- genMarkdown(*static_cast<clang::doc::NamespaceInfo *>(I), OS);
+ genMarkdown(CDCtx, *static_cast<clang::doc::NamespaceInfo *>(I), OS);
break;
case InfoType::IT_record:
- genMarkdown(*static_cast<clang::doc::RecordInfo *>(I), OS);
+ genMarkdown(CDCtx, *static_cast<clang::doc::RecordInfo *>(I), OS);
break;
case InfoType::IT_enum:
- genMarkdown(*static_cast<clang::doc::EnumInfo *>(I), OS);
+ genMarkdown(CDCtx, *static_cast<clang::doc::EnumInfo *>(I), OS);
break;
case InfoType::IT_function:
- genMarkdown(*static_cast<clang::doc::FunctionInfo *>(I), OS);
+ genMarkdown(CDCtx, *static_cast<clang::doc::FunctionInfo *>(I), OS);
break;
case InfoType::IT_default:
return createStringError(llvm::inconvertibleErrorCode(),
return llvm::Error::success();
}
+llvm::Error MDGenerator::createResources(ClangDocContext &CDCtx) {
+ // Write an all_files.md
+ auto Err = serializeIndex(CDCtx);
+ if (Err)
+ return Err;
+
+ // Generate the index page.
+ Err = genIndex(CDCtx);
+ if (Err)
+ return Err;
+
+ return llvm::Error::success();
+}
+
static GeneratorRegistry::Add<MDGenerator> MD(MDGenerator::Format,
"Generator for MD output.");
-// This anchor is used to force the linker to link in the generated object file
-// and thus register the generator.
+// This anchor is used to force the linker to link in the generated object
+// file and thus register the generator.
volatile int MDGeneratorAnchorSource = 0;
} // namespace doc