Skip to content

Commit

Permalink
Custom definitions files (#172)
Browse files Browse the repository at this point in the history
Implements #79.

The CLI will now load more than the first `definitions.units` file it
finds. It will stick them together and load them as one big
`definitions.units` file. This lets you easily add custom definitions by
adding them to `~/.config/rink/definitions.units`. The format for it is
already documented in the manpage.
  • Loading branch information
tiffany352 authored May 11, 2024
1 parent 07dc170 commit 8cf08d2
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 29 deletions.
70 changes: 45 additions & 25 deletions cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,24 +223,34 @@ impl Config {
}
}

fn read_from_search_path(filename: &str, paths: &[PathBuf]) -> Result<String> {
for path in paths {
let mut buf = PathBuf::from(path);
buf.push(filename);
if let Ok(result) = read_to_string(buf) {
return Ok(result);
}
fn read_from_search_path(
filename: &str,
paths: &[PathBuf],
default: Option<&'static str>,
) -> Result<Vec<String>> {
let result: Vec<String> = paths
.iter()
.filter_map(|path| {
let mut buf = PathBuf::from(path);
buf.push(filename);
read_to_string(buf).ok()
})
.chain(default.map(ToOwned::to_owned))
.collect();

if result.is_empty() {
Err(eyre!(
"Could not find {}, and rink was not built with one bundled. Search path:{}",
filename,
paths
.iter()
.map(|path| format!("\n {}", path.display()))
.collect::<Vec<String>>()
.join("")
))
} else {
Ok(result)
}

Err(eyre!(
"Could not find {} in search path. Paths:{}",
filename,
paths
.iter()
.map(|path| format!("{}", path.display()))
.collect::<Vec<String>>()
.join("\n ")
))
}

fn load_live_currency(config: &Currency) -> Result<ast::Defs> {
Expand All @@ -255,8 +265,10 @@ fn load_live_currency(config: &Currency) -> Result<ast::Defs> {
}

fn try_load_currency(config: &Currency, ctx: &mut Context, search_path: &[PathBuf]) -> Result<()> {
let base = read_from_search_path("currency.units", search_path)
.or_else(|err| CURRENCY_FILE.map(ToOwned::to_owned).ok_or(err)).wrap_err("Rink was not built with a bundled currency.units file, and one was not found in the search path.")?;
let base = read_from_search_path("currency.units", search_path, CURRENCY_FILE)?
.into_iter()
.next()
.unwrap();

let mut base_defs = gnu_units::parse_str(&base);
let mut live_defs = load_live_currency(config)?;
Expand All @@ -283,24 +295,32 @@ pub fn read_config() -> Result<Config> {
/// Creates a context by searching standard directories
pub fn load(config: &Config) -> Result<Context> {
let mut search_path = vec![PathBuf::from("./")];
if let Some(config_dir) = dirs::config_dir() {
if let Some(mut config_dir) = dirs::config_dir() {
config_dir.push("rink");
search_path.push(config_dir);
}
if let Some(prefix) = option_env!("RINK_PATH") {
search_path.push(prefix.into());
}

// Read definitions.units
let units = read_from_search_path("definitions.units", &search_path)
.or_else(|err| DEFAULT_FILE.map(ToOwned::to_owned).ok_or(err).wrap_err("Rink was not built with a bundled definitions.units file, and one was not found in the search path."))?;
let units_files = read_from_search_path("definitions.units", &search_path, DEFAULT_FILE)?;

let unit_defs: Vec<_> = units_files
.iter()
.map(|s| gnu_units::parse_str(s).defs)
.flatten()
.collect();

// Read datepatterns.txt
let dates = read_from_search_path("datepatterns.txt", &search_path)
.or_else(|err| DATES_FILE.map(ToOwned::to_owned).ok_or(err).wrap_err("Rink was not built with a bundled datepatterns.txt file, and one was not found in the search path."))?;
let dates = read_from_search_path("datepatterns.txt", &search_path, DATES_FILE)?
.into_iter()
.next()
.unwrap();

let mut ctx = Context::new();
ctx.save_previous_result = true;
ctx.load(gnu_units::parse_str(&units))
ctx.load(rink_core::ast::Defs { defs: unit_defs })
.map_err(|err| eyre!(err))?;
ctx.load_dates(datetime::parse_datefile(&dates));

Expand Down
2 changes: 1 addition & 1 deletion docs/rink-dates.5.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Files

Rink searches the following locations:

* `./rink/datepatterns.txt`
* `./datepatterns.txt`
* `__$XDG_CONFIG_DIR__/rink/datepatterns.txt`
* `/usr/share/rink/datepatterns.txt`
Expand Down
10 changes: 7 additions & 3 deletions docs/rink-defs.5.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -248,16 +248,20 @@ decimal point.
Files
-----

Rink searches for the definitions file in these locations:
Rink searches for definitions files in these locations:

* `./rink/definitions.units`
* `./definitions.units`
* `$XDG_CONFIG_DIR/rink/definitions.units`
* `/usr/share/rink/definitions.units`

It will load all of the files it finds. The files can reference
definitions from each other. This can be used for custom definitions
building on top of the default units database.

When live currency fetching is enabled, Rink also looks for a currency
file in these locations:

* `./rink/currency.units`
* `./currency.units`
* `$XDG_CONFIG_DIR/rink/currency.units`
* `/usr/share/rink/currency.units`

Expand Down

0 comments on commit 8cf08d2

Please sign in to comment.