Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clap_complete generates invalid powershell code when docs have RIGHT_SINGLE_QUOTATION_MARK #5820

Open
2 tasks done
fnando opened this issue Nov 15, 2024 · 0 comments
Open
2 tasks done
Labels
A-completion Area: completion generator C-bug Category: Updating dependencies E-help-wanted Call for participation: Help is requested to fix this issue. E-medium Call for participation: Experience needed to fix: Medium / intermediate

Comments

@fnando
Copy link

fnando commented Nov 15, 2024

Please complete the following tasks

Rust Version

rustc 1.81.0 (eeb90cda1 2024-09-04)

Clap Version

4.5.21

Minimal reproducible code

use std::io;

use clap::{CommandFactory, Parser};
use clap_complete::{generate, Shell};

fn main() {
    let cmd = Cmd::parse();
    cmd.run();
}

#[derive(Parser, Debug)]
struct Cmd {
    /// This doesn’t work on powershell.
    #[arg(long)]
    shell: Shell,
}

impl Cmd {
    fn run(&self) {
        let cmd = &mut Cmd::command();
        generate(self.shell, cmd, "sample", &mut io::stdout());
    }
}

Steps to reproduce the bug with the above code

On Windows (PowerShell), run:

cargo run -- --shell powershell > bug.ps1

Then try to load this file:

$ . .\bug.ps1
ParserError: C:\Users\fnando\Downloads\bug.ps1:24
Line |
  24 |  … --shell', [CompletionResultType]::ParameterName, 'This doesn’t work o …
     |                                                                 ~
     | Missing ')' in method call.

Actual Behaviour

When trying to load the generated completion code, I get an exception because it's not properly escaping .

Expected Behaviour

clap_complete escapes

Additional Context

No response

Debug Output

