fix: path input consistency & minor code cleanup

this should fix and improve cross platform experience of the application without breaking compatibility with anything, but needs more testing so if anyone wants to try it out they are welcome
This commit is contained in:
Swarnim Arun 2023-05-12 02:34:52 +05:30
parent 153e060043
commit 73596971bf
No known key found for this signature in database
GPG Key ID: F1EEE523F3F007BE
4 changed files with 28 additions and 18 deletions

View File

@ -64,11 +64,11 @@ pub struct Edit {
#[derive(Clone, Debug, Subcommand)] #[derive(Clone, Debug, Subcommand)]
pub enum EditCommand { pub enum EditCommand {
#[clap(hide = true)] #[clap(hide = true)]
Decrement { path: String }, Decrement { path: PathBuf },
#[clap(hide = true)] #[clap(hide = true)]
Delete { path: String }, Delete { path: PathBuf },
#[clap(hide = true)] #[clap(hide = true)]
Increment { path: String }, Increment { path: PathBuf },
#[clap(hide = true)] #[clap(hide = true)]
Reload, Reload,
} }

View File

@ -1,5 +1,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use std::path::Path;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -8,7 +9,7 @@ use crate::util::{DAY, HOUR, WEEK};
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Dir<'a> { pub struct Dir<'a> {
#[serde(borrow)] #[serde(borrow)]
pub path: Cow<'a, str>, pub path: Cow<'a, Path>,
pub rank: Rank, pub rank: Rank,
pub last_accessed: Epoch, pub last_accessed: Epoch,
} }
@ -61,7 +62,7 @@ impl Display for DirDisplay<'_> {
let score = self.dir.score(now).clamp(0.0, 9999.0); let score = self.dir.score(now).clamp(0.0, 9999.0);
write!(f, "{score:>6.1}{}", self.separator)?; write!(f, "{score:>6.1}{}", self.separator)?;
} }
write!(f, "{}", self.dir.path) write!(f, "{}", self.dir.path.display())
} }
} }

View File

