Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
templategenerator.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include "aggregate.h"
7#include "codemarker.h"
9#include "config.h"
10#include "injabridge.h"
11#include "ir/documentir.h"
12#include "ir/irbuilder.h"
13#include "node.h"
14#include "pagenode.h"
15#include "qdocdatabase.h"
16#include "qmltypenode.h"
17
18#include <QtCore/qdir.h>
19#include <QtCore/qfile.h>
20#include <QtCore/qloggingcategory.h>
21#include <QtCore/qtextstream.h>
22
24
25Q_LOGGING_CATEGORY(lcQDocTemplateGenerator, "qt.qdoc.templategenerator")
26
27using namespace Qt::Literals;
28
29/*!
30 \class TemplateGenerator
31 \internal
32 \brief Generates documentation using external templates and a pre-built IR.
33
34 TemplateGenerator is designed to consume a complete IR (Intermediate
35 Representation) that contains all resolved links, organized content
36 sections, and file paths. The generator itself is "dumb": it only
37 formats pre-resolved data according to template rules, without
38 performing resolution, database lookups, or state modifications.
39
40 \section1 Architecture
41
42 The generator follows QDoc's compile/link/render pipeline:
43
44 \list
45 \li \b{Build phase} (IRBuilder): Extract data from Node tree into IR.
46 Handles all atom processing and Node interaction.
47 \li \b{Link phase} (HrefResolver, future): Resolve cross-module links.
48 \li \b{Render phase} (TemplateGenerator): Format IR into output.
49 Implemented by \c{renderDocument()}, which knows nothing about Nodes.
50 \endlist
51
52 The \c{generateXxx()} methods inherited from Generator are thin wrappers
53 that call IRBuilder to build IR, then renderDocument() to format it.
54 This separation ensures the render phase can be tested independently
55 and that IR design is driven by actual rendering needs.
56
57 \sa IRBuilder, DocumentIR
58*/
59
61 : Generator(file_resolver)
62{
63}
64
66{
68
69 const Config &config = Config::instance();
70
71 QString extensionConfig = config.get(u"template.extension"_s).asString();
72 if (!extensionConfig.isEmpty())
73 m_fileExtension = extensionConfig;
74
75 QString templateDirConfig = config.get(u"template.templatedir"_s).asString();
76
77 if (templateDirConfig.isEmpty()) {
78 m_templateDir.clear();
79 } else if (QDir::isAbsolutePath(templateDirConfig)) {
80 m_templateDir = templateDirConfig;
81 } else {
82 // Relative path: resolve relative to output directory
83 QString outDir = outputDir();
84 if (!outDir.isEmpty())
85 m_templateDir = outDir + "/"_L1 + templateDirConfig;
86 else
87 m_templateDir = templateDirConfig;
88 }
89
90 bool foundTemplates = false;
91 if (!m_templateDir.isEmpty()) {
92 QDir templateDir(m_templateDir);
93 if (templateDir.exists() && !templateDir.entryList(QDir::Files).isEmpty()) {
94 foundTemplates = true;
95 qCInfo(lcQDocTemplateGenerator) << "Using template directory:" << m_templateDir;
96 } else if (!templateDir.exists()) {
97 qCInfo(lcQDocTemplateGenerator)
98 << "Configured template directory does not exist:" << m_templateDir
99 << "- will use embedded templates";
100 } else {
101 qCInfo(lcQDocTemplateGenerator)
102 << "Configured template directory is empty:" << m_templateDir
103 << "- will use embedded templates";
104 }
105 } else {
106 qCInfo(lcQDocTemplateGenerator)
107 << "No external template directory configured - will use embedded templates";
108 }
109
110 if (!foundTemplates)
111 m_templateDir.clear();
112}
113
118
120{
121 return "template"_L1;
122}
123
125{
126 return m_fileExtension;
127}
128
130{
131 // TODO: This will be replaced with IR-based generation
132 // For now, call the base implementation to demonstrate integration
134}
135
136/*
137 Placeholder implementation.
138
139 \note File management is handled by Generator::generateDocumentation().
140 This method only writes content.
141 */
143{
144 Q_UNUSED(marker);
145
146 // TODO: Load template, populate with IR data, render
147 out() << "<!-- TemplateGenerator: C++ Reference Page for "
148 << aggregate->name() << " -->\n";
149 out() << "<h1>" << aggregate->fullTitle() << "</h1>\n";
150 out() << "<p>Template-based output (IR integration pending)</p>\n";
151}
152
154{
155 Q_UNUSED(marker);
156
157 // TODO: Load template, populate with IR data, render
158 out() << "<!-- TemplateGenerator: QML Type Page for "
159 << qcn->name() << " -->\n";
160 out() << "<h1>" << qcn->fullTitle() << "</h1>\n";
161 out() << "<p>Template-based output (IR integration pending)</p>\n";
162}
163
165{
166 Q_UNUSED(marker);
167
168 // Build phase: Node → IR (handled by IRBuilder)
169 IRBuilder builder;
170 DocumentIR ir = builder.buildPageIR(pn);
171
172 // Render phase: IR → Output (TemplateGenerator's actual job)
173 renderDocument(ir, "page"_L1);
174}
175
176/*!
177 \internal
178 Render phase: Format pre-built IR according to a template.
179
180 This is TemplateGenerator's core responsibility. It receives IR and
181 produces formatted output without any knowledge of Nodes or the database.
182*/
183void TemplateGenerator::renderDocument(const DocumentIR &ir, const QString &templateBaseName)
184{
185 const QString templateFileName = templateBaseName + '.'_L1 + m_fileExtension;
186 QString templateContent;
187
188 if (!m_templateDir.isEmpty()) {
189 QString templatePath = m_templateDir + '/'_L1 + templateFileName;
190 QFile templateFile(templatePath);
191
192 if (templateFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
193 templateContent = QString::fromUtf8(templateFile.readAll());
194 templateFile.close();
195 }
196 }
197
198 if (templateContent.isEmpty()) {
199 QFile resourceFile(":/qdoc/templates/"_L1 + templateFileName);
200 if (resourceFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
201 templateContent = QString::fromUtf8(resourceFile.readAll());
202 resourceFile.close();
203 }
204 }
205
206 if (templateContent.isEmpty())
207 qFatal("TemplateGenerator: No template file found for extension '%s'. "
208 "Ensure '%s.%s' exists in the configured template directory or in resources.",
209 qPrintable(m_fileExtension), qPrintable(templateBaseName),
210 qPrintable(m_fileExtension));
211
212 QString rendered = InjaBridge::render(templateContent, ir.toJson());
213 out() << rendered;
214}
215
217{
218 Q_UNUSED(marker);
219
220 out() << "<!-- TemplateGenerator: Collection "
221 << cn->name() << " -->\n";
222 out() << "<h1>" << cn->fullTitle() << "</h1>\n";
223 out() << "<p>Template-based output (IR integration pending)</p>\n";
224}
225
226/*!
227 \internal
228 Stub implementation - not yet IR-driven.
229
230 This method emits placeholder HTML comments and should not be relied upon
231 for actual content rendering. Atom processing will be integrated with the
232 IR system in future commits.
233*/
234qsizetype TemplateGenerator::generateAtom(const Atom *atom, const Node *relative,
235 CodeMarker *marker)
236{
237 Q_UNUSED(relative);
238 Q_UNUSED(marker);
239
240 // TODO: This will be replaced with template-based rendering
241 if (atom) {
242 out() << "<!-- Atom: " << atom->typeString() << " -->\n";
243 return 1;
244 }
245 return 0;
246}
247
248QT_END_NAMESPACE
The Atom class is the fundamental unit for representing documents internally.
Definition atom.h:19
A class for holding the members of a collection of doc pages.
The Config class contains the configuration variables for controlling how qdoc produces documentation...
Definition config.h:85
Encapsulate the logic that QDoc uses to find files whose path is provided by the user and that are re...
Generator(FileResolver &file_resolver)
Constructs the generator base class.
virtual void terminateGenerator()
virtual void generateDocs()
Traverses the database recursively to generate all the documentation.
QTextStream & out()
virtual void initializeGenerator()
No-op base implementation.
Builds IR (Intermediate Representation) from QDoc's Node tree.
Definition irbuilder.h:14
DocumentIR buildPageIR(const PageNode *pn) const
Definition irbuilder.cpp:64
A PageNode is a Node that generates a documentation page.
Definition pagenode.h:19
Generates documentation using external templates and a pre-built IR.
QString fileExtension() const override
void initializeGenerator() override
No-op base implementation.
void generateCppReferencePage(Aggregate *aggregate, CodeMarker *marker) override
void generatePageNode(PageNode *pn, CodeMarker *marker) override
TemplateGenerator(FileResolver &file_resolver)
qsizetype generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker) override
void generateDocs() override
Traverses the database recursively to generate all the documentation.
void terminateGenerator() override
void generateCollectionNode(CollectionNode *cn, CodeMarker *marker) override
QString format() const override
Returns the format identifier for this producer (e.g., "HTML", "DocBook", "template").
void generateQmlTypePage(QmlTypeNode *qcn, CodeMarker *marker) override
Combined button and popup list for selecting options.
Intermediate representation for a documentation topic.
Definition documentir.h:20
The Node class is the base class for all the nodes in QDoc's parse tree.