Merge pull request #3993 from dotCooCoo/fix/save-errors-name-save-command

Save: option errors name the save command that was run
This commit is contained in:
BFlat
2026-10-24 19:06:48 +07:00
committed by GitHub
2 changed files with 37 additions and 2 deletions
+12 -2
View File
@@ -520,6 +520,15 @@ fn blank_pages(doc: &Document) -> Document {
/// Why a `.ai` file saved without PDF content looks empty elsewhere.
const NOT_PDF_COMPATIBLE: &str = "saved without PDF content: VectorCraft opens it as before, other apps show empty pages";
/// `e`, an error of the export encoders, under the save command `cmd` instead of
/// `document.export`.
fn named_for_save(cmd: &str, e: crate::EngineError) -> crate::EngineError {
match e {
crate::EngineError::BadParams { cmd: c, msg } if c == "document.export" => bad(cmd, msg),
e => e,
}
}
/// The shared Save and Export encoder for PDF-compatible `.ai` files (and `.ait` templates, the
/// same file).
pub(super) fn encode_ai(cmd: &str, f: &Format, doc: &Document, p: &Value) -> Result<Encoded> {
@@ -603,7 +612,7 @@ fn job_for_stamped(s: &Session, st: &DocState, plan: SavePlan, stamped: Option<i
if matches!(plan.format.id, "vectorcraft" | "template") {
// Not remembered with the options: the preference decides each time it isn't given.
params = with_compression_pref(&s.prefs, &params);
super::native::save_options(cmd, plan.format, &doc, &params)?;
super::native::save_options(cmd, plan.format, &doc, &params).map_err(|e| named_for_save(cmd, e))?;
}
let boards = separate_boards(cmd, plan.format, &doc, &params)?;
let mut params = super::pdf::expand_preset(s, cmd, &params)?.into_owned();
@@ -658,7 +667,8 @@ impl SaveJob {
/// Encode one file of `doc` in the job's format.
fn encode_one(&self, doc: &Document) -> Result<Encoded> {
let (cmd, f) = (self.plan.mode.command(), self.plan.format);
let enc = if matches!(f.id, "ai" | "ait") { encode_ai(cmd, f, doc, &self.params)? } else { encode_all(doc, f.id, &self.params)? };
let enc = if matches!(f.id, "ai" | "ait") { encode_ai(cmd, f, doc, &self.params) } else { encode_all(doc, f.id, &self.params) }
.map_err(|e| named_for_save(cmd, e))?;
// A legacy .ai file per artboard.
let per_artboard = f.id == "ai" && super::legacy_ai::wanted(cmd, f, &self.params)?;
if enc.files.len() != 1 && !per_artboard {
+25
View File
@@ -160,6 +160,31 @@ fn pdf_compatible_files_carry_a_pdf() {
assert!(vectorcraft_format::pdf_content(&bytes_of(&s.execute("file.saveCopy", &json!({})).unwrap()["dataBase64"])).is_none());
}
#[test]
fn save_option_errors_name_the_save_command() {
let mut s = three_boards();
for (cmd, p) in [
("file.saveCopy", json!({"format": "pdf", "range": "5"})),
("file.saveCopy", json!({"format": "svg", "artboard": 5})),
("file.saveAs", json!({"format": "svg", "range": "4"})),
("document.save", json!({"format": "pdf", "artboards": [3]})),
("file.saveCopy", json!({"format": "ai", "compress": "yes"})),
("file.saveCopy", json!({"format": "ai", "pdfCompatible": false, "artboard": "B"})),
("file.saveCopy", json!({"format": "ai", "aiVersion": 7, "artboard": "B"})),
("file.saveCopy", json!({"format": "ait", "compress": "yes"})),
] {
let e = s.execute(cmd, &p).unwrap_err().to_string();
assert!(e.contains(&format!("`{cmd}`")) && !e.contains("document.export"), "{p}: {e}");
}
// A native file written to a path.
let dir = Folder::new("save-errors");
for (cmd, name) in [("document.save", "a.vectorcraft"), ("file.saveAs", "b.vectorcraft"), ("file.saveCopy", "c.vectorcraft")] {
let p = json!({"path": dir.file(name), "compress": "yes"});
let e = s.execute(cmd, &p).unwrap_err().to_string();
assert!(e.contains(&format!("`{cmd}`")) && !e.contains("document.export"), "{p}: {e}");
}
}
#[test]
fn ai_without_pdf_content_and_compression() {
let mut s = three_boards();