@ -64,11 +64,11 @@ impl Database {
} }
/// Increments the rank of a directory, or creates it if it does not exist. /// Increments the rank of a directory, or creates it if it does not exist.
pub fn add(&mut self, path: impl AsRef<str> + Into<String>, by: Rank, now: Epoch) { pub fn add(&mut self, path: impl AsRef<Path>, by: Rank, now: Epoch) {
self.with_dirs_mut(|dirs| match dirs.iter_mut().find(|dir| dir.path == path.as_ref()) { self.with_dirs_mut(|dirs| match dirs.iter_mut().find(|dir| dir.path == path.as_ref()) {
Some(dir) => dir.rank = (dir.rank + by).max(0.0), Some(dir) => dir.rank = (dir.rank + by).max(0.0),
None => { None => {
dirs.push(Dir { path: path.into().into(), rank: by.max(0.0), last_accessed: now }) dirs.push(Dir { path: path.as_ref().to_owned().into(), rank: by.max(0.0), last_accessed: now })
} }
}); });
self.with_dirty_mut(|dirty| *dirty = true); self.with_dirty_mut(|dirty| *dirty = true);
@ -77,23 +77,23 @@ impl Database {
/// Creates a new directory. This will create a duplicate entry if this /// Creates a new directory. This will create a duplicate entry if this
/// directory is always in the database, it is expected that the user either /// directory is always in the database, it is expected that the user either
/// does a check before calling this, or calls `dedup()` afterward. /// does a check before calling this, or calls `dedup()` afterward.
pub fn add_unchecked(&mut self, path: impl AsRef<str> + Into<String>, rank: Rank, now: Epoch) { pub fn add_unchecked(&mut self, path: impl AsRef<Path>, rank: Rank, now: Epoch) {
self.with_dirs_mut(|dirs| { self.with_dirs_mut(|dirs| {
dirs.push(Dir { path: path.into().into(), rank, last_accessed: now }) dirs.push(Dir { path: path.as_ref().to_owned().into(), rank, last_accessed: now })
}); });
self.with_dirty_mut(|dirty| *dirty = true); self.with_dirty_mut(|dirty| *dirty = true);
} }
/// Increments the rank and updates the last_accessed of a directory, or /// Increments the rank and updates the last_accessed of a directory, or
/// creates it if it does not exist. /// creates it if it does not exist.
pub fn add_update(&mut self, path: impl AsRef<str> + Into<String>, by: Rank, now: Epoch) { pub fn add_update(&mut self, path: impl AsRef<Path>, by: Rank, now: Epoch) {
self.with_dirs_mut(|dirs| match dirs.iter_mut().find(|dir| dir.path == path.as_ref()) { self.with_dirs_mut(|dirs| match dirs.iter_mut().find(|dir| dir.path == path.as_ref()) {
Some(dir) => { Some(dir) => {
dir.rank = (dir.rank + by).max(0.0); dir.rank = (dir.rank + by).max(0.0);
dir.last_accessed = now; dir.last_accessed = now;
} }
None => { None => {
dirs.push(Dir { path: path.into().into(), rank: by.max(0.0), last_accessed: now }) dirs.push(Dir { path: path.as_ref().to_owned().into(), rank: by.max(0.0), last_accessed: now })
} }
}); });
self.with_dirty_mut(|dirty| *dirty = true); self.with_dirty_mut(|dirty| *dirty = true);
@ -101,7 +101,7 @@ impl Database {
/// Removes the directory with `path` from the store. This does not preserve /// Removes the directory with `path` from the store. This does not preserve
/// ordering, but is O(1). /// ordering, but is O(1).
pub fn remove(&mut self, path: impl AsRef<str>) -> bool { pub fn remove(&mut self, path: impl AsRef<Path>) -> bool {
match self.dirs().iter().position(|dir| dir.path == path.as_ref()) { match self.dirs().iter().position(|dir| dir.path == path.as_ref()) {
Some(idx) => { Some(idx) => {
self.swap_remove(idx); self.swap_remove(idx);
@ -256,7 +256,7 @@ mod tests {
assert_eq!(db.dirs().len(), 1); assert_eq!(db.dirs().len(), 1);
let dir = &db.dirs()[0]; let dir = &db.dirs()[0];
assert_eq!(dir.path, path); assert_eq!(dir.path, Path::new(path));
assert!((dir.rank - 2.0).abs() < 0.01); assert!((dir.rank - 2.0).abs() < 0.01);
assert_eq!(dir.last_accessed, now); assert_eq!(dir.last_accessed, now);
} }

View File

@ -1,5 +1,6 @@
use std::iter::Rev; use std::iter::Rev;
use std::ops::Range; use std::ops::Range;
use std::path::Path;
use std::{fs, path}; use std::{fs, path};
use crate::db::{Database, Dir, Epoch}; use crate::db::{Database, Dir, Epoch};
@ -71,7 +72,13 @@ impl<'a> Stream<'a> {
continue; continue;
} }
if Some(dir.path.as_ref()) == self.exclude_path.as_deref() { if self
.exclude_path
.as_deref()
.map(|a| dir.path.to_str().map(|x| x == a))
.flatten()
.unwrap_or_default()
{
self.did_exclude = true; self.did_exclude = true;
continue; continue;
} }
@ -87,7 +94,7 @@ impl<'a> Stream<'a> {
self.did_exclude self.did_exclude
} }
fn matches_exists(&self, path: &str) -> bool { fn matches_exists(&self, path: &Path) -> bool {
if !self.check_exists { if !self.check_exists {
return true; return true;
} }
@ -95,12 +102,14 @@ impl<'a> Stream<'a> {
resolver(path).map(|m| m.is_dir()).unwrap_or_default() resolver(path).map(|m| m.is_dir()).unwrap_or_default()
} }
fn matches_keywords(&self, path: &str) -> bool { fn matches_keywords(&self, path: &Path) -> bool {
let (keywords_last, keywords) = match self.keywords.split_last() { let (keywords_last, keywords) = match self.keywords.split_last() {
Some(split) => split, Some(split) => split,
None => return true, None => return true,
}; };
let Some(path) = path.to_str() else {
return false;
};
let path = util::to_lowercase(path); let path = util::to_lowercase(path);
let mut path = path.as_str(); let mut path = path.as_str();
match path.rfind(keywords_last) { match path.rfind(keywords_last) {
@ -155,6 +164,6 @@ mod tests {
fn query(#[case] keywords: &[&str], #[case] path: &str, #[case] is_match: bool) { fn query(#[case] keywords: &[&str], #[case] path: &str, #[case] is_match: bool) {
let db = &mut Database::new(PathBuf::new(), Vec::new(), |_| Vec::new(), false); let db = &mut Database::new(PathBuf::new(), Vec::new(), |_| Vec::new(), false);
let stream = Stream::new(db, 0).with_keywords(keywords); let stream = Stream::new(db, 0).with_keywords(keywords);
assert_eq!(is_match, stream.matches_keywords(path)); assert_eq!(is_match, stream.matches_keywords(Path::new(path)));
} }
} }