mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-14 19:26:56 -04:00
Part of #861: a file the user can't open is reported in a dialog
Opening a file that fails (File › Open, Open Recent, the Home screen, a
drop, the Finder or the command line) only set the status bar's
message, which is easily missed: it looked as if nothing happened. A
dialog now says "Can't open “name”." with the reason, as well. An
agent's file.open {path} still just answers with the error.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
9a0183a02d
commit
c19873e220
17 files changed
+68
-12
No files matched your search
@@ -118,12 +118,11 @@ fn end_before_teardown(frames: u64) {
|
||||
}
|
||||
|
||||
/// Open files handed to the app (command line, macOS Finder and Dock) as documents. A file that
|
||||
/// can't be opened is reported in the status bar and on stderr; the others still open.
|
||||
/// can't be opened is reported to the user and on stderr; the others still open.
|
||||
fn open_files(app: &mut VectorcraftApp, files: Vec<String>) {
|
||||
for f in files {
|
||||
if let Err(e) = vectorcraft_ui_egui::io::open_path(app, &f) {
|
||||
if let Err(e) = vectorcraft_ui_egui::io::open_reporting(app, &f) {
|
||||
eprintln!("vectorcraft: {f}: {e}");
|
||||
app.status(format!("Couldn't open {}: {e}", fileio::file_name(&f)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1850,10 +1850,9 @@ fn recent(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
crate::icons::icon(ui, "history", 16.0, t.icon);
|
||||
let r = ui.add(egui::Button::new(egui::RichText::new(&name).color(t.accent).size(13.0)).frame(false)).on_hover_text(&path);
|
||||
ui.add(egui::Label::new(egui::RichText::new(&folder).size(12.0).color(t.text_dim)).truncate());
|
||||
if r.clicked()
|
||||
&& let Err(e) = crate::io::open_path(app, &path)
|
||||
{
|
||||
app.status(e);
|
||||
if r.clicked() {
|
||||
// A failure is reported to the user there.
|
||||
let _ = crate::io::open_reporting(app, &path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,6 +36,17 @@ pub fn ask(app: &mut VectorcraftApp, message: &str, detail: &str, command: &str,
|
||||
app.ui.dialog = Some(Dialog::new(KIND, fields));
|
||||
}
|
||||
|
||||
/// The dialog kind of a message with a Close button only ([`tell`]).
|
||||
pub const MESSAGE: &str = "message";
|
||||
|
||||
pub(super) const MESSAGE_SPEC: DialogSpec = DialogSpec { ok: None, ..SPEC };
|
||||
|
||||
/// Tell the user `message` (with an optional `detail` line), both in the UI language, in a dialog
|
||||
/// they close.
|
||||
pub fn tell(app: &mut VectorcraftApp, message: &str, detail: &str) {
|
||||
app.ui.dialog = Some(Dialog::new(MESSAGE, json!({"message": message, "detail": detail})));
|
||||
}
|
||||
|
||||
/// Closes before running, so a dialog the command opens stays open.
|
||||
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
|
||||
let params = d.fields.get("__params").cloned().unwrap_or_else(|| json!({}));
|
||||
|
||||
@@ -216,6 +216,7 @@ registry! {
|
||||
FindFont: ["findFont"] => DialogSpec::window(crate::find_font::show, |app, _| crate::find_font::confirm(app)),
|
||||
SwatchOptions: [swatch_options::KIND] => swatch_options::SPEC,
|
||||
Confirm: [confirm::KIND] => confirm::SPEC,
|
||||
Message: [confirm::MESSAGE] => confirm::MESSAGE_SPEC,
|
||||
NewSwatch: [new_swatch::KIND] => new_swatch::SPEC,
|
||||
NewColorGroup: [new_color_group::KIND] => new_color_group::SPEC,
|
||||
GradientStop: ["gradientStop"] => gradient_stop::SPEC,
|
||||
|
||||
@@ -686,6 +686,7 @@
|
||||
Divide Vertically Into Dividir verticalmente en
|
||||
Do Not Move No mover
|
||||
Do you want to save the changes you made to “{name}”? ¿Quieres guardar los cambios hechos en “{name}”?
|
||||
Can't open “{name}”. No se puede abrir «{name}».
|
||||
Document Documento
|
||||
Document Color Mode Modo de color del documento
|
||||
Document Info Información del documento
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -688,6 +688,7 @@
|
||||
Divide Vertically Into Diviser verticalement en
|
||||
Do Not Move Ne pas déplacer
|
||||
Do you want to save the changes you made to “{name}”? Voulez-vous enregistrer les modifications apportées à « {name} » ?
|
||||
Can't open “{name}”. Impossible d’ouvrir « {name} ».
|
||||
Document Document
|
||||
Document Color Mode Mode colorimétrique du document
|
||||
Document Info Informations sur le document
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -686,6 +686,7 @@
|
||||
Divide Vertically Into Dividi verticalmente in
|
||||
Do Not Move Non spostare
|
||||
Do you want to save the changes you made to “{name}”? Vuoi salvare le modifiche apportate a “{name}”?
|
||||
Can't open “{name}”. Impossibile aprire «{name}».
|
||||
Document Documento
|
||||
Document Color Mode Metodo colore documento
|
||||
Document Info Informazioni documento
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1122,6 +1122,7 @@
|
||||
Divide Slices スライスを分割
|
||||
Divide Vertically Into 垂直方向に分割
|
||||
Do you want to save the changes you made to “{name}”? 「{name}」への変更を保存しますか?
|
||||
Can't open “{name}”. 「{name}」を開けません。
|
||||
Document ドキュメント
|
||||
Document Ink Options ドキュメントのインキオプション
|
||||
Document JSON ドキュメント JSON
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -636,6 +636,7 @@
|
||||
Divide Slices… Dividir Fatias…
|
||||
Divide Vertically Into Dividir Verticalmente Em
|
||||
Do you want to save the changes you made to “{name}”? Deseja salvar as alterações feitas em “{name}”?
|
||||
Can't open “{name}”. Não é possível abrir “{name}”.
|
||||
Document Documento
|
||||
Document Color Mode Modo de Cor do Documento
|
||||
Document Info Informações do Documento
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -684,6 +684,7 @@
|
||||
Divide Vertically Into Разделить по вертикали на
|
||||
Do Not Move Не перемещать
|
||||
Do you want to save the changes you made to “{name}”? Сохранить изменения, внесённые в «{name}»?
|
||||
Can't open “{name}”. Не удаётся открыть «{name}».
|
||||
Document Документ
|
||||
Document Color Mode Цветовой режим документа
|
||||
Document Info Сведения о документе
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -680,6 +680,7 @@
|
||||
Divide Vertically Into Розділити по вертикалі на
|
||||
Do Not Move Не переміщати
|
||||
Do you want to save the changes you made to “{name}”? Зберегти зміни, внесені до «{name}»?
|
||||
Can't open “{name}”. Не вдається відкрити «{name}».
|
||||
Document Документ
|
||||
Document Color Mode Колірний режим документа
|
||||
Document Info Відомості про документ
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 632 and column 40.
|
@@ -666,6 +666,7 @@
|
||||
Divide Vertically Into 垂直分割为
|
||||
Do Not Move 不移动
|
||||
Do you want to save the changes you made to “{name}”? 要存储对“{name}”所做的更改吗?
|
||||
Can't open “{name}”. 无法打开“{name}”。
|
||||
Document 文档
|
||||
Document Color Mode 文档颜色模式
|
||||
Document Info 文档信息
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -684,6 +684,7 @@
|
||||
Divide Vertically Into 垂直分割為
|
||||
Do Not Move 不移動
|
||||
Do you want to save the changes you made to “{name}”? 要儲存對「{name}」所做的變更嗎?
|
||||
Can't open “{name}”. 無法開啟「{name}」。
|
||||
Document 文件
|
||||
Document Color Mode 文件色彩模式
|
||||
Document Info 文件資訊
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -97,7 +97,24 @@ pub fn open_dialog(app: &mut VectorcraftApp) -> Result<(), String> {
|
||||
return Ok(());
|
||||
}
|
||||
let path = pick_open(app, &FilePick { filters: fileio::open_filters().collect(), ..Default::default() })?;
|
||||
open_path(app, &path).map(|_| ())
|
||||
open_reporting(app, &path).map(|_| ())
|
||||
}
|
||||
|
||||
/// A file the user asked to open (File › Open, Open Recent, the Home screen, a drop, the Finder)
|
||||
/// couldn't be: say so in a dialog as well as the status bar, which is easily missed (#861).
|
||||
pub fn report_open_error(app: &mut VectorcraftApp, name: &str, e: &str) {
|
||||
app.status(format!("Couldn't open {name}: {e}"));
|
||||
let message = crate::i18n::fmt(tl!("Can't open “{name}”."), &[("name", name)]);
|
||||
dialogs::confirm::tell(app, &message, &crate::i18n::message(crate::i18n::current(), e));
|
||||
}
|
||||
|
||||
/// [`open_path`] for a file the user asked for, a failure reported ([`report_open_error`]).
|
||||
pub fn open_reporting(app: &mut VectorcraftApp, path: &str) -> Result<Value, String> {
|
||||
let r = open_path(app, path);
|
||||
if let Err(e) = &r {
|
||||
report_open_error(app, &fileio::file_name(path), e);
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
fn read(app: &VectorcraftApp, path: &str) -> Result<Vec<u8>, String> {
|
||||
@@ -699,6 +716,24 @@ mod tests {
|
||||
(VectorcraftApp::new(Session::new(), services), written)
|
||||
}
|
||||
|
||||
/// #861: a file the user opens that can't be opened is reported in a dialog they close, not
|
||||
/// only in the status bar; a file an agent opens by path only answers with the error.
|
||||
#[test]
|
||||
fn a_file_the_user_cant_open_is_reported_in_a_dialog() {
|
||||
let (mut app, _) = app();
|
||||
app.services.read = Some(Box::new(|_: &str| Err("no such file".into())));
|
||||
assert!(open_reporting(&mut app, "/docs/gone.ai").is_err());
|
||||
let d = app.ui.dialog.take().expect("a dialog says so");
|
||||
assert_eq!(
|
||||
(d.kind.as_str(), d.str("message"), d.str("detail")),
|
||||
(dialogs::confirm::MESSAGE, "Can't open “gone.ai”.".to_string(), "no such file".to_string())
|
||||
);
|
||||
assert!(app.ui.status.contains("gone.ai"));
|
||||
// An agent's `file.open {path}` gets the error back and no dialog.
|
||||
assert!(app.run("file.open", json!({"path": "/docs/gone.ai"})).is_err());
|
||||
assert!(app.ui.dialog.is_none());
|
||||
}
|
||||
|
||||
fn bytes_of(app: &mut VectorcraftApp, cmd: &str, p: Value) -> Vec<u8> {
|
||||
let v = app.session.execute(cmd, &p).unwrap();
|
||||
vectorcraft_format::base64_decode(v["dataBase64"].as_str().unwrap()).unwrap()
|
||||
|
||||
@@ -706,7 +706,7 @@ impl VectorcraftApp {
|
||||
self.services.inbox.as_ref().map(|q| std::mem::take(&mut *q.lock().unwrap_or_else(|e| e.into_inner()))).unwrap_or_default();
|
||||
for (name, bytes) in arrived {
|
||||
if let Err(e) = io::open_bytes(self, &name, &bytes, None) {
|
||||
self.status(format!("Couldn't open {name}: {e}"));
|
||||
io::report_open_error(self, &name, &e);
|
||||
}
|
||||
}
|
||||
place::drain(self);
|
||||
|
||||
@@ -884,7 +884,7 @@ pub fn run_ui_command(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<R
|
||||
"file.revert" if p.get("confirmed").and_then(Value::as_bool) != Some(true) => io::ask_revert(app),
|
||||
"file.reveal" => io::reveal(app),
|
||||
id if id.starts_with("file.openRecent") => match recent_slot(app, id).cloned() {
|
||||
Some(path) => io::open_path(app, &path),
|
||||
Some(path) => io::open_reporting(app, &path),
|
||||
None => Err("no such recent file".into()),
|
||||
},
|
||||
"type.findFont" => {
|
||||
|
||||
@@ -357,8 +357,10 @@ pub fn drop_files(app: &mut VectorcraftApp, mut files: Vec<(DropTarget, DropFile
|
||||
}),
|
||||
},
|
||||
};
|
||||
if let Err(e) = r {
|
||||
app.status(if target == DropTarget::Open { format!("Couldn't open {name}: {e}") } else { format!("Couldn't place {name}: {e}") });
|
||||
match r {
|
||||
Err(e) if target == DropTarget::Open => io::report_open_error(app, &name, &e),
|
||||
Err(e) => app.status(format!("Couldn't place {name}: {e}")),
|
||||
Ok(()) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user