Skip to content

Commit

Permalink
feat: tagfiles generation for cross-referencing in doxygen format
Browse files Browse the repository at this point in the history
  • Loading branch information
fpelliccioni committed Oct 19, 2024
1 parent 1e162bf commit e469482
Show file tree
Hide file tree
Showing 20 changed files with 794 additions and 22 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -589,8 +589,9 @@ jobs:
for generator in "${generators[@]}"; do
[[ $generator = xml && $variant = multi ]] && continue
[[ $variant = multi ]] && multipage="true" || multipage="false"
echo "Generating demos for $variant/$generator"
mrdocs --config="$(pwd)/boost/libs/url/doc/mrdocs.yml" "../CMakeLists.txt" --output="$(pwd)/demos/boost-url/$variant/$generator" --multipage=$multipage --generate="$generator"
echo "Number of files in demos/boost-url/$variant/$format: $(find demos/boost-url/$variant/$format -type f | wc -l)"
echo "Number of files in demos/boost-url/$variant/$generator: $(find demos/boost-url/$variant/$generator -type f | wc -l)"
done
done
Expand Down
33 changes: 33 additions & 0 deletions include/mrdocs/Corpus.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,39 @@ class MRDOCS_VISIBLE
}
}

/** Visit the members of specified Info.
This function iterates the members of the specified
Info `I`. For each member associated with a
function with the same name as the member, the
function object `f` is invoked with the member
as the first argument, followed by `args...`.
When there are more than one member function
with the same name, the function object `f` is
invoked with an @ref OverloadSet as the first
argument, followed by `args...`.
@param I The Info to traverse.
@param pred The predicate to use to determine if the member should be visited.
@param f The function to invoke with the member as the first argument, followed by `args...`.
@param args The arguments to pass to the function.
*/
template <InfoParent T, class Pred, class F, class... Args>
void
traverseIf(
T const& I, Pred&& pred, F&& f, Args&&... args) const
{
for (auto const& id : I.Members)
{
if (std::forward<Pred>(pred)(get(id)))
{
visit(get(id), std::forward<F>(f),
std::forward<Args>(args)...);
}
}
}

/** Visit the function members of specified Info.
This function iterates the members of the specified
Expand Down
5 changes: 4 additions & 1 deletion include/mrdocs/Generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,16 @@ class MRDOCS_VISIBLE
@param os The stream to write to.
@param corpus The metadata to emit.
@param fileName The file name to use for the output.
*/
MRDOCS_DECL
virtual
Error
buildOne(
std::ostream& os,
Corpus const& corpus) const = 0;
Corpus const& corpus,
std::string_view fileName) const = 0;

