diff --git a/apps/gridcraft/src/main.rs b/apps/gridcraft/src/main.rs index 8093205..cf3a371 100644 --- a/apps/gridcraft/src/main.rs +++ b/apps/gridcraft/src/main.rs @@ -369,3 +369,32 @@ fn main() -> eframe::Result<()> { } result } + +#[cfg(test)] +mod packaging_tests { + use gridcraft_engine::io::FileKind; + + /// The text between `start` and `end` that follows each `marker` in `text`, sorted (e.g. the + /// `xlsb` in `Classes\.xlsb\OpenWithProgids`). + fn extensions(text: &str, marker: &str, start: &str, end: char) -> Vec { + let mut v: Vec = text.split(marker).skip(1).filter_map(|s| s.split_once(start)?.1.split(end).next()).map(str::to_string).collect(); + v.sort(); + v + } + + /// macOS Open With (`CFBundleDocumentTypes`) offers GridCraft for the same files as Windows + /// Open with, and GridCraft opens each of them. #321 added `.xlsb` and `.ods` on Windows and + /// Linux only. + #[test] + fn macos_and_windows_offer_the_same_file_types() { + let plist = include_str!("../../../packaging/macos/Info.plist.in"); + let wxs = include_str!("../../../packaging/windows/gridcraft.wxs"); + let mac = extensions(plist, "CFBundleTypeExtensions", "", '<'); + let win = extensions(wxs, "Key=\"Software\\Classes\\.", "", '\\'); + assert!(mac.iter().any(|e| e == "xlsx"), "Info.plist.in extensions not found: {mac:?}"); + assert_eq!(mac, win); + for ext in &mac { + assert!(FileKind::from_path(&format!("book.{ext}")).is_some(), "GridCraft doesn't open .{ext}"); + } + } +} diff --git a/docs/file-format-parity.md b/docs/file-format-parity.md index 8510659..83c1849 100644 --- a/docs/file-format-parity.md +++ b/docs/file-format-parity.md @@ -1,6 +1,6 @@ # File-format parity -> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-12 · **Change:** minor (CSV save keeps the separator it was opened with) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4 +> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-12 · **Change:** minor (macOS Open With offers GridCraft for `.xlsb` and `.ods`) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4 Every format Excel opens or saves, with GridCraft's read and write support, fidelity and tests. Part of [target-app-parity.md](target-app-parity.md). **File formats: ~50% ready, 80–120 h** @@ -78,6 +78,7 @@ refresh. Counted under features (Get & Transform, ~10% ready), not here. | Date | Change | Summary | |---|---|---| +| 2026-10-12 | minor | macOS: the app bundle declares `.xlsb` and `.ods`, so Finder's Open With offers GridCraft for them, as Linux and Windows already did (#321) | | 2026-10-12 | minor | CSV: saving a file opened as CSV keeps its detected separator (`;` files were rewritten with `,`) | | 2026-10-11 | minor | XLSX: cell/shared/array formulas read through the file→model conversion (`_xlpm.` LET/LAMBDA parameter prefixes stripped); table column names keep line breaks; table names may start with `\` | | 2026-10-11 | minor | CSV/TSV export writes displayed values (number formats applied, no `#####`); `.xltx`, `.xltm` and `.xlsm` saved with their own workbook content types | diff --git a/docs/releasing.md b/docs/releasing.md index 7f7ecce..479c2c0 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -15,7 +15,7 @@ This is GridCraft's implementation of the shared [release playbook](release-play | Display name `GridCraft`, binaries `gridcraft` + `gridcraft-cli` | every script and workflow | | Bundle / app id `ai.storyteller.gridcraft` | `packaging/macos/Info.plist.in`, `packaging/linux/*`, flatpak manifest | | WiX UpgradeCode `5511327B-F305-41BE-92D0-EB84944E7C4D` (fixed forever) | `packaging/windows/gridcraft.wxs` | -| File types `.xlsx` `.xlsm` `.csv` `.tsv` | Info.plist (`CFBundleDocumentTypes`), WiX (ProgIds/OpenWithProgids), `.desktop` `MimeType=`, `ai.storyteller.gridcraft.mime.xml`, metainfo | +| File types `.xlsx` `.xlsm` `.xlsb` `.ods` `.csv` `.tsv` | Info.plist (`CFBundleDocumentTypes`), WiX (ProgIds/OpenWithProgids), `.desktop` `MimeType=`, `ai.storyteller.gridcraft.mime.xml`, metainfo | | Web app dir `apps/gridcraft-web` | `packaging/web/package.sh` | | App colour `#1f9d55` (ink `#147a40`), **proposed** | `assets/app-icon/README.md`, metainfo `` | @@ -94,9 +94,9 @@ and upload their artifacts, the environment refuses macOS and Windows, and no re - `Info.plist` comes from `Info.plist.in`: bundle id `ai.storyteller.gridcraft`, `LSMinimumSystemVersion` 11.0, `NSHighResolutionCapable`, category productivity, and - `CFBundleDocumentTypes` for `.xlsx`, `.xlsm`, `.csv` and `.tsv` with rank **Alternate**, so - GridCraft is offered in *Open With* without taking over Numbers' (or another app's) - defaults. `.xlsm` gets an imported UTI in case macOS doesn't know it. + `CFBundleDocumentTypes` for `.xlsx`, `.xlsm`, `.xlsb`, `.ods`, `.csv` and `.tsv` with rank + **Alternate**, so GridCraft is offered in *Open With* without taking over Numbers' (or another + app's) defaults. `.xlsm` and `.xlsb` get imported UTIs in case macOS doesn't know them. - **Signing** goes inside-out with the hardened runtime and a secure timestamp; no `--deep` on the final signature; `entitlements.plist` is deliberately empty. - **Notarization:** the app is zipped and sent with `xcrun notarytool submit --wait`, then diff --git a/packaging/macos/Info.plist.in b/packaging/macos/Info.plist.in index 9379279..4ed6d97 100644 --- a/packaging/macos/Info.plist.in +++ b/packaging/macos/Info.plist.in @@ -111,6 +111,39 @@ CFBundleTypeMIMETypes text/tab-separated-values + + + CFBundleTypeName + Excel Binary Workbook + CFBundleTypeRole + Editor + LSHandlerRank + Alternate + LSItemContentTypes + + com.microsoft.excel.sheet.binary.macroenabled + + CFBundleTypeExtensions + xlsb + CFBundleTypeMIMETypes + application/vnd.ms-excel.sheet.binary.macroEnabled.12 + + + CFBundleTypeName + OpenDocument Spreadsheet + CFBundleTypeRole + Editor + LSHandlerRank + Alternate + LSItemContentTypes + + org.oasis-open.opendocument.spreadsheet + + CFBundleTypeExtensions + ods + CFBundleTypeMIMETypes + application/vnd.oasis.opendocument.spreadsheet + @@ -134,6 +167,24 @@ application/vnd.ms-excel.sheet.macroEnabled.12 + + UTTypeIdentifier + com.microsoft.excel.sheet.binary.macroenabled + UTTypeDescription + Excel Binary Workbook + UTTypeConformsTo + + public.data + public.zip-archive + + UTTypeTagSpecification + + public.filename-extension + xlsb + public.mime-type + application/vnd.ms-excel.sheet.binary.macroEnabled.12 + +