use {
super::{
AppContext,
CmdResult,
},
crate::{
errors::ProgramError,
launchable::Launchable,
stage::Stage,
},
std::{
fs::OpenOptions,
io::Write,
path::Path,
},
};
pub type LineNumber = usize;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum SelectionType {
File,
Directory,
Any,
}
#[derive(Debug, Clone, Copy)]
pub struct Selection<'s> {
pub path: &'s Path,
pub line: LineNumber, pub stype: SelectionType,
pub is_exe: bool,
}
#[derive(Debug, Clone, Copy)]
pub enum SelInfo<'s> {
None,
One(Selection<'s>),
More(&'s Stage), }
impl SelectionType {
pub fn respects(self, constraint: Self) -> bool {
constraint == Self::Any || self == constraint
}
pub fn is_respected_by(self, sel_type: Option<Self>) -> bool {
match (self, sel_type) {
(Self::File, Some(Self::File)) => true,
(Self::Directory, Some(Self::Directory)) => true,
(Self::Any, _) => true,
_ => false,
}
}
pub fn from(path: &Path) -> Self {
if path.is_dir() {
Self::Directory
} else {
Self::File
}
}
}
impl Selection<'_> {
pub fn to_opener(
self,
con: &AppContext,
) -> Result<CmdResult, ProgramError> {
Ok(if self.is_exe {
let path = self.path.to_string_lossy().to_string();
if let Some(export_path) = &con.launch_args.outcmd {
let f = OpenOptions::new().append(true).open(export_path)?;
writeln!(&f, "{path}")?;
CmdResult::Quit
} else {
CmdResult::from(Launchable::program(
vec![path],
None, true, con,
)?)
}
} else {
CmdResult::from(Launchable::opener(self.path.to_path_buf()))
})
}
}
impl<'a> SelInfo<'a> {
pub fn from_path(path: &'a Path) -> Self {
Self::One(
Selection {
stype: SelectionType::from(path),
line: 0,
path,
is_exe: false, }
)
}
pub fn count_paths(&self) -> usize {
match self {
SelInfo::None => 0,
SelInfo::One(_) => 1,
SelInfo::More(stage) => stage.len(),
}
}
pub fn common_stype(&self) -> Option<SelectionType> {
match self {
SelInfo::None => None,
SelInfo::One(sel) => Some(sel.stype),
SelInfo::More(stage) => {
let stype = SelectionType::from(&stage.paths()[0]);
for path in stage.paths().iter().skip(1) {
if stype != SelectionType::from(path) {
return None;
}
}
Some(stype)
}
}
}
pub fn one_sel(self) -> Option<Selection<'a>> {
match self {
SelInfo::One(sel) => Some(sel),
_ => None,
}
}
pub fn one_path(self) -> Option<&'a Path> {
self.one_sel().map(|sel| sel.path)
}
pub fn extension(&self) -> Option<&str> {
match self {
SelInfo::None => None,
SelInfo::One(sel) => sel.path.extension().and_then(|e| e.to_str()),
SelInfo::More(stage) => {
let common_extension = stage.paths()[0]
.extension().and_then(|e| e.to_str());
#[allow(clippy::question_mark)]
if common_extension.is_none() {
return None;
}
for path in stage.paths().iter().skip(1) {
let extension = path.extension().and_then(|e| e.to_str());
if extension != common_extension {
return None;
}
}
common_extension
}
}
}
}