1use std::{fmt::Display, io, string};
2
3#[derive(Debug)]
4pub enum Error {
5 StashList(git2::Error),
6 ReadLog(git2::Error),
7 OpenRepo(git2::Error),
8 FindGitDir(io::Error),
9 Term(io::Error),
10 GitDirUtf8(string::FromUtf8Error),
11 Config(Box<figment::Error>),
12 EditConfig(String),
13 Bindings { bad_key_bindings: Vec<String> },
14 FileWatcher(notify::Error),
15 ReadRebaseStatusFile(io::Error),
16 ReadRebaseTodo(io::Error),
17 ReadPipedInput(io::Error),
18 PagerWithoutInput,
19 WriteRebaseTodo(io::Error),
20 ReadBranchName(io::Error),
21 BranchNameUtf8(Utf8Error),
22 GitDiff(io::Error),
23 GitDiffUtf8(string::FromUtf8Error),
24 GitShow(io::Error),
25 GitShowUtf8(string::FromUtf8Error),
26 GitShowMeta(git2::Error),
27 NotOnBranch,
28 GetHead(git2::Error),
29 CurrentBranchName(git2::Error),
30 GetCurrentBranchUpstream(git2::Error),
31 GetCurrentBranchUpstreamUtf8(Utf8Error),
32 RemoteNameUtf8(Utf8Error),
33 CannotDeleteCurrentBranch,
34 BranchNameRequired,
35 IsBranchMerged(git2::Error),
36 GetRemote(git2::Error),
37 ReadGitConfig(git2::Error),
38 ReadGitConfigUtf8(Utf8Error),
39 DeleteGitConfig(git2::Error),
40 SetGitConfig(git2::Error),
41 RemoteHasNoName,
42 ReadOid(git2::Error),
43 ArgMustBePositiveNumber,
44 ArgInvalidRegex(regex::Error),
45 Clipboard(arboard::Error),
46 FindGitRev(git2::Error),
47 NoEditorSet,
48 GitStatus(git2::Error),
49 CmdAlreadyRunning,
50 StashWorkTreeEmpty,
51 CouldntAwaitCmd(io::Error),
52 NoRepoWorkdir,
53 SpawnCmd(io::Error),
54 CmdBadExit(String, Option<i32>),
55 CouldntReadCmdOutput(io::Error),
56 ListGitReferences(git2::Error),
57 OpenLogFile(io::Error),
58 PromptAborted,
59 ReadPromptHistory(io::Error),
60 WritePromptHistory(io::Error),
61 NoMoreEvents,
62 CannotSpinoffCurrentBranch,
63 SpinoffBranchExists(String),
64 DoesBranchExist(git2::Error),
65 GetBranchName(git2::Error),
66 BaseCommitOid,
67 UpstreamCommitOid,
68 GitBlame(io::Error),
69 NoSearchMatch(String),
70 NoPreviousSearch,
71 InvalidSearchRegex(regex::Error),
72 EditedCommandQuotes,
73 EditedCommandFixed,
74 EditedCommandWrites(String),
75 GitRefusedTheCommand(String),
76}
77
78impl std::error::Error for Error {}
79
80impl Display for Error {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 match self {
83 Error::StashList(e) => f.write_fmt(format_args!("Couldn't list stash: {e}")),
84 Error::ReadLog(e) => f.write_fmt(format_args!("Couldn't read log: {e}")),
85 Error::ReadPipedInput(e) => {
86 f.write_fmt(format_args!("Couldn't read the piped input: {e}"))
87 }
88 Error::PagerWithoutInput => {
89 f.write_str("--pager expects a patch on stdin, e.g. `git show | gitu --pager`")
90 }
91 Error::ReadRebaseTodo(e) => {
92 f.write_fmt(format_args!("Couldn't read the rebase todo list: {e}"))
93 }
94 Error::WriteRebaseTodo(e) => {
95 f.write_fmt(format_args!("Couldn't write the rebase todo list: {e}"))
96 }
97 Error::OpenRepo(e) => match e.code() {
98 git2::ErrorCode::NotFound => f.write_str("No .git found in the current directory"),
99 _ => f.write_fmt(format_args!("Couldn't open repo: {e:?}")),
100 },
101 Error::FindGitDir(e) => f.write_fmt(format_args!("Couldn't find git directory: {}", e)),
102 Error::Term(e) => f.write_fmt(format_args!("Terminal error: {}", e)),
103 Error::GitDirUtf8(_e) => f.write_str("Git directory not valid UTF-8"),
104 Error::Config(e) => f.write_fmt(format_args!("Configuration error: {e}")),
105 Error::EditConfig(e) => {
106 f.write_fmt(format_args!("Couldn't save to the config file: {e}"))
107 }
108 Error::Bindings { bad_key_bindings } => {
109 let mut error_string = String::from("Errors while parsing key bindings:");
110 for item in bad_key_bindings {
111 error_string.push_str(&format!("\n{item}"));
112 }
113 f.write_fmt(format_args!("{error_string}"))
114 }
115 Error::FileWatcher(e) => f.write_fmt(format_args!("File watcher error: {e}")),
116 Error::ReadRebaseStatusFile(e) => {
117 f.write_fmt(format_args!("Couldn't read rebase status file: {e}"))
118 }
119 Error::ReadBranchName(e) => f.write_fmt(format_args!("Couldn't read branch name: {e}")),
120 Error::BranchNameUtf8(_e) => f.write_str("Branch name error"),
121 Error::GitDiff(e) => f.write_fmt(format_args!("Git diff error: {e}")),
122 Error::GitDiffUtf8(e) => {
123 f.write_fmt(format_args!("Git diff output is not valid UTF-8: {e}"))
124 }
125 Error::GitShow(e) => f.write_fmt(format_args!("Git show error: {e}")),
126 Error::GitShowUtf8(e) => {
127 f.write_fmt(format_args!("Git show output is not valid UTF-8: {e}"))
128 }
129 Error::GitShowMeta(e) => f.write_fmt(format_args!("Git show metadata error: {e}")),
130 Error::NotOnBranch => f.write_str("Head is not a branch"),
131 Error::GetHead(e) => f.write_fmt(format_args!("Couldn't get HEAD: {e}")),
132 Error::CurrentBranchName(e) => {
133 f.write_fmt(format_args!("Couldn't get current branch name: {e}"))
134 }
135 Error::GetCurrentBranchUpstream(e) => {
136 f.write_fmt(format_args!("Couldn't get current branch upstream: {e}"))
137 }
138 Error::GetCurrentBranchUpstreamUtf8(_e) => {
139 f.write_str("Current branch upstream is not valid UTF-8")
140 }
141 Error::RemoteNameUtf8(_e) => f.write_str("Remote name is not valid UTF-8"),
142 Error::CannotDeleteCurrentBranch => f.write_str("Cannot delete current branch"),
143 Error::BranchNameRequired => f.write_str("Branch name required"),
144 Error::IsBranchMerged(e) => {
145 f.write_fmt(format_args!("Couldn't check if branch is merged: {e}"))
146 }
147 Error::GetRemote(e) => f.write_fmt(format_args!("Couldn't get remote: {e}")),
148 Error::ReadGitConfig(e) => f.write_fmt(format_args!("Couldn't read git config: {e}")),
149 Error::ReadGitConfigUtf8(_e) => f.write_str("Git config is not valid UTF-8"),
150 Error::DeleteGitConfig(e) => {
151 f.write_fmt(format_args!("Couldn't delete git config: {e}"))
152 }
153 Error::SetGitConfig(e) => f.write_fmt(format_args!("Couldn't set git config: {e}")),
154 Error::RemoteHasNoName => f.write_str("Remote has no name"),
155 Error::ReadOid(e) => f.write_fmt(format_args!("Couldn't read OID: {e}")),
156 Error::ArgMustBePositiveNumber => f.write_str("Value must be a number greater than 0"),
157 Error::ArgInvalidRegex(e) => f.write_fmt(format_args!("Invalid regex: {e}")),
158 Error::Clipboard(e) => f.write_fmt(format_args!("Clipboard error: {e}")),
159 Error::FindGitRev(e) => f.write_fmt(format_args!("Couldn't find git revision: {e}")),
160 Error::NoEditorSet => f.write_fmt(format_args!(
161 "No editor environment variable set ({})",
162 crate::ops::show::EDITOR_VARS.join(", ")
163 )),
164 Error::GitStatus(e) => f.write_fmt(format_args!("Git status error: {e}")),
165 Error::CmdAlreadyRunning => f.write_str("A command is already running"),
166 Error::StashWorkTreeEmpty => f.write_str("Cannot stash: working tree is empty"),
167 Error::CouldntAwaitCmd(e) => f.write_fmt(format_args!("Couldn't await command: {e}")),
168 Error::NoRepoWorkdir => f.write_str("No repository working directory"),
169 Error::SpawnCmd(e) => f.write_fmt(format_args!("Failed to spawn command: {e}")),
170 Error::CmdBadExit(args, code) => f.write_fmt(format_args!(
171 "'{}' exited with code: {}",
172 args,
173 code.map(|c| c.to_string())
174 .unwrap_or_else(|| "".to_string())
175 )),
176 Error::CouldntReadCmdOutput(e) => {
177 f.write_fmt(format_args!("Couldn't read command output: {e}"))
178 }
179 Error::ListGitReferences(e) => {
180 f.write_fmt(format_args!("Couldn't list git references: {e}"))
181 }
182 Error::OpenLogFile(e) => f.write_fmt(format_args!("Couldn't open log file: {e}")),
183 Error::PromptAborted => f.write_str("Aborted"),
184 Error::ReadPromptHistory(e) => {
185 f.write_fmt(format_args!("Couldn't read prompt history: {e}"))
186 }
187 Error::WritePromptHistory(e) => {
188 f.write_fmt(format_args!("Couldn't write prompt history: {e}"))
189 }
190 Error::NoMoreEvents => unimplemented!(),
191 Error::CannotSpinoffCurrentBranch => f.write_str("Cannot spin-off current branch"),
192 Error::SpinoffBranchExists(new_branch_name) => f.write_fmt(format_args!(
193 "Cannot spin-off {new_branch_name}. It already exists"
194 )),
195 Error::DoesBranchExist(e) => {
196 f.write_fmt(format_args!("Couldn't check if branch exists: {}", e))
197 }
198 Error::GetBranchName(e) => f.write_fmt(format_args!("Couldn't get branch name: {}", e)),
199 Error::BaseCommitOid => f.write_str("Could not resolve OID of base commit"),
200 Error::UpstreamCommitOid => {
201 f.write_str("Could not resolve OID of upstream branch commit")
202 }
203 Error::GitBlame(e) => f.write_fmt(format_args!("Git blame error: {e}")),
204 Error::NoSearchMatch(query) => f.write_fmt(format_args!("No match: {query}")),
205 Error::NoPreviousSearch => f.write_str("No previous search"),
206 Error::InvalidSearchRegex(e) => f.write_fmt(format_args!("Invalid search: {e}")),
207 Error::EditedCommandQuotes => f.write_str("Unbalanced quotes"),
208 Error::EditedCommandFixed => f.write_str(
209 "Only git's arguments can be edited, not the program or git's own options",
210 ),
211 Error::EditedCommandWrites(subcommand) => f.write_fmt(format_args!(
212 "gitu re-runs this command on every refresh, so it must only report: {subcommand}"
213 )),
214 Error::GitRefusedTheCommand(stderr) => f.write_str(stderr),
215 }
216 }
217}
218
219#[derive(Debug)]
220pub enum Utf8Error {
221 Str(std::str::Utf8Error),
222 String(string::FromUtf8Error),
223}
224
225impl std::error::Error for Utf8Error {}
226
227impl Display for Utf8Error {
228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229 f.write_str("not valid UTF-8")
230 }
231}