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.
memfd
Manos Pitsidianakis 2020-02-04 15:52:12 +02:00
parent 6fcc792b83
commit 8b6ea8de9a
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
69 changed files with 320 additions and 892 deletions

62
Cargo.lock generated
View File

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

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

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

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 = "*" }

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

View File

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

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

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

View File

@ -1,5 +1,5 @@
/*
* meli - ui crate.
* meli
*
* Copyright 2017-2018 Manos Pitsidianakis
*
@ -19,10 +19,10 @@
* 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::*;

View File

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

View File

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

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 =

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

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

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;

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

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;

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

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

View File

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

View File

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

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

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;

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

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

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

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

View File

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

View File

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

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

View File

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

View File

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

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;

View File

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

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 {

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

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"

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

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 {

View File

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

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 = []

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

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

View File

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