diff --git a/Cargo.lock b/Cargo.lock index 9294cc9cf..1c515b40b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,14 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi 0.3.8", -] - [[package]] name = "arc-swap" version = "0.4.7" @@ -36,17 +27,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi 0.3.8", -] - [[package]] name = "autocfg" version = "1.0.0" @@ -145,13 +125,9 @@ version = "2.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" dependencies = [ - "ansi_term", - "atty", "bitflags", - "strsim", "textwrap", "unicode-width", - "vec_map", ] [[package]] @@ -1613,12 +1589,6 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - [[package]] name = "structopt" version = "0.3.14" @@ -1861,12 +1831,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55d1e41d56121e07f1e223db0a4def204e45c85425f6a16d462fd07c8d10d74c" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.9.2" diff --git a/Cargo.toml b/Cargo.toml index a1dc25851..eca68f9c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ rmp-serde = "^0.14.0" smallvec = { version = "1.1.0", features = ["serde", ] } bitflags = "1.0" pcre2 = { version = "0.2.3", optional = true } -structopt = { version = "0.3.14" } +structopt = { version = "0.3.14", default-features = false } [profile.release] diff --git a/meli.1 b/meli.1 index ff0a908d9..b00ae5f7e 100644 --- a/meli.1 +++ b/meli.1 @@ -48,6 +48,8 @@ Print documentation page and exit (Piping to a pager is recommended.) Print default theme keys and values in TOML syntax, to be used as a blueprint. .It Cm print-loaded-themes Print all loaded themes in TOML syntax. +.It Cm view +View mail from input file. .El .Sh DESCRIPTION .Nm diff --git a/src/bin.rs b/src/bin.rs index fccb80503..3e32379d1 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -199,6 +199,12 @@ enum SubCommand { #[structopt(display_order = 3)] /// print documentation page and exit (Piping to a pager is recommended.). Man(ManOpt), + + /// View mail from input file. + View { + #[structopt(value_name = "INPUT", parse(from_os_str))] + path: PathBuf, + }, } #[derive(Debug, StructOpt)] @@ -272,6 +278,19 @@ fn run_app(opt: Opt) -> Result<()> { print!("{}", conf::Themes::default().key_to_string("dark", false)); return Ok(()); } + Some(SubCommand::View { ref path }) => { + if !path.exists() { + return Err(MeliError::new(format!( + "`{}` is not a valid path", + path.display() + ))); + } else if !path.is_file() { + return Err(MeliError::new(format!( + "`{}` is a directory", + path.display() + ))); + } + } None => {} } @@ -289,26 +308,40 @@ fn run_app(opt: Opt) -> Result<()> { let signal_recvr = notify(signals, sender.clone())?; /* Create the application State. */ - let mut state = State::new(sender, receiver.clone())?; + let mut state; - let window = Box::new(Tabbed::new( - vec![ - Box::new(listing::Listing::new(&mut state.context)), - Box::new(ContactList::new(&state.context)), - Box::new(StatusPanel::new(crate::conf::value( - &state.context, - "theme_default", - ))), - ], - &state.context, - )); + if let Some(SubCommand::View { path }) = opt.subcommand { + let bytes = std::fs::read(&path) + .chain_err_summary(|| format!("Could not read from `{}`", path.display()))?; + let wrapper = EnvelopeWrapper::new(bytes) + .chain_err_summary(|| format!("Could not parse `{}`", path.display()))?; + state = State::new( + Some(Settings::without_accounts().unwrap_or_default()), + sender, + receiver.clone(), + )?; + state.register_component(Box::new(EnvelopeView::new(wrapper, None, None, 0))); + } else { + state = State::new(None, sender, receiver.clone())?; + let window = Box::new(Tabbed::new( + vec![ + Box::new(listing::Listing::new(&mut state.context)), + Box::new(ContactList::new(&state.context)), + Box::new(StatusPanel::new(crate::conf::value( + &state.context, + "theme_default", + ))), + ], + &state.context, + )); - let status_bar = Box::new(StatusBar::new(window)); - state.register_component(status_bar); + let status_bar = Box::new(StatusBar::new(window)); + state.register_component(status_bar); - let xdg_notifications = Box::new(components::notifications::XDGNotifications::new()); - state.register_component(xdg_notifications); - state.register_component(Box::new(components::notifications::NotificationFilter {})); + let xdg_notifications = Box::new(components::notifications::XDGNotifications::new()); + state.register_component(xdg_notifications); + state.register_component(Box::new(components::notifications::NotificationFilter {})); + } /* Keep track of the input mode. See UIMode for details */ 'main: loop { diff --git a/src/conf.rs b/src/conf.rs index 2a2bdc074..0cb43e3cf 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -499,6 +499,30 @@ impl Settings { log: fs.log, }) } + + pub fn without_accounts() -> Result { + let fs = FileSettings::new()?; + if let Some(ref log_path) = fs.log.log_file { + melib::change_log_dest(log_path.into()); + } + if fs.log.maximum_level != melib::LoggingLevel::default() { + melib::change_log_level(fs.log.maximum_level); + } + + Ok(Settings { + accounts: HashMap::new(), + pager: fs.pager, + listing: fs.listing, + notifications: fs.notifications, + shortcuts: fs.shortcuts, + tags: fs.tags, + composing: fs.composing, + pgp: fs.pgp, + terminal: fs.terminal, + plugins: fs.plugins, + log: fs.log, + }) + } } #[derive(Copy, Debug, Clone, Hash, PartialEq)] diff --git a/src/state.rs b/src/state.rs index b22139f33..8b60e4214 100644 --- a/src/state.rs +++ b/src/state.rs @@ -207,7 +207,11 @@ impl Drop for State { } impl State { - pub fn new(sender: Sender, receiver: Receiver) -> Result { + pub fn new( + settings: Option, + sender: Sender, + receiver: Receiver, + ) -> Result { /* * Create async channel to block the input-thread if we need to fork and stop it from reading * stdin, see get_events() for details @@ -216,7 +220,11 @@ impl State { let input_thread_pipe = nix::unistd::pipe() .map_err(|err| Box::new(err) as Box)?; let mut backends = Backends::new(); - let settings = Settings::new()?; + let settings = if let Some(settings) = settings { + settings + } else { + Settings::new()? + }; let mut plugin_manager = PluginManager::new(); for (_, p) in settings.plugins.clone() { if crate::plugins::PluginKind::Backend == p.kind() {