Add `view` subcommand
Add subcommand to view standalone e-mail files in meli's pager without instantiating any accounts.async
parent
7dc8a87a62
commit
e97cf98b3b
|
@ -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"
|
||||
|
|
|
@ -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]
|
||||
|
|
2
meli.1
2
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
|
||||
|
|
67
src/bin.rs
67
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 {
|
||||
|
|
24
src/conf.rs
24
src/conf.rs
|
@ -499,6 +499,30 @@ impl Settings {
|
|||
log: fs.log,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn without_accounts() -> Result<Settings> {
|
||||
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)]
|
||||
|
|
12
src/state.rs
12
src/state.rs
|
@ -207,7 +207,11 @@ impl Drop for State {
|
|||
}
|
||||
|
||||
impl State {
|
||||
pub fn new(sender: Sender<ThreadEvent>, receiver: Receiver<ThreadEvent>) -> Result<Self> {
|
||||
pub fn new(
|
||||
settings: Option<Settings>,
|
||||
sender: Sender<ThreadEvent>,
|
||||
receiver: Receiver<ThreadEvent>,
|
||||
) -> Result<Self> {
|
||||
/*
|
||||
* 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<dyn std::error::Error + Send + Sync + 'static>)?;
|
||||
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() {
|
||||
|
|
Loading…
Reference in New Issue