CP6.13: hunspell.rs — Windows drives are probed for LibreOffice only when its language folders are wanted (CodeRabbit on craft-libs#489)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
This commit is contained in:
Martin BallandClaude Opus 5.5 committed 2026-11-01 22:34:33 +00:00
1 parent 9614ab270d
commit 6057debe6e
1 file changed
+34 -10
+34 -10
View File
@@ -105,16 +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()));
}
}
// If LibreOffice is installed on another drive (e.g. D:\Program Files\LibreOffice), check drives C..Z
for drive in b'C'..=b'Z' {
let drive_char = drive as char;
for pf in ["Program Files", "Program Files (x86)"] {
let lo_base = PathBuf::from(format!(r"{drive_char}:\{pf}\LibreOffice\share\extensions"));
if lo_base.is_dir() {
system.extend(lo_dirs(&lo_base.to_string_lossy()));
}
}
}
system.extend(lo_drive_dirs(lo_exts, 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
@@ -144,6 +135,23 @@ fn search_tiers(lo_exts: Option<&[String]>) -> (Vec<PathBuf>, Vec<PathBuf>) {
(dirs, system)
}
/// 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
/// `lo_exts` (no LibreOffice folders are wanted then).
fn lo_drive_dirs(lo_exts: Option<&[String]>, is_dir: impl Fn(&Path) -> bool) -> 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
}
/// 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> {
@@ -610,6 +618,22 @@ fn decode_utf8_dic(dic: &[u8]) -> Result<String, String> {
mod tests {
use super::*;
/// CodeRabbit on craft-libs#489: without LibreOffice extension names no drive is probed; with
/// them, only drives where LibreOffice is found give folders.
#[test]
fn libreoffice_drives_are_probed_only_when_wanted() {
let probes = std::cell::Cell::new(0);
let count = |_: &Path| {
probes.set(probes.get() + 1);
false
};
assert!(lo_drive_dirs(None, count).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")]);
}
/// Another region's Language pack never beats the system's dictionary of the right region
/// (`pt-pt` pack vs system `pt_BR`; `de-ch` vs `de_DE`; `en-gb` vs `en_US`), but beats the
/// system's other names; the right region's pack beats the system; the dictionaries folder