mirror of
https://github.com/soywod/himalaya.git
synced 2024-07-08 10:35:13 +00:00
move domain stuff to domain/, improve completion
This commit is contained in:
parent
223537c4ca
commit
0ed1147f3d
|
@ -1,29 +0,0 @@
|
|||
use anyhow::Result;
|
||||
use clap::{self, App, Arg, ArgMatches, Shell, SubCommand};
|
||||
use log::debug;
|
||||
use std::io;
|
||||
|
||||
pub fn subcmds<'s>() -> Vec<App<'s, 's>> {
|
||||
vec![SubCommand::with_name("completion")
|
||||
.about("Generates the completion script for the given shell")
|
||||
.args(&[Arg::with_name("shell")
|
||||
.possible_values(&["bash", "zsh", "fish"])
|
||||
.required(true)])]
|
||||
}
|
||||
|
||||
pub fn matches<'a>(app: fn() -> App<'a, 'a>, matches: &ArgMatches) -> Result<bool> {
|
||||
if let Some(matches) = matches.subcommand_matches("completion") {
|
||||
debug!("completion command matched");
|
||||
let shell = match matches.value_of("shell").unwrap() {
|
||||
"fish" => Shell::Fish,
|
||||
"zsh" => Shell::Zsh,
|
||||
"bash" | _ => Shell::Bash,
|
||||
};
|
||||
debug!("shell: {}", shell);
|
||||
app().gen_completions_to("himalaya", shell, &mut io::stdout());
|
||||
return Ok(true);
|
||||
};
|
||||
|
||||
debug!("nothing matched");
|
||||
Ok(false)
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
pub mod cli;
|
34
src/compl/arg.rs
Normal file
34
src/compl/arg.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
//! Module related to completion arguments.
|
||||
//!
|
||||
//! This module provides subcommands and an argument matcher for the completion command.
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::{self, App, Arg, ArgMatches, Shell, SubCommand};
|
||||
use log::debug;
|
||||
|
||||
/// Subcommands related to the completion generation.
|
||||
pub fn subcmds<'a>() -> Vec<App<'a, 'a>> {
|
||||
vec![SubCommand::with_name("completion")
|
||||
.about("Generates the completion script for the given shell")
|
||||
.args(&[Arg::with_name("shell")
|
||||
.possible_values(&Shell::variants()[..])
|
||||
.required(true)])]
|
||||
}
|
||||
|
||||
/// Enumeration of all possible completion matches.
|
||||
pub enum Match<'a> {
|
||||
/// Generate completion script for the given shell slice.
|
||||
Generate(&'a str),
|
||||
}
|
||||
|
||||
/// Completion arg matcher.
|
||||
pub fn matches<'a>(m: &'a ArgMatches) -> Result<Option<Match<'a>>> {
|
||||
if let Some(m) = m.subcommand_matches("completion") {
|
||||
debug!("completion command matched");
|
||||
let shell = m.value_of("shell").unwrap();
|
||||
debug!("shell: {}", shell);
|
||||
return Ok(Some(Match::Generate(shell)));
|
||||
};
|
||||
|
||||
Ok(None)
|
||||
}
|
16
src/compl/handler.rs
Normal file
16
src/compl/handler.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
//! Module related to completion handling.
|
||||
//!
|
||||
//! This module gathers all completion actions triggered by the CLI.
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use clap::{App, Shell};
|
||||
use std::{io, str::FromStr};
|
||||
|
||||
/// Generate completion script from the given [`clap::App`] for the given shell slice.
|
||||
pub fn generate<'a>(shell: &'a str, mut app: App<'a, 'a>) -> Result<()> {
|
||||
let shell = Shell::from_str(shell)
|
||||
.map_err(|err| anyhow!(err))
|
||||
.context("cannot parse shell")?;
|
||||
app.gen_completions_to("himalaya", shell, &mut io::stdout());
|
||||
Ok(())
|
||||
}
|
9
src/compl/mod.rs
Normal file
9
src/compl/mod.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
//! Module related to shell completion.
|
||||
//!
|
||||
//! This module allows users to generate autocompletion scripts for their shells. You can see the
|
||||
//! list of available shells directly on the [clap's docs.rs website].
|
||||
//!
|
||||
//! [clap's docs.rs website]: https://docs.rs/clap/2.33.3/clap/enum.Shell.html
|
||||
|
||||
pub mod arg;
|
||||
pub mod handler;
|
|
@ -2,7 +2,7 @@ use anyhow::Result;
|
|||
use clap;
|
||||
use log::debug;
|
||||
|
||||
use crate::domain::{config::entity::Config, imap::ImapServiceInterface};
|
||||
use crate::domain::{config::entity::Config, imap::service::ImapServiceInterface};
|
||||
|
||||
pub fn subcmds<'a>() -> Vec<clap::App<'a, 'a>> {
|
||||
vec![
|
4
src/domain/imap/mod.rs
Normal file
4
src/domain/imap/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
//! Modules related to IMAP.
|
||||
|
||||
pub mod cli;
|
||||
pub mod service;
|
|
@ -4,9 +4,10 @@ use log::{debug, trace};
|
|||
use native_tls::{self, TlsConnector, TlsStream};
|
||||
use std::{collections::HashSet, convert::TryFrom, iter::FromIterator, net::TcpStream};
|
||||
|
||||
use crate::{domain::account::entity::Account, flag::model::Flags, msg::model::Msg};
|
||||
|
||||
use super::config::entity::Config;
|
||||
use crate::{
|
||||
domain::{account::entity::Account, config::entity::Config, msg::entity::Msg},
|
||||
flag::model::Flags,
|
||||
};
|
||||
|
||||
type ImapSession = imap::Session<TlsStream<TcpStream>>;
|
||||
type ImapMsgs = imap::types::ZeroCopy<Vec<imap::types::Fetch>>;
|
|
@ -3,8 +3,7 @@ use clap;
|
|||
use log::{debug, trace};
|
||||
|
||||
use crate::{
|
||||
domain::imap::ImapServiceInterface,
|
||||
mbox::model::Mboxes,
|
||||
domain::{imap::service::ImapServiceInterface, mbox::entity::Mboxes},
|
||||
output::service::{OutputService, OutputServiceInterface},
|
||||
};
|
||||
|
2
src/domain/mbox/mod.rs
Normal file
2
src/domain/mbox/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod cli;
|
||||
pub mod entity;
|
|
@ -3,4 +3,6 @@
|
|||
pub mod account;
|
||||
pub mod config;
|
||||
pub mod imap;
|
||||
pub mod mbox;
|
||||
pub mod msg;
|
||||
pub mod smtp;
|
||||
|
|
|
@ -15,14 +15,16 @@ use url::Url;
|
|||
|
||||
use super::{
|
||||
body::Body,
|
||||
entity::{Msg, MsgSerialized, Msgs},
|
||||
headers::Headers,
|
||||
model::{Msg, MsgSerialized, Msgs},
|
||||
};
|
||||
use crate::{
|
||||
domain::{account::entity::Account, imap::ImapServiceInterface, smtp::*},
|
||||
domain::{
|
||||
account::entity::Account, imap::service::ImapServiceInterface, mbox::cli::mbox_target_arg,
|
||||
smtp::service::SmtpServiceInterface,
|
||||
},
|
||||
flag::model::Flags,
|
||||
input,
|
||||
mbox::cli::mbox_target_arg,
|
||||
output::service::{OutputService, OutputServiceInterface},
|
||||
};
|
||||
|
|
@ -22,7 +22,7 @@ pub mod cli;
|
|||
|
||||
/// Here are the two **main structs** of this module: `Msg` and `Msgs` which
|
||||
/// represent a *Mail* or *multiple Mails* in this crate.
|
||||
pub mod model;
|
||||
pub mod entity;
|
||||
|
||||
/// This module is used in the `Msg` struct, which should represent an
|
||||
/// attachment of a msg.
|
3
src/domain/smtp/mod.rs
Normal file
3
src/domain/smtp/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
//! Modules related to SMTP.
|
||||
|
||||
pub mod service;
|
|
@ -2,7 +2,10 @@ use anyhow::Result;
|
|||
use clap;
|
||||
use log::debug;
|
||||
|
||||
use crate::{domain::imap::ImapServiceInterface, flag::model::Flags, msg::cli::uid_arg};
|
||||
use crate::{
|
||||
domain::{imap::service::ImapServiceInterface, msg::cli::uid_arg},
|
||||
flag::model::Flags,
|
||||
};
|
||||
|
||||
fn flags_arg<'a>() -> clap::Arg<'a, 'a> {
|
||||
clap::Arg::with_name("flags")
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
pub mod cli;
|
13
src/lib.rs
13
src/lib.rs
|
@ -12,9 +12,7 @@
|
|||
//!
|
||||
//! [here]: https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html
|
||||
|
||||
/// `comp` stands for `completion`. This module makes it possible to create autocompletion-settings
|
||||
/// for himalaya for your shell :)
|
||||
pub mod comp;
|
||||
pub mod compl;
|
||||
|
||||
/// Everything which is related to the config files. For example the structure of your config file.
|
||||
pub mod config;
|
||||
|
@ -23,19 +21,10 @@ pub mod config;
|
|||
/// read-flag.
|
||||
pub mod flag;
|
||||
|
||||
/// A wrapper for creating connections easier to the IMAP-Servers.
|
||||
pub mod imap;
|
||||
|
||||
/// Handles the input-interaction with the user. For example if you want to edit the body of your
|
||||
/// message, his module takes care of the draft and calls your ~(neo)vim~ your favourite editor.
|
||||
pub mod input;
|
||||
|
||||
/// Everything which is related to mboxes, for example creating or deleting some.
|
||||
pub mod mbox;
|
||||
|
||||
/// Includes everything related to a message. This means: Body, Headers, Attachments, etc.
|
||||
pub mod msg;
|
||||
|
||||
/// Handles the output. For example the JSON and HTML output.
|
||||
pub mod output;
|
||||
|
||||
|
|
42
src/main.rs
42
src/main.rs
|
@ -5,16 +5,20 @@ use log::{debug, trace};
|
|||
use std::{convert::TryFrom, env, path::PathBuf};
|
||||
|
||||
use himalaya::{
|
||||
comp,
|
||||
compl,
|
||||
config::cli::config_args,
|
||||
domain::{
|
||||
account::entity::Account, config::entity::Config, imap::ImapService, smtp::SmtpService,
|
||||
account::entity::Account,
|
||||
config::entity::Config,
|
||||
imap::{self, service::ImapService},
|
||||
mbox, msg,
|
||||
smtp::service::SmtpService,
|
||||
},
|
||||
flag, imap, mbox, msg,
|
||||
flag,
|
||||
output::{cli::output_args, service::OutputService},
|
||||
};
|
||||
|
||||
fn parse_args<'a>() -> clap::App<'a, 'a> {
|
||||
fn create_app<'a>() -> clap::App<'a, 'a> {
|
||||
clap::App::new(env!("CARGO_PKG_NAME"))
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.about(env!("CARGO_PKG_DESCRIPTION"))
|
||||
|
@ -27,7 +31,7 @@ fn parse_args<'a>() -> clap::App<'a, 'a> {
|
|||
.subcommands(imap::cli::subcmds())
|
||||
.subcommands(mbox::cli::subcmds())
|
||||
.subcommands(msg::cli::subcmds())
|
||||
.subcommands(comp::cli::subcmds())
|
||||
.subcommands(compl::arg::subcmds())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
|
@ -50,23 +54,23 @@ fn main() -> Result<()> {
|
|||
// return Ok(msg_matches_mailto(&app, &url, smtp)?);
|
||||
// }
|
||||
|
||||
let args = parse_args();
|
||||
let arg_matches = args.get_matches();
|
||||
let app = create_app();
|
||||
let m = app.get_matches();
|
||||
|
||||
// Check completion before init config
|
||||
if comp::cli::matches(parse_args, &arg_matches)? {
|
||||
// Check shell completion BEFORE any entity or service initialization.
|
||||
if let Some(compl::arg::Match::Generate(shell)) = compl::arg::matches(&m)? {
|
||||
let app = create_app();
|
||||
compl::handler::generate(shell, app)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
debug!("init output service");
|
||||
let output = OutputService::new(arg_matches.value_of("output").unwrap());
|
||||
debug!("output service: {:?}", output);
|
||||
let output = OutputService::new(m.value_of("output").unwrap())?;
|
||||
|
||||
debug!("init mbox");
|
||||
let mbox = arg_matches.value_of("mailbox").unwrap();
|
||||
let mbox = m.value_of("mailbox").unwrap();
|
||||
debug!("mbox: {}", mbox);
|
||||
|
||||
let config_path: PathBuf = arg_matches
|
||||
let config_path: PathBuf = m
|
||||
.value_of("config")
|
||||
.map(|s| s.into())
|
||||
.unwrap_or(Config::path()?);
|
||||
|
@ -74,7 +78,7 @@ fn main() -> Result<()> {
|
|||
let config = Config::try_from(config_path.clone())?;
|
||||
trace!("{:#?}", config);
|
||||
|
||||
let account_name = arg_matches.value_of("account");
|
||||
let account_name = m.value_of("account");
|
||||
debug!("init account `{}`", account_name.unwrap_or("default"));
|
||||
let account = Account::try_from((&config, account_name))?;
|
||||
trace!("{:#?}", account);
|
||||
|
@ -86,10 +90,10 @@ fn main() -> Result<()> {
|
|||
let mut smtp = SmtpService::new(&account)?;
|
||||
|
||||
debug!("begin matching");
|
||||
let _matched = mbox::cli::matches(&arg_matches, &output, &mut imap)?
|
||||
|| flag::cli::matches(&arg_matches, &mut imap)?
|
||||
|| imap::cli::matches(&arg_matches, &config, &mut imap)?
|
||||
|| msg::cli::matches(&arg_matches, mbox, &account, &output, &mut imap, &mut smtp)?;
|
||||
let _matched = mbox::cli::matches(&m, &output, &mut imap)?
|
||||
|| flag::cli::matches(&m, &mut imap)?
|
||||
|| imap::cli::matches(&m, &config, &mut imap)?
|
||||
|| msg::cli::matches(&m, mbox, &account, &output, &mut imap, &mut smtp)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
pub mod cli;
|
||||
pub mod model;
|
|
@ -1,6 +1,7 @@
|
|||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use log::debug;
|
||||
use serde::Serialize;
|
||||
use std::fmt;
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum OutputFmt {
|
||||
|
@ -8,11 +9,13 @@ pub enum OutputFmt {
|
|||
Json,
|
||||
}
|
||||
|
||||
impl From<&str> for OutputFmt {
|
||||
fn from(slice: &str) -> Self {
|
||||
impl FromStr for OutputFmt {
|
||||
type Err = Error;
|
||||
fn from_str(slice: &str) -> Result<Self, Self::Err> {
|
||||
match slice {
|
||||
"json" => Self::Json,
|
||||
"plain" | _ => Self::Plain,
|
||||
"JSON" | _ if slice.eq_ignore_ascii_case("json") => Ok(Self::Json),
|
||||
"PLAIN" | _ if slice.eq_ignore_ascii_case("plain") => Ok(Self::Plain),
|
||||
_ => Err(anyhow!("cannot parse output `{}`", slice)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +24,7 @@ impl fmt::Display for OutputFmt {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let slice = match self {
|
||||
&OutputFmt::Json => "JSON",
|
||||
&OutputFmt::Plain => "Plain",
|
||||
&OutputFmt::Plain => "PLAIN",
|
||||
};
|
||||
write!(f, "{}", slice)
|
||||
}
|
||||
|
@ -51,8 +54,11 @@ pub struct OutputService {
|
|||
|
||||
impl OutputService {
|
||||
/// Create a new output-handler by setting the given formatting style.
|
||||
pub fn new(fmt: &str) -> Self {
|
||||
Self { fmt: fmt.into() }
|
||||
pub fn new(slice: &str) -> Result<Self> {
|
||||
debug!("init output service");
|
||||
debug!("output: {}", slice);
|
||||
let fmt = OutputFmt::from_str(slice)?;
|
||||
Ok(Self { fmt })
|
||||
}
|
||||
|
||||
/// Returns true, if the formatting should be plaintext.
|
||||
|
|
Loading…
Reference in a new issue