A keyword with a line break in its name split the export toast in two.
Names left out now show escaped (Line\nbreak).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Export now leaves out only what it must, and its counts are exact:
- A name starting with a byte-order mark is left out. On the first
line, the reader would take the mark for the file's own.
- A synonym in braces is written, since it reads back. An empty
synonym, or one that repeats another in a different case, is
skipped quietly, as the reader would drop it anyway.
- keyword.export counts and checks for Capture One the keywords it
actually wrote, now returned with the text. It used to guess from
the lines, so a name starting with a brace was missed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What's New now says that an unreadable list names its line or asks for
UTF-8, and that export names any keyword it had to leave out.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Se añadieron 1 palabra clave" and "1 Stichwort/Stichwörter" didn't read
right. The counts now follow a label ("Palabras clave añadidas: 1",
"Stichwörter hinzugefügt: 1"), which reads right for any number, as the
Portuguese toasts already do.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A list that couldn't be written, for example to a folder that's gone,
used to fail silently from the menu. Its error now shows as a toast, as
Import Keywords…'s already does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Like the other menu commands, Auto-Tag from Tracklog stamped its toast
with a throwaway context whose clock starts at zero. A while into a
session, the toast had already expired by the time it was drawn. It now
uses the app's context. Lightroom catalog import gets the app's context
too, so its background work repaints the window it belongs to.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A list saved as UTF-16, as Windows' Notepad can, now says to save it as
UTF-8 instead of only "not UTF-8 text". Text passed to keyword.import is
capped at 16 MB, like a file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The list format can't hold some names. A name in brackets or braces
would read back as a left-out keyword or a synonym. A line break or a
leading space would split it or break the indentation. A keyword nested
deeper than 64 levels won't read back either. These keywords, and those
inside them, are now left out of the file. keyword.export names them as
`unwritable`, and the toast says which.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reading a list looked each line up in all the lines before it, and
importing looked each keyword up among every photo's keywords: a
40,000-line list into a 20,000-photo library took nearly two minutes.
Both now use an index built once, and the same import takes about a
second.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Classic Mac line ends (a lone carriage return) are lines: a whole
file used to become one keyword holding them.
- Indenting with spaces is refused at its line: the levels are tabs,
and space-indented files (hand edits, editors that turn tabs into
spaces) used to come in flat without a word.
- Control characters in a name, and "|" in a synonym, are refused.
- A keyword repeated in another case keeps its first spelling for the
keywords inside it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The parity row covers File ▸ Import / Export Keywords… and the apps
that share the format, and lists what stays open (IPTC keywords in
exported files, hierarchy from other apps' XMP fields); What's New
explains it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The File menu (beside the presets) imports a keyword list file
(Lightroom Classic's, Capture One's, Photo Supreme's .utf8) and exports
LightCraft's, with native file dialogs off the UI thread like the
other file commands; the desktop app gives the synchronous ones too.
Import says how many keywords it added and how many gained synonyms;
export says how many it wrote and names the keywords Capture One won't
import (; , < or > in a name).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The UI's menu commands made their toasts with a fresh egui context,
whose clock starts at 0, while the app checks a toast's end against its
own clock: once the app had run a few seconds, every such toast (Auto
Advance On, presets imported or exported, the keyword painter, …) was
over before it was drawn. They use the app's context now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `keyword.export {path?}` writes the keyword list file (Lightroom
Classic's format, which Capture One, Photo Supreme and Bridge read),
or gives its text, and names the keywords Capture One's importer
refuses (none of ; , < > may be in a list it reads).
- `keyword.import {path | text}` reads one (Photo Supreme's Formatted
Vocabulary File too) as one undo step → {added, updated}. A line it
can't read is named and nothing is taken; a file larger than 16 MB or
not UTF-8 is refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Photo Supreme's Formatted Vocabulary File (Data ▸ Export to Formatted
Vocabulary File) turns out to be Lightroom Classic's keyword list
format: plain text with Windows line ends, a top-level category in
square brackets, keywords a tab further in at each level. A test with
a file of that shape pins it down; a real export of 118 keywords read
and wrote back line for line. (Photo Supreme reads Lightroom keyword
files too: Data ▸ Import from Lightroom Keywords file.)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lightroom Classic's keyword list files (Metadata ▸ Import / Export
Keywords): a keyword a line, those inside it one tab further in, a
synonym in braces on a line of its own under its keyword, a keyword
left out of export in square brackets.
- `Catalog::keyword_list_text` writes the whole tree that way, by name.
- `keywords::parse_keyword_list` reads one: Windows line ends, a
byte-order mark and blank lines are fine; a line it can't read (two
levels down at once, a synonym of nothing, a "|" in a name, nesting
past 64 levels: a file is input) is an error naming its line.
- `Catalog::import_keywords_ops` adds the keywords the library doesn't
have, with the file's attributes and in the library's spelling of
the levels it has; those it has keep their attributes and gain the
file's synonyms. One undo step.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Set name" (Edit Keyword Set, Save Keyword Set) read 标签集名称 /
標籤集名稱, the colour label sets' term; it is 关键字集名称 /
關鍵字集名稱, as the rest of the dialog says. "Edit Set…" says what it
edits: 编辑关键字集… / 編輯關鍵字集….
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Edit Set… on Recent Keywords saves a new set (`new: true`): a name
another set has is refused, where it used to replace that set.
- The dialog checks names before saving and says why in the user's
language ("There is a keyword set “…” already"; Recent Keywords is
built in), instead of showing the engine's message.
- A set deleted while its dialog was open is saved again, as a new set,
rather than refused with no way out but Cancel.
- Save as a new set (Lightroom Classic's Save as New Preset) keeps the
edited set and saves the edits under the new name.
Russian gets "Recent Keywords", which showed in English.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Saving compared set names by any letter's case while using, deleting
and the current set compared ASCII case only: "été" saved over "ÉTÉ"
but couldn't use or delete it. Every set command (and Recent Keywords)
now compares names one way, as keywords are compared.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Saving Recent Keywords as a set under the name of an existing one
(Edit Set… on Recent Keywords) replaced that set's keywords without a
word, while renaming onto a taken name was refused. `keyword.saveSet`
takes `new: true` for a set that must be new, and refuses a name
another set has.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`keyword.saveSet {name, replace}` without `keywords` took the current
set's keywords, so renaming a set that wasn't current gave it another
set's nine. The keywords default to the renamed set's own now (the
current nine only for a new set), and an empty `replace` is no rename.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The nine fields took their width from what the dialog had while it
found its size: the first two columns came out squeezed ("ceremony"
showed "ceren") and the third wide. They are now equal columns of a
set width.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Keyword Set menu gets Edit Set… (Lightroom Classic's Edit Keyword
Set): the set's name and its nine keywords, one field per ⌥ key, typed
in place. Editing Recent Keywords and naming them saves a new set and
makes it current; editing a named set renames it in its place. An
empty field is an empty slot, shown as an idle button so the others
keep their keys. Return in any field saves; a set without a name says
so and the dialog stays open. Russian gets "Set name", and the label
check covers the new labels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
For Edit Keyword Set (Lightroom Classic's), `keyword.saveSet`:
- keeps each slot in its place: an empty one ("") is an empty slot, so
the keywords after it keep their ⌥ keys (empty ones were dropped and
the rest moved up); trailing empty slots go, nine at most;
- holds each keyword once, whatever its case: a second one leaves its
slot empty;
- with `replace`, renames that set in its place among the sets and
keeps it current; a name another set has is refused.
⌥ on an empty slot does nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
German says "Es werden keine Stichwörter exportiert", the natural word
order; Japanese names the view "書き出されるキーワード" (the keywords
that will be exported) rather than the vaguer "書き出される内容".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lightroom Classic's Keywording box has three views; the box had two.
The switch now offers Keywords, & Containing (the selection's keywords
with the keywords containing them, flat and read only) and Will Export,
the two read-only views cached per selection. The label check covers
the box's other labels passed through variables too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The box emptied itself on Esc, on top of the shared field's own undo of
the edit: text left there by an earlier edit (ended by clicking away)
went too. Esc now gives back what the box held before the edit, as
every text field does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`chips_stay_on_one_line` held by construction once chips were drawn at
a fixed height with their × on their own line. It now checks that every
chip is on one line inside the panel and that none overlaps another,
with a keyword longer than the panel among them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drawn as one widget, a chip and its × lost the names a button gave
them: screen readers met unlabeled buttons. The chip is now named after
its whole keyword (even when cut short on screen) and the × "Remove
“…”". Both answer under ids made from their keyword rather than their
place in the row, so a chip's open menu stays with its keyword when the
chips change underneath it (an undo, a sync).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A photo listed twice in the selection counted twice, and an id the
library doesn't have counted in "of": the chips, Will Export and the
Keyword List's tick boxes now count the distinct selected photos.
- The chips looked each keyword's spelling up by scanning every photo
(178 ms with 20,000 photos and 2,000 keywords selected, at every
change while selected): they now take the keyword list's spelling
(`Catalog::listed_path`) or the first one seen, 26 ms.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A chip too long for its row was cut with the file-path shortener, which
keeps the start: "Places › Portugal ›…" lost the keyword's own name and
the asterisk of a partial one. `chip_label` now cuts from the front
("…Lisbon › Belém tower *"). A chip also had two tooltips (its whole
name, and how many selected photos have it); it has one with both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`keyword.toggleFromSet` checked whether every target photo had the
keyword by ASCII case, while the set's buttons and the rest of the
keyword code match any letter's case: with "ÄRZTE" and "ärzte" on the
photos the button showed on, but ⌥N added the keyword (a no-op) instead
of taking it off, so it could never be toggled off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keyword commands act on the selected photos, or on the active photo
when the selection is empty (`Session::targets`), but the Keywording
box, the keyword set's buttons, the suggestions and the Keyword List's
tick boxes read the selection only: with just an active photo the box
showed nothing while typed keywords went to it. They now all use the
photos the commands use.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The keyword rows of the parity tracker describe the box and the chip
menu; What's New explains the chips, Will Export and what follows the
selection.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A chip was a frame laid out in what was left of its line: one that
didn't fit wrapped its own text, down to a letter a line, and pushed
its × to the next line. A chip is now one widget measured before it is
placed (its name cut short to fit the row), so the row moves it whole
to the next line; the Will Export names alike.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Suggestions were worked out from the active photo's keywords: a keyword
it had wasn't suggested though other selected photos lacked it. They
now leave out only the keywords every selected photo has, and build on
those for keywords used with them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Keyword to paint" gets the Cut / Copy / Paste / Select All menu and
Esc, and Return starts painting as the Paint button does. It stays
fixed while painting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lightroom Classic's Keywording box can show the keywords that will be
exported rather than those entered. A Keywords / Will Export switch
under the box now does the same for the selection: the names exported
files carry as the keyword tag options say (a keyword left out of
export goes, parents and synonyms come), one only some of the photos
carry marked with an asterisk. Read only; cached per selection.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The nine buttons showed "on" when the active photo had the keyword,
while their ⌥1–⌥9 toggle acts on every selected photo. A button is now
on when every selected photo has its keyword, and marked with an
asterisk when only some do, as the chips are.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It gets the Cut / Copy / Paste / Select All menu (paste a list of
keywords from elsewhere), Return gives the keywords to every selected
photo as before, and Esc gives up what was typed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The chip menu offered Delete Keyword, which takes the keyword off every
photo in the library, beside "Remove from Photo". It now acts on the
selected photos only: Add to All Selected Photos (for a keyword only
some have), Remove from Selected Photos, Show Photos with Keyword, and
Edit Keyword Tag… (the Keyword List's dialog, for renaming too).
Deleting a keyword from the library is the Keyword List's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The chips at the top of the Keywords panel showed the active photo's
keywords, while adding and removing applied to every selected photo:
with several selected they misreported what the selection had. They
are now the keywords of every selected photo, each once whatever its
case (`panels::keywording`, cached per selection), and one only some
of them have is marked with an asterisk ("On 1 of 2 selected photos").
Only the × removes a keyword, from every selected photo: a click on
the chip itself used to remove it too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The parity row said Person shapes exported files: it is stored only.
It now also covers the list without a selection, the default parent's
reach (typed keywords too) and keywords' hierarchy on import. The
synonyms' doc no longer says search finds them, which it doesn't yet.
What's New follows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With nothing selected a tick box still offered "Add to Selected
Photos", and while a filter holds the levels open the triangle lit up
on hover though a click does nothing. Neither does now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The toast said every dropped photo got the keyword, those that had it
already included. It now counts the photos that didn't have it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lightroom Classic puts new keywords typed for photos inside the keyword
marked Put New Keywords Inside This Keyword; only + did here. The
Keywords panel's box now does too (`Catalog::typed_keyword`): a new
name goes inside the default parent, while a keyword the library has,
or a path typed whole, stays as typed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Russian had no "Person": the option showed in English (it reaches
`tr` through a variable). A test now checks that every label the
Keyword List passes that way is in every language's file.
- The merge confirmation's button said "Merge", which some languages
translate as merging photos (HDR, panorama): it says "Merge Keywords".
- Traditional Chinese uses 匯出 for Export, as everywhere else in the
file, not 轉存; "Export Containing Keywords" means the parent
keywords in both Chinese files (上層 / 上级), not "included" ones.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>