Skip to content

Commit

Permalink
feat: do not update docs if they are not outdated (#148)
Browse files Browse the repository at this point in the history
Fixes #101
  • Loading branch information
smnppKDAB authored Aug 22, 2024
1 parent 6041dbf commit 44f1101
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 22 deletions.
49 changes: 49 additions & 0 deletions docs/API/mapping.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
Document,core/document.cpp,API/knut/document.md,Knut,,2
Project,core/project.cpp,API/knut/project.md,Knut,,2
CodeDocument,core/codedocument.cpp,API/knut/codedocument.md,Knut,CodeDocument,1
ClassSymbol,core/classsymbol.cpp,API/knut/classsymbol.md,Knut,CodeDocument,2
FunctionArgument,core/functionsymbol.cpp,API/knut/functionargument.md,Knut,CodeDocument,2
FunctionSymbol,core/functionsymbol.cpp,API/knut/functionsymbol.md,Knut,CodeDocument,2
QueryCapture,core/querymatch.cpp,API/knut/querycapture.md,Knut,CodeDocument,2
QueryMatch,core/querymatch.cpp,API/knut/querymatch.md,Knut,CodeDocument,2
Symbol,core/symbol.cpp,API/knut/symbol.md,Knut,CodeDocument,2
TypedSymbol,core/typedsymbol.cpp,API/knut/typedsymbol.md,Knut,CodeDocument,2
CppDocument,core/cppdocument.cpp,API/knut/cppdocument.md,Knut,CppDocument,1
DataExchange,core/dataexchange.cpp,API/knut/dataexchange.md,Knut,CppDocument,2
DataExchangeEntry,core/dataexchange.cpp,API/knut/dataexchangeentry.md,Knut,CppDocument,2
MessageMap,core/messagemap.cpp,API/knut/messagemap.md,Knut,CppDocument,2
MessageMapEntry,core/messagemap.cpp,API/knut/messagemapentry.md,Knut,CppDocument,2
QtTsDocument,core/qttsdocument.cpp,API/knut/qttsdocument.md,Knut,QtTsDocument,1
QtTsMessage,core/qttsdocument.cpp,API/knut/qttsmessage.md,Knut,QtTsDocument,2
QtUiDocument,core/qtuidocument.cpp,API/knut/qtuidocument.md,Knut,QtUiDocument,1
QtUiWidget,core/qtuidocument.cpp,API/knut/qtuiwidget.md,Knut,QtUiDocument,2
RcDocument,core/rcdocument.cpp,API/knut/rcdocument.md,Knut,RcDocument,1
Action,rccore/data.cpp,API/knut/action.md,Knut,RcDocument,2
Asset,rccore/data.cpp,API/knut/asset.md,Knut,RcDocument,2
Menu,rccore/data.cpp,API/knut/menu.md,Knut,RcDocument,2
MenuItem,rccore/data.cpp,API/knut/menuitem.md,Knut,RcDocument,2
Ribbon,rccore/ribbon.cpp,API/knut/ribbon.md,Knut,RcDocument,2
RibbonCategory,rccore/ribbon.cpp,API/knut/ribboncategory.md,Knut,RcDocument,2
RibbonContext,rccore/ribbon.cpp,API/knut/ribboncontext.md,Knut,RcDocument,2
RibbonElement,rccore/ribbon.cpp,API/knut/ribbonelement.md,Knut,RcDocument,2
RibbonMenu,rccore/ribbon.cpp,API/knut/ribbonmenu.md,Knut,RcDocument,2
RibbonPanel,rccore/ribbon.cpp,API/knut/ribbonpanel.md,Knut,RcDocument,2
Shortcut,rccore/data.cpp,API/knut/shortcut.md,Knut,RcDocument,2
String,rccore/data.cpp,API/knut/string.md,Knut,RcDocument,2
ToolBar,rccore/data.cpp,API/knut/toolbar.md,Knut,RcDocument,2
ToolBarItem,rccore/data.cpp,API/knut/toolbaritem.md,Knut,RcDocument,2
Widget,rccore/data.cpp,API/knut/widget.md,Knut,RcDocument,2
TextDocument,core/textdocument.cpp,API/knut/textdocument.md,Knut,TextDocument,1
Mark,core/mark.cpp,API/knut/mark.md,Knut,TextDocument,2
RangeMark,core/rangemark.cpp,API/knut/rangemark.md,Knut,TextDocument,2
Script,core/scriptitem.cpp,API/knut/script.md,Knut,Items,2
ScriptDialog,core/scriptdialogitem.cpp,API/knut/scriptdialog.md,Knut,Items,2
Dir,core/dir.cpp,API/knut/dir.md,Knut,Utilities,2
File,core/file.cpp,API/knut/file.md,Knut,Utilities,2
FileInfo,core/fileinfo.cpp,API/knut/fileinfo.md,Knut,Utilities,2
Message,core/message.cpp,API/knut/message.md,Knut,Utilities,2
Settings,core/settings.cpp,API/knut/settings.md,Knut,Utilities,2
UserDialog,core/userdialog.cpp,API/knut/userdialog.md,Knut,Utilities,2
Utils,core/utils.cpp,API/knut/utils.md,Knut,Utilities,2
QDirValueType,core/qdirvaluetype.cpp,API/knut/qdirvaluetype.md,Knut,Utilities,3
QFileInfoValueType,core/qfileinfovaluetype.cpp,API/knut/qfileinfovaluetype.md,Knut,Utilities,3
3 changes: 2 additions & 1 deletion tools/cpp2doc/cpp2doc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ int main(int argc, char *argv[])

Data data;
SourceParser parser(data);
parser.loadMappingFile(KNUT_DOC_PATH "/API");
parser.parseDirectory(KNUT_SOURCE_PATH "/core");
parser.parseDirectory(KNUT_SOURCE_PATH "/rccore");

DocWriter writer(data);
writer.saveDocumentation();
writer.saveDocumentation(KNUT_DOC_PATH "/API");
}
11 changes: 11 additions & 0 deletions tools/cpp2doc/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ struct Data
LastInGroup,
};

struct MappedType
{
QString typeName;
QString sourceFile;
QString docFile;
QString qmlModule;
QString group;
PositionInGroup positionInGroup = InTheMiddle;
};

struct Block
{
QString brief;
Expand Down Expand Up @@ -75,4 +85,5 @@ struct Data
std::vector<PropertyBlock> properties;
std::vector<MethodBlock> methods;
std::vector<SignalBlock> qmlSignals;
std::vector<MappedType> mappedTypes;
};
51 changes: 36 additions & 15 deletions tools/cpp2doc/docwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,24 @@ DocWriter::DocWriter(Data data)
{
}

void DocWriter::saveDocumentation()
void DocWriter::saveMappingFile(const QString &docsDirectory)
{
QFile file(docsDirectory + "/mapping.txt");

if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "Unable to open mapping.txt for writing.";
return;
}

QTextStream out(&file);

for (const auto &entry : m_data.mappedTypes) {
out << entry.typeName << "," << entry.sourceFile << "," << entry.docFile << "," << entry.qmlModule << ","
<< entry.group << "," << static_cast<int>(entry.positionInGroup) << "\n";
}
}

void DocWriter::saveDocumentation(const QString &docsDirectory)
{
// Ensure API directory exists
QDir apiDir(QString(KNUT_DOC_PATH "/API"));
Expand All @@ -31,18 +48,18 @@ void DocWriter::saveDocumentation()
}

