Browse Source

Remove ui crate

Merge ui crate with root crate.

In preparation for uploading `meli` as a separate crate on crates.io.

Workspace crates will need to be published as well and having a separate
`ui` crate and binary perhaps doesn't make sense anymore.
tags/alpha-0.6.0
Manos Pitsidianakis 6 months ago
parent
commit
8b6ea8de9a
WARNING! Although there is a key with this ID in the database it does not verify this commit! This commit is SUSPICIOUS. GPG Key ID: 73627C2F690DF710
69 changed files with 320 additions and 892 deletions
  1. +21
    -41
      Cargo.lock
  2. +29
    -6
      Cargo.toml
  3. +6
    -5
      Makefile
  4. +0
    -17
      debug_printer/Cargo.toml
  5. +0
    -44
      debug_printer/src/lib.rs
  6. +1
    -1
      melib/src/email/list_management.rs
  7. +64
    -19
      src/bin.rs
  8. +13
    -2
      src/cache.rs
  9. +6
    -9
      src/components.rs
  10. +0
    -0
      src/components/contacts.rs
  11. +0
    -0
      src/components/contacts/contact_list.rs
  12. +1
    -1
      src/components/mail.rs
  13. +1
    -1
      src/components/mail/compose.rs
  14. +2
    -1
      src/components/mail/listing.rs
  15. +1
    -1
      src/components/mail/listing/compact.rs
  16. +1
    -1
      src/components/mail/listing/conversations.rs
  17. +1
    -1
      src/components/mail/listing/plain.rs
  18. +1
    -1
      src/components/mail/listing/thread.rs
  19. +1
    -1
      src/components/mail/pgp.rs
  20. +0
    -0
      src/components/mail/status.rs
  21. +1
    -1
      src/components/mail/view.rs
  22. +1
    -1
      src/components/mail/view/envelope.rs
  23. +1
    -1
      src/components/mail/view/html.rs
  24. +1
    -1
      src/components/mail/view/thread.rs
  25. +1
    -1
      src/components/notifications.rs
  26. +1
    -1
      src/components/utilities.rs
  27. +1
    -1
      src/components/utilities/widgets.rs
  28. +8
    -1
      src/conf.rs
  29. +3
    -4
      src/conf/accounts.rs
  30. +2
    -0
      src/conf/composing.rs
  31. +0
    -0
      src/conf/listing.rs
  32. +0
    -0
      src/conf/notifications.rs
  33. +2
    -0
      src/conf/pager.rs
  34. +0
    -0
      src/conf/pgp.rs
  35. +0
    -0
      src/conf/shortcuts.rs
  36. +2
    -0
      src/conf/tags.rs
  37. +2
    -0
      src/conf/terminal.rs
  38. +12
    -0
      src/conf/themes.rs
  39. +2
    -2
      src/execute.rs
  40. +1
    -1
      src/execute/actions.rs
  41. +1
    -1
      src/execute/history.rs
  42. +3
    -0
      src/mailcap.rs
  43. +2
    -0
      src/plugins.rs
  44. +0
    -0
      src/plugins/backend.rs
  45. +0
    -0
      src/plugins/python3/ansi-plugin.py
  46. +0
    -0
      src/plugins/python3/libmeliapi.py
  47. +0
    -0
      src/plugins/python3/nntp-backend.py
  48. +0
    -0
      src/plugins/rpc.rs
  49. +3
    -12
      src/sqlite3.rs
  50. +11
    -1
      src/state.rs
  51. +4
    -1
      src/terminal.rs
  52. +26
    -27
      src/terminal/cells.rs
  53. +1
    -1
      src/terminal/embed.rs
  54. +1
    -1
      src/terminal/embed/grid.rs
  55. +8
    -2
      src/terminal/keys.rs
  56. +1
    -1
      src/terminal/position.rs
  57. +1
    -1
      src/terminal/text_editing.rs
  58. +13
    -1
      src/types.rs
  59. +1
    -1
      src/types/helpers.rs
  60. +23
    -166
      src/unix.rs
  61. +3
    -1
      src/workers.rs
  62. +0
    -3
      testing/Cargo.toml
  63. +19
    -10
      testing/src/email_parse.rs
  64. +9
    -0
      testing/src/imap_conn.rs
  65. +0
    -2
      tests/generating_email.rs
  66. +0
    -41
      ui/Cargo.toml
  67. +0
    -134
      ui/src/components/indexer.rs
  68. +0
    -185
      ui/src/components/indexer/index.rs
  69. +0
    -133
      ui/src/sample-plugin.py

+ 21
- 41
Cargo.lock View File

@@ -237,15 +237,6 @@ dependencies = [
]

