1use std::{io, process::Command};
19
20use eyre::Result;
21use terminal_size::{Height, Width, terminal_size};
22use thiserror::Error;
23
24use crate::{
25 config::{CONFIG_FILE_NAME, Config, VERSION},
26 hint,
27 tracing::LogResult as _,
28 warning,
29};
30
31#[derive(Debug, Error)]
33pub enum NotInGitWorktree {
34 #[error("Failed to run the git command")]
36 CannotRunGit(#[source] io::Error),
37 #[error("Not in a Git repository")]
39 NotInRepo,
40 #[error("Not inside a Git worktree")]
42 NotInWorktree,
43}
44
45#[tracing::instrument(level = "trace")]
47pub fn ensure_in_git_worktree() -> Result<(), NotInGitWorktree> {
48 let is_inside_work_tree = Command::new("git")
49 .args(["rev-parse", "--is-inside-work-tree"])
50 .output()
51 .map_err(NotInGitWorktree::CannotRunGit)
52 .log_err()?;
53
54 if !is_inside_work_tree.status.success() {
55 return Err(NotInGitWorktree::NotInRepo).log_err();
56 }
57
58 if is_inside_work_tree.stdout == b"true\n" {
59 Ok(())
60 } else {
61 Err(NotInGitWorktree::NotInWorktree).log_err()
62 }
63}
64
65#[tracing::instrument(level = "trace")]
67pub fn load_config() -> Result<Config> {
68 let config = Config::load()?;
69
70 if config.version != VERSION {
71 warning!("The configuration in {CONFIG_FILE_NAME} is out of date.");
72 hint!("You can update it by running `git z update`.");
73 }
74
75 Ok(config)
76}
77
78pub fn page_size(previous_questions: usize) -> usize {
80 if let Some((Width(_), Height(term_height))) = terminal_size() {
81 usize::from(term_height) - 4 - previous_questions
82 } else {
83 15
84 }
85}
86
87#[macro_export]
89macro_rules! success {
90 ($($arg:tt)*) => {{
91 use colored::Colorize as _;
92 let message = indoc::formatdoc!($($arg)*).green().bold();
93 println!("{message}");
94 }};
95}
96
97#[macro_export]
99macro_rules! warning {
100 ($($arg:tt)*) => {{
101 use colored::Colorize as _;
102
103 let log_message = $crate::helpers::uncapitalise(&format!($($arg)*));
104 let log_message = log_message.trim_end_matches(".");
105 tracing::warn!("{log_message}");
106
107 let message = indoc::formatdoc!($($arg)*).yellow().bold();
108 eprintln!("{message}");
109 }};
110}
111
112#[macro_export]
114macro_rules! error {
115 ($($arg:tt)*) => {{
116 use colored::Colorize as _;
117 let message = indoc::formatdoc!($($arg)*);
118 let message = $crate::helpers::uncapitalise(&message);
119 let message = format!("Error: {message}").red().bold();
120 eprintln!("{message}");
121 }};
122}
123
124#[macro_export]
126macro_rules! hint {
127 ($($arg:tt)*) => {{
128 use colored::Colorize as _;
129 let message = indoc::formatdoc!($($arg)*).blue();
130 eprintln!("{message}");
131 }};
132}