Commit Graph
104 Commits
Author SHA1 Message Date
RWoldbergandClaude Fable 5.1 a0c8a08020 craft-crw: Canon CRW (CIFF) raw decoder, moved from LightCraft with its clean-room record
The clean-room Canon CRW decoder written in LightCraft (crates/raw/src/vendor/crw.rs,
crw_tables.rs, branch clean-room-crw-format-decode, revision 70c755e4) becomes the shared
crate craft-crw: the CIFF heap container, the entropy coding derived by black-box analysis
(frozen code tables for selectors 0-2), sensor black and white levels, as-shot white
balance, orientation and the make/model/time records. Public types are the crate's own
(Error, Limits, Cfa, Rect, BlackLevel, Header, Image); the capture time is handed on as
Unix seconds so no calendar code lives here; LightCraft's shared plateau estimate is
copied as saturation_plateau. Algorithm, tables and thresholds are unchanged.

Tests: the ported synthetic round-trip, table-structure and hostile-input tests; a
proptest mutation sweep (tests/robust.rs); and tests/samples.rs, which pins the eleven
CC0 raw.pixls.us sample files (tests/samples.json: URL, SHA-256, licence) to the SHA-256
of the verified decode plus levels, white balance and metadata, so the port is proven
byte-identical to the LightCraft decode without redistributing the reference TIFFs.
scripts/fetch-crw-samples.py downloads the files outside the checkout; CRAFT_CRW_SAMPLES
and CRAFT_CRW_ORACLE point the tests at them. The crate builds for wasm32.

The whole derivation record (starting assumptions, plan with the maintainer's decisions,
source log, container and payload notes, derivation log, frozen format, verification,
colour/levels notes, private-corpus and chart notes, scripts, logs and the frozen table
JSON) moves verbatim to crates/crw/clean-room/ with a README that indexes it and maps the
LightCraft paths it cites; tools/gen_tables.py regenerates src/tables.rs from the JSON,
byte for byte.

