use alloc::borrow::Cow;
use tap::Pipe;
use crate::os_cmd::{MiniStr, RunnableCommand, presets::CowStrVec};
pub(crate) type TinyCmds<'a> = CowStrVec<'a, 9>;
impl<'a> RunnableCommand<'a> for CommandRepr<'a> {}
#[derive(Debug, Clone)]
pub enum CommandRepr<'a> {
Raw(&'a str),
Slice(Box<[&'a str]>),
OwnedSlice(Box<[MiniStr]>),
}
impl Default for CommandRepr<'_> {
fn default() -> Self {
Self::Raw("cargo")
}
}
impl From<Box<[MiniStr]>> for CommandRepr<'_> {
fn from(value: Box<[MiniStr]>) -> Self {
Self::OwnedSlice(value)
}
}
impl From<Vec<MiniStr>> for CommandRepr<'_> {
fn from(value: Vec<MiniStr>) -> Self {
Self::OwnedSlice(value.into())
}
}
impl<'a> From<Box<[&'a str]>> for CommandRepr<'a> {
fn from(value: Box<[&'a str]>) -> Self {
Self::Slice(value)
}
}
impl<'a> From<Vec<&'a str>> for CommandRepr<'a> {
fn from(value: Vec<&'a str>) -> Self {
Self::Slice(value.into_boxed_slice())
}
}
impl<'a, const N: usize> From<[&'a str; N]> for CommandRepr<'a> {
fn from(value: [&'a str; N]) -> Self {
Self::Slice(value.into())
}
}
impl<'a> From<&'a str> for CommandRepr<'a> {
fn from(value: &'a str) -> Self {
Self::Raw(value)
}
}
impl<'a> CommandRepr<'a> {
pub fn into_tinyvec(self, remove_comments: bool) -> TinyCmds<'a> {
match self {
Self::Raw(raw) => collect_raw(raw, remove_comments),
Self::Slice(items) => items
.into_iter()
.map(Cow::from)
.collect(),
Self::OwnedSlice(items) => items
.into_iter()
.map(Cow::from)
.collect(),
}
}
}
pub fn collect_raw(raw: &str, remove_comments: bool) -> TinyCmds<'_> {
raw
.trim_ascii() .pipe(|s| match remove_comments {
true => remove_comments_and_collect(s),
_ => s.into(), })
.pipe_deref(shlex::Shlex::new) .map(Cow::from)
.collect()
}
pub fn remove_comments_and_collect(s: &str) -> Cow<'_, str> {
if !s.contains("//") {
return s.into();
}
s.lines()
.filter(|x| {
!x.trim_ascii_start()
.starts_with("//")
})
.collect::<String>()
.pipe(Cow::from)
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(all(feature = "print_ext", feature = "re_exports_tap"))]
#[test]
fn doc_collect_raw() {
use crate::{os_cmd::collect_raw, tap::Pipe};
let into_vec = |s| collect_raw(s, true);
let vec = r#"
// This is a comment
printf
"%s" world
"#
.pipe(into_vec);
assert_eq!(vec.as_ref(), &["printf", "%s", "world"]);
}
#[cfg(feature = "print_ext")]
#[ignore]
#[test]
fn test_collect_raw() {
use tap::Tap;
use crate::print_ext::normal::edbg;
let into_vec = |s| collect_raw(s, true);
r#"
// This is a comment
printf "%s" "
Hello
// wonderful
world
"
"#
.pipe(into_vec)
.tap(edbg);
}
#[cfg(feature = "print_ext")]
#[ignore]
#[test]
fn test_run_trait() {
let cmd = r#"printf "%s\n" Hello"#;
let repr: CommandRepr = cmd.into();
crate::dbg!(repr);
let _ = repr.run();
}
}