1use std::io;
4use std::path::PathBuf;
5use thiserror::Error;
6
7#[derive(Error, Debug)]
9pub enum SelError {
10 #[error("invalid selector: {0}")]
12 InvalidSelector(String),
13
14 #[error("invalid regex: {0}")]
16 InvalidRegex(String),
17
18 #[error("positional selectors require a seekable file; stdin is line-only")]
20 PositionalWithStdin,
21
22 #[error("--invert-match requires --regex")]
24 InvertWithoutRegex,
25
26 #[error("--char-context requires --regex or a positional selector")]
28 CharContextWithoutTarget,
29
30 #[error("{path}: {source}")]
32 Io {
33 path: String,
34 #[source]
35 source: io::Error,
36 },
37
38 #[error("output file already exists: {} (use --force to overwrite)", .0.display())]
40 OutputExists(PathBuf),
41}
42
43pub type Result<T> = std::result::Result<T, SelError>;
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49 use std::io;
50 use std::path::PathBuf;
51
52 #[test]
53 fn io_error_includes_path() {
54 let err = SelError::Io {
55 path: "nope.txt".into(),
56 source: io::Error::new(io::ErrorKind::NotFound, "no such"),
57 };
58 let msg = format!("{err}");
59 assert!(msg.contains("nope.txt"), "got: {msg}");
60 }
61
62 #[test]
63 fn positional_with_stdin_has_clear_message() {
64 let err = SelError::PositionalWithStdin;
65 let msg = format!("{err}");
66 assert!(msg.contains("stdin"));
67 }
68
69 #[test]
70 fn output_exists_names_path() {
71 let err = SelError::OutputExists(PathBuf::from("out.txt"));
72 let msg = format!("{err}");
73 assert!(msg.contains("out.txt"));
74 assert!(msg.contains("--force"));
75 }
76}