From 1e7adc5e0cfe566ebe0e343928b14c88f72a046d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Wed, 28 Feb 2024 09:09:03 +0100 Subject: [PATCH] add query arg to envelope list command --- CHANGELOG.md | 6 ++++ Cargo.lock | 21 +++++++++++-- Cargo.toml | 4 +++ src/backend/mod.rs | 12 +++++--- src/cache/args.rs | 29 ------------------ src/cache/mod.rs | 1 - src/email/envelope/command/list.rs | 47 +++++++++++++++++++++++++++--- src/folder/arg/name.rs | 8 +++++ 8 files changed, 88 insertions(+), 40 deletions(-) delete mode 100644 src/cache/args.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 2953c78..1ded1c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Changed the `envelope list` options: + - the folder argument became a flag `--folder ` + - the query argument has been added at the end of the command to filter and sort results (only filter and IMAP for now) + ## [1.0.0-beta.3] - 2024-02-25 ### Added diff --git a/Cargo.lock b/Cargo.lock index 4d965b4..be1418f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,6 +159,16 @@ version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +[[package]] +name = "ariadne" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "367fd0ad87307588d087544707bc5fbf4805ded96c7db922b70d368fa1cb5702" +dependencies = [ + "unicode-width", + "yansi", +] + [[package]] name = "async-broadcast" version = "0.5.1" @@ -1209,13 +1219,13 @@ dependencies = [ [[package]] name = "email-lib" version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7444aaa4ce80e796febd3def00dd27ec59f4097d65d727cfa5f16dfb07a4fd72" +source = "git+https://git.sr.ht/~soywod/pimalaya#79af9b0fa5fb30dcb1f8fbd322f7e40b9e05053a" dependencies = [ "advisory-lock", "anyhow", "async-trait", "chrono", + "chumsky", "convert_case", "dirs 4.0.0", "email-macros", @@ -1856,6 +1866,7 @@ name = "himalaya" version = "1.0.0-beta.3" dependencies = [ "anyhow", + "ariadne", "async-trait", "chrono", "clap", @@ -4956,6 +4967,12 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "z-base-32" version = "0.1.3" diff --git a/Cargo.toml b/Cargo.toml index a905bf8..83f337d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ tempfile = "3.3" [dependencies] anyhow = "1" +ariadne = "0.2" async-trait = "0.1" chrono = "0.4.24" clap = { version = "4.4", features = ["derive"] } @@ -88,3 +89,6 @@ uuid = { version = "0.8", features = ["v4"] } [target.'cfg(not(windows))'.dependencies.coredump] version = "0.1" + +[patch.crates-io] +email-lib = { git = "https://git.sr.ht/~soywod/pimalaya" } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 94ad6c7..23b6044 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -22,7 +22,12 @@ use email::{ backend::{ feature::BackendFeature, macros::BackendContext, mapper::SomeBackendContextBuilderMapper, }, - envelope::{get::GetEnvelope, list::ListEnvelopes, watch::WatchEnvelopes, Id, SingleId}, + envelope::{ + get::GetEnvelope, + list::{ListEnvelopes, ListEnvelopesOptions}, + watch::WatchEnvelopes, + Id, SingleId, + }, flag::{add::AddFlags, remove::RemoveFlags, set::SetFlags, Flag, Flags}, folder::{ add::AddFolder, delete::DeleteFolder, expunge::ExpungeFolder, list::ListFolders, @@ -644,12 +649,11 @@ impl Backend { pub async fn list_envelopes( &self, folder: &str, - page_size: usize, - page: usize, + opts: ListEnvelopesOptions, ) -> Result { let backend_kind = self.toml_account_config.list_envelopes_kind(); let id_mapper = self.build_id_mapper(folder, backend_kind)?; - let envelopes = self.backend.list_envelopes(folder, page_size, page).await?; + let envelopes = self.backend.list_envelopes(folder, opts).await?; let envelopes = Envelopes::from_backend(&self.account_config, &id_mapper, envelopes)?; Ok(envelopes) } diff --git a/src/cache/args.rs b/src/cache/args.rs deleted file mode 100644 index c32f6e4..0000000 --- a/src/cache/args.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! This module provides arguments related to the cache. - -use clap::{Arg, ArgAction, ArgMatches}; - -const ARG_DISABLE_CACHE: &str = "disable-cache"; - -/// Represents the disable cache flag argument. This argument allows -/// the user to disable any sort of cache. -pub fn global_args() -> impl IntoIterator { - [Arg::new(ARG_DISABLE_CACHE) - .help("Disable any sort of cache") - .long_help( - "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.", - ) - .long("disable-cache") - .alias("no-cache") - .global(true) - .action(ArgAction::SetTrue)] -} - -/// Represents the disable cache flag parser. -pub fn parse_disable_cache_arg(m: &ArgMatches) -> bool { - m.get_flag(ARG_DISABLE_CACHE) -} diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 9190120..fce7241 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -1,5 +1,4 @@ pub mod arg; -pub mod args; use anyhow::{anyhow, Context, Result}; use dirs::data_dir; diff --git a/src/email/envelope/command/list.rs b/src/email/envelope/command/list.rs index 6b88c89..b84739a 100644 --- a/src/email/envelope/command/list.rs +++ b/src/email/envelope/command/list.rs @@ -1,6 +1,7 @@ use anyhow::Result; +use ariadne::{Color, Label, Report, ReportKind, Source}; use clap::Parser; -use email::backend::feature::BackendFeatureSource; +use email::{backend::feature::BackendFeatureSource, envelope::list::ListEnvelopesOptions}; use log::info; #[cfg(feature = "account-sync")] @@ -9,7 +10,7 @@ use crate::{ account::arg::name::AccountNameFlag, backend::Backend, config::TomlConfig, - folder::arg::name::FolderNameOptionalArg, + folder::arg::name::FolderNameOptionalFlag, printer::{PrintTableOpts, Printer}, ui::arg::max_width::TableMaxWidthFlag, }; @@ -21,7 +22,7 @@ use crate::{ #[derive(Debug, Parser)] pub struct ListEnvelopesCommand { #[command(flatten)] - pub folder: FolderNameOptionalArg, + pub folder: FolderNameOptionalFlag, /// The page number. /// @@ -45,6 +46,12 @@ pub struct ListEnvelopesCommand { #[command(flatten)] pub account: AccountNameFlag, + + /// The list envelopes filter and sort query. + /// + /// TODO + #[arg(allow_hyphen_values = true, trailing_var_arg = true)] + pub query: Option>, } impl Default for ListEnvelopesCommand { @@ -57,6 +64,7 @@ impl Default for ListEnvelopesCommand { #[cfg(feature = "account-sync")] cache: Default::default(), account: Default::default(), + query: Default::default(), } } } @@ -87,7 +95,38 @@ impl ListEnvelopesCommand { ) .await?; - let envelopes = backend.list_envelopes(folder, page_size, page).await?; + let filter = match self.query.map(|filter| filter.join(" ").parse()) { + Some(Ok(filter)) => Some(filter), + Some(Err(err)) => { + if let email::envelope::list::Error::ParseFilterError(errs, query) = &err { + errs.into_iter().for_each(|e| { + Report::build(ReportKind::Error, "query", e.span().start) + .with_message(e.to_string()) + .with_label( + Label::new(("query", e.span().into_range())) + .with_message(e.reason().to_string()) + .with_color(Color::Red), + ) + .finish() + .eprint(("query", Source::from(&query))) + .unwrap() + }); + }; + + Err(err)?; + None + } + None => None, + }; + + let opts = ListEnvelopesOptions { + page, + page_size, + filter, + sort: Default::default(), + }; + + let envelopes = backend.list_envelopes(folder, opts).await?; printer.print_table( Box::new(envelopes), diff --git a/src/folder/arg/name.rs b/src/folder/arg/name.rs index 1e2257e..139c98d 100644 --- a/src/folder/arg/name.rs +++ b/src/folder/arg/name.rs @@ -10,6 +10,14 @@ pub struct FolderNameOptionalFlag { pub name: String, } +impl Default for FolderNameOptionalFlag { + fn default() -> Self { + Self { + name: INBOX.to_owned(), + } + } +} + /// The optional folder name argument parser. #[derive(Debug, Parser)] pub struct FolderNameOptionalArg {