[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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]]
@@ -1840,37 +1851,6 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"


+ 29
- 6
Cargo.toml View File

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

+ 6
- 5
Makefile View File

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


+ 0
- 17
debug_printer/Cargo.toml View File

@@ -1,17 +0,0 @@
[package]
name = "debug_printer"
version = "0.0.1" #:version
authors = ["Manos Pitsidianakis <el13635@mail.ntua.gr>"]
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 = "*" }

+ 0
- 44
debug_printer/src/lib.rs View File

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

+ 1
- 1
melib/src/email/list_management.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2019 Manos Pitsidianakis
*


+ 64
- 19
src/bin.rs View File

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


ui/src/cache.rs → src/cache.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*
@@ -19,6 +19,8 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

/*! 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<str> {
if w.contains('"') {
Cow::from(w.replace('"', "\"\""))
} else {
Cow::from(w)
}
}

ui/src/components.rs → src/components.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*
@@ -19,11 +19,11 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

/*!
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::*;


ui/src/components/contacts.rs → src/components/contacts.rs View File


ui/src/components/contacts/contact_list.rs → src/components/contacts/contact_list.rs View File


ui/src/components/mail.rs → src/components/mail.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/mail/compose.rs → src/components/mail/compose.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/mail/listing.rs → src/components/mail/listing.rs View File

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

ui/src/components/mail/listing/compact.rs → src/components/mail/listing/compact.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/mail/listing/conversations.rs → src/components/mail/listing/conversations.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/mail/listing/plain.rs → src/components/mail/listing/plain.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/mail/listing/thread.rs → src/components/mail/listing/thread.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/mail/pgp.rs → src/components/mail/pgp.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2019 Manos Pitsidianakis
*

ui/src/components/mail/status.rs → src/components/mail/status.rs View File


ui/src/components/mail/view.rs → src/components/mail/view.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/mail/view/envelope.rs → src/components/mail/view/envelope.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/mail/view/html.rs → src/components/mail/view/html.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/mail/view/thread.rs → src/components/mail/view/thread.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/notifications.rs → src/components/notifications.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/utilities.rs → src/components/utilities.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/components/utilities/widgets.rs → src/components/utilities/widgets.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2020 Manos Pitsidianakis
*

ui/src/conf.rs → src/conf.rs View File

@@ -19,6 +19,8 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

/*! 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<String> {
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<P: AsRef<Path>>(path: P) -> Result<String> {
let p_buf: PathBuf = if path.as_ref().is_relative() {
path.as_ref().canonicalize()?

ui/src/conf/accounts.rs → src/conf/accounts.rs View File

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

ui/src/conf/composing.rs → src/conf/composing.rs View File

@@ -18,6 +18,8 @@
* You should have received a copy of the GNU General Public License
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

//! Configuration for composing email.
use super::default_vals::{false_val, none, true_val};

/// Settings for writing and sending new e-mail

ui/src/conf/listing.rs → src/conf/listing.rs View File


ui/src/conf/notifications.rs → src/conf/notifications.rs View File


ui/src/conf/pager.rs → src/conf/pager.rs View File

@@ -19,6 +19,8 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

//! Settings for the pager function.

use super::default_vals::*;
use super::deserializers::*;
use melib::ToggleFlag;

ui/src/conf/pgp.rs → src/conf/pgp.rs View File


ui/src/conf/shortcuts.rs → src/conf/shortcuts.rs View File


ui/src/conf/tags.rs → src/conf/tags.rs View File

@@ -19,6 +19,8 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

//! E-mail tag configuration and {de,}serializing.

use crate::terminal::Color;
use serde::{Deserialize, Deserializer};
use std::collections::{hash_map::DefaultHasher, HashMap, HashSet};

ui/src/conf/terminal.rs → src/conf/terminal.rs View File

@@ -19,6 +19,8 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

//! Settings for terminal display

use super::deserializers::non_empty_string;
use super::Theme;
use super::ToggleFlag;

ui/src/conf/themes.rs → src/conf/themes.rs View File

@@ -19,6 +19,15 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

//! Application themes.
//!
//! * An attribute is a triple of foreground color, background color and terminal attribute `ThemeValue`s.
//! * A `ThemeValue<T>` 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<T> {
Value(T),
Link(Cow<'static, str>),

ui/src/execute.rs → src/execute.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*
@@ -19,7 +19,7 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

/*! 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};

ui/src/execute/actions.rs → src/execute/actions.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/execute/history.rs → src/execute/history.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2019 Manos Pitsidianakis
*

ui/src/mailcap.rs → src/mailcap.rs View File

@@ -18,6 +18,9 @@
* You should have received a copy of the GNU General Public License
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

/*! Find mailcap entries to execute attachments.
*/
use crate::split_command;
use crate::state::Context;
use crate::types::{create_temp_file, ForkType, UIEvent};

