add_ed/error/
mod.rs

1//! Holds Error type for the crate
2
3use std::rc::Rc;
4use std::borrow::Cow;
5
6pub type Result<T> = std::result::Result<T, EdError>;
7
8#[macro_use]
9mod internal;
10pub use internal::*;
11
12// Define structs and traits for UI and IO errors
13/// A trait to mark fulfilling the requirements put upon UI error types.
14pub trait UIErrorTrait: std::error::Error + as_any::AsAny + 'static {}
15/// A wrapping struct for any UI's error type
16///
17/// To use the wrapper implement [`UIErrorTrait`] on the error type to wrap and
18/// use `.into()` to convert it into this UIError wrapper.
19#[derive(Clone, Debug)]
20pub struct UIError {
21  pub inner: Rc<dyn UIErrorTrait>,
22}
23impl UIError {
24  /// Helper for downcasting into the internal error type
25  ///
26  /// Due to how finnicky this is to get right, with coercing the Rc<T> into &T
27  /// before downcasting, I very much recommend using this helper.
28  pub fn downcast_ref<T: UIErrorTrait>(&self) -> Option<&T> {
29    use as_any::Downcast;
30    (&*self.inner).downcast_ref::<T>()
31  }
32}
33/// A trait to mark fulfilling the requirements put upon IO error types.
34pub trait IOErrorTrait: std::error::Error + as_any::AsAny + 'static {}
35/// A wrapper type for any IO implementation's error type
36///
37/// To use the wrapper implement [`IOErrorTrait`] on the error type to wrap. The
38/// return types on the [`crate::IO`] trait's methods will give automatic
39/// conversion via the `?` operator in a lot of cases, but in some cases it is
40/// likely still needed to call `.into()` to convert.
41#[derive(Clone, Debug)]
42pub struct IOError {
43  pub inner: Rc<dyn IOErrorTrait>,
44}
45impl IOError {
46  /// Helper for downcasting into the internal error type
47  ///
48  /// Due to how finnicky this is to get right, with coercing the Rc<T> into &T
49  /// before downcasting, I very much recommend using this helper.
50  pub fn downcast_ref<T: IOErrorTrait>(&self) -> Option<&T> {
51    use as_any::Downcast;
52    (&*self.inner).downcast_ref::<T>()
53  }
54}
55
56// Large trait implementations in their own files
57mod display;
58mod partialeq;
59
60/// A basic enum Error implementation
61///
62/// Whilst it does implement `PartialEq`, partial is key in that. Since UI and
63/// IO errors aren't sure to be comparable they are assumed to be equal, so 
64/// library users can easily identify UI resp. IO errors and downcast them for
65/// the proper comparison for the abstracted type.
66#[derive(Debug, Clone)]
67pub enum EdError {
68  /// Internal error, usually from something OS related.
69  Internal(InternalError),
70  /// A holder for errors from the IO implementation.
71  ///
72  /// WARNING: internal equality of the held IO error will not be checked. You
73  /// will need to downcast and verify this yourself if relevant. (See helper on
74  /// [`IOError`].)
75  IO(IOError),
76  /// A holder for errors from the UI implementation.
77  ///
78  /// WARNING: internal equality of the held UI error will not be checked. You
79  /// will need to downcast and verify this yourself if relevant. (See helper on
80  /// [`UIError`].)
81  UI(UIError),
82
83  /// Execution recursed more times than [`Ed.recursion_limit`], indicating
84  /// infinite recursion.
85  ///
86  /// Contains no details until someone writes stack unwinding for it.
87  InfiniteRecursion,
88
89  // Selection/index interpretation/validation errors
90  /// Given index exceeds size of buffer.
91  ///
92  /// (Always given if buffer is empty)
93  IndexTooBig{index: usize, buffer_len: usize},
94  /// Index 0 isn't a valid line.
95  Line0Invalid,
96  /// Selection empty or inverted.
97  /// Holds the interpreted bad selection.
98  SelectionEmpty((usize, usize)),
99  /// Given command doesn't allow any selection and one was given.
100  SelectionForbidden,
101
102  // Command+argument+flag interpretation errors
103  /// Unsaved changes when about to non-forcibly drop/delete buffer.
104  UnsavedChanges,
105  /// Selection and arguments were given that makes its command do nothing.
106  NoOp,
107  /// Tried to undo beyond start of history.
108  UndoIndexNegative{relative_undo_limit: usize},
109  /// Tried to redo past end of history.
110  UndoIndexTooBig{index: usize, history_len: usize, relative_redo_limit: usize},
111  /// Tried to given shell escape where a file path is required.
112  /// Holds given path string.
113  CommandEscapeForbidden(String),
114  /// `k` or `K` command received an invalid character to tag with.
115  /// Holds given argument string.
116  TagInvalid(String),
117  /// Given tag found no match.
118  /// Holds the used tag.
119  TagNoMatch(char),
120  /// Any regex operation received an invalid regex or substitution.
121  RegexInvalid{regex: String, error: regex::Error},
122  /// Given regex found no match.
123  /// Holds the used regex.
124  RegexNoMatch(String),
125  /// Flags asked to print after the whole buffer was deleted.
126  PrintAfterWipe,
127
128  // Errors related to unset state variables
129  /// Tried to get default shell command, but it isn't yet set
130  DefaultFileUnset,
131  /// Tried to get default shell command, but it isn't yet set
132  DefaultShellCommandUnset,
133  /// Tried to get default `s` arguments, but it isn't yet set
134  DefaultSArgsUnset,
135
136  // Index parsing errors
137  /// Special index character found after start of index.
138  IndexSpecialAfterStart{prior_index: String, special_index: char},
139  /// Given index couldn't be parsed as a number.
140  /// Holds its text.
141  IndexNotInt(String),
142  /// Offset part of index couldn't be parsed as a number.
143  /// Holds its text.
144  OffsetNotInt(String),
145  /// Multiple indices with unclear relation (for example `'x2`)
146  IndicesUnrelated{prior_index: String, unrelated_index: String},
147  /// Unfinished index, a special index without its arguments.
148  /// Holds its text.
149  IndexUnfinished(String),
150
151  // Command and argument parsing errors
152  /// The given command doesn't exist.
153  /// Holds given command char.
154  CommandUndefined(char),
155  /// Argument list ended with `\`.
156  /// Holds whole argument list.
157  ArgumentListEscapedEnd(String),
158  /// Wrong number of argument.
159  ArgumentsWrongNr{expected: Cow<'static, str>, received: usize},
160  /// `z` command received a non numeric number of lines to scroll.
161  /// Holds given argument.
162  ScrollNotInt(String),
163  /// `u` or `U` command couldn't interpret nr of steps to undo/redo as integer.
164  /// Holds given argument.
165  UndoStepsNotInt(String),
166  /// `J` command received a non numeric number of columns to reflow within.
167  /// Holds given argument.
168  ReflowNotInt{error: String, text: String},
169  /// The macro invoked wasn't found.
170  /// Holds given macro name.
171  MacroUndefined(String),
172
173  // Flag parsing errors
174  /// Same flag appears more than once.
175  /// Holds duplicated flag.
176  FlagDuplicate(char),
177  /// Unexpected flag was received.
178  /// Holds undefined flag.
179  FlagUndefined(char),
180}
181
182impl std::error::Error for EdError {}
183
184impl From<UIError> for EdError {
185  fn from(e: UIError) -> Self {
186    Self::UI(e)
187  }
188}
189impl<E: UIErrorTrait> From<E> for UIError {
190  fn from(e: E) -> Self {
191    Self{ inner: Rc::new(e) }
192  }
193}
194// Causes conflicting trait bounds error for now. Instead use
195// Into::<UIError>::into(error).into() to convert via UIError.
196//impl<E: UIErrorTrait> From<E> for EdError {
197//  fn from(e: E) -> Self {
198//    Self::UI(e.into())
199//  }
200//}
201impl From<IOError> for EdError {
202  fn from(e: IOError) -> Self {
203    Self::IO(e)
204  }
205}
206impl<E: IOErrorTrait> From<E> for IOError {
207  fn from(e: E) -> Self {
208    Self{ inner: Rc::new(e) }
209  }
210}
211// Causes conflicting trait bounds error for now. Instead use
212// Into::<IOError>::into(error).into() to convert via IOError.
213//impl<E: IOErrorTrait> From<E> for EdError {
214// fn from(e: E) -> Self {
215//   Self::IO(e.into())
216// }
217//}
218impl From<InternalError> for EdError {
219  fn from(e: InternalError) -> Self {
220    Self::Internal(e)
221  }
222}
223
224impl EdError {
225  pub fn regex_error<S: Into<String>>(error: regex::Error, regex: S) -> Self {
226    Self::RegexInvalid{regex: regex.into(), error: error}
227  }
228}