From 64b155af5be1baf72d535b411d17f76fd8e36c3d Mon Sep 17 00:00:00 2001 From: Ofer Sadan Date: Tue, 2 Jan 2024 13:36:00 +0200 Subject: [PATCH 1/3] Add support for tilde (~) expansion on windows --- CHANGELOG.md | 1 + src/core.rs | 5 +++++ src/meta/mod.rs | 2 +- src/meta/windows_utils.rs | 14 +++++++++++++- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b60fd735..610fb6ca7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 configuration fields) to truncate user and group names if they exceed a certain number of characters (disabled by default). - Add support for `--literal` from [PanGan21](https://github.com/PanGan21) +- Add support for tilde (`~`) expansion on Windows from [Ofer Sadan](https://github.com/ofersadan85) ## [v1.0.0] - 2023-08-25 diff --git a/src/core.rs b/src/core.rs index 54ec086b7..4b730a86e 100644 --- a/src/core.rs +++ b/src/core.rs @@ -19,6 +19,8 @@ use std::os::unix::io::AsRawFd; use crate::flags::blocks::Block; use crate::git_theme::GitTheme; #[cfg(target_os = "windows")] +use crate::meta::windows_utils; +#[cfg(target_os = "windows")] use terminal_size::terminal_size; pub struct Core { @@ -105,6 +107,9 @@ impl Core { _ => 1, }; + #[cfg(target_os = "windows")] + let paths: Vec = paths.into_iter().map(windows_utils::expand_home).collect(); + for path in paths { let mut meta = match Meta::from_path( &path, diff --git a/src/meta/mod.rs b/src/meta/mod.rs index 8e9432410..0063ee886 100644 --- a/src/meta/mod.rs +++ b/src/meta/mod.rs @@ -13,7 +13,7 @@ mod size; mod symlink; #[cfg(windows)] -mod windows_utils; +pub mod windows_utils; pub use self::access_control::AccessControl; pub use self::date::Date; diff --git a/src/meta/windows_utils.rs b/src/meta/windows_utils.rs index e647c26a5..a9db17251 100644 --- a/src/meta/windows_utils.rs +++ b/src/meta/windows_utils.rs @@ -2,7 +2,7 @@ use std::ffi::{OsStr, OsString}; use std::io; use std::mem::MaybeUninit; use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use std::path::Path; +use std::path::{Path, PathBuf}; use windows::Win32::Foundation::PSID; use windows::Win32::Security::{self, Authorization::TRUSTEE_W, ACL}; @@ -343,6 +343,18 @@ pub fn is_path_system(path: &Path) -> bool { ) } +/// Expands the `~` in a path to the current user's home directory +pub fn expand_home(path: PathBuf) -> PathBuf { + if path.starts_with("~") { + if let Some(home) = dirs::home_dir() { + let mut expanded = home.to_path_buf(); + expanded.push(path.strip_prefix("~").unwrap()); + return expanded; + } + } + path +} + #[cfg(test)] mod test { use super::*; From 0f93744a5969641164c448c0f51c417ce474cd56 Mon Sep 17 00:00:00 2001 From: Ofer Sadan Date: Tue, 2 Jan 2024 13:38:10 +0200 Subject: [PATCH 2/3] Support multiple file paths for config and theme --- CHANGELOG.md | 4 +++ Cargo.lock | 24 ++++++++--------- Cargo.toml | 3 +-- README.md | 19 +++++++++----- src/config_file.rs | 64 ++++++++++++++++++++++++---------------------- src/main.rs | 1 - src/theme.rs | 19 +++++++++----- 7 files changed, 76 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 610fb6ca7..2dbb43988 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 of characters (disabled by default). - Add support for `--literal` from [PanGan21](https://github.com/PanGan21) - Add support for tilde (`~`) expansion on Windows from [Ofer Sadan](https://github.com/ofersadan85) +- Add support to search multiple paths for config file and theme files from [Ofer Sadan](https://github.com/ofersadan85): + - `$XDG_CONFIG_HOME/lsd` or `$HOME/.config/lsd` (in that order) on non-Windows platforms (these are usually the same) + - `%APPDATA%\lsd` or `%USERPROFILE%\.config\lsd` (in that order) on Windows +- Add support for both `config.yaml` and `config.yml` for the config file name from [Ofer Sadan](https://github.com/ofersadan85) ## [v1.0.0] - 2023-08-25 diff --git a/Cargo.lock b/Cargo.lock index c2649ab06..c3321bfb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -226,22 +226,23 @@ checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.3.7" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -658,7 +659,6 @@ dependencies = [ "wild", "windows", "xattr", - "xdg", "yaml-rust", ] @@ -727,6 +727,12 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "os_str_bytes" version = "6.3.0" @@ -1566,12 +1572,6 @@ dependencies = [ "libc", ] -[[package]] -name = "xdg" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66b7c2281ebde13cf4391d70d4c7e5946c3c25e72a7b859ca8f677dcd0b0c61" - [[package]] name = "yaml-rust" version = "0.4.5" diff --git a/Cargo.toml b/Cargo.toml index 3c2ed4279..899c5e2dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ version_check = "0.9.*" [dependencies] crossterm = { version = "0.27.0", features = ["serde"] } -dirs = "4" +dirs = "5.0.1" libc = "0.2.*" human-sort = "0.2.2" term_grid = "0.1.*" @@ -37,7 +37,6 @@ unicode-width = "0.1.*" lscolors = "0.15.0" wild = "2.0" globset = "0.4.*" -xdg = "2.1" yaml-rust = "0.4.*" serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.8" diff --git a/README.md b/README.md index fc9bdd3f8..7ec8d2029 100644 --- a/README.md +++ b/README.md @@ -102,16 +102,21 @@ Check [Config file content](#config-file-content) for details. On non-Windows systems `lsd` follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) -convention for the location of the configuration file. The configuration dir -`lsd` uses is itself named `lsd`. In that directory it looks first for a file -called `config.yaml`. -For most people it should be enough to put their config file at -`~/.config/lsd/config.yaml`. +convention for the location of the configuration file. A `config.yaml` or `config.yml` file will be searched for in these locations, in order: + +- `$XDG_CONFIG_HOME/lsd` +- `$HOME/.config/lsd` + +On most systems these are mapped to the same location, which is `~/.config/lsd/config.yaml`. ### Windows -On Windows systems `lsd` only looks for the `config.yaml` files in one location: -`%APPDATA%\lsd\` +On Windows systems `lsd` searches for `config.yaml` or `config.yml` in the following locations, in order: + +- `%APPDATA%\lsd` +- `%USERPROFILE%\.config\lsd` + +These are usually something like `C:\Users\username\AppData\Roaming\lsd\config.yaml` and `C:\Users\username\.config\lsd\config.yaml` respectively. ### Custom diff --git a/src/config_file.rs b/src/config_file.rs index b32a1f1d4..31781a1b2 100644 --- a/src/config_file.rs +++ b/src/config_file.rs @@ -17,9 +17,6 @@ use serde::Deserialize; use std::fs; use std::io; -const CONF_DIR: &str = "lsd"; -const CONF_FILE_NAME: &str = "config.yaml"; - /// A struct to hold an optional configuration items, and provides methods /// around error handling in a config file. #[derive(Eq, PartialEq, Debug, Deserialize)] @@ -144,27 +141,6 @@ impl Config { serde_yaml::from_str::(yaml) } - /// This provides the path for a configuration file, according to the XDG_BASE_DIRS specification. - /// return None if error like PermissionDenied - #[cfg(not(windows))] - pub fn config_file_path() -> Option { - use xdg::BaseDirectories; - match BaseDirectories::with_prefix(CONF_DIR) { - Ok(p) => Some(p.get_config_home()), - Err(e) => { - print_error!("Can not open config file: {}.", e); - None - } - } - } - - /// This provides the path for a configuration file, inside the %APPDATA% directory. - /// return None if error like PermissionDenied - #[cfg(windows)] - pub fn config_file_path() -> Option { - dirs::config_dir().map(|x| x.join(CONF_DIR)) - } - /// This expand the `~` in path to HOME dir /// returns the origin one if no `~` found; /// returns None if error happened when getting home dir @@ -189,16 +165,44 @@ impl Config { } }) } + + /// Config paths for non-Windows platforms will be read from + /// `$XDG_CONFIG_HOME/lsd` or `$HOME/.config/lsd` + /// (usually, those are the same) in that order. + /// The default paths for Windows will be read from + /// `%APPDATA%\lsd` or `%USERPROFILE%\.config\lsd` in that order. + /// This will apply both to the config file and the theme file. + pub fn config_paths() -> impl Iterator { + [ + dirs::config_dir(), + dirs::home_dir().map(|h| h.join(".config")), + ] + .iter() + .filter_map(|p| p.as_ref().map(|p| p.join("lsd"))) + .collect::>() + .into_iter() + } } impl Default for Config { + /// Try to find either config.yaml or config.yml in the config directories + /// and use the first one that is found. If none are found, or the parsing fails, + /// use the default from DEFAULT_CONFIG. fn default() -> Self { - if let Some(p) = Self::config_file_path() { - if let Some(c) = Self::from_file(p.join(CONF_FILE_NAME)) { - return c; - } - } - Self::from_yaml(DEFAULT_CONFIG).unwrap() + Config::config_paths() + .find_map(|p| { + let yaml = p.join("config.yaml"); + let yml = p.join("config.yml"); + if yaml.is_file() { + Config::from_file(yaml) + } else if yml.is_file() { + Config::from_file(yml) + } else { + None + } + }) + .or(Self::from_yaml(DEFAULT_CONFIG).ok()) + .expect("Failed to read both config file and default config") } } diff --git a/src/main.rs b/src/main.rs index 1f7dd227c..a8cc1650f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,6 @@ extern crate terminal_size; extern crate unicode_width; extern crate url; extern crate wild; -extern crate xdg; extern crate yaml_rust; #[cfg(unix)] diff --git a/src/theme.rs b/src/theme.rs index f18b33106..82daeb488 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -38,9 +38,9 @@ pub enum Error { } impl Theme { - /// This read theme from file, - /// use the file path if it is absolute - /// prefix the config_file dir to it if it is not + /// Read theme from a file path + /// use the file path as-is if it is absolute + /// search the config paths folders for it if not pub fn from_path(file: &str) -> Result where D: DeserializeOwned + Default, @@ -54,9 +54,16 @@ impl Theme { let path = if Path::new(&real).is_absolute() { real } else { - match config_file::Config::config_file_path() { - Some(p) => p.join(real), - None => return Err(Error::InvalidPath("config home not existed".into())), + let path = config_file::Config::config_paths() + .map(|p| p.join(real.clone())) + .find(|p| p.is_file()); + match path { + Some(p) => p, + None => { + return Err(Error::InvalidPath( + "Did not find theme file in config folders".into(), + )) + } } }; From 9b0edf270e91766a9f46f34038ec7ac7589a430f Mon Sep 17 00:00:00 2001 From: Ofer Sadan Date: Thu, 4 Jan 2024 16:17:58 +0200 Subject: [PATCH 3/3] fixed "elided_lifetimes_in_associated_constant" warning --- src/meta/filetype.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meta/filetype.rs b/src/meta/filetype.rs index 61f63482c..66a235b95 100644 --- a/src/meta/filetype.rs +++ b/src/meta/filetype.rs @@ -16,7 +16,7 @@ pub enum FileType { impl FileType { #[cfg(windows)] - const EXECUTABLE_EXTENSIONS: &[&'static str] = &["exe", "msi", "bat", "ps1"]; + const EXECUTABLE_EXTENSIONS: &'static[&'static str] = &["exe", "msi", "bat", "ps1"]; #[cfg(unix)] pub fn new(