cargo_e/
e_eventdispatcher.rs1use regex::Regex;
2use std::fmt;
3use std::sync::atomic::AtomicBool;
4use std::sync::atomic::Ordering;
5use std::sync::Arc;
6use std::sync::Mutex;
7
8use crate::e_command_builder::TerminalError;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
12pub enum CargoDiagnosticLevel {
13 Error,
14 Warning,
15 Help,
16 Note,
17}
18
19#[derive(Debug, Clone)]
53pub enum CallbackType {
54 LevelMessage,
55 Warning,
56 Error,
57 Help,
58 Note,
59 Location,
60 OpenedUrl,
61 Unspecified,
62 Suggestion,
63}
64
65#[derive(Debug, Clone)]
67pub struct CallbackResponse {
68 pub callback_type: CallbackType,
69 pub message: Option<String>,
70 pub file: Option<String>,
71 pub line: Option<usize>,
72 pub column: Option<usize>,
73 pub suggestion: Option<String>,
74 pub terminal_status: Option<TerminalError>,
75}
76
77#[derive(Clone)]
78pub struct PatternCallback {
79 pub pattern: Regex,
80 pub callback: Arc<
82 dyn Fn(&str, Option<regex::Captures>, Arc<AtomicBool>) -> Option<CallbackResponse>
83 + Send
84 + Sync,
85 >,
86 pub is_reading_multiline: Arc<AtomicBool>,
87}
88
89impl fmt::Debug for PatternCallback {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 f.debug_struct("PatternCallback")
92 .field("pattern", &self.pattern.as_str())
93 .field("callback", &"Closure")
94 .finish()
95 }
96}
97
98impl PatternCallback {
99 pub fn new(
100 pattern: &str,
101 callback: Box<
102 dyn Fn(&str, Option<regex::Captures>, Arc<AtomicBool>) -> Option<CallbackResponse>
103 + Send
104 + Sync,
105 >,
106 ) -> Self {
107 PatternCallback {
108 pattern: Regex::new(pattern).expect("Invalid regex"),
109 callback: Arc::new(callback),
110 is_reading_multiline: Arc::new(AtomicBool::new(false)),
111 }
112 }
113}
114
115#[derive(Clone, Debug)]
117pub struct EventDispatcher {
118 pub callbacks: Arc<Mutex<Vec<PatternCallback>>>,
119}
120
121impl EventDispatcher {
122 pub fn new() -> Self {
123 EventDispatcher {
124 callbacks: Arc::new(Mutex::new(Vec::new())),
125 }
126 }
127
128 pub fn add_callback(
130 &mut self,
131 pattern: &str,
132 callback: Box<
133 dyn Fn(&str, Option<regex::Captures>, Arc<AtomicBool>) -> Option<CallbackResponse>
134 + Send
135 + Sync,
136 >,
137 ) {
138 if let Ok(mut callbacks) = self.callbacks.lock() {
139 callbacks.push(PatternCallback::new(pattern, callback));
140 } else {
141 eprintln!("Failed to acquire lock on callbacks in add_callback");
142 }
143 }
144
145 pub fn dispatch(&self, line: &str) -> Vec<Option<CallbackResponse>> {
147 let mut responses = Vec::new();
148 if let Ok(callbacks) = self.callbacks.lock() {
149 for cb in callbacks.iter() {
150 let state = Arc::clone(&cb.is_reading_multiline);
151 if state.load(Ordering::Relaxed) {
152 let response = (cb.callback)(line, None, state);
154 responses.push(response);
155 } else if let Some(captures) = cb.pattern.captures(line) {
156 let response = (cb.callback)(line, Some(captures), state);
158 responses.push(response);
159 } else if cb.pattern.is_match(line) {
160 let response = (cb.callback)(line, None, state);
162 responses.push(response);
163 }
164 }
165 } else {
166 eprintln!("Failed to acquire lock on callbacks in dispatch");
167 }
168 responses
169 }
170}