use crate::config::*;
use indicatif::{ProgressBar, ProgressStyle};
use log::*;
use serde::{de, Deserialize};
use std::{
ffi::OsStr,
fs, io,
path::{Component, Path, PathBuf},
};
pub fn new_progress_bar(n: u64) -> ProgressBar {
ProgressBar::new(n).with_style(
ProgressStyle::default_bar().template("{msg} {wide_bar} {pos}/{len}"),
)
}
pub fn walk_and_resolve_paths(path: &Path, ext: &str) -> Vec<PathBuf> {
walkdir::WalkDir::new(path)
.into_iter()
.filter_map(|e| {
e.ok()
.filter(|e| e.file_type().is_file())
.map(|e| e.into_path())
.filter(|p| p.extension().and_then(OsStr::to_str) == Some(ext))
.and_then(|p| fs::canonicalize(p).ok())
})
.collect()
}
pub fn deserialize_absolute_path<'de, D>(d: D) -> Result<PathBuf, D::Error>
where
D: de::Deserializer<'de>,
{
let value = PathBuf::deserialize(d)?;
let value = PathBuf::from(
shellexpand::full(&value.to_string_lossy())
.map_err(|x| {
de::Error::invalid_value(
de::Unexpected::Str(value.to_string_lossy().as_ref()),
&x.to_string().as_str(),
)
})?
.to_string(),
);
let value = normalize_path(value.as_path());
if !value.is_absolute() {
return Err(de::Error::invalid_value(
de::Unexpected::Str(value.to_string_lossy().as_ref()),
&"path must be absolute",
));
}
Ok(value)
}
pub fn normalize_path(path: &Path) -> PathBuf {
let mut components = path.components().peekable();
let mut ret =
if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
components.next();
PathBuf::from(c.as_os_str())
} else {
PathBuf::new()
};
for component in components {
match component {
Component::Prefix(..) => unreachable!(),
Component::RootDir => {
ret.push(component.as_os_str());
}
Component::CurDir => {}
Component::ParentDir => {
ret.pop();
}
Component::Normal(c) => {
ret.push(c);
}
}
}
ret
}
pub fn load_config<'a, I: Into<Option<&'a Path>>>(
path: I,
merge: bool,
) -> io::Result<Config> {
let maybe_path = path.into();
trace!("load_config(path = {:?}, merge = {})", maybe_path, merge);
let mut config: Config = if let Some(path) = maybe_path {
let config_string = std::fs::read_to_string(path)?;
toml::from_str(config_string.as_str())?
} else {
Config::default()
};
if config.wikis.is_empty() || merge {
match load_vimwiki_list() {
Ok(wikis) => config.wikis.extend(wikis),
Err(x) => {
error!("Failed to load vimwiki_list from vim/neovim: {}", x)
}
}
}
Ok(config)
}
fn load_vimwiki_list() -> std::io::Result<Vec<WikiConfig>> {
trace!("load_vimwiki_list()");
let vimwiki_list_json = vimvar::load_global_var("vimwiki_list", false)?;
trace!("g:vimwiki_list == {:?}", vimwiki_list_json);
if let Some(json) = vimwiki_list_json {
serde_json::from_value(json).map_err(Into::into)
} else {
Ok(Vec::new())
}
}