From 7ca11293a0af5e86f12bc90d5ea3b00f1b90e1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Thu, 10 Oct 2024 15:40:06 +0200 Subject: [PATCH] fix wizard --- Cargo.lock | 11 +++--- Cargo.toml | 2 +- flake.lock | 6 ++-- src/account/config.rs | 2 +- src/backend.rs | 2 +- src/cli.rs | 7 ++++ src/config.rs | 80 +++++++++++++++++++++++++++++++++++-------- src/main.rs | 29 +++++++++++----- 8 files changed, 104 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c80e81..4e3d155 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1143,7 +1143,7 @@ dependencies = [ [[package]] name = "email-lib" version = "0.25.0" -source = "git+https://github.com/pimalaya/core#124ff23ebd38c259e3fa377c043dbe4f010488bd" +source = "git+https://github.com/pimalaya/core#5be014bb70728260cbb906463c9281c1c37e7093" dependencies = [ "async-trait", "chrono", @@ -2779,7 +2779,7 @@ dependencies = [ [[package]] name = "oauth-lib" version = "0.1.1" -source = "git+https://github.com/pimalaya/core#124ff23ebd38c259e3fa377c043dbe4f010488bd" +source = "git+https://github.com/pimalaya/core#5be014bb70728260cbb906463c9281c1c37e7093" dependencies = [ "log", "oauth2", @@ -3054,7 +3054,7 @@ dependencies = [ [[package]] name = "pgp-lib" version = "0.2.0" -source = "git+https://github.com/pimalaya/core#124ff23ebd38c259e3fa377c043dbe4f010488bd" +source = "git+https://github.com/pimalaya/core#5be014bb70728260cbb906463c9281c1c37e7093" dependencies = [ "async-recursion", "futures", @@ -3074,7 +3074,7 @@ dependencies = [ [[package]] name = "pimalaya-tui" version = "0.1.0" -source = "git+https://github.com/pimalaya/tui#ff25e31f455c338e3f438164d3b3df3e087c312e" +source = "git+https://github.com/pimalaya/tui#79e708cfed9e6396347d5efb4e3615d78a8934c2" dependencies = [ "async-trait", "clap", @@ -3093,6 +3093,7 @@ dependencies = [ "serde_json", "shellexpand-utils", "thiserror", + "tokio", "toml", "toml_edit 0.22.22", "tracing", @@ -3245,7 +3246,7 @@ dependencies = [ [[package]] name = "process-lib" version = "0.4.2" -source = "git+https://github.com/pimalaya/core#124ff23ebd38c259e3fa377c043dbe4f010488bd" +source = "git+https://github.com/pimalaya/core#5be014bb70728260cbb906463c9281c1c37e7093" dependencies = [ "log", "serde", diff --git a/Cargo.toml b/Cargo.toml index e322888..5552b5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ sendmail = ["email-lib/sendmail", "pimalaya-tui/sendmail"] keyring = ["email-lib/keyring", "pimalaya-tui/keyring", "secret-lib?/keyring-tokio"] oauth2 = ["dep:oauth-lib", "email-lib/oauth2", "pimalaya-tui/oauth2", "keyring"] -wizard = ["dep:email_address", "dep:secret-lib", "email-lib/autoconfig"] +wizard = ["dep:email_address", "dep:secret-lib", "pimalaya-tui/wizard", "email-lib/autoconfig"] pgp = [] pgp-commands = ["email-lib/pgp-commands", "mml-lib/pgp-commands", "pgp"] diff --git a/flake.lock b/flake.lock index aa59fc9..3373a3e 100644 --- a/flake.lock +++ b/flake.lock @@ -79,11 +79,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1728328465, - "narHash": "sha256-a0a0M1TmXMK34y3M0cugsmpJ4FJPT/xsblhpiiX1CXo=", + "lastModified": 1728500571, + "narHash": "sha256-dOymOQ3AfNI4Z337yEwHGohrVQb4yPODCW9MDUyAc4w=", "owner": "nixos", "repo": "nixpkgs", - "rev": "1bfbbbe5bbf888d675397c66bfdb275d0b99361c", + "rev": "d51c28603def282a24fa034bcb007e2bcb5b5dd0", "type": "github" }, "original": { diff --git a/src/account/config.rs b/src/account/config.rs index 998614a..2722b8d 100644 --- a/src/account/config.rs +++ b/src/account/config.rs @@ -19,7 +19,7 @@ use email::sendmail::config::SendmailConfig; #[cfg(feature = "smtp")] use email::smtp::config::SmtpConfig; use email::{account::config::AccountConfig, template::config::TemplateConfig}; -use pimalaya_tui::config::toml::himalaya::{ +use pimalaya_tui::config::toml::himalaya::config::{ BackendKind, EnvelopeConfig, FolderConfig, MessageConfig, }; use serde::{Deserialize, Serialize}; diff --git a/src/backend.rs b/src/backend.rs index fa9b390..63fb5d4 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -22,7 +22,7 @@ use email::{ }, AnyResult, }; -use pimalaya_tui::config::toml::himalaya::BackendKind; +use pimalaya_tui::config::toml::himalaya::config::BackendKind; #[derive(Clone, Debug, Eq, PartialEq)] pub enum BackendConfig { diff --git a/src/cli.rs b/src/cli.rs index cc47e74..34b36ae 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -19,6 +19,13 @@ pub struct Cli { #[arg(value_name = "PATH", value_parser = path_parser)] pub config_paths: Vec, + /// Override the default account. + /// + /// An account name corresponds to an entry in the table at the + /// root level of your TOML configuration file. + #[arg(long, short, name = "account", value_name = "NAME")] + pub account: Option, + /// Enable logs with spantrace. /// /// This is the same as running the command with `RUST_LOG=debug` diff --git a/src/config.rs b/src/config.rs index a147b0b..89ed7b2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,8 +1,11 @@ use std::{collections::HashMap, path::PathBuf}; -use color_eyre::{eyre::eyre, Result}; +use async_trait::async_trait; use email::{account::config::AccountConfig, config::Config}; -use pimalaya_tui::config::toml::himalaya::AccountsConfig; +use pimalaya_tui::{ + config::toml::himalaya::config::{AccountsConfig, HimalayaTomlConfig}, + Result, +}; use serde::{Deserialize, Serialize}; use crate::account::config::TomlAccountConfig; @@ -69,29 +72,76 @@ impl From for Config { } } +#[async_trait] impl pimalaya_tui::config::toml::TomlConfig for TomlConfig { type AccountConfig = TomlAccountConfig; fn project_name() -> &'static str { - "himalaya" + HimalayaTomlConfig::project_name() } - fn get_default_account_config(&self) -> Result<(String, Self::AccountConfig)> { - self.accounts - .iter() - .find_map(|(name, account)| { - account - .default - .filter(|default| *default) - .map(|_| (name.to_owned(), account.clone())) - }) - .ok_or_else(|| eyre!("cannot find default account")) + fn get_default_account_config(&self) -> Option<(String, Self::AccountConfig)> { + self.accounts.iter().find_map(|(name, account)| { + account + .default + .filter(|default| *default) + .map(|_| (name.to_owned(), account.clone())) + }) } - fn get_account_config(&self, name: &str) -> Result<(String, Self::AccountConfig)> { + fn get_account_config(&self, name: &str) -> Option<(String, Self::AccountConfig)> { self.accounts .get(name) .map(|account| (name.to_owned(), account.clone())) - .ok_or_else(|| eyre!("cannot find account {name}")) + } + + #[cfg(feature = "wizard")] + async fn from_wizard(path: &std::path::Path) -> Result { + let config = HimalayaTomlConfig::from_wizard(path).await?; + Ok(Self { + display_name: config.display_name, + signature: config.signature, + signature_delim: config.signature_delim, + downloads_dir: config.downloads_dir, + accounts: config + .accounts + .into_iter() + .map(|(name, config)| { + ( + name, + TomlAccountConfig { + default: config.default, + email: config.email, + display_name: config.display_name, + signature: config.signature, + signature_delim: config.signature_delim, + downloads_dir: config.downloads_dir, + backend: config.backend, + + #[cfg(feature = "pgp")] + pgp: config.pgp, + + folder: config.folder, + envelope: config.envelope, + message: config.message, + template: config.template, + + #[cfg(feature = "imap")] + imap: config.imap, + #[cfg(feature = "maildir")] + maildir: config.maildir, + #[cfg(feature = "notmuch")] + notmuch: config.notmuch, + #[cfg(feature = "smtp")] + smtp: config.smtp, + #[cfg(feature = "sendmail")] + sendmail: config.sendmail, + }, + ) + }) + .collect(), + account: config.account, + repl: None, + }) } } diff --git a/src/main.rs b/src/main.rs index bfc678e..6da7120 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,7 +38,7 @@ use email::{ }; use pimalaya_tui::{ cli::tracing, - config::toml::{himalaya::BackendKind, TomlConfig as _}, + config::toml::{himalaya::config::BackendKind, TomlConfig as _}, prompt, }; use reedline::{ @@ -54,21 +54,26 @@ use crate::{ id_mapper::IdMapper, }; +static COMMANDS: [&str; 11] = [ + "help", "select", "unselect", "list", "read", "write", "reply", "forward", "copy", "move", + "delete", +]; + #[tokio::main] async fn main() -> Result<()> { tracing::install()?; let cli = Cli::parse(); - println!("Welcome to Himalaya REPL!"); - println!("Setting up backends…"); - let toml_cfg = TomlConfig::from_paths_or_default(&cli.config_paths).await?; let keybinds = toml_cfg.repl_keybinds().cloned().unwrap_or_default(); - let (toml_account_cfg, account_cfg) = toml_cfg.into_account_configs(None)?; + let (toml_account_cfg, account_cfg) = toml_cfg.into_account_configs(cli.account.as_deref())?; let account_cfg = Arc::new(account_cfg); + println!("Welcome to Himalaya REPL!"); + println!("Starting up backends…"); + let backend = BackendBuilder::new( account_cfg.clone(), @@ -129,6 +134,9 @@ async fn main() -> Result<()> { match mode.read_line(&prompt)? { Signal::Success(cmd) => match cmd.trim() { + "help" | "h" => { + println!("Available commands: {}", COMMANDS.join(", ")); + } "select" => { let folders = backend.list_folders().await?.into_iter().map(|f| f.name); let f = prompt::item("Select a folder:", folders, None)?; @@ -314,13 +322,16 @@ struct UnselectedMode(Reedline); impl UnselectedMode { pub fn new(keybinds: KeybindsStyle) -> impl DerefMut { - let commands = vec!["create".into(), "list".into(), "select".into()]; - let completer = Box::new(DefaultCompleter::new_with_wordlen(commands.clone(), 2)); - let completion_menu = Box::new(ColumnarMenu::default().with_name("completion")); + let completer = Box::new(DefaultCompleter::new_with_wordlen( + COMMANDS.iter().map(ToString::to_string).collect(), + 0, + )); + + let completion = Box::new(ColumnarMenu::default().with_name("completion")); let reedline = Reedline::create() .with_completer(completer) - .with_menu(ReedlineMenu::EngineCompleter(completion_menu)); + .with_menu(ReedlineMenu::EngineCompleter(completion)); let reedline = match keybinds { KeybindsStyle::Emacs => {