Fix all clippy warnings in `meli` crate
parent
d921b3c320
commit
9cb66ef818
|
@ -50,7 +50,9 @@ pub fn override_derive(filenames: &[(&str, &str)]) {
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//! This module is automatically generated by build.rs.
|
||||
#![allow(clippy::derivable_impls)]
|
||||
|
||||
//! This module is automatically generated by config_macros.rs.
|
||||
use super::*;
|
||||
|
||||
"##
|
||||
|
|
38
src/bin.rs
38
src/bin.rs
|
@ -42,6 +42,8 @@ extern crate serde_json;
|
|||
extern crate smallvec;
|
||||
extern crate termion;
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: System = System;
|
||||
|
||||
|
@ -120,6 +122,7 @@ fn notify(
|
|||
Ok(r)
|
||||
}
|
||||
|
||||
#[cfg(feature = "cli-docs")]
|
||||
fn parse_manpage(src: &str) -> Result<ManPages> {
|
||||
match src {
|
||||
"" | "meli" | "main" => Ok(ManPages::Main),
|
||||
|
@ -132,8 +135,7 @@ fn parse_manpage(src: &str) -> Result<ManPages> {
|
|||
}
|
||||
}
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[cfg(feature = "cli-docs")]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
/// Choose manpage
|
||||
enum ManPages {
|
||||
|
@ -193,9 +195,11 @@ enum SubCommand {
|
|||
#[derive(Debug, StructOpt)]
|
||||
struct ManOpt {
|
||||
#[structopt(default_value = "meli", possible_values=&["meli", "conf", "themes"], value_name="PAGE", parse(try_from_str = parse_manpage))]
|
||||
#[cfg(feature = "cli-docs")]
|
||||
page: ManPages,
|
||||
/// If true, output text in stdout instead of spawning $PAGER.
|
||||
#[structopt(long = "no-raw", alias = "no-raw", value_name = "bool")]
|
||||
#[cfg(feature = "cli-docs")]
|
||||
no_raw: Option<Option<bool>>,
|
||||
}
|
||||
|
||||
|
@ -243,7 +247,7 @@ fn run_app(opt: Opt) -> Result<()> {
|
|||
#[cfg(feature = "cli-docs")]
|
||||
Some(SubCommand::Man(manopt)) => {
|
||||
let ManOpt { page, no_raw } = manopt;
|
||||
const MANPAGES: [&'static [u8]; 3] = [
|
||||
const MANPAGES: [&[u8]; 3] = [
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.txt.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli.conf.txt.gz")),
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/meli-themes.txt.gz")),
|
||||
|
@ -255,10 +259,9 @@ fn run_app(opt: Opt) -> Result<()> {
|
|||
str::parse::<usize>(unsafe {
|
||||
std::str::from_utf8_unchecked(gz.header().unwrap().comment().unwrap())
|
||||
})
|
||||
.expect(&format!(
|
||||
"{:?} was not compressed with size comment header",
|
||||
page
|
||||
)),
|
||||
.unwrap_or_else(|_| {
|
||||
panic!("{:?} was not compressed with size comment header", page)
|
||||
}),
|
||||
);
|
||||
gz.read_to_string(&mut v)?;
|
||||
|
||||
|
@ -271,19 +274,18 @@ fn run_app(opt: Opt) -> Result<()> {
|
|||
return Ok(());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if unsafe { libc::isatty(libc::STDOUT_FILENO) != 1 } {
|
||||
println!("{}", &v);
|
||||
return Ok(());
|
||||
}
|
||||
} else if unsafe { libc::isatty(libc::STDOUT_FILENO) != 1 } {
|
||||
println!("{}", &v);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
use std::process::{Command, Stdio};
|
||||
let mut handle = Command::new(std::env::var("PAGER").unwrap_or("more".to_string()))
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit())
|
||||
.spawn()?;
|
||||
let mut handle =
|
||||
Command::new(std::env::var("PAGER").unwrap_or_else(|_| "more".to_string()))
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit())
|
||||
.spawn()?;
|
||||
handle.stdin.take().unwrap().write_all(v.as_bytes())?;
|
||||
handle.wait()?;
|
||||
|
||||
|
@ -314,7 +316,7 @@ fn run_app(opt: Opt) -> Result<()> {
|
|||
}
|
||||
Some(SubCommand::PrintLoadedThemes) => {
|
||||
let s = conf::FileSettings::new()?;
|
||||
print!("{}", s.terminal.themes.to_string());
|
||||
print!("{}", s.terminal.themes);
|
||||
return Ok(());
|
||||
}
|
||||
Some(SubCommand::PrintDefaultTheme) => {
|
||||
|
|
|
@ -116,7 +116,7 @@ impl TokenStream {
|
|||
}
|
||||
*s = &s[ptr..];
|
||||
//println!("\t before s.is_empty() {:?} {:?}", t, s);
|
||||
if s.is_empty() || &*s == &" " {
|
||||
if s.is_empty() || *s == " " {
|
||||
match t.inner() {
|
||||
Literal(lit) => {
|
||||
sugg.insert(format!("{}{}", if s.is_empty() { " " } else { "" }, lit));
|
||||
|
@ -126,7 +126,7 @@ impl TokenStream {
|
|||
//println!("adding empty suggestions for {:?}", t);
|
||||
let mut _s = *s;
|
||||
let mut m = t.matches(&mut _s, sugg);
|
||||
tokens.extend(m.drain(..));
|
||||
tokens.append(&mut m);
|
||||
}
|
||||
}
|
||||
Seq(_s) => {}
|
||||
|
@ -167,7 +167,7 @@ impl TokenStream {
|
|||
let mut _s = *s;
|
||||
let mut m = t.matches(&mut _s, sugg);
|
||||
if !m.is_empty() {
|
||||
tokens.extend(m.drain(..));
|
||||
tokens.append(&mut m);
|
||||
//println!("_s is empty {}", _s.is_empty());
|
||||
cont = !_s.is_empty();
|
||||
*s = _s;
|
||||
|
@ -262,7 +262,7 @@ define_commands!([
|
|||
desc: "set [seen/unseen], toggles message's Seen flag.",
|
||||
tokens: &[One(Literal("set")), One(Alternatives(&[to_stream!(One(Literal("seen"))), to_stream!(One(Literal("unseen")))]))],
|
||||
parser: (
|
||||
fn seen_flag<'a>(input: &'a [u8]) -> IResult<&'a [u8], Action> {
|
||||
fn seen_flag(input: &'_ [u8]) -> IResult<&'_ [u8], Action> {
|
||||
let (input, _) = tag("set")(input.trim())?;
|
||||
let (input, _) = is_a(" ")(input)?;
|
||||
let (input, ret) = alt((map(tag("seen"), |_| Listing(SetSeen)), map(tag("unseen"), |_| Listing(SetUnseen))))(input)?;
|
||||
|
@ -275,7 +275,7 @@ define_commands!([
|
|||
desc: "delete message",
|
||||
tokens: &[One(Literal("delete"))],
|
||||
parser: (
|
||||
fn delete_message<'a>(input: &'a [u8]) -> IResult<&'a [u8], Action> {
|
||||
fn delete_message(input: &'_ [u8]) -> IResult<&'_ [u8], Action> {
|
||||
let (input, ret) = map(preceded(tag("delete"), eof), |_| Listing(Delete))(input)?;
|
||||
let (input, _) = eof(input)?;
|
||||
Ok((input, ret))
|
||||
|
@ -536,7 +536,7 @@ define_commands!([
|
|||
desc: "filter EXECUTABLE ARGS",
|
||||
tokens: &[One(Literal("filter")), One(Filepath), ZeroOrMore(QuotedStringValue)],
|
||||
parser:(
|
||||
fn filter<'a>(input: &'a [u8]) -> IResult<&'a [u8], Action> {
|
||||
fn filter(input: &'_ [u8]) -> IResult<&'_ [u8], Action> {
|
||||
let (input, _) = tag("filter")(input.trim())?;
|
||||
let (input, _) = is_a(" ")(input)?;
|
||||
let (input, cmd) = map_res(not_line_ending, std::str::from_utf8)(input)?;
|
||||
|
@ -1080,7 +1080,7 @@ pub fn command_completion_suggestions(input: &str) -> Vec<String> {
|
|||
}
|
||||
if let Some((s, Filepath)) = _m.last() {
|
||||
let p = std::path::Path::new(s);
|
||||
sugg.extend(p.complete(true).into_iter().map(|m| m.into()));
|
||||
sugg.extend(p.complete(true).into_iter());
|
||||
}
|
||||
}
|
||||
sugg.into_iter()
|
||||
|
|
|
@ -29,7 +29,7 @@ pub use self::contact_list::*;
|
|||
#[derive(Debug)]
|
||||
enum ViewMode {
|
||||
ReadOnly,
|
||||
Discard(UIDialog<char>),
|
||||
Discard(Box<UIDialog<char>>),
|
||||
Edit,
|
||||
//New,
|
||||
}
|
||||
|
@ -113,27 +113,21 @@ impl ContactManager {
|
|||
self.form = FormWidget::new(("Save".into(), true));
|
||||
self.form.add_button(("Cancel(Esc)".into(), false));
|
||||
self.form
|
||||
.push(("NAME".into(), self.card.name().to_string().into()));
|
||||
.push(("NAME".into(), self.card.name().to_string()));
|
||||
self.form.push((
|
||||
"ADDITIONAL NAME".into(),
|
||||
self.card.additionalname().to_string().into(),
|
||||
));
|
||||
self.form.push((
|
||||
"NAME PREFIX".into(),
|
||||
self.card.name_prefix().to_string().into(),
|
||||
));
|
||||
self.form.push((
|
||||
"NAME SUFFIX".into(),
|
||||
self.card.name_suffix().to_string().into(),
|
||||
self.card.additionalname().to_string(),
|
||||
));
|
||||
self.form
|
||||
.push(("E-MAIL".into(), self.card.email().to_string().into()));
|
||||
.push(("NAME PREFIX".into(), self.card.name_prefix().to_string()));
|
||||
self.form
|
||||
.push(("URL".into(), self.card.url().to_string().into()));
|
||||
.push(("NAME SUFFIX".into(), self.card.name_suffix().to_string()));
|
||||
self.form
|
||||
.push(("KEY".into(), self.card.key().to_string().into()));
|
||||
.push(("E-MAIL".into(), self.card.email().to_string()));
|
||||
self.form.push(("URL".into(), self.card.url().to_string()));
|
||||
self.form.push(("KEY".into(), self.card.key().to_string()));
|
||||
for (k, v) in self.card.extra_properties() {
|
||||
self.form.push((k.to_string().into(), v.to_string().into()));
|
||||
self.form.push((k.to_string().into(), v.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,26 +162,20 @@ impl Component for ContactManager {
|
|||
(set_y(upper_left, get_y(upper_left) + 2), bottom_right),
|
||||
context,
|
||||
);
|
||||
match self.mode {
|
||||
ViewMode::Discard(ref mut selector) => {
|
||||
/* Let user choose whether to quit with/without saving or cancel */
|
||||
selector.draw(grid, area, context);
|
||||
}
|
||||
_ => {}
|
||||
if let ViewMode::Discard(ref mut selector) = self.mode {
|
||||
/* Let user choose whether to quit with/without saving or cancel */
|
||||
selector.draw(grid, area, context);
|
||||
}
|
||||
|
||||
context.dirty_areas.push_back(area);
|
||||
}
|
||||
|
||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||
match event {
|
||||
UIEvent::ConfigReload { old_settings: _ } => {
|
||||
self.theme_default = crate::conf::value(context, "theme_default");
|
||||
self.content = CellBuffer::new_with_context(100, 1, None, context);
|
||||
self.initialized = false;
|
||||
self.set_dirty(true);
|
||||
}
|
||||
_ => {}
|
||||
if let UIEvent::ConfigReload { old_settings: _ } = event {
|
||||
self.theme_default = crate::conf::value(context, "theme_default");
|
||||
self.content = CellBuffer::new_with_context(100, 1, None, context);
|
||||
self.initialized = false;
|
||||
self.set_dirty(true);
|
||||
}
|
||||
match self.mode {
|
||||
ViewMode::Discard(ref mut selector) => {
|
||||
|
@ -209,9 +197,7 @@ impl Component for ContactManager {
|
|||
match self.form.buttons_result() {
|
||||
None => {}
|
||||
Some(true) => {
|
||||
let fields = std::mem::replace(&mut self.form, FormWidget::default())
|
||||
.collect()
|
||||
.unwrap();
|
||||
let fields = std::mem::take(&mut self.form).collect().unwrap();
|
||||
let fields: HashMap<String, String> = fields
|
||||
.into_iter()
|
||||
.map(|(s, v)| {
|
||||
|
@ -290,7 +276,7 @@ impl Component for ContactManager {
|
|||
|
||||
let parent_id = self.parent_id;
|
||||
/* Play it safe and ask user for confirmation */
|
||||
self.mode = ViewMode::Discard(UIDialog::new(
|
||||
self.mode = ViewMode::Discard(Box::new(UIDialog::new(
|
||||
"this contact has unsaved changes",
|
||||
vec![
|
||||
('x', "quit without saving".to_string()),
|
||||
|
@ -305,7 +291,7 @@ impl Component for ContactManager {
|
|||
_ => None,
|
||||
})),
|
||||
context,
|
||||
));
|
||||
)));
|
||||
self.set_dirty(true);
|
||||
false
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ enum ViewMode {
|
|||
#[derive(Debug)]
|
||||
struct AccountMenuEntry {
|
||||
name: String,
|
||||
hash: AccountHash,
|
||||
_hash: AccountHash,
|
||||
// Index in the config account vector.
|
||||
index: usize,
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ impl ContactList {
|
|||
.enumerate()
|
||||
.map(|(i, (h, a))| AccountMenuEntry {
|
||||
name: a.name().to_string(),
|
||||
hash: *h,
|
||||
_hash: *h,
|
||||
index: i,
|
||||
})
|
||||
.collect();
|
||||
|
@ -216,7 +216,6 @@ impl ContactList {
|
|||
((0, 0), (message.len() - 1, 0)),
|
||||
None,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,7 +240,7 @@ impl ContactList {
|
|||
self.dirty = false;
|
||||
let mut y = get_y(upper_left);
|
||||
for a in &self.accounts {
|
||||
self.print_account(grid, (set_y(upper_left, y), bottom_right), &a, context);
|
||||
self.print_account(grid, (set_y(upper_left, y), bottom_right), a, context);
|
||||
y += 1;
|
||||
}
|
||||
|
||||
|
@ -393,6 +392,7 @@ impl ContactList {
|
|||
}
|
||||
}
|
||||
PageMovement::PageDown(multiplier) => {
|
||||
#[allow(clippy::comparison_chain)]
|
||||
if self.new_cursor_pos + rows * multiplier < self.length {
|
||||
self.new_cursor_pos += rows * multiplier;
|
||||
} else if self.new_cursor_pos + rows * multiplier > self.length {
|
||||
|
@ -782,7 +782,7 @@ impl Component for ContactList {
|
|||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(Key::Char(c)) if c >= '0' && c <= '9' => {
|
||||
UIEvent::Input(Key::Char(c)) if ('0'..='9').contains(&c) => {
|
||||
self.cmd_buf.push(c);
|
||||
context
|
||||
.replies
|
||||
|
|
|
@ -116,19 +116,11 @@ enum ViewMode {
|
|||
|
||||
impl ViewMode {
|
||||
fn is_edit(&self) -> bool {
|
||||
if let ViewMode::Edit = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
matches!(self, ViewMode::Edit)
|
||||
}
|
||||
|
||||
fn is_edit_attachments(&self) -> bool {
|
||||
if let ViewMode::EditAttachments { .. } = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
matches!(self, ViewMode::EditAttachments { .. })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +152,7 @@ impl Composer {
|
|||
form: FormWidget::default(),
|
||||
mode: ViewMode::Edit,
|
||||
#[cfg(feature = "gpgme")]
|
||||
gpg_state: gpg::GpgComposeState::new(),
|
||||
gpg_state: gpg::GpgComposeState::default(),
|
||||
dirty: true,
|
||||
has_changes: false,
|
||||
embed_area: ((0, 0), (0, 0)),
|
||||
|
@ -249,11 +241,7 @@ impl Composer {
|
|||
ret.draft
|
||||
.set_header("In-Reply-To", envelope.message_id_display().into());
|
||||
|
||||
if let Some(reply_to) = envelope
|
||||
.other_headers()
|
||||
.get("To")
|
||||
.and_then(|v| v.as_str().try_into().ok())
|
||||
{
|
||||
if let Some(reply_to) = envelope.other_headers().get("To").map(|v| v.as_str()) {
|
||||
let to: &str = reply_to;
|
||||
let extra_identities = &account.settings.account.extra_identities;
|
||||
if let Some(extra) = extra_identities
|
||||
|
@ -288,30 +276,26 @@ impl Composer {
|
|||
.and_then(|v| v.as_str().try_into().ok())
|
||||
{
|
||||
to.insert(reply_to);
|
||||
} else if let Some(reply_to) = envelope
|
||||
.other_headers()
|
||||
.get("Reply-To")
|
||||
.and_then(|v| v.as_str().try_into().ok())
|
||||
{
|
||||
to.insert(reply_to);
|
||||
} else {
|
||||
if let Some(reply_to) = envelope
|
||||
.other_headers()
|
||||
.get("Reply-To")
|
||||
.and_then(|v| v.as_str().try_into().ok())
|
||||
{
|
||||
to.insert(reply_to);
|
||||
} else {
|
||||
to.extend(envelope.from().iter().cloned());
|
||||
}
|
||||
to.extend(envelope.from().iter().cloned());
|
||||
}
|
||||
to.extend(envelope.to().iter().cloned());
|
||||
if let Some(ours) = TryInto::<Address>::try_into(
|
||||
if let Ok(ours) = TryInto::<Address>::try_into(
|
||||
crate::components::mail::get_display_name(context, coordinates.0).as_str(),
|
||||
)
|
||||
.ok()
|
||||
{
|
||||
) {
|
||||
to.remove(&ours);
|
||||
}
|
||||
ret.draft.set_header("To", {
|
||||
let mut ret: String =
|
||||
to.into_iter()
|
||||
.fold(String::new(), |mut s: String, n: Address| {
|
||||
s.extend(n.to_string().chars());
|
||||
s.push_str(&n.to_string());
|
||||
s.push_str(", ");
|
||||
s
|
||||
});
|
||||
|
@ -320,14 +304,12 @@ impl Composer {
|
|||
ret
|
||||
});
|
||||
ret.draft.set_header("Cc", envelope.field_cc_to_string());
|
||||
} else if let Some(reply_to) = envelope.other_headers().get("Mail-Reply-To") {
|
||||
ret.draft.set_header("To", reply_to.to_string());
|
||||
} else if let Some(reply_to) = envelope.other_headers().get("Reply-To") {
|
||||
ret.draft.set_header("To", reply_to.to_string());
|
||||
} else {
|
||||
if let Some(reply_to) = envelope.other_headers().get("Mail-Reply-To") {
|
||||
ret.draft.set_header("To", reply_to.to_string());
|
||||
} else if let Some(reply_to) = envelope.other_headers().get("Reply-To") {
|
||||
ret.draft.set_header("To", reply_to.to_string());
|
||||
} else {
|
||||
ret.draft.set_header("To", envelope.field_from_to_string());
|
||||
}
|
||||
ret.draft.set_header("To", envelope.field_from_to_string());
|
||||
}
|
||||
ret.draft.body = {
|
||||
let mut ret = attribution_string(
|
||||
|
@ -481,7 +463,7 @@ To: {}
|
|||
let header_values = self.form.values_mut();
|
||||
let draft_header_map = self.draft.headers_mut();
|
||||
for (k, v) in draft_header_map.iter_mut() {
|
||||
if let Some(ref vn) = header_values.get(k.as_str()) {
|
||||
if let Some(vn) = header_values.get(k.as_str()) {
|
||||
*v = vn.as_str().to_string();
|
||||
}
|
||||
}
|
||||
|
@ -498,23 +480,22 @@ To: {}
|
|||
if k == "To" || k == "Cc" || k == "Bcc" {
|
||||
self.form.push_cl((
|
||||
k.into(),
|
||||
headers[k].to_string().into(),
|
||||
headers[k].to_string(),
|
||||
Box::new(move |c, term| {
|
||||
let book: &AddressBook = &c.accounts[&account_hash].address_book;
|
||||
let results: Vec<String> = book.search(term);
|
||||
results
|
||||
.into_iter()
|
||||
.map(|r| AutoCompleteEntry::from(r))
|
||||
.map(AutoCompleteEntry::from)
|
||||
.collect::<Vec<AutoCompleteEntry>>()
|
||||
}),
|
||||
));
|
||||
} else if k == "From" {
|
||||
self.form.push_cl((
|
||||
k.into(),
|
||||
headers[k].to_string().into(),
|
||||
headers[k].to_string(),
|
||||
Box::new(move |c, _term| {
|
||||
let results: Vec<(String, String)> = c
|
||||
.accounts
|
||||
c.accounts
|
||||
.values()
|
||||
.map(|acc| {
|
||||
let addr = if let Some(display_name) =
|
||||
|
@ -548,15 +529,12 @@ To: {}
|
|||
|
||||
(addr, desc)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
results
|
||||
.into_iter()
|
||||
.map(|r| AutoCompleteEntry::from(r))
|
||||
.map(AutoCompleteEntry::from)
|
||||
.collect::<Vec<AutoCompleteEntry>>()
|
||||
}),
|
||||
));
|
||||
} else {
|
||||
self.form.push((k.into(), headers[k].to_string().into()));
|
||||
self.form.push((k.into(), headers[k].to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -858,7 +836,7 @@ impl Component for Composer {
|
|||
clear_area(grid, embed_area, theme_default);
|
||||
copy_area(
|
||||
grid,
|
||||
&guard.grid.buffer(),
|
||||
guard.grid.buffer(),
|
||||
embed_area,
|
||||
((0, 0), pos_dec(guard.grid.terminal_size, (1, 1))),
|
||||
);
|
||||
|
@ -871,7 +849,7 @@ impl Component for Composer {
|
|||
let guard = embed_pty.lock().unwrap();
|
||||
copy_area(
|
||||
grid,
|
||||
&guard.grid.buffer(),
|
||||
guard.grid.buffer(),
|
||||
embed_area,
|
||||
((0, 0), pos_dec(guard.grid.terminal_size, (1, 1))),
|
||||
);
|
||||
|
@ -1120,8 +1098,7 @@ impl Component for Composer {
|
|||
UIEvent::FinishedUIDialog(id, ref mut result),
|
||||
) if selector.id() == *id => {
|
||||
if let Some(to_val) = result.downcast_mut::<String>() {
|
||||
self.draft
|
||||
.set_header("To", std::mem::replace(to_val, String::new()));
|
||||
self.draft.set_header("To", std::mem::take(to_val));
|
||||
self.update_form();
|
||||
}
|
||||
self.mode = ViewMode::Edit;
|
||||
|
@ -1677,7 +1654,7 @@ impl Component for Composer {
|
|||
log(
|
||||
format!(
|
||||
"Executing: sh -c \"{}\"",
|
||||
editor_command.replace("\"", "\\\"")
|
||||
editor_command.replace('"', "\\\"")
|
||||
),
|
||||
DEBUG,
|
||||
);
|
||||
|
@ -1804,9 +1781,10 @@ impl Component for Composer {
|
|||
return true;
|
||||
}
|
||||
Action::Compose(ComposeAction::AddAttachmentFilePicker(ref command)) => {
|
||||
let command = if let Some(ref cmd) = command
|
||||
.as_ref()
|
||||
.or_else(|| context.settings.terminal.file_picker_command.as_ref())
|
||||
let command = if let Some(cmd) =
|
||||
command
|
||||
.as_ref()
|
||||
.or(context.settings.terminal.file_picker_command.as_ref())
|
||||
{
|
||||
cmd.as_str()
|
||||
} else {
|
||||
|
@ -1823,7 +1801,7 @@ impl Component for Composer {
|
|||
}
|
||||
|
||||
log(
|
||||
format!("Executing: sh -c \"{}\"", command.replace("\"", "\\\"")),
|
||||
format!("Executing: sh -c \"{}\"", command.replace('"', "\\\"")),
|
||||
DEBUG,
|
||||
);
|
||||
match Command::new("sh")
|
||||
|
@ -1838,7 +1816,7 @@ impl Component for Composer {
|
|||
debug!(&String::from_utf8_lossy(&stderr));
|
||||
for path in stderr.split(|c| [b'\0', b'\t', b'\n'].contains(c)) {
|
||||
match melib::email::compose::attachment_from_file(
|
||||
&String::from_utf8_lossy(&path).as_ref(),
|
||||
&String::from_utf8_lossy(path).as_ref(),
|
||||
) {
|
||||
Ok(a) => {
|
||||
self.draft.attachments_mut().push(a);
|
||||
|
@ -1848,7 +1826,7 @@ impl Component for Composer {
|
|||
context.replies.push_back(UIEvent::Notification(
|
||||
Some(format!(
|
||||
"could not add attachment: {}",
|
||||
String::from_utf8_lossy(&path)
|
||||
String::from_utf8_lossy(path)
|
||||
)),
|
||||
err.to_string(),
|
||||
Some(NotificationType::Error(
|
||||
|
@ -1984,7 +1962,7 @@ impl Component for Composer {
|
|||
Some(Box::new(move |id: ComponentId, results: &[char]| {
|
||||
Some(UIEvent::FinishedUIDialog(
|
||||
id,
|
||||
Box::new(results.get(0).map(|c| *c).unwrap_or('n')),
|
||||
Box::new(results.get(0).copied().unwrap_or('n')),
|
||||
))
|
||||
})),
|
||||
context,
|
||||
|
@ -2033,7 +2011,7 @@ impl Component for Composer {
|
|||
Some(Box::new(move |id: ComponentId, results: &[char]| {
|
||||
Some(UIEvent::FinishedUIDialog(
|
||||
id,
|
||||
Box::new(results.get(0).map(|c| *c).unwrap_or('n')),
|
||||
Box::new(results.get(0).copied().unwrap_or('n')),
|
||||
))
|
||||
})),
|
||||
context,
|
||||
|
@ -2136,7 +2114,7 @@ pub fn send_draft(
|
|||
let body: AttachmentBuilder = Attachment::new(
|
||||
content_type,
|
||||
Default::default(),
|
||||
std::mem::replace(&mut draft.body, String::new()).into_bytes(),
|
||||
std::mem::take(&mut draft.body).into_bytes(),
|
||||
)
|
||||
.into();
|
||||
draft.attachments.insert(0, body);
|
||||
|
@ -2195,6 +2173,7 @@ pub fn send_draft_async(
|
|||
let format_flowed = *account_settings!(context[account_hash].composing.format_flowed);
|
||||
let event_sender = context.sender.clone();
|
||||
#[cfg(feature = "gpgme")]
|
||||
#[allow(clippy::type_complexity)]
|
||||
let mut filters_stack: Vec<
|
||||
Box<
|
||||
dyn FnOnce(
|
||||
|
@ -2207,7 +2186,7 @@ pub fn send_draft_async(
|
|||
#[cfg(feature = "gpgme")]
|
||||
if gpg_state.sign_mail.is_true() && !gpg_state.encrypt_mail.is_true() {
|
||||
filters_stack.push(Box::new(crate::components::mail::pgp::sign_filter(
|
||||
gpg_state.sign_keys.clone(),
|
||||
gpg_state.sign_keys,
|
||||
)?));
|
||||
} else if gpg_state.encrypt_mail.is_true() {
|
||||
filters_stack.push(Box::new(crate::components::mail::pgp::encrypt_filter(
|
||||
|
@ -2216,7 +2195,7 @@ pub fn send_draft_async(
|
|||
} else {
|
||||
None
|
||||
},
|
||||
gpg_state.encrypt_keys.clone(),
|
||||
gpg_state.encrypt_keys,
|
||||
)?));
|
||||
}
|
||||
let send_mail = account_settings!(context[account_hash].composing.send_mail).clone();
|
||||
|
@ -2233,11 +2212,11 @@ pub fn send_draft_async(
|
|||
let mut body: AttachmentBuilder = Attachment::new(
|
||||
content_type,
|
||||
Default::default(),
|
||||
std::mem::replace(&mut draft.body, String::new()).into_bytes(),
|
||||
std::mem::take(&mut draft.body).into_bytes(),
|
||||
)
|
||||
.into();
|
||||
if !draft.attachments.is_empty() {
|
||||
let mut parts = std::mem::replace(&mut draft.attachments, Vec::new());
|
||||
let mut parts = std::mem::take(&mut draft.attachments);
|
||||
parts.insert(0, body);
|
||||
let boundary = ContentType::make_boundary(&parts);
|
||||
body = Attachment::new(
|
||||
|
@ -2261,7 +2240,7 @@ pub fn send_draft_async(
|
|||
let message = Arc::new(draft.finalise()?);
|
||||
let ret = send_cb(message.clone()).await;
|
||||
let is_ok = ret.is_ok();
|
||||
if !is_ok || (store_sent_mail && is_ok) {
|
||||
if !is_ok || store_sent_mail {
|
||||
event_sender
|
||||
.send(ThreadEvent::UIEvent(UIEvent::Callback(CallbackFn(
|
||||
Box::new(move |context| {
|
||||
|
|
|
@ -37,7 +37,7 @@ impl Default for EditAttachmentCursor {
|
|||
pub enum EditAttachmentMode {
|
||||
Overview,
|
||||
Edit {
|
||||
inner: FormWidget<FormButtonActions>,
|
||||
inner: Box<FormWidget<FormButtonActions>>,
|
||||
no: usize,
|
||||
},
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ impl EditAttachments {
|
|||
}
|
||||
|
||||
impl EditAttachmentsRefMut<'_, '_> {
|
||||
fn new_edit_widget(&self, no: usize) -> Option<FormWidget<FormButtonActions>> {
|
||||
fn new_edit_widget(&self, no: usize) -> Option<Box<FormWidget<FormButtonActions>>> {
|
||||
if no >= self.draft.attachments().len() {
|
||||
return None;
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ impl EditAttachmentsRefMut<'_, '_> {
|
|||
ret.add_button(("Cancel".into(), FormButtonActions::Cancel));
|
||||
ret.push(("Filename".into(), filename.unwrap_or_default().to_string()));
|
||||
ret.push(("Mime type".into(), mime_type.to_string()));
|
||||
Some(ret)
|
||||
Some(Box::new(ret))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ pub enum KeySelection {
|
|||
err: MeliError,
|
||||
},
|
||||
Loaded {
|
||||
widget: UIDialog<melib::gpgme::Key>,
|
||||
widget: Box<UIDialog<melib::gpgme::Key>>,
|
||||
keys: Vec<melib::gpgme::Key>,
|
||||
},
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ impl Component for KeySelection {
|
|||
match Self::new(
|
||||
*secret,
|
||||
*local,
|
||||
std::mem::replace(pattern, String::new()),
|
||||
std::mem::take(pattern),
|
||||
*allow_remote_lookup,
|
||||
context,
|
||||
) {
|
||||
|
@ -166,7 +166,7 @@ impl Component for KeySelection {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
let mut widget = UIDialog::new(
|
||||
let mut widget = Box::new(UIDialog::new(
|
||||
"select key",
|
||||
keys.iter()
|
||||
.map(|k| {
|
||||
|
@ -185,12 +185,12 @@ impl Component for KeySelection {
|
|||
move |id: ComponentId, results: &[melib::gpgme::Key]| {
|
||||
Some(UIEvent::FinishedUIDialog(
|
||||
id,
|
||||
Box::new(results.get(0).map(|k| k.clone())),
|
||||
Box::new(results.get(0).cloned()),
|
||||
))
|
||||
},
|
||||
)),
|
||||
context,
|
||||
);
|
||||
));
|
||||
widget.set_dirty(true);
|
||||
*self = KeySelection::Loaded { widget, keys };
|
||||
}
|
||||
|
@ -275,8 +275,8 @@ pub struct GpgComposeState {
|
|||
pub sign_keys: Vec<melib::gpgme::Key>,
|
||||
}
|
||||
|
||||
impl GpgComposeState {
|
||||
pub fn new() -> Self {
|
||||
impl Default for GpgComposeState {
|
||||
fn default() -> Self {
|
||||
GpgComposeState {
|
||||
sign_mail: ToggleFlag::Unset,
|
||||
encrypt_mail: ToggleFlag::Unset,
|
||||
|
|
|
@ -176,7 +176,6 @@ struct AccountMenuEntry {
|
|||
name: String,
|
||||
hash: AccountHash,
|
||||
index: usize,
|
||||
visible: bool,
|
||||
entries: SmallVec<[MailboxMenuEntry; 16]>,
|
||||
}
|
||||
|
||||
|
@ -380,7 +379,7 @@ pub trait MailListingTrait: ListingTrait {
|
|||
.map(|&env_hash| account.operation(env_hash).and_then(|mut op| op.as_bytes()))
|
||||
.collect::<Result<Vec<_>>>();
|
||||
let path_ = path.to_path_buf();
|
||||
let format = format.clone().unwrap_or_default();
|
||||
let format = (*format).unwrap_or_default();
|
||||
let collection = account.collection.clone();
|
||||
let (sender, mut receiver) = crate::jobs::oneshot::channel();
|
||||
let fut: Pin<Box<dyn Future<Output = Result<()>> + Send + 'static>> =
|
||||
|
@ -521,11 +520,11 @@ pub trait ListingTrait: Component {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum ListingComponent {
|
||||
Plain(PlainListing),
|
||||
Threaded(ThreadListing),
|
||||
Compact(CompactListing),
|
||||
Conversations(ConversationsListing),
|
||||
Offline(OfflineListing),
|
||||
Plain(Box<PlainListing>),
|
||||
Threaded(Box<ThreadListing>),
|
||||
Compact(Box<CompactListing>),
|
||||
Conversations(Box<ConversationsListing>),
|
||||
Offline(Box<OfflineListing>),
|
||||
}
|
||||
use crate::ListingComponent::*;
|
||||
|
||||
|
@ -534,11 +533,11 @@ impl core::ops::Deref for ListingComponent {
|
|||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match &self {
|
||||
Compact(ref l) => l,
|
||||
Plain(ref l) => l,
|
||||
Threaded(ref l) => l,
|
||||
Conversations(ref l) => l,
|
||||
Offline(ref l) => l,
|
||||
Compact(ref l) => l.as_ref(),
|
||||
Plain(ref l) => l.as_ref(),
|
||||
Threaded(ref l) => l.as_ref(),
|
||||
Conversations(ref l) => l.as_ref(),
|
||||
Offline(ref l) => l.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -546,11 +545,11 @@ impl core::ops::Deref for ListingComponent {
|
|||
impl core::ops::DerefMut for ListingComponent {
|
||||
fn deref_mut(&mut self) -> &mut (dyn MailListingTrait + 'static) {
|
||||
match self {
|
||||
Compact(l) => l,
|
||||
Plain(l) => l,
|
||||
Threaded(l) => l,
|
||||
Conversations(l) => l,
|
||||
Offline(l) => l,
|
||||
Compact(l) => l.as_mut(),
|
||||
Plain(l) => l.as_mut(),
|
||||
Threaded(l) => l.as_mut(),
|
||||
Conversations(l) => l.as_mut(),
|
||||
Offline(l) => l.as_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -611,7 +610,6 @@ pub struct Listing {
|
|||
accounts: Vec<AccountMenuEntry>,
|
||||
status: Option<AccountStatus>,
|
||||
dirty: bool,
|
||||
visible: bool,
|
||||
cursor_pos: (usize, MenuEntryCursor),
|
||||
menu_cursor_pos: (usize, MenuEntryCursor),
|
||||
menu_content: CellBuffer,
|
||||
|
@ -755,12 +753,10 @@ impl Component for Listing {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
UIEvent::StartupCheck(ref f) => {
|
||||
if self.component.coordinates().1 == *f {
|
||||
if !self.startup_checks_rate.tick() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
UIEvent::StartupCheck(ref f)
|
||||
if self.component.coordinates().1 == *f && !self.startup_checks_rate.tick() =>
|
||||
{
|
||||
return false;
|
||||
}
|
||||
UIEvent::Timer(n) if *n == self.startup_checks_rate.id() => {
|
||||
if self.startup_checks_rate.active {
|
||||
|
@ -1127,7 +1123,7 @@ impl Component for Listing {
|
|||
Action::Listing(ListingAction::Import(file_path, mailbox_path)) => {
|
||||
let account = &mut context.accounts[self.cursor_pos.0];
|
||||
if let Err(err) = account
|
||||
.mailbox_by_path(&mailbox_path)
|
||||
.mailbox_by_path(mailbox_path)
|
||||
.and_then(|mailbox_hash| {
|
||||
Ok((
|
||||
std::fs::read(&file_path).chain_err_summary(|| {
|
||||
|
@ -1687,7 +1683,7 @@ impl Component for Listing {
|
|||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(Key::Char(c)) if c >= '0' && c <= '9' => {
|
||||
UIEvent::Input(Key::Char(c)) if ('0'..='9').contains(&c) => {
|
||||
self.cmd_buf.push(c);
|
||||
self.component.set_modifier_active(true);
|
||||
context
|
||||
|
@ -1808,7 +1804,6 @@ impl Listing {
|
|||
name: a.name().to_string(),
|
||||
hash: *h,
|
||||
index: i,
|
||||
visible: true,
|
||||
entries,
|
||||
}
|
||||
})
|
||||
|
@ -1818,7 +1813,6 @@ impl Listing {
|
|||
component: Offline(OfflineListing::new((first_account_hash, 0))),
|
||||
accounts: account_entries,
|
||||
status: None,
|
||||
visible: true,
|
||||
dirty: true,
|
||||
cursor_pos: (0, MenuEntryCursor::Mailbox(0)),
|
||||
menu_cursor_pos: (0, MenuEntryCursor::Mailbox(0)),
|
||||
|
@ -1954,7 +1948,6 @@ impl Listing {
|
|||
|
||||
#[derive(Copy, Debug, Clone)]
|
||||
struct Line {
|
||||
visible: bool,
|
||||
collapsed: bool,
|
||||
depth: usize,
|
||||
inc: usize,
|
||||
|
@ -1990,7 +1983,7 @@ impl Listing {
|
|||
indentation,
|
||||
has_sibling,
|
||||
mailbox_hash,
|
||||
visible,
|
||||
visible: _,
|
||||
collapsed,
|
||||
},
|
||||
) in self.accounts[aidx].entries.iter().enumerate()
|
||||
|
@ -1999,7 +1992,6 @@ impl Listing {
|
|||
match context.accounts[self.accounts[aidx].index][&mailbox_hash].status {
|
||||
crate::conf::accounts::MailboxStatus::Failed(_) => {
|
||||
lines.push(Line {
|
||||
visible,
|
||||
collapsed,
|
||||
depth,
|
||||
inc: i,
|
||||
|
@ -2012,7 +2004,6 @@ impl Listing {
|
|||
}
|
||||
_ => {
|
||||
lines.push(Line {
|
||||
visible,
|
||||
collapsed,
|
||||
depth,
|
||||
inc: i,
|
||||
|
|
|
@ -172,9 +172,12 @@ pub struct CompactListing {
|
|||
/// Cache current view.
|
||||
data_columns: DataColumns,
|
||||
rows_drawn: SegmentTree,
|
||||
#[allow(clippy::type_complexity)]
|
||||
rows: Vec<((usize, (ThreadHash, EnvelopeHash)), EntryStrings)>,
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
search_job: Option<(String, JoinHandle<Result<SmallVec<[EnvelopeHash; 512]>>>)>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
select_job: Option<(String, JoinHandle<Result<SmallVec<[EnvelopeHash; 512]>>>)>,
|
||||
filter_term: String,
|
||||
filtered_selection: Vec<ThreadHash>,
|
||||
|
@ -220,7 +223,7 @@ impl MailListingTrait for CompactListing {
|
|||
.flatten()
|
||||
.chain(cursor_iter.into_iter().flatten())
|
||||
.cloned();
|
||||
SmallVec::from_iter(iter.into_iter())
|
||||
SmallVec::from_iter(iter)
|
||||
}
|
||||
|
||||
/// Fill the `self.data_columns` `CellBuffers` with the contents of the account mailbox the user has
|
||||
|
@ -324,6 +327,7 @@ impl MailListingTrait for CompactListing {
|
|||
self.length = 0;
|
||||
let mut rows = Vec::with_capacity(1024);
|
||||
let mut min_width = (0, 0, 0, 0);
|
||||
#[allow(clippy::type_complexity)]
|
||||
let mut row_widths: (
|
||||
SmallVec<[u8; 1024]>,
|
||||
SmallVec<[u8; 1024]>,
|
||||
|
@ -404,11 +408,7 @@ impl MailListingTrait for CompactListing {
|
|||
);
|
||||
/* subject */
|
||||
row_widths.3.push(
|
||||
(entry_strings
|
||||
.flag
|
||||
.grapheme_width()
|
||||
.try_into()
|
||||
.unwrap_or(255)
|
||||
(entry_strings.flag.grapheme_width()
|
||||
+ 1
|
||||
+ entry_strings.subject.grapheme_width()
|
||||
+ 1
|
||||
|
@ -876,8 +876,8 @@ impl fmt::Display for CompactListing {
|
|||
|
||||
impl CompactListing {
|
||||
pub const DESCRIPTION: &'static str = "compact listing";
|
||||
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Self {
|
||||
CompactListing {
|
||||
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Box<Self> {
|
||||
Box::new(CompactListing {
|
||||
cursor_pos: (coordinates.0, 1, 0),
|
||||
new_cursor_pos: (coordinates.0, coordinates.1, 0),
|
||||
length: 0,
|
||||
|
@ -905,8 +905,9 @@ impl CompactListing {
|
|||
modifier_active: false,
|
||||
modifier_command: None,
|
||||
id: ComponentId::new_v4(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn make_entry_string(
|
||||
&self,
|
||||
e: &Envelope,
|
||||
|
@ -1423,7 +1424,7 @@ impl CompactListing {
|
|||
}
|
||||
/* Set fg color for flags */
|
||||
let mut x = 0;
|
||||
if self.selection.get(&thread_hash).cloned().unwrap_or(false) {
|
||||
if self.selection.get(thread_hash).cloned().unwrap_or(false) {
|
||||
x += selected_flag_len;
|
||||
}
|
||||
if thread.snoozed() {
|
||||
|
@ -1887,7 +1888,7 @@ impl Component for CompactListing {
|
|||
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => {
|
||||
let account = &context.accounts[&self.cursor_pos.0];
|
||||
let threads = account.collection.get_threads(self.cursor_pos.1);
|
||||
if !account.collection.contains_key(&new_hash) {
|
||||
if !account.collection.contains_key(new_hash) {
|
||||
return false;
|
||||
}
|
||||
let new_env_thread_node_hash = account.collection.get_env(*new_hash).thread();
|
||||
|
@ -1917,7 +1918,7 @@ impl Component for CompactListing {
|
|||
UIEvent::EnvelopeUpdate(ref env_hash) => {
|
||||
let account = &context.accounts[&self.cursor_pos.0];
|
||||
let threads = account.collection.get_threads(self.cursor_pos.1);
|
||||
if !account.collection.contains_key(&env_hash) {
|
||||
if !account.collection.contains_key(env_hash) {
|
||||
return false;
|
||||
}
|
||||
let new_env_thread_node_hash = account.collection.get_env(*env_hash).thread();
|
||||
|
|
|
@ -101,8 +101,10 @@ pub struct ConversationsListing {
|
|||
subsort: (SortField, SortOrder),
|
||||
all_threads: HashSet<ThreadHash>,
|
||||
order: HashMap<ThreadHash, usize>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
rows: std::result::Result<Vec<((usize, (ThreadHash, EnvelopeHash)), EntryStrings)>, String>,
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
search_job: Option<(String, JoinHandle<Result<SmallVec<[EnvelopeHash; 512]>>>)>,
|
||||
filter_term: String,
|
||||
filtered_selection: Vec<ThreadHash>,
|
||||
|
@ -148,7 +150,7 @@ impl MailListingTrait for ConversationsListing {
|
|||
.flatten()
|
||||
.chain(cursor_iter.into_iter().flatten())
|
||||
.cloned();
|
||||
SmallVec::from_iter(iter.into_iter())
|
||||
SmallVec::from_iter(iter)
|
||||
}
|
||||
|
||||
fn refresh_mailbox(&mut self, context: &mut Context, force: bool) {
|
||||
|
@ -376,7 +378,7 @@ impl ListingTrait for ConversationsListing {
|
|||
if let Err(message) = self.rows.as_ref() {
|
||||
clear_area(grid, area, self.color_cache.theme_default);
|
||||
write_string_to_grid(
|
||||
&message,
|
||||
message,
|
||||
grid,
|
||||
self.color_cache.theme_default.fg,
|
||||
self.color_cache.theme_default.bg,
|
||||
|
@ -584,8 +586,8 @@ impl ConversationsListing {
|
|||
const DESCRIPTION: &'static str = "conversations listing";
|
||||
//const PADDING_CHAR: char = ' '; //░';
|
||||
|
||||
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Self {
|
||||
ConversationsListing {
|
||||
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Box<Self> {
|
||||
Box::new(ConversationsListing {
|
||||
cursor_pos: (coordinates.0, 1, 0),
|
||||
new_cursor_pos: (coordinates.0, coordinates.1, 0),
|
||||
length: 0,
|
||||
|
@ -609,7 +611,7 @@ impl ConversationsListing {
|
|||
modifier_active: false,
|
||||
modifier_command: None,
|
||||
id: ComponentId::new_v4(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn make_entry_string(
|
||||
|
@ -714,8 +716,7 @@ impl ConversationsListing {
|
|||
.settings
|
||||
.listing
|
||||
.datetime_fmt
|
||||
.as_ref()
|
||||
.map(String::as_str)
|
||||
.as_deref()
|
||||
.or(Some("%Y-%m-%d %T")),
|
||||
false,
|
||||
),
|
||||
|
@ -1226,7 +1227,7 @@ impl Component for ConversationsListing {
|
|||
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => {
|
||||
let account = &context.accounts[&self.cursor_pos.0];
|
||||
let threads = account.collection.get_threads(self.cursor_pos.1);
|
||||
if !account.collection.contains_key(&new_hash) {
|
||||
if !account.collection.contains_key(new_hash) {
|
||||
return false;
|
||||
}
|
||||
let env_thread_node_hash = account.collection.get_env(*new_hash).thread();
|
||||
|
@ -1258,7 +1259,7 @@ impl Component for ConversationsListing {
|
|||
UIEvent::EnvelopeUpdate(ref env_hash) => {
|
||||
let account = &context.accounts[&self.cursor_pos.0];
|
||||
let threads = account.collection.get_threads(self.cursor_pos.1);
|
||||
if !account.collection.contains_key(&env_hash) {
|
||||
if !account.collection.contains_key(env_hash) {
|
||||
return false;
|
||||
}
|
||||
let env_thread_node_hash = account.collection.get_env(*env_hash).thread();
|
||||
|
|
|
@ -41,7 +41,7 @@ impl MailListingTrait for OfflineListing {
|
|||
}
|
||||
|
||||
fn get_focused_items(&self, _context: &Context) -> SmallVec<[ThreadHash; 8]> {
|
||||
return SmallVec::new();
|
||||
SmallVec::new()
|
||||
}
|
||||
|
||||
fn refresh_mailbox(&mut self, _context: &mut Context, _force: bool) {}
|
||||
|
@ -93,14 +93,14 @@ impl fmt::Display for OfflineListing {
|
|||
}
|
||||
|
||||
impl OfflineListing {
|
||||
pub fn new(cursor_pos: (AccountHash, MailboxHash)) -> Self {
|
||||
OfflineListing {
|
||||
pub fn new(cursor_pos: (AccountHash, MailboxHash)) -> Box<Self> {
|
||||
Box::new(OfflineListing {
|
||||
cursor_pos,
|
||||
_row_updates: SmallVec::new(),
|
||||
_selection: HashMap::default(),
|
||||
dirty: true,
|
||||
id: ComponentId::new_v4(),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -133,6 +133,7 @@ pub struct PlainListing {
|
|||
/// Cache current view.
|
||||
data_columns: DataColumns,
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
search_job: Option<(String, JoinHandle<Result<SmallVec<[EnvelopeHash; 512]>>>)>,
|
||||
filter_term: String,
|
||||
filtered_selection: Vec<EnvelopeHash>,
|
||||
|
@ -311,7 +312,7 @@ impl MailListingTrait for PlainListing {
|
|||
let roots = items
|
||||
.filter_map(|r| threads.groups[&r].root().map(|r| r.root))
|
||||
.collect::<_>();
|
||||
let thread_nodes: &HashMap<ThreadNodeHash, ThreadNode> = &threads.thread_nodes();
|
||||
let thread_nodes: &HashMap<ThreadNodeHash, ThreadNode> = threads.thread_nodes();
|
||||
let env_hash_iter = Box::new(
|
||||
threads
|
||||
.threads_group_iter(roots)
|
||||
|
@ -685,8 +686,8 @@ impl fmt::Display for PlainListing {
|
|||
|
||||
impl PlainListing {
|
||||
const DESCRIPTION: &'static str = "plain listing";
|
||||
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Self {
|
||||
PlainListing {
|
||||
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Box<Self> {
|
||||
Box::new(PlainListing {
|
||||
cursor_pos: (0, 1, 0),
|
||||
new_cursor_pos: (coordinates.0, coordinates.1, 0),
|
||||
length: 0,
|
||||
|
@ -714,7 +715,7 @@ impl PlainListing {
|
|||
|
||||
movement: None,
|
||||
id: ComponentId::new_v4(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn make_entry_string(&self, e: EnvelopeRef, context: &Context) -> EntryStrings {
|
||||
|
@ -884,7 +885,7 @@ impl PlainListing {
|
|||
Box::new(self.local_collection.iter().cloned())
|
||||
as Box<dyn Iterator<Item = EnvelopeHash>>
|
||||
} else {
|
||||
Box::new(self.filtered_selection.iter().map(|h| *h))
|
||||
Box::new(self.filtered_selection.iter().cloned())
|
||||
as Box<dyn Iterator<Item = EnvelopeHash>>
|
||||
};
|
||||
|
||||
|
@ -1234,7 +1235,7 @@ impl Component for PlainListing {
|
|||
.flatten()
|
||||
.chain(cursor_iter.into_iter().flatten())
|
||||
.cloned();
|
||||
let stack: SmallVec<[_; 8]> = SmallVec::from_iter(iter.into_iter());
|
||||
let stack: SmallVec<[_; 8]> = SmallVec::from_iter(iter);
|
||||
for i in stack {
|
||||
self.perform_action(context, i, a);
|
||||
}
|
||||
|
|
|
@ -241,6 +241,7 @@ impl MailListingTrait for ThreadListing {
|
|||
}
|
||||
let mut rows = Vec::with_capacity(1024);
|
||||
let mut min_width = (0, 0, 0, 0, 0);
|
||||
#[allow(clippy::type_complexity)]
|
||||
let mut row_widths: (
|
||||
SmallVec<[u8; 1024]>,
|
||||
SmallVec<[u8; 1024]>,
|
||||
|
@ -260,7 +261,7 @@ impl MailListingTrait for ThreadListing {
|
|||
.filter_map(|r| threads.groups[&r].root().map(|r| r.root))
|
||||
.collect::<_>();
|
||||
let mut iter = threads.threads_group_iter(roots).peekable();
|
||||
let thread_nodes: &HashMap<ThreadNodeHash, ThreadNode> = &threads.thread_nodes();
|
||||
let thread_nodes: &HashMap<ThreadNodeHash, ThreadNode> = threads.thread_nodes();
|
||||
/* This is just a desugared for loop so that we can use .peek() */
|
||||
let mut idx = 0;
|
||||
let mut prev_group = ThreadHash::null();
|
||||
|
@ -737,8 +738,8 @@ impl fmt::Display for ThreadListing {
|
|||
}
|
||||
|
||||
impl ThreadListing {
|
||||
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Self {
|
||||
ThreadListing {
|
||||
pub fn new(coordinates: (AccountHash, MailboxHash)) -> Box<Self> {
|
||||
Box::new(ThreadListing {
|
||||
cursor_pos: (coordinates.0, 0, 0),
|
||||
new_cursor_pos: (coordinates.0, coordinates.1, 0),
|
||||
length: 0,
|
||||
|
@ -757,7 +758,7 @@ impl ThreadListing {
|
|||
initialised: false,
|
||||
movement: None,
|
||||
id: ComponentId::new_v4(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn highlight_line_self(&mut self, _idx: usize, _context: &Context) {
|
||||
|
@ -879,7 +880,7 @@ impl ThreadListing {
|
|||
EntryStrings {
|
||||
date: DateString(ConversationsListing::format_date(context, e.date())),
|
||||
subject: SubjectString(subject),
|
||||
flag: FlagString(format!("{}", if e.has_attachments() { "📎" } else { "" },)),
|
||||
flag: FlagString((if e.has_attachments() { "📎" } else { "" }).to_string()),
|
||||
from: FromString(address_list!((e.from()) as comma_sep_list)),
|
||||
tags: TagString(tags, colors),
|
||||
}
|
||||
|
@ -1243,7 +1244,7 @@ impl Component for ThreadListing {
|
|||
}
|
||||
UIEvent::EnvelopeRename(ref old_hash, ref new_hash) => {
|
||||
let account = &context.accounts[&self.cursor_pos.0];
|
||||
if !account.collection.contains_key(&new_hash) {
|
||||
if !account.collection.contains_key(new_hash) {
|
||||
return false;
|
||||
}
|
||||
if let Some(row) = self.order.remove(old_hash) {
|
||||
|
|
|
@ -39,7 +39,7 @@ pub async fn verify(a: Attachment) -> Result<()> {
|
|||
let (data, sig) =
|
||||
melib_pgp::verify_signature(&a).chain_err_summary(|| "Could not verify signature.")?;
|
||||
let mut ctx = Context::new()?;
|
||||
let sig = ctx.new_data_mem(&sig.body().trim())?;
|
||||
let sig = ctx.new_data_mem(sig.body().trim())?;
|
||||
let data = ctx.new_data_mem(&data)?;
|
||||
ctx.verify(sig, data)?.await
|
||||
}
|
||||
|
|
|
@ -292,7 +292,7 @@ impl Component for AccountStatus {
|
|||
None,
|
||||
);
|
||||
line += 1;
|
||||
for (name, status) in extensions.into_iter() {
|
||||
for (name, status) in extensions.iter() {
|
||||
width = self.content.size().0;
|
||||
write_string_to_grid(
|
||||
name.trim_at_boundary(30),
|
||||
|
@ -418,7 +418,7 @@ impl Component for AccountStatus {
|
|||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key) if shortcut!(key == shortcuts["general"]["scroll_right"]) => {
|
||||
self.cursor.0 = self.cursor.0 + 1;
|
||||
self.cursor.0 += 1;
|
||||
self.dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -428,7 +428,7 @@ impl Component for AccountStatus {
|
|||
return true;
|
||||
}
|
||||
UIEvent::Input(ref key) if shortcut!(key == shortcuts["general"]["scroll_down"]) => {
|
||||
self.cursor.1 = self.cursor.1 + 1;
|
||||
self.cursor.1 += 1;
|
||||
self.dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ enum ViewMode {
|
|||
Source(Source),
|
||||
//Ansi(RawBuffer),
|
||||
Subview,
|
||||
ContactSelector(UIDialog<Card>),
|
||||
ContactSelector(Box<UIDialog<Card>>),
|
||||
}
|
||||
|
||||
impl Default for ViewMode {
|
||||
|
@ -76,69 +76,65 @@ impl ViewMode {
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
fn is_attachment(&self) -> bool {
|
||||
match self {
|
||||
ViewMode::Attachment(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, ViewMode::Attachment(_))
|
||||
}
|
||||
|
||||
fn is_contact_selector(&self) -> bool {
|
||||
match self {
|
||||
ViewMode::ContactSelector(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, ViewMode::ContactSelector(_))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AttachmentDisplay {
|
||||
Alternative {
|
||||
inner: Attachment,
|
||||
inner: Box<Attachment>,
|
||||
shown_display: usize,
|
||||
display: Vec<AttachmentDisplay>,
|
||||
},
|
||||
InlineText {
|
||||
inner: Attachment,
|
||||
inner: Box<Attachment>,
|
||||
comment: Option<String>,
|
||||
text: String,
|
||||
},
|
||||
InlineOther {
|
||||
inner: Attachment,
|
||||
inner: Box<Attachment>,
|
||||
},
|
||||
Attachment {
|
||||
inner: Attachment,
|
||||
inner: Box<Attachment>,
|
||||
},
|
||||
SignedPending {
|
||||
inner: Attachment,
|
||||
inner: Box<Attachment>,
|
||||
display: Vec<AttachmentDisplay>,
|
||||
handle: JoinHandle<Result<()>>,
|
||||
job_id: JobId,
|
||||
},
|
||||
SignedFailed {
|
||||
inner: Attachment,
|
||||
inner: Box<Attachment>,
|
||||
display: Vec<AttachmentDisplay>,
|
||||
error: MeliError,
|
||||
},
|
||||
SignedUnverified {
|
||||
inner: Attachment,
|
||||
inner: Box<Attachment>,
|
||||
display: Vec<AttachmentDisplay>,
|
||||
},
|
||||
SignedVerified {
|
||||
inner: Attachment,
|
||||
inner: Box<Attachment>,
|
||||
display: Vec<AttachmentDisplay>,
|
||||
description: String,
|
||||
},
|
||||
EncryptedPending {
|
||||
inner: Attachment,
|
||||
inner: Box<Attachment>,
|
||||
handle: JoinHandle<Result<(melib::pgp::DecryptionMetadata, Vec<u8>)>>,
|
||||
},
|
||||
EncryptedFailed {
|
||||
inner: Attachment,
|
||||
inner: Box<Attachment>,
|
||||
error: MeliError,
|
||||
},
|
||||
EncryptedSuccess {
|
||||
inner: Attachment,
|
||||
plaintext: Attachment,
|
||||
inner: Box<Attachment>,
|
||||
plaintext: Box<Attachment>,
|
||||
plaintext_display: Vec<AttachmentDisplay>,
|
||||
description: String,
|
||||
},
|
||||
|
@ -191,8 +187,8 @@ enum MailViewState {
|
|||
},
|
||||
Loaded {
|
||||
bytes: Vec<u8>,
|
||||
env: Envelope,
|
||||
body: Attachment,
|
||||
env: Box<Envelope>,
|
||||
body: Box<Attachment>,
|
||||
display: Vec<AttachmentDisplay>,
|
||||
body_text: String,
|
||||
links: Vec<Link>,
|
||||
|
@ -313,9 +309,10 @@ impl MailView {
|
|||
.get_env_mut(self.coordinates.2)
|
||||
.populate_headers(&bytes);
|
||||
}
|
||||
let env =
|
||||
account.collection.get_env(self.coordinates.2).clone();
|
||||
let body = AttachmentBuilder::new(&bytes).build();
|
||||
let env = Box::new(
|
||||
account.collection.get_env(self.coordinates.2).clone(),
|
||||
);
|
||||
let body = Box::new(AttachmentBuilder::new(&bytes).build());
|
||||
let display = Self::attachment_to(
|
||||
&body,
|
||||
context,
|
||||
|
@ -415,7 +412,7 @@ impl MailView {
|
|||
..
|
||||
} => (
|
||||
bytes,
|
||||
self.attachment_displays_to_text(&display, context, false),
|
||||
self.attachment_displays_to_text(display, context, false),
|
||||
env,
|
||||
),
|
||||
MailViewState::Error { .. } => {
|
||||
|
@ -489,13 +486,13 @@ impl MailView {
|
|||
if !acc.ends_with("\n\n") {
|
||||
acc.push_str("\n\n");
|
||||
}
|
||||
acc.push_str(&text);
|
||||
acc.push_str(text);
|
||||
}
|
||||
InlineText {
|
||||
inner: _,
|
||||
text,
|
||||
comment: _,
|
||||
} => acc.push_str(&text),
|
||||
} => acc.push_str(text),
|
||||
InlineOther { inner } => {
|
||||
if !acc.ends_with("\n\n") {
|
||||
acc.push_str("\n\n");
|
||||
|
@ -550,7 +547,7 @@ impl MailView {
|
|||
if description.is_empty() {
|
||||
acc.push_str("Verified signature.\n\n");
|
||||
} else {
|
||||
acc.push_str(&description);
|
||||
acc.push_str(description);
|
||||
acc.push_str("\n\n");
|
||||
}
|
||||
}
|
||||
|
@ -574,7 +571,7 @@ impl MailView {
|
|||
if description.is_empty() {
|
||||
acc.push_str("Succesfully decrypted.\n\n");
|
||||
} else {
|
||||
acc.push_str(&description);
|
||||
acc.push_str(description);
|
||||
acc.push_str("\n\n");
|
||||
}
|
||||
}
|
||||
|
@ -672,35 +669,32 @@ impl MailView {
|
|||
s.push(' ');
|
||||
}
|
||||
|
||||
s.extend(att.to_string().chars());
|
||||
s.push_str(&att.to_string());
|
||||
paths.push(cur_path.clone());
|
||||
match att.content_type {
|
||||
ContentType::Multipart { .. } => {
|
||||
let mut iter = (0..sub_att_display_vec.len()).peekable();
|
||||
if has_sibling {
|
||||
branches.push(true);
|
||||
} else {
|
||||
branches.push(false);
|
||||
}
|
||||
while let Some(i) = iter.next() {
|
||||
*idx += 1;
|
||||
cur_path.push(i);
|
||||
append_entry(
|
||||
(idx, (depth + 1, &sub_att_display_vec[i])),
|
||||
branches,
|
||||
paths,
|
||||
cur_path,
|
||||
iter.peek() != None,
|
||||
s,
|
||||
);
|
||||
if Some(i) == default_alternative {
|
||||
s.push_str(" (displayed by default)");
|
||||
}
|
||||
cur_path.pop();
|
||||
}
|
||||
branches.pop();
|
||||
if matches!(att.content_type, ContentType::Multipart { .. }) {
|
||||
let mut iter = (0..sub_att_display_vec.len()).peekable();
|
||||
if has_sibling {
|
||||
branches.push(true);
|
||||
} else {
|
||||
branches.push(false);
|
||||
}
|
||||
_ => {}
|
||||
while let Some(i) = iter.next() {
|
||||
*idx += 1;
|
||||
cur_path.push(i);
|
||||
append_entry(
|
||||
(idx, (depth + 1, &sub_att_display_vec[i])),
|
||||
branches,
|
||||
paths,
|
||||
cur_path,
|
||||
iter.peek() != None,
|
||||
s,
|
||||
);
|
||||
if Some(i) == default_alternative {
|
||||
s.push_str(" (displayed by default)");
|
||||
}
|
||||
cur_path.pop();
|
||||
}
|
||||
branches.pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -735,7 +729,9 @@ impl MailView {
|
|||
active_jobs: &mut HashSet<JobId>,
|
||||
) {
|
||||
if a.content_disposition.kind.is_attachment() || a.content_type == "message/rfc822" {
|
||||
acc.push(AttachmentDisplay::Attachment { inner: a.clone() });
|
||||
acc.push(AttachmentDisplay::Attachment {
|
||||
inner: Box::new(a.clone()),
|
||||
});
|
||||
} else if a.content_type().is_text_html() {
|
||||
let bytes = decode(a, None);
|
||||
let filter_invocation =
|
||||
|
@ -764,7 +760,7 @@ impl MailView {
|
|||
));
|
||||
let text = String::from_utf8_lossy(&bytes).to_string();
|
||||
acc.push(AttachmentDisplay::InlineText {
|
||||
inner: a.clone(),
|
||||
inner: Box::new(a.clone()),
|
||||
comment,
|
||||
text,
|
||||
});
|
||||
|
@ -785,7 +781,7 @@ impl MailView {
|
|||
)
|
||||
.to_string();
|
||||
acc.push(AttachmentDisplay::InlineText {
|
||||
inner: a.clone(),
|
||||
inner: Box::new(a.clone()),
|
||||
comment,
|
||||
text,
|
||||
});
|
||||
|
@ -794,7 +790,7 @@ impl MailView {
|
|||
} else if a.is_text() {
|
||||
let bytes = decode(a, None);
|
||||
acc.push(AttachmentDisplay::InlineText {
|
||||
inner: a.clone(),
|
||||
inner: Box::new(a.clone()),
|
||||
comment: None,
|
||||
text: String::from_utf8_lossy(&bytes).to_string(),
|
||||
});
|
||||
|
@ -838,7 +834,7 @@ impl MailView {
|
|||
rec(a, context, coordinates, &mut display, active_jobs);
|
||||
}
|
||||
acc.push(AttachmentDisplay::Alternative {
|
||||
inner: a.clone(),
|
||||
inner: Box::new(a.clone()),
|
||||
shown_display: chosen_attachment_idx,
|
||||
display,
|
||||
});
|
||||
|
@ -847,7 +843,7 @@ impl MailView {
|
|||
#[cfg(not(feature = "gpgme"))]
|
||||
{
|
||||
acc.push(AttachmentDisplay::SignedUnverified {
|
||||
inner: a.clone(),
|
||||
inner: Box::new(a.clone()),
|
||||
display: {
|
||||
let mut v = vec![];
|
||||
rec(&parts[0], context, coordinates, &mut v, active_jobs);
|
||||
|
@ -869,7 +865,7 @@ impl MailView {
|
|||
StatusEvent::NewJob(handle.job_id),
|
||||
));
|
||||
acc.push(AttachmentDisplay::SignedPending {
|
||||
inner: a.clone(),
|
||||
inner: Box::new(a.clone()),
|
||||
job_id: handle.job_id,
|
||||
display: {
|
||||
let mut v = vec![];
|
||||
|
@ -880,7 +876,7 @@ impl MailView {
|
|||
});
|
||||
} else {
|
||||
acc.push(AttachmentDisplay::SignedUnverified {
|
||||
inner: a.clone(),
|
||||
inner: Box::new(a.clone()),
|
||||
display: {
|
||||
let mut v = vec![];
|
||||
rec(&parts[0], context, coordinates, &mut v, active_jobs);
|
||||
|
@ -896,7 +892,7 @@ impl MailView {
|
|||
#[cfg(not(feature = "gpgme"))]
|
||||
{
|
||||
acc.push(AttachmentDisplay::EncryptedFailed {
|
||||
inner: a.clone(),
|
||||
inner: Box::new(a.clone()),
|
||||
error: MeliError::new("Cannot decrypt: meli must be compiled with libgpgme support."),
|
||||
});
|
||||
}
|
||||
|
@ -914,12 +910,12 @@ impl MailView {
|
|||
StatusEvent::NewJob(handle.job_id),
|
||||
));
|
||||
acc.push(AttachmentDisplay::EncryptedPending {
|
||||
inner: a.clone(),
|
||||
inner: Box::new(a.clone()),
|
||||
handle,
|
||||
});
|
||||
} else {
|
||||
acc.push(AttachmentDisplay::EncryptedFailed {
|
||||
inner: a.clone(),
|
||||
inner: Box::new(a.clone()),
|
||||
error: MeliError::new("Undecrypted."),
|
||||
});
|
||||
}
|
||||
|
@ -963,17 +959,13 @@ impl MailView {
|
|||
} else {
|
||||
return None;
|
||||
};
|
||||
if let Some(path) =
|
||||
self.attachment_paths.get(lidx).and_then(
|
||||
|path| {
|
||||
if path.len() > 0 {
|
||||
Some(path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
{
|
||||
if let Some(path) = self.attachment_paths.get(lidx).and_then(|path| {
|
||||
if !path.is_empty() {
|
||||
Some(path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
let first = path[0];
|
||||
use AttachmentDisplay::*;
|
||||
let root_attachment = match &display[first] {
|
||||
|
@ -1022,14 +1014,11 @@ impl MailView {
|
|||
if path.is_empty() {
|
||||
return Some(a);
|
||||
}
|
||||
match a.content_type {
|
||||
ContentType::Multipart { ref parts, .. } => {
|
||||
let first = path[0];
|
||||
if first < parts.len() {
|
||||
return find_attachment(&parts[first], &path[1..]);
|
||||
}
|
||||
if let ContentType::Multipart { ref parts, .. } = a.content_type {
|
||||
let first = path[0];
|
||||
if first < parts.len() {
|
||||
return find_attachment(&parts[first], &path[1..]);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -1080,7 +1069,7 @@ impl MailView {
|
|||
entries.push((new_card, format!("{}", addr)));
|
||||
}
|
||||
drop(envelope);
|
||||
self.mode = ViewMode::ContactSelector(Selector::new(
|
||||
self.mode = ViewMode::ContactSelector(Box::new(Selector::new(
|
||||
"select contacts to add",
|
||||
entries,
|
||||
false,
|
||||
|
@ -1088,7 +1077,7 @@ impl MailView {
|
|||
Some(UIEvent::FinishedUIDialog(id, Box::new(results.to_vec())))
|
||||
})),
|
||||
context,
|
||||
));
|
||||
)));
|
||||
self.dirty = true;
|
||||
self.initialised = false;
|
||||
}
|
||||
|
@ -1420,10 +1409,7 @@ impl Component for MailView {
|
|||
err.to_string(),
|
||||
Some(NotificationType::Error(err.kind)),
|
||||
));
|
||||
log(
|
||||
format!("Failed to open envelope: {}", err.to_string()),
|
||||
ERROR,
|
||||
);
|
||||
log(format!("Failed to open envelope: {}", err), ERROR);
|
||||
self.init_futures(context);
|
||||
return;
|
||||
} else {
|
||||
|
@ -1444,7 +1430,7 @@ impl Component for MailView {
|
|||
let mut text = "Viewing attachment. Press `r` to return \n".to_string();
|
||||
if let Some(attachment) = self.open_attachment(aidx, context) {
|
||||
if attachment.is_html() {
|
||||
self.subview = Some(Box::new(HtmlView::new(&attachment, context)));
|
||||
self.subview = Some(Box::new(HtmlView::new(attachment, context)));
|
||||
self.mode = ViewMode::Subview;
|
||||
} else {
|
||||
text.push_str(&attachment.text());
|
||||
|
@ -1475,7 +1461,7 @@ impl Component for MailView {
|
|||
}
|
||||
}
|
||||
ViewMode::Normal if body.is_html() => {
|
||||
self.subview = Some(Box::new(HtmlView::new(&body, context)));
|
||||
self.subview = Some(Box::new(HtmlView::new(body, context)));
|
||||
self.mode = ViewMode::Subview;
|
||||
}
|
||||
ViewMode::Normal
|
||||
|
@ -1497,13 +1483,12 @@ impl Component for MailView {
|
|||
} =>
|
||||
{
|
||||
self.subview = Some(Box::new(HtmlView::new(
|
||||
&body
|
||||
.content_type
|
||||
body.content_type
|
||||
.parts()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.iter()
|
||||
.find(|a| a.is_html())
|
||||
.unwrap_or(&body),
|
||||
.unwrap_or(body),
|
||||
context,
|
||||
)));
|
||||
self.mode = ViewMode::Subview;
|
||||
|
@ -1541,7 +1526,7 @@ impl Component for MailView {
|
|||
if !ret.ends_with("\n\n") {
|
||||
ret.push_str("\n\n");
|
||||
}
|
||||
ret.extend(body_text.chars());
|
||||
ret.push_str(body_text);
|
||||
if !ret.ends_with("\n\n") {
|
||||
ret.push_str("\n\n");
|
||||
}
|
||||
|
@ -1721,10 +1706,8 @@ impl Component for MailView {
|
|||
self.force_draw_headers = true;
|
||||
if self.pager.cursor_pos() == 0 {
|
||||
self.headers_cursor = self.headers_cursor.saturating_sub(1);
|
||||
} else {
|
||||
if self.pager.process_event(event, context) {
|
||||
return true;
|
||||
}
|
||||
} else if self.pager.process_event(event, context) {
|
||||
return true;
|
||||
}
|
||||
self.pager.set_dirty(true);
|
||||
return true;
|
||||
|
@ -1767,11 +1750,13 @@ impl Component for MailView {
|
|||
.get_env_mut(self.coordinates.2)
|
||||
.populate_headers(&bytes);
|
||||
}
|
||||
let env = context.accounts[&self.coordinates.0]
|
||||
.collection
|
||||
.get_env(self.coordinates.2)
|
||||
.clone();
|
||||
let body = AttachmentBuilder::new(&bytes).build();
|
||||
let env = Box::new(
|
||||
context.accounts[&self.coordinates.0]
|
||||
.collection
|
||||
.get_env(self.coordinates.2)
|
||||
.clone(),
|
||||
);
|
||||
let body = Box::new(AttachmentBuilder::new(&bytes).build());
|
||||
let display = Self::attachment_to(
|
||||
&body,
|
||||
context,
|
||||
|
@ -1823,9 +1808,11 @@ impl Component for MailView {
|
|||
*d = AttachmentDisplay::SignedVerified {
|
||||
inner: std::mem::replace(
|
||||
inner,
|
||||
AttachmentBuilder::new(&[]).build(),
|
||||
Box::new(
|
||||
AttachmentBuilder::new(&[]).build(),
|
||||
),
|
||||
),
|
||||
display: std::mem::replace(display, vec![]),
|
||||
display: std::mem::take(display),
|
||||
description: String::new(),
|
||||
};
|
||||
}
|
||||
|
@ -1833,9 +1820,11 @@ impl Component for MailView {
|
|||
*d = AttachmentDisplay::SignedFailed {
|
||||
inner: std::mem::replace(
|
||||
inner,
|
||||
AttachmentBuilder::new(&[]).build(),
|
||||
Box::new(
|
||||
AttachmentBuilder::new(&[]).build(),
|
||||
),
|
||||
),
|
||||
display: std::mem::replace(display, vec![]),
|
||||
display: std::mem::take(display),
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
@ -1851,9 +1840,10 @@ impl Component for MailView {
|
|||
Ok(None) => { /* something happened, perhaps a worker thread panicked */
|
||||
}
|
||||
Ok(Some(Ok((metadata, decrypted_bytes)))) => {
|
||||
let plaintext =
|
||||
let plaintext = Box::new(
|
||||
AttachmentBuilder::new(&decrypted_bytes)
|
||||
.build();
|
||||
.build(),
|
||||
);
|
||||
let plaintext_display = Self::attachment_to(
|
||||
&plaintext,
|
||||
context,
|
||||
|
@ -1863,7 +1853,9 @@ impl Component for MailView {
|
|||
*d = AttachmentDisplay::EncryptedSuccess {
|
||||
inner: std::mem::replace(
|
||||
inner,
|
||||
AttachmentBuilder::new(&[]).build(),
|
||||
Box::new(
|
||||
AttachmentBuilder::new(&[]).build(),
|
||||
),
|
||||
),
|
||||
plaintext,
|
||||
plaintext_display,
|
||||
|
@ -1874,7 +1866,9 @@ impl Component for MailView {
|
|||
*d = AttachmentDisplay::EncryptedFailed {
|
||||
inner: std::mem::replace(
|
||||
inner,
|
||||
AttachmentBuilder::new(&[]).build(),
|
||||
Box::new(
|
||||
AttachmentBuilder::new(&[]).build(),
|
||||
),
|
||||
),
|
||||
error,
|
||||
};
|
||||
|
@ -1888,9 +1882,9 @@ impl Component for MailView {
|
|||
let mut new_body_text = String::new();
|
||||
if let MailViewState::Loaded { ref display, .. } = self.state {
|
||||
new_body_text =
|
||||
self.attachment_displays_to_text(&display, context, true);
|
||||
self.attachment_displays_to_text(display, context, true);
|
||||
let (paths, attachment_tree_s) =
|
||||
self.attachment_displays_to_tree(&display);
|
||||
self.attachment_displays_to_tree(display);
|
||||
self.attachment_tree = attachment_tree_s;
|
||||
self.attachment_paths = paths;
|
||||
}
|
||||
|
@ -2042,7 +2036,7 @@ impl Component for MailView {
|
|||
.get(&env_hash)
|
||||
.map(|env| env.message_id_display())
|
||||
.unwrap_or_else(|| "Not found".into()),
|
||||
err.to_string()
|
||||
err
|
||||
);
|
||||
log(&err_string, ERROR);
|
||||
context.replies.push_back(UIEvent::Notification(
|
||||
|
@ -2088,7 +2082,7 @@ impl Component for MailView {
|
|||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(Key::Char(c)) if c >= '0' && c <= '9' => {
|
||||
UIEvent::Input(Key::Char(c)) if ('0'..='9').contains(&c) => {
|
||||
self.cmd_buf.push(c);
|
||||
context
|
||||
.replies
|
||||
|
@ -2218,7 +2212,7 @@ impl Component for MailView {
|
|||
if let Ok(command) = query_default_app(&attachment_type) {
|
||||
let p = create_temp_file(
|
||||
&decode(attachment, None),
|
||||
filename.as_ref().map(|s| s.as_str()),
|
||||
filename.as_deref(),
|
||||
None,
|
||||
true,
|
||||
);
|
||||
|
@ -2400,10 +2394,7 @@ impl Component for MailView {
|
|||
err.to_string(),
|
||||
Some(NotificationType::Error(err.kind)),
|
||||
));
|
||||
log(
|
||||
format!("Failed to open envelope: {}", err.to_string()),
|
||||
ERROR,
|
||||
);
|
||||
log(format!("Failed to open envelope: {}", err), ERROR);
|
||||
self.init_futures(context);
|
||||
return true;
|
||||
} else {
|
||||
|
@ -2424,11 +2415,7 @@ impl Component for MailView {
|
|||
Some(NotificationType::Error(melib::ErrorKind::External)),
|
||||
));
|
||||
log(
|
||||
format!(
|
||||
"Failed to create file at {}: {}",
|
||||
path.display(),
|
||||
err.to_string()
|
||||
),
|
||||
format!("Failed to create file at {}: {}", path.display(), err),
|
||||
ERROR,
|
||||
);
|
||||
return true;
|
||||
|
@ -2461,10 +2448,7 @@ impl Component for MailView {
|
|||
err.to_string(),
|
||||
Some(NotificationType::Error(err.kind)),
|
||||
));
|
||||
log(
|
||||
format!("Failed to open envelope: {}", err.to_string()),
|
||||
ERROR,
|
||||
);
|
||||
log(format!("Failed to open envelope: {}", err), ERROR);
|
||||
self.init_futures(context);
|
||||
return true;
|
||||
} else {
|
||||
|
@ -2490,11 +2474,7 @@ impl Component for MailView {
|
|||
Some(NotificationType::Error(melib::ErrorKind::External)),
|
||||
));
|
||||
log(
|
||||
format!(
|
||||
"Failed to create file at {}: {}",
|
||||
path.display(),
|
||||
err.to_string()
|
||||
),
|
||||
format!("Failed to create file at {}: {}", path.display(), err),
|
||||
ERROR,
|
||||
);
|
||||
}
|
||||
|
@ -2521,11 +2501,7 @@ impl Component for MailView {
|
|||
Some(NotificationType::Error(melib::ErrorKind::External)),
|
||||
));
|
||||
log(
|
||||
format!(
|
||||
"Failed to create file at {}: {}",
|
||||
path.display(),
|
||||
err.to_string()
|
||||
),
|
||||
format!("Failed to create file at {}: {}", path.display(), err),
|
||||
ERROR,
|
||||
);
|
||||
return true;
|
||||
|
|
|
@ -36,10 +36,7 @@ enum ViewMode {
|
|||
|
||||
impl ViewMode {
|
||||
fn is_attachment(&self) -> bool {
|
||||
match self {
|
||||
ViewMode::Attachment(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, ViewMode::Attachment(_))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,7 +50,7 @@ pub struct EnvelopeView {
|
|||
mode: ViewMode,
|
||||
mail: Mail,
|
||||
|
||||
account_hash: AccountHash,
|
||||
_account_hash: AccountHash,
|
||||
cmd_buf: String,
|
||||
id: ComponentId,
|
||||
}
|
||||
|
@ -69,7 +66,7 @@ impl EnvelopeView {
|
|||
mail: Mail,
|
||||
pager: Option<Pager>,
|
||||
subview: Option<Box<dyn Component>>,
|
||||
account_hash: AccountHash,
|
||||
_account_hash: AccountHash,
|
||||
) -> Self {
|
||||
EnvelopeView {
|
||||
pager,
|
||||
|
@ -77,7 +74,7 @@ impl EnvelopeView {
|
|||
dirty: true,
|
||||
mode: ViewMode::Normal,
|
||||
mail,
|
||||
account_hash,
|
||||
_account_hash,
|
||||
cmd_buf: String::with_capacity(4),
|
||||
id: ComponentId::new_v4(),
|
||||
}
|
||||
|
@ -87,7 +84,7 @@ impl EnvelopeView {
|
|||
fn attachment_to_text(&self, body: &Attachment, context: &mut Context) -> String {
|
||||
let finder = LinkFinder::new();
|
||||
let body_text = String::from_utf8_lossy(&decode_rec(
|
||||
&body,
|
||||
body,
|
||||
Some(Box::new(|a: &Attachment, v: &mut Vec<u8>| {
|
||||
if a.content_type().is_text_html() {
|
||||
let settings = &context.settings;
|
||||
|
@ -107,14 +104,13 @@ impl EnvelopeView {
|
|||
err.to_string(),
|
||||
Some(NotificationType::Error(melib::ErrorKind::External)),
|
||||
));
|
||||
return;
|
||||
}
|
||||
Ok(mut html_filter) => {
|
||||
html_filter
|
||||
.stdin
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write_all(&v)
|
||||
.write_all(v)
|
||||
.expect("Failed to write to stdin");
|
||||
*v = format!(
|
||||
"Text piped through `{}`. Press `v` to open in web browser. \n\n",
|
||||
|
@ -286,7 +282,7 @@ impl Component for EnvelopeView {
|
|||
match self.mode {
|
||||
ViewMode::Attachment(aidx) if body.attachments()[aidx].is_html() => {
|
||||
let attachment = &body.attachments()[aidx];
|
||||
self.subview = Some(Box::new(HtmlView::new(&attachment, context)));
|
||||
self.subview = Some(Box::new(HtmlView::new(attachment, context)));
|
||||
}
|
||||
ViewMode::Normal if body.is_html() => {
|
||||
self.subview = Some(Box::new(HtmlView::new(&body, context)));
|
||||
|
@ -336,7 +332,7 @@ impl Component for EnvelopeView {
|
|||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(Key::Char(c)) if c >= '0' && c <= '9' => {
|
||||
UIEvent::Input(Key::Char(c)) if ('0'..='9').contains(&c) => {
|
||||
self.cmd_buf.push(c);
|
||||
return true;
|
||||
}
|
||||
|
@ -368,71 +364,70 @@ impl Component for EnvelopeView {
|
|||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::BufClear));
|
||||
|
||||
{
|
||||
if let Some(u) = self.mail.body().attachments().get(lidx) {
|
||||
match u.content_type() {
|
||||
ContentType::MessageRfc822 => {
|
||||
self.mode = ViewMode::Subview;
|
||||
let colors = crate::conf::value(context, "mail.view.body");
|
||||
self.subview = Some(Box::new(Pager::from_string(
|
||||
String::from_utf8_lossy(&decode_rec(u, None)).to_string(),
|
||||
Some(context),
|
||||
None,
|
||||
None,
|
||||
colors,
|
||||
)));
|
||||
}
|
||||
if let Some(u) = self.mail.body().attachments().get(lidx) {
|
||||
match u.content_type() {
|
||||
ContentType::MessageRfc822 => {
|
||||
self.mode = ViewMode::Subview;
|
||||
let colors = crate::conf::value(context, "mail.view.body");
|
||||
self.subview = Some(Box::new(Pager::from_string(
|
||||
String::from_utf8_lossy(&decode_rec(u, None)).to_string(),
|
||||
Some(context),
|
||||
None,
|
||||
None,
|
||||
colors,
|
||||
)));
|
||||
}
|
||||
|
||||
ContentType::Text { .. }
|
||||
| ContentType::PGPSignature
|
||||
| ContentType::CMSSignature => {
|
||||
self.mode = ViewMode::Attachment(lidx);
|
||||
self.dirty = true;
|
||||
}
|
||||
ContentType::Multipart { .. } => {
|
||||
context.replies.push_back(UIEvent::StatusEvent(
|
||||
StatusEvent::DisplayMessage(
|
||||
"Multipart attachments are not supported yet.".to_string(),
|
||||
),
|
||||
));
|
||||
return true;
|
||||
}
|
||||
ContentType::Other { .. } => {
|
||||
let attachment_type = u.mime_type();
|
||||
let filename = u.filename();
|
||||
if let Ok(command) = query_default_app(&attachment_type) {
|
||||
let p = create_temp_file(
|
||||
&decode(u, None),
|
||||
filename.as_ref().map(|s| s.as_str()),
|
||||
None,
|
||||
true,
|
||||
);
|
||||
let (exec_cmd, argument) = super::desktop_exec_to_command(
|
||||
&command,
|
||||
p.path.display().to_string(),
|
||||
false,
|
||||
);
|
||||
match Command::new(&exec_cmd)
|
||||
.arg(&argument)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
{
|
||||
Ok(child) => {
|
||||
context.temp_files.push(p);
|
||||
context.children.push(child);
|
||||
}
|
||||
Err(err) => {
|
||||
context.replies.push_back(UIEvent::StatusEvent(
|
||||
StatusEvent::DisplayMessage(format!(
|
||||
"Failed to start `{} {}`: {}",
|
||||
&exec_cmd, &argument, err
|
||||
)),
|
||||
));
|
||||
}
|
||||
ContentType::Text { .. }
|
||||
| ContentType::PGPSignature
|
||||
| ContentType::CMSSignature => {
|
||||
self.mode = ViewMode::Attachment(lidx);
|
||||
self.dirty = true;
|
||||
}
|
||||
ContentType::Multipart { .. } => {
|
||||
context.replies.push_back(UIEvent::StatusEvent(
|
||||
StatusEvent::DisplayMessage(
|
||||
"Multipart attachments are not supported yet.".to_string(),
|
||||
),
|
||||
));
|
||||
return true;
|
||||
}
|
||||
ContentType::Other { .. } => {
|
||||
let attachment_type = u.mime_type();
|
||||
let filename = u.filename();
|
||||
if let Ok(command) = query_default_app(&attachment_type) {
|
||||
let p = create_temp_file(
|
||||
&decode(u, None),
|
||||
filename.as_deref(),
|
||||
None,
|
||||
true,
|
||||
);
|
||||
let (exec_cmd, argument) = super::desktop_exec_to_command(
|
||||
&command,
|
||||
p.path.display().to_string(),
|
||||
false,
|
||||
);
|
||||
match Command::new(&exec_cmd)
|
||||
.arg(&argument)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
{
|
||||
Ok(child) => {
|
||||
context.temp_files.push(p);
|
||||
context.children.push(child);
|
||||
}
|
||||
} else {
|
||||
context.replies.push_back(UIEvent::StatusEvent(
|
||||
Err(err) => {
|
||||
context.replies.push_back(UIEvent::StatusEvent(
|
||||
StatusEvent::DisplayMessage(format!(
|
||||
"Failed to start `{} {}`: {}",
|
||||
&exec_cmd, &argument, err
|
||||
)),
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
context.replies.push_back(UIEvent::StatusEvent(
|
||||
StatusEvent::DisplayMessage(if let Some(filename) = filename.as_ref() {
|
||||
format!(
|
||||
"Couldn't find a default application for file {} (type {})",
|
||||
|
@ -445,29 +440,28 @@ impl Component for EnvelopeView {
|
|||
attachment_type
|
||||
)
|
||||
}),
|
||||
));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ContentType::OctetStream { .. } => {
|
||||
context.replies.push_back(UIEvent::StatusEvent(
|
||||
StatusEvent::DisplayMessage(
|
||||
"application/octet-stream isn't supported yet".to_string(),
|
||||
),
|
||||
));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
context.replies.push_back(UIEvent::StatusEvent(
|
||||
StatusEvent::DisplayMessage(format!(
|
||||
"Attachment `{}` not found.",
|
||||
lidx
|
||||
)),
|
||||
));
|
||||
return true;
|
||||
ContentType::OctetStream { .. } => {
|
||||
context.replies.push_back(UIEvent::StatusEvent(
|
||||
StatusEvent::DisplayMessage(
|
||||
"application/octet-stream isn't supported yet".to_string(),
|
||||
),
|
||||
));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::DisplayMessage(format!(
|
||||
"Attachment `{}` not found.",
|
||||
lidx
|
||||
))));
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
UIEvent::Input(Key::Char('g'))
|
||||
|
@ -492,22 +486,16 @@ impl Component for EnvelopeView {
|
|||
}
|
||||
};
|
||||
|
||||
let url_launcher = context
|
||||
.settings
|
||||
.pager
|
||||
.url_launcher
|
||||
.as_ref()
|
||||
.map(|s| s.as_str())
|
||||
.unwrap_or(
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
"open"
|
||||
},
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
"xdg-open"
|
||||
},
|
||||
);
|
||||
let url_launcher = context.settings.pager.url_launcher.as_deref().unwrap_or(
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
"open"
|
||||
},
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
"xdg-open"
|
||||
},
|
||||
);
|
||||
match Command::new(url_launcher)
|
||||
.arg(url)
|
||||
.stdin(Stdio::piped())
|
||||
|
|
|
@ -415,11 +415,7 @@ impl ThreadView {
|
|||
idx: usize,
|
||||
context: &Context,
|
||||
) {
|
||||
let visibles: Vec<&usize> = self
|
||||
.visible_entries
|
||||
.iter()
|
||||
.flat_map(|ref v| v.iter())
|
||||
.collect();
|
||||
let visibles: Vec<&usize> = self.visible_entries.iter().flat_map(|v| v.iter()).collect();
|
||||
if idx == *visibles[self.cursor_pos] {
|
||||
let theme_default = crate::conf::value(context, "theme_default");
|
||||
let bg_color = crate::conf::value(context, "highlight").bg;
|
||||
|
@ -514,11 +510,8 @@ impl ThreadView {
|
|||
if page_no != prev_page_no {
|
||||
clear_area(grid, area, crate::conf::value(context, "theme_default"));
|
||||
}
|
||||
let visibles: Vec<&usize> = self
|
||||
.visible_entries
|
||||
.iter()
|
||||
.flat_map(|ref v| v.iter())
|
||||
.collect();
|
||||
let visibles: Vec<&usize> =
|
||||
self.visible_entries.iter().flat_map(|v| v.iter()).collect();
|
||||
|
||||
for (visible_entry_counter, v) in visibles.iter().skip(top_idx).take(rows).enumerate() {
|
||||
if visible_entry_counter >= rows {
|
||||
|
@ -595,11 +588,8 @@ impl ThreadView {
|
|||
self.cursor_pos = self.new_cursor_pos;
|
||||
/* If cursor position has changed, remove the highlight from the previous position and
|
||||
* apply it in the new one. */
|
||||
let visibles: Vec<&usize> = self
|
||||
.visible_entries
|
||||
.iter()
|
||||
.flat_map(|ref v| v.iter())
|
||||
.collect();
|
||||
let visibles: Vec<&usize> =
|
||||
self.visible_entries.iter().flat_map(|v| v.iter()).collect();
|
||||
for &idx in &[old_cursor_pos, self.cursor_pos] {
|
||||
let entry_idx = *visibles[idx];
|
||||
let src_area = { get_entry_area(entry_idx, &self.entries) };
|
||||
|
@ -948,11 +938,7 @@ impl ThreadView {
|
|||
|
||||
/// Current position in self.entries (not in drawn entries which might exclude nonvisible ones)
|
||||
fn current_pos(&self) -> usize {
|
||||
let visibles: Vec<&usize> = self
|
||||
.visible_entries
|
||||
.iter()
|
||||
.flat_map(|ref v| v.iter())
|
||||
.collect();
|
||||
let visibles: Vec<&usize> = self.visible_entries.iter().flat_map(|v| v.iter()).collect();
|
||||
*visibles[self.new_cursor_pos]
|
||||
}
|
||||
}
|
||||
|
@ -999,15 +985,12 @@ impl Component for ThreadView {
|
|||
self.dirty = false;
|
||||
}
|
||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||
match event {
|
||||
UIEvent::Action(Listing(OpenInNewTab)) => {
|
||||
/* Handle this before self.mailview does */
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::Action(Tab(New(Some(Box::new(self.clone()))))));
|
||||
return true;
|
||||
}
|
||||
_ => {}
|
||||
if let UIEvent::Action(Listing(OpenInNewTab)) = event {
|
||||
/* Handle this before self.mailview does */
|
||||
context
|
||||
.replies
|
||||
.push_back(UIEvent::Action(Tab(New(Some(Box::new(self.clone()))))));
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.show_mailview && self.mailview.process_event(event, context) {
|
||||
|
|
|
@ -169,7 +169,7 @@ mod dbus {
|
|||
}
|
||||
|
||||
/// Passes notifications to a user defined shell command
|
||||
#[derive(Debug)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct NotificationCommand {}
|
||||
|
||||
impl NotificationCommand {
|
||||
|
@ -204,7 +204,7 @@ impl Component for NotificationCommand {
|
|||
}
|
||||
Err(err) => {
|
||||
log(
|
||||
format!("Could not run notification script: {}.", err.to_string()),
|
||||
format!("Could not run notification script: {}.", err),
|
||||
ERROR,
|
||||
);
|
||||
debug!("Could not run notification script: {:?}", err);
|
||||
|
@ -226,10 +226,7 @@ impl Component for NotificationCommand {
|
|||
}
|
||||
Err(err) => {
|
||||
log(
|
||||
format!(
|
||||
"Could not run notification script: {}.",
|
||||
err.to_string()
|
||||
),
|
||||
format!("Could not run notification script: {}.", err),
|
||||
ERROR,
|
||||
);
|
||||
debug!("Could not run notification script: {:?}", err);
|
||||
|
|
|
@ -67,7 +67,7 @@ pub struct StatusBar {
|
|||
done_jobs: HashSet<JobId>,
|
||||
scroll_contexts: IndexMap<ComponentId, ScrollContext>,
|
||||
|
||||
auto_complete: AutoComplete,
|
||||
auto_complete: Box<AutoComplete>,
|
||||
cmd_history: Vec<String>,
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ impl StatusBar {
|
|||
.set_bg(attribute.bg)
|
||||
.set_attrs(attribute.attrs);
|
||||
}
|
||||
let offset = self.status.find('|').unwrap_or_else(|| self.status.len());
|
||||
let offset = self.status.find('|').unwrap_or(self.status.len());
|
||||
if y < get_y(bottom_right!(area)) + 1 {
|
||||
for x in get_x(upper_left!(area))
|
||||
..std::cmp::min(
|
||||
|
@ -209,8 +209,7 @@ impl StatusBar {
|
|||
.settings
|
||||
.terminal
|
||||
.mouse_flag
|
||||
.as_ref()
|
||||
.map(|s| s.as_str())
|
||||
.as_deref()
|
||||
.unwrap_or("🖱️ ")
|
||||
} else {
|
||||
""
|
||||
|
@ -362,7 +361,7 @@ impl Component for StatusBar {
|
|||
}
|
||||
|
||||
suggestions.sort_by(|a, b| a.entry.cmp(&b.entry));
|
||||
suggestions.dedup_by(|a, b| &a.entry == &b.entry);
|
||||
suggestions.dedup_by(|a, b| a.entry == b.entry);
|
||||
if self.auto_complete.set_suggestions(suggestions) {
|
||||
let len = self.auto_complete.suggestions().len() - 1;
|
||||
self.auto_complete.set_cursor(len);
|
||||
|
@ -529,7 +528,7 @@ impl Component for StatusBar {
|
|||
self.container.set_dirty(true);
|
||||
}
|
||||
UIEvent::ChangeMode(m) => {
|
||||
let offset = self.status.find('|').unwrap_or_else(|| self.status.len());
|
||||
let offset = self.status.find('|').unwrap_or(self.status.len());
|
||||
self.status.replace_range(
|
||||
..offset,
|
||||
&format!(
|
||||
|
@ -540,8 +539,7 @@ impl Component for StatusBar {
|
|||
.settings
|
||||
.terminal
|
||||
.mouse_flag
|
||||
.as_ref()
|
||||
.map(|s| s.as_str())
|
||||
.as_deref()
|
||||
.unwrap_or("🖱️ ")
|
||||
} else {
|
||||
""
|
||||
|
@ -559,7 +557,7 @@ impl Component for StatusBar {
|
|||
.replies
|
||||
.push_back(UIEvent::Command(self.ex_buffer.as_str().to_string()));
|
||||
}
|
||||
if parse_command(&self.ex_buffer.as_str().as_bytes()).is_ok()
|
||||
if parse_command(self.ex_buffer.as_str().as_bytes()).is_ok()
|
||||
&& self.cmd_history.last().map(String::as_str)
|
||||
!= Some(self.ex_buffer.as_str())
|
||||
{
|
||||
|
@ -1138,7 +1136,7 @@ impl Component for Tabbed {
|
|||
None,
|
||||
);
|
||||
write_string_to_grid(
|
||||
&k,
|
||||
k,
|
||||
&mut self.help_content,
|
||||
self.theme_default.fg,
|
||||
self.theme_default.bg,
|
||||
|
@ -1485,13 +1483,13 @@ impl Component for Tabbed {
|
|||
self.help_screen_cursor.1 = self.help_screen_cursor.1.saturating_sub(1);
|
||||
}
|
||||
_ if shortcut!(key == shortcuts["general"]["scroll_down"]) => {
|
||||
self.help_screen_cursor.1 = self.help_screen_cursor.1 + 1;
|
||||
self.help_screen_cursor.1 += 1;
|
||||
}
|
||||
_ if shortcut!(key == shortcuts["general"]["scroll_left"]) => {
|
||||
self.help_screen_cursor.0 = self.help_screen_cursor.0.saturating_sub(1);
|
||||
}
|
||||
_ if shortcut!(key == shortcuts["general"]["scroll_right"]) => {
|
||||
self.help_screen_cursor.0 = self.help_screen_cursor.0 + 1;
|
||||
self.help_screen_cursor.0 += 1;
|
||||
}
|
||||
_ => {
|
||||
/* ignore, don't pass to components below the shortcut panel */
|
||||
|
@ -1600,7 +1598,7 @@ impl Component for RawBuffer {
|
|||
true
|
||||
}
|
||||
UIEvent::Input(Key::Right) => {
|
||||
self.cursor.0 = self.cursor.0 + 1;
|
||||
self.cursor.0 += 1;
|
||||
self.dirty = true;
|
||||
true
|
||||
}
|
||||
|
@ -1610,7 +1608,7 @@ impl Component for RawBuffer {
|
|||
true
|
||||
}
|
||||
UIEvent::Input(Key::Down) => {
|
||||
self.cursor.1 = self.cursor.1 + 1;
|
||||
self.cursor.1 += 1;
|
||||
self.dirty = true;
|
||||
true
|
||||
}
|
||||
|
@ -1641,9 +1639,6 @@ impl RawBuffer {
|
|||
}
|
||||
}
|
||||
pub fn title(&self) -> &str {
|
||||
self.title
|
||||
.as_ref()
|
||||
.map(String::as_str)
|
||||
.unwrap_or("untitled")
|
||||
self.title.as_deref().unwrap_or("untitled")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -760,7 +760,7 @@ impl<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> Selec
|
|||
) -> Selector<T, F> {
|
||||
let entry_titles = entries
|
||||
.iter_mut()
|
||||
.map(|(_id, ref mut title)| std::mem::replace(title, String::new()))
|
||||
.map(|(_id, ref mut title)| std::mem::take(title))
|
||||
.collect::<Vec<String>>();
|
||||
let mut identifiers: Vec<(T, bool)> =
|
||||
entries.into_iter().map(|(id, _)| (id, false)).collect();
|
||||
|
@ -812,7 +812,7 @@ impl<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> Selec
|
|||
if self.single_only {
|
||||
for (i, e) in self.entry_titles.iter().enumerate() {
|
||||
write_string_to_grid(
|
||||
&e,
|
||||
e,
|
||||
&mut content,
|
||||
self.theme_default.fg,
|
||||
self.theme_default.bg,
|
||||
|
@ -824,7 +824,7 @@ impl<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> Selec
|
|||
} else {
|
||||
for (i, e) in self.entry_titles.iter().enumerate() {
|
||||
write_string_to_grid(
|
||||
&format!("[ ] {}", &e),
|
||||
&format!("[ ] {}", e),
|
||||
&mut content,
|
||||
self.theme_default.fg,
|
||||
self.theme_default.bg,
|
||||
|
|
|
@ -39,7 +39,6 @@ pub struct Pager {
|
|||
colors: ThemeAttribute,
|
||||
initialised: bool,
|
||||
show_scrollbar: bool,
|
||||
content: CellBuffer,
|
||||
filtered_content: Option<(String, Result<CellBuffer>)>,
|
||||
text_lines: Vec<String>,
|
||||
line_breaker: LineBreakText,
|
||||
|
@ -57,8 +56,10 @@ impl Pager {
|
|||
pub const DESCRIPTION: &'static str = "pager";
|
||||
const PAGES_AHEAD_TO_RENDER_NO: usize = 16;
|
||||
pub fn new(context: &Context) -> Self {
|
||||
let mut ret = Pager::default();
|
||||
ret.minimum_width = context.settings.pager.minimum_width;
|
||||
let mut ret = Pager {
|
||||
minimum_width: context.settings.pager.minimum_width,
|
||||
..Pager::default()
|
||||
};
|
||||
ret.set_colors(crate::conf::value(context, "theme_default"))
|
||||
.set_reflow(if context.settings.pager.split_long_lines {
|
||||
Reflow::All
|
||||
|
@ -178,10 +179,7 @@ impl Pager {
|
|||
.stdout(Stdio::piped())
|
||||
.spawn()
|
||||
.chain_err_summary(|| "Failed to start pager filter process")?;
|
||||
let stdin = filter_child
|
||||
.stdin
|
||||
.as_mut()
|
||||
.ok_or_else(|| "failed to open stdin")?;
|
||||
let stdin = filter_child.stdin.as_mut().ok_or("failed to open stdin")?;
|
||||
stdin
|
||||
.write_all(text.as_bytes())
|
||||
.chain_err_summary(|| "Failed to write to stdin")?;
|
||||
|
@ -196,7 +194,7 @@ impl Pager {
|
|||
for b in out {
|
||||
embedded.process_byte(&mut dev_null, b);
|
||||
}
|
||||
Ok(std::mem::replace(embedded.buffer_mut(), Default::default()))
|
||||
Ok(std::mem::take(embedded.buffer_mut()))
|
||||
};
|
||||
let buf = _f(cmd, &self.text);
|
||||
if let Some((width, height)) = buf.as_ref().ok().map(CellBuffer::size) {
|
||||
|
@ -301,7 +299,7 @@ impl Pager {
|
|||
Ok(ref content) => {
|
||||
copy_area(
|
||||
grid,
|
||||
&content,
|
||||
content,
|
||||
area,
|
||||
(
|
||||
(
|
||||
|
@ -353,7 +351,7 @@ impl Pager {
|
|||
(upper_left, bottom_right),
|
||||
None,
|
||||
);
|
||||
if l.starts_with("⤷") {
|
||||
if l.starts_with('⤷') {
|
||||
grid[upper_left]
|
||||
.set_fg(crate::conf::value(context, "highlight").fg)
|
||||
.set_attrs(crate::conf::value(context, "highlight").attrs);
|
||||
|
|
|
@ -42,7 +42,7 @@ impl Default for FormFocus {
|
|||
}
|
||||
|
||||
pub enum Field {
|
||||
Text(UText, Option<(AutoCompleteFn, AutoComplete)>),
|
||||
Text(UText, Option<(AutoCompleteFn, Box<AutoComplete>)>),
|
||||
Choice(Vec<Cow<'static, str>>, Cursor),
|
||||
}
|
||||
|
||||
|
@ -456,6 +456,10 @@ impl<T: 'static + std::fmt::Debug + Copy + Default + Send + Sync> FormWidget<T>
|
|||
self.layout.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.layout.len() == 0
|
||||
}
|
||||
|
||||
pub fn add_button(&mut self, val: (Cow<'static, str>, T)) {
|
||||
self.buttons.push(val);
|
||||
}
|
||||
|
@ -1003,7 +1007,7 @@ impl Component for AutoComplete {
|
|||
}
|
||||
|
||||
impl AutoComplete {
|
||||
pub fn new(entries: Vec<AutoCompleteEntry>) -> Self {
|
||||
pub fn new(entries: Vec<AutoCompleteEntry>) -> Box<Self> {
|
||||
let mut ret = AutoComplete {
|
||||
entries: Vec::new(),
|
||||
content: CellBuffer::default(),
|
||||
|
@ -1012,7 +1016,7 @@ impl AutoComplete {
|
|||
id: ComponentId::new_v4(),
|
||||
};
|
||||
ret.set_suggestions(entries);
|
||||
ret
|
||||
Box::new(ret)
|
||||
}
|
||||
|
||||
pub fn set_suggestions(&mut self, entries: Vec<AutoCompleteEntry>) -> bool {
|
||||
|
@ -1401,7 +1405,7 @@ impl Component for ProgressSpinner {
|
|||
if self.active {
|
||||
write_string_to_grid(
|
||||
match self.kind.as_ref() {
|
||||
Ok(kind) => (Self::KINDS[*kind].1)[self.stage].as_ref(),
|
||||
Ok(kind) => (Self::KINDS[*kind].1)[self.stage],
|
||||
Err(custom) => custom[self.stage].as_ref(),
|
||||
},
|
||||
grid,
|
||||
|
|
23
src/conf.rs
23
src/conf.rs
|
@ -250,7 +250,7 @@ impl From<FileAccount> for AccountConf {
|
|||
let root_mailbox = x.root_mailbox.clone();
|
||||
let identity = x.identity.clone();
|
||||
let display_name = x.display_name.clone();
|
||||
let order = x.order.clone();
|
||||
let order = x.order;
|
||||
let mailboxes = x
|
||||
.mailboxes
|
||||
.iter()
|
||||
|
@ -365,13 +365,14 @@ impl FileSettings {
|
|||
|
||||
pub fn validate(path: PathBuf, interactive: bool, clear_extras: bool) -> Result<Self> {
|
||||
let s = pp::pp(&path)?;
|
||||
let map: toml::map::Map<String, toml::value::Value> = toml::from_str(&s).map_err(|e| {
|
||||
MeliError::new(format!(
|
||||
"{}:\nConfig file is invalid TOML: {}",
|
||||
path.display(),
|
||||
e.to_string()
|
||||
))
|
||||
})?;
|
||||
let map: toml::map::Map<String, toml::value::Value> =
|
||||
toml::from_str(&s).map_err(|err| {
|
||||
MeliError::new(format!(
|
||||
"{}:\nConfig file is invalid TOML: {}",
|
||||
path.display(),
|
||||
err
|
||||
))
|
||||
})?;
|
||||
/*
|
||||
* Check that a global composing option is set and return a user-friendly error message because the
|
||||
* default serde one is confusing.
|
||||
|
@ -410,11 +411,11 @@ This is required so that you don't accidentally start meli and find out later th
|
|||
path.display()
|
||||
)));
|
||||
}
|
||||
let mut s: FileSettings = toml::from_str(&s).map_err(|e| {
|
||||
let mut s: FileSettings = toml::from_str(&s).map_err(|err| {
|
||||
MeliError::new(format!(
|
||||
"{}:\nConfig file contains errors: {}",
|
||||
path.display(),
|
||||
e.to_string()
|
||||
err
|
||||
))
|
||||
})?;
|
||||
let backends = melib::backends::Backends::new();
|
||||
|
@ -831,7 +832,7 @@ mod pp {
|
|||
}
|
||||
i += 1;
|
||||
}
|
||||
return Ok(("", None));
|
||||
Ok(("", None))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -89,18 +89,11 @@ impl Default for MailboxStatus {
|
|||
|
||||
impl MailboxStatus {
|
||||
pub fn is_available(&self) -> bool {
|
||||
if let MailboxStatus::Available = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
matches!(self, MailboxStatus::Available)
|
||||
}
|
||||
|
||||
pub fn is_parsing(&self) -> bool {
|
||||
if let MailboxStatus::Parsing(_, _) = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
matches!(self, MailboxStatus::Parsing(_, _))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +125,7 @@ impl MailboxEntry {
|
|||
if let Some(name) = self.conf.mailbox_conf.alias.as_ref() {
|
||||
name
|
||||
} else {
|
||||
&self.ref_mailbox.name()
|
||||
self.ref_mailbox.name()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +158,7 @@ pub enum JobRequest {
|
|||
},
|
||||
Fetch {
|
||||
mailbox_hash: MailboxHash,
|
||||
#[allow(clippy::type_complexity)]
|
||||
handle: JoinHandle<(
|
||||
Option<Result<Vec<Envelope>>>,
|
||||
Pin<Box<dyn Stream<Item = Result<Vec<Envelope>>> + Send + 'static>>,
|
||||
|
@ -345,26 +339,17 @@ impl core::fmt::Display for JobRequest {
|
|||
|
||||
impl JobRequest {
|
||||
pub fn is_watch(&self) -> bool {
|
||||
match self {
|
||||
JobRequest::Watch { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, JobRequest::Watch { .. })
|
||||
}
|
||||
|
||||
pub fn is_fetch(&self, mailbox_hash: MailboxHash) -> bool {
|
||||
match self {
|
||||
JobRequest::Fetch {
|
||||
mailbox_hash: h, ..
|
||||
} if *h == mailbox_hash => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, JobRequest::Fetch {
|
||||
mailbox_hash: h, ..
|
||||
} if *h == mailbox_hash)
|
||||
}
|
||||
|
||||
pub fn is_online(&self) -> bool {
|
||||
match self {
|
||||
JobRequest::IsOnline { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, JobRequest::IsOnline { .. })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,7 +373,6 @@ impl Drop for Account {
|
|||
let writer = io::BufWriter::new(f);
|
||||
if let Err(err) = serde_json::to_writer(writer, &self.address_book) {
|
||||
eprintln!("{}", err);
|
||||
return;
|
||||
};
|
||||
};
|
||||
/*
|
||||
|
@ -455,7 +439,7 @@ impl Account {
|
|||
)?;
|
||||
|
||||
let data_dir = xdg::BaseDirectories::with_profile("meli", &name).unwrap();
|
||||
let mut address_book = AddressBook::with_account(&settings.account());
|
||||
let mut address_book = AddressBook::with_account(settings.account());
|
||||
|
||||
if let Ok(data) = data_dir.place_data_file("addressbook") {
|
||||
if data.exists() {
|
||||
|
@ -730,7 +714,7 @@ impl Account {
|
|||
format!(
|
||||
"Failed to update envelope {} in cache: {}",
|
||||
envelope.message_id_display(),
|
||||
err.to_string()
|
||||
err
|
||||
),
|
||||
melib::ERROR,
|
||||
);
|
||||
|
@ -804,7 +788,7 @@ impl Account {
|
|||
"Failed to update envelope {} in cache: {}",
|
||||
self.collection.envelopes.read().unwrap()[&env_hash]
|
||||
.message_id_display(),
|
||||
err.to_string()
|
||||
err
|
||||
),
|
||||
melib::ERROR,
|
||||
);
|
||||
|
@ -834,7 +818,7 @@ impl Account {
|
|||
"Failed to update envelope {} in cache: {}",
|
||||
&self.collection.envelopes.read().unwrap()[&new_hash]
|
||||
.message_id_display(),
|
||||
err.to_string()
|
||||
err
|
||||
),
|
||||
melib::ERROR,
|
||||
);
|
||||
|
@ -961,7 +945,7 @@ impl Account {
|
|||
"Failed to remove envelope {} [{}] in cache: {}",
|
||||
&envelopes[&env_hash].message_id_display(),
|
||||
env_hash,
|
||||
err.to_string()
|
||||
err
|
||||
),
|
||||
melib::ERROR,
|
||||
);
|
||||
|
@ -1193,14 +1177,10 @@ impl Account {
|
|||
self.special_use_mailbox(SpecialUsageMailbox::Normal),
|
||||
] {
|
||||
if let Some(mailbox_hash) = mailbox {
|
||||
if let Err(e) = self.save(bytes, *mailbox_hash, Some(flags)) {
|
||||
debug!("{:?} could not save msg", e);
|
||||
if let Err(err) = self.save(bytes, *mailbox_hash, Some(flags)) {
|
||||
debug!("{:?} could not save msg", err);
|
||||
melib::log(
|
||||
format!(
|
||||
"Could not save in '{}' mailbox: {}.",
|
||||
*mailbox_hash,
|
||||
e.to_string()
|
||||
),
|
||||
format!("Could not save in '{}' mailbox: {}.", *mailbox_hash, err),
|
||||
melib::ERROR,
|
||||
);
|
||||
} else {
|
||||
|
@ -1311,9 +1291,7 @@ impl Account {
|
|||
)
|
||||
};
|
||||
melib::log(&error_message, melib::LoggingLevel::ERROR);
|
||||
return Err(
|
||||
MeliError::new(error_message.clone()).set_summary("Message not sent.")
|
||||
);
|
||||
return Err(MeliError::new(error_message).set_summary("Message not sent."));
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
@ -1334,11 +1312,11 @@ impl Account {
|
|||
}
|
||||
SendMail::ServerSubmission => {
|
||||
if self.backend_capabilities.supports_submission {
|
||||
let job = self.backend.write().unwrap().submit(
|
||||
message.clone().into_bytes(),
|
||||
None,
|
||||
None,
|
||||
)?;
|
||||
let job =
|
||||
self.backend
|
||||
.write()
|
||||
.unwrap()
|
||||
.submit(message.into_bytes(), None, None)?;
|
||||
|
||||
let handle = if self.backend_capabilities.is_async {
|
||||
self.job_executor.spawn_specialized(job)
|
||||
|
@ -1348,8 +1326,8 @@ impl Account {
|
|||
self.insert_job(handle.job_id, JobRequest::SendMessageBackground { handle });
|
||||
return Ok(None);
|
||||
}
|
||||
return Err(MeliError::new("Server does not support submission.")
|
||||
.set_summary("Message not sent."));
|
||||
Err(MeliError::new("Server does not support submission.")
|
||||
.set_summary("Message not sent."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1400,8 +1378,9 @@ impl Account {
|
|||
)
|
||||
};
|
||||
melib::log(&error_message, melib::LoggingLevel::ERROR);
|
||||
return Err(MeliError::new(error_message.clone())
|
||||
.set_summary("Message not sent."));
|
||||
return Err(
|
||||
MeliError::new(error_message).set_summary("Message not sent.")
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1423,8 +1402,8 @@ impl Account {
|
|||
fut.await?;
|
||||
return Ok(());
|
||||
}
|
||||
return Err(MeliError::new("Server does not support submission.")
|
||||
.set_summary("Message not sent."));
|
||||
Err(MeliError::new("Server does not support submission.")
|
||||
.set_summary("Message not sent."))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1537,11 +1516,7 @@ impl Account {
|
|||
.mailbox_entries
|
||||
.iter()
|
||||
.find(|(_, f)| f.conf.mailbox_conf().usage == Some(special_use));
|
||||
if let Some(ret) = ret.as_ref() {
|
||||
Some(ret.1.ref_mailbox.hash())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
ret.as_ref().map(|ret| ret.1.ref_mailbox.hash())
|
||||
}
|
||||
|
||||
/* Call only in Context::is_online, since only Context can launch the watcher threads if an
|
||||
|
@ -1575,7 +1550,7 @@ impl Account {
|
|||
self.insert_job(handle.job_id, JobRequest::IsOnline { handle });
|
||||
}
|
||||
}
|
||||
return self.is_online.clone();
|
||||
self.is_online.clone()
|
||||
}
|
||||
|
||||
pub fn search(
|
||||
|
@ -2272,7 +2247,7 @@ fn build_mailboxes_order(
|
|||
node
|
||||
}
|
||||
|
||||
tree.push(rec(*h, &mailbox_entries, 0));
|
||||
tree.push(rec(*h, mailbox_entries, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2356,7 +2331,6 @@ fn build_mailboxes_order(
|
|||
fn rec(
|
||||
node: &mut MailboxNode,
|
||||
mailbox_entries: &IndexMap<MailboxHash, MailboxEntry>,
|
||||
depth: usize,
|
||||
mut indentation: u32,
|
||||
has_sibling: bool,
|
||||
) {
|
||||
|
@ -2379,16 +2353,10 @@ fn build_mailboxes_order(
|
|||
}
|
||||
while let Some(i) = iter.next() {
|
||||
let c = &mut node.children[i];
|
||||
rec(
|
||||
c,
|
||||
mailbox_entries,
|
||||
depth + 1,
|
||||
indentation,
|
||||
iter.peek() != None,
|
||||
);
|
||||
rec(c, mailbox_entries, indentation, iter.peek() != None);
|
||||
}
|
||||
}
|
||||
|
||||
rec(node, &mailbox_entries, 1, 0, false);
|
||||
rec(node, mailbox_entries, 0, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//! This module is automatically generated by build.rs.
|
||||
#![allow(clippy::derivable_impls)]
|
||||
|
||||
//! This module is automatically generated by config_macros.rs.
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
|
|
|
@ -34,7 +34,7 @@ macro_rules! shortcut {
|
|||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Shortcuts {
|
||||
#[serde(default)]
|
||||
|
@ -55,21 +55,6 @@ pub struct Shortcuts {
|
|||
pub pager: PagerShortcuts,
|
||||
}
|
||||
|
||||
impl Default for Shortcuts {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
general: GeneralShortcuts::default(),
|
||||
listing: ListingShortcuts::default(),
|
||||
composing: ComposingShortcuts::default(),
|
||||
compact_listing: CompactListingShortcuts::default(),
|
||||
contact_list: ContactListShortcuts::default(),
|
||||
envelope_view: EnvelopeViewShortcuts::default(),
|
||||
thread_view: ThreadViewShortcuts::default(),
|
||||
pager: PagerShortcuts::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DotAddressable for Shortcuts {
|
||||
fn lookup(&self, parent_field: &str, path: &[&str]) -> Result<String> {
|
||||
match path.first() {
|
||||
|
|
|
@ -28,7 +28,7 @@ use serde::{Deserialize, Deserializer};
|
|||
use std::collections::{hash_map::DefaultHasher, HashMap, HashSet};
|
||||
use std::hash::Hasher;
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Serialize)]
|
||||
#[derive(Default, Debug, Deserialize, Clone, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct TagsSettings {
|
||||
#[serde(default, deserialize_with = "tag_color_de")]
|
||||
|
@ -37,15 +37,6 @@ pub struct TagsSettings {
|
|||
pub ignore_tags: HashSet<u64>,
|
||||
}
|
||||
|
||||
impl Default for TagsSettings {
|
||||
fn default() -> Self {
|
||||
TagsSettings {
|
||||
colors: Default::default(),
|
||||
ignore_tags: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tag_set_de<'de, D, T: std::convert::From<HashSet<u64>>>(
|
||||
deserializer: D,
|
||||
) -> std::result::Result<T, D::Error>
|
||||
|
|
|
@ -102,7 +102,7 @@ pub fn attrs(context: &Context, key: &'static str) -> Attr {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unlink<'k, 't: 'k>(theme: &'t Theme, key: &'k Cow<'static, str>) -> ThemeAttribute {
|
||||
fn unlink<'k, 't: 'k>(theme: &'t Theme, key: &'k str) -> ThemeAttribute {
|
||||
ThemeAttribute {
|
||||
fg: unlink_fg(theme, &ColorField::Fg, key),
|
||||
bg: unlink_bg(theme, &ColorField::Bg, key),
|
||||
|
@ -111,11 +111,7 @@ fn unlink<'k, 't: 'k>(theme: &'t Theme, key: &'k Cow<'static, str>) -> ThemeAttr
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unlink_fg<'k, 't: 'k>(
|
||||
theme: &'t Theme,
|
||||
mut field: &'k ColorField,
|
||||
mut key: &'k Cow<'static, str>,
|
||||
) -> Color {
|
||||
fn unlink_fg<'k, 't: 'k>(theme: &'t Theme, mut field: &'k ColorField, mut key: &'k str) -> Color {
|
||||
loop {
|
||||
match field {
|
||||
ColorField::LikeSelf | ColorField::Fg => match &theme[key].fg {
|
||||
|
@ -166,11 +162,7 @@ fn unlink_fg<'k, 't: 'k>(
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unlink_bg<'k, 't: 'k>(
|
||||
theme: &'t Theme,
|
||||
mut field: &'k ColorField,
|
||||
mut key: &'k Cow<'static, str>,
|
||||
) -> Color {
|
||||
fn unlink_bg<'k, 't: 'k>(theme: &'t Theme, mut field: &'k ColorField, mut key: &'k str) -> Color {
|
||||
loop {
|
||||
match field {
|
||||
ColorField::LikeSelf | ColorField::Bg => match &theme[key].bg {
|
||||
|
@ -220,7 +212,7 @@ fn unlink_bg<'k, 't: 'k>(
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unlink_attrs<'k, 't: 'k>(theme: &'t Theme, mut key: &'k Cow<'static, str>) -> Attr {
|
||||
fn unlink_attrs<'k, 't: 'k>(theme: &'t Theme, mut key: &'k str) -> Attr {
|
||||
loop {
|
||||
match &theme[key].attrs {
|
||||
ThemeValue::Link(ref new_key, ()) => key = new_key,
|
||||
|
@ -416,8 +408,8 @@ impl<'de> Deserialize<'de> for ThemeValue<Attr> {
|
|||
D: Deserializer<'de>,
|
||||
{
|
||||
if let Ok(s) = <String>::deserialize(deserializer) {
|
||||
if s.starts_with("$") {
|
||||
Ok(ThemeValue::Alias(s[1..].to_string().into()))
|
||||
if let Some(stripped) = s.strip_prefix('$') {
|
||||
Ok(ThemeValue::Alias(stripped.to_string().into()))
|
||||
} else if let Ok(c) = Attr::from_string_de::<'de, D, String>(s.clone()) {
|
||||
Ok(ThemeValue::Value(c))
|
||||
} else {
|
||||
|
@ -467,8 +459,8 @@ impl<'de> Deserialize<'de> for ThemeValue<Color> {
|
|||
D: Deserializer<'de>,
|
||||
{
|
||||
if let Ok(s) = <String>::deserialize(deserializer) {
|
||||
if s.starts_with("$") {
|
||||
Ok(ThemeValue::Alias(s[1..].to_string().into()))
|
||||
if let Some(stripped) = s.strip_prefix('$') {
|
||||
Ok(ThemeValue::Alias(stripped.to_string().into()))
|
||||
} else if let Ok(c) = Color::from_string_de::<'de, D>(s.clone()) {
|
||||
Ok(ThemeValue::Value(c))
|
||||
} else if s.ends_with(".fg") {
|
||||
|
@ -606,37 +598,26 @@ mod regexp {
|
|||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
loop {
|
||||
let next_byte_offset = self.pcre_iter.next();
|
||||
if next_byte_offset.is_none() {
|
||||
return None;
|
||||
}
|
||||
let next_byte_offset = next_byte_offset.unwrap();
|
||||
let next_byte_offset = self.pcre_iter.next()?;
|
||||
if next_byte_offset.is_err() {
|
||||
continue;
|
||||
}
|
||||
let next_byte_offset = next_byte_offset.unwrap();
|
||||
|
||||
let mut next_char_index = self.char_indices.next();
|
||||
if next_char_index.is_none() {
|
||||
return None;
|
||||
}
|
||||
let mut next_char_index = self.char_indices.next()?;
|
||||
|
||||
while next_byte_offset.start() < next_char_index.unwrap().0 {
|
||||
while next_byte_offset.start() < next_char_index.0 {
|
||||
self.char_offset += 1;
|
||||
next_char_index = self.char_indices.next();
|
||||
if next_char_index.is_none() {
|
||||
return None;
|
||||
}
|
||||
next_char_index = self.char_indices.next()?;
|
||||
}
|
||||
let start = self.char_offset;
|
||||
|
||||
while next_byte_offset.end()
|
||||
>= self
|
||||
> self
|
||||
.char_indices
|
||||
.next()
|
||||
.map(|(v, _)| v)
|
||||
.unwrap_or(next_byte_offset.end())
|
||||
+ 1
|
||||
.unwrap_or_else(|| next_byte_offset.end())
|
||||
{
|
||||
self.char_offset += 1;
|
||||
}
|
||||
|
@ -1219,7 +1200,7 @@ impl Themes {
|
|||
Ok(())
|
||||
}
|
||||
pub fn validate(&self) -> Result<()> {
|
||||
let hash_set: HashSet<&'static str> = DEFAULT_KEYS.into_iter().map(|k| *k).collect();
|
||||
let hash_set: HashSet<&'static str> = DEFAULT_KEYS.iter().copied().collect();
|
||||
Themes::validate_keys("light", &self.light, &hash_set)?;
|
||||
Themes::validate_keys("dark", &self.dark, &hash_set)?;
|
||||
for (name, t) in self.other_themes.iter() {
|
||||
|
@ -1255,51 +1236,49 @@ impl Themes {
|
|||
t => self.other_themes.get(t).unwrap_or(&self.dark),
|
||||
};
|
||||
let mut ret = String::new();
|
||||
ret.extend(format!("[terminal.themes.{}]\n", key).chars());
|
||||
ret.push_str(&format!("[terminal.themes.{}]\n", key));
|
||||
if unlink {
|
||||
for k in theme.keys() {
|
||||
ret.extend(
|
||||
format!(
|
||||
"\"{}\" = {{ fg = {}, bg = {}, attrs = {} }}\n",
|
||||
k,
|
||||
toml::to_string(&unlink_fg(&theme, &ColorField::Fg, k)).unwrap(),
|
||||
toml::to_string(&unlink_bg(&theme, &ColorField::Bg, k)).unwrap(),
|
||||
toml::to_string(&unlink_attrs(&theme, k)).unwrap(),
|
||||
)
|
||||
.chars(),
|
||||
);
|
||||
ret.push_str(&format!(
|
||||
"\"{}\" = {{ fg = {}, bg = {}, attrs = {} }}\n",
|
||||
k,
|
||||
toml::to_string(&unlink_fg(theme, &ColorField::Fg, k)).unwrap(),
|
||||
toml::to_string(&unlink_bg(theme, &ColorField::Bg, k)).unwrap(),
|
||||
toml::to_string(&unlink_attrs(theme, k)).unwrap(),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
for k in theme.keys() {
|
||||
ret.extend(
|
||||
format!(
|
||||
"\"{}\" = {{ fg = {}, bg = {}, attrs = {} }}\n",
|
||||
k,
|
||||
toml::to_string(&theme[k].fg).unwrap(),
|
||||
toml::to_string(&theme[k].bg).unwrap(),
|
||||
toml::to_string(&theme[k].attrs).unwrap(),
|
||||
)
|
||||
.chars(),
|
||||
);
|
||||
ret.push_str(&format!(
|
||||
"\"{}\" = {{ fg = {}, bg = {}, attrs = {} }}\n",
|
||||
k,
|
||||
toml::to_string(&theme[k].fg).unwrap(),
|
||||
toml::to_string(&theme[k].bg).unwrap(),
|
||||
toml::to_string(&theme[k].attrs).unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut ret = String::new();
|
||||
ret.extend(self.key_to_string("dark", true).chars());
|
||||
|
||||
ret.push_str("\n\n");
|
||||
ret.extend(self.key_to_string("light", true).chars());
|
||||
for name in self.other_themes.keys() {
|
||||
ret.push_str("\n\n");
|
||||
ret.extend(self.key_to_string(name, true).chars());
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Themes {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let mut ret = String::new();
|
||||
ret.push_str(&self.key_to_string("dark", true));
|
||||
|
||||
ret.push_str("\n\n");
|
||||
ret.push_str(&self.key_to_string("light", true));
|
||||
for name in self.other_themes.keys() {
|
||||
ret.push_str("\n\n");
|
||||
ret.push_str(&self.key_to_string(name, true));
|
||||
}
|
||||
write!(fmt, "{}", ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Themes {
|
||||
#[allow(clippy::needless_update)]
|
||||
fn default() -> Themes {
|
||||
let mut light = IndexMap::default();
|
||||
let mut dark = IndexMap::default();
|
||||
|
@ -1762,9 +1741,9 @@ impl Serialize for Themes {
|
|||
new_map.insert(
|
||||
k.clone(),
|
||||
ThemeAttribute {
|
||||
fg: unlink_fg(&t, &ColorField::Fg, k),
|
||||
bg: unlink_bg(&t, &ColorField::Bg, k),
|
||||
attrs: unlink_attrs(&t, k),
|
||||
fg: unlink_fg(t, &ColorField::Fg, k),
|
||||
bg: unlink_bg(t, &ColorField::Bg, k),
|
||||
attrs: unlink_attrs(t, k),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -1790,10 +1769,10 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
}
|
||||
fn is_cyclic_util<'a>(
|
||||
course: Course,
|
||||
k: &'a Cow<'static, str>,
|
||||
visited: &mut IndexMap<(&'a Cow<'static, str>, Course), bool>,
|
||||
stack: &mut IndexMap<(&'a Cow<'static, str>, Course), bool>,
|
||||
path: &mut SmallVec<[(&'a Cow<'static, str>, Course); 16]>,
|
||||
k: &'a str,
|
||||
visited: &mut IndexMap<(&'a str, Course), bool>,
|
||||
stack: &mut IndexMap<(&'a str, Course), bool>,
|
||||
path: &mut SmallVec<[(&'a str, Course); 16]>,
|
||||
theme: &'a Theme,
|
||||
) -> bool {
|
||||
if !visited[&(k, course)] {
|
||||
|
@ -1804,6 +1783,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
Course::Fg => match theme[k].fg {
|
||||
ThemeValue::Link(ref l, ColorField::LikeSelf)
|
||||
| ThemeValue::Link(ref l, ColorField::Fg) => {
|
||||
let l = l.as_ref();
|
||||
path.push((l, Course::Fg));
|
||||
if (!visited[&(l, Course::Fg)]
|
||||
&& is_cyclic_util(course, l, visited, stack, path, theme))
|
||||
|
@ -1814,6 +1794,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
path.pop();
|
||||
}
|
||||
ThemeValue::Link(ref l, ColorField::Bg) => {
|
||||
let l = l.as_ref();
|
||||
path.push((l, Course::Bg));
|
||||
if (!visited[&(l, Course::Bg)]
|
||||
&& is_cyclic_util(Course::Bg, l, visited, stack, path, theme))
|
||||
|
@ -1824,6 +1805,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
path.pop();
|
||||
}
|
||||
ThemeValue::Alias(ref ident) => {
|
||||
let ident = ident.as_ref();
|
||||
path.push((ident, Course::ColorAliasFg));
|
||||
if (!visited[&(ident, Course::ColorAliasFg)]
|
||||
&& is_cyclic_util(
|
||||
|
@ -1845,6 +1827,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
Course::Bg => match theme[k].bg {
|
||||
ThemeValue::Link(ref l, ColorField::LikeSelf)
|
||||
| ThemeValue::Link(ref l, ColorField::Bg) => {
|
||||
let l = l.as_ref();
|
||||
path.push((l, Course::Bg));
|
||||
if (!visited[&(l, Course::Bg)]
|
||||
&& is_cyclic_util(Course::Bg, l, visited, stack, path, theme))
|
||||
|
@ -1855,6 +1838,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
path.pop();
|
||||
}
|
||||
ThemeValue::Link(ref l, ColorField::Fg) => {
|
||||
let l = l.as_ref();
|
||||
path.push((l, Course::Fg));
|
||||
if (!visited[&(l, Course::Fg)]
|
||||
&& is_cyclic_util(Course::Fg, l, visited, stack, path, theme))
|
||||
|
@ -1865,6 +1849,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
path.pop();
|
||||
}
|
||||
ThemeValue::Alias(ref ident) => {
|
||||
let ident = ident.as_ref();
|
||||
path.push((ident, Course::ColorAliasBg));
|
||||
if (!visited[&(ident, Course::ColorAliasBg)]
|
||||
&& is_cyclic_util(
|
||||
|
@ -1885,6 +1870,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
},
|
||||
Course::Attrs => match theme[k].attrs {
|
||||
ThemeValue::Link(ref l, _) => {
|
||||
let l = l.as_ref();
|
||||
path.push((l, course));
|
||||
if (!visited[&(l, course)]
|
||||
&& is_cyclic_util(course, l, visited, stack, path, theme))
|
||||
|
@ -1895,6 +1881,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
path.pop();
|
||||
}
|
||||
ThemeValue::Alias(ref ident) => {
|
||||
let ident = ident.as_ref();
|
||||
path.push((ident, Course::AttrAlias));
|
||||
if (!visited[&(ident, Course::AttrAlias)]
|
||||
&& is_cyclic_util(
|
||||
|
@ -1915,6 +1902,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
},
|
||||
Course::ColorAliasFg | Course::ColorAliasBg => match &theme.color_aliases[k] {
|
||||
ThemeValue::Link(ref l, ref field) => {
|
||||
let l = l.as_ref();
|
||||
let course = match (course, field) {
|
||||
(Course::ColorAliasFg, ColorField::LikeSelf) => Course::Fg,
|
||||
(Course::ColorAliasBg, ColorField::LikeSelf) => Course::Bg,
|
||||
|
@ -1934,6 +1922,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
path.pop();
|
||||
}
|
||||
ThemeValue::Alias(ref ident) => {
|
||||
let ident = ident.as_ref();
|
||||
path.push((ident, course));
|
||||
if (!visited[&(ident, course)]
|
||||
&& is_cyclic_util(course, ident, visited, stack, path, theme))
|
||||
|
@ -1947,6 +1936,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
},
|
||||
Course::AttrAlias => match &theme.attr_aliases[k] {
|
||||
ThemeValue::Link(ref l, ()) => {
|
||||
let l = l.as_ref();
|
||||
path.push((l, Course::Attrs));
|
||||
if (!visited[&(l, Course::Attrs)]
|
||||
&& is_cyclic_util(Course::Attrs, l, visited, stack, path, theme))
|
||||
|
@ -1957,6 +1947,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
path.pop();
|
||||
}
|
||||
ThemeValue::Alias(ref ident) => {
|
||||
let ident = ident.as_ref();
|
||||
path.push((ident, course));
|
||||
if (!visited[&(ident, course)]
|
||||
&& is_cyclic_util(course, ident, visited, stack, path, theme))
|
||||
|
@ -1977,35 +1968,28 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
let mut path = SmallVec::new();
|
||||
let mut visited = theme
|
||||
.keys()
|
||||
.map(|k| {
|
||||
std::iter::once(((k, Course::Fg), false))
|
||||
.chain(std::iter::once(((k, Course::Bg), false)))
|
||||
.chain(std::iter::once(((k, Course::Attrs), false)))
|
||||
.flat_map(|k| {
|
||||
std::iter::once(((k.as_ref(), Course::Fg), false))
|
||||
.chain(std::iter::once(((k.as_ref(), Course::Bg), false)))
|
||||
.chain(std::iter::once(((k.as_ref(), Course::Attrs), false)))
|
||||
})
|
||||
.flatten()
|
||||
.chain(
|
||||
theme
|
||||
.color_aliases
|
||||
.keys()
|
||||
.map(|k| {
|
||||
std::iter::once(((k, Course::ColorAliasFg), false))
|
||||
.chain(std::iter::once(((k, Course::ColorAliasBg), false)))
|
||||
})
|
||||
.flatten(),
|
||||
)
|
||||
.chain(theme.color_aliases.keys().flat_map(|k| {
|
||||
std::iter::once(((k.as_ref(), Course::ColorAliasFg), false))
|
||||
.chain(std::iter::once(((k.as_ref(), Course::ColorAliasBg), false)))
|
||||
}))
|
||||
.chain(
|
||||
theme
|
||||
.attr_aliases
|
||||
.keys()
|
||||
.map(|k| ((k, Course::AttrAlias), false)),
|
||||
.map(|k| ((k.as_ref(), Course::AttrAlias), false)),
|
||||
)
|
||||
.collect::<IndexMap<(&Cow<'static, str>, Course), bool>>();
|
||||
.collect::<IndexMap<(&str, Course), bool>>();
|
||||
|
||||
let mut stack = visited.clone();
|
||||
for k in theme.keys() {
|
||||
for &course in [Course::Fg, Course::Bg, Course::Attrs].iter() {
|
||||
path.push((k, course));
|
||||
if is_cyclic_util(course, k, &mut visited, &mut stack, &mut path, &theme) {
|
||||
path.push((k.as_ref(), course));
|
||||
if is_cyclic_util(course, k, &mut visited, &mut stack, &mut path, theme) {
|
||||
let path = path
|
||||
.into_iter()
|
||||
.map(|(k, c)| match c {
|
||||
|
@ -2037,7 +2021,7 @@ fn is_cyclic(theme: &Theme) -> std::result::Result<(), String> {
|
|||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -96,6 +96,7 @@ impl MailcapEntry {
|
|||
//let flags = parts_iter.next().unwrap();
|
||||
if key.starts_with(&content_type) || key.matches_glob(&content_type) {
|
||||
let mut copiousoutput = false;
|
||||
#[allow(clippy::while_let_on_iterator)]
|
||||
while let Some(flag) = parts_iter.next() {
|
||||
if flag.trim() == "copiousoutput" {
|
||||
copiousoutput = true;
|
||||
|
@ -118,6 +119,7 @@ impl MailcapEntry {
|
|||
//let flags = parts_iter.next().unwrap();
|
||||
if key.starts_with(&content_type) || key.matches_glob(&content_type) {
|
||||
let mut copiousoutput = false;
|
||||
#[allow(clippy::while_let_on_iterator)]
|
||||
while let Some(flag) = parts_iter.next() {
|
||||
if flag.trim() == "copiousoutput" {
|
||||
copiousoutput = true;
|
||||
|
@ -178,7 +180,7 @@ impl MailcapEntry {
|
|||
.collect::<Vec<String>>();
|
||||
let cmd_string = format!("{} {}", cmd, args.join(" "));
|
||||
melib::log(
|
||||
format!("Executing: sh -c \"{}\"", cmd_string.replace("\"", "\\\"")),
|
||||
format!("Executing: sh -c \"{}\"", cmd_string.replace('"', "\\\"")),
|
||||
melib::DEBUG,
|
||||
);
|
||||
if copiousoutput {
|
||||
|
@ -212,25 +214,23 @@ impl MailcapEntry {
|
|||
.spawn()?;
|
||||
pager.stdin.as_mut().unwrap().write_all(&out)?;
|
||||
debug!(pager.wait_with_output()?.stdout);
|
||||
} else if needs_stdin {
|
||||
let mut child = Command::new("sh")
|
||||
.args(&["-c", &cmd_string])
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::inherit())
|
||||
.spawn()?;
|
||||
|
||||
child.stdin.as_mut().unwrap().write_all(&decode(a, None))?;
|
||||
debug!(child.wait_with_output()?.stdout);
|
||||
} else {
|
||||
if needs_stdin {
|
||||
let mut child = Command::new("sh")
|
||||
.args(&["-c", &cmd_string])
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::inherit())
|
||||
.spawn()?;
|
||||
let child = Command::new("sh")
|
||||
.args(&["-c", &cmd_string])
|
||||
.stdin(Stdio::inherit())
|
||||
.stdout(Stdio::inherit())
|
||||
.spawn()?;
|
||||
|
||||
child.stdin.as_mut().unwrap().write_all(&decode(a, None))?;
|
||||
debug!(child.wait_with_output()?.stdout);
|
||||
} else {
|
||||
let child = Command::new("sh")
|
||||
.args(&["-c", &cmd_string])
|
||||
.stdin(Stdio::inherit())
|
||||
.stdout(Stdio::inherit())
|
||||
.spawn()?;
|
||||
|
||||
debug!(child.wait_with_output()?.stdout);
|
||||
}
|
||||
debug!(child.wait_with_output()?.stdout);
|
||||
}
|
||||
context.replies.push_back(UIEvent::Fork(ForkType::Finished));
|
||||
Ok(())
|
||||
|
|
|
@ -168,14 +168,14 @@ pub async fn insert(
|
|||
format!(
|
||||
"Failed to open envelope {}: {}",
|
||||
envelope.message_id_display(),
|
||||
err.to_string()
|
||||
err
|
||||
)
|
||||
);
|
||||
log(
|
||||
format!(
|
||||
"Failed to open envelope {}: {}",
|
||||
envelope.message_id_display(),
|
||||
err.to_string()
|
||||
err
|
||||
),
|
||||
ERROR,
|
||||
);
|
||||
|
@ -190,13 +190,13 @@ pub async fn insert(
|
|||
debug!(
|
||||
"Failed to insert envelope {}: {}",
|
||||
envelope.message_id_display(),
|
||||
err.to_string()
|
||||
err
|
||||
);
|
||||
log(
|
||||
format!(
|
||||
"Failed to insert envelope {}: {}",
|
||||
envelope.message_id_display(),
|
||||
err.to_string()
|
||||
err
|
||||
),
|
||||
ERROR,
|
||||
);
|
||||
|
@ -217,19 +217,19 @@ pub async fn insert(
|
|||
if let Err(err) = conn.execute(
|
||||
"INSERT OR REPLACE INTO envelopes (account_id, hash, date, _from, _to, cc, bcc, subject, message_id, in_reply_to, _references, flags, has_attachments, body_text, timestamp)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)",
|
||||
params![account_id, envelope.hash().to_be_bytes().to_vec(), envelope.date_as_str(), envelope.field_from_to_string(), envelope.field_to_to_string(), envelope.field_cc_to_string(), envelope.field_bcc_to_string(), envelope.subject().into_owned().trim_end_matches('\u{0}'), envelope.message_id_display().to_string(), envelope.in_reply_to_display().map(|f| f.to_string()).unwrap_or(String::new()), envelope.field_references_to_string(), i64::from(envelope.flags().bits()), if envelope.has_attachments() { 1 } else { 0 }, body, envelope.date().to_be_bytes().to_vec()],
|
||||
params![account_id, envelope.hash().to_be_bytes().to_vec(), envelope.date_as_str(), envelope.field_from_to_string(), envelope.field_to_to_string(), envelope.field_cc_to_string(), envelope.field_bcc_to_string(), envelope.subject().into_owned().trim_end_matches('\u{0}'), envelope.message_id_display().to_string(), envelope.in_reply_to_display().map(|f| f.to_string()).unwrap_or_default(), envelope.field_references_to_string(), i64::from(envelope.flags().bits()), if envelope.has_attachments() { 1 } else { 0 }, body, envelope.date().to_be_bytes().to_vec()],
|
||||
)
|
||||
.map_err(|e| MeliError::new(e.to_string())) {
|
||||
debug!(
|
||||
"Failed to insert envelope {}: {}",
|
||||
envelope.message_id_display(),
|
||||
err.to_string()
|
||||
err
|
||||
);
|
||||
log(
|
||||
format!(
|
||||
"Failed to insert envelope {}: {}",
|
||||
envelope.message_id_display(),
|
||||
err.to_string()
|
||||
err
|
||||
),
|
||||
ERROR,
|
||||
);
|
||||
|
@ -253,17 +253,9 @@ pub fn remove(env_hash: EnvelopeHash) -> Result<()> {
|
|||
)
|
||||
.map_err(|e| MeliError::new(e.to_string()))
|
||||
{
|
||||
debug!(
|
||||
"Failed to remove envelope {}: {}",
|
||||
env_hash,
|
||||
err.to_string()
|
||||
);
|
||||
debug!("Failed to remove envelope {}: {}", env_hash, err);
|
||||
log(
|
||||
format!(
|
||||
"Failed to remove envelope {}: {}",
|
||||
env_hash,
|
||||
err.to_string()
|
||||
),
|
||||
format!("Failed to remove envelope {}: {}", env_hash, err),
|
||||
ERROR,
|
||||
);
|
||||
return Err(err);
|
||||
|
@ -324,11 +316,11 @@ pub fn index(context: &mut crate::state::Context, account_index: usize) -> Resul
|
|||
.await
|
||||
.chain_err_summary(|| format!("Failed to open envelope {}", env_hash))?;
|
||||
let envelopes_lck = acc_mutex.read().unwrap();
|
||||
if let Some(e) = envelopes_lck.get(&env_hash) {
|
||||
if let Some(e) = envelopes_lck.get(env_hash) {
|
||||
let body = e.body_bytes(&bytes).text().replace('\0', "");
|
||||
conn.execute("INSERT OR REPLACE INTO envelopes (account_id, hash, date, _from, _to, cc, bcc, subject, message_id, in_reply_to, _references, flags, has_attachments, body_text, timestamp)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)",
|
||||
params![account_id, e.hash().to_be_bytes().to_vec(), e.date_as_str(), e.field_from_to_string(), e.field_to_to_string(), e.field_cc_to_string(), e.field_bcc_to_string(), e.subject().into_owned().trim_end_matches('\u{0}'), e.message_id_display().to_string(), e.in_reply_to_display().map(|f| f.to_string()).unwrap_or(String::new()), e.field_references_to_string(), i64::from(e.flags().bits()), if e.has_attachments() { 1 } else { 0 }, body, e.date().to_be_bytes().to_vec()],
|
||||
params![account_id, e.hash().to_be_bytes().to_vec(), e.date_as_str(), e.field_from_to_string(), e.field_to_to_string(), e.field_cc_to_string(), e.field_bcc_to_string(), e.subject().into_owned().trim_end_matches('\u{0}'), e.message_id_display().to_string(), e.in_reply_to_display().map(|f| f.to_string()).unwrap_or_default(), e.field_references_to_string(), i64::from(e.flags().bits()), if e.has_attachments() { 1 } else { 0 }, body, e.date().to_be_bytes().to_vec()],
|
||||
).chain_err_summary(|| format!( "Failed to insert envelope {}", e.message_id_display()))?;
|
||||
}
|
||||
}
|
||||
|
@ -366,7 +358,7 @@ pub fn search(
|
|||
.prepare(
|
||||
debug!(format!(
|
||||
"SELECT hash FROM envelopes WHERE {} ORDER BY {} {};",
|
||||
query_to_sql(&query),
|
||||
query_to_sql(query),
|
||||
sort_field,
|
||||
sort_order
|
||||
))
|
||||
|
@ -375,7 +367,7 @@ pub fn search(
|
|||
.map_err(|e| MeliError::new(e.to_string()))?;
|
||||
|
||||
let results = stmt
|
||||
.query_map([], |row| Ok(row.get(0)?))
|
||||
.query_map([], |row| row.get(0))
|
||||
.map_err(|e| MeliError::new(e.to_string()))?
|
||||
.map(|r: std::result::Result<Vec<u8>, rusqlite::Error>| {
|
||||
Ok(u64::from_be_bytes(
|
||||
|
@ -424,14 +416,14 @@ pub fn query_to_sql(q: &Query) -> String {
|
|||
s.push_str("%\" ");
|
||||
}
|
||||
And(q1, q2) => {
|
||||
s.push_str("(");
|
||||
s.push('(');
|
||||
rec(q1, s);
|
||||
s.push_str(") AND (");
|
||||
rec(q2, s);
|
||||
s.push_str(") ");
|
||||
}
|
||||
Or(q1, q2) => {
|
||||
s.push_str("(");
|
||||
s.push('(');
|
||||
rec(q1, s);
|
||||
s.push_str(") OR (");
|
||||
rec(q2, s);
|
||||
|
@ -445,7 +437,7 @@ pub fn query_to_sql(q: &Query) -> String {
|
|||
Flags(v) => {
|
||||
let total = v.len();
|
||||
if total > 1 {
|
||||
s.push_str("(");
|
||||
s.push('(');
|
||||
}
|
||||
for (i, f) in v.iter().enumerate() {
|
||||
match f.as_str() {
|
||||
|
|
73
src/state.rs
73
src/state.rs
|
@ -134,20 +134,18 @@ impl Context {
|
|||
} = self;
|
||||
let was_online = accounts[account_pos].is_online.is_ok();
|
||||
let ret = accounts[account_pos].is_online();
|
||||
if ret.is_ok() {
|
||||
if !was_online {
|
||||
debug!("inserting mailbox hashes:");
|
||||
for mailbox_node in accounts[account_pos].list_mailboxes() {
|
||||
debug!(
|
||||
"hash & mailbox: {:?} {}",
|
||||
mailbox_node.hash,
|
||||
accounts[account_pos][&mailbox_node.hash].name()
|
||||
);
|
||||
}
|
||||
accounts[account_pos].watch();
|
||||
|
||||
replies.push_back(UIEvent::AccountStatusChange(accounts[account_pos].hash()));
|
||||
if ret.is_ok() && !was_online {
|
||||
debug!("inserting mailbox hashes:");
|
||||
for mailbox_node in accounts[account_pos].list_mailboxes() {
|
||||
debug!(
|
||||
"hash & mailbox: {:?} {}",
|
||||
mailbox_node.hash,
|
||||
accounts[account_pos][&mailbox_node.hash].name()
|
||||
);
|
||||
}
|
||||
accounts[account_pos].watch();
|
||||
|
||||
replies.push_back(UIEvent::AccountStatusChange(accounts[account_pos].hash()));
|
||||
}
|
||||
if ret.is_ok() != was_online {
|
||||
replies.push_back(UIEvent::AccountStatusChange(accounts[account_pos].hash()));
|
||||
|
@ -331,7 +329,7 @@ impl State {
|
|||
display_messages_area: ((0, 0), (0, 0)),
|
||||
context: Context {
|
||||
accounts,
|
||||
settings: settings,
|
||||
settings,
|
||||
dirty_areas: VecDeque::with_capacity(5),
|
||||
replies: VecDeque::with_capacity(5),
|
||||
temp_files: Vec::new(),
|
||||
|
@ -399,10 +397,8 @@ impl State {
|
|||
}
|
||||
self.rcv_event(notification);
|
||||
}
|
||||
} else {
|
||||
if let melib::backends::RefreshEventKind::Failure(err) = event.kind {
|
||||
debug!(err);
|
||||
}
|
||||
} else if let melib::backends::RefreshEventKind::Failure(err) = event.kind {
|
||||
debug!(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -850,7 +846,7 @@ impl State {
|
|||
));
|
||||
}
|
||||
AccountAction(ref account_name, PrintAccountSetting(ref setting)) => {
|
||||
let path = setting.split(".").collect::<SmallVec<[&str; 16]>>();
|
||||
let path = setting.split('.').collect::<SmallVec<[&str; 16]>>();
|
||||
if let Some(pos) = self
|
||||
.context
|
||||
.accounts
|
||||
|
@ -858,13 +854,12 @@ impl State {
|
|||
.position(|(_h, a)| a.name() == account_name)
|
||||
{
|
||||
self.context.replies.push_back(UIEvent::StatusEvent(
|
||||
StatusEvent::UpdateStatus(format!(
|
||||
"{}",
|
||||
StatusEvent::UpdateStatus(
|
||||
self.context.accounts[pos]
|
||||
.settings
|
||||
.lookup("settings", &path)
|
||||
.unwrap_or_else(|err| err.to_string())
|
||||
)),
|
||||
.unwrap_or_else(|err| err.to_string()),
|
||||
),
|
||||
));
|
||||
} else {
|
||||
self.context.replies.push_back(UIEvent::Notification(
|
||||
|
@ -872,20 +867,18 @@ impl State {
|
|||
format!("Account {} was not found.", account_name),
|
||||
Some(NotificationType::Error(ErrorKind::None)),
|
||||
));
|
||||
return;
|
||||
}
|
||||
}
|
||||
PrintSetting(ref setting) => {
|
||||
let path = setting.split(".").collect::<SmallVec<[&str; 16]>>();
|
||||
let path = setting.split('.').collect::<SmallVec<[&str; 16]>>();
|
||||
self.context
|
||||
.replies
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(format!(
|
||||
"{}",
|
||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||
self.context
|
||||
.settings
|
||||
.lookup("settings", &path)
|
||||
.unwrap_or_else(|err| err.to_string())
|
||||
))));
|
||||
.unwrap_or_else(|err| err.to_string()),
|
||||
)));
|
||||
}
|
||||
ToggleMouse => {
|
||||
self.screen.mouse = !self.screen.mouse;
|
||||
|
@ -920,7 +913,7 @@ impl State {
|
|||
match event {
|
||||
// Command type is handled only by State.
|
||||
UIEvent::Command(cmd) => {
|
||||
if let Ok(action) = parse_command(&cmd.as_bytes()) {
|
||||
if let Ok(action) = parse_command(cmd.as_bytes()) {
|
||||
if action.needs_confirmation() {
|
||||
self.overlay.push(Box::new(UIConfirmationDialog::new(
|
||||
"You sure?",
|
||||
|
@ -932,7 +925,7 @@ impl State {
|
|||
Box::new(if result { Some(action) } else { None }),
|
||||
))
|
||||
})),
|
||||
&mut self.context,
|
||||
&self.context,
|
||||
)));
|
||||
} else if let Action::ReloadConfiguration = action {
|
||||
match Settings::new().and_then(|new_settings| {
|
||||
|
@ -952,7 +945,7 @@ impl State {
|
|||
Ok(new_settings)
|
||||
}) {
|
||||
Ok(new_settings) => {
|
||||
let old_settings = std::mem::replace(&mut self.context.settings, new_settings);
|
||||
let old_settings = Box::new(std::mem::replace(&mut self.context.settings, new_settings));
|
||||
self.context.replies.push_back(UIEvent::ConfigReload {
|
||||
old_settings
|
||||
});
|
||||
|
@ -1130,11 +1123,8 @@ impl State {
|
|||
match w {
|
||||
Ok(Some(_)) => true,
|
||||
Ok(None) => false,
|
||||
Err(e) => {
|
||||
log(
|
||||
format!("Failed to wait on editor process: {}", e.to_string()),
|
||||
ERROR,
|
||||
);
|
||||
Err(err) => {
|
||||
log(format!("Failed to wait on editor process: {}", err), ERROR);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
@ -1144,11 +1134,8 @@ impl State {
|
|||
match w {
|
||||
Ok(Some(_)) => true,
|
||||
Ok(None) => false,
|
||||
Err(e) => {
|
||||
log(
|
||||
format!("Failed to wait on child process: {}", e.to_string()),
|
||||
ERROR,
|
||||
);
|
||||
Err(err) => {
|
||||
log(format!("Failed to wait on child process: {}", err), ERROR);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
@ -1174,7 +1161,7 @@ impl State {
|
|||
}
|
||||
|
||||
pub fn switch_to_alternate_screen(&mut self) {
|
||||
self.screen.switch_to_alternate_screen(&mut self.context);
|
||||
self.screen.switch_to_alternate_screen(&self.context);
|
||||
}
|
||||
|
||||
fn flush(&mut self) {
|
||||
|
|
|
@ -151,7 +151,7 @@ impl CellBuffer {
|
|||
pub fn resize(&mut self, newcols: usize, newrows: usize, blank: Option<Cell>) -> bool {
|
||||
let newlen = newcols * newrows;
|
||||
if (self.cols, self.rows) == (newcols, newrows) || newlen >= Self::MAX_SIZE {
|
||||
return !(newlen >= Self::MAX_SIZE);
|
||||
return newlen < Self::MAX_SIZE;
|
||||
}
|
||||
|
||||
let blank = blank.unwrap_or(self.default_cell);
|
||||
|
@ -432,10 +432,10 @@ impl CellBuffer {
|
|||
pub fn set_tag(&mut self, tag: u64, start: (usize, usize), end: (usize, usize)) {
|
||||
let start = self
|
||||
.pos_to_index(start.0, start.1)
|
||||
.unwrap_or(self.buf.len().saturating_sub(1));
|
||||
.unwrap_or_else(|| self.buf.len().saturating_sub(1));
|
||||
let end = self
|
||||
.pos_to_index(end.0, end.1)
|
||||
.unwrap_or(self.buf.len().saturating_sub(1));
|
||||
.unwrap_or_else(|| self.buf.len().saturating_sub(1));
|
||||
if start != end {
|
||||
self.tag_associations.push((tag, (start, end)));
|
||||
}
|
||||
|
@ -856,9 +856,9 @@ impl Attr {
|
|||
"Blink" => Ok(Attr::BLINK),
|
||||
"Reverse" => Ok(Attr::REVERSE),
|
||||
"Hidden" => Ok(Attr::HIDDEN),
|
||||
combination if combination.contains("|") => {
|
||||
combination if combination.contains('|') => {
|
||||
let mut ret = Attr::DEFAULT;
|
||||
for c in combination.trim().split("|") {
|
||||
for c in combination.trim().split('|') {
|
||||
ret |= Self::from_string_de::<'de, D, &str>(c)?;
|
||||
}
|
||||
Ok(ret)
|
||||
|
@ -1725,7 +1725,7 @@ impl core::cmp::Ord for FormatTag {
|
|||
|
||||
impl core::cmp::PartialOrd for FormatTag {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||
Some(self.cmp(&other))
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -391,10 +391,12 @@ impl Color {
|
|||
"Yellow5" => 106,
|
||||
"Yellow6" => 148,
|
||||
"Default" => return Ok(Color::Default),
|
||||
s if s.starts_with("#")
|
||||
s if s.starts_with('#')
|
||||
&& s.len() == 7
|
||||
&& s[1..].as_bytes().iter().all(|&b| {
|
||||
(b >= b'0' && b <= b'9') || (b >= b'a' && b <= b'f') || (b >= b'A' && b <= b'F')
|
||||
(b'0'..=b'9').contains(&b)
|
||||
|| (b'a'..=b'f').contains(&b)
|
||||
|| (b'A'..=b'F').contains(&b)
|
||||
}) =>
|
||||
{
|
||||
return Ok(Color::Rgb(
|
||||
|
@ -406,10 +408,12 @@ impl Color {
|
|||
.map_err(|_| de::Error::custom("invalid `color` value"))?,
|
||||
))
|
||||
}
|
||||
s if s.starts_with("#")
|
||||
s if s.starts_with('#')
|
||||
&& s.len() == 4
|
||||
&& s[1..].as_bytes().iter().all(|&b| {
|
||||
(b >= b'0' && b <= b'9') || (b >= b'a' && b <= b'f') || (b >= b'A' && b <= b'F')
|
||||
(b'0'..=b'9').contains(&b)
|
||||
|| (b'a'..=b'f').contains(&b)
|
||||
|| (b'A'..=b'F').contains(&b)
|
||||
}) =>
|
||||
{
|
||||
return Ok(Color::Rgb(
|
||||
|
@ -421,7 +425,8 @@ impl Color {
|
|||
.map_err(|_| de::Error::custom("invalid `color` value"))?,
|
||||
))
|
||||
}
|
||||
_ => u8::from_str_radix(&s, 10)
|
||||
_ => s
|
||||
.parse::<u8>()
|
||||
.map_err(|_| de::Error::custom("invalid `color` value"))?,
|
||||
};
|
||||
Ok(Color::Byte(byte))
|
||||
|
|
|
@ -346,7 +346,7 @@ impl EmbedGrid {
|
|||
*state = State::CsiQ(buf1);
|
||||
}
|
||||
/* OSC stuff */
|
||||
(c, State::Osc1(ref mut buf)) if (c >= b'0' && c <= b'9') || c == b'?' => {
|
||||
(c, State::Osc1(ref mut buf)) if (b'0'..=b'9').contains(&c) || c == b'?' => {
|
||||
buf.push(c);
|
||||
}
|
||||
(b';', State::Osc1(ref mut buf1_p)) => {
|
||||
|
@ -354,7 +354,7 @@ impl EmbedGrid {
|
|||
let buf2 = SmallVec::new();
|
||||
*state = State::Osc2(buf1, buf2);
|
||||
}
|
||||
(c, State::Osc2(_, ref mut buf)) if (c >= b'0' && c <= b'9') || c == b'?' => {
|
||||
(c, State::Osc2(_, ref mut buf)) if (b'0'..=b'9').contains(&c) || c == b'?' => {
|
||||
buf.push(c);
|
||||
}
|
||||
/* Normal */
|
||||
|
@ -512,7 +512,7 @@ impl EmbedGrid {
|
|||
*state = State::Normal;
|
||||
}
|
||||
/* CSI ? stuff */
|
||||
(c, State::CsiQ(ref mut buf)) if c >= b'0' && c <= b'9' => {
|
||||
(c, State::CsiQ(ref mut buf)) if (b'0'..=b'9').contains(&c) => {
|
||||
buf.push(c);
|
||||
}
|
||||
(b'h', State::CsiQ(ref buf)) => {
|
||||
|
@ -569,7 +569,7 @@ impl EmbedGrid {
|
|||
*state = State::Normal;
|
||||
}
|
||||
/* END OF CSI ? stuff */
|
||||
(c, State::Csi) if c >= b'0' && c <= b'9' => {
|
||||
(c, State::Csi) if (b'0'..=b'9').contains(&c) => {
|
||||
let mut buf1 = SmallVec::new();
|
||||
buf1.push(c);
|
||||
*state = State::Csi1(buf1);
|
||||
|
@ -973,17 +973,9 @@ impl EmbedGrid {
|
|||
*bg_color = Color::Default;
|
||||
}
|
||||
b"1" => { /* bold */ }
|
||||
b"7" => {
|
||||
/* Inverse */
|
||||
let temp = *fg_color;
|
||||
*fg_color = *bg_color;
|
||||
*bg_color = temp;
|
||||
}
|
||||
b"27" => {
|
||||
/* Inverse off */
|
||||
let temp = *fg_color;
|
||||
*fg_color = *bg_color;
|
||||
*bg_color = temp;
|
||||
b"7" | b"27" => {
|
||||
/* Inverse on/off */
|
||||
std::mem::swap(&mut (*fg_color), &mut (*bg_color))
|
||||
}
|
||||
b"30" => *fg_color = Color::Black,
|
||||
b"31" => *fg_color = Color::Red,
|
||||
|
@ -1037,17 +1029,9 @@ impl EmbedGrid {
|
|||
*bg_color = Color::Default;
|
||||
}
|
||||
b"1" => { /* bold */ }
|
||||
b"7" => {
|
||||
/* Inverse */
|
||||
let temp = *fg_color;
|
||||
*fg_color = *bg_color;
|
||||
*bg_color = temp;
|
||||
}
|
||||
b"27" => {
|
||||
/* Inverse off */
|
||||
let temp = *fg_color;
|
||||
*fg_color = *bg_color;
|
||||
*bg_color = temp;
|
||||
b"7" | b"27" => {
|
||||
/* Inverse on/off */
|
||||
std::mem::swap(&mut (*fg_color), &mut (*bg_color))
|
||||
}
|
||||
b"30" => *fg_color = Color::Black,
|
||||
b"31" => *fg_color = Color::Red,
|
||||
|
@ -1094,7 +1078,7 @@ impl EmbedGrid {
|
|||
grid[cursor_val!()].set_bg(*bg_color);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(c, State::Csi1(ref mut buf)) if (c >= b'0' && c <= b'9') || c == b' ' => {
|
||||
(c, State::Csi1(ref mut buf)) if (b'0'..=b'9').contains(&c) || c == b' ' => {
|
||||
buf.push(c);
|
||||
}
|
||||
(b';', State::Csi2(ref mut buf1_p, ref mut buf2_p)) => {
|
||||
|
@ -1144,7 +1128,7 @@ impl EmbedGrid {
|
|||
//debug!("cursor became: {:?}", cursor);
|
||||
*state = State::Normal;
|
||||
}
|
||||
(c, State::Csi2(_, ref mut buf)) if c >= b'0' && c <= b'9' => {
|
||||
(c, State::Csi2(_, ref mut buf)) if (b'0'..=b'9').contains(&c) => {
|
||||
buf.push(c);
|
||||
}
|
||||
(b'r', State::Csi2(_, _)) | (b'r', State::Csi) => {
|
||||
|
@ -1177,7 +1161,7 @@ impl EmbedGrid {
|
|||
*state = State::Normal;
|
||||
}
|
||||
|
||||
(c, State::Csi3(_, _, ref mut buf)) if c >= b'0' && c <= b'9' => {
|
||||
(c, State::Csi3(_, _, ref mut buf)) if (b'0'..=b'9').contains(&c) => {
|
||||
buf.push(c);
|
||||
}
|
||||
(b'm', State::Csi3(ref buf1, ref buf2, ref buf3))
|
||||
|
@ -1185,7 +1169,7 @@ impl EmbedGrid {
|
|||
{
|
||||
/* Set character attributes | foreground color */
|
||||
*fg_color = if let Ok(byte) =
|
||||
u8::from_str_radix(unsafe { std::str::from_utf8_unchecked(buf3) }, 10)
|
||||
unsafe { std::str::from_utf8_unchecked(buf3) }.parse::<u8>()
|
||||
{
|
||||
//debug!("parsed buf as {}", byte);
|
||||
Color::Byte(byte)
|
||||
|
@ -1200,7 +1184,7 @@ impl EmbedGrid {
|
|||
{
|
||||
/* Set character attributes | background color */
|
||||
*bg_color = if let Ok(byte) =
|
||||
u8::from_str_radix(unsafe { std::str::from_utf8_unchecked(buf3) }, 10)
|
||||
unsafe { std::str::from_utf8_unchecked(buf3) }.parse::<u8>()
|
||||
{
|
||||
//debug!("parsed buf as {}", byte);
|
||||
Color::Byte(byte)
|
||||
|
@ -1246,3 +1230,9 @@ impl EmbedGrid {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EmbedGrid {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@ pub fn get_events(
|
|||
select! {
|
||||
default => {
|
||||
if stdin_fd.revents().is_some() {
|
||||
'stdin_while: while let Some(c) = stdin_iter.next(){
|
||||
'stdin_while: for c in stdin_iter.by_ref() {
|
||||
match (c, &mut input_mode) {
|
||||
(Ok((TermionEvent::Key(k), bytes)), InputMode::Normal) => {
|
||||
closure((Key::from(k), bytes));
|
||||
|
@ -192,7 +192,7 @@ pub fn get_events(
|
|||
Ok((TermionEvent::Key(TermionKey::Char(k)), ref mut bytes)), InputMode::Paste(ref mut buf),
|
||||
) => {
|
||||
paste_buf.push(k);
|
||||
let bytes = std::mem::replace(bytes, Vec::new());
|
||||
let bytes = std::mem::take(bytes);
|
||||
buf.extend(bytes.into_iter());
|
||||
continue 'stdin_while;
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ pub fn get_events(
|
|||
(Ok((TermionEvent::Unsupported(ref k), _)), InputMode::Paste(ref mut buf))
|
||||
if k.as_slice() == BRACKET_PASTE_END =>
|
||||
{
|
||||
let buf = std::mem::replace(buf, Vec::new());
|
||||
let buf = std::mem::take(buf);
|
||||
input_mode = InputMode::Normal;
|
||||
let ret = Key::from(&paste_buf);
|
||||
paste_buf.clear();
|
||||
|
@ -277,12 +277,12 @@ impl<'de> Deserialize<'de> for Key {
|
|||
"Enter" | "enter" => Ok(Key::Char('\n')),
|
||||
"Tab" | "tab" => Ok(Key::Char('\t')),
|
||||
"Esc" | "esc" => Ok(Key::Esc),
|
||||
ref s if s.len() == 1 => Ok(Key::Char(s.chars().nth(0).unwrap())),
|
||||
ref s if s.starts_with("F") && (s.len() == 2 || s.len() == 3) => {
|
||||
s if s.len() == 1 => Ok(Key::Char(s.chars().next().unwrap())),
|
||||
s if s.starts_with('F') && (s.len() == 2 || s.len() == 3) => {
|
||||
use std::str::FromStr;
|
||||
|
||||
if let Ok(n) = u8::from_str(&s[1..]) {
|
||||
if n >= 1 && n <= 12 {
|
||||
if (1..=12).contains(&n) {
|
||||
return Ok(Key::F(n));
|
||||
}
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ impl<'de> Deserialize<'de> for Key {
|
|||
&s[1..]
|
||||
)))
|
||||
}
|
||||
ref s if s.starts_with("M-") && s.len() == 3 => {
|
||||
s if s.starts_with("M-") && s.len() == 3 => {
|
||||
let c = s.as_bytes()[2] as char;
|
||||
|
||||
if c.is_lowercase() || c.is_numeric() {
|
||||
|
@ -303,7 +303,7 @@ impl<'de> Deserialize<'de> for Key {
|
|||
&s[2..]
|
||||
)))
|
||||
}
|
||||
ref s if s.starts_with("C-") && s.len() == 3 => {
|
||||
s if s.starts_with("C-") && s.len() == 3 => {
|
||||
let c = s.as_bytes()[2] as char;
|
||||
|
||||
if c.is_lowercase() || c.is_numeric() {
|
||||
|
|
|
@ -149,12 +149,12 @@ pub enum UIEvent {
|
|||
GlobalUIDialog(Box<dyn Component>),
|
||||
Timer(Uuid),
|
||||
ConfigReload {
|
||||
old_settings: crate::conf::Settings,
|
||||
old_settings: Box<crate::conf::Settings>,
|
||||
},
|
||||
VisibilityChange(bool),
|
||||
}
|
||||
|
||||
pub struct CallbackFn(pub Box<dyn FnOnce(&mut crate::Context) -> () + Send + 'static>);
|
||||
pub struct CallbackFn(pub Box<dyn FnOnce(&mut crate::Context) + Send + 'static>);
|
||||
|
||||
impl core::fmt::Debug for CallbackFn {
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
|
@ -322,8 +322,6 @@ pub struct RateLimit {
|
|||
last_tick: std::time::Instant,
|
||||
pub timer: crate::jobs::Timer,
|
||||
rate: std::time::Duration,
|
||||
reqs: u64,
|
||||
millis: std::time::Duration,
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
|
@ -336,8 +334,6 @@ impl RateLimit {
|
|||
std::time::Duration::from_millis(millis),
|
||||
),
|
||||
rate: std::time::Duration::from_millis(millis / reqs),
|
||||
reqs,
|
||||
millis: std::time::Duration::from_millis(millis),
|
||||
active: false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ pub struct File {
|
|||
impl Drop for File {
|
||||
fn drop(&mut self) {
|
||||
if self.delete_on_drop {
|
||||
std::fs::remove_file(self.path()).unwrap_or_else(|_| {});
|
||||
let _ = std::fs::remove_file(self.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ impl File {
|
|||
pub fn path(&self) -> &PathBuf {
|
||||
&self.path
|
||||
}
|
||||
|
||||
pub fn read_to_string(&self) -> String {
|
||||
let mut buf = Vec::new();
|
||||
let mut f = fs::File::open(&self.path)
|
||||
|
|
Loading…
Reference in New Issue