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