diff --git a/.github/workflows/windows-arm64.yml b/.github/workflows/windows-arm64.yml index f577b3f7..1e5b3883 100644 --- a/.github/workflows/windows-arm64.yml +++ b/.github/workflows/windows-arm64.yml @@ -24,8 +24,8 @@ permissions: jobs: windows-arm64: - # Immutable supporting workflow revision until the new install contract lands upstream. - uses: storytold/craft-common-actions/.github/workflows/windows-arm64.yml@8bb4e5ab95443171104ad88113fe1ef9b0e5ce3f + # Intentionally tracked at @main (not SHA-pinned) so org-wide CI improvements, security fixes, and build optimizations propagate without PR churn across all craftapp repos. + uses: storytold/craft-common-actions/.github/workflows/windows-arm64.yml@main with: app-name: deckcraft app-dir: DeckCraft diff --git a/AGENTS.md b/AGENTS.md index 8a7ce7cf..c998e871 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -192,3 +192,8 @@ the `ROADMAP.md` progress log, and update each touched doc's status line and rev GitHub profiles). Never hand-edit `contributors.json`. - Maintainers refresh the stats with `python3 ../../craftrules/scripts/contributors.py .` (it also re-verifies who wrote each `people.toml` entry; `--check` only verifies). + +## CI workflows +- Workflows in `.github/workflows/` call the shared workflows in [`storytold/craft-common-actions`](https://github.com/storytold/craft-common-actions) at `@main`, with their inputs and secrets. No other jobs: if no shared workflow does what's needed, it doesn't go here. +- Don't add or change CI in a feature or fix PR. If the existing workflows can't build or test a change, link an existing craft-common-actions issue or PR, or open a new issue, or a PR only for a small fix that is safe for every app and does not increase CI time. +- Some workflow files here still run their own jobs. Don't add to them. Moving a job into craft-common-actions is its own task, never part of another PR, and the job stays here until a shared workflow runs it. diff --git a/CLAUDE.md b/CLAUDE.md index aae6e13f..669965b5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,3 +19,8 @@ before modules or other crate items; crate-level `//!` documentation may precede - Commit after each landed arc (`M.: what`) and push to `origin main`. - Keep `ROADMAP.md`, the progress docs in `docs/` (AGENTS.md ยง7) and `plan/STATUS.md` current. - Don't ask the user questions; record genuinely-theirs decisions in `plan/STATUS.md`. + +## CI workflows +- Workflows in `.github/workflows/` call the shared workflows in [`storytold/craft-common-actions`](https://github.com/storytold/craft-common-actions) at `@main`, with their inputs and secrets. No other jobs: if no shared workflow does what's needed, it doesn't go here. +- Don't add or change CI in a feature or fix PR. If the existing workflows can't build or test a change, link an existing craft-common-actions issue or PR, or open a new issue, or a PR only for a small fix that is safe for every app and does not increase CI time. +- Some workflow files here still run their own jobs. Don't add to them. Moving a job into craft-common-actions is its own task, never part of another PR, and the job stays here until a shared workflow runs it. diff --git a/Cargo.lock b/Cargo.lock index ed9a4995..a6ef452e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -222,7 +222,7 @@ dependencies = [ "objc2-foundation 0.3.2", "parking_lot", "percent-encoding", - "windows-sys 0.52.0", + "windows-sys 0.61.2", "wl-clipboard-rs", "x11rb", ] @@ -888,13 +888,14 @@ dependencies = [ [[package]] name = "craft-update" version = "0.1.0" -source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0" +source = "git+https://github.com/storytold/craft-libs?rev=04aa1703b32d299e54f78fcde4182f2b393a9116#04aa1703b32d299e54f78fcde4182f2b393a9116" dependencies = [ "chrono", "dunce", "egui", "flate2", "getrandom 0.3.4", + "image", "log", "plist", "semver", @@ -1651,7 +1652,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3013,7 +3014,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3486,7 +3487,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.45.0", ] [[package]] @@ -4041,7 +4042,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -4098,7 +4099,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -4731,10 +4732,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix 1.1.5", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5658,7 +5659,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 07960495..3eada708 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,8 @@ vello_common = { version = "0.2", default-features = false } image = { version = "0.25", default-features = false, features = ["png", "jpeg", "webp", "gif", "tiff", "bmp"] } craft-media = { git = "https://github.com/storytold/craft-libs", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0", version = "=0.1.0", default-features = false } craft-pdf = { git = "https://github.com/storytold/craft-libs", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0", version = "=0.1.0", default-features = false, features = ["write", "write-simple-text"] } -craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0", features = ["egui"] } +# craft-update: app-specific pretend versions apply to startup and manual checks. +craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "04aa1703b32d299e54f78fcde4182f2b393a9116", features = ["egui"] } craft-ui = { git = "https://github.com/storytold/craft-libs", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0", version = "=0.1.0" } i_overlay = "9" quick-xml = "0.41" diff --git a/apps/deckcraft/src/main.rs b/apps/deckcraft/src/main.rs index 605dc84a..03859dc0 100644 --- a/apps/deckcraft/src/main.rs +++ b/apps/deckcraft/src/main.rs @@ -187,7 +187,7 @@ fn main() -> eframe::Result { // First, so every start-up record (and the engine's panic hook, installed with the first // Session) is captured; see `logging`. let logger = logging::install(); - if let Some(done) = craft_update::self_update::finish(&craft_update::suite::DECKCRAFT, &std::env::args_os().skip(1).collect::>()) { + if let Some(done) = craft_update::self_update::finish(&deckcraft_ui_egui::UPDATE_APP, &std::env::args_os().skip(1).collect::>()) { if let Err(e) = done { eprintln!("DeckCraft update helper failed: {e}"); std::process::exit(1); diff --git a/contributors/people.toml b/contributors/people.toml index 31dccab2..caf4daa4 100644 --- a/contributors/people.toml +++ b/contributors/people.toml @@ -68,3 +68,6 @@ sync_github_name = true [people.SofiaAFigueredo] real_name = "Sofia Alves Figueredo" + +[people.dylanmtaylor] +sync_github_name = true diff --git a/crates/engine/src/tools/click.rs b/crates/engine/src/tools/click.rs index 0f066dc0..802eb8c5 100644 --- a/crates/engine/src/tools/click.rs +++ b/crates/engine/src/tools/click.rs @@ -206,7 +206,7 @@ impl Session { let Some(f) = st.shape(id).and_then(|sh| cmd::table::table_frame(st, sh)) else { return Ok(()) }; let size = if column { f.cols.get(index) } else { f.heights.get(index) }.copied().unwrap_or(0.0); let (start, frame) = (f.local(p), f.affine); - if !st.selection.text.as_ref().is_some_and(|t| t.shape == id) { + if st.selection.text.as_ref().is_none_or(|t| t.shape != id) { self.select(|_, sel| { sel.shapes = vec![id]; sel.text = None; diff --git a/crates/engine/src/tools/pointer.rs b/crates/engine/src/tools/pointer.rs index bee8f320..cb71cfed 100644 --- a/crates/engine/src/tools/pointer.rs +++ b/crates/engine/src/tools/pointer.rs @@ -455,12 +455,11 @@ impl Session { self.execute("guide.move", &json!({"index": index, "pos": pos}))? }; } - Some(Drag::Move { moved: false, enter_text: Some((id, at)), .. }) => { + Some(Drag::Move { moved: false, enter_text: Some((id, at)), .. }) // Plain click on text: caret at the click (in a table, in the clicked cell). - if self.edit_text_at(id, at)? { + if self.edit_text_at(id, at)? => { out = json!({"editing": id}); } - } Some(Drag::Marquee { start, add }) => { let r = Rect::from_points(start, p); self.tool.marquee = None; diff --git a/crates/metafile/src/emfplus.rs b/crates/metafile/src/emfplus.rs index 62e8f714..afdb3c88 100644 --- a/crates/metafile/src/emfplus.rs +++ b/crates/metafile/src/emfplus.rs @@ -93,7 +93,7 @@ impl Fill { if w == 0.0 || h == 0.0 { return [0, 0, 0, 0]; } - if *wrap == 4 && !(0.0..w).contains(&p.0) || *wrap == 4 && !(0.0..h).contains(&p.1) { + if *wrap == 4 && !((0.0..w).contains(&p.0) && (0.0..h).contains(&p.1)) { return [0, 0, 0, 0]; } let x = (p.0.rem_euclid(w) as usize).min(img.w - 1); diff --git a/crates/model/src/trendline.rs b/crates/model/src/trendline.rs index b2645ac6..2b9cdf6b 100644 --- a/crates/model/src/trendline.rs +++ b/crates/model/src/trendline.rs @@ -480,7 +480,7 @@ fn num(v: f64) -> String { if a == 0.0 { return "0".to_string(); } - if a >= 1.0e6 || a < 1.0e-3 { + if !(1.0e-3..1.0e6).contains(&a) { return format!("{v:.2e}").replace('+', ""); } let digits = if a >= 100.0 { diff --git a/crates/pptx/src/read/dml.rs b/crates/pptx/src/read/dml.rs index e96fcd22..767b7dc0 100644 --- a/crates/pptx/src/read/dml.rs +++ b/crates/pptx/src/read/dml.rs @@ -631,18 +631,14 @@ pub fn paragraph(imp: &mut Imp, part: &Part, p: &El) -> Paragraph { let text: String = e.child("t").map(|t| t.text()).unwrap_or_default(); push_text_runs(&mut para, props, &text); } - "br" => { - if para.runs.len() < MAX_PARAGRAPH_RUNS { - let props = run_props(imp, part, e); - para.runs.push(Run { text: String::new(), props, kind: RunKind::Break }); - } + "br" if para.runs.len() < MAX_PARAGRAPH_RUNS => { + let props = run_props(imp, part, e); + para.runs.push(Run { text: String::new(), props, kind: RunKind::Break }); } - "fld" => { - if para.runs.len() < MAX_PARAGRAPH_RUNS { - let props = run_props(imp, part, e); - let text = e.child("t").map(|t| t.text()).unwrap_or_default(); - para.runs.push(Run { text, props, kind: RunKind::Field { field: e.attr("type").unwrap_or("").to_string() } }); - } + "fld" if para.runs.len() < MAX_PARAGRAPH_RUNS => { + let props = run_props(imp, part, e); + let text = e.child("t").map(|t| t.text()).unwrap_or_default(); + para.runs.push(Run { text, props, kind: RunKind::Field { field: e.attr("type").unwrap_or("").to_string() } }); } "m" => push_math_run(&mut para, part, e), "endParaRPr" => para.end_props = rpr(imp, part, e), diff --git a/crates/ui-egui/src/dialogs/updates_ui.rs b/crates/ui-egui/src/dialogs/updates_ui.rs index 1b65dcb2..1fbfe4d2 100644 --- a/crates/ui-egui/src/dialogs/updates_ui.rs +++ b/crates/ui-egui/src/dialogs/updates_ui.rs @@ -16,7 +16,7 @@ pub(crate) struct Runtime { impl Default for Runtime { fn default() -> Self { - Self { updater: Updater::new(&craft_update::suite::DECKCRAFT, VERSION), enabled: false, check_requested: false } + Self { updater: Updater::new(&crate::UPDATE_APP, VERSION), enabled: false, check_requested: false } } } diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 30b5a0cd..5f9e9cd2 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -6,6 +6,15 @@ #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] #![forbid(unsafe_code)] +/// DeckCraft as craft-update knows it, with its 128 px icon and accent colour: the update +/// prompt shows both, and an AppImage's menu entry gets the icon. +#[cfg(not(target_arch = "wasm32"))] +pub const UPDATE_APP: craft_update::app::App = craft_update::app::App { + icon_png: Some(include_bytes!("../../../assets/app-icon/hicolor/128x128/apps/ai.storyteller.deckcraft.png")), + accent: Some([0xf0, 0x7a, 0x1e]), + ..craft_update::suite::DECKCRAFT +}; + pub mod backstage; pub mod canvas; pub mod capture; diff --git a/xtask/src/layers.rs b/xtask/src/layers.rs index 9921f9d7..47a9e67a 100644 --- a/xtask/src/layers.rs +++ b/xtask/src/layers.rs @@ -183,11 +183,11 @@ pub fn check(crates: &[Crate]) -> Vec { match classify(&d.name) { // Unregistered deps are reported on their own entry. None => {} - Some(Class::Testkit) => { - if d.kind != DepKind::Dev { - out.push(Violation::TestkitAsNormalDep { krate: c.name.clone() }); - } + Some(Class::Testkit) if d.kind != DepKind::Dev => { + out.push(Violation::TestkitAsNormalDep { krate: c.name.clone() }); } + // Test support is allowed as a dev-dependency, regardless of its layer. + Some(Class::Testkit) => {} Some(dc) => { let to = dc.layer().unwrap_or(u8::MAX); let dev_ok = d.kind == DepKind::Dev && DEV_EXCEPTIONS.contains(&(short_name(&c.name), short_name(&d.name)));