1use std::fmt;
2
3#[derive(Debug)]
8pub enum AftError {
9 SymbolNotFound {
10 name: String,
11 file: String,
12 },
13 AmbiguousSymbol {
14 name: String,
15 candidates: Vec<String>,
16 },
17 ParseError {
18 message: String,
19 },
20 FileNotFound {
21 path: String,
22 },
23 InvalidRequest {
24 message: String,
25 },
26 CheckpointNotFound {
27 name: String,
28 },
29 NoUndoHistory {
30 path: String,
31 },
32 AmbiguousMatch {
33 pattern: String,
34 count: usize,
35 },
36 ScopeNotFound {
37 scope: String,
38 available: Vec<String>,
39 file: String,
40 },
41 MemberNotFound {
42 member: String,
43 scope: String,
44 file: String,
45 },
46 IoError {
47 path: String,
48 message: String,
49 },
50}
51
52impl AftError {
53 pub fn code(&self) -> &'static str {
55 match self {
56 AftError::SymbolNotFound { .. } => "symbol_not_found",
57 AftError::AmbiguousSymbol { .. } => "ambiguous_symbol",
58 AftError::ParseError { .. } => "parse_error",
59 AftError::FileNotFound { .. } => "file_not_found",
60 AftError::InvalidRequest { .. } => "invalid_request",
61 AftError::CheckpointNotFound { .. } => "checkpoint_not_found",
62 AftError::NoUndoHistory { .. } => "no_undo_history",
63 AftError::AmbiguousMatch { .. } => "ambiguous_match",
64 AftError::ScopeNotFound { .. } => "scope_not_found",
65 AftError::MemberNotFound { .. } => "member_not_found",
66 AftError::IoError { .. } => "io_error",
67 }
68 }
69
70 pub fn to_error_json(&self) -> serde_json::Value {
74 serde_json::json!({
75 "code": self.code(),
76 "message": self.to_string(),
77 })
78 }
79}
80
81impl fmt::Display for AftError {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 match self {
84 AftError::SymbolNotFound { name, file } => {
85 write!(f, "symbol '{}' not found in {}", name, file)
86 }
87 AftError::AmbiguousSymbol { name, candidates } => {
88 write!(
89 f,
90 "symbol '{}' is ambiguous, candidates: [{}]",
91 name,
92 candidates.join(", ")
93 )
94 }
95 AftError::ParseError { message } => {
96 write!(f, "parse error: {}", message)
97 }
98 AftError::FileNotFound { path } => {
99 write!(f, "file not found: {}", path)
100 }
101 AftError::InvalidRequest { message } => {
102 write!(f, "invalid request: {}", message)
103 }
104 AftError::CheckpointNotFound { name } => {
105 write!(f, "checkpoint not found: {}", name)
106 }
107 AftError::NoUndoHistory { path } => {
108 write!(f, "no undo history for: {}", path)
109 }
110 AftError::AmbiguousMatch { pattern, count } => {
111 write!(
112 f,
113 "pattern '{}' matches {} occurrences, expected exactly 1",
114 pattern, count
115 )
116 }
117 AftError::ScopeNotFound {
118 scope,
119 available,
120 file,
121 } => {
122 if available.is_empty() {
123 write!(
124 f,
125 "scope '{}' not found in {} (no scopes available)",
126 scope, file
127 )
128 } else {
129 write!(
130 f,
131 "scope '{}' not found in {}, available: [{}]",
132 scope,
133 file,
134 available.join(", ")
135 )
136 }
137 }
138 AftError::MemberNotFound {
139 member,
140 scope,
141 file,
142 } => {
143 write!(
144 f,
145 "member '{}' not found in scope '{}' in {}",
146 member, scope, file
147 )
148 }
149 AftError::IoError { path, message } => {
150 write!(f, "I/O error on {}: {}", path, message)
151 }
152 }
153 }
154}
155
156impl std::error::Error for AftError {}