mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-24 10:27:44 -06:00
Backstage: non-Latin file names in Recent and Recover draw, not boxes (#3545)
File › Home's Recent list and File › Recover draw file names with the interface faces, which have no CJK, Arabic, Hebrew… glyphs; nothing asked for a covering face the way the window caption and comment balloons do, so a name like 小红书帖子-草稿.md showed as a row of boxes. A new ensure_backstage_fonts does what ensure_caption_fonts does for those names: CJK loads the CJK UI font, other scripts borrow the document fallback faces, re-checked only when the names change. Regression test fails without the call; checked live on the Recover page. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
05839461af
commit
6cab843f00
@@ -578,6 +578,8 @@ pub struct WordApp {
|
||||
/// The document (id, revision) whose comment text [`WordApp::ensure_comment_fonts`] last
|
||||
/// looked at.
|
||||
comment_fonts_for: Option<(u64, u64)>,
|
||||
/// The Recover list's document names [`WordApp::ensure_recover_fonts`] last looked at.
|
||||
recover_fonts_for: Option<u64>,
|
||||
/// The list of recent document paths [`WordApp::ensure_recent_fonts`] last looked at.
|
||||
recent_fonts_for: Vec<String>,
|
||||
/// The Find query and result count [`WordApp::ensure_find_fonts`] last looked at.
|
||||
@@ -716,6 +718,7 @@ impl WordApp {
|
||||
fonts_system_cjk: false,
|
||||
want_system_cjk: false,
|
||||
comment_fonts_for: None,
|
||||
recover_fonts_for: None,
|
||||
recent_fonts_for: Vec::new(),
|
||||
find_fonts_for: None,
|
||||
fonts_frames: 0,
|
||||
@@ -2010,6 +2013,34 @@ impl WordApp {
|
||||
}
|
||||
}
|
||||
|
||||
/// File › Recover draws the recovered documents' names with the interface faces too: a
|
||||
/// Chinese name was a row of boxes, an Arabic or Hebrew one likewise. The same treatment as
|
||||
/// the caption (and as the Recent list, `ensure_recent_fonts`): CJK loads the CJK UI font,
|
||||
/// other scripts borrow the document fallback faces. Looked at again only when the names change.
|
||||
fn ensure_recover_fonts(&mut self) {
|
||||
use std::hash::{Hash, Hasher};
|
||||
let docs = self.session.recovery_documents();
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
docs.iter().for_each(|d| d.name.hash(&mut hasher));
|
||||
let key = hasher.finish();
|
||||
if self.recover_fonts_for == Some(key) {
|
||||
return;
|
||||
}
|
||||
self.recover_fonts_for = Some(key);
|
||||
let chars: std::collections::BTreeSet<char> = docs.iter().flat_map(|d| d.name.chars()).collect();
|
||||
if chars.iter().any(|c| wordcraft_fonts::is_cjk(*c)) {
|
||||
self.want_system_cjk = true;
|
||||
}
|
||||
let text: String = chars.into_iter().collect();
|
||||
let new = theme::faces_for_preedit(&text, &self.canvas.ime_faces, theme::caption_char_covered, |c| {
|
||||
wordcraft_fonts::FontDb::global().fallback_for(c, u32::MAX)
|
||||
});
|
||||
if !new.is_empty() {
|
||||
self.canvas.ime_faces.extend(new);
|
||||
self.styled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Recent documents in Backstage (and the Start screen) show file names and paths with the
|
||||
/// interface faces. Borrow document fallback faces for characters in non-Latin scripts (#2067),
|
||||
/// as the caption and comments do.
|
||||
@@ -2142,6 +2173,7 @@ impl WordApp {
|
||||
// in this frame (dialog, drop, control channel) is picked up again at the end.
|
||||
self.ensure_caption_fonts();
|
||||
self.ensure_comment_fonts();
|
||||
self.ensure_recover_fonts();
|
||||
self.ensure_recent_fonts();
|
||||
self.ensure_find_fonts();
|
||||
self.install_ui_fonts(ctx, lang);
|
||||
@@ -2254,6 +2286,7 @@ impl WordApp {
|
||||
// The open above may have changed the file name the caption draws.
|
||||
self.ensure_caption_fonts();
|
||||
self.ensure_comment_fonts();
|
||||
self.ensure_recover_fonts();
|
||||
self.ensure_recent_fonts();
|
||||
self.ensure_find_fonts();
|
||||
self.install_ui_fonts(ctx, lang);
|
||||
@@ -3167,6 +3200,46 @@ mod tests {
|
||||
assert!(cjk.canvas.ime_faces.is_empty(), "CJK collections are not copied into the fallback list");
|
||||
}
|
||||
|
||||
/// File › Recover draws the recovered documents' names with the interface faces: a Chinese
|
||||
/// name there was a row of boxes because nothing asked for the CJK UI font. (The Recent list
|
||||
/// has its own, `ensure_recent_fonts`.)
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[test]
|
||||
fn non_latin_names_in_the_recover_list_get_a_face() {
|
||||
let with_copy = |name: &str| {
|
||||
let root = std::env::temp_dir().join(format!(
|
||||
"wordcraft-recover-fonts-{}-{}",
|
||||
std::process::id(),
|
||||
std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()
|
||||
));
|
||||
let id = "0123456789abcdef0123456789abcdef";
|
||||
std::fs::create_dir_all(root.join(id)).unwrap();
|
||||
let snapshot = json!({
|
||||
"version": 1, "generation": 1, "info": {"id": id, "name": name, "savedAt": "2026-10-11T10:42:00Z"},
|
||||
"document": wordcraft_doc::Document::from_text("Recovered work")
|
||||
});
|
||||
std::fs::write(root.join(id).join("snapshot-00000000000000000001.json"), serde_json::to_vec(&snapshot).unwrap()).unwrap();
|
||||
let mut a = app();
|
||||
a.session.enable_recovery(root.clone(), std::sync::Arc::new(|| {})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
let end = std::time::Instant::now() + std::time::Duration::from_secs(10);
|
||||
loop {
|
||||
ctx.run_ui(egui::RawInput::default(), |ui| a.logic(ui.ctx())).drop_without_applying_deltas();
|
||||
if a.session.recovery_ready() && !a.session.recovery_documents().is_empty() {
|
||||
// One more frame looks at the names it found.
|
||||
ctx.run_ui(egui::RawInput::default(), |ui| a.logic(ui.ctx())).drop_without_applying_deltas();
|
||||
break;
|
||||
}
|
||||
assert!(std::time::Instant::now() < end, "the recovery copy was never found");
|
||||
std::thread::sleep(std::time::Duration::from_millis(5));
|
||||
}
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
a
|
||||
};
|
||||
assert!(!with_copy("Synthetic draft").want_system_cjk, "Latin names need no CJK font");
|
||||
assert!(with_copy("会议记录-草稿").want_system_cjk, "a CJK name in Recover loads the CJK UI font");
|
||||
}
|
||||
|
||||
/// Comment balloons draw comment text and author names with the interface faces, which have
|
||||
/// no Arabic, so an Arabic comment was all boxes. A document with one borrows a document
|
||||
/// fallback face that covers it, once per document revision.
|
||||
|
||||
Reference in New Issue
Block a user