* Camera profile: Sony ILCE-7RM5 (α7R V)
* Camera profile: register the bundled ILCE-7RM5 profile
* Camera profile: attribution for the ILCE-7RM5 profile
* Camera profile: list ILCE-7RM5 among the built-in profiles in the README
* Camera profile: list ILCE-7RM5 in the Simplified Chinese README
* Camera profile: list ILCE-7RM5 in the Traditional Chinese README
* Camera profile: ILCE-7RM5 calibration set used the Standard creative style only
Preserve current main, adapt frame/input and IME handling, and keep library
check results stable across layout passes. Include the matching Nix font lock
and reviewed attribution changes.
Lightroom Classic's keyboard shortcut page lists Option+0 / Option+Shift+0
(Alt+0 / Alt+Shift+0 on Windows) for cycling forward and backward through
the keyword sets; LightCraft had no key or command for it. Next Keyword
Set (keyword.nextSet, Alt+0) and Previous Keyword Set
(keyword.previousSet, Alt+Shift+0) make the set after or before the
current one current, in the Keyword Set menu's order: Recent Keywords,
then the saved sets. The keys wrap around at either end, and Alt+1 to
Alt+9 then apply the new set's keywords.
The two command labels have rows in every catalog. The KEYC-METADATA and
LRC-LIB-KEYWORDS rows, docs/ui-parity.md and docs/library-shortcuts.md
list the keys.
Copy Metadata and Paste Metadata had no shortcut. They now use
Cmd+Option+Shift+C and Cmd+Option+Shift+V on macOS and
Ctrl+Alt+Shift+C and Ctrl+Alt+Shift+V on Windows and Linux, the keys
Lightroom Classic's keyboard shortcut page lists for copying and
pasting metadata in the Library module. Both keys also work when
Windows and Linux deliver them as clipboard events. The KEYC-METADATA
row now lists the keys LightCraft binds (Cmd+S, the two new keys and
Alt+1 to Alt+9 for keyword sets) and every other key of that table
that is still missing. Gap 28 in docs/gaps.md and the Library keys in
docs/ui-parity.md list the two new keys.
The template file tests now create their folder through a Scratch guard
that removes it when the test ends, including when an assertion fails,
as tests_folders.rs and tests_slideshow_export.rs do.
print.template.save, delete and import changed the template list before
saving the preferences, and left the change in place when the save failed.
A retried import then saw its own unsaved copy and stored another one as
"Name (2)". The list now goes back to what it was when the save fails, as
library.holdView and the slide templates do.
The slideshow always advanced on its own after the slide duration.
The new Manual slideshow setting (Settings > Slideshow > Playback, or
manual in slideshow.playback and view.slideshow) keeps each slide, the
intro and the ending up until the right or left arrow or the control
bar changes it. Space, Esc, random order and repeat work as before.
Exports still use the slide duration. The setting is saved with the
library and in slideshow templates; a template without it reads as off.
The Print dialog's templates could be saved, applied and deleted, but
not moved to another library or another computer. Each saved template
now has an Export… button that writes it to a .lcprint file, and
Import… beside Save adds templates from such files.
print.template.export {name, path} writes {format, version, name,
settings}. print.template.import {path} reads at most 256 KB, checks
the format, version, name and every setting as a saved template's
settings are checked, drops cell photos and guides, and adds the
template under its name, or under "name (2)" and so on when the name is
in use. The buttons appear where the host provides open and save
dialogs: the desktop app does, and the web build does not.
CodeRabbit on #2689 (head 496291276):
- `cull` takes the view it hands on from before ending an open drag, so the
drag's own commit can't change it first. (In practice the view already
follows the drag's preview, so the photo is out of it mid-drag either way;
this is the order every caller should use.)
- LR-BEHAV-LOCALE cites the commands of all 18 languages.
- Two 2026-10-21 revision rows moved above the 2026-10-20 ones.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CodeRabbit on #2689 (head 02743d187):
- crates/engine/src/cmd/library.rs: `cull` (#2327: a rating, flag or label
that takes the active photo out of the view) and `photo.delete` /
`photo.deletePermanently` moved the active photo without ending an open
interaction, unlike `step` and `library.select`: the drag stayed open with
no undo step. Each ends it now before its own change, so the drag is its
own undo step and comes first: undo brings the rating or the photo back,
with its edit, then the edit (Delete Permanently's undo restores the
edit too). Test an_open_edit_ends_before_the_selection_moves_on (rating,
delete, delete permanently) fails without the fix.
- docs/parity-checklist.md (LR-BEHAV-LOCALIZE) and docs/localization.md: list
every shipped language (Polish, and the others the row lacked; Italian in
the localization doc).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
library.source cleared the filter's library folder when a library folder became the source, but not the filter's album when an album did. LibrarySource::to_filter makes the album shown replace the filter's, so the grid was right; but the filter bar has no album chip, so the old album stayed in the filter unseen and narrowed the next source (All Photos, Picks). As for a library folder, the one shown now wins.
Found while testing crates/engine/src/cmd/library.rs:736
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Conflicts:
- apps/lightcraft/src/native_menu.rs: upstream's item swapping (macOS keys
given up for real, Help menu not swapped, Settings / Quit tracked) with
KEY-GRID's keymap-aware rows. `Item.label` stays the text the row shows
(native_item_presentation), so `Item::native_label` reuses it instead of
formatting it again; Settings / Quit store theirs through
display_item_label, as upstream's native_label did. No early return after
a rebuild (upstream).
- crates/ui-egui/src/i18n.rs: upstream's tests (#2729: one test per check
across languages, gaps reported, never a failure) plus the batch's two new
ones (dropped-photos notice, Polish counts); production code as merged.
- grid.rs, keyword_list.rs, masking.rs: the translation tests #2729 removed
stay removed; the batch's new keyword and segmenter tests stay.
- cmd/library.rs, ui-egui/src/lib.rs: both test modules, each with its
#[cfg(test)].
- xtask/src/main.rs: #2302's test_selected and upstream's translation_gaps.
- docs: tracker / gap rows take both sides' edits, headers list both sides'
changes, history rows of both sides newest-first. What's New: one section
per date, newest first (the batch had 10-22 above 10-23, and second 10-21
and 10-19 sections); no line lost.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tests_segment::a_failing_download_ends_with_an_error_and_never_blocks
checks that a second download request while one runs starts nothing. Its
local mirror answered 404 at once, so on a loaded runner the first
download could end before the second request, which then rightly started
a new one: the assertion failed (upstream's gate on #2689, 5223c8095). The
mirror's first answer now waits until the second request is made. A
300 ms pause between the two requests failed the test before and passes
now. Test code only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
doc_path::resolve uses craft_docpath::resolve_absolute; a path that resolves but is not absolute here is reported as not on this computer. Adds tests for Windows-form, GVFS-relative and colon-in-name paths, and a git-sources check in nix.yml and release.yml.
Conflicts:
- xtask/src/main.rs: upstream's runners (cargo test or nextest, no
examples, doctests apart, one wasm `cargo check --keep-going`) with
#2302's `ci --quick` on top: test_selected builds the same targets
(--lib --bins --tests), the wasm check takes the changed crates in one
call, the full test step is upstream's.
- apps/lightcraft/src/control_server.rs: upstream's `before` closure, with
the batch's no-delay sockets kept.
- docs/parity-checklist.md: LR-BEHAV-ACCESS from main (tests/it path),
LR-BEHAV-LOCALE / LR-BEHAV-LOCALIZE from the batch (Polish).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CI: dev profile keeps line tables for workspace crates and no debug info for dependencies
* Control server tests: persistent_requests_and_slow_replies_outlive_the_idle_read_timeout no longer races the idle timeout
Each request (and the closing half-shutdown) reaches the socket before the
worker reads, so on a slow machine only the reply waits outlast the 100 ms
idle timeout, as the test intends. The idle test sends its input the same
way, and the no-frames test allows 5 s instead of 2 s to give up.
* CI: one integration-test binary per crate
Each crate's tests/*.rs become modules of tests/it/main.rs (51 test files
into 13 binaries, plus 6 that stay their own). Inner #![cfg] attributes
move to the mod lines. Files that change state for the whole process keep
a binary of their own: codecs jxl_tail_heap and raw sr2_heap (dhat global
allocator), gpu shutdown, shutdown_first and memory, ui-egui shutdown.
Docs, comments and the GPU probe name the new paths and targets
(--test it <module>::); the CI report names an it binary's skips after
the crate.
* CI: tests under nextest, doctests apart, one wasm check
xtask ci runs the tests with cargo nextest run --lib --bins --tests when
cargo-nextest is installed, else cargo test with the same targets and a
one-line notice; doctests run after them with cargo test --workspace --doc.
The heif and hardware GPU steps use the same runner. Examples stay out of
the test build (clippy --all-targets still checks them). Concurrent tests
under nextest follow the RUST_TEST_THREADS cap (NEXTEST_TEST_THREADS).
The wasm check is one cargo check --keep-going over the same crates, and
clippy runs with --keep-going.
* CI: tests run under cargo test by default, nextest with LIGHTCRAFT_NEXTEST=1 (per-process scene cache)
The command sweep ran metadata.downloadPlaceNames with empty params, which
starts a real download from download.geonames.org into the settings folder.
The sweep now skips it (the command has its own loopback-server tests) and
asserts that no place names download was started.
Co-Authored-By: Claude <noreply@anthropic.com>