1

I want to make an CLI application with an package autocomplete.
I use the function below to make it.

fn package_completion() -> Result<Vec<String>, String> {
    let command = process::Command::new("yay")
        .arg("-Pc")
        .output()
        .expect("failed to execute process");

    let stdout = String::from_utf8(command.stdout).unwrap();
    let stderr = String::from_utf8(command.stderr).unwrap();

    if !stderr.is_empty() {
        return Err(stderr);
    }

    let mut output: Vec<String> = stdout
        .lines()
        .map(|line| line.split_whitespace().next().unwrap().to_string())
        .collect();

    if output.len() > 0 {
        output.remove(0);
    }

    Ok(output)
}

pub fn build_cli() -> Command {
    let package_list = package_completion().unwrap();
    let packages: Vec<&str> = package_list.iter().map(|s| s.as_str()).collect(); // This line occurs error

    Command::new("yay-helper")
        .version("0.0.0")
        .subcommand_required(true)
        .arg_required_else_help(true)
        .subcommand(
            Command::new("query")
                .long_flag("query")
                .short_flag('q')
                .about("Query a package")
                .arg(
                    Arg::new("package")
                        .help("Package to query")
                        .required(true)
                        .action(ArgAction::Set)
                        .num_args(1..),
                ),
        )
        .subcommand(
            Command::new("install")
                .long_flag("install")
                .short_flag('i')
                .about("Install a package")
                .arg(
                    Arg::new("package")
                        .help("Package to query")
                        .value_parser(packages) // Here goes the packages
                        .required(true)
                        .action(ArgAction::Set)
                        .num_args(1..),
                ),
        //...

The error occurs in cargo build:

   |
30 |     let package_list = package_completion().unwrap();
   |         ------------ binding `package_list` declared here
31 |     let packages: Vec<&str> = package_list.iter().map(|s| s.as_str()).collect(); // This line occurs error
   |                               ^^^^^^^^^^^^^^^^^^^         ---------- returning this value requires that `package_list` is borrowed for `'static`
   |                               |
   |                               borrowed value does not live long enough
...
83 | }
   | - `package_list` dropped here while still borrowed

I need to this be faster, because is an autocomplete in CLI.

I don't understand why it not works, because in value_parser I should use an vector or array.
If someone explain to me I'll be thankful.

Sorry if this question isn't good, I've never made a question in StackOverflow before.

zx485
  • 28,498
  • 28
  • 50
  • 59
DevAles
  • 11
  • 2
  • The error message says that something is happening on line 83 that is causing package_list to be dropped. I would look at line 83 to see what's happening. Perhaps line 83 is the end of package_completion function outside of which the value of package_list does not live? I also suggest looking at how Rust manages lifetimes and borrowing. – Seth Difley Jul 08 '23 at 20:30
  • Is the end of build_cli function. I not understand why the error happens because the variable works in the same scope but with other functions, just this specific function cause this issue – DevAles Jul 08 '23 at 21:54

1 Answers1

0

I figured there had to be a way to use String directly, and after traversing many From implementations, found this.

NOTE: To support dynamic values (i.e. String), enable the string feature

So you can enable the string feature, then pass in the original Vec.

.value_parser(package_list)
drewtato
  • 6,783
  • 1
  • 12
  • 17