1use crate::{eval, git, model};
2use yansi::Paint;
3
4#[derive(Debug, Default, Clone, Copy)]
5pub struct DisplayOptions {
6 pub branches: bool,
7 pub commands: bool,
8 pub force: bool,
9 pub quiet: bool,
10 pub remotes: bool,
11 pub verbose: u8,
12 pub worktrees: bool,
13}
14
15pub(crate) fn display_missing_tree(
16 tree: &model::Tree,
17 path: &str,
18 verbose: u8,
19 force: bool,
20) -> String {
21 let skipped = if force {
22 String::new()
23 } else {
24 " (skipped)".bold().to_string()
25 };
26 if verbose > 0 {
27 format!(
28 "{} {} {}{}",
29 "#".black().bold(),
30 tree.get_name().black().bold(),
31 path.black().bold(),
32 skipped
33 )
34 } else {
35 format!(
36 "{} {}{}",
37 "#".black().bold(),
38 tree.get_name().black().bold(),
39 skipped
40 )
41 }
42}
43
44pub(crate) fn display_tree(
45 tree: &model::Tree,
46 path_str: &str,
47 tree_branches: bool,
48 verbose: u8,
49) -> String {
50 if verbose > 0 {
51 if tree_branches {
52 if let Some(path) = tree.canonical_pathbuf() {
53 if let Some(branch) = git::branch(&path) {
54 return format!(
55 "{} {} {}{}{} {}",
56 "#".cyan(),
57 tree.get_name().blue().bold(),
58 "[".blue(),
59 branch.green().bold(),
60 "]".blue(),
61 path_str.blue()
62 );
63 }
64 }
65 }
66 format!(
67 "{} {} {}",
68 "#".cyan(),
69 tree.get_name().blue().bold(),
70 path_str.blue()
71 )
72 } else {
73 if tree_branches {
74 if let Some(path) = tree.canonical_pathbuf() {
75 if let Some(branch) = git::branch(&path) {
76 return format!(
77 "{} {} {}{}{}",
78 "#".cyan(),
79 tree.get_name().blue().bold(),
80 "[".blue(),
81 branch.green().bold(),
82 "]".blue()
83 );
84 }
85 }
86 }
87 format!("{} {}", "#".cyan(), tree.get_name().blue().bold())
88 }
89}
90
91pub(crate) fn print_tree(tree: &model::Tree, options: &DisplayOptions) -> bool {
93 if let Ok(path) = tree.path_as_ref() {
94 if !std::path::PathBuf::from(&path).exists() {
96 if !options.quiet {
97 eprintln!(
98 "{}",
99 display_missing_tree(tree, path, options.verbose, options.force)
100 );
101 }
102 return false;
103 }
104
105 print_tree_details(tree, options.branches, options.verbose, options.quiet);
106 return true;
107 }
108 if !options.quiet {
109 eprintln!(
110 "{}",
111 display_missing_tree(tree, "(invalid-path)", options.verbose, options.force)
112 );
113 }
114
115 false
116}
117
118pub(crate) fn print_tree_details(
120 tree: &model::Tree,
121 tree_branches: bool,
122 verbose: u8,
123 quiet: bool,
124) {
125 if quiet {
126 return;
127 }
128 if let Ok(path) = tree.path_as_ref() {
129 eprintln!("{}", display_tree(tree, path, tree_branches, verbose));
130 }
131}
132
133pub(crate) fn print_missing_tree(tree: &model::Tree, path: &str, verbose: u8) {
135 if verbose > 0 {
136 println!(
137 "{} {} {}",
138 "#-".red().dim(),
139 tree.get_name().red(),
140 path.red().dim()
141 );
142 } else {
143 println!("{} {}", "#-".red().dim(), tree.get_name().red());
144 }
145}
146
147pub(crate) fn print_symlink_tree_entry(tree: &model::Tree, path: &str, verbose: u8) {
149 let symlink = match tree.symlink_as_ref() {
150 Ok(symlink) => symlink,
151 Err(_) => return,
152 };
153 if verbose > 0 {
154 println!(
155 "{} {} {} {} {}",
156 "#+".cyan(),
157 tree.get_name().blue().bold(),
158 path.green(),
159 "->".green(),
160 symlink.yellow()
161 );
162 } else {
163 println!(
164 "{} {} {} {}",
165 "#".cyan(),
166 tree.get_name().blue().bold(),
167 "->".green(),
168 symlink.yellow()
169 );
170 }
171}
172
173pub(crate) fn print_tree_extended_details(
175 app_context: &model::ApplicationContext,
176 context: &model::TreeContext,
177 tree: &model::Tree,
178 display_options: &DisplayOptions,
179) {
180 let config = match context.config {
181 Some(config_id) => app_context.get_config(config_id),
182 None => app_context.get_root_config(),
183 };
184 if !tree.description.is_empty() {
185 println!("{}", tree.description.green());
186 }
187 if tree.is_worktree && !display_options.worktrees {
188 return;
189 }
190 if display_options.remotes && !tree.remotes.is_empty() {
191 println!("{}", "remotes:".blue());
192 for (name, remote) in &tree.remotes {
193 let value = eval::tree_variable(
194 app_context,
195 config,
196 None,
197 &context.tree,
198 context.garden.as_ref(),
199 remote,
200 );
201 println!(" {}{} {}", name.blue(), ":".blue(), value.yellow());
202 }
203 }
204 if !tree.links.is_empty() {
205 println!("{}", "links:".blue());
206 for link in &tree.links {
207 let value = eval::tree_variable(
208 app_context,
209 config,
210 None,
211 &context.tree,
212 context.garden.as_ref(),
213 link,
214 );
215 println!(" {} {}", "-".blue(), value.yellow());
216 }
217 }
218}
219
220pub(crate) fn print_commands(commands: &model::MultiVariableMap) {
222 println!("{}", "commands:".blue());
223 for cmd in commands.keys() {
224 println!(" {} {}", "-".blue(), cmd.yellow());
225 }
226}
227
228pub(crate) fn print_groups(groups: &model::GroupMap) {
230 println!("{}", "groups:".blue());
231 for group in groups.keys() {
232 println!(" {} {}", "-".blue(), group.yellow());
233 }
234}
235
236pub(crate) fn print_gardens(gardens: &model::GardenMap) {
238 println!("{}", "gardens:".blue());
239 for garden in gardens.keys() {
240 println!(" {} {}", "-".blue(), garden.yellow());
241 }
242}
243
244pub fn print_command_vec(command: &[&str]) {
246 let cmd_str = shell_words::join(command);
248 println!("{} {}", ":".cyan(), cmd_str.green(),);
249}
250
251pub fn print_command_string_vec(command: &[String]) {
253 let str_vec: Vec<&str> = command.iter().map(String::as_str).collect();
254 print_command_vec(&str_vec);
255}