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