use crate::{
assets::get_l10n_text,
conversion::{
convert::convert_data_format,
fmt::{
auto_detect_unknown_fmt, check_supported_formats,
get_different_file_format, get_src_format, trim_unknown_fmt,
yml_is_yaml,
},
},
highlight::HighLightRes,
};
use anyhow::Result;
use glossa::{assets::OnceCell, GetText};
use std::{
borrow::Cow,
fs,
io::{self, Read},
path::{Path, PathBuf},
};
pub(crate) mod convert;
pub(crate) mod fmt;
pub(crate) mod serialisation;
#[derive(Debug, Default)]
pub(crate) struct ConvFmt<'fmt, 'src, 'dst> {
src: Cow<'src, Path>,
src_fmt: &'fmt str,
dst_fmt: &'fmt str,
dst: Cow<'dst, Path>,
save: bool,
}
pub(crate) fn is_src_stdin(src: &Path) -> bool {
matches!(src.as_os_str().to_str(), Some("-"))
}
pub(crate) fn get_static_stdin_data() -> &'static str {
static STDIN: OnceCell<String> = OnceCell::new();
STDIN.get_or_init(|| {
let mut s = String::with_capacity(64);
log::warn!("Getting data from stdin");
io::stdin()
.read_to_string(&mut s)
.expect("Failed to get data from stdin");
s
})
}
pub fn task(
src: &Path,
dst: Option<&Vec<PathBuf>>,
save: bool,
src_format: Option<&String>,
high_light_resource: Option<&HighLightRes>,
) -> Result<()> {
let src_fmt = match src_format {
Some(s) => s,
_ if is_src_stdin(src) => auto_detect_unknown_fmt(get_static_stdin_data()),
_ => match get_src_format(src) {
s if s.is_empty() => auto_detect_unknown_fmt(&fs::read_to_string(src)?),
s => s,
},
};
match dst {
None => {
let dst_fmt = get_different_file_format(src_fmt);
convert_data_format(
ConvFmt::new(
src,
src_fmt,
dst_fmt,
src.with_extension(dst_fmt),
save,
),
false,
high_light_resource,
)?;
}
Some(dst_path_list) => {
write_to_dst(dst_path_list, src, save, src_fmt, high_light_resource)?;
}
};
Ok(())
}
pub(crate) fn write_to_dst(
dst_path_list: &[PathBuf],
src: &Path,
save: bool,
src_fmt: &str,
high_light_resource: Option<&HighLightRes>,
) -> Result<()> {
for (org_dst, dst_fname) in dst_path_list
.iter()
.map(|x| (x, x.file_name()))
.filter_map(|(x, f)| {
f.map(|new_f| {
(
x,
new_f
.to_string_lossy()
.to_ascii_lowercase(),
)
})
})
{
let dst_fmt =
get_dst_fmt(&dst_fname, true).unwrap_or_else(||
src_fmt
);
let dst = get_dst(org_dst, dst_fmt, src);
if src == dst && save {
log::warn!(
"Please use a different file extension. All supported extensions are {:?}",
fmt::FORMATS
);
log::error!(
"Input and output files cannot be the same, skipping: {}",
dst.display()
);
continue;
}
convert_data_format(
ConvFmt::new(src, src_fmt, dst_fmt, dst, save),
false,
high_light_resource,
)?;
}
Ok(())
}
pub(crate) fn get_dst(org: &Path, dst_fmt: &str, src: &Path) -> PathBuf {
let new_dir_path =
|| Path::new(src.file_name().unwrap()).with_extension(dst_fmt);
match org.extension() {
None if org.components().count() == 1 => match org.to_str() {
Some(o) if o == dst_fmt => src.with_extension(dst_fmt),
Some(o) if o == "yml" => src.with_extension("yml"),
_ if org.is_dir() => org.join(new_dir_path()),
_ => org.with_extension(dst_fmt),
},
_ if org.is_dir() => org.join(new_dir_path()),
_ => org.into(),
}
}
pub(crate) fn get_dst_fmt(fname: &str, auto_guess: bool) -> Option<&str> {
let ext = fname.rsplit('.').next();
let sup = ext.map(check_supported_formats);
if sup
.filter(|s| !s.trim().is_empty())
.is_some()
{
return sup.map(yml_is_yaml);
}
if !auto_guess {
return None;
}
trim_unknown_fmt(ext.unwrap_or(fname)).map(yml_is_yaml)
}
fn get_conv_text(k: &str) -> glossa::Result<&str> {
get_l10n_text().get("conversion", k)
}
pub(crate) fn get_conv_dft(k: &str) -> Cow<str> {
get_l10n_text().get_or_default("conversion", k)
}
fn get_conv_md(k: &str) -> glossa::Result<&str> {
get_l10n_text().get("conversion_md", k)
}