Add {Timer,Component}Id wrapper types over Uuid
parent
4da5366959
commit
96537e48c5
|
@ -19,16 +19,14 @@
|
||||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
//! User actions that need to be handled by the UI
|
||||||
* User actions that need to be handled by the UI
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use melib::email::mailto::Mailto;
|
||||||
pub use melib::thread::{SortField, SortOrder};
|
pub use melib::thread::{SortField, SortOrder};
|
||||||
use melib::{email::mailto::Mailto, uuid::Uuid};
|
|
||||||
|
|
||||||
use crate::components::Component;
|
use crate::components::{Component, ComponentId};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TagAction {
|
pub enum TagAction {
|
||||||
|
@ -61,7 +59,7 @@ pub enum ListingAction {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TabAction {
|
pub enum TabAction {
|
||||||
Close,
|
Close,
|
||||||
Kill(Uuid),
|
Kill(ComponentId),
|
||||||
New(Option<Box<dyn Component>>),
|
New(Option<Box<dyn Component>>),
|
||||||
ManageMailboxes,
|
ManageMailboxes,
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,9 @@
|
||||||
/*! Components visual and logical separations of application interfaces.
|
/*! Components visual and logical separations of application interfaces.
|
||||||
*
|
*
|
||||||
* They can draw on the terminal and receive events, but also do other stuff
|
* They can draw on the terminal and receive events, but also do other stuff
|
||||||
* as well. (For example, see the `notifications` module.)
|
* as well.
|
||||||
* See the `Component` Trait for more details.
|
* For an example, see the [`notifications`] module.
|
||||||
|
* See also the [`Component`] trait for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -57,7 +58,46 @@ use std::{
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
pub type ComponentId = Uuid;
|
#[derive(Clone, Copy, Eq, Deserialize, Hash, Ord, PartialOrd, PartialEq, Serialize)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct ComponentId(Uuid);
|
||||||
|
|
||||||
|
impl AsRef<Uuid> for ComponentId {
|
||||||
|
fn as_ref(&self) -> &Uuid {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ComponentId {
|
||||||
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(&self.0.as_simple(), fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for ComponentId {
|
||||||
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(&self.0.as_simple(), fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ComponentId {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(Uuid::new_v4())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::LowerHex for ComponentId {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::LowerHex::fmt(self.0.as_hyphenated(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::UpperHex for ComponentId {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::UpperHex::fmt(self.0.as_hyphenated(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type ShortcutMap = IndexMap<&'static str, Key>;
|
pub type ShortcutMap = IndexMap<&'static str, Key>;
|
||||||
pub type ShortcutMaps = IndexMap<&'static str, ShortcutMap>;
|
pub type ShortcutMaps = IndexMap<&'static str, ShortcutMap>;
|
||||||
|
@ -92,28 +132,37 @@ pub enum ScrollUpdate {
|
||||||
|
|
||||||
/// Types implementing this Trait can draw on the terminal and receive events.
|
/// Types implementing this Trait can draw on the terminal and receive events.
|
||||||
/// If a type wants to skip drawing if it has not changed anything, it can hold
|
/// If a type wants to skip drawing if it has not changed anything, it can hold
|
||||||
/// some flag in its fields (eg self.dirty = false) and act upon that in their
|
/// some flag in its fields (eg `self.dirty = false`) and act upon that in their
|
||||||
/// `draw` implementation.
|
/// [`draw`](Component::draw) implementation.
|
||||||
pub trait Component: Display + Debug + Send + Sync {
|
pub trait Component: Display + Debug + Send + Sync {
|
||||||
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context);
|
fn draw(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context);
|
||||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool;
|
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool;
|
||||||
fn is_dirty(&self) -> bool;
|
fn is_dirty(&self) -> bool;
|
||||||
|
/// If the component is meant to be currently visible to the user.
|
||||||
fn is_visible(&self) -> bool {
|
fn is_visible(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the component can quit right away without any unsaved or ongoing
|
||||||
|
/// operations.
|
||||||
fn can_quit_cleanly(&mut self, _context: &Context) -> bool {
|
fn can_quit_cleanly(&mut self, _context: &Context) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_dirty(&mut self, value: bool);
|
fn set_dirty(&mut self, value: bool);
|
||||||
|
|
||||||
fn kill(&mut self, _id: ComponentId, _context: &mut Context) {}
|
fn kill(&mut self, _id: ComponentId, _context: &mut Context) {}
|
||||||
|
|
||||||
fn set_id(&mut self, _id: ComponentId) {}
|
fn set_id(&mut self, _id: ComponentId) {}
|
||||||
|
|
||||||
fn id(&self) -> ComponentId;
|
fn id(&self) -> ComponentId;
|
||||||
|
|
||||||
fn get_shortcuts(&self, _context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, _context: &Context) -> ShortcutMaps {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_status(&self, _context: &Context) -> String {
|
/// Get status message for the status line.
|
||||||
|
fn status(&self, _context: &Context) -> String {
|
||||||
String::new()
|
String::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ enum ViewMode {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ContactManager {
|
pub struct ContactManager {
|
||||||
id: ComponentId,
|
id: ComponentId,
|
||||||
parent_id: ComponentId,
|
parent_id: Option<ComponentId>,
|
||||||
pub card: Card,
|
pub card: Card,
|
||||||
mode: ViewMode,
|
mode: ViewMode,
|
||||||
form: FormWidget<bool>,
|
form: FormWidget<bool>,
|
||||||
|
@ -63,8 +63,8 @@ impl ContactManager {
|
||||||
fn new(context: &Context) -> Self {
|
fn new(context: &Context) -> Self {
|
||||||
let theme_default: ThemeAttribute = crate::conf::value(context, "theme_default");
|
let theme_default: ThemeAttribute = crate::conf::value(context, "theme_default");
|
||||||
ContactManager {
|
ContactManager {
|
||||||
id: Uuid::nil(),
|
id: ComponentId::default(),
|
||||||
parent_id: Uuid::nil(),
|
parent_id: None,
|
||||||
card: Card::new(),
|
card: Card::new(),
|
||||||
mode: ViewMode::Edit,
|
mode: ViewMode::Edit,
|
||||||
form: FormWidget::default(),
|
form: FormWidget::default(),
|
||||||
|
@ -135,7 +135,7 @@ impl ContactManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_parent_id(&mut self, new_val: ComponentId) {
|
pub fn set_parent_id(&mut self, new_val: ComponentId) {
|
||||||
self.parent_id = new_val;
|
self.parent_id = Some(new_val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,11 +188,11 @@ impl Component for ContactManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ViewMode::Edit => {
|
ViewMode::Edit => {
|
||||||
if let &mut UIEvent::Input(Key::Esc) = event {
|
if let (Some(parent_id), &UIEvent::Input(Key::Esc)) = (self.parent_id, &event) {
|
||||||
if self.can_quit_cleanly(context) {
|
if self.can_quit_cleanly(context) {
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::Action(Tab(Kill(self.parent_id))));
|
.push_back(UIEvent::Action(Tab(Kill(parent_id))));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ impl Component for ContactManager {
|
||||||
s.to_string(),
|
s.to_string(),
|
||||||
match v {
|
match v {
|
||||||
Field::Text(v) => v.as_str().to_string(),
|
Field::Text(v) => v.as_str().to_string(),
|
||||||
Field::Choice(mut v, c) => v.remove(c).to_string(),
|
Field::Choice(mut v, c, _) => v.remove(c).to_string(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -277,25 +277,28 @@ impl Component for ContactManager {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let parent_id = self.parent_id;
|
if let Some(parent_id) = self.parent_id {
|
||||||
/* Play it safe and ask user for confirmation */
|
/* Play it safe and ask user for confirmation */
|
||||||
self.mode = ViewMode::Discard(Box::new(UIDialog::new(
|
self.mode = ViewMode::Discard(Box::new(UIDialog::new(
|
||||||
"this contact has unsaved changes",
|
"this contact has unsaved changes",
|
||||||
vec![
|
vec![
|
||||||
('x', "quit without saving".to_string()),
|
('x', "quit without saving".to_string()),
|
||||||
('y', "save draft and quit".to_string()),
|
('y', "save draft and quit".to_string()),
|
||||||
('n', "cancel".to_string()),
|
('n', "cancel".to_string()),
|
||||||
],
|
],
|
||||||
true,
|
true,
|
||||||
Some(Box::new(move |_, results: &[char]| match results[0] {
|
Some(Box::new(move |_, results: &[char]| match results[0] {
|
||||||
'x' => Some(UIEvent::Action(Tab(Kill(parent_id)))),
|
'x' => Some(UIEvent::Action(Tab(Kill(parent_id)))),
|
||||||
'n' => None,
|
'n' => None,
|
||||||
'y' => None,
|
'y' => None,
|
||||||
_ => None,
|
_ => None,
|
||||||
})),
|
})),
|
||||||
context,
|
context,
|
||||||
)));
|
)));
|
||||||
self.set_dirty(true);
|
self.set_dirty(true);
|
||||||
false
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ impl ContactList {
|
||||||
sidebar_divider: context.settings.listing.sidebar_divider,
|
sidebar_divider: context.settings.listing.sidebar_divider,
|
||||||
sidebar_divider_theme: conf::value(context, "mail.sidebar_divider"),
|
sidebar_divider_theme: conf::value(context, "mail.sidebar_divider"),
|
||||||
menu_visibility: true,
|
menu_visibility: true,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,7 +631,7 @@ impl Component for ContactList {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
if self.view.is_none() {
|
if self.view.is_none() {
|
||||||
match *event {
|
match *event {
|
||||||
UIEvent::Input(ref key)
|
UIEvent::Input(ref key)
|
||||||
|
@ -724,7 +724,7 @@ impl Component for ContactList {
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||||
self.get_status(context),
|
self.status(context),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,7 +761,7 @@ impl Component for ContactList {
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||||
self.get_status(context),
|
self.status(context),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -928,15 +928,15 @@ impl Component for ContactList {
|
||||||
self.dirty = value;
|
self.dirty = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kill(&mut self, uuid: Uuid, context: &mut Context) {
|
fn kill(&mut self, uuid: ComponentId, context: &mut Context) {
|
||||||
debug_assert!(uuid == self.id);
|
debug_assert!(uuid == self.id);
|
||||||
context.replies.push_back(UIEvent::Action(Tab(Kill(uuid))));
|
context.replies.push_back(UIEvent::Action(Tab(Kill(uuid))));
|
||||||
}
|
}
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = self
|
let mut map = self
|
||||||
.view
|
.view
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|p| p.get_shortcuts(context))
|
.map(|p| p.shortcuts(context))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
map.insert(
|
map.insert(
|
||||||
|
@ -966,7 +966,7 @@ impl Component for ContactList {
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_status(&self, context: &Context) -> String {
|
fn status(&self, context: &Context) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} entries",
|
"{} entries",
|
||||||
context.accounts[self.account_pos].address_book.len()
|
context.accounts[self.account_pos].address_book.len()
|
||||||
|
|
|
@ -113,7 +113,7 @@ pub struct Composer {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ViewMode {
|
enum ViewMode {
|
||||||
Discard(Uuid, UIDialog<char>),
|
Discard(ComponentId, UIDialog<char>),
|
||||||
EditAttachments {
|
EditAttachments {
|
||||||
widget: EditAttachments,
|
widget: EditAttachments,
|
||||||
},
|
},
|
||||||
|
@ -175,7 +175,7 @@ impl Composer {
|
||||||
embed_area: ((0, 0), (0, 0)),
|
embed_area: ((0, 0), (0, 0)),
|
||||||
embed: None,
|
embed: None,
|
||||||
initialized: false,
|
initialized: false,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1122,7 +1122,7 @@ impl Component for Composer {
|
||||||
if let UIEvent::VisibilityChange(_) = event {
|
if let UIEvent::VisibilityChange(_) = event {
|
||||||
self.pager.process_event(event, context);
|
self.pager.process_event(event, context);
|
||||||
}
|
}
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
match (&mut self.mode, &mut event) {
|
match (&mut self.mode, &mut event) {
|
||||||
(ViewMode::Edit, _) => {
|
(ViewMode::Edit, _) => {
|
||||||
if self.pager.process_event(event, context) {
|
if self.pager.process_event(event, context) {
|
||||||
|
@ -2090,7 +2090,7 @@ impl Component for Composer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kill(&mut self, uuid: Uuid, context: &mut Context) {
|
fn kill(&mut self, uuid: ComponentId, context: &mut Context) {
|
||||||
if self.id != uuid {
|
if self.id != uuid {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2121,9 +2121,9 @@ impl Component for Composer {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = if self.mode.is_edit() {
|
let mut map = if self.mode.is_edit() {
|
||||||
self.pager.get_shortcuts(context)
|
self.pager.shortcuts(context)
|
||||||
} else {
|
} else {
|
||||||
Default::default()
|
Default::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl EditAttachments {
|
||||||
buttons,
|
buttons,
|
||||||
cursor: EditAttachmentCursor::Buttons,
|
cursor: EditAttachmentCursor::Buttons,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,9 +291,9 @@ impl Component for EditAttachmentsRefMut<'_, '_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kill(&mut self, _uuid: Uuid, _context: &mut Context) {}
|
fn kill(&mut self, _uuid: ComponentId, _context: &mut Context) {}
|
||||||
|
|
||||||
fn get_shortcuts(&self, _context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, _context: &Context) -> ShortcutMaps {
|
||||||
ShortcutMaps::default()
|
ShortcutMaps::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,7 @@ impl Component for KeySelection {
|
||||||
Ok(Some(Err(err))) => {
|
Ok(Some(Err(err))) => {
|
||||||
*self = KeySelection::Error {
|
*self = KeySelection::Error {
|
||||||
err,
|
err,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,14 +229,14 @@ impl Component for KeySelection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kill(&mut self, _uuid: Uuid, _context: &mut Context) {}
|
fn kill(&mut self, _uuid: ComponentId, _context: &mut Context) {}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
match self {
|
match self {
|
||||||
KeySelection::LoadingKeys { .. } | KeySelection::Error { .. } => {
|
KeySelection::LoadingKeys { .. } | KeySelection::Error { .. } => {
|
||||||
ShortcutMaps::default()
|
ShortcutMaps::default()
|
||||||
}
|
}
|
||||||
KeySelection::Loaded { ref widget, .. } => widget.get_shortcuts(context),
|
KeySelection::Loaded { ref widget, .. } => widget.shortcuts(context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1041,8 +1041,8 @@ impl Component for Listing {
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(match msg {
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(match msg {
|
||||||
Some(msg) => format!("{} {}", self.get_status(context), msg),
|
Some(msg) => format!("{} {}", self.status(context), msg),
|
||||||
None => self.get_status(context),
|
None => self.status(context),
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1105,7 +1105,7 @@ impl Component for Listing {
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||||
self.get_status(context),
|
self.status(context),
|
||||||
)));
|
)));
|
||||||
self.set_dirty(true);
|
self.set_dirty(true);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1149,7 +1149,7 @@ impl Component for Listing {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
if self.focus == ListingFocus::Mailbox {
|
if self.focus == ListingFocus::Mailbox {
|
||||||
match *event {
|
match *event {
|
||||||
UIEvent::Input(Key::Mouse(MouseEvent::Press(MouseButton::Left, x, _y)))
|
UIEvent::Input(Key::Mouse(MouseEvent::Press(MouseButton::Left, x, _y)))
|
||||||
|
@ -1634,7 +1634,7 @@ impl Component for Listing {
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||||
self.get_status(context),
|
self.status(context),
|
||||||
)));
|
)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1910,7 +1910,7 @@ impl Component for Listing {
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||||
self.get_status(context),
|
self.status(context),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
UIEvent::Input(Key::Backspace) if !self.cmd_buf.is_empty() => {
|
UIEvent::Input(Key::Backspace) if !self.cmd_buf.is_empty() => {
|
||||||
|
@ -1963,11 +1963,11 @@ impl Component for Listing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = if let Some(s) = self.status.as_ref() {
|
let mut map = if let Some(s) = self.status.as_ref() {
|
||||||
s.get_shortcuts(context)
|
s.shortcuts(context)
|
||||||
} else {
|
} else {
|
||||||
self.component.get_shortcuts(context)
|
self.component.shortcuts(context)
|
||||||
};
|
};
|
||||||
let mut config_map = context.settings.shortcuts.listing.key_values();
|
let mut config_map = context.settings.shortcuts.listing.key_values();
|
||||||
if self.focus != ListingFocus::Menu {
|
if self.focus != ListingFocus::Menu {
|
||||||
|
@ -1985,7 +1985,7 @@ impl Component for Listing {
|
||||||
self.component.set_id(id);
|
self.component.set_id(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_status(&self, context: &Context) -> String {
|
fn status(&self, context: &Context) -> String {
|
||||||
let mailbox_hash = match self.cursor_pos.1 {
|
let mailbox_hash = match self.cursor_pos.1 {
|
||||||
MenuEntryCursor::Mailbox(idx) => {
|
MenuEntryCursor::Mailbox(idx) => {
|
||||||
if let Some(MailboxMenuEntry { mailbox_hash, .. }) =
|
if let Some(MailboxMenuEntry { mailbox_hash, .. }) =
|
||||||
|
@ -2075,7 +2075,7 @@ impl Listing {
|
||||||
show_menu_scrollbar: ShowMenuScrollbar::Never,
|
show_menu_scrollbar: ShowMenuScrollbar::Never,
|
||||||
startup_checks_rate: RateLimit::new(2, 1000, context.job_executor.clone()),
|
startup_checks_rate: RateLimit::new(2, 1000, context.job_executor.clone()),
|
||||||
theme_default: conf::value(context, "theme_default"),
|
theme_default: conf::value(context, "theme_default"),
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
sidebar_divider: *account_settings!(
|
sidebar_divider: *account_settings!(
|
||||||
context[first_account_hash].listing.sidebar_divider
|
context[first_account_hash].listing.sidebar_divider
|
||||||
),
|
),
|
||||||
|
@ -2592,7 +2592,7 @@ impl Listing {
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||||
self.get_status(context),
|
self.status(context),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
MenuEntryCursor::Status => {
|
MenuEntryCursor::Status => {
|
||||||
|
@ -2618,7 +2618,7 @@ impl Listing {
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||||
self.get_status(context),
|
self.status(context),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -894,7 +894,7 @@ impl CompactListing {
|
||||||
movement: None,
|
movement: None,
|
||||||
modifier_active: false,
|
modifier_active: false,
|
||||||
modifier_command: None,
|
modifier_command: None,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1687,7 +1687,7 @@ impl Component for CompactListing {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
|
|
||||||
match (&event, self.focus) {
|
match (&event, self.focus) {
|
||||||
(UIEvent::Input(ref k), Focus::Entry)
|
(UIEvent::Input(ref k), Focus::Entry)
|
||||||
|
@ -2023,9 +2023,9 @@ impl Component for CompactListing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = if self.unfocused() {
|
let mut map = if self.unfocused() {
|
||||||
self.view.get_shortcuts(context)
|
self.view.shortcuts(context)
|
||||||
} else {
|
} else {
|
||||||
ShortcutMaps::default()
|
ShortcutMaps::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -636,7 +636,7 @@ impl ConversationsListing {
|
||||||
movement: None,
|
movement: None,
|
||||||
modifier_active: false,
|
modifier_active: false,
|
||||||
modifier_command: None,
|
modifier_command: None,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1234,7 +1234,7 @@ impl Component for ConversationsListing {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
|
|
||||||
match (&event, self.focus) {
|
match (&event, self.focus) {
|
||||||
(UIEvent::Input(ref k), Focus::Entry)
|
(UIEvent::Input(ref k), Focus::Entry)
|
||||||
|
@ -1545,9 +1545,9 @@ impl Component for ConversationsListing {
|
||||||
self.dirty = value;
|
self.dirty = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = if self.unfocused() {
|
let mut map = if self.unfocused() {
|
||||||
self.view.get_shortcuts(context)
|
self.view.shortcuts(context)
|
||||||
} else {
|
} else {
|
||||||
ShortcutMaps::default()
|
ShortcutMaps::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -117,7 +117,7 @@ impl OfflineListing {
|
||||||
_selection: HashMap::default(),
|
_selection: HashMap::default(),
|
||||||
messages: vec![],
|
messages: vec![],
|
||||||
dirty: true,
|
dirty: true,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -628,7 +628,7 @@ impl PlainListing {
|
||||||
movement: None,
|
movement: None,
|
||||||
modifier_active: false,
|
modifier_active: false,
|
||||||
modifier_command: None,
|
modifier_command: None,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1346,7 +1346,7 @@ impl Component for PlainListing {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
|
|
||||||
match (&event, self.focus) {
|
match (&event, self.focus) {
|
||||||
(UIEvent::Input(ref k), Focus::Entry)
|
(UIEvent::Input(ref k), Focus::Entry)
|
||||||
|
@ -1594,9 +1594,9 @@ impl Component for PlainListing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = if self.unfocused() {
|
let mut map = if self.unfocused() {
|
||||||
self.view.get_shortcuts(context)
|
self.view.shortcuts(context)
|
||||||
} else {
|
} else {
|
||||||
ShortcutMaps::default()
|
ShortcutMaps::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -696,7 +696,7 @@ impl ThreadListing {
|
||||||
movement: None,
|
movement: None,
|
||||||
modifier_active: false,
|
modifier_active: false,
|
||||||
modifier_command: None,
|
modifier_command: None,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
search_job: None,
|
search_job: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1316,7 +1316,7 @@ impl Component for ThreadListing {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
|
|
||||||
match (&event, self.focus) {
|
match (&event, self.focus) {
|
||||||
(UIEvent::Input(ref k), Focus::Entry)
|
(UIEvent::Input(ref k), Focus::Entry)
|
||||||
|
@ -1559,11 +1559,11 @@ impl Component for ThreadListing {
|
||||||
self.dirty = value;
|
self.dirty = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = if self.unfocused() {
|
let mut map = if self.unfocused() {
|
||||||
self.view
|
self.view
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|p| p.get_shortcuts(context))
|
.map(|p| p.shortcuts(context))
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
} else {
|
} else {
|
||||||
ShortcutMaps::default()
|
ShortcutMaps::default()
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl AccountStatus {
|
||||||
content,
|
content,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
theme_default,
|
theme_default,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -398,7 +398,7 @@ impl Component for AccountStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
match *event {
|
match *event {
|
||||||
UIEvent::ConfigReload { old_settings: _ } => {
|
UIEvent::ConfigReload { old_settings: _ } => {
|
||||||
self.theme_default = crate::conf::value(context, "theme_default");
|
self.theme_default = crate::conf::value(context, "theme_default");
|
||||||
|
@ -447,7 +447,7 @@ impl Component for AccountStatus {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut ret: ShortcutMaps = ShortcutMaps::default();
|
let mut ret: ShortcutMaps = ShortcutMaps::default();
|
||||||
ret.insert(
|
ret.insert(
|
||||||
Shortcuts::GENERAL,
|
Shortcuts::GENERAL,
|
||||||
|
|
|
@ -354,7 +354,7 @@ impl MailView {
|
||||||
state: MailViewState::default(),
|
state: MailViewState::default(),
|
||||||
force_charset: ForceCharset::None,
|
force_charset: ForceCharset::None,
|
||||||
cmd_buf: String::with_capacity(4),
|
cmd_buf: String::with_capacity(4),
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
ret.init_futures(context);
|
ret.init_futures(context);
|
||||||
|
@ -1789,7 +1789,7 @@ impl Component for MailView {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
match (&mut self.mode, &mut event) {
|
match (&mut self.mode, &mut event) {
|
||||||
/*(ViewMode::Ansi(ref mut buf), _) => {
|
/*(ViewMode::Ansi(ref mut buf), _) => {
|
||||||
if buf.process_event(event, context) {
|
if buf.process_event(event, context) {
|
||||||
|
@ -2015,7 +2015,7 @@ impl Component for MailView {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let shortcuts = &self.get_shortcuts(context);
|
let shortcuts = &self.shortcuts(context);
|
||||||
match *event {
|
match *event {
|
||||||
UIEvent::ConfigReload { old_settings: _ } => {
|
UIEvent::ConfigReload { old_settings: _ } => {
|
||||||
self.theme_default = crate::conf::value(context, "theme_default");
|
self.theme_default = crate::conf::value(context, "theme_default");
|
||||||
|
@ -2571,8 +2571,10 @@ impl Component for MailView {
|
||||||
if let Some(filename) = u.filename() {
|
if let Some(filename) = u.filename() {
|
||||||
path.push(filename);
|
path.push(filename);
|
||||||
} else {
|
} else {
|
||||||
let u = melib::uuid::Uuid::new_v4();
|
path.push(format!(
|
||||||
path.push(u.as_hyphenated().to_string());
|
"meli_attachment_{a_i}_{}",
|
||||||
|
Uuid::new_v4().as_simple()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match save_attachment(&path, &u.decode(Default::default())) {
|
match save_attachment(&path, &u.decode(Default::default())) {
|
||||||
|
@ -2874,11 +2876,11 @@ impl Component for MailView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = if let Some(ref sbv) = self.subview {
|
let mut map = if let Some(ref sbv) = self.subview {
|
||||||
sbv.get_shortcuts(context)
|
sbv.shortcuts(context)
|
||||||
} else {
|
} else {
|
||||||
self.pager.get_shortcuts(context)
|
self.pager.shortcuts(context)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut our_map = context.settings.shortcuts.envelope_view.key_values();
|
let mut our_map = context.settings.shortcuts.envelope_view.key_values();
|
||||||
|
|
|
@ -79,7 +79,7 @@ impl EnvelopeView {
|
||||||
mail,
|
mail,
|
||||||
_account_hash,
|
_account_hash,
|
||||||
cmd_buf: String::with_capacity(4),
|
cmd_buf: String::with_capacity(4),
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub struct HtmlView {
|
||||||
|
|
||||||
impl HtmlView {
|
impl HtmlView {
|
||||||
pub fn new(body: &Attachment, context: &mut Context) -> Self {
|
pub fn new(body: &Attachment, context: &mut Context) -> Self {
|
||||||
let id = ComponentId::new_v4();
|
let id = ComponentId::default();
|
||||||
let bytes: Vec<u8> = body.decode_rec(Default::default());
|
let bytes: Vec<u8> = body.decode_rec(Default::default());
|
||||||
|
|
||||||
let settings = &context.settings;
|
let settings = &context.settings;
|
||||||
|
@ -193,12 +193,15 @@ impl Component for HtmlView {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
|
||||||
self.pager.get_shortcuts(context)
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
|
self.pager.shortcuts(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_dirty(&self) -> bool {
|
fn is_dirty(&self) -> bool {
|
||||||
self.pager.is_dirty()
|
self.pager.is_dirty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_dirty(&mut self, value: bool) {
|
fn set_dirty(&mut self, value: bool) {
|
||||||
self.pager.set_dirty(value);
|
self.pager.set_dirty(value);
|
||||||
}
|
}
|
||||||
|
@ -206,6 +209,7 @@ impl Component for HtmlView {
|
||||||
fn id(&self) -> ComponentId {
|
fn id(&self) -> ComponentId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_id(&mut self, id: ComponentId) {
|
fn set_id(&mut self, id: ComponentId) {
|
||||||
self.id = id;
|
self.id = id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ impl ThreadView {
|
||||||
cursor_pos: 1,
|
cursor_pos: 1,
|
||||||
new_cursor_pos: 0,
|
new_cursor_pos: 0,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
indentation_colors: [
|
indentation_colors: [
|
||||||
crate::conf::value(context, "mail.view.thread.indentation.a"),
|
crate::conf::value(context, "mail.view.thread.indentation.a"),
|
||||||
crate::conf::value(context, "mail.view.thread.indentation.b"),
|
crate::conf::value(context, "mail.view.thread.indentation.b"),
|
||||||
|
@ -1002,7 +1002,7 @@ impl Component for ThreadView {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
match *event {
|
match *event {
|
||||||
UIEvent::Input(ref key)
|
UIEvent::Input(ref key)
|
||||||
if shortcut!(key == shortcuts[Shortcuts::THREAD_VIEW]["scroll_up"]) =>
|
if shortcut!(key == shortcuts[Shortcuts::THREAD_VIEW]["scroll_up"]) =>
|
||||||
|
@ -1157,8 +1157,8 @@ impl Component for ThreadView {
|
||||||
self.mailview.set_dirty(value);
|
self.mailview.set_dirty(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = self.mailview.get_shortcuts(context);
|
let mut map = self.mailview.shortcuts(context);
|
||||||
|
|
||||||
map.insert(
|
map.insert(
|
||||||
Shortcuts::THREAD_VIEW,
|
Shortcuts::THREAD_VIEW,
|
||||||
|
|
|
@ -87,7 +87,7 @@ impl MailboxManager {
|
||||||
initialized: false,
|
initialized: false,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
movement: None,
|
movement: None,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,7 +416,7 @@ impl Component for MailboxManager {
|
||||||
return s.process_event(event, context);
|
return s.process_event(event, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
match event {
|
match event {
|
||||||
UIEvent::AccountStatusChange(account_hash, msg)
|
UIEvent::AccountStatusChange(account_hash, msg)
|
||||||
if *account_hash == self.account_hash =>
|
if *account_hash == self.account_hash =>
|
||||||
|
@ -428,8 +428,8 @@ impl Component for MailboxManager {
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(match msg {
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(match msg {
|
||||||
Some(msg) => format!("{} {}", self.get_status(context), msg),
|
Some(msg) => format!("{} {}", self.status(context), msg),
|
||||||
None => self.get_status(context),
|
None => self.status(context),
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
UIEvent::Input(ref key)
|
UIEvent::Input(ref key)
|
||||||
|
@ -522,12 +522,12 @@ impl Component for MailboxManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kill(&mut self, uuid: Uuid, context: &mut Context) {
|
fn kill(&mut self, uuid: ComponentId, context: &mut Context) {
|
||||||
debug_assert!(uuid == self.id);
|
debug_assert!(uuid == self.id);
|
||||||
context.replies.push_back(UIEvent::Action(Tab(Kill(uuid))));
|
context.replies.push_back(UIEvent::Action(Tab(Kill(uuid))));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = ShortcutMaps::default();
|
let mut map = ShortcutMaps::default();
|
||||||
|
|
||||||
map.insert(
|
map.insert(
|
||||||
|
@ -550,7 +550,7 @@ impl Component for MailboxManager {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_status(&self, _context: &Context) -> String {
|
fn status(&self, _context: &Context) -> String {
|
||||||
format!("{} entries", self.entries.len())
|
format!("{} entries", self.entries.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ mod dbus {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DbusNotifications {
|
pub struct DbusNotifications {
|
||||||
rate_limit: RateLimit,
|
rate_limit: RateLimit,
|
||||||
|
id: ComponentId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for DbusNotifications {
|
impl fmt::Display for DbusNotifications {
|
||||||
|
@ -50,6 +51,7 @@ mod dbus {
|
||||||
pub fn new(context: &Context) -> Self {
|
pub fn new(context: &Context) -> Self {
|
||||||
DbusNotifications {
|
DbusNotifications {
|
||||||
rate_limit: RateLimit::new(1000, 1000, context.job_executor.clone()),
|
rate_limit: RateLimit::new(1000, 1000, context.job_executor.clone()),
|
||||||
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,10 +133,12 @@ mod dbus {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id(&self) -> ComponentId {
|
fn id(&self) -> ComponentId {
|
||||||
ComponentId::nil()
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_id(&mut self, _id: ComponentId) {}
|
fn set_id(&mut self, id: ComponentId) {
|
||||||
|
self.id = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn escape_str(s: &str) -> String {
|
fn escape_str(s: &str) -> String {
|
||||||
|
@ -168,11 +172,13 @@ mod dbus {
|
||||||
|
|
||||||
/// Passes notifications to a user defined shell command
|
/// Passes notifications to a user defined shell command
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct NotificationCommand {}
|
pub struct NotificationCommand {
|
||||||
|
id: ComponentId,
|
||||||
|
}
|
||||||
|
|
||||||
impl NotificationCommand {
|
impl NotificationCommand {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
NotificationCommand {}
|
NotificationCommand::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,14 +276,20 @@ impl Component for NotificationCommand {
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
fn id(&self) -> ComponentId {
|
|
||||||
ComponentId::nil()
|
|
||||||
}
|
|
||||||
fn is_dirty(&self) -> bool {
|
fn is_dirty(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_dirty(&mut self, _value: bool) {}
|
fn set_dirty(&mut self, _value: bool) {}
|
||||||
fn set_id(&mut self, _id: ComponentId) {}
|
|
||||||
|
fn id(&self) -> ComponentId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_id(&mut self, id: ComponentId) {
|
||||||
|
self.id = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_xbiff(path: &str) -> Result<()> {
|
fn update_xbiff(path: &str) -> Result<()> {
|
||||||
|
|
|
@ -25,6 +25,7 @@ use super::*;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SVGScreenshotFilter {
|
pub struct SVGScreenshotFilter {
|
||||||
save_screenshot: bool,
|
save_screenshot: bool,
|
||||||
|
id: ComponentId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for SVGScreenshotFilter {
|
impl fmt::Display for SVGScreenshotFilter {
|
||||||
|
@ -37,6 +38,7 @@ impl SVGScreenshotFilter {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SVGScreenshotFilter {
|
SVGScreenshotFilter {
|
||||||
save_screenshot: false,
|
save_screenshot: false,
|
||||||
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,9 +444,12 @@ impl Component for SVGScreenshotFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id(&self) -> ComponentId {
|
fn id(&self) -> ComponentId {
|
||||||
ComponentId::nil()
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_id(&mut self, id: ComponentId) {
|
||||||
|
self.id = id;
|
||||||
}
|
}
|
||||||
fn set_id(&mut self, _id: ComponentId) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CSS_STYLE: &str = r#"#t{font-family:'DejaVu Sans Mono',monospace;font-style:normal;font-size:14px;} text {dominant-baseline: text-before-edge; white-space: pre;} .f{fill:#e5e5e5;} .b{fill:#000;} .c0 {fill:#000;} .c1 {fill:#cd0000;} .c2 {fill:#00cd00;} .c3 {fill:#cdcd00;} .c4 {fill:#00e;} .c5 {fill:#cd00cd;} .c6 {fill:#00cdcd;} .c7 {fill:#e5e5e5;} .c8 {fill:#7f7f7f;} .c9 {fill:#f00;} .c10 {fill:#0f0;} .c11 {fill:#ff0;} .c12 {fill:#5c5cff;} .c13 {fill:#f0f;} .c14 {fill:#0ff;} .c15 {fill:#fff;}"#;
|
const CSS_STYLE: &str = r#"#t{font-family:'DejaVu Sans Mono',monospace;font-style:normal;font-size:14px;} text {dominant-baseline: text-before-edge; white-space: pre;} .f{fill:#e5e5e5;} .b{fill:#000;} .c0 {fill:#000;} .c1 {fill:#cd0000;} .c2 {fill:#00cd00;} .c3 {fill:#cdcd00;} .c4 {fill:#00e;} .c5 {fill:#cd00cd;} .c6 {fill:#00cdcd;} .c7 {fill:#e5e5e5;} .c8 {fill:#7f7f7f;} .c9 {fill:#f00;} .c10 {fill:#0f0;} .c11 {fill:#ff0;} .c12 {fill:#5c5cff;} .c13 {fill:#f0f;} .c14 {fill:#0ff;} .c15 {fill:#fff;}"#;
|
||||||
|
|
|
@ -115,7 +115,7 @@ impl StatusBar {
|
||||||
mode: UIMode::Normal,
|
mode: UIMode::Normal,
|
||||||
mouse: context.settings.terminal.use_mouse.is_true(),
|
mouse: context.settings.terminal.use_mouse.is_true(),
|
||||||
height: 1,
|
height: 1,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
auto_complete: AutoComplete::new(Vec::new()),
|
auto_complete: AutoComplete::new(Vec::new()),
|
||||||
progress_spinner,
|
progress_spinner,
|
||||||
in_progress_jobs: HashSet::default(),
|
in_progress_jobs: HashSet::default(),
|
||||||
|
@ -784,8 +784,8 @@ impl Component for StatusBar {
|
||||||
self.progress_spinner.set_dirty(value);
|
self.progress_spinner.set_dirty(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
self.container.get_shortcuts(context)
|
self.container.shortcuts(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id(&self) -> ComponentId {
|
fn id(&self) -> ComponentId {
|
||||||
|
@ -823,7 +823,7 @@ impl Tabbed {
|
||||||
let mut ret = Tabbed {
|
let mut ret = Tabbed {
|
||||||
help_curr_views: children
|
help_curr_views: children
|
||||||
.get(0)
|
.get(0)
|
||||||
.map(|c| c.get_shortcuts(context))
|
.map(|c| c.shortcuts(context))
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
help_content: CellBuffer::default(),
|
help_content: CellBuffer::default(),
|
||||||
help_screen_cursor: (0, 0),
|
help_screen_cursor: (0, 0),
|
||||||
|
@ -834,10 +834,10 @@ impl Tabbed {
|
||||||
cursor_pos: 0,
|
cursor_pos: 0,
|
||||||
show_shortcuts: false,
|
show_shortcuts: false,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
};
|
};
|
||||||
ret.help_curr_views
|
ret.help_curr_views
|
||||||
.extend(ret.get_shortcuts(context).into_iter());
|
.extend(ret.shortcuts(context).into_iter());
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
fn draw_tabs(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
|
fn draw_tabs(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) {
|
||||||
|
@ -969,8 +969,8 @@ impl Component for Tabbed {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.show_shortcuts && self.dirty) || must_redraw_shortcuts {
|
if (self.show_shortcuts && self.dirty) || must_redraw_shortcuts {
|
||||||
let mut children_maps = self.children[self.cursor_pos].get_shortcuts(context);
|
let mut children_maps = self.children[self.cursor_pos].shortcuts(context);
|
||||||
let our_map = self.get_shortcuts(context);
|
let our_map = self.shortcuts(context);
|
||||||
children_maps.extend(our_map.into_iter());
|
children_maps.extend(our_map.into_iter());
|
||||||
if children_maps.is_empty() {
|
if children_maps.is_empty() {
|
||||||
return;
|
return;
|
||||||
|
@ -1343,13 +1343,13 @@ impl Component for Tabbed {
|
||||||
self.children[self.cursor_pos]
|
self.children[self.cursor_pos]
|
||||||
.process_event(&mut UIEvent::VisibilityChange(false), context);
|
.process_event(&mut UIEvent::VisibilityChange(false), context);
|
||||||
self.cursor_pos = no % self.children.len();
|
self.cursor_pos = no % self.children.len();
|
||||||
let mut children_maps = self.children[self.cursor_pos].get_shortcuts(context);
|
let mut children_maps = self.children[self.cursor_pos].shortcuts(context);
|
||||||
children_maps.extend(self.get_shortcuts(context));
|
children_maps.extend(self.shortcuts(context));
|
||||||
self.help_curr_views = children_maps;
|
self.help_curr_views = children_maps;
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||||
self.children[self.cursor_pos].get_status(context),
|
self.children[self.cursor_pos].status(context),
|
||||||
)));
|
)));
|
||||||
self.set_dirty(true);
|
self.set_dirty(true);
|
||||||
}
|
}
|
||||||
|
@ -1361,13 +1361,13 @@ impl Component for Tabbed {
|
||||||
self.children[self.cursor_pos]
|
self.children[self.cursor_pos]
|
||||||
.process_event(&mut UIEvent::VisibilityChange(false), context);
|
.process_event(&mut UIEvent::VisibilityChange(false), context);
|
||||||
self.cursor_pos = (self.cursor_pos + 1) % self.children.len();
|
self.cursor_pos = (self.cursor_pos + 1) % self.children.len();
|
||||||
let mut children_maps = self.children[self.cursor_pos].get_shortcuts(context);
|
let mut children_maps = self.children[self.cursor_pos].shortcuts(context);
|
||||||
children_maps.extend(self.get_shortcuts(context));
|
children_maps.extend(self.shortcuts(context));
|
||||||
self.help_curr_views = children_maps;
|
self.help_curr_views = children_maps;
|
||||||
context
|
context
|
||||||
.replies
|
.replies
|
||||||
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
.push_back(UIEvent::StatusEvent(StatusEvent::UpdateStatus(
|
||||||
self.children[self.cursor_pos].get_status(context),
|
self.children[self.cursor_pos].status(context),
|
||||||
)));
|
)));
|
||||||
self.set_dirty(true);
|
self.set_dirty(true);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1394,8 +1394,8 @@ impl Component for Tabbed {
|
||||||
.process_event(&mut UIEvent::VisibilityChange(false), context);
|
.process_event(&mut UIEvent::VisibilityChange(false), context);
|
||||||
self.cursor_pos = self.children.len() - 1;
|
self.cursor_pos = self.children.len() - 1;
|
||||||
self.children[self.cursor_pos].set_dirty(true);
|
self.children[self.cursor_pos].set_dirty(true);
|
||||||
let mut children_maps = self.children[self.cursor_pos].get_shortcuts(context);
|
let mut children_maps = self.children[self.cursor_pos].shortcuts(context);
|
||||||
children_maps.extend(self.get_shortcuts(context));
|
children_maps.extend(self.shortcuts(context));
|
||||||
self.help_curr_views = children_maps;
|
self.help_curr_views = children_maps;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1405,8 +1405,8 @@ impl Component for Tabbed {
|
||||||
}
|
}
|
||||||
let id = self.children[self.cursor_pos].id();
|
let id = self.children[self.cursor_pos].id();
|
||||||
self.children[self.cursor_pos].kill(id, context);
|
self.children[self.cursor_pos].kill(id, context);
|
||||||
let mut children_maps = self.children[self.cursor_pos].get_shortcuts(context);
|
let mut children_maps = self.children[self.cursor_pos].shortcuts(context);
|
||||||
children_maps.extend(self.get_shortcuts(context));
|
children_maps.extend(self.shortcuts(context));
|
||||||
self.help_curr_views = children_maps;
|
self.help_curr_views = children_maps;
|
||||||
self.set_dirty(true);
|
self.set_dirty(true);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1421,8 +1421,8 @@ impl Component for Tabbed {
|
||||||
self.children.remove(c_idx);
|
self.children.remove(c_idx);
|
||||||
self.cursor_pos = 0;
|
self.cursor_pos = 0;
|
||||||
self.set_dirty(true);
|
self.set_dirty(true);
|
||||||
let mut children_maps = self.children[self.cursor_pos].get_shortcuts(context);
|
let mut children_maps = self.children[self.cursor_pos].shortcuts(context);
|
||||||
children_maps.extend(self.get_shortcuts(context));
|
children_maps.extend(self.shortcuts(context));
|
||||||
self.help_curr_views = children_maps;
|
self.help_curr_views = children_maps;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1525,9 +1525,11 @@ impl Component for Tabbed {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_dirty(&self) -> bool {
|
fn is_dirty(&self) -> bool {
|
||||||
self.dirty || self.children[self.cursor_pos].is_dirty()
|
self.dirty || self.children[self.cursor_pos].is_dirty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_dirty(&mut self, value: bool) {
|
fn set_dirty(&mut self, value: bool) {
|
||||||
self.dirty = value;
|
self.dirty = value;
|
||||||
self.children[self.cursor_pos].set_dirty(value);
|
self.children[self.cursor_pos].set_dirty(value);
|
||||||
|
@ -1536,11 +1538,12 @@ impl Component for Tabbed {
|
||||||
fn id(&self) -> ComponentId {
|
fn id(&self) -> ComponentId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_id(&mut self, id: ComponentId) {
|
fn set_id(&mut self, id: ComponentId) {
|
||||||
self.id = id;
|
self.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = ShortcutMaps::default();
|
let mut map = ShortcutMaps::default();
|
||||||
map.insert(
|
map.insert(
|
||||||
Shortcuts::GENERAL,
|
Shortcuts::GENERAL,
|
||||||
|
@ -1566,6 +1569,7 @@ pub struct RawBuffer {
|
||||||
pub buf: CellBuffer,
|
pub buf: CellBuffer,
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
cursor: (usize, usize),
|
cursor: (usize, usize),
|
||||||
|
id: ComponentId,
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1639,7 +1643,11 @@ impl Component for RawBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn id(&self) -> ComponentId {
|
fn id(&self) -> ComponentId {
|
||||||
ComponentId::nil()
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_id(&mut self, id: ComponentId) {
|
||||||
|
self.id = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1648,8 +1656,9 @@ impl RawBuffer {
|
||||||
RawBuffer {
|
RawBuffer {
|
||||||
buf,
|
buf,
|
||||||
title,
|
title,
|
||||||
dirty: true,
|
|
||||||
cursor: (0, 0),
|
cursor: (0, 0),
|
||||||
|
dirty: true,
|
||||||
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn title(&self) -> &str {
|
pub fn title(&self) -> &str {
|
||||||
|
|
|
@ -113,7 +113,7 @@ impl<T: 'static + PartialEq + Debug + Clone + Sync + Send> Component for UIDialo
|
||||||
}
|
}
|
||||||
|
|
||||||
let (width, height) = self.content.size();
|
let (width, height) = self.content.size();
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted");
|
let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted");
|
||||||
if !context.settings.terminal.use_color() {
|
if !context.settings.terminal.use_color() {
|
||||||
highlighted_attrs.attrs |= Attr::REVERSE;
|
highlighted_attrs.attrs |= Attr::REVERSE;
|
||||||
|
@ -404,7 +404,7 @@ impl<T: 'static + PartialEq + Debug + Clone + Sync + Send> Component for UIDialo
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = ShortcutMaps::default();
|
let mut map = ShortcutMaps::default();
|
||||||
map.insert(
|
map.insert(
|
||||||
Shortcuts::GENERAL,
|
Shortcuts::GENERAL,
|
||||||
|
@ -442,7 +442,7 @@ impl Component for UIConfirmationDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
let (width, height) = self.content.size();
|
let (width, height) = self.content.size();
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted");
|
let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted");
|
||||||
if !context.settings.terminal.use_color() {
|
if !context.settings.terminal.use_color() {
|
||||||
highlighted_attrs.attrs |= Attr::REVERSE;
|
highlighted_attrs.attrs |= Attr::REVERSE;
|
||||||
|
@ -733,7 +733,7 @@ impl Component for UIConfirmationDialog {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut map = ShortcutMaps::default();
|
let mut map = ShortcutMaps::default();
|
||||||
map.insert(
|
map.insert(
|
||||||
Shortcuts::GENERAL,
|
Shortcuts::GENERAL,
|
||||||
|
@ -791,7 +791,7 @@ impl<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> Selec
|
||||||
done_fn,
|
done_fn,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
theme_default: Default::default(),
|
theme_default: Default::default(),
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
};
|
};
|
||||||
ret.initialise(context);
|
ret.initialise(context);
|
||||||
ret
|
ret
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl HSplit {
|
||||||
bottom,
|
bottom,
|
||||||
show_divider,
|
show_divider,
|
||||||
ratio,
|
ratio,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,9 +101,9 @@ impl Component for HSplit {
|
||||||
self.bottom.set_dirty(value);
|
self.bottom.set_dirty(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut top_map = self.top.get_shortcuts(context);
|
let mut top_map = self.top.shortcuts(context);
|
||||||
top_map.extend(self.bottom.get_shortcuts(context).into_iter());
|
top_map.extend(self.bottom.shortcuts(context).into_iter());
|
||||||
top_map
|
top_map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ impl VSplit {
|
||||||
show_divider,
|
show_divider,
|
||||||
prev_visibility: (true, true),
|
prev_visibility: (true, true),
|
||||||
ratio,
|
ratio,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,9 +241,9 @@ impl Component for VSplit {
|
||||||
self.right.set_dirty(value);
|
self.right.set_dirty(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut right_map = self.right.get_shortcuts(context);
|
let mut right_map = self.right.shortcuts(context);
|
||||||
right_map.extend(self.left.get_shortcuts(context).into_iter());
|
right_map.extend(self.left.shortcuts(context).into_iter());
|
||||||
right_map
|
right_map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ impl Pager {
|
||||||
minimum_width: pager_minimum_width,
|
minimum_width: pager_minimum_width,
|
||||||
initialised: false,
|
initialised: false,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
filtered_content: None,
|
filtered_content: None,
|
||||||
colors,
|
colors,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -648,7 +648,7 @@ impl Component for Pager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||||
let shortcuts = self.get_shortcuts(context);
|
let shortcuts = self.shortcuts(context);
|
||||||
match event {
|
match event {
|
||||||
UIEvent::ConfigReload { old_settings: _ } => {
|
UIEvent::ConfigReload { old_settings: _ } => {
|
||||||
self.set_colors(crate::conf::value(context, "theme_default"));
|
self.set_colors(crate::conf::value(context, "theme_default"));
|
||||||
|
@ -829,7 +829,7 @@ impl Component for Pager {
|
||||||
self.dirty = value;
|
self.dirty = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_shortcuts(&self, context: &Context) -> ShortcutMaps {
|
fn shortcuts(&self, context: &Context) -> ShortcutMaps {
|
||||||
let mut ret: ShortcutMaps = Default::default();
|
let mut ret: ShortcutMaps = Default::default();
|
||||||
ret.insert(
|
ret.insert(
|
||||||
Shortcuts::PAGER,
|
Shortcuts::PAGER,
|
||||||
|
|
|
@ -24,11 +24,13 @@ use super::*;
|
||||||
pub struct TextField {
|
pub struct TextField {
|
||||||
inner: UText,
|
inner: UText,
|
||||||
autocomplete: Option<(AutoCompleteFn, Box<AutoComplete>)>,
|
autocomplete: Option<(AutoCompleteFn, Box<AutoComplete>)>,
|
||||||
|
id: ComponentId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for TextField {
|
impl Debug for TextField {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt.debug_struct(stringify!(TextField))
|
fmt.debug_struct(stringify!(TextField))
|
||||||
|
.field("id", &self.id)
|
||||||
.field("inner", &self.inner)
|
.field("inner", &self.inner)
|
||||||
.field("has AutoComplete", &self.autocomplete.is_some())
|
.field("has AutoComplete", &self.autocomplete.is_some())
|
||||||
.finish()
|
.finish()
|
||||||
|
@ -40,6 +42,7 @@ impl Default for TextField {
|
||||||
Self {
|
Self {
|
||||||
inner: UText::new(String::with_capacity(256)),
|
inner: UText::new(String::with_capacity(256)),
|
||||||
autocomplete: None,
|
autocomplete: None,
|
||||||
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +52,7 @@ impl TextField {
|
||||||
Self {
|
Self {
|
||||||
inner,
|
inner,
|
||||||
autocomplete,
|
autocomplete,
|
||||||
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,15 +308,20 @@ impl Component for TextField {
|
||||||
self.set_dirty(true);
|
self.set_dirty(true);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_dirty(&self) -> bool {
|
fn is_dirty(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_dirty(&mut self, _value: bool) {}
|
fn set_dirty(&mut self, _value: bool) {}
|
||||||
|
|
||||||
fn id(&self) -> ComponentId {
|
fn id(&self) -> ComponentId {
|
||||||
ComponentId::nil()
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_id(&mut self, id: ComponentId) {
|
||||||
|
self.id = id;
|
||||||
}
|
}
|
||||||
fn set_id(&mut self, _id: ComponentId) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for TextField {
|
impl fmt::Display for TextField {
|
||||||
|
|
|
@ -35,7 +35,7 @@ type Cursor = usize;
|
||||||
|
|
||||||
pub enum Field {
|
pub enum Field {
|
||||||
Text(TextField),
|
Text(TextField),
|
||||||
Choice(Vec<Cow<'static, str>>, Cursor),
|
Choice(Vec<Cow<'static, str>>, Cursor, ComponentId),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Field {
|
impl Debug for Field {
|
||||||
|
@ -57,7 +57,7 @@ impl Field {
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Self::Text(ref s) => s.as_str(),
|
Self::Text(ref s) => s.as_str(),
|
||||||
Self::Choice(ref v, cursor) => {
|
Self::Choice(ref v, cursor, _) => {
|
||||||
if v.is_empty() {
|
if v.is_empty() {
|
||||||
""
|
""
|
||||||
} else {
|
} else {
|
||||||
|
@ -70,7 +70,7 @@ impl Field {
|
||||||
pub fn cursor(&self) -> usize {
|
pub fn cursor(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::Text(ref s) => s.cursor(),
|
Self::Text(ref s) => s.cursor(),
|
||||||
Self::Choice(_, ref cursor) => *cursor,
|
Self::Choice(_, ref cursor, _) => *cursor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,14 +81,14 @@ impl Field {
|
||||||
pub fn into_string(self) -> String {
|
pub fn into_string(self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::Text(s) => s.into_string(),
|
Self::Text(s) => s.into_string(),
|
||||||
Self::Choice(mut v, cursor) => v.remove(cursor).to_string(),
|
Self::Choice(mut v, cursor, _) => v.remove(cursor).to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
Self::Text(s) => s.clear(),
|
Self::Text(s) => s.clear(),
|
||||||
Self::Choice(_, _) => {}
|
Self::Choice(_, _, _) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ impl Field {
|
||||||
Self::Text(ref mut text_field) => {
|
Self::Text(ref mut text_field) => {
|
||||||
text_field.draw_cursor(grid, area, secondary_area, context);
|
text_field.draw_cursor(grid, area, secondary_area, context);
|
||||||
}
|
}
|
||||||
Self::Choice(_, _cursor) => {}
|
Self::Choice(_, _cursor, _) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ impl Component for Field {
|
||||||
Self::Text(ref mut text_field) => {
|
Self::Text(ref mut text_field) => {
|
||||||
text_field.draw(grid, area, context);
|
text_field.draw(grid, area, context);
|
||||||
}
|
}
|
||||||
Self::Choice(_, _) => {
|
Self::Choice(_, _, _) => {
|
||||||
write_string_to_grid(
|
write_string_to_grid(
|
||||||
str,
|
str,
|
||||||
grid,
|
grid,
|
||||||
|
@ -139,7 +139,7 @@ impl Component for Field {
|
||||||
Self::Text(_) => {
|
Self::Text(_) => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Self::Choice(ref vec, ref mut cursor) => {
|
Self::Choice(ref vec, ref mut cursor, _) => {
|
||||||
*cursor = if *cursor == vec.len().saturating_sub(1) {
|
*cursor = if *cursor == vec.len().saturating_sub(1) {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
|
@ -151,7 +151,7 @@ impl Component for Field {
|
||||||
Self::Text(_) => {
|
Self::Text(_) => {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Self::Choice(_, ref mut cursor) => {
|
Self::Choice(_, ref mut cursor, _) => {
|
||||||
if *cursor == 0 {
|
if *cursor == 0 {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -174,10 +174,18 @@ impl Component for Field {
|
||||||
fn set_dirty(&mut self, _value: bool) {}
|
fn set_dirty(&mut self, _value: bool) {}
|
||||||
|
|
||||||
fn id(&self) -> ComponentId {
|
fn id(&self) -> ComponentId {
|
||||||
ComponentId::nil()
|
match self {
|
||||||
|
Self::Text(i) => i.id(),
|
||||||
|
Self::Choice(_, _, i) => *i,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_id(&mut self, _id: ComponentId) {}
|
fn set_id(&mut self, id: ComponentId) {
|
||||||
|
match self {
|
||||||
|
Self::Text(ref mut i) => i.set_id(id),
|
||||||
|
Self::Choice(_, _, i) => *i = id,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Field {
|
impl fmt::Display for Field {
|
||||||
|
@ -187,7 +195,7 @@ impl fmt::Display for Field {
|
||||||
"{}",
|
"{}",
|
||||||
match self {
|
match self {
|
||||||
Self::Text(ref s) => s.as_str(),
|
Self::Text(ref s) => s.as_str(),
|
||||||
Self::Choice(ref v, ref cursor) => v[*cursor].as_ref(),
|
Self::Choice(ref v, ref cursor, _) => v[*cursor].as_ref(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -231,7 +239,7 @@ impl<T: 'static + std::fmt::Debug + Copy + Default + Send + Sync> FormWidget<T>
|
||||||
buttons: ButtonWidget::new(action),
|
buttons: ButtonWidget::new(action),
|
||||||
focus: FormFocus::Fields,
|
focus: FormFocus::Fields,
|
||||||
hide_buttons: false,
|
hide_buttons: false,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
dirty: true,
|
dirty: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
@ -265,7 +273,8 @@ impl<T: 'static + std::fmt::Debug + Copy + Default + Send + Sync> FormWidget<T>
|
||||||
pub fn push_choices(&mut self, value: (Cow<'static, str>, Vec<Cow<'static, str>>)) {
|
pub fn push_choices(&mut self, value: (Cow<'static, str>, Vec<Cow<'static, str>>)) {
|
||||||
self.field_name_max_length = std::cmp::max(self.field_name_max_length, value.0.len());
|
self.field_name_max_length = std::cmp::max(self.field_name_max_length, value.0.len());
|
||||||
self.layout.push(value.0.clone());
|
self.layout.push(value.0.clone());
|
||||||
self.fields.insert(value.0, Field::Choice(value.1, 0));
|
self.fields
|
||||||
|
.insert(value.0, Field::Choice(value.1, 0, ComponentId::default()));
|
||||||
}
|
}
|
||||||
pub fn push_cl(&mut self, value: (Cow<'static, str>, String, AutoCompleteFn)) {
|
pub fn push_cl(&mut self, value: (Cow<'static, str>, String, AutoCompleteFn)) {
|
||||||
self.field_name_max_length = std::cmp::max(self.field_name_max_length, value.0.len());
|
self.field_name_max_length = std::cmp::max(self.field_name_max_length, value.0.len());
|
||||||
|
@ -568,7 +577,7 @@ where
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
focus: false,
|
focus: false,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,7 +823,7 @@ impl AutoComplete {
|
||||||
content: CellBuffer::default(),
|
content: CellBuffer::default(),
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
};
|
};
|
||||||
ret.set_suggestions(entries);
|
ret.set_suggestions(entries);
|
||||||
Box::new(ret)
|
Box::new(ret)
|
||||||
|
@ -1145,7 +1154,7 @@ impl ProgressSpinner {
|
||||||
theme_attr,
|
theme_attr,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
active: false,
|
active: false,
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
src/jobs.rs
31
src/jobs.rs
|
@ -63,9 +63,7 @@ fn find_task<T>(local: &Worker<T>, global: &Injector<T>, stealers: &[Stealer<T>]
|
||||||
|
|
||||||
macro_rules! uuid_hash_type {
|
macro_rules! uuid_hash_type {
|
||||||
($n:ident) => {
|
($n:ident) => {
|
||||||
#[derive(
|
#[derive(PartialEq, Hash, Eq, Copy, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
||||||
PartialEq, Hash, Eq, Copy, Clone, Ord, PartialOrd, Serialize, Deserialize, Default,
|
|
||||||
)]
|
|
||||||
pub struct $n(Uuid);
|
pub struct $n(Uuid);
|
||||||
|
|
||||||
impl core::fmt::Debug for $n {
|
impl core::fmt::Debug for $n {
|
||||||
|
@ -80,17 +78,24 @@ macro_rules! uuid_hash_type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for $n {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl $n {
|
impl $n {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
$n(Uuid::new_v4())
|
Self(Uuid::new_v4())
|
||||||
}
|
}
|
||||||
pub fn null() -> Self {
|
pub fn null() -> Self {
|
||||||
$n(Uuid::nil())
|
Self(Uuid::nil())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
uuid_hash_type!(JobId);
|
uuid_hash_type!(JobId);
|
||||||
|
uuid_hash_type!(TimerId);
|
||||||
|
|
||||||
/// A spawned future and its current state.
|
/// A spawned future and its current state.
|
||||||
pub struct MeliTask {
|
pub struct MeliTask {
|
||||||
|
@ -105,7 +110,7 @@ pub struct JobExecutor {
|
||||||
workers: Vec<Stealer<MeliTask>>,
|
workers: Vec<Stealer<MeliTask>>,
|
||||||
sender: Sender<ThreadEvent>,
|
sender: Sender<ThreadEvent>,
|
||||||
parkers: Vec<Unparker>,
|
parkers: Vec<Unparker>,
|
||||||
timers: Arc<Mutex<HashMap<Uuid, TimerPrivate>>>,
|
timers: Arc<Mutex<HashMap<TimerId, TimerPrivate>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -121,12 +126,12 @@ struct TimerPrivate {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Timer {
|
pub struct Timer {
|
||||||
id: Uuid,
|
id: TimerId,
|
||||||
job_executor: Arc<JobExecutor>,
|
job_executor: Arc<JobExecutor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
pub fn id(&self) -> Uuid {
|
pub fn id(&self) -> TimerId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +265,6 @@ impl JobExecutor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_timer(self: Arc<JobExecutor>, interval: Duration, value: Duration) -> Timer {
|
pub fn create_timer(self: Arc<JobExecutor>, interval: Duration, value: Duration) -> Timer {
|
||||||
let id = Uuid::new_v4();
|
|
||||||
let timer = TimerPrivate {
|
let timer = TimerPrivate {
|
||||||
interval,
|
interval,
|
||||||
cancel: Arc::new(Mutex::new(false)),
|
cancel: Arc::new(Mutex::new(false)),
|
||||||
|
@ -268,6 +272,7 @@ impl JobExecutor {
|
||||||
active: true,
|
active: true,
|
||||||
handle: None,
|
handle: None,
|
||||||
};
|
};
|
||||||
|
let id = TimerId::default();
|
||||||
self.timers.lock().unwrap().insert(id, timer);
|
self.timers.lock().unwrap().insert(id, timer);
|
||||||
self.arm_timer(id, value);
|
self.arm_timer(id, value);
|
||||||
Timer {
|
Timer {
|
||||||
|
@ -276,7 +281,7 @@ impl JobExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rearm(&self, timer_id: Uuid) {
|
pub fn rearm(&self, timer_id: TimerId) {
|
||||||
let mut timers_lck = self.timers.lock().unwrap();
|
let mut timers_lck = self.timers.lock().unwrap();
|
||||||
if let Some(timer) = timers_lck.get_mut(&timer_id) {
|
if let Some(timer) = timers_lck.get_mut(&timer_id) {
|
||||||
let value = timer.value;
|
let value = timer.value;
|
||||||
|
@ -285,7 +290,7 @@ impl JobExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arm_timer(&self, id: Uuid, value: Duration) {
|
fn arm_timer(&self, id: TimerId, value: Duration) {
|
||||||
let job_id = JobId::new();
|
let job_id = JobId::new();
|
||||||
let sender = self.sender.clone();
|
let sender = self.sender.clone();
|
||||||
let injector = self.global_queue.clone();
|
let injector = self.global_queue.clone();
|
||||||
|
@ -337,7 +342,7 @@ impl JobExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable_timer(&self, id: Uuid) {
|
fn disable_timer(&self, id: TimerId) {
|
||||||
let mut timers_lck = self.timers.lock().unwrap();
|
let mut timers_lck = self.timers.lock().unwrap();
|
||||||
if let Some(timer) = timers_lck.get_mut(&id) {
|
if let Some(timer) = timers_lck.get_mut(&id) {
|
||||||
timer.active = false;
|
timer.active = false;
|
||||||
|
@ -345,7 +350,7 @@ impl JobExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_interval(&self, id: Uuid, new_val: Duration) {
|
fn set_interval(&self, id: TimerId, new_val: Duration) {
|
||||||
let mut timers_lck = self.timers.lock().unwrap();
|
let mut timers_lck = self.timers.lock().unwrap();
|
||||||
if let Some(timer) = timers_lck.get_mut(&id) {
|
if let Some(timer) = timers_lck.get_mut(&id) {
|
||||||
timer.interval = new_val;
|
timer.interval = new_val;
|
||||||
|
|
228
src/types.rs
228
src/types.rs
|
@ -19,27 +19,27 @@
|
||||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*! UI types used throughout meli.
|
//! UI types used throughout meli.
|
||||||
*
|
//!
|
||||||
* The `segment_tree` module performs maximum range queries. This is used in
|
//! The [`segment_tree`] module performs maximum range queries.
|
||||||
* getting the maximum element of a column within a specific range in e-mail
|
//! This is used in getting the maximum element of a column within a specific
|
||||||
* lists. That way a very large value that is not the in the currently
|
//! range in e-mail lists.
|
||||||
* displayed page does not cause the column to be rendered bigger
|
//! That way a very large value that is not the in the currently displayed page
|
||||||
* than it has to.
|
//! 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
|
//! [`UIMode`] describes the application's... mode. Same as in the modal editor
|
||||||
* `vi`.
|
//! `vi`.
|
||||||
*
|
//!
|
||||||
* `UIEvent` is the type passed around `Component`s when something happens.
|
//! [`UIEvent`] is the type passed around
|
||||||
*/
|
//! [`Component`](crate::components::Component)'s when something happens.
|
||||||
extern crate serde;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod helpers;
|
mod helpers;
|
||||||
|
|
||||||
use std::{borrow::Cow, fmt, sync::Arc};
|
use std::{borrow::Cow, fmt, sync::Arc};
|
||||||
|
|
||||||
use melib::{
|
use melib::{
|
||||||
backends::{AccountHash, BackendEvent, MailboxHash},
|
backends::{AccountHash, BackendEvent, MailboxHash},
|
||||||
uuid::Uuid,
|
|
||||||
EnvelopeHash, RefreshEvent, ThreadHash,
|
EnvelopeHash, RefreshEvent, ThreadHash,
|
||||||
};
|
};
|
||||||
use nix::unistd::Pid;
|
use nix::unistd::Pid;
|
||||||
|
@ -47,7 +47,7 @@ use nix::unistd::Pid;
|
||||||
pub use self::helpers::*;
|
pub use self::helpers::*;
|
||||||
use super::{
|
use super::{
|
||||||
command::Action,
|
command::Action,
|
||||||
jobs::{JobExecutor, JobId},
|
jobs::{JobExecutor, JobId, TimerId},
|
||||||
terminal::*,
|
terminal::*,
|
||||||
};
|
};
|
||||||
use crate::components::{Component, ComponentId, ScrollUpdate};
|
use crate::components::{Component, ComponentId, ScrollUpdate};
|
||||||
|
@ -66,7 +66,7 @@ pub enum StatusEvent {
|
||||||
ScrollUpdate(ScrollUpdate),
|
ScrollUpdate(ScrollUpdate),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `ThreadEvent` encapsulates all of the possible values we need to transfer
|
/// [`ThreadEvent`] encapsulates all of the possible values we need to transfer
|
||||||
/// between our threads to the main process.
|
/// between our threads to the main process.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ThreadEvent {
|
pub enum ThreadEvent {
|
||||||
|
@ -140,7 +140,7 @@ pub enum UIEvent {
|
||||||
MailboxDelete((AccountHash, MailboxHash)),
|
MailboxDelete((AccountHash, MailboxHash)),
|
||||||
MailboxCreate((AccountHash, MailboxHash)),
|
MailboxCreate((AccountHash, MailboxHash)),
|
||||||
AccountStatusChange(AccountHash, Option<Cow<'static, str>>),
|
AccountStatusChange(AccountHash, Option<Cow<'static, str>>),
|
||||||
ComponentKill(Uuid),
|
ComponentKill(ComponentId),
|
||||||
BackendEvent(AccountHash, BackendEvent),
|
BackendEvent(AccountHash, BackendEvent),
|
||||||
StartupCheck(MailboxHash),
|
StartupCheck(MailboxHash),
|
||||||
RefreshEvent(Box<RefreshEvent>),
|
RefreshEvent(Box<RefreshEvent>),
|
||||||
|
@ -152,7 +152,7 @@ pub enum UIEvent {
|
||||||
FinishedUIDialog(ComponentId, UIMessage),
|
FinishedUIDialog(ComponentId, UIMessage),
|
||||||
Callback(CallbackFn),
|
Callback(CallbackFn),
|
||||||
GlobalUIDialog(Box<dyn Component>),
|
GlobalUIDialog(Box<dyn Component>),
|
||||||
Timer(Uuid),
|
Timer(TimerId),
|
||||||
ConfigReload {
|
ConfigReload {
|
||||||
old_settings: Box<crate::conf::Settings>,
|
old_settings: Box<crate::conf::Settings>,
|
||||||
},
|
},
|
||||||
|
@ -200,10 +200,10 @@ impl fmt::Display for UIMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod segment_tree {
|
pub mod segment_tree {
|
||||||
/*! Simple segment tree implementation for maximum in range queries. This
|
//! Simple segment tree implementation for maximum in range queries. This is
|
||||||
* is useful if given an array of numbers you want to get the
|
//! useful if given an array of numbers you want to get the maximum
|
||||||
* maximum value inside an interval quickly.
|
//! value inside an interval quickly.
|
||||||
*/
|
|
||||||
use std::{convert::TryFrom, iter::FromIterator};
|
use std::{convert::TryFrom, iter::FromIterator};
|
||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -298,20 +298,25 @@ pub mod segment_tree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn test_segment_tree() {
|
mod tests {
|
||||||
let array: SmallVec<[u8; 1024]> = [9, 1, 17, 2, 3, 23, 4, 5, 6, 37]
|
use super::*;
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.collect::<SmallVec<[u8; 1024]>>();
|
|
||||||
let mut segment_tree = SegmentTree::from(array);
|
|
||||||
|
|
||||||
assert_eq!(segment_tree.get_max(0, 5), 23);
|
#[test]
|
||||||
assert_eq!(segment_tree.get_max(6, 9), 37);
|
fn test_segment_tree() {
|
||||||
|
let array: SmallVec<[u8; 1024]> = [9, 1, 17, 2, 3, 23, 4, 5, 6, 37]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<SmallVec<[u8; 1024]>>();
|
||||||
|
let mut segment_tree = SegmentTree::from(array);
|
||||||
|
|
||||||
segment_tree.update(2_usize, 24_u8);
|
assert_eq!(segment_tree.get_max(0, 5), 23);
|
||||||
|
assert_eq!(segment_tree.get_max(6, 9), 37);
|
||||||
|
|
||||||
assert_eq!(segment_tree.get_max(0, 5), 24);
|
segment_tree.update(2_usize, 24_u8);
|
||||||
|
|
||||||
|
assert_eq!(segment_tree.get_max(0, 5), 24);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,85 +359,11 @@ impl RateLimit {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn id(&self) -> Uuid {
|
pub fn id(&self) -> TimerId {
|
||||||
self.timer.id()
|
self.timer.id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rate_limit() {
|
|
||||||
/*
|
|
||||||
let (sender, receiver) =
|
|
||||||
crossbeam::channel::bounded(4096 * ::std::mem::size_of::<ThreadEvent>());
|
|
||||||
use std::sync::Arc;
|
|
||||||
let job_executor = Arc::new(JobExecutor::new(sender));
|
|
||||||
/* Accept at most one request per 3 milliseconds */
|
|
||||||
let mut rt = RateLimit::new(1, 3, job_executor.clone());
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(2000));
|
|
||||||
/* assert that only one request per 3 milliseconds is accepted */
|
|
||||||
for _ in 0..5 {
|
|
||||||
assert!(rt.tick());
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(1));
|
|
||||||
assert!(!rt.tick());
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(1));
|
|
||||||
assert!(!rt.tick());
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(1));
|
|
||||||
/* How many times was the signal handler called? We've slept for at least 3
|
|
||||||
* milliseconds, so it should have been called once */
|
|
||||||
let mut ctr = 0;
|
|
||||||
while receiver.try_recv().is_ok() {
|
|
||||||
ctr += 1;
|
|
||||||
println!("got {}", ctr);
|
|
||||||
}
|
|
||||||
println!("ctr = {} {}", ctr, ctr == 1);
|
|
||||||
assert_eq!(ctr, 1);
|
|
||||||
}
|
|
||||||
/* next, test at most 100 requests per second */
|
|
||||||
let mut rt = RateLimit::new(100, 1000, job_executor.clone());
|
|
||||||
for _ in 0..5 {
|
|
||||||
let mut ctr = 0;
|
|
||||||
for _ in 0..500 {
|
|
||||||
if rt.tick() {
|
|
||||||
ctr += 1;
|
|
||||||
}
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(2));
|
|
||||||
}
|
|
||||||
/* around 100 requests should succeed. might be 99 if in first loop, since
|
|
||||||
* RateLimit::new() has a delay */
|
|
||||||
assert!(ctr > 97 && ctr < 103);
|
|
||||||
/* alarm should expire in 1 second */
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
|
||||||
/* How many times was the signal handler called? */
|
|
||||||
ctr = 0;
|
|
||||||
while receiver.try_recv().is_ok() {
|
|
||||||
ctr += 1;
|
|
||||||
}
|
|
||||||
assert_eq!(ctr, 1);
|
|
||||||
}
|
|
||||||
/* next, test at most 500 requests per second */
|
|
||||||
let mut rt = RateLimit::new(500, 1000, job_executor.clone());
|
|
||||||
for _ in 0..5 {
|
|
||||||
let mut ctr = 0;
|
|
||||||
for _ in 0..500 {
|
|
||||||
if rt.tick() {
|
|
||||||
ctr += 1;
|
|
||||||
}
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(2));
|
|
||||||
}
|
|
||||||
/* all requests should succeed. */
|
|
||||||
assert!(ctr < 503 && ctr > 497);
|
|
||||||
/* alarm should expire in 1 second */
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
|
||||||
/* How many times was the signal handler called? */
|
|
||||||
ctr = 0;
|
|
||||||
while receiver.try_recv().is_ok() {
|
|
||||||
ctr += 1;
|
|
||||||
}
|
|
||||||
assert_eq!(ctr, 1);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ContactEvent {
|
pub enum ContactEvent {
|
||||||
CreateContacts(Vec<melib::Card>),
|
CreateContacts(Vec<melib::Card>),
|
||||||
|
@ -444,3 +375,82 @@ pub enum ComposeEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type UIMessage = Box<dyn 'static + std::any::Any + Send + Sync>;
|
pub type UIMessage = Box<dyn 'static + std::any::Any + Send + Sync>;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
//use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rate_limit() {
|
||||||
|
/*
|
||||||
|
let (sender, receiver) =
|
||||||
|
crossbeam::channel::bounded(4096 * ::std::mem::size_of::<ThreadEvent>());
|
||||||
|
use std::sync::Arc;
|
||||||
|
let job_executor = Arc::new(JobExecutor::new(sender));
|
||||||
|
/* Accept at most one request per 3 milliseconds */
|
||||||
|
let mut rt = RateLimit::new(1, 3, job_executor.clone());
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(2000));
|
||||||
|
/* assert that only one request per 3 milliseconds is accepted */
|
||||||
|
for _ in 0..5 {
|
||||||
|
assert!(rt.tick());
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(1));
|
||||||
|
assert!(!rt.tick());
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(1));
|
||||||
|
assert!(!rt.tick());
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(1));
|
||||||
|
/* How many times was the signal handler called? We've slept for at least 3
|
||||||
|
* milliseconds, so it should have been called once */
|
||||||
|
let mut ctr = 0;
|
||||||
|
while receiver.try_recv().is_ok() {
|
||||||
|
ctr += 1;
|
||||||
|
println!("got {}", ctr);
|
||||||
|
}
|
||||||
|
println!("ctr = {} {}", ctr, ctr == 1);
|
||||||
|
assert_eq!(ctr, 1);
|
||||||
|
}
|
||||||
|
/* next, test at most 100 requests per second */
|
||||||
|
let mut rt = RateLimit::new(100, 1000, job_executor.clone());
|
||||||
|
for _ in 0..5 {
|
||||||
|
let mut ctr = 0;
|
||||||
|
for _ in 0..500 {
|
||||||
|
if rt.tick() {
|
||||||
|
ctr += 1;
|
||||||
|
}
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(2));
|
||||||
|
}
|
||||||
|
/* around 100 requests should succeed. might be 99 if in first loop, since
|
||||||
|
* RateLimit::new() has a delay */
|
||||||
|
assert!(ctr > 97 && ctr < 103);
|
||||||
|
/* alarm should expire in 1 second */
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||||
|
/* How many times was the signal handler called? */
|
||||||
|
ctr = 0;
|
||||||
|
while receiver.try_recv().is_ok() {
|
||||||
|
ctr += 1;
|
||||||
|
}
|
||||||
|
assert_eq!(ctr, 1);
|
||||||
|
}
|
||||||
|
/* next, test at most 500 requests per second */
|
||||||
|
let mut rt = RateLimit::new(500, 1000, job_executor.clone());
|
||||||
|
for _ in 0..5 {
|
||||||
|
let mut ctr = 0;
|
||||||
|
for _ in 0..500 {
|
||||||
|
if rt.tick() {
|
||||||
|
ctr += 1;
|
||||||
|
}
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(2));
|
||||||
|
}
|
||||||
|
/* all requests should succeed. */
|
||||||
|
assert!(ctr < 503 && ctr > 497);
|
||||||
|
/* alarm should expire in 1 second */
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||||
|
/* How many times was the signal handler called? */
|
||||||
|
ctr = 0;
|
||||||
|
while receiver.try_recv().is_ok() {
|
||||||
|
ctr += 1;
|
||||||
|
}
|
||||||
|
assert_eq!(ctr, 1);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ pub fn create_temp_file(
|
||||||
dir.push(filename)
|
dir.push(filename)
|
||||||
} else {
|
} else {
|
||||||
let u = Uuid::new_v4();
|
let u = Uuid::new_v4();
|
||||||
dir.push(u.as_hyphenated().to_string());
|
dir.push(u.as_simple().to_string());
|
||||||
}
|
}
|
||||||
&mut dir
|
&mut dir
|
||||||
});
|
});
|
||||||
|
|
|
@ -101,7 +101,7 @@ impl EmbedContainer {
|
||||||
embed_area: ((0, 0), (80, 20)),
|
embed_area: ((0, 0), (80, 20)),
|
||||||
dirty: true,
|
dirty: true,
|
||||||
log_file: File::open(".embed.out").unwrap(),
|
log_file: File::open(".embed.out").unwrap(),
|
||||||
id: ComponentId::new_v4(),
|
id: ComponentId::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue