1use std::fmt::{self, Display, Formatter};
2use std::io;
3use std::path::PathBuf;
4
5pub type Result<T> = std::result::Result<T, AppError>;
6
7#[derive(Debug)]
8pub enum AppError {
9 Io(io::Error),
10 InvalidArgs(String),
11 TodoNotFound(PathBuf),
12 AlreadyInitialized(PathBuf),
13 InvalidTaskIndex { index: usize, len: usize },
14 MalformedTodoLine { line: usize, content: String },
15 NotGitRepository(PathBuf),
16 GitCommandFailed(String),
17 CommandFailed(String),
18 EmptyTask,
19}
20
21impl Display for AppError {
22 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
23 match self {
24 Self::Io(err) => write!(f, "{err}"),
25 Self::InvalidArgs(message) => write!(f, "{message}"),
26 Self::TodoNotFound(path) => write!(
27 f,
28 "no `.todo` file found from {} upward; run `to init` in your project root",
29 path.display()
30 ),
31 Self::AlreadyInitialized(path) => {
32 write!(f, "a `.todo` file already exists at {}", path.display())
33 }
34 Self::InvalidTaskIndex { index, len } => {
35 write!(f, "task {index} is out of range; expected a number between 1 and {len}")
36 }
37 Self::MalformedTodoLine { line, content } => write!(
38 f,
39 "invalid `.todo` format on line {line}: expected `[ ] task` or `[x] task`, got `{content}`"
40 ),
41 Self::NotGitRepository(path) => write!(
42 f,
43 "{} is not inside a git repository; `to scan` only works on git-tracked files",
44 path.display()
45 ),
46 Self::GitCommandFailed(message) => write!(f, "{message}"),
47 Self::CommandFailed(message) => write!(f, "{message}"),
48 Self::EmptyTask => write!(f, "task text cannot be empty"),
49 }
50 }
51}
52
53impl std::error::Error for AppError {}
54
55impl From<io::Error> for AppError {
56 fn from(value: io::Error) -> Self {
57 Self::Io(value)
58 }
59}