119625d8cSopenharmony_ciuse std::io::Write;
219625d8cSopenharmony_ci
319625d8cSopenharmony_ciuse clap::builder::StyledStr;
419625d8cSopenharmony_ciuse clap::*;
519625d8cSopenharmony_ci
619625d8cSopenharmony_ciuse crate::generator::{utils, Generator};
719625d8cSopenharmony_ciuse crate::INTERNAL_ERROR_MSG;
819625d8cSopenharmony_ci
919625d8cSopenharmony_ci/// Generate powershell completion file
1019625d8cSopenharmony_ci#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1119625d8cSopenharmony_cipub struct PowerShell;
1219625d8cSopenharmony_ci
1319625d8cSopenharmony_ciimpl Generator for PowerShell {
1419625d8cSopenharmony_ci    fn file_name(&self, name: &str) -> String {
1519625d8cSopenharmony_ci        format!("_{name}.ps1")
1619625d8cSopenharmony_ci    }
1719625d8cSopenharmony_ci
1819625d8cSopenharmony_ci    fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
1919625d8cSopenharmony_ci        let bin_name = cmd
2019625d8cSopenharmony_ci            .get_bin_name()
2119625d8cSopenharmony_ci            .expect("crate::generate should have set the bin_name");
2219625d8cSopenharmony_ci
2319625d8cSopenharmony_ci        let subcommands_cases = generate_inner(cmd, "");
2419625d8cSopenharmony_ci
2519625d8cSopenharmony_ci        let result = format!(
2619625d8cSopenharmony_ci            r#"
2719625d8cSopenharmony_ciusing namespace System.Management.Automation
2819625d8cSopenharmony_ciusing namespace System.Management.Automation.Language
2919625d8cSopenharmony_ci
3019625d8cSopenharmony_ciRegister-ArgumentCompleter -Native -CommandName '{bin_name}' -ScriptBlock {{
3119625d8cSopenharmony_ci    param($wordToComplete, $commandAst, $cursorPosition)
3219625d8cSopenharmony_ci
3319625d8cSopenharmony_ci    $commandElements = $commandAst.CommandElements
3419625d8cSopenharmony_ci    $command = @(
3519625d8cSopenharmony_ci        '{bin_name}'
3619625d8cSopenharmony_ci        for ($i = 1; $i -lt $commandElements.Count; $i++) {{
3719625d8cSopenharmony_ci            $element = $commandElements[$i]
3819625d8cSopenharmony_ci            if ($element -isnot [StringConstantExpressionAst] -or
3919625d8cSopenharmony_ci                $element.StringConstantType -ne [StringConstantType]::BareWord -or
4019625d8cSopenharmony_ci                $element.Value.StartsWith('-') -or
4119625d8cSopenharmony_ci                $element.Value -eq $wordToComplete) {{
4219625d8cSopenharmony_ci                break
4319625d8cSopenharmony_ci        }}
4419625d8cSopenharmony_ci        $element.Value
4519625d8cSopenharmony_ci    }}) -join ';'
4619625d8cSopenharmony_ci
4719625d8cSopenharmony_ci    $completions = @(switch ($command) {{{subcommands_cases}
4819625d8cSopenharmony_ci    }})
4919625d8cSopenharmony_ci
5019625d8cSopenharmony_ci    $completions.Where{{ $_.CompletionText -like "$wordToComplete*" }} |
5119625d8cSopenharmony_ci        Sort-Object -Property ListItemText
5219625d8cSopenharmony_ci}}
5319625d8cSopenharmony_ci"#,
5419625d8cSopenharmony_ci            bin_name = bin_name,
5519625d8cSopenharmony_ci            subcommands_cases = subcommands_cases
5619625d8cSopenharmony_ci        );
5719625d8cSopenharmony_ci
5819625d8cSopenharmony_ci        w!(buf, result.as_bytes());
5919625d8cSopenharmony_ci    }
6019625d8cSopenharmony_ci}
6119625d8cSopenharmony_ci
6219625d8cSopenharmony_ci// Escape string inside single quotes
6319625d8cSopenharmony_cifn escape_string(string: &str) -> String {
6419625d8cSopenharmony_ci    string.replace('\'', "''")
6519625d8cSopenharmony_ci}
6619625d8cSopenharmony_ci
6719625d8cSopenharmony_cifn get_tooltip<T: ToString>(help: Option<&StyledStr>, data: T) -> String {
6819625d8cSopenharmony_ci    match help {
6919625d8cSopenharmony_ci        Some(help) => escape_string(&help.to_string()),
7019625d8cSopenharmony_ci        _ => data.to_string(),
7119625d8cSopenharmony_ci    }
7219625d8cSopenharmony_ci}
7319625d8cSopenharmony_ci
7419625d8cSopenharmony_cifn generate_inner(p: &Command, previous_command_name: &str) -> String {
7519625d8cSopenharmony_ci    debug!("generate_inner");
7619625d8cSopenharmony_ci
7719625d8cSopenharmony_ci    let command_name = if previous_command_name.is_empty() {
7819625d8cSopenharmony_ci        p.get_bin_name().expect(INTERNAL_ERROR_MSG).to_string()
7919625d8cSopenharmony_ci    } else {
8019625d8cSopenharmony_ci        format!("{};{}", previous_command_name, &p.get_name())
8119625d8cSopenharmony_ci    };
8219625d8cSopenharmony_ci
8319625d8cSopenharmony_ci    let mut completions = String::new();
8419625d8cSopenharmony_ci    let preamble = String::from("\n            [CompletionResult]::new(");
8519625d8cSopenharmony_ci
8619625d8cSopenharmony_ci    for option in p.get_opts() {
8719625d8cSopenharmony_ci        if let Some(shorts) = option.get_short_and_visible_aliases() {
8819625d8cSopenharmony_ci            let tooltip = get_tooltip(option.get_help(), shorts[0]);
8919625d8cSopenharmony_ci            for short in shorts {
9019625d8cSopenharmony_ci                completions.push_str(&preamble);
9119625d8cSopenharmony_ci                completions.push_str(
9219625d8cSopenharmony_ci                    format!(
9319625d8cSopenharmony_ci                        "'-{}', '{}', {}, '{}')",
9419625d8cSopenharmony_ci                        short, short, "[CompletionResultType]::ParameterName", tooltip
9519625d8cSopenharmony_ci                    )
9619625d8cSopenharmony_ci                    .as_str(),
9719625d8cSopenharmony_ci                );
9819625d8cSopenharmony_ci            }
9919625d8cSopenharmony_ci        }
10019625d8cSopenharmony_ci
10119625d8cSopenharmony_ci        if let Some(longs) = option.get_long_and_visible_aliases() {
10219625d8cSopenharmony_ci            let tooltip = get_tooltip(option.get_help(), longs[0]);
10319625d8cSopenharmony_ci            for long in longs {
10419625d8cSopenharmony_ci                completions.push_str(&preamble);
10519625d8cSopenharmony_ci                completions.push_str(
10619625d8cSopenharmony_ci                    format!(
10719625d8cSopenharmony_ci                        "'--{}', '{}', {}, '{}')",
10819625d8cSopenharmony_ci                        long, long, "[CompletionResultType]::ParameterName", tooltip
10919625d8cSopenharmony_ci                    )
11019625d8cSopenharmony_ci                    .as_str(),
11119625d8cSopenharmony_ci                );
11219625d8cSopenharmony_ci            }
11319625d8cSopenharmony_ci        }
11419625d8cSopenharmony_ci    }
11519625d8cSopenharmony_ci
11619625d8cSopenharmony_ci    for flag in utils::flags(p) {
11719625d8cSopenharmony_ci        if let Some(shorts) = flag.get_short_and_visible_aliases() {
11819625d8cSopenharmony_ci            let tooltip = get_tooltip(flag.get_help(), shorts[0]);
11919625d8cSopenharmony_ci            for short in shorts {
12019625d8cSopenharmony_ci                completions.push_str(&preamble);
12119625d8cSopenharmony_ci                completions.push_str(
12219625d8cSopenharmony_ci                    format!(
12319625d8cSopenharmony_ci                        "'-{}', '{}', {}, '{}')",
12419625d8cSopenharmony_ci                        short, short, "[CompletionResultType]::ParameterName", tooltip
12519625d8cSopenharmony_ci                    )
12619625d8cSopenharmony_ci                    .as_str(),
12719625d8cSopenharmony_ci                );
12819625d8cSopenharmony_ci            }
12919625d8cSopenharmony_ci        }
13019625d8cSopenharmony_ci
13119625d8cSopenharmony_ci        if let Some(longs) = flag.get_long_and_visible_aliases() {
13219625d8cSopenharmony_ci            let tooltip = get_tooltip(flag.get_help(), longs[0]);
13319625d8cSopenharmony_ci            for long in longs {
13419625d8cSopenharmony_ci                completions.push_str(&preamble);
13519625d8cSopenharmony_ci                completions.push_str(
13619625d8cSopenharmony_ci                    format!(
13719625d8cSopenharmony_ci                        "'--{}', '{}', {}, '{}')",
13819625d8cSopenharmony_ci                        long, long, "[CompletionResultType]::ParameterName", tooltip
13919625d8cSopenharmony_ci                    )
14019625d8cSopenharmony_ci                    .as_str(),
14119625d8cSopenharmony_ci                );
14219625d8cSopenharmony_ci            }
14319625d8cSopenharmony_ci        }
14419625d8cSopenharmony_ci    }
14519625d8cSopenharmony_ci
14619625d8cSopenharmony_ci    for subcommand in p.get_subcommands() {
14719625d8cSopenharmony_ci        let data = &subcommand.get_name();
14819625d8cSopenharmony_ci        let tooltip = get_tooltip(subcommand.get_about(), data);
14919625d8cSopenharmony_ci
15019625d8cSopenharmony_ci        completions.push_str(&preamble);
15119625d8cSopenharmony_ci        completions.push_str(
15219625d8cSopenharmony_ci            format!(
15319625d8cSopenharmony_ci                "'{}', '{}', {}, '{}')",
15419625d8cSopenharmony_ci                data, data, "[CompletionResultType]::ParameterValue", tooltip
15519625d8cSopenharmony_ci            )
15619625d8cSopenharmony_ci            .as_str(),
15719625d8cSopenharmony_ci        );
15819625d8cSopenharmony_ci    }
15919625d8cSopenharmony_ci
16019625d8cSopenharmony_ci    let mut subcommands_cases = format!(
16119625d8cSopenharmony_ci        r"
16219625d8cSopenharmony_ci        '{}' {{{}
16319625d8cSopenharmony_ci            break
16419625d8cSopenharmony_ci        }}",
16519625d8cSopenharmony_ci        &command_name, completions
16619625d8cSopenharmony_ci    );
16719625d8cSopenharmony_ci
16819625d8cSopenharmony_ci    for subcommand in p.get_subcommands() {
16919625d8cSopenharmony_ci        let subcommand_subcommands_cases = generate_inner(subcommand, &command_name);
17019625d8cSopenharmony_ci        subcommands_cases.push_str(&subcommand_subcommands_cases);
17119625d8cSopenharmony_ci    }
17219625d8cSopenharmony_ci
17319625d8cSopenharmony_ci    subcommands_cases
17419625d8cSopenharmony_ci}
175