tusks_lib/codegen/preparse/tasks/
functions.rs

1use syn::{Item, ItemFn, ItemMod, parse_quote};
2use syn::{Attribute, Meta};
3
4use crate::{AttributeValue, attribute::models::TasksConfig};
5
6pub fn add_use_staements(module: &mut ItemMod) {
7    let use_statement: Item = parse_quote! {
8        use ::tusks::clap::{CommandFactory, Parser};
9    };
10    
11    if let Some((_, ref mut items)) = module.content {
12        items.insert(0, use_statement);
13    }
14}
15
16pub fn set_allow_external_subcommands(module: &mut ItemMod) {
17    if module.get_attribute_bool("command", "allow_external_subcommands") {
18        return;
19    }
20    
21    // Suche nach existierendem #[command(...)]-Attribut
22    if let Some(attr) = module.attrs.iter_mut().find(|a| a.path().is_ident("command")) {
23        // Vorhandenes command-Attribut gefunden
24        match &mut attr.meta {
25            Meta::List(list) => {
26                // Prüfe, ob tokens mit Komma enden
27                let tokens_str = list.tokens.to_string();
28                let has_trailing_comma = tokens_str.trim_end().ends_with(',');
29                
30                let tokens = &list.tokens;
31                if tokens.is_empty() {
32                    list.tokens = parse_quote! { allow_external_subcommands = true };
33                } else if has_trailing_comma {
34                    // Komma ist bereits da, kein zusätzliches einfügen
35                    list.tokens = parse_quote! { #tokens allow_external_subcommands = true };
36                } else {
37                    // Komma hinzufügen
38                    list.tokens = parse_quote! { #tokens, allow_external_subcommands = true };
39                }
40            }
41            Meta::Path(_) => {
42                // #[command] ohne Argumente -> konvertiere zu #[command(allow_external_subcommands = true)]
43                *attr = parse_quote! { #[command(allow_external_subcommands = true)] };
44            }
45            Meta::NameValue(_) => {
46                // Unerwarteter Fall, ersetze komplett
47                *attr = parse_quote! { #[command(allow_external_subcommands = true)] };
48            }
49        }
50    } else {
51        // Kein command-Attribut vorhanden -> füge neues hinzu
52        let new_attr: Attribute = parse_quote! { #[command(allow_external_subcommands = true)] };
53        module.attrs.push(new_attr);
54    }
55}
56
57pub fn add_execute_task_function(module: &mut ItemMod, config: &TasksConfig) {
58    let cmd_name = "tasks"; // TODO
59    let separator = &config.separator;
60    let max_groupsize = &config.max_groupsize;
61    let max_depth = &config.max_depth;
62    
63    let function: ItemFn = parse_quote! {
64        #[command(about = "Execute a task", hide=true)]
65        #[default]
66        pub fn _execute_task(external_args: Vec<String>) -> Option<u8> {
67            let mut transformed_arguments = Vec::new();
68            if let Some(first) = external_args.first() {
69                transformed_arguments.push(#cmd_name.to_string());
70                transformed_arguments.extend(first.split(#separator).map(|s| s.to_string()));
71                transformed_arguments.extend_from_slice(&external_args[1..]);
72                let cli = __internal_tusks_module::cli::Cli::parse_from(
73                    transformed_arguments
74                );
75                __internal_tusks_module::handle_matches(&cli)
76            }
77            else {
78                let command = __internal_tusks_module::cli::Cli::command();
79                if external_args.len() == 0 {
80                    let task_list = ::tusks::tasks::task_list::models::TaskList::from_command(
81                        &command,
82                        #separator.to_string(),
83                        #max_groupsize,
84                        #max_depth
85                    );
86                    task_list.to_list().print(&::tusks::tasks::list::models::RenderConfig::default());
87                }
88                else {
89                    let cli = __internal_tusks_module::cli::Cli::parse_from(
90                        std::iter::once(#cmd_name).chain(external_args.iter().map(String::as_str))
91                    );
92                    __internal_tusks_module::handle_matches(&cli);
93                }
94                Some(0)
95            }
96        }
97    };
98    
99    if let Some((_, ref mut items)) = module.content {
100        items.push(Item::Fn(function));
101    }
102}
103
104pub fn add_show_help_for_task(module: &mut ItemMod, config: &TasksConfig) {
105    let cmd_name = "tasks"; // TODO
106    let separator = &config.separator;
107    let max_groupsize = &config.max_groupsize;
108    let max_depth = &config.max_depth;
109
110    let function: ItemFn = parse_quote! {
111        #[command(about = "Show the help for a task", name="h", hide=true)]
112        pub fn _show_help_for_task(#[arg()] task: Option<String>) {
113            if let Some(task) = task {
114                let parts: Vec<&str> = task.split(#separator).collect();
115
116                let args: Vec<&str> = std::iter::once(#cmd_name)
117                    .chain(parts.iter().copied())
118                    .chain(std::iter::once("--help"))
119                    .collect();
120
121                let cli = __internal_tusks_module::cli::Cli::parse_from(args);
122                __internal_tusks_module::handle_matches(&cli);
123            }
124            else {
125                let command = __internal_tusks_module::cli::Cli::command();
126                let task_list = ::tusks::tasks::task_list::models::TaskList::from_command(
127                    &command,
128                    #separator.to_string(),
129                    #max_groupsize,
130                    #max_depth
131                );
132                task_list.to_list().print(&::tusks::tasks::list::models::RenderConfig::default());
133            }
134        }
135    };
136
137    if let Some((_, ref mut items)) = module.content {
138        items.push(Item::Fn(function));
139    }
140}