diff --git a/apps/figcraft-cli/src/files.rs b/apps/figcraft-cli/src/files.rs index 46215599..37a6aae4 100644 --- a/apps/figcraft-cli/src/files.rs +++ b/apps/figcraft-cli/src/files.rs @@ -1,5 +1,6 @@ //! The file subcommands: info, export, convert, render and run. +use std::ffi::OsStr; use std::path::Path; use std::process::ExitCode; @@ -19,7 +20,7 @@ fn load_noted(path: &str) -> CliResult<(Document, Vec)> { } fn ext(path: &str) -> String { - Path::new(path).extension().and_then(|e| e.to_str()).unwrap_or("").to_ascii_lowercase() + Path::new(path).extension().and_then(OsStr::to_str).unwrap_or("").to_ascii_lowercase() } fn image_format(e: &str) -> Option { diff --git a/apps/figcraft-server/src/cli_tests.rs b/apps/figcraft-server/src/cli_tests.rs index 7b77f71e..7d6a6b9e 100644 --- a/apps/figcraft-server/src/cli_tests.rs +++ b/apps/figcraft-server/src/cli_tests.rs @@ -11,7 +11,7 @@ use crate::store::Store; use crate::test_util::{TempDir, config}; fn args(s: &[&str]) -> Vec { - s.iter().map(|a| a.to_string()).collect() + s.iter().map(ToString::to_string).collect() } fn run(dir: &std::path::Path, command: Command) -> Result { diff --git a/apps/figcraft-server/src/disk.rs b/apps/figcraft-server/src/disk.rs index af6e0f99..d32a1747 100644 --- a/apps/figcraft-server/src/disk.rs +++ b/apps/figcraft-server/src/disk.rs @@ -13,6 +13,7 @@ //! store replays such a log anyway and reports any change the snapshot lacked. A log ends at its //! first damaged record (a write cut short). +use std::ffi::OsStr; use std::fs::{self, File}; use std::io::{self, Read, Write}; use std::path::{Path, PathBuf}; @@ -49,7 +50,7 @@ pub fn free_bytes(path: &Path) -> Option { /// `path` with `.tmp` added: where its next version is written first. pub fn temp_of(path: &Path) -> PathBuf { - let mut name = path.file_name().map(|n| n.to_os_string()).unwrap_or_default(); + let mut name = path.file_name().map(OsStr::to_os_string).unwrap_or_default(); name.push(".tmp"); path.with_file_name(name) } diff --git a/apps/figcraft/src/args_tests.rs b/apps/figcraft/src/args_tests.rs index b274beda..04229e51 100644 --- a/apps/figcraft/src/args_tests.rs +++ b/apps/figcraft/src/args_tests.rs @@ -3,7 +3,7 @@ use crate::args::{Args, file_url_path, is_invite, parse}; fn args(a: &[&str]) -> Vec { - a.iter().map(|s| s.to_string()).collect() + a.iter().map(ToString::to_string).collect() } #[test] diff --git a/crates/color/src/blend.rs b/crates/color/src/blend.rs index 734759ee..250e8ab0 100644 --- a/crates/color/src/blend.rs +++ b/crates/color/src/blend.rs @@ -103,7 +103,7 @@ impl BlendMode { /// The mode named by its label or CSS keyword, ignoring case, spaces and dashes. Labels come /// first: "normal" is Normal, not pass-through (whose CSS keyword is also `normal`). pub fn from_name(s: &str) -> Option { - let key: String = s.chars().filter(|c| c.is_ascii_alphanumeric()).collect::().to_ascii_lowercase(); + let key: String = s.chars().filter(char::is_ascii_alphanumeric).collect::().to_ascii_lowercase(); Self::ALL .into_iter() .find(|m| m.label().replace(' ', "").to_ascii_lowercase() == key) diff --git a/crates/doc/src/props.rs b/crates/doc/src/props.rs index 4f6491c1..a646ae62 100644 --- a/crates/doc/src/props.rs +++ b/crates/doc/src/props.rs @@ -475,7 +475,7 @@ impl WidthPreset { } pub fn from_id(s: &str) -> Option { - let s: String = s.chars().filter(|c| c.is_ascii_alphanumeric()).collect(); + let s: String = s.chars().filter(char::is_ascii_alphanumeric).collect(); WidthPreset::ALL .into_iter() .find(|p| p.id().eq_ignore_ascii_case(&s) || p.label().replace(' ', "").eq_ignore_ascii_case(&s)) diff --git a/crates/engine/src/cmd/component.rs b/crates/engine/src/cmd/component.rs index 6a5b1012..6da64855 100644 --- a/crates/engine/src/cmd/component.rs +++ b/crates/engine/src/cmd/component.rs @@ -786,6 +786,38 @@ fn push_changes(s: &mut Session, p: &Value) -> Result { Ok(json!({"layers": pushed})) } +fn restore_prop_defs(doc: &Document, props: &BTreeMap) -> BTreeMap { + let mut defs = BTreeMap::new(); + for (k, v) in props { + let def = match v { + Value::Bool(b) => PropDef::Boolean { default: *b }, + Value::String(t) => PropDef::Text { default: t.clone() }, + other => match id_of(other) { + Some(c) if doc.contains(c) => PropDef::InstanceSwap { default: c, preferred: Vec::new() }, + _ => continue, + }, + }; + defs.insert(k.clone(), def); + } + defs +} + +fn restore_id_map(doc: &mut Document, i: NodeId, component: NodeId, sub: &[NodeId]) -> BTreeMap { + let mut map: BTreeMap = BTreeMap::new(); + let mut used: BTreeSet = BTreeSet::new(); + map.insert(i, component); + used.insert(component); + for d in sub.iter().filter(|d| **d != i) { + let src = doc.node(*d).and_then(|n| n.source); + let nid = match src { + Some(s) if !doc.contains(s) && used.insert(s) => s, + _ => doc.alloc_id(), + }; + map.insert(*d, nid); + } + map +} + fn restore_main(s: &mut Session, p: &Value) -> Result { let cmd = "component.restoreMain"; let i = targets(s, p).first().copied().ok_or_else(|| bad(cmd, "select an instance"))?; @@ -804,35 +836,13 @@ fn restore_main(s: &mut Session, p: &Value) -> Result { // The main comes back with its old id (other instances point to it) and its layers with the // ids their copies mirror, so every instance re-links by source. let sub = doc.subtree(i); - let mut map: BTreeMap = BTreeMap::new(); - let mut used: BTreeSet = BTreeSet::new(); - map.insert(i, component); - used.insert(component); - for d in sub.iter().filter(|d| **d != i) { - let src = doc.node(*d).and_then(|n| n.source); - let nid = match src { - Some(s) if !doc.contains(s) && used.insert(s) => s, - _ => doc.alloc_id(), - }; - map.insert(*d, nid); - } + let map = restore_id_map(doc, i, component, &sub); let mut nodes = Vec::new(); let mut nested = Vec::new(); for d in &sub { let Some(mut n) = doc.node(*d).cloned() else { continue }; if *d == i { - let mut defs = BTreeMap::new(); - for (k, v) in &props { - let def = match v { - Value::Bool(b) => PropDef::Boolean { default: *b }, - Value::String(t) => PropDef::Text { default: t.clone() }, - other => match id_of(other) { - Some(c) if doc.contains(c) => PropDef::InstanceSwap { default: c, preferred: Vec::new() }, - _ => continue, - }, - }; - defs.insert(k.clone(), def); - } + let defs = restore_prop_defs(doc, &props); n.kind = NodeKind::Component { description: String::new(), props: defs }; n.source = None; n.overrides.clear(); diff --git a/crates/engine/src/cmd/file.rs b/crates/engine/src/cmd/file.rs index d8ad924d..e0a3e0d8 100644 --- a/crates/engine/src/cmd/file.rs +++ b/crates/engine/src/cmd/file.rs @@ -488,11 +488,11 @@ pub(crate) fn write(path: &str, _bytes: &[u8]) -> Result<()> { } fn ext(path: &str) -> String { - std::path::Path::new(path).extension().and_then(|e| e.to_str()).unwrap_or("").to_ascii_lowercase() + std::path::Path::new(path).extension().and_then(std::ffi::OsStr::to_str).unwrap_or("").to_ascii_lowercase() } fn file_stem(path: &str) -> String { - std::path::Path::new(path).file_stem().and_then(|e| e.to_str()).unwrap_or("Untitled").to_string() + std::path::Path::new(path).file_stem().and_then(std::ffi::OsStr::to_str).unwrap_or("Untitled").to_string() } /// The counts the import report shows for a freshly loaded document. diff --git a/crates/engine/src/guard.rs b/crates/engine/src/guard.rs index 6161f46b..d77a1bfc 100644 --- a/crates/engine/src/guard.rs +++ b/crates/engine/src/guard.rs @@ -9,7 +9,7 @@ pub fn run(cmd: &str, f: impl FnOnce() -> Result) -> Result { Err(payload) => { let msg = payload .downcast_ref::<&str>() - .map(|s| s.to_string()) + .map(ToString::to_string) .or_else(|| payload.downcast_ref::().cloned()) .unwrap_or_else(|| "panic".to_string()); log::error!("command `{cmd}` panicked: {msg}"); diff --git a/crates/engine/src/library.rs b/crates/engine/src/library.rs index 26863561..72f2a4ac 100644 --- a/crates/engine/src/library.rs +++ b/crates/engine/src/library.rs @@ -339,7 +339,7 @@ pub fn publish(doc: &Document, prev: Option<&PublishedLibrary>, sel: &Selection, .map(|v| v.id.as_str()) .collect(); let (bound, mode_colls) = used_variables(doc, &units); - let var_ids = alias_closure(&doc.variables, offered_vars.iter().map(|v| v.to_string()).chain(bound)); + let var_ids = alias_closure(&doc.variables, offered_vars.iter().map(ToString::to_string).chain(bound)); snap.variables.variables = doc.variables.variables.iter().filter(|v| var_ids.contains(&v.id)).cloned().collect(); let coll_ids: BTreeSet<&str> = snap .variables diff --git a/crates/engine/src/synthetic.rs b/crates/engine/src/synthetic.rs index c2a9f5d6..d5ead671 100644 --- a/crates/engine/src/synthetic.rs +++ b/crates/engine/src/synthetic.rs @@ -28,6 +28,53 @@ fn fill(doc: &mut Document, id: NodeId, c: Color) { } } +fn add_screen_header(doc: &mut Document, screen: NodeId, s: usize) -> DocResult<()> { + let header = doc.create(screen, NodeKind::Frame, "Header", 0.0, 0.0, SCREEN_W, 40.0)?; + if let Some(n) = doc.node_mut(header) { + n.layout = Some(AutoLayout { gap: 8.0, padding: [8.0; 4], ..AutoLayout::default() }); + n.fills = vec![Paint::solid(Color::from_rgb8_const(0xF5, 0xF5, 0xF5))]; + } + doc.create(header, text(&format!("Screen {}", s + 1)), "Title", 0.0, 0.0, 120.0, 16.0)?; + for k in 0..2 { + let icon = doc.create(header, ellipse(), &format!("Icon {}", k + 1), 0.0, 0.0, 20.0, 20.0)?; + fill(doc, icon, Color::from_rgb8_const(0x99, 0x99, 0x99)); + } + Ok(()) +} + +fn add_card_group(doc: &mut Document, screen: NodeId) -> DocResult<()> { + let card = doc.create(screen, NodeKind::Group, "Card", 12.0, 52.0, 160.0, 64.0)?; + // Children are in the group's space; normalising fits the group around them. + let cbg = doc.create(card, NodeKind::Rectangle, "Card background", 0.0, 0.0, 160.0, 64.0)?; + fill(doc, cbg, Color::from_rgb8_const(0xEE, 0xF4, 0xFF)); + doc.create(card, ellipse(), "Avatar", 8.0, 8.0, 32.0, 32.0)?; + doc.create(card, text("Ada Lovelace"), "Name", 48.0, 8.0, 100.0, 16.0)?; + doc.create(card, text("Analyst"), "Role", 48.0, 28.0, 100.0, 16.0)?; + Ok(()) +} + +fn add_screen_grid(doc: &mut Document, screen: NodeId, s: usize, rest: usize, made: &mut usize) -> DocResult<()> { + for k in 0..rest { + let (gx, gy) = (184.0 + (k % 8) as f64 * 21.0, 52.0 + (k / 8) as f64 * 34.0); + let hue = ((s * PER_SCREEN + k) % 360) as f32 / 360.0; + // The grid starts with a rectangle so even the smallest workload has one. + let kind = (k + 2) % 5; + let id = match kind { + 0 => doc.create(screen, text(&format!("Item {k}")), "Text", gx, gy, 20.0, 14.0)?, + 1 | 3 => doc.create(screen, ellipse(), "Ellipse", gx, gy, 18.0, 18.0)?, + _ => doc.create(screen, NodeKind::Rectangle, "Rectangle", gx, gy, 18.0, 18.0)?, + }; + if kind != 0 { + fill(doc, id, Color::new(hue, 0.5, 1.0 - hue, 1.0)); + if let Some(n) = doc.node_mut(id) { + n.corners.radii = [3.0; 4]; + } + } + *made += 1; + } + Ok(()) +} + /// A page of about `layers` layers (pages not counted), normalised like an opened file. Returns /// the document and its page. pub fn large_document(layers: usize) -> DocResult<(Document, NodeId)> { @@ -53,28 +100,13 @@ pub fn large_document(layers: usize) -> DocResult<(Document, NodeId)> { let budget = |made: usize| layers.saturating_sub(made); // Auto layout header: title + two icons (4 layers). if budget(made) >= 4 { - let header = doc.create(screen, NodeKind::Frame, "Header", 0.0, 0.0, SCREEN_W, 40.0)?; - if let Some(n) = doc.node_mut(header) { - n.layout = Some(AutoLayout { gap: 8.0, padding: [8.0; 4], ..AutoLayout::default() }); - n.fills = vec![Paint::solid(Color::from_rgb8_const(0xF5, 0xF5, 0xF5))]; - } - doc.create(header, text(&format!("Screen {}", s + 1)), "Title", 0.0, 0.0, 120.0, 16.0)?; - for k in 0..2 { - let icon = doc.create(header, ellipse(), &format!("Icon {}", k + 1), 0.0, 0.0, 20.0, 20.0)?; - fill(&mut doc, icon, Color::from_rgb8_const(0x99, 0x99, 0x99)); - } + add_screen_header(&mut doc, screen, s)?; made += 4; } // A card group (5 layers). // The card and the instances leave one layer for the grid, which starts with a rectangle. if budget(made) > 5 { - let card = doc.create(screen, NodeKind::Group, "Card", 12.0, 52.0, 160.0, 64.0)?; - // Children are in the group's space; normalising fits the group around them. - let cbg = doc.create(card, NodeKind::Rectangle, "Card background", 0.0, 0.0, 160.0, 64.0)?; - fill(&mut doc, cbg, Color::from_rgb8_const(0xEE, 0xF4, 0xFF)); - doc.create(card, ellipse(), "Avatar", 8.0, 8.0, 32.0, 32.0)?; - doc.create(card, text("Ada Lovelace"), "Name", 48.0, 8.0, 100.0, 16.0)?; - doc.create(card, text("Analyst"), "Role", 48.0, 28.0, 100.0, 16.0)?; + add_card_group(&mut doc, screen)?; made += 5; } // Three button instances (3 layers each). @@ -87,24 +119,7 @@ pub fn large_document(layers: usize) -> DocResult<(Document, NodeId)> { } // Fill the rest of the screen with a grid of shapes and text. let rest = PER_SCREEN.saturating_sub(4 + 5 + 9 + 1).min(budget(made)); - for k in 0..rest { - let (gx, gy) = (184.0 + (k % 8) as f64 * 21.0, 52.0 + (k / 8) as f64 * 34.0); - let hue = ((s * PER_SCREEN + k) % 360) as f32 / 360.0; - // The grid starts with a rectangle so even the smallest workload has one. - let kind = (k + 2) % 5; - let id = match kind { - 0 => doc.create(screen, text(&format!("Item {k}")), "Text", gx, gy, 20.0, 14.0)?, - 1 | 3 => doc.create(screen, ellipse(), "Ellipse", gx, gy, 18.0, 18.0)?, - _ => doc.create(screen, NodeKind::Rectangle, "Rectangle", gx, gy, 18.0, 18.0)?, - }; - if kind != 0 { - fill(&mut doc, id, Color::new(hue, 0.5, 1.0 - hue, 1.0)); - if let Some(n) = doc.node_mut(id) { - n.corners.radii = [3.0; 4]; - } - } - made += 1; - } + add_screen_grid(&mut doc, screen, s, rest, &mut made)?; if budget(made) == 0 { break; } diff --git a/crates/engine/src/templates/kit.rs b/crates/engine/src/templates/kit.rs index 4ad5b11a..39bd248b 100644 --- a/crates/engine/src/templates/kit.rs +++ b/crates/engine/src/templates/kit.rs @@ -216,7 +216,7 @@ impl Kit { pub fn variables(&mut self, collection: &str, modes: &[&str], vars: Vec<(&str, &str, Vec)>) -> Result<()> { self.run("variable.createCollection", json!({"name": collection, "modes": modes}))?; for (name, kind, values) in vars { - let values: Map = modes.iter().map(|m| m.to_string()).zip(values).collect(); + let values: Map = modes.iter().map(ToString::to_string).zip(values).collect(); self.run("variable.create", json!({"collection": collection, "name": name, "type": kind, "values": values}))?; } Ok(()) diff --git a/crates/geom/src/measure.rs b/crates/geom/src/measure.rs index 7acfe4ed..0c24aa9d 100644 --- a/crates/geom/src/measure.rs +++ b/crates/geom/src/measure.rs @@ -91,6 +91,27 @@ pub fn polylines(path: &BezPath) -> Option> { polylines_with_limit(path, MAX_SAMPLES) } +fn flatten_curve_segment(el: PathEl, seg_start: Point, limit: usize, count: &mut usize, cur: &mut Polyline) -> bool { + let mut over = false; + kurbo::flatten([PathEl::MoveTo(seg_start), el], FLATTEN_TOL, |fel| { + if over { + return; + } + if let PathEl::LineTo(p) = fel { + *count += 1; + if *count > limit { + over = true; + return; + } + if cur.points.is_empty() { + cur.push(seg_start); + } + cur.push(p); + } + }); + !over +} + /// [`polylines`] with an explicit sample budget, so tests can use a small one. /// /// The budget is enforced *while* flattening, not after it (issue #204): the input element @@ -141,25 +162,7 @@ fn polylines_with_limit(path: &BezPath, limit: usize) -> Option> { PathEl::QuadTo(_, end) | PathEl::CurveTo(_, _, end) => { // Flatten this one segment on its own, so an over-budget curve aborts // here instead of after the whole path has been flattened. - let seg_start = pen; - let mut over = false; - kurbo::flatten([PathEl::MoveTo(seg_start), *el], FLATTEN_TOL, |fel| { - if over { - return; - } - if let PathEl::LineTo(p) = fel { - count += 1; - if count > limit { - over = true; - return; - } - if cur.points.is_empty() { - cur.push(seg_start); - } - cur.push(p); - } - }); - if over { + if !flatten_curve_segment(*el, pen, limit, &mut count, &mut cur) { return None; } pen = end; diff --git a/crates/mcp/src/server.rs b/crates/mcp/src/server.rs index aad3530e..9b8bf7be 100644 --- a/crates/mcp/src/server.rs +++ b/crates/mcp/src/server.rs @@ -59,7 +59,7 @@ fn error(id: Value, code: i64, message: impl Into) -> Value { } fn panic_message(payload: &(dyn std::any::Any + Send)) -> String { - payload.downcast_ref::<&str>().map(|s| s.to_string()).or_else(|| payload.downcast_ref::().cloned()).unwrap_or_else(|| "panic".into()) + payload.downcast_ref::<&str>().map(ToString::to_string).or_else(|| payload.downcast_ref::().cloned()).unwrap_or_else(|| "panic".into()) } impl Server { diff --git a/crates/text/src/fontdb.rs b/crates/text/src/fontdb.rs index 604f3eee..079a7efe 100644 --- a/crates/text/src/fontdb.rs +++ b/crates/text/src/fontdb.rs @@ -812,7 +812,7 @@ fn scan_dir(dir: &std::path::Path, depth: usize, out: &mut BTreeMap bool { - path.extension().and_then(|e| e.to_str()).is_some_and(|e| OPEN_EXTENSIONS.iter().any(|x| x.eq_ignore_ascii_case(e))) + path.extension().and_then(OsStr::to_str).is_some_and(|e| OPEN_EXTENSIONS.iter().any(|x| x.eq_ignore_ascii_case(e))) } /// Whether `path` is a whole document (`.figcraft`, `.fig`, file JSON) rather than an image or SVG: /// dropped on the canvas it opens as a file of its own instead of adding its pages to the open one. pub(crate) fn is_document(path: &Path) -> bool { - path.extension().and_then(|e| e.to_str()).is_some_and(|e| ["figcraft", "fig", "json"].iter().any(|x| x.eq_ignore_ascii_case(e))) + path.extension().and_then(OsStr::to_str).is_some_and(|e| ["figcraft", "fig", "json"].iter().any(|x| x.eq_ignore_ascii_case(e))) } /// Reads the contents of dropped file `name` that has no file on disk to read by path. diff --git a/crates/ui-egui/src/windows.rs b/crates/ui-egui/src/windows.rs index 1740c9a7..2fadcf39 100644 --- a/crates/ui-egui/src/windows.rs +++ b/crates/ui-egui/src/windows.rs @@ -95,7 +95,7 @@ pub fn guard(app: &mut FigApp, ctx: &Context, f: impl FnOnce(&mut FigApp)) { let roots = app.automation_roots.clone(); let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| figcraft_engine::file_access::confined(roots.as_ref(), || f(&mut *app)))); if let Err(e) = res { - let msg = e.downcast_ref::<&str>().map(|s| s.to_string()).or_else(|| e.downcast_ref::().cloned()).unwrap_or_else(|| "panic".into()); + let msg = e.downcast_ref::<&str>().map(ToString::to_string).or_else(|| e.downcast_ref::().cloned()).unwrap_or_else(|| "panic".into()); log::error!("UI panic: {msg}"); app.toast(format!("Internal error (please report): {msg}")); ctx.request_repaint(); diff --git a/packaging/linux/package.sh b/packaging/linux/package.sh index a3ea29b1..c6c1284e 100755 --- a/packaging/linux/package.sh +++ b/packaging/linux/package.sh @@ -25,6 +25,12 @@ set -euo pipefail HERE="$ROOT/packaging/linux" APP_ID=ai.storyteller.figcraft +verify_sha256() { + local expected="$1" + local file="$2" + printf '%s %s\n' "$expected" "$file" | sha256sum -c - +} + SKIP_BUILD=0 FORMATS="appimage deb rpm tar" while [[ $# -gt 0 ]]; do @@ -145,21 +151,21 @@ if has appimage; then download="$TOOL.download" curl --proto '=https' -fsSL -o "$download" \ "https://github.com/AppImage/appimagetool/releases/download/$APPIMAGETOOL_VERSION/appimagetool-$ARCH.AppImage" - printf '%s %s\n' "$APPIMAGETOOL_SHA256" "$download" | sha256sum -c - + verify_sha256 "$APPIMAGETOOL_SHA256" "$download" chmod 755 "$download" mv "$download" "$TOOL" fi - printf '%s %s\n' "$APPIMAGETOOL_SHA256" "$TOOL" | sha256sum -c - + verify_sha256 "$APPIMAGETOOL_SHA256" "$TOOL" fi RUNTIME="$CARGO_TARGET_DIR/appimage-runtime-$APPIMAGE_RUNTIME_VERSION-$ARCH" if [[ ! -f "$RUNTIME" ]]; then download="$RUNTIME.download" curl --proto '=https' -fsSL -o "$download" \ "https://github.com/AppImage/type2-runtime/releases/download/$APPIMAGE_RUNTIME_VERSION/runtime-$ARCH" - printf '%s %s\n' "$APPIMAGE_RUNTIME_SHA256" "$download" | sha256sum -c - + verify_sha256 "$APPIMAGE_RUNTIME_SHA256" "$download" mv "$download" "$RUNTIME" fi - printf '%s %s\n' "$APPIMAGE_RUNTIME_SHA256" "$RUNTIME" | sha256sum -c - + verify_sha256 "$APPIMAGE_RUNTIME_SHA256" "$RUNTIME" # Absolute, because appimagetool runs in $DIST below (CARGO_TARGET_DIR or APPIMAGETOOL may be # relative, e.g. target/agent-). OUT="$(cd "$DIST" && pwd)/$BASENAME.AppImage" diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 6c09c921..313de3c6 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -31,7 +31,7 @@ fn cargo() -> Command { } fn root() -> std::path::PathBuf { - std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent().map(|p| p.to_path_buf()).unwrap_or_default() + std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent().map(std::path::Path::to_path_buf).unwrap_or_default() } fn main() -> ExitCode {