diff --git a/build.rs b/build.rs index 7946d81b..22689188 100644 --- a/build.rs +++ b/build.rs @@ -37,14 +37,9 @@ fn main() { ]); #[cfg(feature = "cli-docs")] { - use flate2::Compression; - use flate2::GzBuilder; + use flate2::{Compression, GzBuilder}; const MANDOC_OPTS: &[&str] = &["-T", "utf8", "-I", "os=Generated by mandoc(1)"]; - use std::env; - use std::fs::File; - use std::io::prelude::*; - use std::path::Path; - use std::process::Command; + use std::{env, fs::File, io::prelude::*, path::Path, process::Command}; let out_dir = env::var("OUT_DIR").unwrap(); let mut out_dir_path = Path::new(&out_dir).to_path_buf(); @@ -57,7 +52,8 @@ fn main() { .output() .or_else(|_| Command::new("man").arg("-l").arg(filepath).output()) .expect( - "could not execute `mandoc` or `man`. If the binaries are not available in the PATH, disable `cli-docs` feature to be able to continue compilation.", + "could not execute `mandoc` or `man`. If the binaries are not available in \ + the PATH, disable `cli-docs` feature to be able to continue compilation.", ); let file = File::create(&out_dir_path).unwrap_or_else(|err| { diff --git a/config_macros.rs b/config_macros.rs index 1c8e40c3..ce0ea750 100644 --- a/config_macros.rs +++ b/config_macros.rs @@ -19,9 +19,11 @@ * along with meli. If not, see . */ -use std::fs::File; -use std::io::prelude::*; -use std::process::{Command, Stdio}; +use std::{ + fs::File, + io::prelude::*, + process::{Command, Stdio}, +}; use quote::{format_ident, quote}; @@ -29,7 +31,8 @@ use quote::{format_ident, quote}; pub fn override_derive(filenames: &[(&str, &str)]) { let mut output_file = File::create("src/conf/overrides.rs").expect("Unable to open output file"); - let mut output_string = r##"/* + let mut output_string = r##"// @generated +/* * meli - conf/overrides.rs * * Copyright 2020 Manos Pitsidianakis @@ -60,7 +63,7 @@ use super::*; 'file_loop: for (filename, ident) in filenames { println!("cargo:rerun-if-changed={}", filename); - let mut file = File::open(&filename) + let mut file = File::open(filename) .unwrap_or_else(|err| panic!("Unable to open file `{}` {}", filename, err)); let mut src = String::new(); diff --git a/melib/build.rs b/melib/build.rs index b6ddfcd6..659e6ebd 100644 --- a/melib/build.rs +++ b/melib/build.rs @@ -29,11 +29,12 @@ fn main() -> Result<(), std::io::Error> { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed={}", MOD_PATH); /* Line break tables */ - use std::fs::File; - use std::io::prelude::*; - use std::io::BufReader; - use std::path::Path; - use std::process::{Command, Stdio}; + use std::{ + fs::File, + io::{prelude::*, BufReader}, + path::Path, + process::{Command, Stdio}, + }; const LINE_BREAK_TABLE_URL: &str = "http://www.unicode.org/Public/UCD/latest/ucd/LineBreak.txt"; /* Grapheme width tables */ @@ -52,7 +53,7 @@ fn main() -> Result<(), std::io::Error> { std::process::exit(0); } let mut child = Command::new("curl") - .args(&["-o", "-", LINE_BREAK_TABLE_URL]) + .args(["-o", "-", LINE_BREAK_TABLE_URL]) .stdout(Stdio::piped()) .stdin(Stdio::null()) .stderr(Stdio::inherit()) @@ -69,7 +70,8 @@ fn main() -> Result<(), std::io::Error> { let tokens: &str = line.split_whitespace().next().unwrap(); let semicolon_idx: usize = tokens.chars().position(|c| c == ';').unwrap(); - /* LineBreak.txt list is ascii encoded so we can assume each char takes one byte: */ + /* LineBreak.txt list is ascii encoded so we can assume each char takes one + * byte: */ let chars_str: &str = &tokens[..semicolon_idx]; let mut codepoint_iter = chars_str.split(".."); @@ -87,21 +89,21 @@ fn main() -> Result<(), std::io::Error> { child.wait()?; let child = Command::new("curl") - .args(&["-o", "-", UNICODE_DATA_URL]) + .args(["-o", "-", UNICODE_DATA_URL]) .stdout(Stdio::piped()) .output()?; let unicode_data = String::from_utf8_lossy(&child.stdout); let child = Command::new("curl") - .args(&["-o", "-", EAW_URL]) + .args(["-o", "-", EAW_URL]) .stdout(Stdio::piped()) .output()?; let eaw_data = String::from_utf8_lossy(&child.stdout); let child = Command::new("curl") - .args(&["-o", "-", EMOJI_DATA_URL]) + .args(["-o", "-", EMOJI_DATA_URL]) .stdout(Stdio::piped()) .output()?; @@ -198,13 +200,13 @@ fn main() -> Result<(), std::io::Error> { } // Apply the following special cases: // - The unassigned code points in the following blocks default to "W": - // CJK Unified Ideographs Extension A: U+3400..U+4DBF - // CJK Unified Ideographs: U+4E00..U+9FFF - // CJK Compatibility Ideographs: U+F900..U+FAFF - // - All undesignated code points in Planes 2 and 3, whether inside or - // outside of allocated blocks, default to "W": - // Plane 2: U+20000..U+2FFFD - // Plane 3: U+30000..U+3FFFD + // - CJK Unified Ideographs Extension A: U+3400..U+4DBF + // - CJK Unified Ideographs: U+4E00..U+9FFF + // - CJK Compatibility Ideographs: U+F900..U+FAFF + // - All undesignated code points in Planes 2 and 3, whether inside or outside + // of allocated blocks, default to "W": + // - Plane 2: U+20000..U+2FFFD + // - Plane 3: U+30000..U+3FFFD const WIDE_RANGES: [(usize, usize); 5] = [ (0x3400, 0x4DBF), (0x4E00, 0x9FFF), @@ -245,12 +247,12 @@ fn main() -> Result<(), std::io::Error> { } use std::str::FromStr; - let mut v = comment.trim().split_whitespace().next().unwrap(); + let mut v = comment.split_whitespace().next().unwrap(); if v.starts_with('E') { v = &v[1..]; } if v.as_bytes() - .get(0) + .first() .map(|c| !c.is_ascii_digit()) .unwrap_or(true) { @@ -325,7 +327,7 @@ fn main() -> Result<(), std::io::Error> { } } - let mut file = File::create(&mod_path)?; + let mut file = File::create(mod_path)?; file.write_all( br#"/* * meli - text_processing crate. diff --git a/melib/src/addressbook.rs b/melib/src/addressbook.rs index 42867d08..64374e60 100644 --- a/melib/src/addressbook.rs +++ b/melib/src/addressbook.rs @@ -24,12 +24,14 @@ pub mod vcard; pub mod mutt; -use crate::datetime::{self, UnixTimestamp}; -use crate::parsec::Parser; -use std::collections::HashMap; +use std::{collections::HashMap, ops::Deref}; + use uuid::Uuid; -use std::ops::Deref; +use crate::{ + datetime::{self, UnixTimestamp}, + parsec::Parser, +}; #[derive(Hash, Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)] #[serde(from = "String")] @@ -85,7 +87,8 @@ pub struct Card { last_edited: UnixTimestamp, extra_properties: HashMap, - /// If true, we can't make any changes because we do not manage this resource. + /// If true, we can't make any changes because we do not manage this + /// resource. external_resource: bool, } diff --git a/melib/src/addressbook/mutt.rs b/melib/src/addressbook/mutt.rs index 805c3546..59cb4ff3 100644 --- a/melib/src/addressbook/mutt.rs +++ b/melib/src/addressbook/mutt.rs @@ -20,11 +20,11 @@ */ //! # Mutt contact formats -//! + +use std::collections::VecDeque; use super::*; use crate::parsec::{is_not, map_res, match_literal_anycase, prefix, Parser}; -use std::collections::VecDeque; //alias [ ]
// From mutt doc: diff --git a/melib/src/addressbook/vcard.rs b/melib/src/addressbook/vcard.rs index 2556b6d9..90c19a2f 100644 --- a/melib/src/addressbook/vcard.rs +++ b/melib/src/addressbook/vcard.rs @@ -27,11 +27,13 @@ //! - Version 4 [RFC 6350: vCard Format Specification](https://datatracker.ietf.org/doc/rfc6350/) //! - Parameter escaping [RFC 6868 Parameter Value Encoding in iCalendar and vCard](https://datatracker.ietf.org/doc/rfc6868/) +use std::{collections::HashMap, convert::TryInto}; + use super::*; -use crate::error::{Error, Result}; -use crate::parsec::{match_literal_anycase, one_or_more, peek, prefix, take_until, Parser}; -use std::collections::HashMap; -use std::convert::TryInto; +use crate::{ + error::{Error, Result}, + parsec::{match_literal_anycase, one_or_more, peek, prefix, take_until, Parser}, +}; /* Supported vcard versions */ pub trait VCardVersion: core::fmt::Debug {} @@ -86,7 +88,11 @@ impl CardDeserializer { input = if (!input.starts_with(HEADER_CRLF) || !input.ends_with(FOOTER_CRLF)) && (!input.starts_with(HEADER_LF) || !input.ends_with(FOOTER_LF)) { - return Err(Error::new(format!("Error while parsing vcard: input does not start or end with correct header and footer. input is:\n{:?}", input))); + return Err(Error::new(format!( + "Error while parsing vcard: input does not start or end with correct header and \ + footer. input is:\n{:?}", + input + ))); } else if input.starts_with(HEADER_CRLF) { &input[HEADER_CRLF.len()..input.len() - FOOTER_CRLF.len()] } else { diff --git a/melib/src/backends.rs b/melib/src/backends.rs index be7e8c87..dde57ed2 100644 --- a/melib/src/backends.rs +++ b/melib/src/backends.rs @@ -36,35 +36,41 @@ pub mod jmap; pub mod maildir; #[cfg(feature = "mbox_backend")] pub mod mbox; +use std::{ + any::Any, + borrow::Cow, + collections::{BTreeSet, HashMap}, + fmt, + fmt::Debug, + future::Future, + ops::Deref, + pin::Pin, + sync::{Arc, RwLock}, +}; + +use futures::stream::Stream; + #[cfg(feature = "imap_backend")] pub use self::imap::ImapType; -#[cfg(feature = "imap_backend")] -pub use self::nntp::NntpType; -use crate::conf::AccountSettings; -use crate::error::{Error, ErrorKind, Result}; - #[cfg(feature = "maildir_backend")] use self::maildir::MaildirType; #[cfg(feature = "mbox_backend")] use self::mbox::MboxType; +#[cfg(feature = "imap_backend")] +pub use self::nntp::NntpType; use super::email::{Envelope, EnvelopeHash, Flag}; -use futures::stream::Stream; -use std::any::Any; -use std::borrow::Cow; -use std::collections::BTreeSet; -use std::collections::HashMap; -use std::fmt; -use std::fmt::Debug; -use std::future::Future; -use std::ops::Deref; -use std::pin::Pin; -use std::sync::{Arc, RwLock}; +use crate::{ + conf::AccountSettings, + error::{Error, ErrorKind, Result}, +}; #[macro_export] macro_rules! get_path_hash { ($path:expr) => {{ - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; + use std::{ + collections::hash_map::DefaultHasher, + hash::{Hash, Hasher}, + }; let mut hasher = DefaultHasher::new(); $path.hash(&mut hasher); hasher.finish() @@ -97,10 +103,13 @@ impl Default for Backends { } #[cfg(feature = "notmuch_backend")] -pub const NOTMUCH_ERROR_MSG: &str = - "libnotmuch5 was not found in your system. Make sure it is installed and in the library paths. For a custom file path, use `library_file_path` setting in your notmuch account.\n"; +pub const NOTMUCH_ERROR_MSG: &str = "libnotmuch5 was not found in your system. Make sure it is \ + installed and in the library paths. For a custom file path, \ + use `library_file_path` setting in your notmuch account.\n"; #[cfg(not(feature = "notmuch_backend"))] -pub const NOTMUCH_ERROR_MSG: &str = "this version of meli is not compiled with notmuch support. Use an appropriate version and make sure libnotmuch5 is installed and in the library paths.\n"; +pub const NOTMUCH_ERROR_MSG: &str = "this version of meli is not compiled with notmuch support. \ + Use an appropriate version and make sure libnotmuch5 is \ + installed and in the library paths.\n"; #[cfg(not(feature = "notmuch_backend"))] pub const NOTMUCH_ERROR_DETAILS: &str = ""; @@ -432,13 +441,14 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync { } } -/// A `BackendOp` manages common operations for the various mail backends. They only live for the -/// duration of the operation. They are generated by the `operation` method of `Mailbackend` trait. +/// A `BackendOp` manages common operations for the various mail backends. They +/// only live for the duration of the operation. They are generated by the +/// `operation` method of `Mailbackend` trait. /// /// # Motivation /// -/// We need a way to do various operations on individual mails regardless of what backend they come -/// from (eg local or imap). +/// We need a way to do various operations on individual mails regardless of +/// what backend they come from (eg local or imap). /// /// # Creation /// ```ignore @@ -474,8 +484,8 @@ pub trait BackendOp: ::std::fmt::Debug + ::std::marker::Send { /// Wrapper for BackendOps that are to be set read-only. /// -/// Warning: Backend implementations may still cause side-effects (for example IMAP can set the -/// Seen flag when fetching an envelope) +/// Warning: Backend implementations may still cause side-effects (for example +/// IMAP can set the Seen flag when fetching an envelope) #[derive(Debug)] pub struct ReadOnlyOp { op: Box, diff --git a/melib/src/backends/imap.rs b/melib/src/backends/imap.rs index b9879638..b356f4b4 100644 --- a/melib/src/backends/imap.rs +++ b/melib/src/backends/imap.rs @@ -36,26 +36,29 @@ use cache::{ImapCacheReset, ModSequence}; pub mod managesieve; mod untagged; -use crate::backends::{ - RefreshEventKind::{self, *}, - *, +use std::{ + collections::{hash_map::DefaultHasher, BTreeSet, HashMap, HashSet}, + convert::TryFrom, + hash::Hasher, + pin::Pin, + str::FromStr, + sync::{Arc, Mutex}, + time::{Duration, SystemTime}, }; -use crate::collection::Collection; -use crate::conf::AccountSettings; -use crate::connections::timeout; -use crate::email::{parser::BytesExt, *}; -use crate::error::{Error, Result, ResultIntoError}; -use futures::lock::Mutex as FutureMutex; -use futures::stream::Stream; -use std::collections::hash_map::DefaultHasher; -use std::collections::{BTreeSet, HashMap, HashSet}; -use std::convert::TryFrom; -use std::hash::Hasher; -use std::pin::Pin; -use std::str::FromStr; -use std::sync::{Arc, Mutex}; -use std::time::{Duration, SystemTime}; +use futures::{lock::Mutex as FutureMutex, stream::Stream}; + +use crate::{ + backends::{ + RefreshEventKind::{self, *}, + *, + }, + collection::Collection, + conf::AccountSettings, + connections::timeout, + email::{parser::BytesExt, *}, + error::{Error, Result, ResultIntoError}, +}; pub type ImapNum = usize; pub type UID = ImapNum; @@ -340,7 +343,8 @@ impl MailBackend for ImapType { cache_handle, }; - /* do this in a closure to prevent recursion limit error in async_stream macro */ + /* do this in a closure to prevent recursion limit error in async_stream + * macro */ let prepare_cl = |f: &ImapMailbox| { f.set_warm(true); if let Ok(mut exists) = f.exists.lock() { @@ -526,15 +530,15 @@ impl MailBackend for ImapType { } fn operation(&self, hash: EnvelopeHash) -> Result> { - let (uid, mailbox_hash) = if let Some(v) = - self.uid_store.hash_index.lock().unwrap().get(&hash) - { - *v - } else { - return Err(Error::new( - "Message not found in local cache, it might have been deleted before you requested it." + let (uid, mailbox_hash) = + if let Some(v) = self.uid_store.hash_index.lock().unwrap().get(&hash) { + *v + } else { + return Err(Error::new( + "Message not found in local cache, it might have been deleted before you \ + requested it.", )); - }; + }; Ok(Box::new(ImapOp::new( uid, mailbox_hash, @@ -749,8 +753,20 @@ impl MailBackend for ImapType { cmd.push_str("\\Draft "); } Ok(_) => { - crate::log(format!("Application error: more than one flag bit set in set_flags: {:?}", flags), crate::ERROR); - return Err(Error::new(format!("Application error: more than one flag bit set in set_flags: {:?}", flags)).set_kind(crate::ErrorKind::Bug)); + crate::log( + format!( + "Application error: more than one flag bit set in \ + set_flags: {:?}", + flags + ), + crate::ERROR, + ); + return Err(Error::new(format!( + "Application error: more than one flag bit set in set_flags: \ + {:?}", + flags + )) + .set_kind(crate::ErrorKind::Bug)); } Err(tag) => { let hash = TagHash::from_bytes(tag.as_bytes()); @@ -812,13 +828,17 @@ impl MailBackend for ImapType { Ok(_) => { crate::log( format!( - "Application error: more than one flag bit set in set_flags: {:?}", flags - ), + "Application error: more than one flag bit set in \ + set_flags: {:?}", + flags + ), crate::ERROR, ); return Err(Error::new(format!( - "Application error: more than one flag bit set in set_flags: {:?}", flags - ))); + "Application error: more than one flag bit set in set_flags: \ + {:?}", + flags + ))); } Err(tag) => { cmd.push_str(tag); @@ -892,16 +912,17 @@ impl MailBackend for ImapType { Ok(Box::pin(async move { /* Must transform path to something the IMAP server will accept * - * Each root mailbox has a hierarchy delimeter reported by the LIST entry. All paths - * must use this delimeter to indicate children of this mailbox. + * Each root mailbox has a hierarchy delimeter reported by the LIST entry. + * All paths must use this delimeter to indicate children of this + * mailbox. * - * A new root mailbox should have the default delimeter, which can be found out by issuing - * an empty LIST command as described in RFC3501: + * A new root mailbox should have the default delimeter, which can be found + * out by issuing an empty LIST command as described in RFC3501: * C: A101 LIST "" "" * S: * LIST (\Noselect) "/" "" * - * The default delimiter for us is '/' just like UNIX paths. I apologise if this - * decision is unpleasant for you. + * The default delimiter for us is '/' just like UNIX paths. I apologise if + * this decision is unpleasant for you. */ { @@ -924,8 +945,8 @@ impl MailBackend for ImapType { } } - /* FIXME Do not try to CREATE a sub-mailbox in a mailbox that has the \Noinferiors - * flag set. */ + /* FIXME Do not try to CREATE a sub-mailbox in a mailbox + * that has the \Noinferiors flag set. */ } let mut response = Vec::with_capacity(8 * 1024); @@ -950,7 +971,17 @@ impl MailBackend for ImapType { ret?; let new_hash = MailboxHash::from_bytes(path.as_str().as_bytes()); uid_store.mailboxes.lock().await.clear(); - Ok((new_hash, new_mailbox_fut?.await.map_err(|err| Error::new(format!("Mailbox create was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", String::from_utf8_lossy(&response), err)))?)) + Ok(( + new_hash, + new_mailbox_fut?.await.map_err(|err| { + Error::new(format!( + "Mailbox create was succesful (returned `{}`) but listing mailboxes \ + afterwards returned `{}`", + String::from_utf8_lossy(&response), + err + )) + })?, + )) })) } @@ -970,7 +1001,12 @@ impl MailBackend for ImapType { imap_path = mailboxes[&mailbox_hash].imap_path().to_string(); let permissions = mailboxes[&mailbox_hash].permissions(); if !permissions.delete_mailbox { - return Err(Error::new(format!("You do not have permission to delete `{}`. Set permissions for this mailbox are {}", mailboxes[&mailbox_hash].name(), permissions))); + return Err(Error::new(format!( + "You do not have permission to delete `{}`. Set permissions for this \ + mailbox are {}", + mailboxes[&mailbox_hash].name(), + permissions + ))); } } let mut response = Vec::with_capacity(8 * 1024); @@ -998,7 +1034,15 @@ impl MailBackend for ImapType { let ret: Result<()> = ImapResponse::try_from(response.as_slice())?.into(); ret?; uid_store.mailboxes.lock().await.clear(); - new_mailbox_fut?.await.map_err(|err| format!("Mailbox delete was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", String::from_utf8_lossy(&response), err).into()) + new_mailbox_fut?.await.map_err(|err| { + format!( + "Mailbox delete was succesful (returned `{}`) but listing mailboxes \ + afterwards returned `{}`", + String::from_utf8_lossy(&response), + err + ) + .into() + }) })) } @@ -1064,7 +1108,12 @@ impl MailBackend for ImapType { let mailboxes = uid_store.mailboxes.lock().await; let permissions = mailboxes[&mailbox_hash].permissions(); if !permissions.delete_mailbox { - return Err(Error::new(format!("You do not have permission to rename mailbox `{}` (rename is equivalent to delete + create). Set permissions for this mailbox are {}", mailboxes[&mailbox_hash].name(), permissions))); + return Err(Error::new(format!( + "You do not have permission to rename mailbox `{}` (rename is equivalent \ + to delete + create). Set permissions for this mailbox are {}", + mailboxes[&mailbox_hash].name(), + permissions + ))); } if mailboxes[&mailbox_hash].separator != b'/' { new_path = new_path.replace( @@ -1089,7 +1138,14 @@ impl MailBackend for ImapType { let ret: Result<()> = ImapResponse::try_from(response.as_slice())?.into(); ret?; uid_store.mailboxes.lock().await.clear(); - new_mailbox_fut?.await.map_err(|err| format!("Mailbox rename was succesful (returned `{}`) but listing mailboxes afterwards returned `{}`", String::from_utf8_lossy(&response), err))?; + new_mailbox_fut?.await.map_err(|err| { + format!( + "Mailbox rename was succesful (returned `{}`) but listing mailboxes \ + afterwards returned `{}`", + String::from_utf8_lossy(&response), + err + ) + })?; Ok(BackendMailbox::clone( &uid_store.mailboxes.lock().await[&new_hash], )) @@ -1107,7 +1163,12 @@ impl MailBackend for ImapType { let mailboxes = uid_store.mailboxes.lock().await; let permissions = mailboxes[&mailbox_hash].permissions(); if !permissions.change_permissions { - return Err(Error::new(format!("You do not have permission to change permissions for mailbox `{}`. Set permissions for this mailbox are {}", mailboxes[&mailbox_hash].name(), permissions))); + return Err(Error::new(format!( + "You do not have permission to change permissions for mailbox `{}`. Set \ + permissions for this mailbox are {}", + mailboxes[&mailbox_hash].name(), + permissions + ))); } Err(Error::new("Unimplemented.")) @@ -1262,7 +1323,8 @@ impl ImapType { if use_oauth2 && !s.extra.contains_key("server_password_command") { return Err(Error::new(format!( - "({}) `use_oauth2` use requires `server_password_command` set with a command that returns an OAUTH2 token. Consult documentation for guidance.", + "({}) `use_oauth2` use requires `server_password_command` set with a command that \ + returns an OAUTH2 token. Consult documentation for guidance.", s.name, ))); } @@ -1524,14 +1586,16 @@ impl ImapType { if !s.extra.contains_key("server_password_command") { if use_oauth2 { return Err(Error::new(format!( - "({}) `use_oauth2` use requires `server_password_command` set with a command that returns an OAUTH2 token. Consult documentation for guidance.", + "({}) `use_oauth2` use requires `server_password_command` set with a command \ + that returns an OAUTH2 token. Consult documentation for guidance.", s.name, ))); } get_conf_val!(s["server_password"])?; } else if s.extra.contains_key("server_password") { return Err(Error::new(format!( - "Configuration error ({}): both server_password and server_password_command are set, cannot choose", + "Configuration error ({}): both server_password and server_password_command are \ + set, cannot choose", s.name.as_str(), ))); } @@ -1541,7 +1605,8 @@ impl ImapType { let use_starttls = get_conf_val!(s["use_starttls"], false)?; if !use_tls && use_starttls { return Err(Error::new(format!( - "Configuration error ({}): incompatible use_tls and use_starttls values: use_tls = false, use_starttls = true", + "Configuration error ({}): incompatible use_tls and use_starttls values: use_tls \ + = false, use_starttls = true", s.name.as_str(), ))); } @@ -1565,7 +1630,8 @@ impl ImapType { #[cfg(not(feature = "deflate_compression"))] if s.extra.contains_key("use_deflate") { return Err(Error::new(format!( - "Configuration error ({}): setting `use_deflate` is set but this version of meli isn't compiled with DEFLATE support.", + "Configuration error ({}): setting `use_deflate` is set but this version of meli \ + isn't compiled with DEFLATE support.", s.name.as_str(), ))); } @@ -1578,8 +1644,10 @@ impl ImapType { let diff = extra_keys.difference(&keys).collect::>(); if !diff.is_empty() { return Err(Error::new(format!( - "Configuration error ({}): the following flags are set but are not recognized: {:?}.", - s.name.as_str(), diff + "Configuration error ({}): the following flags are set but are not recognized: \ + {:?}.", + s.name.as_str(), + diff ))); } Ok(()) @@ -1658,7 +1726,14 @@ async fn fetch_hlpr(state: &mut FetchState) -> Result> { /* Try resetting the database */ if let Some(ref mut cache_handle) = state.cache_handle { if let Err(err) = cache_handle.reset() { - crate::log(format!("IMAP cache error: could not reset cache for {}. Reason: {}", state.uid_store.account_name, err), crate::ERROR); + crate::log( + format!( + "IMAP cache error: could not reset cache for {}. Reason: \ + {}", + state.uid_store.account_name, err + ), + crate::ERROR, + ); } } state.stage = FetchStage::InitialFresh; @@ -1743,11 +1818,14 @@ async fn fetch_hlpr(state: &mut FetchState) -> Result> { if max_uid_left > 0 { debug!("{} max_uid_left= {}", mailbox_hash, max_uid_left); let command = if max_uid_left == 1 { - "UID FETCH 1 (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] BODYSTRUCTURE)".to_string() + "UID FETCH 1 (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] \ + BODYSTRUCTURE)" + .to_string() } else { format!( - "UID FETCH {}:{} (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] BODYSTRUCTURE)", - std::cmp::max(max_uid_left.saturating_sub(chunk_size), 1), + "UID FETCH {}:{} (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS \ + (REFERENCES)] BODYSTRUCTURE)", + std::cmp::max(max_uid_left.saturating_sub(chunk_size), 1), max_uid_left ) }; diff --git a/melib/src/backends/imap/cache.rs b/melib/src/backends/imap/cache.rs index f0bca452..3046ab1b 100644 --- a/melib/src/backends/imap/cache.rs +++ b/melib/src/backends/imap/cache.rs @@ -21,12 +21,13 @@ use super::*; mod sync; +use std::convert::TryFrom; + use crate::{ backends::MailboxHash, email::{Envelope, EnvelopeHash}, error::*, }; -use std::convert::TryFrom; #[derive(Debug, PartialEq, Hash, Eq, Ord, PartialOrd, Copy, Clone)] pub struct ModSequence(pub std::num::NonZeroU64); @@ -105,10 +106,11 @@ pub use sqlite3_m::*; #[cfg(feature = "sqlite3")] mod sqlite3_m { use super::*; - use crate::sqlite3::rusqlite::types::{ - FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, + use crate::sqlite3::{ + self, + rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput}, + DatabaseDescription, }; - use crate::sqlite3::{self, DatabaseDescription}; type Sqlite3UID = i32; @@ -287,23 +289,45 @@ mod sqlite3_m { })?; if let Some(Ok(highestmodseq)) = select_response.highestmodseq { - self.connection.execute( - "INSERT OR IGNORE INTO mailbox (uidvalidity, flags, highestmodseq, mailbox_hash) VALUES (?1, ?2, ?3, ?4)", - sqlite3::params![select_response.uidvalidity as Sqlite3UID, select_response.flags.1.iter().map(|s| s.as_str()).collect::>().join("\0").as_bytes(), highestmodseq, mailbox_hash], - ) - .chain_err_summary(|| { - format!( - "Could not insert uidvalidity {} in header_cache of account {}", - select_response.uidvalidity, self.uid_store.account_name - ) - })?; + self.connection + .execute( + "INSERT OR IGNORE INTO mailbox (uidvalidity, flags, highestmodseq, \ + mailbox_hash) VALUES (?1, ?2, ?3, ?4)", + sqlite3::params![ + select_response.uidvalidity as Sqlite3UID, + select_response + .flags + .1 + .iter() + .map(|s| s.as_str()) + .collect::>() + .join("\0") + .as_bytes(), + highestmodseq, + mailbox_hash + ], + ) + .chain_err_summary(|| { + format!( + "Could not insert uidvalidity {} in header_cache of account {}", + select_response.uidvalidity, self.uid_store.account_name + ) + })?; } else { self.connection .execute( - "INSERT OR IGNORE INTO mailbox (uidvalidity, flags, mailbox_hash) VALUES (?1, ?2, ?3)", + "INSERT OR IGNORE INTO mailbox (uidvalidity, flags, mailbox_hash) VALUES \ + (?1, ?2, ?3)", sqlite3::params![ select_response.uidvalidity as Sqlite3UID, - select_response.flags.1.iter().map(|s| s.as_str()).collect::>().join("\0").as_bytes(), + select_response + .flags + .1 + .iter() + .map(|s| s.as_str()) + .collect::>() + .join("\0") + .as_bytes(), mailbox_hash ], ) @@ -463,9 +487,24 @@ mod sqlite3_m { { max_uid = std::cmp::max(max_uid, *uid); tx.execute( - "INSERT OR REPLACE INTO envelopes (hash, uid, mailbox_hash, modsequence, envelope) VALUES (?1, ?2, ?3, ?4, ?5)", - sqlite3::params![envelope.hash(), *uid as Sqlite3UID, mailbox_hash, modseq, &envelope], - ).chain_err_summary(|| format!("Could not insert envelope {} {} in header_cache of account {}", envelope.message_id(), envelope.hash(), uid_store.account_name))?; + "INSERT OR REPLACE INTO envelopes (hash, uid, mailbox_hash, modsequence, \ + envelope) VALUES (?1, ?2, ?3, ?4, ?5)", + sqlite3::params![ + envelope.hash(), + *uid as Sqlite3UID, + mailbox_hash, + modseq, + &envelope + ], + ) + .chain_err_summary(|| { + format!( + "Could not insert envelope {} {} in header_cache of account {}", + envelope.message_id(), + envelope.hash(), + uid_store.account_name + ) + })?; } } tx.commit()?; @@ -523,15 +562,17 @@ mod sqlite3_m { env.tags_mut() .extend(tags.iter().map(|t| TagHash::from_bytes(t.as_bytes()))); tx.execute( - "UPDATE envelopes SET envelope = ?1 WHERE mailbox_hash = ?2 AND uid = ?3;", - sqlite3::params![&env, mailbox_hash, *uid as Sqlite3UID], - ) - .chain_err_summary(|| { - format!( - "Could not update envelope {} uid {} from mailbox {} account {}", - env_hash, *uid, mailbox_hash, uid_store.account_name - ) - })?; + "UPDATE envelopes SET envelope = ?1 WHERE mailbox_hash = ?2 AND \ + uid = ?3;", + sqlite3::params![&env, mailbox_hash, *uid as Sqlite3UID], + ) + .chain_err_summary(|| { + format!( + "Could not update envelope {} uid {} from mailbox {} account \ + {}", + env_hash, *uid, mailbox_hash, uid_store.account_name + ) + })?; uid_store .envelopes .lock() @@ -563,8 +604,9 @@ mod sqlite3_m { let mut ret: Vec<(UID, Envelope, Option)> = match identifier { Ok(uid) => { let mut stmt = self.connection.prepare( - "SELECT uid, envelope, modsequence FROM envelopes WHERE mailbox_hash = ?1 AND uid = ?2;", - )?; + "SELECT uid, envelope, modsequence FROM envelopes WHERE mailbox_hash = ?1 \ + AND uid = ?2;", + )?; let x = stmt .query_map(sqlite3::params![mailbox_hash, uid as Sqlite3UID], |row| { @@ -579,8 +621,9 @@ mod sqlite3_m { } Err(env_hash) => { let mut stmt = self.connection.prepare( - "SELECT uid, envelope, modsequence FROM envelopes WHERE mailbox_hash = ?1 AND hash = ?2;", - )?; + "SELECT uid, envelope, modsequence FROM envelopes WHERE mailbox_hash = ?1 \ + AND hash = ?2;", + )?; let x = stmt .query_map(sqlite3::params![mailbox_hash, env_hash], |row| { diff --git a/melib/src/backends/imap/cache/sync.rs b/melib/src/backends/imap/cache/sync.rs index 2497d4ea..3dde2ccc 100644 --- a/melib/src/backends/imap/cache/sync.rs +++ b/melib/src/backends/imap/cache/sync.rs @@ -130,7 +130,8 @@ impl ImapConnection { // 2. tag1 UID FETCH :* self.send_command( format!( - "UID FETCH {}:* (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] BODYSTRUCTURE)", + "UID FETCH {}:* (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] \ + BODYSTRUCTURE)", max_uid + 1 ) .as_bytes(), @@ -375,9 +376,9 @@ impl ImapConnection { // client MUST // * empty the local cache of that mailbox; // * "forget" the cached HIGHESTMODSEQ value for the mailbox; - // * remove any pending "actions" that refer to UIDs in that - // mailbox (note that this doesn't affect actions performed on - // client-generated fake UIDs; see Section 5); and + // * remove any pending "actions" that refer to UIDs in that mailbox (note + // that this doesn't affect actions performed on client-generated fake UIDs; + // see Section 5); and // * skip steps 1b and 2-II; cache_handle.clear(mailbox_hash, &select_response)?; return Ok(None); @@ -398,9 +399,9 @@ impl ImapConnection { let new_highestmodseq = select_response.highestmodseq.unwrap().unwrap(); let mut refresh_events = vec![]; // 1b) Check the mailbox HIGHESTMODSEQ. - // If the cached value is the same as the one returned by the server, skip fetching - // message flags on step 2-II, i.e., the client only has to find out which messages got - // expunged. + // If the cached value is the same as the one returned by the server, skip + // fetching message flags on step 2-II, i.e., the client only has to + // find out which messages got expunged. if cached_highestmodseq != new_highestmodseq { /* Cache is synced, only figure out which messages got expunged */ @@ -415,7 +416,8 @@ impl ImapConnection { // 2. tag1 UID FETCH :* self.send_command( format!( - "UID FETCH {}:* (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] BODYSTRUCTURE) (CHANGEDSINCE {})", + "UID FETCH {}:* (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] \ + BODYSTRUCTURE) (CHANGEDSINCE {})", cached_max_uid + 1, cached_highestmodseq, ) @@ -571,8 +573,8 @@ impl ImapConnection { .insert(mailbox_hash, Ok(new_highestmodseq)); } let mut valid_envs = BTreeSet::default(); - // This should be UID SEARCH 1: but it's difficult to compare to cached UIDs at the - // point of calling this function + // This should be UID SEARCH 1: but it's difficult to compare to cached + // UIDs at the point of calling this function self.send_command(b"UID SEARCH ALL").await?; self.read_response(&mut response, RequiredResponses::SEARCH) .await?; @@ -614,7 +616,8 @@ impl ImapConnection { Ok(Some(payload.into_iter().map(|(_, env)| env).collect())) } - //rfc7162_Quick Flag Changes Resynchronization (CONDSTORE)_and Quick Mailbox Resynchronization (QRESYNC) + //rfc7162_Quick Flag Changes Resynchronization (CONDSTORE)_and Quick Mailbox + // Resynchronization (QRESYNC) pub async fn resync_condstoreqresync( &mut self, _cache_handle: Box, @@ -634,8 +637,8 @@ impl ImapConnection { ) }; - /* first SELECT the mailbox to get READ/WRITE permissions (because EXAMINE only - * returns READ-ONLY for both cases) */ + /* first SELECT the mailbox to get READ/WRITE permissions (because EXAMINE + * only returns READ-ONLY for both cases) */ let mut select_response = self .select_mailbox(mailbox_hash, &mut response, true) .await? diff --git a/melib/src/backends/imap/connection.rs b/melib/src/backends/imap/connection.rs index 8918117c..1b9c76cc 100644 --- a/melib/src/backends/imap/connection.rs +++ b/melib/src/backends/imap/connection.rs @@ -20,33 +20,38 @@ */ use super::protocol_parser::{ImapLineSplit, ImapResponse, RequiredResponses, SelectResponse}; -use crate::backends::{MailboxHash, RefreshEvent}; -use crate::connections::{lookup_ipv4, timeout, Connection}; -use crate::email::parser::BytesExt; -use crate::error::*; +use crate::{ + backends::{MailboxHash, RefreshEvent}, + connections::{lookup_ipv4, timeout, Connection}, + email::parser::BytesExt, + error::*, +}; extern crate native_tls; +use std::{ + collections::HashSet, + convert::TryFrom, + future::Future, + iter::FromIterator, + pin::Pin, + sync::Arc, + time::{Duration, Instant, SystemTime}, +}; + use futures::io::{AsyncReadExt, AsyncWriteExt}; use native_tls::TlsConnector; pub use smol::Async as AsyncWrapper; -use std::collections::HashSet; -use std::convert::TryFrom; -use std::future::Future; -use std::iter::FromIterator; -use std::pin::Pin; -use std::sync::Arc; -use std::time::{Duration, Instant, SystemTime}; const IMAP_PROTOCOL_TIMEOUT: Duration = Duration::from_secs(60 * 28); -use super::protocol_parser; -use super::{Capabilities, ImapServerConf, UIDStore}; +use super::{protocol_parser, Capabilities, ImapServerConf, UIDStore}; #[derive(Debug, Clone, Copy)] pub enum SyncPolicy { None, ///rfc4549 `Synch Ops for Disconnected IMAP4 Clients` Basic, - ///rfc7162 `IMAP Extensions: Quick Flag Changes Resynchronization (CONDSTORE) and Quick Mailbox Resynchronization (QRESYNC)` + ///rfc7162 `IMAP Extensions: Quick Flag Changes Resynchronization + /// (CONDSTORE) and Quick Mailbox Resynchronization (QRESYNC)` Condstore, CondstoreQresync, } @@ -144,13 +149,14 @@ impl ImapStream { if let Some(timeout) = server_conf.timeout { TcpStream::connect_timeout(&addr, timeout)? } else { - TcpStream::connect(&addr)? + TcpStream::connect(addr)? }, ))?; if server_conf.use_starttls { let err_fn = || { if server_conf.server_port == 993 { - "STARTTLS failed. Server port is set to 993, which normally uses TLS. Maybe try disabling use_starttls." + "STARTTLS failed. Server port is set to 993, which normally uses TLS. \ + Maybe try disabling use_starttls." } else { "STARTTLS failed. Is the connection already encrypted?" } @@ -246,7 +252,7 @@ impl ImapStream { if let Some(timeout) = server_conf.timeout { TcpStream::connect_timeout(&addr, timeout)? } else { - TcpStream::connect(&addr)? + TcpStream::connect(addr)? }, ))? }; @@ -350,10 +356,14 @@ impl ImapStream { .any(|cap| cap.eq_ignore_ascii_case(b"AUTH=XOAUTH2")) { return Err(Error::new(format!( - "Could not connect to {}: OAUTH2 is enabled but server did not return AUTH=XOAUTH2 capability. Returned capabilities were: {}", - &server_conf.server_hostname, - capabilities.iter().map(|capability| - String::from_utf8_lossy(capability).to_string()).collect::>().join(" ") + "Could not connect to {}: OAUTH2 is enabled but server did not return \ + AUTH=XOAUTH2 capability. Returned capabilities were: {}", + &server_conf.server_hostname, + capabilities + .iter() + .map(|capability| String::from_utf8_lossy(capability).to_string()) + .collect::>() + .join(" ") ))); } ret.send_command( @@ -414,8 +424,8 @@ impl ImapStream { } if capabilities.is_none() { - /* sending CAPABILITY after LOGIN automatically is an RFC recommendation, so check - * for lazy servers */ + /* sending CAPABILITY after LOGIN automatically is an RFC recommendation, so + * check for lazy servers */ drop(capabilities); ret.send_command(b"CAPABILITY").await?; ret.read_response(&mut res).await.unwrap(); @@ -648,7 +658,14 @@ impl ImapConnection { | ImapResponse::Bad(code) | ImapResponse::Preauth(code) | ImapResponse::Bye(code) => { - crate::log(format!("Could not use COMPRESS=DEFLATE in account `{}`: server replied with `{}`", self.uid_store.account_name, code), crate::LoggingLevel::WARN); + crate::log( + format!( + "Could not use COMPRESS=DEFLATE in account `{}`: server \ + replied with `{}`", + self.uid_store.account_name, code + ), + crate::LoggingLevel::WARN, + ); } ImapResponse::Ok(_) => { let ImapStream { @@ -750,7 +767,7 @@ impl ImapConnection { &required_responses );*/ for l in response.split_rn() { - /*debug!("check line: {}", &l);*/ + /* debug!("check line: {}", &l); */ if required_responses.check(l) || !self.process_untagged(l).await? { ret.extend_from_slice(l); } diff --git a/melib/src/backends/imap/mailbox.rs b/melib/src/backends/imap/mailbox.rs index 0e8aa7fe..a26d3daa 100644 --- a/melib/src/backends/imap/mailbox.rs +++ b/melib/src/backends/imap/mailbox.rs @@ -19,13 +19,16 @@ * along with meli. If not, see . */ -use super::protocol_parser::SelectResponse; -use crate::backends::{ - BackendMailbox, LazyCountSet, Mailbox, MailboxHash, MailboxPermissions, SpecialUsageMailbox, -}; -use crate::error::*; use std::sync::{Arc, Mutex, RwLock}; +use super::protocol_parser::SelectResponse; +use crate::{ + backends::{ + BackendMailbox, LazyCountSet, Mailbox, MailboxHash, MailboxPermissions, SpecialUsageMailbox, + }, + error::*, +}; + #[derive(Debug, Default, Clone)] pub struct ImapMailbox { pub hash: MailboxHash, @@ -51,7 +54,8 @@ impl ImapMailbox { &self.imap_path } - /// Establish that mailbox contents have been fetched at least once during this execution + /// Establish that mailbox contents have been fetched at least once during + /// this execution #[inline(always)] pub fn set_warm(&self, new_value: bool) { *self.warm.lock().unwrap() = new_value; diff --git a/melib/src/backends/imap/managesieve.rs b/melib/src/backends/imap/managesieve.rs index e8620d04..64932599 100644 --- a/melib/src/backends/imap/managesieve.rs +++ b/melib/src/backends/imap/managesieve.rs @@ -19,19 +19,25 @@ * along with meli. If not, see . */ -use super::{ImapConnection, ImapProtocol, ImapServerConf, UIDStore}; -use crate::conf::AccountSettings; -use crate::email::parser::IResult; -use crate::error::{Error, Result}; -use crate::get_conf_val; -use crate::imap::RequiredResponses; +use std::{ + str::FromStr, + sync::{Arc, Mutex}, + time::SystemTime, +}; + use nom::{ branch::alt, bytes::complete::tag, combinator::map, multi::separated_list1, sequence::separated_pair, }; -use std::str::FromStr; -use std::sync::{Arc, Mutex}; -use std::time::SystemTime; + +use super::{ImapConnection, ImapProtocol, ImapServerConf, UIDStore}; +use crate::{ + conf::AccountSettings, + email::parser::IResult, + error::{Error, Result}, + get_conf_val, + imap::RequiredResponses, +}; pub struct ManageSieveConnection { pub inner: ImapConnection, @@ -61,12 +67,17 @@ pub enum ManageSieveResponse<'a> { } mod parser { + use nom::{ + bytes::complete::tag, + character::complete::crlf, + combinator::{iterator, map, opt}, + }; + pub use nom::{ + bytes::complete::{is_not, tag_no_case}, + sequence::{delimited, pair, preceded, terminated}, + }; + use super::*; - use nom::bytes::complete::tag; - pub use nom::bytes::complete::{is_not, tag_no_case}; - use nom::character::complete::crlf; - use nom::combinator::{iterator, map, opt}; - pub use nom::sequence::{delimited, pair, preceded, terminated}; pub fn sieve_name(input: &[u8]) -> IResult<&[u8], &[u8]> { crate::backends::imap::protocol_parser::string_token(input) diff --git a/melib/src/backends/imap/operations.rs b/melib/src/backends/imap/operations.rs index f7b48e33..e2488de8 100644 --- a/melib/src/backends/imap/operations.rs +++ b/melib/src/backends/imap/operations.rs @@ -19,13 +19,11 @@ * along with meli. If not, see . */ -use super::*; - -use crate::backends::*; -use crate::email::*; -use crate::error::Error; use std::sync::Arc; +use super::*; +use crate::{backends::*, email::*, error::Error}; + /// `BackendOp` implementor for Imap #[derive(Debug, Clone)] pub struct ImapOp { diff --git a/melib/src/backends/imap/protocol_parser.rs b/melib/src/backends/imap/protocol_parser.rs index edcfe98d..6fb8238e 100644 --- a/melib/src/backends/imap/protocol_parser.rs +++ b/melib/src/backends/imap/protocol_parser.rs @@ -19,24 +19,28 @@ * along with meli. If not, see . */ -use super::*; -use crate::email::address::{Address, MailboxAddress}; -use crate::email::parser::{ - generic::{byte_in_range, byte_in_slice}, - BytesExt, IResult, -}; -use crate::error::ResultIntoError; +use std::{convert::TryFrom, str::FromStr}; + use nom::{ branch::{alt, permutation}, bytes::complete::{is_a, is_not, tag, take, take_until, take_while}, - character::complete::digit1, - character::is_digit, + character::{complete::digit1, is_digit}, combinator::{map, map_res, opt}, multi::{fold_many1, length_data, many0, many1, separated_list1}, sequence::{delimited, preceded}, }; -use std::convert::TryFrom; -use std::str::FromStr; + +use super::*; +use crate::{ + email::{ + address::{Address, MailboxAddress}, + parser::{ + generic::{byte_in_range, byte_in_slice}, + BytesExt, IResult, + }, + }, + error::ResultIntoError, +}; bitflags! { #[derive(Default, Serialize, Deserialize)] @@ -137,7 +141,7 @@ fn test_imap_required_responses() { let response = &b"* 1040 FETCH (UID 1064 FLAGS ())\r\nM15 OK Fetch completed (0.001 + 0.299 secs).\r\n"[..]; for l in response.split_rn() { - /*debug!("check line: {}", &l);*/ + /* debug!("check line: {}", &l); */ if required_responses.check(l) { ret.extend_from_slice(l); } @@ -159,35 +163,59 @@ pub struct ImapLineIterator<'a> { #[derive(Debug, PartialEq)] pub enum ResponseCode { - ///The human-readable text contains a special alert that MUST be presented to the user in a fashion that calls the user's attention to the message. + ///The human-readable text contains a special alert that MUST be presented + /// to the user in a fashion that calls the user's attention to the message. Alert(String), - ///Optionally followed by a parenthesized list of charsets. A SEARCH failed because the given charset is not supported by this implementation. If the optional list of charsets is given, this lists the charsets that are supported by this implementation. + ///Optionally followed by a parenthesized list of charsets. A SEARCH + /// failed because the given charset is not supported by this + /// implementation. If the optional list of charsets is given, this lists + /// the charsets that are supported by this implementation. Badcharset(Option), - /// Followed by a list of capabilities. This can appear in the initial OK or PREAUTH response to transmit an initial capabilities list. This makes it unnecessary for a client to send a separate CAPABILITY command if it recognizes this response. + /// Followed by a list of capabilities. This can appear in the initial OK + /// or PREAUTH response to transmit an initial capabilities list. This + /// makes it unnecessary for a client to send a separate CAPABILITY command + /// if it recognizes this response. Capability, - /// The human-readable text represents an error in parsing the [RFC-2822] header or [MIME-IMB] headers of a message in the mailbox. + /// The human-readable text represents an error in parsing the [RFC-2822] + /// header or [MIME-IMB] headers of a message in the mailbox. Parse(String), - /// Followed by a parenthesized list of flags, indicates which of the known flags the client can change permanently. Any flags that are in the FLAGS untagged response, but not the PERMANENTFLAGS list, can not be set permanently. If the client attempts to STORE a flag that is not in the PERMANENTFLAGS list, the server will either ignore the change or store the state change for the remainder of the current session only. The PERMANENTFLAGS list can also include the special flag \*, which indicates that it is possible to create new keywords by attempting to store those flags in the mailbox. + /// Followed by a parenthesized list of flags, indicates which of the known + /// flags the client can change permanently. Any flags that are in the + /// FLAGS untagged response, but not the PERMANENTFLAGS list, can not be set + /// permanently. If the client attempts to STORE a flag that is not in the + /// PERMANENTFLAGS list, the server will either ignore the change or store + /// the state change for the remainder of the current session only. The + /// PERMANENTFLAGS list can also include the special flag \*, which + /// indicates that it is possible to create new keywords by attempting to + /// store those flags in the mailbox. Permanentflags(String), - /// The mailbox is selected read-only, or its access while selected has changed from read-write to read-only. + /// The mailbox is selected read-only, or its access while selected has + /// changed from read-write to read-only. ReadOnly, - /// The mailbox is selected read-write, or its access while selected has changed from read-only to read-write. + /// The mailbox is selected read-write, or its access while selected has + /// changed from read-only to read-write. ReadWrite, - /// An APPEND or COPY attempt is failing because the target mailbox does not exist (as opposed to some other reason). This is a hint to the client that the operation can succeed if the mailbox is first created by the CREATE command. + /// An APPEND or COPY attempt is failing because the target mailbox does not + /// exist (as opposed to some other reason). This is a hint to the client + /// that the operation can succeed if the mailbox is first created by the + /// CREATE command. Trycreate, - /// Followed by a decimal number, indicates the next unique identifier value. Refer to section 2.3.1.1 for more information. + /// Followed by a decimal number, indicates the next unique identifier + /// value. Refer to section 2.3.1.1 for more information. Uidnext(UID), - /// Followed by a decimal number, indicates the unique identifier validity value. Refer to section 2.3.1.1 for more information. + /// Followed by a decimal number, indicates the unique identifier validity + /// value. Refer to section 2.3.1.1 for more information. Uidvalidity(UID), - /// Followed by a decimal number, indicates the number of the first message without the \Seen flag set. + /// Followed by a decimal number, indicates the number of the first message + /// without the \Seen flag set. Unseen(ImapNum), } @@ -195,15 +223,23 @@ impl std::fmt::Display for ResponseCode { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { use ResponseCode::*; match self { - Alert(s)=> write!(fmt, "ALERT: {}", s), - Badcharset(None)=> write!(fmt, "Given charset is not supported by this server."), - Badcharset(Some(s))=> write!(fmt, "Given charset is not supported by this server. Supported ones are: {}", s), + Alert(s) => write!(fmt, "ALERT: {}", s), + Badcharset(None) => write!(fmt, "Given charset is not supported by this server."), + Badcharset(Some(s)) => write!( + fmt, + "Given charset is not supported by this server. Supported ones are: {}", + s + ), Capability => write!(fmt, "Capability response"), Parse(s) => write!(fmt, "Server error in parsing message headers: {}", s), Permanentflags(s) => write!(fmt, "Mailbox supports these flags: {}", s), - ReadOnly=> write!(fmt, "This mailbox is selected read-only."), + ReadOnly => write!(fmt, "This mailbox is selected read-only."), ReadWrite => write!(fmt, "This mailbox is selected with read-write permissions."), - Trycreate => write!(fmt, "Failed to operate on the target mailbox because it doesn't exist. Try creating it first."), + Trycreate => write!( + fmt, + "Failed to operate on the target mailbox because it doesn't exist. Try creating \ + it first." + ), Uidnext(uid) => write!(fmt, "Next UID value is {}", uid), Uidvalidity(uid) => write!(fmt, "Next UIDVALIDITY value is {}", uid), Unseen(uid) => write!(fmt, "First message without the \\Seen flag is {}", uid), @@ -265,7 +301,8 @@ impl TryFrom<&'_ [u8]> for ImapResponse { )) })? + 1..] .trim(); - // M12 NO [CANNOT] Invalid mailbox name: Name must not have \'/\' characters (0.000 + 0.098 + 0.097 secs).\r\n + // M12 NO [CANNOT] Invalid mailbox name: Name must not have \'/\' characters + // (0.000 + 0.098 + 0.097 secs).\r\n if val.ends_with(b" secs).") { val = &val[..val.rfind(b"(").ok_or_else(|| { Error::new(format!( @@ -432,8 +469,8 @@ fn test_imap_line_iterator() { */ /* -* LIST (\HasNoChildren) "." INBOX.Sent -* LIST (\HasChildren) "." INBOX + * LIST (\HasNoChildren) "." INBOX.Sent + * LIST (\HasChildren) "." INBOX */ pub fn list_mailbox_result(input: &[u8]) -> IResult<&[u8], ImapMailbox> { @@ -604,7 +641,8 @@ pub fn fetch_response(input: &[u8]) -> ImapParseResult> { i += (input.len() - i - rest.len()) + 1; } else { return debug!(Err(Error::new(format!( - "Unexpected input while parsing UID FETCH response. Could not parse FLAGS: {:.40}.", + "Unexpected input while parsing UID FETCH response. Could not parse FLAGS: \ + {:.40}.", String::from_utf8_lossy(&input[i..]) )))); } @@ -639,7 +677,8 @@ pub fn fetch_response(input: &[u8]) -> ImapParseResult> { i += input.len() - i - rest.len(); } else { return debug!(Err(Error::new(format!( - "Unexpected input while parsing UID FETCH response. Could not parse RFC822: {:.40}", + "Unexpected input while parsing UID FETCH response. Could not parse RFC822: \ + {:.40}", String::from_utf8_lossy(&input[i..]) )))); } @@ -650,7 +689,8 @@ pub fn fetch_response(input: &[u8]) -> ImapParseResult> { i += input.len() - i - rest.len(); } else { return debug!(Err(Error::new(format!( - "Unexpected input while parsing UID FETCH response. Could not parse ENVELOPE: {:.40}", + "Unexpected input while parsing UID FETCH response. Could not parse ENVELOPE: \ + {:.40}", String::from_utf8_lossy(&input[i..]) )))); } @@ -672,7 +712,8 @@ pub fn fetch_response(input: &[u8]) -> ImapParseResult> { i += input.len() - i - rest.len(); } else { return debug!(Err(Error::new(format!( - "Unexpected input while parsing UID FETCH response. Could not parse BODY[HEADER.FIELDS (REFERENCES)]: {:.40}", + "Unexpected input while parsing UID FETCH response. Could not parse \ + BODY[HEADER.FIELDS (REFERENCES)]: {:.40}", String::from_utf8_lossy(&input[i..]) )))); } @@ -688,7 +729,8 @@ pub fn fetch_response(input: &[u8]) -> ImapParseResult> { i += input.len() - i - rest.len(); } else { return debug!(Err(Error::new(format!( - "Unexpected input while parsing UID FETCH response. Could not parse BODY[HEADER.FIELDS (\"REFERENCES\"): {:.40}", + "Unexpected input while parsing UID FETCH response. Could not parse \ + BODY[HEADER.FIELDS (\"REFERENCES\"): {:.40}", String::from_utf8_lossy(&input[i..]) )))); } @@ -815,9 +857,15 @@ macro_rules! flags_to_imap_list { /* Input Example: * ============== * - * "M0 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SPECIAL-USE] Logged in\r\n" -* "* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENT TOKEN AUTH=OAUTHBEARER AUTH=XOAUTH\r\n" -* "* CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN\r\n" + * "M0 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE + * IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT + * MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS + * LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN + * CONTEXT=SEARCH LIST-STATUS BINARY MOVE SPECIAL-USE] Logged in\r\n" + * "* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN + * X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENT TOKEN + * AUTH=OAUTHBEARER AUTH=XOAUTH\r\n" "* CAPABILITY IMAP4rev1 LITERAL+ + * SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN\r\n" */ pub fn capabilities(input: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { @@ -829,7 +877,8 @@ pub fn capabilities(input: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { Ok((input, ret)) } -/// This enum represents the server's untagged responses detailed in `7. Server Responses` of RFC 3501 INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1 +/// This enum represents the server's untagged responses detailed in `7. Server +/// Responses` of RFC 3501 INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1 #[derive(Debug, PartialEq)] pub enum UntaggedResponse<'s> { /// ```text @@ -1090,7 +1139,8 @@ pub struct SelectResponse { /* * * * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) - * * OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft \*)] Flags permitted. + * * OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft \*)] Flags + * permitted. * * 45 EXISTS * * 0 RECENT * * OK [UNSEEN 16] First unseen. @@ -1283,30 +1333,30 @@ pub fn byte_flags(input: &[u8]) -> IResult<&[u8], (Flag, Vec)> { } /* -* The fields of the envelope structure are in the following -* order: date, subject, from, sender, reply-to, to, cc, bcc, -* in-reply-to, and message-id. The date, subject, in-reply-to, -* and message-id fields are strings. The from, sender, reply-to, -* to, cc, and bcc fields are parenthesized lists of address -* structures. -* An address structure is a parenthesized list that describes an -* electronic mail address. The fields of an address structure -* are in the following order: personal name, [SMTP] -* at-domain-list (source route), mailbox name, and host name. -*/ + * The fields of the envelope structure are in the following + * order: date, subject, from, sender, reply-to, to, cc, bcc, + * in-reply-to, and message-id. The date, subject, in-reply-to, + * and message-id fields are strings. The from, sender, reply-to, + * to, cc, and bcc fields are parenthesized lists of address + * structures. + * An address structure is a parenthesized list that describes an + * electronic mail address. The fields of an address structure + * are in the following order: personal name, [SMTP] + * at-domain-list (source route), mailbox name, and host name. + */ /* -* * 12 FETCH (FLAGS (\Seen) INTERNALDATE "17-Jul-1996 02:44:25 -0700" -* RFC822.SIZE 4286 ENVELOPE ("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)" -* "IMAP4rev1 WG mtg summary and minutes" -* (("Terry Gray" NIL "gray" "cac.washington.edu")) -* (("Terry Gray" NIL "gray" "cac.washington.edu")) -* (("Terry Gray" NIL "gray" "cac.washington.edu")) -* ((NIL NIL "imap" "cac.washington.edu")) -* ((NIL NIL "minutes" "CNRI.Reston.VA.US") -* ("John Klensin" NIL "KLENSIN" "MIT.EDU")) NIL NIL -* "") -*/ + * * 12 FETCH (FLAGS (\Seen) INTERNALDATE "17-Jul-1996 02:44:25 -0700" + * RFC822.SIZE 4286 ENVELOPE ("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)" + * "IMAP4rev1 WG mtg summary and minutes" + * (("Terry Gray" NIL "gray" "cac.washington.edu")) + * (("Terry Gray" NIL "gray" "cac.washington.edu")) + * (("Terry Gray" NIL "gray" "cac.washington.edu")) + * ((NIL NIL "imap" "cac.washington.edu")) + * ((NIL NIL "minutes" "CNRI.Reston.VA.US") + * ("John Klensin" NIL "KLENSIN" "MIT.EDU")) NIL NIL + * "") + */ pub fn envelope(input: &[u8]) -> IResult<&[u8], Envelope> { let (input, _) = tag("(")(input)?; @@ -1466,7 +1516,8 @@ pub fn envelope_address(input: &[u8]) -> IResult<&[u8], Address> { )) } -// Read a literal ie a byte sequence prefixed with a tag containing its length delimited in {}s +// Read a literal ie a byte sequence prefixed with a tag containing its length +// delimited in {}s pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> { length_data(delimited( tag("{"), @@ -1694,7 +1745,8 @@ pub fn string_token(input: &[u8]) -> IResult<&[u8], &[u8]> { // ASTRING-CHAR = ATOM-CHAR / resp-specials // atom = 1*ATOM-CHAR // ATOM-CHAR = -// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials +// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials +// / resp-specials fn astring_char(input: &[u8]) -> IResult<&[u8], &[u8]> { let (rest, chars) = many1(atom_char)(input)?; Ok((rest, &input[0..chars.len()])) diff --git a/melib/src/backends/imap/untagged.rs b/melib/src/backends/imap/untagged.rs index 5f80beb3..89b4df5b 100644 --- a/melib/src/backends/imap/untagged.rs +++ b/melib/src/backends/imap/untagged.rs @@ -19,19 +19,22 @@ * along with meli. If not, see . */ -use super::{ImapConnection, MailboxSelection, UID}; -use crate::backends::imap::protocol_parser::{ - generate_envelope_hash, FetchResponse, ImapLineSplit, RequiredResponses, UntaggedResponse, -}; -use crate::backends::BackendMailbox; -use crate::backends::{ - RefreshEvent, - RefreshEventKind::{self, *}, - TagHash, -}; -use crate::error::*; use std::convert::TryInto; +use super::{ImapConnection, MailboxSelection, UID}; +use crate::{ + backends::{ + imap::protocol_parser::{ + generate_envelope_hash, FetchResponse, ImapLineSplit, RequiredResponses, + UntaggedResponse, + }, + BackendMailbox, RefreshEvent, + RefreshEventKind::{self, *}, + TagHash, + }, + error::*, +}; + impl ImapConnection { pub async fn process_untagged(&mut self, line: &[u8]) -> Result { macro_rules! try_fail { @@ -323,7 +326,11 @@ impl ImapConnection { accum.push(','); accum.push_str(to_str!(ms).trim()); } - format!("UID FETCH {} (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] BODYSTRUCTURE)", accum) + format!( + "UID FETCH {} (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS \ + (REFERENCES)] BODYSTRUCTURE)", + accum + ) }; try_fail!( mailbox_hash, diff --git a/melib/src/backends/imap/watch.rs b/melib/src/backends/imap/watch.rs index 46ae2a2a..61f37040 100644 --- a/melib/src/backends/imap/watch.rs +++ b/melib/src/backends/imap/watch.rs @@ -18,9 +18,10 @@ * You should have received a copy of the GNU General Public License * along with meli. If not, see . */ +use std::sync::Arc; + use super::*; use crate::backends::SpecialUsageMailbox; -use std::sync::Arc; /// Arguments for IMAP watching functions pub struct ImapWatchKit { @@ -52,8 +53,8 @@ pub async fn poll_with_examine(kit: ImapWatchKit) -> Result<()> { pub async fn idle(kit: ImapWatchKit) -> Result<()> { debug!("IDLE"); - /* IDLE only watches the connection's selected mailbox. We will IDLE on INBOX and every ~5 - * minutes wake up and poll the others */ + /* IDLE only watches the connection's selected mailbox. We will IDLE on INBOX + * and every ~5 minutes wake up and poll the others */ let ImapWatchKit { mut conn, main_conn, @@ -70,7 +71,10 @@ pub async fn idle(kit: ImapWatchKit) -> Result<()> { { Some(mailbox) => mailbox, None => { - return Err(Error::new("INBOX mailbox not found in local mailbox index. meli may have not parsed the IMAP mailboxes correctly")); + return Err(Error::new( + "INBOX mailbox not found in local mailbox index. meli may have not parsed the \ + IMAP mailboxes correctly", + )); } }; let mailbox_hash = mailbox.hash(); @@ -342,7 +346,8 @@ pub async fn examine_updates( } else if select_response.exists > mailbox.exists.lock().unwrap().len() { conn.send_command( format!( - "FETCH {}:* (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] BODYSTRUCTURE)", + "FETCH {}:* (UID FLAGS ENVELOPE BODY.PEEK[HEADER.FIELDS (REFERENCES)] \ + BODYSTRUCTURE)", std::cmp::max(mailbox.exists.lock().unwrap().len(), 1) ) .as_bytes(), diff --git a/melib/src/backends/jmap.rs b/melib/src/backends/jmap.rs index 83427f71..54efcabe 100644 --- a/melib/src/backends/jmap.rs +++ b/melib/src/backends/jmap.rs @@ -19,21 +19,26 @@ * along with meli. If not, see . */ -use crate::backends::*; -use crate::conf::AccountSettings; -use crate::connections::timeout; -use crate::email::*; -use crate::error::{Error, Result}; -use crate::Collection; +use std::{ + collections::{HashMap, HashSet}, + convert::TryFrom, + str::FromStr, + sync::{Arc, Mutex, RwLock}, + time::{Duration, Instant}, +}; + use futures::lock::Mutex as FutureMutex; -use isahc::config::RedirectPolicy; -use isahc::{AsyncReadResponseExt, HttpClient}; +use isahc::{config::RedirectPolicy, AsyncReadResponseExt, HttpClient}; use serde_json::Value; -use std::collections::{HashMap, HashSet}; -use std::convert::TryFrom; -use std::str::FromStr; -use std::sync::{Arc, Mutex, RwLock}; -use std::time::{Duration, Instant}; + +use crate::{ + backends::*, + conf::AccountSettings, + connections::timeout, + email::*, + error::{Error, Result}, + Collection, +}; #[macro_export] macro_rules! _impl { @@ -131,7 +136,9 @@ impl JmapServerConf { ^ s.extra.contains_key("server_password")) { return Err(Error::new(format!( - "({}) `use_token` use requires either the `server_password_command` set with a command that returns an Bearer token of your account, or `server_password` with the API Bearer token as a string. Consult documentation for guidance.", + "({}) `use_token` use requires either the `server_password_command` set with a \ + command that returns an Bearer token of your account, or `server_password` with \ + the API Bearer token as a string. Consult documentation for guidance.", s.name, ))); } @@ -416,7 +423,13 @@ impl MailBackend for JmapType { let upload_response: UploadResponse = match serde_json::from_str(&res_text) { Err(err) => { - let err = Error::new(format!("BUG: Could not deserialize {} server JSON response properly, please report this!\nReply from server: {}", &conn.server_conf.server_url, &res_text)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug); + let err = Error::new(format!( + "BUG: Could not deserialize {} server JSON response properly, please \ + report this!\nReply from server: {}", + &conn.server_conf.server_url, &res_text + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } @@ -447,7 +460,13 @@ impl MailBackend for JmapType { let mut v: MethodResponse = match serde_json::from_str(&res_text) { Err(err) => { - let err = Error::new(format!("BUG: Could not deserialize {} server JSON response properly, please report this!\nReply from server: {}", &conn.server_conf.server_url, &res_text)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug); + let err = Error::new(format!( + "BUG: Could not deserialize {} server JSON response properly, please \ + report this!\nReply from server: {}", + &conn.server_conf.server_url, &res_text + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } @@ -528,7 +547,13 @@ impl MailBackend for JmapType { let res_text = res.text().await?; let mut v: MethodResponse = match serde_json::from_str(&res_text) { Err(err) => { - let err = Error::new(format!("BUG: Could not deserialize {} server JSON response properly, please report this!\nReply from server: {}", &conn.server_conf.server_url, &res_text)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug); + let err = Error::new(format!( + "BUG: Could not deserialize {} server JSON response properly, please \ + report this!\nReply from server: {}", + &conn.server_conf.server_url, &res_text + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } @@ -664,7 +689,13 @@ impl MailBackend for JmapType { let mut v: MethodResponse = match serde_json::from_str(&res_text) { Err(err) => { - let err = Error::new(format!("BUG: Could not deserialize {} server JSON response properly, please report this!\nReply from server: {}", &conn.server_conf.server_url, &res_text)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug); + let err = Error::new(format!( + "BUG: Could not deserialize {} server JSON response properly, please \ + report this!\nReply from server: {}", + &conn.server_conf.server_url, &res_text + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } @@ -771,12 +802,22 @@ impl MailBackend for JmapType { let res_text = res.text().await?; /* - *{"methodResponses":[["Email/set",{"notUpdated":null,"notDestroyed":null,"oldState":"86","newState":"87","accountId":"u148940c7","updated":{"M045926eed54b11423918f392":{"id":"M045926eed54b11423918f392"}},"created":null,"destroyed":null,"notCreated":null},"m3"]],"sessionState":"cyrus-0;p-5;vfs-0"} + *{"methodResponses":[["Email/set",{"notUpdated":null,"notDestroyed":null," + * oldState":"86","newState":"87","accountId":"u148940c7","updated":{" + * M045926eed54b11423918f392":{"id":"M045926eed54b11423918f392"}},"created": + * null,"destroyed":null,"notCreated":null},"m3"]],"sessionState":"cyrus-0; + * p-5;vfs-0"} */ //debug!("res_text = {}", &res_text); let mut v: MethodResponse = match serde_json::from_str(&res_text) { Err(err) => { - let err = Error::new(format!("BUG: Could not deserialize {} server JSON response properly, please report this!\nReply from server: {}", &conn.server_conf.server_url, &res_text)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug); + let err = Error::new(format!( + "BUG: Could not deserialize {} server JSON response properly, please \ + report this!\nReply from server: {}", + &conn.server_conf.server_url, &res_text + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } diff --git a/melib/src/backends/jmap/connection.rs b/melib/src/backends/jmap/connection.rs index fd47d2dc..795fdaae 100644 --- a/melib/src/backends/jmap/connection.rs +++ b/melib/src/backends/jmap/connection.rs @@ -19,10 +19,12 @@ * along with meli. If not, see . */ -use super::*; -use isahc::config::Configurable; use std::sync::MutexGuard; +use isahc::config::Configurable; + +use super::*; + #[derive(Debug)] pub struct JmapConnection { pub session: Arc>, @@ -73,11 +75,22 @@ impl JmapConnection { let mut jmap_session_resource_url = self.server_conf.server_url.to_string(); jmap_session_resource_url.push_str("/.well-known/jmap"); - let mut req = self.client.get_async(&jmap_session_resource_url).await.map_err(|err| { - let err = Error::new(format!("Could not connect to JMAP server endpoint for {}. Is your server url setting correct? (i.e. \"jmap.mailserver.org\") (Note: only session resource discovery via /.well-known/jmap is supported. DNS SRV records are not suppported.)\nError connecting to server: {}", &self.server_conf.server_url, &err)).set_source(Some(Arc::new(err))); + let mut req = self + .client + .get_async(&jmap_session_resource_url) + .await + .map_err(|err| { + let err = Error::new(format!( + "Could not connect to JMAP server endpoint for {}. Is your server url setting \ + correct? (i.e. \"jmap.mailserver.org\") (Note: only session resource \ + discovery via /.well-known/jmap is supported. DNS SRV records are not \ + suppported.)\nError connecting to server: {}", + &self.server_conf.server_url, &err + )) + .set_source(Some(Arc::new(err))); //*self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); err - })?; + })?; if !req.status().is_success() { let kind: crate::error::NetworkErrorKind = req.status().into(); @@ -95,7 +108,14 @@ impl JmapConnection { let session: JmapSession = match serde_json::from_str(&res_text) { Err(err) => { - let err = Error::new(format!("Could not connect to JMAP server endpoint for {}. Is your server url setting correct? (i.e. \"jmap.mailserver.org\") (Note: only session resource discovery via /.well-known/jmap is supported. DNS SRV records are not suppported.)\nReply from server: {}", &self.server_conf.server_url, &res_text)).set_source(Some(Arc::new(err))); + let err = Error::new(format!( + "Could not connect to JMAP server endpoint for {}. Is your server url setting \ + correct? (i.e. \"jmap.mailserver.org\") (Note: only session resource \ + discovery via /.well-known/jmap is supported. DNS SRV records are not \ + suppported.)\nReply from server: {}", + &self.server_conf.server_url, &res_text + )) + .set_source(Some(Arc::new(err))); *self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } @@ -105,7 +125,17 @@ impl JmapConnection { .capabilities .contains_key("urn:ietf:params:jmap:core") { - let err = Error::new(format!("Server {} did not return JMAP Core capability (urn:ietf:params:jmap:core). Returned capabilities were: {}", &self.server_conf.server_url, session.capabilities.keys().map(String::as_str).collect::>().join(", "))); + let err = Error::new(format!( + "Server {} did not return JMAP Core capability (urn:ietf:params:jmap:core). \ + Returned capabilities were: {}", + &self.server_conf.server_url, + session + .capabilities + .keys() + .map(String::as_str) + .collect::>() + .join(", ") + )); *self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } @@ -113,7 +143,17 @@ impl JmapConnection { .capabilities .contains_key("urn:ietf:params:jmap:mail") { - let err = Error::new(format!("Server {} does not support JMAP Mail capability (urn:ietf:params:jmap:mail). Returned capabilities were: {}", &self.server_conf.server_url, session.capabilities.keys().map(String::as_str).collect::>().join(", "))); + let err = Error::new(format!( + "Server {} does not support JMAP Mail capability (urn:ietf:params:jmap:mail). \ + Returned capabilities were: {}", + &self.server_conf.server_url, + session + .capabilities + .keys() + .map(String::as_str) + .collect::>() + .join(", ") + )); *self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } @@ -207,7 +247,13 @@ impl JmapConnection { debug!(&res_text); let mut v: MethodResponse = match serde_json::from_str(&res_text) { Err(err) => { - let err = Error::new(format!("BUG: Could not deserialize {} server JSON response properly, please report this!\nReply from server: {}", &self.server_conf.server_url, &res_text)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug); + let err = Error::new(format!( + "BUG: Could not deserialize {} server JSON response properly, please \ + report this!\nReply from server: {}", + &self.server_conf.server_url, &res_text + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug); *self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } diff --git a/melib/src/backends/jmap/mailbox.rs b/melib/src/backends/jmap/mailbox.rs index 023fb1dc..54aed08b 100644 --- a/melib/src/backends/jmap/mailbox.rs +++ b/melib/src/backends/jmap/mailbox.rs @@ -19,9 +19,10 @@ * along with meli. If not, see . */ +use std::sync::{Arc, Mutex, RwLock}; + use super::*; use crate::backends::{LazyCountSet, MailboxPermissions, SpecialUsageMailbox}; -use std::sync::{Arc, Mutex, RwLock}; #[derive(Debug, Clone)] pub struct JmapMailbox { diff --git a/melib/src/backends/jmap/objects/email.rs b/melib/src/backends/jmap/objects/email.rs index 461ce489..64e050a4 100644 --- a/melib/src/backends/jmap/objects/email.rs +++ b/melib/src/backends/jmap/objects/email.rs @@ -19,15 +19,18 @@ * along with meli. If not, see . */ -use super::*; -use crate::backends::jmap::rfc8620::bool_false; -use crate::email::address::{Address, MailboxAddress}; use core::marker::PhantomData; -use serde::de::{Deserialize, Deserializer}; -use serde_json::value::RawValue; -use serde_json::Value; use std::collections::HashMap; +use serde::de::{Deserialize, Deserializer}; +use serde_json::{value::RawValue, Value}; + +use super::*; +use crate::{ + backends::jmap::rfc8620::bool_false, + email::address::{Address, MailboxAddress}, +}; + mod import; pub use import::*; @@ -83,14 +86,13 @@ impl Id { // first character changed from "\" in IMAP to "$" in JMAP and have // particular semantic meaning: // -// * "$draft": The Email is a draft the user is composing. +// * "$draft": The Email is a draft the user is composing. // -// * "$seen": The Email has been read. +// * "$seen": The Email has been read. // -// * "$flagged": The Email has been flagged for urgent/special -// attention. +// * "$flagged": The Email has been flagged for urgent/special attention. // -// * "$answered": The Email has been replied to. +// * "$answered": The Email has been replied to. // // The IMAP "\Recent" keyword is not exposed via JMAP. The IMAP // "\Deleted" keyword is also not present: IMAP uses a delete+expunge @@ -115,19 +117,19 @@ impl Id { // keywords in common use. New keywords may be established here in // the future. In particular, note: // -// * "$forwarded": The Email has been forwarded. +// * "$forwarded": The Email has been forwarded. // -// * "$phishing": The Email is highly likely to be phishing. -// Clients SHOULD warn users to take care when viewing this Email -// and disable links and attachments. +// * "$phishing": The Email is highly likely to be phishing. Clients SHOULD +// warn users to take care when viewing this Email and disable links and +// attachments. // -// * "$junk": The Email is definitely spam. Clients SHOULD set this -// flag when users report spam to help train automated spam- -// detection systems. +// * "$junk": The Email is definitely spam. Clients SHOULD set this flag +// when users report spam to help train automated spam- detection +// systems. // -// * "$notjunk": The Email is definitely not spam. Clients SHOULD -// set this flag when users indicate an Email is legitimate, to -// help train automated spam-detection systems. +// * "$notjunk": The Email is definitely not spam. Clients SHOULD set this +// flag when users indicate an Email is legitimate, to help train +// automated spam-detection systems. // // o size: "UnsignedInt" (immutable; server-set) // @@ -586,8 +588,10 @@ impl From for Filter { fn from(val: crate::search::Query) -> Self { let mut ret = Filter::Condition(EmailFilterCondition::new().into()); fn rec(q: &crate::search::Query, f: &mut Filter) { - use crate::datetime::{timestamp_to_string, RFC3339_FMT}; - use crate::search::Query::*; + use crate::{ + datetime::{timestamp_to_string, RFC3339_FMT}, + search::Query::*, + }; match q { Subject(t) => { *f = Filter::Condition(EmailFilterCondition::new().subject(t.clone()).into()); @@ -849,8 +853,16 @@ pub struct EmailQueryChangesResponse { impl std::convert::TryFrom<&RawValue> for EmailQueryChangesResponse { type Error = crate::error::Error; fn try_from(t: &RawValue) -> Result { - let res: (String, EmailQueryChangesResponse, String) = - serde_json::from_str(t.get()).map_err(|err| crate::error::Error::new(format!("BUG: Could not deserialize server JSON response properly, please report this!\nReply from server: {}", &t)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug))?; + let res: (String, EmailQueryChangesResponse, String) = serde_json::from_str(t.get()) + .map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug) + })?; assert_eq!(&res.0, "Email/queryChanges"); Ok(res.1) } diff --git a/melib/src/backends/jmap/objects/email/import.rs b/melib/src/backends/jmap/objects/email/import.rs index dffff920..475b9d3f 100644 --- a/melib/src/backends/jmap/objects/email/import.rs +++ b/melib/src/backends/jmap/objects/email/import.rs @@ -19,9 +19,10 @@ * along with meli. If not, see . */ -use super::*; use serde_json::value::RawValue; +use super::*; + /// #`import` /// /// Objects of type `Foo` are imported via a call to `Foo/import`. @@ -31,7 +32,6 @@ use serde_json::value::RawValue; /// - `account_id`: "Id" /// /// The id of the account to use. -/// #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct ImportCall { @@ -81,10 +81,9 @@ impl ImportCall { } _impl!( - /// - accountId: "Id" + /// - accountId: "Id" /// /// The id of the account to use. - /// account_id: Id ); _impl!(if_in_state: Option>); @@ -123,9 +122,10 @@ pub enum ImportError { AlreadyExists { description: Option, /// An "existingId" property of type "Id" MUST be included on - ///the SetError object with the id of the existing Email. If duplicates - ///are allowed, the newly created Email object MUST have a separate id - ///and independent mutable properties to the existing object. + ///the SetError object with the id of the existing Email. If + /// duplicates are allowed, the newly created Email object MUST + /// have a separate id and independent mutable properties to the + /// existing object. existing_id: Id, }, ///If the "blobId", "mailboxIds", or "keywords" properties are invalid @@ -146,7 +146,8 @@ pub enum ImportError { ///different to the "blobId" on the EmailImport object. Alternatively, ///the server MAY reject the import with an "invalidEmail" SetError. InvalidEmail { description: Option }, - ///An "ifInState" argument was supplied, and it does not match the current state. + ///An "ifInState" argument was supplied, and it does not match the current + /// state. StateMismatch, } @@ -185,7 +186,15 @@ impl std::convert::TryFrom<&RawValue> for ImportResponse { type Error = crate::error::Error; fn try_from(t: &RawValue) -> Result { let res: (String, ImportResponse, String) = - serde_json::from_str(t.get()).map_err(|err| crate::error::Error::new(format!("BUG: Could not deserialize server JSON response properly, please report this!\nReply from server: {}", &t)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug))?; + serde_json::from_str(t.get()).map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug) + })?; assert_eq!(&res.0, &ImportCall::NAME); Ok(res.1) } diff --git a/melib/src/backends/jmap/operations.rs b/melib/src/backends/jmap/operations.rs index ffe739cd..b0fb0f32 100644 --- a/melib/src/backends/jmap/operations.rs +++ b/melib/src/backends/jmap/operations.rs @@ -19,9 +19,10 @@ * along with meli. If not, see . */ -use super::*; use std::sync::Arc; +use super::*; + /// `BackendOp` implementor for Imap #[derive(Debug, Clone)] pub struct JmapOp { diff --git a/melib/src/backends/jmap/protocol.rs b/melib/src/backends/jmap/protocol.rs index 264ce633..e8c27096 100644 --- a/melib/src/backends/jmap/protocol.rs +++ b/melib/src/backends/jmap/protocol.rs @@ -19,11 +19,12 @@ * along with meli. If not, see . */ -use super::mailbox::JmapMailbox; -use super::*; +use std::convert::{TryFrom, TryInto}; + use serde::Serialize; use serde_json::{json, Value}; -use std::convert::{TryFrom, TryInto}; + +use super::{mailbox::JmapMailbox, *}; pub type UtcDate = String; @@ -97,7 +98,13 @@ pub async fn get_mailboxes(conn: &JmapConnection) -> Result { - let err = Error::new(format!("BUG: Could not deserialize {} server JSON response properly, please report this!\nReply from server: {}", &conn.server_conf.server_url, &res_text)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug); + let err = Error::new(format!( + "BUG: Could not deserialize {} server JSON response properly, please report \ + this!\nReply from server: {}", + &conn.server_conf.server_url, &res_text + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } @@ -108,8 +115,9 @@ pub async fn get_mailboxes(conn: &JmapConnection) -> Result { list, account_id, .. } = m; - // Is account set as `personal`? (`isPersonal` property). Then, even if `isSubscribed` is false - // on a mailbox, it should be regarded as subscribed. + // Is account set as `personal`? (`isPersonal` property). Then, even if + // `isSubscribed` is false on a mailbox, it should be regarded as + // subscribed. let is_personal: bool = { let session = conn.session_guard(); session @@ -204,7 +212,13 @@ pub async fn get_message_list( let res_text = res.text().await?; let mut v: MethodResponse = match serde_json::from_str(&res_text) { Err(err) => { - let err = Error::new(format!("BUG: Could not deserialize {} server JSON response properly, please report this!\nReply from server: {}", &conn.server_conf.server_url, &res_text)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug); + let err = Error::new(format!( + "BUG: Could not deserialize {} server JSON response properly, please report \ + this!\nReply from server: {}", + &conn.server_conf.server_url, &res_text + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } @@ -284,7 +298,13 @@ pub async fn fetch( let mut v: MethodResponse = match serde_json::from_str(&res_text) { Err(err) => { - let err = Error::new(format!("BUG: Could not deserialize {} server JSON response properly, please report this!\nReply from server: {}", &conn.server_conf.server_url, &res_text)).set_source(Some(Arc::new(err))).set_kind(ErrorKind::Bug); + let err = Error::new(format!( + "BUG: Could not deserialize {} server JSON response properly, please report \ + this!\nReply from server: {}", + &conn.server_conf.server_url, &res_text + )) + .set_source(Some(Arc::new(err))) + .set_kind(ErrorKind::Bug); *conn.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } diff --git a/melib/src/backends/jmap/rfc8620.rs b/melib/src/backends/jmap/rfc8620.rs index bc394f59..fb55c5f2 100644 --- a/melib/src/backends/jmap/rfc8620.rs +++ b/melib/src/backends/jmap/rfc8620.rs @@ -19,23 +19,30 @@ * along with meli. If not, see . */ -use crate::email::parser::BytesExt; use core::marker::PhantomData; -use serde::de::DeserializeOwned; -use serde::ser::{Serialize, SerializeStruct, Serializer}; +use std::{ + hash::{Hash, Hasher}, + sync::Arc, +}; + +use serde::{ + de::DeserializeOwned, + ser::{Serialize, SerializeStruct, Serializer}, +}; use serde_json::{value::RawValue, Value}; -use std::hash::{Hash, Hasher}; -use std::sync::Arc; + +use crate::email::parser::BytesExt; mod filters; pub use filters::*; mod comparator; pub use comparator::*; mod argument; +use std::collections::HashMap; + pub use argument::*; use super::protocol::Method; -use std::collections::HashMap; pub trait Object { const NAME: &'static str; } @@ -275,7 +282,6 @@ impl Object for BlobObject { /// - `account_id`: "Id" /// /// The id of the account to use. -/// #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct Get @@ -305,31 +311,30 @@ where } } _impl!( - /// - accountId: "Id" + /// - accountId: "Id" /// /// The id of the account to use. - /// account_id: Id ); _impl!( - /// - ids: `Option>>` - /// - /// The ids of the Foo objects to return. If `None`, then *all* records - /// of the data type are returned, if this is supported for that data - /// type and the number of records does not exceed the - /// "max_objects_in_get" limit. + /// - ids: `Option>>` /// + /// The ids of the Foo objects to return. If `None`, then *all* + /// records of the data type are returned, if this is + /// supported for that data type and the number of records + /// does not exceed the "max_objects_in_get" limit. ids: Option>>> ); _impl!( - /// - properties: Option> + /// - properties: Option> /// - /// If supplied, only the properties listed in the array are returned - /// for each `Foo` object. If `None`, all properties of the object are - /// returned. The `id` property of the object is *always* returned, - /// even if not explicitly requested. If an invalid property is - /// requested, the call WILL be rejected with an "invalid_arguments" - /// error. + /// If supplied, only the properties listed in the array are + /// returned for each `Foo` object. If `None`, all + /// properties of the object are returned. The `id` + /// property of the object is *always* returned, even if + /// not explicitly requested. If an invalid property is + /// requested, the call WILL be rejected with an + /// "invalid_arguments" error. properties: Option> ); } @@ -414,7 +419,15 @@ impl std::convert::TryFrom<&RawValue> for GetRes type Error = crate::error::Error; fn try_from(t: &RawValue) -> Result, crate::error::Error> { let res: (String, GetResponse, String) = - serde_json::from_str(t.get()).map_err(|err| crate::error::Error::new(format!("BUG: Could not deserialize server JSON response properly, please report this!\nReply from server: {}", &t)).set_source(Some(Arc::new(err))).set_kind(crate::error::ErrorKind::Bug))?; + serde_json::from_str(t.get()).map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(crate::error::ErrorKind::Bug) + })?; assert_eq!(&res.0, &format!("{}/get", OBJ::NAME)); Ok(res.1) } @@ -519,7 +532,15 @@ impl std::convert::TryFrom<&RawValue> for QueryR type Error = crate::error::Error; fn try_from(t: &RawValue) -> Result, crate::error::Error> { let res: (String, QueryResponse, String) = - serde_json::from_str(t.get()).map_err(|err| crate::error::Error::new(format!("BUG: Could not deserialize server JSON response properly, please report this!\nReply from server: {}", &t)).set_source(Some(Arc::new(err))).set_kind(crate::error::ErrorKind::Bug))?; + serde_json::from_str(t.get()).map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(crate::error::ErrorKind::Bug) + })?; assert_eq!(&res.0, &format!("{}/query", OBJ::NAME)); Ok(res.1) } @@ -543,8 +564,8 @@ impl, OBJ: Object> ResultField { } } -// error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable -// --> melib/src/backends/jmap/rfc8620.rs:626:6 +// error[E0723]: trait bounds other than `Sized` on const fn parameters are +// unstable --> melib/src/backends/jmap/rfc8620.rs:626:6 // | // 626 | impl, OBJ: Object> ResultField { // | ^ @@ -562,8 +583,9 @@ impl, OBJ: Object> ResultField { /// #`changes` /// -/// The "Foo/changes" method allows a client to efficiently update the state of its Foo cache -/// to match the new state on the server. It takes the following arguments: +/// The "Foo/changes" method allows a client to efficiently update the state +/// of its Foo cache to match the new state on the server. It takes the +/// following arguments: /// /// - accountId: "Id" The id of the account to use. /// - sinceState: "String" @@ -579,7 +601,6 @@ impl, OBJ: Object> ResultField { /// to return. If supplied by the client, the value MUST be a /// positive integer greater than 0. If a value outside of this range /// is given, the server MUST re -/// #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] /* ch-ch-ch-ch-ch-Changes */ @@ -608,10 +629,9 @@ where } } _impl!( - /// - accountId: "Id" + /// - accountId: "Id" /// /// The id of the account to use. - /// account_id: Id ); _impl!( @@ -620,8 +640,6 @@ where /// returned as the "state" argument in the "Foo/get" response. The /// server will return the changes that have occurred since this /// state. - /// - /// since_state: State ); _impl!( @@ -630,8 +648,8 @@ where /// MAY choose to return fewer than this value but MUST NOT return /// more. If not given by the client, the server may choose how many /// to return. If supplied by the client, the value MUST be a - /// positive integer greater than 0. If a value outside of this range - /// is given, the server MUST re + /// positive integer greater than 0. If a value outside of this + /// range is given, the server MUST re max_changes: Option ); } @@ -654,7 +672,15 @@ impl std::convert::TryFrom<&RawValue> for Change type Error = crate::error::Error; fn try_from(t: &RawValue) -> Result, crate::error::Error> { let res: (String, ChangesResponse, String) = - serde_json::from_str(t.get()).map_err(|err| crate::error::Error::new(format!("BUG: Could not deserialize server JSON response properly, please report this!\nReply from server: {}", &t)).set_source(Some(Arc::new(err))).set_kind(crate::error::ErrorKind::Bug))?; + serde_json::from_str(t.get()).map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(crate::error::ErrorKind::Bug) + })?; assert_eq!(&res.0, &format!("{}/changes", OBJ::NAME)); Ok(res.1) } @@ -707,7 +733,6 @@ where /// /// The client MUST omit any properties that may only be set by the /// server (for example, the "id" property on most object types). - /// pub create: Option, OBJ>>, ///o update: "Id[PatchObject]|null" /// @@ -722,26 +747,26 @@ where /// All paths MUST also conform to the following restrictions; if /// there is any violation, the update MUST be rejected with an /// "invalidPatch" error: - /// * The pointer MUST NOT reference inside an array (i.e., you MUST - /// NOT insert/delete from an array; the array MUST be replaced in - /// its entirety instead). + /// * The pointer MUST NOT reference inside an array (i.e., you MUST NOT + /// insert/delete from an array; the array MUST be replaced in its + /// entirety instead). /// - /// * All parts prior to the last (i.e., the value after the final - /// slash) MUST already exist on the object being patched. + /// * All parts prior to the last (i.e., the value after the final slash) + /// MUST already exist on the object being patched. /// - /// * There MUST NOT be two patches in the PatchObject where the - /// pointer of one is the prefix of the pointer of the other, e.g., - /// "alerts/1/offset" and "alerts". + /// * There MUST NOT be two patches in the PatchObject where the pointer + /// of one is the prefix of the pointer of the other, e.g., + /// "alerts/1/offset" and "alerts". /// /// The value associated with each pointer determines how to apply /// that patch: /// - /// * If null, set to the default value if specified for this - /// property; otherwise, remove the property from the patched - /// object. If the key is not present in the parent, this a no-op. + /// * If null, set to the default value if specified for this property; + /// otherwise, remove the property from the patched object. If the key + /// is not present in the parent, this a no-op. /// - /// * Anything else: The value to set for this property (this may be - /// a replacement or addition to the object being patched). + /// * Anything else: The value to set for this property (this may be a + /// replacement or addition to the object being patched). /// /// Any server-set properties MAY be included in the patch if their /// value is identical to the current server value (before applying @@ -853,7 +878,15 @@ impl std::convert::TryFrom<&RawValue> for SetRes type Error = crate::error::Error; fn try_from(t: &RawValue) -> Result, crate::error::Error> { let res: (String, SetResponse, String) = - serde_json::from_str(t.get()).map_err(|err| crate::error::Error::new(format!("BUG: Could not deserialize server JSON response properly, please report this!\nReply from server: {}", &t)).set_source(Some(Arc::new(err))).set_kind(crate::error::ErrorKind::Bug))?; + serde_json::from_str(t.get()).map_err(|err| { + crate::error::Error::new(format!( + "BUG: Could not deserialize server JSON response properly, please report \ + this!\nReply from server: {}", + &t + )) + .set_source(Some(Arc::new(err))) + .set_kind(crate::error::ErrorKind::Bug) + })?; assert_eq!(&res.0, &format!("{}/set", OBJ::NAME)); Ok(res.1) } @@ -863,31 +896,41 @@ impl std::convert::TryFrom<&RawValue> for SetRes #[serde(rename_all = "camelCase")] #[serde(tag = "type", content = "description")] pub enum SetError { - ///(create; update; destroy). The create/update/destroy would violate an ACL or other permissions policy. + ///(create; update; destroy). The create/update/destroy would violate an + /// ACL or other permissions policy. Forbidden(Option), - ///(create; update). The create would exceed a server- defined limit on the number or total size of objects of this type. + ///(create; update). The create would exceed a server- defined limit on + /// the number or total size of objects of this type. OverQuota(Option), - ///(create; update). The create/update would result in an object that exceeds a server-defined limit for the maximum size of a single object of this type. + ///(create; update). The create/update would result in an object that + /// exceeds a server-defined limit for the maximum size of a single object + /// of this type. TooLarge(Option), - ///(create). Too many objects of this type have been created recently, and a server-defined rate limit has been reached. It may work if tried again later. + ///(create). Too many objects of this type have been created recently, and + /// a server-defined rate limit has been reached. It may work if tried + /// again later. RateLimit(Option), ///(update; destroy). The id given to update/destroy cannot be found. NotFound(Option), - ///(update). The PatchObject given to update the record was not a valid patch (see the patch description). + ///(update). The PatchObject given to update the record was not a valid + /// patch (see the patch description). InvalidPatch(Option), - ///(update). The client requested that an object be both updated and destroyed in the same /set request, and the server has decided to therefore ignore the update. + ///(update). The client requested that an object be both updated and + /// destroyed in the same /set request, and the server has decided to + /// therefore ignore the update. WillDestroy(Option), ///(create; update). The record given is invalid in some way. InvalidProperties { description: Option, properties: Vec, }, - ///(create; destroy). This is a singleton type, so you cannot create another one or destroy the existing one. + ///(create; destroy). This is a singleton type, so you cannot create + /// another one or destroy the existing one. Singleton(Option), RequestTooLarge(Option), StateMismatch(Option), @@ -1001,8 +1044,9 @@ pub struct UploadResponse { pub account_id: Id, ///o blobId: "Id" /// - ///The id representing the binary data uploaded. The data for this id is immutable. - ///The id *only* refers to the binary data, not any metadata. + ///The id representing the binary data uploaded. The data for this id is + /// immutable. The id *only* refers to the binary data, not any + /// metadata. pub blob_id: Id, ///o type: "String" /// @@ -1098,11 +1142,15 @@ where pub struct QueryChangesResponse { /// The id of the account used for the call. pub account_id: Id, - /// This is the "sinceQueryState" argument echoed back; that is, the state from which the server is returning changes. + /// This is the "sinceQueryState" argument echoed back; that is, the state + /// from which the server is returning changes. pub old_query_state: String, - ///This is the state the query will be in after applying the set of changes to the old state. + ///This is the state the query will be in after applying the set of changes + /// to the old state. pub new_query_state: String, - /// The total number of Foos in the results (given the "filter"). This argument MUST be omitted if the "calculateTotal" request argument is not true. + /// The total number of Foos in the results (given the "filter"). This + /// argument MUST be omitted if the "calculateTotal" request argument is not + /// true. #[serde(default)] pub total: Option, ///The "id" for every Foo that was in the query results in the old @@ -1139,9 +1187,9 @@ pub struct QueryChangesResponse { ///An *AddedItem* object has the following properties: - ///* id: "Id" + /// * id: "Id" - ///* index: "UnsignedInt" + /// * index: "UnsignedInt" ///The result of this is that if the client has a cached sparse array of ///Foo ids corresponding to the results in the old state, then: diff --git a/melib/src/backends/jmap/rfc8620/argument.rs b/melib/src/backends/jmap/rfc8620/argument.rs index 1410d0b8..932579b9 100644 --- a/melib/src/backends/jmap/rfc8620/argument.rs +++ b/melib/src/backends/jmap/rfc8620/argument.rs @@ -19,9 +19,10 @@ * along with meli. If not, see . */ -use crate::backends::jmap::protocol::Method; -use crate::backends::jmap::rfc8620::Object; -use crate::backends::jmap::rfc8620::ResultField; +use crate::backends::jmap::{ + protocol::Method, + rfc8620::{Object, ResultField}, +}; #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] diff --git a/melib/src/backends/maildir.rs b/melib/src/backends/maildir.rs index dbfd57fe..97b4aaf7 100644 --- a/melib/src/backends/maildir.rs +++ b/melib/src/backends/maildir.rs @@ -24,19 +24,24 @@ mod backend; pub use self::backend::*; mod stream; +use std::{ + collections::hash_map::DefaultHasher, + fs, + hash::{Hash, Hasher}, + io::{BufReader, Read}, + path::{Path, PathBuf}, + sync::{Arc, Mutex}, +}; + +use futures::stream::Stream; pub use stream::*; -use crate::backends::*; -use crate::email::Flag; -use crate::error::{Error, Result}; -use crate::shellexpand::ShellExpandTrait; -use futures::stream::Stream; -use std::collections::hash_map::DefaultHasher; -use std::fs; -use std::hash::{Hash, Hasher}; -use std::io::{BufReader, Read}; -use std::path::{Path, PathBuf}; -use std::sync::{Arc, Mutex}; +use crate::{ + backends::*, + email::Flag, + error::{Error, Result}, + shellexpand::ShellExpandTrait, +}; /// `BackendOp` implementor for Maildir #[derive(Debug)] @@ -96,7 +101,7 @@ impl<'a> BackendOp for MaildirOp { let file = std::fs::OpenOptions::new() .read(true) .write(false) - .open(&self.path()?)?; + .open(self.path()?)?; let mut buf_reader = BufReader::new(file); let mut contents = Vec::new(); buf_reader.read_to_end(&mut contents)?; @@ -141,8 +146,8 @@ impl MaildirMailbox { let mut h = DefaultHasher::new(); pathbuf.hash(&mut h); - /* Check if mailbox path (Eg `INBOX/Lists/luddites`) is included in the subscribed - * mailboxes in user configuration */ + /* Check if mailbox path (Eg `INBOX/Lists/luddites`) is included in the + * subscribed mailboxes in user configuration */ let fname = pathbuf .strip_prefix( PathBuf::from(&settings.root_mailbox) @@ -279,7 +284,11 @@ impl MaildirPathTrait for Path { 'S' => flag |= Flag::SEEN, 'T' => flag |= Flag::TRASHED, _ => { - debug!("DEBUG: in MaildirPathTrait::flags(), encountered unknown flag marker {:?}, path is {}", f, path); + debug!( + "DEBUG: in MaildirPathTrait::flags(), encountered unknown flag marker \ + {:?}, path is {}", + f, path + ); } } } diff --git a/melib/src/backends/maildir/backend.rs b/melib/src/backends/maildir/backend.rs index 0ca01fc5..620d3c00 100644 --- a/melib/src/backends/maildir/backend.rs +++ b/melib/src/backends/maildir/backend.rs @@ -21,32 +21,36 @@ //! # Maildir Backend //! -//! This module implements a maildir backend according to the maildir specification. -//! +//! This module implements a maildir backend according to the maildir +//! specification. -use super::{MaildirMailbox, MaildirOp, MaildirPathTrait}; -use crate::backends::{RefreshEventKind::*, *}; -use crate::conf::AccountSettings; -use crate::email::{Envelope, EnvelopeHash, Flag}; -use crate::error::{Error, ErrorKind, Result}; -use crate::shellexpand::ShellExpandTrait; -use crate::Collection; use futures::prelude::Stream; -extern crate notify; -use self::notify::{watcher, DebouncedEvent, RecursiveMode, Watcher}; -use std::time::Duration; +use super::{MaildirMailbox, MaildirOp, MaildirPathTrait}; +use crate::{ + backends::{RefreshEventKind::*, *}, + conf::AccountSettings, + email::{Envelope, EnvelopeHash, Flag}, + error::{Error, ErrorKind, Result}, + shellexpand::ShellExpandTrait, + Collection, +}; -use std::collections::{hash_map::DefaultHasher, HashMap, HashSet}; -use std::ffi::OsStr; -use std::fs; -use std::hash::{Hash, Hasher}; -use std::io::{self, Read, Write}; -use std::ops::{Deref, DerefMut}; -use std::os::unix::fs::PermissionsExt; -use std::path::{Component, Path, PathBuf}; -use std::sync::mpsc::channel; -use std::sync::{Arc, Mutex}; +extern crate notify; +use std::{ + collections::{hash_map::DefaultHasher, HashMap, HashSet}, + ffi::OsStr, + fs, + hash::{Hash, Hasher}, + io::{self, Read, Write}, + ops::{Deref, DerefMut}, + os::unix::fs::PermissionsExt, + path::{Component, Path, PathBuf}, + sync::{mpsc::channel, Arc, Mutex}, + time::Duration, +}; + +use self::notify::{watcher, DebouncedEvent, RecursiveMode, Watcher}; #[derive(Clone, Debug, PartialEq)] pub(super) enum PathMod { @@ -669,7 +673,10 @@ impl MailBackend for MaildirType { e.modified = Some(PathMod::Hash(new_hash)); e.removed = false; }); - debug!("contains_old_key, key was marked as removed (by external source)"); + debug!( + "contains_old_key, key was marked as removed (by external \ + source)" + ); } else { debug!("not contains_new_key"); } @@ -893,7 +900,7 @@ impl MailBackend for MaildirType { Some(PathMod::Path(new_name.clone())); debug!("renaming {:?} to {:?}", path, new_name); - fs::rename(&path, &new_name)?; + fs::rename(path, &new_name)?; debug!("success in rename"); } Ok(()) @@ -996,12 +1003,16 @@ impl MailBackend for MaildirType { let mut path = self.path.clone(); path.push(&new_path); if !path.starts_with(&self.path) { - return Err(Error::new(format!("Path given (`{}`) is absolute. Please provide a path relative to the account's root mailbox.", &new_path))); + return Err(Error::new(format!( + "Path given (`{}`) is absolute. Please provide a path relative to the account's \ + root mailbox.", + &new_path + ))); } std::fs::create_dir(&path)?; - /* create_dir does not create intermediate directories (like `mkdir -p`), so the parent must be a valid - * mailbox at this point. */ + /* create_dir does not create intermediate directories (like `mkdir -p`), so + * the parent must be a valid mailbox at this point. */ let parent = path.parent().and_then(|p| { self.mailboxes @@ -1143,8 +1154,9 @@ impl MaildirType { children.push(f.hash); mailboxes.insert(f.hash, f); } else { - /* If directory is invalid (i.e. has no {cur,new,tmp} subfolders), - * accept it ONLY if it contains subdirs of any depth that are + /* If directory is invalid (i.e. has no {cur,new,tmp} + * subfolders), accept it ONLY if + * it contains subdirs of any depth that are * valid maildir paths */ let subdirs = recurse_mailboxes(mailboxes, settings, &path)?; @@ -1379,7 +1391,7 @@ fn add_path_to_index( map.len() ); } - let mut reader = io::BufReader::new(fs::File::open(&path)?); + let mut reader = io::BufReader::new(fs::File::open(path)?); buf.clear(); reader.read_to_end(buf)?; let mut env = Envelope::from_bytes(buf.as_slice(), Some(path.flags()))?; diff --git a/melib/src/backends/maildir/stream.rs b/melib/src/backends/maildir/stream.rs index adc408f8..c0bc57ce 100644 --- a/melib/src/backends/maildir/stream.rs +++ b/melib/src/backends/maildir/stream.rs @@ -19,17 +19,22 @@ * along with meli. If not, see . */ +use core::{future::Future, pin::Pin}; +use std::{ + io::{self, Read}, + os::unix::fs::PermissionsExt, + path::PathBuf, + result, + sync::{Arc, Mutex}, +}; + +use futures::{ + stream::{FuturesUnordered, StreamExt}, + task::{Context, Poll}, +}; + use super::*; use crate::backends::maildir::backend::move_to_cur; -use core::future::Future; -use core::pin::Pin; -use futures::stream::{FuturesUnordered, StreamExt}; -use futures::task::{Context, Poll}; -use std::io::{self, Read}; -use std::os::unix::fs::PermissionsExt; -use std::path::PathBuf; -use std::result; -use std::sync::{Arc, Mutex}; pub struct MaildirStream { payloads: Pin< @@ -66,7 +71,7 @@ impl MaildirStream { files .chunks(chunk_size) .map(|chunk| { - let cache_dir = xdg::BaseDirectories::with_profile("meli", &name).unwrap(); + let cache_dir = xdg::BaseDirectories::with_profile("meli", name).unwrap(); Box::pin(Self::chunk( SmallVec::from(chunk), cache_dir, diff --git a/melib/src/backends/mbox.rs b/melib/src/backends/mbox.rs index 3f8a1a84..0304a957 100644 --- a/melib/src/backends/mbox.rs +++ b/melib/src/backends/mbox.rs @@ -31,36 +31,44 @@ //! //! `mbox` describes a family of incompatible legacy formats. //! -//! "All of the 'mbox' formats store all of the messages in the mailbox in a single file. Delivery appends new messages to the end of the file." [^0] +//! "All of the 'mbox' formats store all of the messages in the mailbox in a +//! single file. Delivery appends new messages to the end of the file." [^0] //! -//! "Each message is preceded by a From_ line and followed by a blank line. A From_ line is a line that begins with the five characters 'F', 'r', 'o', 'm', and ' '." [^0] +//! "Each message is preceded by a From_ line and followed by a blank line. A +//! From_ line is a line that begins with the five characters 'F', 'r', 'o', +//! 'm', and ' '." [^0] //! //! ## `From ` / postmark line //! -//! "An mbox is a text file containing an arbitrary number of e-mail messages. Each message -//! consists of a postmark, followed by an e-mail message formatted according to RFC822, RFC2822. -//! The file format is line-oriented. Lines are separated by line feed characters (ASCII 10). +//! "An mbox is a text file containing an arbitrary number of e-mail messages. +//! Each message consists of a postmark, followed by an e-mail message formatted +//! according to RFC822, RFC2822. The file format is line-oriented. Lines are +//! separated by line feed characters (ASCII 10). //! -//! "A postmark line consists of the four characters 'From', followed by a space character, -//! followed by the message's envelope sender address, followed by whitespace, and followed by a -//! time stamp. This line is often called From_ line. +//! "A postmark line consists of the four characters 'From', followed by a space +//! character, followed by the message's envelope sender address, followed by +//! whitespace, and followed by a time stamp. This line is often called From_ +//! line. //! -//! "The sender address is expected to be addr-spec as defined in RFC2822 3.4.1. The date is expected -//! to be date-time as output by asctime(3). For compatibility reasons with legacy software, -//! two-digit years greater than or equal to 70 should be interpreted as the years 1970+, while -//! two-digit years less than 70 should be interpreted as the years 2000-2069. Software reading -//! files in this format should also be prepared to accept non-numeric timezone information such as -//! 'CET DST' for Central European Time, daylight saving time. +//! "The sender address is expected to be addr-spec as defined in RFC2822 3.4.1. +//! The date is expected to be date-time as output by asctime(3). For +//! compatibility reasons with legacy software, two-digit years greater than or +//! equal to 70 should be interpreted as the years 1970+, while two-digit years +//! less than 70 should be interpreted as the years 2000-2069. Software reading +//! files in this format should also be prepared to accept non-numeric timezone +//! information such as 'CET DST' for Central European Time, daylight saving +//! time. //! //! "Example: //! //!```text -//!From example@example.com Fri Jun 23 02:56:55 2000 -//!``` +//! From example@example.com Fri Jun 23 02:56:55 2000 +//! ``` //! -//! "In order to avoid misinterpretation of lines in message bodies which begin with the four -//! characters 'From', followed by a space character, the mail delivery agent must quote -//! any occurrence of 'From ' at the start of a body line." [^2] +//! "In order to avoid misinterpretation of lines in message bodies which begin +//! with the four characters 'From', followed by a space character, the mail +//! delivery agent must quote any occurrence of 'From ' at the start of a body +//! line." [^2] //! //! ## Metadata //! @@ -77,7 +85,8 @@ //! # use std::collections::HashMap; //! # use std::sync::{Arc, Mutex}; //! let file_contents = vec![]; // Replace with actual mbox file contents -//! let index: Arc>> = Arc::new(Mutex::new(HashMap::default())); +//! let index: Arc>> = +//! Arc::new(Mutex::new(HashMap::default())); //! let mut message_iter = MessageIterator { //! index: index.clone(), //! input: &file_contents.as_slice(), @@ -100,9 +109,9 @@ //! format.append( //! &mut file, //! mbox_1, -//! None, // Envelope From +//! None, // Envelope From //! Some(melib::datetime::now()), // Delivered date -//! Default::default(), // Flags and tags +//! Default::default(), // Flags and tags //! MboxMetadata::None, //! true, //! false, @@ -121,29 +130,37 @@ //! # Ok::<(), melib::Error>(()) //! ``` -use crate::backends::*; -use crate::collection::Collection; -use crate::conf::AccountSettings; -use crate::email::parser::BytesExt; -use crate::email::*; -use crate::error::{Error, ErrorKind, Result}; -use crate::get_path_hash; -use crate::shellexpand::ShellExpandTrait; -use nom::bytes::complete::tag; -use nom::character::complete::digit1; -use nom::combinator::map_res; -use nom::{self, error::Error as NomError, error::ErrorKind as NomErrorKind, IResult}; +use nom::{ + self, + bytes::complete::tag, + character::complete::digit1, + combinator::map_res, + error::{Error as NomError, ErrorKind as NomErrorKind}, + IResult, +}; + +use crate::{ + backends::*, + collection::Collection, + conf::AccountSettings, + email::{parser::BytesExt, *}, + error::{Error, ErrorKind, Result}, + get_path_hash, + shellexpand::ShellExpandTrait, +}; extern crate notify; +use std::{ + collections::hash_map::HashMap, + fs::File, + io::{BufReader, Read}, + os::unix::io::AsRawFd, + path::{Path, PathBuf}, + str::FromStr, + sync::{mpsc::channel, Arc, Mutex, RwLock}, +}; + use self::notify::{watcher, DebouncedEvent, RecursiveMode, Watcher}; -use std::collections::hash_map::HashMap; -use std::fs::File; -use std::io::{BufReader, Read}; -use std::os::unix::io::AsRawFd; -use std::path::{Path, PathBuf}; -use std::str::FromStr; -use std::sync::mpsc::channel; -use std::sync::{Arc, Mutex, RwLock}; pub mod write; @@ -163,7 +180,8 @@ fn get_rw_lock_blocking(f: &File, path: &Path) -> Result<()> { l_start: 0, l_len: 0, /* "Specifying 0 for l_len has the special meaning: lock all bytes starting at the location specified by l_whence and l_start through to the end of file, no matter how large the file grows." */ - l_pid: 0, /* "By contrast with traditional record locks, the l_pid field of that structure must be set to zero when using the commands described below." */ + l_pid: 0, /* "By contrast with traditional record locks, the l_pid field of that + * structure must be set to zero when using the commands described below." */ #[cfg(target_os = "freebsd")] l_sysid: 0, }; @@ -368,9 +386,12 @@ impl BackendOp for MboxOp { #[derive(Debug, Clone, Copy)] pub enum MboxMetadata { - /// Dovecot uses C-Client (ie. UW-IMAP, Pine) compatible headers in mbox messages to store me - /// - X-IMAPbase: Contains UIDVALIDITY, last used UID and list of used keywords - /// - X-IMAP: Same as X-IMAPbase but also specifies that the message is a “pseudo message” + /// Dovecot uses C-Client (ie. UW-IMAP, Pine) compatible headers in mbox + /// messages to store me + /// - X-IMAPbase: Contains UIDVALIDITY, last used UID and list of used + /// keywords + /// - X-IMAP: Same as X-IMAPbase but also specifies that the message is a + /// “pseudo message” /// - X-UID: Message’s allocated UID /// - Status: R (Seen) and O (non-Recent) flags /// - X-Status: A (Answered), F (Flagged), T (Draft) and D (Deleted) flags @@ -380,8 +401,8 @@ pub enum MboxMetadata { None, } -/// Choose between "mboxo", "mboxrd", "mboxcl", "mboxcl2". For new mailboxes, prefer "mboxcl2" -/// which does not alter the mail body. +/// Choose between "mboxo", "mboxrd", "mboxcl", "mboxcl2". For new mailboxes, +/// prefer "mboxcl2" which does not alter the mail body. #[derive(Debug, Clone, Copy)] pub enum MboxFormat { MboxO, @@ -1406,7 +1427,8 @@ impl MboxType { ); } else { return Err(Error::new(format!( - "mbox mailbox configuration entry \"{}\" should have a \"path\" value set pointing to an mbox file.", + "mbox mailbox configuration entry \"{}\" should have a \"path\" value set \ + pointing to an mbox file.", k ))); } diff --git a/melib/src/backends/nntp.rs b/melib/src/backends/nntp.rs index 4615bc9b..a6d96f21 100644 --- a/melib/src/backends/nntp.rs +++ b/melib/src/backends/nntp.rs @@ -21,14 +21,14 @@ //! # NNTP backend / client //! -//! Implements an NNTP client as specified by [RFC 3977: Network News Transfer Protocol -//! (NNTP)](https://datatracker.ietf.org/doc/html/rfc3977). Also implements [RFC 6048: Network News +//! Implements an NNTP client as specified by [RFC 3977: Network News Transfer +//! Protocol (NNTP)](https://datatracker.ietf.org/doc/html/rfc3977). Also implements [RFC 6048: Network News //! Transfer Protocol (NNTP) Additions to LIST //! Command](https://datatracker.ietf.org/doc/html/rfc6048). -use crate::get_conf_val; -use crate::get_path_hash; use smallvec::SmallVec; + +use crate::{get_conf_val, get_path_hash}; #[macro_use] mod protocol_parser; pub use protocol_parser::*; @@ -37,21 +37,26 @@ pub use mailbox::*; mod operations; pub use operations::*; mod connection; -pub use connection::*; +use std::{ + collections::{hash_map::DefaultHasher, BTreeSet, HashMap, HashSet}, + hash::Hasher, + pin::Pin, + str::FromStr, + sync::{Arc, Mutex}, + time::{Duration, Instant}, +}; -use crate::conf::AccountSettings; -use crate::connections::timeout; -use crate::email::*; -use crate::error::{Error, Result, ResultIntoError}; -use crate::{backends::*, Collection}; -use futures::lock::Mutex as FutureMutex; -use futures::stream::Stream; -use std::collections::{hash_map::DefaultHasher, BTreeSet, HashMap, HashSet}; -use std::hash::Hasher; -use std::pin::Pin; -use std::str::FromStr; -use std::sync::{Arc, Mutex}; -use std::time::{Duration, Instant}; +pub use connection::*; +use futures::{lock::Mutex as FutureMutex, stream::Stream}; + +use crate::{ + backends::*, + conf::AccountSettings, + connections::timeout, + email::*, + error::{Error, Result, ResultIntoError}, + Collection, +}; pub type UID = usize; macro_rules! get_conf_val { @@ -253,9 +258,21 @@ impl MailBackend for NntpType { let uid_store = self.uid_store.clone(); let connection = self.connection.clone(); Ok(Box::pin(async move { - /* To get updates, either issue NEWNEWS if it's supported by the server, and fallback - * to OVER otherwise */ - let mbox: NntpMailbox = uid_store.mailboxes.lock().await.get(&mailbox_hash).map(std::clone::Clone::clone).ok_or_else(|| Error::new(format!("Mailbox with hash {} not found in NNTP connection, this could possibly be a bug or it was deleted.", mailbox_hash)))?; + /* To get updates, either issue NEWNEWS if it's supported by the server, and + * fallback to OVER otherwise */ + let mbox: NntpMailbox = uid_store + .mailboxes + .lock() + .await + .get(&mailbox_hash) + .map(std::clone::Clone::clone) + .ok_or_else(|| { + Error::new(format!( + "Mailbox with hash {} not found in NNTP connection, this could possibly \ + be a bug or it was deleted.", + mailbox_hash + )) + })?; let latest_article: Option = *mbox.latest_article.lock().unwrap(); let (over_msgid_support, newnews_support): (bool, bool) = { let caps = uid_store.capabilities.lock().unwrap(); @@ -374,15 +391,15 @@ impl MailBackend for NntpType { } fn operation(&self, env_hash: EnvelopeHash) -> Result> { - let (uid, mailbox_hash) = if let Some(v) = - self.uid_store.hash_index.lock().unwrap().get(&env_hash) - { - *v - } else { - return Err(Error::new( - "Message not found in local cache, it might have been deleted before you requested it." + let (uid, mailbox_hash) = + if let Some(v) = self.uid_store.hash_index.lock().unwrap().get(&env_hash) { + *v + } else { + return Err(Error::new( + "Message not found in local cache, it might have been deleted before you \ + requested it.", )); - }; + }; Ok(Box::new(NntpOp::new( uid, mailbox_hash, @@ -671,34 +688,35 @@ impl NntpType { pub fn validate_config(s: &mut AccountSettings) -> Result<()> { let mut keys: HashSet<&'static str> = Default::default(); macro_rules! get_conf_val { - ($s:ident[$var:literal]) => {{ - keys.insert($var); - $s.extra.remove($var).ok_or_else(|| { - Error::new(format!( - "Configuration error ({}): NNTP connection requires the field `{}` set", - $s.name.as_str(), - $var - )) - }) - }}; - ($s:ident[$var:literal], $default:expr) => {{ - keys.insert($var); - $s.extra - .remove($var) - .map(|v| { - <_>::from_str(&v).map_err(|e| { + ($s:ident[$var:literal]) => {{ + keys.insert($var); + $s.extra.remove($var).ok_or_else(|| { Error::new(format!( - "Configuration error ({}) NNTP: Invalid value for field `{}`: {}\n{}", + "Configuration error ({}): NNTP connection requires the field `{}` set", $s.name.as_str(), - $var, - v, - e + $var )) }) - }) - .unwrap_or_else(|| Ok($default)) - }}; -} + }}; + ($s:ident[$var:literal], $default:expr) => {{ + keys.insert($var); + $s.extra + .remove($var) + .map(|v| { + <_>::from_str(&v).map_err(|e| { + Error::new(format!( + "Configuration error ({}) NNTP: Invalid value for field `{}`: \ + {}\n{}", + $s.name.as_str(), + $var, + v, + e + )) + }) + }) + .unwrap_or_else(|| Ok($default)) + }}; + } get_conf_val!(s["require_auth"], false)?; get_conf_val!(s["server_hostname"])?; get_conf_val!(s["server_username"], String::new())?; @@ -706,7 +724,8 @@ impl NntpType { get_conf_val!(s["server_password"], String::new())?; } else if s.extra.contains_key("server_password") { return Err(Error::new(format!( - "Configuration error ({}): both server_password and server_password_command are set, cannot choose", + "Configuration error ({}): both server_password and server_password_command are \ + set, cannot choose", s.name.as_str(), ))); } @@ -716,7 +735,8 @@ impl NntpType { let use_starttls = get_conf_val!(s["use_starttls"], server_port != 563)?; if !use_tls && use_starttls { return Err(Error::new(format!( - "Configuration error ({}): incompatible use_tls and use_starttls values: use_tls = false, use_starttls = true", + "Configuration error ({}): incompatible use_tls and use_starttls values: use_tls \ + = false, use_starttls = true", s.name.as_str(), ))); } @@ -725,7 +745,8 @@ impl NntpType { #[cfg(not(feature = "deflate_compression"))] if s.extra.contains_key("use_deflate") { return Err(Error::new(format!( - "Configuration error ({}): setting `use_deflate` is set but this version of meli isn't compiled with DEFLATE support.", + "Configuration error ({}): setting `use_deflate` is set but this version of meli \ + isn't compiled with DEFLATE support.", s.name.as_str(), ))); } @@ -738,8 +759,10 @@ impl NntpType { let diff = extra_keys.difference(&keys).collect::>(); if !diff.is_empty() { return Err(Error::new(format!( - "Configuration error ({}) NNTP: the following flags are set but are not recognized: {:?}.", - s.name.as_str(), diff + "Configuration error ({}) NNTP: the following flags are set but are not \ + recognized: {:?}.", + s.name.as_str(), + diff ))); } Ok(()) diff --git a/melib/src/backends/nntp/connection.rs b/melib/src/backends/nntp/connection.rs index 21d10fd4..6eafefe5 100644 --- a/melib/src/backends/nntp/connection.rs +++ b/melib/src/backends/nntp/connection.rs @@ -19,19 +19,18 @@ * along with meli. If not, see . */ -use crate::backends::{BackendMailbox, MailboxHash}; -use crate::connections::{lookup_ipv4, Connection}; -use crate::email::parser::BytesExt; -use crate::error::*; +use crate::{ + backends::{BackendMailbox, MailboxHash}, + connections::{lookup_ipv4, Connection}, + email::parser::BytesExt, + error::*, +}; extern crate native_tls; +use std::{collections::HashSet, future::Future, pin::Pin, sync::Arc, time::Instant}; + use futures::io::{AsyncReadExt, AsyncWriteExt}; use native_tls::TlsConnector; pub use smol::Async as AsyncWrapper; -use std::collections::HashSet; -use std::future::Future; -use std::pin::Pin; -use std::sync::Arc; -use std::time::Instant; use super::{Capabilities, NntpServerConf, UIDStore}; diff --git a/melib/src/backends/nntp/mailbox.rs b/melib/src/backends/nntp/mailbox.rs index 67b976ed..7cb0d088 100644 --- a/melib/src/backends/nntp/mailbox.rs +++ b/melib/src/backends/nntp/mailbox.rs @@ -19,13 +19,16 @@ * along with meli. If not, see . */ -use crate::backends::{ - BackendMailbox, LazyCountSet, Mailbox, MailboxHash, MailboxPermissions, SpecialUsageMailbox, -}; -use crate::error::*; -use crate::UnixTimestamp; use std::sync::{Arc, Mutex}; +use crate::{ + backends::{ + BackendMailbox, LazyCountSet, Mailbox, MailboxHash, MailboxPermissions, SpecialUsageMailbox, + }, + error::*, + UnixTimestamp, +}; + #[derive(Debug, Default, Clone)] pub struct NntpMailbox { pub(super) hash: MailboxHash, diff --git a/melib/src/backends/nntp/operations.rs b/melib/src/backends/nntp/operations.rs index 6bff3637..6ea5e6b5 100644 --- a/melib/src/backends/nntp/operations.rs +++ b/melib/src/backends/nntp/operations.rs @@ -19,13 +19,11 @@ * along with meli. If not, see . */ -use super::*; - -use crate::backends::*; -use crate::email::*; -use crate::error::Error; use std::sync::Arc; +use super::*; +use crate::{backends::*, email::*, error::Error}; + /// `BackendOp` implementor for Nntp #[derive(Debug, Clone)] pub struct NntpOp { diff --git a/melib/src/backends/nntp/protocol_parser.rs b/melib/src/backends/nntp/protocol_parser.rs index 2501288b..1f619291 100644 --- a/melib/src/backends/nntp/protocol_parser.rs +++ b/melib/src/backends/nntp/protocol_parser.rs @@ -19,13 +19,15 @@ * along with meli. If not, see . */ -use super::*; -use crate::email::parser::IResult; +use std::str::FromStr; + use nom::{ bytes::complete::{is_not, tag}, combinator::opt, }; -use std::str::FromStr; + +use super::*; +use crate::email::parser::IResult; pub struct NntpLineIterator<'a> { slice: &'a str, diff --git a/melib/src/backends/notmuch.rs b/melib/src/backends/notmuch.rs index 8c7cca0c..4a582cc7 100644 --- a/melib/src/backends/notmuch.rs +++ b/melib/src/backends/notmuch.rs @@ -19,18 +19,25 @@ * along with meli. If not, see . */ -use crate::conf::AccountSettings; -use crate::email::{Envelope, EnvelopeHash, Flag}; -use crate::error::{Error, Result}; -use crate::shellexpand::ShellExpandTrait; -use crate::{backends::*, Collection}; +use std::{ + collections::{hash_map::HashMap, BTreeMap}, + ffi::{CStr, CString, OsStr}, + io::Read, + os::unix::ffi::OsStrExt, + path::{Path, PathBuf}, + sync::{Arc, Mutex, RwLock}, +}; + use smallvec::SmallVec; -use std::collections::{hash_map::HashMap, BTreeMap}; -use std::ffi::{CStr, CString, OsStr}; -use std::io::Read; -use std::os::unix::ffi::OsStrExt; -use std::path::{Path, PathBuf}; -use std::sync::{Arc, Mutex, RwLock}; + +use crate::{ + backends::*, + conf::AccountSettings, + email::{Envelope, EnvelopeHash, Flag}, + error::{Error, Result}, + shellexpand::ShellExpandTrait, + Collection, +}; macro_rules! call { ($lib:expr, $func:ty) => {{ @@ -316,9 +323,14 @@ impl NotmuchDb { Ok(l) => l, Err(err) => { if custom_dlpath { - return Err(Error::new(format!("Notmuch `library_file_path` setting value `{}` for account {} does not exist or is a directory or not a valid library file.",dlpath, s.name())) - .set_kind(ErrorKind::Configuration) - .set_source(Some(Arc::new(err)))); + return Err(Error::new(format!( + "Notmuch `library_file_path` setting value `{}` for account {} does \ + not exist or is a directory or not a valid library file.", + dlpath, + s.name() + )) + .set_kind(ErrorKind::Configuration) + .set_source(Some(Arc::new(err)))); } else { return Err(Error::new("Could not load libnotmuch!") .set_details(super::NOTMUCH_ERROR_DETAILS) @@ -347,10 +359,12 @@ impl NotmuchDb { path.push(".notmuch"); if !path.exists() || !path.is_dir() { return Err(Error::new(format!( - "Notmuch `root_mailbox` {} for account {} does not contain a `.notmuch` subdirectory.", + "Notmuch `root_mailbox` {} for account {} does not contain a `.notmuch` \ + subdirectory.", s.root_mailbox.as_str(), s.name() - )).set_kind(ErrorKind::Configuration)); + )) + .set_kind(ErrorKind::Configuration)); } path.pop(); @@ -378,7 +392,8 @@ impl NotmuchDb { ); } else { return Err(Error::new(format!( - "notmuch mailbox configuration entry `{}` for account {} should have a `query` value set.", + "notmuch mailbox configuration entry `{}` for account {} should have a \ + `query` value set.", k, s.name(), )) @@ -399,7 +414,8 @@ impl NotmuchDb { mailboxes.entry(hash).or_default().parent = Some(parent_hash); } else { return Err(Error::new(format!( - "Mailbox configuration for `{}` defines its parent mailbox as `{}` but no mailbox exists with this exact name.", + "Mailbox configuration for `{}` defines its parent mailbox as `{}` but no \ + mailbox exists with this exact name.", mailboxes[&hash].name(), parent )) @@ -445,10 +461,12 @@ impl NotmuchDb { path.push(".notmuch"); if !path.exists() || !path.is_dir() { return Err(Error::new(format!( - "Notmuch `root_mailbox` {} for account {} does not contain a `.notmuch` subdirectory.", + "Notmuch `root_mailbox` {} for account {} does not contain a `.notmuch` \ + subdirectory.", s.root_mailbox.as_str(), s.name() - )).set_kind(ErrorKind::Configuration)); + )) + .set_kind(ErrorKind::Configuration)); } path.pop(); @@ -456,19 +474,21 @@ impl NotmuchDb { if let Some(lib_path) = s.extra.remove("library_file_path") { if !Path::new(&lib_path).exists() || Path::new(&lib_path).is_dir() { return Err(Error::new(format!( - "Notmuch `library_file_path` setting value `{}` for account {} does not exist or is a directory.", - &lib_path, - s.name() - )).set_kind(ErrorKind::Configuration)); + "Notmuch `library_file_path` setting value `{}` for account {} does not exist \ + or is a directory.", + &lib_path, + s.name() + )) + .set_kind(ErrorKind::Configuration)); } } let mut parents: Vec<(String, String)> = Vec::with_capacity(s.mailboxes.len()); for (k, f) in s.mailboxes.iter_mut() { if f.extra.remove("query").is_none() { return Err(Error::new(format!( - "notmuch mailbox configuration entry `{}` for account {} should have a `query` value set.", - k, - account_name, + "notmuch mailbox configuration entry `{}` for account {} should have a \ + `query` value set.", + k, account_name, )) .set_kind(ErrorKind::Configuration)); } @@ -480,9 +500,9 @@ impl NotmuchDb { for (mbox, parent) in parents.iter() { if !s.mailboxes.contains_key(parent) { return Err(Error::new(format!( - "Mailbox configuration for `{}` defines its parent mailbox as `{}` but no mailbox exists with this exact name.", - mbox, - parent + "Mailbox configuration for `{}` defines its parent mailbox as `{}` but no \ + mailbox exists with this exact name.", + mbox, parent )) .set_kind(ErrorKind::Configuration)); } diff --git a/melib/src/backends/notmuch/bindings.rs b/melib/src/backends/notmuch/bindings.rs index 8841e97b..acb42576 100644 --- a/melib/src/backends/notmuch/bindings.rs +++ b/melib/src/backends/notmuch/bindings.rs @@ -244,7 +244,6 @@ pub type notmuch_database_open_verbose = unsafe extern "C" fn( ) -> notmuch_status_t; /// Retrieve last status string for given database. -/// pub type notmuch_database_status_string = unsafe extern "C" fn(notmuch: *const notmuch_database_t) -> *const ::std::os::raw::c_char; @@ -509,7 +508,6 @@ extern "C" { /// @deprecated Deprecated as of libnotmuch 5.1 (notmuch 0.26). Please /// use notmuch_database_index_file instead. /// ``` - /// pub fn notmuch_database_add_message( database: *mut notmuch_database_t, filename: *const ::std::os::raw::c_char, @@ -751,7 +749,7 @@ pub type notmuch_query_add_tag_exclude = unsafe extern "C" fn( /// } /// /// notmuch_query_destroy (query); -///``` +/// ``` /// /// Note: If you are finished with a thread before its containing /// query, you can call notmuch_thread_destroy to clean up some memory @@ -779,7 +777,6 @@ pub type notmuch_query_search_threads = unsafe extern "C" fn( /// @deprecated Deprecated as of libnotmuch 5 (notmuch 0.25). Please /// ``` /// use notmuch_query_search_threads instead. -/// pub type notmuch_query_search_threads_st = unsafe extern "C" fn( query: *mut notmuch_query_t, out: *mut *mut notmuch_threads_t, @@ -809,7 +806,7 @@ pub type notmuch_query_search_threads_st = unsafe extern "C" fn( /// } /// /// notmuch_query_destroy (query); -///``` +/// ``` /// /// Note: If you are finished with a message before its containing /// query, you can call notmuch_message_destroy to clean up some memory @@ -839,7 +836,6 @@ pub type notmuch_query_search_messages = unsafe extern "C" fn( /// @deprecated Deprecated as of libnotmuch 5 (notmuch 0.25). Please use /// ``` /// notmuch_query_search_messages instead. -/// pub type notmuch_query_search_messages_st = unsafe extern "C" fn( query: *mut notmuch_query_t, out: *mut *mut notmuch_messages_t, @@ -1091,7 +1087,7 @@ pub type notmuch_thread_get_newest_date = /// } /// /// notmuch_thread_destroy (thread); -///``` +/// ``` /// /// Note that there's no explicit destructor needed for the /// notmuch_tags_t object. (For consistency, we do provide a @@ -1250,7 +1246,8 @@ pub type notmuch_message_get_filename = pub type notmuch_message_get_filenames = unsafe extern "C" fn(message: *mut notmuch_message_t) -> *mut notmuch_filenames_t; -/// Re-index the e-mail corresponding to 'message' using the supplied index options +/// Re-index the e-mail corresponding to 'message' using the supplied index +/// options /// /// Returns the status of the re-index operation. (see the return /// codes documented in notmuch_database_index_file) @@ -1333,7 +1330,7 @@ pub type notmuch_message_get_header = unsafe extern "C" fn( /// } /// /// notmuch_message_destroy (message); -///``` +/// ``` /// /// Note that there's no explicit destructor needed for the /// notmuch_tags_t object. (For consistency, we do provide a @@ -1423,7 +1420,6 @@ pub type notmuch_message_maildir_flags_to_tags = /// return TRUE if any filename of 'message' has maildir flag 'flag', /// FALSE otherwise. -/// pub type notmuch_message_has_maildir_flag = unsafe extern "C" fn( message: *mut notmuch_message_t, flag: ::std::os::raw::c_char, @@ -1673,7 +1669,7 @@ extern "C" { /// } /// /// notmuch_message_properties_destroy (list); - ///``` + /// ``` /// /// Note that there's no explicit destructor needed for the /// notmuch_message_properties_t object. (For consistency, we do @@ -1689,7 +1685,8 @@ extern "C" { exact: notmuch_bool_t, ) -> *mut notmuch_message_properties_t; } -/// Return the number of properties named "key" belonging to the specific message. +/// Return the number of properties named "key" belonging to the specific +/// message. /// /// ```text /// @param[in] message The message to examine @@ -1970,7 +1967,8 @@ pub type notmuch_database_get_config_list = unsafe extern "C" fn( out: *mut *mut notmuch_config_list_t, ) -> notmuch_status_t; -/// Is 'config_list' iterator valid (i.e. _key, _value, _move_to_next can be called). +/// Is 'config_list' iterator valid (i.e. _key, _value, _move_to_next can be +/// called). /// /// ```text /// @since libnotmuch 4.4 (notmuch 0.23) diff --git a/melib/src/backends/utf7.rs b/melib/src/backends/utf7.rs index 12218d85..d8ef0083 100644 --- a/melib/src/backends/utf7.rs +++ b/melib/src/backends/utf7.rs @@ -3,23 +3,23 @@ * * Copyright (c) 2021 Ilya Medvedev * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. */ /* Code from */ @@ -111,7 +111,7 @@ fn encode_modified_utf7(text: &str) -> String { /// pub fn decode_utf7_imap(text: &str) -> String { let pattern = Regex::new(r"&([^-]*)-").unwrap(); - pattern.replace_all(&text, expand).to_string() + pattern.replace_all(text, expand).to_string() } fn expand(cap: &Captures) -> String { diff --git a/melib/src/collection.rs b/melib/src/collection.rs index 7320ab6e..3fed7584 100644 --- a/melib/src/collection.rs +++ b/melib/src/collection.rs @@ -19,13 +19,16 @@ * along with meli. If not, see . */ +use std::{ + collections::{BTreeMap, HashMap, HashSet}, + ops::{Deref, DerefMut}, + sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}, +}; + +use smallvec::SmallVec; + use super::*; use crate::backends::{MailboxHash, TagHash}; -use smallvec::SmallVec; -use std::ops::{Deref, DerefMut}; -use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; - -use std::collections::{BTreeMap, HashMap, HashSet}; pub type EnvelopeRef<'g> = RwRef<'g, EnvelopeHash, Envelope>; pub type EnvelopeRefMut<'g> = RwRefMut<'g, EnvelopeHash, Envelope>; diff --git a/melib/src/conf.rs b/melib/src/conf.rs index 9f7c1f43..ae182b7a 100644 --- a/melib/src/conf.rs +++ b/melib/src/conf.rs @@ -19,13 +19,18 @@ * along with meli. If not, see . */ -//! Basic mail account configuration to use with [`backends`](./backends/index.html) -use crate::backends::SpecialUsageMailbox; -use crate::error::{Error, Result}; -pub use crate::{SortField, SortOrder}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; +//! Basic mail account configuration to use with +//! [`backends`](./backends/index.html) use std::collections::HashMap; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::{ + backends::SpecialUsageMailbox, + error::{Error, Result}, +}; +pub use crate::{SortField, SortOrder}; + #[derive(Debug, Serialize, Default, Clone)] pub struct AccountSettings { pub name: String, @@ -87,7 +92,7 @@ impl AccountSettings { pub fn server_password(&self) -> Result { if let Some(cmd) = self.extra.get("server_password_command") { let output = std::process::Command::new("sh") - .args(&["-c", cmd]) + .args(["-c", cmd]) .stdin(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) @@ -107,7 +112,10 @@ impl AccountSettings { } else if let Some(pass) = self.extra.get("server_password") { Ok(pass.to_owned()) } else { - Err(Error::new(format!("Configuration error: connection requires either server_password or server_password_command"))) + Err(Error::new(format!( + "Configuration error: connection requires either server_password or \ + server_password_command" + ))) } } } diff --git a/melib/src/connections.rs b/melib/src/connections.rs index 5db98c94..f7674a35 100644 --- a/melib/src/connections.rs +++ b/melib/src/connections.rs @@ -20,6 +20,8 @@ */ //! Connections layers (TCP/fd/TLS/Deflate) to use with remote backends. +use std::{os::unix::io::AsRawFd, time::Duration}; + #[cfg(feature = "deflate_compression")] use flate2::{read::DeflateDecoder, write::DeflateEncoder, Compression}; #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "haiku"))] @@ -35,8 +37,6 @@ use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION; )))] use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; use libc::{self, c_int, c_void}; -use std::os::unix::io::AsRawFd; -use std::time::Duration; #[derive(Debug)] pub enum Connection { diff --git a/melib/src/datetime.rs b/melib/src/datetime.rs index 73a3ae91..3084bae3 100644 --- a/melib/src/datetime.rs +++ b/melib/src/datetime.rs @@ -37,11 +37,14 @@ //! let s = timestamp_to_string(timestamp, Some("%Y-%m-%d"), true); //! assert_eq!(s, "2020-01-08"); //! ``` +use std::{ + borrow::Cow, + convert::TryInto, + ffi::{CStr, CString}, + os::raw::c_int, +}; + use crate::error::{Result, ResultIntoError}; -use std::borrow::Cow; -use std::convert::TryInto; -use std::ffi::{CStr, CString}; -use std::os::raw::c_int; pub type UnixTimestamp = u64; pub const RFC3339_FMT_WITH_TIME: &str = "%Y-%m-%dT%H:%M:%S\0"; @@ -122,7 +125,8 @@ impl Drop for Locale { } } -// How to unit test this? Test machine is not guaranteed to have non-english locales. +// How to unit test this? Test machine is not guaranteed to have non-english +// locales. impl Locale { #[cfg(not(target_os = "netbsd"))] fn new( diff --git a/melib/src/email.rs b/melib/src/email.rs index 23b2d8d0..37a65543 100644 --- a/melib/src/email.rs +++ b/melib/src/email.rs @@ -24,8 +24,9 @@ * * # Parsing bytes into an `Envelope` * - * An [`Envelope`](Envelope) represents the information you can get from an email's headers and body - * structure. Addresses in `To`, `From` fields etc are parsed into [`Address`](crate::email::Address) types. + * An [`Envelope`](Envelope) represents the information you can get from an + * email's headers and body structure. Addresses in `To`, `From` fields etc + * are parsed into [`Address`](crate::email::Address) types. * * ``` * use melib::{Attachment, Envelope}; @@ -75,7 +76,10 @@ * * let envelope = Envelope::from_bytes(raw_mail.as_bytes(), None).expect("Could not parse mail"); * assert_eq!(envelope.subject().as_ref(), "gratuitously encoded subject"); - * assert_eq!(envelope.message_id_display().as_ref(), ""); + * assert_eq!( + * envelope.message_id_display().as_ref(), + * "" + * ); * * let body = envelope.body_bytes(raw_mail.as_bytes()); * assert_eq!(body.content_type().to_string().as_str(), "multipart/mixed"); @@ -85,7 +89,10 @@ * * let subattachments: Vec = body.attachments(); * assert_eq!(subattachments.len(), 3); - * assert_eq!(subattachments[2].content_type().name().unwrap(), "test_image.gif"); + * assert_eq!( + * subattachments[2].content_type().name().unwrap(), + * "test_image.gif" + * ); * ``` */ @@ -99,22 +106,22 @@ pub mod mailto; pub mod parser; pub mod pgp; +use std::{borrow::Cow, convert::TryInto, ops::Deref}; + pub use address::{Address, MessageID, References, StrBuild, StrBuilder}; pub use attachments::{Attachment, AttachmentBuilder}; pub use compose::{attachment_from_file, Draft}; pub use headers::*; pub use mailto::*; - -use crate::datetime::UnixTimestamp; -use crate::error::{Error, Result}; -use crate::parser::BytesExt; -use crate::thread::ThreadNodeHash; -use crate::TagHash; - use smallvec::SmallVec; -use std::borrow::Cow; -use std::convert::TryInto; -use std::ops::Deref; + +use crate::{ + datetime::UnixTimestamp, + error::{Error, Result}, + parser::BytesExt, + thread::ThreadNodeHash, + TagHash, +}; bitflags! { #[derive(Default, Serialize, Deserialize)] @@ -159,9 +166,10 @@ impl Flag { flag_impl!(fn is_flagged, Flag::FLAGGED); } -///`Mail` holds both the envelope info of an email in its `envelope` field and the raw bytes that -///describe the email in `bytes`. Its body as an `melib::email::Attachment` can be parsed on demand -///with the `melib::email::Mail::body` method. +///`Mail` holds both the envelope info of an email in its `envelope` field and +/// the raw bytes that describe the email in `bytes`. Its body as an +/// `melib::email::Attachment` can be parsed on demand +/// with the `melib::email::Mail::body` method. #[derive(Debug, Clone, Default)] pub struct Mail { pub envelope: Envelope, @@ -199,12 +207,13 @@ impl Mail { crate::declare_u64_hash!(EnvelopeHash); -/// `Envelope` represents all the header and structure data of an email we need to know. +/// `Envelope` represents all the header and structure data of an email we need +/// to know. /// /// Attachments (the email's body) is parsed on demand with `body` method. /// -///To access the email attachments, you need to parse them from the raw email bytes into an -///`Attachment` object. +///To access the email attachments, you need to parse them from the raw email +/// bytes into an `Attachment` object. #[derive(Clone, Serialize, Deserialize)] pub struct Envelope { pub hash: EnvelopeHash, @@ -364,7 +373,11 @@ impl Envelope { self.has_attachments = Attachment::check_if_has_attachments_quick(body, boundary); } else { - debug!("{:?} has no boundary field set in multipart/mixed content-type field.", &self); + debug!( + "{:?} has no boundary field set in multipart/mixed content-type \ + field.", + &self + ); } } _ => {} diff --git a/melib/src/email/address.rs b/melib/src/email/address.rs index 4c22c43c..37d8bb97 100644 --- a/melib/src/email/address.rs +++ b/melib/src/email/address.rs @@ -19,11 +19,15 @@ * along with meli. If not, see . */ -//! Email addresses. Parsing functions are in [melib::email::parser::address](../parser/address/index.html). +//! Email addresses. Parsing functions are in +//! [melib::email::parser::address](../parser/address/index.html). +use std::{ + collections::HashSet, + convert::TryFrom, + hash::{Hash, Hasher}, +}; + use super::*; -use std::collections::HashSet; -use std::convert::TryFrom; -use std::hash::{Hash, Hasher}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct GroupAddress { @@ -53,7 +57,7 @@ pub struct GroupAddress { * > display_name │ * > │ * > address_spec - *``` + * ``` */ pub struct MailboxAddress { pub raw: Vec, @@ -78,14 +82,20 @@ impl PartialEq for MailboxAddress { /// /// ```rust /// # use melib::email::Address; -/// let addr = Address::new(Some("Jörg Doe".to_string()), "joerg@example.com".to_string()); +/// let addr = Address::new( +/// Some("Jörg Doe".to_string()), +/// "joerg@example.com".to_string(), +/// ); /// assert_eq!(addr.to_string().as_str(), "Jörg Doe "); /// ``` /// /// or parse it from a raw value: /// /// ```rust -/// let (rest_bytes, addr) = melib::email::parser::address::address("=?utf-8?q?J=C3=B6rg_Doe?= ".as_bytes()).unwrap(); +/// let (rest_bytes, addr) = melib::email::parser::address::address( +/// "=?utf-8?q?J=C3=B6rg_Doe?= ".as_bytes(), +/// ) +/// .unwrap(); /// assert!(rest_bytes.is_empty()); /// assert_eq!(addr.get_display_name(), Some("Jörg Doe".to_string())); /// assert_eq!(addr.get_email(), "joerg@example.com".to_string()); @@ -154,8 +164,8 @@ impl Address { /// Get the display name of this address. /// - /// If it's a group, it's the name of the group. Otherwise it's the `display_name` part of - /// the mailbox: + /// If it's a group, it's the name of the group. Otherwise it's the + /// `display_name` part of the mailbox: /// /// /// ```text @@ -166,7 +176,7 @@ impl Address { /// display_name │ display_name │ /// │ │ /// address_spec address_spec - ///``` + /// ``` pub fn get_display_name(&self) -> Option { let ret = match self { Address::Mailbox(m) => m.display_name.display(&m.raw), @@ -179,7 +189,8 @@ impl Address { } } - /// Get the address spec part of this address. A group returns an empty `String`. + /// Get the address spec part of this address. A group returns an empty + /// `String`. pub fn get_email(&self) -> String { match self { Address::Mailbox(m) => m.address_spec.display(&m.raw), @@ -238,8 +249,8 @@ impl Address { /// Get subaddress out of an address (e.g. `ken+subaddress@example.org`). /// - /// Subaddresses are commonly text following a "+" character in an email address's local part - /// . They are defined in [RFC5233 `Sieve Email Filtering: Subaddress Extension`](https://tools.ietf.org/html/rfc5233.html) + /// Subaddresses are commonly text following a "+" character in an email + /// address's local part . They are defined in [RFC5233 `Sieve Email Filtering: Subaddress Extension`](https://tools.ietf.org/html/rfc5233.html) /// /// # Examples /// diff --git a/melib/src/email/attachment_types.rs b/melib/src/email/attachment_types.rs index b00f5a34..a758e796 100644 --- a/melib/src/email/attachment_types.rs +++ b/melib/src/email/attachment_types.rs @@ -18,11 +18,15 @@ * You should have received a copy of the GNU General Public License * along with meli. If not, see . */ -use crate::email::attachments::{Attachment, AttachmentBuilder}; -use crate::email::parser::BytesExt; +use std::{ + fmt::{Display, Formatter, Result as FmtResult}, + str, +}; -use std::fmt::{Display, Formatter, Result as FmtResult}; -use std::str; +use crate::email::{ + attachments::{Attachment, AttachmentBuilder}, + parser::BytesExt, +}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum Charset { @@ -421,9 +425,10 @@ impl ContentType { boundary.push_str(&random_boundary); /* rfc134 - * "The only mandatory parameter for the multipart Content-Type is the boundary parameter, - * which consists of 1 to 70 characters from a set of characters known to be very robust - * through email gateways, and NOT ending with white space"*/ + * "The only mandatory parameter for the multipart Content-Type is the + * boundary parameter, which consists of 1 to 70 characters from a + * set of characters known to be very robust through email gateways, + * and NOT ending with white space" */ boundary.truncate(70); boundary } diff --git a/melib/src/email/attachments.rs b/melib/src/email/attachments.rs index 0be39635..24855356 100644 --- a/melib/src/email/attachments.rs +++ b/melib/src/email/attachments.rs @@ -20,17 +20,17 @@ */ /*! Encoding/decoding of attachments */ -use crate::email::{ - address::StrBuilder, - parser::{self, BytesExt}, - Mail, -}; -use core::fmt; -use core::str; +use core::{fmt, str}; + use data_encoding::BASE64_MIME; use smallvec::SmallVec; -use crate::email::attachment_types::*; +use crate::email::{ + address::StrBuilder, + attachment_types::*, + parser::{self, BytesExt}, + Mail, +}; pub type Filter<'a> = Box) + 'a>; @@ -117,8 +117,9 @@ impl AttachmentBuilder { self } - /// Set body to the entire raw contents, use this if raw contains only data and no headers - /// If raw contains data and headers pass it through AttachmentBuilder::new(). + /// Set body to the entire raw contents, use this if raw contains only data + /// and no headers If raw contains data and headers pass it through + /// AttachmentBuilder::new(). pub fn set_body_to_raw(&mut self) -> &mut Self { self.body = StrBuilder { offset: 0, @@ -515,8 +516,8 @@ impl Attachment { } } - /* Call on the body of a multipart/mixed Envelope to check if there are attachments without - * completely parsing them */ + /* Call on the body of a multipart/mixed Envelope to check if there are + * attachments without completely parsing them */ pub fn check_if_has_attachments_quick(bytes: &[u8], boundary: &[u8]) -> bool { if bytes.is_empty() { return false; diff --git a/melib/src/email/compose.rs b/melib/src/email/compose.rs index 924431b8..40cf5152 100644 --- a/melib/src/email/compose.rs +++ b/melib/src/email/compose.rs @@ -20,19 +20,25 @@ */ /*! Compose a `Draft`, with MIME and attachment support */ -use super::*; -use crate::email::attachment_types::{ - Charset, ContentTransferEncoding, ContentType, MultipartType, +use std::{ + ffi::OsStr, + io::Read, + path::{Path, PathBuf}, + str::FromStr, }; -use crate::email::attachments::AttachmentBuilder; -use crate::shellexpand::ShellExpandTrait; + use data_encoding::BASE64_MIME; -use std::ffi::OsStr; -use std::io::Read; -use std::path::{Path, PathBuf}; -use std::str::FromStr; use xdg_utils::query_mime_info; +use super::*; +use crate::{ + email::{ + attachment_types::{Charset, ContentTransferEncoding, ContentType, MultipartType}, + attachments::AttachmentBuilder, + }, + shellexpand::ShellExpandTrait, +}; + pub mod mime; pub mod random; @@ -370,7 +376,10 @@ fn build_multipart( } ret.push_str("\r\n\r\n"); /* rfc1341 */ - ret.push_str("This is a MIME formatted message with attachments. Use a MIME-compliant client to view it properly.\r\n"); + ret.push_str( + "This is a MIME formatted message with attachments. Use a MIME-compliant client to view \ + it properly.\r\n", + ); for sub in parts { ret.push_str("--"); ret.push_str(&boundary); @@ -484,9 +493,10 @@ fn print_attachment(ret: &mut String, a: AttachmentBuilder) { #[cfg(test)] mod tests { - use super::*; use std::str::FromStr; + use super::*; + #[test] fn test_new_draft() { let mut default = Draft::default(); @@ -508,21 +518,33 @@ mod tests { let original = default.clone(); let s = default.to_edit_string(); - assert_eq!(s, "\n\nαδφαφσαφασ"); + assert_eq!( + s, + "\n\nαδφαφσαφασ" + ); assert!(!default.update(&s).unwrap()); assert_eq!(&original, &default); default.set_wrap_header_preamble(Some(("".to_string(), "".to_string()))); let original = default.clone(); let s = default.to_edit_string(); - assert_eq!(s, "Date: Sun, 16 Jun 2013 17:56:45 +0200\nFrom: \nTo: \nCc: \nBcc: \nSubject: test_update()\n\nαδφαφσαφασ"); + assert_eq!( + s, + "Date: Sun, 16 Jun 2013 17:56:45 +0200\nFrom: \nTo: \nCc: \nBcc: \nSubject: \ + test_update()\n\nαδφαφσαφασ" + ); assert!(!default.update(&s).unwrap()); assert_eq!(&original, &default); default.set_wrap_header_preamble(None); let original = default.clone(); let s = default.to_edit_string(); - assert_eq!(s, "Date: Sun, 16 Jun 2013 17:56:45 +0200\nFrom: \nTo: \nCc: \nBcc: \nSubject: test_update()\n\nαδφαφσαφασ"); + assert_eq!( + s, + "Date: Sun, 16 Jun 2013 17:56:45 +0200\nFrom: \nTo: \nCc: \nBcc: \nSubject: \ + test_update()\n\nαδφαφσαφασ" + ); assert!(!default.update(&s).unwrap()); assert_eq!(&original, &default); @@ -532,7 +554,11 @@ mod tests { ))); let original = default.clone(); let s = default.to_edit_string(); - assert_eq!(s, "{-\n\n\n===========\nDate: Sun, 16 Jun 2013 17:56:45 +0200\nFrom: \nTo: \nCc: \nBcc: \nSubject: test_update()\n\n\nαδφαφσαφασ"); + assert_eq!( + s, + "{-\n\n\n===========\nDate: Sun, 16 Jun 2013 17:56:45 +0200\nFrom: \nTo: \nCc: \nBcc: \ + \nSubject: test_update()\n\n\nαδφαφσαφασ" + ); assert!(!default.update(&s).unwrap()); assert_eq!(&original, &default); @@ -543,7 +569,11 @@ mod tests { .set_wrap_header_preamble(Some(("".to_string()))); let original = default.clone(); let s = default.to_edit_string(); - assert_eq!(s, "\n\nhellohello\n-->\n-->hello\n"); + assert_eq!( + s, + "\n\nhellohello\n-->\n-->hello\n" + ); assert!(!default.update(&s).unwrap()); assert_eq!(&original, &default); } @@ -572,7 +602,8 @@ mod tests { */ } -/// Reads file from given path, and returns an 'application/octet-stream' AttachmentBuilder object +/// Reads file from given path, and returns an 'application/octet-stream' +/// AttachmentBuilder object pub fn attachment_from_file(path: &I) -> Result where I: AsRef, diff --git a/melib/src/email/compose/mime.rs b/melib/src/email/compose/mime.rs index ef466ee1..f47e1b18 100644 --- a/melib/src/email/compose/mime.rs +++ b/melib/src/email/compose/mime.rs @@ -20,7 +20,6 @@ */ use super::*; - #[cfg(feature = "unicode_algorithms")] use crate::text_processing::grapheme_clusters::TextProcessing; @@ -61,9 +60,9 @@ pub fn encode_header(value: &str) -> String { is_current_window_ascii = false; } /* RFC2047 recommends: - * 'While there is no limit to the length of a multiple-line header field, each line of - * a header field that contains one or more 'encoded-word's is limited to 76 - * characters.' + * 'While there is no limit to the length of a multiple-line header field, each + * line of a header field that contains one or more + * 'encoded-word's is limited to 76 characters.' * This is a rough compliance. */ (false, false) if (((4 * (idx - current_window_start) / 3) + 3) & !3) > 33 => { @@ -84,8 +83,8 @@ pub fn encode_header(value: &str) -> String { } #[cfg(not(feature = "unicode_algorithms"))] { - /* TODO: test this. If it works as fine as the one above, there's no need to keep the above - * implementation.*/ + /* TODO: test this. If it works as fine as the one above, there's no need to + * keep the above implementation. */ for (i, g) in value.char_indices() { match (g.is_ascii(), is_current_window_ascii) { (true, true) => { @@ -116,9 +115,9 @@ pub fn encode_header(value: &str) -> String { is_current_window_ascii = false; } /* RFC2047 recommends: - * 'While there is no limit to the length of a multiple-line header field, each line of - * a header field that contains one or more 'encoded-word's is limited to 76 - * characters.' + * 'While there is no limit to the length of a multiple-line header field, each + * line of a header field that contains one or more + * 'encoded-word's is limited to 76 characters.' * This is a rough compliance. */ (false, false) @@ -139,8 +138,8 @@ pub fn encode_header(value: &str) -> String { } } } - /* If the last part of the header value is encoded, it won't be pushed inside the previous for - * block */ + /* If the last part of the header value is encoded, it won't be pushed inside + * the previous for block */ if !is_current_window_ascii { ret.push_str(&format!( "=?UTF-8?B?{}?=", @@ -156,35 +155,39 @@ fn test_encode_header() { let words = "compilers/2020a σε Rust"; assert_eq!( "compilers/2020a =?UTF-8?B?z4POtSA=?=Rust", - &encode_header(&words), + &encode_header(words), ); assert_eq!( &std::str::from_utf8( - &crate::email::parser::encodings::phrase(encode_header(&words).as_bytes(), false) + &crate::email::parser::encodings::phrase(encode_header(words).as_bytes(), false) .unwrap() .1 ) .unwrap(), &words, ); - let words = "[internal] =?UTF-8?B?zp3Orc6/z4Igzp/OtM63zrPPjM+CIM6jz4U=?= =?UTF-8?B?zrPOs8+BzrHPhs6uz4I=?="; + let words = "[internal] =?UTF-8?B?zp3Orc6/z4Igzp/OtM63zrPPjM+CIM6jz4U=?= \ + =?UTF-8?B?zrPOs8+BzrHPhs6uz4I=?="; let words_enc = r#"[internal] Νέος Οδηγός Συγγραφής"#; - assert_eq!(words, &encode_header(&words_enc),); + assert_eq!(words, &encode_header(words_enc),); assert_eq!( r#"[internal] Νέος Οδηγός Συγγραφής"#, std::str::from_utf8( - &crate::email::parser::encodings::phrase(encode_header(&words_enc).as_bytes(), false) + &crate::email::parser::encodings::phrase(encode_header(words_enc).as_bytes(), false) .unwrap() .1 ) .unwrap(), ); - //let words = "[Advcomparch] =?utf-8?b?zqPPhc68z4DOtc+BzrnPhs6/z4HOrCDPg861IGZs?=\n\t=?utf-8?b?dXNoIM67z4zOs8+JIG1pc3ByZWRpY3Rpb24gzrrOsc+Ezqwgz4TOt869?=\n\t=?utf-8?b?IM61zrrPhM6tzrvOtc+Dzrcgc3RvcmU=?="; + //let words = "[Advcomparch] + // =?utf-8?b?zqPPhc68z4DOtc+BzrnPhs6/z4HOrCDPg861IGZs?=\n\t=?utf-8?b? + // dXNoIM67z4zOs8+JIG1pc3ByZWRpY3Rpb24gzrrOsc+Ezqwgz4TOt869?=\n\t=?utf-8?b? + // IM61zrrPhM6tzrvOtc+Dzrcgc3RvcmU=?="; let words_enc = "[Advcomparch] Συμπεριφορά σε flush λόγω misprediction κατά την εκτέλεση store"; assert_eq!( "[Advcomparch] Συμπεριφορά σε flush λόγω misprediction κατά την εκτέλεση store", std::str::from_utf8( - &crate::email::parser::encodings::phrase(encode_header(&words_enc).as_bytes(), false) + &crate::email::parser::encodings::phrase(encode_header(words_enc).as_bytes(), false) .unwrap() .1 ) diff --git a/melib/src/email/compose/random.rs b/melib/src/email/compose/random.rs index 6e5cbe35..67fba6ca 100644 --- a/melib/src/email/compose/random.rs +++ b/melib/src/email/compose/random.rs @@ -19,10 +19,7 @@ * along with meli. If not, see . */ -use std::char; -use std::fs::File; -use std::io::prelude::*; -use std::time::SystemTime; +use std::{char, fs::File, io::prelude::*, time::SystemTime}; fn random_u64() -> u64 { let mut f = File::open("/dev/urandom").unwrap(); diff --git a/melib/src/email/headers.rs b/melib/src/email/headers.rs index f7486690..2be6bd57 100644 --- a/melib/src/email/headers.rs +++ b/melib/src/email/headers.rs @@ -20,20 +20,25 @@ */ /*! Wrapper type `HeaderName` for case-insensitive comparisons */ -use crate::error::Error; +use std::{ + borrow::Borrow, + cmp::{Eq, PartialEq}, + convert::TryFrom, + fmt, + hash::{Hash, Hasher}, + ops::{Deref, DerefMut}, +}; + use indexmap::IndexMap; use smallvec::SmallVec; -use std::borrow::Borrow; -use std::cmp::{Eq, PartialEq}; -use std::convert::TryFrom; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::ops::{Deref, DerefMut}; + +use crate::error::Error; #[derive(Clone, Copy, Serialize, Deserialize)] pub struct HeaderNameType(S); -///Case insensitive wrapper for a header name. As of `RFC5322` it's guaranteened to be ASCII. +/// Case insensitive wrapper for a header name. As of `RFC5322` it's +/// guaranteed to be ASCII. pub type HeaderName = HeaderNameType>; impl HeaderName { @@ -148,7 +153,7 @@ impl<'a> Borrow for HeaderName { impl> HeaderNameType { pub fn as_str(&self) -> &str { - //HeadersType are ascii so valid utf8 + // HeadersType are ascii so valid utf8 unsafe { std::str::from_utf8_unchecked(self.0.as_ref()) } } diff --git a/melib/src/email/list_management.rs b/melib/src/email/list_management.rs index b0e07d82..5129480e 100644 --- a/melib/src/email/list_management.rs +++ b/melib/src/email/list_management.rs @@ -20,11 +20,12 @@ */ /*! Parsing of rfc2369/rfc2919 `List-*` headers */ -use super::parser; -use super::Envelope; -use smallvec::SmallVec; use std::convert::From; +use smallvec::SmallVec; + +use super::{parser, Envelope}; + #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum ListAction<'a> { Url(&'a [u8]), @@ -43,8 +44,8 @@ impl<'a> From<&'a [u8]> for ListAction<'a> { } else if value.starts_with(b"NO") { ListAction::No } else { - /* Otherwise treat it as url. There's no foolproof way to check if this is valid, so - * postpone it until we try an HTTP request. + /* Otherwise treat it as url. There's no foolproof way to check if this is + * valid, so postpone it until we try an HTTP request. */ ListAction::Url(value) } @@ -55,8 +56,8 @@ impl<'a> ListAction<'a> { pub fn parse_options_list(input: &'a [u8]) -> Option; 4]>> { parser::mailing_lists::rfc_2369_list_headers_action_list(input) .map(|(_, mut vec)| { - /* Prefer email options first, since this _is_ a mail client after all and it's - * more automated */ + /* Prefer email options first, since this _is_ a mail client after all and + * it's more automated */ vec.sort_unstable_by(|a, b| { match (a.starts_with(b"mailto:"), b.starts_with(b"mailto:")) { (true, false) => std::cmp::Ordering::Less, diff --git a/melib/src/email/mailto.rs b/melib/src/email/mailto.rs index f41167f6..998b4a26 100644 --- a/melib/src/email/mailto.rs +++ b/melib/src/email/mailto.rs @@ -20,9 +20,10 @@ */ /*! Parsing of `mailto` addresses */ -use super::*; use std::convert::TryFrom; +use super::*; + #[derive(Debug, Clone)] pub struct Mailto { pub address: Address, diff --git a/melib/src/email/parser.rs b/melib/src/email/parser.rs index efb66fa8..c1bd25b1 100644 --- a/melib/src/email/parser.rs +++ b/melib/src/email/parser.rs @@ -20,20 +20,21 @@ */ /*! Parsers for email. See submodules */ -use crate::error::{Error, Result, ResultIntoError}; +use std::borrow::Cow; + use nom::{ branch::alt, bytes::complete::{is_a, is_not, tag, take, take_until, take_while, take_while1}, character::{is_alphabetic, is_digit, is_hex_digit}, - combinator::peek, - combinator::{map, opt}, + combinator::{map, opt, peek}, error::{context, ErrorKind}, multi::{many0, many1, separated_list1}, number::complete::le_u8, sequence::{delimited, pair, preceded, separated_pair, terminated}, }; use smallvec::SmallVec; -use std::borrow::Cow; + +use crate::error::{Error, Result, ResultIntoError}; macro_rules! to_str { ($l:expr) => {{ @@ -318,8 +319,7 @@ pub fn mail(input: &[u8]) -> Result<(Vec<(&[u8], &[u8])>, &[u8])> { pub mod dates { /*! Date values in headers */ - use super::generic::*; - use super::*; + use super::{generic::*, *}; use crate::datetime::UnixTimestamp; fn take_n_digits(n: usize) -> impl Fn(&[u8]) -> IResult<&[u8], &[u8]> { @@ -451,15 +451,15 @@ pub mod dates { ///e.g Wed Sep 9 00:27:54 2020 ///```text - ///day-of-week month day time year - ///date-time = [ day-of-week "," ] date time [CFWS] - ///date = day month year - ///time = time-of-day zone - ///time-of-day = hour ":" minute [ ":" second ] - ///hour = 2DIGIT / obs-hour - ///minute = 2DIGIT / obs-minute - ///second = 2DIGIT / obs-second - ///``` + /// day-of-week month day time year + /// date-time = [ day-of-week "," ] date time [CFWS] + /// date = day month year + /// time = time-of-day zone + /// time-of-day = hour ":" minute [ ":" second ] + /// hour = 2DIGIT / obs-hour + /// minute = 2DIGIT / obs-minute + /// second = 2DIGIT / obs-second + /// ``` pub fn mbox_date_time(input: &[u8]) -> IResult<&[u8], UnixTimestamp> { let orig_input = input; let mut accum: SmallVec<[u8; 32]> = SmallVec::new(); @@ -656,7 +656,8 @@ pub mod generic { let (rest, _) = utf8_tail(rest)?; Ok((rest, &input[0..2])) } - /// UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) + /// UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / %xED + /// %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) fn utf8_3<'a>(input: &'a [u8]) -> IResult<&'a [u8], &'a [u8]> { alt(( |input: &'a [u8]| -> IResult<&'a [u8], &'a [u8]> { @@ -685,7 +686,8 @@ pub mod generic { }, ))(input) } - /// UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / %xF4 %x80-8F 2( UTF8-tail ) + /// UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / + /// %xF4 %x80-8F 2( UTF8-tail ) fn utf8_4<'a>(input: &'a [u8]) -> IResult<&'a [u8], &'a [u8]> { alt(( |input: &'a [u8]| -> IResult<&'a [u8], &'a [u8]> { @@ -741,11 +743,11 @@ pub mod generic { } ///```text - ///ctext = %d33-39 / ; Printable US-ASCII + /// ctext = %d33-39 / ; Printable US-ASCII /// %d42-91 / ; characters not including /// %d93-126 / ; "(", ")", or "\" /// obs-ctext - ///``` + /// ``` fn ctext(input: &[u8]) -> IResult<&[u8], ()> { alt(( map( @@ -761,13 +763,13 @@ pub mod generic { } ///```text - ///ctext = %d33-39 / ; Printable US-ASCII + /// ctext = %d33-39 / ; Printable US-ASCII /// %d42-91 / ; characters not including /// %d93-126 / ; "(", ")", or "\" /// obs-ctext - ///ccontent = ctext / quoted-pair / comment - ///comment = "(" *([FWS] ccontent) [FWS] ")" - ///``` + /// ccontent = ctext / quoted-pair / comment + /// comment = "(" *([FWS] ccontent) [FWS] ")" + /// ``` pub fn comment(input: &[u8]) -> IResult<&[u8], ()> { if !input.starts_with(b"(") { return Err(nom::Err::Error( @@ -911,8 +913,7 @@ pub mod generic { } } - use crate::email::address::Address; - use crate::email::mailto::Mailto; + use crate::email::{address::Address, mailto::Mailto}; pub fn mailto(mut input: &[u8]) -> IResult<&[u8], Mailto> { if !input.starts_with(b"mailto:") { return Err(nom::Err::Error( @@ -1081,7 +1082,8 @@ pub mod generic { Ok((rest, ret)) } - ///`quoted-string = [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE [CFWS]` + ///`quoted-string = [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE + /// [CFWS]` pub fn quoted_string(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> { let (input, opt_space) = opt(cfws)(input)?; if !input.starts_with(b"\"") { @@ -1213,7 +1215,10 @@ pub mod generic { Ok((input, ret.into())) } - ///`atext = ALPHA / DIGIT / ; Printable US-ASCII "!" / "#" / ; characters not including "$" / "%" / ; specials. Used for atoms. "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~"` + ///`atext = ALPHA / DIGIT / ; Printable US-ASCII "!" / "#" / + /// ; characters not including "$" / "%" / ; specials. Used for + /// atoms. "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" + /// / "{" / "|" / "}" / "~"` pub fn atext_ascii(input: &[u8]) -> IResult<&[u8], Cow<'_, [u8]>> { if input.is_empty() { return Err(nom::Err::Error((input, "atext(): empty input").into())); @@ -1244,10 +1249,10 @@ pub mod generic { } ///```text - ///dtext = %d33-90 / ; Printable US-ASCII + /// dtext = %d33-90 / ; Printable US-ASCII /// %d94-126 / ; characters not including /// obs-dtext ; "[", "]", or "\" - ///``` + /// ``` pub fn dtext(input: &[u8]) -> IResult<&[u8], u8> { alt((byte_in_range(33, 90), byte_in_range(94, 125)))(input) } @@ -1259,11 +1264,13 @@ pub mod mailing_lists { //! Implemented RFCs: //! //! - [RFC2369 "The Use of URLs as Meta-Syntax for Core Mail List Commands and their Transport through Message Header Fields"](https://tools.ietf.org/html/rfc2369) - use super::*; use generic::cfws; - ///Parse the value of headers defined in RFC2369 "The Use of URLs as Meta-Syntax for Core - ///Mail List Commands and their Transport through Message Header Fields" + use super::*; + + ///Parse the value of headers defined in RFC2369 "The Use of URLs as + /// Meta-Syntax for Core Mail List Commands and their Transport through + /// Message Header Fields" pub fn rfc_2369_list_headers_action_list(input: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { let (input, _) = opt(cfws)(input)?; let (input, ret) = alt(( @@ -1458,9 +1465,9 @@ pub mod headers { /* A header can span multiple lines, eg: * * Received: from -------------------- (-------------------------) - * by --------------------- (--------------------- [------------------]) (-----------------------) - * with ESMTP id ------------ for <------------------->; - * Tue, 5 Jan 2016 21:30:44 +0100 (CET) + * by --------------------- (--------------------- [------------------]) + * (-----------------------) with ESMTP id ------------ for + * <------------------->; Tue, 5 Jan 2016 21:30:44 +0100 (CET) */ pub fn header_value(input: &[u8]) -> IResult<&[u8], &[u8]> { @@ -1580,8 +1587,10 @@ pub mod headers { pub mod attachments { /*! Email attachments */ use super::*; - use crate::email::address::*; - use crate::email::attachment_types::{ContentDisposition, ContentDispositionKind}; + use crate::email::{ + address::*, + attachment_types::{ContentDisposition, ContentDispositionKind}, + }; pub fn attachment(input: &[u8]) -> IResult<&[u8], (std::vec::Vec<(&[u8], &[u8])>, &[u8])> { alt(( separated_pair( @@ -1807,7 +1816,8 @@ pub mod attachments { pub fn content_disposition(input: &[u8]) -> IResult<&[u8], ContentDisposition> { let (input, kind) = alt((take_until(";"), take_while(|_| true)))(input.trim())?; let mut ret = ContentDisposition { - /* RFC2183 Content-Disposition: "Unrecognized disposition types should be treated as `attachment'." */ + /* RFC2183 Content-Disposition: "Unrecognized disposition types should be treated as + * `attachment'." */ kind: if kind.trim().eq_ignore_ascii_case(b"inline") { ContentDispositionKind::Inline } else { @@ -1846,11 +1856,11 @@ pub mod attachments { pub mod encodings { /*! Email encodings (quoted printable, MIME) */ + use data_encoding::BASE64_MIME; + use encoding::{all::*, DecoderTrap, Encoding}; + use super::*; use crate::email::attachment_types::Charset; - use data_encoding::BASE64_MIME; - use encoding::all::*; - use encoding::{DecoderTrap, Encoding}; pub fn quoted_printable_byte(input: &[u8]) -> IResult<&[u8], u8> { if input.len() < 3 { Err(nom::Err::Error( @@ -2023,7 +2033,8 @@ pub mod encodings { if input.starts_with(b"=\n") { Ok((&input[2..], input[1])) // `=\n` is an escaped space character. } else if input.starts_with(b"=\r\n") { - Ok((&input[3..], input[2])) // `=\r\n` is an escaped space character. + Ok((&input[3..], input[2])) // `=\r\n` is an escaped space + // character. } else { Err(nom::Err::Error( (input, "quoted_printable_soft_break(): invalid input").into(), @@ -2036,8 +2047,9 @@ pub mod encodings { Ok((rest, 0x20)) } - // With MIME, headers in quoted printable format can contain underscores that represent spaces. - // In non-header context, an underscore is just a plain underscore. + // With MIME, headers in quoted printable format can contain underscores that + // represent spaces. In non-header context, an underscore is just a plain + // underscore. pub fn quoted_printable_bytes_header(input: &[u8]) -> IResult<&[u8], Vec> { many0(alt((quoted_printable_byte, qp_underscore_header, le_u8)))(input) } @@ -2173,9 +2185,9 @@ pub mod address { //! - [RFC6532 "Internationalized Email Headers"](https://tools.ietf.org/html/rfc6532) //! - [RFC2047 "MIME Part Three: Message Header Extensions for Non-ASCII Text"](https://tools.ietf.org/html/rfc2047) use super::*; - use crate::email::address::*; - use crate::email::parser::generic::{ - atom, cfws, dot_atom, dot_atom_text, dtext, phrase2, quoted_string, + use crate::email::{ + address::*, + parser::generic::{atom, cfws, dot_atom, dot_atom_text, dtext, phrase2, quoted_string}, }; pub fn display_addr(input: &[u8]) -> IResult<&[u8], Address> { if input.is_empty() || input.len() < 3 { @@ -2447,8 +2459,8 @@ pub mod address { } ///```text - ///address = mailbox / group - ///``` + /// address = mailbox / group + /// ``` pub fn address(input: &[u8]) -> IResult<&[u8], Address> { alt((mailbox, group))(input) } @@ -2599,15 +2611,18 @@ pub mod address { #[cfg(test)] mod tests { use super::{address::*, encodings::*, *}; - use crate::email::address::*; - use crate::make_address; + use crate::{email::address::*, make_address}; #[test] fn test_phrase() { let words = b"=?iso-8859-7?B?W215Y291cnNlcy5udHVhLmdyIC0gyvXs4fTp6t4g6uHpIMri4e306ere?= =?iso-8859-7?B?INb18+nq3l0gzd3hIMHt4erv3+358+c6IMzF0c/TIMHQz9TFy8XTzMHU?= =?iso-8859-7?B?2c0gwiDUzC4gysHNLiDFzsXUwdPH0yAyMDE3LTE4OiDTx8zFydnTxw==?="; - assert_eq!("[mycourses.ntua.gr - Κυματική και Κβαντική Φυσική] Νέα Ανακοίνωση: ΜΕΡΟΣ ΑΠΟΤΕΛΕΣΜΑΤΩΝ Β ΤΜ. ΚΑΝ. ΕΞΕΤΑΣΗΣ 2017-18: ΣΗΜΕΙΩΣΗ" , std::str::from_utf8(&phrase(words.trim(), false).unwrap().1).unwrap()); + assert_eq!( + "[mycourses.ntua.gr - Κυματική και Κβαντική Φυσική] Νέα Ανακοίνωση: ΜΕΡΟΣ \ + ΑΠΟΤΕΛΕΣΜΑΤΩΝ Β ΤΜ. ΚΑΝ. ΕΞΕΤΑΣΗΣ 2017-18: ΣΗΜΕΙΩΣΗ", + std::str::from_utf8(&phrase(words.trim(), false).unwrap().1).unwrap() + ); let words = b"=?UTF-8?Q?=CE=A0=CF=81=CF=8C=CF=83=CE=B8=CE=B5?= =?UTF-8?Q?=CF=84=CE=B7_=CE=B5=CE=BE=CE=B5=CF=84?= =?UTF-8?Q?=CE=B1=CF=83=CF=84=CE=B9=CE=BA=CE=AE?="; assert_eq!( "Πρόσθετη εξεταστική", @@ -2929,12 +2944,16 @@ mod tests { "=?iso-8859-1?q?Fran=E7ois?= Pons " ); assert_parse!( - "هل تتكلم اللغة الإنجليزية /العربية؟", "do.you.speak@arabic.com", - "=?utf-8?b?2YfZhCDYqtiq2YPZhNmFINin2YTZhNi62Kkg2KfZhNil2YbYrNmE2YrYstmK2Kk=?=\n =?utf-8?b?IC/Yp9mE2LnYsdio2YrYqdif?= " + "هل تتكلم اللغة الإنجليزية /العربية؟", + "do.you.speak@arabic.com", + "=?utf-8?b?2YfZhCDYqtiq2YPZhNmFINin2YTZhNi62Kkg2KfZhNil2YbYrNmE2YrYstmK2Kk=?=\n \ + =?utf-8?b?IC/Yp9mE2LnYsdio2YrYqdif?= " ); assert_parse!( - "狂ったこの世で狂うなら気は確かだ。", "famous@quotes.ja", - "=?utf-8?b?54uC44Gj44Gf44GT44Gu5LiW44Gn54uC44GG44Gq44KJ5rCX44Gv56K644GL44Gg?=\n =?utf-8?b?44CC?= " + "狂ったこの世で狂うなら気は確かだ。", + "famous@quotes.ja", + "=?utf-8?b?54uC44Gj44Gf44GT44Gu5LiW44Gn54uC44GG44Gq44KJ5rCX44Gv56K644GL44Gg?=\n \ + =?utf-8?b?44CC?= " ); assert_eq!( Address::new_group( diff --git a/melib/src/email/pgp.rs b/melib/src/email/pgp.rs index d17e7259..507f785a 100644 --- a/melib/src/email/pgp.rs +++ b/melib/src/email/pgp.rs @@ -20,11 +20,13 @@ */ /*! Verification of OpenPGP signatures */ -use crate::email::{ - attachment_types::{ContentType, MultipartType}, - attachments::Attachment, +use crate::{ + email::{ + attachment_types::{ContentType, MultipartType}, + attachments::Attachment, + }, + Error, Result, }; -use crate::{Error, Result}; /// Convert raw attachment to the form needed for signature verification ([rfc3156](https://tools.ietf.org/html/rfc3156)) /// diff --git a/melib/src/error.rs b/melib/src/error.rs index 8e576640..4f1515d9 100644 --- a/melib/src/error.rs +++ b/melib/src/error.rs @@ -23,13 +23,7 @@ * An error object for `melib` */ -use std::borrow::Cow; -use std::fmt; -use std::io; -use std::result; -use std::str; -use std::string; -use std::sync::Arc; +use std::{borrow::Cow, fmt, io, result, str, string, sync::Arc}; pub type Result = result::Result; diff --git a/melib/src/gpgme/bindings.rs b/melib/src/gpgme/bindings.rs index 4883b899..4ff92587 100644 --- a/melib/src/gpgme/bindings.rs +++ b/melib/src/gpgme/bindings.rs @@ -195,8 +195,7 @@ pub struct gpgme_data { } pub type gpgme_data_t = *mut gpgme_data; pub type gpgme_error_t = gpg_error_t; -pub use self::gpg_err_code_t as gpgme_err_code_t; -pub use self::gpg_err_source_t as gpgme_err_source_t; +pub use self::{gpg_err_code_t as gpgme_err_code_t, gpg_err_source_t as gpgme_err_source_t}; pub type gpgme_strerror = extern "C" fn(err: gpgme_error_t) -> *const ::std::os::raw::c_char; pub type gpgme_strerror_r = unsafe extern "C" fn( err: gpg_error_t, @@ -5326,14 +5325,12 @@ pub type gpgme_op_assuan_transact = extern "C" fn( pub type GpgmeCtx = gpgme_ctx_t; pub type GpgmeData = gpgme_data_t; pub type GpgmeError = gpgme_error_t; -pub use self::gpgme_attr_t as GpgmeAttr; -pub use self::gpgme_data_encoding_t as GpgmeDataEncoding; -pub use self::gpgme_hash_algo_t as GpgmeHashAlgo; -pub use self::gpgme_protocol_t as GpgmeProtocol; -pub use self::gpgme_pubkey_algo_t as GpgmePubKeyAlgo; -pub use self::gpgme_sig_mode_t as GpgmeSigMode; -pub use self::gpgme_sig_stat_t as GpgmeSigStat; -pub use self::gpgme_validity_t as GpgmeValidity; +pub use self::{ + gpgme_attr_t as GpgmeAttr, gpgme_data_encoding_t as GpgmeDataEncoding, + gpgme_hash_algo_t as GpgmeHashAlgo, gpgme_protocol_t as GpgmeProtocol, + gpgme_pubkey_algo_t as GpgmePubKeyAlgo, gpgme_sig_mode_t as GpgmeSigMode, + gpgme_sig_stat_t as GpgmeSigStat, gpgme_validity_t as GpgmeValidity, +}; pub type GpgmeEngineInfo = gpgme_engine_info_t; pub type GpgmeSubkey = gpgme_subkey_t; pub type GpgmeKeySig = gpgme_key_sig_t; diff --git a/melib/src/gpgme/io.rs b/melib/src/gpgme/io.rs index 5d375787..d716e35b 100644 --- a/melib/src/gpgme/io.rs +++ b/melib/src/gpgme/io.rs @@ -19,9 +19,10 @@ * along with meli. If not, see . */ -use super::*; use std::io::{self, Read, Seek, Write}; +use super::*; + #[repr(C)] struct TagData { idx: usize, diff --git a/melib/src/gpgme/mod.rs b/melib/src/gpgme/mod.rs index 511d4ccd..858a14cb 100644 --- a/melib/src/gpgme/mod.rs +++ b/melib/src/gpgme/mod.rs @@ -19,26 +19,34 @@ * along with meli. If not, see . */ -use crate::email::{ - pgp::{DecryptionMetadata, Recipient}, - Address, +use std::{ + borrow::Cow, + collections::HashMap, + ffi::{CStr, CString, OsStr}, + future::Future, + io::Seek, + os::unix::{ + ffi::OsStrExt, + io::{AsRawFd, RawFd}, + }, + path::Path, + sync::{Arc, Mutex}, }; -use crate::error::{Error, ErrorKind, IntoError, Result, ResultIntoError}; + use futures::FutureExt; use serde::{ de::{self, Deserialize}, Deserializer, Serialize, Serializer, }; use smol::Async; -use std::borrow::Cow; -use std::collections::HashMap; -use std::ffi::{CStr, CString, OsStr}; -use std::future::Future; -use std::io::Seek; -use std::os::unix::ffi::OsStrExt; -use std::os::unix::io::{AsRawFd, RawFd}; -use std::path::Path; -use std::sync::{Arc, Mutex}; + +use crate::{ + email::{ + pgp::{DecryptionMetadata, Recipient}, + Address, + }, + error::{Error, ErrorKind, IntoError, Result, ResultIntoError}, +}; macro_rules! call { ($lib:expr, $func:ty) => {{ @@ -247,10 +255,10 @@ impl Context { let mut io_cbs = gpgme_io_cbs { add: Some(io::gpgme_register_io_cb), - add_priv: Arc::into_raw(add_priv_data) as *mut ::std::os::raw::c_void, //add_priv: *mut ::std::os::raw::c_void, + add_priv: Arc::into_raw(add_priv_data) as *mut ::std::os::raw::c_void, /* add_priv: *mut ::std::os::raw::c_void, */ remove: Some(io::gpgme_remove_io_cb), event: Some(io::gpgme_event_io_cb), - event_priv: Arc::into_raw(event_priv_data) as *mut ::std::os::raw::c_void, //pub event_priv: *mut ::std::os::raw::c_void, + event_priv: Arc::into_raw(event_priv_data) as *mut ::std::os::raw::c_void, /* pub event_priv: *mut ::std::os::raw::c_void, */ }; unsafe { @@ -1345,7 +1353,8 @@ impl Drop for Key { // futures::executor::block_on(ctx.keylist().unwrap()).unwrap() // ); // let cipher = ctx.new_data_file("/tmp/msg.asc").unwrap(); -// let plain = futures::executor::block_on(ctx.decrypt(cipher).unwrap()).unwrap(); +// let plain = +// futures::executor::block_on(ctx.decrypt(cipher).unwrap()).unwrap(); // println!( // "buf: {}", // String::from_utf8_lossy(&plain.into_bytes().unwrap()) diff --git a/melib/src/lib.rs b/melib/src/lib.rs index c50086d2..8902d27d 100644 --- a/melib/src/lib.rs +++ b/melib/src/lib.rs @@ -20,19 +20,29 @@ */ //! A crate that performs mail client operations such as -//! - Hold an [`Envelope`](./email/struct.Envelope.html) with methods convenient for mail client use. (see module [`email`](./email/index.html)) -//! - Abstract through mail storages through the [`MailBackend`](./backends/trait.MailBackend.html) trait, and handle read/writes/updates through it. (see module [`backends`](./backends/index.html)) -//! - Decode attachments (see module [`email::attachments`](./email/attachments/index.html)) +//! - Hold an [`Envelope`](./email/struct.Envelope.html) with methods convenient +//! for mail client use. (see module [`email`](./email/index.html)) +//! - Abstract through mail storages through the +//! [`MailBackend`](./backends/trait.MailBackend.html) trait, and handle +//! read/writes/updates through it. (see module +//! [`backends`](./backends/index.html)) +//! - Decode attachments (see module +//! [`email::attachments`](./email/attachments/index.html)) //! - Create new mail (see [`email::Draft`](./email/compose/struct.Draft.html)) //! - Send mail with an SMTP client (see module [`smtp`](./smtp/index.html)) -//! - Manage an `addressbook` i.e. have contacts (see module [`addressbook`](./addressbook/index.html)) -//! - Build thread structures out of a list of mail via their `In-Reply-To` and `References` header values (see module [`thread`](./thread/index.html)) +//! - Manage an `addressbook` i.e. have contacts (see module +//! [`addressbook`](./addressbook/index.html)) +//! - Build thread structures out of a list of mail via their `In-Reply-To` and +//! `References` header values (see module [`thread`](./thread/index.html)) //! //! Other exports are -//! - Basic mail account configuration to use with [`backends`](./backends/index.html) (see module [`conf`](./conf/index.html)) +//! - Basic mail account configuration to use with +//! [`backends`](./backends/index.html) (see module +//! [`conf`](./conf/index.html)) //! - Parser combinators (see module [`parsec`](./parsec/index.html)) //! - A `ShellExpandTrait` to expand paths like a shell. -//! - A `debug` macro that works like `std::dbg` but for multiple threads. (see [`debug` macro](./macro.debug.html)) +//! - A `debug` macro that works like `std::dbg` but for multiple threads. (see +//! [`debug` macro](./macro.debug.html)) #[macro_use] pub mod dbg { @@ -102,8 +112,7 @@ pub use datetime::UnixTimestamp; #[macro_use] mod logging; -pub use self::logging::LoggingLevel::*; -pub use self::logging::*; +pub use self::logging::{LoggingLevel::*, *}; pub mod addressbook; pub use addressbook::*; @@ -180,12 +189,15 @@ impl core::fmt::Display for Bytes { pub use shellexpand::ShellExpandTrait; pub mod shellexpand { - use smallvec::SmallVec; - use std::ffi::OsStr; - use std::os::unix::ffi::OsStrExt; #[cfg(not(any(target_os = "netbsd", target_os = "macos")))] use std::os::unix::io::AsRawFd; - use std::path::{Path, PathBuf}; + use std::{ + ffi::OsStr, + os::unix::ffi::OsStrExt, + path::{Path, PathBuf}, + }; + + use smallvec::SmallVec; pub trait ShellExpandTrait { fn expand(&self) -> PathBuf; @@ -233,23 +245,20 @@ pub mod shellexpand { let (prefix, _match) = if self.as_os_str().as_bytes().ends_with(b"/.") { (self.components().as_path(), OsStr::from_bytes(b".")) + } else if self.exists() && (!force || self.as_os_str().as_bytes().ends_with(b"/")) { + return SmallVec::new(); } else { - if self.exists() && (!force || self.as_os_str().as_bytes().ends_with(b"/")) { - // println!("{} {:?}", self.display(), self.components().last()); - return SmallVec::new(); + let last_component = self + .components() + .last() + .map(|c| c.as_os_str()) + .unwrap_or_else(|| OsStr::from_bytes(b"")); + let prefix = if let Some(p) = self.parent() { + p } else { - let last_component = self - .components() - .last() - .map(|c| c.as_os_str()) - .unwrap_or_else(|| OsStr::from_bytes(b"")); - let prefix = if let Some(p) = self.parent() { - p - } else { - return SmallVec::new(); - }; - (prefix, last_component) - } + return SmallVec::new(); + }; + (prefix, last_component) }; let dir = match ::nix::dir::Dir::openat( @@ -322,10 +331,13 @@ pub mod shellexpand { pos += dir[0].d_reclen as usize; } // https://github.com/romkatv/gitstatus/blob/caf44f7aaf33d0f46e6749e50595323c277e0908/src/dir.cc - // "It's tempting to bail here if n + sizeof(linux_dirent64) + 512 <= n. After all, there - // was enough space for another entry but SYS_getdents64 didn't write it, so this must be - // the end of the directory listing, right? Unfortunately, no. SYS_getdents64 is finicky. - // It sometimes writes a partial list of entries even if the full list would fit." + // "It's tempting to bail here if n + sizeof(linux_dirent64) + + // 512 <= n. After all, there was enough space + // for another entry but SYS_getdents64 didn't write it, so this + // must be the end of the directory listing, + // right? Unfortunately, no. SYS_getdents64 is finicky. + // It sometimes writes a partial list of entries even if the + // full list would fit." } entries } @@ -420,8 +432,7 @@ macro_rules! declare_u64_hash { impl $type_name { #[inline(always)] pub fn from_bytes(bytes: &[u8]) -> Self { - use std::collections::hash_map::DefaultHasher; - use std::hash::Hasher; + use std::{collections::hash_map::DefaultHasher, hash::Hasher}; let mut h = DefaultHasher::new(); h.write(bytes); Self(h.finish()) diff --git a/melib/src/logging.rs b/melib/src/logging.rs index 6259b4a3..36f9c165 100644 --- a/melib/src/logging.rs +++ b/melib/src/logging.rs @@ -19,11 +19,14 @@ * along with meli. If not, see . */ +use std::{ + fs::OpenOptions, + io::{BufWriter, Write}, + path::PathBuf, + sync::{Arc, Mutex}, +}; + use crate::shellexpand::ShellExpandTrait; -use std::fs::OpenOptions; -use std::io::{BufWriter, Write}; -use std::path::PathBuf; -use std::sync::{Arc, Mutex}; #[derive(Copy, Clone, PartialEq, PartialOrd, Hash, Debug, Serialize, Deserialize)] pub enum LoggingLevel { diff --git a/melib/src/parsec.rs b/melib/src/parsec.rs index c4205b19..a8541c05 100644 --- a/melib/src/parsec.rs +++ b/melib/src/parsec.rs @@ -442,30 +442,17 @@ pub fn is_not<'a>(slice: &'static [u8]) -> impl Parser<'a, &'a str> { /// /// let parser = |input| { /// alt([ -/// delimited( -/// match_literal("{"), -/// quoted_slice(), -/// match_literal("}"), -/// ), -/// delimited( -/// match_literal("["), -/// quoted_slice(), -/// match_literal("]"), -/// ), -/// ]).parse(input) +/// delimited(match_literal("{"), quoted_slice(), match_literal("}")), +/// delimited(match_literal("["), quoted_slice(), match_literal("]")), +/// ]) +/// .parse(input) /// }; /// /// let input1: &str = "{\"quoted\"}"; /// let input2: &str = "[\"quoted\"]"; -/// assert_eq!( -/// Ok(("", "quoted")), -/// parser.parse(input1) -/// ); +/// assert_eq!(Ok(("", "quoted")), parser.parse(input1)); /// -/// assert_eq!( -/// Ok(("", "quoted")), -/// parser.parse(input2) -/// ); +/// assert_eq!(Ok(("", "quoted")), parser.parse(input2)); /// ``` pub fn alt<'a, P, A, const N: usize>(parsers: [P; N]) -> impl Parser<'a, A> where @@ -591,20 +578,17 @@ pub fn take<'a>(count: usize) -> impl Parser<'a, &'a str> { ///```rust /// # use std::str::FromStr; /// # use melib::parsec::{Parser, delimited, match_literal, map_res, is_a, take_literal}; -/// let lit: &str = "{31}\r\nThere is no script by that name\r\n"; -/// assert_eq!( -/// take_literal(delimited( -/// match_literal("{"), -/// map_res(is_a(b"0123456789"), |s| usize::from_str(s)), -/// match_literal("}\r\n"), -/// )) -/// .parse(lit), -/// Ok(( -/// "\r\n", -/// "There is no script by that name", -/// )) -/// ); -///``` +/// let lit: &str = "{31}\r\nThere is no script by that name\r\n"; +/// assert_eq!( +/// take_literal(delimited( +/// match_literal("{"), +/// map_res(is_a(b"0123456789"), |s| usize::from_str(s)), +/// match_literal("}\r\n"), +/// )) +/// .parse(lit), +/// Ok(("\r\n", "There is no script by that name",)) +/// ); +/// ``` pub fn take_literal<'a, P>(parser: P) -> impl Parser<'a, &'a str> where P: Parser<'a, usize>, @@ -617,9 +601,10 @@ where #[cfg(test)] mod test { - use super::*; use std::collections::HashMap; + use super::*; + #[test] fn test_parsec() { #[derive(Debug, PartialEq)] @@ -639,16 +624,16 @@ mod test { either( either( either( - map(parse_bool(), |b| JsonValue::JsonBool(b)), + map(parse_bool(), JsonValue::JsonBool), map(parse_null(), |()| JsonValue::JsonNull), ), - map(parse_array(), |vec| JsonValue::JsonArray(vec)), + map(parse_array(), JsonValue::JsonArray), ), - map(parse_object(), |obj| JsonValue::JsonObject(obj)), + map(parse_object(), JsonValue::JsonObject), ), - map(parse_number(), |n| JsonValue::JsonNumber(n)), + map(parse_number(), JsonValue::JsonNumber), ), - map(quoted_string(), |s| JsonValue::JsonString(s)), + map(quoted_string(), JsonValue::JsonString), ) .parse(input) } diff --git a/melib/src/search.rs b/melib/src/search.rs index 467d7b02..0693cc7a 100644 --- a/melib/src/search.rs +++ b/melib/src/search.rs @@ -19,14 +19,13 @@ * along with meli. If not, see . */ -use crate::parsec::*; -use crate::UnixTimestamp; -use std::borrow::Cow; -use std::convert::TryFrom; +use std::{borrow::Cow, convert::TryFrom}; pub use query_parser::query; use Query::*; +use crate::{parsec::*, UnixTimestamp}; + #[derive(Debug, PartialEq, Clone, Serialize)] pub enum Query { Before(UnixTimestamp), @@ -233,9 +232,10 @@ pub mod query_parser { /// /// # Invocation /// ``` - /// use melib::search::query; - /// use melib::search::Query; - /// use melib::parsec::Parser; + /// use melib::{ + /// parsec::Parser, + /// search::{query, Query}, + /// }; /// /// let input = "test"; /// let query = query().parse(input); diff --git a/melib/src/sieve.rs b/melib/src/sieve.rs index d84e07b3..6a66a264 100644 --- a/melib/src/sieve.rs +++ b/melib/src/sieve.rs @@ -153,7 +153,8 @@ pub enum ZoneRule { ///time zone in offset format "+hhmm" or "-hhmm". An ///offset of 0 (Zulu) always has a positive sign. Zone, - /// "weekday" => the day of the week expressed as an integer between "0" and "6". "0" is Sunday, "1" is Monday, etc. + /// "weekday" => the day of the week expressed as an integer between "0" + /// and "6". "0" is Sunday, "1" is Monday, etc. Weekday, } @@ -370,9 +371,9 @@ pub mod parser { ), |(num_s, quant)| { Ok(match (num_s.parse::(), quant.to_ascii_lowercase()) { - (Ok(num), 'k') => num * 1000, - (Ok(num), 'm') => num * 1000_000, - (Ok(num), 'g') => num * 1000_000_000, + (Ok(num), 'k') => num * 1_000, + (Ok(num), 'm') => num * 1_000_000, + (Ok(num), 'g') => num * 1_000_000_000, _ => return Err(num_s), }) }, @@ -483,7 +484,8 @@ pub mod parser { } } - // address [COMPARATOR] [ADDRESS-PART] [MATCH-TYPE] + // address [COMPARATOR] [ADDRESS-PART] [MATCH-TYPE] + // pub fn parse_sieve_address<'a>() -> impl Parser<'a, ConditionRule> { move |input| { map( @@ -677,19 +679,12 @@ pub mod parser { #[cfg(test)] mod test { - use super::parser::*; + use super::{ + parser::*, ActionCommand::*, AddressOperator::*, CharacterOperator::*, ConditionRule::*, + ControlCommand::*, IntegerOperator::*, MatchOperator::*, Rule::*, RuleBlock, + }; use crate::parsec::Parser; - use super::ActionCommand::*; - use super::AddressOperator::*; - use super::CharacterOperator::*; - use super::ConditionRule::*; - use super::ControlCommand::*; - use super::IntegerOperator::*; - use super::MatchOperator::*; - use super::Rule::*; - use super::RuleBlock; - #[test] fn test_sieve_parse_strings() { assert_eq!( @@ -705,9 +700,10 @@ mod test { #[test] fn test_sieve_parse_conditionals() { - /* Operators that start with : like :matches are unordered and optional, since they have - * defaults. But that means we must handle any order correctly, which is tricky if we use - * an optional parser; for an optional parser both None and Some(_) are valid values. + /* Operators that start with : like :matches are unordered and optional, + * since they have defaults. But that means we must handle any order + * correctly, which is tricky if we use an optional parser; for an + * optional parser both None and Some(_) are valid values. */ /* Permutations of two */ diff --git a/melib/src/smtp.rs b/melib/src/smtp.rs index 1c384117..8f9d1f3b 100644 --- a/melib/src/smtp.rs +++ b/melib/src/smtp.rs @@ -24,8 +24,8 @@ //! SMTP client support //! -//! This module implements a client for the SMTP protocol as specified by [RFC 5321 Simple Mail -//! Transfer Protocol](https://www.rfc-editor.org/rfc/rfc5321). +//! This module implements a client for the SMTP protocol as specified by [RFC +//! 5321 Simple Mail Transfer Protocol](https://www.rfc-editor.org/rfc/rfc5321). //! //! The connection and methods are `async` and uses the `smol` runtime. //!# Example @@ -72,18 +72,18 @@ //! Ok(()) //! ``` -use crate::connections::{lookup_ipv4, Connection}; -use crate::email::{parser::BytesExt, Address, Envelope}; -use crate::error::{Error, Result, ResultIntoError}; +use std::{borrow::Cow, convert::TryFrom, net::TcpStream, process::Command}; + use futures::io::{AsyncReadExt, AsyncWriteExt}; use native_tls::TlsConnector; use smallvec::SmallVec; -use smol::unblock; -use smol::Async as AsyncWrapper; -use std::borrow::Cow; -use std::convert::TryFrom; -use std::net::TcpStream; -use std::process::Command; +use smol::{unblock, Async as AsyncWrapper}; + +use crate::{ + connections::{lookup_ipv4, Connection}, + email::{parser::BytesExt, Address, Envelope}, + error::{Error, Result, ResultIntoError}, +}; /// Kind of server security (StartTLS/TLS/None) the client should attempt #[derive(Debug, Copy, PartialEq, Eq, Clone, Serialize, Deserialize)] @@ -191,11 +191,12 @@ pub struct SmtpExtensionSupport { /// [RFC 6152: SMTP Service Extension for 8-bit MIME Transport](https://www.rfc-editor.org/rfc/rfc6152) #[serde(default = "crate::conf::true_val")] _8bitmime: bool, - /// Essentially, the PRDR extension to SMTP allows (but does not require) an SMTP server to - /// issue multiple responses after a message has been transferred, by mutual consent of the - /// client and server. SMTP clients that support the PRDR extension then use the expanded - /// responses as supplemental data to the responses that were received during the earlier - /// envelope exchange. + /// Essentially, the PRDR extension to SMTP allows (but does not require) an + /// SMTP server to issue multiple responses after a message has been + /// transferred, by mutual consent of the client and server. SMTP + /// clients that support the PRDR extension then use the expanded + /// responses as supplemental data to the responses that were received + /// during the earlier envelope exchange. #[serde(default = "crate::conf::true_val")] prdr: bool, #[serde(default = "crate::conf::true_val")] @@ -284,7 +285,10 @@ impl SmtpConnection { danger_accept_invalid_certs, }; } else { - return Err(Error::new("Please specify what SMTP security transport to use explicitly instead of `auto`.")); + return Err(Error::new( + "Please specify what SMTP security transport to use explicitly \ + instead of `auto`.", + )); } } socket.write_all(b"EHLO meli.delivery\r\n").await?; @@ -386,9 +390,11 @@ impl SmtpConnection { .any(|l| l.starts_with("AUTH")) { return Err(Error::new(format!( - "SMTP Server doesn't advertise Authentication support. Server response was: {:?}", - pre_auth_extensions_reply - )).set_kind(crate::error::ErrorKind::Authentication)); + "SMTP Server doesn't advertise Authentication support. Server response was: \ + {:?}", + pre_auth_extensions_reply + )) + .set_kind(crate::error::ErrorKind::Authentication)); } no_auth_needed = ret.server_conf.auth == SmtpAuth::None || !ret.server_conf.auth.require_auth(); @@ -430,7 +436,7 @@ impl SmtpConnection { let mut output = unblock(move || { Command::new("sh") - .args(&["-c", &_command]) + .args(["-c", &_command]) .stdin(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) @@ -493,7 +499,7 @@ impl SmtpConnection { let _token_command = token_command.clone(); let mut output = unblock(move || { Command::new("sh") - .args(&["-c", &_token_command]) + .args(["-c", &_token_command]) .stdin(std::process::Stdio::piped()) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()) @@ -538,7 +544,7 @@ impl SmtpConnection { self.server_conf.envelope_from = envelope_from; } - fn set_extension_support(&mut self, reply: Reply<'_>) { + fn set_extension_support(&mut self, reply: Reply) { debug_assert_eq!(reply.code, ReplyCode::_250); self.server_conf.extensions.pipelining &= reply.lines.contains(&"PIPELINING"); self.server_conf.extensions.chunking &= reply.lines.contains(&"CHUNKING"); @@ -595,7 +601,10 @@ impl SmtpConnection { .chain_err_summary(|| "SMTP submission was aborted")?; let tos = tos.unwrap_or_else(|| envelope.to()); if tos.is_empty() && envelope.cc().is_empty() && envelope.bcc().is_empty() { - return Err(Error::new("SMTP submission was aborted because there was no e-mail address found in the To: header field. Consider adding recipients.")); + return Err(Error::new( + "SMTP submission was aborted because there was no e-mail address found in the To: \ + header field. Consider adding recipients.", + )); } let mut current_command: SmallVec<[&[u8]; 16]> = SmallVec::new(); //first step in the procedure is the MAIL command. @@ -605,9 +614,17 @@ impl SmtpConnection { current_command.push(envelope_from.trim().as_bytes()); } else { if envelope.from().is_empty() { - return Err(Error::new("SMTP submission was aborted because there was no e-mail address found in the From: header field. Consider adding a valid value or setting `envelope_from` in SMTP client settings")); + return Err(Error::new( + "SMTP submission was aborted because there was no e-mail address found in the \ + From: header field. Consider adding a valid value or setting `envelope_from` \ + in SMTP client settings", + )); } else if envelope.from().len() != 1 { - return Err(Error::new("SMTP submission was aborted because there was more than one e-mail address found in the From: header field. Consider setting `envelope_from` in SMTP client settings")); + return Err(Error::new( + "SMTP submission was aborted because there was more than one e-mail address \ + found in the From: header field. Consider setting `envelope_from` in SMTP \ + client settings", + )); } current_command.push(envelope.from()[0].address_spec_raw().trim()); } @@ -628,12 +645,13 @@ impl SmtpConnection { } else { pipelining_queue.push(Some((ReplyCode::_250, &[]))); } - //The second step in the procedure is the RCPT command. This step of the procedure can - //be repeated any number of times. If accepted, the SMTP server returns a "250 OK" - //reply. If the mailbox specification is not acceptable for some reason, the server MUST - //return a reply indicating whether the failure is permanent (i.e., will occur again if - //the client tries to send the same address again) or temporary (i.e., the address might - //be accepted if the client tries again later). + //The second step in the procedure is the RCPT command. This step of the + // procedure can be repeated any number of times. If accepted, the SMTP + // server returns a "250 OK" reply. If the mailbox specification is not + // acceptable for some reason, the server MUST return a reply indicating + // whether the failure is permanent (i.e., will occur again if + // the client tries to send the same address again) or temporary (i.e., the + // address might be accepted if the client tries again later). for addr in tos .iter() .chain(envelope.cc().iter()) @@ -651,7 +669,8 @@ impl SmtpConnection { self.send_command(¤t_command).await?; //RCPT TO: [ SP ] - //If accepted, the SMTP server returns a "250 OK" reply and stores the forward-path. + //If accepted, the SMTP server returns a "250 OK" reply and stores the + // forward-path. if !self.server_conf.extensions.pipelining { self.read_lines(&mut res, Some((ReplyCode::_250, &[]))) .await?; @@ -660,9 +679,10 @@ impl SmtpConnection { } } - //Since it has been a common source of errors, it is worth noting that spaces are not - //permitted on either side of the colon following FROM in the MAIL command or TO in the - //RCPT command. The syntax is exactly as given above. + //Since it has been a common source of errors, it is worth noting that spaces + // are not permitted on either side of the colon following FROM in the + // MAIL command or TO in the RCPT command. The syntax is exactly as + // given above. if self.server_conf.extensions.binarymime { let mail_length = format!("{}", mail.as_bytes().len()); @@ -674,13 +694,14 @@ impl SmtpConnection { //(or some alternative specified in a service extension). //DATA self.send_command(&[b"DATA"]).await?; - //Client SMTP implementations that employ pipelining MUST check ALL statuses associated - //with each command in a group. For example, if none of the RCPT TO recipient addresses - //were accepted the client must then check the response to the DATA command -- the client - //cannot assume that the DATA command will be rejected just because none of the RCPT TO - //commands worked. If the DATA command was properly rejected the client SMTP can just - //issue RSET, but if the DATA command was accepted the client SMTP should send a single - //dot. + //Client SMTP implementations that employ pipelining MUST check ALL statuses + // associated with each command in a group. For example, if none of + // the RCPT TO recipient addresses were accepted the client must + // then check the response to the DATA command -- the client + // cannot assume that the DATA command will be rejected just because none of the + // RCPT TO commands worked. If the DATA command was properly + // rejected the client SMTP can just issue RSET, but if the DATA + // command was accepted the client SMTP should send a single dot. let mut _all_error = self.server_conf.extensions.pipelining; let mut _any_error = false; let mut ignore_mailfrom = true; @@ -694,15 +715,17 @@ impl SmtpConnection { pipelining_results.push(reply.into()); } - //If accepted, the SMTP server returns a 354 Intermediate reply and considers all - //succeeding lines up to but not including the end of mail data indicator to be the - //message text. When the end of text is successfully received and stored, the - //SMTP-receiver sends a "250 OK" reply. + //If accepted, the SMTP server returns a 354 Intermediate reply and considers + // all succeeding lines up to but not including the end of mail data + // indicator to be the message text. When the end of text is + // successfully received and stored, the SMTP-receiver sends a "250 + // OK" reply. self.read_lines(&mut res, Some((ReplyCode::_354, &[]))) .await?; - //Before sending a line of mail text, the SMTP client checks the first character of the - //line.If it is a period, one additional period is inserted at the beginning of the line. + //Before sending a line of mail text, the SMTP client checks the first + // character of the line.If it is a period, one additional period is + // inserted at the beginning of the line. for line in mail.lines() { if line.starts_with('.') { self.stream.write_all(b".").await?; @@ -715,15 +738,16 @@ impl SmtpConnection { self.stream.write_all(b".\r\n").await?; } - //The mail data are terminated by a line containing only a period, that is, the character - //sequence ".", where the first is actually the terminator of the - //previous line (see Section 4.5.2). This is the end of mail data indication. + //The mail data are terminated by a line containing only a period, that is, the + // character sequence ".", where the first is + // actually the terminator of the previous line (see Section 4.5.2). + // This is the end of mail data indication. self.stream.write_all(b".\r\n").await?; } - //The end of mail data indicator also confirms the mail transaction and tells the SMTP - //server to now process the stored recipients and mail data. If accepted, the SMTP - //server returns a "250 OK" reply. + //The end of mail data indicator also confirms the mail transaction and tells + // the SMTP server to now process the stored recipients and mail data. + // If accepted, the SMTP server returns a "250 OK" reply. let reply_code = self .read_lines( &mut res, @@ -760,7 +784,9 @@ pub type ExpectedReplyCode = Option<(ReplyCode, &'static [ReplyCode])>; pub enum ReplyCode { /// System status, or system help reply _211, - /// Help message (Information on how to use the receiver or the meaning of a particular non-standard command; this reply is useful only to the human user) + /// Help message (Information on how to use the receiver or the meaning of a + /// particular non-standard command; this reply is useful only to the human + /// user) _214, /// Service ready _220, @@ -772,7 +798,8 @@ pub enum ReplyCode { _250, /// User not local; will forward to (See Section 3.4) _251, - /// Cannot VRFY user, but will accept message and attempt delivery (See Section 3.5.3) + /// Cannot VRFY user, but will accept message and attempt delivery (See + /// Section 3.5.3) _252, /// rfc4954 AUTH continuation request _334, @@ -780,9 +807,11 @@ pub enum ReplyCode { _353, /// Start mail input; end with . _354, - /// Service not available, closing transmission channel (This may be a reply to any command if the service knows it must shut down) + /// Service not available, closing transmission channel (This may + /// be a reply to any command if the service knows it must shut down) _421, - /// Requested mail action not taken: mailbox unavailable (e.g., mailbox busy or temporarily blocked for policy reasons) + /// Requested mail action not taken: mailbox unavailable (e.g., mailbox busy + /// or temporarily blocked for policy reasons) _450, /// Requested action aborted: local error in processing _451, @@ -790,7 +819,8 @@ pub enum ReplyCode { _452, /// Server unable to accommodate parameters _455, - /// Syntax error, command unrecognized (This may include errors such as command line too long) + /// Syntax error, command unrecognized (This may include errors such as + /// command line too long) _500, /// Syntax error in parameters or arguments _501, @@ -802,15 +832,18 @@ pub enum ReplyCode { _504, /// Authentication failed _535, - /// Requested action not taken: mailbox unavailable (e.g., mailbox not found, no access, or command rejected for policy reasons) + /// Requested action not taken: mailbox unavailable (e.g., mailbox not + /// found, no access, or command rejected for policy reasons) _550, /// User not local; please try (See Section 3.4) _551, /// Requested mail action aborted: exceeded storage allocation _552, - /// Requested action not taken: mailbox name not allowed (e.g., mailbox syntax incorrect) + /// Requested action not taken: mailbox name not allowed (e.g., mailbox + /// syntax incorrect) _553, - /// Transaction failed (Or, in the case of a connection-opening response, "No SMTP service here") + /// Transaction failed (Or, in the case of a connection-opening response, + /// "No SMTP service here") _554, /// MAIL FROM/RCPT TO parameters not recognized or not implemented _555, @@ -844,10 +877,16 @@ impl ReplyCode { _503 => "Bad sequence of commands", _504 => "Command parameter not implemented", _535 => "Authentication failed", - _550 => "Requested action not taken: mailbox unavailable (e.g., mailbox not found, no access, or command rejected for policy reasons)", + _550 => { + "Requested action not taken: mailbox unavailable (e.g., mailbox not found, no \ + access, or command rejected for policy reasons)" + } _551 => "User not local", _552 => "Requested mail action aborted: exceeded storage allocation", - _553 => "Requested action not taken: mailbox name not allowed (e.g., mailbox syntax incorrect)", + _553 => { + "Requested action not taken: mailbox name not allowed (e.g., mailbox syntax \ + incorrect)" + } _554 => "Transaction failed", _555 => "MAIL FROM/RCPT TO parameters not recognized or not implemented", _530 => "Must issue a STARTTLS command first", @@ -927,19 +966,19 @@ pub struct Reply<'s> { pub lines: SmallVec<[&'s str; 16]>, } -impl<'s> Into> for Reply<'s> { - fn into(self: Reply<'s>) -> Result { - if self.code.is_err() { - Err(Error::new(self.lines.join("\n")).set_summary(self.code.as_str())) +impl<'s> From> for Result { + fn from(val: Reply<'s>) -> Self { + if val.code.is_err() { + Err(Error::new(val.lines.join("\n")).set_summary(val.code.as_str())) } else { - Ok(self.code) + Ok(val.code) } } } impl<'s> Reply<'s> { - /// `s` must be raw SMTP output i.e each line must start with 3 digit reply code, a space - /// or '-' and end with '\r\n' + /// `s` must be raw SMTP output i.e each line must start with 3 digit reply + /// code, a space or '-' and end with '\r\n' pub fn new(s: &'s str, code: ReplyCode) -> Self { let lines: SmallVec<_> = s.lines().map(|l| &l[4..l.len()]).collect(); Reply { lines, code } @@ -959,7 +998,9 @@ async fn read_lines<'r>( let mut returned_code: Option = None; 'read_loop: loop { while let Some(pos) = ret[last_line_idx..].find("\r\n") { - // "Formally, a reply is defined to be the sequence: a three-digit code, , one line of text, and , or a multiline reply (as defined in the same section)." + // "Formally, a reply is defined to be the sequence: a three-digit code, , + // one line of text, and , or a multiline reply (as defined in the same + // section)." if ret[last_line_idx..].len() < 4 || !ret[last_line_idx..] .chars() @@ -1022,12 +1063,15 @@ async fn read_lines<'r>( #[cfg(test)] mod test { - use super::*; + use std::net::IpAddr; //, Ipv4Addr, Ipv6Addr}; + use std::{ + sync::{Arc, Mutex}, + thread, + }; use mailin_embedded::{Handler, Response, Server, SslConfig}; - use std::net::IpAddr; //, Ipv4Addr, Ipv6Addr}; - use std::sync::{Arc, Mutex}; - use std::thread; + + use super::*; const ADDRESS: &str = "127.0.0.1:8825"; #[derive(Debug, Clone)] @@ -1229,7 +1273,7 @@ mod test { futures::executor::block_on(SmtpConnection::new_connection(smtp_server_conf)).unwrap(); futures::executor::block_on(connection.mail_transaction( input_str, - /*tos*/ + /* tos */ Some(&[ Address::try_from("foo-chat@example.com").unwrap(), Address::try_from("webmaster@example.com").unwrap(), diff --git a/melib/src/sqlite3.rs b/melib/src/sqlite3.rs index a8177d49..9c6995b0 100644 --- a/melib/src/sqlite3.rs +++ b/melib/src/sqlite3.rs @@ -19,10 +19,12 @@ * along with meli. If not, see . */ -use crate::{error::*, logging::log, Envelope}; +use std::path::PathBuf; + use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput}; pub use rusqlite::{self, params, Connection}; -use std::path::PathBuf; + +use crate::{error::*, logging::log, Envelope}; #[derive(Copy, Clone, Debug)] pub struct DatabaseDescription { @@ -90,8 +92,9 @@ pub fn open_or_create_db( ); if second_try { return Err(Error::new(format!( - "Database version mismatch, is {} but expected {}. Could not recreate database.", - version, description.version + "Database version mismatch, is {} but expected {}. Could not recreate \ + database.", + version, description.version ))); } reset_db(description, identifier)?; @@ -100,7 +103,7 @@ pub fn open_or_create_db( } if version == 0 { - conn.pragma_update(None, "user_version", &description.version)?; + conn.pragma_update(None, "user_version", description.version)?; } if let Some(s) = description.init_script { conn.execute_batch(s) diff --git a/melib/src/text_processing/grapheme_clusters.rs b/melib/src/text_processing/grapheme_clusters.rs index e74cf7ed..069417ea 100644 --- a/melib/src/text_processing/grapheme_clusters.rs +++ b/melib/src/text_processing/grapheme_clusters.rs @@ -29,8 +29,10 @@ */ -use super::types::Reflow; -use super::wcwidth::{wcwidth, CodePointsIter}; +use super::{ + types::Reflow, + wcwidth::{wcwidth, CodePointsIter}, +}; extern crate unicode_segmentation; use self::unicode_segmentation::UnicodeSegmentation; @@ -187,12 +189,13 @@ pub fn word_break_string(s: &str, width: usize) -> Vec<&str> { //} // //fn is_surrogate(s: &str, pos: usize) -> bool { -// return 0xd800 <= char_code_at(s, pos) && char_code_at(s, pos) <= 0xdbff && -// 0xdc00 <= char_code_at(s, pos + 1) && char_code_at(s, pos + 1) <= 0xdfff; +// return 0xd800 <= char_code_at(s, pos) && char_code_at(s, pos) <= 0xdbff +// && 0xdc00 <= char_code_at(s, pos + 1) && char_code_at(s, pos + 1) <= +// 0xdfff; //} // -//// Private function, gets a Unicode code point from a java_script UTF-16 string -//// handling surrogate pairs appropriately +//// Private function, gets a Unicode code point from a java_script UTF-16 +//// string handling surrogate pairs appropriately //fn code_point_at(s: &str, idx: usize) -> u8 { // let mut code: u8 = char_code_at(s, idx); // @@ -234,8 +237,8 @@ pub fn word_break_string(s: &str, width: usize) -> Vec<&str> { // // GB10. (E_Base | EBG) Extend* ? E_Modifier // let mut e_modifier_index = all.last_index_of(E_Modifier) // if(e_modifier_index > 1 && -// all.slice(1, e_modifier_index).every(function(c){return c == Extend}) && -// [Extend, E_Base, E_Base_GAZ].index_of(start) == -1){ +// all.slice(1, e_modifier_index).every(function(c){return c == +// Extend}) && [Extend, E_Base, E_Base_GAZ].index_of(start) == -1){ // return Break // } // @@ -244,9 +247,10 @@ pub fn word_break_string(s: &str, width: usize) -> Vec<&str> { // // GB13. [^RI] (RI RI)* RI ? RI // let mut r_iIndex = all.last_index_of(Regional_Indicator) // if(r_iIndex > 0 && -// all.slice(1, r_iIndex).every(function(c){return c == Regional_Indicator}) && -// [Prepend, Regional_Indicator].index_of(previous) == -1) { -// if(all.filter(function(c){return c == Regional_Indicator}).length % 2 == 1) { +// all.slice(1, r_iIndex).every(function(c){return c == +// Regional_Indicator}) && [Prepend, +// Regional_Indicator].index_of(previous) == -1) { +// if(all.filter(function(c){return c == Regional_Indicator}).length % 2 == 1) { // return BreakLastRegional // } // else { @@ -300,10 +304,11 @@ pub fn word_break_string(s: &str, width: usize) -> Vec<&str> { // } // // // GB10. (E_Base | EBG) Extend* ? E_Modifier -// let mut previous_non_extend_index = all.index_of(Extend) != -1 ? all.last_index_of(Extend) - 1 : all.length - 2; -// if([E_Base, E_Base_GAZ].index_of(all[previous_non_extend_index]) != -1 && -// all.slice(previous_non_extend_index + 1, -1).every(function(c){return c == Extend}) && -// next == E_Modifier){ +// let mut previous_non_extend_index = all.index_of(Extend) != -1 ? +// all.last_index_of(Extend) - 1 : all.length - 2; if([E_Base, +// E_Base_GAZ].index_of(all[previous_non_extend_index]) != -1 && +// all.slice(previous_non_extend_index + 1, -1).every(function(c){return c +// == Extend}) && next == E_Modifier){ // return NotBreak; // } // @@ -388,8 +393,8 @@ pub fn word_break_string(s: &str, width: usize) -> Vec<&str> { //// return { value: undefined, done: true }; //// }).bind(this) //// }; -//// // ES2015 @@iterator method (iterable) for spread syntax and for...of statement -//// if (typeof Symbol !== 'undefined' && Symbol.iterator) { +//// // ES2015 @@iterator method (iterable) for spread syntax and for...of +//// statement if (typeof Symbol !== 'undefined' && Symbol.iterator) { //// res[Symbol.iterator] = function() {return res}; //// } //// return res; @@ -419,17 +424,18 @@ pub fn word_break_string(s: &str, width: usize) -> Vec<&str> { // //and adapted to java_script rules // // if( -// (0x0600 <= code && code <= 0x0605) || // Cf [6] ARABIC NUMBER SIGN..ARABIC NUMBER MARK ABOVE -// 0x06DD == code || // Cf ARABIC END OF AYAH -// 0x070F == code || // Cf SYRIAC ABBREVIATION MARK +// (0x0600 <= code && code <= 0x0605) || // Cf [6] ARABIC NUMBER +// SIGN..ARABIC NUMBER MARK ABOVE 0x06DD == code || // Cf ARABIC +// END OF AYAH 0x070F == code || // Cf SYRIAC ABBREVIATION MARK // 0x08E2 == code || // Cf ARABIC DISPUTED END OF AYAH // 0x0D4E == code || // Lo MALAYALAM LETTER DOT REPH // 0x110BD == code || // Cf KAITHI NUMBER SIGN -// (0x111C2 <= code && code <= 0x111C3) || // Lo [2] SHARADA SIGN JIHVAMULIYA..SHARADA SIGN UPADHMANIYA -// 0x11A3A == code || // Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA -// (0x11A86 <= code && code <= 0x11A89) || // Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO CLUSTER-INITIAL LETTER SA -// 0x11D46 == code // Lo MASARAM GONDI REPHA -// ){ +// (0x111C2 <= code && code <= 0x111C3) || // Lo [2] SHARADA SIGN +// JIHVAMULIYA..SHARADA SIGN UPADHMANIYA 0x11A3A == code || // Lo +// ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA (0x11A86 <= code && code <= +// 0x11A89) || // Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO +// CLUSTER-INITIAL LETTER SA 0x11D46 == code // Lo MASARAM GONDI +// REPHA ){ // return Prepend; // } // if( @@ -446,549 +452,679 @@ pub fn word_break_string(s: &str, width: usize) -> Vec<&str> { // // // if( -// (0x0000 <= code && code <= 0x0009) || // Cc [10] .. -// (0x000B <= code && code <= 0x000C) || // Cc [2] .. -// (0x000E <= code && code <= 0x001F) || // Cc [18] .. -// (0x007F <= code && code <= 0x009F) || // Cc [33] .. +// (0x0000 <= code && code <= 0x0009) || // Cc [10] +// .. (0x000B <= code && code <= 0x000C) || +// // Cc [2] .. (0x000E <= code && code <= +// 0x001F) || // Cc [18] .. (0x007F <= code +// && code <= 0x009F) || // Cc [33] .. // 0x00AD == code || // Cf SOFT HYPHEN // 0x061C == code || // Cf ARABIC LETTER MARK // // 0x180E == code || // Cf MONGOLIAN VOWEL SEPARATOR // 0x200B == code || // Cf ZERO WIDTH SPACE -// (0x200E <= code && code <= 0x200F) || // Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK -// 0x2028 == code || // Zl LINE SEPARATOR +// (0x200E <= code && code <= 0x200F) || // Cf [2] LEFT-TO-RIGHT +// MARK..RIGHT-TO-LEFT MARK 0x2028 == code || // Zl LINE SEPARATOR // 0x2029 == code || // Zp PARAGRAPH SEPARATOR -// (0x202A <= code && code <= 0x202E) || // Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE -// (0x2060 <= code && code <= 0x2064) || // Cf [5] WORD JOINER..INVISIBLE PLUS -// 0x2065 == code || // Cn -// (0x2066 <= code && code <= 0x206F) || // Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES -// (0x_d800 <= code && code <= 0x_dFFF) || // Cs [2048] .. -// 0x_fEFF == code || // Cf ZERO WIDTH NO-BREAK SPACE -// (0x_fFF0 <= code && code <= 0x_fFF8) || // Cn [9] .. -// (0x_fFF9 <= code && code <= 0x_fFFB) || // Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR -// (0x1BCA0 <= code && code <= 0x1BCA3) || // Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP -// (0x1D173 <= code && code <= 0x1D17A) || // Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE -// 0x_e0000 == code || // Cn -// 0x_e0001 == code || // Cf LANGUAGE TAG -// (0x_e0002 <= code && code <= 0x_e001F) || // Cn [30] .. -// (0x_e0080 <= code && code <= 0x_e00FF) || // Cn [128] .. -// (0x_e01F0 <= code && code <= 0x_e0FFF) // Cn [3600] .. +// (0x202A <= code && code <= 0x202E) || // Cf [5] LEFT-TO-RIGHT +// EMBEDDING..RIGHT-TO-LEFT OVERRIDE (0x2060 <= code && code <= 0x2064) +// || // Cf [5] WORD JOINER..INVISIBLE PLUS 0x2065 == code || // Cn +// (0x2066 <= code && code <= 0x206F) || // Cf [10] +// LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES (0x_d800 <= code && code +// <= 0x_dFFF) || // Cs [2048] .. 0x_fEFF +// == code || // Cf ZERO WIDTH NO-BREAK SPACE (0x_fFF0 <= code && +// code <= 0x_fFF8) || // Cn [9] .. +// (0x_fFF9 <= code && code <= 0x_fFFB) || // Cf [3] INTERLINEAR +// ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR (0x1BCA0 <= code +// && code <= 0x1BCA3) || // Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND +// FORMAT UP STEP (0x1D173 <= code && code <= 0x1D17A) || // Cf [8] +// MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE 0x_e0000 == code +// || // Cn 0x_e0001 == code || // Cf +// LANGUAGE TAG (0x_e0002 <= code && code <= 0x_e001F) || // Cn [30] +// .. (0x_e0080 <= code && code <= +// 0x_e00FF) || // Cn [128] .. (0x_e01F0 +// <= code && code <= 0x_e0FFF) // Cn [3600] .. // ){ // return Control; // } // // // if( -// (0x0300 <= code && code <= 0x036F) || // Mn [112] COMBINING GRAVE ACCENT..COMBINING LATIN SMALL LETTER X -// (0x0483 <= code && code <= 0x0487) || // Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE -// (0x0488 <= code && code <= 0x0489) || // Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN -// (0x0591 <= code && code <= 0x05BD) || // Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT METEG -// 0x05BF == code || // Mn HEBREW POINT RAFE -// (0x05C1 <= code && code <= 0x05C2) || // Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT -// (0x05C4 <= code && code <= 0x05C5) || // Mn [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT -// 0x05C7 == code || // Mn HEBREW POINT QAMATS QATAN -// (0x0610 <= code && code <= 0x061A) || // Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA -// (0x064B <= code && code <= 0x065F) || // Mn [21] ARABIC FATHATAN..ARABIC WAVY HAMZA BELOW -// 0x0670 == code || // Mn ARABIC LETTER SUPERSCRIPT ALEF -// (0x06D6 <= code && code <= 0x06DC) || // Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN -// (0x06DF <= code && code <= 0x06E4) || // Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA -// (0x06E7 <= code && code <= 0x06E8) || // Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON -// (0x06EA <= code && code <= 0x06ED) || // Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM -// 0x0711 == code || // Mn SYRIAC LETTER SUPERSCRIPT ALAPH -// (0x0730 <= code && code <= 0x074A) || // Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH -// (0x07A6 <= code && code <= 0x07B0) || // Mn [11] THAANA ABAFILI..THAANA SUKUN -// (0x07EB <= code && code <= 0x07F3) || // Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE -// (0x0816 <= code && code <= 0x0819) || // Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH -// (0x081B <= code && code <= 0x0823) || // Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A -// (0x0825 <= code && code <= 0x0827) || // Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U -// (0x0829 <= code && code <= 0x082D) || // Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA -// (0x0859 <= code && code <= 0x085B) || // Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK -// (0x08D4 <= code && code <= 0x08E1) || // Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA -// (0x08E3 <= code && code <= 0x0902) || // Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA -// 0x093A == code || // Mn DEVANAGARI VOWEL SIGN OE -// 0x093C == code || // Mn DEVANAGARI SIGN NUKTA -// (0x0941 <= code && code <= 0x0948) || // Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI -// 0x094D == code || // Mn DEVANAGARI SIGN VIRAMA -// (0x0951 <= code && code <= 0x0957) || // Mn [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE -// (0x0962 <= code && code <= 0x0963) || // Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL -// 0x0981 == code || // Mn BENGALI SIGN CANDRABINDU -// 0x09BC == code || // Mn BENGALI SIGN NUKTA -// 0x09BE == code || // Mc BENGALI VOWEL SIGN AA -// (0x09C1 <= code && code <= 0x09C4) || // Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR -// 0x09CD == code || // Mn BENGALI SIGN VIRAMA -// 0x09D7 == code || // Mc BENGALI AU LENGTH MARK -// (0x09E2 <= code && code <= 0x09E3) || // Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL -// (0x0A01 <= code && code <= 0x0A02) || // Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI +// (0x0300 <= code && code <= 0x036F) || // Mn [112] COMBINING GRAVE +// ACCENT..COMBINING LATIN SMALL LETTER X (0x0483 <= code && code <= +// 0x0487) || // Mn [5] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC POKRYTIE +// (0x0488 <= code && code <= 0x0489) || // Me [2] COMBINING CYRILLIC +// HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN (0x0591 <= +// code && code <= 0x05BD) || // Mn [45] HEBREW ACCENT ETNAHTA..HEBREW POINT +// METEG 0x05BF == code || // Mn HEBREW POINT RAFE +// (0x05C1 <= code && code <= 0x05C2) || // Mn [2] HEBREW POINT SHIN +// DOT..HEBREW POINT SIN DOT (0x05C4 <= code && code <= 0x05C5) || // Mn +// [2] HEBREW MARK UPPER DOT..HEBREW MARK LOWER DOT 0x05C7 == code || // +// Mn HEBREW POINT QAMATS QATAN (0x0610 <= code && code <= 0x061A) +// || // Mn [11] ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM..ARABIC SMALL KASRA +// (0x064B <= code && code <= 0x065F) || // Mn [21] ARABIC +// FATHATAN..ARABIC WAVY HAMZA BELOW 0x0670 == code || // Mn ARABIC +// LETTER SUPERSCRIPT ALEF (0x06D6 <= code && code <= 0x06DC) || // Mn +// [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL +// HIGH SEEN (0x06DF <= code && code <= 0x06E4) || // Mn [6] ARABIC +// SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA (0x06E7 <= code && +// code <= 0x06E8) || // Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON +// (0x06EA <= code && code <= 0x06ED) || // Mn [4] ARABIC EMPTY CENTRE +// LOW STOP..ARABIC SMALL LOW MEEM 0x0711 == code || // Mn SYRIAC +// LETTER SUPERSCRIPT ALAPH (0x0730 <= code && code <= 0x074A) || // Mn +// [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH (0x07A6 <= code && code <= +// 0x07B0) || // Mn [11] THAANA ABAFILI..THAANA SUKUN (0x07EB <= code && +// code <= 0x07F3) || // Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING +// DOUBLE DOT ABOVE (0x0816 <= code && code <= 0x0819) || // Mn [4] +// SAMARITAN MARK IN..SAMARITAN MARK DAGESH (0x081B <= code && code <= +// 0x0823) || // Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A +// (0x0825 <= code && code <= 0x0827) || // Mn [3] SAMARITAN VOWEL SIGN +// SHORT A..SAMARITAN VOWEL SIGN U (0x0829 <= code && code <= 0x082D) || +// // Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA +// (0x0859 <= code && code <= 0x085B) || // Mn [3] MANDAIC AFFRICATION +// MARK..MANDAIC GEMINATION MARK (0x08D4 <= code && code <= 0x08E1) || // +// Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA +// (0x08E3 <= code && code <= 0x0902) || // Mn [32] ARABIC TURNED DAMMA +// BELOW..DEVANAGARI SIGN ANUSVARA 0x093A == code || // Mn +// DEVANAGARI VOWEL SIGN OE 0x093C == code || // Mn DEVANAGARI SIGN +// NUKTA (0x0941 <= code && code <= 0x0948) || // Mn [8] DEVANAGARI +// VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI 0x094D == code || // Mn +// DEVANAGARI SIGN VIRAMA (0x0951 <= code && code <= 0x0957) || // Mn +// [7] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI VOWEL SIGN UUE (0x0962 +// <= code && code <= 0x0963) || // Mn [2] DEVANAGARI VOWEL SIGN VOCALIC +// L..DEVANAGARI VOWEL SIGN VOCALIC LL 0x0981 == code || // Mn +// BENGALI SIGN CANDRABINDU 0x09BC == code || // Mn BENGALI SIGN +// NUKTA 0x09BE == code || // Mc BENGALI VOWEL SIGN AA +// (0x09C1 <= code && code <= 0x09C4) || // Mn [4] BENGALI VOWEL SIGN +// U..BENGALI VOWEL SIGN VOCALIC RR 0x09CD == code || // Mn BENGALI +// SIGN VIRAMA 0x09D7 == code || // Mc BENGALI AU LENGTH MARK +// (0x09E2 <= code && code <= 0x09E3) || // Mn [2] BENGALI VOWEL SIGN +// VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL (0x0A01 <= code && code <= +// 0x0A02) || // Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI // 0x0A3C == code || // Mn GURMUKHI SIGN NUKTA -// (0x0A41 <= code && code <= 0x0A42) || // Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU -// (0x0A47 <= code && code <= 0x0A48) || // Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI -// (0x0A4B <= code && code <= 0x0A4D) || // Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA +// (0x0A41 <= code && code <= 0x0A42) || // Mn [2] GURMUKHI VOWEL SIGN +// U..GURMUKHI VOWEL SIGN UU (0x0A47 <= code && code <= 0x0A48) || // Mn +// [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI (0x0A4B <= code && +// code <= 0x0A4D) || // Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA // 0x0A51 == code || // Mn GURMUKHI SIGN UDAAT -// (0x0A70 <= code && code <= 0x0A71) || // Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK -// 0x0A75 == code || // Mn GURMUKHI SIGN YAKASH -// (0x0A81 <= code && code <= 0x0A82) || // Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA -// 0x0ABC == code || // Mn GUJARATI SIGN NUKTA -// (0x0AC1 <= code && code <= 0x0AC5) || // Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E -// (0x0AC7 <= code && code <= 0x0AC8) || // Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI +// (0x0A70 <= code && code <= 0x0A71) || // Mn [2] GURMUKHI +// TIPPI..GURMUKHI ADDAK 0x0A75 == code || // Mn GURMUKHI SIGN +// YAKASH (0x0A81 <= code && code <= 0x0A82) || // Mn [2] GUJARATI SIGN +// CANDRABINDU..GUJARATI SIGN ANUSVARA 0x0ABC == code || // Mn +// GUJARATI SIGN NUKTA (0x0AC1 <= code && code <= 0x0AC5) || // Mn [5] +// GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E (0x0AC7 <= code && +// code <= 0x0AC8) || // Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI // 0x0ACD == code || // Mn GUJARATI SIGN VIRAMA -// (0x0AE2 <= code && code <= 0x0AE3) || // Mn [2] GUJARATI VOWEL SIGN VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL -// (0x0AFA <= code && code <= 0x0AFF) || // Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA ABOVE -// 0x0B01 == code || // Mn ORIYA SIGN CANDRABINDU +// (0x0AE2 <= code && code <= 0x0AE3) || // Mn [2] GUJARATI VOWEL SIGN +// VOCALIC L..GUJARATI VOWEL SIGN VOCALIC LL (0x0AFA <= code && code <= +// 0x0AFF) || // Mn [6] GUJARATI SIGN SUKUN..GUJARATI SIGN TWO-CIRCLE NUKTA +// ABOVE 0x0B01 == code || // Mn ORIYA SIGN CANDRABINDU // 0x0B3C == code || // Mn ORIYA SIGN NUKTA // 0x0B3E == code || // Mc ORIYA VOWEL SIGN AA // 0x0B3F == code || // Mn ORIYA VOWEL SIGN I -// (0x0B41 <= code && code <= 0x0B44) || // Mn [4] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC RR -// 0x0B4D == code || // Mn ORIYA SIGN VIRAMA -// 0x0B56 == code || // Mn ORIYA AI LENGTH MARK +// (0x0B41 <= code && code <= 0x0B44) || // Mn [4] ORIYA VOWEL SIGN +// U..ORIYA VOWEL SIGN VOCALIC RR 0x0B4D == code || // Mn ORIYA +// SIGN VIRAMA 0x0B56 == code || // Mn ORIYA AI LENGTH MARK // 0x0B57 == code || // Mc ORIYA AU LENGTH MARK -// (0x0B62 <= code && code <= 0x0B63) || // Mn [2] ORIYA VOWEL SIGN VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL -// 0x0B82 == code || // Mn TAMIL SIGN ANUSVARA -// 0x0BBE == code || // Mc TAMIL VOWEL SIGN AA +// (0x0B62 <= code && code <= 0x0B63) || // Mn [2] ORIYA VOWEL SIGN +// VOCALIC L..ORIYA VOWEL SIGN VOCALIC LL 0x0B82 == code || // Mn +// TAMIL SIGN ANUSVARA 0x0BBE == code || // Mc TAMIL VOWEL SIGN AA // 0x0BC0 == code || // Mn TAMIL VOWEL SIGN II // 0x0BCD == code || // Mn TAMIL SIGN VIRAMA // 0x0BD7 == code || // Mc TAMIL AU LENGTH MARK // 0x0C00 == code || // Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE -// (0x0C3E <= code && code <= 0x0C40) || // Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II -// (0x0C46 <= code && code <= 0x0C48) || // Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI -// (0x0C4A <= code && code <= 0x0C4D) || // Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA -// (0x0C55 <= code && code <= 0x0C56) || // Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK -// (0x0C62 <= code && code <= 0x0C63) || // Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL +// (0x0C3E <= code && code <= 0x0C40) || // Mn [3] TELUGU VOWEL SIGN +// AA..TELUGU VOWEL SIGN II (0x0C46 <= code && code <= 0x0C48) || // Mn +// [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI (0x0C4A <= code && code +// <= 0x0C4D) || // Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA +// (0x0C55 <= code && code <= 0x0C56) || // Mn [2] TELUGU LENGTH +// MARK..TELUGU AI LENGTH MARK (0x0C62 <= code && code <= 0x0C63) || // +// Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL // 0x0C81 == code || // Mn KANNADA SIGN CANDRABINDU // 0x0CBC == code || // Mn KANNADA SIGN NUKTA // 0x0CBF == code || // Mn KANNADA VOWEL SIGN I // 0x0CC2 == code || // Mc KANNADA VOWEL SIGN UU // 0x0CC6 == code || // Mn KANNADA VOWEL SIGN E -// (0x0CCC <= code && code <= 0x0CCD) || // Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA -// (0x0CD5 <= code && code <= 0x0CD6) || // Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK -// (0x0CE2 <= code && code <= 0x0CE3) || // Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL -// (0x0D00 <= code && code <= 0x0D01) || // Mn [2] MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU -// (0x0D3B <= code && code <= 0x0D3C) || // Mn [2] MALAYALAM SIGN VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA -// 0x0D3E == code || // Mc MALAYALAM VOWEL SIGN AA -// (0x0D41 <= code && code <= 0x0D44) || // Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR +// (0x0CCC <= code && code <= 0x0CCD) || // Mn [2] KANNADA VOWEL SIGN +// AU..KANNADA SIGN VIRAMA (0x0CD5 <= code && code <= 0x0CD6) || // Mc +// [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK (0x0CE2 <= code && +// code <= 0x0CE3) || // Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL +// SIGN VOCALIC LL (0x0D00 <= code && code <= 0x0D01) || // Mn [2] +// MALAYALAM SIGN COMBINING ANUSVARA ABOVE..MALAYALAM SIGN CANDRABINDU +// (0x0D3B <= code && code <= 0x0D3C) || // Mn [2] MALAYALAM SIGN +// VERTICAL BAR VIRAMA..MALAYALAM SIGN CIRCULAR VIRAMA 0x0D3E == code || +// // Mc MALAYALAM VOWEL SIGN AA (0x0D41 <= code && code <= 0x0D44) +// || // Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR // 0x0D4D == code || // Mn MALAYALAM SIGN VIRAMA // 0x0D57 == code || // Mc MALAYALAM AU LENGTH MARK -// (0x0D62 <= code && code <= 0x0D63) || // Mn [2] MALAYALAM VOWEL SIGN VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL -// 0x0DCA == code || // Mn SINHALA SIGN AL-LAKUNA -// 0x0DCF == code || // Mc SINHALA VOWEL SIGN AELA-PILLA -// (0x0DD2 <= code && code <= 0x0DD4) || // Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA +// (0x0D62 <= code && code <= 0x0D63) || // Mn [2] MALAYALAM VOWEL SIGN +// VOCALIC L..MALAYALAM VOWEL SIGN VOCALIC LL 0x0DCA == code || // Mn +// SINHALA SIGN AL-LAKUNA 0x0DCF == code || // Mc SINHALA VOWEL +// SIGN AELA-PILLA (0x0DD2 <= code && code <= 0x0DD4) || // Mn [3] +// SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA // 0x0DD6 == code || // Mn SINHALA VOWEL SIGN DIGA PAA-PILLA // 0x0DDF == code || // Mc SINHALA VOWEL SIGN GAYANUKITTA // 0x0E31 == code || // Mn THAI CHARACTER MAI HAN-AKAT -// (0x0E34 <= code && code <= 0x0E3A) || // Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU -// (0x0E47 <= code && code <= 0x0E4E) || // Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN -// 0x0EB1 == code || // Mn LAO VOWEL SIGN MAI KAN -// (0x0EB4 <= code && code <= 0x0EB9) || // Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU -// (0x0EBB <= code && code <= 0x0EBC) || // Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO -// (0x0EC8 <= code && code <= 0x0ECD) || // Mn [6] LAO TONE MAI EK..LAO NIGGAHITA -// (0x0F18 <= code && code <= 0x0F19) || // Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS +// (0x0E34 <= code && code <= 0x0E3A) || // Mn [7] THAI CHARACTER SARA +// I..THAI CHARACTER PHINTHU (0x0E47 <= code && code <= 0x0E4E) || // Mn +// [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN 0x0EB1 == code +// || // Mn LAO VOWEL SIGN MAI KAN (0x0EB4 <= code && code <= +// 0x0EB9) || // Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU (0x0EBB <= +// code && code <= 0x0EBC) || // Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL +// SIGN LO (0x0EC8 <= code && code <= 0x0ECD) || // Mn [6] LAO TONE MAI +// EK..LAO NIGGAHITA (0x0F18 <= code && code <= 0x0F19) || // Mn [2] +// TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS // 0x0F35 == code || // Mn TIBETAN MARK NGAS BZUNG NYI ZLA // 0x0F37 == code || // Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS // 0x0F39 == code || // Mn TIBETAN MARK TSA -PHRU -// (0x0F71 <= code && code <= 0x0F7E) || // Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO -// (0x0F80 <= code && code <= 0x0F84) || // Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA -// (0x0F86 <= code && code <= 0x0F87) || // Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS -// (0x0F8D <= code && code <= 0x0F97) || // Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA -// (0x0F99 <= code && code <= 0x0FBC) || // Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA -// 0x0FC6 == code || // Mn TIBETAN SYMBOL PADMA GDAN -// (0x102D <= code && code <= 0x1030) || // Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU -// (0x1032 <= code && code <= 0x1037) || // Mn [6] MYANMAR VOWEL SIGN AI..MYANMAR SIGN DOT BELOW -// (0x1039 <= code && code <= 0x103A) || // Mn [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT -// (0x103D <= code && code <= 0x103E) || // Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT SIGN MEDIAL HA -// (0x1058 <= code && code <= 0x1059) || // Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL -// (0x105E <= code && code <= 0x1060) || // Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL NA..MYANMAR CONSONANT SIGN MON MEDIAL LA -// (0x1071 <= code && code <= 0x1074) || // Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN KAYAH EE -// 0x1082 == code || // Mn MYANMAR CONSONANT SIGN SHAN MEDIAL WA -// (0x1085 <= code && code <= 0x1086) || // Mn [2] MYANMAR VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y -// 0x108D == code || // Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE -// 0x109D == code || // Mn MYANMAR VOWEL SIGN AITON AI -// (0x135D <= code && code <= 0x135F) || // Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH MARK..ETHIOPIC COMBINING GEMINATION MARK -// (0x1712 <= code && code <= 0x1714) || // Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA -// (0x1732 <= code && code <= 0x1734) || // Mn [3] HANUNOO VOWEL SIGN I..HANUNOO SIGN PAMUDPOD -// (0x1752 <= code && code <= 0x1753) || // Mn [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U -// (0x1772 <= code && code <= 0x1773) || // Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U -// (0x17B4 <= code && code <= 0x17B5) || // Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA -// (0x17B7 <= code && code <= 0x17BD) || // Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA -// 0x17C6 == code || // Mn KHMER SIGN NIKAHIT -// (0x17C9 <= code && code <= 0x17D3) || // Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT -// 0x17DD == code || // Mn KHMER SIGN ATTHACAN -// (0x180B <= code && code <= 0x180D) || // Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE -// (0x1885 <= code && code <= 0x1886) || // Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +// (0x0F71 <= code && code <= 0x0F7E) || // Mn [14] TIBETAN VOWEL SIGN +// AA..TIBETAN SIGN RJES SU NGA RO (0x0F80 <= code && code <= 0x0F84) || +// // Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA +// (0x0F86 <= code && code <= 0x0F87) || // Mn [2] TIBETAN SIGN LCI +// RTAGS..TIBETAN SIGN YANG RTAGS (0x0F8D <= code && code <= 0x0F97) || +// // Mn [11] TIBETAN SUBJOINED SIGN LCE TSA CAN..TIBETAN SUBJOINED LETTER JA +// (0x0F99 <= code && code <= 0x0FBC) || // Mn [36] TIBETAN SUBJOINED +// LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA 0x0FC6 == code || +// // Mn TIBETAN SYMBOL PADMA GDAN (0x102D <= code && code <= +// 0x1030) || // Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU +// (0x1032 <= code && code <= 0x1037) || // Mn [6] MYANMAR VOWEL SIGN +// AI..MYANMAR SIGN DOT BELOW (0x1039 <= code && code <= 0x103A) || // Mn +// [2] MYANMAR SIGN VIRAMA..MYANMAR SIGN ASAT (0x103D <= code && code <= +// 0x103E) || // Mn [2] MYANMAR CONSONANT SIGN MEDIAL WA..MYANMAR CONSONANT +// SIGN MEDIAL HA (0x1058 <= code && code <= 0x1059) || // Mn [2] +// MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL (0x105E <= +// code && code <= 0x1060) || // Mn [3] MYANMAR CONSONANT SIGN MON MEDIAL +// NA..MYANMAR CONSONANT SIGN MON MEDIAL LA (0x1071 <= code && code <= +// 0x1074) || // Mn [4] MYANMAR VOWEL SIGN GEBA KAREN I..MYANMAR VOWEL SIGN +// KAYAH EE 0x1082 == code || // Mn MYANMAR CONSONANT SIGN SHAN +// MEDIAL WA (0x1085 <= code && code <= 0x1086) || // Mn [2] MYANMAR +// VOWEL SIGN SHAN E ABOVE..MYANMAR VOWEL SIGN SHAN FINAL Y 0x108D == +// code || // Mn MYANMAR SIGN SHAN COUNCIL EMPHATIC TONE 0x109D == +// code || // Mn MYANMAR VOWEL SIGN AITON AI (0x135D <= code && +// code <= 0x135F) || // Mn [3] ETHIOPIC COMBINING GEMINATION AND VOWEL LENGTH +// MARK..ETHIOPIC COMBINING GEMINATION MARK (0x1712 <= code && code <= +// 0x1714) || // Mn [3] TAGALOG VOWEL SIGN I..TAGALOG SIGN VIRAMA +// (0x1732 <= code && code <= 0x1734) || // Mn [3] HANUNOO VOWEL SIGN +// I..HANUNOO SIGN PAMUDPOD (0x1752 <= code && code <= 0x1753) || // Mn +// [2] BUHID VOWEL SIGN I..BUHID VOWEL SIGN U (0x1772 <= code && code <= +// 0x1773) || // Mn [2] TAGBANWA VOWEL SIGN I..TAGBANWA VOWEL SIGN U +// (0x17B4 <= code && code <= 0x17B5) || // Mn [2] KHMER VOWEL INHERENT +// AQ..KHMER VOWEL INHERENT AA (0x17B7 <= code && code <= 0x17BD) || // +// Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA 0x17C6 == code || // +// Mn KHMER SIGN NIKAHIT (0x17C9 <= code && code <= 0x17D3) || // +// Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT 0x17DD == code +// || // Mn KHMER SIGN ATTHACAN (0x180B <= code && code <= 0x180D) +// || // Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE +// VARIATION SELECTOR THREE (0x1885 <= code && code <= 0x1886) || // Mn +// [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA // 0x18A9 == code || // Mn MONGOLIAN LETTER ALI GALI DAGALGA -// (0x1920 <= code && code <= 0x1922) || // Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U -// (0x1927 <= code && code <= 0x1928) || // Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O -// 0x1932 == code || // Mn LIMBU SMALL LETTER ANUSVARA -// (0x1939 <= code && code <= 0x193B) || // Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I -// (0x1A17 <= code && code <= 0x1A18) || // Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U +// (0x1920 <= code && code <= 0x1922) || // Mn [3] LIMBU VOWEL SIGN +// A..LIMBU VOWEL SIGN U (0x1927 <= code && code <= 0x1928) || // Mn +// [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O 0x1932 == code || // Mn +// LIMBU SMALL LETTER ANUSVARA (0x1939 <= code && code <= 0x193B) || // +// Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I (0x1A17 <= code && code +// <= 0x1A18) || // Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U // 0x1A1B == code || // Mn BUGINESE VOWEL SIGN AE // 0x1A56 == code || // Mn TAI THAM CONSONANT SIGN MEDIAL LA -// (0x1A58 <= code && code <= 0x1A5E) || // Mn [7] TAI THAM SIGN MAI KANG LAI..TAI THAM CONSONANT SIGN SA -// 0x1A60 == code || // Mn TAI THAM SIGN SAKOT -// 0x1A62 == code || // Mn TAI THAM VOWEL SIGN MAI SAT -// (0x1A65 <= code && code <= 0x1A6C) || // Mn [8] TAI THAM VOWEL SIGN I..TAI THAM VOWEL SIGN OA BELOW -// (0x1A73 <= code && code <= 0x1A7C) || // Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE KARAN -// 0x1A7F == code || // Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT -// (0x1AB0 <= code && code <= 0x1ABD) || // Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW -// 0x1ABE == code || // Me COMBINING PARENTHESES OVERLAY -// (0x1B00 <= code && code <= 0x1B03) || // Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG +// (0x1A58 <= code && code <= 0x1A5E) || // Mn [7] TAI THAM SIGN MAI +// KANG LAI..TAI THAM CONSONANT SIGN SA 0x1A60 == code || // Mn TAI +// THAM SIGN SAKOT 0x1A62 == code || // Mn TAI THAM VOWEL SIGN MAI +// SAT (0x1A65 <= code && code <= 0x1A6C) || // Mn [8] TAI THAM VOWEL +// SIGN I..TAI THAM VOWEL SIGN OA BELOW (0x1A73 <= code && code <= +// 0x1A7C) || // Mn [10] TAI THAM VOWEL SIGN OA ABOVE..TAI THAM SIGN KHUEN-LUE +// KARAN 0x1A7F == code || // Mn TAI THAM COMBINING CRYPTOGRAMMIC +// DOT (0x1AB0 <= code && code <= 0x1ABD) || // Mn [14] COMBINING +// DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW 0x1ABE == code +// || // Me COMBINING PARENTHESES OVERLAY (0x1B00 <= code && code +// <= 0x1B03) || // Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG // 0x1B34 == code || // Mn BALINESE SIGN REREKAN -// (0x1B36 <= code && code <= 0x1B3A) || // Mn [5] BALINESE VOWEL SIGN ULU..BALINESE VOWEL SIGN RA REPA -// 0x1B3C == code || // Mn BALINESE VOWEL SIGN LA LENGA -// 0x1B42 == code || // Mn BALINESE VOWEL SIGN PEPET -// (0x1B6B <= code && code <= 0x1B73) || // Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG -// (0x1B80 <= code && code <= 0x1B81) || // Mn [2] SUNDANESE SIGN PANYECEK..SUNDANESE SIGN PANGLAYAR -// (0x1BA2 <= code && code <= 0x1BA5) || // Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU -// (0x1BA8 <= code && code <= 0x1BA9) || // Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG -// (0x1BAB <= code && code <= 0x1BAD) || // Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA -// 0x1BE6 == code || // Mn BATAK SIGN TOMPI -// (0x1BE8 <= code && code <= 0x1BE9) || // Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE -// 0x1BED == code || // Mn BATAK VOWEL SIGN KARO O -// (0x1BEF <= code && code <= 0x1BF1) || // Mn [3] BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H -// (0x1C2C <= code && code <= 0x1C33) || // Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T -// (0x1C36 <= code && code <= 0x1C37) || // Mn [2] LEPCHA SIGN RAN..LEPCHA SIGN NUKTA -// (0x1CD0 <= code && code <= 0x1CD2) || // Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA -// (0x1CD4 <= code && code <= 0x1CE0) || // Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA -// (0x1CE2 <= code && code <= 0x1CE8) || // Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL -// 0x1CED == code || // Mn VEDIC SIGN TIRYAK -// 0x1CF4 == code || // Mn VEDIC TONE CANDRA ABOVE -// (0x1CF8 <= code && code <= 0x1CF9) || // Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE -// (0x1DC0 <= code && code <= 0x1DF9) || // Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE BELOW -// (0x1DFB <= code && code <= 0x1DFF) || // Mn [5] COMBINING DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW +// (0x1B36 <= code && code <= 0x1B3A) || // Mn [5] BALINESE VOWEL SIGN +// ULU..BALINESE VOWEL SIGN RA REPA 0x1B3C == code || // Mn +// BALINESE VOWEL SIGN LA LENGA 0x1B42 == code || // Mn BALINESE +// VOWEL SIGN PEPET (0x1B6B <= code && code <= 0x1B73) || // Mn [9] +// BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING +// GONG (0x1B80 <= code && code <= 0x1B81) || // Mn [2] SUNDANESE SIGN +// PANYECEK..SUNDANESE SIGN PANGLAYAR (0x1BA2 <= code && code <= 0x1BA5) +// || // Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN +// PANYUKU (0x1BA8 <= code && code <= 0x1BA9) || // Mn [2] SUNDANESE +// VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG (0x1BAB <= code && +// code <= 0x1BAD) || // Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT +// SIGN PASANGAN WA 0x1BE6 == code || // Mn BATAK SIGN TOMPI +// (0x1BE8 <= code && code <= 0x1BE9) || // Mn [2] BATAK VOWEL SIGN +// PAKPAK E..BATAK VOWEL SIGN EE 0x1BED == code || // Mn BATAK +// VOWEL SIGN KARO O (0x1BEF <= code && code <= 0x1BF1) || // Mn [3] +// BATAK VOWEL SIGN U FOR SIMALUNGUN SA..BATAK CONSONANT SIGN H (0x1C2C +// <= code && code <= 0x1C33) || // Mn [8] LEPCHA VOWEL SIGN E..LEPCHA +// CONSONANT SIGN T (0x1C36 <= code && code <= 0x1C37) || // Mn [2] +// LEPCHA SIGN RAN..LEPCHA SIGN NUKTA (0x1CD0 <= code && code <= 0x1CD2) +// || // Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA (0x1CD4 <= code +// && code <= 0x1CE0) || // Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE +// SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA (0x1CE2 <= +// code && code <= 0x1CE8) || // Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN +// VISARGA ANUDATTA WITH TAIL 0x1CED == code || // Mn VEDIC SIGN +// TIRYAK 0x1CF4 == code || // Mn VEDIC TONE CANDRA ABOVE +// (0x1CF8 <= code && code <= 0x1CF9) || // Mn [2] VEDIC TONE RING +// ABOVE..VEDIC TONE DOUBLE RING ABOVE (0x1DC0 <= code && code <= 0x1DF9) +// || // Mn [58] COMBINING DOTTED GRAVE ACCENT..COMBINING WIDE INVERTED BRIDGE +// BELOW (0x1DFB <= code && code <= 0x1DFF) || // Mn [5] COMBINING +// DELETION MARK..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW // 0x200C == code || // Cf ZERO WIDTH NON-JOINER -// (0x20D0 <= code && code <= 0x20DC) || // Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE -// (0x20DD <= code && code <= 0x20E0) || // Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH -// 0x20E1 == code || // Mn COMBINING LEFT RIGHT ARROW ABOVE -// (0x20E2 <= code && code <= 0x20E4) || // Me [3] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE -// (0x20E5 <= code && code <= 0x20F0) || // Mn [12] COMBINING REVERSE SOLIDUS OVERLAY..COMBINING ASTERISK ABOVE -// (0x2CEF <= code && code <= 0x2CF1) || // Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS +// (0x20D0 <= code && code <= 0x20DC) || // Mn [13] COMBINING LEFT +// HARPOON ABOVE..COMBINING FOUR DOTS ABOVE (0x20DD <= code && code <= +// 0x20E0) || // Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE +// BACKSLASH 0x20E1 == code || // Mn COMBINING LEFT RIGHT ARROW +// ABOVE (0x20E2 <= code && code <= 0x20E4) || // Me [3] COMBINING +// ENCLOSING SCREEN..COMBINING ENCLOSING UPWARD POINTING TRIANGLE (0x20E5 +// <= code && code <= 0x20F0) || // Mn [12] COMBINING REVERSE SOLIDUS +// OVERLAY..COMBINING ASTERISK ABOVE (0x2CEF <= code && code <= 0x2CF1) +// || // Mn [3] COPTIC COMBINING NI ABOVE..COPTIC COMBINING SPIRITUS LENIS // 0x2D7F == code || // Mn TIFINAGH CONSONANT JOINER -// (0x2DE0 <= code && code <= 0x2DFF) || // Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS -// (0x302A <= code && code <= 0x302D) || // Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK -// (0x302E <= code && code <= 0x302F) || // Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK -// (0x3099 <= code && code <= 0x309A) || // Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK -// 0x_a66F == code || // Mn COMBINING CYRILLIC VZMET -// (0x_a670 <= code && code <= 0x_a672) || // Me [3] COMBINING CYRILLIC TEN MILLIONS SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN -// (0x_a674 <= code && code <= 0x_a67D) || // Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK -// (0x_a69E <= code && code <= 0x_a69F) || // Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED E -// (0x_a6F0 <= code && code <= 0x_a6F1) || // Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS -// 0x_a802 == code || // Mn SYLOTI NAGRI SIGN DVISVARA -// 0x_a806 == code || // Mn SYLOTI NAGRI SIGN HASANTA -// 0x_a80B == code || // Mn SYLOTI NAGRI SIGN ANUSVARA -// (0x_a825 <= code && code <= 0x_a826) || // Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E -// (0x_a8C4 <= code && code <= 0x_a8C5) || // Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU -// (0x_a8E0 <= code && code <= 0x_a8F1) || // Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA -// (0x_a926 <= code && code <= 0x_a92D) || // Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU -// (0x_a947 <= code && code <= 0x_a951) || // Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R -// (0x_a980 <= code && code <= 0x_a982) || // Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR +// (0x2DE0 <= code && code <= 0x2DFF) || // Mn [32] COMBINING CYRILLIC +// LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS (0x302A <= code +// && code <= 0x302D) || // Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC +// ENTERING TONE MARK (0x302E <= code && code <= 0x302F) || // Mc [2] +// HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK (0x3099 <= +// code && code <= 0x309A) || // Mn [2] COMBINING KATAKANA-HIRAGANA VOICED +// SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK 0x_a66F +// == code || // Mn COMBINING CYRILLIC VZMET (0x_a670 <= code && +// code <= 0x_a672) || // Me [3] COMBINING CYRILLIC TEN MILLIONS +// SIGN..COMBINING CYRILLIC THOUSAND MILLIONS SIGN (0x_a674 <= code && +// code <= 0x_a67D) || // Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN +// IE..COMBINING CYRILLIC PAYEROK (0x_a69E <= code && code <= 0x_a69F) || +// // Mn [2] COMBINING CYRILLIC LETTER EF..COMBINING CYRILLIC LETTER IOTIFIED +// E (0x_a6F0 <= code && code <= 0x_a6F1) || // Mn [2] BAMUM COMBINING +// MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS 0x_a802 == code || // Mn +// SYLOTI NAGRI SIGN DVISVARA 0x_a806 == code || // Mn SYLOTI NAGRI +// SIGN HASANTA 0x_a80B == code || // Mn SYLOTI NAGRI SIGN ANUSVARA +// (0x_a825 <= code && code <= 0x_a826) || // Mn [2] SYLOTI NAGRI VOWEL +// SIGN U..SYLOTI NAGRI VOWEL SIGN E (0x_a8C4 <= code && code <= 0x_a8C5) +// || // Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU +// (0x_a8E0 <= code && code <= 0x_a8F1) || // Mn [18] COMBINING +// DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA (0x_a926 <= +// code && code <= 0x_a92D) || // Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE +// CALYA PLOPHU (0x_a947 <= code && code <= 0x_a951) || // Mn [11] +// REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R (0x_a980 <= code && code +// <= 0x_a982) || // Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR // 0x_a9B3 == code || // Mn JAVANESE SIGN CECAK TELU -// (0x_a9B6 <= code && code <= 0x_a9B9) || // Mn [4] JAVANESE VOWEL SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT -// 0x_a9BC == code || // Mn JAVANESE VOWEL SIGN PEPET -// 0x_a9E5 == code || // Mn MYANMAR SIGN SHAN SAW -// (0x_aA29 <= code && code <= 0x_aA2E) || // Mn [6] CHAM VOWEL SIGN AA..CHAM VOWEL SIGN OE -// (0x_aA31 <= code && code <= 0x_aA32) || // Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE -// (0x_aA35 <= code && code <= 0x_aA36) || // Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT SIGN WA -// 0x_aA43 == code || // Mn CHAM CONSONANT SIGN FINAL NG +// (0x_a9B6 <= code && code <= 0x_a9B9) || // Mn [4] JAVANESE VOWEL +// SIGN WULU..JAVANESE VOWEL SIGN SUKU MENDUT 0x_a9BC == code || // Mn +// JAVANESE VOWEL SIGN PEPET 0x_a9E5 == code || // Mn MYANMAR SIGN +// SHAN SAW (0x_aA29 <= code && code <= 0x_aA2E) || // Mn [6] CHAM +// VOWEL SIGN AA..CHAM VOWEL SIGN OE (0x_aA31 <= code && code <= 0x_aA32) +// || // Mn [2] CHAM VOWEL SIGN AU..CHAM VOWEL SIGN UE (0x_aA35 <= code +// && code <= 0x_aA36) || // Mn [2] CHAM CONSONANT SIGN LA..CHAM CONSONANT +// SIGN WA 0x_aA43 == code || // Mn CHAM CONSONANT SIGN FINAL NG // 0x_aA4C == code || // Mn CHAM CONSONANT SIGN FINAL M // 0x_aA7C == code || // Mn MYANMAR SIGN TAI LAING TONE-2 // 0x_aAB0 == code || // Mn TAI VIET MAI KANG -// (0x_aAB2 <= code && code <= 0x_aAB4) || // Mn [3] TAI VIET VOWEL I..TAI VIET VOWEL U -// (0x_aAB7 <= code && code <= 0x_aAB8) || // Mn [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA -// (0x_aABE <= code && code <= 0x_aABF) || // Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK +// (0x_aAB2 <= code && code <= 0x_aAB4) || // Mn [3] TAI VIET VOWEL +// I..TAI VIET VOWEL U (0x_aAB7 <= code && code <= 0x_aAB8) || // Mn +// [2] TAI VIET MAI KHIT..TAI VIET VOWEL IA (0x_aABE <= code && code <= +// 0x_aABF) || // Mn [2] TAI VIET VOWEL AM..TAI VIET TONE MAI EK // 0x_aAC1 == code || // Mn TAI VIET TONE MAI THO -// (0x_aAEC <= code && code <= 0x_aAED) || // Mn [2] MEETEI MAYEK VOWEL SIGN UU..MEETEI MAYEK VOWEL SIGN AAI -// 0x_aAF6 == code || // Mn MEETEI MAYEK VIRAMA -// 0x_aBE5 == code || // Mn MEETEI MAYEK VOWEL SIGN ANAP -// 0x_aBE8 == code || // Mn MEETEI MAYEK VOWEL SIGN UNAP +// (0x_aAEC <= code && code <= 0x_aAED) || // Mn [2] MEETEI MAYEK VOWEL +// SIGN UU..MEETEI MAYEK VOWEL SIGN AAI 0x_aAF6 == code || // Mn +// MEETEI MAYEK VIRAMA 0x_aBE5 == code || // Mn MEETEI MAYEK VOWEL +// SIGN ANAP 0x_aBE8 == code || // Mn MEETEI MAYEK VOWEL SIGN UNAP // 0x_aBED == code || // Mn MEETEI MAYEK APUN IYEK // 0x_fB1E == code || // Mn HEBREW POINT JUDEO-SPANISH VARIKA -// (0x_fE00 <= code && code <= 0x_fE0F) || // Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16 -// (0x_fE20 <= code && code <= 0x_fE2F) || // Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT HALF -// (0x_fF9E <= code && code <= 0x_fF9F) || // Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK -// 0x101FD == code || // Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE -// 0x102E0 == code || // Mn COPTIC EPACT THOUSANDS MARK -// (0x10376 <= code && code <= 0x1037A) || // Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII -// (0x10A01 <= code && code <= 0x10A03) || // Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R -// (0x10A05 <= code && code <= 0x10A06) || // Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O -// (0x10A0C <= code && code <= 0x10A0F) || // Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA -// (0x10A38 <= code && code <= 0x10A3A) || // Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW -// 0x10A3F == code || // Mn KHAROSHTHI VIRAMA -// (0x10AE5 <= code && code <= 0x10AE6) || // Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW +// (0x_fE00 <= code && code <= 0x_fE0F) || // Mn [16] VARIATION +// SELECTOR-1..VARIATION SELECTOR-16 (0x_fE20 <= code && code <= 0x_fE2F) +// || // Mn [16] COMBINING LIGATURE LEFT HALF..COMBINING CYRILLIC TITLO RIGHT +// HALF (0x_fF9E <= code && code <= 0x_fF9F) || // Lm [2] HALFWIDTH +// KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK +// 0x101FD == code || // Mn PHAISTOS DISC SIGN COMBINING OBLIQUE +// STROKE 0x102E0 == code || // Mn COPTIC EPACT THOUSANDS MARK +// (0x10376 <= code && code <= 0x1037A) || // Mn [5] COMBINING OLD +// PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII (0x10A01 <= code && +// code <= 0x10A03) || // Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL +// SIGN VOCALIC R (0x10A05 <= code && code <= 0x10A06) || // Mn [2] +// KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O (0x10A0C <= code && +// code <= 0x10A0F) || // Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN +// VISARGA (0x10A38 <= code && code <= 0x10A3A) || // Mn [3] KHAROSHTHI +// SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW 0x10A3F == code || // Mn +// KHAROSHTHI VIRAMA (0x10AE5 <= code && code <= 0x10AE6) || // Mn [2] +// MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW // 0x11001 == code || // Mn BRAHMI SIGN ANUSVARA -// (0x11038 <= code && code <= 0x11046) || // Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA -// (0x1107F <= code && code <= 0x11081) || // Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA -// (0x110B3 <= code && code <= 0x110B6) || // Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI -// (0x110B9 <= code && code <= 0x110BA) || // Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA -// (0x11100 <= code && code <= 0x11102) || // Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA -// (0x11127 <= code && code <= 0x1112B) || // Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU -// (0x1112D <= code && code <= 0x11134) || // Mn [8] CHAKMA VOWEL SIGN AI..CHAKMA MAAYYAA -// 0x11173 == code || // Mn MAHAJANI SIGN NUKTA -// (0x11180 <= code && code <= 0x11181) || // Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA -// (0x111B6 <= code && code <= 0x111BE) || // Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O -// (0x111CA <= code && code <= 0x111CC) || // Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK -// (0x1122F <= code && code <= 0x11231) || // Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI +// (0x11038 <= code && code <= 0x11046) || // Mn [15] BRAHMI VOWEL SIGN +// AA..BRAHMI VIRAMA (0x1107F <= code && code <= 0x11081) || // Mn [3] +// BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA (0x110B3 <= code && code <= +// 0x110B6) || // Mn [4] KAITHI VOWEL SIGN U..KAITHI VOWEL SIGN AI +// (0x110B9 <= code && code <= 0x110BA) || // Mn [2] KAITHI SIGN +// VIRAMA..KAITHI SIGN NUKTA (0x11100 <= code && code <= 0x11102) || // +// Mn [3] CHAKMA SIGN CANDRABINDU..CHAKMA SIGN VISARGA (0x11127 <= code +// && code <= 0x1112B) || // Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU +// (0x1112D <= code && code <= 0x11134) || // Mn [8] CHAKMA VOWEL SIGN +// AI..CHAKMA MAAYYAA 0x11173 == code || // Mn MAHAJANI SIGN NUKTA +// (0x11180 <= code && code <= 0x11181) || // Mn [2] SHARADA SIGN +// CANDRABINDU..SHARADA SIGN ANUSVARA (0x111B6 <= code && code <= +// 0x111BE) || // Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O +// (0x111CA <= code && code <= 0x111CC) || // Mn [3] SHARADA SIGN +// NUKTA..SHARADA EXTRA SHORT VOWEL MARK (0x1122F <= code && code <= +// 0x11231) || // Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI // 0x11234 == code || // Mn KHOJKI SIGN ANUSVARA -// (0x11236 <= code && code <= 0x11237) || // Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA -// 0x1123E == code || // Mn KHOJKI SIGN SUKUN -// 0x112DF == code || // Mn KHUDAWADI SIGN ANUSVARA -// (0x112E3 <= code && code <= 0x112EA) || // Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA -// (0x11300 <= code && code <= 0x11301) || // Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU +// (0x11236 <= code && code <= 0x11237) || // Mn [2] KHOJKI SIGN +// NUKTA..KHOJKI SIGN SHADDA 0x1123E == code || // Mn KHOJKI SIGN +// SUKUN 0x112DF == code || // Mn KHUDAWADI SIGN ANUSVARA +// (0x112E3 <= code && code <= 0x112EA) || // Mn [8] KHUDAWADI VOWEL +// SIGN U..KHUDAWADI SIGN VIRAMA (0x11300 <= code && code <= 0x11301) || +// // Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU // 0x1133C == code || // Mn GRANTHA SIGN NUKTA // 0x1133E == code || // Mc GRANTHA VOWEL SIGN AA // 0x11340 == code || // Mn GRANTHA VOWEL SIGN II // 0x11357 == code || // Mc GRANTHA AU LENGTH MARK -// (0x11366 <= code && code <= 0x1136C) || // Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX -// (0x11370 <= code && code <= 0x11374) || // Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA -// (0x11438 <= code && code <= 0x1143F) || // Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI -// (0x11442 <= code && code <= 0x11444) || // Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA -// 0x11446 == code || // Mn NEWA SIGN NUKTA -// 0x114B0 == code || // Mc TIRHUTA VOWEL SIGN AA -// (0x114B3 <= code && code <= 0x114B8) || // Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL -// 0x114BA == code || // Mn TIRHUTA VOWEL SIGN SHORT E -// 0x114BD == code || // Mc TIRHUTA VOWEL SIGN SHORT O -// (0x114BF <= code && code <= 0x114C0) || // Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA -// (0x114C2 <= code && code <= 0x114C3) || // Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA +// (0x11366 <= code && code <= 0x1136C) || // Mn [7] COMBINING GRANTHA +// DIGIT ZERO..COMBINING GRANTHA DIGIT SIX (0x11370 <= code && code <= +// 0x11374) || // Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER +// PA (0x11438 <= code && code <= 0x1143F) || // Mn [8] NEWA VOWEL SIGN +// U..NEWA VOWEL SIGN AI (0x11442 <= code && code <= 0x11444) || // Mn +// [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA 0x11446 == code || // Mn +// NEWA SIGN NUKTA 0x114B0 == code || // Mc TIRHUTA VOWEL SIGN AA +// (0x114B3 <= code && code <= 0x114B8) || // Mn [6] TIRHUTA VOWEL SIGN +// U..TIRHUTA VOWEL SIGN VOCALIC LL 0x114BA == code || // Mn +// TIRHUTA VOWEL SIGN SHORT E 0x114BD == code || // Mc TIRHUTA +// VOWEL SIGN SHORT O (0x114BF <= code && code <= 0x114C0) || // Mn [2] +// TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA (0x114C2 <= code && +// code <= 0x114C3) || // Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA // 0x115AF == code || // Mc SIDDHAM VOWEL SIGN AA -// (0x115B2 <= code && code <= 0x115B5) || // Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR -// (0x115BC <= code && code <= 0x115BD) || // Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA -// (0x115BF <= code && code <= 0x115C0) || // Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA -// (0x115DC <= code && code <= 0x115DD) || // Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU -// (0x11633 <= code && code <= 0x1163A) || // Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI -// 0x1163D == code || // Mn MODI SIGN ANUSVARA -// (0x1163F <= code && code <= 0x11640) || // Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA -// 0x116AB == code || // Mn TAKRI SIGN ANUSVARA -// 0x116AD == code || // Mn TAKRI VOWEL SIGN AA -// (0x116B0 <= code && code <= 0x116B5) || // Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU -// 0x116B7 == code || // Mn TAKRI SIGN NUKTA -// (0x1171D <= code && code <= 0x1171F) || // Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA -// (0x11722 <= code && code <= 0x11725) || // Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU -// (0x11727 <= code && code <= 0x1172B) || // Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER -// (0x11A01 <= code && code <= 0x11A06) || // Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O -// (0x11A09 <= code && code <= 0x11A0A) || // Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK -// (0x11A33 <= code && code <= 0x11A38) || // Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA -// (0x11A3B <= code && code <= 0x11A3E) || // Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA -// 0x11A47 == code || // Mn ZANABAZAR SQUARE SUBJOINER -// (0x11A51 <= code && code <= 0x11A56) || // Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE -// (0x11A59 <= code && code <= 0x11A5B) || // Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO VOWEL LENGTH MARK -// (0x11A8A <= code && code <= 0x11A96) || // Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA -// (0x11A98 <= code && code <= 0x11A99) || // Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER -// (0x11C30 <= code && code <= 0x11C36) || // Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L -// (0x11C38 <= code && code <= 0x11C3D) || // Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA +// (0x115B2 <= code && code <= 0x115B5) || // Mn [4] SIDDHAM VOWEL SIGN +// U..SIDDHAM VOWEL SIGN VOCALIC RR (0x115BC <= code && code <= 0x115BD) +// || // Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA +// (0x115BF <= code && code <= 0x115C0) || // Mn [2] SIDDHAM SIGN +// VIRAMA..SIDDHAM SIGN NUKTA (0x115DC <= code && code <= 0x115DD) || // +// Mn [2] SIDDHAM VOWEL SIGN ALTERNATE U..SIDDHAM VOWEL SIGN ALTERNATE UU +// (0x11633 <= code && code <= 0x1163A) || // Mn [8] MODI VOWEL SIGN +// U..MODI VOWEL SIGN AI 0x1163D == code || // Mn MODI SIGN +// ANUSVARA (0x1163F <= code && code <= 0x11640) || // Mn [2] MODI SIGN +// VIRAMA..MODI SIGN ARDHACANDRA 0x116AB == code || // Mn TAKRI +// SIGN ANUSVARA 0x116AD == code || // Mn TAKRI VOWEL SIGN AA +// (0x116B0 <= code && code <= 0x116B5) || // Mn [6] TAKRI VOWEL SIGN +// U..TAKRI VOWEL SIGN AU 0x116B7 == code || // Mn TAKRI SIGN NUKTA +// (0x1171D <= code && code <= 0x1171F) || // Mn [3] AHOM CONSONANT +// SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA (0x11722 <= +// code && code <= 0x11725) || // Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU +// (0x11727 <= code && code <= 0x1172B) || // Mn [5] AHOM VOWEL SIGN +// AW..AHOM SIGN KILLER (0x11A01 <= code && code <= 0x11A06) || // Mn +// [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O +// (0x11A09 <= code && code <= 0x11A0A) || // Mn [2] ZANABAZAR SQUARE +// VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK (0x11A33 <= +// code && code <= 0x11A38) || // Mn [6] ZANABAZAR SQUARE FINAL CONSONANT +// MARK..ZANABAZAR SQUARE SIGN ANUSVARA (0x11A3B <= code && code <= +// 0x11A3E) || // Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR +// SQUARE CLUSTER-FINAL LETTER VA 0x11A47 == code || // Mn +// ZANABAZAR SQUARE SUBJOINER (0x11A51 <= code && code <= 0x11A56) || // +// Mn [6] SOYOMBO VOWEL SIGN I..SOYOMBO VOWEL SIGN OE (0x11A59 <= code +// && code <= 0x11A5B) || // Mn [3] SOYOMBO VOWEL SIGN VOCALIC R..SOYOMBO +// VOWEL LENGTH MARK (0x11A8A <= code && code <= 0x11A96) || // Mn [13] +// SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA (0x11A98 <= code +// && code <= 0x11A99) || // Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER +// (0x11C30 <= code && code <= 0x11C36) || // Mn [7] BHAIKSUKI VOWEL +// SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L (0x11C38 <= code && code <= +// 0x11C3D) || // Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA // 0x11C3F == code || // Mn BHAIKSUKI SIGN VIRAMA -// (0x11C92 <= code && code <= 0x11CA7) || // Mn [22] MARCHEN SUBJOINED LETTER KA..MARCHEN SUBJOINED LETTER ZA -// (0x11CAA <= code && code <= 0x11CB0) || // Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA -// (0x11CB2 <= code && code <= 0x11CB3) || // Mn [2] MARCHEN VOWEL SIGN U..MARCHEN VOWEL SIGN E -// (0x11CB5 <= code && code <= 0x11CB6) || // Mn [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU -// (0x11D31 <= code && code <= 0x11D36) || // Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI VOWEL SIGN VOCALIC R -// 0x11D3A == code || // Mn MASARAM GONDI VOWEL SIGN E -// (0x11D3C <= code && code <= 0x11D3D) || // Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O -// (0x11D3F <= code && code <= 0x11D45) || // Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA -// 0x11D47 == code || // Mn MASARAM GONDI RA-KARA -// (0x16AF0 <= code && code <= 0x16AF4) || // Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE -// (0x16B30 <= code && code <= 0x16B36) || // Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM -// (0x16F8F <= code && code <= 0x16F92) || // Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW -// (0x1BC9D <= code && code <= 0x1BC9E) || // Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +// (0x11C92 <= code && code <= 0x11CA7) || // Mn [22] MARCHEN SUBJOINED +// LETTER KA..MARCHEN SUBJOINED LETTER ZA (0x11CAA <= code && code <= +// 0x11CB0) || // Mn [7] MARCHEN SUBJOINED LETTER RA..MARCHEN VOWEL SIGN AA +// (0x11CB2 <= code && code <= 0x11CB3) || // Mn [2] MARCHEN VOWEL SIGN +// U..MARCHEN VOWEL SIGN E (0x11CB5 <= code && code <= 0x11CB6) || // Mn +// [2] MARCHEN SIGN ANUSVARA..MARCHEN SIGN CANDRABINDU (0x11D31 <= code +// && code <= 0x11D36) || // Mn [6] MASARAM GONDI VOWEL SIGN AA..MASARAM GONDI +// VOWEL SIGN VOCALIC R 0x11D3A == code || // Mn MASARAM GONDI +// VOWEL SIGN E (0x11D3C <= code && code <= 0x11D3D) || // Mn [2] +// MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O (0x11D3F <= +// code && code <= 0x11D45) || // Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM +// GONDI VIRAMA 0x11D47 == code || // Mn MASARAM GONDI RA-KARA +// (0x16AF0 <= code && code <= 0x16AF4) || // Mn [5] BASSA VAH +// COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE (0x16B30 <= +// code && code <= 0x16B36) || // Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH +// HMONG MARK CIM TAUM (0x16F8F <= code && code <= 0x16F92) || // Mn +// [4] MIAO TONE RIGHT..MIAO TONE BELOW (0x1BC9D <= code && code <= +// 0x1BC9E) || // Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK // 0x1D165 == code || // Mc MUSICAL SYMBOL COMBINING STEM -// (0x1D167 <= code && code <= 0x1D169) || // Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 -// (0x1D16E <= code && code <= 0x1D172) || // Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5 -// (0x1D17B <= code && code <= 0x1D182) || // Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE -// (0x1D185 <= code && code <= 0x1D18B) || // Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE -// (0x1D1AA <= code && code <= 0x1D1AD) || // Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO -// (0x1D242 <= code && code <= 0x1D244) || // Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME -// (0x1DA00 <= code && code <= 0x1DA36) || // Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN -// (0x1DA3B <= code && code <= 0x1DA6C) || // Mn [50] SIGNWRITING MOUTH CLOSED NEUTRAL..SIGNWRITING EXCITEMENT -// 0x1DA75 == code || // Mn SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS -// 0x1DA84 == code || // Mn SIGNWRITING LOCATION HEAD NECK -// (0x1DA9B <= code && code <= 0x1DA9F) || // Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL MODIFIER-6 -// (0x1DAA1 <= code && code <= 0x1DAAF) || // Mn [15] SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 -// (0x1E000 <= code && code <= 0x1E006) || // Mn [7] COMBINING GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE -// (0x1E008 <= code && code <= 0x1E018) || // Mn [17] COMBINING GLAGOLITIC LETTER ZEMLJA..COMBINING GLAGOLITIC LETTER HERU -// (0x1E01B <= code && code <= 0x1E021) || // Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING GLAGOLITIC LETTER YATI -// (0x1E023 <= code && code <= 0x1E024) || // Mn [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS -// (0x1E026 <= code && code <= 0x1E02A) || // Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA -// (0x1E8D0 <= code && code <= 0x1E8D6) || // Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS -// (0x1E944 <= code && code <= 0x1E94A) || // Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA -// (0x_e0020 <= code && code <= 0x_e007F) || // Cf [96] TAG SPACE..CANCEL TAG -// (0x_e0100 <= code && code <= 0x_e01EF) // Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256 -// ){ +// (0x1D167 <= code && code <= 0x1D169) || // Mn [3] MUSICAL SYMBOL +// COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 (0x1D16E <= +// code && code <= 0x1D172) || // Mc [5] MUSICAL SYMBOL COMBINING +// FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5 (0x1D17B <= code && code <= +// 0x1D182) || // Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL +// COMBINING LOURE (0x1D185 <= code && code <= 0x1D18B) || // Mn [7] +// MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE +// (0x1D1AA <= code && code <= 0x1D1AD) || // Mn [4] MUSICAL SYMBOL +// COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO (0x1D242 +// <= code && code <= 0x1D244) || // Mn [3] COMBINING GREEK MUSICAL +// TRISEME..COMBINING GREEK MUSICAL PENTASEME (0x1DA00 <= code && code <= +// 0x1DA36) || // Mn [55] SIGNWRITING HEAD RIM..SIGNWRITING AIR SUCKING IN +// (0x1DA3B <= code && code <= 0x1DA6C) || // Mn [50] SIGNWRITING MOUTH +// CLOSED NEUTRAL..SIGNWRITING EXCITEMENT 0x1DA75 == code || // Mn +// SIGNWRITING UPPER BODY TILTING FROM HIP JOINTS 0x1DA84 == code || // +// Mn SIGNWRITING LOCATION HEAD NECK (0x1DA9B <= code && code <= +// 0x1DA9F) || // Mn [5] SIGNWRITING FILL MODIFIER-2..SIGNWRITING FILL +// MODIFIER-6 (0x1DAA1 <= code && code <= 0x1DAAF) || // Mn [15] +// SIGNWRITING ROTATION MODIFIER-2..SIGNWRITING ROTATION MODIFIER-16 +// (0x1E000 <= code && code <= 0x1E006) || // Mn [7] COMBINING +// GLAGOLITIC LETTER AZU..COMBINING GLAGOLITIC LETTER ZHIVETE (0x1E008 <= +// code && code <= 0x1E018) || // Mn [17] COMBINING GLAGOLITIC LETTER +// ZEMLJA..COMBINING GLAGOLITIC LETTER HERU (0x1E01B <= code && code <= +// 0x1E021) || // Mn [7] COMBINING GLAGOLITIC LETTER SHTA..COMBINING +// GLAGOLITIC LETTER YATI (0x1E023 <= code && code <= 0x1E024) || // Mn +// [2] COMBINING GLAGOLITIC LETTER YU..COMBINING GLAGOLITIC LETTER SMALL YUS +// (0x1E026 <= code && code <= 0x1E02A) || // Mn [5] COMBINING +// GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA (0x1E8D0 <= +// code && code <= 0x1E8D6) || // Mn [7] MENDE KIKAKUI COMBINING NUMBER +// TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS (0x1E944 <= code && +// code <= 0x1E94A) || // Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +// (0x_e0020 <= code && code <= 0x_e007F) || // Cf [96] TAG +// SPACE..CANCEL TAG (0x_e0100 <= code && code <= 0x_e01EF) // Mn [240] +// VARIATION SELECTOR-17..VARIATION SELECTOR-256 ){ // return Extend; // } // // // if( -// (0x1F1E6 <= code && code <= 0x1F1FF) // So [26] REGIONAL INDICATOR SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z -// ){ +// (0x1F1E6 <= code && code <= 0x1F1FF) // So [26] REGIONAL INDICATOR +// SYMBOL LETTER A..REGIONAL INDICATOR SYMBOL LETTER Z ){ // return Regional_Indicator; // } // // if( // 0x0903 == code || // Mc DEVANAGARI SIGN VISARGA // 0x093B == code || // Mc DEVANAGARI VOWEL SIGN OOE -// (0x093E <= code && code <= 0x0940) || // Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II -// (0x0949 <= code && code <= 0x094C) || // Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU -// (0x094E <= code && code <= 0x094F) || // Mc [2] DEVANAGARI VOWEL SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW -// (0x0982 <= code && code <= 0x0983) || // Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA -// (0x09BF <= code && code <= 0x09C0) || // Mc [2] BENGALI VOWEL SIGN I..BENGALI VOWEL SIGN II -// (0x09C7 <= code && code <= 0x09C8) || // Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI -// (0x09CB <= code && code <= 0x09CC) || // Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU +// (0x093E <= code && code <= 0x0940) || // Mc [3] DEVANAGARI VOWEL +// SIGN AA..DEVANAGARI VOWEL SIGN II (0x0949 <= code && code <= 0x094C) +// || // Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU +// (0x094E <= code && code <= 0x094F) || // Mc [2] DEVANAGARI VOWEL +// SIGN PRISHTHAMATRA E..DEVANAGARI VOWEL SIGN AW (0x0982 <= code && code +// <= 0x0983) || // Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA +// (0x09BF <= code && code <= 0x09C0) || // Mc [2] BENGALI VOWEL SIGN +// I..BENGALI VOWEL SIGN II (0x09C7 <= code && code <= 0x09C8) || // Mc +// [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI (0x09CB <= code && +// code <= 0x09CC) || // Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU // 0x0A03 == code || // Mc GURMUKHI SIGN VISARGA -// (0x0A3E <= code && code <= 0x0A40) || // Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II -// 0x0A83 == code || // Mc GUJARATI SIGN VISARGA -// (0x0ABE <= code && code <= 0x0AC0) || // Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II -// 0x0AC9 == code || // Mc GUJARATI VOWEL SIGN CANDRA O -// (0x0ACB <= code && code <= 0x0ACC) || // Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU -// (0x0B02 <= code && code <= 0x0B03) || // Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA +// (0x0A3E <= code && code <= 0x0A40) || // Mc [3] GURMUKHI VOWEL SIGN +// AA..GURMUKHI VOWEL SIGN II 0x0A83 == code || // Mc GUJARATI SIGN +// VISARGA (0x0ABE <= code && code <= 0x0AC0) || // Mc [3] GUJARATI +// VOWEL SIGN AA..GUJARATI VOWEL SIGN II 0x0AC9 == code || // Mc +// GUJARATI VOWEL SIGN CANDRA O (0x0ACB <= code && code <= 0x0ACC) || // +// Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU (0x0B02 <= code +// && code <= 0x0B03) || // Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA // 0x0B40 == code || // Mc ORIYA VOWEL SIGN II -// (0x0B47 <= code && code <= 0x0B48) || // Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI -// (0x0B4B <= code && code <= 0x0B4C) || // Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU -// 0x0BBF == code || // Mc TAMIL VOWEL SIGN I -// (0x0BC1 <= code && code <= 0x0BC2) || // Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU -// (0x0BC6 <= code && code <= 0x0BC8) || // Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI -// (0x0BCA <= code && code <= 0x0BCC) || // Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU -// (0x0C01 <= code && code <= 0x0C03) || // Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA -// (0x0C41 <= code && code <= 0x0C44) || // Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR -// (0x0C82 <= code && code <= 0x0C83) || // Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA -// 0x0CBE == code || // Mc KANNADA VOWEL SIGN AA -// (0x0CC0 <= code && code <= 0x0CC1) || // Mc [2] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN U -// (0x0CC3 <= code && code <= 0x0CC4) || // Mc [2] KANNADA VOWEL SIGN VOCALIC R..KANNADA VOWEL SIGN VOCALIC RR -// (0x0CC7 <= code && code <= 0x0CC8) || // Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI -// (0x0CCA <= code && code <= 0x0CCB) || // Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO -// (0x0D02 <= code && code <= 0x0D03) || // Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA -// (0x0D3F <= code && code <= 0x0D40) || // Mc [2] MALAYALAM VOWEL SIGN I..MALAYALAM VOWEL SIGN II -// (0x0D46 <= code && code <= 0x0D48) || // Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI -// (0x0D4A <= code && code <= 0x0D4C) || // Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU -// (0x0D82 <= code && code <= 0x0D83) || // Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA -// (0x0DD0 <= code && code <= 0x0DD1) || // Mc [2] SINHALA VOWEL SIGN KETTI AEDA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA -// (0x0DD8 <= code && code <= 0x0DDE) || // Mc [7] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA -// (0x0DF2 <= code && code <= 0x0DF3) || // Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA +// (0x0B47 <= code && code <= 0x0B48) || // Mc [2] ORIYA VOWEL SIGN +// E..ORIYA VOWEL SIGN AI (0x0B4B <= code && code <= 0x0B4C) || // Mc +// [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU 0x0BBF == code || // Mc +// TAMIL VOWEL SIGN I (0x0BC1 <= code && code <= 0x0BC2) || // Mc [2] +// TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU (0x0BC6 <= code && code <= +// 0x0BC8) || // Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI (0x0BCA +// <= code && code <= 0x0BCC) || // Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL +// SIGN AU (0x0C01 <= code && code <= 0x0C03) || // Mc [3] TELUGU SIGN +// CANDRABINDU..TELUGU SIGN VISARGA (0x0C41 <= code && code <= 0x0C44) || +// // Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR (0x0C82 +// <= code && code <= 0x0C83) || // Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN +// VISARGA 0x0CBE == code || // Mc KANNADA VOWEL SIGN AA +// (0x0CC0 <= code && code <= 0x0CC1) || // Mc [2] KANNADA VOWEL SIGN +// II..KANNADA VOWEL SIGN U (0x0CC3 <= code && code <= 0x0CC4) || // Mc +// [2] KANNADA VOWEL SIGN VOCALIC R..KANNADA VOWEL SIGN VOCALIC RR +// (0x0CC7 <= code && code <= 0x0CC8) || // Mc [2] KANNADA VOWEL SIGN +// EE..KANNADA VOWEL SIGN AI (0x0CCA <= code && code <= 0x0CCB) || // Mc +// [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO (0x0D02 <= code && +// code <= 0x0D03) || // Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN +// VISARGA (0x0D3F <= code && code <= 0x0D40) || // Mc [2] MALAYALAM +// VOWEL SIGN I..MALAYALAM VOWEL SIGN II (0x0D46 <= code && code <= +// 0x0D48) || // Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI +// (0x0D4A <= code && code <= 0x0D4C) || // Mc [3] MALAYALAM VOWEL SIGN +// O..MALAYALAM VOWEL SIGN AU (0x0D82 <= code && code <= 0x0D83) || // Mc +// [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA (0x0DD0 <= code && +// code <= 0x0DD1) || // Mc [2] SINHALA VOWEL SIGN KETTI AEDA-PILLA..SINHALA +// VOWEL SIGN DIGA AEDA-PILLA (0x0DD8 <= code && code <= 0x0DDE) || // Mc +// [7] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN KOMBUVA HAA +// GAYANUKITTA (0x0DF2 <= code && code <= 0x0DF3) || // Mc [2] SINHALA +// VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA // 0x0E33 == code || // Lo THAI CHARACTER SARA AM // 0x0EB3 == code || // Lo LAO VOWEL SIGN AM -// (0x0F3E <= code && code <= 0x0F3F) || // Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES -// 0x0F7F == code || // Mc TIBETAN SIGN RNAM BCAD -// 0x1031 == code || // Mc MYANMAR VOWEL SIGN E -// (0x103B <= code && code <= 0x103C) || // Mc [2] MYANMAR CONSONANT SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA -// (0x1056 <= code && code <= 0x1057) || // Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR -// 0x1084 == code || // Mc MYANMAR VOWEL SIGN SHAN E -// 0x17B6 == code || // Mc KHMER VOWEL SIGN AA -// (0x17BE <= code && code <= 0x17C5) || // Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU -// (0x17C7 <= code && code <= 0x17C8) || // Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU -// (0x1923 <= code && code <= 0x1926) || // Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU -// (0x1929 <= code && code <= 0x192B) || // Mc [3] LIMBU SUBJOINED LETTER YA..LIMBU SUBJOINED LETTER WA -// (0x1930 <= code && code <= 0x1931) || // Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA -// (0x1933 <= code && code <= 0x1938) || // Mc [6] LIMBU SMALL LETTER TA..LIMBU SMALL LETTER LA -// (0x1A19 <= code && code <= 0x1A1A) || // Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O -// 0x1A55 == code || // Mc TAI THAM CONSONANT SIGN MEDIAL RA -// 0x1A57 == code || // Mc TAI THAM CONSONANT SIGN LA TANG LAI -// (0x1A6D <= code && code <= 0x1A72) || // Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI +// (0x0F3E <= code && code <= 0x0F3F) || // Mc [2] TIBETAN SIGN YAR +// TSHES..TIBETAN SIGN MAR TSHES 0x0F7F == code || // Mc TIBETAN +// SIGN RNAM BCAD 0x1031 == code || // Mc MYANMAR VOWEL SIGN E +// (0x103B <= code && code <= 0x103C) || // Mc [2] MYANMAR CONSONANT +// SIGN MEDIAL YA..MYANMAR CONSONANT SIGN MEDIAL RA (0x1056 <= code && +// code <= 0x1057) || // Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL +// SIGN VOCALIC RR 0x1084 == code || // Mc MYANMAR VOWEL SIGN SHAN +// E 0x17B6 == code || // Mc KHMER VOWEL SIGN AA +// (0x17BE <= code && code <= 0x17C5) || // Mc [8] KHMER VOWEL SIGN +// OE..KHMER VOWEL SIGN AU (0x17C7 <= code && code <= 0x17C8) || // Mc +// [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU (0x1923 <= code && +// code <= 0x1926) || // Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU +// (0x1929 <= code && code <= 0x192B) || // Mc [3] LIMBU SUBJOINED +// LETTER YA..LIMBU SUBJOINED LETTER WA (0x1930 <= code && code <= +// 0x1931) || // Mc [2] LIMBU SMALL LETTER KA..LIMBU SMALL LETTER NGA +// (0x1933 <= code && code <= 0x1938) || // Mc [6] LIMBU SMALL LETTER +// TA..LIMBU SMALL LETTER LA (0x1A19 <= code && code <= 0x1A1A) || // Mc +// [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O 0x1A55 == code || // +// Mc TAI THAM CONSONANT SIGN MEDIAL RA 0x1A57 == code || // Mc +// TAI THAM CONSONANT SIGN LA TANG LAI (0x1A6D <= code && code <= 0x1A72) +// || // Mc [6] TAI THAM VOWEL SIGN OY..TAI THAM VOWEL SIGN THAM AI // 0x1B04 == code || // Mc BALINESE SIGN BISAH // 0x1B35 == code || // Mc BALINESE VOWEL SIGN TEDUNG // 0x1B3B == code || // Mc BALINESE VOWEL SIGN RA REPA TEDUNG -// (0x1B3D <= code && code <= 0x1B41) || // Mc [5] BALINESE VOWEL SIGN LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG -// (0x1B43 <= code && code <= 0x1B44) || // Mc [2] BALINESE VOWEL SIGN PEPET TEDUNG..BALINESE ADEG ADEG -// 0x1B82 == code || // Mc SUNDANESE SIGN PANGWISAD -// 0x1BA1 == code || // Mc SUNDANESE CONSONANT SIGN PAMINGKAL -// (0x1BA6 <= code && code <= 0x1BA7) || // Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG -// 0x1BAA == code || // Mc SUNDANESE SIGN PAMAAEH -// 0x1BE7 == code || // Mc BATAK VOWEL SIGN E -// (0x1BEA <= code && code <= 0x1BEC) || // Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O -// 0x1BEE == code || // Mc BATAK VOWEL SIGN U -// (0x1BF2 <= code && code <= 0x1BF3) || // Mc [2] BATAK PANGOLAT..BATAK PANONGONAN -// (0x1C24 <= code && code <= 0x1C2B) || // Mc [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU -// (0x1C34 <= code && code <= 0x1C35) || // Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG -// 0x1CE1 == code || // Mc VEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITA -// (0x1CF2 <= code && code <= 0x1CF3) || // Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA +// (0x1B3D <= code && code <= 0x1B41) || // Mc [5] BALINESE VOWEL SIGN +// LA LENGA TEDUNG..BALINESE VOWEL SIGN TALING REPA TEDUNG (0x1B43 <= +// code && code <= 0x1B44) || // Mc [2] BALINESE VOWEL SIGN PEPET +// TEDUNG..BALINESE ADEG ADEG 0x1B82 == code || // Mc SUNDANESE +// SIGN PANGWISAD 0x1BA1 == code || // Mc SUNDANESE CONSONANT SIGN +// PAMINGKAL (0x1BA6 <= code && code <= 0x1BA7) || // Mc [2] SUNDANESE +// VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG 0x1BAA == code || +// // Mc SUNDANESE SIGN PAMAAEH 0x1BE7 == code || // Mc BATAK +// VOWEL SIGN E (0x1BEA <= code && code <= 0x1BEC) || // Mc [3] BATAK +// VOWEL SIGN I..BATAK VOWEL SIGN O 0x1BEE == code || // Mc BATAK +// VOWEL SIGN U (0x1BF2 <= code && code <= 0x1BF3) || // Mc [2] BATAK +// PANGOLAT..BATAK PANONGONAN (0x1C24 <= code && code <= 0x1C2B) || // Mc +// [8] LEPCHA SUBJOINED LETTER YA..LEPCHA VOWEL SIGN UU (0x1C34 <= code +// && code <= 0x1C35) || // Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA +// CONSONANT SIGN KANG 0x1CE1 == code || // Mc VEDIC TONE +// ATHARVAVEDIC INDEPENDENT SVARITA (0x1CF2 <= code && code <= 0x1CF3) || +// // Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA // 0x1CF7 == code || // Mc VEDIC SIGN ATIKRAMA -// (0x_a823 <= code && code <= 0x_a824) || // Mc [2] SYLOTI NAGRI VOWEL SIGN A..SYLOTI NAGRI VOWEL SIGN I -// 0x_a827 == code || // Mc SYLOTI NAGRI VOWEL SIGN OO -// (0x_a880 <= code && code <= 0x_a881) || // Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA -// (0x_a8B4 <= code && code <= 0x_a8C3) || // Mc [16] SAURASHTRA CONSONANT SIGN HAARU..SAURASHTRA VOWEL SIGN AU -// (0x_a952 <= code && code <= 0x_a953) || // Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA -// 0x_a983 == code || // Mc JAVANESE SIGN WIGNYAN -// (0x_a9B4 <= code && code <= 0x_a9B5) || // Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN TOLONG -// (0x_a9BA <= code && code <= 0x_a9BB) || // Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE -// (0x_a9BD <= code && code <= 0x_a9C0) || // Mc [4] JAVANESE CONSONANT SIGN KERET..JAVANESE PANGKON -// (0x_aA2F <= code && code <= 0x_aA30) || // Mc [2] CHAM VOWEL SIGN O..CHAM VOWEL SIGN AI -// (0x_aA33 <= code && code <= 0x_aA34) || // Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA -// 0x_aA4D == code || // Mc CHAM CONSONANT SIGN FINAL H -// 0x_aAEB == code || // Mc MEETEI MAYEK VOWEL SIGN II -// (0x_aAEE <= code && code <= 0x_aAEF) || // Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN AAU -// 0x_aAF5 == code || // Mc MEETEI MAYEK VOWEL SIGN VISARGA -// (0x_aBE3 <= code && code <= 0x_aBE4) || // Mc [2] MEETEI MAYEK VOWEL SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP -// (0x_aBE6 <= code && code <= 0x_aBE7) || // Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL SIGN SOUNAP -// (0x_aBE9 <= code && code <= 0x_aBEA) || // Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG -// 0x_aBEC == code || // Mc MEETEI MAYEK LUM IYEK -// 0x11000 == code || // Mc BRAHMI SIGN CANDRABINDU -// 0x11002 == code || // Mc BRAHMI SIGN VISARGA -// 0x11082 == code || // Mc KAITHI SIGN VISARGA -// (0x110B0 <= code && code <= 0x110B2) || // Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II -// (0x110B7 <= code && code <= 0x110B8) || // Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU -// 0x1112C == code || // Mc CHAKMA VOWEL SIGN E -// 0x11182 == code || // Mc SHARADA SIGN VISARGA -// (0x111B3 <= code && code <= 0x111B5) || // Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II -// (0x111BF <= code && code <= 0x111C0) || // Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA -// (0x1122C <= code && code <= 0x1122E) || // Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II -// (0x11232 <= code && code <= 0x11233) || // Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU -// 0x11235 == code || // Mc KHOJKI SIGN VIRAMA -// (0x112E0 <= code && code <= 0x112E2) || // Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II -// (0x11302 <= code && code <= 0x11303) || // Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA +// (0x_a823 <= code && code <= 0x_a824) || // Mc [2] SYLOTI NAGRI VOWEL +// SIGN A..SYLOTI NAGRI VOWEL SIGN I 0x_a827 == code || // Mc +// SYLOTI NAGRI VOWEL SIGN OO (0x_a880 <= code && code <= 0x_a881) || // +// Mc [2] SAURASHTRA SIGN ANUSVARA..SAURASHTRA SIGN VISARGA (0x_a8B4 <= +// code && code <= 0x_a8C3) || // Mc [16] SAURASHTRA CONSONANT SIGN +// HAARU..SAURASHTRA VOWEL SIGN AU (0x_a952 <= code && code <= 0x_a953) +// || // Mc [2] REJANG CONSONANT SIGN H..REJANG VIRAMA 0x_a983 == code +// || // Mc JAVANESE SIGN WIGNYAN (0x_a9B4 <= code && code <= +// 0x_a9B5) || // Mc [2] JAVANESE VOWEL SIGN TARUNG..JAVANESE VOWEL SIGN +// TOLONG (0x_a9BA <= code && code <= 0x_a9BB) || // Mc [2] JAVANESE +// VOWEL SIGN TALING..JAVANESE VOWEL SIGN DIRGA MURE (0x_a9BD <= code && +// code <= 0x_a9C0) || // Mc [4] JAVANESE CONSONANT SIGN KERET..JAVANESE +// PANGKON (0x_aA2F <= code && code <= 0x_aA30) || // Mc [2] CHAM VOWEL +// SIGN O..CHAM VOWEL SIGN AI (0x_aA33 <= code && code <= 0x_aA34) || // +// Mc [2] CHAM CONSONANT SIGN YA..CHAM CONSONANT SIGN RA 0x_aA4D == +// code || // Mc CHAM CONSONANT SIGN FINAL H 0x_aAEB == code || // +// Mc MEETEI MAYEK VOWEL SIGN II (0x_aAEE <= code && code <= +// 0x_aAEF) || // Mc [2] MEETEI MAYEK VOWEL SIGN AU..MEETEI MAYEK VOWEL SIGN +// AAU 0x_aAF5 == code || // Mc MEETEI MAYEK VOWEL SIGN VISARGA +// (0x_aBE3 <= code && code <= 0x_aBE4) || // Mc [2] MEETEI MAYEK VOWEL +// SIGN ONAP..MEETEI MAYEK VOWEL SIGN INAP (0x_aBE6 <= code && code <= +// 0x_aBE7) || // Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETEI MAYEK VOWEL +// SIGN SOUNAP (0x_aBE9 <= code && code <= 0x_aBEA) || // Mc [2] MEETEI +// MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG 0x_aBEC == code +// || // Mc MEETEI MAYEK LUM IYEK 0x11000 == code || // Mc +// BRAHMI SIGN CANDRABINDU 0x11002 == code || // Mc BRAHMI SIGN +// VISARGA 0x11082 == code || // Mc KAITHI SIGN VISARGA +// (0x110B0 <= code && code <= 0x110B2) || // Mc [3] KAITHI VOWEL SIGN +// AA..KAITHI VOWEL SIGN II (0x110B7 <= code && code <= 0x110B8) || // Mc +// [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU 0x1112C == code || // Mc +// CHAKMA VOWEL SIGN E 0x11182 == code || // Mc SHARADA SIGN +// VISARGA (0x111B3 <= code && code <= 0x111B5) || // Mc [3] SHARADA +// VOWEL SIGN AA..SHARADA VOWEL SIGN II (0x111BF <= code && code <= +// 0x111C0) || // Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA +// (0x1122C <= code && code <= 0x1122E) || // Mc [3] KHOJKI VOWEL SIGN +// AA..KHOJKI VOWEL SIGN II (0x11232 <= code && code <= 0x11233) || // Mc +// [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU 0x11235 == code || // Mc +// KHOJKI SIGN VIRAMA (0x112E0 <= code && code <= 0x112E2) || // Mc [3] +// KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II (0x11302 <= code && +// code <= 0x11303) || // Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA // 0x1133F == code || // Mc GRANTHA VOWEL SIGN I -// (0x11341 <= code && code <= 0x11344) || // Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR -// (0x11347 <= code && code <= 0x11348) || // Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI -// (0x1134B <= code && code <= 0x1134D) || // Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA -// (0x11362 <= code && code <= 0x11363) || // Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL -// (0x11435 <= code && code <= 0x11437) || // Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL SIGN II -// (0x11440 <= code && code <= 0x11441) || // Mc [2] NEWA VOWEL SIGN O..NEWA VOWEL SIGN AU -// 0x11445 == code || // Mc NEWA SIGN VISARGA -// (0x114B1 <= code && code <= 0x114B2) || // Mc [2] TIRHUTA VOWEL SIGN I..TIRHUTA VOWEL SIGN II -// 0x114B9 == code || // Mc TIRHUTA VOWEL SIGN E -// (0x114BB <= code && code <= 0x114BC) || // Mc [2] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN O -// 0x114BE == code || // Mc TIRHUTA VOWEL SIGN AU -// 0x114C1 == code || // Mc TIRHUTA SIGN VISARGA -// (0x115B0 <= code && code <= 0x115B1) || // Mc [2] SIDDHAM VOWEL SIGN I..SIDDHAM VOWEL SIGN II -// (0x115B8 <= code && code <= 0x115BB) || // Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU +// (0x11341 <= code && code <= 0x11344) || // Mc [4] GRANTHA VOWEL SIGN +// U..GRANTHA VOWEL SIGN VOCALIC RR (0x11347 <= code && code <= 0x11348) +// || // Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI (0x1134B +// <= code && code <= 0x1134D) || // Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA +// SIGN VIRAMA (0x11362 <= code && code <= 0x11363) || // Mc [2] +// GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL (0x11435 +// <= code && code <= 0x11437) || // Mc [3] NEWA VOWEL SIGN AA..NEWA VOWEL +// SIGN II (0x11440 <= code && code <= 0x11441) || // Mc [2] NEWA VOWEL +// SIGN O..NEWA VOWEL SIGN AU 0x11445 == code || // Mc NEWA SIGN +// VISARGA (0x114B1 <= code && code <= 0x114B2) || // Mc [2] TIRHUTA +// VOWEL SIGN I..TIRHUTA VOWEL SIGN II 0x114B9 == code || // Mc +// TIRHUTA VOWEL SIGN E (0x114BB <= code && code <= 0x114BC) || // Mc +// [2] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN O 0x114BE == code || // +// Mc TIRHUTA VOWEL SIGN AU 0x114C1 == code || // Mc TIRHUTA +// SIGN VISARGA (0x115B0 <= code && code <= 0x115B1) || // Mc [2] +// SIDDHAM VOWEL SIGN I..SIDDHAM VOWEL SIGN II (0x115B8 <= code && code +// <= 0x115BB) || // Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU // 0x115BE == code || // Mc SIDDHAM SIGN VISARGA -// (0x11630 <= code && code <= 0x11632) || // Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II -// (0x1163B <= code && code <= 0x1163C) || // Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU -// 0x1163E == code || // Mc MODI SIGN VISARGA -// 0x116AC == code || // Mc TAKRI SIGN VISARGA -// (0x116AE <= code && code <= 0x116AF) || // Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II -// 0x116B6 == code || // Mc TAKRI SIGN VIRAMA -// (0x11720 <= code && code <= 0x11721) || // Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA -// 0x11726 == code || // Mc AHOM VOWEL SIGN E -// (0x11A07 <= code && code <= 0x11A08) || // Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU -// 0x11A39 == code || // Mc ZANABAZAR SQUARE SIGN VISARGA -// (0x11A57 <= code && code <= 0x11A58) || // Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU +// (0x11630 <= code && code <= 0x11632) || // Mc [3] MODI VOWEL SIGN +// AA..MODI VOWEL SIGN II (0x1163B <= code && code <= 0x1163C) || // Mc +// [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU 0x1163E == code || // Mc +// MODI SIGN VISARGA 0x116AC == code || // Mc TAKRI SIGN VISARGA +// (0x116AE <= code && code <= 0x116AF) || // Mc [2] TAKRI VOWEL SIGN +// I..TAKRI VOWEL SIGN II 0x116B6 == code || // Mc TAKRI SIGN +// VIRAMA (0x11720 <= code && code <= 0x11721) || // Mc [2] AHOM VOWEL +// SIGN A..AHOM VOWEL SIGN AA 0x11726 == code || // Mc AHOM VOWEL +// SIGN E (0x11A07 <= code && code <= 0x11A08) || // Mc [2] ZANABAZAR +// SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU 0x11A39 == code +// || // Mc ZANABAZAR SQUARE SIGN VISARGA (0x11A57 <= code && code +// <= 0x11A58) || // Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU // 0x11A97 == code || // Mc SOYOMBO SIGN VISARGA // 0x11C2F == code || // Mc BHAIKSUKI VOWEL SIGN AA // 0x11C3E == code || // Mc BHAIKSUKI SIGN VISARGA // 0x11CA9 == code || // Mc MARCHEN SUBJOINED LETTER YA // 0x11CB1 == code || // Mc MARCHEN VOWEL SIGN I // 0x11CB4 == code || // Mc MARCHEN VOWEL SIGN O -// (0x16F51 <= code && code <= 0x16F7E) || // Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG -// 0x1D166 == code || // Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM -// 0x1D16D == code // Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT -// ){ +// (0x16F51 <= code && code <= 0x16F7E) || // Mc [46] MIAO SIGN +// ASPIRATION..MIAO VOWEL SIGN NG 0x1D166 == code || // Mc MUSICAL +// SYMBOL COMBINING SPRECHGESANG STEM 0x1D16D == code // Mc MUSICAL +// SYMBOL COMBINING AUGMENTATION DOT ){ // return SpacingMark; // } // // // if( -// (0x1100 <= code && code <= 0x115F) || // Lo [96] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG FILLER -// (0x_a960 <= code && code <= 0x_a97C) // Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH -// ){ +// (0x1100 <= code && code <= 0x115F) || // Lo [96] HANGUL CHOSEONG +// KIYEOK..HANGUL CHOSEONG FILLER (0x_a960 <= code && code <= 0x_a97C) // +// Lo [29] HANGUL CHOSEONG TIKEUT-MIEUM..HANGUL CHOSEONG SSANGYEORINHIEUH ){ // return L; // } // // if( -// (0x1160 <= code && code <= 0x11A7) || // Lo [72] HANGUL JUNGSEONG FILLER..HANGUL JUNGSEONG O-YAE -// (0x_d7B0 <= code && code <= 0x_d7C6) // Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E -// ){ +// (0x1160 <= code && code <= 0x11A7) || // Lo [72] HANGUL JUNGSEONG +// FILLER..HANGUL JUNGSEONG O-YAE (0x_d7B0 <= code && code <= 0x_d7C6) // +// Lo [23] HANGUL JUNGSEONG O-YEO..HANGUL JUNGSEONG ARAEA-E ){ // return V; // } // // // if( -// (0x11A8 <= code && code <= 0x11FF) || // Lo [88] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG SSANGNIEUN -// (0x_d7CB <= code && code <= 0x_d7FB) // Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG PHIEUPH-THIEUTH -// ){ +// (0x11A8 <= code && code <= 0x11FF) || // Lo [88] HANGUL JONGSEONG +// KIYEOK..HANGUL JONGSEONG SSANGNIEUN (0x_d7CB <= code && code <= +// 0x_d7FB) // Lo [49] HANGUL JONGSEONG NIEUN-RIEUL..HANGUL JONGSEONG +// PHIEUPH-THIEUTH ){ // return T; // } // @@ -1397,448 +1533,601 @@ pub fn word_break_string(s: &str, width: usize) -> Vec<&str> { // } // // if( -// (0x_aC01 <= code && code <= 0x_aC1B) || // Lo [27] HANGUL SYLLABLE GAG..HANGUL SYLLABLE GAH -// (0x_aC1D <= code && code <= 0x_aC37) || // Lo [27] HANGUL SYLLABLE GAEG..HANGUL SYLLABLE GAEH -// (0x_aC39 <= code && code <= 0x_aC53) || // Lo [27] HANGUL SYLLABLE GYAG..HANGUL SYLLABLE GYAH -// (0x_aC55 <= code && code <= 0x_aC6F) || // Lo [27] HANGUL SYLLABLE GYAEG..HANGUL SYLLABLE GYAEH -// (0x_aC71 <= code && code <= 0x_aC8B) || // Lo [27] HANGUL SYLLABLE GEOG..HANGUL SYLLABLE GEOH -// (0x_aC8D <= code && code <= 0x_aCA7) || // Lo [27] HANGUL SYLLABLE GEG..HANGUL SYLLABLE GEH -// (0x_aCA9 <= code && code <= 0x_aCC3) || // Lo [27] HANGUL SYLLABLE GYEOG..HANGUL SYLLABLE GYEOH -// (0x_aCC5 <= code && code <= 0x_aCDF) || // Lo [27] HANGUL SYLLABLE GYEG..HANGUL SYLLABLE GYEH -// (0x_aCE1 <= code && code <= 0x_aCFB) || // Lo [27] HANGUL SYLLABLE GOG..HANGUL SYLLABLE GOH -// (0x_aCFD <= code && code <= 0x_aD17) || // Lo [27] HANGUL SYLLABLE GWAG..HANGUL SYLLABLE GWAH -// (0x_aD19 <= code && code <= 0x_aD33) || // Lo [27] HANGUL SYLLABLE GWAEG..HANGUL SYLLABLE GWAEH -// (0x_aD35 <= code && code <= 0x_aD4F) || // Lo [27] HANGUL SYLLABLE GOEG..HANGUL SYLLABLE GOEH -// (0x_aD51 <= code && code <= 0x_aD6B) || // Lo [27] HANGUL SYLLABLE GYOG..HANGUL SYLLABLE GYOH -// (0x_aD6D <= code && code <= 0x_aD87) || // Lo [27] HANGUL SYLLABLE GUG..HANGUL SYLLABLE GUH -// (0x_aD89 <= code && code <= 0x_aDA3) || // Lo [27] HANGUL SYLLABLE GWEOG..HANGUL SYLLABLE GWEOH -// (0x_aDA5 <= code && code <= 0x_aDBF) || // Lo [27] HANGUL SYLLABLE GWEG..HANGUL SYLLABLE GWEH -// (0x_aDC1 <= code && code <= 0x_aDDB) || // Lo [27] HANGUL SYLLABLE GWIG..HANGUL SYLLABLE GWIH -// (0x_aDDD <= code && code <= 0x_aDF7) || // Lo [27] HANGUL SYLLABLE GYUG..HANGUL SYLLABLE GYUH -// (0x_aDF9 <= code && code <= 0x_aE13) || // Lo [27] HANGUL SYLLABLE GEUG..HANGUL SYLLABLE GEUH -// (0x_aE15 <= code && code <= 0x_aE2F) || // Lo [27] HANGUL SYLLABLE GYIG..HANGUL SYLLABLE GYIH -// (0x_aE31 <= code && code <= 0x_aE4B) || // Lo [27] HANGUL SYLLABLE GIG..HANGUL SYLLABLE GIH -// (0x_aE4D <= code && code <= 0x_aE67) || // Lo [27] HANGUL SYLLABLE GGAG..HANGUL SYLLABLE GGAH -// (0x_aE69 <= code && code <= 0x_aE83) || // Lo [27] HANGUL SYLLABLE GGAEG..HANGUL SYLLABLE GGAEH -// (0x_aE85 <= code && code <= 0x_aE9F) || // Lo [27] HANGUL SYLLABLE GGYAG..HANGUL SYLLABLE GGYAH -// (0x_aEA1 <= code && code <= 0x_aEBB) || // Lo [27] HANGUL SYLLABLE GGYAEG..HANGUL SYLLABLE GGYAEH -// (0x_aEBD <= code && code <= 0x_aED7) || // Lo [27] HANGUL SYLLABLE GGEOG..HANGUL SYLLABLE GGEOH -// (0x_aED9 <= code && code <= 0x_aEF3) || // Lo [27] HANGUL SYLLABLE GGEG..HANGUL SYLLABLE GGEH -// (0x_aEF5 <= code && code <= 0x_aF0F) || // Lo [27] HANGUL SYLLABLE GGYEOG..HANGUL SYLLABLE GGYEOH -// (0x_aF11 <= code && code <= 0x_aF2B) || // Lo [27] HANGUL SYLLABLE GGYEG..HANGUL SYLLABLE GGYEH -// (0x_aF2D <= code && code <= 0x_aF47) || // Lo [27] HANGUL SYLLABLE GGOG..HANGUL SYLLABLE GGOH -// (0x_aF49 <= code && code <= 0x_aF63) || // Lo [27] HANGUL SYLLABLE GGWAG..HANGUL SYLLABLE GGWAH -// (0x_aF65 <= code && code <= 0x_aF7F) || // Lo [27] HANGUL SYLLABLE GGWAEG..HANGUL SYLLABLE GGWAEH -// (0x_aF81 <= code && code <= 0x_aF9B) || // Lo [27] HANGUL SYLLABLE GGOEG..HANGUL SYLLABLE GGOEH -// (0x_aF9D <= code && code <= 0x_aFB7) || // Lo [27] HANGUL SYLLABLE GGYOG..HANGUL SYLLABLE GGYOH -// (0x_aFB9 <= code && code <= 0x_aFD3) || // Lo [27] HANGUL SYLLABLE GGUG..HANGUL SYLLABLE GGUH -// (0x_aFD5 <= code && code <= 0x_aFEF) || // Lo [27] HANGUL SYLLABLE GGWEOG..HANGUL SYLLABLE GGWEOH -// (0x_aFF1 <= code && code <= 0x_b00B) || // Lo [27] HANGUL SYLLABLE GGWEG..HANGUL SYLLABLE GGWEH -// (0x_b00D <= code && code <= 0x_b027) || // Lo [27] HANGUL SYLLABLE GGWIG..HANGUL SYLLABLE GGWIH -// (0x_b029 <= code && code <= 0x_b043) || // Lo [27] HANGUL SYLLABLE GGYUG..HANGUL SYLLABLE GGYUH -// (0x_b045 <= code && code <= 0x_b05F) || // Lo [27] HANGUL SYLLABLE GGEUG..HANGUL SYLLABLE GGEUH -// (0x_b061 <= code && code <= 0x_b07B) || // Lo [27] HANGUL SYLLABLE GGYIG..HANGUL SYLLABLE GGYIH -// (0x_b07D <= code && code <= 0x_b097) || // Lo [27] HANGUL SYLLABLE GGIG..HANGUL SYLLABLE GGIH -// (0x_b099 <= code && code <= 0x_b0B3) || // Lo [27] HANGUL SYLLABLE NAG..HANGUL SYLLABLE NAH -// (0x_b0B5 <= code && code <= 0x_b0CF) || // Lo [27] HANGUL SYLLABLE NAEG..HANGUL SYLLABLE NAEH -// (0x_b0D1 <= code && code <= 0x_b0EB) || // Lo [27] HANGUL SYLLABLE NYAG..HANGUL SYLLABLE NYAH -// (0x_b0ED <= code && code <= 0x_b107) || // Lo [27] HANGUL SYLLABLE NYAEG..HANGUL SYLLABLE NYAEH -// (0x_b109 <= code && code <= 0x_b123) || // Lo [27] HANGUL SYLLABLE NEOG..HANGUL SYLLABLE NEOH -// (0x_b125 <= code && code <= 0x_b13F) || // Lo [27] HANGUL SYLLABLE NEG..HANGUL SYLLABLE NEH -// (0x_b141 <= code && code <= 0x_b15B) || // Lo [27] HANGUL SYLLABLE NYEOG..HANGUL SYLLABLE NYEOH -// (0x_b15D <= code && code <= 0x_b177) || // Lo [27] HANGUL SYLLABLE NYEG..HANGUL SYLLABLE NYEH -// (0x_b179 <= code && code <= 0x_b193) || // Lo [27] HANGUL SYLLABLE NOG..HANGUL SYLLABLE NOH -// (0x_b195 <= code && code <= 0x_b1AF) || // Lo [27] HANGUL SYLLABLE NWAG..HANGUL SYLLABLE NWAH -// (0x_b1B1 <= code && code <= 0x_b1CB) || // Lo [27] HANGUL SYLLABLE NWAEG..HANGUL SYLLABLE NWAEH -// (0x_b1CD <= code && code <= 0x_b1E7) || // Lo [27] HANGUL SYLLABLE NOEG..HANGUL SYLLABLE NOEH -// (0x_b1E9 <= code && code <= 0x_b203) || // Lo [27] HANGUL SYLLABLE NYOG..HANGUL SYLLABLE NYOH -// (0x_b205 <= code && code <= 0x_b21F) || // Lo [27] HANGUL SYLLABLE NUG..HANGUL SYLLABLE NUH -// (0x_b221 <= code && code <= 0x_b23B) || // Lo [27] HANGUL SYLLABLE NWEOG..HANGUL SYLLABLE NWEOH -// (0x_b23D <= code && code <= 0x_b257) || // Lo [27] HANGUL SYLLABLE NWEG..HANGUL SYLLABLE NWEH -// (0x_b259 <= code && code <= 0x_b273) || // Lo [27] HANGUL SYLLABLE NWIG..HANGUL SYLLABLE NWIH -// (0x_b275 <= code && code <= 0x_b28F) || // Lo [27] HANGUL SYLLABLE NYUG..HANGUL SYLLABLE NYUH -// (0x_b291 <= code && code <= 0x_b2AB) || // Lo [27] HANGUL SYLLABLE NEUG..HANGUL SYLLABLE NEUH -// (0x_b2AD <= code && code <= 0x_b2C7) || // Lo [27] HANGUL SYLLABLE NYIG..HANGUL SYLLABLE NYIH -// (0x_b2C9 <= code && code <= 0x_b2E3) || // Lo [27] HANGUL SYLLABLE NIG..HANGUL SYLLABLE NIH -// (0x_b2E5 <= code && code <= 0x_b2FF) || // Lo [27] HANGUL SYLLABLE DAG..HANGUL SYLLABLE DAH -// (0x_b301 <= code && code <= 0x_b31B) || // Lo [27] HANGUL SYLLABLE DAEG..HANGUL SYLLABLE DAEH -// (0x_b31D <= code && code <= 0x_b337) || // Lo [27] HANGUL SYLLABLE DYAG..HANGUL SYLLABLE DYAH -// (0x_b339 <= code && code <= 0x_b353) || // Lo [27] HANGUL SYLLABLE DYAEG..HANGUL SYLLABLE DYAEH -// (0x_b355 <= code && code <= 0x_b36F) || // Lo [27] HANGUL SYLLABLE DEOG..HANGUL SYLLABLE DEOH -// (0x_b371 <= code && code <= 0x_b38B) || // Lo [27] HANGUL SYLLABLE DEG..HANGUL SYLLABLE DEH -// (0x_b38D <= code && code <= 0x_b3A7) || // Lo [27] HANGUL SYLLABLE DYEOG..HANGUL SYLLABLE DYEOH -// (0x_b3A9 <= code && code <= 0x_b3C3) || // Lo [27] HANGUL SYLLABLE DYEG..HANGUL SYLLABLE DYEH -// (0x_b3C5 <= code && code <= 0x_b3DF) || // Lo [27] HANGUL SYLLABLE DOG..HANGUL SYLLABLE DOH -// (0x_b3E1 <= code && code <= 0x_b3FB) || // Lo [27] HANGUL SYLLABLE DWAG..HANGUL SYLLABLE DWAH -// (0x_b3FD <= code && code <= 0x_b417) || // Lo [27] HANGUL SYLLABLE DWAEG..HANGUL SYLLABLE DWAEH -// (0x_b419 <= code && code <= 0x_b433) || // Lo [27] HANGUL SYLLABLE DOEG..HANGUL SYLLABLE DOEH -// (0x_b435 <= code && code <= 0x_b44F) || // Lo [27] HANGUL SYLLABLE DYOG..HANGUL SYLLABLE DYOH -// (0x_b451 <= code && code <= 0x_b46B) || // Lo [27] HANGUL SYLLABLE DUG..HANGUL SYLLABLE DUH -// (0x_b46D <= code && code <= 0x_b487) || // Lo [27] HANGUL SYLLABLE DWEOG..HANGUL SYLLABLE DWEOH -// (0x_b489 <= code && code <= 0x_b4A3) || // Lo [27] HANGUL SYLLABLE DWEG..HANGUL SYLLABLE DWEH -// (0x_b4A5 <= code && code <= 0x_b4BF) || // Lo [27] HANGUL SYLLABLE DWIG..HANGUL SYLLABLE DWIH -// (0x_b4C1 <= code && code <= 0x_b4DB) || // Lo [27] HANGUL SYLLABLE DYUG..HANGUL SYLLABLE DYUH -// (0x_b4DD <= code && code <= 0x_b4F7) || // Lo [27] HANGUL SYLLABLE DEUG..HANGUL SYLLABLE DEUH -// (0x_b4F9 <= code && code <= 0x_b513) || // Lo [27] HANGUL SYLLABLE DYIG..HANGUL SYLLABLE DYIH -// (0x_b515 <= code && code <= 0x_b52F) || // Lo [27] HANGUL SYLLABLE DIG..HANGUL SYLLABLE DIH -// (0x_b531 <= code && code <= 0x_b54B) || // Lo [27] HANGUL SYLLABLE DDAG..HANGUL SYLLABLE DDAH -// (0x_b54D <= code && code <= 0x_b567) || // Lo [27] HANGUL SYLLABLE DDAEG..HANGUL SYLLABLE DDAEH -// (0x_b569 <= code && code <= 0x_b583) || // Lo [27] HANGUL SYLLABLE DDYAG..HANGUL SYLLABLE DDYAH -// (0x_b585 <= code && code <= 0x_b59F) || // Lo [27] HANGUL SYLLABLE DDYAEG..HANGUL SYLLABLE DDYAEH -// (0x_b5A1 <= code && code <= 0x_b5BB) || // Lo [27] HANGUL SYLLABLE DDEOG..HANGUL SYLLABLE DDEOH -// (0x_b5BD <= code && code <= 0x_b5D7) || // Lo [27] HANGUL SYLLABLE DDEG..HANGUL SYLLABLE DDEH -// (0x_b5D9 <= code && code <= 0x_b5F3) || // Lo [27] HANGUL SYLLABLE DDYEOG..HANGUL SYLLABLE DDYEOH -// (0x_b5F5 <= code && code <= 0x_b60F) || // Lo [27] HANGUL SYLLABLE DDYEG..HANGUL SYLLABLE DDYEH -// (0x_b611 <= code && code <= 0x_b62B) || // Lo [27] HANGUL SYLLABLE DDOG..HANGUL SYLLABLE DDOH -// (0x_b62D <= code && code <= 0x_b647) || // Lo [27] HANGUL SYLLABLE DDWAG..HANGUL SYLLABLE DDWAH -// (0x_b649 <= code && code <= 0x_b663) || // Lo [27] HANGUL SYLLABLE DDWAEG..HANGUL SYLLABLE DDWAEH -// (0x_b665 <= code && code <= 0x_b67F) || // Lo [27] HANGUL SYLLABLE DDOEG..HANGUL SYLLABLE DDOEH -// (0x_b681 <= code && code <= 0x_b69B) || // Lo [27] HANGUL SYLLABLE DDYOG..HANGUL SYLLABLE DDYOH -// (0x_b69D <= code && code <= 0x_b6B7) || // Lo [27] HANGUL SYLLABLE DDUG..HANGUL SYLLABLE DDUH -// (0x_b6B9 <= code && code <= 0x_b6D3) || // Lo [27] HANGUL SYLLABLE DDWEOG..HANGUL SYLLABLE DDWEOH -// (0x_b6D5 <= code && code <= 0x_b6EF) || // Lo [27] HANGUL SYLLABLE DDWEG..HANGUL SYLLABLE DDWEH -// (0x_b6F1 <= code && code <= 0x_b70B) || // Lo [27] HANGUL SYLLABLE DDWIG..HANGUL SYLLABLE DDWIH -// (0x_b70D <= code && code <= 0x_b727) || // Lo [27] HANGUL SYLLABLE DDYUG..HANGUL SYLLABLE DDYUH -// (0x_b729 <= code && code <= 0x_b743) || // Lo [27] HANGUL SYLLABLE DDEUG..HANGUL SYLLABLE DDEUH -// (0x_b745 <= code && code <= 0x_b75F) || // Lo [27] HANGUL SYLLABLE DDYIG..HANGUL SYLLABLE DDYIH -// (0x_b761 <= code && code <= 0x_b77B) || // Lo [27] HANGUL SYLLABLE DDIG..HANGUL SYLLABLE DDIH -// (0x_b77D <= code && code <= 0x_b797) || // Lo [27] HANGUL SYLLABLE RAG..HANGUL SYLLABLE RAH -// (0x_b799 <= code && code <= 0x_b7B3) || // Lo [27] HANGUL SYLLABLE RAEG..HANGUL SYLLABLE RAEH -// (0x_b7B5 <= code && code <= 0x_b7CF) || // Lo [27] HANGUL SYLLABLE RYAG..HANGUL SYLLABLE RYAH -// (0x_b7D1 <= code && code <= 0x_b7EB) || // Lo [27] HANGUL SYLLABLE RYAEG..HANGUL SYLLABLE RYAEH -// (0x_b7ED <= code && code <= 0x_b807) || // Lo [27] HANGUL SYLLABLE REOG..HANGUL SYLLABLE REOH -// (0x_b809 <= code && code <= 0x_b823) || // Lo [27] HANGUL SYLLABLE REG..HANGUL SYLLABLE REH -// (0x_b825 <= code && code <= 0x_b83F) || // Lo [27] HANGUL SYLLABLE RYEOG..HANGUL SYLLABLE RYEOH -// (0x_b841 <= code && code <= 0x_b85B) || // Lo [27] HANGUL SYLLABLE RYEG..HANGUL SYLLABLE RYEH -// (0x_b85D <= code && code <= 0x_b877) || // Lo [27] HANGUL SYLLABLE ROG..HANGUL SYLLABLE ROH -// (0x_b879 <= code && code <= 0x_b893) || // Lo [27] HANGUL SYLLABLE RWAG..HANGUL SYLLABLE RWAH -// (0x_b895 <= code && code <= 0x_b8AF) || // Lo [27] HANGUL SYLLABLE RWAEG..HANGUL SYLLABLE RWAEH -// (0x_b8B1 <= code && code <= 0x_b8CB) || // Lo [27] HANGUL SYLLABLE ROEG..HANGUL SYLLABLE ROEH -// (0x_b8CD <= code && code <= 0x_b8E7) || // Lo [27] HANGUL SYLLABLE RYOG..HANGUL SYLLABLE RYOH -// (0x_b8E9 <= code && code <= 0x_b903) || // Lo [27] HANGUL SYLLABLE RUG..HANGUL SYLLABLE RUH -// (0x_b905 <= code && code <= 0x_b91F) || // Lo [27] HANGUL SYLLABLE RWEOG..HANGUL SYLLABLE RWEOH -// (0x_b921 <= code && code <= 0x_b93B) || // Lo [27] HANGUL SYLLABLE RWEG..HANGUL SYLLABLE RWEH -// (0x_b93D <= code && code <= 0x_b957) || // Lo [27] HANGUL SYLLABLE RWIG..HANGUL SYLLABLE RWIH -// (0x_b959 <= code && code <= 0x_b973) || // Lo [27] HANGUL SYLLABLE RYUG..HANGUL SYLLABLE RYUH -// (0x_b975 <= code && code <= 0x_b98F) || // Lo [27] HANGUL SYLLABLE REUG..HANGUL SYLLABLE REUH -// (0x_b991 <= code && code <= 0x_b9AB) || // Lo [27] HANGUL SYLLABLE RYIG..HANGUL SYLLABLE RYIH -// (0x_b9AD <= code && code <= 0x_b9C7) || // Lo [27] HANGUL SYLLABLE RIG..HANGUL SYLLABLE RIH -// (0x_b9C9 <= code && code <= 0x_b9E3) || // Lo [27] HANGUL SYLLABLE MAG..HANGUL SYLLABLE MAH -// (0x_b9E5 <= code && code <= 0x_b9FF) || // Lo [27] HANGUL SYLLABLE MAEG..HANGUL SYLLABLE MAEH -// (0x_bA01 <= code && code <= 0x_bA1B) || // Lo [27] HANGUL SYLLABLE MYAG..HANGUL SYLLABLE MYAH -// (0x_bA1D <= code && code <= 0x_bA37) || // Lo [27] HANGUL SYLLABLE MYAEG..HANGUL SYLLABLE MYAEH -// (0x_bA39 <= code && code <= 0x_bA53) || // Lo [27] HANGUL SYLLABLE MEOG..HANGUL SYLLABLE MEOH -// (0x_bA55 <= code && code <= 0x_bA6F) || // Lo [27] HANGUL SYLLABLE MEG..HANGUL SYLLABLE MEH -// (0x_bA71 <= code && code <= 0x_bA8B) || // Lo [27] HANGUL SYLLABLE MYEOG..HANGUL SYLLABLE MYEOH -// (0x_bA8D <= code && code <= 0x_bAA7) || // Lo [27] HANGUL SYLLABLE MYEG..HANGUL SYLLABLE MYEH -// (0x_bAA9 <= code && code <= 0x_bAC3) || // Lo [27] HANGUL SYLLABLE MOG..HANGUL SYLLABLE MOH -// (0x_bAC5 <= code && code <= 0x_bADF) || // Lo [27] HANGUL SYLLABLE MWAG..HANGUL SYLLABLE MWAH -// (0x_bAE1 <= code && code <= 0x_bAFB) || // Lo [27] HANGUL SYLLABLE MWAEG..HANGUL SYLLABLE MWAEH -// (0x_bAFD <= code && code <= 0x_bB17) || // Lo [27] HANGUL SYLLABLE MOEG..HANGUL SYLLABLE MOEH -// (0x_bB19 <= code && code <= 0x_bB33) || // Lo [27] HANGUL SYLLABLE MYOG..HANGUL SYLLABLE MYOH -// (0x_bB35 <= code && code <= 0x_bB4F) || // Lo [27] HANGUL SYLLABLE MUG..HANGUL SYLLABLE MUH -// (0x_bB51 <= code && code <= 0x_bB6B) || // Lo [27] HANGUL SYLLABLE MWEOG..HANGUL SYLLABLE MWEOH -// (0x_bB6D <= code && code <= 0x_bB87) || // Lo [27] HANGUL SYLLABLE MWEG..HANGUL SYLLABLE MWEH -// (0x_bB89 <= code && code <= 0x_bBA3) || // Lo [27] HANGUL SYLLABLE MWIG..HANGUL SYLLABLE MWIH -// (0x_bBA5 <= code && code <= 0x_bBBF) || // Lo [27] HANGUL SYLLABLE MYUG..HANGUL SYLLABLE MYUH -// (0x_bBC1 <= code && code <= 0x_bBDB) || // Lo [27] HANGUL SYLLABLE MEUG..HANGUL SYLLABLE MEUH -// (0x_bBDD <= code && code <= 0x_bBF7) || // Lo [27] HANGUL SYLLABLE MYIG..HANGUL SYLLABLE MYIH -// (0x_bBF9 <= code && code <= 0x_bC13) || // Lo [27] HANGUL SYLLABLE MIG..HANGUL SYLLABLE MIH -// (0x_bC15 <= code && code <= 0x_bC2F) || // Lo [27] HANGUL SYLLABLE BAG..HANGUL SYLLABLE BAH -// (0x_bC31 <= code && code <= 0x_bC4B) || // Lo [27] HANGUL SYLLABLE BAEG..HANGUL SYLLABLE BAEH -// (0x_bC4D <= code && code <= 0x_bC67) || // Lo [27] HANGUL SYLLABLE BYAG..HANGUL SYLLABLE BYAH -// (0x_bC69 <= code && code <= 0x_bC83) || // Lo [27] HANGUL SYLLABLE BYAEG..HANGUL SYLLABLE BYAEH -// (0x_bC85 <= code && code <= 0x_bC9F) || // Lo [27] HANGUL SYLLABLE BEOG..HANGUL SYLLABLE BEOH -// (0x_bCA1 <= code && code <= 0x_bCBB) || // Lo [27] HANGUL SYLLABLE BEG..HANGUL SYLLABLE BEH -// (0x_bCBD <= code && code <= 0x_bCD7) || // Lo [27] HANGUL SYLLABLE BYEOG..HANGUL SYLLABLE BYEOH -// (0x_bCD9 <= code && code <= 0x_bCF3) || // Lo [27] HANGUL SYLLABLE BYEG..HANGUL SYLLABLE BYEH -// (0x_bCF5 <= code && code <= 0x_bD0F) || // Lo [27] HANGUL SYLLABLE BOG..HANGUL SYLLABLE BOH -// (0x_bD11 <= code && code <= 0x_bD2B) || // Lo [27] HANGUL SYLLABLE BWAG..HANGUL SYLLABLE BWAH -// (0x_bD2D <= code && code <= 0x_bD47) || // Lo [27] HANGUL SYLLABLE BWAEG..HANGUL SYLLABLE BWAEH -// (0x_bD49 <= code && code <= 0x_bD63) || // Lo [27] HANGUL SYLLABLE BOEG..HANGUL SYLLABLE BOEH -// (0x_bD65 <= code && code <= 0x_bD7F) || // Lo [27] HANGUL SYLLABLE BYOG..HANGUL SYLLABLE BYOH -// (0x_bD81 <= code && code <= 0x_bD9B) || // Lo [27] HANGUL SYLLABLE BUG..HANGUL SYLLABLE BUH -// (0x_bD9D <= code && code <= 0x_bDB7) || // Lo [27] HANGUL SYLLABLE BWEOG..HANGUL SYLLABLE BWEOH -// (0x_bDB9 <= code && code <= 0x_bDD3) || // Lo [27] HANGUL SYLLABLE BWEG..HANGUL SYLLABLE BWEH -// (0x_bDD5 <= code && code <= 0x_bDEF) || // Lo [27] HANGUL SYLLABLE BWIG..HANGUL SYLLABLE BWIH -// (0x_bDF1 <= code && code <= 0x_bE0B) || // Lo [27] HANGUL SYLLABLE BYUG..HANGUL SYLLABLE BYUH -// (0x_bE0D <= code && code <= 0x_bE27) || // Lo [27] HANGUL SYLLABLE BEUG..HANGUL SYLLABLE BEUH -// (0x_bE29 <= code && code <= 0x_bE43) || // Lo [27] HANGUL SYLLABLE BYIG..HANGUL SYLLABLE BYIH -// (0x_bE45 <= code && code <= 0x_bE5F) || // Lo [27] HANGUL SYLLABLE BIG..HANGUL SYLLABLE BIH -// (0x_bE61 <= code && code <= 0x_bE7B) || // Lo [27] HANGUL SYLLABLE BBAG..HANGUL SYLLABLE BBAH -// (0x_bE7D <= code && code <= 0x_bE97) || // Lo [27] HANGUL SYLLABLE BBAEG..HANGUL SYLLABLE BBAEH -// (0x_bE99 <= code && code <= 0x_bEB3) || // Lo [27] HANGUL SYLLABLE BBYAG..HANGUL SYLLABLE BBYAH -// (0x_bEB5 <= code && code <= 0x_bECF) || // Lo [27] HANGUL SYLLABLE BBYAEG..HANGUL SYLLABLE BBYAEH -// (0x_bED1 <= code && code <= 0x_bEEB) || // Lo [27] HANGUL SYLLABLE BBEOG..HANGUL SYLLABLE BBEOH -// (0x_bEED <= code && code <= 0x_bF07) || // Lo [27] HANGUL SYLLABLE BBEG..HANGUL SYLLABLE BBEH -// (0x_bF09 <= code && code <= 0x_bF23) || // Lo [27] HANGUL SYLLABLE BBYEOG..HANGUL SYLLABLE BBYEOH -// (0x_bF25 <= code && code <= 0x_bF3F) || // Lo [27] HANGUL SYLLABLE BBYEG..HANGUL SYLLABLE BBYEH -// (0x_bF41 <= code && code <= 0x_bF5B) || // Lo [27] HANGUL SYLLABLE BBOG..HANGUL SYLLABLE BBOH -// (0x_bF5D <= code && code <= 0x_bF77) || // Lo [27] HANGUL SYLLABLE BBWAG..HANGUL SYLLABLE BBWAH -// (0x_bF79 <= code && code <= 0x_bF93) || // Lo [27] HANGUL SYLLABLE BBWAEG..HANGUL SYLLABLE BBWAEH -// (0x_bF95 <= code && code <= 0x_bFAF) || // Lo [27] HANGUL SYLLABLE BBOEG..HANGUL SYLLABLE BBOEH -// (0x_bFB1 <= code && code <= 0x_bFCB) || // Lo [27] HANGUL SYLLABLE BBYOG..HANGUL SYLLABLE BBYOH -// (0x_bFCD <= code && code <= 0x_bFE7) || // Lo [27] HANGUL SYLLABLE BBUG..HANGUL SYLLABLE BBUH -// (0x_bFE9 <= code && code <= 0x_c003) || // Lo [27] HANGUL SYLLABLE BBWEOG..HANGUL SYLLABLE BBWEOH -// (0x_c005 <= code && code <= 0x_c01F) || // Lo [27] HANGUL SYLLABLE BBWEG..HANGUL SYLLABLE BBWEH -// (0x_c021 <= code && code <= 0x_c03B) || // Lo [27] HANGUL SYLLABLE BBWIG..HANGUL SYLLABLE BBWIH -// (0x_c03D <= code && code <= 0x_c057) || // Lo [27] HANGUL SYLLABLE BBYUG..HANGUL SYLLABLE BBYUH -// (0x_c059 <= code && code <= 0x_c073) || // Lo [27] HANGUL SYLLABLE BBEUG..HANGUL SYLLABLE BBEUH -// (0x_c075 <= code && code <= 0x_c08F) || // Lo [27] HANGUL SYLLABLE BBYIG..HANGUL SYLLABLE BBYIH -// (0x_c091 <= code && code <= 0x_c0AB) || // Lo [27] HANGUL SYLLABLE BBIG..HANGUL SYLLABLE BBIH -// (0x_c0AD <= code && code <= 0x_c0C7) || // Lo [27] HANGUL SYLLABLE SAG..HANGUL SYLLABLE SAH -// (0x_c0C9 <= code && code <= 0x_c0E3) || // Lo [27] HANGUL SYLLABLE SAEG..HANGUL SYLLABLE SAEH -// (0x_c0E5 <= code && code <= 0x_c0FF) || // Lo [27] HANGUL SYLLABLE SYAG..HANGUL SYLLABLE SYAH -// (0x_c101 <= code && code <= 0x_c11B) || // Lo [27] HANGUL SYLLABLE SYAEG..HANGUL SYLLABLE SYAEH -// (0x_c11D <= code && code <= 0x_c137) || // Lo [27] HANGUL SYLLABLE SEOG..HANGUL SYLLABLE SEOH -// (0x_c139 <= code && code <= 0x_c153) || // Lo [27] HANGUL SYLLABLE SEG..HANGUL SYLLABLE SEH -// (0x_c155 <= code && code <= 0x_c16F) || // Lo [27] HANGUL SYLLABLE SYEOG..HANGUL SYLLABLE SYEOH -// (0x_c171 <= code && code <= 0x_c18B) || // Lo [27] HANGUL SYLLABLE SYEG..HANGUL SYLLABLE SYEH -// (0x_c18D <= code && code <= 0x_c1A7) || // Lo [27] HANGUL SYLLABLE SOG..HANGUL SYLLABLE SOH -// (0x_c1A9 <= code && code <= 0x_c1C3) || // Lo [27] HANGUL SYLLABLE SWAG..HANGUL SYLLABLE SWAH -// (0x_c1C5 <= code && code <= 0x_c1DF) || // Lo [27] HANGUL SYLLABLE SWAEG..HANGUL SYLLABLE SWAEH -// (0x_c1E1 <= code && code <= 0x_c1FB) || // Lo [27] HANGUL SYLLABLE SOEG..HANGUL SYLLABLE SOEH -// (0x_c1FD <= code && code <= 0x_c217) || // Lo [27] HANGUL SYLLABLE SYOG..HANGUL SYLLABLE SYOH -// (0x_c219 <= code && code <= 0x_c233) || // Lo [27] HANGUL SYLLABLE SUG..HANGUL SYLLABLE SUH -// (0x_c235 <= code && code <= 0x_c24F) || // Lo [27] HANGUL SYLLABLE SWEOG..HANGUL SYLLABLE SWEOH -// (0x_c251 <= code && code <= 0x_c26B) || // Lo [27] HANGUL SYLLABLE SWEG..HANGUL SYLLABLE SWEH -// (0x_c26D <= code && code <= 0x_c287) || // Lo [27] HANGUL SYLLABLE SWIG..HANGUL SYLLABLE SWIH -// (0x_c289 <= code && code <= 0x_c2A3) || // Lo [27] HANGUL SYLLABLE SYUG..HANGUL SYLLABLE SYUH -// (0x_c2A5 <= code && code <= 0x_c2BF) || // Lo [27] HANGUL SYLLABLE SEUG..HANGUL SYLLABLE SEUH -// (0x_c2C1 <= code && code <= 0x_c2DB) || // Lo [27] HANGUL SYLLABLE SYIG..HANGUL SYLLABLE SYIH -// (0x_c2DD <= code && code <= 0x_c2F7) || // Lo [27] HANGUL SYLLABLE SIG..HANGUL SYLLABLE SIH -// (0x_c2F9 <= code && code <= 0x_c313) || // Lo [27] HANGUL SYLLABLE SSAG..HANGUL SYLLABLE SSAH -// (0x_c315 <= code && code <= 0x_c32F) || // Lo [27] HANGUL SYLLABLE SSAEG..HANGUL SYLLABLE SSAEH -// (0x_c331 <= code && code <= 0x_c34B) || // Lo [27] HANGUL SYLLABLE SSYAG..HANGUL SYLLABLE SSYAH -// (0x_c34D <= code && code <= 0x_c367) || // Lo [27] HANGUL SYLLABLE SSYAEG..HANGUL SYLLABLE SSYAEH -// (0x_c369 <= code && code <= 0x_c383) || // Lo [27] HANGUL SYLLABLE SSEOG..HANGUL SYLLABLE SSEOH -// (0x_c385 <= code && code <= 0x_c39F) || // Lo [27] HANGUL SYLLABLE SSEG..HANGUL SYLLABLE SSEH -// (0x_c3A1 <= code && code <= 0x_c3BB) || // Lo [27] HANGUL SYLLABLE SSYEOG..HANGUL SYLLABLE SSYEOH -// (0x_c3BD <= code && code <= 0x_c3D7) || // Lo [27] HANGUL SYLLABLE SSYEG..HANGUL SYLLABLE SSYEH -// (0x_c3D9 <= code && code <= 0x_c3F3) || // Lo [27] HANGUL SYLLABLE SSOG..HANGUL SYLLABLE SSOH -// (0x_c3F5 <= code && code <= 0x_c40F) || // Lo [27] HANGUL SYLLABLE SSWAG..HANGUL SYLLABLE SSWAH -// (0x_c411 <= code && code <= 0x_c42B) || // Lo [27] HANGUL SYLLABLE SSWAEG..HANGUL SYLLABLE SSWAEH -// (0x_c42D <= code && code <= 0x_c447) || // Lo [27] HANGUL SYLLABLE SSOEG..HANGUL SYLLABLE SSOEH -// (0x_c449 <= code && code <= 0x_c463) || // Lo [27] HANGUL SYLLABLE SSYOG..HANGUL SYLLABLE SSYOH -// (0x_c465 <= code && code <= 0x_c47F) || // Lo [27] HANGUL SYLLABLE SSUG..HANGUL SYLLABLE SSUH -// (0x_c481 <= code && code <= 0x_c49B) || // Lo [27] HANGUL SYLLABLE SSWEOG..HANGUL SYLLABLE SSWEOH -// (0x_c49D <= code && code <= 0x_c4B7) || // Lo [27] HANGUL SYLLABLE SSWEG..HANGUL SYLLABLE SSWEH -// (0x_c4B9 <= code && code <= 0x_c4D3) || // Lo [27] HANGUL SYLLABLE SSWIG..HANGUL SYLLABLE SSWIH -// (0x_c4D5 <= code && code <= 0x_c4EF) || // Lo [27] HANGUL SYLLABLE SSYUG..HANGUL SYLLABLE SSYUH -// (0x_c4F1 <= code && code <= 0x_c50B) || // Lo [27] HANGUL SYLLABLE SSEUG..HANGUL SYLLABLE SSEUH -// (0x_c50D <= code && code <= 0x_c527) || // Lo [27] HANGUL SYLLABLE SSYIG..HANGUL SYLLABLE SSYIH -// (0x_c529 <= code && code <= 0x_c543) || // Lo [27] HANGUL SYLLABLE SSIG..HANGUL SYLLABLE SSIH -// (0x_c545 <= code && code <= 0x_c55F) || // Lo [27] HANGUL SYLLABLE AG..HANGUL SYLLABLE AH -// (0x_c561 <= code && code <= 0x_c57B) || // Lo [27] HANGUL SYLLABLE AEG..HANGUL SYLLABLE AEH -// (0x_c57D <= code && code <= 0x_c597) || // Lo [27] HANGUL SYLLABLE YAG..HANGUL SYLLABLE YAH -// (0x_c599 <= code && code <= 0x_c5B3) || // Lo [27] HANGUL SYLLABLE YAEG..HANGUL SYLLABLE YAEH -// (0x_c5B5 <= code && code <= 0x_c5CF) || // Lo [27] HANGUL SYLLABLE EOG..HANGUL SYLLABLE EOH -// (0x_c5D1 <= code && code <= 0x_c5EB) || // Lo [27] HANGUL SYLLABLE EG..HANGUL SYLLABLE EH -// (0x_c5ED <= code && code <= 0x_c607) || // Lo [27] HANGUL SYLLABLE YEOG..HANGUL SYLLABLE YEOH -// (0x_c609 <= code && code <= 0x_c623) || // Lo [27] HANGUL SYLLABLE YEG..HANGUL SYLLABLE YEH -// (0x_c625 <= code && code <= 0x_c63F) || // Lo [27] HANGUL SYLLABLE OG..HANGUL SYLLABLE OH -// (0x_c641 <= code && code <= 0x_c65B) || // Lo [27] HANGUL SYLLABLE WAG..HANGUL SYLLABLE WAH -// (0x_c65D <= code && code <= 0x_c677) || // Lo [27] HANGUL SYLLABLE WAEG..HANGUL SYLLABLE WAEH -// (0x_c679 <= code && code <= 0x_c693) || // Lo [27] HANGUL SYLLABLE OEG..HANGUL SYLLABLE OEH -// (0x_c695 <= code && code <= 0x_c6AF) || // Lo [27] HANGUL SYLLABLE YOG..HANGUL SYLLABLE YOH -// (0x_c6B1 <= code && code <= 0x_c6CB) || // Lo [27] HANGUL SYLLABLE UG..HANGUL SYLLABLE UH -// (0x_c6CD <= code && code <= 0x_c6E7) || // Lo [27] HANGUL SYLLABLE WEOG..HANGUL SYLLABLE WEOH -// (0x_c6E9 <= code && code <= 0x_c703) || // Lo [27] HANGUL SYLLABLE WEG..HANGUL SYLLABLE WEH -// (0x_c705 <= code && code <= 0x_c71F) || // Lo [27] HANGUL SYLLABLE WIG..HANGUL SYLLABLE WIH -// (0x_c721 <= code && code <= 0x_c73B) || // Lo [27] HANGUL SYLLABLE YUG..HANGUL SYLLABLE YUH -// (0x_c73D <= code && code <= 0x_c757) || // Lo [27] HANGUL SYLLABLE EUG..HANGUL SYLLABLE EUH -// (0x_c759 <= code && code <= 0x_c773) || // Lo [27] HANGUL SYLLABLE YIG..HANGUL SYLLABLE YIH -// (0x_c775 <= code && code <= 0x_c78F) || // Lo [27] HANGUL SYLLABLE IG..HANGUL SYLLABLE IH -// (0x_c791 <= code && code <= 0x_c7AB) || // Lo [27] HANGUL SYLLABLE JAG..HANGUL SYLLABLE JAH -// (0x_c7AD <= code && code <= 0x_c7C7) || // Lo [27] HANGUL SYLLABLE JAEG..HANGUL SYLLABLE JAEH -// (0x_c7C9 <= code && code <= 0x_c7E3) || // Lo [27] HANGUL SYLLABLE JYAG..HANGUL SYLLABLE JYAH -// (0x_c7E5 <= code && code <= 0x_c7FF) || // Lo [27] HANGUL SYLLABLE JYAEG..HANGUL SYLLABLE JYAEH -// (0x_c801 <= code && code <= 0x_c81B) || // Lo [27] HANGUL SYLLABLE JEOG..HANGUL SYLLABLE JEOH -// (0x_c81D <= code && code <= 0x_c837) || // Lo [27] HANGUL SYLLABLE JEG..HANGUL SYLLABLE JEH -// (0x_c839 <= code && code <= 0x_c853) || // Lo [27] HANGUL SYLLABLE JYEOG..HANGUL SYLLABLE JYEOH -// (0x_c855 <= code && code <= 0x_c86F) || // Lo [27] HANGUL SYLLABLE JYEG..HANGUL SYLLABLE JYEH -// (0x_c871 <= code && code <= 0x_c88B) || // Lo [27] HANGUL SYLLABLE JOG..HANGUL SYLLABLE JOH -// (0x_c88D <= code && code <= 0x_c8A7) || // Lo [27] HANGUL SYLLABLE JWAG..HANGUL SYLLABLE JWAH -// (0x_c8A9 <= code && code <= 0x_c8C3) || // Lo [27] HANGUL SYLLABLE JWAEG..HANGUL SYLLABLE JWAEH -// (0x_c8C5 <= code && code <= 0x_c8DF) || // Lo [27] HANGUL SYLLABLE JOEG..HANGUL SYLLABLE JOEH -// (0x_c8E1 <= code && code <= 0x_c8FB) || // Lo [27] HANGUL SYLLABLE JYOG..HANGUL SYLLABLE JYOH -// (0x_c8FD <= code && code <= 0x_c917) || // Lo [27] HANGUL SYLLABLE JUG..HANGUL SYLLABLE JUH -// (0x_c919 <= code && code <= 0x_c933) || // Lo [27] HANGUL SYLLABLE JWEOG..HANGUL SYLLABLE JWEOH -// (0x_c935 <= code && code <= 0x_c94F) || // Lo [27] HANGUL SYLLABLE JWEG..HANGUL SYLLABLE JWEH -// (0x_c951 <= code && code <= 0x_c96B) || // Lo [27] HANGUL SYLLABLE JWIG..HANGUL SYLLABLE JWIH -// (0x_c96D <= code && code <= 0x_c987) || // Lo [27] HANGUL SYLLABLE JYUG..HANGUL SYLLABLE JYUH -// (0x_c989 <= code && code <= 0x_c9A3) || // Lo [27] HANGUL SYLLABLE JEUG..HANGUL SYLLABLE JEUH -// (0x_c9A5 <= code && code <= 0x_c9BF) || // Lo [27] HANGUL SYLLABLE JYIG..HANGUL SYLLABLE JYIH -// (0x_c9C1 <= code && code <= 0x_c9DB) || // Lo [27] HANGUL SYLLABLE JIG..HANGUL SYLLABLE JIH -// (0x_c9DD <= code && code <= 0x_c9F7) || // Lo [27] HANGUL SYLLABLE JJAG..HANGUL SYLLABLE JJAH -// (0x_c9F9 <= code && code <= 0x_cA13) || // Lo [27] HANGUL SYLLABLE JJAEG..HANGUL SYLLABLE JJAEH -// (0x_cA15 <= code && code <= 0x_cA2F) || // Lo [27] HANGUL SYLLABLE JJYAG..HANGUL SYLLABLE JJYAH -// (0x_cA31 <= code && code <= 0x_cA4B) || // Lo [27] HANGUL SYLLABLE JJYAEG..HANGUL SYLLABLE JJYAEH -// (0x_cA4D <= code && code <= 0x_cA67) || // Lo [27] HANGUL SYLLABLE JJEOG..HANGUL SYLLABLE JJEOH -// (0x_cA69 <= code && code <= 0x_cA83) || // Lo [27] HANGUL SYLLABLE JJEG..HANGUL SYLLABLE JJEH -// (0x_cA85 <= code && code <= 0x_cA9F) || // Lo [27] HANGUL SYLLABLE JJYEOG..HANGUL SYLLABLE JJYEOH -// (0x_cAA1 <= code && code <= 0x_cABB) || // Lo [27] HANGUL SYLLABLE JJYEG..HANGUL SYLLABLE JJYEH -// (0x_cABD <= code && code <= 0x_cAD7) || // Lo [27] HANGUL SYLLABLE JJOG..HANGUL SYLLABLE JJOH -// (0x_cAD9 <= code && code <= 0x_cAF3) || // Lo [27] HANGUL SYLLABLE JJWAG..HANGUL SYLLABLE JJWAH -// (0x_cAF5 <= code && code <= 0x_cB0F) || // Lo [27] HANGUL SYLLABLE JJWAEG..HANGUL SYLLABLE JJWAEH -// (0x_cB11 <= code && code <= 0x_cB2B) || // Lo [27] HANGUL SYLLABLE JJOEG..HANGUL SYLLABLE JJOEH -// (0x_cB2D <= code && code <= 0x_cB47) || // Lo [27] HANGUL SYLLABLE JJYOG..HANGUL SYLLABLE JJYOH -// (0x_cB49 <= code && code <= 0x_cB63) || // Lo [27] HANGUL SYLLABLE JJUG..HANGUL SYLLABLE JJUH -// (0x_cB65 <= code && code <= 0x_cB7F) || // Lo [27] HANGUL SYLLABLE JJWEOG..HANGUL SYLLABLE JJWEOH -// (0x_cB81 <= code && code <= 0x_cB9B) || // Lo [27] HANGUL SYLLABLE JJWEG..HANGUL SYLLABLE JJWEH -// (0x_cB9D <= code && code <= 0x_cBB7) || // Lo [27] HANGUL SYLLABLE JJWIG..HANGUL SYLLABLE JJWIH -// (0x_cBB9 <= code && code <= 0x_cBD3) || // Lo [27] HANGUL SYLLABLE JJYUG..HANGUL SYLLABLE JJYUH -// (0x_cBD5 <= code && code <= 0x_cBEF) || // Lo [27] HANGUL SYLLABLE JJEUG..HANGUL SYLLABLE JJEUH -// (0x_cBF1 <= code && code <= 0x_cC0B) || // Lo [27] HANGUL SYLLABLE JJYIG..HANGUL SYLLABLE JJYIH -// (0x_cC0D <= code && code <= 0x_cC27) || // Lo [27] HANGUL SYLLABLE JJIG..HANGUL SYLLABLE JJIH -// (0x_cC29 <= code && code <= 0x_cC43) || // Lo [27] HANGUL SYLLABLE CAG..HANGUL SYLLABLE CAH -// (0x_cC45 <= code && code <= 0x_cC5F) || // Lo [27] HANGUL SYLLABLE CAEG..HANGUL SYLLABLE CAEH -// (0x_cC61 <= code && code <= 0x_cC7B) || // Lo [27] HANGUL SYLLABLE CYAG..HANGUL SYLLABLE CYAH -// (0x_cC7D <= code && code <= 0x_cC97) || // Lo [27] HANGUL SYLLABLE CYAEG..HANGUL SYLLABLE CYAEH -// (0x_cC99 <= code && code <= 0x_cCB3) || // Lo [27] HANGUL SYLLABLE CEOG..HANGUL SYLLABLE CEOH -// (0x_cCB5 <= code && code <= 0x_cCCF) || // Lo [27] HANGUL SYLLABLE CEG..HANGUL SYLLABLE CEH -// (0x_cCD1 <= code && code <= 0x_cCEB) || // Lo [27] HANGUL SYLLABLE CYEOG..HANGUL SYLLABLE CYEOH -// (0x_cCED <= code && code <= 0x_cD07) || // Lo [27] HANGUL SYLLABLE CYEG..HANGUL SYLLABLE CYEH -// (0x_cD09 <= code && code <= 0x_cD23) || // Lo [27] HANGUL SYLLABLE COG..HANGUL SYLLABLE COH -// (0x_cD25 <= code && code <= 0x_cD3F) || // Lo [27] HANGUL SYLLABLE CWAG..HANGUL SYLLABLE CWAH -// (0x_cD41 <= code && code <= 0x_cD5B) || // Lo [27] HANGUL SYLLABLE CWAEG..HANGUL SYLLABLE CWAEH -// (0x_cD5D <= code && code <= 0x_cD77) || // Lo [27] HANGUL SYLLABLE COEG..HANGUL SYLLABLE COEH -// (0x_cD79 <= code && code <= 0x_cD93) || // Lo [27] HANGUL SYLLABLE CYOG..HANGUL SYLLABLE CYOH -// (0x_cD95 <= code && code <= 0x_cDAF) || // Lo [27] HANGUL SYLLABLE CUG..HANGUL SYLLABLE CUH -// (0x_cDB1 <= code && code <= 0x_cDCB) || // Lo [27] HANGUL SYLLABLE CWEOG..HANGUL SYLLABLE CWEOH -// (0x_cDCD <= code && code <= 0x_cDE7) || // Lo [27] HANGUL SYLLABLE CWEG..HANGUL SYLLABLE CWEH -// (0x_cDE9 <= code && code <= 0x_cE03) || // Lo [27] HANGUL SYLLABLE CWIG..HANGUL SYLLABLE CWIH -// (0x_cE05 <= code && code <= 0x_cE1F) || // Lo [27] HANGUL SYLLABLE CYUG..HANGUL SYLLABLE CYUH -// (0x_cE21 <= code && code <= 0x_cE3B) || // Lo [27] HANGUL SYLLABLE CEUG..HANGUL SYLLABLE CEUH -// (0x_cE3D <= code && code <= 0x_cE57) || // Lo [27] HANGUL SYLLABLE CYIG..HANGUL SYLLABLE CYIH -// (0x_cE59 <= code && code <= 0x_cE73) || // Lo [27] HANGUL SYLLABLE CIG..HANGUL SYLLABLE CIH -// (0x_cE75 <= code && code <= 0x_cE8F) || // Lo [27] HANGUL SYLLABLE KAG..HANGUL SYLLABLE KAH -// (0x_cE91 <= code && code <= 0x_cEAB) || // Lo [27] HANGUL SYLLABLE KAEG..HANGUL SYLLABLE KAEH -// (0x_cEAD <= code && code <= 0x_cEC7) || // Lo [27] HANGUL SYLLABLE KYAG..HANGUL SYLLABLE KYAH -// (0x_cEC9 <= code && code <= 0x_cEE3) || // Lo [27] HANGUL SYLLABLE KYAEG..HANGUL SYLLABLE KYAEH -// (0x_cEE5 <= code && code <= 0x_cEFF) || // Lo [27] HANGUL SYLLABLE KEOG..HANGUL SYLLABLE KEOH -// (0x_cF01 <= code && code <= 0x_cF1B) || // Lo [27] HANGUL SYLLABLE KEG..HANGUL SYLLABLE KEH -// (0x_cF1D <= code && code <= 0x_cF37) || // Lo [27] HANGUL SYLLABLE KYEOG..HANGUL SYLLABLE KYEOH -// (0x_cF39 <= code && code <= 0x_cF53) || // Lo [27] HANGUL SYLLABLE KYEG..HANGUL SYLLABLE KYEH -// (0x_cF55 <= code && code <= 0x_cF6F) || // Lo [27] HANGUL SYLLABLE KOG..HANGUL SYLLABLE KOH -// (0x_cF71 <= code && code <= 0x_cF8B) || // Lo [27] HANGUL SYLLABLE KWAG..HANGUL SYLLABLE KWAH -// (0x_cF8D <= code && code <= 0x_cFA7) || // Lo [27] HANGUL SYLLABLE KWAEG..HANGUL SYLLABLE KWAEH -// (0x_cFA9 <= code && code <= 0x_cFC3) || // Lo [27] HANGUL SYLLABLE KOEG..HANGUL SYLLABLE KOEH -// (0x_cFC5 <= code && code <= 0x_cFDF) || // Lo [27] HANGUL SYLLABLE KYOG..HANGUL SYLLABLE KYOH -// (0x_cFE1 <= code && code <= 0x_cFFB) || // Lo [27] HANGUL SYLLABLE KUG..HANGUL SYLLABLE KUH -// (0x_cFFD <= code && code <= 0x_d017) || // Lo [27] HANGUL SYLLABLE KWEOG..HANGUL SYLLABLE KWEOH -// (0x_d019 <= code && code <= 0x_d033) || // Lo [27] HANGUL SYLLABLE KWEG..HANGUL SYLLABLE KWEH -// (0x_d035 <= code && code <= 0x_d04F) || // Lo [27] HANGUL SYLLABLE KWIG..HANGUL SYLLABLE KWIH -// (0x_d051 <= code && code <= 0x_d06B) || // Lo [27] HANGUL SYLLABLE KYUG..HANGUL SYLLABLE KYUH -// (0x_d06D <= code && code <= 0x_d087) || // Lo [27] HANGUL SYLLABLE KEUG..HANGUL SYLLABLE KEUH -// (0x_d089 <= code && code <= 0x_d0A3) || // Lo [27] HANGUL SYLLABLE KYIG..HANGUL SYLLABLE KYIH -// (0x_d0A5 <= code && code <= 0x_d0BF) || // Lo [27] HANGUL SYLLABLE KIG..HANGUL SYLLABLE KIH -// (0x_d0C1 <= code && code <= 0x_d0DB) || // Lo [27] HANGUL SYLLABLE TAG..HANGUL SYLLABLE TAH -// (0x_d0DD <= code && code <= 0x_d0F7) || // Lo [27] HANGUL SYLLABLE TAEG..HANGUL SYLLABLE TAEH -// (0x_d0F9 <= code && code <= 0x_d113) || // Lo [27] HANGUL SYLLABLE TYAG..HANGUL SYLLABLE TYAH -// (0x_d115 <= code && code <= 0x_d12F) || // Lo [27] HANGUL SYLLABLE TYAEG..HANGUL SYLLABLE TYAEH -// (0x_d131 <= code && code <= 0x_d14B) || // Lo [27] HANGUL SYLLABLE TEOG..HANGUL SYLLABLE TEOH -// (0x_d14D <= code && code <= 0x_d167) || // Lo [27] HANGUL SYLLABLE TEG..HANGUL SYLLABLE TEH -// (0x_d169 <= code && code <= 0x_d183) || // Lo [27] HANGUL SYLLABLE TYEOG..HANGUL SYLLABLE TYEOH -// (0x_d185 <= code && code <= 0x_d19F) || // Lo [27] HANGUL SYLLABLE TYEG..HANGUL SYLLABLE TYEH -// (0x_d1A1 <= code && code <= 0x_d1BB) || // Lo [27] HANGUL SYLLABLE TOG..HANGUL SYLLABLE TOH -// (0x_d1BD <= code && code <= 0x_d1D7) || // Lo [27] HANGUL SYLLABLE TWAG..HANGUL SYLLABLE TWAH -// (0x_d1D9 <= code && code <= 0x_d1F3) || // Lo [27] HANGUL SYLLABLE TWAEG..HANGUL SYLLABLE TWAEH -// (0x_d1F5 <= code && code <= 0x_d20F) || // Lo [27] HANGUL SYLLABLE TOEG..HANGUL SYLLABLE TOEH -// (0x_d211 <= code && code <= 0x_d22B) || // Lo [27] HANGUL SYLLABLE TYOG..HANGUL SYLLABLE TYOH -// (0x_d22D <= code && code <= 0x_d247) || // Lo [27] HANGUL SYLLABLE TUG..HANGUL SYLLABLE TUH -// (0x_d249 <= code && code <= 0x_d263) || // Lo [27] HANGUL SYLLABLE TWEOG..HANGUL SYLLABLE TWEOH -// (0x_d265 <= code && code <= 0x_d27F) || // Lo [27] HANGUL SYLLABLE TWEG..HANGUL SYLLABLE TWEH -// (0x_d281 <= code && code <= 0x_d29B) || // Lo [27] HANGUL SYLLABLE TWIG..HANGUL SYLLABLE TWIH -// (0x_d29D <= code && code <= 0x_d2B7) || // Lo [27] HANGUL SYLLABLE TYUG..HANGUL SYLLABLE TYUH -// (0x_d2B9 <= code && code <= 0x_d2D3) || // Lo [27] HANGUL SYLLABLE TEUG..HANGUL SYLLABLE TEUH -// (0x_d2D5 <= code && code <= 0x_d2EF) || // Lo [27] HANGUL SYLLABLE TYIG..HANGUL SYLLABLE TYIH -// (0x_d2F1 <= code && code <= 0x_d30B) || // Lo [27] HANGUL SYLLABLE TIG..HANGUL SYLLABLE TIH -// (0x_d30D <= code && code <= 0x_d327) || // Lo [27] HANGUL SYLLABLE PAG..HANGUL SYLLABLE PAH -// (0x_d329 <= code && code <= 0x_d343) || // Lo [27] HANGUL SYLLABLE PAEG..HANGUL SYLLABLE PAEH -// (0x_d345 <= code && code <= 0x_d35F) || // Lo [27] HANGUL SYLLABLE PYAG..HANGUL SYLLABLE PYAH -// (0x_d361 <= code && code <= 0x_d37B) || // Lo [27] HANGUL SYLLABLE PYAEG..HANGUL SYLLABLE PYAEH -// (0x_d37D <= code && code <= 0x_d397) || // Lo [27] HANGUL SYLLABLE PEOG..HANGUL SYLLABLE PEOH -// (0x_d399 <= code && code <= 0x_d3B3) || // Lo [27] HANGUL SYLLABLE PEG..HANGUL SYLLABLE PEH -// (0x_d3B5 <= code && code <= 0x_d3CF) || // Lo [27] HANGUL SYLLABLE PYEOG..HANGUL SYLLABLE PYEOH -// (0x_d3D1 <= code && code <= 0x_d3EB) || // Lo [27] HANGUL SYLLABLE PYEG..HANGUL SYLLABLE PYEH -// (0x_d3ED <= code && code <= 0x_d407) || // Lo [27] HANGUL SYLLABLE POG..HANGUL SYLLABLE POH -// (0x_d409 <= code && code <= 0x_d423) || // Lo [27] HANGUL SYLLABLE PWAG..HANGUL SYLLABLE PWAH -// (0x_d425 <= code && code <= 0x_d43F) || // Lo [27] HANGUL SYLLABLE PWAEG..HANGUL SYLLABLE PWAEH -// (0x_d441 <= code && code <= 0x_d45B) || // Lo [27] HANGUL SYLLABLE POEG..HANGUL SYLLABLE POEH -// (0x_d45D <= code && code <= 0x_d477) || // Lo [27] HANGUL SYLLABLE PYOG..HANGUL SYLLABLE PYOH -// (0x_d479 <= code && code <= 0x_d493) || // Lo [27] HANGUL SYLLABLE PUG..HANGUL SYLLABLE PUH -// (0x_d495 <= code && code <= 0x_d4AF) || // Lo [27] HANGUL SYLLABLE PWEOG..HANGUL SYLLABLE PWEOH -// (0x_d4B1 <= code && code <= 0x_d4CB) || // Lo [27] HANGUL SYLLABLE PWEG..HANGUL SYLLABLE PWEH -// (0x_d4CD <= code && code <= 0x_d4E7) || // Lo [27] HANGUL SYLLABLE PWIG..HANGUL SYLLABLE PWIH -// (0x_d4E9 <= code && code <= 0x_d503) || // Lo [27] HANGUL SYLLABLE PYUG..HANGUL SYLLABLE PYUH -// (0x_d505 <= code && code <= 0x_d51F) || // Lo [27] HANGUL SYLLABLE PEUG..HANGUL SYLLABLE PEUH -// (0x_d521 <= code && code <= 0x_d53B) || // Lo [27] HANGUL SYLLABLE PYIG..HANGUL SYLLABLE PYIH -// (0x_d53D <= code && code <= 0x_d557) || // Lo [27] HANGUL SYLLABLE PIG..HANGUL SYLLABLE PIH -// (0x_d559 <= code && code <= 0x_d573) || // Lo [27] HANGUL SYLLABLE HAG..HANGUL SYLLABLE HAH -// (0x_d575 <= code && code <= 0x_d58F) || // Lo [27] HANGUL SYLLABLE HAEG..HANGUL SYLLABLE HAEH -// (0x_d591 <= code && code <= 0x_d5AB) || // Lo [27] HANGUL SYLLABLE HYAG..HANGUL SYLLABLE HYAH -// (0x_d5AD <= code && code <= 0x_d5C7) || // Lo [27] HANGUL SYLLABLE HYAEG..HANGUL SYLLABLE HYAEH -// (0x_d5C9 <= code && code <= 0x_d5E3) || // Lo [27] HANGUL SYLLABLE HEOG..HANGUL SYLLABLE HEOH -// (0x_d5E5 <= code && code <= 0x_d5FF) || // Lo [27] HANGUL SYLLABLE HEG..HANGUL SYLLABLE HEH -// (0x_d601 <= code && code <= 0x_d61B) || // Lo [27] HANGUL SYLLABLE HYEOG..HANGUL SYLLABLE HYEOH -// (0x_d61D <= code && code <= 0x_d637) || // Lo [27] HANGUL SYLLABLE HYEG..HANGUL SYLLABLE HYEH -// (0x_d639 <= code && code <= 0x_d653) || // Lo [27] HANGUL SYLLABLE HOG..HANGUL SYLLABLE HOH -// (0x_d655 <= code && code <= 0x_d66F) || // Lo [27] HANGUL SYLLABLE HWAG..HANGUL SYLLABLE HWAH -// (0x_d671 <= code && code <= 0x_d68B) || // Lo [27] HANGUL SYLLABLE HWAEG..HANGUL SYLLABLE HWAEH -// (0x_d68D <= code && code <= 0x_d6A7) || // Lo [27] HANGUL SYLLABLE HOEG..HANGUL SYLLABLE HOEH -// (0x_d6A9 <= code && code <= 0x_d6C3) || // Lo [27] HANGUL SYLLABLE HYOG..HANGUL SYLLABLE HYOH -// (0x_d6C5 <= code && code <= 0x_d6DF) || // Lo [27] HANGUL SYLLABLE HUG..HANGUL SYLLABLE HUH -// (0x_d6E1 <= code && code <= 0x_d6FB) || // Lo [27] HANGUL SYLLABLE HWEOG..HANGUL SYLLABLE HWEOH -// (0x_d6FD <= code && code <= 0x_d717) || // Lo [27] HANGUL SYLLABLE HWEG..HANGUL SYLLABLE HWEH -// (0x_d719 <= code && code <= 0x_d733) || // Lo [27] HANGUL SYLLABLE HWIG..HANGUL SYLLABLE HWIH -// (0x_d735 <= code && code <= 0x_d74F) || // Lo [27] HANGUL SYLLABLE HYUG..HANGUL SYLLABLE HYUH -// (0x_d751 <= code && code <= 0x_d76B) || // Lo [27] HANGUL SYLLABLE HEUG..HANGUL SYLLABLE HEUH -// (0x_d76D <= code && code <= 0x_d787) || // Lo [27] HANGUL SYLLABLE HYIG..HANGUL SYLLABLE HYIH -// (0x_d789 <= code && code <= 0x_d7A3) // Lo [27] HANGUL SYLLABLE HIG..HANGUL SYLLABLE HIH -// ){ +// (0x_aC01 <= code && code <= 0x_aC1B) || // Lo [27] HANGUL SYLLABLE +// GAG..HANGUL SYLLABLE GAH (0x_aC1D <= code && code <= 0x_aC37) || // Lo +// [27] HANGUL SYLLABLE GAEG..HANGUL SYLLABLE GAEH (0x_aC39 <= code && +// code <= 0x_aC53) || // Lo [27] HANGUL SYLLABLE GYAG..HANGUL SYLLABLE GYAH +// (0x_aC55 <= code && code <= 0x_aC6F) || // Lo [27] HANGUL SYLLABLE +// GYAEG..HANGUL SYLLABLE GYAEH (0x_aC71 <= code && code <= 0x_aC8B) || +// // Lo [27] HANGUL SYLLABLE GEOG..HANGUL SYLLABLE GEOH (0x_aC8D <= +// code && code <= 0x_aCA7) || // Lo [27] HANGUL SYLLABLE GEG..HANGUL SYLLABLE +// GEH (0x_aCA9 <= code && code <= 0x_aCC3) || // Lo [27] HANGUL +// SYLLABLE GYEOG..HANGUL SYLLABLE GYEOH (0x_aCC5 <= code && code <= +// 0x_aCDF) || // Lo [27] HANGUL SYLLABLE GYEG..HANGUL SYLLABLE GYEH +// (0x_aCE1 <= code && code <= 0x_aCFB) || // Lo [27] HANGUL SYLLABLE +// GOG..HANGUL SYLLABLE GOH (0x_aCFD <= code && code <= 0x_aD17) || // Lo +// [27] HANGUL SYLLABLE GWAG..HANGUL SYLLABLE GWAH (0x_aD19 <= code && +// code <= 0x_aD33) || // Lo [27] HANGUL SYLLABLE GWAEG..HANGUL SYLLABLE GWAEH +// (0x_aD35 <= code && code <= 0x_aD4F) || // Lo [27] HANGUL SYLLABLE +// GOEG..HANGUL SYLLABLE GOEH (0x_aD51 <= code && code <= 0x_aD6B) || // +// Lo [27] HANGUL SYLLABLE GYOG..HANGUL SYLLABLE GYOH (0x_aD6D <= code +// && code <= 0x_aD87) || // Lo [27] HANGUL SYLLABLE GUG..HANGUL SYLLABLE GUH +// (0x_aD89 <= code && code <= 0x_aDA3) || // Lo [27] HANGUL SYLLABLE +// GWEOG..HANGUL SYLLABLE GWEOH (0x_aDA5 <= code && code <= 0x_aDBF) || +// // Lo [27] HANGUL SYLLABLE GWEG..HANGUL SYLLABLE GWEH (0x_aDC1 <= +// code && code <= 0x_aDDB) || // Lo [27] HANGUL SYLLABLE GWIG..HANGUL SYLLABLE +// GWIH (0x_aDDD <= code && code <= 0x_aDF7) || // Lo [27] HANGUL +// SYLLABLE GYUG..HANGUL SYLLABLE GYUH (0x_aDF9 <= code && code <= +// 0x_aE13) || // Lo [27] HANGUL SYLLABLE GEUG..HANGUL SYLLABLE GEUH +// (0x_aE15 <= code && code <= 0x_aE2F) || // Lo [27] HANGUL SYLLABLE +// GYIG..HANGUL SYLLABLE GYIH (0x_aE31 <= code && code <= 0x_aE4B) || // +// Lo [27] HANGUL SYLLABLE GIG..HANGUL SYLLABLE GIH (0x_aE4D <= code && +// code <= 0x_aE67) || // Lo [27] HANGUL SYLLABLE GGAG..HANGUL SYLLABLE GGAH +// (0x_aE69 <= code && code <= 0x_aE83) || // Lo [27] HANGUL SYLLABLE +// GGAEG..HANGUL SYLLABLE GGAEH (0x_aE85 <= code && code <= 0x_aE9F) || +// // Lo [27] HANGUL SYLLABLE GGYAG..HANGUL SYLLABLE GGYAH (0x_aEA1 <= +// code && code <= 0x_aEBB) || // Lo [27] HANGUL SYLLABLE GGYAEG..HANGUL +// SYLLABLE GGYAEH (0x_aEBD <= code && code <= 0x_aED7) || // Lo [27] +// HANGUL SYLLABLE GGEOG..HANGUL SYLLABLE GGEOH (0x_aED9 <= code && code +// <= 0x_aEF3) || // Lo [27] HANGUL SYLLABLE GGEG..HANGUL SYLLABLE GGEH +// (0x_aEF5 <= code && code <= 0x_aF0F) || // Lo [27] HANGUL SYLLABLE +// GGYEOG..HANGUL SYLLABLE GGYEOH (0x_aF11 <= code && code <= 0x_aF2B) || +// // Lo [27] HANGUL SYLLABLE GGYEG..HANGUL SYLLABLE GGYEH (0x_aF2D <= +// code && code <= 0x_aF47) || // Lo [27] HANGUL SYLLABLE GGOG..HANGUL SYLLABLE +// GGOH (0x_aF49 <= code && code <= 0x_aF63) || // Lo [27] HANGUL +// SYLLABLE GGWAG..HANGUL SYLLABLE GGWAH (0x_aF65 <= code && code <= +// 0x_aF7F) || // Lo [27] HANGUL SYLLABLE GGWAEG..HANGUL SYLLABLE GGWAEH +// (0x_aF81 <= code && code <= 0x_aF9B) || // Lo [27] HANGUL SYLLABLE +// GGOEG..HANGUL SYLLABLE GGOEH (0x_aF9D <= code && code <= 0x_aFB7) || +// // Lo [27] HANGUL SYLLABLE GGYOG..HANGUL SYLLABLE GGYOH (0x_aFB9 <= +// code && code <= 0x_aFD3) || // Lo [27] HANGUL SYLLABLE GGUG..HANGUL SYLLABLE +// GGUH (0x_aFD5 <= code && code <= 0x_aFEF) || // Lo [27] HANGUL +// SYLLABLE GGWEOG..HANGUL SYLLABLE GGWEOH (0x_aFF1 <= code && code <= +// 0x_b00B) || // Lo [27] HANGUL SYLLABLE GGWEG..HANGUL SYLLABLE GGWEH +// (0x_b00D <= code && code <= 0x_b027) || // Lo [27] HANGUL SYLLABLE +// GGWIG..HANGUL SYLLABLE GGWIH (0x_b029 <= code && code <= 0x_b043) || +// // Lo [27] HANGUL SYLLABLE GGYUG..HANGUL SYLLABLE GGYUH (0x_b045 <= +// code && code <= 0x_b05F) || // Lo [27] HANGUL SYLLABLE GGEUG..HANGUL +// SYLLABLE GGEUH (0x_b061 <= code && code <= 0x_b07B) || // Lo [27] +// HANGUL SYLLABLE GGYIG..HANGUL SYLLABLE GGYIH (0x_b07D <= code && code +// <= 0x_b097) || // Lo [27] HANGUL SYLLABLE GGIG..HANGUL SYLLABLE GGIH +// (0x_b099 <= code && code <= 0x_b0B3) || // Lo [27] HANGUL SYLLABLE +// NAG..HANGUL SYLLABLE NAH (0x_b0B5 <= code && code <= 0x_b0CF) || // Lo +// [27] HANGUL SYLLABLE NAEG..HANGUL SYLLABLE NAEH (0x_b0D1 <= code && +// code <= 0x_b0EB) || // Lo [27] HANGUL SYLLABLE NYAG..HANGUL SYLLABLE NYAH +// (0x_b0ED <= code && code <= 0x_b107) || // Lo [27] HANGUL SYLLABLE +// NYAEG..HANGUL SYLLABLE NYAEH (0x_b109 <= code && code <= 0x_b123) || +// // Lo [27] HANGUL SYLLABLE NEOG..HANGUL SYLLABLE NEOH (0x_b125 <= +// code && code <= 0x_b13F) || // Lo [27] HANGUL SYLLABLE NEG..HANGUL SYLLABLE +// NEH (0x_b141 <= code && code <= 0x_b15B) || // Lo [27] HANGUL +// SYLLABLE NYEOG..HANGUL SYLLABLE NYEOH (0x_b15D <= code && code <= +// 0x_b177) || // Lo [27] HANGUL SYLLABLE NYEG..HANGUL SYLLABLE NYEH +// (0x_b179 <= code && code <= 0x_b193) || // Lo [27] HANGUL SYLLABLE +// NOG..HANGUL SYLLABLE NOH (0x_b195 <= code && code <= 0x_b1AF) || // Lo +// [27] HANGUL SYLLABLE NWAG..HANGUL SYLLABLE NWAH (0x_b1B1 <= code && +// code <= 0x_b1CB) || // Lo [27] HANGUL SYLLABLE NWAEG..HANGUL SYLLABLE NWAEH +// (0x_b1CD <= code && code <= 0x_b1E7) || // Lo [27] HANGUL SYLLABLE +// NOEG..HANGUL SYLLABLE NOEH (0x_b1E9 <= code && code <= 0x_b203) || // +// Lo [27] HANGUL SYLLABLE NYOG..HANGUL SYLLABLE NYOH (0x_b205 <= code +// && code <= 0x_b21F) || // Lo [27] HANGUL SYLLABLE NUG..HANGUL SYLLABLE NUH +// (0x_b221 <= code && code <= 0x_b23B) || // Lo [27] HANGUL SYLLABLE +// NWEOG..HANGUL SYLLABLE NWEOH (0x_b23D <= code && code <= 0x_b257) || +// // Lo [27] HANGUL SYLLABLE NWEG..HANGUL SYLLABLE NWEH (0x_b259 <= +// code && code <= 0x_b273) || // Lo [27] HANGUL SYLLABLE NWIG..HANGUL SYLLABLE +// NWIH (0x_b275 <= code && code <= 0x_b28F) || // Lo [27] HANGUL +// SYLLABLE NYUG..HANGUL SYLLABLE NYUH (0x_b291 <= code && code <= +// 0x_b2AB) || // Lo [27] HANGUL SYLLABLE NEUG..HANGUL SYLLABLE NEUH +// (0x_b2AD <= code && code <= 0x_b2C7) || // Lo [27] HANGUL SYLLABLE +// NYIG..HANGUL SYLLABLE NYIH (0x_b2C9 <= code && code <= 0x_b2E3) || // +// Lo [27] HANGUL SYLLABLE NIG..HANGUL SYLLABLE NIH (0x_b2E5 <= code && +// code <= 0x_b2FF) || // Lo [27] HANGUL SYLLABLE DAG..HANGUL SYLLABLE DAH +// (0x_b301 <= code && code <= 0x_b31B) || // Lo [27] HANGUL SYLLABLE +// DAEG..HANGUL SYLLABLE DAEH (0x_b31D <= code && code <= 0x_b337) || // +// Lo [27] HANGUL SYLLABLE DYAG..HANGUL SYLLABLE DYAH (0x_b339 <= code +// && code <= 0x_b353) || // Lo [27] HANGUL SYLLABLE DYAEG..HANGUL SYLLABLE +// DYAEH (0x_b355 <= code && code <= 0x_b36F) || // Lo [27] HANGUL +// SYLLABLE DEOG..HANGUL SYLLABLE DEOH (0x_b371 <= code && code <= +// 0x_b38B) || // Lo [27] HANGUL SYLLABLE DEG..HANGUL SYLLABLE DEH +// (0x_b38D <= code && code <= 0x_b3A7) || // Lo [27] HANGUL SYLLABLE +// DYEOG..HANGUL SYLLABLE DYEOH (0x_b3A9 <= code && code <= 0x_b3C3) || +// // Lo [27] HANGUL SYLLABLE DYEG..HANGUL SYLLABLE DYEH (0x_b3C5 <= +// code && code <= 0x_b3DF) || // Lo [27] HANGUL SYLLABLE DOG..HANGUL SYLLABLE +// DOH (0x_b3E1 <= code && code <= 0x_b3FB) || // Lo [27] HANGUL +// SYLLABLE DWAG..HANGUL SYLLABLE DWAH (0x_b3FD <= code && code <= +// 0x_b417) || // Lo [27] HANGUL SYLLABLE DWAEG..HANGUL SYLLABLE DWAEH +// (0x_b419 <= code && code <= 0x_b433) || // Lo [27] HANGUL SYLLABLE +// DOEG..HANGUL SYLLABLE DOEH (0x_b435 <= code && code <= 0x_b44F) || // +// Lo [27] HANGUL SYLLABLE DYOG..HANGUL SYLLABLE DYOH (0x_b451 <= code +// && code <= 0x_b46B) || // Lo [27] HANGUL SYLLABLE DUG..HANGUL SYLLABLE DUH +// (0x_b46D <= code && code <= 0x_b487) || // Lo [27] HANGUL SYLLABLE +// DWEOG..HANGUL SYLLABLE DWEOH (0x_b489 <= code && code <= 0x_b4A3) || +// // Lo [27] HANGUL SYLLABLE DWEG..HANGUL SYLLABLE DWEH (0x_b4A5 <= +// code && code <= 0x_b4BF) || // Lo [27] HANGUL SYLLABLE DWIG..HANGUL SYLLABLE +// DWIH (0x_b4C1 <= code && code <= 0x_b4DB) || // Lo [27] HANGUL +// SYLLABLE DYUG..HANGUL SYLLABLE DYUH (0x_b4DD <= code && code <= +// 0x_b4F7) || // Lo [27] HANGUL SYLLABLE DEUG..HANGUL SYLLABLE DEUH +// (0x_b4F9 <= code && code <= 0x_b513) || // Lo [27] HANGUL SYLLABLE +// DYIG..HANGUL SYLLABLE DYIH (0x_b515 <= code && code <= 0x_b52F) || // +// Lo [27] HANGUL SYLLABLE DIG..HANGUL SYLLABLE DIH (0x_b531 <= code && +// code <= 0x_b54B) || // Lo [27] HANGUL SYLLABLE DDAG..HANGUL SYLLABLE DDAH +// (0x_b54D <= code && code <= 0x_b567) || // Lo [27] HANGUL SYLLABLE +// DDAEG..HANGUL SYLLABLE DDAEH (0x_b569 <= code && code <= 0x_b583) || +// // Lo [27] HANGUL SYLLABLE DDYAG..HANGUL SYLLABLE DDYAH (0x_b585 <= +// code && code <= 0x_b59F) || // Lo [27] HANGUL SYLLABLE DDYAEG..HANGUL +// SYLLABLE DDYAEH (0x_b5A1 <= code && code <= 0x_b5BB) || // Lo [27] +// HANGUL SYLLABLE DDEOG..HANGUL SYLLABLE DDEOH (0x_b5BD <= code && code +// <= 0x_b5D7) || // Lo [27] HANGUL SYLLABLE DDEG..HANGUL SYLLABLE DDEH +// (0x_b5D9 <= code && code <= 0x_b5F3) || // Lo [27] HANGUL SYLLABLE +// DDYEOG..HANGUL SYLLABLE DDYEOH (0x_b5F5 <= code && code <= 0x_b60F) || +// // Lo [27] HANGUL SYLLABLE DDYEG..HANGUL SYLLABLE DDYEH (0x_b611 <= +// code && code <= 0x_b62B) || // Lo [27] HANGUL SYLLABLE DDOG..HANGUL SYLLABLE +// DDOH (0x_b62D <= code && code <= 0x_b647) || // Lo [27] HANGUL +// SYLLABLE DDWAG..HANGUL SYLLABLE DDWAH (0x_b649 <= code && code <= +// 0x_b663) || // Lo [27] HANGUL SYLLABLE DDWAEG..HANGUL SYLLABLE DDWAEH +// (0x_b665 <= code && code <= 0x_b67F) || // Lo [27] HANGUL SYLLABLE +// DDOEG..HANGUL SYLLABLE DDOEH (0x_b681 <= code && code <= 0x_b69B) || +// // Lo [27] HANGUL SYLLABLE DDYOG..HANGUL SYLLABLE DDYOH (0x_b69D <= +// code && code <= 0x_b6B7) || // Lo [27] HANGUL SYLLABLE DDUG..HANGUL SYLLABLE +// DDUH (0x_b6B9 <= code && code <= 0x_b6D3) || // Lo [27] HANGUL +// SYLLABLE DDWEOG..HANGUL SYLLABLE DDWEOH (0x_b6D5 <= code && code <= +// 0x_b6EF) || // Lo [27] HANGUL SYLLABLE DDWEG..HANGUL SYLLABLE DDWEH +// (0x_b6F1 <= code && code <= 0x_b70B) || // Lo [27] HANGUL SYLLABLE +// DDWIG..HANGUL SYLLABLE DDWIH (0x_b70D <= code && code <= 0x_b727) || +// // Lo [27] HANGUL SYLLABLE DDYUG..HANGUL SYLLABLE DDYUH (0x_b729 <= +// code && code <= 0x_b743) || // Lo [27] HANGUL SYLLABLE DDEUG..HANGUL +// SYLLABLE DDEUH (0x_b745 <= code && code <= 0x_b75F) || // Lo [27] +// HANGUL SYLLABLE DDYIG..HANGUL SYLLABLE DDYIH (0x_b761 <= code && code +// <= 0x_b77B) || // Lo [27] HANGUL SYLLABLE DDIG..HANGUL SYLLABLE DDIH +// (0x_b77D <= code && code <= 0x_b797) || // Lo [27] HANGUL SYLLABLE +// RAG..HANGUL SYLLABLE RAH (0x_b799 <= code && code <= 0x_b7B3) || // Lo +// [27] HANGUL SYLLABLE RAEG..HANGUL SYLLABLE RAEH (0x_b7B5 <= code && +// code <= 0x_b7CF) || // Lo [27] HANGUL SYLLABLE RYAG..HANGUL SYLLABLE RYAH +// (0x_b7D1 <= code && code <= 0x_b7EB) || // Lo [27] HANGUL SYLLABLE +// RYAEG..HANGUL SYLLABLE RYAEH (0x_b7ED <= code && code <= 0x_b807) || +// // Lo [27] HANGUL SYLLABLE REOG..HANGUL SYLLABLE REOH (0x_b809 <= +// code && code <= 0x_b823) || // Lo [27] HANGUL SYLLABLE REG..HANGUL SYLLABLE +// REH (0x_b825 <= code && code <= 0x_b83F) || // Lo [27] HANGUL +// SYLLABLE RYEOG..HANGUL SYLLABLE RYEOH (0x_b841 <= code && code <= +// 0x_b85B) || // Lo [27] HANGUL SYLLABLE RYEG..HANGUL SYLLABLE RYEH +// (0x_b85D <= code && code <= 0x_b877) || // Lo [27] HANGUL SYLLABLE +// ROG..HANGUL SYLLABLE ROH (0x_b879 <= code && code <= 0x_b893) || // Lo +// [27] HANGUL SYLLABLE RWAG..HANGUL SYLLABLE RWAH (0x_b895 <= code && +// code <= 0x_b8AF) || // Lo [27] HANGUL SYLLABLE RWAEG..HANGUL SYLLABLE RWAEH +// (0x_b8B1 <= code && code <= 0x_b8CB) || // Lo [27] HANGUL SYLLABLE +// ROEG..HANGUL SYLLABLE ROEH (0x_b8CD <= code && code <= 0x_b8E7) || // +// Lo [27] HANGUL SYLLABLE RYOG..HANGUL SYLLABLE RYOH (0x_b8E9 <= code +// && code <= 0x_b903) || // Lo [27] HANGUL SYLLABLE RUG..HANGUL SYLLABLE RUH +// (0x_b905 <= code && code <= 0x_b91F) || // Lo [27] HANGUL SYLLABLE +// RWEOG..HANGUL SYLLABLE RWEOH (0x_b921 <= code && code <= 0x_b93B) || +// // Lo [27] HANGUL SYLLABLE RWEG..HANGUL SYLLABLE RWEH (0x_b93D <= +// code && code <= 0x_b957) || // Lo [27] HANGUL SYLLABLE RWIG..HANGUL SYLLABLE +// RWIH (0x_b959 <= code && code <= 0x_b973) || // Lo [27] HANGUL +// SYLLABLE RYUG..HANGUL SYLLABLE RYUH (0x_b975 <= code && code <= +// 0x_b98F) || // Lo [27] HANGUL SYLLABLE REUG..HANGUL SYLLABLE REUH +// (0x_b991 <= code && code <= 0x_b9AB) || // Lo [27] HANGUL SYLLABLE +// RYIG..HANGUL SYLLABLE RYIH (0x_b9AD <= code && code <= 0x_b9C7) || // +// Lo [27] HANGUL SYLLABLE RIG..HANGUL SYLLABLE RIH (0x_b9C9 <= code && +// code <= 0x_b9E3) || // Lo [27] HANGUL SYLLABLE MAG..HANGUL SYLLABLE MAH +// (0x_b9E5 <= code && code <= 0x_b9FF) || // Lo [27] HANGUL SYLLABLE +// MAEG..HANGUL SYLLABLE MAEH (0x_bA01 <= code && code <= 0x_bA1B) || // +// Lo [27] HANGUL SYLLABLE MYAG..HANGUL SYLLABLE MYAH (0x_bA1D <= code +// && code <= 0x_bA37) || // Lo [27] HANGUL SYLLABLE MYAEG..HANGUL SYLLABLE +// MYAEH (0x_bA39 <= code && code <= 0x_bA53) || // Lo [27] HANGUL +// SYLLABLE MEOG..HANGUL SYLLABLE MEOH (0x_bA55 <= code && code <= +// 0x_bA6F) || // Lo [27] HANGUL SYLLABLE MEG..HANGUL SYLLABLE MEH +// (0x_bA71 <= code && code <= 0x_bA8B) || // Lo [27] HANGUL SYLLABLE +// MYEOG..HANGUL SYLLABLE MYEOH (0x_bA8D <= code && code <= 0x_bAA7) || +// // Lo [27] HANGUL SYLLABLE MYEG..HANGUL SYLLABLE MYEH (0x_bAA9 <= +// code && code <= 0x_bAC3) || // Lo [27] HANGUL SYLLABLE MOG..HANGUL SYLLABLE +// MOH (0x_bAC5 <= code && code <= 0x_bADF) || // Lo [27] HANGUL +// SYLLABLE MWAG..HANGUL SYLLABLE MWAH (0x_bAE1 <= code && code <= +// 0x_bAFB) || // Lo [27] HANGUL SYLLABLE MWAEG..HANGUL SYLLABLE MWAEH +// (0x_bAFD <= code && code <= 0x_bB17) || // Lo [27] HANGUL SYLLABLE +// MOEG..HANGUL SYLLABLE MOEH (0x_bB19 <= code && code <= 0x_bB33) || // +// Lo [27] HANGUL SYLLABLE MYOG..HANGUL SYLLABLE MYOH (0x_bB35 <= code +// && code <= 0x_bB4F) || // Lo [27] HANGUL SYLLABLE MUG..HANGUL SYLLABLE MUH +// (0x_bB51 <= code && code <= 0x_bB6B) || // Lo [27] HANGUL SYLLABLE +// MWEOG..HANGUL SYLLABLE MWEOH (0x_bB6D <= code && code <= 0x_bB87) || +// // Lo [27] HANGUL SYLLABLE MWEG..HANGUL SYLLABLE MWEH (0x_bB89 <= +// code && code <= 0x_bBA3) || // Lo [27] HANGUL SYLLABLE MWIG..HANGUL SYLLABLE +// MWIH (0x_bBA5 <= code && code <= 0x_bBBF) || // Lo [27] HANGUL +// SYLLABLE MYUG..HANGUL SYLLABLE MYUH (0x_bBC1 <= code && code <= +// 0x_bBDB) || // Lo [27] HANGUL SYLLABLE MEUG..HANGUL SYLLABLE MEUH +// (0x_bBDD <= code && code <= 0x_bBF7) || // Lo [27] HANGUL SYLLABLE +// MYIG..HANGUL SYLLABLE MYIH (0x_bBF9 <= code && code <= 0x_bC13) || // +// Lo [27] HANGUL SYLLABLE MIG..HANGUL SYLLABLE MIH (0x_bC15 <= code && +// code <= 0x_bC2F) || // Lo [27] HANGUL SYLLABLE BAG..HANGUL SYLLABLE BAH +// (0x_bC31 <= code && code <= 0x_bC4B) || // Lo [27] HANGUL SYLLABLE +// BAEG..HANGUL SYLLABLE BAEH (0x_bC4D <= code && code <= 0x_bC67) || // +// Lo [27] HANGUL SYLLABLE BYAG..HANGUL SYLLABLE BYAH (0x_bC69 <= code +// && code <= 0x_bC83) || // Lo [27] HANGUL SYLLABLE BYAEG..HANGUL SYLLABLE +// BYAEH (0x_bC85 <= code && code <= 0x_bC9F) || // Lo [27] HANGUL +// SYLLABLE BEOG..HANGUL SYLLABLE BEOH (0x_bCA1 <= code && code <= +// 0x_bCBB) || // Lo [27] HANGUL SYLLABLE BEG..HANGUL SYLLABLE BEH +// (0x_bCBD <= code && code <= 0x_bCD7) || // Lo [27] HANGUL SYLLABLE +// BYEOG..HANGUL SYLLABLE BYEOH (0x_bCD9 <= code && code <= 0x_bCF3) || +// // Lo [27] HANGUL SYLLABLE BYEG..HANGUL SYLLABLE BYEH (0x_bCF5 <= +// code && code <= 0x_bD0F) || // Lo [27] HANGUL SYLLABLE BOG..HANGUL SYLLABLE +// BOH (0x_bD11 <= code && code <= 0x_bD2B) || // Lo [27] HANGUL +// SYLLABLE BWAG..HANGUL SYLLABLE BWAH (0x_bD2D <= code && code <= +// 0x_bD47) || // Lo [27] HANGUL SYLLABLE BWAEG..HANGUL SYLLABLE BWAEH +// (0x_bD49 <= code && code <= 0x_bD63) || // Lo [27] HANGUL SYLLABLE +// BOEG..HANGUL SYLLABLE BOEH (0x_bD65 <= code && code <= 0x_bD7F) || // +// Lo [27] HANGUL SYLLABLE BYOG..HANGUL SYLLABLE BYOH (0x_bD81 <= code +// && code <= 0x_bD9B) || // Lo [27] HANGUL SYLLABLE BUG..HANGUL SYLLABLE BUH +// (0x_bD9D <= code && code <= 0x_bDB7) || // Lo [27] HANGUL SYLLABLE +// BWEOG..HANGUL SYLLABLE BWEOH (0x_bDB9 <= code && code <= 0x_bDD3) || +// // Lo [27] HANGUL SYLLABLE BWEG..HANGUL SYLLABLE BWEH (0x_bDD5 <= +// code && code <= 0x_bDEF) || // Lo [27] HANGUL SYLLABLE BWIG..HANGUL SYLLABLE +// BWIH (0x_bDF1 <= code && code <= 0x_bE0B) || // Lo [27] HANGUL +// SYLLABLE BYUG..HANGUL SYLLABLE BYUH (0x_bE0D <= code && code <= +// 0x_bE27) || // Lo [27] HANGUL SYLLABLE BEUG..HANGUL SYLLABLE BEUH +// (0x_bE29 <= code && code <= 0x_bE43) || // Lo [27] HANGUL SYLLABLE +// BYIG..HANGUL SYLLABLE BYIH (0x_bE45 <= code && code <= 0x_bE5F) || // +// Lo [27] HANGUL SYLLABLE BIG..HANGUL SYLLABLE BIH (0x_bE61 <= code && +// code <= 0x_bE7B) || // Lo [27] HANGUL SYLLABLE BBAG..HANGUL SYLLABLE BBAH +// (0x_bE7D <= code && code <= 0x_bE97) || // Lo [27] HANGUL SYLLABLE +// BBAEG..HANGUL SYLLABLE BBAEH (0x_bE99 <= code && code <= 0x_bEB3) || +// // Lo [27] HANGUL SYLLABLE BBYAG..HANGUL SYLLABLE BBYAH (0x_bEB5 <= +// code && code <= 0x_bECF) || // Lo [27] HANGUL SYLLABLE BBYAEG..HANGUL +// SYLLABLE BBYAEH (0x_bED1 <= code && code <= 0x_bEEB) || // Lo [27] +// HANGUL SYLLABLE BBEOG..HANGUL SYLLABLE BBEOH (0x_bEED <= code && code +// <= 0x_bF07) || // Lo [27] HANGUL SYLLABLE BBEG..HANGUL SYLLABLE BBEH +// (0x_bF09 <= code && code <= 0x_bF23) || // Lo [27] HANGUL SYLLABLE +// BBYEOG..HANGUL SYLLABLE BBYEOH (0x_bF25 <= code && code <= 0x_bF3F) || +// // Lo [27] HANGUL SYLLABLE BBYEG..HANGUL SYLLABLE BBYEH (0x_bF41 <= +// code && code <= 0x_bF5B) || // Lo [27] HANGUL SYLLABLE BBOG..HANGUL SYLLABLE +// BBOH (0x_bF5D <= code && code <= 0x_bF77) || // Lo [27] HANGUL +// SYLLABLE BBWAG..HANGUL SYLLABLE BBWAH (0x_bF79 <= code && code <= +// 0x_bF93) || // Lo [27] HANGUL SYLLABLE BBWAEG..HANGUL SYLLABLE BBWAEH +// (0x_bF95 <= code && code <= 0x_bFAF) || // Lo [27] HANGUL SYLLABLE +// BBOEG..HANGUL SYLLABLE BBOEH (0x_bFB1 <= code && code <= 0x_bFCB) || +// // Lo [27] HANGUL SYLLABLE BBYOG..HANGUL SYLLABLE BBYOH (0x_bFCD <= +// code && code <= 0x_bFE7) || // Lo [27] HANGUL SYLLABLE BBUG..HANGUL SYLLABLE +// BBUH (0x_bFE9 <= code && code <= 0x_c003) || // Lo [27] HANGUL +// SYLLABLE BBWEOG..HANGUL SYLLABLE BBWEOH (0x_c005 <= code && code <= +// 0x_c01F) || // Lo [27] HANGUL SYLLABLE BBWEG..HANGUL SYLLABLE BBWEH +// (0x_c021 <= code && code <= 0x_c03B) || // Lo [27] HANGUL SYLLABLE +// BBWIG..HANGUL SYLLABLE BBWIH (0x_c03D <= code && code <= 0x_c057) || +// // Lo [27] HANGUL SYLLABLE BBYUG..HANGUL SYLLABLE BBYUH (0x_c059 <= +// code && code <= 0x_c073) || // Lo [27] HANGUL SYLLABLE BBEUG..HANGUL +// SYLLABLE BBEUH (0x_c075 <= code && code <= 0x_c08F) || // Lo [27] +// HANGUL SYLLABLE BBYIG..HANGUL SYLLABLE BBYIH (0x_c091 <= code && code +// <= 0x_c0AB) || // Lo [27] HANGUL SYLLABLE BBIG..HANGUL SYLLABLE BBIH +// (0x_c0AD <= code && code <= 0x_c0C7) || // Lo [27] HANGUL SYLLABLE +// SAG..HANGUL SYLLABLE SAH (0x_c0C9 <= code && code <= 0x_c0E3) || // Lo +// [27] HANGUL SYLLABLE SAEG..HANGUL SYLLABLE SAEH (0x_c0E5 <= code && +// code <= 0x_c0FF) || // Lo [27] HANGUL SYLLABLE SYAG..HANGUL SYLLABLE SYAH +// (0x_c101 <= code && code <= 0x_c11B) || // Lo [27] HANGUL SYLLABLE +// SYAEG..HANGUL SYLLABLE SYAEH (0x_c11D <= code && code <= 0x_c137) || +// // Lo [27] HANGUL SYLLABLE SEOG..HANGUL SYLLABLE SEOH (0x_c139 <= +// code && code <= 0x_c153) || // Lo [27] HANGUL SYLLABLE SEG..HANGUL SYLLABLE +// SEH (0x_c155 <= code && code <= 0x_c16F) || // Lo [27] HANGUL +// SYLLABLE SYEOG..HANGUL SYLLABLE SYEOH (0x_c171 <= code && code <= +// 0x_c18B) || // Lo [27] HANGUL SYLLABLE SYEG..HANGUL SYLLABLE SYEH +// (0x_c18D <= code && code <= 0x_c1A7) || // Lo [27] HANGUL SYLLABLE +// SOG..HANGUL SYLLABLE SOH (0x_c1A9 <= code && code <= 0x_c1C3) || // Lo +// [27] HANGUL SYLLABLE SWAG..HANGUL SYLLABLE SWAH (0x_c1C5 <= code && +// code <= 0x_c1DF) || // Lo [27] HANGUL SYLLABLE SWAEG..HANGUL SYLLABLE SWAEH +// (0x_c1E1 <= code && code <= 0x_c1FB) || // Lo [27] HANGUL SYLLABLE +// SOEG..HANGUL SYLLABLE SOEH (0x_c1FD <= code && code <= 0x_c217) || // +// Lo [27] HANGUL SYLLABLE SYOG..HANGUL SYLLABLE SYOH (0x_c219 <= code +// && code <= 0x_c233) || // Lo [27] HANGUL SYLLABLE SUG..HANGUL SYLLABLE SUH +// (0x_c235 <= code && code <= 0x_c24F) || // Lo [27] HANGUL SYLLABLE +// SWEOG..HANGUL SYLLABLE SWEOH (0x_c251 <= code && code <= 0x_c26B) || +// // Lo [27] HANGUL SYLLABLE SWEG..HANGUL SYLLABLE SWEH (0x_c26D <= +// code && code <= 0x_c287) || // Lo [27] HANGUL SYLLABLE SWIG..HANGUL SYLLABLE +// SWIH (0x_c289 <= code && code <= 0x_c2A3) || // Lo [27] HANGUL +// SYLLABLE SYUG..HANGUL SYLLABLE SYUH (0x_c2A5 <= code && code <= +// 0x_c2BF) || // Lo [27] HANGUL SYLLABLE SEUG..HANGUL SYLLABLE SEUH +// (0x_c2C1 <= code && code <= 0x_c2DB) || // Lo [27] HANGUL SYLLABLE +// SYIG..HANGUL SYLLABLE SYIH (0x_c2DD <= code && code <= 0x_c2F7) || // +// Lo [27] HANGUL SYLLABLE SIG..HANGUL SYLLABLE SIH (0x_c2F9 <= code && +// code <= 0x_c313) || // Lo [27] HANGUL SYLLABLE SSAG..HANGUL SYLLABLE SSAH +// (0x_c315 <= code && code <= 0x_c32F) || // Lo [27] HANGUL SYLLABLE +// SSAEG..HANGUL SYLLABLE SSAEH (0x_c331 <= code && code <= 0x_c34B) || +// // Lo [27] HANGUL SYLLABLE SSYAG..HANGUL SYLLABLE SSYAH (0x_c34D <= +// code && code <= 0x_c367) || // Lo [27] HANGUL SYLLABLE SSYAEG..HANGUL +// SYLLABLE SSYAEH (0x_c369 <= code && code <= 0x_c383) || // Lo [27] +// HANGUL SYLLABLE SSEOG..HANGUL SYLLABLE SSEOH (0x_c385 <= code && code +// <= 0x_c39F) || // Lo [27] HANGUL SYLLABLE SSEG..HANGUL SYLLABLE SSEH +// (0x_c3A1 <= code && code <= 0x_c3BB) || // Lo [27] HANGUL SYLLABLE +// SSYEOG..HANGUL SYLLABLE SSYEOH (0x_c3BD <= code && code <= 0x_c3D7) || +// // Lo [27] HANGUL SYLLABLE SSYEG..HANGUL SYLLABLE SSYEH (0x_c3D9 <= +// code && code <= 0x_c3F3) || // Lo [27] HANGUL SYLLABLE SSOG..HANGUL SYLLABLE +// SSOH (0x_c3F5 <= code && code <= 0x_c40F) || // Lo [27] HANGUL +// SYLLABLE SSWAG..HANGUL SYLLABLE SSWAH (0x_c411 <= code && code <= +// 0x_c42B) || // Lo [27] HANGUL SYLLABLE SSWAEG..HANGUL SYLLABLE SSWAEH +// (0x_c42D <= code && code <= 0x_c447) || // Lo [27] HANGUL SYLLABLE +// SSOEG..HANGUL SYLLABLE SSOEH (0x_c449 <= code && code <= 0x_c463) || +// // Lo [27] HANGUL SYLLABLE SSYOG..HANGUL SYLLABLE SSYOH (0x_c465 <= +// code && code <= 0x_c47F) || // Lo [27] HANGUL SYLLABLE SSUG..HANGUL SYLLABLE +// SSUH (0x_c481 <= code && code <= 0x_c49B) || // Lo [27] HANGUL +// SYLLABLE SSWEOG..HANGUL SYLLABLE SSWEOH (0x_c49D <= code && code <= +// 0x_c4B7) || // Lo [27] HANGUL SYLLABLE SSWEG..HANGUL SYLLABLE SSWEH +// (0x_c4B9 <= code && code <= 0x_c4D3) || // Lo [27] HANGUL SYLLABLE +// SSWIG..HANGUL SYLLABLE SSWIH (0x_c4D5 <= code && code <= 0x_c4EF) || +// // Lo [27] HANGUL SYLLABLE SSYUG..HANGUL SYLLABLE SSYUH (0x_c4F1 <= +// code && code <= 0x_c50B) || // Lo [27] HANGUL SYLLABLE SSEUG..HANGUL +// SYLLABLE SSEUH (0x_c50D <= code && code <= 0x_c527) || // Lo [27] +// HANGUL SYLLABLE SSYIG..HANGUL SYLLABLE SSYIH (0x_c529 <= code && code +// <= 0x_c543) || // Lo [27] HANGUL SYLLABLE SSIG..HANGUL SYLLABLE SSIH +// (0x_c545 <= code && code <= 0x_c55F) || // Lo [27] HANGUL SYLLABLE +// AG..HANGUL SYLLABLE AH (0x_c561 <= code && code <= 0x_c57B) || // Lo +// [27] HANGUL SYLLABLE AEG..HANGUL SYLLABLE AEH (0x_c57D <= code && code +// <= 0x_c597) || // Lo [27] HANGUL SYLLABLE YAG..HANGUL SYLLABLE YAH +// (0x_c599 <= code && code <= 0x_c5B3) || // Lo [27] HANGUL SYLLABLE +// YAEG..HANGUL SYLLABLE YAEH (0x_c5B5 <= code && code <= 0x_c5CF) || // +// Lo [27] HANGUL SYLLABLE EOG..HANGUL SYLLABLE EOH (0x_c5D1 <= code && +// code <= 0x_c5EB) || // Lo [27] HANGUL SYLLABLE EG..HANGUL SYLLABLE EH +// (0x_c5ED <= code && code <= 0x_c607) || // Lo [27] HANGUL SYLLABLE +// YEOG..HANGUL SYLLABLE YEOH (0x_c609 <= code && code <= 0x_c623) || // +// Lo [27] HANGUL SYLLABLE YEG..HANGUL SYLLABLE YEH (0x_c625 <= code && +// code <= 0x_c63F) || // Lo [27] HANGUL SYLLABLE OG..HANGUL SYLLABLE OH +// (0x_c641 <= code && code <= 0x_c65B) || // Lo [27] HANGUL SYLLABLE +// WAG..HANGUL SYLLABLE WAH (0x_c65D <= code && code <= 0x_c677) || // Lo +// [27] HANGUL SYLLABLE WAEG..HANGUL SYLLABLE WAEH (0x_c679 <= code && +// code <= 0x_c693) || // Lo [27] HANGUL SYLLABLE OEG..HANGUL SYLLABLE OEH +// (0x_c695 <= code && code <= 0x_c6AF) || // Lo [27] HANGUL SYLLABLE +// YOG..HANGUL SYLLABLE YOH (0x_c6B1 <= code && code <= 0x_c6CB) || // Lo +// [27] HANGUL SYLLABLE UG..HANGUL SYLLABLE UH (0x_c6CD <= code && code +// <= 0x_c6E7) || // Lo [27] HANGUL SYLLABLE WEOG..HANGUL SYLLABLE WEOH +// (0x_c6E9 <= code && code <= 0x_c703) || // Lo [27] HANGUL SYLLABLE +// WEG..HANGUL SYLLABLE WEH (0x_c705 <= code && code <= 0x_c71F) || // Lo +// [27] HANGUL SYLLABLE WIG..HANGUL SYLLABLE WIH (0x_c721 <= code && code +// <= 0x_c73B) || // Lo [27] HANGUL SYLLABLE YUG..HANGUL SYLLABLE YUH +// (0x_c73D <= code && code <= 0x_c757) || // Lo [27] HANGUL SYLLABLE +// EUG..HANGUL SYLLABLE EUH (0x_c759 <= code && code <= 0x_c773) || // Lo +// [27] HANGUL SYLLABLE YIG..HANGUL SYLLABLE YIH (0x_c775 <= code && code +// <= 0x_c78F) || // Lo [27] HANGUL SYLLABLE IG..HANGUL SYLLABLE IH +// (0x_c791 <= code && code <= 0x_c7AB) || // Lo [27] HANGUL SYLLABLE +// JAG..HANGUL SYLLABLE JAH (0x_c7AD <= code && code <= 0x_c7C7) || // Lo +// [27] HANGUL SYLLABLE JAEG..HANGUL SYLLABLE JAEH (0x_c7C9 <= code && +// code <= 0x_c7E3) || // Lo [27] HANGUL SYLLABLE JYAG..HANGUL SYLLABLE JYAH +// (0x_c7E5 <= code && code <= 0x_c7FF) || // Lo [27] HANGUL SYLLABLE +// JYAEG..HANGUL SYLLABLE JYAEH (0x_c801 <= code && code <= 0x_c81B) || +// // Lo [27] HANGUL SYLLABLE JEOG..HANGUL SYLLABLE JEOH (0x_c81D <= +// code && code <= 0x_c837) || // Lo [27] HANGUL SYLLABLE JEG..HANGUL SYLLABLE +// JEH (0x_c839 <= code && code <= 0x_c853) || // Lo [27] HANGUL +// SYLLABLE JYEOG..HANGUL SYLLABLE JYEOH (0x_c855 <= code && code <= +// 0x_c86F) || // Lo [27] HANGUL SYLLABLE JYEG..HANGUL SYLLABLE JYEH +// (0x_c871 <= code && code <= 0x_c88B) || // Lo [27] HANGUL SYLLABLE +// JOG..HANGUL SYLLABLE JOH (0x_c88D <= code && code <= 0x_c8A7) || // Lo +// [27] HANGUL SYLLABLE JWAG..HANGUL SYLLABLE JWAH (0x_c8A9 <= code && +// code <= 0x_c8C3) || // Lo [27] HANGUL SYLLABLE JWAEG..HANGUL SYLLABLE JWAEH +// (0x_c8C5 <= code && code <= 0x_c8DF) || // Lo [27] HANGUL SYLLABLE +// JOEG..HANGUL SYLLABLE JOEH (0x_c8E1 <= code && code <= 0x_c8FB) || // +// Lo [27] HANGUL SYLLABLE JYOG..HANGUL SYLLABLE JYOH (0x_c8FD <= code +// && code <= 0x_c917) || // Lo [27] HANGUL SYLLABLE JUG..HANGUL SYLLABLE JUH +// (0x_c919 <= code && code <= 0x_c933) || // Lo [27] HANGUL SYLLABLE +// JWEOG..HANGUL SYLLABLE JWEOH (0x_c935 <= code && code <= 0x_c94F) || +// // Lo [27] HANGUL SYLLABLE JWEG..HANGUL SYLLABLE JWEH (0x_c951 <= +// code && code <= 0x_c96B) || // Lo [27] HANGUL SYLLABLE JWIG..HANGUL SYLLABLE +// JWIH (0x_c96D <= code && code <= 0x_c987) || // Lo [27] HANGUL +// SYLLABLE JYUG..HANGUL SYLLABLE JYUH (0x_c989 <= code && code <= +// 0x_c9A3) || // Lo [27] HANGUL SYLLABLE JEUG..HANGUL SYLLABLE JEUH +// (0x_c9A5 <= code && code <= 0x_c9BF) || // Lo [27] HANGUL SYLLABLE +// JYIG..HANGUL SYLLABLE JYIH (0x_c9C1 <= code && code <= 0x_c9DB) || // +// Lo [27] HANGUL SYLLABLE JIG..HANGUL SYLLABLE JIH (0x_c9DD <= code && +// code <= 0x_c9F7) || // Lo [27] HANGUL SYLLABLE JJAG..HANGUL SYLLABLE JJAH +// (0x_c9F9 <= code && code <= 0x_cA13) || // Lo [27] HANGUL SYLLABLE +// JJAEG..HANGUL SYLLABLE JJAEH (0x_cA15 <= code && code <= 0x_cA2F) || +// // Lo [27] HANGUL SYLLABLE JJYAG..HANGUL SYLLABLE JJYAH (0x_cA31 <= +// code && code <= 0x_cA4B) || // Lo [27] HANGUL SYLLABLE JJYAEG..HANGUL +// SYLLABLE JJYAEH (0x_cA4D <= code && code <= 0x_cA67) || // Lo [27] +// HANGUL SYLLABLE JJEOG..HANGUL SYLLABLE JJEOH (0x_cA69 <= code && code +// <= 0x_cA83) || // Lo [27] HANGUL SYLLABLE JJEG..HANGUL SYLLABLE JJEH +// (0x_cA85 <= code && code <= 0x_cA9F) || // Lo [27] HANGUL SYLLABLE +// JJYEOG..HANGUL SYLLABLE JJYEOH (0x_cAA1 <= code && code <= 0x_cABB) || +// // Lo [27] HANGUL SYLLABLE JJYEG..HANGUL SYLLABLE JJYEH (0x_cABD <= +// code && code <= 0x_cAD7) || // Lo [27] HANGUL SYLLABLE JJOG..HANGUL SYLLABLE +// JJOH (0x_cAD9 <= code && code <= 0x_cAF3) || // Lo [27] HANGUL +// SYLLABLE JJWAG..HANGUL SYLLABLE JJWAH (0x_cAF5 <= code && code <= +// 0x_cB0F) || // Lo [27] HANGUL SYLLABLE JJWAEG..HANGUL SYLLABLE JJWAEH +// (0x_cB11 <= code && code <= 0x_cB2B) || // Lo [27] HANGUL SYLLABLE +// JJOEG..HANGUL SYLLABLE JJOEH (0x_cB2D <= code && code <= 0x_cB47) || +// // Lo [27] HANGUL SYLLABLE JJYOG..HANGUL SYLLABLE JJYOH (0x_cB49 <= +// code && code <= 0x_cB63) || // Lo [27] HANGUL SYLLABLE JJUG..HANGUL SYLLABLE +// JJUH (0x_cB65 <= code && code <= 0x_cB7F) || // Lo [27] HANGUL +// SYLLABLE JJWEOG..HANGUL SYLLABLE JJWEOH (0x_cB81 <= code && code <= +// 0x_cB9B) || // Lo [27] HANGUL SYLLABLE JJWEG..HANGUL SYLLABLE JJWEH +// (0x_cB9D <= code && code <= 0x_cBB7) || // Lo [27] HANGUL SYLLABLE +// JJWIG..HANGUL SYLLABLE JJWIH (0x_cBB9 <= code && code <= 0x_cBD3) || +// // Lo [27] HANGUL SYLLABLE JJYUG..HANGUL SYLLABLE JJYUH (0x_cBD5 <= +// code && code <= 0x_cBEF) || // Lo [27] HANGUL SYLLABLE JJEUG..HANGUL +// SYLLABLE JJEUH (0x_cBF1 <= code && code <= 0x_cC0B) || // Lo [27] +// HANGUL SYLLABLE JJYIG..HANGUL SYLLABLE JJYIH (0x_cC0D <= code && code +// <= 0x_cC27) || // Lo [27] HANGUL SYLLABLE JJIG..HANGUL SYLLABLE JJIH +// (0x_cC29 <= code && code <= 0x_cC43) || // Lo [27] HANGUL SYLLABLE +// CAG..HANGUL SYLLABLE CAH (0x_cC45 <= code && code <= 0x_cC5F) || // Lo +// [27] HANGUL SYLLABLE CAEG..HANGUL SYLLABLE CAEH (0x_cC61 <= code && +// code <= 0x_cC7B) || // Lo [27] HANGUL SYLLABLE CYAG..HANGUL SYLLABLE CYAH +// (0x_cC7D <= code && code <= 0x_cC97) || // Lo [27] HANGUL SYLLABLE +// CYAEG..HANGUL SYLLABLE CYAEH (0x_cC99 <= code && code <= 0x_cCB3) || +// // Lo [27] HANGUL SYLLABLE CEOG..HANGUL SYLLABLE CEOH (0x_cCB5 <= +// code && code <= 0x_cCCF) || // Lo [27] HANGUL SYLLABLE CEG..HANGUL SYLLABLE +// CEH (0x_cCD1 <= code && code <= 0x_cCEB) || // Lo [27] HANGUL +// SYLLABLE CYEOG..HANGUL SYLLABLE CYEOH (0x_cCED <= code && code <= +// 0x_cD07) || // Lo [27] HANGUL SYLLABLE CYEG..HANGUL SYLLABLE CYEH +// (0x_cD09 <= code && code <= 0x_cD23) || // Lo [27] HANGUL SYLLABLE +// COG..HANGUL SYLLABLE COH (0x_cD25 <= code && code <= 0x_cD3F) || // Lo +// [27] HANGUL SYLLABLE CWAG..HANGUL SYLLABLE CWAH (0x_cD41 <= code && +// code <= 0x_cD5B) || // Lo [27] HANGUL SYLLABLE CWAEG..HANGUL SYLLABLE CWAEH +// (0x_cD5D <= code && code <= 0x_cD77) || // Lo [27] HANGUL SYLLABLE +// COEG..HANGUL SYLLABLE COEH (0x_cD79 <= code && code <= 0x_cD93) || // +// Lo [27] HANGUL SYLLABLE CYOG..HANGUL SYLLABLE CYOH (0x_cD95 <= code +// && code <= 0x_cDAF) || // Lo [27] HANGUL SYLLABLE CUG..HANGUL SYLLABLE CUH +// (0x_cDB1 <= code && code <= 0x_cDCB) || // Lo [27] HANGUL SYLLABLE +// CWEOG..HANGUL SYLLABLE CWEOH (0x_cDCD <= code && code <= 0x_cDE7) || +// // Lo [27] HANGUL SYLLABLE CWEG..HANGUL SYLLABLE CWEH (0x_cDE9 <= +// code && code <= 0x_cE03) || // Lo [27] HANGUL SYLLABLE CWIG..HANGUL SYLLABLE +// CWIH (0x_cE05 <= code && code <= 0x_cE1F) || // Lo [27] HANGUL +// SYLLABLE CYUG..HANGUL SYLLABLE CYUH (0x_cE21 <= code && code <= +// 0x_cE3B) || // Lo [27] HANGUL SYLLABLE CEUG..HANGUL SYLLABLE CEUH +// (0x_cE3D <= code && code <= 0x_cE57) || // Lo [27] HANGUL SYLLABLE +// CYIG..HANGUL SYLLABLE CYIH (0x_cE59 <= code && code <= 0x_cE73) || // +// Lo [27] HANGUL SYLLABLE CIG..HANGUL SYLLABLE CIH (0x_cE75 <= code && +// code <= 0x_cE8F) || // Lo [27] HANGUL SYLLABLE KAG..HANGUL SYLLABLE KAH +// (0x_cE91 <= code && code <= 0x_cEAB) || // Lo [27] HANGUL SYLLABLE +// KAEG..HANGUL SYLLABLE KAEH (0x_cEAD <= code && code <= 0x_cEC7) || // +// Lo [27] HANGUL SYLLABLE KYAG..HANGUL SYLLABLE KYAH (0x_cEC9 <= code +// && code <= 0x_cEE3) || // Lo [27] HANGUL SYLLABLE KYAEG..HANGUL SYLLABLE +// KYAEH (0x_cEE5 <= code && code <= 0x_cEFF) || // Lo [27] HANGUL +// SYLLABLE KEOG..HANGUL SYLLABLE KEOH (0x_cF01 <= code && code <= +// 0x_cF1B) || // Lo [27] HANGUL SYLLABLE KEG..HANGUL SYLLABLE KEH +// (0x_cF1D <= code && code <= 0x_cF37) || // Lo [27] HANGUL SYLLABLE +// KYEOG..HANGUL SYLLABLE KYEOH (0x_cF39 <= code && code <= 0x_cF53) || +// // Lo [27] HANGUL SYLLABLE KYEG..HANGUL SYLLABLE KYEH (0x_cF55 <= +// code && code <= 0x_cF6F) || // Lo [27] HANGUL SYLLABLE KOG..HANGUL SYLLABLE +// KOH (0x_cF71 <= code && code <= 0x_cF8B) || // Lo [27] HANGUL +// SYLLABLE KWAG..HANGUL SYLLABLE KWAH (0x_cF8D <= code && code <= +// 0x_cFA7) || // Lo [27] HANGUL SYLLABLE KWAEG..HANGUL SYLLABLE KWAEH +// (0x_cFA9 <= code && code <= 0x_cFC3) || // Lo [27] HANGUL SYLLABLE +// KOEG..HANGUL SYLLABLE KOEH (0x_cFC5 <= code && code <= 0x_cFDF) || // +// Lo [27] HANGUL SYLLABLE KYOG..HANGUL SYLLABLE KYOH (0x_cFE1 <= code +// && code <= 0x_cFFB) || // Lo [27] HANGUL SYLLABLE KUG..HANGUL SYLLABLE KUH +// (0x_cFFD <= code && code <= 0x_d017) || // Lo [27] HANGUL SYLLABLE +// KWEOG..HANGUL SYLLABLE KWEOH (0x_d019 <= code && code <= 0x_d033) || +// // Lo [27] HANGUL SYLLABLE KWEG..HANGUL SYLLABLE KWEH (0x_d035 <= +// code && code <= 0x_d04F) || // Lo [27] HANGUL SYLLABLE KWIG..HANGUL SYLLABLE +// KWIH (0x_d051 <= code && code <= 0x_d06B) || // Lo [27] HANGUL +// SYLLABLE KYUG..HANGUL SYLLABLE KYUH (0x_d06D <= code && code <= +// 0x_d087) || // Lo [27] HANGUL SYLLABLE KEUG..HANGUL SYLLABLE KEUH +// (0x_d089 <= code && code <= 0x_d0A3) || // Lo [27] HANGUL SYLLABLE +// KYIG..HANGUL SYLLABLE KYIH (0x_d0A5 <= code && code <= 0x_d0BF) || // +// Lo [27] HANGUL SYLLABLE KIG..HANGUL SYLLABLE KIH (0x_d0C1 <= code && +// code <= 0x_d0DB) || // Lo [27] HANGUL SYLLABLE TAG..HANGUL SYLLABLE TAH +// (0x_d0DD <= code && code <= 0x_d0F7) || // Lo [27] HANGUL SYLLABLE +// TAEG..HANGUL SYLLABLE TAEH (0x_d0F9 <= code && code <= 0x_d113) || // +// Lo [27] HANGUL SYLLABLE TYAG..HANGUL SYLLABLE TYAH (0x_d115 <= code +// && code <= 0x_d12F) || // Lo [27] HANGUL SYLLABLE TYAEG..HANGUL SYLLABLE +// TYAEH (0x_d131 <= code && code <= 0x_d14B) || // Lo [27] HANGUL +// SYLLABLE TEOG..HANGUL SYLLABLE TEOH (0x_d14D <= code && code <= +// 0x_d167) || // Lo [27] HANGUL SYLLABLE TEG..HANGUL SYLLABLE TEH +// (0x_d169 <= code && code <= 0x_d183) || // Lo [27] HANGUL SYLLABLE +// TYEOG..HANGUL SYLLABLE TYEOH (0x_d185 <= code && code <= 0x_d19F) || +// // Lo [27] HANGUL SYLLABLE TYEG..HANGUL SYLLABLE TYEH (0x_d1A1 <= +// code && code <= 0x_d1BB) || // Lo [27] HANGUL SYLLABLE TOG..HANGUL SYLLABLE +// TOH (0x_d1BD <= code && code <= 0x_d1D7) || // Lo [27] HANGUL +// SYLLABLE TWAG..HANGUL SYLLABLE TWAH (0x_d1D9 <= code && code <= +// 0x_d1F3) || // Lo [27] HANGUL SYLLABLE TWAEG..HANGUL SYLLABLE TWAEH +// (0x_d1F5 <= code && code <= 0x_d20F) || // Lo [27] HANGUL SYLLABLE +// TOEG..HANGUL SYLLABLE TOEH (0x_d211 <= code && code <= 0x_d22B) || // +// Lo [27] HANGUL SYLLABLE TYOG..HANGUL SYLLABLE TYOH (0x_d22D <= code +// && code <= 0x_d247) || // Lo [27] HANGUL SYLLABLE TUG..HANGUL SYLLABLE TUH +// (0x_d249 <= code && code <= 0x_d263) || // Lo [27] HANGUL SYLLABLE +// TWEOG..HANGUL SYLLABLE TWEOH (0x_d265 <= code && code <= 0x_d27F) || +// // Lo [27] HANGUL SYLLABLE TWEG..HANGUL SYLLABLE TWEH (0x_d281 <= +// code && code <= 0x_d29B) || // Lo [27] HANGUL SYLLABLE TWIG..HANGUL SYLLABLE +// TWIH (0x_d29D <= code && code <= 0x_d2B7) || // Lo [27] HANGUL +// SYLLABLE TYUG..HANGUL SYLLABLE TYUH (0x_d2B9 <= code && code <= +// 0x_d2D3) || // Lo [27] HANGUL SYLLABLE TEUG..HANGUL SYLLABLE TEUH +// (0x_d2D5 <= code && code <= 0x_d2EF) || // Lo [27] HANGUL SYLLABLE +// TYIG..HANGUL SYLLABLE TYIH (0x_d2F1 <= code && code <= 0x_d30B) || // +// Lo [27] HANGUL SYLLABLE TIG..HANGUL SYLLABLE TIH (0x_d30D <= code && +// code <= 0x_d327) || // Lo [27] HANGUL SYLLABLE PAG..HANGUL SYLLABLE PAH +// (0x_d329 <= code && code <= 0x_d343) || // Lo [27] HANGUL SYLLABLE +// PAEG..HANGUL SYLLABLE PAEH (0x_d345 <= code && code <= 0x_d35F) || // +// Lo [27] HANGUL SYLLABLE PYAG..HANGUL SYLLABLE PYAH (0x_d361 <= code +// && code <= 0x_d37B) || // Lo [27] HANGUL SYLLABLE PYAEG..HANGUL SYLLABLE +// PYAEH (0x_d37D <= code && code <= 0x_d397) || // Lo [27] HANGUL +// SYLLABLE PEOG..HANGUL SYLLABLE PEOH (0x_d399 <= code && code <= +// 0x_d3B3) || // Lo [27] HANGUL SYLLABLE PEG..HANGUL SYLLABLE PEH +// (0x_d3B5 <= code && code <= 0x_d3CF) || // Lo [27] HANGUL SYLLABLE +// PYEOG..HANGUL SYLLABLE PYEOH (0x_d3D1 <= code && code <= 0x_d3EB) || +// // Lo [27] HANGUL SYLLABLE PYEG..HANGUL SYLLABLE PYEH (0x_d3ED <= +// code && code <= 0x_d407) || // Lo [27] HANGUL SYLLABLE POG..HANGUL SYLLABLE +// POH (0x_d409 <= code && code <= 0x_d423) || // Lo [27] HANGUL +// SYLLABLE PWAG..HANGUL SYLLABLE PWAH (0x_d425 <= code && code <= +// 0x_d43F) || // Lo [27] HANGUL SYLLABLE PWAEG..HANGUL SYLLABLE PWAEH +// (0x_d441 <= code && code <= 0x_d45B) || // Lo [27] HANGUL SYLLABLE +// POEG..HANGUL SYLLABLE POEH (0x_d45D <= code && code <= 0x_d477) || // +// Lo [27] HANGUL SYLLABLE PYOG..HANGUL SYLLABLE PYOH (0x_d479 <= code +// && code <= 0x_d493) || // Lo [27] HANGUL SYLLABLE PUG..HANGUL SYLLABLE PUH +// (0x_d495 <= code && code <= 0x_d4AF) || // Lo [27] HANGUL SYLLABLE +// PWEOG..HANGUL SYLLABLE PWEOH (0x_d4B1 <= code && code <= 0x_d4CB) || +// // Lo [27] HANGUL SYLLABLE PWEG..HANGUL SYLLABLE PWEH (0x_d4CD <= +// code && code <= 0x_d4E7) || // Lo [27] HANGUL SYLLABLE PWIG..HANGUL SYLLABLE +// PWIH (0x_d4E9 <= code && code <= 0x_d503) || // Lo [27] HANGUL +// SYLLABLE PYUG..HANGUL SYLLABLE PYUH (0x_d505 <= code && code <= +// 0x_d51F) || // Lo [27] HANGUL SYLLABLE PEUG..HANGUL SYLLABLE PEUH +// (0x_d521 <= code && code <= 0x_d53B) || // Lo [27] HANGUL SYLLABLE +// PYIG..HANGUL SYLLABLE PYIH (0x_d53D <= code && code <= 0x_d557) || // +// Lo [27] HANGUL SYLLABLE PIG..HANGUL SYLLABLE PIH (0x_d559 <= code && +// code <= 0x_d573) || // Lo [27] HANGUL SYLLABLE HAG..HANGUL SYLLABLE HAH +// (0x_d575 <= code && code <= 0x_d58F) || // Lo [27] HANGUL SYLLABLE +// HAEG..HANGUL SYLLABLE HAEH (0x_d591 <= code && code <= 0x_d5AB) || // +// Lo [27] HANGUL SYLLABLE HYAG..HANGUL SYLLABLE HYAH (0x_d5AD <= code +// && code <= 0x_d5C7) || // Lo [27] HANGUL SYLLABLE HYAEG..HANGUL SYLLABLE +// HYAEH (0x_d5C9 <= code && code <= 0x_d5E3) || // Lo [27] HANGUL +// SYLLABLE HEOG..HANGUL SYLLABLE HEOH (0x_d5E5 <= code && code <= +// 0x_d5FF) || // Lo [27] HANGUL SYLLABLE HEG..HANGUL SYLLABLE HEH +// (0x_d601 <= code && code <= 0x_d61B) || // Lo [27] HANGUL SYLLABLE +// HYEOG..HANGUL SYLLABLE HYEOH (0x_d61D <= code && code <= 0x_d637) || +// // Lo [27] HANGUL SYLLABLE HYEG..HANGUL SYLLABLE HYEH (0x_d639 <= +// code && code <= 0x_d653) || // Lo [27] HANGUL SYLLABLE HOG..HANGUL SYLLABLE +// HOH (0x_d655 <= code && code <= 0x_d66F) || // Lo [27] HANGUL +// SYLLABLE HWAG..HANGUL SYLLABLE HWAH (0x_d671 <= code && code <= +// 0x_d68B) || // Lo [27] HANGUL SYLLABLE HWAEG..HANGUL SYLLABLE HWAEH +// (0x_d68D <= code && code <= 0x_d6A7) || // Lo [27] HANGUL SYLLABLE +// HOEG..HANGUL SYLLABLE HOEH (0x_d6A9 <= code && code <= 0x_d6C3) || // +// Lo [27] HANGUL SYLLABLE HYOG..HANGUL SYLLABLE HYOH (0x_d6C5 <= code +// && code <= 0x_d6DF) || // Lo [27] HANGUL SYLLABLE HUG..HANGUL SYLLABLE HUH +// (0x_d6E1 <= code && code <= 0x_d6FB) || // Lo [27] HANGUL SYLLABLE +// HWEOG..HANGUL SYLLABLE HWEOH (0x_d6FD <= code && code <= 0x_d717) || +// // Lo [27] HANGUL SYLLABLE HWEG..HANGUL SYLLABLE HWEH (0x_d719 <= +// code && code <= 0x_d733) || // Lo [27] HANGUL SYLLABLE HWIG..HANGUL SYLLABLE +// HWIH (0x_d735 <= code && code <= 0x_d74F) || // Lo [27] HANGUL +// SYLLABLE HYUG..HANGUL SYLLABLE HYUH (0x_d751 <= code && code <= +// 0x_d76B) || // Lo [27] HANGUL SYLLABLE HEUG..HANGUL SYLLABLE HEUH +// (0x_d76D <= code && code <= 0x_d787) || // Lo [27] HANGUL SYLLABLE +// HYIG..HANGUL SYLLABLE HYIH (0x_d789 <= code && code <= 0x_d7A3) // Lo +// [27] HANGUL SYLLABLE HIG..HANGUL SYLLABLE HIH ){ // return LVT; // } // // if( // 0x261D == code || // So WHITE UP POINTING INDEX // 0x26F9 == code || // So PERSON WITH BALL -// (0x270A <= code && code <= 0x270D) || // So [4] RAISED FIST..WRITING HAND -// 0x1F385 == code || // So FATHER CHRISTMAS -// (0x1F3C2 <= code && code <= 0x1F3C4) || // So [3] SNOWBOARDER..SURFER -// 0x1F3C7 == code || // So HORSE RACING +// (0x270A <= code && code <= 0x270D) || // So [4] RAISED FIST..WRITING +// HAND 0x1F385 == code || // So FATHER CHRISTMAS +// (0x1F3C2 <= code && code <= 0x1F3C4) || // So [3] +// SNOWBOARDER..SURFER 0x1F3C7 == code || // So HORSE RACING // (0x1F3CA <= code && code <= 0x1F3CC) || // So [3] SWIMMER..GOLFER // (0x1F442 <= code && code <= 0x1F443) || // So [2] EAR..NOSE -// (0x1F446 <= code && code <= 0x1F450) || // So [11] WHITE UP POINTING BACKHAND INDEX..OPEN HANDS SIGN -// 0x1F46E == code || // So POLICE OFFICER -// (0x1F470 <= code && code <= 0x1F478) || // So [9] BRIDE WITH VEIL..PRINCESS -// 0x1F47C == code || // So BABY ANGEL -// (0x1F481 <= code && code <= 0x1F483) || // So [3] INFORMATION DESK PERSON..DANCER -// (0x1F485 <= code && code <= 0x1F487) || // So [3] NAIL POLISH..HAIRCUT -// 0x1F4AA == code || // So FLEXED BICEPS -// (0x1F574 <= code && code <= 0x1F575) || // So [2] MAN IN BUSINESS SUIT LEVITATING..SLEUTH OR SPY -// 0x1F57A == code || // So MAN DANCING -// 0x1F590 == code || // So RAISED HAND WITH FINGERS SPLAYED -// (0x1F595 <= code && code <= 0x1F596) || // So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS -// (0x1F645 <= code && code <= 0x1F647) || // So [3] FACE WITH NO GOOD GESTURE..PERSON BOWING DEEPLY -// (0x1F64B <= code && code <= 0x1F64F) || // So [5] HAPPY PERSON RAISING ONE HAND..PERSON WITH FOLDED HANDS -// 0x1F6A3 == code || // So ROWBOAT -// (0x1F6B4 <= code && code <= 0x1F6B6) || // So [3] BICYCLIST..PEDESTRIAN -// 0x1F6C0 == code || // So BATH +// (0x1F446 <= code && code <= 0x1F450) || // So [11] WHITE UP POINTING +// BACKHAND INDEX..OPEN HANDS SIGN 0x1F46E == code || // So POLICE +// OFFICER (0x1F470 <= code && code <= 0x1F478) || // So [9] BRIDE WITH +// VEIL..PRINCESS 0x1F47C == code || // So BABY ANGEL +// (0x1F481 <= code && code <= 0x1F483) || // So [3] INFORMATION DESK +// PERSON..DANCER (0x1F485 <= code && code <= 0x1F487) || // So [3] +// NAIL POLISH..HAIRCUT 0x1F4AA == code || // So FLEXED BICEPS +// (0x1F574 <= code && code <= 0x1F575) || // So [2] MAN IN BUSINESS +// SUIT LEVITATING..SLEUTH OR SPY 0x1F57A == code || // So MAN +// DANCING 0x1F590 == code || // So RAISED HAND WITH FINGERS +// SPLAYED (0x1F595 <= code && code <= 0x1F596) || // So [2] REVERSED +// HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND +// RING FINGERS (0x1F645 <= code && code <= 0x1F647) || // So [3] FACE +// WITH NO GOOD GESTURE..PERSON BOWING DEEPLY (0x1F64B <= code && code <= +// 0x1F64F) || // So [5] HAPPY PERSON RAISING ONE HAND..PERSON WITH FOLDED +// HANDS 0x1F6A3 == code || // So ROWBOAT +// (0x1F6B4 <= code && code <= 0x1F6B6) || // So [3] +// BICYCLIST..PEDESTRIAN 0x1F6C0 == code || // So BATH // 0x1F6CC == code || // So SLEEPING ACCOMMODATION -// (0x1F918 <= code && code <= 0x1F91C) || // So [5] SIGN OF THE HORNS..RIGHT-FACING FIST -// (0x1F91E <= code && code <= 0x1F91F) || // So [2] HAND WITH INDEX AND MIDDLE FINGERS CROSSED..I LOVE YOU HAND SIGN +// (0x1F918 <= code && code <= 0x1F91C) || // So [5] SIGN OF THE +// HORNS..RIGHT-FACING FIST (0x1F91E <= code && code <= 0x1F91F) || // So +// [2] HAND WITH INDEX AND MIDDLE FINGERS CROSSED..I LOVE YOU HAND SIGN // 0x1F926 == code || // So FACE PALM -// (0x1F930 <= code && code <= 0x1F939) || // So [10] PREGNANT WOMAN..JUGGLING -// (0x1F93D <= code && code <= 0x1F93E) || // So [2] WATER POLO..HANDBALL -// (0x1F9D1 <= code && code <= 0x1F9DD) // So [13] ADULT..ELF -// ){ +// (0x1F930 <= code && code <= 0x1F939) || // So [10] PREGNANT +// WOMAN..JUGGLING (0x1F93D <= code && code <= 0x1F93E) || // So [2] +// WATER POLO..HANDBALL (0x1F9D1 <= code && code <= 0x1F9DD) // So [13] +// ADULT..ELF ){ // return E_Base; // } // // if( -// (0x1F3FB <= code && code <= 0x1F3FF) // Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 -// ){ +// (0x1F3FB <= code && code <= 0x1F3FF) // Sk [5] EMOJI MODIFIER +// FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6 ){ // return E_Modifier; // } // @@ -1851,8 +2140,8 @@ pub fn word_break_string(s: &str, width: usize) -> Vec<&str> { // if( // 0x2640 == code || // So FEMALE SIGN // 0x2642 == code || // So MALE SIGN -// (0x2695 <= code && code <= 0x2696) || // So [2] STAFF OF AESCULAPIUS..SCALES -// 0x2708 == code || // So AIRPLANE +// (0x2695 <= code && code <= 0x2696) || // So [2] STAFF OF +// AESCULAPIUS..SCALES 0x2708 == code || // So AIRPLANE // 0x2764 == code || // So HEAVY BLACK HEART // 0x1F308 == code || // So RAINBOW // 0x1F33E == code || // So EAR OF RICE @@ -1863,8 +2152,8 @@ pub fn word_break_string(s: &str, width: usize) -> Vec<&str> { // 0x1F3EB == code || // So SCHOOL // 0x1F3ED == code || // So FACTORY // 0x1F48B == code || // So KISS MARK -// (0x1F4BB <= code && code <= 0x1F4BC) || // So [2] PERSONAL COMPUTER..BRIEFCASE -// 0x1F527 == code || // So WRENCH +// (0x1F4BB <= code && code <= 0x1F4BC) || // So [2] PERSONAL +// COMPUTER..BRIEFCASE 0x1F527 == code || // So WRENCH // 0x1F52C == code || // So MICROSCOPE // 0x1F5E8 == code || // So LEFT SPEECH BUBBLE // 0x1F680 == code || // So ROCKET diff --git a/melib/src/text_processing/line_break.rs b/melib/src/text_processing/line_break.rs index f35d8274..ff7cb357 100644 --- a/melib/src/text_processing/line_break.rs +++ b/melib/src/text_processing/line_break.rs @@ -20,17 +20,18 @@ */ extern crate unicode_segmentation; -use self::unicode_segmentation::UnicodeSegmentation; -use super::grapheme_clusters::TextProcessing; -use super::tables::LINE_BREAK_RULES; -use super::types::LineBreakClass; -use super::types::Reflow; -use core::cmp::Ordering; -use core::iter::Peekable; -use core::str::FromStr; +use core::{cmp::Ordering, iter::Peekable, str::FromStr}; use std::collections::VecDeque; + use LineBreakClass::*; +use self::unicode_segmentation::UnicodeSegmentation; +use super::{ + grapheme_clusters::TextProcessing, + tables::LINE_BREAK_RULES, + types::{LineBreakClass, Reflow}, +}; + #[derive(Debug, PartialEq, Copy, Clone)] pub enum LineBreakCandidate { MandatoryBreak, @@ -138,14 +139,32 @@ impl EvenAfterSpaces for str { /// Returns positions where breaks can happen /// Examples: /// ``` -/// use melib::text_processing::{self, LineBreakCandidate::{self, *}}; -/// use melib::text_processing::line_break::LineBreakCandidateIter; +/// use melib::text_processing::{ +/// self, +/// line_break::LineBreakCandidateIter, +/// LineBreakCandidate::{self, *}, +/// }; /// -/// assert!(LineBreakCandidateIter::new("").collect::>().is_empty()); -/// assert_eq!(&[(7, BreakAllowed), (12, MandatoryBreak)], -/// LineBreakCandidateIter::new("Sample Text.").collect::>().as_slice()); -/// assert_eq!(&[(3, MandatoryBreak), (7, MandatoryBreak), (10, BreakAllowed), (17, MandatoryBreak)], -/// LineBreakCandidateIter::new("Sa\nmp\r\nle T(e)xt.").collect::>().as_slice()); +/// assert!(LineBreakCandidateIter::new("") +/// .collect::>() +/// .is_empty()); +/// assert_eq!( +/// &[(7, BreakAllowed), (12, MandatoryBreak)], +/// LineBreakCandidateIter::new("Sample Text.") +/// .collect::>() +/// .as_slice() +/// ); +/// assert_eq!( +/// &[ +/// (3, MandatoryBreak), +/// (7, MandatoryBreak), +/// (10, BreakAllowed), +/// (17, MandatoryBreak) +/// ], +/// LineBreakCandidateIter::new("Sa\nmp\r\nle T(e)xt.") +/// .collect::>() +/// .as_slice() +/// ); /// ``` impl<'a> Iterator for LineBreakCandidateIter<'a> { type Item = (usize, LineBreakCandidate); @@ -190,13 +209,13 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { *reg_ind_streak = 0; } - /* LB1 Assign a line breaking class to each code point of the input. Resolve AI, CB, CJ, - * SA, SG, and XX into other line breaking classes depending on criteria outside the scope - * of this algorithm. + /* LB1 Assign a line breaking class to each code point of the input. Resolve + * AI, CB, CJ, SA, SG, and XX into other line breaking classes + * depending on criteria outside the scope of this algorithm. * - * In the absence of such criteria all characters with a specific combination of original - * class and General_Category property value are resolved as follows: - * Resolved Original General_Category + * In the absence of such criteria all characters with a specific combination + * of original class and General_Category property value are + * resolved as follows: Resolved Original General_Category * AL AI, SG, XX Any * CM SA Only Mn or Mc * AL SA Any except Mn and Mc @@ -245,7 +264,8 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { continue; } WJ => { - /*: LB11 Do not break before or after Word joiner and related characters.*/ + /* : LB11 Do not break before or after Word joiner and related + * characters. */ *pos += grapheme.len(); continue; } @@ -266,8 +286,8 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { } match class { ZW => { - // LB8 Break before any character following a zero-width space, even if one or more - // spaces intervene + // LB8 Break before any character following a zero-width space, even if one or + // more spaces intervene // ZW SP* ÷ *pos += grapheme.len(); while next_grapheme_class!((next_char is SP)) { @@ -286,9 +306,9 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { } CM => { - // LB9 Do not break a combining character sequence; treat it as if it has the line - // breaking class of the base character in all of the following rules. Treat ZWJ as - // if it were CM. + // LB9 Do not break a combining character sequence; treat it as if it has the + // line breaking class of the base character in all of the + // following rules. Treat ZWJ as if it were CM. // Treat X (CM | ZWJ)* as if it were X. // where X is any line break class except BK, CR, LF, NL, SP, or ZW. @@ -296,7 +316,7 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { continue; } WJ => { - /*: LB11 Do not break before or after Word joiner and related characters.*/ + /* : LB11 Do not break before or after Word joiner and related characters. */ *pos += grapheme.len(); /* Get next grapheme */ if next_grapheme_class!(iter, grapheme).is_some() { @@ -305,7 +325,8 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { continue; } GL => { - /*LB12 Non-breaking characters: LB12 Do not break after NBSP and related characters.*/ + /* LB12 Non-breaking characters: LB12 Do not break after NBSP and related + * characters. */ *pos += grapheme.len(); continue; } @@ -315,8 +336,8 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { let next_class = get_class!(next_grapheme); match next_class { GL if ![SP, BA, HY].contains(&class) => { - /* LB12a Do not break before NBSP and related characters, except after spaces and - * hyphens. [^SP BA HY] × GL + /* LB12a Do not break before NBSP and related characters, except after + * spaces and hyphens. [^SP BA HY] × GL * Also LB12 Do not break after NBSP and related characters */ *pos += grapheme.len(); continue; @@ -384,8 +405,8 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { if !text[idx + grapheme.len()..].even_after_spaces().is_empty() && get_class!(text[idx + grapheme.len()..].even_after_spaces()) == NS => { - /* LB16 Do not break between closing punctuation and a nonstarter (lb=NS), even with - * intervening spaces. + /* LB16 Do not break between closing punctuation and a nonstarter (lb=NS), + * even with intervening spaces. * (CL | CP) SP* × NS */ *pos += grapheme.len(); while Some(SP) == next_grapheme_class!(iter, grapheme) { @@ -397,7 +418,7 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { && get_class!(text[idx + grapheme.len()..].even_after_spaces()) == B2 => { /* LB17 Do not break within ‘——’, even with intervening spaces. - * B2 SP* × B2*/ + * B2 SP* × B2 */ *pos += grapheme.len(); continue; } @@ -434,8 +455,9 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { set_last_break!(*last_break, ret); return Some((ret, BreakAllowed)); } - /* LB21 Do not break before hyphen-minus, other hyphens, fixed-width spaces, small - * kana, and other non-starters, or after acute accents. × BA, × HY, × NS, BB × */ + /* LB21 Do not break before hyphen-minus, other hyphens, fixed-width spaces, + * small kana, and other non-starters, or after acute accents. × + * BA, × HY, × NS, BB × */ BB if !*break_now => { *pos += grapheme.len(); continue; @@ -447,8 +469,9 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { let next_class = get_class!(next_grapheme); match next_class { BA | HY | NS => { - /* LB21 Do not break before hyphen-minus, other hyphens, fixed-width spaces, small - * kana, and other non-starters, or after acute accents. × BA, × HY, × NS, BB × */ + /* LB21 Do not break before hyphen-minus, other hyphens, fixed-width + * spaces, small kana, and other non-starters, or + * after acute accents. × BA, × HY, × NS, BB × */ *pos += grapheme.len(); //*pos += next_grapheme.len(); continue; @@ -485,7 +508,7 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { self.iter.next(); continue; } - /* EX × IN */ + /* EX × IN */ EX if next_grapheme_class!((next_char is IN)) => { let (idx, next_grapheme) = next_char.unwrap(); *pos = idx + next_grapheme.len(); @@ -497,21 +520,21 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { *pos += grapheme.len(); continue; } - /* (ID | EB | EM) × IN */ + /* (ID | EB | EM) × IN */ ID | EB | EM if next_grapheme_class!((next_char is IN)) => { let (idx, next_grapheme) = next_char.unwrap(); *pos = idx + next_grapheme.len(); self.iter.next(); continue; } - /* IN × IN */ + /* IN × IN */ IN if next_grapheme_class!((next_char is IN)) => { let (idx, next_grapheme) = next_char.unwrap(); *pos = idx + next_grapheme.len(); self.iter.next(); continue; } - /* NU × IN */ + /* NU × IN */ NU if next_grapheme_class!((next_char is IN)) => { let (idx, next_grapheme) = next_char.unwrap(); *pos = idx + next_grapheme.len(); @@ -533,8 +556,8 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { self.iter.next(); continue; } - /* LB23a Do not break between numeric prefixes and ideographs, or between ideographs - * and numeric postfixes. + /* LB23a Do not break between numeric prefixes and ideographs, or between + * ideographs and numeric postfixes. * PR × (ID | EB | EM) */ PR if next_grapheme_class!((next_char is ID, EB, EM)) => { let (idx, next_grapheme) = next_char.unwrap(); @@ -558,7 +581,7 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { self.iter.next(); continue; } - /*(AL | HL) × (PR | PO) */ + /* (AL | HL) × (PR | PO) */ AL | HL if next_grapheme_class!((next_char is PR, PO)) => { let (idx, next_grapheme) = next_char.unwrap(); *pos = idx + next_grapheme.len(); @@ -749,9 +772,9 @@ impl<'a> Iterator for LineBreakCandidateIter<'a> { continue; } RI => { - /* LB30a Break between two regional indicator symbols if and only if there are an - * even number of regional indicators preceding the position of the break. - * sot (RI RI)* RI × RI + /* LB30a Break between two regional indicator symbols if and only if there + * are an even number of regional indicators preceding + * the position of the break. sot (RI RI)* RI × RI * [^RI] (RI RI)* RI × RI */ *reg_ind_streak += 1; *pos += grapheme.len(); @@ -852,8 +875,7 @@ mod tests { pub use alg::linear; mod alg { - use super::super::grapheme_clusters::TextProcessing; - use super::super::*; + use super::super::{grapheme_clusters::TextProcessing, *}; fn cost(i: usize, j: usize, width: usize, minima: &[usize], offsets: &[usize]) -> usize { let w = offsets[j] + j - offsets[i] - i - 1; if w > width { @@ -1060,7 +1082,7 @@ pub fn split_lines_reflow(text: &str, reflow: Reflow, width: Option) -> V } else if prev_quote_depth == quote_depth { /* This becomes part of the paragraph we're in */ } else { - /*Malformed line, different quote depths can't be in the same paragraph. */ + /* Malformed line, different quote depths can't be in the same paragraph. */ let paragraph = &text[paragraph_start..prev_index]; reflow_helper(&mut ret, paragraph, prev_quote_depth, in_paragraph, width); @@ -1071,7 +1093,7 @@ pub fn split_lines_reflow(text: &str, reflow: Reflow, width: Option) -> V let paragraph = &text[paragraph_start..*i]; reflow_helper(&mut ret, paragraph, quote_depth, in_paragraph, width); } else { - /*Malformed line, different quote depths can't be in the same paragraph. */ + /* Malformed line, different quote depths can't be in the same paragraph. */ let paragraph = &text[paragraph_start..prev_index]; reflow_helper(&mut ret, paragraph, prev_quote_depth, in_paragraph, width); let paragraph = &text[prev_index..*i]; @@ -1248,12 +1270,13 @@ easy to take MORE than nothing.'"#; } mod segment_tree { - /*! Simple segment tree implementation for maximum in range queries. This is useful if given an - * array of numbers you want to get the maximum value inside an interval quickly. + /*! Simple segment tree implementation for maximum in range queries. This + * is useful if given an array of numbers you want to get the + * maximum value inside an interval quickly. */ + use std::{convert::TryFrom, iter::FromIterator}; + use smallvec::SmallVec; - use std::convert::TryFrom; - use std::iter::FromIterator; #[derive(Default, Debug, Clone)] pub(super) struct SegmentTree { @@ -1329,8 +1352,9 @@ mod segment_tree { } } -/// A lazy stateful iterator for line breaking text. Useful for very long text where you don't want -/// to linebreak it completely before user requests specific lines. +/// A lazy stateful iterator for line breaking text. Useful for very long text +/// where you don't want to linebreak it completely before user requests +/// specific lines. #[derive(Debug, Clone)] pub struct LineBreakText { text: String, @@ -1511,7 +1535,8 @@ impl Iterator for LineBreakText { } else if prev_quote_depth == quote_depth { /* This becomes part of the paragraph we're in */ } else { - /*Malformed line, different quote depths can't be in the same paragraph. */ + /* Malformed line, different quote depths can't be in the same + * paragraph. */ let paragraph_s = &self.text[paragraph_start..prev_index]; reflow_helper2( &mut paragraph, @@ -1534,7 +1559,8 @@ impl Iterator for LineBreakText { self.width, ); } else { - /*Malformed line, different quote depths can't be in the same paragraph. */ + /* Malformed line, different quote depths can't be in the same + * paragraph. */ let paragraph_s = &self.text[paragraph_start..prev_index]; reflow_helper2( &mut paragraph, diff --git a/melib/src/text_processing/search.rs b/melib/src/text_processing/search.rs index 57282e34..29a76c02 100644 --- a/melib/src/text_processing/search.rs +++ b/melib/src/text_processing/search.rs @@ -19,10 +19,10 @@ * along with meli. If not, see . */ -use super::TextProcessing; - use smallvec::SmallVec; +use super::TextProcessing; + pub trait KMP { fn kmp_search(&self, pattern: &str) -> SmallVec<[usize; 256]>; fn kmp_table(graphemes: &[&str]) -> SmallVec<[i32; 256]> { diff --git a/melib/src/text_processing/types.rs b/melib/src/text_processing/types.rs index b088b79d..a049558c 100644 --- a/melib/src/text_processing/types.rs +++ b/melib/src/text_processing/types.rs @@ -123,15 +123,10 @@ impl From<&str> for LineBreakClass { } } -#[derive(PartialEq, Eq, Debug, Copy, Clone)] +#[derive(PartialEq, Eq, Debug, Copy, Clone, Default)] pub enum Reflow { No, All, + #[default] FormatFlowed, } - -impl Default for Reflow { - fn default() -> Self { - Reflow::FormatFlowed - } -} diff --git a/melib/src/text_processing/wcwidth.rs b/melib/src/text_processing/wcwidth.rs index 3c91f40c..cde86861 100644 --- a/melib/src/text_processing/wcwidth.rs +++ b/melib/src/text_processing/wcwidth.rs @@ -48,7 +48,10 @@ pub struct CodePointsIterator<'a> { } /* - * UTF-8 uses a system of binary prefixes, in which the high bits of each byte mark whether it’s a single byte, the beginning of a multi-byte sequence, or a continuation byte; the remaining bits, concatenated, give the code point index. This table shows how it works: + * UTF-8 uses a system of binary prefixes, in which the high bits of each + * byte mark whether it’s a single byte, the beginning of a multi-byte + * sequence, or a continuation byte; the remaining bits, concatenated, give + * the code point index. This table shows how it works: * * UTF-8 (binary) Code point (binary) Range * 0xxxxxxx xxxxxxx U+0000–U+007F diff --git a/melib/src/thread.rs b/melib/src/thread.rs index 76ed82d8..2af03568 100644 --- a/melib/src/thread.rs +++ b/melib/src/thread.rs @@ -25,36 +25,38 @@ * This module implements Jamie Zawinski's [threading algorithm](https://www.jwz.org/doc/threading.html). Quoted comments (/* " .. " */) are * taken almost verbatim from the algorithm. * - * The entry point of this module is the `Threads` struct and its `new` method. It contains - * `ThreadNodes` which are the nodes in the thread trees that might have messages associated with - * them. The root nodes (first messages in each thread) are stored in `root_set` and `tree` - * vectors. `Threads` has inner mutability since we need to sort without the user having mutable - * ownership. + * The entry point of this module is the `Threads` struct and its `new` + * method. It contains `ThreadNodes` which are the nodes in the thread trees + * that might have messages associated with them. The root nodes (first + * messages in each thread) are stored in `root_set` and `tree` + * vectors. `Threads` has inner mutability since we need to sort without the + * user having mutable ownership. */ -use crate::datetime::UnixTimestamp; -use crate::email::address::StrBuild; -use crate::email::parser::BytesExt; -use crate::email::*; +use crate::{ + datetime::UnixTimestamp, + email::{address::StrBuild, parser::BytesExt, *}, +}; mod iterators; +use std::{ + cmp::Ordering, + collections::{HashMap, HashSet}, + fmt, + iter::FromIterator, + ops::Index, + result::Result as StdResult, + str::FromStr, + string::ToString, + sync::{Arc, RwLock}, +}; + pub use iterators::*; +use smallvec::SmallVec; +use uuid::Uuid; #[cfg(feature = "unicode_algorithms")] use crate::text_processing::grapheme_clusters::*; -use uuid::Uuid; - -use std::cmp::Ordering; -use std::collections::{HashMap, HashSet}; -use std::fmt; -use std::iter::FromIterator; -use std::ops::Index; -use std::result::Result as StdResult; -use std::str::FromStr; -use std::string::ToString; -use std::sync::{Arc, RwLock}; - -use smallvec::SmallVec; type Envelopes = Arc>>; @@ -120,24 +122,35 @@ macro_rules! make { let old_group_hash = $threads.find_group($threads.thread_nodes[&$c].group); let parent_group_hash = $threads.find_group($threads.thread_nodes[&$p].group); if old_group_hash != parent_group_hash { - if let Some(old_env_hashes) = $threads.thread_to_envelope.get(&old_group_hash).cloned() { + if let Some(old_env_hashes) = $threads.thread_to_envelope.get(&old_group_hash).cloned() + { for &env_hash in &old_env_hashes { *$threads.envelope_to_thread.entry(env_hash).or_default() = parent_group_hash; } - $threads.thread_to_envelope.entry(parent_group_hash).or_default().extend(old_env_hashes.into_iter()); + $threads + .thread_to_envelope + .entry(parent_group_hash) + .or_default() + .extend(old_env_hashes.into_iter()); } let prev_parent = remove_from_parent!(&mut $threads.thread_nodes, $c); if !($threads.thread_nodes[&$p]).children.contains(&$c) { - /* Pruned nodes keep their children in case they show up in a later merge, so do not panic - * if children exists */ - $threads.thread_nodes.entry($p).and_modify(|e| e.children.push($c)); + /* Pruned nodes keep their children in case they show up in a later merge, so + * do not panic if children exists */ + $threads + .thread_nodes + .entry($p) + .and_modify(|e| e.children.push($c)); } $threads.thread_nodes.entry($c).and_modify(|e| { e.parent = Some($p); }); - let old_group = std::mem::replace($threads.groups.entry(old_group_hash).or_default(), ThreadGroup::Node { - parent: Arc::new(RwLock::new(parent_group_hash)), - }); + let old_group = std::mem::replace( + $threads.groups.entry(old_group_hash).or_default(), + ThreadGroup::Node { + parent: Arc::new(RwLock::new(parent_group_hash)), + }, + ); $threads.thread_nodes.entry($c).and_modify(|e| { e.group = parent_group_hash; }); @@ -147,21 +160,24 @@ macro_rules! make { { let parent_group = $threads.thread_ref_mut(parent_group_hash); match (parent_group, old_group) { - (Thread { - ref mut date, - ref mut len, - ref mut unseen, - ref mut snoozed, - ref mut attachments, - .. - }, ThreadGroup::Root(Thread { - date: old_date, - len: old_len, - unseen: old_unseen, - snoozed: old_snoozed, - attachments: old_attachments, - .. - })) => { + ( + Thread { + ref mut date, + ref mut len, + ref mut unseen, + ref mut snoozed, + ref mut attachments, + .. + }, + ThreadGroup::Root(Thread { + date: old_date, + len: old_len, + unseen: old_unseen, + snoozed: old_snoozed, + attachments: old_attachments, + .. + }), + ) => { *date = std::cmp::max(old_date, *date); *len += old_len; *unseen += old_unseen; @@ -169,13 +185,13 @@ macro_rules! make { *snoozed |= old_snoozed; } _ => unreachable!(), - } + } } prev_parent } else { None } - }}; + }}; } /// Strip common prefixes from subjects @@ -185,9 +201,15 @@ macro_rules! make { /// use melib::thread::SubjectPrefix; /// /// let mut subject = "Re: RE: Res: Re: Res: Subject"; -/// assert_eq!(subject.strip_prefixes_from_list(<&str>::USUAL_PREFIXES, None), &"Subject"); +/// assert_eq!( +/// subject.strip_prefixes_from_list(<&str>::USUAL_PREFIXES, None), +/// &"Subject" +/// ); /// let mut subject = "Re: RE: Res: Re: Res: Subject"; -/// assert_eq!(subject.strip_prefixes_from_list(<&str>::USUAL_PREFIXES, Some(1)), &"RE: Res: Re: Res: Subject"); +/// assert_eq!( +/// subject.strip_prefixes_from_list(<&str>::USUAL_PREFIXES, Some(1)), +/// &"RE: Res: Re: Res: Subject" +/// ); /// ``` pub trait SubjectPrefix { const USUAL_PREFIXES: &'static [&'static str] = &[ @@ -199,7 +221,7 @@ pub trait SubjectPrefix { "Fw:", /* taken from * https://en.wikipedia.org/wiki/List_of_email_subject_abbreviations#Abbreviations_in_other_languages - * */ + */ "回复:", "回覆:", // Dutch (Antwoord) @@ -919,8 +941,9 @@ impl Threads { .unwrap() .set_thread(thread_hash); - /* If thread node currently has a message from a foreign mailbox and env_hash is - * from current mailbox we want to update it, otherwise return */ + /* If thread node currently has a message from a foreign mailbox and env_hash + * is from current mailbox we want to update it, otherwise + * return */ if node.other_mailbox || other_mailbox { return false; } diff --git a/melib/src/thread/iterators.rs b/melib/src/thread/iterators.rs index 74ded212..99c9d89c 100644 --- a/melib/src/thread/iterators.rs +++ b/melib/src/thread/iterators.rs @@ -19,12 +19,14 @@ * along with meli. If not, see . */ -use super::{ThreadNode, ThreadNodeHash}; -use smallvec::SmallVec; use std::collections::HashMap; -/* `ThreadsIterator` returns messages according to the sorted order. For example, for the following - * threads: +use smallvec::SmallVec; + +use super::{ThreadNode, ThreadNodeHash}; + +/* `ThreadsIterator` returns messages according to the sorted order. For + * example, for the following threads: * * ``` * A_ @@ -82,8 +84,8 @@ impl<'a> Iterator for ThreadsGroupIterator<'a> { } } } -/* `ThreadIterator` returns messages of a specific thread according to the sorted order. For example, for the following - * thread: +/* `ThreadIterator` returns messages of a specific thread according to the + * sorted order. For example, for the following thread: * * ``` * A_ diff --git a/rustfmt.toml b/rustfmt.toml index 32a9786f..c6f0942d 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1 +1,7 @@ edition = "2018" +format_generated_files = false +format_code_in_doc_comments = true +format_strings = true +imports_granularity = "Crate" +group_imports = "StdExternalCrate" +wrap_comments = true diff --git a/src/args.rs b/src/args.rs index aea88e28..d4c0d34a 100644 --- a/src/args.rs +++ b/src/args.rs @@ -67,7 +67,9 @@ pub enum SubCommand { PrintLoadedThemes, /// edit configuration files in `$EDITOR`/`$VISUAL`. EditConfig, - /// create a sample configuration file with available configuration options. If PATH is not specified, meli will try to create it in $XDG_CONFIG_HOME/meli/config.toml + /// create a sample configuration file with available configuration options. + /// If PATH is not specified, meli will try to create it in + /// $XDG_CONFIG_HOME/meli/config.toml #[structopt(display_order = 1)] CreateConfig { #[structopt(value_name = "NEW_CONFIG_PATH", parse(from_os_str))] diff --git a/src/command.rs b/src/command.rs index 562b1a5d..22b24907 100644 --- a/src/command.rs +++ b/src/command.rs @@ -20,35 +20,42 @@ */ /*! A parser module for user commands passed through Command mode. -*/ -use crate::melib::parser::BytesExt; -use melib::nom::{ - self, - branch::alt, - bytes::complete::{is_a, is_not, tag, take_until}, - character::complete::{digit1, not_line_ending}, - combinator::{map, map_res}, - error::Error as NomError, - multi::separated_list1, - sequence::{pair, preceded, separated_pair}, - IResult, -}; + */ pub use melib::thread::{SortField, SortOrder}; -use melib::Error; +use melib::{ + nom::{ + self, + branch::alt, + bytes::complete::{is_a, is_not, tag, take_until}, + character::complete::{digit1, not_line_ending}, + combinator::{map, map_res}, + error::Error as NomError, + multi::separated_list1, + sequence::{pair, preceded, separated_pair}, + IResult, + }, + Error, +}; + +use crate::melib::parser::BytesExt; pub mod actions; -use actions::MailboxOperation; use std::collections::HashSet; + +use actions::MailboxOperation; pub mod history; -pub use crate::actions::AccountAction::{self, *}; -pub use crate::actions::Action::{self, *}; -pub use crate::actions::ComposeAction::{self, *}; -pub use crate::actions::ListingAction::{self, *}; -pub use crate::actions::MailingListAction::{self, *}; -pub use crate::actions::TabAction::{self, *}; -pub use crate::actions::TagAction::{self, *}; -pub use crate::actions::ViewAction::{self, *}; use std::str::FromStr; +pub use crate::actions::{ + AccountAction::{self, *}, + Action::{self, *}, + ComposeAction::{self, *}, + ListingAction::{self, *}, + MailingListAction::{self, *}, + TabAction::{self, *}, + TagAction::{self, *}, + ViewAction::{self, *}, +}; + /// Helper macro to convert an array of tokens into a TokenStream macro_rules! to_stream { ($token: expr) => { @@ -63,7 +70,8 @@ macro_rules! to_stream { }; } -/// Macro to create a const table with every command part that can be auto-completed and its description +/// Macro to create a const table with every command part that can be +/// auto-completed and its description macro_rules! define_commands { ( [$({ tags: [$( $tags:literal),*], desc: $desc:literal, tokens: $tokens:expr, parser: ($parser:item)}),*]) => { pub const COMMAND_COMPLETION: &[(&str, &str, TokenStream)] = &[$($( ($tags, $desc, TokenStream { tokens: $tokens } ) ),*),* ]; @@ -142,7 +150,8 @@ impl TokenStream { | t @ QuotedStringValue | t @ AlphanumericStringValue => { let _t = t; - //sugg.insert(format!("{}{:?}", if s.is_empty() { " " } else { "" }, t)); + //sugg.insert(format!("{}{:?}", if s.is_empty() { " " } + // else { "" }, t)); } } tokens.push((*s, *t.inner())); @@ -209,7 +218,8 @@ impl TokenStream { } } -/// `Token` wrapper that defines how many times a token is expected to be repeated +/// `Token` wrapper that defines how many times a token is expected to be +/// repeated #[derive(Debug, Copy, Clone)] pub enum TokenAdicity { ZeroOrOne(Token), diff --git a/src/command/actions.rs b/src/command/actions.rs index 7152471e..46c8decc 100644 --- a/src/command/actions.rs +++ b/src/command/actions.rs @@ -23,10 +23,12 @@ * User actions that need to be handled by the UI */ -use crate::components::Component; +use std::path::PathBuf; + pub use melib::thread::{SortField, SortOrder}; use melib::uuid::Uuid; -use std::path::PathBuf; + +use crate::components::Component; #[derive(Debug)] pub enum TagAction { diff --git a/src/command/history.rs b/src/command/history.rs index d47d88b5..80436c69 100644 --- a/src/command/history.rs +++ b/src/command/history.rs @@ -19,9 +19,11 @@ * along with meli. If not, see . */ -use std::fs::OpenOptions; -use std::io::{Read, Write}; -use std::sync::{Arc, Mutex}; +use std::{ + fs::OpenOptions, + io::{Read, Write}, + sync::{Arc, Mutex}, +}; thread_local!(static CMD_HISTORY_FILE: Arc> = Arc::new(Mutex::new({ let data_dir = xdg::BaseDirectories::with_prefix("meli").unwrap(); diff --git a/src/components.rs b/src/components.rs index acb3c7b5..c7cc5446 100644 --- a/src/components.rs +++ b/src/components.rs @@ -21,13 +21,16 @@ /*! Components visual and logical separations of application interfaces. * - * They can draw on the terminal and receive events, but also do other stuff as well. (For example, see the `notifications` module.) + * They can draw on the terminal and receive events, but also do other stuff + * as well. (For example, see the `notifications` module.) * See the `Component` Trait for more details. */ use super::*; -use crate::melib::text_processing::{TextProcessing, Truncate}; -use crate::terminal::boundaries::*; +use crate::{ + melib::text_processing::{TextProcessing, Truncate}, + terminal::boundaries::*, +}; pub mod mail; pub use crate::mail::*; @@ -46,8 +49,10 @@ pub use self::mailbox_management::*; #[cfg(feature = "svgscreenshot")] pub mod svg; -use std::fmt; -use std::fmt::{Debug, Display}; +use std::{ + fmt, + fmt::{Debug, Display}, +}; use indexmap::IndexMap; use uuid::Uuid; @@ -86,8 +91,9 @@ pub enum ScrollUpdate { } /// Types implementing this Trait can draw on the terminal and receive events. -/// If a type wants to skip drawing if it has not changed anything, it can hold some flag in its -/// fields (eg self.dirty = false) and act upon that in their `draw` implementation. +/// If a type wants to skip drawing if it has not changed anything, it can hold +/// some flag in its fields (eg self.dirty = false) and act upon that in their +/// `draw` implementation. pub trait Component: Display + Debug + Send + Sync { fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context); fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool; diff --git a/src/components/contacts.rs b/src/components/contacts.rs index e72ab3f2..72b43727 100644 --- a/src/components/contacts.rs +++ b/src/components/contacts.rs @@ -19,9 +19,10 @@ * along with meli. If not, see . */ -use super::*; use std::collections::HashMap; +use super::*; + mod contact_list; pub use self::contact_list::*; diff --git a/src/components/contacts/contact_list.rs b/src/components/contacts/contact_list.rs index adf3717c..b5ce8e2a 100644 --- a/src/components/contacts/contact_list.rs +++ b/src/components/contacts/contact_list.rs @@ -18,12 +18,12 @@ * You should have received a copy of the GNU General Public License * along with meli. If not, see . */ +use std::cmp; + +use melib::{backends::AccountHash, CardId}; + use super::*; use crate::melib::text_processing::TextProcessing; -use melib::backends::AccountHash; -use melib::CardId; - -use std::cmp; #[derive(Debug, PartialEq, Eq)] enum ViewMode { @@ -69,7 +69,7 @@ pub struct ContactList { impl fmt::Display for ContactList { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", "contact list") + write!(f, "contact list") } } @@ -436,8 +436,8 @@ impl ContactList { ))); } - /* If cursor position has changed, remove the highlight from the previous position and - * apply it in the new one. */ + /* If cursor position has changed, remove the highlight from the previous + * position and apply it in the new one. */ if self.cursor_pos != self.new_cursor_pos && prev_page_no == page_no { let old_cursor_pos = self.cursor_pos; self.cursor_pos = self.new_cursor_pos; @@ -464,7 +464,7 @@ impl ContactList { let width = width!(area); self.data_columns.widths = Default::default(); self.data_columns.widths[0] = self.data_columns.columns[0].size().0; /* name */ - self.data_columns.widths[1] = self.data_columns.columns[1].size().0; /* email*/ + self.data_columns.widths[1] = self.data_columns.columns[1].size().0; /* email */ self.data_columns.widths[2] = self.data_columns.columns[2].size().0; /* url */ self.data_columns.widths[3] = self.data_columns.columns[3].size().0; /* source */ @@ -783,7 +783,7 @@ impl Component for ContactList { .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); return true; } - UIEvent::Input(Key::Char(c)) if ('0'..='9').contains(&c) => { + UIEvent::Input(Key::Char(c)) if c.is_ascii_digit() => { self.cmd_buf.push(c); context .replies diff --git a/src/components/mail.rs b/src/components/mail.rs index cb9be3d2..941f5483 100644 --- a/src/components/mail.rs +++ b/src/components/mail.rs @@ -21,10 +21,13 @@ /*! Entities that handle Mail specific functions. */ +use melib::{ + backends::{AccountHash, Mailbox, MailboxHash}, + email::{attachment_types::*, attachments::*}, + thread::ThreadNodeHash, +}; + use super::*; -use melib::backends::{AccountHash, Mailbox, MailboxHash}; -use melib::email::{attachment_types::*, attachments::*}; -use melib::thread::ThreadNodeHash; pub mod listing; pub use crate::listing::*; diff --git a/src/components/mail/compose.rs b/src/components/mail/compose.rs index c6a35ce9..a8f91d98 100644 --- a/src/components/mail/compose.rs +++ b/src/components/mail/compose.rs @@ -19,21 +19,23 @@ * along with meli. If not, see . */ -use super::*; -use melib::email::attachment_types::{ContentType, MultipartType}; -use melib::list_management; -use melib::Draft; +use std::{ + convert::TryInto, + future::Future, + pin::Pin, + process::{Command, Stdio}, + sync::{Arc, Mutex}, +}; -use crate::conf::accounts::JobRequest; -use crate::jobs::JoinHandle; -use crate::terminal::embed::EmbedTerminal; use indexmap::IndexSet; +use melib::{ + email::attachment_types::{ContentType, MultipartType}, + list_management, Draft, +}; use nix::sys::wait::WaitStatus; -use std::convert::TryInto; -use std::future::Future; -use std::pin::Pin; -use std::process::{Command, Stdio}; -use std::sync::{Arc, Mutex}; + +use super::*; +use crate::{conf::accounts::JobRequest, jobs::JoinHandle, terminal::embed::EmbedTerminal}; #[cfg(feature = "gpgme")] mod gpg; @@ -373,8 +375,9 @@ impl Composer { let mut ret = Composer::reply_to(coordinates, reply_body, context, false); let account = &context.accounts[&coordinates.0]; let parent_message = account.collection.get_env(coordinates.2); - /* If message is from a mailing list and we detect a List-Post header, ask user if they - * want to reply to the mailing list or the submitter of the message */ + /* If message is from a mailing list and we detect a List-Post header, ask + * user if they want to reply to the mailing list or the submitter of + * the message */ if let Some(actions) = list_management::ListActions::detect(&parent_message) { if let Some(post) = actions.post { if let list_management::ListAction::Email(list_post_addr) = post[0] { @@ -1104,20 +1107,27 @@ impl Component for Composer { ))); self.mode = ViewMode::WaitingForSendResult( UIDialog::new( - "Waiting for confirmation.. The tab will close automatically on successful submission.", + "Waiting for confirmation.. The tab will close automatically \ + on successful submission.", vec![ - ('c', "force close tab".to_string()), - ('n', "close this message and return to edit mode".to_string()), + ('c', "force close tab".to_string()), + ( + 'n', + "close this message and return to edit mode" + .to_string(), + ), ], true, Some(Box::new(move |id: ComponentId, results: &[char]| { Some(UIEvent::FinishedUIDialog( - id, - Box::new(results.first().cloned().unwrap_or('c')), + id, + Box::new(results.first().cloned().unwrap_or('c')), )) })), context, - ), handle); + ), + handle, + ); } Err(err) => { context.replies.push_back(UIEvent::Notification( @@ -1680,10 +1690,12 @@ impl Component for Composer { match std::env::var("EDITOR") { Err(err) => { context.replies.push_back(UIEvent::Notification( - Some(err.to_string()), - "$EDITOR is not set. You can change an envvar's value with setenv or set composing.editor_command setting in your configuration.".to_string(), - Some(NotificationType::Error(melib::error::ErrorKind::None)), - )); + Some(err.to_string()), + "$EDITOR is not set. You can change an envvar's value with setenv \ + or set composing.editor_command setting in your configuration." + .to_string(), + Some(NotificationType::Error(melib::error::ErrorKind::None)), + )); return true; } Ok(v) => v, @@ -1744,7 +1756,7 @@ impl Component for Composer { DEBUG, ); match Command::new("sh") - .args(&["-c", &editor_command]) + .args(["-c", &editor_command]) .stdin(Stdio::inherit()) .stdout(Stdio::inherit()) .spawn() @@ -1798,7 +1810,7 @@ impl Component for Composer { } let f = create_temp_file(&[], None, None, true); match Command::new("sh") - .args(&["-c", command]) + .args(["-c", command]) .stdin(Stdio::null()) .stdout(Stdio::from(f.file())) .spawn() @@ -1886,7 +1898,7 @@ impl Component for Composer { DEBUG, ); match Command::new("sh") - .args(&["-c", command]) + .args(["-c", command]) .stdin(Stdio::inherit()) .stdout(Stdio::inherit()) .stderr(Stdio::piped()) diff --git a/src/components/mail/compose/edit_attachments.rs b/src/components/mail/compose/edit_attachments.rs index 9e1a61a8..baa9d444 100644 --- a/src/components/mail/compose/edit_attachments.rs +++ b/src/components/mail/compose/edit_attachments.rs @@ -21,18 +21,13 @@ use super::*; -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] pub enum EditAttachmentCursor { AttachmentNo(usize), + #[default] Buttons, } -impl Default for EditAttachmentCursor { - fn default() -> Self { - EditAttachmentCursor::Buttons - } -} - #[derive(Debug)] pub enum EditAttachmentMode { Overview, diff --git a/src/components/mail/listing.rs b/src/components/mail/listing.rs index 5a0e9d06..c99fef29 100644 --- a/src/components/mail/listing.rs +++ b/src/components/mail/listing.rs @@ -19,27 +19,32 @@ * along with meli. If not, see . */ -use super::*; -use crate::conf::accounts::JobRequest; -use crate::types::segment_tree::SegmentTree; +use std::{ + collections::{BTreeSet, HashMap, HashSet}, + convert::TryFrom, + ops::{Deref, DerefMut}, +}; + use melib::backends::EnvelopeHashBatch; use smallvec::SmallVec; -use std::collections::{BTreeSet, HashMap, HashSet}; -use std::convert::TryFrom; -use std::ops::{Deref, DerefMut}; -// TODO: emoji_text_presentation_selector should be printed along with the chars before it but not -// as a separate Cell +use super::*; +use crate::{conf::accounts::JobRequest, types::segment_tree::SegmentTree}; + +// TODO: emoji_text_presentation_selector should be printed along with the chars +// before it but not as a separate Cell //macro_rules! emoji_text_presentation_selector { // () => { // "\u{FE0E}" // }; //} // -//pub const DEFAULT_ATTACHMENT_FLAG: &str = concat!("📎", emoji_text_presentation_selector!()); -//pub const DEFAULT_SELECTED_FLAG: &str = concat!("☑️", emoji_text_presentation_selector!()); -//pub const DEFAULT_UNSEEN_FLAG: &str = concat!("●", emoji_text_presentation_selector!()); -//pub const DEFAULT_SNOOZED_FLAG: &str = concat!("💤", emoji_text_presentation_selector!()); +//pub const DEFAULT_ATTACHMENT_FLAG: &str = concat!("📎", +// emoji_text_presentation_selector!()); pub const DEFAULT_SELECTED_FLAG: &str = +// concat!("☑️", emoji_text_presentation_selector!()); +// pub const DEFAULT_UNSEEN_FLAG: &str = concat!("●", +// emoji_text_presentation_selector!()); pub const DEFAULT_SNOOZED_FLAG: &str = +// concat!("💤", emoji_text_presentation_selector!()); pub const DEFAULT_ATTACHMENT_FLAG: &str = "📎"; pub const DEFAULT_SELECTED_FLAG: &str = "☑️"; @@ -225,20 +230,15 @@ pub enum Focus { EntryFullscreen, } -#[derive(Debug, Copy, PartialEq, Eq, Clone)] +#[derive(Debug, Copy, PartialEq, Eq, Clone, Default)] pub enum Modifier { + #[default] SymmetricDifference, Union, Difference, Intersection, } -impl Default for Modifier { - fn default() -> Self { - Modifier::SymmetricDifference - } -} - #[derive(Debug, Default)] /// Save theme colors to avoid looking them up again and again from settings pub struct ColorCache { @@ -601,10 +601,9 @@ pub trait MailListingTrait: ListingTrait { } } ListingAction::ExportMbox(format, ref path) => { + use std::{future::Future, io::Write, pin::Pin}; + use futures::future::try_join_all; - use std::future::Future; - use std::io::Write; - use std::pin::Pin; let futures: Result> = envs_to_set .iter() @@ -725,7 +724,8 @@ pub trait MailListingTrait: ListingTrait { ) { } - /// Use `force` when there have been changes in the mailbox or account lists in `context` + /// Use `force` when there have been changes in the mailbox or account lists + /// in `context` fn refresh_mailbox(&mut self, context: &mut Context, force: bool); } @@ -1357,7 +1357,7 @@ impl Component for Listing { .mailbox_by_path(mailbox_path) .and_then(|mailbox_hash| { Ok(( - std::fs::read(&file_path).chain_err_summary(|| { + std::fs::read(file_path).chain_err_summary(|| { format!("Could not read {}", file_path.display()) })?, mailbox_hash, @@ -1716,7 +1716,8 @@ impl Component for Listing { *account_cursor += 1; *entry_cursor = MenuEntryCursor::Status; } - /* If current account has no mailboxes and there is no next account, return true */ + /* If current account has no mailboxes and there is no next + * account, return true */ (_, MenuEntryCursor::Status) => { return true; } @@ -1929,7 +1930,7 @@ impl Component for Listing { .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); return true; } - UIEvent::Input(Key::Char(c)) if ('0'..='9').contains(&c) => { + UIEvent::Input(Key::Char(c)) if c.is_ascii_digit() => { self.cmd_buf.push(c); self.component.set_modifier_active(true); context @@ -2309,8 +2310,8 @@ impl Listing { let mut branches = String::with_capacity(16); // What depth to skip if a mailbox is toggled to collapse - // The value should be the collapsed mailbox's indentation, so that its children are not - // visible. + // The value should be the collapsed mailbox's indentation, so that its children + // are not visible. let mut skip: Option = None; let mut skipped_counter: usize = 0; 'grid_loop: for y in get_y(upper_left) + 1..get_y(bottom_right) { @@ -2381,8 +2382,8 @@ impl Listing { ) }; - /* Calculate how many columns the mailbox index tags should occupy with right alignment, - * eg. + /* Calculate how many columns the mailbox index tags should occupy with right + * alignment, eg. * 1 * 2 * ... diff --git a/src/components/mail/listing/compact.rs b/src/components/mail/listing/compact.rs index ed90dd28..0466c413 100644 --- a/src/components/mail/listing/compact.rs +++ b/src/components/mail/listing/compact.rs @@ -19,14 +19,12 @@ * along with meli. If not, see . */ -use super::*; -use crate::components::PageMovement; -use crate::jobs::JoinHandle; +use std::{cmp, collections::BTreeMap, convert::TryInto, iter::FromIterator}; + use indexmap::IndexSet; -use std::cmp; -use std::collections::BTreeMap; -use std::convert::TryInto; -use std::iter::FromIterator; + +use super::*; +use crate::{components::PageMovement, jobs::JoinHandle}; macro_rules! digits_of_num { ($num:expr) => {{ @@ -158,8 +156,8 @@ macro_rules! row_attr { }}; } -/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the `Envelope` content in a -/// `ThreadView`. +/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the +/// `Envelope` content in a `ThreadView`. #[derive(Debug)] pub struct CompactListing { /// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox. @@ -239,8 +237,8 @@ impl MailListingTrait for CompactListing { SmallVec::from_iter(iter) } - /// Fill the `self.data_columns` `CellBuffers` with the contents of the account mailbox the user has - /// chosen. + /// Fill the `self.data_columns` `CellBuffers` with the contents of the + /// account mailbox the user has chosen. fn refresh_mailbox(&mut self, context: &mut Context, force: bool) { self.set_dirty(true); self.rows.clear(); @@ -565,7 +563,7 @@ impl ListingTrait for CompactListing { fn set_coordinates(&mut self, coordinates: (AccountHash, MailboxHash)) { self.new_cursor_pos = (coordinates.0, coordinates.1, 0); self.focus = Focus::None; - self.view = Box::new(ThreadView::default()); + self.view = Box::::default(); self.filtered_selection.clear(); self.filtered_order.clear(); self.filter_term.clear(); @@ -692,8 +690,8 @@ impl ListingTrait for CompactListing { let end_idx = cmp::min(self.length.saturating_sub(1), top_idx + rows - 1); self.draw_rows(context, top_idx, end_idx); - /* If cursor position has changed, remove the highlight from the previous position and - * apply it in the new one. */ + /* If cursor position has changed, remove the highlight from the previous + * position and apply it in the new one. */ if self.cursor_pos.2 != self.new_cursor_pos.2 && prev_page_no == page_no { let old_cursor_pos = self.cursor_pos; self.cursor_pos = self.new_cursor_pos; @@ -840,9 +838,10 @@ impl ListingTrait for CompactListing { self.view .process_event(&mut UIEvent::VisibilityChange(false), context); self.dirty = true; - /* If self.rows.row_updates is not empty and we exit a thread, the row_update events - * will be performed but the list will not be drawn. So force a draw in any case. - * */ + /* If self.rows.row_updates is not empty and we exit a thread, the row_update + * events will be performed but the list will not be drawn. + * So force a draw in any case. + */ self.force_draw = true; } Focus::Entry => { @@ -889,7 +888,7 @@ impl CompactListing { rows: RowsState::default(), dirty: true, force_draw: true, - view: Box::new(ThreadView::default()), + view: Box::::default(), color_cache: ColorCache::default(), movement: None, modifier_active: false, @@ -1064,8 +1063,8 @@ impl CompactListing { let account = &context.accounts[&self.cursor_pos.0]; if !account.contains_key(env_hash) { - /* The envelope has been renamed or removed, so wait for the appropriate event to - * arrive */ + /* The envelope has been renamed or removed, so wait for the appropriate + * event to arrive */ return; } let tags_lck = account.collection.tag_index.read().unwrap(); diff --git a/src/components/mail/listing/conversations.rs b/src/components/mail/listing/conversations.rs index bee30123..d9751d61 100644 --- a/src/components/mail/listing/conversations.rs +++ b/src/components/mail/listing/conversations.rs @@ -19,12 +19,12 @@ * along with meli. If not, see . */ -use super::*; -use crate::components::PageMovement; -use crate::jobs::JoinHandle; +use std::{collections::BTreeMap, iter::FromIterator}; + use indexmap::IndexSet; -use std::collections::BTreeMap; -use std::iter::FromIterator; + +use super::*; +use crate::{components::PageMovement, jobs::JoinHandle}; macro_rules! row_attr { ($field:ident, $color_cache:expr, $unseen:expr, $highlighted:expr, $selected:expr $(,)*) => {{ @@ -91,8 +91,8 @@ macro_rules! row_attr { }}; } -/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the `Envelope` content in a -/// `ThreadView`. +/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the +/// `Envelope` content in a `ThreadView`. #[derive(Debug)] pub struct ConversationsListing { /// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox. @@ -455,8 +455,8 @@ impl ListingTrait for ConversationsListing { let top_idx = page_no * rows; - /* If cursor position has changed, remove the highlight from the previous position and - * apply it in the new one. */ + /* If cursor position has changed, remove the highlight from the previous + * position and apply it in the new one. */ if self.cursor_pos.2 != self.new_cursor_pos.2 && prev_page_no == page_no { let old_cursor_pos = self.cursor_pos; self.cursor_pos = self.new_cursor_pos; @@ -582,9 +582,10 @@ impl ListingTrait for ConversationsListing { self.view .process_event(&mut UIEvent::VisibilityChange(false), context); self.dirty = true; - /* If self.rows.row_updates is not empty and we exit a thread, the row_update events - * will be performed but the list will not be drawn. So force a draw in any case. - * */ + /* If self.rows.row_updates is not empty and we exit a thread, the row_update + * events will be performed but the list will not be drawn. + * So force a draw in any case. + */ self.force_draw = true; } Focus::Entry => { @@ -1181,7 +1182,7 @@ impl Component for ConversationsListing { if !self.rows.row_updates.is_empty() { /* certain rows need to be updated (eg an unseen message was just set seen) - * */ + */ while let Some(row) = self.rows.row_updates.pop() { self.update_line(context, row); let row: usize = self.rows.env_order[&row]; @@ -1379,7 +1380,8 @@ impl Component for ConversationsListing { // FIXME subsort //if !self.filtered_selection.is_empty() { // let threads = &account.collection.threads[&self.cursor_pos.1]; - // threads.vec_inner_sort_by(&mut self.filtered_selection, self.sort, &account.collection); + // threads.vec_inner_sort_by(&mut self.filtered_selection, self.sort, + // &account.collection); //} else { // self.refresh_mailbox(context, false); //} diff --git a/src/components/mail/listing/offline.rs b/src/components/mail/listing/offline.rs index 3fdcebe7..aa4a83e0 100644 --- a/src/components/mail/listing/offline.rs +++ b/src/components/mail/listing/offline.rs @@ -19,9 +19,10 @@ * along with meli. If not, see . */ +use std::borrow::Cow; + use super::*; use crate::components::PageMovement; -use std::borrow::Cow; #[derive(Debug)] pub struct OfflineListing { diff --git a/src/components/mail/listing/plain.rs b/src/components/mail/listing/plain.rs index 94e692d3..d7af0c33 100644 --- a/src/components/mail/listing/plain.rs +++ b/src/components/mail/listing/plain.rs @@ -19,12 +19,10 @@ * along with meli. If not, see . */ -use super::EntryStrings; -use super::*; -use crate::components::PageMovement; -use crate::jobs::JoinHandle; -use std::cmp; -use std::iter::FromIterator; +use std::{cmp, iter::FromIterator}; + +use super::{EntryStrings, *}; +use crate::{components::PageMovement, jobs::JoinHandle}; macro_rules! address_list { (($name:expr) as comma_sep_list) => {{ @@ -118,8 +116,8 @@ macro_rules! row_attr { }}; } -/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the `Envelope` content in a -/// `MailView`. +/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the +/// `Envelope` content in a `MailView`. #[derive(Debug)] pub struct PlainListing { /// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox. @@ -182,8 +180,8 @@ impl MailListingTrait for PlainListing { ) } - /// Fill the `self.data_columns` `CellBuffers` with the contents of the account mailbox the user has - /// chosen. + /// Fill the `self.data_columns` `CellBuffers` with the contents of the + /// account mailbox the user has chosen. fn refresh_mailbox(&mut self, context: &mut Context, force: bool) { self.set_dirty(true); let old_cursor_pos = self.cursor_pos; @@ -423,8 +421,8 @@ impl ListingTrait for PlainListing { let top_idx = page_no * rows; - /* If cursor position has changed, remove the highlight from the previous position and - * apply it in the new one. */ + /* If cursor position has changed, remove the highlight from the previous + * position and apply it in the new one. */ if self.cursor_pos.2 != self.new_cursor_pos.2 && prev_page_no == page_no { let old_cursor_pos = self.cursor_pos; self.cursor_pos = self.new_cursor_pos; @@ -571,9 +569,10 @@ impl ListingTrait for PlainListing { self.view .process_event(&mut UIEvent::VisibilityChange(false), context); self.dirty = true; - /* If self.rows.row_updates is not empty and we exit a thread, the row_update events - * will be performed but the list will not be drawn. So force a draw in any case. - * */ + /* If self.rows.row_updates is not empty and we exit a thread, the row_update + * events will be performed but the list will not be drawn. + * So force a draw in any case. + */ self.force_draw = true; } Focus::Entry => { @@ -973,8 +972,8 @@ impl PlainListing { let account = &context.accounts[&self.cursor_pos.0]; if !account.contains_key(env_hash) { - /* The envelope has been renamed or removed, so wait for the appropriate event to - * arrive */ + /* The envelope has been renamed or removed, so wait for the appropriate + * event to arrive */ return; } let envelope: EnvelopeRef = account.collection.get_env(env_hash); @@ -1425,7 +1424,8 @@ impl Component for PlainListing { self.subsort = (*field, *order); //if !self.filtered_selection.is_empty() { // let threads = &account.collection.threads[&self.cursor_pos.1]; - // threads.vec_inner_sort_by(&mut self.filtered_selection, self.sort, &account.collection); + // threads.vec_inner_sort_by(&mut self.filtered_selection, self.sort, + // &account.collection); //} else { // self.refresh_mailbox(contex, falset); //} diff --git a/src/components/mail/listing/thread.rs b/src/components/mail/listing/thread.rs index 765be9cf..ed0398f2 100644 --- a/src/components/mail/listing/thread.rs +++ b/src/components/mail/listing/thread.rs @@ -19,12 +19,10 @@ * along with meli. If not, see . */ +use std::{cmp, convert::TryInto, fmt::Write, iter::FromIterator}; + use super::*; use crate::components::PageMovement; -use std::cmp; -use std::convert::TryInto; -use std::fmt::Write; -use std::iter::FromIterator; macro_rules! row_attr { ($color_cache:expr, $even: expr, $unseen:expr, $highlighted:expr, $selected:expr $(,)*) => {{ @@ -102,8 +100,8 @@ macro_rules! row_attr { }}; } -/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the `Envelope` content in a -/// `MailView`. +/// A list of all mail (`Envelope`s) in a `Mailbox`. On `\n` it opens the +/// `Envelope` content in a `MailView`. #[derive(Debug)] pub struct ThreadListing { /// (x, y, z): x is accounts, y is mailboxes, z is index inside a mailbox. @@ -167,8 +165,8 @@ impl MailListingTrait for ThreadListing { ) } - /// Fill the `self.content` `CellBuffer` with the contents of the account mailbox the user has - /// chosen. + /// Fill the `self.content` `CellBuffer` with the contents of the account + /// mailbox the user has chosen. fn refresh_mailbox(&mut self, context: &mut Context, _force: bool) { self.set_dirty(true); if !(self.cursor_pos.0 == self.new_cursor_pos.0 @@ -485,8 +483,8 @@ impl ListingTrait for ThreadListing { let top_idx = page_no * rows; - /* If cursor position has changed, remove the highlight from the previous position and - * apply it in the new one. */ + /* If cursor position has changed, remove the highlight from the previous + * position and apply it in the new one. */ if self.cursor_pos.2 != self.new_cursor_pos.2 && prev_page_no == page_no { let old_cursor_pos = self.cursor_pos; self.cursor_pos = self.new_cursor_pos; @@ -634,9 +632,10 @@ impl ListingTrait for ThreadListing { Focus::None => { self.view = None; self.dirty = true; - /* If self.rows.row_updates is not empty and we exit a thread, the row_update events - * will be performed but the list will not be drawn. So force a draw in any case. - * */ + /* If self.rows.row_updates is not empty and we exit a thread, the row_update + * events will be performed but the list will not be drawn. + * So force a draw in any case. + */ self.force_draw = true; } Focus::Entry => { @@ -982,8 +981,8 @@ impl ThreadListing { let account = &context.accounts[&self.cursor_pos.0]; if !account.contains_key(env_hash) { - /* The envelope has been renamed or removed, so wait for the appropriate event to - * arrive */ + /* The envelope has been renamed or removed, so wait for the appropriate + * event to arrive */ return; } let envelope: EnvelopeRef = account.collection.get_env(env_hash); diff --git a/src/components/mail/pgp.rs b/src/components/mail/pgp.rs index 06a11d59..89516003 100644 --- a/src/components/mail/pgp.rs +++ b/src/components/mail/pgp.rs @@ -22,15 +22,17 @@ //FIXME #![allow(unused_imports, unused_variables)] -use melib::email::{ - attachment_types::{ContentDisposition, ContentType, MultipartType}, - pgp as melib_pgp, Attachment, AttachmentBuilder, +use std::{future::Future, pin::Pin}; + +use melib::{ + email::{ + attachment_types::{ContentDisposition, ContentType, MultipartType}, + pgp as melib_pgp, Attachment, AttachmentBuilder, + }, + error::*, + gpgme::*, + parser::BytesExt, }; -use melib::error::*; -use melib::gpgme::*; -use melib::parser::BytesExt; -use std::future::Future; -use std::pin::Pin; pub async fn decrypt(raw: Vec) -> Result<(melib_pgp::DecryptionMetadata, Vec)> { Err("libgpgme functions are temporarily disabled due to an unsolved bug .".into()) diff --git a/src/components/mail/status.rs b/src/components/mail/status.rs index 4748e92f..b93e93a1 100644 --- a/src/components/mail/status.rs +++ b/src/components/mail/status.rs @@ -33,7 +33,7 @@ pub struct AccountStatus { impl fmt::Display for AccountStatus { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", "status") + write!(f, "status") } } @@ -368,8 +368,8 @@ impl Component for AccountStatus { } } - /* self.content may have been resized with write_string_to_grid() calls above since it has - * growable set */ + /* self.content may have been resized with write_string_to_grid() calls above + * since it has growable set */ let (width, height) = self.content.size(); let (cols, rows) = (width!(area), height!(area)); self.cursor = ( diff --git a/src/components/mail/view.rs b/src/components/mail/view.rs index 88b6fb56..16617154 100644 --- a/src/components/mail/view.rs +++ b/src/components/mail/view.rs @@ -19,20 +19,23 @@ * along with meli. If not, see . */ -use super::*; -use crate::conf::accounts::JobRequest; -use crate::jobs::{JobId, JoinHandle}; -use melib::email::attachment_types::ContentType; -use melib::list_management; -use melib::parser::BytesExt; -use smallvec::SmallVec; -use std::collections::HashSet; -use std::fmt::Write as _; -use std::io::Write; +use std::{ + collections::HashSet, + convert::TryFrom, + fmt::Write as _, + io::Write, + os::unix::fs::PermissionsExt, + process::{Command, Stdio}, +}; -use std::convert::TryFrom; -use std::os::unix::fs::PermissionsExt; -use std::process::{Command, Stdio}; +use melib::{email::attachment_types::ContentType, list_management, parser::BytesExt}; +use smallvec::SmallVec; + +use super::*; +use crate::{ + conf::accounts::JobRequest, + jobs::{JobId, JoinHandle}, +}; mod html; pub use self::html::*; @@ -40,11 +43,11 @@ mod thread; pub use self::thread::*; mod envelope; -pub use self::envelope::*; - use linkify::LinkFinder; use xdg_utils::query_default_app; +pub use self::envelope::*; + #[derive(Debug, Default)] enum ForceCharset { #[default] @@ -68,8 +71,9 @@ enum Source { Raw, } -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Debug, Default)] enum ViewMode { + #[default] Normal, Url, Attachment(usize), @@ -79,12 +83,6 @@ enum ViewMode { ContactSelector(Box>), } -impl Default for ViewMode { - fn default() -> Self { - ViewMode::Normal - } -} - impl ViewMode { /* fn is_ansi(&self) -> bool { @@ -158,8 +156,8 @@ pub enum AttachmentDisplay { }, } -/// Contains an Envelope view, with sticky headers, a pager for the body, and subviews for more -/// menus +/// Contains an Envelope view, with sticky headers, a pager for the body, and +/// subviews for more menus #[derive(Debug, Default)] pub struct MailView { coordinates: (AccountHash, MailboxHash, EnvelopeHash), @@ -322,7 +320,7 @@ impl Clone for MailView { impl fmt::Display for MailView { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", "view mail") + write!(f, "view mail") } } @@ -739,7 +737,7 @@ impl MailView { branches, paths, cur_path, - iter.peek() != None, + iter.peek().is_some(), s, ); if Some(i) == default_alternative { @@ -795,7 +793,7 @@ impl MailView { .map(|s| s.as_str()) .unwrap_or("w3m -I utf-8 -T text/html"); let command_obj = Command::new("sh") - .args(&["-c", filter_invocation]) + .args(["-c", filter_invocation]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn(); @@ -810,9 +808,10 @@ impl MailView { Some(NotificationType::Error(melib::ErrorKind::External)), )); let comment = Some(format!( - "Failed to start html filter process: `{}`. Press `v` to open in web browser. \n\n", - filter_invocation - )); + "Failed to start html filter process: `{}`. Press `v` to open in web \ + browser. \n\n", + filter_invocation + )); let text = String::from_utf8_lossy(&bytes).to_string(); acc.push(AttachmentDisplay::InlineText { inner: Box::new(a.clone()), @@ -975,9 +974,12 @@ impl MailView { #[cfg(not(feature = "gpgme"))] { acc.push(AttachmentDisplay::EncryptedFailed { - inner: Box::new(a.clone()), - error: Error::new("Cannot decrypt: meli must be compiled with libgpgme support."), - }); + inner: Box::new(a.clone()), + error: Error::new( + "Cannot decrypt: meli must be compiled with libgpgme \ + support.", + ), + }); } #[cfg(feature = "gpgme")] { @@ -1185,8 +1187,8 @@ impl Component for MailView { let y: usize = { let account = &context.accounts[&self.coordinates.0]; if !account.contains_key(self.coordinates.2) { - /* The envelope has been renamed or removed, so wait for the appropriate event to - * arrive */ + /* The envelope has been renamed or removed, so wait for the appropriate + * event to arrive */ return; } let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2); @@ -1866,7 +1868,8 @@ impl Component for MailView { } if handle.job_id == *job_id => { match handle.chan.try_recv() { Err(_) => { /* Job was canceled */ } - Ok(None) => { /* something happened, perhaps a worker thread panicked */ + Ok(None) => { /* something happened, perhaps a worker + * thread panicked */ } Ok(Some(Ok(bytes))) => { MailViewState::load_bytes(self, bytes, context); @@ -1895,7 +1898,9 @@ impl Component for MailView { self.initialised = false; match handle.chan.try_recv() { Err(_) => { /* Job was canceled */ } - Ok(None) => { /* something happened, perhaps a worker thread panicked */ + Ok(None) => { /* something happened, + * perhaps a worker thread + * panicked */ } Ok(Some(Ok(()))) => { *d = AttachmentDisplay::SignedVerified { @@ -1930,7 +1935,9 @@ impl Component for MailView { self.initialised = false; match handle.chan.try_recv() { Err(_) => { /* Job was canceled */ } - Ok(None) => { /* something happened, perhaps a worker thread panicked */ + Ok(None) => { /* something happened, + * perhaps a worker thread + * panicked */ } Ok(Some(Ok((metadata, decrypted_bytes)))) => { let plaintext = Box::new( @@ -2108,35 +2115,36 @@ impl Component for MailView { on_finish: Some(CallbackFn(Box::new(move |context: &mut Context| { match receiver.try_recv() { Err(_) => { /* Job was canceled */ } - Ok(None) => { /* something happened, perhaps a worker thread panicked */ + Ok(None) => { /* something happened, perhaps a worker + * thread panicked */ } Ok(Some(result)) => { match result.and_then(|bytes| { Composer::edit(account_hash, env_hash, &bytes, context) }) { Ok(composer) => { - context.replies.push_back(UIEvent::Action(Tab(New(Some( - Box::new(composer), - ))))); + context.replies.push_back(UIEvent::Action(Tab(New( + Some(Box::new(composer)), + )))); } Err(err) => { let err_string = format!( "Failed to open envelope {}: {}", context.accounts[&account_hash] - .collection - .envelopes - .read() - .unwrap() - .get(&env_hash) - .map(|env| env.message_id_display()) - .unwrap_or_else(|| "Not found".into()), + .collection + .envelopes + .read() + .unwrap() + .get(&env_hash) + .map(|env| env.message_id_display()) + .unwrap_or_else(|| "Not found".into()), err ); log(&err_string, ERROR); context.replies.push_back(UIEvent::Notification( - Some("Failed to open e-mail".to_string()), - err_string, - Some(NotificationType::Error(err.kind)), + Some("Failed to open e-mail".to_string()), + err_string, + Some(NotificationType::Error(err.kind)), )); } } @@ -2176,7 +2184,7 @@ impl Component for MailView { .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); return true; } - UIEvent::Input(Key::Char(c)) if ('0'..='9').contains(&c) => { + UIEvent::Input(Key::Char(c)) if c.is_ascii_digit() => { self.cmd_buf.push(c); context .replies @@ -2316,7 +2324,7 @@ impl Component for MailView { false, ); match Command::new("sh") - .args(&["-c", &exec_cmd]) + .args(["-c", &exec_cmd]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() @@ -2336,19 +2344,22 @@ impl Component for MailView { } } 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 {})", - filename, - attachment_type - ) - } else { - format!( - "Couldn't find a default application for type {}", - attachment_type - ) - }), - )); + StatusEvent::DisplayMessage( + if let Some(filename) = filename.as_ref() { + format!( + "Couldn't find a default application for \ + file {} (type {})", + filename, attachment_type + ) + } else { + format!( + "Couldn't find a default application for \ + type {}", + attachment_type + ) + }, + ), + )); } } ContentType::OctetStream { @@ -2357,9 +2368,10 @@ impl Component for MailView { } => { context.replies.push_back(UIEvent::StatusEvent( StatusEvent::DisplayMessage(format!( - "Failed to open {}. application/octet-stream isn't supported yet", - name.as_ref().map(|n| n.as_str()).unwrap_or("file") - )), + "Failed to open {}. application/octet-stream isn't \ + supported yet", + name.as_ref().map(|n| n.as_str()).unwrap_or("file") + )), )); } } @@ -2479,8 +2491,8 @@ impl Component for MailView { // Save entire message as eml let account = &context.accounts[&self.coordinates.0]; if !account.contains_key(self.coordinates.2) { - /* The envelope has been renamed or removed, so wait for the appropriate event to - * arrive */ + /* The envelope has been renamed or removed, so wait for the appropriate + * event to arrive */ return true; } let bytes = if let MailViewState::Loaded { ref bytes, .. } = self.state { @@ -2532,8 +2544,8 @@ impl Component for MailView { { let account = &context.accounts[&self.coordinates.0]; if !account.contains_key(self.coordinates.2) { - /* The envelope has been renamed or removed, so wait for the appropriate event to - * arrive */ + /* The envelope has been renamed or removed, so wait for the appropriate + * event to arrive */ return true; } } @@ -2626,8 +2638,8 @@ impl Component for MailView { UIEvent::Action(MailingListAction(ref e)) => { let account = &context.accounts[&self.coordinates.0]; if !account.contains_key(self.coordinates.2) { - /* The envelope has been renamed or removed, so wait for the appropriate event to - * arrive */ + /* The envelope has been renamed or removed, so wait for the appropriate + * event to arrive */ return true; } let envelope: EnvelopeRef = account.collection.get_env(self.coordinates.2); @@ -2661,7 +2673,7 @@ impl Component for MailView { return true; } MailingListAction::ListUnsubscribe if actions.unsubscribe.is_some() => { - /* autosend or open unsubscribe option*/ + /* autosend or open unsubscribe option */ let unsubscribe = actions.unsubscribe.as_ref().unwrap(); for option in unsubscribe.iter() { /* TODO: Ask for confirmation before proceding with an action */ diff --git a/src/components/mail/view/envelope.rs b/src/components/mail/view/envelope.rs index 616d835a..d37dd32a 100644 --- a/src/components/mail/view/envelope.rs +++ b/src/components/mail/view/envelope.rs @@ -19,12 +19,13 @@ * along with meli. If not, see . */ -use super::*; -use linkify::{Link, LinkFinder}; use std::process::{Command, Stdio}; +use linkify::{Link, LinkFinder}; use xdg_utils::query_default_app; +use super::*; + #[derive(PartialEq, Eq, Debug)] enum ViewMode { Normal, @@ -40,8 +41,8 @@ impl ViewMode { } } -/// Contains an Envelope view, with sticky headers, a pager for the body, and subviews for more -/// menus +/// Contains an Envelope view, with sticky headers, a pager for the body, and +/// subviews for more menus #[derive(Debug)] pub struct EnvelopeView { pager: Option, @@ -91,7 +92,7 @@ impl EnvelopeView { let settings = &context.settings; if let Some(filter_invocation) = settings.pager.html_filter.as_ref() { let command_obj = Command::new("sh") - .args(&["-c", filter_invocation]) + .args(["-c", filter_invocation]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn(); @@ -114,9 +115,10 @@ impl EnvelopeView { .write_all(v) .expect("Failed to write to stdin"); *v = format!( - "Text piped through `{}`. Press `v` to open in web browser. \n\n", - filter_invocation - ) + "Text piped through `{}`. Press `v` to open in web browser. \ + \n\n", + filter_invocation + ) .into_bytes(); v.extend(html_filter.wait_with_output().unwrap().stdout); } @@ -372,7 +374,7 @@ impl Component for EnvelopeView { .push_back(UIEvent::StatusEvent(StatusEvent::BufClear)); return true; } - UIEvent::Input(Key::Char(c)) if ('0'..='9').contains(&c) => { + UIEvent::Input(Key::Char(c)) if c.is_ascii_digit() => { self.cmd_buf.push(c); return true; } @@ -449,7 +451,7 @@ impl Component for EnvelopeView { false, ); match Command::new("sh") - .args(&["-c", &exec_cmd]) + .args(["-c", &exec_cmd]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() @@ -469,18 +471,20 @@ impl Component for EnvelopeView { } } else { context.replies.push_back(UIEvent::StatusEvent( - StatusEvent::DisplayMessage(if let Some(filename) = filename.as_ref() { + StatusEvent::DisplayMessage( + if let Some(filename) = filename.as_ref() { format!( - "Couldn't find a default application for file {} (type {})", - filename, - attachment_type + "Couldn't find a default application for file {} \ + (type {})", + filename, attachment_type ) } else { format!( "Couldn't find a default application for type {}", attachment_type ) - }), + }, + ), )); return true; } diff --git a/src/components/mail/view/html.rs b/src/components/mail/view/html.rs index d5334561..b319ee8c 100644 --- a/src/components/mail/view/html.rs +++ b/src/components/mail/view/html.rs @@ -19,9 +19,12 @@ * along with meli. If not, see . */ +use std::{ + io::Write, + process::{Command, Stdio}, +}; + use super::*; -use std::io::Write; -use std::process::{Command, Stdio}; #[derive(Debug)] pub struct HtmlView { @@ -40,7 +43,7 @@ impl HtmlView { let mut display_text = if let Some(filter_invocation) = settings.pager.html_filter.as_ref() { let command_obj = Command::new("sh") - .args(&["-c", filter_invocation]) + .args(["-c", filter_invocation]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn(); @@ -74,7 +77,7 @@ impl HtmlView { } } } else if let Ok(mut html_filter) = Command::new("w3m") - .args(&["-I", "utf-8", "-T", "text/html"]) + .args(["-I", "utf-8", "-T", "text/html"]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() @@ -154,7 +157,7 @@ impl Component for HtmlView { let exec_cmd = super::desktop_exec_to_command(&command, p.path.display().to_string(), false); match Command::new("sh") - .args(&["-c", &exec_cmd]) + .args(["-c", &exec_cmd]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() diff --git a/src/components/mail/view/thread.rs b/src/components/mail/view/thread.rs index d2ce3f4e..ea74269d 100644 --- a/src/components/mail/view/thread.rs +++ b/src/components/mail/view/thread.rs @@ -19,9 +19,10 @@ * along with meli. If not, see . */ +use std::cmp; + use super::*; use crate::components::PageMovement; -use std::cmp; #[derive(Debug, Clone)] struct ThreadEntry { @@ -62,8 +63,8 @@ pub struct ThreadView { impl ThreadView { /* * coordinates: (account index, mailbox_hash, root set thread_node index) - * expanded_hash: optional position of expanded entry when we render the threadview. Default - * expanded message is the last one. + * expanded_hash: optional position of expanded entry when we render the + * threadview. Default expanded message is the last one. * context: current context */ pub fn new( @@ -491,8 +492,8 @@ impl ThreadView { let page_no = (self.new_cursor_pos).wrapping_div(rows); let top_idx = page_no * rows; - /* This closure (written for code clarity, should be inlined by the compiler) returns the - * **line** of an entry in the ThreadView grid. */ + /* This closure (written for code clarity, should be inlined by the compiler) + * returns the **line** of an entry in the ThreadView grid. */ let get_entry_area = |idx: usize, entries: &[ThreadEntry]| { let entries = &entries; let visual_indentation = entries[idx].index.0 * 4; @@ -530,8 +531,8 @@ impl ThreadView { ), ); } - /* If cursor position has changed, remove the highlight from the previous position and - * apply it in the new one. */ + /* If cursor position has changed, remove the highlight from the previous + * position and apply it in the new one. */ self.cursor_pos = self.new_cursor_pos; if self.cursor_pos + 1 > visibles.len() { self.cursor_pos = visibles.len().saturating_sub(1); @@ -588,8 +589,8 @@ impl ThreadView { } else { let old_cursor_pos = self.cursor_pos; 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. */ + /* 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(|v| v.iter()).collect(); for &idx in &[old_cursor_pos, self.cursor_pos] { @@ -941,7 +942,8 @@ impl ThreadView { } } - /// Current position in self.entries (not in drawn entries which might exclude nonvisible ones) + /// 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(|v| v.iter()).collect(); *visibles[self.new_cursor_pos] diff --git a/src/components/mailbox_management.rs b/src/components/mailbox_management.rs index 5e8cce5a..1da104da 100644 --- a/src/components/mailbox_management.rs +++ b/src/components/mailbox_management.rs @@ -18,12 +18,12 @@ * You should have received a copy of the GNU General Public License * along with meli. If not, see . */ -use super::*; -use crate::conf::accounts::MailboxEntry; -use crate::melib::text_processing::TextProcessing; +use std::cmp; + use melib::backends::AccountHash; -use std::cmp; +use super::*; +use crate::{conf::accounts::MailboxEntry, melib::text_processing::TextProcessing}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum MailboxAction { @@ -63,7 +63,7 @@ pub struct MailboxManager { impl fmt::Display for MailboxManager { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", "mailboxes") + write!(f, "mailboxes") } } @@ -96,7 +96,7 @@ impl MailboxManager { self.length = account.mailbox_entries.len(); self.entries = account.mailbox_entries.clone(); self.entries - .sort_by(|_, a, _, b| a.ref_mailbox.path().cmp(&b.ref_mailbox.path())); + .sort_by(|_, a, _, b| a.ref_mailbox.path().cmp(b.ref_mailbox.path())); self.set_dirty(true); let mut min_width = ( @@ -268,8 +268,8 @@ impl MailboxManager { ))); } - /* If cursor position has changed, remove the highlight from the previous position and - * apply it in the new one. */ + /* If cursor position has changed, remove the highlight from the previous + * position and apply it in the new one. */ if self.cursor_pos != self.new_cursor_pos && prev_page_no == page_no { let old_cursor_pos = self.cursor_pos; self.cursor_pos = self.new_cursor_pos; @@ -362,11 +362,13 @@ impl Component for MailboxManager { MailboxAction::Move | MailboxAction::Rename => { context.replies.push_back(UIEvent::CmdInput(Key::Paste( format!( - "rename-mailbox \"{account_name}\" \"{mailbox_path_src}\" ", - account_name = context.accounts[&self.account_hash].name(), - mailbox_path_src = - self.entries[self.cursor_pos].ref_mailbox.path() - ), + "rename-mailbox \"{account_name}\" \ + \"{mailbox_path_src}\" ", + account_name = + context.accounts[&self.account_hash].name(), + mailbox_path_src = + self.entries[self.cursor_pos].ref_mailbox.path() + ), ))); context .replies diff --git a/src/components/notifications.rs b/src/components/notifications.rs index 3d959a6a..c03f15da 100644 --- a/src/components/notifications.rs +++ b/src/components/notifications.rs @@ -24,11 +24,11 @@ Notification handling components. */ use std::process::{Command, Stdio}; -use super::*; - #[cfg(all(target_os = "linux", feature = "dbus-notifications"))] pub use dbus::*; +use super::*; + #[cfg(all(target_os = "linux", feature = "dbus-notifications"))] mod dbus { use super::*; @@ -230,7 +230,20 @@ impl Component for NotificationCommand { } else { #[cfg(target_os = "macos")] { - let applescript = format!("display notification \"{message}\" with title \"{title}\" subtitle \"{subtitle}\"", message = body.replace('"', "'"), title = title.as_ref().map(String::as_str).unwrap_or("meli").replace('"', "'"), subtitle = kind.map(|k| k.to_string()).unwrap_or_default().replace('"', "'")); + let applescript = format!( + "display notification \"{message}\" with title \"{title}\" subtitle \ + \"{subtitle}\"", + message = body.replace('"', "'"), + title = title + .as_ref() + .map(String::as_str) + .unwrap_or("meli") + .replace('"', "'"), + subtitle = kind + .map(|k| k.to_string()) + .unwrap_or_default() + .replace('"', "'") + ); match Command::new("osascript") .arg("-e") .arg(applescript) @@ -279,7 +292,7 @@ impl Component for NotificationCommand { fn update_xbiff(path: &str) -> Result<()> { let mut file = std::fs::OpenOptions::new() .append(true) /* writes will append to a file instead of overwriting previous contents */ - .create(true) /* a new file will be created if the file does not yet already exist.*/ + .create(true) /* a new file will be created if the file does not yet already exist. */ .open(path)?; if file.metadata()?.len() > 128 { file.set_len(0)?; diff --git a/src/components/svg.rs b/src/components/svg.rs index 048867ff..c49c244d 100644 --- a/src/components/svg.rs +++ b/src/components/svg.rs @@ -18,9 +18,9 @@ * You should have received a copy of the GNU General Public License * along with meli. If not, see . */ +use std::{collections::BTreeMap, io::Write}; + use super::*; -use std::collections::BTreeMap; -use std::io::Write; #[derive(Debug)] pub struct SVGScreenshotFilter { @@ -48,22 +48,29 @@ impl Component for SVGScreenshotFilter { } self.save_screenshot = false; let grid: &CellBuffer = _grid; - use svg_crate::node::element::{Definitions, Group, Rectangle, Style, Text, Use}; - use svg_crate::node::Text as TextNode; - use svg_crate::Document; + use svg_crate::{ + node::{ + element::{Definitions, Group, Rectangle, Style, Text, Use}, + Text as TextNode, + }, + Document, + }; let (width, height) = grid.size(); /* * Format frame as follows: * - The entire background is a big rectangle. - * - Every text piece with unified foreground color is a text element inserted into the + * - Every text piece with unified foreground color is a text element + * inserted into the * `definitions` field of the svg, and then `use`ed as a reference - * - Every background piece (a slice of unified background color) is a rectangle element + * - Every background piece (a slice of unified background color) is a + * rectangle element * inserted along with the `use` elements * - * Each row is arbritarily set at 17px high, and each character cell is 8 pixels wide. - * Rectangle cells each have one extra pixel (so 18px * 9px) in their dimensions in order - * to cover the spacing between cells. + * Each row is arbritarily set at 17px high, and each character cell is 8 + * pixels wide. Rectangle cells each have one extra pixel (so 18px * + * 9px) in their dimensions in order to cover the spacing between + * cells. */ let mut definitions = Definitions::new(); let mut rows_group = Group::new(); @@ -79,9 +86,11 @@ impl Component for SVGScreenshotFilter { /* Each row is a group element, consisting of text elements */ let mut row_group = Group::new().set("id", format!("{:x}", row_idx + 1)); /* Keep track of colors and attributes. - * - Whenever the foreground color changes, emit a text element with the accumulated + * - Whenever the foreground color changes, emit a text element with the + * accumulated * text in the specific foreground color. - * - Whenever the backgrund color changes, emit a rectangle element filled with the + * - Whenever the backgrund color changes, emit a rectangle element filled + * with the * specific background color. */ let mut cur_fg = Color::Default; @@ -151,7 +160,7 @@ impl Component for SVGScreenshotFilter { .add(TextNode::new(&escaped_text)) .set("x", prev_x_fg * 8) .set("textLength", text_length * 8); - /*.set("fgname", format!("{:?}", cur_fg));*/ + /* .set("fgname", format!("{:?}", cur_fg)); */ if cur_attrs.intersects(Attr::BOLD) { text_el = text_el.set("font-weight", "bold"); } @@ -275,7 +284,7 @@ impl Component for SVGScreenshotFilter { .add(TextNode::new(&escaped_text)) .set("x", prev_x_fg * 8) .set("textLength", text_length * 8); - /*.set("fgname", format!("{:?}", cur_fg));*/ + /* .set("fgname", format!("{:?}", cur_fg)); */ if cur_attrs.intersects(Attr::BOLD) { text_el = text_el.set("font-weight", "bold"); } @@ -441,260 +450,260 @@ impl Component for SVGScreenshotFilter { const CSS_STYLE: &str = r#"#t{font-family:'DejaVu Sans Mono',monospace;font-style:normal;font-size:14px;} text {dominant-baseline: text-before-edge; white-space: pre;} .f{fill:#e5e5e5;} .b{fill:#000;} .c0 {fill:#000;} .c1 {fill:#cd0000;} .c2 {fill:#00cd00;} .c3 {fill:#cdcd00;} .c4 {fill:#00e;} .c5 {fill:#cd00cd;} .c6 {fill:#00cdcd;} .c7 {fill:#e5e5e5;} .c8 {fill:#7f7f7f;} .c9 {fill:#f00;} .c10 {fill:#0f0;} .c11 {fill:#ff0;} .c12 {fill:#5c5cff;} .c13 {fill:#f0f;} .c14 {fill:#0ff;} .c15 {fill:#fff;}"#; const XTERM_COLORS: &[(u8, u8, u8)] = &[ - /*0*/ (0, 0, 0), - /*1*/ (128, 0, 0), - /*2*/ (0, 128, 0), - /*3*/ (128, 128, 0), - /*4*/ (0, 0, 128), - /*5*/ (128, 0, 128), - /*6*/ (0, 128, 128), - /*7*/ (192, 192, 192), - /*8*/ (128, 128, 128), - /*9*/ (255, 0, 0), - /*10*/ (0, 255, 0), - /*11*/ (255, 255, 0), - /*12*/ (0, 0, 255), - /*13*/ (255, 0, 255), - /*14*/ (0, 255, 255), - /*15*/ (255, 255, 255), - /*16*/ (0, 0, 0), - /*17*/ (0, 0, 95), - /*18*/ (0, 0, 135), - /*19*/ (0, 0, 175), - /*20*/ (0, 0, 215), - /*21*/ (0, 0, 255), - /*22*/ (0, 95, 0), - /*23*/ (0, 95, 95), - /*24*/ (0, 95, 135), - /*25*/ (0, 95, 175), - /*26*/ (0, 95, 215), - /*27*/ (0, 95, 255), - /*28*/ (0, 135, 0), - /*29*/ (0, 135, 95), - /*30*/ (0, 135, 135), - /*31*/ (0, 135, 175), - /*32*/ (0, 135, 215), - /*33*/ (0, 135, 255), - /*34*/ (0, 175, 0), - /*35*/ (0, 175, 95), - /*36*/ (0, 175, 135), - /*37*/ (0, 175, 175), - /*38*/ (0, 175, 215), - /*39*/ (0, 175, 255), - /*40*/ (0, 215, 0), - /*41*/ (0, 215, 95), - /*42*/ (0, 215, 135), - /*43*/ (0, 215, 175), - /*44*/ (0, 215, 215), - /*45*/ (0, 215, 255), - /*46*/ (0, 255, 0), - /*47*/ (0, 255, 95), - /*48*/ (0, 255, 135), - /*49*/ (0, 255, 175), - /*50*/ (0, 255, 215), - /*51*/ (0, 255, 255), - /*52*/ (95, 0, 0), - /*53*/ (95, 0, 95), - /*54*/ (95, 0, 135), - /*55*/ (95, 0, 175), - /*56*/ (95, 0, 215), - /*57*/ (95, 0, 255), - /*58*/ (95, 95, 0), - /*59*/ (95, 95, 95), - /*60*/ (95, 95, 135), - /*61*/ (95, 95, 175), - /*62*/ (95, 95, 215), - /*63*/ (95, 95, 255), - /*64*/ (95, 135, 0), - /*65*/ (95, 135, 95), - /*66*/ (95, 135, 135), - /*67*/ (95, 135, 175), - /*68*/ (95, 135, 215), - /*69*/ (95, 135, 255), - /*70*/ (95, 175, 0), - /*71*/ (95, 175, 95), - /*72*/ (95, 175, 135), - /*73*/ (95, 175, 175), - /*74*/ (95, 175, 215), - /*75*/ (95, 175, 255), - /*76*/ (95, 215, 0), - /*77*/ (95, 215, 95), - /*78*/ (95, 215, 135), - /*79*/ (95, 215, 175), - /*80*/ (95, 215, 215), - /*81*/ (95, 215, 255), - /*82*/ (95, 255, 0), - /*83*/ (95, 255, 95), - /*84*/ (95, 255, 135), - /*85*/ (95, 255, 175), - /*86*/ (95, 255, 215), - /*87*/ (95, 255, 255), - /*88*/ (135, 0, 0), - /*89*/ (135, 0, 95), - /*90*/ (135, 0, 135), - /*91*/ (135, 0, 175), - /*92*/ (135, 0, 215), - /*93*/ (135, 0, 255), - /*94*/ (135, 95, 0), - /*95*/ (135, 95, 95), - /*96*/ (135, 95, 135), - /*97*/ (135, 95, 175), - /*98*/ (135, 95, 215), - /*99*/ (135, 95, 255), - /*100*/ (135, 135, 0), - /*101*/ (135, 135, 95), - /*102*/ (135, 135, 135), - /*103*/ (135, 135, 175), - /*104*/ (135, 135, 215), - /*105*/ (135, 135, 255), - /*106*/ (135, 175, 0), - /*107*/ (135, 175, 95), - /*108*/ (135, 175, 135), - /*109*/ (135, 175, 175), - /*110*/ (135, 175, 215), - /*111*/ (135, 175, 255), - /*112*/ (135, 215, 0), - /*113*/ (135, 215, 95), - /*114*/ (135, 215, 135), - /*115*/ (135, 215, 175), - /*116*/ (135, 215, 215), - /*117*/ (135, 215, 255), - /*118*/ (135, 255, 0), - /*119*/ (135, 255, 95), - /*120*/ (135, 255, 135), - /*121*/ (135, 255, 175), - /*122*/ (135, 255, 215), - /*123*/ (135, 255, 255), - /*124*/ (175, 0, 0), - /*125*/ (175, 0, 95), - /*126*/ (175, 0, 135), - /*127*/ (175, 0, 175), - /*128*/ (175, 0, 215), - /*129*/ (175, 0, 255), - /*130*/ (175, 95, 0), - /*131*/ (175, 95, 95), - /*132*/ (175, 95, 135), - /*133*/ (175, 95, 175), - /*134*/ (175, 95, 215), - /*135*/ (175, 95, 255), - /*136*/ (175, 135, 0), - /*137*/ (175, 135, 95), - /*138*/ (175, 135, 135), - /*139*/ (175, 135, 175), - /*140*/ (175, 135, 215), - /*141*/ (175, 135, 255), - /*142*/ (175, 175, 0), - /*143*/ (175, 175, 95), - /*144*/ (175, 175, 135), - /*145*/ (175, 175, 175), - /*146*/ (175, 175, 215), - /*147*/ (175, 175, 255), - /*148*/ (175, 215, 0), - /*149*/ (175, 215, 95), - /*150*/ (175, 215, 135), - /*151*/ (175, 215, 175), - /*152*/ (175, 215, 215), - /*153*/ (175, 215, 255), - /*154*/ (175, 255, 0), - /*155*/ (175, 255, 95), - /*156*/ (175, 255, 135), - /*157*/ (175, 255, 175), - /*158*/ (175, 255, 215), - /*159*/ (175, 255, 255), - /*160*/ (215, 0, 0), - /*161*/ (215, 0, 95), - /*162*/ (215, 0, 135), - /*163*/ (215, 0, 175), - /*164*/ (215, 0, 215), - /*165*/ (215, 0, 255), - /*166*/ (215, 95, 0), - /*167*/ (215, 95, 95), - /*168*/ (215, 95, 135), - /*169*/ (215, 95, 175), - /*170*/ (215, 95, 215), - /*171*/ (215, 95, 255), - /*172*/ (215, 135, 0), - /*173*/ (215, 135, 95), - /*174*/ (215, 135, 135), - /*175*/ (215, 135, 175), - /*176*/ (215, 135, 215), - /*177*/ (215, 135, 255), - /*178*/ (215, 175, 0), - /*179*/ (215, 175, 95), - /*180*/ (215, 175, 135), - /*181*/ (215, 175, 175), - /*182*/ (215, 175, 215), - /*183*/ (215, 175, 255), - /*184*/ (215, 215, 0), - /*185*/ (215, 215, 95), - /*186*/ (215, 215, 135), - /*187*/ (215, 215, 175), - /*188*/ (215, 215, 215), - /*189*/ (215, 215, 255), - /*190*/ (215, 255, 0), - /*191*/ (215, 255, 95), - /*192*/ (215, 255, 135), - /*193*/ (215, 255, 175), - /*194*/ (215, 255, 215), - /*195*/ (215, 255, 255), - /*196*/ (255, 0, 0), - /*197*/ (255, 0, 95), - /*198*/ (255, 0, 135), - /*199*/ (255, 0, 175), - /*200*/ (255, 0, 215), - /*201*/ (255, 0, 255), - /*202*/ (255, 95, 0), - /*203*/ (255, 95, 95), - /*204*/ (255, 95, 135), - /*205*/ (255, 95, 175), - /*206*/ (255, 95, 215), - /*207*/ (255, 95, 255), - /*208*/ (255, 135, 0), - /*209*/ (255, 135, 95), - /*210*/ (255, 135, 135), - /*211*/ (255, 135, 175), - /*212*/ (255, 135, 215), - /*213*/ (255, 135, 255), - /*214*/ (255, 175, 0), - /*215*/ (255, 175, 95), - /*216*/ (255, 175, 135), - /*217*/ (255, 175, 175), - /*218*/ (255, 175, 215), - /*219*/ (255, 175, 255), - /*220*/ (255, 215, 0), - /*221*/ (255, 215, 95), - /*222*/ (255, 215, 135), - /*223*/ (255, 215, 175), - /*224*/ (255, 215, 215), - /*225*/ (255, 215, 255), - /*226*/ (255, 255, 0), - /*227*/ (255, 255, 95), - /*228*/ (255, 255, 135), - /*229*/ (255, 255, 175), - /*230*/ (255, 255, 215), - /*231*/ (255, 255, 255), - /*232*/ (8, 8, 8), - /*233*/ (18, 18, 18), - /*234*/ (28, 28, 28), - /*235*/ (38, 38, 38), - /*236*/ (48, 48, 48), - /*237*/ (58, 58, 58), - /*238*/ (68, 68, 68), - /*239*/ (78, 78, 78), - /*240*/ (88, 88, 88), - /*241*/ (98, 98, 98), - /*242*/ (108, 108, 108), - /*243*/ (118, 118, 118), - /*244*/ (128, 128, 128), - /*245*/ (138, 138, 138), - /*246*/ (148, 148, 148), - /*247*/ (158, 158, 158), - /*248*/ (168, 168, 168), - /*249*/ (178, 178, 178), - /*250*/ (188, 188, 188), - /*251*/ (198, 198, 198), - /*252*/ (208, 208, 208), - /*253*/ (218, 218, 218), - /*254*/ (228, 228, 228), - /*255*/ (238, 238, 238), + /* 0 */ (0, 0, 0), + /* 1 */ (128, 0, 0), + /* 2 */ (0, 128, 0), + /* 3 */ (128, 128, 0), + /* 4 */ (0, 0, 128), + /* 5 */ (128, 0, 128), + /* 6 */ (0, 128, 128), + /* 7 */ (192, 192, 192), + /* 8 */ (128, 128, 128), + /* 9 */ (255, 0, 0), + /* 10 */ (0, 255, 0), + /* 11 */ (255, 255, 0), + /* 12 */ (0, 0, 255), + /* 13 */ (255, 0, 255), + /* 14 */ (0, 255, 255), + /* 15 */ (255, 255, 255), + /* 16 */ (0, 0, 0), + /* 17 */ (0, 0, 95), + /* 18 */ (0, 0, 135), + /* 19 */ (0, 0, 175), + /* 20 */ (0, 0, 215), + /* 21 */ (0, 0, 255), + /* 22 */ (0, 95, 0), + /* 23 */ (0, 95, 95), + /* 24 */ (0, 95, 135), + /* 25 */ (0, 95, 175), + /* 26 */ (0, 95, 215), + /* 27 */ (0, 95, 255), + /* 28 */ (0, 135, 0), + /* 29 */ (0, 135, 95), + /* 30 */ (0, 135, 135), + /* 31 */ (0, 135, 175), + /* 32 */ (0, 135, 215), + /* 33 */ (0, 135, 255), + /* 34 */ (0, 175, 0), + /* 35 */ (0, 175, 95), + /* 36 */ (0, 175, 135), + /* 37 */ (0, 175, 175), + /* 38 */ (0, 175, 215), + /* 39 */ (0, 175, 255), + /* 40 */ (0, 215, 0), + /* 41 */ (0, 215, 95), + /* 42 */ (0, 215, 135), + /* 43 */ (0, 215, 175), + /* 44 */ (0, 215, 215), + /* 45 */ (0, 215, 255), + /* 46 */ (0, 255, 0), + /* 47 */ (0, 255, 95), + /* 48 */ (0, 255, 135), + /* 49 */ (0, 255, 175), + /* 50 */ (0, 255, 215), + /* 51 */ (0, 255, 255), + /* 52 */ (95, 0, 0), + /* 53 */ (95, 0, 95), + /* 54 */ (95, 0, 135), + /* 55 */ (95, 0, 175), + /* 56 */ (95, 0, 215), + /* 57 */ (95, 0, 255), + /* 58 */ (95, 95, 0), + /* 59 */ (95, 95, 95), + /* 60 */ (95, 95, 135), + /* 61 */ (95, 95, 175), + /* 62 */ (95, 95, 215), + /* 63 */ (95, 95, 255), + /* 64 */ (95, 135, 0), + /* 65 */ (95, 135, 95), + /* 66 */ (95, 135, 135), + /* 67 */ (95, 135, 175), + /* 68 */ (95, 135, 215), + /* 69 */ (95, 135, 255), + /* 70 */ (95, 175, 0), + /* 71 */ (95, 175, 95), + /* 72 */ (95, 175, 135), + /* 73 */ (95, 175, 175), + /* 74 */ (95, 175, 215), + /* 75 */ (95, 175, 255), + /* 76 */ (95, 215, 0), + /* 77 */ (95, 215, 95), + /* 78 */ (95, 215, 135), + /* 79 */ (95, 215, 175), + /* 80 */ (95, 215, 215), + /* 81 */ (95, 215, 255), + /* 82 */ (95, 255, 0), + /* 83 */ (95, 255, 95), + /* 84 */ (95, 255, 135), + /* 85 */ (95, 255, 175), + /* 86 */ (95, 255, 215), + /* 87 */ (95, 255, 255), + /* 88 */ (135, 0, 0), + /* 89 */ (135, 0, 95), + /* 90 */ (135, 0, 135), + /* 91 */ (135, 0, 175), + /* 92 */ (135, 0, 215), + /* 93 */ (135, 0, 255), + /* 94 */ (135, 95, 0), + /* 95 */ (135, 95, 95), + /* 96 */ (135, 95, 135), + /* 97 */ (135, 95, 175), + /* 98 */ (135, 95, 215), + /* 99 */ (135, 95, 255), + /* 100 */ (135, 135, 0), + /* 101 */ (135, 135, 95), + /* 102 */ (135, 135, 135), + /* 103 */ (135, 135, 175), + /* 104 */ (135, 135, 215), + /* 105 */ (135, 135, 255), + /* 106 */ (135, 175, 0), + /* 107 */ (135, 175, 95), + /* 108 */ (135, 175, 135), + /* 109 */ (135, 175, 175), + /* 110 */ (135, 175, 215), + /* 111 */ (135, 175, 255), + /* 112 */ (135, 215, 0), + /* 113 */ (135, 215, 95), + /* 114 */ (135, 215, 135), + /* 115 */ (135, 215, 175), + /* 116 */ (135, 215, 215), + /* 117 */ (135, 215, 255), + /* 118 */ (135, 255, 0), + /* 119 */ (135, 255, 95), + /* 120 */ (135, 255, 135), + /* 121 */ (135, 255, 175), + /* 122 */ (135, 255, 215), + /* 123 */ (135, 255, 255), + /* 124 */ (175, 0, 0), + /* 125 */ (175, 0, 95), + /* 126 */ (175, 0, 135), + /* 127 */ (175, 0, 175), + /* 128 */ (175, 0, 215), + /* 129 */ (175, 0, 255), + /* 130 */ (175, 95, 0), + /* 131 */ (175, 95, 95), + /* 132 */ (175, 95, 135), + /* 133 */ (175, 95, 175), + /* 134 */ (175, 95, 215), + /* 135 */ (175, 95, 255), + /* 136 */ (175, 135, 0), + /* 137 */ (175, 135, 95), + /* 138 */ (175, 135, 135), + /* 139 */ (175, 135, 175), + /* 140 */ (175, 135, 215), + /* 141 */ (175, 135, 255), + /* 142 */ (175, 175, 0), + /* 143 */ (175, 175, 95), + /* 144 */ (175, 175, 135), + /* 145 */ (175, 175, 175), + /* 146 */ (175, 175, 215), + /* 147 */ (175, 175, 255), + /* 148 */ (175, 215, 0), + /* 149 */ (175, 215, 95), + /* 150 */ (175, 215, 135), + /* 151 */ (175, 215, 175), + /* 152 */ (175, 215, 215), + /* 153 */ (175, 215, 255), + /* 154 */ (175, 255, 0), + /* 155 */ (175, 255, 95), + /* 156 */ (175, 255, 135), + /* 157 */ (175, 255, 175), + /* 158 */ (175, 255, 215), + /* 159 */ (175, 255, 255), + /* 160 */ (215, 0, 0), + /* 161 */ (215, 0, 95), + /* 162 */ (215, 0, 135), + /* 163 */ (215, 0, 175), + /* 164 */ (215, 0, 215), + /* 165 */ (215, 0, 255), + /* 166 */ (215, 95, 0), + /* 167 */ (215, 95, 95), + /* 168 */ (215, 95, 135), + /* 169 */ (215, 95, 175), + /* 170 */ (215, 95, 215), + /* 171 */ (215, 95, 255), + /* 172 */ (215, 135, 0), + /* 173 */ (215, 135, 95), + /* 174 */ (215, 135, 135), + /* 175 */ (215, 135, 175), + /* 176 */ (215, 135, 215), + /* 177 */ (215, 135, 255), + /* 178 */ (215, 175, 0), + /* 179 */ (215, 175, 95), + /* 180 */ (215, 175, 135), + /* 181 */ (215, 175, 175), + /* 182 */ (215, 175, 215), + /* 183 */ (215, 175, 255), + /* 184 */ (215, 215, 0), + /* 185 */ (215, 215, 95), + /* 186 */ (215, 215, 135), + /* 187 */ (215, 215, 175), + /* 188 */ (215, 215, 215), + /* 189 */ (215, 215, 255), + /* 190 */ (215, 255, 0), + /* 191 */ (215, 255, 95), + /* 192 */ (215, 255, 135), + /* 193 */ (215, 255, 175), + /* 194 */ (215, 255, 215), + /* 195 */ (215, 255, 255), + /* 196 */ (255, 0, 0), + /* 197 */ (255, 0, 95), + /* 198 */ (255, 0, 135), + /* 199 */ (255, 0, 175), + /* 200 */ (255, 0, 215), + /* 201 */ (255, 0, 255), + /* 202 */ (255, 95, 0), + /* 203 */ (255, 95, 95), + /* 204 */ (255, 95, 135), + /* 205 */ (255, 95, 175), + /* 206 */ (255, 95, 215), + /* 207 */ (255, 95, 255), + /* 208 */ (255, 135, 0), + /* 209 */ (255, 135, 95), + /* 210 */ (255, 135, 135), + /* 211 */ (255, 135, 175), + /* 212 */ (255, 135, 215), + /* 213 */ (255, 135, 255), + /* 214 */ (255, 175, 0), + /* 215 */ (255, 175, 95), + /* 216 */ (255, 175, 135), + /* 217 */ (255, 175, 175), + /* 218 */ (255, 175, 215), + /* 219 */ (255, 175, 255), + /* 220 */ (255, 215, 0), + /* 221 */ (255, 215, 95), + /* 222 */ (255, 215, 135), + /* 223 */ (255, 215, 175), + /* 224 */ (255, 215, 215), + /* 225 */ (255, 215, 255), + /* 226 */ (255, 255, 0), + /* 227 */ (255, 255, 95), + /* 228 */ (255, 255, 135), + /* 229 */ (255, 255, 175), + /* 230 */ (255, 255, 215), + /* 231 */ (255, 255, 255), + /* 232 */ (8, 8, 8), + /* 233 */ (18, 18, 18), + /* 234 */ (28, 28, 28), + /* 235 */ (38, 38, 38), + /* 236 */ (48, 48, 48), + /* 237 */ (58, 58, 58), + /* 238 */ (68, 68, 68), + /* 239 */ (78, 78, 78), + /* 240 */ (88, 88, 88), + /* 241 */ (98, 98, 98), + /* 242 */ (108, 108, 108), + /* 243 */ (118, 118, 118), + /* 244 */ (128, 128, 128), + /* 245 */ (138, 138, 138), + /* 246 */ (148, 148, 148), + /* 247 */ (158, 158, 158), + /* 248 */ (168, 168, 168), + /* 249 */ (178, 178, 178), + /* 250 */ (188, 188, 188), + /* 251 */ (198, 198, 198), + /* 252 */ (208, 208, 208), + /* 253 */ (218, 218, 218), + /* 254 */ (228, 228, 228), + /* 255 */ (238, 238, 238), ]; diff --git a/src/components/utilities.rs b/src/components/utilities.rs index 848770ed..b76cbacc 100644 --- a/src/components/utilities.rs +++ b/src/components/utilities.rs @@ -21,9 +21,10 @@ /*! Various useful components that can be used in a generic fashion. */ -use super::*; use text_processing::Reflow; +use super::*; + mod pager; pub use self::pager::*; @@ -37,11 +38,11 @@ mod dialogs; pub use self::dialogs::*; mod tables; -pub use self::tables::*; - -use crate::jobs::JobId; use std::collections::HashSet; +pub use self::tables::*; +use crate::jobs::JobId; + #[derive(Default, Debug, Clone)] pub struct SearchPattern { pattern: String, @@ -943,12 +944,13 @@ impl Component for Tabbed { )); } - /* If children are dirty but self isn't and the shortcuts panel is visible, it will get - * overwritten. */ + /* If children are dirty but self isn't and the shortcuts panel is visible, + * it will get overwritten. */ let must_redraw_shortcuts: bool = self.show_shortcuts && !self.dirty && self.is_dirty(); - /* children should be drawn after the shortcuts/help panel lest they overwrite the panel on - * the grid. the drawing order is determined by the dirty_areas queue which is LIFO */ + /* children should be drawn after the shortcuts/help panel lest they + * overwrite the panel on the grid. the drawing order is determined + * by the dirty_areas queue which is LIFO */ if self.children.len() > 1 { self.draw_tabs( grid, diff --git a/src/components/utilities/dialogs.rs b/src/components/utilities/dialogs.rs index 1ace1dec..1086cacd 100644 --- a/src/components/utilities/dialogs.rs +++ b/src/components/utilities/dialogs.rs @@ -40,9 +40,10 @@ enum SelectorCursor { /// Shows a little window with options for user to select. /// -/// Instantiate with Selector::new(). Set single_only to true if user should only choose one of the -/// options. After passing input events to this component, check Selector::is_done to see if the -/// user has finalised their choices. Collect the choices by consuming the Selector with +/// Instantiate with Selector::new(). Set single_only to true if user should +/// only choose one of the options. After passing input events to this +/// component, check Selector::is_done to see if the user has finalised their +/// choices. Collect the choices by consuming the Selector with /// Selector::collect() pub struct Selector { diff --git a/src/components/utilities/pager.rs b/src/components/utilities/pager.rs index cbda1394..6a73225c 100644 --- a/src/components/utilities/pager.rs +++ b/src/components/utilities/pager.rs @@ -19,12 +19,14 @@ * along with meli. If not, see . */ -use super::*; use melib::text_processing::LineBreakText; +use super::*; + /// A pager for text. -/// `Pager` holds its own content in its own `CellBuffer` and when `draw` is called, it draws the -/// current view of the text. It is responsible for scrolling etc. +/// `Pager` holds its own content in its own `CellBuffer` and when `draw` is +/// called, it draws the current view of the text. It is responsible for +/// scrolling etc. #[derive(Default, Debug, Clone)] pub struct Pager { text: String, @@ -48,7 +50,7 @@ pub struct Pager { impl fmt::Display for Pager { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", "pager") + write!(f, "pager") } } @@ -171,10 +173,12 @@ impl Pager { pub fn filter(&mut self, cmd: &str) { let _f = |bin: &str, text: &str| -> Result { - use std::io::Write; - use std::process::{Command, Stdio}; + use std::{ + io::Write, + process::{Command, Stdio}, + }; let mut filter_child = Command::new("sh") - .args(&["-c", bin]) + .args(["-c", bin]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() @@ -708,8 +712,10 @@ impl Component for Pager { self.dirty = true; } UIEvent::Action(View(Pipe(ref bin, ref args))) => { - use std::io::Write; - use std::process::{Command, Stdio}; + use std::{ + io::Write, + process::{Command, Stdio}, + }; let mut command_obj = match Command::new(bin) .args(args.as_slice()) .stdin(Stdio::piped()) diff --git a/src/components/utilities/tables.rs b/src/components/utilities/tables.rs index 25ce5492..b6cdd331 100644 --- a/src/components/utilities/tables.rs +++ b/src/components/utilities/tables.rs @@ -20,9 +20,10 @@ */ /*! UI components to display tabular lists. */ +use std::mem::MaybeUninit; + use super::*; use crate::segment_tree::SegmentTree; -use std::mem::MaybeUninit; #[derive(Debug, Default, Copy, Clone)] pub enum ColumnElasticity { @@ -130,7 +131,8 @@ pub struct DataColumns { pub segment_tree: Box<[SegmentTree; N]>, } -// Workaround because Default derive doesn't work for const generic array lengths yet. +// Workaround because Default derive doesn't work for const generic array +// lengths yet. impl Default for DataColumns { fn default() -> Self { fn init_array(cl: impl Fn() -> T) -> [T; N] { diff --git a/src/components/utilities/widgets.rs b/src/components/utilities/widgets.rs index 682d6b12..475aad2c 100644 --- a/src/components/utilities/widgets.rs +++ b/src/components/utilities/widgets.rs @@ -19,15 +19,15 @@ * along with meli. If not, see . */ +use std::{borrow::Cow, collections::HashMap, time::Duration}; + use super::*; -use std::borrow::Cow; -use std::collections::HashMap; -use std::time::Duration; type AutoCompleteFn = Box Vec + Send + Sync>; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Default)] enum FormFocus { + #[default] Fields, Buttons, TextInput, @@ -35,12 +35,6 @@ enum FormFocus { type Cursor = usize; -impl Default for FormFocus { - fn default() -> FormFocus { - FormFocus::Fields - } -} - pub enum Field { Text(UText, Option<(AutoCompleteFn, Box)>), Choice(Vec>, Cursor), @@ -149,8 +143,8 @@ impl Component for Field { * ########################################## * * Example: - * For the string "The quick brown fox jumps over the lazy dog" with visible width - * of field of 10 columns + * For the string "The quick brown fox jumps over the lazy dog" with visible + * width of field of 10 columns * * * Cursor <= width @@ -390,20 +384,15 @@ impl fmt::Display for Field { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] pub enum FormButtonActions { Accept, Reset, + #[default] Cancel, Other(&'static str), } -impl Default for FormButtonActions { - fn default() -> Self { - FormButtonActions::Cancel - } -} - #[derive(Debug, Default)] pub struct FormWidget where diff --git a/src/conf.rs b/src/conf.rs index eaff8689..196718ed 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -26,14 +26,17 @@ extern crate serde; extern crate toml; extern crate xdg; -use crate::conf::deserializers::non_empty_string; -use crate::terminal::Color; -use melib::backends::TagHash; -use melib::search::Query; -use std::collections::HashSet; -use std::io::Read; -use std::process::{Command, Stdio}; +use std::{ + collections::HashSet, + io::Read, + process::{Command, Stdio}, +}; +use melib::{backends::TagHash, search::Query}; + +use crate::{conf::deserializers::non_empty_string, terminal::Color}; + +#[rustfmt::skip] mod overrides; pub use overrides::*; pub mod composing; @@ -49,30 +52,29 @@ mod themes; pub use themes::*; pub mod accounts; -pub use self::accounts::Account; -pub use self::composing::*; -pub use self::pgp::*; -pub use self::shortcuts::*; -pub use self::tags::*; -pub use melib::thread::{SortField, SortOrder}; - -use self::default_vals::*; -use self::listing::ListingSettings; -use self::notifications::NotificationsSettings; -use self::terminal::TerminalSettings; -use crate::pager::PagerSettings; -use melib::conf::{AccountSettings, MailboxConf, ToggleFlag}; -use melib::error::*; - -use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +use std::{ + collections::HashMap, + env, + fs::OpenOptions, + io::{self, BufRead, Write}, + os::unix::fs::PermissionsExt, + path::{Path, PathBuf}, +}; use indexmap::IndexMap; -use std::collections::HashMap; -use std::env; -use std::fs::OpenOptions; -use std::io::{self, BufRead, Write}; -use std::os::unix::fs::PermissionsExt; -use std::path::{Path, PathBuf}; +pub use melib::thread::{SortField, SortOrder}; +use melib::{ + conf::{AccountSettings, MailboxConf, ToggleFlag}, + error::*, +}; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; + +pub use self::{accounts::Account, composing::*, pgp::*, shortcuts::*, tags::*}; +use self::{ + default_vals::*, listing::ListingSettings, notifications::NotificationsSettings, + terminal::TerminalSettings, +}; +use crate::pager::PagerSettings; #[macro_export] macro_rules! split_command { @@ -185,7 +187,8 @@ pub struct FileAccount { pub conf_override: MailUIConf, #[serde(flatten)] #[serde(deserialize_with = "extra_settings")] - pub extra: IndexMap, /* use custom deserializer to convert any given value (eg bool, number, etc) to string */ + pub extra: IndexMap, /* use custom deserializer to convert any given value + * (eg bool, number, etc) to string */ } impl FileAccount { @@ -381,7 +384,7 @@ define(`include', `builtin_include(substr($1,1,decr(decr(len($1)))))dnl')dnl file.read_to_string(&mut contents)?; let mut handle = Command::new("m4") - .current_dir(conf_path.parent().unwrap_or(&Path::new("/"))) + .current_dir(conf_path.parent().unwrap_or(Path::new("/"))) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) @@ -390,7 +393,7 @@ define(`include', `builtin_include(substr($1,1,decr(decr(len($1)))))dnl')dnl stdin.write_all(M4_PREAMBLE.as_bytes())?; stdin.write_all(contents.as_bytes())?; drop(stdin); - let stdout = handle.wait_with_output()?.stdout.clone(); + let stdout = handle.wait_with_output()?.stdout; Ok(String::from_utf8_lossy(&stdout).to_string()) } @@ -452,6 +455,7 @@ impl FileSettings { } #[cfg(test)] return Ok(FileSettings::default()); + #[cfg(not(test))] return Err(Error::new("No configuration file found.")); } @@ -469,8 +473,8 @@ impl FileSettings { )) })?; /* - * Check that a global composing option is set and return a user-friendly error message because the - * default serde one is confusing. + * Check that a global composing option is set and return a user-friendly + * error message because the default serde one is confusing. */ if !map.contains_key("composing") { let err_msg = r#"You must set a global `composing` option. If you override `composing` in each account, you can use a dummy global like follows: @@ -483,9 +487,10 @@ This is required so that you don't accidentally start meli and find out later th println!("{}", err_msg); let ask = Ask { message: format!( - "Would you like to append this dummy value in your configuration file {} and continue?", - path.display() - ) + "Would you like to append this dummy value in your configuration file {} \ + and continue?", + path.display() + ), }; if ask.run() { let mut file = OpenOptions::new().append(true).open(&path)?; @@ -664,20 +669,15 @@ impl Settings { } } -#[derive(Copy, Debug, Clone, Hash, PartialEq, Eq)] +#[derive(Copy, Debug, Clone, Hash, PartialEq, Eq, Default)] pub enum IndexStyle { Plain, Threaded, + #[default] Compact, Conversations, } -impl Default for IndexStyle { - fn default() -> Self { - IndexStyle::Compact - } -} - /* * Deserialize default functions */ @@ -753,9 +753,9 @@ mod deserializers { where D: Deserializer<'de>, { - /* Why is this needed? If the user gives a configuration value such as key = true, the - * parsing will fail since it expects string values. We want to accept key = true as well - * as key = "true". */ + /* Why is this needed? If the user gives a configuration value such as key = + * true, the parsing will fail since it expects string values. We + * want to accept key = true as well as key = "true". */ #[derive(Deserialize)] struct Wrapper(#[serde(deserialize_with = "any_of")] String); @@ -794,20 +794,15 @@ impl Serialize for IndexStyle { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] pub enum SearchBackend { None, + #[default] Auto, #[cfg(feature = "sqlite3")] Sqlite3, } -impl Default for SearchBackend { - fn default() -> Self { - SearchBackend::Auto - } -} - impl<'de> Deserialize<'de> for SearchBackend { fn deserialize(deserializer: D) -> std::result::Result where @@ -878,13 +873,16 @@ pub fn create_config_file(p: &Path) -> Result<()> { mod pp { //! Preprocess configuration files by unfolding `include` macros. + use std::{ + io::Read, + path::{Path, PathBuf}, + }; + use melib::{ error::{Error, Result}, parsec::*, ShellExpandTrait, }; - use std::io::Read; - use std::path::{Path, PathBuf}; /// Try to parse line into a path to be included. fn include_directive<'a>() -> impl Parser<'a, Option<&'a str>> { @@ -946,7 +944,11 @@ mod pp { /// Expands `include` macros in path. fn pp_helper(path: &Path, level: u8) -> Result { if level > 7 { - return Err(Error::new(format!("Maximum recursion limit reached while unfolding include directives in {}. Have you included a config file within itself?", path.display()))); + return Err(Error::new(format!( + "Maximum recursion limit reached while unfolding include directives in {}. Have \ + you included a config file within itself?", + path.display() + ))); } let mut contents = String::new(); let mut file = std::fs::File::open(path)?; @@ -956,14 +958,15 @@ mod pp { for (i, l) in contents.lines().enumerate() { if let (_, Some(sub_path)) = include_directive().parse(l).map_err(|l| { Error::new(format!( - "Malformed include directive in line {} of file {}: {}\nConfiguration uses the standard m4 macro include(\"filename\").", + "Malformed include directive in line {} of file {}: {}\nConfiguration uses \ + the standard m4 macro include(\"filename\").", i, path.display(), l )) })? { let mut p = Path::new(sub_path).expand(); - if p.is_relative() { + if p.is_relative() { /* We checked that path is ok above so we can do unwrap here */ let prefix = path.parent().unwrap(); p = prefix.join(p) @@ -979,8 +982,8 @@ mod pp { Ok(ret) } - /// Expands `include` macros in configuration file and other configuration files (eg. themes) - /// in the filesystem. + /// Expands `include` macros in configuration file and other configuration + /// files (eg. themes) in the filesystem. pub fn pp>(path: P) -> Result { let p_buf: PathBuf = if path.as_ref().is_relative() { path.as_ref().expand().canonicalize()? @@ -1137,14 +1140,22 @@ mod dotaddressable { Some(field) => { let _tail = &path[1..]; match *field { - "pager" => Err(Error::new("unimplemented")), //self.pager.lookup(field, tail), - "listing" => Err(Error::new("unimplemented")), // self.listing.lookup(field, tail), - "notifications" => Err(Error::new("unimplemented")), // self.notifications.lookup(field, tail), - "shortcuts" => Err(Error::new("unimplemented")), //self.shortcuts.lookup(field, tail), - "composing" => Err(Error::new("unimplemented")), //self.composing.lookup(field, tail), - "identity" => Err(Error::new("unimplemented")), //self.identity.lookup(field, tail), - "tags" => Err(Error::new("unimplemented")), //self.tags.lookup(field, tail), - "themes" => Err(Error::new("unimplemented")), //self.themes.lookup(field, tail), + "pager" => Err(Error::new("unimplemented")), /* self.pager.lookup(field, */ + // tail), + "listing" => Err(Error::new("unimplemented")), /* self.listing.lookup(field, tail), */ + "notifications" => Err(Error::new("unimplemented")), /* self.notifications.lookup(field, tail), */ + "shortcuts" => Err(Error::new("unimplemented")), /* self.shortcuts. */ + // lookup(field, + // tail), + "composing" => Err(Error::new("unimplemented")), /* self.composing.lookup(field, tail), */ + "identity" => Err(Error::new("unimplemented")), /* self.identity. */ + // lookup(field, + // tail), + "tags" => Err(Error::new("unimplemented")), /* self.tags.lookup(field, */ + // tail), + "themes" => Err(Error::new("unimplemented")), /* self.themes. */ + // lookup(field, + // tail), "pgp" => Err(Error::new("unimplemented")), //self.pgp.lookup(field, tail), other => Err(Error::new(format!( @@ -1260,10 +1271,7 @@ mod dotaddressable { #[test] fn test_config_parse() { - use std::fmt::Write; - use std::fs; - use std::io::prelude::*; - use std::path::PathBuf; + use std::{fmt::Write, fs, io::prelude::*, path::PathBuf}; struct ConfigFile { path: PathBuf, @@ -1346,13 +1354,20 @@ send_mail = 'false' let mut new_file = ConfigFile::new(TEST_CONFIG).unwrap(); let err = FileSettings::validate(new_file.path.clone(), false, true).unwrap_err(); - assert!(err.summary.as_ref().starts_with("You must set a global `composing` option. If you override `composing` in each account, you can use a dummy global like follows")); + assert!(err.summary.as_ref().starts_with( + "You must set a global `composing` option. If you override `composing` in each account, \ + you can use a dummy global like follows" + )); new_file .file .write_all("[composing]\nsend_mail = 'false'\n".as_bytes()) .unwrap(); let err = FileSettings::validate(new_file.path.clone(), false, true).unwrap_err(); - assert_eq!(err.summary.as_ref(), "Configuration error (account-name): root_mailbox `/path/to/root/mailbox` is not a valid directory."); + assert_eq!( + err.summary.as_ref(), + "Configuration error (account-name): root_mailbox `/path/to/root/mailbox` is not a valid \ + directory." + ); /* Test unrecognised configuration entries error */ diff --git a/src/conf/accounts.rs b/src/conf/accounts.rs index 305f5700..05b24e05 100644 --- a/src/conf/accounts.rs +++ b/src/conf/accounts.rs @@ -23,38 +23,42 @@ * Account management from user configuration. */ -use super::{AccountConf, FileMailboxConf}; -use crate::jobs::{JobExecutor, JobId, JoinHandle}; -use indexmap::IndexMap; -use melib::backends::*; -use melib::email::*; -use melib::error::{Error, ErrorKind, Result}; -use melib::text_processing::GlobMatch; -use melib::thread::{SortField, SortOrder, Threads}; -use melib::AddressBook; -use melib::Collection; -use smallvec::SmallVec; -use std::collections::BTreeMap; -use std::collections::{HashMap, HashSet}; +use std::{ + borrow::Cow, + collections::{BTreeMap, HashMap, HashSet, VecDeque}, + convert::TryFrom, + fs, + future::Future, + io, + ops::{Index, IndexMut}, + os::unix::fs::PermissionsExt, + pin::Pin, + result, + sync::{Arc, RwLock}, +}; -use crate::types::UIEvent::{self, EnvelopeRemove, EnvelopeRename, EnvelopeUpdate, Notification}; -use crate::{StatusEvent, ThreadEvent}; use crossbeam::channel::Sender; use futures::{ future::FutureExt, stream::{Stream, StreamExt}, }; -use std::borrow::Cow; -use std::collections::VecDeque; -use std::convert::TryFrom; -use std::fs; -use std::future::Future; -use std::io; -use std::ops::{Index, IndexMut}; -use std::os::unix::fs::PermissionsExt; -use std::pin::Pin; -use std::result; -use std::sync::{Arc, RwLock}; +use indexmap::IndexMap; +use melib::{ + backends::*, + email::*, + error::{Error, ErrorKind, Result}, + text_processing::GlobMatch, + thread::{SortField, SortOrder, Threads}, + AddressBook, Collection, +}; +use smallvec::SmallVec; + +use super::{AccountConf, FileMailboxConf}; +use crate::{ + jobs::{JobExecutor, JobId, JoinHandle}, + types::UIEvent::{self, EnvelopeRemove, EnvelopeRename, EnvelopeUpdate, Notification}, + StatusEvent, ThreadEvent, +}; #[macro_export] macro_rules! try_recv_timeout { @@ -72,21 +76,16 @@ macro_rules! try_recv_timeout { }}; } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub enum MailboxStatus { Available, Failed(Error), /// first argument is done work, and second is total work Parsing(usize, usize), + #[default] None, } -impl Default for MailboxStatus { - fn default() -> Self { - MailboxStatus::None - } -} - impl MailboxStatus { pub fn is_available(&self) -> bool { matches!(self, MailboxStatus::Available) @@ -512,7 +511,11 @@ impl Account { Err(err) => { sender .send(ThreadEvent::UIEvent(UIEvent::StatusEvent( - StatusEvent::DisplayMessage(format!("Error with setting up an sqlite3 search database for account `{}`: {}", name, err)) + StatusEvent::DisplayMessage(format!( + "Error with setting up an sqlite3 search database for account \ + `{}`: {}", + name, err + )), ))) .unwrap(); None @@ -523,7 +526,11 @@ impl Account { if !db_path.exists() { sender .send(ThreadEvent::UIEvent(UIEvent::StatusEvent( - StatusEvent::DisplayMessage(format!("An sqlite3 search database for account `{}` seems to be missing, a new one must be created with the `reindex` command.", name)) + StatusEvent::DisplayMessage(format!( + "An sqlite3 search database for account `{}` seems to be missing, \ + a new one must be created with the `reindex` command.", + name + )), ))) .unwrap(); } @@ -563,9 +570,10 @@ impl Account { let mut sent_mailbox = None; - /* Keep track of which mailbox config values we encounter in the actual mailboxes returned - * by the backend. For each of the actual mailboxes, delete the key from the hash set. If - * any are left, they are misconfigurations (eg misspelling) and a warning is shown to the + /* Keep track of which mailbox config values we encounter in the actual + * mailboxes returned by the backend. For each of the actual + * mailboxes, delete the key from the hash set. If any are left, they + * are misconfigurations (eg misspelling) and a warning is shown to the * user */ let mut mailbox_conf_hash_set = self .settings @@ -630,17 +638,19 @@ impl Account { for missing_mailbox in &mailbox_conf_hash_set { melib::log( format!( - "Account `{}` mailbox `{}` configured but not present in account's mailboxes. Is it misspelled?", + "Account `{}` mailbox `{}` configured but not present in account's mailboxes. \ + Is it misspelled?", &self.name, missing_mailbox, ), melib::WARN, ); self.sender .send(ThreadEvent::UIEvent(UIEvent::StatusEvent( - StatusEvent::DisplayMessage(format!( - "Account `{}` mailbox `{}` configured but not present in account's mailboxes. Is it misspelled?", - &self.name, missing_mailbox, - )), + StatusEvent::DisplayMessage(format!( + "Account `{}` mailbox `{}` configured but not present in account's \ + mailboxes. Is it misspelled?", + &self.name, missing_mailbox, + )), ))) .unwrap(); } @@ -732,7 +742,8 @@ impl Account { } { - //let mailbox: &mut Mailbox = self.mailboxes[idx].as_mut().unwrap().as_mut().unwrap(); + //let mailbox: &mut Mailbox = + // self.mailboxes[idx].as_mut().unwrap().as_mut().unwrap(); match event.kind { RefreshEventKind::Update(old_hash, envelope) => { if !self.collection.contains_key(&old_hash) { @@ -1056,7 +1067,7 @@ impl Account { pub fn refresh(&mut self, mailbox_hash: MailboxHash) -> Result<()> { if let Some(ref refresh_command) = self.settings.conf().refresh_command { let child = std::process::Command::new("sh") - .args(&["-c", refresh_command]) + .args(["-c", refresh_command]) .stdin(std::process::Stdio::null()) .stdout(std::process::Stdio::null()) .stderr(std::process::Stdio::piped()) @@ -1297,9 +1308,12 @@ impl Account { send_mail: crate::conf::composing::SendMail, complete_in_background: bool, ) -> Result>>> { + use std::{ + io::Write, + process::{Command, Stdio}, + }; + use crate::conf::composing::SendMail; - use std::io::Write; - use std::process::{Command, Stdio}; debug!(&send_mail); match send_mail { SendMail::ShellCommand(ref command) => { @@ -1309,7 +1323,7 @@ impl Account { )); } let mut msmtp = Command::new("sh") - .args(&["-c", command]) + .args(["-c", command]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() @@ -1385,9 +1399,12 @@ impl Account { let backend = self.backend.clone(); |message: Arc| -> Pin> + Send>> { Box::pin(async move { + use std::{ + io::Write, + process::{Command, Stdio}, + }; + use crate::conf::composing::SendMail; - use std::io::Write; - use std::process::{Command, Stdio}; match send_mail { SendMail::ShellCommand(ref command) => { if command.is_empty() { @@ -1396,7 +1413,7 @@ impl Account { )); } let mut msmtp = Command::new("sh") - .args(&["-c", command]) + .args(["-c", command]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() @@ -1418,9 +1435,10 @@ impl Account { ) } else { format!( - "Could not send e-mail using `{}`: Process was killed by signal", - command - ) + "Could not send e-mail using `{}`: Process was killed by \ + signal", + command + ) }; melib::log(&error_message, melib::LoggingLevel::ERROR); return Err(Error::new(error_message).set_summary("Message not sent.")); @@ -1566,8 +1584,8 @@ impl Account { 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 - * account goes from offline to online. */ + /* Call only in Context::is_online, since only Context can launch the watcher + * threads if an account goes from offline to online. */ pub fn is_online(&mut self) -> Result<()> { if !self.backend_capabilities.is_remote && !self.backend_capabilities.is_async { return Ok(()); @@ -1967,7 +1985,8 @@ impl Account { } tmp }; - /* if new mailbox has parent, we need to update its children field */ + /* if new mailbox has parent, we need to update its children + * field */ if let Some(parent_hash) = mailboxes[&mailbox_hash].parent() { self.mailbox_entries .entry(parent_hash) @@ -2002,7 +2021,8 @@ impl Account { &self.mailbox_entries, &mut self.mailboxes_order, ); - //Ok(format!("`{}` successfully created.", &path)) + //Ok(format!("`{}` successfully created.", + // &path)) } } } @@ -2050,7 +2070,8 @@ impl Account { .remove(&mailbox_hash); let deleted_mailbox = self.mailbox_entries.remove(&mailbox_hash).unwrap(); - /* if deleted mailbox had parent, we need to update its children field */ + /* if deleted mailbox had parent, we need to update its children + * field */ if let Some(parent_hash) = deleted_mailbox.ref_mailbox.parent() { self.mailbox_entries .entry(parent_hash) @@ -2392,7 +2413,7 @@ fn build_mailboxes_order( } while let Some(i) = iter.next() { let c = &mut node.children[i]; - rec(c, mailbox_entries, indentation, iter.peek() != None); + rec(c, mailbox_entries, indentation, iter.peek().is_some()); } } diff --git a/src/conf/composing.rs b/src/conf/composing.rs index 8bbd9c78..5c477d77 100644 --- a/src/conf/composing.rs +++ b/src/conf/composing.rs @@ -20,10 +20,12 @@ */ //! Configuration for composing email. -use super::default_vals::{ask, false_val, none, true_val}; -use melib::ToggleFlag; use std::collections::HashMap; +use melib::ToggleFlag; + +use super::default_vals::{ask, false_val, none, true_val}; + /// Settings for writing and sending new e-mail #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(deny_unknown_fields)] @@ -31,7 +33,9 @@ pub struct ComposingSettings { /// A command to pipe new emails to /// Required pub send_mail: SendMail, - /// Command to launch editor. Can have arguments. Draft filename is given as the last argument. If it's missing, the environment variable $EDITOR is looked up. + /// Command to launch editor. Can have arguments. Draft filename is given as + /// the last argument. If it's missing, the environment variable $EDITOR is + /// looked up. #[serde( default = "none", alias = "editor-command", @@ -54,15 +58,16 @@ pub struct ComposingSettings { /// Default: empty #[serde(default, alias = "default-header-values")] pub default_header_values: HashMap, - /// Wrap header preample when editing a draft in an editor. This allows you to write non-plain - /// text email without the preamble creating syntax errors. They are stripped when you return - /// from the editor. The values should be a two element array of strings, a prefix and suffix. + /// Wrap header preample when editing a draft in an editor. This allows you + /// to write non-plain text email without the preamble creating syntax + /// errors. They are stripped when you return from the editor. The + /// values should be a two element array of strings, a prefix and suffix. /// Default: None #[serde(default, alias = "wrap-header-preample")] pub wrap_header_preamble: Option<(String, String)>, - /// Store sent mail after successful submission. This setting is meant to be disabled for - /// non-standard behaviour in gmail, which auto-saves sent mail on its own. - /// Default: true + /// Store sent mail after successful submission. This setting is meant to be + /// disabled for non-standard behaviour in gmail, which auto-saves sent + /// mail on its own. Default: true #[serde(default = "true_val")] pub store_sent_mail: bool, /// The attribution line appears above the quoted reply text. @@ -70,12 +75,12 @@ pub struct ComposingSettings { /// - `%+f` — the sender's name and email address. /// - `%+n` — the sender's name (or email address, if no name is included). /// - `%+a` — the sender's email address. - /// The format string is passed to strftime(3) with the replied envelope's date. - /// Default: "On %a, %0e %b %Y %H:%M, %+f wrote:%n" + /// The format string is passed to strftime(3) with the replied envelope's + /// date. Default: "On %a, %0e %b %Y %H:%M, %+f wrote:%n" #[serde(default = "none")] pub attribution_format_string: Option, - /// Whether the strftime call for the attribution string uses the POSIX locale instead of - /// the user's active locale + /// Whether the strftime call for the attribution string uses the POSIX + /// locale instead of the user's active locale /// Default: true #[serde(default = "true_val")] pub attribution_use_posix_locale: bool, @@ -84,7 +89,12 @@ pub struct ComposingSettings { #[serde(default = "ask", alias = "forward-as-attachment")] pub forward_as_attachment: ToggleFlag, /// Alternative lists of reply prefixes (etc. ["Re:", "RE:", ...]) to strip - /// Default: `["Re:", "RE:", "Fwd:", "Fw:", "回复:", "回覆:", "SV:", "Sv:", "VS:", "Antw:", "Doorst:", "VS:", "VL:", "REF:", "TR:", "TR:", "AW:", "WG:", "ΑΠ:", "Απ:", "απ:", "ΠΡΘ:", "Πρθ:", "πρθ:", "ΣΧΕΤ:", "Σχετ:", "σχετ:", "ΠΡΘ:", "Πρθ:", "πρθ:", "Vá:", "Továbbítás:", "R:", "I:", "RIF:", "FS:", "BLS:", "TRS:", "VS:", "VB:", "RV:", "RES:", "Res", "ENC:", "Odp:", "PD:", "YNT:", "İLT:", "ATB:", "YML:"]` + /// Default: `["Re:", "RE:", "Fwd:", "Fw:", "回复:", "回覆:", "SV:", "Sv:", + /// "VS:", "Antw:", "Doorst:", "VS:", "VL:", "REF:", "TR:", "TR:", "AW:", + /// "WG:", "ΑΠ:", "Απ:", "απ:", "ΠΡΘ:", "Πρθ:", "πρθ:", "ΣΧΕΤ:", "Σχετ:", + /// "σχετ:", "ΠΡΘ:", "Πρθ:", "πρθ:", "Vá:", "Továbbítás:", "R:", "I:", + /// "RIF:", "FS:", "BLS:", "TRS:", "VS:", "VB:", "RV:", "RES:", "Res", + /// "ENC:", "Odp:", "PD:", "YNT:", "İLT:", "ATB:", "YML:"]` #[serde(default, alias = "reply-prefix-list-to-strip")] pub reply_prefix_list_to_strip: Option>, /// The prefix to use in reply subjects. The de facto prefix is "Re:". diff --git a/src/conf/listing.rs b/src/conf/listing.rs index 2bf4b3db..09079e62 100644 --- a/src/conf/listing.rs +++ b/src/conf/listing.rs @@ -19,9 +19,9 @@ * along with meli. If not, see . */ +use melib::{search::Query, Error, Result}; + use super::{default_vals::*, DotAddressable, IndexStyle}; -use melib::search::Query; -use melib::{Error, Result}; /// Settings for mail listings /// @@ -29,32 +29,32 @@ use melib::{Error, Result}; /// Tree decoration examples: /// ///```no_run -///const HAS_SIBLING: &str = " ┃"; -///const NO_SIBLING: &str = " "; -///const HAS_SIBLING_LEAF: &str = " ┣━"; -///const NO_SIBLING_LEAF: &str = " ┗━"; -///``` +/// const HAS_SIBLING: &str = " ┃"; +/// const NO_SIBLING: &str = " "; +/// const HAS_SIBLING_LEAF: &str = " ┣━"; +/// const NO_SIBLING_LEAF: &str = " ┗━"; +/// ``` /// ///```no_run -///const HAS_SIBLING: &str = " |"; -///const NO_SIBLING: &str = " "; -///const HAS_SIBLING_LEAF: &str = " |\\_"; -///const NO_SIBLING_LEAF: &str = " \\_"; -///``` +/// const HAS_SIBLING: &str = " |"; +/// const NO_SIBLING: &str = " "; +/// const HAS_SIBLING_LEAF: &str = " |\\_"; +/// const NO_SIBLING_LEAF: &str = " \\_"; +/// ``` /// ///```no_run -///const HAS_SIBLING: &str = " "; -///const NO_SIBLING: &str = " "; -///const HAS_SIBLING_LEAF: &str = " "; -///const NO_SIBLING_LEAF: &str = " "; -///``` +/// const HAS_SIBLING: &str = " "; +/// const NO_SIBLING: &str = " "; +/// const HAS_SIBLING_LEAF: &str = " "; +/// const NO_SIBLING_LEAF: &str = " "; +/// ``` /// ///```no_run -///const HAS_SIBLING: &str = " │"; -///const NO_SIBLING: &str = " "; -///const HAS_SIBLING_LEAF: &str = " ├─"; -///const NO_SIBLING_LEAF: &str = " ╰─"; -///``` +/// const HAS_SIBLING: &str = " │"; +/// const NO_SIBLING: &str = " "; +/// const HAS_SIBLING_LEAF: &str = " ├─"; +/// const NO_SIBLING_LEAF: &str = " ╰─"; +/// ``` #[derive(Debug, Deserialize, Clone, Serialize)] #[serde(deny_unknown_fields)] pub struct ListingSettings { @@ -130,8 +130,8 @@ pub struct ListingSettings { #[serde(default)] pub attachment_flag: Option, - /// Should threads with differentiating Subjects show a list of those subjects on the entry - /// title? + /// Should threads with differentiating Subjects show a list of those + /// subjects on the entry title? /// Default: "true" #[serde(default = "true_val")] pub thread_subject_pack: bool, diff --git a/src/conf/notifications.rs b/src/conf/notifications.rs index ea68a477..b49741ab 100644 --- a/src/conf/notifications.rs +++ b/src/conf/notifications.rs @@ -19,10 +19,13 @@ * along with meli. If not, see . */ -use super::default_vals::{internal_value_false, none, true_val}; -use super::DotAddressable; use melib::{Error, Result, ToggleFlag}; +use super::{ + default_vals::{internal_value_false, none, true_val}, + DotAddressable, +}; + /// Settings for the notifications function. #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(deny_unknown_fields)] @@ -37,14 +40,14 @@ pub struct NotificationsSettings { #[serde(default = "none")] pub script: Option, - /// A command to pipe new mail notifications through (preferred over `script`). - /// Default: None + /// A command to pipe new mail notifications through (preferred over + /// `script`). Default: None #[serde(default = "none")] pub new_mail_script: Option, - /// A file location which has its size changed when new mail arrives (max 128 bytes). Can be - /// used to trigger new mail notifications eg with `xbiff(1)`. - /// Default: None + /// A file location which has its size changed when new mail arrives (max + /// 128 bytes). Can be used to trigger new mail notifications eg with + /// `xbiff(1)`. Default: None #[serde(default = "none", alias = "xbiff-file-path")] pub xbiff_file_path: Option, diff --git a/src/conf/overrides.rs b/src/conf/overrides.rs index 4f0d4a6e..b7f3e0c3 100644 --- a/src/conf/overrides.rs +++ b/src/conf/overrides.rs @@ -1,3 +1,4 @@ +// @generated /* * meli - conf/overrides.rs * @@ -83,7 +84,8 @@ pub struct PagerSettingsOverride { #[serde(alias = "show-date-in-my-timezone")] #[serde(default)] pub show_date_in_my_timezone: Option, - #[doc = " A command to launch URLs with. The URL will be given as the first argument of the command."] + #[doc = " A command to launch URLs with. The URL will be given as the first argument of the \ + command."] #[doc = " Default: None"] #[serde(deserialize_with = "non_empty_string")] #[serde(default)] @@ -177,7 +179,8 @@ pub struct ListingSettingsOverride { #[doc = " Default: \"📎\""] #[serde(default)] pub attachment_flag: Option>, - #[doc = " Should threads with differentiating Subjects show a list of those subjects on the entry"] + #[doc = " Should threads with differentiating Subjects show a list of those subjects on the \ + entry"] #[doc = " title?"] #[doc = " Default: \"true\""] #[serde(default)] @@ -222,7 +225,8 @@ pub struct NotificationsSettingsOverride { #[doc = " Default: None"] #[serde(default)] pub new_mail_script: Option>, - #[doc = " A file location which has its size changed when new mail arrives (max 128 bytes). Can be"] + #[doc = " A file location which has its size changed when new mail arrives (max 128 bytes). \ + Can be"] #[doc = " used to trigger new mail notifications eg with `xbiff(1)`."] #[doc = " Default: None"] #[serde(alias = "xbiff-file-path")] @@ -290,7 +294,8 @@ pub struct ComposingSettingsOverride { #[doc = " Required"] #[serde(default)] pub send_mail: Option, - #[doc = " Command to launch editor. Can have arguments. Draft filename is given as the last argument. If it's missing, the environment variable $EDITOR is looked up."] + #[doc = " Command to launch editor. Can have arguments. Draft filename is given as the last \ + argument. If it's missing, the environment variable $EDITOR is looked up."] #[serde(alias = "editor-command", alias = "editor-cmd", alias = "editor_cmd")] #[serde(default)] pub editor_command: Option>, @@ -312,14 +317,18 @@ pub struct ComposingSettingsOverride { #[serde(alias = "default-header-values")] #[serde(default)] pub default_header_values: Option>, - #[doc = " Wrap header preample when editing a draft in an editor. This allows you to write non-plain"] - #[doc = " text email without the preamble creating syntax errors. They are stripped when you return"] - #[doc = " from the editor. The values should be a two element array of strings, a prefix and suffix."] + #[doc = " Wrap header preample when editing a draft in an editor. This allows you to write \ + non-plain"] + #[doc = " text email without the preamble creating syntax errors. They are stripped when you \ + return"] + #[doc = " from the editor. The values should be a two element array of strings, a prefix and \ + suffix."] #[doc = " Default: None"] #[serde(alias = "wrap-header-preample")] #[serde(default)] pub wrap_header_preamble: Option>, - #[doc = " Store sent mail after successful submission. This setting is meant to be disabled for"] + #[doc = " Store sent mail after successful submission. This setting is meant to be disabled \ + for"] #[doc = " non-standard behaviour in gmail, which auto-saves sent mail on its own."] #[doc = " Default: true"] #[serde(default)] @@ -333,7 +342,8 @@ pub struct ComposingSettingsOverride { #[doc = " Default: \"On %a, %0e %b %Y %H:%M, %+f wrote:%n\""] #[serde(default)] pub attribution_format_string: Option>, - #[doc = " Whether the strftime call for the attribution string uses the POSIX locale instead of"] + #[doc = " Whether the strftime call for the attribution string uses the POSIX locale instead \ + of"] #[doc = " the user's active locale"] #[doc = " Default: true"] #[serde(default)] @@ -344,7 +354,13 @@ pub struct ComposingSettingsOverride { #[serde(default)] pub forward_as_attachment: Option, #[doc = " Alternative lists of reply prefixes (etc. [\"Re:\", \"RE:\", ...]) to strip"] - #[doc = " Default: `[\"Re:\", \"RE:\", \"Fwd:\", \"Fw:\", \"回复:\", \"回覆:\", \"SV:\", \"Sv:\", \"VS:\", \"Antw:\", \"Doorst:\", \"VS:\", \"VL:\", \"REF:\", \"TR:\", \"TR:\", \"AW:\", \"WG:\", \"ΑΠ:\", \"Απ:\", \"απ:\", \"ΠΡΘ:\", \"Πρθ:\", \"πρθ:\", \"ΣΧΕΤ:\", \"Σχετ:\", \"σχετ:\", \"ΠΡΘ:\", \"Πρθ:\", \"πρθ:\", \"Vá:\", \"Továbbítás:\", \"R:\", \"I:\", \"RIF:\", \"FS:\", \"BLS:\", \"TRS:\", \"VS:\", \"VB:\", \"RV:\", \"RES:\", \"Res\", \"ENC:\", \"Odp:\", \"PD:\", \"YNT:\", \"İLT:\", \"ATB:\", \"YML:\"]`"] + #[doc = " Default: `[\"Re:\", \"RE:\", \"Fwd:\", \"Fw:\", \"回复:\", \"回覆:\", \"SV:\", \ + \"Sv:\", \"VS:\", \"Antw:\", \"Doorst:\", \"VS:\", \"VL:\", \"REF:\", \"TR:\", \ + \"TR:\", \"AW:\", \"WG:\", \"ΑΠ:\", \"Απ:\", \"απ:\", \"ΠΡΘ:\", \"Πρθ:\", \"πρθ:\", \ + \"ΣΧΕΤ:\", \"Σχετ:\", \"σχετ:\", \"ΠΡΘ:\", \"Πρθ:\", \"πρθ:\", \"Vá:\", \ + \"Továbbítás:\", \"R:\", \"I:\", \"RIF:\", \"FS:\", \"BLS:\", \"TRS:\", \"VS:\", \ + \"VB:\", \"RV:\", \"RES:\", \"Res\", \"ENC:\", \"Odp:\", \"PD:\", \"YNT:\", \ + \"İLT:\", \"ATB:\", \"YML:\"]`"] #[serde(alias = "reply-prefix-list-to-strip")] #[serde(default)] pub reply_prefix_list_to_strip: Option>>, diff --git a/src/conf/pager.rs b/src/conf/pager.rs index 38efeace..8bbce8d3 100644 --- a/src/conf/pager.rs +++ b/src/conf/pager.rs @@ -21,11 +21,10 @@ //! Settings for the pager function. -use super::default_vals::*; -use super::deserializers::*; -use super::DotAddressable; use melib::{Error, Result, ToggleFlag}; +use super::{default_vals::*, deserializers::*, DotAddressable}; + /// Settings for the pager function. #[derive(Debug, Deserialize, Clone, Serialize)] #[serde(deny_unknown_fields)] @@ -79,8 +78,8 @@ pub struct PagerSettings { #[serde(default = "eighty_val", alias = "minimum-width")] pub minimum_width: usize, - /// Choose `text/html` alternative if `text/plain` is empty in `multipart/alternative` - /// attachments. + /// Choose `text/html` alternative if `text/plain` is empty in + /// `multipart/alternative` attachments. /// Default: true #[serde( default = "internal_value_true", @@ -93,8 +92,8 @@ pub struct PagerSettings { #[serde(default = "internal_value_true", alias = "show-date-in-my-timezone")] pub show_date_in_my_timezone: ToggleFlag, - /// A command to launch URLs with. The URL will be given as the first argument of the command. - /// Default: None + /// A command to launch URLs with. The URL will be given as the first + /// argument of the command. Default: None #[serde(default = "none", deserialize_with = "non_empty_string")] pub url_launcher: Option, diff --git a/src/conf/pgp.rs b/src/conf/pgp.rs index 7d9ce7e2..16cecc0d 100644 --- a/src/conf/pgp.rs +++ b/src/conf/pgp.rs @@ -19,11 +19,12 @@ * along with meli. If not, see . */ -#[cfg(feature = "gpgme")] -use super::default_vals::*; #[cfg(feature = "gpgme")] use melib::conf::ToggleFlag; +#[cfg(feature = "gpgme")] +use super::default_vals::*; + #[cfg(feature = "gpgme")] /// Settings for digital signing and encryption #[derive(Debug, Deserialize, Clone, Serialize)] diff --git a/src/conf/shortcuts.rs b/src/conf/shortcuts.rs index 28d99e85..f85ec146 100644 --- a/src/conf/shortcuts.rs +++ b/src/conf/shortcuts.rs @@ -19,11 +19,12 @@ * along with meli. If not, see . */ -use super::DotAddressable; -use crate::terminal::Key; use indexmap::IndexMap; use melib::{Error, Result}; +use super::DotAddressable; +use crate::terminal::Key; + #[macro_export] macro_rules! shortcut { ($key:ident == $shortcuts:ident[$section:expr][$val:literal]) => { diff --git a/src/conf/tags.rs b/src/conf/tags.rs index 58559cdf..4c06aada 100644 --- a/src/conf/tags.rs +++ b/src/conf/tags.rs @@ -21,11 +21,13 @@ //! E-mail tag configuration and {de,}serializing. -use super::DotAddressable; -use crate::terminal::Color; +use std::collections::{HashMap, HashSet}; + use melib::{Error, Result, TagHash}; use serde::{Deserialize, Deserializer}; -use std::collections::{HashMap, HashSet}; + +use super::DotAddressable; +use crate::terminal::Color; #[derive(Default, Debug, Deserialize, Clone, Serialize)] #[serde(deny_unknown_fields)] diff --git a/src/conf/terminal.rs b/src/conf/terminal.rs index 57faafe6..6b3beeb1 100644 --- a/src/conf/terminal.rs +++ b/src/conf/terminal.rs @@ -21,11 +21,10 @@ //! Settings for terminal display -use super::deserializers::non_empty_string; -use super::DotAddressable; -use super::Themes; use melib::{Error, Result, ToggleFlag}; +use super::{deserializers::non_empty_string, DotAddressable, Themes}; + /// Settings for terminal display #[derive(Debug, Deserialize, Clone, Serialize)] #[serde(default, deny_unknown_fields)] @@ -35,8 +34,8 @@ pub struct TerminalSettings { pub themes: Themes, pub ascii_drawing: bool, pub use_color: ToggleFlag, - /// Use mouse events. This will disable text selection, but you will be able to resize some - /// widgets. + /// Use mouse events. This will disable text selection, but you will be able + /// to resize some widgets. /// Default: False pub use_mouse: ToggleFlag, /// String to show in status bar if mouse is active. @@ -47,9 +46,9 @@ pub struct TerminalSettings { pub window_title: Option, #[serde(deserialize_with = "non_empty_string")] pub file_picker_command: Option, - /// Choose between 30-something built in sequences (integers between 0-30) or define your own - /// list of strings for the progress spinner animation. - /// Default: 0 + /// Choose between 30-something built in sequences (integers between 0-30) + /// or define your own list of strings for the progress spinner + /// animation. Default: 0 #[serde(default)] pub progress_spinner_sequence: Option, } diff --git a/src/conf/themes.rs b/src/conf/themes.rs index 204e8597..1543be83 100644 --- a/src/conf/themes.rs +++ b/src/conf/themes.rs @@ -21,22 +21,26 @@ //! Application themes. //! -//! * An attribute is a triple of foreground color, background color and terminal attribute `ThemeValue`s. -//! * A `ThemeValue` is either an actual value or the key name of another value to which it depends. The value is either `Color` or `Attr`. +//! * An attribute is a triple of foreground color, background color and +//! terminal attribute `ThemeValue`s. +//! * A `ThemeValue` is either an actual value or the key name of another +//! value to which it depends. The value is either `Color` or `Attr`. //! * `ThemeAttributeInner` is an attribute triplet. //! * `ThemeAttribute` is an attribute triplet with the links resolved. //! //! On startup a [DFS](https://en.wikipedia.org/wiki/Depth-first_search) is performed to see if there are any cycles in the link graph. -use crate::terminal::{Attr, Color}; -use crate::Context; +use std::{borrow::Cow, collections::HashSet, fmt::Write}; + use indexmap::IndexMap; use melib::{Error, Result}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use smallvec::SmallVec; -use std::borrow::Cow; -use std::collections::HashSet; -use std::fmt::Write; + +use crate::{ + terminal::{Attr, Color}, + Context, +}; #[inline(always)] pub fn value(context: &Context, key: &'static str) -> ThemeAttribute { @@ -364,7 +368,8 @@ impl ThemeLink for Attr { } #[derive(Debug, Clone)] -/// Holds either an actual value or refers to the key name of the attribute that holds the value. +/// Holds either an actual value or refers to the key name of the attribute that +/// holds the value. enum ThemeValue { Value(T), Alias(Cow<'static, str>), @@ -839,7 +844,6 @@ impl<'de> Deserialize<'de> for Themes { s.light .keys .keys() - .into_iter() .map(|k| k.as_ref()) .collect::>() .join(", ") @@ -895,7 +899,6 @@ impl<'de> Deserialize<'de> for Themes { s.dark .keys .keys() - .into_iter() .map(|k| k.as_ref()) .collect::>() .join(", ") @@ -954,7 +957,6 @@ impl<'de> Deserialize<'de> for Themes { theme .keys .keys() - .into_iter() .map(|k| k.as_ref()) .collect::>() .join(", ") @@ -2038,7 +2040,8 @@ fn test_theme_parsing() { /* MUST SUCCEED: default themes should be valid */ let def = Themes::default(); assert!(def.validate().is_ok()); - /* MUST SUCCEED: new user theme `hunter2`, theme `dark` has user redefinitions */ + /* MUST SUCCEED: new user theme `hunter2`, theme `dark` has user + * redefinitions */ const TEST_STR: &str = r##"[dark] "mail.listing.tag_default" = { fg = "White", bg = "HotPink3" } "mail.listing.attachment_flag" = { fg = "mail.listing.tag_default.bg" } @@ -2147,10 +2150,7 @@ color_aliases= { "Jebediah" = "$JebediahJr", "JebediahJr" = "mail.listing.tag_de #[test] fn test_theme_key_values() { - use std::collections::VecDeque; - use std::fs::File; - use std::io::Read; - use std::path::PathBuf; + use std::{collections::VecDeque, fs::File, io::Read, path::PathBuf}; let mut rust_files: VecDeque = VecDeque::new(); let mut dirs_queue: VecDeque = VecDeque::new(); dirs_queue.push_back("src/".into()); @@ -2162,9 +2162,9 @@ fn test_theme_key_values() { let entry = entry.unwrap(); let path = entry.path(); if path.is_dir() { - dirs_queue.push_back(path.into()); + dirs_queue.push_back(path); } else if path.extension().map(|os_s| os_s == "rs").unwrap_or(false) { - rust_files.push_back(path.into()); + rust_files.push_back(path); } } } @@ -2176,7 +2176,12 @@ fn test_theme_key_values() { for mat in re_conf.captures_iter(&content) { let theme_key = &mat[1]; if !DEFAULT_KEYS.contains(&theme_key) { - panic!("Source file {} contains a hardcoded theme key str, {:?}, that is not included in the DEFAULT_KEYS table.", file_path.display(), theme_key); + panic!( + "Source file {} contains a hardcoded theme key str, {:?}, that is not \ + included in the DEFAULT_KEYS table.", + file_path.display(), + theme_key + ); } } } diff --git a/src/jobs.rs b/src/jobs.rs index d201c5ef..58c39973 100644 --- a/src/jobs.rs +++ b/src/jobs.rs @@ -21,21 +21,25 @@ //! Async job executor thread pool -use melib::smol; -use melib::uuid::Uuid; -use std::collections::HashMap; -use std::future::Future; -use std::panic::catch_unwind; -use std::sync::{Arc, Mutex}; -use std::thread; -use std::time::Duration; +use std::{ + collections::HashMap, + future::Future, + iter, + panic::catch_unwind, + sync::{Arc, Mutex}, + thread, + time::Duration, +}; + +use crossbeam::{ + channel::Sender, + deque::{Injector, Stealer, Worker}, + sync::{Parker, Unparker}, +}; +pub use futures::channel::oneshot; +use melib::{smol, uuid::Uuid}; use crate::types::{ThreadEvent, UIEvent}; -use crossbeam::channel::Sender; -use crossbeam::deque::{Injector, Stealer, Worker}; -use crossbeam::sync::{Parker, Unparker}; -pub use futures::channel::oneshot; -use std::iter; type AsyncTask = async_task::Runnable; @@ -245,7 +249,8 @@ impl JobExecutor { } } - /// Spawns a future with a generic return value `R` that might block on a new thread + /// Spawns a future with a generic return value `R` that might block on a + /// new thread pub fn spawn_blocking(&self, future: F) -> JoinHandle where F: Future + Send + 'static, diff --git a/src/lib.rs b/src/lib.rs index b9726211..875b50cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,16 +20,16 @@ */ //! -//! This crate contains the frontend stuff of the application. The application entry way on -//! `src/bin.rs` creates an event loop and passes input to a thread. -//! -//! The mail handling stuff is done in the `melib` crate which includes all backend needs. The -//! split is done to theoretically be able to create different frontends with the same innards. +//! This crate contains the frontend stuff of the application. The application +//! entry way on `src/bin.rs` creates an event loop and passes input to a +//! thread. //! +//! The mail handling stuff is done in the `melib` crate which includes all +//! backend needs. The split is done to theoretically be able to create +//! different frontends with the same innards. use std::alloc::System; -pub use std::collections::VecDeque; -pub use std::path::PathBuf; +pub use std::{collections::VecDeque, path::PathBuf}; #[macro_use] extern crate serde_derive; diff --git a/src/mailcap.rs b/src/mailcap.rs index 62a3552e..1c8a1e0a 100644 --- a/src/mailcap.rs +++ b/src/mailcap.rs @@ -21,17 +21,21 @@ //! # mailcap file - Find mailcap entries to execute attachments. //! -//! Implements [RFC 1524 A User Agent Configuration Mechanism For Multimedia Mail Format -//! Information](https://www.rfc-editor.org/rfc/inline-errata/rfc1524.html) -use crate::state::Context; -use crate::types::{create_temp_file, ForkType, UIEvent}; -use melib::text_processing::GlobMatch; -use melib::{email::Attachment, Error, Result}; -use std::collections::HashMap; -use std::io::Read; -use std::io::Write; -use std::path::PathBuf; -use std::process::{Command, Stdio}; +//! Implements [RFC 1524 A User Agent Configuration Mechanism For Multimedia +//! Mail Format Information](https://www.rfc-editor.org/rfc/inline-errata/rfc1524.html) +use std::{ + collections::HashMap, + io::{Read, Write}, + path::PathBuf, + process::{Command, Stdio}, +}; + +use melib::{email::Attachment, text_processing::GlobMatch, Error, Result}; + +use crate::{ + state::Context, + types::{create_temp_file, ForkType, UIEvent}, +}; pub struct MailcapEntry { command: String, @@ -42,7 +46,8 @@ pub struct MailcapEntry { impl MailcapEntry { pub fn execute(a: &Attachment, context: &mut Context) -> Result<()> { /* lookup order: - * $XDG_CONFIG_HOME/meli/mailcap:$XDG_CONFIG_HOME/.mailcap:$HOME/.mailcap:/etc/mailcap:/usr/etc/mailcap:/usr/local/etc/mailcap + * $XDG_CONFIG_HOME/meli/mailcap:$XDG_CONFIG_HOME/.mailcap:$HOME/.mailcap:/ + * etc/mailcap:/usr/etc/mailcap:/usr/local/etc/mailcap */ let xdg_dirs = xdg::BaseDirectories::with_prefix("meli").map_err(|e| Error::new(e.to_string()))?; @@ -188,7 +193,7 @@ impl MailcapEntry { if copiousoutput { let out = if needs_stdin { let mut child = Command::new("sh") - .args(&["-c", &cmd_string]) + .args(["-c", &cmd_string]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn()?; @@ -201,7 +206,7 @@ impl MailcapEntry { child.wait_with_output()?.stdout } else { let child = Command::new("sh") - .args(&["-c", &cmd_string]) + .args(["-c", &cmd_string]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn()?; @@ -223,7 +228,7 @@ impl MailcapEntry { debug!(pager.wait_with_output()?.stdout); } else if needs_stdin { let mut child = Command::new("sh") - .args(&["-c", &cmd_string]) + .args(["-c", &cmd_string]) .stdin(Stdio::piped()) .stdout(Stdio::inherit()) .spawn()?; @@ -236,7 +241,7 @@ impl MailcapEntry { debug!(child.wait_with_output()?.stdout); } else { let child = Command::new("sh") - .args(&["-c", &cmd_string]) + .args(["-c", &cmd_string]) .stdin(Stdio::inherit()) .stdout(Stdio::inherit()) .spawn()?; diff --git a/src/main.rs b/src/main.rs index 408352be..07d828b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,17 +21,20 @@ //! Command line client binary. //! -//! This crate contains the frontend stuff of the application. The application entry way on -//! `src/bin.rs` creates an event loop and passes input to a thread. +//! This crate contains the frontend stuff of the application. The application +//! entry way on `src/bin.rs` creates an event loop and passes input to a +//! thread. //! -//! The mail handling stuff is done in the `melib` crate which includes all backend needs. The -//! split is done to theoretically be able to create different frontends with the same innards. +//! The mail handling stuff is done in the `melib` crate which includes all +//! backend needs. The split is done to theoretically be able to create +//! different frontends with the same innards. use meli::*; mod args; -use args::*; use std::os::raw::c_int; +use args::*; + fn notify( signals: &[c_int], sender: crossbeam::channel::Sender, @@ -119,7 +122,10 @@ fn run_app(opt: Opt) -> Result<()> { let editor = std::env::var("EDITOR") .or_else(|_| std::env::var("VISUAL")) .map_err(|err| { - format!("Could not find any value in environment variables EDITOR and VISUAL. {err}") + format!( + "Could not find any value in environment variables EDITOR and VISUAL. \ + {err}" + ) })?; let config_path = crate::conf::get_config_file()?; @@ -146,8 +152,9 @@ fn run_app(opt: Opt) -> Result<()> { include_bytes!(concat!(env!("OUT_DIR"), "/meli-themes.txt.gz")), include_bytes!(concat!(env!("OUT_DIR"), "/meli.7.txt.gz")), ]; - use flate2::bufread::GzDecoder; use std::io::prelude::*; + + use flate2::bufread::GzDecoder; let mut gz = GzDecoder::new(MANPAGES[page as usize]); let mut v = String::with_capacity( str::parse::(unsafe { @@ -231,8 +238,9 @@ fn run_app(opt: Opt) -> Result<()> { None => {} } - /* Create a channel to communicate with other threads. The main process is the sole receiver. - * */ + /* Create a channel to communicate with other threads. The main process is + * the sole receiver. + */ let (sender, receiver) = crossbeam::channel::bounded(32 * ::std::mem::size_of::()); /* Catch SIGWINCH to handle terminal resizing */ let signals = &[ @@ -310,7 +318,8 @@ fn run_app(opt: Opt) -> Result<()> { } state.redraw(); - /* Poll on all channels. Currently we have the input channel for stdin, watching events and the signal watcher. */ + /* Poll on all channels. Currently we have the input channel for stdin, + * watching events and the signal watcher. */ crossbeam::select! { recv(receiver) -> r => { match r { diff --git a/src/managesieve.rs b/src/managesieve.rs index f68ef43f..a9538ca8 100644 --- a/src/managesieve.rs +++ b/src/managesieve.rs @@ -21,9 +21,9 @@ #[macro_use] extern crate melib; -use melib::*; - use std::collections::VecDeque; + +use melib::*; #[macro_use] extern crate serde_derive; extern crate linkify; @@ -32,8 +32,7 @@ extern crate serde_json; extern crate smallvec; extern crate termion; -use melib::backends::imap::managesieve::ManageSieveConnection; -use melib::Result; +use melib::{backends::imap::managesieve::ManageSieveConnection, Result}; #[macro_use] pub mod types; @@ -66,14 +65,16 @@ pub mod mailcap; use futures::executor::block_on; -/// Opens an interactive shell on a managesieve server. Suggested use is with rlwrap(1) +/// Opens an interactive shell on a managesieve server. Suggested use is with +/// rlwrap(1) /// /// # Example invocation: /// ```sh /// ./manage_sieve server_hostname server_username server_password server_port"); /// ``` /// -/// `danger_accept_invalid_certs` is turned on by default, so no certificate validation is performed. +/// `danger_accept_invalid_certs` is turned on by default, so no certificate +/// validation is performed. fn main() -> Result<()> { let mut args = std::env::args().skip(1).collect::>(); @@ -139,8 +140,7 @@ fn main() -> Result<()> { use PrevCmd::*; let mut prev_cmd: PrevCmd = None; loop { - use std::io; - use std::io::Write; + use std::{io, io::Write}; input.clear(); print!("> "); io::stdout().flush().unwrap(); @@ -193,7 +193,7 @@ fn main() -> Result<()> { match prev_cmd { None => println!("invalid command `{}`", input), Checkscript => { - let content = std::fs::read_to_string(&input).unwrap(); + let content = std::fs::read_to_string(input).unwrap(); let result = block_on(conn.checkscript(content.as_bytes())); println!("Got {:?}", result); prev_cmd = None; @@ -204,7 +204,7 @@ fn main() -> Result<()> { } PutscriptString(name) => { prev_cmd = None; - let content = std::fs::read_to_string(&input).unwrap(); + let content = std::fs::read_to_string(input).unwrap(); let result = block_on(conn.putscript(name.as_bytes(), content.as_bytes())); println!("Got {:?}", result); diff --git a/src/sqlite3.rs b/src/sqlite3.rs index 4348cd15..be15ded7 100644 --- a/src/sqlite3.rs +++ b/src/sqlite3.rs @@ -21,27 +21,31 @@ /*! Use an sqlite3 database for fast searching. */ -use crate::melib::ResultIntoError; -use melib::search::{ - escape_double_quote, - Query::{self, *}, +use std::{ + path::PathBuf, + sync::{Arc, RwLock}, }; + use melib::{ backends::{MailBackend, ResultFuture}, email::{Envelope, EnvelopeHash}, log, + search::{ + escape_double_quote, + Query::{self, *}, + }, sqlite3::{self as melib_sqlite3, rusqlite::params, DatabaseDescription}, thread::{SortField, SortOrder}, Error, Result, ERROR, }; - use smallvec::SmallVec; -use std::path::PathBuf; -use std::sync::{Arc, RwLock}; + +use crate::melib::ResultIntoError; const DB: DatabaseDescription = DatabaseDescription { -name: "index.db", -init_script:Some( "CREATE TABLE IF NOT EXISTS envelopes ( + name: "index.db", + init_script: Some( + "CREATE TABLE IF NOT EXISTS envelopes ( id INTEGER PRIMARY KEY, account_id INTEGER REFERENCES accounts ON UPDATE CASCADE, hash BLOB NOT NULL UNIQUE, @@ -89,7 +93,8 @@ CREATE INDEX IF NOT EXISTS envelope_cc_index ON envelopes (cc); CREATE INDEX IF NOT EXISTS envelope_bcc_index ON envelopes (bcc); CREATE INDEX IF NOT EXISTS envelope_message_id_index ON envelopes (message_id); - CREATE VIRTUAL TABLE IF NOT EXISTS fts USING fts5(subject, body_text, content=envelopes, content_rowid=id); + CREATE VIRTUAL TABLE IF NOT EXISTS fts USING fts5(subject, body_text, content=envelopes, \ + content_rowid=id); -- Triggers to keep the FTS index up to date. CREATE TRIGGER IF NOT EXISTS envelopes_ai AFTER INSERT ON envelopes BEGIN @@ -97,14 +102,17 @@ CREATE TRIGGER IF NOT EXISTS envelopes_ai AFTER INSERT ON envelopes BEGIN END; CREATE TRIGGER IF NOT EXISTS envelopes_ad AFTER DELETE ON envelopes BEGIN - INSERT INTO fts(fts, rowid, subject, body_text) VALUES('delete', old.id, old.subject, old.body_text); + INSERT INTO fts(fts, rowid, subject, body_text) VALUES('delete', old.id, old.subject, \ + old.body_text); END; CREATE TRIGGER IF NOT EXISTS envelopes_au AFTER UPDATE ON envelopes BEGIN - INSERT INTO fts(fts, rowid, subject, body_text) VALUES('delete', old.id, old.subject, old.body_text); + INSERT INTO fts(fts, rowid, subject, body_text) VALUES('delete', old.id, old.subject, \ + old.body_text); INSERT INTO fts(rowid, subject, body_text) VALUES (new.id, new.subject, new.body_text); -END; "), -version: 1, +END; ", + ), + version: 1, }; pub fn db_path() -> Result { @@ -126,8 +134,8 @@ pub fn db_path() -> Result { // || b != 0x60 // || b != 26 // { -// return Cow::from(format!("\"{}\"", escape_double_quote(w))); -// } +// return Cow::from(format!("\"{}\"", +// escape_double_quote(w))); } // } // Cow::from(w) // } @@ -209,26 +217,49 @@ pub async fn insert( .unwrap(); x }; - 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) + 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_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()], + 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| Error::new(e.to_string())) { - debug!( - "Failed to insert envelope {}: {}", - envelope.message_id_display(), - err - ); - log( - format!( - "Failed to insert envelope {}: {}", - envelope.message_id_display(), - err - ), - ERROR, - ); - } + .map_err(|e| Error::new(e.to_string())) + { + debug!( + "Failed to insert envelope {}: {}", + envelope.message_id_display(), + err + ); + log( + format!( + "Failed to insert envelope {}: {}", + envelope.message_id_display(), + err + ), + ERROR, + ); + } Ok(()) } @@ -313,10 +344,34 @@ pub fn index(context: &mut crate::state::Context, account_index: usize) -> Resul let envelopes_lck = acc_mutex.read().unwrap(); 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) + 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_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()))?; + 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()) + })?; } } let sleep_dur = std::time::Duration::from_millis(20); @@ -478,14 +533,14 @@ pub fn query_to_sql(q: &Query) -> String { #[test] fn test_query_to_sql() { - use melib::parsec::Parser; - use melib::search::query; + use melib::{parsec::Parser, search::query}; assert_eq!( "(subject LIKE \"%test%\" ) AND (body_text LIKE \"%i%\" ) ", &query_to_sql(&query().parse_complete("subject: test and i").unwrap().1) ); assert_eq!( - "(subject LIKE \"%github%\" ) OR ((_from LIKE \"%epilys%\" ) AND ((subject LIKE \"%lib%\" ) OR (subject LIKE \"%meli%\" ) ) ) ", + "(subject LIKE \"%github%\" ) OR ((_from LIKE \"%epilys%\" ) AND ((subject LIKE \"%lib%\" \ + ) OR (subject LIKE \"%meli%\" ) ) ) ", &query_to_sql( &query() .parse_complete( diff --git a/src/state.rs b/src/state.rs index b9e7aefb..f917911b 100644 --- a/src/state.rs +++ b/src/state.rs @@ -28,19 +28,16 @@ The UI crate has an Box-Component-System design. The System part, Input is received in the main loop from threads which listen on the stdin for user input, observe folders for file changes etc. The relevant struct is `ThreadEvent`. */ -use super::*; -//use crate::plugins::PluginManager; -use melib::backends::{AccountHash, BackendEventConsumer}; +use std::{env, os::unix::io::RawFd, sync::Arc, thread}; -use crate::jobs::JobExecutor; -use crate::terminal::screen::Screen; use crossbeam::channel::{unbounded, Receiver, Sender}; use indexmap::IndexMap; +//use crate::plugins::PluginManager; +use melib::backends::{AccountHash, BackendEventConsumer}; use smallvec::SmallVec; -use std::env; -use std::os::unix::io::RawFd; -use std::sync::Arc; -use std::thread; + +use super::*; +use crate::{jobs::JobExecutor, terminal::screen::Screen}; struct InputHandler { pipe: (RawFd, RawFd), @@ -56,8 +53,8 @@ impl InputHandler { let control = Arc::downgrade(&working); /* Clear channel without blocking. switch_to_main_screen() issues a kill when - * returning from a fork and there's no input thread, so the newly created thread will - * receive it and die. */ + * returning from a fork and there's no input thread, so the newly created + * thread will receive it and die. */ //let _ = self.rx.try_iter().count(); let rx = self.rx.clone(); let pipe = self.pipe.0; @@ -228,8 +225,9 @@ impl Context { } } -/// A State object to manage and own components and components of the UI. `State` is responsible for -/// managing the terminal and interfacing with `melib` +/// A State object to manage and own components and components of the UI. +/// `State` is responsible for managing the terminal and interfacing with +/// `melib` pub struct State { screen: Box, draw_rate_limit: RateLimit, @@ -284,9 +282,9 @@ impl State { receiver: Receiver, ) -> Result { /* - * Create async channel to block the input-thread if we need to fork and stop it from reading - * stdin, see get_events() for details - * */ + * Create async channel to block the input-thread if we need to fork and stop + * it from reading stdin, see get_events() for details + */ let input_thread = unbounded(); let input_thread_pipe = nix::unistd::pipe() .map_err(|err| Box::new(err) as Box)?; @@ -434,7 +432,8 @@ impl State { /* * When we receive a mailbox hash from a watcher thread, * we match the hash to the index of the mailbox, request a reload - * and startup a thread to remind us to poll it every now and then till it's finished. + * and startup a thread to remind us to poll it every now and then till it's + * finished. */ pub fn refresh_event(&mut self, event: RefreshEvent) { let account_hash = event.account_hash; @@ -477,7 +476,8 @@ impl State { self.context.restore_input(); } - /// On `SIGWNICH` the `State` redraws itself according to the new terminal size. + /// On `SIGWNICH` the `State` redraws itself according to the new terminal + /// size. pub fn update_size(&mut self) { self.screen.update_size(); self.rcv_event(UIEvent::Resize); @@ -525,8 +525,8 @@ impl State { areas.sort_by(|a, b| (a.0).0.partial_cmp(&(b.0).0).unwrap()); if self.display_messages_active { - /* Check if any dirty area intersects with the area occupied by floating notification - * box */ + /* Check if any dirty area intersects with the area occupied by floating + * notification box */ let (displ_top, displ_bot) = self.display_messages_area; for &((top_x, top_y), (bottom_x, bottom_y)) in &areas { self.display_messages_dirty |= !(bottom_y < displ_top.1 @@ -992,34 +992,51 @@ impl State { ))); } else if let Action::ReloadConfiguration = action { match Settings::new().and_then(|new_settings| { - let old_accounts = self.context.settings.accounts.keys().collect::>(); - let new_accounts = new_settings.accounts.keys().collect::>(); + let old_accounts = self + .context + .settings + .accounts + .keys() + .collect::>(); + let new_accounts = new_settings + .accounts + .keys() + .collect::>(); if old_accounts != new_accounts { - return Err("cannot reload account configuration changes; restart meli instead.".into()); + return Err("cannot reload account configuration changes; \ + restart meli instead." + .into()); } for (key, acc) in new_settings.accounts.iter() { - if toml::Value::try_from(&acc) != toml::Value::try_from(&self.context.settings.accounts[key]) { - return Err("cannot reload account configuration changes; restart meli instead.".into()); + if toml::Value::try_from(acc) + != toml::Value::try_from(&self.context.settings.accounts[key]) + { + return Err("cannot reload account configuration changes; \ + restart meli instead." + .into()); } } - if toml::Value::try_from(&new_settings) == toml::Value::try_from(&self.context.settings) { + if toml::Value::try_from(&new_settings) + == toml::Value::try_from(&self.context.settings) + { return Err("No changes detected.".into()); } Ok(Box::new(new_settings)) }) { Ok(new_settings) => { - let old_settings = std::mem::replace(&mut self.context.settings, new_settings); - self.context.replies.push_back(UIEvent::ConfigReload { - old_settings - }); + let old_settings = + std::mem::replace(&mut self.context.settings, new_settings); + self.context + .replies + .push_back(UIEvent::ConfigReload { old_settings }); self.context.replies.push_back(UIEvent::Resize); } Err(err) => { self.context.replies.push_back(UIEvent::StatusEvent( - StatusEvent::DisplayMessage(format!( - "Could not load configuration: {}", - err - )), + StatusEvent::DisplayMessage(format!( + "Could not load configuration: {}", + err + )), )); } } @@ -1221,8 +1238,8 @@ impl State { } Some(false) } - /// Switch back to the terminal's main screen (The command line the user sees before opening - /// the application) + /// Switch back to the terminal's main screen (The command line the user + /// sees before opening the application) pub fn switch_to_main_screen(&mut self) { self.screen.switch_to_main_screen(); } diff --git a/src/terminal.rs b/src/terminal.rs index 916c77f2..46f0f632 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -22,8 +22,7 @@ /*! Terminal grid cells, keys, colors, etc. */ extern crate serde; -use self::serde::de::Visitor; -use self::serde::{de, Deserialize, Deserializer}; +use self::serde::{de, de::Visitor, Deserialize, Deserializer}; extern crate unicode_segmentation; mod color; @@ -36,12 +35,9 @@ mod cells; mod keys; pub mod embed; mod text_editing; -pub use self::cells::*; -pub use self::keys::*; -pub use self::position::*; -pub use self::text_editing::*; - use std::fmt; + +pub use self::{cells::*, keys::*, position::*, text_editing::*}; /* * CSI events we use */ @@ -101,12 +97,14 @@ derive_csi_sequence!( ); derive_csi_sequence!( - #[doc = "`CSI Ps ; Ps ; Ps t`, where `Ps = 2 2 ; 0` -> Save xterm icon and window title on stack."] + #[doc = "`CSI Ps ; Ps ; Ps t`, where `Ps = 2 2 ; 0` -> Save xterm icon and window title on \ + stack."] (SaveWindowTitleIconToStack, "22;0t") ); derive_csi_sequence!( - #[doc = "Restore window title and icon from terminal's title stack. `CSI Ps ; Ps ; Ps t`, where `Ps = 2 3 ; 0` -> Restore xterm icon and window title from stack."] + #[doc = "Restore window title and icon from terminal's title stack. `CSI Ps ; Ps ; Ps t`, \ + where `Ps = 2 3 ; 0` -> Restore xterm icon and window title from stack."] (RestoreWindowTitleIconFromStack, "23;0t") ); @@ -284,9 +282,10 @@ mod braille { } */ - /// Iterate on 2x4 pixel blocks from a bitmap and return a unicode braille character for each - /// block. The iterator holds four lines of bitmaps encoded as `u16` numbers in swapped bit - /// order, like the `xbm` graphics format. The bitmap is split to `u16` columns. + /// Iterate on 2x4 pixel blocks from a bitmap and return a unicode braille + /// character for each block. The iterator holds four lines of bitmaps + /// encoded as `u16` numbers in swapped bit order, like the `xbm` + /// graphics format. The bitmap is split to `u16` columns. /// /// ## Usage /// ```no_run @@ -339,6 +338,7 @@ mod braille { /// /// ## Explanation: /// For the following bitmap: + /// /// ```text /// ◻◼◻◻◼◻◻◼◻◻◻◼◼◼◼◼ /// ◼◼◼◼◼◼◻◻◼◻◼◻◻◼◼◼ @@ -347,6 +347,7 @@ mod braille { /// ``` /// /// Iteration on each step examines two columns: + /// /// ```text /// ⇩⇩ /// ◻◼┆◻◻┆◼◻┆◻◼┆◻◻┆◻◼┆◼◼┆◼◼ @@ -355,7 +356,7 @@ mod braille { /// ◼◻┆◼◼┆◻◼┆◼◻┆◼◼┆◼◻┆◻◻┆◻◻ /// ``` /// - /// The first two columns are encoded as: + /// The first two columns are encoded as: /// /// ```text /// ┏━━━━━━┳━━━━┓ @@ -371,12 +372,16 @@ mod braille { /// ◻◼◻◼◼◻◼◻ = 0b01011010 = 0x5A /// 12345678 /// ``` - /// and braille character is bitmap + 0x2800 (Braille block's position in Unicode) + /// + /// and braille character is bitmap + 0x2800 (Braille block's position in + /// Unicode) + /// /// ```text /// 0x5A + 0x2800 = 0x285A = '⡚' /// ``` /// - /// Why three columns? I originally wrote this for X-Face bitmaps, which are 48x48 pixels. + /// Why three columns? I originally wrote this for X-Face bitmaps, which are + /// 48x48 pixels. pub struct BraillePixelIter { columns: [Braille16bitColumn; 3], column_ptr: usize, @@ -445,8 +450,9 @@ mod braille { bits += (0x1 & (bitmaps.3.rotate_left(*bitcolumn))) * 0x80; *bitcolumn += 1; - /* The Braille Patterns block spans the entire [U+2800, U+28FF] range and bits is a - * 16bit integer ∈ [0x00, 0xFF] so this is guaranteed to be a Unicode char */ + /* The Braille Patterns block spans the entire [U+2800, U+28FF] range and + * bits is a 16bit integer ∈ [0x00, 0xFF] so this is guaranteed + * to be a Unicode char */ Some(unsafe { std::char::from_u32_unchecked(bits as u32 + 0x2800) }) } } @@ -454,13 +460,12 @@ mod braille { pub use screen::StateStdout; pub mod screen { - use super::*; + use std::io::{BufWriter, Write}; + use cells::CellBuffer; - use std::io::BufWriter; - use std::io::Write; - use termion::raw::IntoRawMode; - use termion::screen::AlternateScreen; - use termion::{clear, cursor}; + use termion::{clear, cursor, raw::IntoRawMode, screen::AlternateScreen}; + + use super::*; pub type StateStdout = termion::screen::AlternateScreen>>; @@ -476,8 +481,8 @@ pub mod screen { } impl Screen { - /// Switch back to the terminal's main screen (The command line the user sees before opening - /// the application) + /// Switch back to the terminal's main screen (The command line the user + /// sees before opening the application) pub fn switch_to_main_screen(&mut self) { let mouse = self.mouse; write!( @@ -554,7 +559,8 @@ pub mod screen { } self.flush(); } - /// On `SIGWNICH` the `State` redraws itself according to the new terminal size. + /// On `SIGWNICH` the `State` redraws itself according to the new + /// terminal size. pub fn update_size(&mut self) { let termsize = termion::terminal_size().ok(); let termcols = termsize.map(|(w, _)| w); diff --git a/src/terminal/cells.rs b/src/terminal/cells.rs index 20f239e8..45b04d6f 100644 --- a/src/terminal/cells.rs +++ b/src/terminal/cells.rs @@ -24,23 +24,25 @@ colors and attributes. */ -use super::{position::*, Color}; -use crate::state::Context; -use crate::ThemeAttribute; -use melib::text_processing::wcwidth; +use std::{ + collections::HashMap, + convert::From, + fmt, + ops::{Deref, DerefMut, Index, IndexMut}, +}; +use melib::text_processing::wcwidth; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use smallvec::SmallVec; -use std::collections::HashMap; -use std::convert::From; -use std::fmt; -use std::ops::{Deref, DerefMut, Index, IndexMut}; -/// In a scroll region up and down cursor movements shift the region vertically. The new lines are -/// empty. +use super::{position::*, Color}; +use crate::{state::Context, ThemeAttribute}; + +/// In a scroll region up and down cursor movements shift the region vertically. +/// The new lines are empty. /// -/// See `CellBuffer::scroll_up` and `CellBuffer::scroll_down` for an explanation of how `xterm` -/// scrolling works. +/// See `CellBuffer::scroll_up` and `CellBuffer::scroll_down` for an explanation +/// of how `xterm` scrolling works. #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct ScrollRegion { pub top: usize, @@ -51,11 +53,12 @@ pub struct ScrollRegion { /// An array of `Cell`s that represents a terminal display. /// -/// A `CellBuffer` is a two-dimensional array of `Cell`s, each pair of indices correspond to a -/// single point on the underlying terminal. +/// A `CellBuffer` is a two-dimensional array of `Cell`s, each pair of indices +/// correspond to a single point on the underlying terminal. /// -/// The first index, `Cellbuffer[y]`, corresponds to a row, and thus the y-axis. The second -/// index, `Cellbuffer[y][x]`, corresponds to a column within a row and thus the x-axis. +/// The first index, `Cellbuffer[y]`, corresponds to a row, and thus the y-axis. +/// The second index, `Cellbuffer[y][x]`, corresponds to a column within a row +/// and thus the x-axis. #[derive(Clone, PartialEq, Eq)] pub struct CellBuffer { pub cols: usize, @@ -97,8 +100,8 @@ impl CellBuffer { self.cols = new_cols; } - /// Constructs a new `CellBuffer` with the given number of columns and rows, using the given - /// `cell` as a blank. + /// Constructs a new `CellBuffer` with the given number of columns and rows, + /// using the given `cell` as a blank. pub fn new(cols: usize, rows: usize, default_cell: Cell) -> CellBuffer { CellBuffer { cols, @@ -146,8 +149,8 @@ impl CellBuffer { self.growable = new_val; } - /// Resizes `CellBuffer` to the given number of rows and columns, using the given `Cell` as - /// a blank. + /// Resizes `CellBuffer` to the given number of rows and columns, using the + /// given `Cell` as a blank. #[must_use] pub fn resize(&mut self, newcols: usize, newrows: usize, blank: Option) -> bool { let newlen = newcols * newrows; @@ -196,8 +199,8 @@ impl CellBuffer { } } - /// Returns a reference to the `Cell` at the given coordinates, or `None` if the index is out of - /// bounds. + /// Returns a reference to the `Cell` at the given coordinates, or `None` if + /// the index is out of bounds. pub fn get(&self, x: usize, y: usize) -> Option<&Cell> { match self.pos_to_index(x, y) { Some(i) => self.cellvec().get(i), @@ -205,8 +208,8 @@ impl CellBuffer { } } - /// Returns a mutable reference to the `Cell` at the given coordinates, or `None` if the index - /// is out of bounds. + /// Returns a mutable reference to the `Cell` at the given coordinates, or + /// `None` if the index is out of bounds. pub fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut Cell> { match self.pos_to_index(x, y) { Some(i) => self.cellvec_mut().get_mut(i), @@ -271,7 +274,6 @@ impl CellBuffer { /// | 555555555555 | | 666666666666 | /// | 666666666666 | | | /// ``` - /// pub fn scroll_up(&mut self, scroll_region: &ScrollRegion, top: usize, offset: usize) { //debug!( // "scroll_up scroll_region {:?}, top: {} offset {}", @@ -334,7 +336,6 @@ impl CellBuffer { /// | 555555555555 | | 444444444444 | /// | 666666666666 | | 555555555555 | /// ``` - /// pub fn scroll_down(&mut self, scroll_region: &ScrollRegion, top: usize, offset: usize) { //debug!( // "scroll_down scroll_region {:?}, top: {} offset {}", @@ -409,8 +410,10 @@ impl CellBuffer { } pub fn insert_tag(&mut self, tag: FormatTag) -> u64 { - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; + use std::{ + collections::hash_map::DefaultHasher, + hash::{Hash, Hasher}, + }; let mut hasher = DefaultHasher::new(); tag.hash(&mut hasher); @@ -463,7 +466,8 @@ impl IndexMut for CellBuffer { } impl Default for CellBuffer { - /// Constructs a new `CellBuffer` with a size of `(0, 0)`, using the default `Cell` as a blank. + /// Constructs a new `CellBuffer` with a size of `(0, 0)`, using the default + /// `Cell` as a blank. fn default() -> CellBuffer { CellBuffer::new(0, 0, Cell::default()) } @@ -491,8 +495,8 @@ impl fmt::Display for CellBuffer { pub struct Cell { ch: char, - /// Set a `Cell` as empty when a previous cell spans multiple columns and it would - /// "overflow" to this cell. + /// Set a `Cell` as empty when a previous cell spans multiple columns and it + /// would "overflow" to this cell. empty: bool, fg: Color, bg: Color, @@ -508,7 +512,7 @@ impl Cell { /// # Examples /// /// ```no_run - /// use meli::{Color, Attr, Cell}; + /// use meli::{Attr, Cell, Color}; /// /// let cell = Cell::new('x', Color::Default, Color::Green, Attr::DEFAULT); /// assert_eq!(cell.ch(), 'x'); @@ -534,7 +538,7 @@ impl Cell { /// # Examples /// /// ```no_run - /// use meli::{Color, Attr, Cell}; + /// use meli::{Attr, Cell, Color}; /// /// let mut cell = Cell::with_char('x'); /// assert_eq!(cell.ch(), 'x'); @@ -551,7 +555,7 @@ impl Cell { /// # Examples /// /// ```no_run - /// use meli::{Color, Attr, Cell}; + /// use meli::{Attr, Cell, Color}; /// /// let mut cell = Cell::with_style(Color::Default, Color::Red, Attr::BOLD); /// assert_eq!(cell.fg(), Color::Default); @@ -603,7 +607,7 @@ impl Cell { /// # Examples /// /// ```no_run - /// use meli::{Color, Attr, Cell}; + /// use meli::{Attr, Cell, Color}; /// /// let mut cell = Cell::with_style(Color::Blue, Color::Default, Attr::DEFAULT); /// assert_eq!(cell.fg(), Color::Blue); @@ -617,7 +621,7 @@ impl Cell { /// # Examples /// /// ```no_run - /// use meli::{Color, Cell}; + /// use meli::{Cell, Color}; /// /// let mut cell = Cell::default(); /// assert_eq!(cell.fg(), Color::Default); @@ -637,7 +641,7 @@ impl Cell { /// # Examples /// /// ```no_run - /// use meli::{Attr, Color, Cell}; + /// use meli::{Attr, Cell, Color}; /// /// let mut cell = Cell::with_style(Color::Default, Color::Green, Attr::DEFAULT); /// assert_eq!(cell.bg(), Color::Green); @@ -677,8 +681,8 @@ impl Cell { self } - /// Set a `Cell` as empty when a previous cell spans multiple columns and it would - /// "overflow" to this cell. + /// Set a `Cell` as empty when a previous cell spans multiple columns and it + /// would "overflow" to this cell. pub fn empty(&self) -> bool { self.empty } @@ -688,22 +692,23 @@ impl Cell { self } - /// Sets `keep_fg` field. If true, the foreground color will not be altered if attempted so - /// until the character content of the cell is changed. + /// Sets `keep_fg` field. If true, the foreground color will not be altered + /// if attempted so until the character content of the cell is changed. pub fn set_keep_fg(&mut self, new_val: bool) -> &mut Cell { self.keep_fg = new_val; self } - /// Sets `keep_bg` field. If true, the background color will not be altered if attempted so - /// until the character content of the cell is changed. + /// Sets `keep_bg` field. If true, the background color will not be altered + /// if attempted so until the character content of the cell is changed. pub fn set_keep_bg(&mut self, new_val: bool) -> &mut Cell { self.keep_bg = new_val; self } - /// Sets `keep_attrs` field. If true, the text attributes will not be altered if attempted so - /// until the character content of the cell is changed. + /// Sets `keep_attrs` field. If true, the text attributes will not be + /// altered if attempted so until the character content of the cell is + /// changed. pub fn set_keep_attrs(&mut self, new_val: bool) -> &mut Cell { self.keep_attrs = new_val; self @@ -716,7 +721,7 @@ impl Default for Cell { /// # Examples /// /// ```no_run - /// use meli::{Color, Cell}; + /// use meli::{Cell, Color}; /// /// let mut cell = Cell::default(); /// assert_eq!(cell.ch(), ' '); @@ -1125,7 +1130,8 @@ macro_rules! inspect_bounds { }; } -/// Write an `&str` to a `CellBuffer` in a specified `Area` with the passed colors. +/// Write an `&str` to a `CellBuffer` in a specified `Area` with the passed +/// colors. pub fn write_string_to_grid( s: &str, grid: &mut CellBuffer, @@ -1225,7 +1231,8 @@ pub fn write_string_to_grid( (x, y) } -/// Completely clear an `Area` with an empty char and the terminal's default colors. +/// Completely clear an `Area` with an empty char and the terminal's default +/// colors. pub fn clear_area(grid: &mut CellBuffer, area: Area, attributes: crate::conf::ThemeAttribute) { if !is_valid_area!(area) { return; @@ -1241,17 +1248,14 @@ pub fn clear_area(grid: &mut CellBuffer, area: Area, attributes: crate::conf::Th } } -/// Use `RowIterator` to iterate the cells of a row without the need to do any bounds checking; -/// the iterator will simply return `None` when it reaches the end of the row. -/// `RowIterator` can be created via the `CellBuffer::row_iter` method and can be returned by -/// `BoundsIterator` which iterates each row. +/// Use `RowIterator` to iterate the cells of a row without the need to do any +/// bounds checking; the iterator will simply return `None` when it reaches the +/// end of the row. `RowIterator` can be created via the `CellBuffer::row_iter` +/// method and can be returned by `BoundsIterator` which iterates each row. /// ```no_run /// # let mut grid = meli::CellBuffer::new(1, 1, meli::Cell::default()); /// # let x = 0; -/// for c in grid.row_iter( -/// x..(x + 11), -/// 0, -/// ) { +/// for c in grid.row_iter(x..(x + 11), 0) { /// grid[c].set_ch('w'); /// } /// ``` @@ -1268,8 +1272,8 @@ pub struct RowIterator { /// # let area = ((0, 0), (1, 1)); /// /* Visit each `Cell` in `area`. */ /// for row in grid.bounds_iter(area) { -/// for c in row { -/// grid[c].set_ch('w'); +/// for c in row { +/// grid[c].set_ch('w'); /// } /// } /// ``` diff --git a/src/terminal/color.rs b/src/terminal/color.rs index cc32ebc5..67f33aaf 100644 --- a/src/terminal/color.rs +++ b/src/terminal/color.rs @@ -26,9 +26,9 @@ use termion::color::{AnsiValue, Rgb as TermionRgb}; /// /// `Color::Default` represents the default color of the underlying terminal. /// -/// The eight basic colors may be used directly and correspond to 0x00..0x07 in the 8-bit (256) -/// color range; in addition, the eight basic colors coupled with `Attr::BOLD` correspond to -/// 0x08..0x0f in the 8-bit color range. +/// The eight basic colors may be used directly and correspond to 0x00..0x07 in +/// the 8-bit (256) color range; in addition, the eight basic colors coupled +/// with `Attr::BOLD` correspond to 0x08..0x0f in the 8-bit color range. /// /// `Color::Byte(..)` may be used to specify a color in the 8-bit range. /// @@ -49,7 +49,7 @@ use termion::color::{AnsiValue, Rgb as TermionRgb}; /// // Basic colors are also 8-bit colors (but not vice-versa). /// assert_eq!(red.as_byte(), fancy.as_byte()) /// ``` -#[derive(Hash, Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Hash, Debug, Copy, Clone, PartialEq, Eq, Default)] pub enum Color { Black, Red, @@ -62,6 +62,7 @@ pub enum Color { Byte(u8), Rgb(u8, u8, u8), /// Terminal default. + #[default] Default, } @@ -396,9 +397,7 @@ impl Color { s if s.starts_with('#') && s.len() == 7 && s[1..].as_bytes().iter().all(|&b| { - (b'0'..=b'9').contains(&b) - || (b'a'..=b'f').contains(&b) - || (b'A'..=b'F').contains(&b) + b.is_ascii_digit() || (b'a'..=b'f').contains(&b) || (b'A'..=b'F').contains(&b) }) => { return Ok(Color::Rgb( @@ -413,9 +412,7 @@ impl Color { s if s.starts_with('#') && s.len() == 4 && s[1..].as_bytes().iter().all(|&b| { - (b'0'..=b'9').contains(&b) - || (b'a'..=b'f').contains(&b) - || (b'A'..=b'F').contains(&b) + b.is_ascii_digit() || (b'a'..=b'f').contains(&b) || (b'A'..=b'F').contains(&b) }) => { return Ok(Color::Rgb( @@ -435,12 +432,6 @@ impl Color { } } -impl Default for Color { - fn default() -> Self { - Color::Default - } -} - impl<'de> Deserialize<'de> for Color { fn deserialize(deserializer: D) -> std::result::Result where diff --git a/src/terminal/embed.rs b/src/terminal/embed.rs index d9888410..2e4b2b16 100644 --- a/src/terminal/embed.rs +++ b/src/terminal/embed.rs @@ -19,44 +19,48 @@ * along with meli. If not, see . */ -use crate::terminal::position::*; -use melib::{error::*, log, ERROR}; -use smallvec::SmallVec; +use std::{ + ffi::{CString, OsStr}, + os::unix::{ + ffi::OsStrExt, + io::{AsRawFd, FromRawFd, IntoRawFd}, + }, +}; +use melib::{error::*, log, ERROR}; #[cfg(not(target_os = "macos"))] use nix::{ fcntl::{open, OFlag}, pty::{grantpt, posix_openpt, ptsname, unlockpt}, sys::stat, }; - -use nix::libc::{STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; -use nix::pty::Winsize; -use nix::unistd::{dup2, fork, ForkResult}; -use nix::{ioctl_none_bad, ioctl_write_ptr_bad}; -use std::ffi::{CString, OsStr}; -use std::os::unix::{ - ffi::OsStrExt, - io::{AsRawFd, FromRawFd, IntoRawFd}, +use nix::{ + ioctl_none_bad, ioctl_write_ptr_bad, + libc::{STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}, + pty::Winsize, + unistd::{dup2, fork, ForkResult}, }; +use smallvec::SmallVec; + +use crate::terminal::position::*; mod grid; -pub use grid::{EmbedGrid, EmbedTerminal}; +#[cfg(not(target_os = "macos"))] +use std::path::Path; +use std::{ + convert::TryFrom, + io::{Read, Write}, + sync::{Arc, Mutex}, +}; -// ioctl request code to "Make the given terminal the controlling terminal of the calling process" +pub use grid::{EmbedGrid, EmbedTerminal}; +// ioctl request code to "Make the given terminal the controlling terminal of the calling +// process" use libc::TIOCSCTTY; // ioctl request code to set window size of pty: use libc::TIOCSWINSZ; -#[cfg(not(target_os = "macos"))] -use std::path::Path; - -use std::convert::TryFrom; -use std::io::Read; -use std::io::Write; -use std::sync::{Arc, Mutex}; - // Macro generated function that calls ioctl to set window size of slave pty end ioctl_write_ptr_bad!(set_window_size, TIOCSWINSZ, Winsize); @@ -142,7 +146,7 @@ pub fn create_pty( } /* Find posix sh location, because POSIX shell is not always at /bin/sh */ let path_var = std::process::Command::new("getconf") - .args(&["PATH"]) + .args(["PATH"]) .output()? .stdout; for mut p in std::env::split_paths(&OsStr::from_bytes(&path_var[..])) { @@ -273,9 +277,7 @@ impl std::fmt::Display for EscCode<'_> { unsafestr!(buf2), *c as char ), - EscCode(ExpectingControlChar, b'D') => write!( - f, "ESC D Linefeed" - ), + EscCode(ExpectingControlChar, b'D') => write!(f, "ESC D Linefeed"), EscCode(Csi, b'm') => write!( f, "ESC[m\t\tCSI Character Attributes | Set Attr and Color to Normal (default)" @@ -284,14 +286,8 @@ impl std::fmt::Display for EscCode<'_> { f, "ESC[K\t\tCSI Erase from the cursor to the end of the line" ), - EscCode(Csi, b'L') => write!( - f, - "ESC[L\t\tCSI Insert one blank line" - ), - EscCode(Csi, b'M') => write!( - f, - "ESC[M\t\tCSI delete line" - ), + EscCode(Csi, b'L') => write!(f, "ESC[L\t\tCSI Insert one blank line"), + EscCode(Csi, b'M') => write!(f, "ESC[M\t\tCSI delete line"), EscCode(Csi, b'J') => write!( f, "ESC[J\t\tCSI Erase from the cursor to the end of the screen" @@ -368,17 +364,16 @@ impl std::fmt::Display for EscCode<'_> { "ESC[{buf}S\t\tCSI P s S Scroll up P s lines (default = 1) (SU), VT420, EC", buf = unsafestr!(buf) ), - EscCode(Csi1(ref buf), b'J') => write!( - f, - "Erase in display {buf}", - buf = unsafestr!(buf) - ), + EscCode(Csi1(ref buf), b'J') => { + write!(f, "Erase in display {buf}", buf = unsafestr!(buf)) + } EscCode(Csi1(ref buf), c) => { write!(f, "ESC[{}{}\t\tCSI [UNKNOWN]", unsafestr!(buf), *c as char) } EscCode(Csi2(ref buf1, ref buf2), b'r') => write!( f, - "ESC[{};{}r\t\tCSI Set Scrolling Region [top;bottom] (default = full size of window) (DECSTBM), VT100.", + "ESC[{};{}r\t\tCSI Set Scrolling Region [top;bottom] (default = full size of \ + window) (DECSTBM), VT100.", unsafestr!(buf1), unsafestr!(buf2), ), diff --git a/src/terminal/embed/grid.rs b/src/terminal/embed/grid.rs index 1e5cfc87..2785d488 100644 --- a/src/terminal/embed/grid.rs +++ b/src/terminal/embed/grid.rs @@ -19,12 +19,14 @@ * along with meli. If not, see . */ +use melib::{ + error::{Error, Result}, + text_processing::wcwidth, +}; +use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus}; + use super::*; use crate::terminal::{cells::*, Color}; -use melib::error::{Error, Result}; -use melib::text_processing::wcwidth; -use nix::sys::wait::WaitStatus; -use nix::sys::wait::{waitpid, WaitPidFlag}; #[derive(Debug)] enum ScreenBuffer { @@ -34,9 +36,9 @@ enum ScreenBuffer { /// `EmbedGrid` manages the terminal grid state of the embed process. /// -/// The embed process sends bytes to the master end (see super mod) and interprets them in a state -/// machine stored in `State`. Escape codes are translated as changes to the grid, eg changes in a -/// cell's colors. +/// The embed process sends bytes to the master end (see super mod) and +/// interprets them in a state machine stored in `State`. Escape codes are +/// translated as changes to the grid, eg changes in a cell's colors. /// /// The main process copies the grid whenever the actual terminal is redrawn. #[derive(Debug)] @@ -52,8 +54,8 @@ pub struct EmbedGrid { fg_color: Color, bg_color: Color, attrs: Attr, - /// Store the fg/bg color when highlighting the cell where the cursor is so that it can be - /// restored afterwards + /// Store the fg/bg color when highlighting the cell where the cursor is so + /// that it can be restored afterwards prev_fg_color: Option, prev_bg_color: Option, prev_attrs: Option, @@ -405,7 +407,7 @@ impl EmbedGrid { *state = State::CsiQ(buf1); } /* OSC stuff */ - (c, State::Osc1(ref mut buf)) if (b'0'..=b'9').contains(&c) || c == b'?' => { + (c, State::Osc1(ref mut buf)) if c.is_ascii_digit() || c == b'?' => { buf.push(c); } (b';', State::Osc1(ref mut buf1_p)) => { @@ -413,7 +415,7 @@ impl EmbedGrid { let buf2 = SmallVec::new(); *state = State::Osc2(buf1, buf2); } - (c, State::Osc2(_, ref mut buf)) if (b'0'..=b'9').contains(&c) || c == b'?' => { + (c, State::Osc2(_, ref mut buf)) if c.is_ascii_digit() || c == b'?' => { buf.push(c); } /* Normal */ @@ -575,7 +577,7 @@ impl EmbedGrid { *state = State::Normal; } /* CSI ? stuff */ - (c, State::CsiQ(ref mut buf)) if (b'0'..=b'9').contains(&c) => { + (c, State::CsiQ(ref mut buf)) if c.is_ascii_digit() => { buf.push(c); } (b'h', State::CsiQ(ref buf)) => { @@ -652,13 +654,13 @@ impl EmbedGrid { *state = State::Normal; } /* END OF CSI ? stuff */ - (c, State::Csi) if (b'0'..=b'9').contains(&c) => { + (c, State::Csi) if c.is_ascii_digit() => { let mut buf1 = SmallVec::new(); buf1.push(c); *state = State::Csi1(buf1); } (b'J', State::Csi) => { - /* Erase in Display (ED), VT100.*/ + /* Erase in Display (ED), VT100. */ /* Erase Below (default). */ clear_area( grid, @@ -681,7 +683,7 @@ impl EmbedGrid { *state = State::Normal; } (b'K', State::Csi) => { - /* Erase in Line (ED), VT100.*/ + /* Erase in Line (ED), VT100. */ /* Erase to right (Default) */ //debug!("{}", EscCode::from((&(*state), byte))); for x in cursor.0..terminal_size.0 { @@ -732,7 +734,7 @@ impl EmbedGrid { *state = State::Normal; } (b'K', State::Csi1(buf)) if buf.as_ref() == b"0" => { - /* Erase in Line (ED), VT100.*/ + /* Erase in Line (ED), VT100. */ /* Erase to right (Default) */ //debug!("{}", EscCode::from((&(*state), byte))); for x in cursor.0..terminal_size.0 { @@ -741,7 +743,7 @@ impl EmbedGrid { *state = State::Normal; } (b'K', State::Csi1(buf)) if buf.as_ref() == b"1" => { - /* Erase in Line (ED), VT100.*/ + /* Erase in Line (ED), VT100. */ /* Erase to left (Default) */ for x in 0..=cursor.0 { grid[(x, cursor.1)] = Cell::default(); @@ -750,7 +752,7 @@ impl EmbedGrid { *state = State::Normal; } (b'K', State::Csi1(buf)) if buf.as_ref() == b"2" => { - /* Erase in Line (ED), VT100.*/ + /* Erase in Line (ED), VT100. */ /* Erase all */ for y in 0..terminal_size.1 { for x in 0..terminal_size.0 { @@ -766,7 +768,7 @@ impl EmbedGrid { *state = State::Normal; } (b'J', State::Csi1(ref buf)) if buf.as_ref() == b"0" => { - /* Erase in Display (ED), VT100.*/ + /* Erase in Display (ED), VT100. */ /* Erase Below (default). */ clear_area( grid, @@ -789,7 +791,7 @@ impl EmbedGrid { *state = State::Normal; } (b'J', State::Csi1(ref buf)) if buf.as_ref() == b"1" => { - /* Erase in Display (ED), VT100.*/ + /* Erase in Display (ED), VT100. */ /* Erase Above */ clear_area( grid, @@ -806,7 +808,7 @@ impl EmbedGrid { *state = State::Normal; } (b'J', State::Csi1(ref buf)) if buf.as_ref() == b"2" => { - /* Erase in Display (ED), VT100.*/ + /* Erase in Display (ED), VT100. */ /* Erase All */ clear_area( grid, @@ -817,7 +819,7 @@ impl EmbedGrid { *state = State::Normal; } (b'X', State::Csi1(ref buf)) => { - /* Erase Ps Character(s) (default = 1) (ECH)..*/ + /* Erase Ps Character(s) (default = 1) (ECH).. */ let ps = unsafe { std::str::from_utf8_unchecked(buf) } .parse::() .unwrap(); @@ -842,8 +844,8 @@ impl EmbedGrid { (b't', State::Csi1(buf)) => { /* Window manipulation */ if buf.as_ref() == b"18" || buf.as_ref() == b"19" { - // Ps = 18 → Report the size of the text area in characters as CSI 8 ; height ; width t - //debug!("report size of the text area"); + // Ps = 18 → Report the size of the text area in characters as CSI 8 ; height ; + // width t debug!("report size of the text area"); //debug!("got {}", EscCode::from((&(*state), byte))); stdin.write_all(b"\x1b[8;").unwrap(); stdin @@ -856,7 +858,8 @@ impl EmbedGrid { stdin.write_all(&[b't']).unwrap(); stdin.flush().unwrap(); } else { - //debug!("ignoring unknown code {}", EscCode::from((&(*state), byte))); + //debug!("ignoring unknown code {}", + // EscCode::from((&(*state), byte))); } *state = State::Normal; } @@ -980,7 +983,8 @@ impl EmbedGrid { cursor.0 = new_col.saturating_sub(1); } else { //debug!( - // "error: new_cal = {} > terminal.size.0 = {}\nterminal_size = {:?}", + // "error: new_cal = {} > terminal.size.0 = + // {}\nterminal_size = {:?}", // new_col, terminal_size.0, terminal_size //); } @@ -1269,7 +1273,7 @@ impl EmbedGrid { grid[cursor_val!()].set_attrs(*attrs); *state = State::Normal; } - (c, State::Csi1(ref mut buf)) if (b'0'..=b'9').contains(&c) || c == b' ' => { + (c, State::Csi1(ref mut buf)) if c.is_ascii_digit() || c == b' ' => { buf.push(c); } (b';', State::Csi2(ref mut buf1_p, ref mut buf2_p)) => { @@ -1319,11 +1323,12 @@ impl EmbedGrid { //debug!("cursor became: {:?}", cursor); *state = State::Normal; } - (c, State::Csi2(_, ref mut buf)) if (b'0'..=b'9').contains(&c) => { + (c, State::Csi2(_, ref mut buf)) if c.is_ascii_digit() => { buf.push(c); } (b'r', State::Csi2(_, _)) | (b'r', State::Csi) => { - /* CSI Ps ; Ps r Set Scrolling Region [top;bottom] (default = full size of window) (DECSTBM). */ + /* CSI Ps ; Ps r Set Scrolling Region [top;bottom] (default = full size of + * window) (DECSTBM). */ let (top, bottom) = if let State::Csi2(ref top, ref bottom) = state { ( unsafe { std::str::from_utf8_unchecked(top) } @@ -1352,7 +1357,7 @@ impl EmbedGrid { *state = State::Normal; } - (c, State::Csi3(_, _, ref mut buf)) if (b'0'..=b'9').contains(&c) => { + (c, State::Csi3(_, _, ref mut buf)) if c.is_ascii_digit() => { buf.push(c); } (b'm', State::Csi3(ref buf1, ref buf2, ref buf3)) @@ -1385,7 +1390,7 @@ impl EmbedGrid { grid[cursor_val!()].set_bg(*bg_color); *state = State::Normal; } - (c, State::Csi3(_, _, ref mut buf)) if (b'0'..=b'9').contains(&c) => { + (c, State::Csi3(_, _, ref mut buf)) if c.is_ascii_digit() => { buf.push(c); } (b';', State::Csi3(ref mut buf1_p, ref mut buf2_p, ref mut buf3_p)) => { @@ -1395,7 +1400,7 @@ impl EmbedGrid { let buf4 = SmallVec::new(); *state = State::Csi4(buf1, buf2, buf3, buf4); } - (c, State::Csi4(_, _, _, ref mut buf)) if (b'0'..=b'9').contains(&c) => { + (c, State::Csi4(_, _, _, ref mut buf)) if c.is_ascii_digit() => { buf.push(c); } (b';', State::Csi4(ref mut buf1_p, ref mut buf2_p, ref mut buf3_p, ref mut buf4_p)) => { @@ -1406,7 +1411,7 @@ impl EmbedGrid { let buf5 = SmallVec::new(); *state = State::Csi5(buf1, buf2, buf3, buf4, buf5); } - (c, State::Csi5(_, _, _, _, ref mut buf)) if (b'0'..=b'9').contains(&c) => { + (c, State::Csi5(_, _, _, _, ref mut buf)) if c.is_ascii_digit() => { buf.push(c); } ( @@ -1427,7 +1432,7 @@ impl EmbedGrid { let buf6 = SmallVec::new(); *state = State::Csi6(buf1, buf2, buf3, buf4, buf5, buf6); } - (c, State::Csi6(_, _, _, _, _, ref mut buf)) if (b'0'..=b'9').contains(&c) => { + (c, State::Csi6(_, _, _, _, _, ref mut buf)) if c.is_ascii_digit() => { buf.push(c); } ( diff --git a/src/terminal/keys.rs b/src/terminal/keys.rs index 10ba784e..6d558f82 100644 --- a/src/terminal/keys.rs +++ b/src/terminal/keys.rs @@ -19,11 +19,11 @@ * along with meli. If not, see . */ -use super::*; use crossbeam::{channel::Receiver, select}; use serde::{Serialize, Serializer}; -use termion::event::Event as TermionEvent; -use termion::event::Key as TermionKey; +use termion::event::{Event as TermionEvent, Key as TermionKey}; + +use super::*; #[derive(Debug, PartialEq, Eq, Clone)] pub enum Key { @@ -59,7 +59,8 @@ pub enum Key { Alt(char), /// Ctrl modified character. /// - /// Note that certain keys may not be modifiable with `ctrl`, due to limitations of terminals. + /// Note that certain keys may not be modifiable with `ctrl`, due to + /// limitations of terminals. Ctrl(char), /// Null byte. Null, @@ -69,8 +70,7 @@ pub enum Key { Paste(String), } -pub use termion::event::MouseButton; -pub use termion::event::MouseEvent; +pub use termion::event::{MouseButton, MouseEvent}; impl fmt::Display for Key { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -153,18 +153,21 @@ pub enum InputCommand { Kill, } -use nix::poll::{poll, PollFd, PollFlags}; use std::os::unix::io::{AsRawFd, RawFd}; + +use nix::poll::{poll, PollFd, PollFlags}; use termion::input::TermReadEventsAndRaw; /* - * If we fork (for example start $EDITOR) we want the input-thread to stop reading from stdin. The - * best way I came up with right now is to send a signal to the thread that is read in the first - * input in stdin after the fork, and then the thread kills itself. The parent process spawns a new + * If we fork (for example start $EDITOR) we want the input-thread to stop + * reading from stdin. The best way I came up with right now is to send a + * signal to the thread that is read in the first input in stdin after the + * fork, and then the thread kills itself. The parent process spawns a new * input-thread when the child returns. * * The main loop uses try_wait_on_child() to check if child has exited. */ -/// The thread function that listens for user input and forwards it to the main event loop. +/// The thread function that listens for user input and forwards it to the main +/// event loop. pub fn get_events( mut closure: impl FnMut((Key, Vec)), rx: &Receiver, @@ -287,8 +290,8 @@ impl<'de> Deserialize<'de> for Key { } } Err(de::Error::custom(format!( - "`{}` should be a number 1 <= n <= 12 instead.", - &s[1..] + "`{}` should be a number 1 <= n <= 12 instead.", + &s[1..] ))) } s if s.starts_with("M-") && s.len() == 3 => { @@ -299,8 +302,8 @@ impl<'de> Deserialize<'de> for Key { } Err(de::Error::custom(format!( - "`{}` should be a lowercase and alphanumeric character instead.", - &s[2..] + "`{}` should be a lowercase and alphanumeric character instead.", + &s[2..] ))) } s if s.starts_with("C-") && s.len() == 3 => { @@ -310,13 +313,14 @@ impl<'de> Deserialize<'de> for Key { return Ok(Key::Ctrl(c)); } Err(de::Error::custom(format!( - "`{}` should be a lowercase and alphanumeric character instead.", - &s[2..] + "`{}` should be a lowercase and alphanumeric character instead.", + &s[2..] ))) } _ => Err(de::Error::custom(format!( - "Cannot derive shortcut from `{}`. Please consult the manual for valid key inputs.", - value + "Cannot derive shortcut from `{}`. Please consult the manual for valid \ + key inputs.", + value ))), } } diff --git a/src/terminal/position.rs b/src/terminal/position.rs index 8f62da86..6391012b 100644 --- a/src/terminal/position.rs +++ b/src/terminal/position.rs @@ -142,7 +142,6 @@ macro_rules! bottom_right { /// let invalid_area = ((2, 2), (1, 1)); /// assert!(!is_valid_area!(invalid_area)); /// ``` -/// #[macro_export] macro_rules! is_valid_area { ($a:expr) => {{ @@ -172,25 +171,22 @@ pub fn center_area(area: Area, (width, height): (usize, usize)) -> Area { ) } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] pub enum Alignment { - /// Stretch to fill all space if possible, center if no meaningful way to stretch. + /// Stretch to fill all space if possible, center if no meaningful way to + /// stretch. Fill, /// Snap to left or top side, leaving space on right or bottom. Start, /// Snap to right or bottom side, leaving space on left or top. End, /// Center natural width of widget inside the allocation. + #[default] Center, } -impl Default for Alignment { - fn default() -> Self { - Alignment::Center - } -} - -/// Place given area of dimensions `(width, height)` inside `area` according to given alignment +/// Place given area of dimensions `(width, height)` inside `area` according to +/// given alignment pub fn align_area( area: Area, (width, height): (usize, usize), diff --git a/src/types.rs b/src/types.rs index b338e873..fdb2f968 100644 --- a/src/types.rs +++ b/src/types.rs @@ -21,32 +21,36 @@ /*! UI types used throughout meli. * - * The `segment_tree` module performs maximum range queries. This is used in getting the maximum - * element of a column within a specific range in e-mail lists. That way a very large value that - * is not the in the currently displayed page does not cause the column to be rendered bigger + * The `segment_tree` module performs maximum range queries. This is used in + * getting the maximum element of a column within a specific range in e-mail + * lists. That way a very large value that is not the in the currently + * displayed page does not cause the column to be rendered bigger * than it has to. * - * `UIMode` describes the application's... mode. Same as in the modal editor `vi`. + * `UIMode` describes the application's... mode. Same as in the modal editor + * `vi`. * * `UIEvent` is the type passed around `Component`s when something happens. */ extern crate serde; #[macro_use] mod helpers; -pub use self::helpers::*; +use std::{borrow::Cow, fmt, sync::Arc}; -use super::command::Action; -use super::jobs::{JobExecutor, JobId}; -use super::terminal::*; -use crate::components::{Component, ComponentId, ScrollUpdate}; -use std::borrow::Cow; -use std::sync::Arc; - -use melib::backends::{AccountHash, BackendEvent, MailboxHash}; -use melib::uuid::Uuid; -use melib::{EnvelopeHash, RefreshEvent, ThreadHash}; +use melib::{ + backends::{AccountHash, BackendEvent, MailboxHash}, + uuid::Uuid, + EnvelopeHash, RefreshEvent, ThreadHash, +}; use nix::unistd::Pid; -use std::fmt; + +pub use self::helpers::*; +use super::{ + command::Action, + jobs::{JobExecutor, JobId}, + terminal::*, +}; +use crate::components::{Component, ComponentId, ScrollUpdate}; #[derive(Debug)] pub enum StatusEvent { @@ -62,8 +66,8 @@ pub enum StatusEvent { ScrollUpdate(ScrollUpdate), } -/// `ThreadEvent` encapsulates all of the possible values we need to transfer between our threads -/// to the main process. +/// `ThreadEvent` encapsulates all of the possible values we need to transfer +/// between our threads to the main process. #[derive(Debug)] pub enum ThreadEvent { /// User input. @@ -196,12 +200,13 @@ impl fmt::Display for UIMode { } pub mod segment_tree { - /*! Simple segment tree implementation for maximum in range queries. This is useful if given an - * array of numbers you want to get the maximum value inside an interval quickly. + /*! Simple segment tree implementation for maximum in range queries. This + * is useful if given an array of numbers you want to get the + * maximum value inside an interval quickly. */ + use std::{convert::TryFrom, iter::FromIterator}; + use smallvec::SmallVec; - use std::convert::TryFrom; - use std::iter::FromIterator; #[derive(Default, Debug, Clone)] pub struct SegmentTree { @@ -299,7 +304,7 @@ pub mod segment_tree { .iter() .cloned() .collect::>(); - let mut segment_tree = SegmentTree::from(array.clone()); + let mut segment_tree = SegmentTree::from(array); assert_eq!(segment_tree.get_max(0, 5), 23); assert_eq!(segment_tree.get_max(6, 9), 37); diff --git a/src/types/helpers.rs b/src/types/helpers.rs index 1f33f676..1d411dff 100644 --- a/src/types/helpers.rs +++ b/src/types/helpers.rs @@ -19,11 +19,13 @@ * along with meli. If not, see . */ -use std::fs; -use std::fs::OpenOptions; -use std::io::{Read, Write}; -use std::os::unix::fs::PermissionsExt; -use std::path::PathBuf; +use std::{ + fs, + fs::OpenOptions, + io::{Read, Write}, + os::unix::fs::PermissionsExt, + path::PathBuf, +}; use melib::uuid::Uuid; @@ -65,8 +67,8 @@ impl File { } } -/// Returned `File` will be deleted when dropped if delete_on_drop is set, so make sure to add it on `context.temp_files` -/// to reap it later. +/// Returned `File` will be deleted when dropped if delete_on_drop is set, so +/// make sure to add it on `context.temp_files` to reap it later. pub fn create_temp_file( bytes: &[u8], filename: Option<&str>, diff --git a/tools/src/email_parse.rs b/tools/src/email_parse.rs index aa240a0b..c2312ac3 100644 --- a/tools/src/email_parse.rs +++ b/tools/src/email_parse.rs @@ -1,8 +1,8 @@ extern crate melib; -use melib::Result; -use melib::*; +use melib::{Result, *}; -/// Parses e-mail from files and prints the debug information of the parsed `Envelope` +/// Parses e-mail from files and prints the debug information of the parsed +/// `Envelope` /// /// # Example invocation /// ```sh @@ -21,8 +21,8 @@ fn main() -> Result<()> { if filename.exists() && filename.is_file() { let buffer = std::fs::read_to_string(&filename) - .expect(&format!("Something went wrong reading the file {}", i,)); - let env = Envelope::from_bytes(&buffer.as_bytes(), None).expect("Couldn't parse email"); + .unwrap_or_else(|_| panic!("Something went wrong reading the file {}", i)); + let env = Envelope::from_bytes(buffer.as_bytes(), None).expect("Couldn't parse email"); println!("Env is {:#?}", env); println!("{:?}", env.body_bytes(buffer.as_bytes())); } else { diff --git a/tools/src/embed.rs b/tools/src/embed.rs index b2a2299a..c6847a2d 100644 --- a/tools/src/embed.rs +++ b/tools/src/embed.rs @@ -1,11 +1,15 @@ -use meli::terminal::embed::*; -use meli::terminal::*; -use meli::*; +use std::{ + fs::File, + io::prelude::*, + os::raw::c_int, + sync::{Arc, Mutex}, +}; + +use meli::{ + terminal::{embed::*, *}, + *, +}; use nix::sys::wait::WaitStatus; -use std::fs::File; -use std::io::prelude::*; -use std::os::raw::c_int; -use std::sync::{Arc, Mutex}; fn notify( signals: &[c_int], @@ -140,7 +144,7 @@ impl Component for EmbedContainer { change_colors(grid, embed_area, Color::Byte(8), theme_default.bg); let stopped_message: String = format!("Process with PID {} has stopped.", guard.child_pid); - let stopped_message_2: String = format!("-press 'e' to re-activate.",); + let stopped_message_2: String = "-press 'e' to re-activate.".to_string(); const STOPPED_MESSAGE_3: &str = "-press Ctrl-C to forcefully kill it and return to editor."; let max_len = std::cmp::max( @@ -215,7 +219,6 @@ impl Component for EmbedContainer { } context.dirty_areas.push_back(area); self.dirty = false; - return; } fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool { @@ -244,7 +247,7 @@ impl Component for EmbedContainer { match embed_guard.is_active() { Ok(WaitStatus::Exited(_, exit_code)) => { drop(embed_guard); - let embed = self.embed.take(); + _ = self.embed.take(); if exit_code != 0 { context.replies.push_back(UIEvent::Notification( None, @@ -393,11 +396,11 @@ impl Component for EmbedContainer { fn main() -> std::io::Result<()> { let command = std::env::args() - .skip(1) - .next() + .nth(1) .expect("expected command as first argument"); - /* Create a channel to communicate with other threads. The main process is the sole receiver. - * */ + /* Create a channel to communicate with other threads. The main process is + * the sole receiver. + */ let (sender, receiver) = crossbeam::channel::bounded(32 * ::std::mem::size_of::()); /* Catch SIGWINCH to handle terminal resizing */ let signals = &[ @@ -425,7 +428,8 @@ fn main() -> std::io::Result<()> { } state.redraw(); - /* Poll on all channels. Currently we have the input channel for stdin, watching events and the signal watcher. */ + /* Poll on all channels. Currently we have the input channel for stdin, + * watching events and the signal watcher. */ crossbeam::select! { recv(receiver) -> r => { match r { diff --git a/tools/src/imapshell.rs b/tools/src/imapshell.rs index e6df86b2..3b50eb5a 100644 --- a/tools/src/imapshell.rs +++ b/tools/src/imapshell.rs @@ -1,17 +1,17 @@ extern crate melib; -use melib::backends::ImapType; -use melib::{futures, smol, Result}; -use melib::{AccountSettings, BackendEventConsumer}; +use melib::{backends::ImapType, futures, smol, AccountSettings, BackendEventConsumer, Result}; -/// Opens an interactive shell on an IMAP server. Suggested use is with rlwrap(1) +/// Opens an interactive shell on an IMAP server. Suggested use is with +/// rlwrap(1) /// /// # Example invocation: /// ```sh /// ./imapshell server_hostname server_username server_password server_port"); /// ``` /// -/// `danger_accept_invalid_certs` is turned on by default, so no certificate validation is performed. +/// `danger_accept_invalid_certs` is turned on by default, so no certificate +/// validation is performed. fn main() -> Result<()> { let mut args = std::env::args().skip(1).collect::>(); @@ -21,10 +21,10 @@ fn main() -> Result<()> { } let (a, b, c, d) = ( - std::mem::replace(&mut args[0], String::new()), - std::mem::replace(&mut args[1], String::new()), - std::mem::replace(&mut args[2], String::new()), - std::mem::replace(&mut args[3], String::new()), + std::mem::take(&mut args[0]), + std::mem::take(&mut args[1]), + std::mem::take(&mut args[2]), + std::mem::take(&mut args[3]), ); let set = AccountSettings { extra: [ diff --git a/tools/src/mboxparse.rs b/tools/src/mboxparse.rs index 100018f6..ac28bdc5 100644 --- a/tools/src/mboxparse.rs +++ b/tools/src/mboxparse.rs @@ -22,7 +22,8 @@ extern crate melib; use melib::Result; -/// Parses e-mail from files and prints the debug information of the parsed `Envelope` +/// Parses e-mail from files and prints the debug information of the parsed +/// `Envelope` /// /// # Example invocation /// ```sh @@ -41,7 +42,7 @@ fn main() -> Result<()> { if filename.exists() && filename.is_file() { let buffer = std::fs::read_to_string(&filename) - .expect(&format!("Something went wrong reading the file {}", i,)); + .unwrap_or_else(|_| panic!("Something went wrong reading the file {}", i)); let res = melib::backends::mbox::mbox_parse(Default::default(), buffer.as_bytes(), 0, None); match res { diff --git a/tools/src/smtp_conn.rs b/tools/src/smtp_conn.rs index 913cc86f..00ea8c90 100644 --- a/tools/src/smtp_conn.rs +++ b/tools/src/smtp_conn.rs @@ -1,9 +1,6 @@ extern crate melib; -use melib::futures; -use melib::smol; -use melib::smtp::*; -use melib::Result; +use melib::{futures, smol, smtp::*, Result}; fn main() -> Result<()> { let conf = SmtpServerConf {