From bcdb33ad1dc6d965d21ddb4c825e739c32fc0493 Mon Sep 17 00:00:00 2001 From: DonislawDev Date: Sat, 14 Nov 2026 13:49:55 +0100 Subject: [PATCH 1/3] A run into a folder that holds an earlier one can be added beside it A second run into an output directory was refused, because the manifest of the first is the only record able to remove its files. In the window that meant choosing a new folder for every run. - engine.Options.NumberIfTaken: the run takes the smallest number at which every name it would write is free, its manifest's included, and carries it on every name - files-2_0001.pdf, invoice_0001-2.pdf, manifest-2.json. Counted from the manifest rather than from the names that collide, so a name an earlier record still lists is not written again while that record lies in the folder. The bytes are the ones an empty folder gets. - A number that makes a name too long for a file name refuses the run with NumberTooLongError, exit 5, rather than shortening a name that was asked for at the limit. - tfg generate --number-if-taken, off unless given. - The window: Add beside earlier runs under the output directory on the three work screens, on by default, carried between them and remembered with the folder. The output directory box and its two methods are one component instead of three copies. - The directory is listed once for choosing the number and for preflight. Measured on a plan of a million files into a folder of a hundred thousand: the cost of the number stays inside the spread of the timing, and a second run of a hundred thousand files took as long as the first. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 8 + README.md | 9 + internal/cli/errors.go | 7 + internal/cli/generate.go | 17 +- internal/engine/engine.go | 31 +- internal/engine/numbering.go | 274 +++++++++++++ internal/engine/preflight.go | 47 ++- internal/engine/record.go | 3 + internal/guard/branching_test.go | 2 +- internal/guard/formcolumns_test.go | 8 + internal/guard/guitext_test.go | 4 + internal/guard/mutation/entries.py | 7 + internal/guard/mutationcoverage_test.go | 17 + internal/guard/numbering_test.go | 378 ++++++++++++++++++ internal/guard/numberswitch_test.go | 113 ++++++ internal/guard/remembered_test.go | 36 ++ internal/guard/settingslot_test.go | 4 + .../screens/generate-chosen-by-key.png | Bin 96801 -> 99485 bytes .../screens/generate-chosen-by-key.xml | 27 +- .../testdata/screens/generate-chosen.png | Bin 96351 -> 99035 bytes .../testdata/screens/generate-chosen.xml | 27 +- .../guard/testdata/screens/generate-empty.png | Bin 100521 -> 103041 bytes .../guard/testdata/screens/generate-empty.xml | 27 +- .../testdata/screens/generate-focused.png | Bin 96814 -> 99497 bytes .../testdata/screens/generate-focused.xml | 27 +- .../testdata/screens/generate-hovered.png | Bin 109054 -> 111726 bytes .../testdata/screens/generate-hovered.xml | 27 +- .../screens/generate-menu-hovered.png | Bin 139436 -> 144372 bytes .../screens/generate-menu-hovered.xml | 27 +- .../testdata/screens/generate-menu-keyed.png | Bin 139629 -> 144572 bytes .../testdata/screens/generate-menu-keyed.xml | 27 +- .../guard/testdata/screens/generate-menu.png | Bin 139312 -> 144251 bytes .../guard/testdata/screens/generate-menu.xml | 27 +- .../screens/generate-pdf-settings.png | Bin 133279 -> 135765 bytes .../screens/generate-pdf-settings.xml | 27 +- .../screens/generate-refused-both.png | Bin 109616 -> 112108 bytes .../screens/generate-refused-both.xml | 27 +- .../screens/generate-refused-setting.png | Bin 122230 -> 124881 bytes .../screens/generate-refused-setting.xml | 27 +- .../testdata/screens/generate-refused.png | Bin 125608 -> 128129 bytes .../testdata/screens/generate-refused.xml | 27 +- .../screens/generate-switch-by-key.png | Bin 96599 -> 99233 bytes .../screens/generate-switch-by-key.xml | 27 +- .../guard/testdata/screens/generate-typed.png | Bin 98966 -> 101486 bytes .../guard/testdata/screens/generate-typed.xml | 27 +- .../testdata/screens/generate-unchecked.png | Bin 96134 -> 99063 bytes .../testdata/screens/generate-unchecked.xml | 27 +- internal/guard/testdata/screens/generate.png | Bin 96252 -> 98936 bytes internal/guard/testdata/screens/generate.xml | 27 +- .../testdata/screens/preset-many-settings.png | Bin 167509 -> 171359 bytes .../testdata/screens/preset-many-settings.xml | 25 +- .../testdata/screens/preset-menu-setting.png | Bin 176664 -> 178284 bytes .../testdata/screens/preset-menu-setting.xml | 25 +- .../guard/testdata/screens/preset-menu.png | Bin 124279 -> 128172 bytes .../guard/testdata/screens/preset-menu.xml | 25 +- .../guard/testdata/screens/preset-refused.png | Bin 137243 -> 141034 bytes .../guard/testdata/screens/preset-refused.xml | 25 +- internal/guard/testdata/screens/preset.png | Bin 127638 -> 131543 bytes internal/guard/testdata/screens/preset.xml | 25 +- .../testdata/screens/recipe-contents.png | Bin 136302 -> 140091 bytes .../testdata/screens/recipe-contents.xml | 43 +- .../testdata/screens/recipe-on-a-preset.png | Bin 137379 -> 141223 bytes .../testdata/screens/recipe-on-a-preset.xml | 43 +- .../recipe-refused-with-one-batch-filled.png | Bin 178390 -> 178393 bytes .../recipe-refused-with-one-batch-filled.xml | 51 ++- .../guard/testdata/screens/recipe-refused.png | Bin 163723 -> 167651 bytes .../guard/testdata/screens/recipe-refused.xml | 43 +- .../testdata/screens/recipe-two-batches.png | Bin 137911 -> 137936 bytes .../testdata/screens/recipe-two-batches.xml | 51 ++- internal/guard/testdata/screens/recipe.png | Bin 127128 -> 131095 bytes internal/guard/testdata/screens/recipe.xml | 43 +- internal/guard/window_test.go | 28 -- internal/gui/run_cgo.go | 6 +- internal/gui/text/locale/en.json | 10 + internal/gui/text/locale/pl.json | 2 + internal/gui/text/locale/said/en.json | 10 + internal/gui/text/locale/said/pl.json | 2 + internal/gui/text/screens.go | 8 +- internal/gui/window/closing.go | 6 +- internal/gui/window/destination.go | 82 ++++ internal/gui/window/generate.go | 31 +- internal/gui/window/open.go | 18 +- internal/gui/window/preset.go | 32 +- internal/gui/window/recipe.go | 29 +- internal/gui/window/remembered.go | 15 + internal/gui/window/runoffers.go | 10 +- 86 files changed, 1853 insertions(+), 232 deletions(-) create mode 100644 internal/engine/numbering.go create mode 100644 internal/guard/numbering_test.go create mode 100644 internal/guard/numberswitch_test.go create mode 100644 internal/gui/window/destination.go diff --git a/CHANGELOG.md b/CHANGELOG.md index a76a81ac..2f388397 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,14 @@ because it turns other people's test suites red. ### Added +- **Generate into the same folder again.** A run into an output directory + that already holds an earlier run is added beside it: every name of the run, + its manifest's too, gets a number, such as `files-2_0001.pdf` and + `manifest-2.json`, and nothing already there changes. In the window this is + Add beside earlier runs under the output directory, on unless you turn it + off. On the command line it is `--number-if-taken`. When the number would + make a name too long for a file name, the run is refused with code `5`. + - **Drop a folder or a file onto the window.** A folder dropped onto Single batch, Presets or Several batches becomes the output directory. On the Tools screen it goes into the box of the chosen tool when the tool takes that diff --git a/README.md b/README.md index 6795705c..f1107301 100644 --- a/README.md +++ b/README.md @@ -368,6 +368,7 @@ tfg generate --format txt --size 1mb settings come from the flags | `--name