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.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# 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]]
|
[[package]]
|
||||||
name = "arc-swap"
|
name = "arc-swap"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
|
@ -36,17 +27,6 @@ version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
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]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -145,13 +125,9 @@ version = "2.33.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
|
||||||
"atty",
|
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"strsim",
|
|
||||||
"textwrap",
|
"textwrap",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
"vec_map",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1613,12 +1589,6 @@ version = "0.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
|
checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "strsim"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "structopt"
|
name = "structopt"
|
||||||
version = "0.3.14"
|
version = "0.3.14"
|
||||||
|
@ -1861,12 +1831,6 @@ version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55d1e41d56121e07f1e223db0a4def204e45c85425f6a16d462fd07c8d10d74c"
|
checksum = "55d1e41d56121e07f1e223db0a4def204e45c85425f6a16d462fd07c8d10d74c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vec_map"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.2"
|
version = "0.9.2"
|
||||||
|
|
|
@ -49,7 +49,7 @@ rmp-serde = "^0.14.0"
|
||||||
smallvec = { version = "1.1.0", features = ["serde", ] }
|
smallvec = { version = "1.1.0", features = ["serde", ] }
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
pcre2 = { version = "0.2.3", optional = true }
|
pcre2 = { version = "0.2.3", optional = true }
|
||||||
structopt = { version = "0.3.14" }
|
structopt = { version = "0.3.14", default-features = false }
|
||||||
|
|
||||||
|
|
||||||
[profile.release]
|
[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.
|
Print default theme keys and values in TOML syntax, to be used as a blueprint.
|
||||||
.It Cm print-loaded-themes
|
.It Cm print-loaded-themes
|
||||||
Print all loaded themes in TOML syntax.
|
Print all loaded themes in TOML syntax.
|
||||||
|
.It Cm view
|
||||||
|
View mail from input file.
|
||||||
.El
|
.El
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Nm
|
.Nm
|
||||||
|
|
67
src/bin.rs
67
src/bin.rs
|
@ -199,6 +199,12 @@ enum SubCommand {
|
||||||
#[structopt(display_order = 3)]
|
#[structopt(display_order = 3)]
|
||||||
/// print documentation page and exit (Piping to a pager is recommended.).
|
/// print documentation page and exit (Piping to a pager is recommended.).
|
||||||
Man(ManOpt),
|
Man(ManOpt),
|
||||||
|
|
||||||
|
/// View mail from input file.
|
||||||
|
View {
|
||||||
|
#[structopt(value_name = "INPUT", parse(from_os_str))]
|
||||||
|
path: PathBuf,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
|
@ -272,6 +278,19 @@ fn run_app(opt: Opt) -> Result<()> {
|
||||||
print!("{}", conf::Themes::default().key_to_string("dark", false));
|
print!("{}", conf::Themes::default().key_to_string("dark", false));
|
||||||
return Ok(());
|
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 => {}
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,26 +308,40 @@ fn run_app(opt: Opt) -> Result<()> {
|
||||||
let signal_recvr = notify(signals, sender.clone())?;
|
let signal_recvr = notify(signals, sender.clone())?;
|
||||||
|
|
||||||
/* Create the application State. */
|
/* Create the application State. */
|
||||||
let mut state = State::new(sender, receiver.clone())?;
|
let mut state;
|
||||||
|
|
||||||
let window = Box::new(Tabbed::new(
|
if let Some(SubCommand::View { path }) = opt.subcommand {
|
||||||
vec![
|
let bytes = std::fs::read(&path)
|
||||||
Box::new(listing::Listing::new(&mut state.context)),
|
.chain_err_summary(|| format!("Could not read from `{}`", path.display()))?;
|
||||||
Box::new(ContactList::new(&state.context)),
|
let wrapper = EnvelopeWrapper::new(bytes)
|
||||||
Box::new(StatusPanel::new(crate::conf::value(
|
.chain_err_summary(|| format!("Could not parse `{}`", path.display()))?;
|
||||||
&state.context,
|
state = State::new(
|
||||||
"theme_default",
|
Some(Settings::without_accounts().unwrap_or_default()),
|
||||||
))),
|
sender,
|
||||||
],
|
receiver.clone(),
|
||||||
&state.context,
|
)?;
|
||||||
));
|
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));
|
let status_bar = Box::new(StatusBar::new(window));
|
||||||
state.register_component(status_bar);
|
state.register_component(status_bar);
|
||||||
|
|
||||||
let xdg_notifications = Box::new(components::notifications::XDGNotifications::new());
|
let xdg_notifications = Box::new(components::notifications::XDGNotifications::new());
|
||||||
state.register_component(xdg_notifications);
|
state.register_component(xdg_notifications);
|
||||||
state.register_component(Box::new(components::notifications::NotificationFilter {}));
|
state.register_component(Box::new(components::notifications::NotificationFilter {}));
|
||||||
|
}
|
||||||
|
|
||||||
/* Keep track of the input mode. See UIMode for details */
|
/* Keep track of the input mode. See UIMode for details */
|
||||||
'main: loop {
|
'main: loop {
|
||||||
|
|
24
src/conf.rs
24
src/conf.rs
|
@ -499,6 +499,30 @@ impl Settings {
|
||||||
log: fs.log,
|
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)]
|
#[derive(Copy, Debug, Clone, Hash, PartialEq)]
|
||||||
|
|
12
src/state.rs
12
src/state.rs
|
@ -207,7 +207,11 @@ impl Drop for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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
|
* Create async channel to block the input-thread if we need to fork and stop it from reading
|
||||||
* stdin, see get_events() for details
|
* stdin, see get_events() for details
|
||||||
|
@ -216,7 +220,11 @@ impl State {
|
||||||
let input_thread_pipe = nix::unistd::pipe()
|
let input_thread_pipe = nix::unistd::pipe()
|
||||||
.map_err(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync + 'static>)?;
|
.map_err(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync + 'static>)?;
|
||||||
let mut backends = Backends::new();
|
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();
|
let mut plugin_manager = PluginManager::new();
|
||||||
for (_, p) in settings.plugins.clone() {
|
for (_, p) in settings.plugins.clone() {
|
||||||
if crate::plugins::PluginKind::Backend == p.kind() {
|
if crate::plugins::PluginKind::Backend == p.kind() {
|
||||||
|
|
Loading…
Reference in New Issue