ass_editor/events/
mod.rs

1//! Event system for document changes and editor notifications  
2//!
3//! Provides `DocumentEvent` enum for representing editor changes and
4//! `EventChannel` for distributing events to observers. Supports both
5//! synchronous and asynchronous event handling with filtering.
6
7#[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/// Types of events that can occur in the editor
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub enum DocumentEvent {
44    /// Text was inserted at a position
45    TextInserted {
46        /// Position where text was inserted
47        position: Position,
48        /// Text that was inserted
49        text: String,
50        /// Length of inserted text in bytes
51        length: usize,
52    },
53
54    /// Text was deleted from a range
55    TextDeleted {
56        /// Range where text was deleted
57        range: Range,
58        /// Text that was deleted (for undo purposes)
59        deleted_text: String,
60    },
61
62    /// Text was replaced in a range
63    TextReplaced {
64        /// Range where text was replaced
65        range: Range,
66        /// Old text that was replaced
67        old_text: String,
68        /// New text that replaced the old text
69        new_text: String,
70    },
71
72    /// Selection changed
73    SelectionChanged {
74        /// Previous selection range (if any)
75        old_selection: Option<Range>,
76        /// New selection range (if any)
77        new_selection: Option<Range>,
78    },
79
80    /// Cursor position changed
81    CursorMoved {
82        /// Previous cursor position
83        old_position: Position,
84        /// New cursor position
85        new_position: Position,
86    },
87
88    /// Document was saved to a file
89    DocumentSaved {
90        /// File path where document was saved
91        file_path: String,
92        /// Whether this was a "save as" operation
93        save_as: bool,
94    },
95
96    /// Document was loaded from a file
97    DocumentLoaded {
98        /// File path from which document was loaded
99        file_path: String,
100        /// Size of loaded document in bytes
101        size: usize,
102    },
103
104    /// Undo operation was performed
105    UndoPerformed {
106        /// Description of the undone action
107        action_description: String,
108        /// Number of changes undone
109        changes_count: usize,
110    },
111
112    /// Redo operation was performed  
113    RedoPerformed {
114        /// Description of the redone action
115        action_description: String,
116        /// Number of changes redone
117        changes_count: usize,
118    },
119
120    /// Validation completed with results
121    ValidationCompleted {
122        /// Number of issues found
123        issues_count: usize,
124        /// Number of errors found
125        error_count: usize,
126        /// Number of warnings found
127        warning_count: usize,
128        /// Time taken for validation in milliseconds
129        validation_time_ms: u64,
130    },
131
132    /// Search operation completed
133    SearchCompleted {
134        /// Search pattern that was used
135        pattern: String,
136        /// Number of matches found
137        matches_count: usize,
138        /// Whether the search hit the result limit
139        hit_limit: bool,
140        /// Time taken for search in microseconds
141        search_time_us: u64,
142    },
143
144    /// Document parsing completed
145    ParsingCompleted {
146        /// Whether parsing was successful
147        success: bool,
148        /// Number of sections parsed
149        sections_count: usize,
150        /// Time taken for parsing in milliseconds
151        parse_time_ms: u64,
152        /// Any error message if parsing failed
153        error_message: Option<String>,
154    },
155
156    /// Extension was loaded or unloaded
157    ExtensionChanged {
158        /// Name of the extension
159        extension_name: String,
160        /// Whether the extension was loaded (true) or unloaded (false)
161        loaded: bool,
162    },
163
164    /// Configuration setting changed
165    ConfigChanged {
166        /// Name of the configuration key
167        key: String,
168        /// Old value (if any)
169        old_value: Option<String>,
170        /// New value
171        new_value: String,
172    },
173
174    /// Generic custom event for extensions
175    CustomEvent {
176        /// Event type identifier
177        event_type: String,
178        /// Event data as key-value pairs
179        data: HashMap<String, String>,
180    },
181}
182
183impl DocumentEvent {
184    /// Get a human-readable description of the event
185    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    /// Check if this event represents a document modification
261    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    /// Check if this event affects the document's text content
273    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    /// Get the affected range for events that modify text
286    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/// Event filter for selective event handling
298#[derive(Debug, Clone)]
299pub struct EventFilter {
300    /// Event types to include (empty means all types)
301    include_types: Vec<String>,
302    /// Event types to exclude
303    exclude_types: Vec<String>,
304    /// Whether to include modification events
305    include_modifications: Option<bool>,
306    /// Whether to include cursor/selection events  
307    include_cursor_events: Option<bool>,
308}
309
310impl EventFilter {
311    /// Create a new event filter that accepts all events
312    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    /// Only include specific event types
322    pub fn include_types(mut self, types: Vec<String>) -> Self {
323        self.include_types = types;
324        self
325    }
326
327    /// Exclude specific event types
328    pub fn exclude_types(mut self, types: Vec<String>) -> Self {
329        self.exclude_types = types;
330        self
331    }
332
333    /// Set whether to include modification events
334    pub fn include_modifications(mut self, include: bool) -> Self {
335        self.include_modifications = Some(include);
336        self
337    }
338
339    /// Set whether to include cursor/selection events
340    pub fn include_cursor_events(mut self, include: bool) -> Self {
341        self.include_cursor_events = Some(include);
342        self
343    }
344
345    /// Check if an event passes this filter
346    pub fn matches(&self, event: &DocumentEvent) -> bool {
347        let event_type = event.event_type_name();
348
349        // Check exclude list first
350        if self.exclude_types.contains(&event_type) {
351            return false;
352        }
353
354        // Check include list if specified
355        if !self.include_types.is_empty() && !self.include_types.contains(&event_type) {
356            return false;
357        }
358
359        // Check modification filter
360        if let Some(include_mods) = self.include_modifications {
361            if event.is_modification() != include_mods {
362                return false;
363            }
364        }
365
366        // Check cursor event filter
367        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    /// Get the event type as a string for filtering
389    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
410/// Event handler trait for responding to document events
411pub trait EventHandler: Send + Sync {
412    /// Handle a document event
413    fn handle_event(&mut self, event: &DocumentEvent) -> Result<()>;
414
415    /// Get the event filter for this handler
416    fn event_filter(&self) -> EventFilter {
417        EventFilter::new()
418    }
419
420    /// Get handler priority (higher numbers = higher priority)
421    fn priority(&self) -> i32 {
422        0
423    }
424}
425
426/// Statistics about event handling
427#[derive(Debug, Clone, PartialEq, Eq)]
428pub struct EventStats {
429    /// Total number of events dispatched
430    pub events_dispatched: usize,
431    /// Number of handlers currently registered
432    pub handlers_count: usize,
433    /// Number of events dropped due to filters
434    pub events_filtered: usize,
435    /// Number of async events queued
436    pub async_events_queued: usize,
437    /// Average event processing time in microseconds
438    pub avg_processing_time_us: u64,
439}
440
441/// Event channel configuration
442#[derive(Debug, Clone)]
443pub struct EventChannelConfig {
444    /// Maximum number of handlers
445    pub max_handlers: usize,
446    /// Maximum size of async event queue
447    pub max_async_queue_size: usize,
448    /// Whether to enable event batching
449    pub enable_batching: bool,
450    /// Maximum batch size for event processing
451    pub max_batch_size: usize,
452    /// Whether to log events for debugging
453    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/// Event channel for distributing document events to handlers
469#[derive(Debug)]
470pub struct EventChannel {
471    /// Configuration for this channel
472    config: EventChannelConfig,
473
474    /// Registered event handlers
475    #[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    /// Event statistics
482    stats: EventStats,
483
484    /// Async event sender (if async feature is enabled)
485    #[cfg(feature = "async")]
486    async_sender: Option<mpsc::UnboundedSender<DocumentEvent>>,
487
488    /// Next handler ID for unique identification
489    next_handler_id: usize,
490}
491
492/// Information about a registered handler
493struct HandlerInfo {
494    /// Unique handler ID
495    id: usize,
496    /// Handler implementation
497    handler: Box<dyn EventHandler>,
498    /// Event filter for this handler
499    filter: EventFilter,
500    /// Handler priority
501    priority: i32,
502    /// Number of events processed by this handler
503    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    /// Create a new event channel with default configuration
520    pub fn new() -> Self {
521        Self::with_config(EventChannelConfig::default())
522    }
523
524    /// Create a new event channel with custom configuration
525    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    /// Register an event handler
546    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            // Sort by priority (highest first)
578            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            // Sort by priority (highest first)
593            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    /// Unregister an event handler by ID
601    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    /// Dispatch an event to all registered handlers
635    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        // Update average processing time
683        #[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    /// Dispatch multiple events in a batch
708    pub fn dispatch_batch(&mut self, events: Vec<DocumentEvent>) -> Result<()> {
709        if self.config.enable_batching && events.len() <= self.config.max_batch_size {
710            // Process as a batch
711            for event in events {
712                self.dispatch(event)?;
713            }
714        } else {
715            // Process individually
716            for event in events {
717                self.dispatch(event)?;
718            }
719        }
720        Ok(())
721    }
722
723    /// Get event statistics
724    pub fn stats(&self) -> &EventStats {
725        &self.stats
726    }
727
728    /// Clear all event handlers
729    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    /// Setup async event processing (requires async feature)
752    #[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    /// Dispatch event asynchronously (requires async feature)
760    #[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
785/// Convenience functions for creating common events
786impl DocumentEvent {
787    /// Create a text insertion event
788    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    /// Create a text deletion event
798    pub fn text_deleted(range: Range, deleted_text: String) -> Self {
799        Self::TextDeleted {
800            range,
801            deleted_text,
802        }
803    }
804
805    /// Create a text replacement event
806    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    /// Create a cursor moved event
815    pub fn cursor_moved(old_position: Position, new_position: Position) -> Self {
816        Self::CursorMoved {
817            old_position,
818            new_position,
819        }
820    }
821
822    /// Create a document saved event
823    pub fn document_saved(file_path: String, save_as: bool) -> Self {
824        Self::DocumentSaved { file_path, save_as }
825    }
826
827    /// Create a validation completed event
828    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    // Mock handler for testing
955    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        // This should be handled
1037        let insert_event = DocumentEvent::text_inserted(Position::new(0), "Hello".to_string());
1038        channel.dispatch(insert_event).unwrap();
1039
1040        // This should be filtered out
1041        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        // Register in reverse priority order
1056        channel.register_handler(low_priority_handler).unwrap();
1057        channel.register_handler(high_priority_handler).unwrap();
1058
1059        // Handlers should be sorted by priority internally
1060        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}