diff --git a/deja_vu/config/config.json5 b/deja_vu/config/config.json5 index bb9e684..c2cc437 100644 --- a/deja_vu/config/config.json5 +++ b/deja_vu/config/config.json5 @@ -87,5 +87,36 @@ "": "Quit", // Yet another way to quit "": "Suspend" // Suspend the application }, + // Diagnostic modes + "DiagMenu": { + "": "Quit", // Quit the application + "": "Quit", // Another way to quit + "": "Quit", // Yet another way to quit + "": "Suspend" // Suspend the application + }, + "BootDiags": { + "": "Quit", // Quit the application + "": "Quit", // Another way to quit + "": "Quit", // Yet another way to quit + "": "Suspend" // Suspend the application + }, + "BootSetup": { + "": "Quit", // Quit the application + "": "Quit", // Another way to quit + "": "Quit", // Yet another way to quit + "": "Suspend" // Suspend the application + }, + "InjectDrivers": { + "": "Quit", // Quit the application + "": "Quit", // Another way to quit + "": "Quit", // Yet another way to quit + "": "Suspend" // Suspend the application + }, + "ToggleSafeBoot": { + "": "Quit", // Quit the application + "": "Quit", // Another way to quit + "": "Quit", // Yet another way to quit + "": "Suspend" // Suspend the application + }, } } diff --git a/deja_vu/src/app.rs b/deja_vu/src/app.rs index f68b066..dc1eec7 100644 --- a/deja_vu/src/app.rs +++ b/deja_vu/src/app.rs @@ -31,6 +31,7 @@ use tracing::{debug, info}; use crate::{ action::Action, + cli, components::{ footer::Footer, fps::FpsCounter, left::Left, popup, right::Right, title::Title, Component, }, @@ -57,6 +58,7 @@ pub struct App { should_suspend: bool, tick_rate: f64, // App + cli_cmd: cli::Command, cur_mode: Mode, disk_index_dest: Option, disk_index_source: Option, @@ -84,10 +86,16 @@ pub enum Mode { PostClone, Done, Failed, + // Diagnostic modes + DiagMenu, + BootDiags, + BootSetup, + InjectDrivers, + ToggleSafeBoot, } impl App { - pub fn new(tick_rate: f64, frame_rate: f64) -> Result { + pub fn new(cli_cmd: cli::Command, tick_rate: f64, frame_rate: f64) -> Result { let (action_tx, action_rx) = mpsc::unbounded_channel(); let disk_list_arc = Arc::new(Mutex::new(Vec::new())); let mut tasks = Tasks::new(action_tx.clone(), disk_list_arc.clone()); @@ -104,6 +112,7 @@ impl App { Box::new(Footer::new()), Box::new(popup::Popup::new()), ], + cli_cmd, config: Config::new()?, frame_rate, last_tick_key_events: Vec::new(), @@ -111,7 +120,10 @@ impl App { should_suspend: false, tick_rate, // App - cur_mode: Mode::ScanDisks, + cur_mode: match cli_cmd { + cli::Command::Clone => Mode::ScanDisks, + cli::Command::Diagnose => Mode::DiagMenu, + }, disk_index_dest: None, disk_index_source: None, disk_list: disk_list_arc, @@ -127,6 +139,7 @@ impl App { pub fn next_mode(&mut self) -> Option { let new_mode = match (self.prev_mode, self.cur_mode) { + // Clone states (_, Mode::InstallDrivers) => Mode::ScanDisks, (_, Mode::ScanDisks) => Mode::SelectDisks, (_, Mode::SelectDisks | Mode::SelectTableType | Mode::SelectParts) => { @@ -143,6 +156,17 @@ impl App { (Mode::SelectParts, Mode::Confirm) => Mode::PostClone, (_, Mode::PostClone | Mode::Done) => Mode::Done, (_, Mode::Failed) => Mode::Failed, + + // Diagnostic states + ( + _, + Mode::DiagMenu + | Mode::BootDiags + | Mode::BootSetup + | Mode::InjectDrivers + | Mode::ToggleSafeBoot, + ) => Mode::DiagMenu, + // Invalid states (_, Mode::Confirm) => panic!("This shouldn't happen."), }; @@ -247,7 +271,7 @@ impl App { // Inject driver(s) (if selected) if let Some(driver) = &self.driver { - if let Ok(task) = boot::inject_driver(&driver, &letter_os, &system32) { + if let Ok(task) = boot::inject_driver(driver, &letter_os, &system32) { self.tasks.add(task); } else { self.action_tx.send(Action::Error(format!( @@ -288,6 +312,19 @@ impl App { } let action_tx = self.action_tx.clone(); + // Init based on cli::Command + match self.cli_cmd { + cli::Command::Clone => { + action_tx.send(Action::SetMode(Mode::ScanDisks))?; + } + cli::Command::Diagnose => { + action_tx.send(Action::DisplayPopup( + popup::Type::Info, + String::from("Boot Diagnostics?"), + ))?; + } + } + loop { self.handle_events(&mut tui).await?; self.handle_actions(&mut tui)?; diff --git a/deja_vu/src/cli.rs b/deja_vu/src/cli.rs index be4d597..8d886d2 100644 --- a/deja_vu/src/cli.rs +++ b/deja_vu/src/cli.rs @@ -13,13 +13,17 @@ // You should have received a copy of the GNU General Public License // along with Deja-vu. If not, see . // -use clap::Parser; +use clap::{Parser, Subcommand}; use crate::config::{get_config_dir, get_data_dir}; #[derive(Parser, Debug)] #[command(author, version = version(), about)] pub struct Cli { + /// App mode + #[command(subcommand)] + pub cli_cmd: Command, + /// Tick rate, i.e. number of ticks per second #[arg(short, long, value_name = "FLOAT", default_value_t = 4.0)] pub tick_rate: f64, @@ -29,6 +33,15 @@ pub struct Cli { pub frame_rate: f64, } +#[derive(Clone, Copy, Debug, Subcommand)] +pub enum Command { + /// Clone Windows from one disk to another + Clone, + + /// Diagnose Windows boot issues + Diagnose, +} + const VERSION_MESSAGE: &str = concat!( env!("CARGO_PKG_VERSION"), "-", diff --git a/deja_vu/src/components/footer.rs b/deja_vu/src/components/footer.rs index 1530cd7..6b92fac 100644 --- a/deja_vu/src/components/footer.rs +++ b/deja_vu/src/components/footer.rs @@ -53,6 +53,7 @@ impl Component for Footer { fn update(&mut self, action: Action) -> Result> { if let Action::SetMode(new_mode) = action { self.text = match new_mode { + // Clone modes Mode::ScanDisks | Mode::PreClone | Mode::Clone | Mode::PostClone => { String::from("(q) to quit") } @@ -69,6 +70,13 @@ impl Component for Footer { Mode::Done | Mode::Failed | Mode::InstallDrivers => { String::from("(Enter) or (q) to quit") } + + // Diagnostic modes + Mode::DiagMenu + | Mode::BootDiags + | Mode::BootSetup + | Mode::InjectDrivers + | Mode::ToggleSafeBoot => String::from("(q) to quit"), } } Ok(None) diff --git a/deja_vu/src/components/left.rs b/deja_vu/src/components/left.rs index 8ccfa12..7b18095 100644 --- a/deja_vu/src/components/left.rs +++ b/deja_vu/src/components/left.rs @@ -218,6 +218,16 @@ impl Component for Left { self.title_text = String::from("Confirm Selections (Again)"); } (_, Mode::Done | Mode::Failed) => self.title_text = String::from("Done"), + // Diagnostic states + ( + _, + Mode::DiagMenu + | Mode::BootDiags + | Mode::BootSetup + | Mode::InjectDrivers + | Mode::ToggleSafeBoot, + ) => self.title_text = String::from("Boot Diagnostics"), + // Invalid states (_, Mode::Confirm) => panic!("This shouldn't happen."), } @@ -381,6 +391,14 @@ impl Component for Left { _ => panic!("This shouldn't happen."), } } + Mode::DiagMenu + | Mode::BootDiags + | Mode::BootSetup + | Mode::InjectDrivers + | Mode::ToggleSafeBoot => { + // Diagnostic modes + return Ok(()); + } } // Done diff --git a/deja_vu/src/components/popup.rs b/deja_vu/src/components/popup.rs index 933dbde..545f803 100644 --- a/deja_vu/src/components/popup.rs +++ b/deja_vu/src/components/popup.rs @@ -45,7 +45,7 @@ pub struct Popup { impl Popup { pub fn new() -> Self { Self { - popup_text: String::from("Scanning Disks..."), + popup_text: String::new(), ..Default::default() } } diff --git a/deja_vu/src/components/right.rs b/deja_vu/src/components/right.rs index d053b25..61814d3 100644 --- a/deja_vu/src/components/right.rs +++ b/deja_vu/src/components/right.rs @@ -86,7 +86,7 @@ impl Component for Right { }, Action::Process => { if self.prev_mode == Mode::SelectDisks && self.cur_mode == Mode::Confirm { - self.selected_disks = self.selections.clone(); + self.selected_disks.clone_from(&self.selections); } } Action::Select(one, two) => { diff --git a/deja_vu/src/components/title.rs b/deja_vu/src/components/title.rs index 1394186..01799ec 100644 --- a/deja_vu/src/components/title.rs +++ b/deja_vu/src/components/title.rs @@ -46,19 +46,16 @@ impl Component for Title { Ok(()) } - fn update(&mut self, action: Action) -> Result> { - match action { - _ => {} - } - Ok(None) - } + // fn update(&mut self, action: Action) -> Result> { + // match action { + // _ => {} + // } + // Ok(None) + // } fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> { // Title Block - let title_text = Span::styled( - "WizardKit: Clone Tool", - Style::default().fg(Color::LightCyan), - ); + let title_text = Span::styled("WizardKit: Deja-Vu", Style::default().fg(Color::LightCyan)); let title = Paragraph::new(Line::from(title_text).centered()) .block(Block::default().borders(Borders::ALL)); frame.render_widget(title, area); diff --git a/deja_vu/src/main.rs b/deja_vu/src/main.rs index 72a1b88..326069a 100644 --- a/deja_vu/src/main.rs +++ b/deja_vu/src/main.rs @@ -37,7 +37,7 @@ async fn main() -> Result<()> { crate::logging::init()?; let args = Cli::parse(); - let mut app = App::new(args.tick_rate, args.frame_rate)?; + let mut app = App::new(args.cli_cmd, args.tick_rate, args.frame_rate)?; app.run().await?; Ok(()) }