Repository: .github/workflows/crw.yml (fmt, clippy, tests on Linux, Windows and macOS;
wasm check; the sample-file job with cached downloads), README and ATTRIBUTION rows,
NOTICE source provenance, docs/clean-room.md (the clean-room standard a format crate
follows here), and AGENTS.md expanded with the start-of-session steps, the new-crate
checklist, clean-room, assets and test rules; CLAUDE.md points at it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-26 08:20:01 -06:00
aiongg 8250aa62ae Merge branch 'lang-2-ui' into lang-3-fonts 2026-10-26 03:14:35 +00:00
aiongg 9d0a57ab1c Merge remote-tracking branch 'upstream/main' into lang-2-ui 2026-10-26 03:14:20 +00:00
aiongg ee4103fe78 Merge pull request #337 from aiongg/lang-1-text
craft-text: hyphenation, line-break segmentation, bidi and line breaking
2026-10-25 23:08:26 -04:00
aiongg 9f89fe8f6d Add craft-menu: one menu definition, native on macOS and an egui bar on Windows, Linux and web (#66)
* Add craft-menu: Mac menu-bar layout and native-menu driver

A platform-free menu model (built directly or from flat rows), the macOS
layout (app menu, Window, Help, system-key clash resolution, translatable
labels), and NativeMenu, which feeds a backend's key equivalents to egui as
key presses, runs Minimize and craft-quit's Quit, and re-syncs only when the
app's state changes. Generalised from PhotoCraft's native_menu.rs.

* craft-menu: macOS menu bar through muda

* craft-menu: clipboard keys, layout-assigned shortcuts, Hide Others and atomic rebuilds

* craft-menu: menu key equivalents run while a text field has the keys

* craft-menu: commands as CommandRef, item kinds, craft-keymap chords

Items and rows run a craft_keymap::CommandRef and take a craft_keymap::Chord
shortcut; crates/menu/src/chord.rs is gone. Native ids are the command's key,
made unique with #2, #3 when a command is shown twice. Item.checked becomes
ItemKind { Plain, Check, Radio } (radio shows as a check item on macOS).
The built-in items' commands are Builtin::{Hide, HideOthers, Minimize, Quit}.
MenuRole gains Edit, View and Other; tag_submenu finds its menu by role.
While text editing, the keys left to the field are the clipboard keys and
craft_keymap::text_editing_chords. Adds the Platforms, Document and Gate types
(data only) and MenuBar::documents.

* craft-menu: Gate::allows, the one rule for what may run from the menus

* craft-menu: Windows, Linux and web layouts, documents in Window, keymap adapter

layout(bar, Target, options) dispatches to mac_layout, desktop_layout or
web_layout. Every layout drops what the target's Platforms leave out and lists
MenuBar::documents as radio items last in the Window menu (ItemRole::Document
is gone). Windows and Linux put About in Help, Settings in Edit as
Preferences and Quit in File (Exit on Windows); the web layout has no Quit and
takes the browser's own shortcuts off the items, reporting clashes. tidy drops
empty submenus.

apply_keymap sets shortcuts and toggle check items from a craft-keymap Keymap;
apply_state sets enabled and checked per frame.

* craft-menu: the egui-drawn menu bar for Windows, Linux and the web

* craft-menu: gate, command hook and one muda handler for the native menu

- NativeMenu::set_gate: app items greyed in place while modal or recording a
  shortcut; take_clicks drops clicks the gate forbids when they are taken.
  While recording, key equivalents reach egui as plain key presses.
- NativeMenu::on_command: a hook called from the menu event handler for each
  allowed app click; take_clicks still returns every command.
- Dispatch, shared between the driver and the backend's handler
  (Backend::attach replaces Backend::set_text_editing).
- Only Cmd or Ctrl chords become key equivalents; other shortcuts are not
  shown natively (building an attributed title needs unsafe objc2 calls).
- mac: one muda event handler per process, routed to the latest install;
  mac::install_app_menu ports craft-quit's minimal app menu onto it.
- craft_quit::install_app_menu is deprecated in favor of
  craft_menu::mac::install_app_menu.

* craft-menu: the bar takes Target, README section and NOTICE credit

* craft-menu: bar tests beside the layout and native ones; only a click outside closes the menus

* craft-menu: clippy (complex types, Copy clones, elided lifetimes)

* craft-menu: keyboard access to the egui bar

A tap on Alt alone or F10 focuses the bar, Alt+letter opens a menu and
a letter in an open menu runs or opens the row with that mnemonic, as
in a Windows menu bar. Mnemonics are assigned per level from the shown
labels, underlined only while the keyboard drives the bar, and a label
without an ASCII letter shows its English letter after it ("文件(F)")
through the optional english hook. Preferred letters come from
MenuBarUi::mnemonics. A Mac target has none, and a dialog or the
shortcut recorder keeps the keys. Ported from PhotoCraft's menu_keys.rs
and menu_keys_tests.rs.

* craft-menu: one installer or the other; sort mnemonics before checking uniqueness

* craft-menu: egui 0.37

* craft-menu: text fields keep their Edit items; web names by the browser's system; sync per frame; stable check kinds; handled hook clicks

* craft-menu: sync reports a clash change on an unchanged bar
2026-10-25 21:59:22 -04:00
aiongg 1f1c1ab490 Merge branch 'lang-2-ui' into lang-3-fonts 2026-10-26 01:55:48 +00:00
aiongg fdd6ad530e Merge remote-tracking branch 'upstream/main' into lang-2-ui
# Conflicts:
#	Cargo.lock
2026-10-26 01:55:42 +00:00
skylar taylor-barrick cb53221767 fix(print): stop relying on inflate error output; bump miniz_oxide to 0.9 (#348)
* fix(print): do not treat early inflate errors as partial output

* chore(deps): bump miniz_oxide to 0.9
2026-10-25 20:37:49 -04:00
skylar 8e42b9ff4e fix(print): keep miniz_oxide at 0.8 2026-10-25 16:52:57 -06:00
skylar ce020c5811 chore(deps): bump roxmltree, miniz_oxide, serde_json, fixed_decimal
craft-print: roxmltree 0.20 -> 0.21 (locked 0.21.2, fixes a stack
overflow on deeply nested XML) and miniz_oxide 0.8 -> 0.9.
Lockfile only: serde_json 1.0.154, fixed_decimal 0.7.3.
2026-10-25 16:35:43 -06:00
aiongg 06a4ec194a craft-font-catalog, craft-font-store and craft-font-manager: installed fonts, the font store and the Font Manager panel 2026-10-25 19:09:33 +00:00
aiongg 3c574ddc61 craft-ui: interface fonts, text direction, IME composer, localized widgets and screen testing
craft-fonts-build gains Embed::serve (served faces for web builds) and the coverage module that craft-ui's fonts use.
2026-10-25 19:08:59 +00:00
aiongg acf6f79739 craft-text: hyphenation, line-break segmentation, bidi and line breaking 2026-10-25 19:08:20 +00:00
Dylan M. Taylor 6ff2a458b4 Merge remote-tracking branch 'storytold/main' into migration/egui-037-20261024 2026-10-25 12:54:10 -04:00
skylar taylor-barrick e5da4a7a68 M0: reconcile shared UI and updater changes with egui 0.37 2026-10-25 17:07:55 +01:00
Dylan M. Taylor fcd3441993 fix(update): drop the dirs crate and move to zip 9
dirs pulls in option-ext (MPL-2.0), which the apps' cargo-deny licence policy rejects, and zip 8.6 carries RUSTSEC-2026-0367, -0368 and -0369. The per-user folders now come from the environment.
2026-10-25 11:56:58 -04:00
aiongg e9824219c7 window: title_bar module for app-drawn title bars (#316)
* window: title_bar module for app-drawn title bars

The empty part of an app's top strip moves the window on drag and follows
the macOS title-bar double-click setting. A control on the strip or an
in-window Order::Middle panel over it (floating docks, egui::Window) keeps
its own drag: window_movable is false there and, on macOS, sync_movable
sets NSWindow.movable from it. No gesture acts on the window in full
screen.

* window: empty_area returns the empty area's response
2026-10-25 09:49:44 -04:00
Dylan M. Taylor fe61243ebf feat(update): add craft-update crate for release checking, install, and self-updating (#311)
* feat(update): add craft-update crate for release checking, install, and self-updating

* fix(update): provide non-windows stub for finish

* fix(update): address CodeRabbit review feedback on craft-update

* feat(dialog,self_update): enhance prompt styling, support standalone self-updates

* fix(update): make startup prompt modal with Escape, skip non-file tar entries
2026-10-25 09:32:22 -04:00
skylartaylor 650b1c0b05 M037: reconcile current libraries and preserve native IME reset acknowledgements 2026-10-25 01:58:55 +02:00
skylartaylor b282cb2d29 egui037: Reconcile shared UI pins with reviewed PDF updates 2026-10-25 01:29:13 +02:00
aiongg 5b609acb6f jpeg: make the decoder a standalone crate
Own Error and Limits types, a Decoded image with typed samples, a
public frame() probe for routing, and the tests adapted to them.
2026-10-24 20:43:14 +00:00
aiongg 24a472717a prepress: transparency flattener (flatten feature) (#194)
* hayro-interpret: ink colors, overprint and font bytes for the flattener

Local patches for craft-prepress's PDF-in adapter, labeled Craft patch
(flatten) and listed in vendor/README.craft-reader.md:

- Device::set_overprint and Device::set_isolated, called where the
  blend mode is set and after an isolated group is pushed.
- Color::ink_paint, ColorSpace::ink_space and ink_values: colors and
  image samples as the inks they print, without converting to RGB.
  RasterImage::with_inks gives native samples with Decode and Matte.
- OutlineFontData::embedded and index, and the CFF bytes of Type1C
  fonts, so text can be embedded again.
- The sh operator ignores /Background (ISO 32000-2 8.7.4.5.1).

* plate-test: flattened-page checks, image alpha and scenes F01, F02

- report::run_flattened separates each scene's page after a caller's
  flattener as well as the original, and structure::transparency lists
  what transparency a page still has. plate-test doesn't depend on the
  flattener.
- Scene images take an alpha channel, written as /SMask.
- F01: a partly transparent image over a flat fill; where its alpha is
  0 the fill keeps its exact inks (vectorcraft#2160).
- F02: art hidden under opaque fills leaves no trace after flattening
  (vectorcraft#2161).

* prepress: transparency flattener (flatten feature)

craft_prepress::flatten turns PDF pages with transparency into pages
without it, keeping inks, overprint and live text, for PDF/X-1a and
other output that can't carry transparency.

- pdf: reads a page into a display list in inks through hayro-interpret:
  paths, outlined strokes, clips, groups, soft masks, overprint, spot
  and DeviceN colors, images in their own color space, gradients,
  rasterized mesh shadings, tiling patterns and glyph runs.
- font: prepares the source fonts for embedding again (TrueType,
  OpenType, CFF wrapped as OpenType); others fall back to outlines with
  ActualText.
- geom: planar regions with the shapes that cover each one (linesweeper).
- compose: composites each region per ink (separable and non-separable
  blend modes, isolated and knockout groups, overprint per plate as ISO
  32000 defines it); regions under images, gradients and soft masks are
  marked complex.
- raster: complex regions as DeviceN images through plate mode, grid
  snapped with a one-pixel outset; flatten_page.
- write: writes the result with the vendored krilla; flatten_document
  writes every page into one PDF with the output intent, page boxes and
  fonts shared across pages when their bytes match.

The regions and the compositor are ported from VectorCraft (commit
c2b15982, crates/pathops and crates/engine/src/cmd/flatten.rs), credited
in the crate README. scripts/plate-check.sh --flatten separates every
scene's flattened page with Ghostscript (local only). CI runs
craft-prepress with all features.

* krilla: DeviceN /Colorants from PDF 1.3, NChannel attributes from 1.6 (patch 11)

* prepress: flatten_document output PDF version and PDF/X version

* prepress: format the PDF/X-1a flatten test

* krilla, craft-prepress: write GTS_PDFXConformance next to GTS_PDFXVersion

PDF/X-1a:2003 files carry GTS_PDFXVersion (PDF/X-1:2003) and
GTS_PDFXConformance (PDF/X-1a:2003). Krilla patch 12 adds
SerializeSettings::pdfx_conformance, and FlattenDocumentOptions passes it
through.

* krilla, craft-pdf, craft-prepress: carry the modification date over

Krilla patch 13 adds Metadata::modification_date, written as /ModDate and
xmp:ModifyDate in place of the creation date. craft-pdf's Metadata gains
modified, and flatten_document takes it from the source's ModDate.

* craft-prepress: count the print annotations a read leaves out

ReadReport::dropped_annotations counts the annotations a printer would
paint (Print flag, not Hidden, with a normal appearance) when
ReadOptions::annotations is false; FlattenTotals sums it.

* craft-prepress: degenerate groups rasterize without a soft mask

A group the region sweep fails on is clipped to its members' boxes, which
no other group's items reach, so the paper is its only backdrop. Its
image is written opaque, as the plates of the items over paper, and the
page keeps no transparency for PDF/X-1a.

* craft-prepress: write untouched JPEG images as they are

A DCT-encoded DeviceGray or DeviceCMYK image that krilla's JPEG
passthrough writes with the same meaning (8 bits, no decode parameters,
the default gray Decode or the inverted Adobe CMYK one) keeps its data
in ImageItem::jpeg, and the writer embeds it unchanged when the image
has no soft mask. Other images are still 8-bit Flate samples.

* craft-prepress: keep group members with no transparency above them

Groups are transitive by bounding box, so a background frame put all the
body text on it under a transparent object far away, and the text came
back as outlined fills. A member is now drawn as it is when it is opaque
and, in every region its shapes are in, only members kept this way are
above it. The region fills under it are the composite of the other
members, and it is drawn over them in paint order.

* prepress: keep the backdrop under elements of a knockout group

* prepress: rasterize complex regions thinner than a point

* prepress: mark flatten errors, reasons and reports non_exhaustive

* prepress: bound the items a tiling pattern fill expands into

Each of up to MAX_TILING_CELLS cells copied the whole cell content, and a
cell can hold many items or an expanded pattern of its own. A fill whose
cells would hold more than MAX_TILING_ITEMS items in all, counting groups,
masks and nested patterns, is read as an image.

* prepress: stroke solid past the dash budget

A dash pattern that cuts a stroke into more than 250,000 pieces is outlined
solid, with the estimate hayro's renderer uses.

* prepress: bound the sampling and memory of rasterized tiling patterns

Each pixel sampled every cell over it, which for a BBox far larger than
its step is millions of cells per pixel; past MAX_TILING_CELLS cells per
pixel the fill paints nothing, and below it the image resolution drops to
keep the samples within MAX_TILING_SAMPLES. The canvases also hold a value
per page ink, so their pixel limits shrink with the ink count to keep the
memory of CMYK canvases, and the canvas size uses checked arithmetic.

* prepress: mark the page reader's error and report non_exhaustive

* prepress: format the tiling tests

* prepress: CodeRabbit fixes: no nonzero overprint mode for images and shadings, count dropped tilings, widen the hhea ascender

* prepress: refuse DeviceN spaces past the output's colorant limit and regions past the separated spot inks
2026-10-24 16:15:41 -04:00
aiongg 95be650aba Merge upstream main into docking-batch 2026-10-24 12:55:36 +00:00
skylartaylor 8c05070a63 MIG-037: integrate current shared-library main and clarify performance reports
Preserve the reviewed current-main print/vendor changes, render the benchmark
font path as readable JSON, and document the implemented example harness.
2026-10-24 09:48:06 +02:00
aiongg 4238a2dd57 Merge upstream main into print-color
Conflicts: NOTICE, vendor/README.craft-reader.md and the hayro-interpret and
hayro-syntax SOURCE.json keep the ec0a965 provenance and add hayro-cmap
(a2ec27b) and hayro-postscript (crates.io 0.1.0). type0.rs keeps PdfCraft's
flat sample array with its 64-bit largest sample and main's 32-bit test.
Local sha256 values recomputed for the merged files.
2026-10-24 05:46:57 +00:00
skylartaylor 0f46902e32 Reconcile egui 0.37 with current shared libraries
Preserve the reviewed shared UI tree and the frozen app dependency commit while
bringing in current main. Port the new keymap UI APIs and use verified central
fonts in its strict UI tests and snapshots.
2026-10-24 07:20:20 +02:00
aiongg 8e074ac261 Merge #244: fade a dragged native window on macOS 2026-10-24 04:32:36 +00:00
aiongg a22c6d0c63 docking: a native window fades to half opacity while it is dragged, on macOS 2026-10-24 04:32:17 +00:00
aiongg 69a3ae83c5 Merge upstream main into docking-batch 2026-10-24 03:54:18 +00:00
aiongg 2eca9b3a53 pdf: vendor hayro-postscript and skip << and >> runs without recursion (#263)
hayro-postscript 0.1.0 is the token scanner hayro-cmap uses for the
CMap streams PDFs embed. Its object reader skipped each `<<` or `>>`
by calling itself again, so a stream holding a long run of `<` or `>`
bytes recursed once per pair and aborted the process with a stack
overflow.

Vendor the crates.io package unchanged and patch `object::read` to
skip those runs in a loop, returning the same next object as before.
Wire it in like the other Hayro crates: workspace exclude,
[patch.crates-io] entry, SOURCE.json with registry and local hashes,
the backend test script, NOTICE, ATTRIBUTION.md and the reader README.

Tests cover a million `<` and a million `>` bytes, `<< /A 1 >>` and
nested `<<<< /X >>>>` runs.
2026-10-23 23:31:35 -04:00
skylartaylor c488caa9fb egui037: add shared screenshot and text helpers 2026-10-24 05:25:10 +02:00
aiongg 2529d038b4 Merge #244: ui: floating panels in their own OS windows (native-windows) 2026-10-24 03:13:34 +00:00
aiongg 1ccdad9512 docking: Floating::with_id for layouts built in code; debug builds warn about rebuilt layouts
Floating::new, single and stack draw a fresh id on each call, so a layout
built anew each frame opened a new OS window each frame. with_id gives such
a layout the same windows every frame. Debug builds log a warning once when
three frames running replace every native window with new ones holding the
same panels.
2026-10-24 03:09:14 +00:00
aiongg 332a4456dd Merge #186: keymap: Keyboard Shortcuts dialog, named shortcut sets and the shortcut editor
# Conflicts:
#	crates/keymap/src/lib.rs
2026-10-24 02:29:57 +00:00
aiongg f0379def18 Merge #205: keymap: read presses by the keyboard layout 2026-10-24 02:29:52 +00:00
aiongg 4d646b3cbd Merge #164: Add craft-keymap: shared keyboard bindings and shortcut-set import 2026-10-24 02:29:52 +00:00
aiongg ec65b95a65 Merge #213: Add craft-fonts-build: embed craft-fonts faces from an app's build.rs
# Conflicts:
#	Cargo.lock
2026-10-24 02:26:24 +00:00
aiongg aaf9f29e4f Merge #210: i18n: numbers for a region on ICU4X, locale digits in counts and sizes
# Conflicts:
#	Cargo.lock
#	crates/i18n/Cargo.toml
#	crates/i18n/README.md
#	crates/i18n/src/lib.rs
2026-10-24 02:25:57 +00:00
aiongg fa78cb52a5 Merge #206: craft-i18n: search folding and locale sorting
# Conflicts:
#	crates/i18n/Cargo.toml
#	crates/i18n/src/lib.rs
2026-10-24 02:25:27 +00:00
aiongg 1faeabfead Merge #203: i18n: formatting region apart from the interface language
# Conflicts:
#	Cargo.lock
#	crates/i18n/README.md
#	crates/i18n/src/lib.rs
2026-10-24 02:20:33 +00:00
aiongg 9f75d3dc19 pdf: keep a CID font's /W2 table past an out-of-range first CID; vendor hayro-cmap from PdfCraft (#254)
* pdf: keep a CID font's /W2 table past an out-of-range first CID; vendor hayro-cmap from PdfCraft

- hayro-interpret: a /W2 run whose first CID is past 65535 is skipped, as in
  /W. A run starting at 4294967295 overflowed the CID counter and discarded
  the whole table. Unit test in font::cid.
- hayro-cmap 0.1.0 is vendored from PdfCraft a2ec27b47 with its malformed-CMap
  patch (PdfCraft #3177): bad bfchar/bfrange entries, an unresolvable usecmap
  and an unparseable tail are skipped instead of failing the whole CMap. The
  crate's tests come with it. Wired up like the other vendored Hayro crates
  (workspace exclude, patch entry, SOURCE.json, backend test script); NOTICE,
  ATTRIBUTION.md and vendor/README.craft-reader.md record the source.

* hayro-syntax: refuse an xref-stream subsection that runs past object number u32::MAX

The object number was start + i in unchecked u32: a subsection starting near
u32::MAX overflowed (a panic in debug builds, a wrong object number in
release). Covered in xref::tests::xref_stream_entries_need_backing_bytes.

* hayro-cmap: a binary usecmap counts against the nesting limit; /W2 checks the CID first

- hayro-cmap: a binary CMap's usecmap passed its own depth to the nested
  parse, so a self-referencing binary CMap recursed until the stack
  overflowed. It now counts like a text usecmap. Test:
  self_referencing_binary_usecmap_stops_at_the_nesting_limit.
- hayro-interpret: the /W2 first-CID check runs before the run's metrics
  are read, so an incomplete run past CID 65535 no longer discards the
  rest of the table.

* hayro-syntax: refuse xref-stream object numbers past i32::MAX

ObjectIdentifier stores an i32; a number between i32::MAX and u32::MAX
was cast to a negative object number.
2026-10-23 22:17:04 -04:00
aiongg 07f1250d6c Merge upstream main into print-color 2026-10-24 02:09:21 +00:00
aiongg c52c6f3ec0 Merge upstream main into print-color
- hayro-syntax ascii_85.rs: main's decode-limit version (same bound as
  the pdfcraft ec0a965 copy, plus its test).
- hayro-interpret and krilla SOURCE.json: source fields from pdfcraft
  ec0a965 / krilla 0.8.2, sha256 recomputed for merged files.
- krilla PNG decode cap from main recorded as patches/11-png-decode-cap.patch
  with its ledger row and README section.
2026-10-24 02:08:42 +00:00
aiongg 9c5ebb782e Revert "craft-ui: update egui to 0.37 (#199)" (#251)
This reverts commit 3832c47ef6.
2026-10-23 22:08:41 -04:00
aiongg 5354479ce3 i18n: scripts, direction and regional Han per language tag (#200)
* i18n: scripts, direction and regional Han per language tag

scripts(tag) lists the ISO 15924 scripts a language's interface text is
written in, direction(tag) follows the main script, and han(tag) gives
the regional Han forms (SC, TC, HK, JP, KR) for picking a CJK face.
I18n::rtl uses direction.

* i18n: non_exhaustive Script and Han; regions that imply a script

pa-PK, uz-AF and az-IR are written in Arabic and sd-IN in Devanagari, as
CLDR's likely subtags give them. A script subtag still wins.

* i18n: han and catalog matching follow region-implied scripts

han(zh-US), zh-AU and the other regions CLDR writes in Traditional
characters give Traditional, and pa-PK picks a pa-arab catalog, never
Gurmukhi pa, as pa-Arab-PK does.

* i18n: Hani and yue-Hant pick Han forms by region; usual scripts for kk, ky, tg, ku, ms, ug

* i18n: base_direction of a paragraph from its first strong character
2026-10-23 21:07:32 -04:00
aionggandDavis Brief 3832c47ef6 craft-ui: update egui to 0.37 (#199)
* craft-ui: match guard for a stack's hit test (clippy 1.95 collapsible_match)

* Update egui to 0.37

egui 0.37 replaces WidgetType with accesskit's Role and renames a few
methods. Mapped per egui's own table (WidgetType docs): Checkbox is
CheckBox, SelectableLabel is Button, Other is Unknown; UiBuilder::id and
Ui::id are scope_id; Id::new is Id::unique (the same hash). No behaviour
change.

egui's test harness now panics on a glyph no installed font has, and its
bundled fonts dropped U+22EE, so the docking fixture's group header draws
an ellipsis instead of a vertical ellipsis.

* craft-ui: README says egui 0.37

---------

Co-authored-by: Davis Brief <davisbrief@gmail.com>
2026-10-23 20:02:10 -04:00
Martin BallandClaude Opus 5.5 4ecda6fa8c i18n: parse each locale lazily on first lookup
I18n::new keeps the embedded text and parses nothing; a locale's rows
are parsed on the first lookup that reaches it (also as a fallback) and
its bad rows logged with log::warn!. new returns only the locale-level
problems. check_all parses every locale and returns all problems.
name() scans for the language.name row instead of parsing the locale.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 21:11:48 +01:00
aiongg e2b452482a docking: an example with native floating windows 2026-10-23 18:05:09 +00:00
Dylan M. Taylor f180fc0d35 Use chrono instead of hand-rolled UTC conversion (#219)
* Use chrono for UTC/calendar conversion instead of hand-rolled copies

Replaces the hand-rolled civil_from_days and Day::to_days in
crates/ai-core/src/history/report.rs with chrono, added as a workspace
dependency (std-only, so ai-core still compiles for wasm). The day/month
grouping, ISO and CSV timestamps and the Day/Month display are byte-identical
and pinned by the existing tests. AGENTS.md now says time goes through chrono.

Follow-up to storytold/cadcraft#1785

* history: preserve out-of-range conversion failure in civil_from_days

civil_from_days used `i32::try_from(..).unwrap_or(0)` before calling
NaiveDate::from_num_days_from_ce_opt, so a CE day count past i32 (e.g.
from Day::from_days(i64::MAX)) passed a valid day 0 to chrono and read
as 0000-12-31 instead of the 0000-01-01 fallback the None arm gives for
every other out-of-range date. Convert with `.ok().and_then(..)` so both
the integer-conversion and NaiveDate-construction failures share the one
fallback. Regression test covers i64::MAX and i64::MIN.

Doc comments on the chrono-touched to_days/from_days/civil_from_days now
state the out-of-range behaviour (0 / 0000-01-01) for the docstring gate.

* Convert every i32 year, not only chrono's range

Day holds any i32 year, but NaiveDate stops near ±262143, so years like
262144 read as 0 / 0000-01-01. The Gregorian calendar repeats every 400
years: chrono now converts the day within its cycle and whole cycles are
added back, in both directions. Values match the pre-chrono formula
(tested for 262144, -262145, i32::MAX and i32::MIN). Nonexistent days
still read as 0, and day counts whose year doesn't fit i32 still read as 0000-01-01.

* Name the 400-year range extension as the one exception to the time rule

The rule said never to hand-roll calendar math, but the range fix
(shifting by whole 400-year Gregorian cycles so dates past chrono's year
range keep their old output) is cycle arithmetic, so the rule and the code
disagreed. The rule now names that exception: the library still computes
month, day and time, and only whole cycles are carried in the year.

* Say the library computes month and day; time-of-day is plain arithmetic

Narrows the range-extension wording: the date library computes the
calendar fields, and splitting seconds into hours, minutes and seconds
is ordinary arithmetic, which is what the code does.
2026-10-23 11:17:51 -04:00
aiongg f0ed593d9f keymap: update Cargo.lock for the egui dev-dependency with serde 2026-10-23 08:14:06 +00:00