$ cargo run -- --shell powershell
[clap_builder::builder::command]Command::_do_parse
[clap_builder::builder::command]Command::_build: name="clap_complete_bug"
[clap_builder::builder::command]Command::_propagate:clap_complete_bug
[clap_builder::builder::command]Command::_check_help_and_version:clap_complete_bug expand_help_tree=false
[clap_builder::builder::command]Command::long_help_exists
[clap_builder::builder::command]Command::_check_help_and_version: Building default --help
[clap_builder::builder::command]Command::_propagate_global_args:clap_complete_bug
[clap_builder::builder::debug_asserts]Command::_debug_asserts
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:shell
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:help
[clap_builder::builder::debug_asserts]Command::_verify_positionals
[clap_builder::parser::parser]Parser::get_matches_with
[clap_builder::parser::parser]Parser::parse
[clap_builder::parser::parser]Parser::get_matches_with: Begin parsing '"--shell"'
[clap_builder::parser::parser]Parser::possible_subcommand: arg=Ok("--shell")
[clap_builder::parser::parser]Parser::get_matches_with: sc=None
[clap_builder::parser::parser]Parser::parse_long_arg
[clap_builder::parser::parser]Parser::parse_long_arg: Does it contain '='...
[clap_builder::parser::parser]Parser::parse_long_arg: Found valid arg or flag '--shell <SHELL>'
[clap_builder::parser::parser]Parser::parse_long_arg("shell"): Found an arg with value 'None'
[clap_builder::parser::parser]Parser::parse_opt_value; arg=shell, val=None, has_eq=false
[clap_builder::parser::parser]Parser::parse_opt_value; arg.settings=ArgFlags(1)
[clap_builder::parser::parser]Parser::parse_opt_value; Checking for val...
[clap_builder::parser::parser]Parser::parse_opt_value: More arg vals required...
[clap_builder::parser::parser]Parser::get_matches_with: After parse_long_arg Opt("shell")
[clap_builder::parser::parser]Parser::get_matches_with: Begin parsing '"powershell"'
[clap_builder::parser::arg_matcher]ArgMatcher::needs_more_vals: o=shell, pending=1
[clap_builder::parser::arg_matcher]ArgMatcher::needs_more_vals: expected=1, actual=1
[clap_builder::parser::parser]Parser::resolve_pending: id="shell"
[clap_builder::parser::parser]Parser::react action=Set, identifier=Some(Long), source=CommandLine
[clap_builder::parser::parser]Parser::react: cur_idx:=1
[clap_builder::parser::parser]Parser::remove_overrides: id="shell"
[clap_builder::parser::arg_matcher]ArgMatcher::start_custom_arg: id="shell", source=CommandLine
[clap_builder::builder::command]Command::groups_for_arg: id="shell"
[clap_builder::parser::arg_matcher]ArgMatcher::start_custom_arg: id="Cmd", source=CommandLine
[clap_builder::parser::parser]Parser::push_arg_values: ["powershell"]
[clap_builder::parser::parser]Parser::add_single_val_to_arg: cur_idx:=2
[clap_builder::parser::arg_matcher]ArgMatcher::needs_more_vals: o=shell, pending=0
[clap_builder::parser::arg_matcher]ArgMatcher::needs_more_vals: expected=1, actual=0
[clap_builder::parser::parser]Parser::react not enough values passed in, leaving it to the validator to complain
[clap_builder::parser::parser]Parser::add_defaults
[clap_builder::parser::parser]Parser::add_defaults:iter:shell:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:shell: doesn't have default vals
[clap_builder::parser::parser]Parser::add_defaults:iter:help:
[clap_builder::parser::parser]Parser::add_default_value: doesn't have conditional defaults
[clap_builder::parser::parser]Parser::add_default_value:iter:help: doesn't have default vals
[clap_builder::parser::validator]Validator::validate
[clap_builder::builder::command]Command::groups_for_arg: id="shell"
[clap_builder::parser::validator]Conflicts::gather_direct_conflicts id="shell", conflicts=[]
[clap_builder::parser::validator]Conflicts::gather_direct_conflicts id="Cmd", conflicts=[]
[clap_builder::parser::validator]Validator::validate_conflicts
[clap_builder::parser::validator]Validator::validate_exclusive
[clap_builder::parser::validator]Validator::validate_conflicts::iter: id="shell"
[clap_builder::parser::validator]Conflicts::gather_conflicts: arg="shell"
[clap_builder::parser::validator]Conflicts::gather_conflicts: conflicts=[]
[clap_builder::parser::validator]Validator::validate_required: required=ChildGraph([Child { id: "shell", children: [] }])
[clap_builder::parser::validator]Validator::gather_requires
[clap_builder::parser::validator]Validator::gather_requires:iter:"shell"
[clap_builder::parser::validator]Validator::gather_requires:iter:"Cmd"
[clap_builder::parser::validator]Validator::gather_requires:iter:"Cmd":group
[clap_builder::parser::validator]Validator::validate_required: is_exclusive_present=false
[clap_builder::parser::arg_matcher]ArgMatcher::get_global_values: global_arg_vec=[]
[clap_builder::builder::command]Command::_build: name="clap_complete_bug"
[clap_builder::builder::command]Command::_propagate:clap_complete_bug
[clap_builder::builder::command]Command::_check_help_and_version:clap_complete_bug expand_help_tree=true
[clap_builder::builder::command]Command::long_help_exists
[clap_builder::builder::command]Command::_check_help_and_version: Building default --help
[clap_builder::builder::command]Command::_propagate_global_args:clap_complete_bug
[clap_builder::builder::debug_asserts]Command::_debug_asserts
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:shell
[clap_builder::builder::debug_asserts]Arg::_debug_asserts:help
[clap_builder::builder::debug_asserts]Command::_verify_positionals
[clap_builder::builder::command]Command::_build_bin_names
[ clap_builder::output::usage]Usage::get_required_usage_from: incls=[], matcher=false, incl_last=true
[ clap_builder::output::usage]Usage::get_required_usage_from: unrolled_reqs=["shell"]
[ clap_builder::output::usage]Usage::get_required_usage_from:iter:"shell" arg is_present=false
[ clap_builder::output::usage]Usage::get_required_usage_from: ret_val=[StyledStr("\u{1b}[1m--shell\u{1b}[0m <SHELL>")]

using namespace System.Management.Automation
using namespace System.Management.Automation.Language

Register-ArgumentCompleter -Native -CommandName 'sample' -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)

    $commandElements = $commandAst.CommandElements
    $command = @(
        'sample'
        for ($i = 1; $i -lt $commandElements.Count; $i++) {
            $element = $commandElements[$i]
            if ($element -isnot [StringConstantExpressionAst] -or
                $element.StringConstantType -ne [StringConstantType]::BareWord -or
                $element.Value.StartsWith('-') -or
                $element.Value -eq $wordToComplete) {
                break
        }
        $element.Value
    }) -join ';'

    $completions = @(switch ($command) {
        'sample' {
            [CompletionResult]::new('--shell', '--shell', [CompletionResultType]::ParameterName, 'This doesn’t work on powershell')
            [CompletionResult]::new('-h', '-h', [CompletionResultType]::ParameterName, 'Print help')
            [CompletionResult]::new('--help', '--help', [CompletionResultType]::ParameterName, 'Print help')
            break
        }
    })

    $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
        Sort-Object -Property ListItemText
}
@fnando fnando added the C-bug Category: Updating dependencies label Nov 15, 2024
@epage epage added A-completion Area: completion generator E-medium Call for participation: Experience needed to fix: Medium / intermediate E-help-wanted Call for participation: Help is requested to fix this issue. labels Nov 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-completion Area: completion generator C-bug Category: Updating dependencies E-help-wanted Call for participation: Help is requested to fix this issue. E-medium Call for participation: Experience needed to fix: Medium / intermediate
Projects
None yet
Development

No branches or pull requests

2 participants