/** Build the reference as a single page to a file.
Expand Down
68 changes: 65 additions & 3 deletions src/lib/Gen/adoc/AdocGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
#include "MultiPageVisitor.hpp"
#include "SinglePageVisitor.hpp"
#include "lib/Support/LegibleNames.hpp"
#include "lib/Support/RawOstream.hpp"
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Path.h>
#include <mrdocs/Metadata/DomMetadata.hpp>
#include <mrdocs/Support/Error.hpp>
#include <mrdocs/Support/Path.hpp>
#include <fstream>
#include <optional>
#include <vector>

Expand Down Expand Up @@ -70,10 +74,35 @@ build(
if(! ex)
return ex.error();

MultiPageVisitor visitor(*ex, outputPath, corpus);
std::string path = files::appendPath(outputPath, "reference.tag.xml");
if(auto err = files::createDirectory(outputPath))
{
return err;
}

std::ofstream os;
try
{
os.open(path,
std::ios_base::binary |
std::ios_base::out |
std::ios_base::trunc // | std::ios_base::noreplace
);
}
catch(std::exception const& ex)
{
return formatError("std::ofstream(\"{}\") threw \"{}\"", path, ex.what());
}

RawOstream raw_os(os);
auto tagfileWriter = TagfileWriter(raw_os, corpus);
tagfileWriter.initialize();

MultiPageVisitor visitor(*ex, outputPath, corpus, tagfileWriter);
visitor(corpus.globalNamespace());

auto errors = ex->wait();
tagfileWriter.finalize();
if(! errors.empty())
return Error(errors);
return Error::success();
Expand All @@ -83,8 +112,12 @@ Error
AdocGenerator::
buildOne(
std::ostream& os,
Corpus const& corpus) const
Corpus const& corpus,
std::string_view outputPath) const
{
namespace path = llvm::sys::path;
using SmallString = llvm::SmallString<0>;

auto options = loadOptions(corpus);
if(! options)
return options.error();
Expand All @@ -106,9 +139,38 @@ buildOne(
if(! errors.empty())
return {errors};

SinglePageVisitor visitor(*ex, corpus, os);
SmallString fileName(outputPath);
path::replace_extension(fileName, "tag.xml");
auto parentDir = files::getParentDir(fileName.str());
if(auto err = files::createDirectory(parentDir))
{
return err;
}

std::ofstream osTagfile;
try
{
osTagfile.open(fileName.str().str(),
std::ios_base::binary |
std::ios_base::out |
std::ios_base::trunc // | std::ios_base::noreplace
);
}
catch(std::exception const& ex)
{
return formatError("std::ofstream(\"{}\") threw \"{}\"", fileName.str().str(), ex.what());
}

RawOstream raw_os(osTagfile);
auto tagfileWriter = TagfileWriter(raw_os, corpus);
tagfileWriter.initialize();


auto const justFileName = path::filename(fileName);
SinglePageVisitor visitor(*ex, corpus, os, justFileName, tagfileWriter);
visitor(corpus.globalNamespace());
errors = ex->wait();
tagfileWriter.finalize();
if(! errors.empty())
return {errors};

Expand Down
3 changes: 2 additions & 1 deletion src/lib/Gen/adoc/AdocGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ class AdocGenerator
Error
buildOne(
std::ostream& os,
Corpus const& corpus) const override;
Corpus const& corpus,
std::string_view fileName) const override;
};

} // adoc
Expand Down
8 changes: 6 additions & 2 deletions src/lib/Gen/adoc/MultiPageVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@ operator()(T const& I)
{
ex_.async([this, &I](Builder& builder)
{
if(const auto r = builder(I))
writePage(*r, builder.domCorpus.getXref(I));
if(const auto r = builder(I))
{
auto const xref = builder.domCorpus.getXref(I);
writePage(*r, xref);
tagfileWriter_(I, xref, 0);
}
else
r.error().Throw();
if constexpr(
Expand Down
6 changes: 5 additions & 1 deletion src/lib/Gen/adoc/MultiPageVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define MRDOCS_LIB_GEN_ADOC_MULTIPAGEVISITOR_HPP

#include "Builder.hpp"
#include <lib/Lib/TagfileWriter.hpp>
#include <mrdocs/Support/ExecutorGroup.hpp>
#include <mutex>
#include <ostream>
Expand All @@ -29,6 +30,7 @@ class MultiPageVisitor
ExecutorGroup<Builder>& ex_;
std::string_view outputPath_;
Corpus const& corpus_;
TagfileWriter& tagfileWriter_;

void
writePage(
Expand All @@ -39,10 +41,12 @@ class MultiPageVisitor
MultiPageVisitor(
ExecutorGroup<Builder>& ex,
std::string_view outputPath,
Corpus const& corpus) noexcept
Corpus const& corpus,
TagfileWriter& tagfileWriter) noexcept
: ex_(ex)
, outputPath_(outputPath)
, corpus_(corpus)
, tagfileWriter_(tagfileWriter)
{
}

Expand Down
5 changes: 4 additions & 1 deletion src/lib/Gen/adoc/SinglePageVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ operator()(T const& I)
{
ex_.async([this, &I, page = numPages_++](Builder& builder)
{
if(auto r = builder(I))
if(auto r = builder(I))
{
writePage(*r, page);
tagfileWriter_(I, fileName_, page);
}
else
r.error().Throw();
});
Expand Down
9 changes: 8 additions & 1 deletion src/lib/Gen/adoc/SinglePageVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "Builder.hpp"
#include <mrdocs/MetadataFwd.hpp>
#include <lib/Lib/TagfileWriter.hpp>
#include <mrdocs/Support/ExecutorGroup.hpp>
#include <mutex>
#include <ostream>
Expand All @@ -35,16 +36,22 @@ class SinglePageVisitor
std::size_t topPage_ = 0;
std::vector<std::optional<
std::string>> pages_;
std::string fileName_;
TagfileWriter& tagfileWriter_;

void writePage(std::string pageText, std::size_t pageNumber);
public:
SinglePageVisitor(
ExecutorGroup<Builder>& ex,
Corpus const& corpus,
std::ostream& os) noexcept
std::ostream& os,
std::string_view fileName,
TagfileWriter& tagfileWriter) noexcept
: ex_(ex)
, corpus_(corpus)
, os_(os)
, fileName_(fileName)
, tagfileWriter_(tagfileWriter)
{
}

Expand Down
66 changes: 63 additions & 3 deletions src/lib/Gen/html/HTMLGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
#include "MultiPageVisitor.hpp"
#include "SinglePageVisitor.hpp"
#include "lib/Support/LegibleNames.hpp"
#include "lib/Support/RawOstream.hpp"
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Path.h>
#include <mrdocs/Metadata/DomMetadata.hpp>
#include <mrdocs/Support/Error.hpp>
#include <mrdocs/Support/Path.hpp>
#include <fstream>
#include <optional>
#include <vector>

Expand Down Expand Up @@ -67,9 +71,34 @@ build(
if(! ex)
return ex.error();

MultiPageVisitor visitor(*ex, outputPath, corpus);
std::string path = files::appendPath(outputPath, "reference.tag.xml");
if(auto err = files::createDirectory(outputPath))
{
return err;
}

std::ofstream os;
try
{
os.open(path,
std::ios_base::binary |
std::ios_base::out |
std::ios_base::trunc // | std::ios_base::noreplace
);
}
catch(std::exception const& ex)
{
return formatError("std::ofstream(\"{}\") threw \"{}\"", path, ex.what());
}

RawOstream raw_os(os);
auto tagfileWriter = TagfileWriter(raw_os, corpus);
tagfileWriter.initialize();

MultiPageVisitor visitor(*ex, outputPath, corpus, tagfileWriter);
visitor(corpus.globalNamespace());
auto errors = ex->wait();
tagfileWriter.finalize();
if(! errors.empty())
return Error(errors);
return Error::success();
Expand All @@ -79,8 +108,12 @@ Error
HTMLGenerator::
buildOne(
std::ostream& os,
Corpus const& corpus) const
Corpus const& corpus,
std::string_view outputPath) const
{
namespace path = llvm::sys::path;
using SmallString = llvm::SmallString<0>;

HTMLCorpus domCorpus(corpus);
auto ex = createExecutors(domCorpus);
if(! ex)
Expand All @@ -98,9 +131,36 @@ buildOne(
if(! errors.empty())
return Error(errors);

SinglePageVisitor visitor(*ex, corpus, os);
SmallString fileName(outputPath);
path::replace_extension(fileName, "tag.xml");
auto parentDir = files::getParentDir(fileName.str());
if(auto err = files::createDirectory(parentDir))
{
return err;
}

std::ofstream osTagfile;
try
{
osTagfile.open(fileName.str().str(),
std::ios_base::binary |
std::ios_base::out |
std::ios_base::trunc // | std::ios_base::noreplace
);
}
catch(std::exception const& ex)
{
return formatError("std::ofstream(\"{}\") threw \"{}\"", fileName.str().str(), ex.what());
}

RawOstream raw_os(osTagfile);
auto tagfileWriter = TagfileWriter(raw_os, corpus);
tagfileWriter.initialize();

SinglePageVisitor visitor(*ex, corpus, os, outputPath, tagfileWriter);
visitor(corpus.globalNamespace());
errors = ex->wait();
tagfileWriter.finalize();
if(! errors.empty())
return Error(errors);

Expand Down
3 changes: 2 additions & 1 deletion src/lib/Gen/html/HTMLGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ class HTMLGenerator
Error
buildOne(
std::ostream& os,
Corpus const& corpus) const override;
Corpus const& corpus,
std::string_view fileName) const override;
};

} // html
Expand Down
1 change: 1 addition & 0 deletions src/lib/Gen/html/MultiPageVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ renderPage(
std::ios_base::trunc // | std::ios_base::noreplace
);
os.write(pageText.data(), pageText.size());
tagfileWriter_(I, fileName, 0);
}
catch(std::exception const& ex)
{
Expand Down
Loading

0 comments on commit e469482

Please sign in to comment.