topiary_config/
error.rs

1use std::{error, fmt, io, path, result};
2
3pub type TopiaryConfigResult<T> = result::Result<T, TopiaryConfigError>;
4
5#[derive(Debug)]
6#[allow(clippy::large_enum_variant)]
7pub enum TopiaryConfigError {
8    FileNotFound(path::PathBuf),
9    UnknownLanguage(String),
10    UnknownExtension(String),
11    NoExtension(path::PathBuf),
12    #[cfg(not(target_arch = "wasm32"))]
13    QueryFileNotFound(path::PathBuf),
14    Io(io::Error),
15    Missing,
16    TreeSitterFacade(topiary_tree_sitter_facade::LanguageError),
17    Nickel(Box<nickel_lang_core::error::Error>),
18    NickelDeserialization(nickel_lang_core::deserialize::RustDeserializationError),
19    #[cfg(not(target_arch = "wasm32"))]
20    Fetching(TopiaryConfigFetchingError),
21}
22
23#[derive(Debug)]
24/// Topiary can fetch an compile grammars, doing so may create errors.
25/// Usually, this error would be part of the `TopiaryConfigError`, however, that enum also includes `nickel_lang_core::error::Error`, which does not implement Sync/Send.
26/// Since fetching an compilation is something that can easily be parallelized, we create a special error that DOES implement Sync/Send.
27#[cfg(not(target_arch = "wasm32"))]
28pub enum TopiaryConfigFetchingError {
29    Git(anyhow::Error),
30    Build(tree_sitter_loader::LoaderError),
31    Io(io::Error),
32    LibLoading(libloading::Error),
33    GrammarFileNotFound(path::PathBuf),
34}
35
36impl fmt::Display for TopiaryConfigError {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        match self {
39            TopiaryConfigError::FileNotFound(path) => write!(
40                f,
41                "We tried to find your configuration file at {}, but failed to do so. Make sure the file exists.",
42                path.display()
43            ),
44            TopiaryConfigError::UnknownLanguage(lang) => write!(
45                f,
46                "You were looking for language \"{lang}\", but we do not know that language."
47            ),
48            TopiaryConfigError::UnknownExtension(ext) => write!(
49                f,
50                "You tried to format a file with extension: \"{ext}\", but we do not know that extension. Make sure the extension is in your configuration file!"
51            ),
52            TopiaryConfigError::NoExtension(path) => write!(
53                f,
54                "You tried to format {} without specifying a language, but we cannot automatically detect the language because we can't find the filetype extension.",
55                path.display()
56            ),
57            #[cfg(not(target_arch = "wasm32"))]
58            TopiaryConfigError::QueryFileNotFound(path) => write!(
59                f,
60                "We could not find the query file: \"{}\" anywhere. If you use the TOPIARY_LANGUAGE_DIR environment variable, make sure it set set correctly.",
61                path.display()
62            ),
63            TopiaryConfigError::Io(error) => write!(f, "We encountered an io error: {error}"),
64            TopiaryConfigError::Missing => write!(
65                f,
66                "A configuration file is missing. If you passed a configuration file, make sure it exists."
67            ),
68            TopiaryConfigError::TreeSitterFacade(_) => {
69                write!(f, "We could not load the grammar for the given language")
70            }
71            TopiaryConfigError::Nickel(e) => write!(
72                f,
73                "Nickel error: {e:#?}\n\nDid you forget to add a \"priority\" annotation in your config file?"
74            ),
75            TopiaryConfigError::NickelDeserialization(e) => write!(f, "Nickel error: {e:#?}"),
76            #[cfg(not(target_arch = "wasm32"))]
77            TopiaryConfigError::Fetching(e) => write!(f, "Error Fetching Language: {e}"),
78        }
79    }
80}
81
82#[cfg(not(target_arch = "wasm32"))]
83impl fmt::Display for TopiaryConfigFetchingError {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        match self {
86            TopiaryConfigFetchingError::Git(e) => write!(f, "Git error: {e:?}"),
87            TopiaryConfigFetchingError::Build(e) => {
88                write!(f, "Compilation error: {e},")
89            }
90            TopiaryConfigFetchingError::Io(error) => {
91                write!(f, "We encountered an io error: {error}")
92            }
93            TopiaryConfigFetchingError::LibLoading(e) => write!(f, "Libloading error: {e:?}"),
94            TopiaryConfigFetchingError::GrammarFileNotFound(path) => write!(
95                f,
96                "Attempted to load grammar at `{}`, but no file found",
97                path.display()
98            ),
99        }
100    }
101}
102
103impl From<nickel_lang_core::deserialize::RustDeserializationError> for TopiaryConfigError {
104    fn from(e: nickel_lang_core::deserialize::RustDeserializationError) -> Self {
105        Self::NickelDeserialization(e)
106    }
107}
108
109impl From<nickel_lang_core::error::Error> for TopiaryConfigError {
110    fn from(e: nickel_lang_core::error::Error) -> Self {
111        Self::Nickel(e.into())
112    }
113}
114
115#[cfg(not(target_arch = "wasm32"))]
116impl From<TopiaryConfigFetchingError> for TopiaryConfigError {
117    fn from(e: TopiaryConfigFetchingError) -> Self {
118        Self::Fetching(e)
119    }
120}
121
122impl From<io::Error> for TopiaryConfigError {
123    fn from(e: io::Error) -> Self {
124        Self::Io(e)
125    }
126}
127
128#[cfg(not(target_arch = "wasm32"))]
129impl From<io::Error> for TopiaryConfigFetchingError {
130    fn from(e: io::Error) -> Self {
131        Self::Io(e)
132    }
133}
134
135impl From<topiary_tree_sitter_facade::LanguageError> for TopiaryConfigError {
136    fn from(e: topiary_tree_sitter_facade::LanguageError) -> Self {
137        Self::TreeSitterFacade(e)
138    }
139}
140
141#[cfg(not(target_arch = "wasm32"))]
142impl From<libloading::Error> for TopiaryConfigFetchingError {
143    fn from(e: libloading::Error) -> Self {
144        Self::LibLoading(e)
145    }
146}
147
148impl error::Error for TopiaryConfigError {
149    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
150        match self {
151            #[cfg(not(target_arch = "wasm32"))]
152            TopiaryConfigError::Io(e) => e.source(),
153            _ => None,
154        }
155    }
156}