use crate::error::NoteError;
use crate::note::FrontMatter;
use crate::note::TMPL_VAR_CLIPBOARD;
use crate::note::TMPL_VAR_CLIPBOARD_HEADER;
use crate::note::TMPL_VAR_DIR_PATH;
use crate::note::TMPL_VAR_EXTENSION_DEFAULT;
use crate::note::TMPL_VAR_FM_;
use crate::note::TMPL_VAR_FM_ALL;
use crate::note::TMPL_VAR_LANG;
use crate::note::TMPL_VAR_PATH;
use crate::note::TMPL_VAR_STDIN;
use crate::note::TMPL_VAR_STDIN_HEADER;
use crate::note::TMPL_VAR_USERNAME;
use crate::settings::CLIPBOARD;
use crate::settings::STDIN;
use crate::CFG;
use std::env;
use std::ops::Deref;
use std::ops::DerefMut;
use std::path::Path;
use std::path::PathBuf;
#[cfg(target_family = "windows")]
use windows_sys::Win32::Globalization::GetUserDefaultLocaleName;
#[cfg(target_family = "windows")]
use windows_sys::Win32::System::SystemServices::LOCALE_NAME_MAX_LENGTH;
#[derive(Debug, PartialEq)]
pub struct ContextWrapper {
ct: tera::Context,
pub dir_path: PathBuf,
}
impl ContextWrapper {
pub fn new() -> Self {
Self {
ct: tera::Context::new(),
dir_path: PathBuf::new(),
}
}
pub fn insert_front_matter(&mut self, fm: &FrontMatter) {
let mut tera_map = tera::Map::new();
for (name, value) in &fm.map {
let val = match value {
tera::Value::String(_) => value.to_owned(),
tera::Value::Number(_) => value.to_owned(),
tera::Value::Bool(_) => value.to_owned(),
_ => tera::Value::String(value.to_string()),
};
tera_map.insert(name.to_string(), val.to_owned());
let mut var_name = TMPL_VAR_FM_.to_string();
var_name.push_str(name);
self.ct.insert(&var_name, &val);
}
self.ct.insert(TMPL_VAR_FM_ALL, &tera_map);
}
pub fn insert_environment(&mut self, path: &Path) -> Result<(), NoteError> {
let file = path.to_str().unwrap_or_default();
(*self).insert(TMPL_VAR_PATH, &file);
let dir_path = if path.is_dir() {
path
} else {
path.parent().unwrap_or_else(|| Path::new("./"))
};
(*self).insert(TMPL_VAR_DIR_PATH, &dir_path.to_str().unwrap_or_default());
(*self).insert(
TMPL_VAR_CLIPBOARD_HEADER,
CLIPBOARD.borrow_dependent().header,
);
(*self).insert(TMPL_VAR_CLIPBOARD, CLIPBOARD.borrow_dependent().body);
(*self).insert(TMPL_VAR_STDIN_HEADER, STDIN.borrow_dependent().header);
(*self).insert(TMPL_VAR_STDIN, STDIN.borrow_dependent().body);
let stdin_fm = FrontMatter::try_from(&*STDIN);
match stdin_fm {
Ok(ref stdin_fm) => log::trace!(
"YAML front matter in the input stream stdin found:\n{:#?}",
&stdin_fm
),
Err(ref e) => {
if !STDIN.borrow_dependent().header.is_empty() {
return Err(NoteError::InvalidStdinYaml {
source_str: e.to_string(),
});
}
}
};
let clipboard_fm = FrontMatter::try_from(&*CLIPBOARD);
match clipboard_fm {
Ok(ref clipboard_fm) => log::trace!(
"YAML front matter in the clipboard found:\n{:#?}",
&clipboard_fm
),
Err(ref e) => {
if !CLIPBOARD.borrow_dependent().header.is_empty() {
return Err(NoteError::InvalidClipboardYaml {
source_str: e.to_string(),
});
}
}
};
if let Ok(fm) = clipboard_fm {
self.insert_front_matter(&fm);
}
if let Ok(fm) = stdin_fm {
self.insert_front_matter(&fm);
}
(*self).insert(
TMPL_VAR_EXTENSION_DEFAULT,
CFG.filename.extension_default.as_str(),
);
let author = env::var("TPNOTEUSER").unwrap_or_else(|_| {
env::var("LOGNAME").unwrap_or_else(|_| {
env::var("USERNAME").unwrap_or_else(|_| env::var("USER").unwrap_or_default())
})
});
(*self).insert(TMPL_VAR_USERNAME, &author);
let tpnotelang = env::var("TPNOTELANG").ok();
#[cfg(not(target_family = "windows"))]
if let Some(tpnotelang) = tpnotelang {
(*self).insert(TMPL_VAR_LANG, &tpnotelang);
} else {
let lang_env = env::var("LANG").unwrap_or_default();
let mut language = "";
let mut territory = "";
if let Some((l, lang_env)) = lang_env.split_once('_') {
language = l;
if let Some((t, _codeset)) = lang_env.split_once('.') {
territory = t;
}
}
let mut lang = language.to_string();
lang.push('-');
lang.push_str(territory);
(*self).insert(TMPL_VAR_LANG, &lang);
}
#[cfg(target_family = "windows")]
if let Some(tpnotelang) = tpnotelang {
(*self).insert(TMPL_VAR_LANG, &tpnotelang);
} else {
let mut lang = String::new();
let mut buf = [0u16; LOCALE_NAME_MAX_LENGTH as usize];
let len = unsafe { GetUserDefaultLocaleName(buf.as_mut_ptr(), buf.len() as i32) };
if len > 0 {
lang = String::from_utf16_lossy(&buf[..((len - 1) as usize)]);
}
(*self).insert(TMPL_VAR_LANG, &lang);
}
self.dir_path = dir_path.to_path_buf();
Ok(())
}
}
impl Deref for ContextWrapper {
type Target = tera::Context;
fn deref(&self) -> &Self::Target {
&self.ct
}
}
impl DerefMut for ContextWrapper {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.ct
}
}