mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-08 19:42:12 +00:00
CP6.13: craft-libs#495 review — Windows drives are probed for LibreOffice once per process; sr@latin is sr-latn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
This commit is contained in:
1 parent
c5cc9c4b7a
commit
89fa1559e9
2 files changed
+34
-16
No files matched your search
@@ -105,7 +105,7 @@ fn search_tiers(lo_exts: Option<&[String]>) -> (Vec<PathBuf>, Vec<PathBuf>) {
|
||||
system.extend(lo_dirs(&base.join("LibreOffice").join("share").join("extensions").to_string_lossy()));
|
||||
}
|
||||
}
|
||||
system.extend(lo_drive_dirs(lo_exts, Path::is_dir));
|
||||
system.extend(lo_drive_dirs(lo_exts, || LO_DRIVE_BASES.get_or_init(|| lo_drive_bases(Path::is_dir))));
|
||||
} else if cfg!(target_os = "macos") {
|
||||
if let Some(h) = &home {
|
||||
// An app started from Finder or the Dock doesn't see `WORDCRAFT_DICTIONARIES`; this
|
||||
@@ -136,22 +136,25 @@ fn search_tiers(lo_exts: Option<&[String]>) -> (Vec<PathBuf>, Vec<PathBuf>) {
|
||||
}
|
||||
|
||||
/// LibreOffice's language folders (`<drive>:\Program Files\LibreOffice\share\extensions\<ext>`)
|
||||
/// on the drives C to Z where `is_dir` finds LibreOffice installed. No drive is probed without
|
||||
/// on the drives C to Z where LibreOffice is installed (`bases`). No drive is probed without
|
||||
/// `lo_exts` (no LibreOffice folders are wanted then).
|
||||
fn lo_drive_dirs(lo_exts: Option<&[String]>, is_dir: impl Fn(&Path) -> bool) -> Vec<PathBuf> {
|
||||
fn lo_drive_dirs<'a>(lo_exts: Option<&[String]>, bases: impl FnOnce() -> &'a [PathBuf]) -> Vec<PathBuf> {
|
||||
let Some(exts) = lo_exts else { return Vec::new() };
|
||||
let mut out = Vec::new();
|
||||
for drive in 'C'..='Z' {
|
||||
for pf in ["Program Files", "Program Files (x86)"] {
|
||||
let base = PathBuf::from(format!(r"{drive}:\{pf}\LibreOffice\share\extensions"));
|
||||
if is_dir(&base) {
|
||||
out.extend(exts.iter().map(|e| base.join(e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
out
|
||||
bases().iter().flat_map(|base| exts.iter().map(|e| base.join(e))).collect()
|
||||
}
|
||||
|
||||
/// The `LibreOffice\share\extensions` folders on drives C to Z (48 probes).
|
||||
fn lo_drive_bases(is_dir: impl Fn(&Path) -> bool) -> Vec<PathBuf> {
|
||||
('C'..='Z')
|
||||
.flat_map(|drive| ["Program Files", "Program Files (x86)"].map(|pf| PathBuf::from(format!(r"{drive}:\{pf}\LibreOffice\share\extensions"))))
|
||||
.filter(|base| is_dir(base))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// [`lo_drive_bases`], probed once per process.
|
||||
// ponytail: a LibreOffice installed while the app runs is seen after a restart.
|
||||
static LO_DRIVE_BASES: std::sync::OnceLock<Vec<PathBuf>> = std::sync::OnceLock::new();
|
||||
|
||||
/// The user's data folder on Linux and the BSDs: `$XDG_DATA_HOME` when it is an absolute path (the
|
||||
/// XDG Base Directory spec ignores a relative one), else `~/.local/share`.
|
||||
fn xdg_data_home(xdg: Option<std::ffi::OsString>, home: Option<&Path>) -> Option<PathBuf> {
|
||||
@@ -627,11 +630,20 @@ mod tests {
|
||||
probes.set(probes.get() + 1);
|
||||
false
|
||||
};
|
||||
assert!(lo_drive_dirs(None, count).is_empty());
|
||||
// craft-libs#495 review: the drives are probed once, not on every lookup.
|
||||
let cache = std::sync::OnceLock::new();
|
||||
let cached = || cache.get_or_init(|| lo_drive_bases(count)).as_slice();
|
||||
assert!(lo_drive_dirs(None, cached).is_empty());
|
||||
assert_eq!(probes.get(), 0);
|
||||
let exts = ["dict-tr".to_string()];
|
||||
let found = lo_drive_dirs(Some(&exts), |p: &Path| p.to_string_lossy().starts_with(r"D:\Program Files\"));
|
||||
assert_eq!(found, [PathBuf::from(r"D:\Program Files\LibreOffice\share\extensions").join("dict-tr")]);
|
||||
assert!(lo_drive_dirs(Some(&exts), cached).is_empty());
|
||||
assert!(lo_drive_dirs(Some(&exts), cached).is_empty());
|
||||
assert_eq!(probes.get(), 48);
|
||||
let found = lo_drive_bases(|p: &Path| p.to_string_lossy().starts_with(r"D:\Program Files\"));
|
||||
assert_eq!(
|
||||
lo_drive_dirs(Some(&exts), || found.as_slice()),
|
||||
[PathBuf::from(r"D:\Program Files\LibreOffice\share\extensions").join("dict-tr")]
|
||||
);
|
||||
}
|
||||
|
||||
/// Another region's Language pack never beats the system's dictionary of the right region
|
||||
|
||||
@@ -147,6 +147,9 @@ impl ProofLang {
|
||||
} else {
|
||||
ProofLang::De
|
||||
}
|
||||
} else if tag.split_once('@').is_some_and(|(_, m)| m.eq_ignore_ascii_case("latin")) {
|
||||
// POSIX `sr_RS@latin`: the Latin-script language (`sr-latn`).
|
||||
PackLocale::new(&format!("{primary}-latn")).map_or(ProofLang::Other, ProofLang::Pack)
|
||||
} else {
|
||||
PackLocale::new(tag).map_or(ProofLang::Other, ProofLang::Pack)
|
||||
}
|
||||
@@ -446,6 +449,9 @@ mod tests {
|
||||
// craft-libs#482 review: a POSIX charset or modifier with no region.
|
||||
assert_tags(&["en.UTF-8", "en@euro"], ProofLang::En);
|
||||
assert_tags(&["de.UTF-8"], ProofLang::De);
|
||||
let sr_latn = ProofLang::Pack(PackLocale::new("sr-latn").unwrap());
|
||||
assert_tags(&["sr@latin", "sr_RS@latin", "sr_RS.UTF-8@latin", "sr-Latn"], sr_latn);
|
||||
assert_tags(&["sr", "sr@cyrillic"], ProofLang::Pack(PackLocale::new("sr").unwrap()));
|
||||
assert_tags(&["pt", "pt-BR", "PT_br", "pt-BR.UTF-8", "pt-AO", "por"], ProofLang::Pt);
|
||||
let pt_pt = ProofLang::Pack(PackLocale::new("pt-pt").unwrap());
|
||||
assert_tags(&[" pt-PT ", "pt_PT.UTF-8", "por-PT"], pt_pt);
|
||||
|
||||
Reference in new issue
Block a user