1use ass_core::utils::errors::CoreError;
11use core::fmt;
12
13#[cfg(feature = "std")]
14use thiserror::Error;
15
16#[cfg(not(feature = "std"))]
17use alloc::string::{String, ToString};
18
19#[cfg_attr(feature = "std", derive(Error))]
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub enum EditorError {
26 #[cfg_attr(feature = "std", error(transparent))]
28 Core(CoreError),
29
30 #[cfg_attr(feature = "std", error("Document not found: {id}"))]
32 DocumentNotFound { id: String },
33
34 #[cfg_attr(
36 feature = "std",
37 error("Invalid position: line {line}, column {column}")
38 )]
39 InvalidPosition { line: usize, column: usize },
40
41 #[cfg_attr(
43 feature = "std",
44 error("Position out of bounds: {position} (document length: {length})")
45 )]
46 PositionOutOfBounds { position: usize, length: usize },
47
48 #[cfg_attr(
50 feature = "std",
51 error("Invalid range: start {start}, end {end} (document length: {length})")
52 )]
53 InvalidRange {
54 start: usize,
55 end: usize,
56 length: usize,
57 },
58
59 #[cfg_attr(feature = "std", error("Command execution failed: {message}"))]
61 CommandFailed { message: String },
62
63 #[cfg_attr(feature = "std", error("History operation failed: {message}"))]
65 HistoryError { message: String },
66
67 #[cfg_attr(feature = "std", error("Nothing to undo"))]
69 NothingToUndo,
70
71 #[cfg_attr(feature = "std", error("Nothing to redo"))]
73 NothingToRedo,
74
75 #[cfg_attr(
77 feature = "std",
78 error("Session limit exceeded: {current}/{limit} sessions")
79 )]
80 SessionLimitExceeded { current: usize, limit: usize },
81
82 #[cfg_attr(feature = "std", error("Search index error: {message}"))]
84 SearchIndexError { message: String },
85
86 #[cfg_attr(feature = "std", error("Extension error: {extension}: {message}"))]
88 ExtensionError { extension: String, message: String },
89
90 #[cfg_attr(
92 feature = "std",
93 error("Feature '{feature}' requires '{required_feature}' feature flag")
94 )]
95 FeatureNotEnabled {
96 feature: String,
97 required_feature: String,
98 },
99
100 #[cfg_attr(feature = "std", error("Arena allocation failed: {message}"))]
102 ArenaAllocationFailed { message: String },
103
104 #[cfg_attr(feature = "std", error("Section not found: {section}"))]
106 SectionNotFound { section: String },
107
108 #[cfg_attr(feature = "std", error("Rope operation failed: {message}"))]
110 RopeOperationFailed { message: String },
111
112 #[cfg_attr(feature = "std", error("Event channel error: {message}"))]
114 EventChannelError { message: String },
115
116 #[cfg_attr(feature = "std", error("Validation error: {message}"))]
118 ValidationError { message: String },
119
120 #[cfg_attr(feature = "std", error("IO error: {0}"))]
122 IoError(String),
123
124 #[cfg_attr(feature = "std", error("Invalid format: {0}"))]
126 InvalidFormat(String),
127
128 #[cfg_attr(feature = "std", error("Unsupported format: {0}"))]
130 UnsupportedFormat(String),
131
132 #[cfg_attr(feature = "std", error("Thread safety error: {message}"))]
134 ThreadSafetyError { message: String },
135
136 #[cfg_attr(feature = "std", error("Builder validation error: {message}"))]
138 BuilderValidationError { message: String },
139
140 #[cfg_attr(feature = "std", error("Serialization error: {message}"))]
142 SerializationError { message: String },
143
144 #[cfg_attr(feature = "std", error("Format line error: {message}"))]
146 FormatLineError { message: String },
147}
148
149impl EditorError {
150 pub fn command_failed<T: fmt::Display>(message: T) -> Self {
152 Self::CommandFailed {
153 message: message.to_string(),
154 }
155 }
156
157 pub fn validation<T: fmt::Display>(message: T) -> Self {
159 Self::ValidationError {
160 message: message.to_string(),
161 }
162 }
163
164 pub fn io<T: fmt::Display>(message: T) -> Self {
166 Self::IoError(message.to_string())
167 }
168
169 pub fn builder_validation<T: fmt::Display>(message: T) -> Self {
171 Self::BuilderValidationError {
172 message: message.to_string(),
173 }
174 }
175
176 pub fn serialization<T: fmt::Display>(message: T) -> Self {
178 Self::SerializationError {
179 message: message.to_string(),
180 }
181 }
182
183 pub fn format_line<T: fmt::Display>(message: T) -> Self {
185 Self::FormatLineError {
186 message: message.to_string(),
187 }
188 }
189
190 #[must_use]
192 pub const fn is_recoverable(&self) -> bool {
193 match self {
194 Self::Core(core_err) => core_err.is_recoverable(),
195 Self::DocumentNotFound { .. }
196 | Self::InvalidPosition { .. }
197 | Self::PositionOutOfBounds { .. }
198 | Self::InvalidRange { .. }
199 | Self::CommandFailed { .. }
200 | Self::HistoryError { .. }
201 | Self::NothingToUndo
202 | Self::NothingToRedo
203 | Self::SearchIndexError { .. }
204 | Self::ExtensionError { .. }
205 | Self::FeatureNotEnabled { .. }
206 | Self::RopeOperationFailed { .. }
207 | Self::EventChannelError { .. }
208 | Self::ValidationError { .. }
209 | Self::IoError(..)
210 | Self::InvalidFormat(..)
211 | Self::UnsupportedFormat(..)
212 | Self::BuilderValidationError { .. }
213 | Self::SerializationError { .. }
214 | Self::FormatLineError { .. }
215 | Self::SectionNotFound { .. } => true,
216 Self::SessionLimitExceeded { .. }
217 | Self::ArenaAllocationFailed { .. }
218 | Self::ThreadSafetyError { .. } => false,
219 }
220 }
221
222 #[must_use]
224 pub const fn is_position_error(&self) -> bool {
225 matches!(
226 self,
227 Self::InvalidPosition { .. }
228 | Self::PositionOutOfBounds { .. }
229 | Self::InvalidRange { .. }
230 )
231 }
232
233 #[must_use]
235 pub const fn is_history_error(&self) -> bool {
236 matches!(
237 self,
238 Self::HistoryError { .. } | Self::NothingToUndo | Self::NothingToRedo
239 )
240 }
241
242 #[must_use]
244 pub const fn as_core_error(&self) -> Option<&CoreError> {
245 match self {
246 Self::Core(core_err) => Some(core_err),
247 _ => None,
248 }
249 }
250}
251
252pub type Result<T> = core::result::Result<T, EditorError>;
254
255impl From<CoreError> for EditorError {
257 fn from(err: CoreError) -> Self {
258 Self::Core(err)
259 }
260}
261
262#[cfg(not(feature = "std"))]
264impl fmt::Display for EditorError {
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 match self {
267 Self::Core(err) => write!(f, "{err}"),
268 Self::DocumentNotFound { id } => write!(f, "Document not found: {id}"),
269 Self::InvalidPosition { line, column } => {
270 write!(f, "Invalid position: line {line}, column {column}")
271 }
272 Self::PositionOutOfBounds { position, length } => {
273 write!(
274 f,
275 "Position out of bounds: {position} (document length: {length})"
276 )
277 }
278 Self::InvalidRange { start, end, length } => {
279 write!(
280 f,
281 "Invalid range: start {start}, end {end} (document length: {length})"
282 )
283 }
284 Self::CommandFailed { message } => write!(f, "Command execution failed: {message}"),
285 Self::HistoryError { message } => write!(f, "History operation failed: {message}"),
286 Self::NothingToUndo => write!(f, "Nothing to undo"),
287 Self::NothingToRedo => write!(f, "Nothing to redo"),
288 Self::SessionLimitExceeded { current, limit } => {
289 write!(f, "Session limit exceeded: {current}/{limit} sessions")
290 }
291 Self::SearchIndexError { message } => write!(f, "Search index error: {message}"),
292 Self::ExtensionError { extension, message } => {
293 write!(f, "Extension error: {extension}: {message}")
294 }
295 Self::FeatureNotEnabled {
296 feature,
297 required_feature,
298 } => {
299 write!(
300 f,
301 "Feature '{feature}' requires '{required_feature}' feature flag"
302 )
303 }
304 Self::ArenaAllocationFailed { message } => {
305 write!(f, "Arena allocation failed: {message}")
306 }
307 Self::RopeOperationFailed { message } => write!(f, "Rope operation failed: {message}"),
308 Self::EventChannelError { message } => write!(f, "Event channel error: {message}"),
309 Self::ValidationError { message } => write!(f, "Validation error: {message}"),
310 Self::IoError(message) => write!(f, "IO error: {message}"),
311 Self::InvalidFormat(message) => write!(f, "Invalid format: {message}"),
312 Self::UnsupportedFormat(format) => write!(f, "Unsupported format: {format}"),
313 Self::ThreadSafetyError { message } => write!(f, "Thread safety error: {message}"),
314 Self::BuilderValidationError { message } => {
315 write!(f, "Builder validation error: {message}")
316 }
317 Self::SerializationError { message } => write!(f, "Serialization error: {message}"),
318 Self::FormatLineError { message } => write!(f, "Format line error: {message}"),
319 Self::SectionNotFound { section } => write!(f, "Section not found: {section}"),
320 }
321 }
322}
323
324#[cfg(not(feature = "std"))]
326impl core::error::Error for EditorError {}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331 #[cfg(not(feature = "std"))]
332 use alloc::string::ToString;
333
334 #[test]
335 fn error_conversion_from_core() {
336 let core_err = CoreError::parse("test error");
337 let editor_err: EditorError = core_err.into();
338 assert!(matches!(editor_err, EditorError::Core(_)));
339 }
340
341 #[test]
342 fn error_recoverability() {
343 assert!(EditorError::command_failed("test").is_recoverable());
344 assert!(EditorError::validation("test").is_recoverable());
345 assert!(!EditorError::SessionLimitExceeded {
346 current: 10,
347 limit: 10
348 }
349 .is_recoverable());
350 }
351
352 #[test]
353 fn position_error_detection() {
354 assert!(EditorError::InvalidPosition { line: 1, column: 1 }.is_position_error());
355 assert!(EditorError::PositionOutOfBounds {
356 position: 100,
357 length: 50
358 }
359 .is_position_error());
360 assert!(!EditorError::command_failed("test").is_position_error());
361 }
362
363 #[test]
364 fn history_error_detection() {
365 assert!(EditorError::NothingToUndo.is_history_error());
366 assert!(EditorError::NothingToRedo.is_history_error());
367 assert!(EditorError::HistoryError {
368 message: "test".to_string()
369 }
370 .is_history_error());
371 assert!(!EditorError::command_failed("test").is_history_error());
372 }
373
374 #[test]
375 fn core_error_extraction() {
376 let core_err = CoreError::parse("test");
377 let editor_err = EditorError::Core(core_err.clone());
378 assert_eq!(editor_err.as_core_error(), Some(&core_err));
379 assert_eq!(EditorError::command_failed("test").as_core_error(), None);
380 }
381
382 #[test]
383 fn new_error_types() {
384 let builder_err = EditorError::builder_validation("Invalid field value");
386 assert!(builder_err.is_recoverable());
387 assert!(matches!(
388 builder_err,
389 EditorError::BuilderValidationError { .. }
390 ));
391
392 let serialization_err = EditorError::serialization("Failed to serialize AST");
394 assert!(serialization_err.is_recoverable());
395 assert!(matches!(
396 serialization_err,
397 EditorError::SerializationError { .. }
398 ));
399
400 let format_err = EditorError::format_line("Invalid format specification");
402 assert!(format_err.is_recoverable());
403 assert!(matches!(format_err, EditorError::FormatLineError { .. }));
404 }
405
406 #[test]
407 fn error_display_new_types() {
408 let builder_err = EditorError::builder_validation("test");
409 assert_eq!(builder_err.to_string(), "Builder validation error: test");
410
411 let serialization_err = EditorError::serialization("test");
412 assert_eq!(serialization_err.to_string(), "Serialization error: test");
413
414 let format_err = EditorError::format_line("test");
415 assert_eq!(format_err.to_string(), "Format line error: test");
416 }
417}