diff --git a/Cargo.lock b/Cargo.lock index 72c3b4bf..ca5bae4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -236,15 +236,6 @@ dependencies = [ "libdbus-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "debug_printer" -version = "0.0.1" -dependencies = [ - "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", - "melib 0.4.1", - "ui 0.4.1", -] - [[package]] name = "dirs" version = "1.0.5" @@ -743,13 +734,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "meli" version = "0.4.1" dependencies = [ + "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "linkify 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "melib 0.4.1", "nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)", + "notify-rust 3.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rmp 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rmp-serde 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rmpv 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook-registry 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ui 0.4.1", + "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "text_processing 0.4.1", + "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "xdg-utils 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1839,37 +1850,6 @@ name = "try-lock" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "ui" -version = "0.4.1" -dependencies = [ - "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", - "linkify 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "melib 0.4.1", - "nix 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)", - "notify-rust 3.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rmp 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rmp-serde 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rmpv 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "text_processing 0.4.1", - "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "xdg-utils 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unicase" version = "2.6.0" diff --git a/Cargo.toml b/Cargo.toml index 8247ec91..a92df14b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,21 +14,44 @@ crossbeam = "0.7.2" signal-hook = "0.1.12" signal-hook-registry = "1.2.0" nix = "0.16.1" -melib = { path = "melib", version = "*" } -ui = { path = "ui", version = "*" } +melib = { path = "melib", version = "0.4.1" } + +serde = "1.0.71" +serde_derive = "1.0.71" +serde_json = "1.0" +toml = "0.5.3" +fnv = "1.0.3" # >:c +linkify = "0.3.1" # >:c +xdg-utils = "0.3.0" +nom = "3.2.0" +notify = "4.0.1" # >:c +notify-rust = "^3" # >:c +termion = "1.5.1" +bincode = "1.2.0" +uuid = { version = "0.7.4", features = ["serde", "v4"] } +unicode-segmentation = "1.2.1" # >:c +text_processing = { path = "text_processing", version = "0.4.1" } +libc = {version = "0.2.59", features = ["extra_traits",]} +rusqlite = {version = "0.20.0", optional =true } +rmp = "^0.8" +rmpv = { version = "^0.4.2", features=["with-serde",] } +rmp-serde = "^0.14.0" +smallvec = { version = "1.1.0", features = ["serde", ] } + [profile.release] lto = true debug = false [workspace] -members = ["melib", "ui", "debug_printer", "testing", "text_processing"] +members = ["melib", "testing", "text_processing"] [features] -default = [] -notmuch = ["melib/notmuch_backend", "ui/notmuch"] +default = ["sqlite3"] +notmuch = ["melib/notmuch_backend", ] jmap = ["melib/jmap_backend",] +sqlite3 = ["rusqlite"] # Print tracing logs as meli runs in stderr # enable for debug tracing logs: build with --features=debug-tracing -debug-tracing = ["melib/debug-tracing", "ui/debug-tracing"] +debug-tracing = ["melib/debug-tracing", ] diff --git a/Makefile b/Makefile index 66e628c7..b3b721b3 100644 --- a/Makefile +++ b/Makefile @@ -46,17 +46,18 @@ GREEN ?= `[ -z $${NO_COLOR+x} ] && tput setaf 2 || echo ""` help: @echo "For a quick start, build and install locally:\n ${BOLD}${GREEN}PREFIX=~/.local make install${ANSI_RESET}\n" @echo "Available subcommands:" - @echo " - ${BOLD}install${ANSI_RESET} (installs binary and documentation)" + @echo " - ${BOLD}meli${ANSI_RESET} (builds meli with optimizations in \$$CARGO_TARGET_DIR)" + @echo " - ${BOLD}install${ANSI_RESET} (installs binary in \$$BINDIR and documentation to \$$MANDIR)" @echo " - ${BOLD}uninstall${ANSI_RESET}" @echo "Secondary subcommands:" @echo " - ${BOLD}clean${ANSI_RESET} (cleans build artifacts)" @echo " - ${BOLD}check-deps${ANSI_RESET} (checks dependencies)" - @echo " - ${BOLD}install-bin${ANSI_RESET} (installs binary to BINDIR)" - @echo " - ${BOLD}install-doc${ANSI_RESET} (installs manpages to MANDIR)" + @echo " - ${BOLD}install-bin${ANSI_RESET} (installs binary to \$$BINDIR)" + @echo " - ${BOLD}install-doc${ANSI_RESET} (installs manpages to \$$MANDIR)" @echo " - ${BOLD}help${ANSI_RESET} (prints this information)" - @echo " - ${BOLD}dist${ANSI_RESET} (creates release tarball named meli-"${VERSION}".tar.gz)" - @echo " - ${BOLD}deb-dist${ANSI_RESET} (builds debian package)" + @echo " - ${BOLD}dist${ANSI_RESET} (creates release tarball named meli-"${VERSION}".tar.gz in this directory)" + @echo " - ${BOLD}deb-dist${ANSI_RESET} (builds debian package in the parent directory)" @echo " - ${BOLD}distclean${ANSI_RESET} (cleans distribution build artifacts)" @echo "\nENVIRONMENT variables of interest:" @echo "* PREFIX = ${UNDERLINE}${PREFIX}${ANSI_RESET}" diff --git a/debug_printer/Cargo.toml b/debug_printer/Cargo.toml deleted file mode 100644 index 2bcd9fc2..00000000 --- a/debug_printer/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "debug_printer" -version = "0.0.1" #:version -authors = ["Manos Pitsidianakis "] -workspace = ".." -edition = "2018" - -[lib] -name = "debugprinter" -crate-type = ["dylib"] -path = "src/lib.rs" - - -[dependencies] -libc = {version = "0.2.55", features = ["extra_traits",] } -melib = { path = "../melib", version = "*" } -ui = { path = "../ui", version = "*" } diff --git a/debug_printer/src/lib.rs b/debug_printer/src/lib.rs deleted file mode 100644 index 072f06c7..00000000 --- a/debug_printer/src/lib.rs +++ /dev/null @@ -1,44 +0,0 @@ -extern crate libc; -extern crate melib; - -use melib::Envelope; -use std::ffi::CString; -use std::os::raw::c_char; - -#[no_mangle] -pub extern "C" fn print_envelope(ptr: *const Envelope) -> *const c_char { - unsafe { - assert!(!ptr.is_null(), "Null pointer in print_envelope"); - //println!("got addr {}", p as u64); - //unsafe { CString::new("blah".to_string()).unwrap().as_ptr() } - let s = CString::new(format!("{:?}", *ptr)).unwrap(); - drop(ptr); - let p = s.as_ptr(); - std::mem::forget(s); - p - } -} - -#[no_mangle] -pub extern "C" fn get_empty_envelope() -> *mut Envelope { - let mut ret = Envelope::default(); - let ptr = std::ptr::NonNull::new(&mut ret as *mut Envelope) - .expect("Envelope::default() has a NULL pointer?"); - - let ptr = ptr.as_ptr(); - std::mem::forget(ret); - ptr -} - -#[no_mangle] -pub extern "C" fn destroy_cstring(ptr: *mut c_char) { - unsafe { - let slice = CString::from_raw(ptr); - drop(slice); - } -} - -#[no_mangle] -pub extern "C" fn envelope_size() -> libc::size_t { - std::mem::size_of::() -} diff --git a/melib/src/email/list_management.rs b/melib/src/email/list_management.rs index 93a14d3d..18e84828 100644 --- a/melib/src/email/list_management.rs +++ b/melib/src/email/list_management.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2019 Manos Pitsidianakis * diff --git a/src/bin.rs b/src/bin.rs index 891115cc..f1feea40 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -21,24 +21,74 @@ //! //! 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 the `ui` module. +//! `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; +use std::collections::VecDeque; use std::path::{Path, PathBuf}; +extern crate notify_rust; +extern crate text_processing; +use text_processing::*; +extern crate xdg_utils; +#[macro_use] +extern crate serde_derive; +extern crate linkify; +extern crate uuid; + +extern crate fnv; +extern crate termion; + +#[macro_use] +extern crate nom; + +extern crate serde_json; +extern crate smallvec; #[global_allocator] static GLOBAL: System = System; -// Re export to put crates in the documentation's start page. -pub use melib; -pub use ui; - +#[macro_use] +extern crate melib; use melib::*; -use ui::*; + +mod unix; +use unix::*; + +#[macro_use] +pub mod types; +use crate::types::*; + +#[macro_use] +pub mod terminal; +use crate::terminal::*; + +#[macro_use] +pub mod execute; +use crate::execute::*; + +pub mod state; +use crate::state::*; + +pub mod components; +use crate::components::*; + +#[macro_use] +pub mod conf; +use crate::conf::*; + +pub mod workers; +use crate::workers::*; + +#[cfg(feature = "sqlite3")] +pub mod sqlite3; + +pub mod cache; +pub mod mailcap; +pub mod plugins; use nix; use std::os::raw::c_int; @@ -152,15 +202,12 @@ fn run_app() -> Result<()> { args.version = true; } "--print-loaded-themes" => { - let s = ui::conf::FileSettings::new()?; + let s = conf::FileSettings::new()?; print!("{}", s.terminal.themes.to_string()); return Ok(()); } "--print-default-theme" => { - print!( - "{}", - ui::conf::Theme::default().key_to_string("dark", false) - ); + print!("{}", conf::Theme::default().key_to_string("dark", false)); return Ok(()); } e => match prev { @@ -215,7 +262,7 @@ fn run_app() -> Result<()> { }; if let Some(config_path) = args.test_config.as_ref() { - ui::conf::FileSettings::validate(config_path)?; + conf::FileSettings::validate(config_path)?; return Ok(()); } @@ -235,7 +282,7 @@ fn run_app() -> Result<()> { if config_path.exists() { return Err(MeliError::new(format!("File `{}` already exists.\nMaybe you meant to specify another path with --create-config=PATH", config_path.display()))); } - ui::conf::create_config_file(&config_path)?; + conf::create_config_file(&config_path)?; return Ok(()); } @@ -268,19 +315,17 @@ fn run_app() -> Result<()> { let status_bar = Box::new(StatusBar::new(window)); state.register_component(status_bar); - let xdg_notifications = Box::new(ui::components::notifications::XDGNotifications::new()); + let xdg_notifications = Box::new(components::notifications::XDGNotifications::new()); state.register_component(xdg_notifications); - state.register_component(Box::new( - ui::components::notifications::NotificationFilter {}, - )); + state.register_component(Box::new(components::notifications::NotificationFilter {})); - /* Keep track of the input mode. See ui::UIMode for details */ + /* Keep track of the input mode. See UIMode for details */ 'main: loop { state.render(); 'inner: loop { /* Check if any components have sent reply events to State. */ - let events: ui::smallvec::SmallVec<[UIEvent; 8]> = state.context.replies(); + let events: smallvec::SmallVec<[UIEvent; 8]> = state.context.replies(); for e in events { state.rcv_event(e); } diff --git a/ui/src/cache.rs b/src/cache.rs similarity index 98% rename from ui/src/cache.rs rename to src/cache.rs index 29f187b8..fd46494b 100644 --- a/ui/src/cache.rs +++ b/src/cache.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * @@ -19,6 +19,8 @@ * along with meli. If not, see . */ +/*! Search queries. + */ use melib::parsec::*; use melib::UnixTimestamp; use melib::{ @@ -27,6 +29,7 @@ use melib::{ thread::{SortField, SortOrder}, Result, }; +use std::borrow::Cow; use std::sync::{Arc, RwLock}; pub use query_parser::query; @@ -334,7 +337,6 @@ pub mod query_parser { pub fn query_to_imap(q: &Query) -> String { fn rec(q: &Query, s: &mut String) { - use crate::sqlite3::escape_double_quote; match q { Subject(t) => { s.push_str(" SUBJECT \""); @@ -440,3 +442,12 @@ pub fn imap_search( panic!("Could not downcast ImapType backend. BUG"); } } + +#[inline(always)] +pub fn escape_double_quote(w: &str) -> Cow { + if w.contains('"') { + Cow::from(w.replace('"', "\"\"")) + } else { + Cow::from(w) + } +} diff --git a/ui/src/components.rs b/src/components.rs similarity index 97% rename from ui/src/components.rs rename to src/components.rs index 3ee8cd98..e0fc897d 100644 --- a/ui/src/components.rs +++ b/src/components.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * @@ -19,11 +19,11 @@ * along with meli. If not, see . */ -/*! -Components are ways to handle application data. 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. -*/ +/*! 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.) + * See the `Component` Trait for more details. + */ use super::*; @@ -32,9 +32,6 @@ pub use crate::mail::*; pub mod notifications; -pub mod indexer; -pub use self::indexer::*; - pub mod utilities; pub use self::utilities::*; diff --git a/ui/src/components/contacts.rs b/src/components/contacts.rs similarity index 100% rename from ui/src/components/contacts.rs rename to src/components/contacts.rs diff --git a/ui/src/components/contacts/contact_list.rs b/src/components/contacts/contact_list.rs similarity index 100% rename from ui/src/components/contacts/contact_list.rs rename to src/components/contacts/contact_list.rs diff --git a/ui/src/components/mail.rs b/src/components/mail.rs similarity index 98% rename from ui/src/components/mail.rs rename to src/components/mail.rs index 9091b93d..8d2bc89a 100644 --- a/ui/src/components/mail.rs +++ b/src/components/mail.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/mail/compose.rs b/src/components/mail/compose.rs similarity index 99% rename from ui/src/components/mail/compose.rs rename to src/components/mail/compose.rs index b4e7521d..1454dba3 100644 --- a/ui/src/components/mail/compose.rs +++ b/src/components/mail/compose.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/mail/listing.rs b/src/components/mail/listing.rs similarity index 99% rename from ui/src/components/mail/listing.rs rename to src/components/mail/listing.rs index da0a9d27..7a64e5a3 100644 --- a/ui/src/components/mail/listing.rs +++ b/src/components/mail/listing.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * @@ -74,6 +74,7 @@ pub(super) struct EntryStrings { } #[macro_export] +/// Creates a comma separated list `String` out of an `Address` iterable. macro_rules! address_list { (($name:expr) as comma_sep_list) => {{ let mut ret: String = diff --git a/ui/src/components/mail/listing/compact.rs b/src/components/mail/listing/compact.rs similarity index 99% rename from ui/src/components/mail/listing/compact.rs rename to src/components/mail/listing/compact.rs index f62191c6..2feda0e0 100644 --- a/ui/src/components/mail/listing/compact.rs +++ b/src/components/mail/listing/compact.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/mail/listing/conversations.rs b/src/components/mail/listing/conversations.rs similarity index 99% rename from ui/src/components/mail/listing/conversations.rs rename to src/components/mail/listing/conversations.rs index 20519b5f..f6588c75 100644 --- a/ui/src/components/mail/listing/conversations.rs +++ b/src/components/mail/listing/conversations.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/mail/listing/plain.rs b/src/components/mail/listing/plain.rs similarity index 99% rename from ui/src/components/mail/listing/plain.rs rename to src/components/mail/listing/plain.rs index 2f8c6bce..66014f9f 100644 --- a/ui/src/components/mail/listing/plain.rs +++ b/src/components/mail/listing/plain.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/mail/listing/thread.rs b/src/components/mail/listing/thread.rs similarity index 99% rename from ui/src/components/mail/listing/thread.rs rename to src/components/mail/listing/thread.rs index f5e0ee16..935326a6 100644 --- a/ui/src/components/mail/listing/thread.rs +++ b/src/components/mail/listing/thread.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/mail/pgp.rs b/src/components/mail/pgp.rs similarity index 99% rename from ui/src/components/mail/pgp.rs rename to src/components/mail/pgp.rs index 233c633b..e4a868ea 100644 --- a/ui/src/components/mail/pgp.rs +++ b/src/components/mail/pgp.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2019 Manos Pitsidianakis * diff --git a/ui/src/components/mail/status.rs b/src/components/mail/status.rs similarity index 100% rename from ui/src/components/mail/status.rs rename to src/components/mail/status.rs diff --git a/ui/src/components/mail/view.rs b/src/components/mail/view.rs similarity index 99% rename from ui/src/components/mail/view.rs rename to src/components/mail/view.rs index 66777f22..3322b4d9 100644 --- a/ui/src/components/mail/view.rs +++ b/src/components/mail/view.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/mail/view/envelope.rs b/src/components/mail/view/envelope.rs similarity index 99% rename from ui/src/components/mail/view/envelope.rs rename to src/components/mail/view/envelope.rs index 65b8fb0d..d4868a85 100644 --- a/ui/src/components/mail/view/envelope.rs +++ b/src/components/mail/view/envelope.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/mail/view/html.rs b/src/components/mail/view/html.rs similarity index 99% rename from ui/src/components/mail/view/html.rs rename to src/components/mail/view/html.rs index 7d750266..cc218fd5 100644 --- a/ui/src/components/mail/view/html.rs +++ b/src/components/mail/view/html.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/mail/view/thread.rs b/src/components/mail/view/thread.rs similarity index 99% rename from ui/src/components/mail/view/thread.rs rename to src/components/mail/view/thread.rs index bfdad2de..d98c4212 100644 --- a/ui/src/components/mail/view/thread.rs +++ b/src/components/mail/view/thread.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/notifications.rs b/src/components/notifications.rs similarity index 99% rename from ui/src/components/notifications.rs rename to src/components/notifications.rs index bdc186bb..5dfd74c4 100644 --- a/ui/src/components/notifications.rs +++ b/src/components/notifications.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/utilities.rs b/src/components/utilities.rs similarity index 99% rename from ui/src/components/utilities.rs rename to src/components/utilities.rs index ea6eb9b5..3b0a05db 100644 --- a/ui/src/components/utilities.rs +++ b/src/components/utilities.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/components/utilities/widgets.rs b/src/components/utilities/widgets.rs similarity index 99% rename from ui/src/components/utilities/widgets.rs rename to src/components/utilities/widgets.rs index d05eaa98..79fd1385 100644 --- a/ui/src/components/utilities/widgets.rs +++ b/src/components/utilities/widgets.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2020 Manos Pitsidianakis * diff --git a/ui/src/conf.rs b/src/conf.rs similarity index 98% rename from ui/src/conf.rs rename to src/conf.rs index 290f1c3b..2964c042 100644 --- a/ui/src/conf.rs +++ b/src/conf.rs @@ -19,6 +19,8 @@ * along with meli. If not, see . */ +/*! Configuration logic and `config.toml` interfaces. */ + extern crate bincode; extern crate serde; extern crate toml; @@ -637,7 +639,7 @@ pub fn create_config_file(p: &Path) -> Result<()> { .create_new(true) .open(p) .expect("Could not create config file."); - file.write_all(include_bytes!("../../sample-config")) + file.write_all(include_bytes!("../sample-config")) .expect("Could not write to config file."); println!("Written example configuration to {}", p.display()); let metadata = file.metadata()?; @@ -649,6 +651,7 @@ pub fn create_config_file(p: &Path) -> Result<()> { } mod pp { + //! Preprocess configuration files by unfolding `include` macros. use melib::{ error::{MeliError, Result}, parsec::*, @@ -656,6 +659,7 @@ mod pp { 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>> { move |input: &'a str| { enum State { @@ -712,6 +716,7 @@ mod pp { } } + /// Expands `include` macros in path. fn pp_helper(path: &Path, level: u8) -> Result { if level > 7 { return Err(MeliError::new(format!("Maximum recursion limit reached while unfolding include directives in {}. Have you included a config file within itself?", path.display()))); @@ -752,6 +757,8 @@ mod pp { Ok(ret) } + /// 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().canonicalize()? diff --git a/ui/src/conf/accounts.rs b/src/conf/accounts.rs similarity index 99% rename from ui/src/conf/accounts.rs rename to src/conf/accounts.rs index 33c2534f..5cda13cd 100644 --- a/ui/src/conf/accounts.rs +++ b/src/conf/accounts.rs @@ -1106,10 +1106,9 @@ impl Account { #[cfg(not(feature = "sqlite3"))] { let mut ret = SmallVec::new(); - let envelopes = self.collection.envelopes.clone().read(); - let envelopes = envelopes.unwrap(); + let envelopes = self.collection.envelopes.read().unwrap(); - for env_hash in self.folders[folder_hash].as_result()?.envelopes { + for &env_hash in &self.folders[&folder_hash].as_result()?.envelopes { let envelope = &envelopes[&env_hash]; if envelope.subject().contains(&search_term) { ret.push(env_hash); @@ -1127,7 +1126,7 @@ impl Account { ret.push(env_hash); } } - ret + Ok(ret) } } } diff --git a/ui/src/conf/composing.rs b/src/conf/composing.rs similarity index 97% rename from ui/src/conf/composing.rs rename to src/conf/composing.rs index 8e5dac49..a497eaac 100644 --- a/ui/src/conf/composing.rs +++ b/src/conf/composing.rs @@ -18,6 +18,8 @@ * You should have received a copy of the GNU General Public License * along with meli. If not, see . */ + +//! Configuration for composing email. use super::default_vals::{false_val, none, true_val}; /// Settings for writing and sending new e-mail diff --git a/ui/src/conf/listing.rs b/src/conf/listing.rs similarity index 100% rename from ui/src/conf/listing.rs rename to src/conf/listing.rs diff --git a/ui/src/conf/notifications.rs b/src/conf/notifications.rs similarity index 100% rename from ui/src/conf/notifications.rs rename to src/conf/notifications.rs diff --git a/ui/src/conf/pager.rs b/src/conf/pager.rs similarity index 98% rename from ui/src/conf/pager.rs rename to src/conf/pager.rs index 40c11d12..fe41e8b4 100644 --- a/ui/src/conf/pager.rs +++ b/src/conf/pager.rs @@ -19,6 +19,8 @@ * along with meli. If not, see . */ +//! Settings for the pager function. + use super::default_vals::*; use super::deserializers::*; use melib::ToggleFlag; diff --git a/ui/src/conf/pgp.rs b/src/conf/pgp.rs similarity index 100% rename from ui/src/conf/pgp.rs rename to src/conf/pgp.rs diff --git a/ui/src/conf/shortcuts.rs b/src/conf/shortcuts.rs similarity index 100% rename from ui/src/conf/shortcuts.rs rename to src/conf/shortcuts.rs diff --git a/ui/src/conf/tags.rs b/src/conf/tags.rs similarity index 97% rename from ui/src/conf/tags.rs rename to src/conf/tags.rs index 135f3291..72d94b7c 100644 --- a/ui/src/conf/tags.rs +++ b/src/conf/tags.rs @@ -19,6 +19,8 @@ * along with meli. If not, see . */ +//! E-mail tag configuration and {de,}serializing. + use crate::terminal::Color; use serde::{Deserialize, Deserializer}; use std::collections::{hash_map::DefaultHasher, HashMap, HashSet}; diff --git a/ui/src/conf/terminal.rs b/src/conf/terminal.rs similarity index 97% rename from ui/src/conf/terminal.rs rename to src/conf/terminal.rs index b434ca04..2f5f7d7d 100644 --- a/ui/src/conf/terminal.rs +++ b/src/conf/terminal.rs @@ -19,6 +19,8 @@ * along with meli. If not, see . */ +//! Settings for terminal display + use super::deserializers::non_empty_string; use super::Theme; use super::ToggleFlag; diff --git a/ui/src/conf/themes.rs b/src/conf/themes.rs similarity index 97% rename from ui/src/conf/themes.rs rename to src/conf/themes.rs index 6bf2c29b..ae7f0d79 100644 --- a/ui/src/conf/themes.rs +++ b/src/conf/themes.rs @@ -19,6 +19,15 @@ * along with meli. If not, see . */ +//! 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`. +//! * `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 melib::{MeliError, Result}; @@ -187,6 +196,7 @@ const DEFAULT_KEYS: &'static [&'static str] = &[ "mail.listing.thread_snooze_flag", ]; +/// `ThemeAttributeInner` but with the links resolved. #[derive(Debug, PartialEq, Eq, Clone, Default, Copy, Serialize, Deserialize)] pub struct ThemeAttribute { pub fg: Color, @@ -194,6 +204,7 @@ pub struct ThemeAttribute { pub attrs: Attr, } +/// Holds {fore,back}ground color and terminal attribute values. #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct ThemeAttributeInner { #[serde(default)] @@ -205,6 +216,7 @@ pub struct ThemeAttributeInner { } #[derive(Debug, Clone)] +/// Holds either an actual value or refers to the key name of the attribute that holds the value. pub enum ThemeValue { Value(T), Link(Cow<'static, str>), diff --git a/ui/src/execute.rs b/src/execute.rs similarity index 99% rename from ui/src/execute.rs rename to src/execute.rs index e6932e45..bb7ec388 100644 --- a/ui/src/execute.rs +++ b/src/execute.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * @@ -19,7 +19,7 @@ * along with meli. If not, see . */ -/*! A parser module for user commands passed through the Ex mode. +/*! A parser module for user commands passed through the Execute mode. */ use melib::backends::FolderOperation; pub use melib::thread::{SortField, SortOrder}; diff --git a/ui/src/execute/actions.rs b/src/execute/actions.rs similarity index 99% rename from ui/src/execute/actions.rs rename to src/execute/actions.rs index fb9922c1..2580f474 100644 --- a/ui/src/execute/actions.rs +++ b/src/execute/actions.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/execute/history.rs b/src/execute/history.rs similarity index 98% rename from ui/src/execute/history.rs rename to src/execute/history.rs index 87907d85..d47d88b5 100644 --- a/ui/src/execute/history.rs +++ b/src/execute/history.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2019 Manos Pitsidianakis * diff --git a/ui/src/mailcap.rs b/src/mailcap.rs similarity index 99% rename from ui/src/mailcap.rs rename to src/mailcap.rs index b712e0a7..0973bcfa 100644 --- a/ui/src/mailcap.rs +++ b/src/mailcap.rs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with meli. If not, see . */ + +/*! Find mailcap entries to execute attachments. + */ use crate::split_command; use crate::state::Context; use crate::types::{create_temp_file, ForkType, UIEvent}; diff --git a/ui/src/plugins.rs b/src/plugins.rs similarity index 99% rename from ui/src/plugins.rs rename to src/plugins.rs index a321ad63..ddcb05ab 100644 --- a/ui/src/plugins.rs +++ b/src/plugins.rs @@ -19,6 +19,8 @@ * along with meli. If not, see . */ +/*! Plugins are executed by meli and communication is done by `messagepack` IPC. + */ use melib::error::{MeliError, Result}; use std::collections::HashMap; use std::io::Write; diff --git a/ui/src/plugins/backend.rs b/src/plugins/backend.rs similarity index 100% rename from ui/src/plugins/backend.rs rename to src/plugins/backend.rs diff --git a/ui/src/plugins/python3/ansi-plugin.py b/src/plugins/python3/ansi-plugin.py similarity index 100% rename from ui/src/plugins/python3/ansi-plugin.py rename to src/plugins/python3/ansi-plugin.py diff --git a/ui/src/plugins/python3/libmeliapi.py b/src/plugins/python3/libmeliapi.py similarity index 100% rename from ui/src/plugins/python3/libmeliapi.py rename to src/plugins/python3/libmeliapi.py diff --git a/ui/src/plugins/python3/nntp-backend.py b/src/plugins/python3/nntp-backend.py similarity index 100% rename from ui/src/plugins/python3/nntp-backend.py rename to src/plugins/python3/nntp-backend.py diff --git a/ui/src/plugins/rpc.rs b/src/plugins/rpc.rs similarity index 100% rename from ui/src/plugins/rpc.rs rename to src/plugins/rpc.rs diff --git a/ui/src/sqlite3.rs b/src/sqlite3.rs similarity index 98% rename from ui/src/sqlite3.rs rename to src/sqlite3.rs index c001236d..047735e9 100644 --- a/ui/src/sqlite3.rs +++ b/src/sqlite3.rs @@ -19,9 +19,10 @@ * along with meli. If not, see . */ +/*! Use an sqlite3 database for fast searching. + */ use smallvec::SmallVec; -use crate::cache::query; -use crate::cache::Query::{self, *}; +use crate::cache::{escape_double_quote, query, Query::{self, *}}; use crate::melib::parsec::Parser; use melib::{ backends::MailBackend, @@ -31,20 +32,10 @@ use melib::{ MeliError, Result, ERROR, }; use rusqlite::{params, Connection}; -use std::borrow::Cow; use std::path::PathBuf; use std::convert::TryInto; use std::sync::{Arc, RwLock}; -#[inline(always)] -pub fn escape_double_quote(w: &str) -> Cow { - if w.contains('"') { - Cow::from(w.replace('"', "\"\"")) - } else { - Cow::from(w) - } -} - pub fn db_path() -> Result { let data_dir = xdg::BaseDirectories::with_prefix("meli").map_err(|e| MeliError::new(e.to_string()))?; diff --git a/ui/src/state.rs b/src/state.rs similarity index 98% rename from ui/src/state.rs rename to src/state.rs index 6ecf8f20..7b4b8b5e 100644 --- a/ui/src/state.rs +++ b/src/state.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * @@ -641,6 +641,7 @@ impl State { } } AccountAction(ref account_name, ReIndex) => { + #[cfg(feature = "sqlite3")] match crate::sqlite3::index(&mut self.context, account_name) { Ok(()) => { self.context.replies.push_back(UIEvent::Notification( @@ -657,6 +658,15 @@ impl State { )); } } + #[cfg(not(feature = "sqlite3"))] + { + self.context.replies.push_back(UIEvent::Notification( + None, + "Message index rebuild failed: meli is not built with sqlite3 support." + .to_string(), + Some(NotificationType::ERROR), + )); + } } v => { self.rcv_event(UIEvent::Action(v)); diff --git a/ui/src/terminal.rs b/src/terminal.rs similarity index 99% rename from ui/src/terminal.rs rename to src/terminal.rs index 9199748b..92f447be 100644 --- a/ui/src/terminal.rs +++ b/src/terminal.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with meli. If not, see . */ + +/*! Terminal grid cells, keys, colors, etc. + */ extern crate serde; use self::serde::de::Visitor; use self::serde::{de, Deserialize, Deserializer}; diff --git a/ui/src/terminal/cells.rs b/src/terminal/cells.rs similarity index 99% rename from ui/src/terminal/cells.rs rename to src/terminal/cells.rs index 875f610a..df76faf6 100644 --- a/ui/src/terminal/cells.rs +++ b/src/terminal/cells.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * @@ -36,6 +36,9 @@ use termion::color::{AnsiValue, Rgb as TermionRgb}; /// 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. #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct ScrollRegion { pub top: usize, @@ -56,7 +59,9 @@ pub struct CellBuffer { cols: usize, rows: usize, buf: Vec, + /// ASCII-only flag. pub ascii_drawing: bool, + /// If printing to this buffer and we run out of space, expand it. growable: bool, } @@ -170,7 +175,7 @@ impl CellBuffer { /// /// # Examples /// - /// ```norun + /// ```no_run /// /// let mut term = Terminal::new().unwrap(); /// @@ -188,7 +193,7 @@ impl CellBuffer { /// /// # Examples /// - /// ```norun + /// ```no_run /// /// let mut term = Terminal::new().unwrap(); /// @@ -427,6 +432,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. empty: bool, fg: Color, bg: Color, @@ -440,8 +447,7 @@ impl Cell { /// /// # Examples /// - /// ```norun - /// + /// ```no_run /// let cell = Cell::new('x', Color::Default, Color::Green, Attr::Default); /// assert_eq!(cell.ch(), 'x'); /// assert_eq!(cell.fg(), Color::Default); @@ -464,8 +470,7 @@ impl Cell { /// /// # Examples /// - /// ```norun - /// + /// ```no_run /// let mut cell = Cell::with_char('x'); /// assert_eq!(cell.ch(), 'x'); /// assert_eq!(cell.fg(), Color::Default); @@ -480,8 +485,7 @@ impl Cell { /// /// # Examples /// - /// ```norun - /// + /// ```no_run /// let mut cell = Cell::with_style(Color::Default, Color::Red, Attr::Bold); /// assert_eq!(cell.fg(), Color::Default); /// assert_eq!(cell.bg(), Color::Red); @@ -496,8 +500,7 @@ impl Cell { /// /// # Examples /// - /// ```norun - /// + /// ```no_run /// let mut cell = Cell::with_char('x'); /// assert_eq!(cell.ch(), 'x'); /// ``` @@ -509,8 +512,7 @@ impl Cell { /// /// # Examples /// - /// ```norun - /// + /// ```no_run /// let mut cell = Cell::with_char('x'); /// assert_eq!(cell.ch(), 'x'); /// @@ -528,8 +530,7 @@ impl Cell { /// /// # Examples /// - /// ```norun - /// + /// ```no_run /// let mut cell = Cell::with_style(Color::Blue, Color::Default, Attr::Default); /// assert_eq!(cell.fg(), Color::Blue); /// ``` @@ -541,8 +542,7 @@ impl Cell { /// /// # Examples /// - /// ```norun - /// + /// ```no_run /// let mut cell = Cell::default(); /// assert_eq!(cell.fg(), Color::Default); /// @@ -560,7 +560,7 @@ impl Cell { /// /// # Examples /// - /// ```norun + /// ```no_run /// let mut cell = Cell::with_style(Color::Default, Color::Green, Attr::Default); /// assert_eq!(cell.bg(), Color::Green); /// ``` @@ -572,7 +572,7 @@ impl Cell { /// /// # Examples /// - /// ```norun + /// ```no_run /// let mut cell = Cell::default(); /// assert_eq!(cell.bg(), Color::Default); /// @@ -626,8 +626,7 @@ impl Default for Cell { /// /// # Examples /// - /// ```norun - /// + /// ```no_run /// let mut cell = Cell::default(); /// assert_eq!(cell.ch(), ' '); /// assert_eq!(cell.fg(), Color::Default); @@ -650,8 +649,7 @@ impl Default for Cell { /// /// # Examples /// -/// ```norun -/// +/// ```no_run /// // The default color. /// let default = Color::Default; /// @@ -676,6 +674,7 @@ pub enum Color { White, Byte(u8), Rgb(u8, u8, u8), + /// Terminal default. Default, } @@ -1371,8 +1370,7 @@ impl Serialize for Color { /// /// # Examples /// -/// ```norun -/// +/// ```no_run /// // Default attribute. /// let def = Attr::Default; /// @@ -1384,6 +1382,7 @@ impl Serialize for Color { /// ``` #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Attr { + /// Terminal default. Default = 0b000, Bold = 0b001, Underline = 0b100, @@ -2003,7 +2002,7 @@ pub mod ansi { /// 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. -/// ```norun +/// ```no_run /// for c in grid.row_iter( /// x..(x + 11), /// 0, @@ -2017,7 +2016,7 @@ pub struct RowIterator { } /// `BoundsIterator` iterates each row returning a `RowIterator`. -/// ```norun +/// ```no_run /// /* Visit each `Cell` in `area`. */ /// for c in grid.bounds_iter(area) { /// grid[c].set_ch('w'); diff --git a/ui/src/terminal/embed.rs b/src/terminal/embed.rs similarity index 99% rename from ui/src/terminal/embed.rs rename to src/terminal/embed.rs index d0251093..3b3b938f 100644 --- a/ui/src/terminal/embed.rs +++ b/src/terminal/embed.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2020 Manos Pitsidianakis * diff --git a/ui/src/terminal/embed/grid.rs b/src/terminal/embed/grid.rs similarity index 99% rename from ui/src/terminal/embed/grid.rs rename to src/terminal/embed/grid.rs index 70c4c9b7..630597bf 100644 --- a/ui/src/terminal/embed/grid.rs +++ b/src/terminal/embed/grid.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2020 Manos Pitsidianakis * diff --git a/ui/src/terminal/keys.rs b/src/terminal/keys.rs similarity index 97% rename from ui/src/terminal/keys.rs rename to src/terminal/keys.rs index b112dded..9b0b9ca5 100644 --- a/ui/src/terminal/keys.rs +++ b/src/terminal/keys.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * @@ -135,6 +135,7 @@ impl PartialEq for &Key { } #[derive(PartialEq)] +/// Keep track of whether we're accepting normal user input or a pasted string. enum InputMode { Normal, Paste, @@ -142,10 +143,13 @@ enum InputMode { } #[derive(Debug)] +/// Main process sends commands to the input thread. pub enum InputCommand { + /// Exit thread Kill, - /// Send Raw bytes as well + /// Send raw bytes as well Raw, + /// Ignore raw bytes NoRaw, } @@ -158,6 +162,7 @@ use termion::input::TermReadEventsAndRaw; * * 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. pub fn get_events( mut closure: impl FnMut(Key), closure_raw: impl FnMut((Key, Vec)), @@ -202,6 +207,7 @@ pub fn get_events( } } +/// Same as `get_events` but also forwards the raw bytes of the input as well pub fn get_events_raw( closure_nonraw: impl FnMut(Key), mut closure: impl FnMut((Key, Vec)), diff --git a/ui/src/terminal/position.rs b/src/terminal/position.rs similarity index 99% rename from ui/src/terminal/position.rs rename to src/terminal/position.rs index 702b7022..06d66d23 100644 --- a/ui/src/terminal/position.rs +++ b/src/terminal/position.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/terminal/text_editing.rs b/src/terminal/text_editing.rs similarity index 99% rename from ui/src/terminal/text_editing.rs rename to src/terminal/text_editing.rs index a73c12f5..e2fb53e3 100644 --- a/ui/src/terminal/text_editing.rs +++ b/src/terminal/text_editing.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2020 Manos Pitsidianakis * diff --git a/ui/src/types.rs b/src/types.rs similarity index 93% rename from ui/src/types.rs rename to src/types.rs index bab1502d..8dc3638b 100644 --- a/ui/src/types.rs +++ b/src/types.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * @@ -18,6 +18,18 @@ * You should have received a copy of the GNU General Public License * along with meli. If not, see . */ + +/*! 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 + * than it has to. + * + * `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; diff --git a/ui/src/types/helpers.rs b/src/types/helpers.rs similarity index 99% rename from ui/src/types/helpers.rs rename to src/types/helpers.rs index 7a0bf34c..ac089e28 100644 --- a/ui/src/types/helpers.rs +++ b/src/types/helpers.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * diff --git a/ui/src/lib.rs b/src/unix.rs similarity index 70% rename from ui/src/lib.rs rename to src/unix.rs index 3f183033..4ee097e8 100644 --- a/ui/src/lib.rs +++ b/src/unix.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2018 Manos Pitsidianakis * @@ -19,177 +19,29 @@ * along with meli. If not, see . */ -/*! - * This library exports the public types and methods of its modules +/*! UNIX and POSIX interfaces. */ -#[macro_use] -extern crate melib; -extern crate notify_rust; -extern crate text_processing; -pub extern crate xdg_utils; -#[macro_use] -extern crate serde_derive; -extern crate linkify; -extern crate uuid; - -extern crate fnv; -extern crate termion; - -#[macro_use] -extern crate nom; - -extern crate serde_json; -pub extern crate smallvec; - -use melib::*; -use std::collections::VecDeque; -use text_processing::*; - -#[macro_use] -mod types; -pub use crate::types::*; - -#[macro_use] -mod terminal; -pub use crate::terminal::*; - -#[macro_use] -mod execute; -use crate::execute::*; - -pub mod state; -pub use crate::state::*; - -pub mod components; -pub use crate::components::*; - -#[macro_use] -pub mod conf; -pub use crate::conf::*; - -pub mod workers; -pub use crate::workers::*; - -#[cfg(feature = "sqlite3")] -pub mod sqlite3; - -pub mod cache; - -pub mod mailcap; - -pub mod plugins; - -pub use crate::username::*; -pub mod username { - use libc; - use std::ptr::null_mut; - /* taken from whoami-0.1.1 */ - fn getpwuid() -> libc::passwd { - let mut pwentp = null_mut(); - #[cfg(target_arch = "aarch64")] - let mut buffer = [0u8; 16384]; // from the man page - #[cfg(not(target_arch = "aarch64"))] - let mut buffer = [0i8; 16384]; // from the man page - #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "openbsd", - target_os = "netbsd" - ))] - { - let mut pwent = libc::passwd { - pw_name: null_mut(), - pw_passwd: null_mut(), - pw_uid: 0, - pw_gid: 0, - pw_change: 0, - pw_class: null_mut(), - pw_gecos: null_mut(), - pw_dir: null_mut(), - pw_shell: null_mut(), - pw_expire: 0, - }; - unsafe { - libc::getpwuid_r( - libc::geteuid(), - &mut pwent, - &mut buffer[0], - 16384, - &mut pwentp, - ); - } - - pwent - } - #[cfg(target_os = "linux")] - { - let mut pwent = libc::passwd { - pw_name: null_mut(), - pw_passwd: null_mut(), - pw_uid: 0, - pw_gid: 0, - pw_gecos: null_mut(), - pw_dir: null_mut(), - pw_shell: null_mut(), - }; - - unsafe { - libc::getpwuid_r( - libc::geteuid(), - &mut pwent, - &mut buffer[0], - 16384, - &mut pwentp, - ); - } - - pwent - } - } - #[cfg(target_arch = "aarch64")] - fn ptr_to_string(name: *mut u8) -> String { - let uname = name as *const u8; - - let s; - let string; - - unsafe { - s = ::std::slice::from_raw_parts(uname, libc::strlen(name)); - string = String::from_utf8_lossy(s).to_string(); - } - - string - } - - #[cfg(not(target_arch = "aarch64"))] - fn ptr_to_string(name: *mut i8) -> String { - let uname = name as *mut _ as *mut u8; - - let s; - let string; - - unsafe { - s = ::std::slice::from_raw_parts(uname, libc::strlen(name)); - string = String::from_utf8_lossy(s).to_string(); - } - - string - } - pub fn username() -> String { - let pwent = getpwuid(); - - ptr_to_string(pwent.pw_name) - } -} - pub mod timer { - use super::{MeliError, Result}; + //! POSIX timers + //! + //! # Example usage + //! ```no_run + //! let timer = crate::timer::PosixTimer::new_with_signal( + //! std::time::Duration::from_secs(0), + //! std::time::Duration::from_secs(1), + //! nix::sys::signal::Signal::SIGALRM, + //! ) + //! .unwrap(); + //! + //! // some time passes, we should receive and handle the SIGALRM + //! // The timer remains unarmed since the interval given was zero, until we rearm it explicitly. + //! self.timer.rearm(); + //! ``` use libc::clockid_t; use libc::sigevent; use libc::{itimerspec, timespec}; + use melib::{MeliError, Result}; use nix::sys::signal::{SigEvent, SigevNotify}; use std::cell::RefCell; use std::convert::TryInto; @@ -216,8 +68,11 @@ pub mod timer { #[derive(Debug)] pub struct PosixTimer { timer_id: timer_t, + /// Interval for periodic timer. interval: Duration, + /// Time until next expiration. value: Duration, + /// `si_value` is a byte accessible from the signal handler when it receives signals from this timer. pub si_value: u8, } @@ -230,6 +85,7 @@ pub mod timer { } impl PosixTimer { + /// Arm without changing interval and value. pub fn rearm(&mut self) { let spec = itimerspec { it_interval: timespec { @@ -316,6 +172,7 @@ pub mod timer { self.interval = interval; } + /// Arm by changing interval and value. pub fn arm(&mut self, value: Duration) { let spec = itimerspec { it_interval: timespec { diff --git a/ui/src/workers.rs b/src/workers.rs similarity index 99% rename from ui/src/workers.rs rename to src/workers.rs index 03645fa7..bed12a33 100644 --- a/ui/src/workers.rs +++ b/src/workers.rs @@ -1,5 +1,5 @@ /* - * meli - ui crate. + * meli * * Copyright 2017-2020 Manos Pitsidianakis * @@ -19,6 +19,8 @@ * along with meli. If not, see . */ +/*! Simple blocking job control. + */ use crate::types::ThreadEvent; use crossbeam::{ channel::{bounded, unbounded, Sender}, diff --git a/testing/Cargo.toml b/testing/Cargo.toml index 56824bf3..3f56d205 100644 --- a/testing/Cargo.toml +++ b/testing/Cargo.toml @@ -8,9 +8,6 @@ edition = "2018" [[bin]] name = "emailparse" path = "src/email_parse.rs" -[[bin]] -name = "linebreak" -path = "src/linebreak.rs" [[bin]] name = "imapconn" diff --git a/testing/src/email_parse.rs b/testing/src/email_parse.rs index 4e1bc28b..2d7cb088 100644 --- a/testing/src/email_parse.rs +++ b/testing/src/email_parse.rs @@ -1,23 +1,32 @@ 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` +/// +/// # Example invocation +/// ```sh +/// ./emailparse /path/to/email [/path/to/email2 /path/to/email3 ..]" +/// ``` fn main() -> Result<()> { + if args.len() == 1 { + eprintln!("Usage: ./emailparse /path/to/email [/path/to/email2 /path/to/email3 ..]"); + std::process::exit(1); + } + for i in std::env::args().skip(1) { - println!("i is {}", i); + println!("Path is {}", i); let filename = std::path::PathBuf::from(i); - if filename.is_file() { - let buffer = std::fs::read_to_string(&filename).expect(&format!( - "Something went wrong reading the file {}", - filename.display() - )); + 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"); - eprintln!("Env is {:#?}", env); - eprintln!("{:?}", env.body_bytes(buffer.as_bytes())); + println!("Env is {:#?}", env); + println!("{:?}", env.body_bytes(buffer.as_bytes())); } else { - println!("it's not a file"); + println!("{} is not a valid file.", i); } } Ok(()) diff --git a/testing/src/imap_conn.rs b/testing/src/imap_conn.rs index efc5ba41..cd467623 100644 --- a/testing/src/imap_conn.rs +++ b/testing/src/imap_conn.rs @@ -4,6 +4,15 @@ use melib::backends::ImapType; use melib::AccountSettings; use melib::Result; +/// Opens an interactive shell on an IMAP server. Suggested use is with rlwrap(1) +/// +/// # Example invocation: +/// ```sh +/// ./imap_conn server_hostname server_username server_password server_port"); +/// ``` +/// +/// `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::>(); if args.len() != 4 { diff --git a/tests/generating_email.rs b/tests/generating_email.rs index 380c4bcc..c0acd498 100644 --- a/tests/generating_email.rs +++ b/tests/generating_email.rs @@ -1,6 +1,4 @@ use melib; -use ui::xdg_utils; - use melib::email::Draft; use xdg_utils::query_mime_info; diff --git a/ui/Cargo.toml b/ui/Cargo.toml deleted file mode 100644 index 6f1c211c..00000000 --- a/ui/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "ui" -version = "0.4.1" -authors = ["Manos Pitsidianakis "] -workspace = ".." -edition = "2018" - -[dependencies] -xdg = "2.1.0" # >:c -serde = "1.0.71" -serde_derive = "1.0.71" -serde_json = "1.0" -toml = "0.5.3" -crossbeam = "0.7.2" -fnv = "1.0.3" # >:c -linkify = "0.3.1" # >:c -melib = { path = "../melib", version = "*" } -xdg-utils = "0.3.0" -nom = "3.2.0" -notify = "4.0.1" # >:c -notify-rust = "^3" # >:c -termion = "1.5.1" -bincode = "1.2.0" -uuid = { version = "0.7.4", features = ["serde", "v4"] } -unicode-segmentation = "1.2.1" # >:c -text_processing = { path = "../text_processing", version = "*" } -libc = {version = "0.2.59", features = ["extra_traits",]} -nix = "0.16.1" -rusqlite = {version = "0.20.0", optional =true } -rmp = "^0.8" -rmpv = { version = "^0.4.2", features=["with-serde",] } -rmp-serde = "^0.14.0" -smallvec = { version = "1.1.0", features = ["serde", ] } - -[features] -default = ["sqlite3"] -notmuch = [] -sqlite3 = ["rusqlite"] - -# Print tracing logs as meli runs -debug-tracing = [] diff --git a/ui/src/components/indexer.rs b/ui/src/components/indexer.rs deleted file mode 100644 index e545fc2f..00000000 --- a/ui/src/components/indexer.rs +++ /dev/null @@ -1,134 +0,0 @@ -/* - * meli - ui crate. - * - * Copyright 2017-2018 Manos Pitsidianakis - * - * This file is part of meli. - * - * meli is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * meli is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with meli. If not, see . - */ - -/*! Entities that handle Mail specific functions. - */ -use super::*; - -pub mod index; -pub use self::index::*; - -#[derive(Debug)] -struct MenuEntry { - name: String, - subentries: Vec, - index: Index, -} - -#[derive(Debug)] -pub struct Indexer { - entries: Vec, - dirty: bool, - cursor: Vec, - id: ComponentId, -} - -impl fmt::Display for Indexer { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // TODO display subject/info - write!(f, "index") - } -} - -impl Default for Indexer { - fn default() -> Self { - Indexer { - entries: Vec::with_capacity(8), - dirty: true, - cursor: Vec::with_capacity(8), - id: ComponentId::new_v4(), - } - } -} - -impl Indexer { - fn draw_menu(&mut self, _grid: &mut CellBuffer, _area: Area, _context: &mut Context) {} -} - -impl Component for Indexer { - fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { - if !self.is_dirty() { - return; - } - - clear_area(grid, area); - let upper_left = upper_left!(area); - let bottom_right = bottom_right!(area); - - let total_cols = get_x(bottom_right) - get_x(upper_left); - let index_entity_width = (30 * total_cols) / 100; - let mid = get_x(bottom_right) - index_entity_width; - for i in get_y(upper_left)..=get_y(bottom_right) { - set_and_join_box(grid, (mid, i), BoxBoundary::Vertical); - } - - let left_menu_area = (upper_left, (set_x(bottom_right, mid - 1))); - let right_index_area = (set_x(upper_left, mid + 1), bottom_right); - - self.draw_menu(grid, left_menu_area, context); - self.entries[self.cursor[0]] - .index - .draw(grid, right_index_area, context); - - self.dirty = false; - context.dirty_areas.push_back(area); - } - - fn process_event(&mut self, event: &mut UIEvent, _context: &mut Context) -> bool { - if !self.entries[self.cursor[0]] - .index - .process_event(event, _context) - { - for i in 0..self.entries.len() { - if i == self.cursor[0] { - continue; - } - self.entries[i].index.process_event(event, _context); - } - } - - match *event { - UIEvent::ChangeMode(UIMode::Normal) => { - self.dirty = true; - } - UIEvent::Resize => { - self.dirty = true; - } - _ => {} - } - false - } - - fn is_dirty(&self) -> bool { - self.dirty - } - - fn set_dirty(&mut self, value: bool) { - self.dirty = value; - } - - fn id(&self) -> ComponentId { - self.id - } - fn set_id(&mut self, id: ComponentId) { - self.id = id; - } -} diff --git a/ui/src/components/indexer/index.rs b/ui/src/components/indexer/index.rs deleted file mode 100644 index 731e5361..00000000 --- a/ui/src/components/indexer/index.rs +++ /dev/null @@ -1,185 +0,0 @@ -use super::*; - -pub trait IndexContent: Component { - /* Handles the drawing of one entry */ - fn make_entry(&mut self, idx: usize) -> (); - - /* Handles what happens when the user selects an entry in the index listing */ - fn enter_entry(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) -> (); - - /* Refreshes content */ - fn refresh(&mut self, context: &mut Context) -> (); - - fn search(&self, term: &str) -> Option; -} - -#[derive(Debug, PartialEq)] -enum IndexState { - //Uninitialized, - Listing, - Unfocused, - //Search, -} - -#[derive(Debug)] -pub struct Index { - cursor_pos: usize, - new_cursor_pos: usize, - length: usize, - - /// Cache current view. - canvas: CellBuffer, - /// If we must redraw on next redraw event - dirty: bool, - state: IndexState, - - content: Box, - id: ComponentId, -} - -impl Index { - fn highlight_line(&self, grid: &mut CellBuffer, area: Area, idx: usize) { - let fg_color = Color::Default; - let bg_color = if self.cursor_pos == idx { - Color::Byte(246) - /* } else if idx % 2 == 0 { - Color::Byte(236)*/ - } else { - Color::Default - }; - change_colors(grid, area, fg_color, bg_color); - } -} - -impl Component for Index { - fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { - if !self.dirty { - return; - } - - match self.state { - IndexState::Listing => { - /* rehighlight entries, redraw pages */ - let upper_left = upper_left!(area); - let bottom_right = bottom_right!(area); - let rows = get_y(bottom_right) - get_y(upper_left) + 1; - let prev_page_no = (self.cursor_pos).wrapping_div(rows); - let page_no = (self.new_cursor_pos).wrapping_div(rows); - - let top_idx = page_no * rows; - if self.new_cursor_pos >= self.length { - self.new_cursor_pos = self.length - 1; - } - /* 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; - for idx in &[old_cursor_pos, self.new_cursor_pos] { - if *idx >= self.length { - continue; //bounds check - } - let new_area = ( - set_y(upper_left, get_y(upper_left) + (*idx % rows)), - set_y(bottom_right, get_y(upper_left) + (*idx % rows)), - ); - self.highlight_line(grid, new_area, *idx); - context.dirty_areas.push_back(new_area); - } - return; - } else if self.cursor_pos != self.new_cursor_pos { - self.cursor_pos = self.new_cursor_pos; - } - - /* Page_no has changed, so draw new page */ - copy_area( - grid, - &self.canvas, - area, - ((0, top_idx), (500 - 1, self.length)), - ); - self.highlight_line( - grid, - ( - ( - get_x(upper_left), - get_y(upper_left) + (self.cursor_pos % rows), - ), - ( - get_x(bottom_right), - get_y(upper_left) + (self.cursor_pos % rows), - ), - ), - self.cursor_pos, - ); - context.dirty_areas.push_back(area); - } - IndexState::Unfocused => { - self.content.draw(grid, area, context); - } - } - - self.dirty = false; - return; - } - - fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool { - if self.content.process_event(event, context) { - return true; - } - match *event { - UIEvent::Input(Key::Up) => { - if self.cursor_pos > 0 { - self.new_cursor_pos = self.new_cursor_pos.saturating_sub(1); - self.set_dirty(true); - } - return true; - } - UIEvent::Input(Key::Down) => { - if self.length > 0 && self.new_cursor_pos < self.length - 1 { - self.new_cursor_pos += 1; - self.set_dirty(true); - } - return true; - } - UIEvent::Input(Key::Char('\n')) if self.state == IndexState::Listing => { - self.state = IndexState::Unfocused; - self.set_dirty(true); - return true; - } - UIEvent::Input(Key::Char('i')) if self.state == IndexState::Unfocused => { - self.state = IndexState::Listing; - self.set_dirty(true); - return true; - } - UIEvent::ChangeMode(UIMode::Normal) => { - self.set_dirty(true); - } - UIEvent::Resize => { - self.set_dirty(true); - } - _ => {} - } - - false - } - fn is_dirty(&self) -> bool { - self.dirty || self.content.is_dirty() - } - fn set_dirty(&mut self, value: bool) { - self.dirty = value; - } - - fn id(&self) -> ComponentId { - self.id - } - fn set_id(&mut self, id: ComponentId) { - self.id = id; - } -} - -impl fmt::Display for Index { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - Display::fmt(&self.content, f) - } -} diff --git a/ui/src/sample-plugin.py b/ui/src/sample-plugin.py deleted file mode 100755 index 58d3e553..00000000 --- a/ui/src/sample-plugin.py +++ /dev/null @@ -1,133 +0,0 @@ -#! /usr/bin/env python3 -""" -meli - sample plugin - -Copyright 2019 Manos Pitsidianakis - -This file is part of meli. - -meli is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -meli is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with meli. If not, see . -""" - -import msgpack -import socket -import time -import struct -import json -import sys - - -class IPCError(Exception): - pass - -class UnknownMessageClass(IPCError): - pass - -class InvalidSerialization(IPCError): - pass - -class ConnectionClosed(IPCError): - pass - - -def _read_objects(sock): - unpacker = msgpack.Unpacker() - ret = [] - #reader = socket.socket.makefile(sock, 'rb') - while True: - try: - buf = sock.recv(1024**2) - if not buf: - break - unpacker.feed(buf) - for o in unpacker: - ret.append(o) - except: - break - return ret - - #try: - # for unpack in unpacker: - # return unpack - #except Exception as e: - # print("_read_objects error ", e, file=sys.stderr,) - # return None - #finally: - # reader.flush() - -def _write_objects(sock, objects): - data = msgpack.packb(objects) - sock.sendall(data) - -def _recursive_subclasses(cls): - classmap = {} - for subcls in cls.__subclasses__(): - classmap[subcls.__name__] = subcls - classmap.update(_recursive_subclasses(subcls)) - return classmap - - -class Client(object): - def __init__(self, server_address): - self.addr = server_address - if isinstance(self.addr, str): - address_family = socket.AF_UNIX - else: - address_family = socket.AF_INET - self.sock = socket.socket(address_family, socket.SOCK_STREAM) - self.sock.setblocking(0) - - def connect(self): - try: - self.sock.connect(self.addr) - print("connected", file=sys.stderr) - except socket.error as msg: - print(msg,file=sys.stderr, ) - sys.exit(1) - - def close(self): - self.sock.close() - - def __enter__(self): - self.connect() - return self - - def __exit__(self, exc_type, exc_value, traceback): - self.close() - - def send(self, objects): - _write_objects(self.sock, objects) - print("wrote object ", objects, file=sys.stderr) - return self.read() - - def read(self): - return _read_objects(self.sock) - -if __name__ == "__main__": - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - server_address = './soworkfile' - client = Client(server_address) - client.connect() - client.send({ "version": "dev" }) - counter = 0 - try: - while True: - message = "This is the message. And this is the well {}.".format(counter) - counter += 1 - time.sleep(0.05) - print('sending {!r}'.format(message),file=sys.stderr, ) - print('returned :', client.send(message), file=sys.stderr,) - except Exception as msg: - print(msg, file=sys.stderr,) -