ui/src/plugins.rs → src/plugins.rs View File

@@ -19,6 +19,8 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

/*! 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;

ui/src/plugins/backend.rs → src/plugins/backend.rs View File


ui/src/plugins/python3/ansi-plugin.py → src/plugins/python3/ansi-plugin.py View File


ui/src/plugins/python3/libmeliapi.py → src/plugins/python3/libmeliapi.py View File


ui/src/plugins/python3/nntp-backend.py → src/plugins/python3/nntp-backend.py View File


ui/src/plugins/rpc.rs → src/plugins/rpc.rs View File


ui/src/sqlite3.rs → src/sqlite3.rs View File

@@ -19,9 +19,10 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

/*! 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<str> {
if w.contains('"') {
Cow::from(w.replace('"', "\"\""))
} else {
Cow::from(w)
}
}

pub fn db_path() -> Result<PathBuf> {
let data_dir =
xdg::BaseDirectories::with_prefix("meli").map_err(|e| MeliError::new(e.to_string()))?;

ui/src/state.rs → src/state.rs View File

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

ui/src/terminal.rs → src/terminal.rs View File

@@ -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 <http://www.gnu.org/licenses/>.
*/

/*! Terminal grid cells, keys, colors, etc.
*/
extern crate serde;
use self::serde::de::Visitor;
use self::serde::{de, Deserialize, Deserializer};

ui/src/terminal/cells.rs → src/terminal/cells.rs View File

@@ -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<Cell>,
/// 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');

ui/src/terminal/embed.rs → src/terminal/embed.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2020 Manos Pitsidianakis
*

ui/src/terminal/embed/grid.rs → src/terminal/embed/grid.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2020 Manos Pitsidianakis
*

ui/src/terminal/keys.rs → src/terminal/keys.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*
@@ -135,6 +135,7 @@ impl PartialEq<Key> 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<u8>)),
@@ -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<u8>)),

ui/src/terminal/position.rs → src/terminal/position.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/terminal/text_editing.rs → src/terminal/text_editing.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2020 Manos Pitsidianakis
*

ui/src/types.rs → src/types.rs View File

@@ -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 <http://www.gnu.org/licenses/>.
*/

/*! 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;

ui/src/types/helpers.rs → src/types/helpers.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*

ui/src/lib.rs → src/unix.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*
@@ -19,177 +19,29 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

/*!
* 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 {

ui/src/workers.rs → src/workers.rs View File

@@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2020 Manos Pitsidianakis
*
@@ -19,6 +19,8 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>.
*/

/*! Simple blocking job control.
*/
use crate::types::ThreadEvent;
use crossbeam::{
channel::{bounded, unbounded, Sender},

+ 0
- 3
testing/Cargo.toml View File

@@ -8,9 +8,6 @@ edition = "2018"
[[bin]]
name = "emailparse"
path = "src/email_parse.rs"
[[bin]]
name = "linebreak"
path = "src/linebreak.rs"

[[bin]]
name = "imapconn"


+ 19
- 10
testing/src/email_parse.rs View File

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


+ 9
- 0
testing/src/imap_conn.rs View File

@@ -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::<Vec<String>>();
if args.len() != 4 {


+ 0
- 2
tests/generating_email.rs View File

@@ -1,6 +1,4 @@
use melib;
use ui::xdg_utils;

use melib::email::Draft;
use xdg_utils::query_mime_info;



+ 0
- 41
ui/Cargo.toml View File

@@ -1,41 +0,0 @@
[package]
name = "ui"
version = "0.4.1"
authors = ["Manos Pitsidianakis <el13635@mail.ntua.gr>"]
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 = []

+ 0
- 134
ui/src/components/indexer.rs View File

@@ -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 <http://www.gnu.org/licenses/>.
*/

/*! Entities that handle Mail specific functions.
*/
use super::*;

pub mod index;
pub use self::index::*;

#[derive(Debug)]
struct MenuEntry {
name: String,
subentries: Vec<MenuEntry>,
index: Index,
}

#[derive(Debug)]
pub struct Indexer {
entries: Vec<MenuEntry>,
dirty: bool,
cursor: Vec<usize>,
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;
}
}

+ 0
- 185
ui/src/components/indexer/index.rs View File

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

#[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<dyn IndexContent>,
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)
}
}

+ 0
- 133
ui/src/sample-plugin.py View File

@@ -1,133 +0,0 @@
#! /usr/bin/env python3
"""
meli - sample plugin