mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-26 10:47:11 -06:00
Save, Save As and Save a Copy already added the save format's extension to a name typed in the save panel, but every other write through it (Export, Export Selection, Save as PDF, text and preset exports, Document Info) wrote the name as typed, so "art" became an extensionless file. The save panel's answer now goes through one rule (io::with_extension): kept when it ends in the suggested name's extension or names a known format, else that extension is added. The web already downloads under the suggested name or adds the format's extension in its Save As dialog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
75 lines
2.9 KiB
Rust
75 lines
2.9 KiB
Rust
//! A name typed in a save panel without an extension gets the chosen format's: Save, Save As,
|
|
//! Save a Copy, Export, Export Selection and other writes through a save panel.
|
|
|
|
use std::cell::RefCell;
|
|
use std::rc::Rc;
|
|
|
|
use serde_json::json;
|
|
use vectorcraft_engine::Session;
|
|
|
|
use crate::{FilePick, Services, VectorcraftApp, io};
|
|
|
|
type Written = Rc<RefCell<Vec<String>>>;
|
|
|
|
/// An app with a document whose save panel answers `typed` and whose writer records the paths.
|
|
fn saving_app(typed: &'static str) -> (VectorcraftApp, Written) {
|
|
let written = Written::default();
|
|
let w = written.clone();
|
|
let services = Services {
|
|
write: Some(Box::new(move |p: &str, _: &[u8]| {
|
|
w.borrow_mut().push(p.to_string());
|
|
Ok(())
|
|
})),
|
|
pick_save: Some(Box::new(move |_: &FilePick| Some(typed.to_string()))),
|
|
..Default::default()
|
|
};
|
|
let mut app = VectorcraftApp::new(Session::new(), services);
|
|
app.run("file.new", json!({"width": 100, "height": 100})).unwrap();
|
|
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 30, "height": 20})).unwrap();
|
|
(app, written)
|
|
}
|
|
|
|
fn last(w: &Written) -> String {
|
|
w.borrow().last().cloned().unwrap_or_default()
|
|
}
|
|
|
|
#[test]
|
|
fn saves_add_the_format_extension_to_a_bare_name() {
|
|
let (mut app, w) = saving_app("/tmp/Untitled-1");
|
|
app.run("file.save", json!({})).unwrap();
|
|
assert_eq!(last(&w), "/tmp/Untitled-1.vectorcraft");
|
|
assert_eq!(app.session.active().unwrap().path.as_deref(), Some("/tmp/Untitled-1.vectorcraft"));
|
|
let (mut app, w) = saving_app("/tmp/copy");
|
|
app.run("file.saveCopy", json!({"format": "svg", "svg": {}})).unwrap();
|
|
assert_eq!(last(&w), "/tmp/copy.svg");
|
|
let (mut app, w) = saving_app("/tmp/as");
|
|
app.run("file.saveAs", json!({"format": "pdf", "options": {}})).unwrap();
|
|
assert_eq!(last(&w), "/tmp/as.pdf");
|
|
}
|
|
|
|
#[test]
|
|
fn exports_add_the_format_extension_to_a_bare_name() {
|
|
let (mut app, w) = saving_app("/tmp/art");
|
|
io::export(&mut app, Some("png"), None, &json!({})).unwrap();
|
|
assert_eq!(last(&w), "/tmp/art.png");
|
|
app.run("select.all", json!({})).unwrap();
|
|
app.run("document.exportSelection", json!({})).unwrap();
|
|
assert_eq!(last(&w), "/tmp/art.png", "Export Selection: its default format");
|
|
io::save_command_output(&mut app, "document.export", "txt", json!({"format": "txt"})).unwrap();
|
|
assert_eq!(last(&w), "/tmp/art.txt");
|
|
}
|
|
|
|
#[test]
|
|
fn typed_extensions_are_kept() {
|
|
let (mut app, w) = saving_app("/tmp/art.svg");
|
|
io::export(&mut app, Some("svg"), None, &json!({})).unwrap();
|
|
assert_eq!(last(&w), "/tmp/art.svg");
|
|
let (mut app, w) = saving_app("/tmp/My.Poster.SVG");
|
|
io::export(&mut app, Some("svg"), None, &json!({})).unwrap();
|
|
assert_eq!(last(&w), "/tmp/My.Poster.SVG");
|
|
// A dot in the name isn't an extension.
|
|
let (mut app, w) = saving_app("/tmp/v1.2");
|
|
io::export(&mut app, Some("png"), None, &json!({})).unwrap();
|
|
assert_eq!(last(&w), "/tmp/v1.2.png");
|
|
}
|