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}