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, actions};
13pub use repository::WORK_DIRECTORY_REPO_PATH;
14use schemars::JsonSchema;
15use serde::{Deserialize, Serialize};
16use std::ffi::OsStr;
17use std::fmt;
18use std::str::FromStr;
19use std::sync::LazyLock;
20
21pub static DOT_GIT: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new(".git"));
22pub static GITIGNORE: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new(".gitignore"));
23pub static FSMONITOR_DAEMON: LazyLock<&'static OsStr> =
24 LazyLock::new(|| OsStr::new("fsmonitor--daemon"));
25pub static LFS_DIR: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new("lfs"));
26pub static COMMIT_MESSAGE: LazyLock<&'static OsStr> =
27 LazyLock::new(|| OsStr::new("COMMIT_EDITMSG"));
28pub static INDEX_LOCK: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new("index.lock"));
29
30actions!(
31 git,
32 [
33 // per-hunk
34 ToggleStaged,
35 StageAndNext,
36 UnstageAndNext,
37 #[action(deprecated_aliases = ["editor::RevertSelectedHunks"])]
38 Restore,
39 // per-file
40 #[action(deprecated_aliases = ["editor::ToggleGitBlame"])]
41 Blame,
42 StageFile,
43 UnstageFile,
44 // repo-wide
45 StageAll,
46 UnstageAll,
47 RestoreTrackedFiles,
48 TrashUntrackedFiles,
49 Uncommit,
50 Push,
51 PushTo,
52 ForcePush,
53 Pull,
54 Fetch,
55 FetchFrom,
56 Commit,
57 Amend,
58 Cancel,
59 ExpandCommitEditor,
60 GenerateCommitMessage,
61 Init,
62 OpenModifiedFiles,
63 ]
64);
65
66#[derive(Clone, Debug, Default, PartialEq, Deserialize, JsonSchema, Action)]
67#[action(namespace = git, deprecated_aliases = ["editor::RevertFile"])]
68#[serde(deny_unknown_fields)]
69pub struct RestoreFile {
70 #[serde(default)]
71 pub skip_prompt: bool,
72}
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}