1pub mod blame;
2pub mod commit;
3mod hosting_provider;
4mod remote;
5pub mod repository;
6pub mod status;
7
8pub use crate::hosting_provider::*;
9pub use crate::remote::*;
10use anyhow::{Context as _, Result};
11pub use git2 as libgit;
12use gpui::action_with_deprecated_aliases;
13use gpui::actions;
14use gpui::impl_action_with_deprecated_aliases;
15pub use repository::WORK_DIRECTORY_REPO_PATH;
16use schemars::JsonSchema;
17use serde::{Deserialize, Serialize};
18use std::ffi::OsStr;
19use std::fmt;
20use std::str::FromStr;
21use std::sync::LazyLock;
22
23pub static DOT_GIT: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new(".git"));
24pub static GITIGNORE: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new(".gitignore"));
25pub static FSMONITOR_DAEMON: LazyLock<&'static OsStr> =
26 LazyLock::new(|| OsStr::new("fsmonitor--daemon"));
27pub static LFS_DIR: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new("lfs"));
28pub static COMMIT_MESSAGE: LazyLock<&'static OsStr> =
29 LazyLock::new(|| OsStr::new("COMMIT_EDITMSG"));
30pub static INDEX_LOCK: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new("index.lock"));
31
32actions!(
33 git,
34 [
35 // per-hunk
36 ToggleStaged,
37 StageAndNext,
38 UnstageAndNext,
39 // per-file
40 StageFile,
41 UnstageFile,
42 // repo-wide
43 StageAll,
44 UnstageAll,
45 RestoreTrackedFiles,
46 TrashUntrackedFiles,
47 Uncommit,
48 Push,
49 PushTo,
50 ForcePush,
51 Pull,
52 Fetch,
53 FetchFrom,
54 Commit,
55 Amend,
56 Cancel,
57 ExpandCommitEditor,
58 GenerateCommitMessage,
59 Init,
60 OpenModifiedFiles,
61 ]
62);
63
64#[derive(Clone, Debug, Default, PartialEq, Deserialize, JsonSchema)]
65pub struct RestoreFile {
66 #[serde(default)]
67 pub skip_prompt: bool,
68}
69
70impl_action_with_deprecated_aliases!(git, RestoreFile, ["editor::RevertFile"]);
71action_with_deprecated_aliases!(git, Restore, ["editor::RevertSelectedHunks"]);
72action_with_deprecated_aliases!(git, Blame, ["editor::ToggleGitBlame"]);
73
74/// The length of a Git short SHA.
75pub const SHORT_SHA_LENGTH: usize = 7;
76
77#[derive(Clone, Copy, Eq, Hash, PartialEq)]
78pub struct Oid(libgit::Oid);
79
80impl Oid {
81 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
82 let oid = libgit::Oid::from_bytes(bytes).context("failed to parse bytes into git oid")?;
83 Ok(Self(oid))
84 }
85
86 pub fn as_bytes(&self) -> &[u8] {
87 self.0.as_bytes()
88 }
89
90 pub(crate) fn is_zero(&self) -> bool {
91 self.0.is_zero()
92 }
93
94 /// Returns this [`Oid`] as a short SHA.
95 pub fn display_short(&self) -> String {
96 self.to_string().chars().take(SHORT_SHA_LENGTH).collect()
97 }
98}
99
100impl FromStr for Oid {
101 type Err = anyhow::Error;
102
103 fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> {
104 libgit::Oid::from_str(s)
105 .context("parsing git oid")
106 .map(Self)
107 }
108}
109
110impl fmt::Debug for Oid {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 fmt::Display::fmt(self, f)
113 }
114}
115
116impl fmt::Display for Oid {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 self.0.fmt(f)
119 }
120}
121
122impl Serialize for Oid {
123 fn serialize<S>(&self, serializer: S) -> std::prelude::v1::Result<S::Ok, S::Error>
124 where
125 S: serde::Serializer,
126 {
127 serializer.serialize_str(&self.0.to_string())
128 }
129}
130
131impl<'de> Deserialize<'de> for Oid {
132 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
133 where
134 D: serde::Deserializer<'de>,
135 {
136 let s = String::deserialize(deserializer)?;
137 s.parse::<Oid>().map_err(serde::de::Error::custom)
138 }
139}
140
141impl Default for Oid {
142 fn default() -> Self {
143 Self(libgit::Oid::zero())
144 }
145}
146
147impl From<Oid> for u32 {
148 fn from(oid: Oid) -> Self {
149 let bytes = oid.0.as_bytes();
150 debug_assert!(bytes.len() > 4);
151
152 let mut u32_bytes: [u8; 4] = [0; 4];
153 u32_bytes.copy_from_slice(&bytes[..4]);
154
155 u32::from_ne_bytes(u32_bytes)
156 }
157}
158
159impl From<Oid> for usize {
160 fn from(oid: Oid) -> Self {
161 let bytes = oid.0.as_bytes();
162 debug_assert!(bytes.len() > 8);
163
164 let mut u64_bytes: [u8; 8] = [0; 8];
165 u64_bytes.copy_from_slice(&bytes[..8]);
166
167 u64::from_ne_bytes(u64_bytes) as usize
168 }
169}