diff --git a/src/account/arg/mod.rs b/src/account/arg/mod.rs new file mode 100644 index 0000000..c427f91 --- /dev/null +++ b/src/account/arg/mod.rs @@ -0,0 +1 @@ +pub mod name; diff --git a/src/account/arg/name.rs b/src/account/arg/name.rs new file mode 100644 index 0000000..4456e14 --- /dev/null +++ b/src/account/arg/name.rs @@ -0,0 +1,26 @@ +use clap::Parser; + +/// The account name argument parser +#[derive(Debug, Parser)] +pub struct AccountNameArg { + /// The name of the account + /// + /// The account names are taken from the table at the root level + /// of your TOML configuration file. + #[arg(value_name = "ACCOUNT")] + pub name: String, +} + +/// The account name flag parser +#[derive(Debug, Parser)] +pub struct AccountNameFlag { + /// Override the default account + #[arg( + long = "account", + short = 'a', + name = "account-name", + value_name = "NAME", + global = true + )] + pub name: Option, +} diff --git a/src/account/command/configure.rs b/src/account/command/configure.rs index 1ce3fb4..bcfbda1 100644 --- a/src/account/command/configure.rs +++ b/src/account/command/configure.rs @@ -7,6 +7,7 @@ use email::smtp::config::SmtpAuthConfig; use log::{debug, info, warn}; use crate::{ + account::arg::name::AccountNameArg, config::{ wizard::{prompt_passwd, prompt_secret}, TomlConfig, @@ -16,26 +17,22 @@ use crate::{ /// Configure the given account #[derive(Debug, Parser)] -pub struct Command { - /// The name of the account that needs to be configured - /// - /// The account names are taken from the table at the root level - /// of your TOML configuration file. - #[arg(value_name = "NAME")] - pub account_name: String, +pub struct AccountConfigureCommand { + #[command(flatten)] + pub account: AccountNameArg, - /// Force the account to reconfigure, even if it is already + /// Force the account to reconfigure, even if it has already been /// configured #[arg(long, short)] pub force: bool, } -impl Command { +impl AccountConfigureCommand { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { info!("executing account configure command"); let (_, account_config) = - config.into_toml_account_config(Some(self.account_name.as_str()))?; + config.into_toml_account_config(Some(self.account.name.as_str()))?; if self.force { #[cfg(feature = "imap")] @@ -106,7 +103,7 @@ impl Command { printer.print(format!( "Account {} successfully {}configured!", - self.account_name, + self.account.name, if self.force { "re" } else { "" } ))?; diff --git a/src/account/command/list.rs b/src/account/command/list.rs index b0a848e..ee70b04 100644 --- a/src/account/command/list.rs +++ b/src/account/command/list.rs @@ -6,17 +6,17 @@ use crate::{ account::Accounts, config::TomlConfig, printer::{PrintTableOpts, Printer}, + ui::arg::max_width::MaxTableWidthFlag, }; /// List all accounts #[derive(Debug, Parser)] -pub struct Command { - /// Define a maximum width for the table - #[arg(long, short = 'w', name = "PIXELS")] - pub max_width: Option, +pub struct AccountListCommand { + #[command(flatten)] + pub table: MaxTableWidthFlag, } -impl Command { +impl AccountListCommand { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { info!("executing account list command"); @@ -29,7 +29,7 @@ impl Command { .email_reading_format .as_ref() .unwrap_or(&Default::default()), - max_width: self.max_width, + max_width: self.table.max_width, }, )?; diff --git a/src/account/command/mod.rs b/src/account/command/mod.rs index ce0d776..2677935 100644 --- a/src/account/command/mod.rs +++ b/src/account/command/mod.rs @@ -7,23 +7,27 @@ use clap::Subcommand; use crate::{config::TomlConfig, printer::Printer}; +use self::{ + configure::AccountConfigureCommand, list::AccountListCommand, sync::AccountSyncCommand, +}; + /// Subcommand to manage accounts #[derive(Debug, Subcommand)] -pub enum Command { - /// Configure the given account +pub enum AccountSubcommand { + /// Configure an account #[command(alias = "cfg")] - Configure(configure::Command), + Configure(AccountConfigureCommand), - /// List all exsting accounts + /// List all accounts #[command(alias = "lst")] - List(list::Command), + List(AccountListCommand), - /// Synchronize the given account locally + /// Synchronize an account locally #[command()] - Sync(sync::Command), + Sync(AccountSyncCommand), } -impl Command { +impl AccountSubcommand { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { match self { Self::Configure(cmd) => cmd.execute(printer, config).await, diff --git a/src/account/command/sync.rs b/src/account/command/sync.rs index 7096924..286d05f 100644 --- a/src/account/command/sync.rs +++ b/src/account/command/sync.rs @@ -12,7 +12,10 @@ use std::{ sync::Mutex, }; -use crate::{backend::BackendBuilder, config::TomlConfig, printer::Printer}; +use crate::{ + account::arg::name::AccountNameArg, backend::BackendBuilder, config::TomlConfig, + printer::Printer, +}; const MAIN_PROGRESS_STYLE: Lazy = Lazy::new(|| { ProgressStyle::with_template(" {spinner:.dim} {msg:.dim}\n {wide_bar:.cyan/blue} \n").unwrap() @@ -30,13 +33,9 @@ const SUB_PROGRESS_DONE_STYLE: Lazy = Lazy::new(|| { }); #[derive(Debug, Parser)] -pub struct Command { - /// The name of the account that needs to be synchronized - /// - /// The account names are taken from the table at the root level - /// of your TOML configuration file. - #[arg(value_name = "ACCOUNT")] - pub account_name: String, +pub struct AccountSyncCommand { + #[command(flatten)] + pub account: AccountNameArg, /// Run the synchronization without applying changes /// @@ -60,7 +59,7 @@ pub struct Command { pub all_folders: bool, } -impl Command { +impl AccountSyncCommand { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { info!("executing account sync command"); @@ -79,7 +78,7 @@ impl Command { let (toml_account_config, account_config) = config .clone() - .into_account_configs(Some(self.account_name.as_str()), true)?; + .into_account_configs(Some(self.account.name.as_str()), true)?; let backend_builder = BackendBuilder::new(toml_account_config, account_config.clone(), false).await?; @@ -110,11 +109,15 @@ impl Command { } printer.print(format!( - "Estimated patch length for account to be synchronized: {hunks_count}", + "Estimated patch length for account {} to be synchronized: {hunks_count}", + self.account.name ))?; } else if printer.is_json() { sync_builder.sync().await?; - printer.print("Account successfully synchronized!")?; + printer.print(format!( + "Account {} successfully synchronized!", + self.account.name + ))?; } else { let multi = MultiProgress::new(); let sub_progresses = Mutex::new(HashMap::new()); @@ -225,7 +228,10 @@ impl Command { ))?; } - printer.print("Account successfully synchronized!")?; + printer.print(format!( + "Account {} successfully synchronized!", + self.account.name + ))?; } Ok(()) diff --git a/src/account/mod.rs b/src/account/mod.rs index b463195..1910174 100644 --- a/src/account/mod.rs +++ b/src/account/mod.rs @@ -1,3 +1,4 @@ +pub mod arg; pub mod command; pub mod config; pub(crate) mod wizard; diff --git a/src/cache/arg/disable.rs b/src/cache/arg/disable.rs new file mode 100644 index 0000000..54d5b8e --- /dev/null +++ b/src/cache/arg/disable.rs @@ -0,0 +1,19 @@ +use clap::Parser; + +/// The disable cache flag parser +#[derive(Debug, Parser)] +pub struct DisableCacheFlag { + /// Disable any sort of cache + /// + /// The action depends on commands it apply on. For example, when + /// listing envelopes using the IMAP backend, this flag will + /// ensure that envelopes are fetched from the IMAP server and not + /// from the synchronized local Maildir. + #[arg( + long = "disable-cache", + alias = "no-cache", + name = "disable-cache", + global = true + )] + pub disable: bool, +} diff --git a/src/cache/arg/mod.rs b/src/cache/arg/mod.rs new file mode 100644 index 0000000..a13d9f3 --- /dev/null +++ b/src/cache/arg/mod.rs @@ -0,0 +1 @@ +pub mod disable; diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 04ac835..4b51a20 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -1,3 +1,4 @@ +pub mod arg; pub mod args; use anyhow::{anyhow, Context, Result}; diff --git a/src/cli.rs b/src/cli.rs index 481320e..2b86351 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,13 +1,13 @@ -use std::path::PathBuf; - use anyhow::Result; use clap::{Parser, Subcommand}; +use std::path::PathBuf; use crate::{ - account::command as account, - completion::command as completion, + account::command::AccountSubcommand, + completion::command::CompletionGenerateCommand, config::{self, TomlConfig}, - man::command as man, + folder::command::FolderSubcommand, + manual::command::ManualGenerateCommand, output::{ColorFmt, OutputFmt}, printer::Printer, }; @@ -23,7 +23,7 @@ use crate::{ )] pub struct Cli { #[command(subcommand)] - pub command: Command, + pub command: HimalayaCommand, /// Override the default configuration file path /// @@ -86,27 +86,31 @@ pub struct Cli { pub color: ColorFmt, } -/// Top-level CLI commands. #[derive(Subcommand, Debug)] -pub enum Command { +pub enum HimalayaCommand { /// Subcommand to manage accounts #[command(subcommand)] - Account(account::Command), + Account(AccountSubcommand), - /// Generate all man pages to the given directory - #[command(arg_required_else_help = true, alias = "mans")] - Man(man::Command), + /// Subcommand to manage folders + #[command(subcommand)] + Folder(FolderSubcommand), - /// Print completion script for the given shell to stdout - #[command(arg_required_else_help = true, aliases = ["completions", "compl", "comp"])] - Completion(completion::Command), + /// Generate manual pages to a directory + #[command(arg_required_else_help = true)] + Manual(ManualGenerateCommand), + + /// Print completion script for a shell to stdout + #[command(arg_required_else_help = true)] + Completion(CompletionGenerateCommand), } -impl Command { +impl HimalayaCommand { pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { match self { Self::Account(cmd) => cmd.execute(printer, config).await, - Self::Man(cmd) => cmd.execute(printer).await, + Self::Folder(cmd) => cmd.execute(printer, config).await, + Self::Manual(cmd) => cmd.execute(printer).await, Self::Completion(cmd) => cmd.execute(printer).await, } } diff --git a/src/completion/command.rs b/src/completion/command.rs index aecefcc..67a3a7f 100644 --- a/src/completion/command.rs +++ b/src/completion/command.rs @@ -6,15 +6,15 @@ use std::io; use crate::{cli::Cli, printer::Printer}; -/// Print completion script for the given shell to stdout +/// Print completion script for a shell to stdout #[derive(Debug, Parser)] -pub struct Command { - /// Shell that completion script should be generated for +pub struct CompletionGenerateCommand { + /// Shell for which completion script should be generated for #[arg(value_parser = value_parser!(Shell))] pub shell: Shell, } -impl Command { +impl CompletionGenerateCommand { pub async fn execute(self, printer: &mut impl Printer) -> Result<()> { info!("executing completion generate command"); diff --git a/src/folder/arg/mod.rs b/src/folder/arg/mod.rs new file mode 100644 index 0000000..c427f91 --- /dev/null +++ b/src/folder/arg/mod.rs @@ -0,0 +1 @@ +pub mod name; diff --git a/src/folder/arg/name.rs b/src/folder/arg/name.rs new file mode 100644 index 0000000..fe80733 --- /dev/null +++ b/src/folder/arg/name.rs @@ -0,0 +1,9 @@ +use clap::Parser; + +/// The folder name argument parser +#[derive(Debug, Parser)] +pub struct FolderNameArg { + /// The name of the folder + #[arg(name = "folder-name", value_name = "FOLDER")] + pub name: String, +} diff --git a/src/folder/command/create.rs b/src/folder/command/create.rs new file mode 100644 index 0000000..02c409e --- /dev/null +++ b/src/folder/command/create.rs @@ -0,0 +1,40 @@ +use anyhow::Result; +use clap::Parser; +use log::info; + +use crate::{ + account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag, + config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer, +}; + +/// Create a new folder +#[derive(Debug, Parser)] +pub struct FolderCreateCommand { + #[command(flatten)] + pub folder: FolderNameArg, + + #[command(flatten)] + pub account: AccountNameFlag, + + #[command(flatten)] + pub cache: DisableCacheFlag, +} + +impl FolderCreateCommand { + pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { + info!("executing folder create command"); + + let folder = &self.folder.name; + + let some_account_name = self.account.name.as_ref().map(String::as_str); + let (toml_account_config, account_config) = config + .clone() + .into_account_configs(some_account_name, self.cache.disable)?; + let backend = Backend::new(toml_account_config, account_config.clone(), false).await?; + + backend.add_folder(&folder).await?; + printer.print(format!("Folder {folder} successfully created!"))?; + + Ok(()) + } +} diff --git a/src/folder/command/delete.rs b/src/folder/command/delete.rs new file mode 100644 index 0000000..e0786db --- /dev/null +++ b/src/folder/command/delete.rs @@ -0,0 +1,55 @@ +use anyhow::Result; +use clap::Parser; +use dialoguer::Confirm; +use log::info; +use std::process; + +use crate::{ + account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag, + config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer, +}; + +/// Delete a folder +/// +/// All emails from a given folder are definitely deleted. The folder +/// is also deleted after execution of the command. +#[derive(Debug, Parser)] +pub struct FolderDeleteCommand { + #[command(flatten)] + pub folder: FolderNameArg, + + #[command(flatten)] + pub account: AccountNameFlag, + + #[command(flatten)] + pub cache: DisableCacheFlag, +} + +impl FolderDeleteCommand { + pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { + info!("executing folder delete command"); + + let folder = &self.folder.name; + + let confirm_msg = format!("Do you really want to delete the folder {folder}? All emails will be definitely deleted."); + let confirm = Confirm::new() + .with_prompt(confirm_msg) + .default(false) + .report(false) + .interact_opt()?; + if let Some(false) | None = confirm { + process::exit(0); + }; + + let some_account_name = self.account.name.as_ref().map(String::as_str); + let (toml_account_config, account_config) = config + .clone() + .into_account_configs(some_account_name, self.cache.disable)?; + let backend = Backend::new(toml_account_config, account_config.clone(), false).await?; + + backend.delete_folder(&folder).await?; + printer.print(format!("Folder {folder} successfully deleted!"))?; + + Ok(()) + } +} diff --git a/src/folder/command/expunge.rs b/src/folder/command/expunge.rs new file mode 100644 index 0000000..ac2c0b3 --- /dev/null +++ b/src/folder/command/expunge.rs @@ -0,0 +1,44 @@ +use anyhow::Result; +use clap::Parser; +use log::info; + +use crate::{ + account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag, + config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer, +}; + +/// Expunge a folder +/// +/// The concept of expunging is similar to the IMAP one: it definitely +/// deletes emails from a given folder that contain the "deleted" +/// flag. +#[derive(Debug, Parser)] +pub struct FolderExpungeCommand { + #[command(flatten)] + pub folder: FolderNameArg, + + #[command(flatten)] + pub account: AccountNameFlag, + + #[command(flatten)] + pub cache: DisableCacheFlag, +} + +impl FolderExpungeCommand { + pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { + info!("executing folder expunge command"); + + let folder = &self.folder.name; + + let some_account_name = self.account.name.as_ref().map(String::as_str); + let (toml_account_config, account_config) = config + .clone() + .into_account_configs(some_account_name, self.cache.disable)?; + let backend = Backend::new(toml_account_config, account_config.clone(), false).await?; + + backend.expunge_folder(&folder).await?; + printer.print(format!("Folder {folder} successfully expunged!"))?; + + Ok(()) + } +} diff --git a/src/folder/command/list.rs b/src/folder/command/list.rs new file mode 100644 index 0000000..03e0a65 --- /dev/null +++ b/src/folder/command/list.rs @@ -0,0 +1,50 @@ +use anyhow::Result; +use clap::Parser; +use log::info; + +use crate::{ + account::arg::name::AccountNameFlag, + backend::Backend, + cache::arg::disable::DisableCacheFlag, + config::TomlConfig, + folder::Folders, + printer::{PrintTableOpts, Printer}, + ui::arg::max_width::MaxTableWidthFlag, +}; + +/// List all folders +#[derive(Debug, Parser)] +pub struct FolderListCommand { + #[command(flatten)] + pub table: MaxTableWidthFlag, + + #[command(flatten)] + pub account: AccountNameFlag, + + #[command(flatten)] + pub cache: DisableCacheFlag, +} + +impl FolderListCommand { + pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { + info!("executing folder list command"); + + let some_account_name = self.account.name.as_ref().map(String::as_str); + let (toml_account_config, account_config) = config + .clone() + .into_account_configs(some_account_name, self.cache.disable)?; + let backend = Backend::new(toml_account_config, account_config.clone(), false).await?; + + let folders: Folders = backend.list_folders().await?.into(); + + printer.print_table( + Box::new(folders), + PrintTableOpts { + format: &account_config.email_reading_format, + max_width: self.table.max_width, + }, + )?; + + Ok(()) + } +} diff --git a/src/folder/command/mod.rs b/src/folder/command/mod.rs new file mode 100644 index 0000000..e00b0f9 --- /dev/null +++ b/src/folder/command/mod.rs @@ -0,0 +1,51 @@ +mod create; +mod delete; +mod expunge; +mod list; +mod purge; + +use anyhow::Result; +use clap::Subcommand; + +use crate::{config::TomlConfig, printer::Printer}; + +use self::{ + create::FolderCreateCommand, delete::FolderDeleteCommand, expunge::FolderExpungeCommand, + list::FolderListCommand, purge::FolderPurgeCommand, +}; + +/// Subcommand to manage accounts +#[derive(Debug, Subcommand)] +pub enum FolderSubcommand { + /// Create a new folder + #[command(alias = "add")] + Create(FolderCreateCommand), + + /// List all folders + #[command(alias = "lst")] + List(FolderListCommand), + + /// Expunge a folder + #[command()] + Expunge(FolderExpungeCommand), + + /// Purge a folder + #[command()] + Purge(FolderPurgeCommand), + + /// Delete a folder + #[command(alias = "remove", alias = "rm")] + Delete(FolderDeleteCommand), +} + +impl FolderSubcommand { + pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { + match self { + Self::Create(cmd) => cmd.execute(printer, config).await, + Self::List(cmd) => cmd.execute(printer, config).await, + Self::Expunge(cmd) => cmd.execute(printer, config).await, + Self::Purge(cmd) => cmd.execute(printer, config).await, + Self::Delete(cmd) => cmd.execute(printer, config).await, + } + } +} diff --git a/src/folder/command/purge.rs b/src/folder/command/purge.rs new file mode 100644 index 0000000..3d870f7 --- /dev/null +++ b/src/folder/command/purge.rs @@ -0,0 +1,55 @@ +use anyhow::Result; +use clap::Parser; +use dialoguer::Confirm; +use log::info; +use std::process; + +use crate::{ + account::arg::name::AccountNameFlag, backend::Backend, cache::arg::disable::DisableCacheFlag, + config::TomlConfig, folder::arg::name::FolderNameArg, printer::Printer, +}; + +/// Purge a folder +/// +/// All emails from a given folder are definitely deleted. The purged +/// folder will remain empty after executing of the command. +#[derive(Debug, Parser)] +pub struct FolderPurgeCommand { + #[command(flatten)] + pub folder: FolderNameArg, + + #[command(flatten)] + pub account: AccountNameFlag, + + #[command(flatten)] + pub cache: DisableCacheFlag, +} + +impl FolderPurgeCommand { + pub async fn execute(self, printer: &mut impl Printer, config: &TomlConfig) -> Result<()> { + info!("executing folder purge command"); + + let folder = &self.folder.name; + + let confirm_msg = format!("Do you really want to purge the folder {folder}? All emails will be definitely deleted."); + let confirm = Confirm::new() + .with_prompt(confirm_msg) + .default(false) + .report(false) + .interact_opt()?; + if let Some(false) | None = confirm { + process::exit(0); + }; + + let some_account_name = self.account.name.as_ref().map(String::as_str); + let (toml_account_config, account_config) = config + .clone() + .into_account_configs(some_account_name, self.cache.disable)?; + let backend = Backend::new(toml_account_config, account_config.clone(), false).await?; + + backend.purge_folder(&folder).await?; + printer.print(format!("Folder {folder} successfully purged!"))?; + + Ok(()) + } +} diff --git a/src/folder/mod.rs b/src/folder/mod.rs index e448920..67fd4c0 100644 --- a/src/folder/mod.rs +++ b/src/folder/mod.rs @@ -1,4 +1,6 @@ +pub mod arg; pub mod args; +pub mod command; pub mod config; pub mod handlers; diff --git a/src/lib.rs b/src/lib.rs index 8cb19cd..0cb7c67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ pub mod folder; pub mod imap; #[cfg(feature = "maildir")] pub mod maildir; -pub mod man; +pub mod manual; #[cfg(feature = "notmuch")] pub mod notmuch; pub mod output; diff --git a/src/main.rs b/src/main.rs index d80c198..8a2a343 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,10 +25,8 @@ async fn main() -> Result<()> { // .author(env!("CARGO_PKG_AUTHORS")) // .propagate_version(true) // .infer_subcommands(true) -// .args(folder::args::global_args()) // .args(cache::args::global_args()) // .args(output::args::global_args()) -// .subcommand(folder::args::subcmd()) // .subcommand(envelope::args::subcmd()) // .subcommand(flag::args::subcmd()) // .subcommand(message::args::subcmd()) @@ -67,63 +65,15 @@ async fn main() -> Result<()> { // let some_config_path = config::args::parse_global_arg(&m); // let some_account_name = account::command::parse_global_arg(&m); // let disable_cache = cache::args::parse_disable_cache_arg(&m); -// let folder = folder::args::parse_global_source_arg(&m); // let toml_config = TomlConfig::from_some_path_or_default(some_config_path).await?; // let mut printer = StdoutPrinter::try_from(&m)?; -// #[cfg(feature = "imap")] -// if let BackendConfig::Imap(imap_config) = &account_config.backend { -// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER); -// match imap::args::matches(&m)? { -// Some(imap::args::Cmd::Notify(keepalive)) => { -// let backend = -// ImapBackend::new(account_config.clone(), imap_config.clone(), None).await?; -// imap::handlers::notify(&mut backend, &folder, keepalive).await?; -// return Ok(()); -// } -// Some(imap::args::Cmd::Watch(keepalive)) => { -// let backend = -// ImapBackend::new(account_config.clone(), imap_config.clone(), None).await?; -// imap::handlers::watch(&mut backend, &folder, keepalive).await?; -// return Ok(()); -// } -// _ => (), -// } -// } - // let (toml_account_config, account_config) = toml_config // .clone() // .into_account_configs(some_account_name, disable_cache)?; -// // checks folder commands -// match folder::args::matches(&m)? { -// Some(folder::args::Cmd::Create) => { -// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?; -// let folder = folder -// .ok_or_else(|| anyhow!("the folder argument is missing")) -// .context("cannot create folder")?; -// return folder::handlers::create(&mut printer, &backend, &folder).await; -// } -// Some(folder::args::Cmd::List(max_width)) => { -// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?; -// return folder::handlers::list(&account_config, &mut printer, &backend, max_width) -// .await; -// } -// Some(folder::args::Cmd::Expunge) => { -// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER); -// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?; -// return folder::handlers::expunge(&mut printer, &backend, &folder).await; -// } -// Some(folder::args::Cmd::Delete) => { -// let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER); -// let backend = Backend::new(toml_account_config, account_config.clone(), false).await?; -// return folder::handlers::delete(&mut printer, &backend, &folder).await; -// } -// _ => (), -// } - // match envelope::args::matches(&m)? { // Some(envelope::args::Cmd::List(max_width, page_size, page)) => { // let folder = folder.unwrap_or(DEFAULT_INBOX_FOLDER); diff --git a/src/man/command.rs b/src/manual/command.rs similarity index 91% rename from src/man/command.rs rename to src/manual/command.rs index 85d17a3..f55ca93 100644 --- a/src/man/command.rs +++ b/src/manual/command.rs @@ -7,17 +7,17 @@ use std::{fs, path::PathBuf}; use crate::{cli::Cli, printer::Printer}; -/// Generate all man pages to the given directory +/// Generate manual pages to a directory #[derive(Debug, Parser)] -pub struct Command { +pub struct ManualGenerateCommand { /// Directory where man files should be generated in #[arg(value_parser = dir_parser)] pub dir: PathBuf, } -impl Command { +impl ManualGenerateCommand { pub async fn execute(self, printer: &mut impl Printer) -> Result<()> { - info!("executing man generate command"); + info!("executing manual generate command"); let cmd = Cli::command(); let cmd_name = cmd.get_name().to_string(); diff --git a/src/man/mod.rs b/src/manual/mod.rs similarity index 100% rename from src/man/mod.rs rename to src/manual/mod.rs diff --git a/src/printer/printer.rs b/src/printer/printer.rs index 872176d..ef00dd0 100644 --- a/src/printer/printer.rs +++ b/src/printer/printer.rs @@ -9,10 +9,14 @@ use crate::{ }; pub trait Printer { + // TODO: rename end fn print(&mut self, data: T) -> Result<()>; + // TODO: rename log fn print_log(&mut self, data: T) -> Result<()>; + // TODO: rename table fn print_table( &mut self, + // TODO: remove Box data: Box, opts: PrintTableOpts, ) -> Result<()>; diff --git a/src/ui/table/arg/max_width.rs b/src/ui/table/arg/max_width.rs new file mode 100644 index 0000000..bbcd977 --- /dev/null +++ b/src/ui/table/arg/max_width.rs @@ -0,0 +1,9 @@ +use clap::Parser; + +/// The table max width argument parser +#[derive(Debug, Parser)] +pub struct MaxTableWidthFlag { + /// The maximum width the table should not exceed + #[arg(long, short = 'w', value_name = "PIXELS")] + pub max_width: Option, +} diff --git a/src/ui/table/arg/mod.rs b/src/ui/table/arg/mod.rs new file mode 100644 index 0000000..e5a0593 --- /dev/null +++ b/src/ui/table/arg/mod.rs @@ -0,0 +1 @@ +pub mod max_width; diff --git a/src/ui/table/mod.rs b/src/ui/table/mod.rs index d9e4ee3..b07ca63 100644 --- a/src/ui/table/mod.rs +++ b/src/ui/table/mod.rs @@ -1,3 +1,4 @@ +pub mod arg; pub mod args; pub mod table;