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 ForcePush,
50 Pull,
51 Fetch,
52 FetchFrom,
53 Commit,
54 Amend,
55 Cancel,
56 ExpandCommitEditor,
57 GenerateCommitMessage,
58 Init,
59 ]
60);
61
62#[derive(Clone, Debug, Default, PartialEq, Deserialize, JsonSchema)]
63pub struct RestoreFile {
64 #[serde(default)]
65 pub skip_prompt: bool,
66}
67
68impl_action_with_deprecated_aliases!(git, RestoreFile, ["editor::RevertFile"]);
69action_with_deprecated_aliases!(git, Restore, ["editor::RevertSelectedHunks"]);
70action_with_deprecated_aliases!(git, Blame, ["editor::ToggleGitBlame"]);
71
72/// The length of a Git short SHA.
73pub const SHORT_SHA_LENGTH: usize = 7;
74
75#[derive(Clone, Copy, Eq, Hash, PartialEq)]
76pub struct Oid(libgit::Oid);
77
78impl Oid {
79 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
80 let oid = libgit::Oid::from_bytes(bytes).context("failed to parse bytes into git oid")?;
81 Ok(Self(oid))
82 }
83
84 pub fn as_bytes(&self) -> &[u8] {
85 self.0.as_bytes()
86 }
87
88 pub(crate) fn is_zero(&self) -> bool {
89 self.0.is_zero()
90 }
91
92 /// Returns this [`Oid`] as a short SHA.
93 pub fn display_short(&self) -> String {
94 self.to_string().chars().take(SHORT_SHA_LENGTH).collect()
95 }
96}
97
98impl FromStr for Oid {
99 type Err = anyhow::Error;
100
101 fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> {
102 libgit::Oid::from_str(s)
103 .context("parsing git oid")
104 .map(Self)
105 }
106}
107
108impl fmt::Debug for Oid {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 fmt::Display::fmt(self, f)
111 }
112}
113
114impl fmt::Display for Oid {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 self.0.fmt(f)
117 }
118}
119
120impl Serialize for Oid {
121 fn serialize<S>(&self, serializer: S) -> std::prelude::v1::Result<S::Ok, S::Error>
122 where
123 S: serde::Serializer,
124 {
125 serializer.serialize_str(&self.0.to_string())
126 }
127}
128
129impl<'de> Deserialize<'de> for Oid {
130 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
131 where
132 D: serde::Deserializer<'de>,
133 {
134 let s = String::deserialize(deserializer)?;
135 s.parse::<Oid>().map_err(serde::de::Error::custom)
136 }
137}
138
139impl Default for Oid {
140 fn default() -> Self {
141 Self(libgit::Oid::zero())
142 }
143}
144
145impl From<Oid> for u32 {
146 fn from(oid: Oid) -> Self {
147 let bytes = oid.0.as_bytes();
148 debug_assert!(bytes.len() > 4);
149
150 let mut u32_bytes: [u8; 4] = [0; 4];
151 u32_bytes.copy_from_slice(&bytes[..4]);
152
153 u32::from_ne_bytes(u32_bytes)
154 }
155}
156
157impl From<Oid> for usize {
158 fn from(oid: Oid) -> Self {
159 let bytes = oid.0.as_bytes();
160 debug_assert!(bytes.len() > 8);
161
162 let mut u64_bytes: [u8; 8] = [0; 8];
163 u64_bytes.copy_from_slice(&bytes[..8]);
164
165 u64::from_ne_bytes(u64_bytes) as usize
166 }
167}