use super::EventType;
use crate::object_model::ObjectHandle;
use std::time::Instant;
#[derive(Clone, Debug)]
pub struct EventArgs {
pub event_type: EventType,
pub window: Option<ObjectHandle>,
pub pane: Option<ObjectHandle>,
pub tab: Option<ObjectHandle>,
pub data: EventData,
pub timestamp: Instant,
}
impl EventArgs {
pub fn new(event_type: EventType) -> Self {
Self {
event_type,
window: None,
pane: None,
tab: None,
data: EventData::None,
timestamp: Instant::now(),
}
}
pub fn with_window(mut self, handle: ObjectHandle) -> Self {
self.window = Some(handle);
self
}
pub fn with_pane(mut self, handle: ObjectHandle) -> Self {
self.pane = Some(handle);
self
}
pub fn with_tab(mut self, handle: ObjectHandle) -> Self {
self.tab = Some(handle);
self
}
pub fn with_data(mut self, data: EventData) -> Self {
self.data = data;
self
}
pub fn data(&self) -> &EventData {
&self.data
}
pub fn has_window(&self) -> bool {
self.window.is_some()
}
pub fn has_pane(&self) -> bool {
self.pane.is_some()
}
pub fn has_tab(&self) -> bool {
self.tab.is_some()
}
pub fn age(&self) -> std::time::Duration {
self.timestamp.elapsed()
}
}
#[derive(Clone, Debug, Default)]
pub enum EventData {
#[default]
None,
Text(String),
Uri(String),
FocusState {
is_focused: bool,
},
Dimensions {
cols: u16,
rows: u16,
},
TitleChange {
old: String,
new: String,
},
UserVar {
name: String,
value: String,
},
Selection {
text: String,
start: (u16, u16),
end: (u16, u16),
},
ExitCode(i32),
Binary(Vec<u8>),
}
impl EventData {
pub fn as_text(&self) -> Option<&str> {
match self {
EventData::Text(s) => Some(s),
_ => None,
}
}
pub fn as_uri(&self) -> Option<&str> {
match self {
EventData::Uri(s) => Some(s),
_ => None,
}
}
pub fn as_focus_state(&self) -> Option<bool> {
match self {
EventData::FocusState { is_focused } => Some(*is_focused),
_ => None,
}
}
pub fn as_dimensions(&self) -> Option<(u16, u16)> {
match self {
EventData::Dimensions { cols, rows } => Some((*cols, *rows)),
_ => None,
}
}
pub fn as_title_change(&self) -> Option<(&str, &str)> {
match self {
EventData::TitleChange { old, new } => Some((old, new)),
_ => None,
}
}
pub fn as_user_var(&self) -> Option<(&str, &str)> {
match self {
EventData::UserVar { name, value } => Some((name, value)),
_ => None,
}
}
pub fn as_selection(&self) -> Option<(&str, (u16, u16), (u16, u16))> {
match self {
EventData::Selection { text, start, end } => Some((text, *start, *end)),
_ => None,
}
}
pub fn as_exit_code(&self) -> Option<i32> {
match self {
EventData::ExitCode(code) => Some(*code),
_ => None,
}
}
pub fn as_binary(&self) -> Option<&[u8]> {
match self {
EventData::Binary(data) => Some(data),
_ => None,
}
}
pub fn is_none(&self) -> bool {
matches!(self, EventData::None)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::object_model::ObjectType;
#[test]
fn test_event_args_builder() {
let window = ObjectHandle::new(ObjectType::Window, 1, 0);
let pane = ObjectHandle::new(ObjectType::Pane, 2, 0);
let args = EventArgs::new(EventType::PaneFocused)
.with_window(window)
.with_pane(pane)
.with_data(EventData::FocusState { is_focused: true });
assert_eq!(args.event_type, EventType::PaneFocused);
assert_eq!(args.window, Some(window));
assert_eq!(args.pane, Some(pane));
assert!(args.has_window());
assert!(args.has_pane());
assert!(!args.has_tab());
assert!(args.data.as_focus_state().unwrap());
}
#[test]
fn test_event_data_text() {
let data = EventData::Text("hello".to_string());
assert_eq!(data.as_text(), Some("hello"));
assert!(data.as_uri().is_none());
assert!(!data.is_none());
}
#[test]
fn test_event_data_dimensions() {
let data = EventData::Dimensions { cols: 80, rows: 24 };
assert_eq!(data.as_dimensions(), Some((80, 24)));
assert!(data.as_text().is_none());
}
#[test]
fn test_event_data_selection() {
let data = EventData::Selection {
text: "selected".to_string(),
start: (0, 0),
end: (8, 0),
};
let (text, start, end) = data.as_selection().unwrap();
assert_eq!(text, "selected");
assert_eq!(start, (0, 0));
assert_eq!(end, (8, 0));
}
#[test]
fn test_event_data_user_var() {
let data = EventData::UserVar {
name: "CWD".to_string(),
value: "/home/user".to_string(),
};
let (name, value) = data.as_user_var().unwrap();
assert_eq!(name, "CWD");
assert_eq!(value, "/home/user");
}
#[test]
fn test_event_data_title_change() {
let data = EventData::TitleChange {
old: "old title".to_string(),
new: "new title".to_string(),
};
let (old, new) = data.as_title_change().unwrap();
assert_eq!(old, "old title");
assert_eq!(new, "new title");
}
#[test]
fn test_event_data_exit_code() {
let data = EventData::ExitCode(42);
assert_eq!(data.as_exit_code(), Some(42));
}
#[test]
fn test_event_data_binary() {
let bytes = vec![1, 2, 3, 4];
let data = EventData::Binary(bytes.clone());
assert_eq!(data.as_binary(), Some(bytes.as_slice()));
}
#[test]
fn test_event_args_age() {
let args = EventArgs::new(EventType::Bell);
std::thread::sleep(std::time::Duration::from_millis(10));
assert!(args.age().as_millis() >= 10);
}
}