tusks_lib/codegen/preparse/tasks/
functions.rs1use syn::{Item, ItemFn, ItemMod, parse_quote};
2use syn::{Attribute, Meta};
3use quote::quote;
4
5use crate::{AttributeValue, attribute::models::TasksConfig};
6
7pub fn add_use_statements(module: &mut ItemMod) {
8 let use_statement: Item = parse_quote! {
9 use ::tusks::clap::{CommandFactory, Parser};
10 };
11
12 if let Some((_, ref mut items)) = module.content {
13 items.insert(0, use_statement);
14 }
15}
16
17pub fn set_allow_external_subcommands(module: &mut ItemMod) {
18 if module.get_attribute_bool("command", "allow_external_subcommands") {
19 return;
20 }
21
22 if let Some(attr) = module.attrs.iter_mut().find(|a| a.path().is_ident("command")) {
24 match &mut attr.meta {
25 Meta::List(list) => {
26 let tokens_str = list.tokens.to_string();
27 let has_trailing_comma = tokens_str.trim_end().ends_with(',');
28
29 let tokens = &list.tokens;
30 if tokens.is_empty() {
31 list.tokens = parse_quote! { allow_external_subcommands = true };
32 } else if has_trailing_comma {
33 list.tokens = parse_quote! { #tokens allow_external_subcommands = true };
34 } else {
35 list.tokens = parse_quote! { #tokens, allow_external_subcommands = true };
36 }
37 }
38 Meta::Path(_) => {
39 *attr = parse_quote! { #[command(allow_external_subcommands = true)] };
40 }
41 Meta::NameValue(_) => {
42 *attr = parse_quote! { #[command(allow_external_subcommands = true)] };
43 }
44 }
45 } else {
46 let new_attr: Attribute = parse_quote! { #[command(allow_external_subcommands = true)] };
48 module.attrs.push(new_attr);
49 }
50}
51
52pub fn add_execute_task_function(module: &mut ItemMod, config: &TasksConfig) {
53 let separator = &config.separator;
54 let max_groupsize = &config.max_groupsize;
55 let max_depth = &config.max_depth;
56 let use_colors = &config.use_colors;
57
58 let (maybe_async, maybe_await) = if cfg!(feature = "async") {
59 (quote! { async }, quote! { .await })
60 } else {
61 (quote! {}, quote! {})
62 };
63
64 let tokens = quote! {
65 #[command(about = "Execute a task", hide=true)]
66 #[default]
67 pub #maybe_async fn _execute_task(external_args: Vec<String>) -> Option<u8> {
68 let command = __internal_tusks_module::cli::Cli::command();
69 if let Some(first) = external_args.first() {
70 let mut transformed_arguments = vec![command.get_name().to_string()];
71 transformed_arguments.extend(first.split(#separator).map(|s| s.to_string()));
72 transformed_arguments.extend_from_slice(&external_args[1..]);
73 let cli = __internal_tusks_module::cli::Cli::parse_from(transformed_arguments);
74 return __internal_tusks_module::handle_matches(&cli)#maybe_await;
75 }
76
77 let task_list = ::tusks::tasks::task_list::models::TaskList::from_command(
78 &command,
79 #separator.to_string(),
80 #max_groupsize,
81 #max_depth
82 );
83 let mut render_config = ::tusks::tasks::list::models::RenderConfig::default();
84 render_config.use_colors = #use_colors;
85 task_list.into_list().print(&render_config);
86 Some(0)
87 }
88 };
89
90 let function: ItemFn = syn::parse2(tokens).expect("failed to parse _execute_task");
91
92 if let Some((_, ref mut items)) = module.content {
93 items.push(Item::Fn(function));
94 }
95}
96
97pub fn add_show_help_for_task(module: &mut ItemMod, config: &TasksConfig) {
98 let separator = &config.separator;
99 let max_groupsize = &config.max_groupsize;
100 let max_depth = &config.max_depth;
101
102 let (maybe_async, maybe_await) = if cfg!(feature = "async") {
103 (quote! { async }, quote! { .await })
104 } else {
105 (quote! {}, quote! {})
106 };
107
108 let tokens = quote! {
109 #[command(about = "Show the help for a task", name="h", hide=true)]
110 pub #maybe_async fn _show_help_for_task(#[arg()] task: Option<String>) {
111 if let Some(task) = task {
112 let command = __internal_tusks_module::cli::Cli::command();
113 let parts: Vec<&str> = task.split(#separator).collect();
114
115 let args: Vec<&str> = std::iter::once(command.get_name())
116 .chain(parts.iter().copied())
117 .chain(std::iter::once("--help"))
118 .collect();
119
120 let cli = __internal_tusks_module::cli::Cli::parse_from(args);
121 __internal_tusks_module::handle_matches(&cli)#maybe_await;
122 }
123 else {
124 let command = __internal_tusks_module::cli::Cli::command();
125 let task_list = ::tusks::tasks::task_list::models::TaskList::from_command(
126 &command,
127 #separator.to_string(),
128 #max_groupsize,
129 #max_depth
130 );
131 task_list.into_list().print(&::tusks::tasks::list::models::RenderConfig::default());
132 }
133 }
134 };
135
136 let function: ItemFn = syn::parse2(tokens).expect("failed to parse _show_help_for_task");
137
138 if let Some((_, ref mut items)) = module.content {
139 items.push(Item::Fn(function));
140 }
141}