https://github.com/ilovepi created https://github.com/llvm/llvm-project/pull/132482
Currently, when we set URLs from JS, we set them only using the protocol and host locations. This works fine when docs are served from the base directory of the site, but if you want to nest it under another directory, our JS fails to set the correct path, leading to broken links. This patch adds a --base option to specify the path prefix to use, which is set in the generated index_json.js file. index.json can then fill in the prefix appropriately when generating links in a browser. This flag has no effect for non HTML output. Given an index hosted at: www.docs.com/base_directory/index.html we used to generate the following link: www.docs.com/file.html Using --base base_directory we now generate: www.docs.com/base_directory/file.html This allows such links to work when hosting pages without using a custom index.js. >From 953bbddc9baa63e8d7649026b08a6cbbbcdeec31 Mon Sep 17 00:00:00 2001 From: Paul Kirth <paulki...@google.com> Date: Fri, 21 Mar 2025 22:29:14 +0000 Subject: [PATCH] [clang-doc] Allow setting a base directory for hosted pages Currently, when we set URLs from JS, we set them only using the protocol and host locations. This works fine when docs are served from the base directory of the site, but if you want to nest it under another directory, our JS fails to set the correct path, leading to broken links. This patch adds a --base option to specify the path prefix to use, which is set in the generated index_json.js file. index.json can then fill in the prefix appropriately when generating links in a browser. This flag has no effect for non HTML output. Given an index hosted at: www.docs.com/base_directory/index.html we used to generate the following link: www.docs.com/file.html Using --base base_directory we now generate: www.docs.com/base_directory/file.html This allows such links to work when hosting pages without using a custom index.js. --- clang-tools-extra/clang-doc/HTMLGenerator.cpp | 5 +++++ clang-tools-extra/clang-doc/Representation.cpp | 4 ++-- clang-tools-extra/clang-doc/Representation.h | 2 ++ clang-tools-extra/clang-doc/assets/index.js | 2 +- clang-tools-extra/clang-doc/tool/ClangDocMain.cpp | 7 +++++++ clang-tools-extra/test/clang-doc/assets.cpp | 4 ++-- clang-tools-extra/test/clang-doc/test-path-abs.cpp | 3 ++- .../unittests/clang-doc/HTMLGeneratorTest.cpp | 9 +++++---- 8 files changed, 26 insertions(+), 10 deletions(-) diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp index a8404479569f9..9b95d082fdfe7 100644 --- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -1078,6 +1078,11 @@ static llvm::Error serializeIndex(ClangDocContext &CDCtx) { std::replace(RootPathEscaped.begin(), RootPathEscaped.end(), '\\', '/'); OS << "var RootPath = \"" << RootPathEscaped << "\";\n"; + llvm::SmallString<128> Base(CDCtx.Base); + std::string BaseEscaped = Base.str().str(); + std::replace(BaseEscaped.begin(), BaseEscaped.end(), '\\', '/'); + OS << "var Base = \"" << BaseEscaped << "\";\n"; + CDCtx.Idx.sort(); llvm::json::OStream J(OS, 2); std::function<void(Index)> IndexToJSON = [&](const Index &I) { diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp index 4da93b24c131f..fd206fb6a18cc 100644 --- a/clang-tools-extra/clang-doc/Representation.cpp +++ b/clang-tools-extra/clang-doc/Representation.cpp @@ -367,10 +367,10 @@ void Index::sort() { ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName, bool PublicOnly, StringRef OutDirectory, StringRef SourceRoot, - StringRef RepositoryUrl, + StringRef RepositoryUrl, StringRef Base, std::vector<std::string> UserStylesheets) : ECtx(ECtx), ProjectName(ProjectName), PublicOnly(PublicOnly), - OutDirectory(OutDirectory), UserStylesheets(UserStylesheets) { + OutDirectory(OutDirectory), UserStylesheets(UserStylesheets), Base(Base) { llvm::SmallString<128> SourceRootDir(SourceRoot); if (SourceRoot.empty()) // If no SourceRoot was provided the current path is used as the default diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h index bb0c534af7b74..562b8938b77ef 100644 --- a/clang-tools-extra/clang-doc/Representation.h +++ b/clang-tools-extra/clang-doc/Representation.h @@ -508,6 +508,7 @@ struct ClangDocContext { ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName, bool PublicOnly, StringRef OutDirectory, StringRef SourceRoot, StringRef RepositoryUrl, + StringRef Base, std::vector<std::string> UserStylesheets); tooling::ExecutionContext *ECtx; std::string ProjectName; // Name of project clang-doc is documenting. @@ -523,6 +524,7 @@ struct ClangDocContext { std::vector<std::string> UserStylesheets; // JavaScript files that will be imported in allHTML file. std::vector<std::string> JsScripts; + StringRef Base; Index Idx; }; diff --git a/clang-tools-extra/clang-doc/assets/index.js b/clang-tools-extra/clang-doc/assets/index.js index 58a92f049f19f..ae3017dab93f4 100644 --- a/clang-tools-extra/clang-doc/assets/index.js +++ b/clang-tools-extra/clang-doc/assets/index.js @@ -3,7 +3,7 @@ function genLink(Ref) { // serving via a http server or viewing from a local var Path = window.location.protocol.startsWith("file") ? `${window.location.protocol}//${RootPath}/${Ref.Path}` : - `${window.location.protocol}//${window.location.host}/${Ref.Path}`; + `${window.location.protocol}//${window.location.host}/${Base}/${Ref.Path}`; if (Ref.RefType === "namespace") { Path = `${Path}/index.html` } else if (Ref.Path === "") { diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp index 2ce707feb3d5e..fc5962b3b6e72 100644 --- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp +++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp @@ -67,6 +67,12 @@ static llvm::cl::opt<std::string> llvm::cl::desc("Directory for outputting generated files."), llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory)); +static llvm::cl::opt<std::string> + BaseDirectory("base", + llvm::cl::desc("Base Directory for generated documentation."), + llvm::cl::init(""), llvm::cl::cat(ClangDocCategory)); + + static llvm::cl::opt<bool> PublicOnly("public", llvm::cl::desc("Document only public declarations."), llvm::cl::init(false), llvm::cl::cat(ClangDocCategory)); @@ -268,6 +274,7 @@ Example usage for a project using a compile commands database: OutDirectory, SourceRoot, RepositoryUrl, + BaseDirectory, {UserStylesheets.begin(), UserStylesheets.end()} }; diff --git a/clang-tools-extra/test/clang-doc/assets.cpp b/clang-tools-extra/test/clang-doc/assets.cpp index d5a2d20e92240..c5933e504f6b9 100644 --- a/clang-tools-extra/test/clang-doc/assets.cpp +++ b/clang-tools-extra/test/clang-doc/assets.cpp @@ -1,5 +1,5 @@ // RUN: rm -rf %t && mkdir %t -// RUN: clang-doc --format=html --output=%t --asset=%S/Inputs/test-assets --executor=standalone %s +// RUN: clang-doc --format=html --output=%t --asset=%S/Inputs/test-assets --executor=standalone %s --base base_dir // RUN: FileCheck %s -input-file=%t/index.html -check-prefix=INDEX // RUN: FileCheck %s -input-file=%t/test.css -check-prefix=CSS // RUN: FileCheck %s -input-file=%t/test.js -check-prefix=JS @@ -19,4 +19,4 @@ // CSS-NEXT: padding: 0; // CSS-NEXT: } -// JS: console.log("Hello, world!"); \ No newline at end of file +// JS: console.log("Hello, world!"); diff --git a/clang-tools-extra/test/clang-doc/test-path-abs.cpp b/clang-tools-extra/test/clang-doc/test-path-abs.cpp index 292a2a3b5474d..8875a3a73ab7e 100644 --- a/clang-tools-extra/test/clang-doc/test-path-abs.cpp +++ b/clang-tools-extra/test/clang-doc/test-path-abs.cpp @@ -1,6 +1,7 @@ // RUN: rm -rf %t && mkdir -p %t -// RUN: clang-doc --format=html --executor=standalone %s --output=%t +// RUN: clang-doc --format=html --executor=standalone %s --output=%t --base base_dir // RUN: FileCheck %s -input-file=%t/index_json.js -check-prefix=JSON-INDEX // JSON-INDEX: var RootPath = "{{.*}}test-path-abs.cpp.tmp"; +// JSON-INDEX-NEXT: var Base = "base_dir"; diff --git a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp index 97afa12cab6d3..64363923ade8f 100644 --- a/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp +++ b/clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp @@ -28,9 +28,9 @@ std::unique_ptr<Generator> getHTMLGenerator() { ClangDocContext getClangDocContext(std::vector<std::string> UserStylesheets = {}, - StringRef RepositoryUrl = "") { - ClangDocContext CDCtx{ - {}, "test-project", {}, {}, {}, RepositoryUrl, UserStylesheets}; + StringRef RepositoryUrl = "", StringRef Base = "") { + ClangDocContext CDCtx{{}, "test-project", {}, {}, + {}, RepositoryUrl, Base, UserStylesheets}; CDCtx.UserStylesheets.insert( CDCtx.UserStylesheets.begin(), "../share/clang/clang-doc-default-stylesheet.css"); @@ -299,7 +299,8 @@ TEST(HTMLGeneratorTest, emitFunctionHTML) { assert(G); std::string Buffer; llvm::raw_string_ostream Actual(Buffer); - ClangDocContext CDCtx = getClangDocContext({}, "https://www.repository.com"); + ClangDocContext CDCtx = + getClangDocContext({}, "https://www.repository.com"); auto Err = G->generateDocForInfo(&I, Actual, CDCtx); assert(!Err); std::string Expected = R"raw(<!DOCTYPE html> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits