Skip to content

Commit 120b717

Browse files
fpelliccionialandefreitas
authored andcommitted
feat: tagfiles generation for cross-referencing in doxygen format
1 parent 1e162bf commit 120b717

19 files changed

+792
-21
lines changed

include/mrdocs/Corpus.hpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,39 @@ class MRDOCS_VISIBLE
160160
}
161161
}
162162

163+
/** Visit the members of specified Info.
164+
165+
This function iterates the members of the specified
166+
Info `I`. For each member associated with a
167+
function with the same name as the member, the
168+
function object `f` is invoked with the member
169+
as the first argument, followed by `args...`.
170+
171+
When there are more than one member function
172+
with the same name, the function object `f` is
173+
invoked with an @ref OverloadSet as the first
174+
argument, followed by `args...`.
175+
176+
@param I The Info to traverse.
177+
@param pred The predicate to use to determine if the member should be visited.
178+
@param f The function to invoke with the member as the first argument, followed by `args...`.
179+
@param args The arguments to pass to the function.
180+
*/
181+
template <InfoParent T, class Pred, class F, class... Args>
182+
void
183+
traverseIf(
184+
T const& I, Pred&& pred, F&& f, Args&&... args) const
185+
{
186+
for (auto const& id : I.Members)
187+
{
188+
if (std::forward<Pred>(pred)(get(id)))
189+
{
190+
visit(get(id), std::forward<F>(f),
191+
std::forward<Args>(args)...);
192+
}
193+
}
194+
}
195+
163196
/** Visit the function members of specified Info.
164197
165198
This function iterates the members of the specified

include/mrdocs/Generator.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,16 @@ class MRDOCS_VISIBLE
115115
@param os The stream to write to.
116116
117117
@param corpus The metadata to emit.
118+
119+
@param fileName The file name to use for the output.
118120
*/
119121
MRDOCS_DECL
120122
virtual
121123
Error
122124
buildOne(
123125
std::ostream& os,
124-
Corpus const& corpus) const = 0;
126+
Corpus const& corpus,
127+
std::string_view fileName) const = 0;
125128

126129
/** Build the reference as a single page to a file.
127130

src/lib/Gen/adoc/AdocGenerator.cpp

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515
#include "MultiPageVisitor.hpp"
1616
#include "SinglePageVisitor.hpp"
1717
#include "lib/Support/LegibleNames.hpp"
18+
#include "lib/Support/RawOstream.hpp"
19+
#include <llvm/Support/FileSystem.h>
20+
#include <llvm/Support/Path.h>
1821
#include <mrdocs/Metadata/DomMetadata.hpp>
1922
#include <mrdocs/Support/Error.hpp>
2023
#include <mrdocs/Support/Path.hpp>
24+
#include <fstream>
2125
#include <optional>
2226
#include <vector>
2327

@@ -70,10 +74,35 @@ build(
7074
if(! ex)
7175
return ex.error();
7276

73-
MultiPageVisitor visitor(*ex, outputPath, corpus);
77+
std::string path = files::appendPath(outputPath, "reference.tag.xml");
78+
if(auto err = files::createDirectory(outputPath))
79+
{
80+
return err;
81+
}
82+
83+
std::ofstream os;
84+
try
85+
{
86+
os.open(path,
87+
std::ios_base::binary |
88+
std::ios_base::out |
89+
std::ios_base::trunc // | std::ios_base::noreplace
90+
);
91+
}
92+
catch(std::exception const& ex)
93+
{
94+
return formatError("std::ofstream(\"{}\") threw \"{}\"", path, ex.what());
95+
}
96+
97+
RawOstream raw_os(os);
98+
auto tagfileWriter = TagfileWriter(raw_os, corpus);
99+
tagfileWriter.initialize();
100+
101+
MultiPageVisitor visitor(*ex, outputPath, corpus, tagfileWriter);
74102
visitor(corpus.globalNamespace());
75103

76104
auto errors = ex->wait();
105+
tagfileWriter.finalize();
77106
if(! errors.empty())
78107
return Error(errors);
79108
return Error::success();
@@ -83,8 +112,12 @@ Error
83112
AdocGenerator::
84113
buildOne(
85114
std::ostream& os,
86-
Corpus const& corpus) const
115+
Corpus const& corpus,
116+
std::string_view outputPath) const
87117
{
118+
namespace path = llvm::sys::path;
119+
using SmallString = llvm::SmallString<0>;
120+
88121
auto options = loadOptions(corpus);
89122
if(! options)
90123
return options.error();
@@ -106,9 +139,38 @@ buildOne(
106139
if(! errors.empty())
107140
return {errors};
108141

109-
SinglePageVisitor visitor(*ex, corpus, os);
142+
SmallString fileName(outputPath);
143+
path::replace_extension(fileName, "tag.xml");
144+
auto parentDir = files::getParentDir(fileName.str());
145+
if(auto err = files::createDirectory(parentDir))
146+
{
147+
return err;
148+
}
149+
150+
std::ofstream osTagfile;
151+
try
152+
{
153+
osTagfile.open(fileName.str().str(),
154+
std::ios_base::binary |
155+
std::ios_base::out |
156+
std::ios_base::trunc // | std::ios_base::noreplace
157+
);
158+
}
159+
catch(std::exception const& ex)
160+
{
161+
return formatError("std::ofstream(\"{}\") threw \"{}\"", fileName.str().str(), ex.what());
162+
}
163+
164+
RawOstream raw_os(osTagfile);
165+
auto tagfileWriter = TagfileWriter(raw_os, corpus);
166+
tagfileWriter.initialize();
167+
168+
169+
auto const justFileName = path::filename(fileName);
170+
SinglePageVisitor visitor(*ex, corpus, os, justFileName, tagfileWriter);
110171
visitor(corpus.globalNamespace());
111172
errors = ex->wait();
173+
tagfileWriter.finalize();
112174
if(! errors.empty())
113175
return {errors};
114176

src/lib/Gen/adoc/AdocGenerator.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ class AdocGenerator
4949
Error
5050
buildOne(
5151
std::ostream& os,
52-
Corpus const& corpus) const override;
52+
Corpus const& corpus,
53+
std::string_view fileName) const override;
5354
};
5455

5556
} // adoc

src/lib/Gen/adoc/MultiPageVisitor.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,12 @@ operator()(T const& I)
5050
{
5151
ex_.async([this, &I](Builder& builder)
5252
{
53-
if(const auto r = builder(I))
54-
writePage(*r, builder.domCorpus.getXref(I));
53+
if(const auto r = builder(I))
54+
{
55+
auto const xref = builder.domCorpus.getXref(I);
56+
writePage(*r, xref);
57+
tagfileWriter_(I, xref, 0);
58+
}
5559
else
5660
r.error().Throw();
5761
if constexpr(

src/lib/Gen/adoc/MultiPageVisitor.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define MRDOCS_LIB_GEN_ADOC_MULTIPAGEVISITOR_HPP
1313

1414
#include "Builder.hpp"
15+
#include <lib/Lib/TagfileWriter.hpp>
1516
#include <mrdocs/Support/ExecutorGroup.hpp>
1617
#include <mutex>
1718
#include <ostream>
@@ -29,6 +30,7 @@ class MultiPageVisitor
2930
ExecutorGroup<Builder>& ex_;
3031
std::string_view outputPath_;
3132
Corpus const& corpus_;
33+
TagfileWriter& tagfileWriter_;
3234

3335
void
3436
writePage(
@@ -39,10 +41,12 @@ class MultiPageVisitor
3941
MultiPageVisitor(
4042
ExecutorGroup<Builder>& ex,
4143
std::string_view outputPath,
42-
Corpus const& corpus) noexcept
44+
Corpus const& corpus,
45+
TagfileWriter& tagfileWriter) noexcept
4346
: ex_(ex)
4447
, outputPath_(outputPath)
4548
, corpus_(corpus)
49+
, tagfileWriter_(tagfileWriter)
4650
{
4751
}
4852

src/lib/Gen/adoc/SinglePageVisitor.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ operator()(T const& I)
2222
{
2323
ex_.async([this, &I, page = numPages_++](Builder& builder)
2424
{
25-
if(auto r = builder(I))
25+
if(auto r = builder(I))
26+
{
2627
writePage(*r, page);
28+
tagfileWriter_(I, fileName_, page);
29+
}
2730
else
2831
r.error().Throw();
2932
});

src/lib/Gen/adoc/SinglePageVisitor.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "Builder.hpp"
1515
#include <mrdocs/MetadataFwd.hpp>
16+
#include <lib/Lib/TagfileWriter.hpp>
1617
#include <mrdocs/Support/ExecutorGroup.hpp>
1718
#include <mutex>
1819
#include <ostream>
@@ -35,16 +36,22 @@ class SinglePageVisitor
3536
std::size_t topPage_ = 0;
3637
std::vector<std::optional<
3738
std::string>> pages_;
39+
std::string fileName_;
40+
TagfileWriter& tagfileWriter_;
3841

3942
void writePage(std::string pageText, std::size_t pageNumber);
4043
public:
4144
SinglePageVisitor(
4245
ExecutorGroup<Builder>& ex,
4346
Corpus const& corpus,
44-
std::ostream& os) noexcept
47+
std::ostream& os,
48+
std::string_view fileName,
49+
TagfileWriter& tagfileWriter) noexcept
4550
: ex_(ex)
4651
, corpus_(corpus)
4752
, os_(os)
53+
, fileName_(fileName)
54+
, tagfileWriter_(tagfileWriter)
4855
{
4956
}
5057

src/lib/Gen/html/HTMLGenerator.cpp

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515
#include "MultiPageVisitor.hpp"
1616
#include "SinglePageVisitor.hpp"
1717
#include "lib/Support/LegibleNames.hpp"
18+
#include "lib/Support/RawOstream.hpp"
19+
#include <llvm/Support/FileSystem.h>
20+
#include <llvm/Support/Path.h>
1821
#include <mrdocs/Metadata/DomMetadata.hpp>
1922
#include <mrdocs/Support/Error.hpp>
2023
#include <mrdocs/Support/Path.hpp>
24+
#include <fstream>
2125
#include <optional>
2226
#include <vector>
2327

@@ -67,9 +71,34 @@ build(
6771
if(! ex)
6872
return ex.error();
6973

70-
MultiPageVisitor visitor(*ex, outputPath, corpus);
74+
std::string path = files::appendPath(outputPath, "reference.tag.xml");
75+
if(auto err = files::createDirectory(outputPath))
76+
{
77+
return err;
78+
}
79+
80+
std::ofstream os;
81+
try
82+
{
83+
os.open(path,
84+
std::ios_base::binary |
85+
std::ios_base::out |
86+
std::ios_base::trunc // | std::ios_base::noreplace
87+
);
88+
}
89+
catch(std::exception const& ex)
90+
{
91+
return formatError("std::ofstream(\"{}\") threw \"{}\"", path, ex.what());
92+
}
93+
94+
RawOstream raw_os(os);
95+
auto tagfileWriter = TagfileWriter(raw_os, corpus);
96+
tagfileWriter.initialize();
97+
98+
MultiPageVisitor visitor(*ex, outputPath, corpus, tagfileWriter);
7199
visitor(corpus.globalNamespace());
72100
auto errors = ex->wait();
101+
tagfileWriter.finalize();
73102
if(! errors.empty())
74103
return Error(errors);
75104
return Error::success();
@@ -79,8 +108,12 @@ Error
79108
HTMLGenerator::
80109
buildOne(
81110
std::ostream& os,
82-
Corpus const& corpus) const
111+
Corpus const& corpus,
112+
std::string_view outputPath) const
83113
{
114+
namespace path = llvm::sys::path;
115+
using SmallString = llvm::SmallString<0>;
116+
84117
HTMLCorpus domCorpus(corpus);
85118
auto ex = createExecutors(domCorpus);
86119
if(! ex)
@@ -98,9 +131,36 @@ buildOne(
98131
if(! errors.empty())
99132
return Error(errors);
100133

101-
SinglePageVisitor visitor(*ex, corpus, os);
134+
SmallString fileName(outputPath);
135+
path::replace_extension(fileName, "tag.xml");
136+
auto parentDir = files::getParentDir(fileName.str());
137+
if(auto err = files::createDirectory(parentDir))
138+
{
139+
return err;
140+
}
141+
142+
std::ofstream osTagfile;
143+
try
144+
{
145+
osTagfile.open(fileName.str().str(),
146+
std::ios_base::binary |
147+
std::ios_base::out |
148+
std::ios_base::trunc // | std::ios_base::noreplace
149+
);
150+
}
151+
catch(std::exception const& ex)
152+
{
153+
return formatError("std::ofstream(\"{}\") threw \"{}\"", fileName.str().str(), ex.what());
154+
}
155+
156+
RawOstream raw_os(osTagfile);
157+
auto tagfileWriter = TagfileWriter(raw_os, corpus);
158+
tagfileWriter.initialize();
159+
160+
SinglePageVisitor visitor(*ex, corpus, os, outputPath, tagfileWriter);
102161
visitor(corpus.globalNamespace());
103162
errors = ex->wait();
163+
tagfileWriter.finalize();
104164
if(! errors.empty())
105165
return Error(errors);
106166

src/lib/Gen/html/HTMLGenerator.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ class HTMLGenerator
4949
Error
5050
buildOne(
5151
std::ostream& os,
52-
Corpus const& corpus) const override;
52+
Corpus const& corpus,
53+
std::string_view fileName) const override;
5354
};
5455

5556
} // html

0 commit comments

Comments
 (0)