1#[cfg(not(feature = "std"))]
8extern crate alloc;
9
10use crate::core::{Position, Range, Result};
11
12#[cfg(feature = "std")]
13use std::collections::HashMap;
14
15#[cfg(not(feature = "std"))]
16use alloc::collections::BTreeMap as HashMap;
17
18#[cfg(not(feature = "std"))]
19use alloc::{
20 boxed::Box,
21 format,
22 string::{String, ToString},
23 vec::Vec,
24};
25
26#[cfg(feature = "multi-thread")]
27use std::sync::{Arc, RwLock};
28
29#[cfg(not(feature = "multi-thread"))]
30use core::cell::RefCell;
31
32#[cfg(all(not(feature = "multi-thread"), not(feature = "std")))]
33use alloc::rc::Rc;
34
35#[cfg(all(not(feature = "multi-thread"), feature = "std"))]
36use std::rc::Rc;
37
38#[cfg(feature = "async")]
39use futures::channel::mpsc;
40
41#[derive(Debug, Clone, PartialEq, Eq)]
43pub enum DocumentEvent {
44 TextInserted {
46 position: Position,
48 text: String,
50 length: usize,
52 },
53
54 TextDeleted {
56 range: Range,
58 deleted_text: String,
60 },
61
62 TextReplaced {
64 range: Range,
66 old_text: String,
68 new_text: String,
70 },
71
72 SelectionChanged {
74 old_selection: Option<Range>,
76 new_selection: Option<Range>,
78 },
79
80 CursorMoved {
82 old_position: Position,
84 new_position: Position,
86 },
87
88 DocumentSaved {
90 file_path: String,
92 save_as: bool,
94 },
95
96 DocumentLoaded {
98 file_path: String,
100 size: usize,
102 },
103
104 UndoPerformed {
106 action_description: String,
108 changes_count: usize,
110 },
111
112 RedoPerformed {
114 action_description: String,
116 changes_count: usize,
118 },
119
120 ValidationCompleted {
122 issues_count: usize,
124 error_count: usize,
126 warning_count: usize,
128 validation_time_ms: u64,
130 },
131
132 SearchCompleted {
134 pattern: String,
136 matches_count: usize,
138 hit_limit: bool,
140 search_time_us: u64,
142 },
143
144 ParsingCompleted {
146 success: bool,
148 sections_count: usize,
150 parse_time_ms: u64,
152 error_message: Option<String>,
154 },
155
156 ExtensionChanged {
158 extension_name: String,
160 loaded: bool,
162 },
163
164 ConfigChanged {
166 key: String,
168 old_value: Option<String>,
170 new_value: String,
172 },
173
174 CustomEvent {
176 event_type: String,
178 data: HashMap<String, String>,
180 },
181}
182
183impl DocumentEvent {
184 pub fn description(&self) -> String {
186 match self {
187 Self::TextInserted { length, .. } => format!("Inserted {length} bytes of text"),
188 Self::TextDeleted { range, .. } => format!("Deleted text from {range}"),
189 Self::TextReplaced { range, .. } => format!("Replaced text in {range}"),
190 Self::SelectionChanged { .. } => "Selection changed".to_string(),
191 Self::CursorMoved { .. } => "Cursor moved".to_string(),
192 Self::DocumentSaved { file_path, save_as } => {
193 if *save_as {
194 format!("Saved document as '{file_path}'")
195 } else {
196 format!("Saved document to '{file_path}'")
197 }
198 }
199 Self::DocumentLoaded { file_path, size } => {
200 format!("Loaded document '{file_path}' ({size} bytes)")
201 }
202 Self::UndoPerformed {
203 action_description,
204 changes_count,
205 } => {
206 format!("Undid '{action_description}' ({changes_count} changes)")
207 }
208 Self::RedoPerformed {
209 action_description,
210 changes_count,
211 } => {
212 format!("Redid '{action_description}' ({changes_count} changes)")
213 }
214 Self::ValidationCompleted {
215 issues_count,
216 validation_time_ms,
217 ..
218 } => {
219 format!(
220 "Validation completed: {issues_count} issues found in {validation_time_ms}ms"
221 )
222 }
223 Self::SearchCompleted {
224 pattern,
225 matches_count,
226 search_time_us,
227 ..
228 } => {
229 format!(
230 "Search for '{pattern}' found {matches_count} matches in {search_time_us}μs"
231 )
232 }
233 Self::ParsingCompleted {
234 success,
235 sections_count,
236 parse_time_ms,
237 ..
238 } => {
239 if *success {
240 format!("Parsed {sections_count} sections in {parse_time_ms}ms")
241 } else {
242 format!("Parsing failed after {parse_time_ms}ms")
243 }
244 }
245 Self::ExtensionChanged {
246 extension_name,
247 loaded,
248 } => {
249 if *loaded {
250 format!("Loaded extension '{extension_name}'")
251 } else {
252 format!("Unloaded extension '{extension_name}'")
253 }
254 }
255 Self::ConfigChanged { key, .. } => format!("Configuration '{key}' changed"),
256 Self::CustomEvent { event_type, .. } => format!("Custom event: {event_type}"),
257 }
258 }
259
260 pub fn is_modification(&self) -> bool {
262 matches!(
263 self,
264 Self::TextInserted { .. }
265 | Self::TextDeleted { .. }
266 | Self::TextReplaced { .. }
267 | Self::UndoPerformed { .. }
268 | Self::RedoPerformed { .. }
269 )
270 }
271
272 pub fn affects_text(&self) -> bool {
274 matches!(
275 self,
276 Self::TextInserted { .. }
277 | Self::TextDeleted { .. }
278 | Self::TextReplaced { .. }
279 | Self::UndoPerformed { .. }
280 | Self::RedoPerformed { .. }
281 | Self::DocumentLoaded { .. }
282 )
283 }
284
285 pub fn affected_range(&self) -> Option<Range> {
287 match self {
288 Self::TextInserted {
289 position, length, ..
290 } => Some(Range::new(*position, position.advance(*length))),
291 Self::TextDeleted { range, .. } | Self::TextReplaced { range, .. } => Some(*range),
292 _ => None,
293 }
294 }
295}
296
297#[derive(Debug, Clone)]
299pub struct EventFilter {
300 include_types: Vec<String>,
302 exclude_types: Vec<String>,
304 include_modifications: Option<bool>,
306 include_cursor_events: Option<bool>,
308}
309
310impl EventFilter {
311 pub fn new() -> Self {
313 Self {
314 include_types: Vec::new(),
315 exclude_types: Vec::new(),
316 include_modifications: None,
317 include_cursor_events: None,
318 }
319 }
320
321 pub fn include_types(mut self, types: Vec<String>) -> Self {
323 self.include_types = types;
324 self
325 }
326
327 pub fn exclude_types(mut self, types: Vec<String>) -> Self {
329 self.exclude_types = types;
330 self
331 }
332
333 pub fn include_modifications(mut self, include: bool) -> Self {
335 self.include_modifications = Some(include);
336 self
337 }
338
339 pub fn include_cursor_events(mut self, include: bool) -> Self {
341 self.include_cursor_events = Some(include);
342 self
343 }
344
345 pub fn matches(&self, event: &DocumentEvent) -> bool {
347 let event_type = event.event_type_name();
348
349 if self.exclude_types.contains(&event_type) {
351 return false;
352 }
353
354 if !self.include_types.is_empty() && !self.include_types.contains(&event_type) {
356 return false;
357 }
358
359 if let Some(include_mods) = self.include_modifications {
361 if event.is_modification() != include_mods {
362 return false;
363 }
364 }
365
366 if let Some(include_cursor) = self.include_cursor_events {
368 let is_cursor_event = matches!(
369 event,
370 DocumentEvent::CursorMoved { .. } | DocumentEvent::SelectionChanged { .. }
371 );
372 if is_cursor_event != include_cursor {
373 return false;
374 }
375 }
376
377 true
378 }
379}
380
381impl Default for EventFilter {
382 fn default() -> Self {
383 Self::new()
384 }
385}
386
387impl DocumentEvent {
388 fn event_type_name(&self) -> String {
390 match self {
391 Self::TextInserted { .. } => "TextInserted".to_string(),
392 Self::TextDeleted { .. } => "TextDeleted".to_string(),
393 Self::TextReplaced { .. } => "TextReplaced".to_string(),
394 Self::SelectionChanged { .. } => "SelectionChanged".to_string(),
395 Self::CursorMoved { .. } => "CursorMoved".to_string(),
396 Self::DocumentSaved { .. } => "DocumentSaved".to_string(),
397 Self::DocumentLoaded { .. } => "DocumentLoaded".to_string(),
398 Self::UndoPerformed { .. } => "UndoPerformed".to_string(),
399 Self::RedoPerformed { .. } => "RedoPerformed".to_string(),
400 Self::ValidationCompleted { .. } => "ValidationCompleted".to_string(),
401 Self::SearchCompleted { .. } => "SearchCompleted".to_string(),
402 Self::ParsingCompleted { .. } => "ParsingCompleted".to_string(),
403 Self::ExtensionChanged { .. } => "ExtensionChanged".to_string(),
404 Self::ConfigChanged { .. } => "ConfigChanged".to_string(),
405 Self::CustomEvent { event_type, .. } => event_type.clone(),
406 }
407 }
408}
409
410pub trait EventHandler: Send + Sync {
412 fn handle_event(&mut self, event: &DocumentEvent) -> Result<()>;
414
415 fn event_filter(&self) -> EventFilter {
417 EventFilter::new()
418 }
419
420 fn priority(&self) -> i32 {
422 0
423 }
424}
425
426#[derive(Debug, Clone, PartialEq, Eq)]
428pub struct EventStats {
429 pub events_dispatched: usize,
431 pub handlers_count: usize,
433 pub events_filtered: usize,
435 pub async_events_queued: usize,
437 pub avg_processing_time_us: u64,
439}
440
441#[derive(Debug, Clone)]
443pub struct EventChannelConfig {
444 pub max_handlers: usize,
446 pub max_async_queue_size: usize,
448 pub enable_batching: bool,
450 pub max_batch_size: usize,
452 pub enable_logging: bool,
454}
455
456impl Default for EventChannelConfig {
457 fn default() -> Self {
458 Self {
459 max_handlers: 100,
460 max_async_queue_size: 1000,
461 enable_batching: false,
462 max_batch_size: 10,
463 enable_logging: false,
464 }
465 }
466}
467
468#[derive(Debug)]
470pub struct EventChannel {
471 config: EventChannelConfig,
473
474 #[cfg(feature = "multi-thread")]
476 handlers: Arc<RwLock<Vec<HandlerInfo>>>,
477
478 #[cfg(not(feature = "multi-thread"))]
479 handlers: Rc<RefCell<Vec<HandlerInfo>>>,
480
481 stats: EventStats,
483
484 #[cfg(feature = "async")]
486 async_sender: Option<mpsc::UnboundedSender<DocumentEvent>>,
487
488 next_handler_id: usize,
490}
491
492struct HandlerInfo {
494 id: usize,
496 handler: Box<dyn EventHandler>,
498 filter: EventFilter,
500 priority: i32,
502 events_processed: usize,
504}
505
506impl core::fmt::Debug for HandlerInfo {
507 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
508 f.debug_struct("HandlerInfo")
509 .field("id", &self.id)
510 .field("filter", &self.filter)
511 .field("priority", &self.priority)
512 .field("events_processed", &self.events_processed)
513 .field("handler", &"<EventHandler>")
514 .finish()
515 }
516}
517
518impl EventChannel {
519 pub fn new() -> Self {
521 Self::with_config(EventChannelConfig::default())
522 }
523
524 pub fn with_config(config: EventChannelConfig) -> Self {
526 Self {
527 config,
528 #[cfg(feature = "multi-thread")]
529 handlers: Arc::new(RwLock::new(Vec::new())),
530 #[cfg(not(feature = "multi-thread"))]
531 handlers: Rc::new(RefCell::new(Vec::new())),
532 stats: EventStats {
533 events_dispatched: 0,
534 handlers_count: 0,
535 events_filtered: 0,
536 async_events_queued: 0,
537 avg_processing_time_us: 0,
538 },
539 #[cfg(feature = "async")]
540 async_sender: None,
541 next_handler_id: 0,
542 }
543 }
544
545 pub fn register_handler(&mut self, handler: Box<dyn EventHandler>) -> Result<usize> {
547 let handler_id = self.next_handler_id;
548 self.next_handler_id += 1;
549
550 let filter = handler.event_filter();
551 let priority = handler.priority();
552
553 let handler_info = HandlerInfo {
554 id: handler_id,
555 handler,
556 filter,
557 priority,
558 events_processed: 0,
559 };
560
561 #[cfg(feature = "multi-thread")]
562 {
563 let mut handlers =
564 self.handlers
565 .write()
566 .map_err(|_| crate::core::EditorError::ThreadSafetyError {
567 message: "Failed to acquire write lock for handlers".to_string(),
568 })?;
569
570 if handlers.len() >= self.config.max_handlers {
571 return Err(crate::core::EditorError::CommandFailed {
572 message: format!("Handler limit reached: {}", self.config.max_handlers),
573 });
574 }
575
576 handlers.push(handler_info);
577 handlers.sort_by(|a, b| b.priority.cmp(&a.priority));
579 }
580
581 #[cfg(not(feature = "multi-thread"))]
582 {
583 let mut handlers = self.handlers.borrow_mut();
584
585 if handlers.len() >= self.config.max_handlers {
586 return Err(crate::core::EditorError::CommandFailed {
587 message: format!("Handler limit reached: {}", self.config.max_handlers),
588 });
589 }
590
591 handlers.push(handler_info);
592 handlers.sort_by(|a, b| b.priority.cmp(&a.priority));
594 }
595
596 self.stats.handlers_count += 1;
597 Ok(handler_id)
598 }
599
600 pub fn unregister_handler(&mut self, handler_id: usize) -> Result<bool> {
602 #[cfg(feature = "multi-thread")]
603 {
604 let mut handlers =
605 self.handlers
606 .write()
607 .map_err(|_| crate::core::EditorError::ThreadSafetyError {
608 message: "Failed to acquire write lock for handlers".to_string(),
609 })?;
610
611 if let Some(pos) = handlers.iter().position(|h| h.id == handler_id) {
612 handlers.remove(pos);
613 self.stats.handlers_count -= 1;
614 Ok(true)
615 } else {
616 Ok(false)
617 }
618 }
619
620 #[cfg(not(feature = "multi-thread"))]
621 {
622 let mut handlers = self.handlers.borrow_mut();
623
624 if let Some(pos) = handlers.iter().position(|h| h.id == handler_id) {
625 handlers.remove(pos);
626 self.stats.handlers_count -= 1;
627 Ok(true)
628 } else {
629 Ok(false)
630 }
631 }
632 }
633
634 pub fn dispatch(&mut self, event: DocumentEvent) -> Result<()> {
636 #[cfg(feature = "std")]
637 let start_time = std::time::Instant::now();
638
639 self.stats.events_dispatched += 1;
640
641 let mut filtered_count = 0;
642 #[allow(unused_variables, unused_assignments)]
643 let mut processed_count = 0;
644
645 #[cfg(feature = "multi-thread")]
646 {
647 let mut handlers =
648 self.handlers
649 .write()
650 .map_err(|_| crate::core::EditorError::ThreadSafetyError {
651 message: "Failed to acquire write lock for handlers".to_string(),
652 })?;
653
654 for handler_info in handlers.iter_mut() {
655 if handler_info.filter.matches(&event) {
656 handler_info.handler.handle_event(&event)?;
657 handler_info.events_processed += 1;
658 processed_count += 1;
659 } else {
660 filtered_count += 1;
661 }
662 }
663 }
664
665 #[cfg(not(feature = "multi-thread"))]
666 {
667 let mut handlers = self.handlers.borrow_mut();
668
669 for handler_info in handlers.iter_mut() {
670 if handler_info.filter.matches(&event) {
671 handler_info.handler.handle_event(&event)?;
672 handler_info.events_processed += 1;
673 processed_count += 1;
674 } else {
675 filtered_count += 1;
676 }
677 }
678 }
679
680 self.stats.events_filtered += filtered_count;
681
682 #[cfg(feature = "std")]
684 {
685 let processing_time = start_time.elapsed().as_micros() as u64;
686 if self.stats.events_dispatched == 1 {
687 self.stats.avg_processing_time_us = processing_time;
688 } else {
689 self.stats.avg_processing_time_us =
690 (self.stats.avg_processing_time_us + processing_time) / 2;
691 }
692 }
693
694 if self.config.enable_logging {
695 #[cfg(feature = "std")]
696 eprintln!(
697 "Event dispatched: {} -> {} handlers (filtered: {})",
698 event.description(),
699 processed_count,
700 filtered_count
701 );
702 }
703
704 Ok(())
705 }
706
707 pub fn dispatch_batch(&mut self, events: Vec<DocumentEvent>) -> Result<()> {
709 if self.config.enable_batching && events.len() <= self.config.max_batch_size {
710 for event in events {
712 self.dispatch(event)?;
713 }
714 } else {
715 for event in events {
717 self.dispatch(event)?;
718 }
719 }
720 Ok(())
721 }
722
723 pub fn stats(&self) -> &EventStats {
725 &self.stats
726 }
727
728 pub fn clear_handlers(&mut self) -> Result<()> {
730 #[cfg(feature = "multi-thread")]
731 {
732 let mut handlers =
733 self.handlers
734 .write()
735 .map_err(|_| crate::core::EditorError::ThreadSafetyError {
736 message: "Failed to acquire write lock for handlers".to_string(),
737 })?;
738 handlers.clear();
739 }
740
741 #[cfg(not(feature = "multi-thread"))]
742 {
743 let mut handlers = self.handlers.borrow_mut();
744 handlers.clear();
745 }
746
747 self.stats.handlers_count = 0;
748 Ok(())
749 }
750
751 #[cfg(feature = "async")]
753 pub fn setup_async(&mut self) -> mpsc::UnboundedReceiver<DocumentEvent> {
754 let (sender, receiver) = mpsc::unbounded();
755 self.async_sender = Some(sender);
756 receiver
757 }
758
759 #[cfg(feature = "async")]
761 pub fn dispatch_async(&mut self, event: DocumentEvent) -> Result<()> {
762 if let Some(ref sender) = self.async_sender {
763 sender
764 .unbounded_send(event)
765 .map_err(|_| crate::core::EditorError::CommandFailed {
766 message: "Failed to send async event".to_string(),
767 })?;
768 self.stats.async_events_queued += 1;
769 } else {
770 return Err(crate::core::EditorError::FeatureNotEnabled {
771 feature: "async event processing".to_string(),
772 required_feature: "async".to_string(),
773 });
774 }
775 Ok(())
776 }
777}
778
779impl Default for EventChannel {
780 fn default() -> Self {
781 Self::new()
782 }
783}
784
785impl DocumentEvent {
787 pub fn text_inserted(position: Position, text: String) -> Self {
789 let length = text.len();
790 Self::TextInserted {
791 position,
792 text,
793 length,
794 }
795 }
796
797 pub fn text_deleted(range: Range, deleted_text: String) -> Self {
799 Self::TextDeleted {
800 range,
801 deleted_text,
802 }
803 }
804
805 pub fn text_replaced(range: Range, old_text: String, new_text: String) -> Self {
807 Self::TextReplaced {
808 range,
809 old_text,
810 new_text,
811 }
812 }
813
814 pub fn cursor_moved(old_position: Position, new_position: Position) -> Self {
816 Self::CursorMoved {
817 old_position,
818 new_position,
819 }
820 }
821
822 pub fn document_saved(file_path: String, save_as: bool) -> Self {
824 Self::DocumentSaved { file_path, save_as }
825 }
826
827 pub fn validation_completed(
829 issues_count: usize,
830 error_count: usize,
831 warning_count: usize,
832 validation_time_ms: u64,
833 ) -> Self {
834 Self::ValidationCompleted {
835 issues_count,
836 error_count,
837 warning_count,
838 validation_time_ms,
839 }
840 }
841}
842
843#[cfg(test)]
844mod tests {
845 use super::*;
846 #[cfg(not(feature = "std"))]
847 use alloc::{string::ToString, vec};
848
849 #[test]
850 fn document_event_creation() {
851 let event = DocumentEvent::text_inserted(Position::new(0), "Hello".to_string());
852
853 match event {
854 DocumentEvent::TextInserted {
855 position,
856 text,
857 length,
858 } => {
859 assert_eq!(position.offset, 0);
860 assert_eq!(text, "Hello");
861 assert_eq!(length, 5);
862 }
863 _ => panic!("Expected TextInserted event"),
864 }
865 }
866
867 #[test]
868 fn document_event_description() {
869 let event = DocumentEvent::text_inserted(Position::new(0), "Hello".to_string());
870 assert_eq!(event.description(), "Inserted 5 bytes of text");
871
872 let event = DocumentEvent::cursor_moved(Position::new(0), Position::new(5));
873 assert_eq!(event.description(), "Cursor moved");
874 }
875
876 #[test]
877 fn document_event_modification_check() {
878 let insert_event = DocumentEvent::text_inserted(Position::new(0), "Hello".to_string());
879 assert!(insert_event.is_modification());
880
881 let cursor_event = DocumentEvent::cursor_moved(Position::new(0), Position::new(5));
882 assert!(!cursor_event.is_modification());
883 }
884
885 #[test]
886 fn document_event_affects_text() {
887 let insert_event = DocumentEvent::text_inserted(Position::new(0), "Hello".to_string());
888 assert!(insert_event.affects_text());
889
890 let config_event = DocumentEvent::ConfigChanged {
891 key: "font_size".to_string(),
892 old_value: Some("12".to_string()),
893 new_value: "14".to_string(),
894 };
895 assert!(!config_event.affects_text());
896 }
897
898 #[test]
899 fn document_event_affected_range() {
900 let insert_event = DocumentEvent::text_inserted(Position::new(10), "Hello".to_string());
901 let range = insert_event.affected_range().unwrap();
902 assert_eq!(range.start.offset, 10);
903 assert_eq!(range.end.offset, 15);
904
905 let cursor_event = DocumentEvent::cursor_moved(Position::new(0), Position::new(5));
906 assert!(cursor_event.affected_range().is_none());
907 }
908
909 #[test]
910 fn event_filter_creation() {
911 let filter = EventFilter::new()
912 .include_modifications(true)
913 .exclude_types(vec!["CursorMoved".to_string()]);
914
915 let insert_event = DocumentEvent::text_inserted(Position::new(0), "Hello".to_string());
916 assert!(filter.matches(&insert_event));
917
918 let cursor_event = DocumentEvent::cursor_moved(Position::new(0), Position::new(5));
919 assert!(!filter.matches(&cursor_event));
920 }
921
922 #[test]
923 fn event_filter_include_types() {
924 let filter = EventFilter::new()
925 .include_types(vec!["TextInserted".to_string(), "TextDeleted".to_string()]);
926
927 let insert_event = DocumentEvent::text_inserted(Position::new(0), "Hello".to_string());
928 assert!(filter.matches(&insert_event));
929
930 let cursor_event = DocumentEvent::cursor_moved(Position::new(0), Position::new(5));
931 assert!(!filter.matches(&cursor_event));
932 }
933
934 #[test]
935 fn event_channel_creation() {
936 let channel = EventChannel::new();
937 assert_eq!(channel.stats().handlers_count, 0);
938 assert_eq!(channel.stats().events_dispatched, 0);
939 }
940
941 #[test]
942 fn event_channel_config() {
943 let config = EventChannelConfig {
944 max_handlers: 50,
945 enable_logging: true,
946 ..Default::default()
947 };
948
949 let channel = EventChannel::with_config(config);
950 assert_eq!(channel.config.max_handlers, 50);
951 assert!(channel.config.enable_logging);
952 }
953
954 struct TestHandler {
956 events_received: Vec<String>,
957 filter: EventFilter,
958 priority: i32,
959 }
960
961 impl TestHandler {
962 fn new() -> Self {
963 Self {
964 events_received: Vec::new(),
965 filter: EventFilter::new(),
966 priority: 0,
967 }
968 }
969
970 fn with_filter(filter: EventFilter) -> Self {
971 Self {
972 events_received: Vec::new(),
973 filter,
974 priority: 0,
975 }
976 }
977
978 fn with_priority(priority: i32) -> Self {
979 Self {
980 events_received: Vec::new(),
981 filter: EventFilter::new(),
982 priority,
983 }
984 }
985 }
986
987 impl EventHandler for TestHandler {
988 fn handle_event(&mut self, event: &DocumentEvent) -> Result<()> {
989 self.events_received.push(event.description());
990 Ok(())
991 }
992
993 fn event_filter(&self) -> EventFilter {
994 self.filter.clone()
995 }
996
997 fn priority(&self) -> i32 {
998 self.priority
999 }
1000 }
1001
1002 #[test]
1003 fn event_channel_handler_registration() {
1004 let mut channel = EventChannel::new();
1005 let handler = Box::new(TestHandler::new());
1006
1007 let handler_id = channel.register_handler(handler).unwrap();
1008 assert_eq!(channel.stats().handlers_count, 1);
1009
1010 let removed = channel.unregister_handler(handler_id).unwrap();
1011 assert!(removed);
1012 assert_eq!(channel.stats().handlers_count, 0);
1013 }
1014
1015 #[test]
1016 fn event_channel_dispatch() {
1017 let mut channel = EventChannel::new();
1018 let handler = Box::new(TestHandler::new());
1019
1020 channel.register_handler(handler).unwrap();
1021
1022 let event = DocumentEvent::text_inserted(Position::new(0), "Hello".to_string());
1023 channel.dispatch(event).unwrap();
1024
1025 assert_eq!(channel.stats().events_dispatched, 1);
1026 }
1027
1028 #[test]
1029 fn event_channel_filtering() {
1030 let mut channel = EventChannel::new();
1031 let filter = EventFilter::new().exclude_types(vec!["CursorMoved".to_string()]);
1032 let handler = Box::new(TestHandler::with_filter(filter));
1033
1034 channel.register_handler(handler).unwrap();
1035
1036 let insert_event = DocumentEvent::text_inserted(Position::new(0), "Hello".to_string());
1038 channel.dispatch(insert_event).unwrap();
1039
1040 let cursor_event = DocumentEvent::cursor_moved(Position::new(0), Position::new(5));
1042 channel.dispatch(cursor_event).unwrap();
1043
1044 assert_eq!(channel.stats().events_dispatched, 2);
1045 assert_eq!(channel.stats().events_filtered, 1);
1046 }
1047
1048 #[test]
1049 fn event_channel_priority_ordering() {
1050 let mut channel = EventChannel::new();
1051
1052 let low_priority_handler = Box::new(TestHandler::with_priority(1));
1053 let high_priority_handler = Box::new(TestHandler::with_priority(10));
1054
1055 channel.register_handler(low_priority_handler).unwrap();
1057 channel.register_handler(high_priority_handler).unwrap();
1058
1059 assert_eq!(channel.stats().handlers_count, 2);
1061 }
1062
1063 #[test]
1064 fn event_channel_batch_dispatch() {
1065 let mut channel = EventChannel::new();
1066 let handler = Box::new(TestHandler::new());
1067
1068 channel.register_handler(handler).unwrap();
1069
1070 let events = vec![
1071 DocumentEvent::text_inserted(Position::new(0), "Hello".to_string()),
1072 DocumentEvent::text_inserted(Position::new(5), " World".to_string()),
1073 ];
1074
1075 channel.dispatch_batch(events).unwrap();
1076 assert_eq!(channel.stats().events_dispatched, 2);
1077 }
1078
1079 #[test]
1080 fn event_channel_clear_handlers() {
1081 let mut channel = EventChannel::new();
1082 let handler = Box::new(TestHandler::new());
1083
1084 channel.register_handler(handler).unwrap();
1085 assert_eq!(channel.stats().handlers_count, 1);
1086
1087 channel.clear_handlers().unwrap();
1088 assert_eq!(channel.stats().handlers_count, 0);
1089 }
1090}