// Fill the map between type and filename
for (const auto &type : m_data.types) {
const QString fileName = QString("../%1/%2.md").arg(type.qmlModule.toLower(), type.name.toLower());
m_typeFileMap[type.name] = fileName;
for (const auto &entry : m_data.mappedTypes) {
const QString fileName = QString("../%1/%2.md").arg(entry.qmlModule.toLower(), entry.typeName.toLower());
m_typeFileMap[entry.typeName] = fileName;

QDir dir(QString(KNUT_DOC_PATH "/API/%1").arg(type.qmlModule.toLower()));
QDir dir(QString(KNUT_DOC_PATH "/API/%1").arg(entry.qmlModule.toLower()));
if (!dir.exists()) {
dir.cdUp();
dir.mkdir(type.qmlModule.toLower());
dir.mkdir(entry.qmlModule.toLower());
}
}

auto byModuleAndGroupAndName = [](const Data::TypeBlock &t1, const Data::TypeBlock &t2) {
auto byModuleAndGroupAndName = [](const Data::MappedType &t1, const Data::MappedType &t2) {
if (t1.qmlModule != t2.qmlModule)
return t1.qmlModule < t2.qmlModule;
if (t1.group != t2.group) {
Expand All @@ -58,13 +75,15 @@ void DocWriter::saveDocumentation()
}
if (t1.positionInGroup != t2.positionInGroup)
return t1.positionInGroup < t2.positionInGroup;
return t1.name < t2.name;
return t1.typeName < t2.typeName;
};
std::ranges::sort(m_data.types, byModuleAndGroupAndName);
std::ranges::sort(m_data.mappedTypes, byModuleAndGroupAndName);
for (const auto &type : m_data.types)
writeTypeFile(type);

writeToc();

saveMappingFile(docsDirectory);
}

void DocWriter::writeToc()
Expand All @@ -73,19 +92,21 @@ void DocWriter::writeToc()
QString currentModule;
QString currentGroup;
auto ident = QString(3 * 4, ' ');
for (const auto &type : m_data.types) {
if (type.qmlModule != currentModule) {
currentModule = type.qmlModule;

for (const auto &entry : m_data.mappedTypes) {
if (entry.qmlModule != currentModule) {
currentModule = entry.qmlModule;
nav += QString(" - %1 Module:\n").arg(currentModule);
currentGroup.clear();
ident = QString(3 * 4, ' ');
}
if (type.group != currentGroup && !type.group.isEmpty()) {
currentGroup = type.group;
if (entry.group != currentGroup && !entry.group.isEmpty()) {
currentGroup = entry.group;
nav += QString(" - %1:\n").arg(currentGroup);
ident = QString(4 * 4, ' ');
}
nav += QString("%4- %1: API/%2/%3.md\n").arg(type.name, type.qmlModule.toLower(), type.name.toLower(), ident);
nav += QString("%4- %1: API/%2/%3.md\n")
.arg(entry.typeName, entry.qmlModule.toLower(), entry.typeName.toLower(), ident);
}

QFile file(KNUT_MKDOCS_PATH);
Expand Down
3 changes: 2 additions & 1 deletion tools/cpp2doc/docwriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ class DocWriter
public:
DocWriter(Data data);

void saveDocumentation();
void saveDocumentation(const QString &docsDirectory);

private:
void writeToc();
void writeTypeFile(const Data::TypeBlock &type);
void saveMappingFile(const QString &docsDirectory);
std::vector<Data::PropertyBlock> propertyForType(const Data::TypeBlock &type) const;
std::vector<Data::MethodBlock> methodForType(const Data::TypeBlock &type) const;
std::vector<Data::SignalBlock> signalForType(const Data::TypeBlock &type) const;
Expand Down
99 changes: 94 additions & 5 deletions tools/cpp2doc/sourceparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "sourceparser.h"

#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QFileInfo>
Expand Down Expand Up @@ -37,11 +38,68 @@ static QStringList getAllSourceFiles(const QString &directory)
return result;
}

void SourceParser::loadMappingFile(const QString &filePath)
{
QFile mappingFile(filePath + "/mapping.txt");
if (!mappingFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "Unable to open file mapping.txt for reading.";
return;
}

QTextStream in(&mappingFile);

while (!in.atEnd()) {
const QString line = in.readLine();
const QStringList parts = line.split(',');

if (parts.size() == 6) {
Data::MappedType entry;
entry.typeName = parts[0];
entry.sourceFile = parts[1];
entry.docFile = parts[2];
entry.qmlModule = parts[3];
entry.group = parts[4];
entry.positionInGroup = static_cast<Data::PositionInGroup>(parts[5].toInt());

m_data.mappedTypes.push_back(std::move(entry));
} else {
qWarning() << "Invalid line format in mapping.txt: " << line;
}
}
}

void SourceParser::parseDirectory(const QString &directory)
{
const QStringList sourceFiles = getAllSourceFiles(directory);
for (const auto &sourceFile : sourceFiles)
parseFile(sourceFile);

for (const auto &sourceFile : sourceFiles) {
const QFileInfo sourceFileInfo(sourceFile);
const QDateTime sourceLastModified = sourceFileInfo.lastModified();

const QString relativeSourceFile = QDir(KNUT_SOURCE_PATH).relativeFilePath(sourceFileInfo.absoluteFilePath());

auto isMatchingSourceFile = [&relativeSourceFile](const Data::MappedType &entry) {
return entry.sourceFile == relativeSourceFile;
};

auto it = std::ranges::find_if(m_data.mappedTypes, isMatchingSourceFile);

if (it != m_data.mappedTypes.end()) {
const QFileInfo docFileInfo(QDir(KNUT_DOC_PATH).absoluteFilePath(it->docFile));
const QDateTime docLastModified = docFileInfo.lastModified();

if (sourceLastModified > docLastModified) {
std::erase_if(m_data.mappedTypes, isMatchingSourceFile);
parseFile(sourceFile);
}
} else
parseFile(sourceFile);
}
auto fileDoesNotExist = [](const Data::MappedType &entry) {
return !QFileInfo::exists(QDir(KNUT_SOURCE_PATH).absoluteFilePath(entry.sourceFile));
};

std::erase_if(m_data.mappedTypes, fileDoesNotExist);
}

QString SourceParser::cleanupCommentLine(QString line)
Expand Down Expand Up @@ -71,9 +129,11 @@ void SourceParser::parseFile(const QString &fileName)
inDocumentation = true;
if (inDocumentation) {
line = cleanupCommentLine(line);
if (line.startsWith("\\qmltype"))
m_data.types.push_back(parseType(stream, line));
else if (line.startsWith("\\qmlproperty"))
if (line.startsWith("\\qmltype")) {
const Data::TypeBlock currentType = parseType(stream, line);
m_data.types.push_back(currentType);
updateFileMap(fileName, currentType);
} else if (line.startsWith("\\qmlproperty"))
m_data.properties.push_back(parseProperty(stream, line));
else if (line.startsWith("\\qmlmethod"))
m_data.methods.push_back(parseMethod(stream, line));
Expand Down Expand Up @@ -110,6 +170,35 @@ Data::TypeBlock SourceParser::parseType(QTextStream &stream, QString line)
return currentType;
}

void SourceParser::updateFileMap(const QString &fileName, const Data::TypeBlock &currentType)
{
const QString relativeSourceFileName = QDir(KNUT_SOURCE_PATH).relativeFilePath(fileName);
const QString relativeDocFileName =
QString("API/%1/%2.md").arg(currentType.qmlModule.toLower(), currentType.name.toLower());

auto isSameFile = [&currentType, &relativeSourceFileName](const Data::MappedType &entry) {
return entry.typeName == currentType.name && entry.sourceFile == relativeSourceFileName;
};
auto it = std::ranges::find_if(m_data.mappedTypes, isSameFile);

if (it == m_data.mappedTypes.end()) {
Data::MappedType entry;
entry.typeName = currentType.name;
entry.sourceFile = relativeSourceFileName;
entry.docFile = relativeDocFileName;
entry.qmlModule = currentType.qmlModule;
entry.group = currentType.group;
entry.positionInGroup = currentType.positionInGroup;

m_data.mappedTypes.push_back(std::move(entry));
} else {
it->qmlModule = currentType.qmlModule;
it->group = currentType.group;
it->positionInGroup = currentType.positionInGroup;
it->docFile = relativeDocFileName;
}
}

Data::PropertyBlock SourceParser::parseProperty(QTextStream &stream, QString line)
{
Data::PropertyBlock currentProperty;
Expand Down
2 changes: 2 additions & 0 deletions tools/cpp2doc/sourceparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ class SourceParser
SourceParser(Data &data);

void parseDirectory(const QString &directory);
void loadMappingFile(const QString &filePath);

private:
QString cleanupCommentLine(QString line);
void parseFile(const QString &fileName);

Data::TypeBlock parseType(QTextStream &stream, QString line);
void updateFileMap(const QString &fileName, const Data::TypeBlock &currentType);
Data::PropertyBlock parseProperty(QTextStream &stream, QString line);
Data::MethodBlock parseMethod(QTextStream &stream, QString line);
Data::SignalBlock parseSignal(QTextStream &stream, QString line);
Expand Down

0 comments on commit 44f1101

Please sign in to comment.