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