Build folios only when needed, by default (stage D6)

Every project now opens without building its folios; a folio is built
when it is shown or something needs its items (QETProject::lazyFolios()).
QET_LAZY_FOLIOS is gone; QET_EAGER_FOLIOS=1 builds every folio on
opening, as before, for comparisons and troubleshooting. Comments that
named the old variable now say "lazy folios"; the tests switch modes
with the new one.

The first save of a .qet as .qetz still builds every folio: a .qet does
not say which program wrote it, so its folios are written again rather
than copied. A .qetz opens and saves without building.

ctest 96/96 by default and with QET_EAGER_FOLIOS=1; 342 corpus projects
save the same in all four arms and export the same. In the GUI
(qet-gui-dialog): a 136-folio .qetz opens with no folio built, shows
folios 1 to 4, saves building none, the save = the original but the time
spent in it; a .qet opens lazily, saves as a .qetz beside it after the
notice, the .qet unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-10-12 19:27:22 +13:00
parent b151f52428
commit 5c4fa8fadf
24 changed files with 104 additions and 87 deletions
+25 -25
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Lazy folios (QET_LAZY_FOLIOS),
// Lazy folios (on by default, QET_EAGER_FOLIOS=1 for every folio built),
// linked against the application's objects: a folio shown in a project
// opened without building its folios draws and links as in the project
// opened as usual, building only it and the folios its links and tables
@@ -59,7 +59,7 @@ static void revisionEveryFolio(const QString &source, const QString &output, con
const QString &path, int label_folio = -1)
{
QString error;
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
QETProject revised(source);
const int unbuilt = revised.unloadedFolioCount();
QetScriptApi api(&revised);
@@ -85,7 +85,7 @@ static void revisionEveryFolio(const QString &source, const QString &output, con
check(built <= with_tables, "saving a new revision builds only the folios holding a table");
else
check(revised.folios().at(label_folio)->isLoaded(), "a folio whose label changed is built to save");
qunsetenv("QET_LAZY_FOLIOS");
qputenv("QET_EAGER_FOLIOS", "1");
const QString usual_path = output + "/" + name + "-usual" + (qetz ? ".qetz" : ".qet");
{
QETProject usual(source);
@@ -99,7 +99,7 @@ static void revisionEveryFolio(const QString &source, const QString &output, con
else { usual.setFilePath(usual_path); check(usual.write().isOk(), "revision saved when built"); }
}
QETProject lazy_back(lazy_path), usual_back(usual_path);
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
//What a save says of itself (file name, path, time) left out
auto lines = [&path](QETProject &project) {
QStringList list = sortedLines(project.toXml().toString(), path);
@@ -364,7 +364,7 @@ int main(int argc, char **argv)
qputenv("QET_LAZY_SAVE_KEPT", "1");
try {
const QString output = QString::fromLocal8Bit(argv[3]);
qunsetenv("QET_LAZY_FOLIOS");
qputenv("QET_EAGER_FOLIOS", "1");
//A file saved by this version: its folios carry their uuids,
//which opening without building them needs
const QString path = output + "/lazy_folios.qet";
@@ -391,9 +391,9 @@ int main(int argc, char **argv)
QETProject eager(path);
check(eager.state() == QETProject::Ok, "project opens");
{
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
QETProject lazy_strips(path);
qunsetenv("QET_LAZY_FOLIOS");
qputenv("QET_EAGER_FOLIOS", "1");
auto strip_of = [](const QETProject &project) {
for (TerminalStrip *strip : project.terminalStrip())
if (strip->name() == QStringLiteral("X99")) return strip->physicalTerminalCount();
@@ -414,7 +414,7 @@ int main(int argc, char **argv)
}
check(linked > 0, "the project has linked symbols");
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
auto same = [&](QETProject &lazy, int i, const char *what) {
Diagram *folio = lazy.folios().at(i);
lazy.buildFolioToShow(folio);
@@ -542,9 +542,9 @@ int main(int argc, char **argv)
}
{
QETProject edited(path), usual(path);
qunsetenv("QET_LAZY_FOLIOS");
qputenv("QET_EAGER_FOLIOS", "1");
QETProject usual_edited(path);
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
edit(edited, busiest);
std::printf("edits on folio %d (%d links to other folios): %d folios not built\n",
busiest + 1, most, edited.unloadedFolioCount());
@@ -624,9 +624,9 @@ int main(int argc, char **argv)
//After everyday edits on a folio: as when built, others not built
{
QETProject edited(path), usual(path);
qunsetenv("QET_LAZY_FOLIOS");
qputenv("QET_EAGER_FOLIOS", "1");
QETProject usual_edited(path);
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
edit(edited, busiest);
edit(usual_edited, busiest);
QFile file(path); file.open(QIODevice::ReadOnly);
@@ -656,9 +656,9 @@ int main(int argc, char **argv)
//links reach are built to be saved, the others not
{
QETProject renamed(path);
qunsetenv("QET_LAZY_FOLIOS");
qputenv("QET_EAGER_FOLIOS", "1");
QETProject usual_renamed(path);
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
for (QETProject *project : {&renamed, &usual_renamed}) {
Diagram *folio = project->folios().at(busiest);
TitleBlockProperties block = folio->border_and_titleblock.exportTitleBlock();
@@ -673,9 +673,9 @@ int main(int argc, char **argv)
//folio is built to be saved
{
QETProject changed(path);
qunsetenv("QET_LAZY_FOLIOS");
qputenv("QET_EAGER_FOLIOS", "1");
QETProject usual_changed(path);
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
for (QETProject *project : {&changed, &usual_changed}) {
DiagramContext properties = project->projectProperties();
properties.addValue(QStringLiteral("lazy_test"), QStringLiteral("1"));
@@ -736,7 +736,7 @@ int main(int argc, char **argv)
check(out.open(QIODevice::WriteOnly), "copy written");
out.write(document.toByteArray(4));
out.close();
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
qputenv("QET_LAZY_FOLIOS_TRACE", "1");
static int built_late; built_late = 0;
const QtMessageHandler previous = qInstallMessageHandler(
@@ -834,9 +834,9 @@ int main(int argc, char **argv)
std::printf(".qetz folio added, moved, removed: %d folios built\n",
unbuilt - shuffled.unloadedFolioCount());
check(shuffled.unloadedFolioCount() == unbuilt, "adding, moving and removing a folio builds no other");
qunsetenv("QET_LAZY_FOLIOS");
qputenv("QET_EAGER_FOLIOS", "1");
QETProject usual_shuffled(zipped);
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
shuffle(usual_shuffled);
check(folioRows(shuffled) == folioRows(usual_shuffled), "folios' rows after a move as when built");
}
@@ -923,7 +923,7 @@ int main(int argc, char **argv)
check(changed.writeContainerFile(changed_path, &error), "saved after the change");
std::printf(".qetz symbol on folio %d changed by a script: %d folios built, %d by saving\n",
folio_index + 1, 0, unbuilt - changed.unloadedFolioCount());
qunsetenv("QET_LAZY_FOLIOS");
qputenv("QET_EAGER_FOLIOS", "1");
const QString usual_path = output + "/changed-usual.qetz";
{
QETProject usual_changed(zipped);
@@ -932,7 +932,7 @@ int main(int argc, char **argv)
check(usual_changed.writeContainerFile(usual_path, &error), "saved after the change when built");
}
QETProject changed_back(changed_path), usual_back(usual_path);
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
check(sortedLines(changed_back.toXml().toString(), path) == sortedLines(usual_back.toXml().toString(), path),
"a symbol changed through the database saved as when built");
check(QetScriptApi(&changed_back).elementInfo(folio_index, uuid, "comment") == value, "the change saved");
@@ -989,9 +989,9 @@ int main(int argc, char **argv)
std::printf(".qetz saved untouched: %d of %d folios not built before, %d after\n",
unbuilt, int(folios.size()), untouched.unloadedFolioCount());
check(untouched.unloadedFolioCount() > 0, "saving an untouched .qetz does not build every folio");
qunsetenv("QET_LAZY_FOLIOS");
qputenv("QET_EAGER_FOLIOS", "1");
QETProject kept_back(kept_path);
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
check(kept_back.toXml().toString() == eager.toXml().toString(),
"a .qetz saved without building holds the project");
@@ -1006,14 +1006,14 @@ int main(int argc, char **argv)
//read back too: what a save and a reading do to a project is
//not what is checked here
const QString usual_path = output + "/edited-usual.qetz";
qunsetenv("QET_LAZY_FOLIOS");
qputenv("QET_EAGER_FOLIOS", "1");
{
QETProject edited_usual(path);
edit(edited_usual, busiest);
check(edited_usual.writeContainerFile(usual_path, &error), "edits saved with every folio built");
}
QETProject edited_back(edited_path), usual_back(usual_path);
qputenv("QET_LAZY_FOLIOS", "1");
qunsetenv("QET_EAGER_FOLIOS");
check(sortedLines(edited_back.toXml().toString(), path) == sortedLines(usual_back.toXml().toString(), path),
"an edited .qetz saved without building holds what the edits made");
//Each symbol's links as saved, partners on folios not built
+1 -1
View File
@@ -328,7 +328,7 @@ private slots:
env.insert(QStringLiteral("QET_ENABLE_SCRIPTING"), QStringLiteral("1"));
env.insert(QStringLiteral("QET_CHECK_ELEMENT_INFO_STORE"), QStringLiteral("1"));
if (eager) {
env.remove(QStringLiteral("QET_LAZY_FOLIOS")); //every folio built on opening
env.insert(QStringLiteral("QET_EAGER_FOLIOS"), QStringLiteral("1")); //every folio built on opening
}
env.insert(QStringLiteral("HOME"), home);
env.insert(QStringLiteral("XDG_CONFIG_HOME"), home + QStringLiteral("/config"));