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