canon sync rewrites the managed block of CMakeLists.txt from .canon.toml,
for after either was edited by hand. It prints a unified diff of the
change (also with --dry-run), writes only CMakeLists.txt so comments in
.canon.toml survive, does nothing if the block already matches, and
warns when the build will still fail because .canon.toml declares files
that do not exist. doctor's hand-edited-block warning now points to it.
- diff: a small line-based unified diff, no external tools
- tests: a sync scenario (hand-edited manifest, --dry-run leaves the file
untouched, sync from a subdirectory, no-op second run, hand edits in
the block replaced); unit tests for plan_sync and unified_diff
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every generated source file, README.md and .gitignore now comes from a
template that a file of the same name can replace:
- <project>/.canon/templates/ for that project, which wins over
- ~/.config/canon/templates/ ($XDG_CONFIG_HOME respected) for all
projects; canon new reads only these
canon templates lists each template, where it comes from and the
placeholders it can use. canon templates export [<file>...] [--user]
copies built-in texts as a starting point and never overwrites.
Overrides are checked strictly: an unknown file name or a placeholder
the template does not provide is an error naming the file; hidden files
are ignored. Generators take a template_set, so they stay pure.
Also:
- executor: a symlink to a directory counts as a directory (macOS /var,
linked config directories)
- plan: add_directory stops at the filesystem root
- project: find_project_root, shared by load_project and templates
- tests: a templates scenario; scenarios run canon with their own empty
XDG_CONFIG_HOME so personal templates cannot affect results
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- add target lib|exe <name>: another library or executable in a source
directory named after it (P1204R0's rule applied per target); a new
executable links the project's library
- add test <name>: tests/<name>/driver.cpp for a library, or a run of an
executable, with --arg and --expect
- add dep <dependency>: link a library of this project (no cycles, no
executables) or an installed package's imported target such as
fmt::fmt, adding its find_package()
- doctor: read-only check of the files against .canon.toml and the
P1204R0 layout; errors for missing declared files or broken markers,
warnings for unbuilt sources, undeclared tests, a hand-edited managed
block, .h/.cc extensions and include/ or src/ directories
- every add command takes --target; the CLI rejects options a command
does not take
- manifest: packages, test args, and validation of target names, shared
source directories and dependencies
- templates moved to canon/templates.hpp
- tests: multi-target and exe-tests scenarios; every scenario ends with
canon doctor; CANON_CHECK accepts expressions containing commas; the
CLI test no longer reads a destroyed temporary
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
canon add module <path> creates <stem>/<path>.hpp, .cpp and .test.cpp
(--no-test skips the test), records the module in .canon.toml, adds the
source to the project's target and re-renders the managed block of
CMakeLists.txt. canon add unit-test adds the test later. Both work from
any directory inside the project.
- toml: a reader for the TOML subset canon writes, with line numbers in
errors, so canon stays dependency-free
- manifest: strict parsing (unknown keys, wrong types, bad references)
- project: finds .canon.toml by walking up from the current directory
- plan/executor: update_file refuses to write if the file changed after
it was read, and the report skips directories that already exist
- tests: shared scenarios drive both the golden and end-to-end tests;
goldens now live in tests/golden/<scenario>/
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
canon new lib|exe creates a project following P1204R0 (Canonical Project
Structure) with a .canon.toml manifest and a CMakeLists.txt whose managed
block is rendered from that manifest.
Generators return a plan; the executor checks every operation before
writing, so conflicts write nothing and --dry-run writes nothing.
Tests: unit tests next to each source file, golden copies of generated
projects, and an end-to-end build of both project kinds.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>