diff --git a/src/config.rs b/src/config.rs index 133d4f2..82e7126 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,16 +12,21 @@ use std::str::FromStr; #[derive(Debug, Clone)] pub struct Config { conf_dir: PathBuf, + settings: Settings, bookmarks: HashMap, } +#[derive(Debug, Clone)] +pub struct Settings {} + impl Config { - const BOOKMARK_FILE_NAME : &str = "bookmarks.conf"; + const BOOKMARK_FILE_NAME: &str = "bookmarks.conf"; /// generates and populates a new instance of Config pub fn new() -> Result { let mut bookmarks = Config { conf_dir: PathBuf::new(), + settings: Settings{}, bookmarks: HashMap::::new(), }; let home_dir = match var("HOME") { @@ -44,7 +49,9 @@ impl Config { pub fn add_bookmark(&mut self, name: &String, path: &PathBuf) -> Result<()> { if !path.is_dir() { - return Err(Error::other("-- provided path argument does not point to a valid directory")) + return Err(Error::other( + "-- provided path argument does not point to a valid directory", + )); } else { self.bookmarks.insert(name.to_string(), path.to_path_buf()); self.write_bookmark_file()?; @@ -57,7 +64,9 @@ impl Config { _ = self.bookmarks.remove(name); self.write_bookmark_file()?; } else { - return Err(Error::other("-- bookmark requested to delete does not exist")); + return Err(Error::other( + "-- bookmark requested to delete does not exist", + )); } Ok(()) } diff --git a/src/main.rs b/src/main.rs index 29a4bc7..c87c023 100644 --- a/src/main.rs +++ b/src/main.rs @@ -57,9 +57,8 @@ fn handle_push(args: &PushArgs, stack: &mut Stack) -> Result<()> { Ok(()) } -fn handle_pop(_args: &PopArgs, stack: &mut Stack) -> Result<()> { - // TODO: handle arguments - let path = stack.pop_entry()?; +fn handle_pop(args: &PopArgs, stack: &mut Stack) -> Result<()> { + let path = stack.pop_entry(args.num_entries)?; println!( "cd -- {}", match path.to_str() { @@ -77,14 +76,8 @@ fn handle_stack(args: &StackArgs, stack: &mut Stack) -> Result<()> { } } // retrieve stack - let output = stack.get_stack()?; - if output.is_empty() { - return Err(Error::other("-- the stack is empty")); - } - // print stack to standard output - for (n, item) in output.iter().rev().enumerate() { - println!("echo '{} - {}'", n, item.to_str().unwrap()); - } + let output: String = stack.to_string(None)?; + print!("echo '{}'", output); Ok(()) } diff --git a/src/stack.rs b/src/stack.rs index b2cccb4..31ee44e 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -4,6 +4,7 @@ use std::io::{Error, Result}; use std::path::{Path, PathBuf}; use std::str::FromStr; use sysinfo::{Pid, System}; +use super::config::Settings; #[derive(Debug, Clone)] pub struct Stack { @@ -19,21 +20,22 @@ impl Stack { path: PathBuf::new(), stack: Vec::::new(), }; - - // remove first entry if it is empty, because after - // creation of the stack there seems to be an empty - // cell in the vector stack.build_stack()?; - if !stack.stack[0].is_dir() { - stack.stack.remove(0); - } Ok(stack) } // return stack - pub fn get_stack(&mut self) -> Result<&Vec> { - Ok(&self.stack) + pub fn to_string(&self, _settings: Option) -> Result { + if self.stack.is_empty() { + return Err(Error::other("-- the stack is empty")); + } + // print stack to string + let mut output : String = "".to_string(); + for (n, item) in self.stack.iter().rev().enumerate() { + output.push_str(&format!("'{} - {}'\n", n, item.to_str().unwrap())); + } + Ok(output) } /// clear stack by deleting the associated stack file @@ -52,10 +54,9 @@ impl Stack { /// pop entry from stack /// return popped entry - pub fn pop_entry(&mut self) -> Result { + pub fn pop_entry(&mut self, _num_entries: Option) -> Result { let entry = self.stack.pop(); self.write_stack_file()?; - match entry { Some(entry) => Ok(entry), None => Err(Error::other( @@ -68,23 +69,26 @@ impl Stack { /// return nth last entry pub fn get_entry_by_number(&mut self, entry_number: usize) -> Result<&PathBuf> { // index from the end of the vector as new entries are appended at the end of the list - match self.stack.get( - self.stack - .len() - .checked_sub(entry_number) - .expect("-- requested entry number is out of bounds"), - ) { + let index = match self.stack.len().checked_sub(entry_number) { + Some(value) => value, + None => return Err(Error::other("-- no entry found at request index")), + }; + match self.stack.get(index) { Some(item) => Ok(item), - None => Err(Error::other( - "-- failed to retrieve stack entry by number", - )), + None => Err(Error::other("-- failed to retrieve stack entry by number")), } } /// clean up dead stack files, parse and build stack fn build_stack(&mut self) -> Result<()> { - let stack_dir: PathBuf = PathBuf::from_str("/tmp/navigation/") - .expect("-- failed to create path object of '/tmp/navigation'"); + let stack_dir: PathBuf = match PathBuf::from_str("/tmp/navigation/") { + Ok(value) => value, + Err(_) => { + return Err(Error::other( + "-- failed to create path object of the stack directory", + )) + } + }; let mut sys = System::new_all(); sys.refresh_all(); let procs = sys.processes(); @@ -94,14 +98,18 @@ impl Stack { let members = fs::read_dir(stack_dir.clone())?; for entry in members { let entry = entry?; - let process_id = Pid::from_str( - entry - .file_name() - .to_str() - .expect("-- failed to convert file name to str"), - ); - if !procs.contains_key(&process_id.expect("-- failed to convert filename to pid")) { - fs::remove_file(entry.path()).expect("-- failed to remove orphaned file"); + let process_id = match Pid::from_str(match entry.file_name().to_str() { + Some(value) => value, + None => return Err(Error::other("-- failed to convert file name to str")), + }) { + Ok(value) => value, + Err(error) => return Err(Error::other(error.to_string())), + }; + if !procs.contains_key(&process_id) { + match fs::remove_file(entry.path()) { + Ok(value) => value, + Err(error) => return Err(Error::other(error.to_string())), + } } } } else { @@ -118,6 +126,7 @@ impl Stack { // create stack file and store current path File::create(self.path.clone())?; } + self.cleanup_stack(); Ok(()) } @@ -133,15 +142,21 @@ impl Stack { Ok(()) } + /// remove invalid paths from stack + fn cleanup_stack(&mut self) { + if !self.stack.is_empty() { + self.stack.retain(|entry| entry.is_dir()); + } + } + /// write stack current stack to file to save it for next execution fn write_stack_file(&mut self) -> Result<()> { let mut output = Vec::<&str>::new(); for entry in &self.stack { - output.push( - entry - .to_str() - .expect("-- failed to convert stack entry to string"), - ); + output.push(match entry.to_str() { + Some(value) => value, + None => return Err(Error::other("-- failed to convert stack entry to string")), + }); } fs::write(self.path.clone(), output.join("\n"))?; diff --git a/todo.md b/todo.md index 8e4006b..319c336 100644 --- a/todo.md +++ b/todo.md @@ -1,8 +1,9 @@ # todos for 'navigation' -- [ ] replace `expect` statements in 'stack.rs' with actual error handling +- [x] replace `expect` statements in 'stack.rs' with actual error handling - [ ] pop several entries at a time - [ ] dedup stack option - [x] drop stack - [ ] config file -- [ ] bookmarks +- [x] bookmarks +- [ ] colored output > make it configurable through config file