1use std::io;
15
16pub type Result<T> = std::result::Result<T, Error>;
18
19#[derive(Debug)]
20pub enum Error {
21 Io(io::Error),
22 Json(serde_json::Error),
23 Prompt(netsky_prompts::prompt::PromptError),
24 Tmux(String),
25 MissingDep(&'static str),
26 SubprocessTimeout {
27 what: String,
28 ceiling_s: u64,
29 },
30 SubprocessFailed {
31 what: String,
32 code: i32,
33 },
34 AiUnknownModel(String),
35 AiJsonParse {
36 runtime: String,
37 detail: String,
38 },
39 AiMissingOutput {
40 runtime: String,
41 },
42 Invalid(String),
43 Message(String),
47}
48
49impl Error {
50 pub fn msg(s: impl Into<String>) -> Self {
51 Self::Message(s.into())
52 }
53}
54
55impl std::fmt::Display for Error {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 match self {
58 Self::Io(e) => write!(f, "I/O: {e}"),
59 Self::Json(e) => write!(f, "JSON: {e}"),
60 Self::Prompt(e) => write!(f, "prompt: {e}"),
61 Self::Tmux(s) => write!(f, "tmux: {s}"),
62 Self::MissingDep(s) => write!(f, "missing dep on PATH: {s}"),
63 Self::SubprocessTimeout { what, ceiling_s } => {
64 write!(f, "subprocess `{what}` timed out after {ceiling_s}s")
65 }
66 Self::SubprocessFailed { what, code } => {
67 write!(f, "subprocess `{what}` failed (exit {code})")
68 }
69 Self::AiUnknownModel(model) => write!(f, "unknown ai model `{model}`"),
70 Self::AiJsonParse { runtime, detail } => {
71 write!(f, "{runtime} JSON parse failed: {detail}")
72 }
73 Self::AiMissingOutput { runtime } => write!(f, "{runtime} JSON missing final text"),
74 Self::Invalid(s) => write!(f, "invalid input: {s}"),
75 Self::Message(s) => f.write_str(s),
76 }
77 }
78}
79
80impl std::error::Error for Error {
81 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
82 match self {
83 Self::Io(e) => Some(e),
84 Self::Json(e) => Some(e),
85 Self::Prompt(e) => Some(e),
86 _ => None,
87 }
88 }
89}
90
91impl From<io::Error> for Error {
92 fn from(e: io::Error) -> Self {
93 Self::Io(e)
94 }
95}
96
97impl From<serde_json::Error> for Error {
98 fn from(e: serde_json::Error) -> Self {
99 Self::Json(e)
100 }
101}
102
103impl From<netsky_prompts::prompt::PromptError> for Error {
104 fn from(e: netsky_prompts::prompt::PromptError) -> Self {
105 Self::Prompt(e)
106 }
107}
108
109impl From<netsky_sh::Error> for Error {
110 fn from(e: netsky_sh::Error) -> Self {
111 Self::Tmux(format!("{e}"))
115 }
116}
117
118impl From<std::time::SystemTimeError> for Error {
119 fn from(e: std::time::SystemTimeError) -> Self {
120 Self::Message(format!("system time: {e}"))
121 }
122}
123
124impl From<std::num::ParseIntError> for Error {
125 fn from(e: std::num::ParseIntError) -> Self {
126 Self::Invalid(format!("parse int: {e}"))
127 }
128}
129
130#[macro_export]
134macro_rules! bail {
135 ($fmt:literal $(,)?) => {
136 return Err($crate::error::Error::Message(format!($fmt)))
137 };
138 ($fmt:expr, $($arg:tt)*) => {
139 return Err($crate::error::Error::Message(format!($fmt, $($arg)*)))
140 };
141}
142
143#[macro_export]
146macro_rules! anyhow {
147 ($fmt:literal $(,)?) => {
148 $crate::error::Error::Message(format!($fmt))
149 };
150 ($fmt:expr, $($arg:tt)*) => {
151 $crate::error::Error::Message(format!($fmt, $($arg)*))
152 };
153}