LRC-LIB-FOLDERS: the sidebar reads the home folder through the engine's helper, so its menu and the rename/move guard agree

This commit is contained in:
Nathaniel Ledford
2026-10-28 19:48:02 -04:00
parent 28e1b9fb16
commit 95a80c954c
3 changed files with 35 additions and 9 deletions
+1 -7
View File
@@ -571,15 +571,9 @@ pub(crate) fn is_protected_place(path: &Path, home: &Path) -> bool {
.any(|p| key(&p) == path)
}
/// The user's home folder; `None` when the host has none.
fn home_folder() -> Option<std::path::PathBuf> {
let home = if cfg!(windows) { std::env::var_os("USERPROFILE") } else { std::env::var_os("HOME") }?;
Some(home.into()).filter(|h: &std::path::PathBuf| !h.as_os_str().is_empty())
}
/// Refuses `from` when renaming or moving it would take the home folder or a standard place of it.
fn refuse_protected_place(command: &str, from: &str) -> Result<()> {
refuse_protected_place_in(command, from, home_folder().as_deref())
refuse_protected_place_in(command, from, crate::library::home_folder().as_deref())
}
/// What `from` names once the file system has read it: made absolute against the working folder
+31
View File
@@ -68,6 +68,37 @@ pub fn default_dir() -> Option<PathBuf> {
Some(PathBuf::from(home).join("Pictures").join(DEFAULT_NAME))
}
/// The user's home folder (`%USERPROFILE%` on Windows, `$HOME` elsewhere); `None` when the host has
/// none or it is empty. The one place the home path is read for Local's built-in places, in the
/// engine's rename/move guard and in the sidebar.
pub fn home_folder() -> Option<PathBuf> {
home_folder_from(cfg!(windows), |name| std::env::var_os(name))
}
fn home_folder_from(windows: bool, var: impl Fn(&str) -> Option<std::ffi::OsString>) -> Option<PathBuf> {
var(if windows { "USERPROFILE" } else { "HOME" }).filter(|h| !h.is_empty()).map(PathBuf::from)
}
#[cfg(test)]
mod home_tests {
use super::home_folder_from;
use std::ffi::OsString;
#[test]
fn windows_reads_userprofile_and_the_rest_read_home() {
let env = |name: &str| match name {
"HOME" => Some(OsString::from("/home/example")),
"USERPROFILE" => Some(OsString::from("C:\\Users\\example")),
_ => None,
};
assert_eq!(home_folder_from(true, env).as_deref(), Some(std::path::Path::new("C:\\Users\\example")));
assert_eq!(home_folder_from(false, env).as_deref(), Some(std::path::Path::new("/home/example")));
// only the other platform's variable is set: no home, never a guess from it
assert_eq!(home_folder_from(true, |n| (n == "HOME").then(|| OsString::from("/home/example"))), None);
assert_eq!(home_folder_from(false, |_| Some(OsString::new())), None);
}
}
pub struct Library {
/// The library directory, or a descriptive pseudo-path when the library isn't on disk.
pub dir: PathBuf,
+3 -2
View File
@@ -51,9 +51,10 @@ pub(super) fn local_now(app: &mut LightcraftApp, ui: &egui::Ui) -> Option<LocalN
Some(LocalNow { places, current, hidden })
}
/// The user's home folder; empty when the host has none.
/// The user's home folder, the engine's own reading of it (so the menu and the rename/move guard
/// agree); empty when the host has none.
fn home_folder() -> String {
std::env::var("HOME").or_else(|_| std::env::var("USERPROFILE")).unwrap_or_default()
lightcraft_engine::library::home_folder().map(|h| h.to_string_lossy().into_owned()).unwrap_or_default()
}
/// Local's built-in places under `home` as (English name, path), in order. The names are keys for