use std::convert::TryFrom; use std::io::{BufRead, Write}; use clap::ArgMatches; use crate::database::Database; use crate::error::{Error, Result}; use crate::commands::{Command, Facts}; use crate::commands::list::ListCommand; use crate::io::Streams; #[derive(Default)] pub struct Args { pub sheet: Option, } impl<'a> TryFrom<&'a ArgMatches> for Args { type Error = Error; fn try_from(matches: &'a ArgMatches) -> Result { Ok(Args { sheet: matches.value_of("sheet").map(|s| s.into()), }) } } pub struct SheetCommand {} impl<'a> Command<'a> for SheetCommand { type Args = Args; fn handle(args: Args, streams: &mut Streams, facts: &Facts) -> Result<()> where D: Database, I: BufRead, O: Write, E: Write, { if let Some(sheet) = args.sheet { let current_sheet = streams.db.current_sheet()?; // sheet given, switch to it let move_to = if sheet == "-" { if let Some(move_to) = streams.db.last_sheet()? { move_to } else { writeln!(streams.out, "No previous sheet to move to. Staying on '{}'. Hint: remember that giving - (a dash) as argument to t sheet switches to the last active sheet", current_sheet)?; return Ok(()); } } else if sheet == current_sheet { writeln!(streams.out, "Already on sheet '{}'", sheet)?; return Ok(()); } else { sheet }; streams.db.set_last_sheet(¤t_sheet)?; streams.db.set_current_sheet(&move_to)?; writeln!(streams.out, "Switching to sheet '{}'", move_to)?; Ok(()) } else { // call list ListCommand::handle(Default::default(), streams, facts) } } } #[cfg(test)] mod tests { use pretty_assertions::assert_eq; use super::*; #[test] fn switch_to_sheet() { let args = Args { sheet: Some("new_sheet".into()), }; let mut streams = Streams::fake(b""); let facts = Facts::new(); SheetCommand::handle(args, &mut streams, &facts).unwrap(); assert_eq!(streams.db.current_sheet().unwrap(), "new_sheet"); assert_eq!(&String::from_utf8_lossy(&streams.out), "Switching to sheet 'new_sheet'\n"); assert_eq!(&String::from_utf8_lossy(&streams.err), ""); } #[test] fn switch_to_sheet_already_in() { let args = Args { sheet: Some("foo".into()), }; let mut streams = Streams::fake(b""); let facts = Facts::new(); streams.db.set_current_sheet("foo").unwrap(); SheetCommand::handle(args, &mut streams, &facts).unwrap(); assert_eq!(streams.db.current_sheet().unwrap(), "foo"); assert_eq!(&String::from_utf8_lossy(&streams.out), "Already on sheet 'foo'\n"); assert_eq!(&String::from_utf8_lossy(&streams.err), ""); } #[test] fn switch_to_last_sheet() { let args = Args { sheet: Some("-".into()), }; let mut streams = Streams::fake(b""); let facts = Facts::new(); streams.db.set_current_sheet("foo").unwrap(); streams.db.set_last_sheet("var").unwrap(); SheetCommand::handle(args, &mut streams, &facts).unwrap(); assert_eq!(streams.db.current_sheet().unwrap(), "var"); assert_eq!(streams.db.last_sheet().unwrap().unwrap(), "foo"); assert_eq!(&String::from_utf8_lossy(&streams.out), "Switching to sheet 'var'\n"); assert_eq!(&String::from_utf8_lossy(&streams.err), ""); } }