Skip to main content

gitu/
error.rs

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    /// A command that failed: as it would be typed in a shell, its exit code
54    /// (none if a signal ended it), and what it wrote to stderr.
55    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            // The command on a line of its own, so that it can be copied whole.
172            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}