Fix all clippy warnings in `meli` crate

pull/144/head
Manos Pitsidianakis 2022-08-25 15:17:18 +03:00
parent d921b3c320
commit 9cb66ef818
39 changed files with 688 additions and 881 deletions

View File

@ -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::*;
"##

View File

@ -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) => {

View File

@ -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()

View File

@ -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
}

View File

@ -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

View File

@ -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| {

View File

@ -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))
}
}

View File

@ -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,

View File

@ -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,

View File

@ -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();

View File

@ -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();

View File

@ -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(),
}
})
}
}

View File

@ -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);
}

View File

@ -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) {

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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())

View File

@ -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) {

View File

@ -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);

View File

@ -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")
}
}

View File

@ -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,

View File

@ -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);

View File

@ -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,

View File

@ -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))
}
}

View File

@ -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);
}
}

View File

@ -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)]

View File

@ -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() {

View File

@ -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>

View File

@ -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]

View File

@ -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(())

View File

@ -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() {

View File

@ -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) {

View File

@ -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))
}
}

View File

@ -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))

View File

@ -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()
}
}

View File

@ -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() {

View File

@ -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,
}
}

View File

@ -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)