1use crate::print::format::CommitFormat;
4use regex::{Error, Regex};
5use serde_derive::{Deserialize, Serialize};
6use std::str::FromStr;
7
8#[derive(Serialize, Deserialize)]
11pub struct RepoSettings {
12 pub model: String,
14}
15
16pub enum BranchOrder {
18 ShortestFirst(bool),
23 LongestFirst(bool),
28}
29
30pub struct Settings {
32 pub reverse_commit_order: bool,
34 pub debug: bool,
36 pub compact: bool,
38 pub colored: bool,
40 pub include_remote: bool,
42 pub format: CommitFormat,
44 pub wrapping: Option<(Option<usize>, Option<usize>, Option<usize>)>,
46 pub characters: Characters,
48 pub branch_order: BranchOrder,
50 pub branches: BranchSettings,
52 pub merge_patterns: MergePatterns,
54}
55
56#[derive(Serialize, Deserialize)]
58pub struct BranchSettingsDef {
59 pub persistence: Vec<String>,
61 pub order: Vec<String>,
63 pub terminal_colors: ColorsDef,
65 pub svg_colors: ColorsDef,
67}
68
69#[derive(Serialize, Deserialize)]
71pub struct ColorsDef {
72 matches: Vec<(String, Vec<String>)>,
73 unknown: Vec<String>,
74}
75
76impl BranchSettingsDef {
77 pub fn git_flow() -> Self {
79 BranchSettingsDef {
80 persistence: vec![
81 r"^(master|main)$".to_string(),
82 r"^(develop|dev)$".to_string(),
83 r"^feature.*$".to_string(),
84 r"^release.*$".to_string(),
85 r"^hotfix.*$".to_string(),
86 r"^bugfix.*$".to_string(),
87 ],
88 order: vec![
89 r"^(master|main)$".to_string(),
90 r"^(hotfix|release).*$".to_string(),
91 r"^(develop|dev)$".to_string(),
92 ],
93 terminal_colors: ColorsDef {
94 matches: vec![
95 (
96 r"^(master|main)$".to_string(),
97 vec!["bright_blue".to_string()],
98 ),
99 (
100 r"^(develop|dev)$".to_string(),
101 vec!["bright_yellow".to_string()],
102 ),
103 (
104 r"^(feature|fork/).*$".to_string(),
105 vec!["bright_magenta".to_string(), "bright_cyan".to_string()],
106 ),
107 (r"^release.*$".to_string(), vec!["bright_green".to_string()]),
108 (
109 r"^(bugfix|hotfix).*$".to_string(),
110 vec!["bright_red".to_string()],
111 ),
112 (r"^tags/.*$".to_string(), vec!["bright_green".to_string()]),
113 ],
114 unknown: vec!["white".to_string()],
115 },
116
117 svg_colors: ColorsDef {
118 matches: vec![
119 (r"^(master|main)$".to_string(), vec!["blue".to_string()]),
120 (r"^(develop|dev)$".to_string(), vec!["orange".to_string()]),
121 (
122 r"^(feature|fork/).*$".to_string(),
123 vec!["purple".to_string(), "turquoise".to_string()],
124 ),
125 (r"^release.*$".to_string(), vec!["green".to_string()]),
126 (r"^(bugfix|hotfix).*$".to_string(), vec!["red".to_string()]),
127 (r"^tags/.*$".to_string(), vec!["green".to_string()]),
128 ],
129 unknown: vec!["gray".to_string()],
130 },
131 }
132 }
133
134 pub fn simple() -> Self {
136 BranchSettingsDef {
137 persistence: vec![r"^(master|main)$".to_string()],
138 order: vec![r"^tags/.*$".to_string(), r"^(master|main)$".to_string()],
139 terminal_colors: ColorsDef {
140 matches: vec![
141 (
142 r"^(master|main)$".to_string(),
143 vec!["bright_blue".to_string()],
144 ),
145 (r"^tags/.*$".to_string(), vec!["bright_green".to_string()]),
146 ],
147 unknown: vec![
148 "bright_yellow".to_string(),
149 "bright_green".to_string(),
150 "bright_red".to_string(),
151 "bright_magenta".to_string(),
152 "bright_cyan".to_string(),
153 ],
154 },
155
156 svg_colors: ColorsDef {
157 matches: vec![
158 (r"^(master|main)$".to_string(), vec!["blue".to_string()]),
159 (r"^tags/.*$".to_string(), vec!["green".to_string()]),
160 ],
161 unknown: vec![
162 "orange".to_string(),
163 "green".to_string(),
164 "red".to_string(),
165 "purple".to_string(),
166 "turquoise".to_string(),
167 ],
168 },
169 }
170 }
171
172 pub fn none() -> Self {
174 BranchSettingsDef {
175 persistence: vec![],
176 order: vec![],
177 terminal_colors: ColorsDef {
178 matches: vec![],
179 unknown: vec![
180 "bright_blue".to_string(),
181 "bright_yellow".to_string(),
182 "bright_green".to_string(),
183 "bright_red".to_string(),
184 "bright_magenta".to_string(),
185 "bright_cyan".to_string(),
186 ],
187 },
188
189 svg_colors: ColorsDef {
190 matches: vec![],
191 unknown: vec![
192 "blue".to_string(),
193 "orange".to_string(),
194 "green".to_string(),
195 "red".to_string(),
196 "purple".to_string(),
197 "turquoise".to_string(),
198 ],
199 },
200 }
201 }
202}
203
204pub struct BranchSettings {
206 pub persistence: Vec<Regex>,
208 pub order: Vec<Regex>,
210 pub terminal_colors: Vec<(Regex, Vec<String>)>,
212 pub terminal_colors_unknown: Vec<String>,
214 pub svg_colors: Vec<(Regex, Vec<String>)>,
216 pub svg_colors_unknown: Vec<String>,
218}
219
220impl BranchSettings {
221 pub fn from(def: BranchSettingsDef) -> Result<Self, Error> {
222 let persistence = def
223 .persistence
224 .iter()
225 .map(|str| Regex::new(str))
226 .collect::<Result<Vec<_>, Error>>()?;
227
228 let order = def
229 .order
230 .iter()
231 .map(|str| Regex::new(str))
232 .collect::<Result<Vec<_>, Error>>()?;
233
234 let terminal_colors = def
235 .terminal_colors
236 .matches
237 .into_iter()
238 .map(|(str, vec)| Regex::new(&str).map(|re| (re, vec)))
239 .collect::<Result<Vec<_>, Error>>()?;
240
241 let terminal_colors_unknown = def.terminal_colors.unknown;
242
243 let svg_colors = def
244 .svg_colors
245 .matches
246 .into_iter()
247 .map(|(str, vec)| Regex::new(&str).map(|re| (re, vec)))
248 .collect::<Result<Vec<_>, Error>>()?;
249
250 let svg_colors_unknown = def.svg_colors.unknown;
251
252 Ok(BranchSettings {
253 persistence,
254 order,
255 terminal_colors,
256 terminal_colors_unknown,
257 svg_colors,
258 svg_colors_unknown,
259 })
260 }
261}
262
263pub struct MergePatterns {
265 pub patterns: Vec<Regex>,
267}
268
269impl Default for MergePatterns {
270 fn default() -> Self {
271 MergePatterns {
272 patterns: vec![
273 Regex::new(r"^Merge branch '(.+)' into '.+'$").unwrap(),
275 Regex::new(r"^Merge branch '(.+)' into .+$").unwrap(),
277 Regex::new(r"^Merge branch '(.+)'$").unwrap(),
279 Regex::new(r"^Merge pull request #[0-9]+ from .[^/]+/(.+)$").unwrap(),
281 Regex::new(r"^Merge branch '(.+)' of .+$").unwrap(),
283 Regex::new(r"^Merged in (.+) \(pull request #[0-9]+\)$").unwrap(),
285 ],
286 }
287 }
288}
289
290pub struct Characters {
292 pub chars: Vec<char>,
293}
294
295impl FromStr for Characters {
296 type Err = String;
297
298 fn from_str(str: &str) -> Result<Self, Self::Err> {
299 match str {
300 "normal" | "thin" | "n" | "t" => Ok(Characters::thin()),
301 "round" | "r" => Ok(Characters::round()),
302 "bold" | "b" => Ok(Characters::bold()),
303 "double" | "d" => Ok(Characters::double()),
304 "ascii" | "a" => Ok(Characters::ascii()),
305 _ => Err(format!("Unknown characters/style '{}'. Must be one of [normal|thin|round|bold|double|ascii]", str)),
306 }
307 }
308}
309
310impl Characters {
311 pub fn thin() -> Self {
313 Characters {
314 chars: " ●○│─┼└┌┐┘┤├┴┬<>".chars().collect(),
315 }
316 }
317 pub fn round() -> Self {
319 Characters {
320 chars: " ●○│─┼╰╭╮╯┤├┴┬<>".chars().collect(),
321 }
322 }
323 pub fn bold() -> Self {
325 Characters {
326 chars: " ●○┃━╋┗┏┓┛┫┣┻┳<>".chars().collect(),
327 }
328 }
329 pub fn double() -> Self {
331 Characters {
332 chars: " ●○║═╬╚╔╗╝╣╠╩╦<>".chars().collect(),
333 }
334 }
335 pub fn ascii() -> Self {
337 Characters {
338 chars: " *o|-+'..'||++<>".chars().collect(),
339 }
340 }
341
342 pub fn reverse(self) -> Self {
343 let mut chars = self.chars;
344
345 chars.swap(6, 8);
346 chars.swap(7, 9);
347 chars.swap(10, 11);
348 chars.swap(12, 13);
349 chars.swap(14, 15);
350
351 Characters { chars }
352 }
353}