Support multiple file paths for config and theme

This commit is contained in:
Ofer Sadan 2024-01-02 13:38:10 +02:00 committed by Wei Zhang
parent a1bd4d6347
commit 94538d01e0
7 changed files with 582 additions and 579 deletions

View file

@ -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

1053
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -37,7 +37,6 @@ unicode-width = "0.1.*"
lscolors = "0.16.0"
wild = "2.0"
globset = "0.4.*"
xdg = "2.1"
yaml-rust = "0.4.*"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9"

View file

@ -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

View file

@ -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::<Self>(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<PathBuf> {
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<PathBuf> {
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<Item = PathBuf> {
[
dirs::config_dir(),
dirs::home_dir().map(|h| h.join(".config")),
]
.iter()
.filter_map(|p| p.as_ref().map(|p| p.join("lsd")))
.collect::<Vec<_>>()
.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;
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
}
}
Self::from_yaml(DEFAULT_CONFIG).unwrap()
})
.or(Self::from_yaml(DEFAULT_CONFIG).ok())
.expect("Failed to read both config file and default config")
}
}

View file

@ -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)]

View file

@ -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<D>(file: &str) -> Result<D, Error>
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(),
))
}
}
};