accounts: suggest tips on mailbox_by_path error

If Account::mailbox_by_path() fails, suggest matching mailbox paths
using aho_corasick case insensitive matching, and also suggest to the
user to inspect mailboxes with the manage-mailboxes command.

Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
This commit is contained in:
Manos Pitsidianakis 2024-11-24 12:01:29 +02:00
parent 0f09633899
commit a389772d96
No known key found for this signature in database
GPG key ID: 7729C7707F7E09D0
3 changed files with 49 additions and 1 deletions

1
Cargo.lock generated
View file

@ -1266,6 +1266,7 @@ dependencies = [
name = "meli"
version = "0.8.8"
dependencies = [
"aho-corasick",
"assert_cmd",
"async-task",
"bitflags 2.6.0",

View file

@ -23,6 +23,7 @@ name = "meli"
path = "src/lib.rs"
[dependencies]
aho-corasick = { version = "1.1.3" }
async-task = { version = "^4.2.0" }
bitflags = { version = "2.4", features = ["serde"] }
crossbeam = { version = "^0.8" }

View file

@ -1331,7 +1331,53 @@ impl Account {
{
Ok(*mailbox_hash)
} else {
Err(Error::new("Mailbox with that path not found."))
use aho_corasick::AhoCorasick;
let nodes = self
.list_mailboxes()
.into_iter()
.map(|n| (n.hash, n.depth))
.collect::<BTreeMap<MailboxHash, usize>>();
let mut entries = self
.mailbox_entries
.iter()
.map(|(h, f)| (h, f.ref_mailbox.path()))
.collect::<Vec<_>>();
entries.sort_by_cached_key(|(h, _)| nodes.get(h).cloned().unwrap_or(usize::MAX));
let patterns = &[path.trim_matches('/')];
let mut potential_matches = IndexSet::new();
for (_, haystack) in entries {
let ac = AhoCorasick::builder()
.ascii_case_insensitive(true)
.build(patterns)
.unwrap();
if ac.find_iter(haystack).next().is_some() {
potential_matches.insert(haystack.to_string());
}
}
const MANAGE_MAILBOXES_TIP: &str = "You can inspect the list of mailbox paths of an \
account with the manage-mailboxes command.";
let details_msg = if potential_matches.is_empty() {
Cow::Borrowed(MANAGE_MAILBOXES_TIP)
} else {
let mut potential_matches = potential_matches.into_iter().collect::<Vec<_>>();
let matches_length = potential_matches.len();
potential_matches.truncate(5);
Cow::Owned(format!(
"Some matching paths that were found: {matches:?}{others}. {tip}",
matches = potential_matches,
tip = MANAGE_MAILBOXES_TIP,
others = if matches_length > 5 {
format!(" and {} others", matches_length - 5)
} else {
String::with_capacity(0)
}
))
};
Err(Error::new("Mailbox with that path not found.")
.set_details(details_msg)
.set_kind(ErrorKind::NotFound))
}
}