use std::path::PathBuf; use anyhow::{bail, Result}; use clap::{ArgAction, Parser, Subcommand}; use url::Url; use crate::{ interface::{input::Input, project::ProjectName}, state::State, task, }; #[derive(Parser, Debug)] #[command(author, version, about, long_about, verbatim_doc_comment)] /// This is the core interface to the system-integrated task management /// /// `tskm` effectively combines multiple applications together: /// - `taskwarrior` projects are raised connected to `firefox` profiles, making it possible to “open” /// a project. /// - Every `taskwarrior` project has a determined `neorg` path, so that extra information for a /// `project` can be stored in this `norg` file. /// - `tskm` can track inputs for you. These are URLs with optional tags which you can that /// “review” to open tasks based on them. pub struct CliArgs { #[command(subcommand)] pub command: Command, /// Increase message verbosity #[arg(long="verbose", short = 'v', action = ArgAction::Count, default_value_t = 2)] pub verbosity: u8, /// Silence all output #[arg(long, short = 'q')] pub quiet: bool, } #[derive(Subcommand, Debug)] pub enum Command { /// Interact with projects. Projects { #[command(subcommand)] command: ProjectCommand, }, /// Manage the input queue. Inputs { #[command(subcommand)] command: InputCommand, }, /// Access the associated `neorg` workspace for the project/task. Neorg { #[command(subcommand)] command: NeorgCommand, }, /// Interface with the Firefox profile of each project. Open { #[command(subcommand)] command: OpenCommand, }, } #[derive(Subcommand, Debug)] pub enum ProjectCommand { /// Lists all available projects. List, /// Allows you to quickly add projects. Add { /// The name of the new project. #[arg(value_parser = ProjectName::try_from_project)] new_project_name: ProjectName, }, } #[derive(Subcommand, Debug, Clone, Copy)] pub enum NeorgCommand { /// Open the `neorg` project associated with id of the task. Task { /// The working set id of the task #[arg(value_parser = task_from_working_set_id)] id: task::Task, }, } fn task_from_working_set_id(id: &str) -> Result { let id: usize = id.parse()?; let mut state = State::new_ro()?; let Some(task) = task::Task::from_working_set(id, &mut state)? else { bail!("Working set id '{id}' is not valid!") }; Ok(task) } #[derive(Subcommand, Debug)] pub enum OpenCommand { /// Open each project's Firefox profile consecutively, that was opened since the last review. /// /// This allows you to remove stale opened tabs and to commit open tabs to the `inputs`. Review, /// Opens Firefox with either the supplied project or the currently active project profile. Project { /// The project to open. #[arg(value_parser = task::Project::from_project_string)] project: task::Project, /// The URL to open. url: Option, }, /// Open a selected project in it's Firefox profile. /// /// This will use rofi's dmenu mode to select one project from the list of all registered /// projects. Select { /// The URL to open. url: Option, }, /// List all open tabs in the project. ListTabs { /// The project to open. #[arg(value_parser = task::Project::from_project_string)] project: Option, }, } #[derive(Subcommand, Debug)] pub enum InputCommand { /// Add URLs as inputs to be categorized. Add { inputs: Vec }, /// Remove URLs Remove { inputs: Vec }, /// Add all URLs in the file as inputs to be categorized. /// /// This expects each line to contain one URL. File { file: PathBuf }, /// Like 'review', but for the inputs that have previously been added. /// It takes a project in which to open the URLs. Review { /// Opens all the URLs in this project. #[arg(value_parser = task::Project::from_project_string)] project: task::Project, }, /// List all the previously added inputs. List, }