1use std::fmt::{self, Display};
2
3use serde::{Deserialize, Serialize};
4use url::Url;
5
6pub const DEFAULT_URL: &str = "https://gitmoji.dev/api/gitmojis";
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10pub enum EmojiFormat {
12 UseCode,
14 UseEmoji,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19#[serde(default)]
20pub struct GitmojiConfig {
22 auto_add: bool,
23 format: EmojiFormat,
24 signed: bool,
25 scope: bool,
26 update_url: Url,
27 gitmojis: Vec<Gitmoji>,
28}
29
30impl GitmojiConfig {
31 #[must_use]
33 pub const fn new(
34 auto_add: bool,
35 format: EmojiFormat,
36 signed: bool,
37 scope: bool,
38 update_url: Url,
39 ) -> Self {
40 Self {
41 auto_add,
42 format,
43 signed,
44 scope,
45 update_url,
46 gitmojis: vec![],
47 }
48 }
49
50 pub fn merge(&mut self, local_config: &LocalGitmojiConfig) {
52 if let Some(auto_add) = local_config.auto_add() {
53 self.auto_add = auto_add;
54 }
55 if let Some(format) = local_config.format() {
56 self.format = format;
57 }
58 if let Some(signed) = local_config.signed() {
59 self.signed = signed;
60 }
61 if let Some(gitmojis) = local_config.gitmojis() {
62 self.gitmojis = gitmojis.to_vec();
63 }
64 }
65
66 #[must_use]
68 pub const fn auto_add(&self) -> bool {
69 self.auto_add
70 }
71
72 #[must_use]
74 pub const fn format(&self) -> &EmojiFormat {
75 &self.format
76 }
77
78 #[must_use]
80 pub const fn signed(&self) -> bool {
81 self.signed
82 }
83
84 #[must_use]
86 pub const fn scope(&self) -> bool {
87 self.scope
88 }
89
90 #[must_use]
92 pub fn update_url(&self) -> &str {
93 self.update_url.as_ref()
94 }
95
96 pub fn set_update_url(&mut self, update_url: Url) {
98 self.update_url = update_url;
99 }
100
101 #[must_use]
103 pub fn gitmojis(&self) -> &[Gitmoji] {
104 self.gitmojis.as_ref()
105 }
106
107 pub fn set_gitmojis(&mut self, gitmojis: Vec<Gitmoji>) {
109 self.gitmojis = gitmojis;
110 }
111}
112
113impl Default for GitmojiConfig {
114 fn default() -> Self {
115 Self {
116 auto_add: false,
117 format: EmojiFormat::UseCode,
118 signed: false,
119 scope: false,
120 update_url: DEFAULT_URL.parse().expect("It's a valid URL"),
121 gitmojis: vec![],
122 }
123 }
124}
125
126#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
127pub struct LocalGitmojiConfig {
129 auto_add: Option<bool>,
130 format: Option<EmojiFormat>,
131 signed: Option<bool>,
132 scope: Option<bool>,
133 gitmojis: Option<Vec<Gitmoji>>,
134}
135
136impl LocalGitmojiConfig {
137 #[must_use]
139 pub fn auto_add(&self) -> Option<bool> {
140 self.auto_add
141 }
142
143 #[must_use]
145 pub fn format(&self) -> Option<EmojiFormat> {
146 self.format
147 }
148
149 #[must_use]
151 pub fn signed(&self) -> Option<bool> {
152 self.signed
153 }
154
155 #[must_use]
157 pub fn scope(&self) -> Option<bool> {
158 self.scope
159 }
160
161 #[must_use]
163 pub fn gitmojis(&self) -> Option<&[Gitmoji]> {
164 self.gitmojis.as_deref()
165 }
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
169pub struct Gitmoji {
171 emoji: String,
172 code: String,
173 name: Option<String>,
174 description: Option<String>,
175}
176
177impl Gitmoji {
178 #[must_use]
180 pub fn new(
181 emoji: String,
182 code: String,
183 name: Option<String>,
184 description: Option<String>,
185 ) -> Self {
186 Self {
187 emoji,
188 code,
189 name,
190 description,
191 }
192 }
193
194 #[must_use]
196 pub fn emoji(&self) -> &str {
197 self.emoji.as_ref()
198 }
199
200 #[must_use]
202 pub fn code(&self) -> &str {
203 self.code.as_ref()
204 }
205
206 #[must_use]
208 pub fn name(&self) -> Option<&str> {
209 self.name.as_deref()
210 }
211
212 #[must_use]
214 pub fn description(&self) -> Option<&str> {
215 self.description.as_deref()
216 }
217}
218
219impl Display for Gitmoji {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 let Gitmoji {
222 emoji,
223 code,
224 name,
225 description,
226 ..
227 } = self;
228 write!(
229 f,
230 "{emoji} {code} {} - {}",
231 name.as_deref().unwrap_or_default(),
232 description.as_deref().unwrap_or_default()
233 )
234 }
235}
236
237#[cfg(test)]
238#[allow(clippy::ignored_unit_patterns)]
239mod tests {
240 use assert2::*;
241
242 use super::*;
243
244 #[test]
245 fn should_serde_gitmoji() {
246 let gitmoji = Gitmoji {
247 emoji: String::from("🚀"),
248 code: String::from("rocket"),
249 name: Some(String::from("Initialize")),
250 description: Some(String::from("Bla bla")),
251 };
252
253 let toml = toml_edit::ser::to_string(&gitmoji);
255 let_assert!(Ok(toml) = toml);
256
257 let result = toml_edit::de::from_str::<Gitmoji>(&toml);
259 let_assert!(Ok(result) = result);
260
261 check!(result == gitmoji);
262 }
263
264 #[test]
265 fn should_serde_config() {
266 let mut config = GitmojiConfig::default();
267 config.gitmojis.push(Gitmoji {
268 emoji: String::from("🚀"),
269 code: String::from("rocket"),
270 name: Some(String::from("Initialize")),
271 description: Some(String::from("Bla bla")),
272 });
273
274 let toml = toml_edit::ser::to_string(&config);
276 let_assert!(Ok(toml) = toml);
277
278 let result = toml_edit::de::from_str::<GitmojiConfig>(&toml);
280 let_assert!(Ok(result) = result);
281
282 check!(result == config);
283 }
284}