use std::borrow::Borrow;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use crate::common::{
current_uid, path_to_config_folder, tilde, HARDCODED_SHORTCUTS, TRASH_FOLDER_FILES,
};
use crate::io::git_root;
use crate::{impl_content, impl_draw_menu_with_char, impl_selectable, log_info};
#[derive(Debug, Clone)]
pub struct Shortcut {
pub content: Vec<PathBuf>,
pub index: usize,
start_folder: PathBuf,
}
impl Shortcut {
#[must_use]
pub fn empty(start_folder: &Path) -> Self {
let content = vec![];
Self {
content,
index: 0,
start_folder: start_folder.to_owned(),
}
}
fn build_content(start_folder: &Path) -> Vec<PathBuf> {
let mut content = Self::hardcoded_shortcuts();
Self::push_home_path(&mut content);
Self::push_trash_folder(&mut content);
Self::push_config_folder(&mut content);
Self::push_start_folder(&mut content, start_folder);
Self::push_git_root(&mut content);
content
}
pub fn update(&mut self) {
self.content = Self::build_content(&self.start_folder)
}
fn hardcoded_shortcuts() -> Vec<PathBuf> {
HARDCODED_SHORTCUTS.iter().map(PathBuf::from).collect()
}
fn push_home_path(shortcuts: &mut Vec<PathBuf>) {
let Ok(home_path) = PathBuf::from_str(tilde("~").borrow());
shortcuts.push(home_path);
}
fn push_trash_folder(shortcuts: &mut Vec<PathBuf>) {
let Ok(trash_path) = PathBuf::from_str(tilde(TRASH_FOLDER_FILES).borrow());
if trash_path.exists() {
shortcuts.push(trash_path);
}
}
fn push_config_folder(shortcuts: &mut Vec<PathBuf>) {
if let Ok(config_folder) = path_to_config_folder() {
shortcuts.push(config_folder);
}
}
fn push_start_folder(shortcuts: &mut Vec<PathBuf>, start_folder: &Path) {
shortcuts.push(start_folder.to_owned());
}
fn git_root_or_cwd() -> PathBuf {
git_root().map_or_else(
|_| std::env::current_dir().unwrap_or_default(),
PathBuf::from,
)
}
fn push_git_root(shortcuts: &mut Vec<PathBuf>) {
shortcuts.push(Self::git_root_or_cwd());
}
fn clear_doublons(&mut self) {
self.content.sort_unstable();
self.content.dedup();
}
fn extend_with_mount_points(&mut self, mount_points: &[&Path]) {
self.content
.extend(mount_points.iter().map(|p| p.to_path_buf()));
self.extend_with_mtp();
self.clear_doublons();
}
fn extend_with_mtp(&mut self) {
let Ok(uid) = current_uid() else {
return;
};
let mtp_mount_point = PathBuf::from(format!("/run/user/{uid}/gvfs/"));
if !mtp_mount_point.exists() || !mtp_mount_point.is_dir() {
return;
}
let mount_points: Vec<PathBuf> = match std::fs::read_dir(&mtp_mount_point) {
Ok(read_dir) => read_dir
.filter_map(std::result::Result::ok)
.filter(|direntry| direntry.path().is_dir())
.map(|direntry| direntry.path())
.collect(),
Err(error) => {
log_info!(
"unreadable gvfs {mtp_mount_point}: {error:?} ",
mtp_mount_point = mtp_mount_point.display(),
);
return;
}
};
self.content.extend(mount_points);
}
pub fn refresh(
&mut self,
mount_points: &[&Path],
left_path: &std::path::Path,
right_path: &std::path::Path,
) {
self.content = Self::build_content(&self.start_folder);
self.content.push(left_path.to_owned());
self.content.push(right_path.to_owned());
self.extend_with_mount_points(mount_points);
}
}
impl_content!(Shortcut, PathBuf);
impl_draw_menu_with_char!(Shortcut, PathBuf);