// SPDX-License-Identifier: GPL-3.0-or-later // examples/cli.rs // // CLI test harness for the noctua_core document foundation. use clap::{ArgGroup, Parser}; use noctua_core::document::manager::{DocumentCommand, DocumentManager, DocumentState}; use noctua_core::document::session::SessionKind; use std::path::PathBuf; fn print_session(manager: &DocumentManager, session_name: &str) { if let Some(session) = manager.session(session_name) { println!("Session '{}' ({:?})", session.name, session.kind); println!( " Items: {}, current_index: {:?}", session.items.len(), session.current_index ); for (i, item) in session.items.iter().enumerate() { let marker = if session.current_index == Some(i) { "*" } else { " " }; println!( " [{}] {} (page {})", marker, item.path.display(), item.page_index ); } } else { println!("Session '{}' not found", session_name); } } fn handle_command(manager: &mut DocumentManager, command: DocumentCommand) { manager.handle(command); match &manager.state { DocumentState::Error(err) => { eprintln!("Error: {}", err); manager.state = DocumentState::Empty; } _ => {} } } #[derive(Parser, Debug)] #[command( name = "noctua", about = "A document viewer for the COSMIC desktop", group( ArgGroup::new("source") .required(true) .args(["open_document", "open_directory", "open_session"]) ) )] struct Cli { /// Open a document (Raster, Vector, Portable) #[arg(long, value_name = "PATH")] open_document: Option, /// Open a directory #[arg(long, value_name = "PATH")] open_directory: Option, /// Open a session file (.ron) #[arg(long, value_name = "PATH")] open_session: Option, } fn main() { env_logger::init(); let cli = Cli::parse(); let mut manager = DocumentManager::new(); if let Some(path) = cli.open_session { manager.handle(DocumentCommand::OpenSession(path)); } else if let Some(path) = cli.open_document { let dir = path .parent() .map(|p| p.to_path_buf()) .unwrap_or_else(|| PathBuf::from(".")); let session_name = dir .file_name() .and_then(|n| n.to_str()) .unwrap_or("Browse") .to_string(); if manager.session(&session_name).is_none() { manager.handle(DocumentCommand::CreateSession { name: session_name.clone(), kind: SessionKind::DirectoryBrowser, path: Some(dir.clone()), }); manager.handle(DocumentCommand::ScanDirectory { session: session_name.clone(), dir, }); } manager.handle(DocumentCommand::AddFileToSession { session: session_name, path, }); } else if let Some(path) = cli.open_directory { let session_name = path .file_name() .and_then(|n| n.to_str()) .unwrap_or("Browse") .to_string(); if manager.session(&session_name).is_none() { manager.handle(DocumentCommand::CreateSession { name: session_name.clone(), kind: SessionKind::DirectoryBrowser, path: Some(path.clone()), }); manager.handle(DocumentCommand::ScanDirectory { session: session_name.clone(), dir: path, }); } manager.handle(DocumentCommand::SetActive(session_name)); } match &manager.state { DocumentState::Empty => println!("UI: No document loaded."), DocumentState::Loading => println!("UI: Loading..."), DocumentState::Error(err) => eprintln!("UI: Error -> {err}"), DocumentState::Loaded(_) => { println!("UI: Document loaded."); if let Some(name) = manager.active_session_name.clone() { if let Some(session) = manager.session(&name) { println!( "UI: Session '{}' ({:?}) has {} items, current index: {:?}", session.name, session.kind, session.items.len(), session.current_index ); match session.kind { SessionKind::DirectoryBrowser => { println!("UI: Display as directory browser (thumbnails in left panel)"); } SessionKind::DocumentCollection => { println!("UI: Display as document collection (pages)"); } } } println!("\nUI: Test navigation..."); handle_command(&mut manager, DocumentCommand::NavigateNext); if let Some(session) = manager.session(&name) { println!( "UI: After NavigateNext -> index {:?}", session.current_index ); } handle_command(&mut manager, DocumentCommand::NavigatePrevious); if let Some(session) = manager.session(&name) { println!( "UI: After NavigatePrevious -> index {:?}", session.current_index ); } handle_command(&mut manager, DocumentCommand::SelectItem(0)); if let Some(session) = manager.session(&name) { println!( "UI: After SelectItem(0) -> index {:?}", session.current_index ); } println!("\nUI: Test copy/move/delete..."); handle_command( &mut manager, DocumentCommand::CreateSession { name: "Favorites".to_string(), kind: SessionKind::DocumentCollection, path: None, }, ); handle_command( &mut manager, DocumentCommand::CreateSession { name: "Workspace".to_string(), kind: SessionKind::DocumentCollection, path: None, }, ); println!("\nBefore CopyItemToSession:"); print_session(&manager, "Favorites"); handle_command( &mut manager, DocumentCommand::CopyItemToSession { source_session: name.clone(), target_session: "Favorites".to_string(), source_item_index: 0, target_item_index: None, }, ); println!("\nAfter CopyItemToSession to Favorites:"); print_session(&manager, "Favorites"); println!("\n--- Test DeleteItemFromSession on DirectoryBrowser (should fail) ---"); handle_command( &mut manager, DocumentCommand::DeleteItemFromSession { session: name.clone(), item_index: None, }, ); println!("\n--- Test Move from Favorites to Workspace ---"); println!("\nBefore Move:"); print_session(&manager, "Favorites"); print_session(&manager, "Workspace"); handle_command( &mut manager, DocumentCommand::CopyItemToSession { source_session: "Favorites".to_string(), target_session: "Workspace".to_string(), source_item_index: 0, target_item_index: None, }, ); handle_command( &mut manager, DocumentCommand::DeleteItemFromSession { session: "Favorites".to_string(), item_index: Some(0), }, ); println!("\nAfter Move:"); print_session(&manager, "Favorites"); print_session(&manager, "Workspace"); } } } }