use std::cmp::{Ord, Ordering};
use std::ops::Index;
use std::os::unix::fs::MetadataExt;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::hash::{Hash, Hasher};
use std::os::unix::ffi::{OsStringExt, OsStrExt};
use std::ffi::{OsStr, OsString};
use lscolors::LsColors;
use mime_detective;
use users::{get_current_username,
get_current_groupname,
get_user_by_uid,
get_group_by_gid};
use chrono::TimeZone;
use failure::Error;
use notify::DebouncedEvent;
use crate::fail::{HResult, HError};
use crate::dirty::{DirtyBit, Dirtyable};
lazy_static! {
static ref COLORS: LsColors = LsColors::from_env().unwrap();
static ref TAGS: Mutex<(bool, Vec<PathBuf>)> = Mutex::new((false, vec![]));
}
pub fn load_tags() -> HResult<()> {
std::thread::spawn(|| -> HResult<()> {
let tag_path = crate::paths::tagfile_path()?;
let tags = std::fs::read_to_string(tag_path)?;
let mut tags = tags.lines().map(|f| PathBuf::from(f)).collect::<Vec<PathBuf>>();
let mut tag_lock = TAGS.lock()?;
tag_lock.0 = true;
tag_lock.1.append(&mut tags);
Ok(())
});
Ok(())
}
pub fn check_tag(path: &PathBuf) -> HResult<bool> {
tags_loaded()?;
let tagged = TAGS.lock()?.1.contains(path);
Ok(tagged)
}
pub fn tags_loaded() -> HResult<()> {
let loaded = TAGS.lock()?.0;
if loaded { Ok(()) }
else { HError::tags_not_loaded() }
}
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub struct Files {
pub directory: File,
pub files: Vec<File>,
pub sort: SortBy,
pub dirs_first: bool,
pub reverse: bool,
pub show_hidden: bool,
pub dirty: DirtyBit
}
impl Index<usize> for Files {
type Output = File;
fn index(&self, pos: usize) -> &File {
&self.files[pos]
}
}
impl Dirtyable for Files {
fn get_bit(&self) -> &DirtyBit {
&self.dirty
}
fn get_bit_mut(&mut self) -> &mut DirtyBit {
&mut self.dirty
}
}
impl Files {
pub fn new_from_path(path: &Path) -> Result<Files, Error> {
let direntries: Result<Vec<_>, _> = std::fs::read_dir(&path)?.collect();
let files: Vec<_> = direntries?
.iter()
.map(|file| {
let name = file.file_name();
let name = name.to_string_lossy();
let path = file.path();
File::new(&name, path)
})
.collect();
let mut files = Files {
directory: File::new_from_path(&path)?,
files: files,
sort: SortBy::Name,
dirs_first: true,
reverse: false,
show_hidden: true,
dirty: DirtyBit::new()
};
files.sort();
if files.files.len() == 0 {
files.files = vec![File::new_placeholder(&path)?];
}
Ok(files)
}
pub fn new_from_path_cancellable(path: &Path, stale: Arc<Mutex<bool>>) -> Result<Files, Error> {
let direntries: Result<Vec<_>, _> = std::fs::read_dir(&path)?.collect();
let files: Vec<_> = direntries?
.iter()
.map(|file| {
if crate::preview::is_stale(&stale).unwrap() {
None
} else {
let name = file.file_name();
let name = name.to_string_lossy();
let path = file.path();
Some(File::new(&name, path))
}
})
.fuse()
.flatten()
.collect();
if crate::preview::is_stale(&stale).unwrap() {
return Err(crate::fail::HError::StalePreviewError {
file: path.to_string_lossy().to_string()
})?;
}
let mut files = Files {
directory: File::new_from_path(&path)?,
files: files,
sort: SortBy::Name,
dirs_first: true,
reverse: false,
show_hidden: true,
dirty: DirtyBit::new()
};
files.sort();
if files.files.len() == 0 {
files.files = vec![File::new_placeholder(&path)?];
}
Ok(files)
}
pub fn sort(&mut self) {
match self.sort {