Allow printing nu completion script with just --completions nushell
(#2140)
This commit is contained in:
parent
1ca53e8b22
commit
0de971942a
3
.github/workflows/release.yaml
vendored
3
.github/workflows/release.yaml
vendored
@ -77,7 +77,8 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -euxo pipefail
|
set -euxo pipefail
|
||||||
cargo build
|
cargo build
|
||||||
for shell in bash elvish fish powershell zsh; do
|
mkdir -p completions
|
||||||
|
for shell in bash elvish fish nu powershell zsh; do
|
||||||
./target/debug/just --completions $shell > completions/just.$shell
|
./target/debug/just --completions $shell > completions/just.$shell
|
||||||
done
|
done
|
||||||
mkdir -p man
|
mkdir -p man
|
||||||
|
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -226,6 +226,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
|
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -250,6 +251,18 @@ dependencies = [
|
|||||||
"clap 4.5.4",
|
"clap 4.5.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.5.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.66",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -22,7 +22,7 @@ ansi_term = "0.12.0"
|
|||||||
blake3 = { version = "1.5.0", features = ["rayon", "mmap"] }
|
blake3 = { version = "1.5.0", features = ["rayon", "mmap"] }
|
||||||
camino = "1.0.4"
|
camino = "1.0.4"
|
||||||
chrono = "0.4.38"
|
chrono = "0.4.38"
|
||||||
clap = { version = "4.0.0", features = ["env", "wrap_help"] }
|
clap = { version = "4.0.0", features = ["derive", "env", "wrap_help"] }
|
||||||
clap_complete = "4.0.0"
|
clap_complete = "4.0.0"
|
||||||
clap_mangen = "0.2.20"
|
clap_mangen = "0.2.20"
|
||||||
ctrlc = { version = "3.1.1", features = ["termination"] }
|
ctrlc = { version = "3.1.1", features = ["termination"] }
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
def "nu-complete just" [] {
|
|
||||||
(^just --dump --unstable --dump-format json | from json).recipes | transpose recipe data | flatten | where {|row| $row.private == false } | select recipe doc parameters | rename value description
|
|
||||||
}
|
|
||||||
|
|
||||||
# Just: A Command Runner
|
|
||||||
export extern "just" [
|
|
||||||
...recipe: string@"nu-complete just", # Recipe(s) to run, may be with argument(s)
|
|
||||||
]
|
|
3
justfile
3
justfile
@ -165,9 +165,6 @@ watch-readme:
|
|||||||
just render-readme
|
just render-readme
|
||||||
fswatch -ro README.adoc | xargs -n1 -I{} just render-readme
|
fswatch -ro README.adoc | xargs -n1 -I{} just render-readme
|
||||||
|
|
||||||
update-completions:
|
|
||||||
./bin/update-completions
|
|
||||||
|
|
||||||
test-completions:
|
test-completions:
|
||||||
./tests/completions/just.bash
|
./tests/completions/just.bash
|
||||||
|
|
||||||
|
@ -1,4 +1,99 @@
|
|||||||
pub(crate) const FISH_RECIPE_COMPLETIONS: &str = r#"function __fish_just_complete_recipes
|
use {super::*, clap::ValueEnum};
|
||||||
|
|
||||||
|
#[derive(ValueEnum, Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub(crate) enum Shell {
|
||||||
|
Bash,
|
||||||
|
Elvish,
|
||||||
|
Fish,
|
||||||
|
#[value(alias = "nu")]
|
||||||
|
Nushell,
|
||||||
|
Powershell,
|
||||||
|
Zsh,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shell {
|
||||||
|
pub(crate) fn script(self) -> RunResult<'static, String> {
|
||||||
|
match self {
|
||||||
|
Self::Bash => completions::clap(clap_complete::Shell::Bash),
|
||||||
|
Self::Elvish => completions::clap(clap_complete::Shell::Elvish),
|
||||||
|
Self::Fish => completions::clap(clap_complete::Shell::Fish),
|
||||||
|
Self::Nushell => Ok(completions::NUSHELL_COMPLETION_SCRIPT.into()),
|
||||||
|
Self::Powershell => completions::clap(clap_complete::Shell::PowerShell),
|
||||||
|
Self::Zsh => completions::clap(clap_complete::Shell::Zsh),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clap(shell: clap_complete::Shell) -> RunResult<'static, String> {
|
||||||
|
fn replace(haystack: &mut String, needle: &str, replacement: &str) -> RunResult<'static, ()> {
|
||||||
|
if let Some(index) = haystack.find(needle) {
|
||||||
|
haystack.replace_range(index..index + needle.len(), replacement);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::internal(format!(
|
||||||
|
"Failed to find text:\n{needle}\n…in completion script:\n{haystack}"
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut script = {
|
||||||
|
let mut tempfile = tempfile().map_err(|io_error| Error::TempfileIo { io_error })?;
|
||||||
|
|
||||||
|
clap_complete::generate(
|
||||||
|
shell,
|
||||||
|
&mut crate::config::Config::app(),
|
||||||
|
env!("CARGO_PKG_NAME"),
|
||||||
|
&mut tempfile,
|
||||||
|
);
|
||||||
|
|
||||||
|
tempfile
|
||||||
|
.rewind()
|
||||||
|
.map_err(|io_error| Error::TempfileIo { io_error })?;
|
||||||
|
|
||||||
|
let mut buffer = String::new();
|
||||||
|
|
||||||
|
tempfile
|
||||||
|
.read_to_string(&mut buffer)
|
||||||
|
.map_err(|io_error| Error::TempfileIo { io_error })?;
|
||||||
|
|
||||||
|
buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
match shell {
|
||||||
|
clap_complete::Shell::Bash => {
|
||||||
|
for (needle, replacement) in completions::BASH_COMPLETION_REPLACEMENTS {
|
||||||
|
replace(&mut script, needle, replacement)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clap_complete::Shell::Fish => {
|
||||||
|
script.insert_str(0, completions::FISH_RECIPE_COMPLETIONS);
|
||||||
|
}
|
||||||
|
clap_complete::Shell::PowerShell => {
|
||||||
|
for (needle, replacement) in completions::POWERSHELL_COMPLETION_REPLACEMENTS {
|
||||||
|
replace(&mut script, needle, replacement)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clap_complete::Shell::Zsh => {
|
||||||
|
for (needle, replacement) in completions::ZSH_COMPLETION_REPLACEMENTS {
|
||||||
|
replace(&mut script, needle, replacement)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(script.trim().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
const NUSHELL_COMPLETION_SCRIPT: &str = r#"def "nu-complete just" [] {
|
||||||
|
(^just --dump --unstable --dump-format json | from json).recipes | transpose recipe data | flatten | where {|row| $row.private == false } | select recipe doc parameters | rename value description
|
||||||
|
}
|
||||||
|
|
||||||
|
# Just: A Command Runner
|
||||||
|
export extern "just" [
|
||||||
|
...recipe: string@"nu-complete just", # Recipe(s) to run, may be with argument(s)
|
||||||
|
]"#;
|
||||||
|
|
||||||
|
const FISH_RECIPE_COMPLETIONS: &str = r#"function __fish_just_complete_recipes
|
||||||
just --list 2> /dev/null | tail -n +2 | awk '{
|
just --list 2> /dev/null | tail -n +2 | awk '{
|
||||||
command = $1;
|
command = $1;
|
||||||
args = $0;
|
args = $0;
|
||||||
@ -37,7 +132,7 @@ complete -c just -a '(__fish_just_complete_recipes)'
|
|||||||
# autogenerated completions
|
# autogenerated completions
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
pub(crate) const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[
|
const ZSH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[
|
||||||
(
|
(
|
||||||
r#" _arguments "${_arguments_options[@]}" \"#,
|
r#" _arguments "${_arguments_options[@]}" \"#,
|
||||||
r" local common=(",
|
r" local common=(",
|
||||||
@ -151,7 +246,7 @@ _just "$@""#,
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub(crate) const POWERSHELL_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[(
|
const POWERSHELL_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[(
|
||||||
r#"$completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
|
r#"$completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
|
||||||
Sort-Object -Property ListItemText"#,
|
Sort-Object -Property ListItemText"#,
|
||||||
r#"function Get-JustFileRecipes([string[]]$CommandElements) {
|
r#"function Get-JustFileRecipes([string[]]$CommandElements) {
|
||||||
@ -178,7 +273,7 @@ pub(crate) const POWERSHELL_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[(
|
|||||||
Sort-Object -Property ListItemText"#,
|
Sort-Object -Property ListItemText"#,
|
||||||
)];
|
)];
|
||||||
|
|
||||||
pub(crate) const BASH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[
|
const BASH_COMPLETION_REPLACEMENTS: &[(&str, &str)] = &[
|
||||||
(
|
(
|
||||||
r#" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
|
r#" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
|
||||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||||
|
@ -381,10 +381,9 @@ impl Config {
|
|||||||
.arg(
|
.arg(
|
||||||
Arg::new(cmd::COMPLETIONS)
|
Arg::new(cmd::COMPLETIONS)
|
||||||
.long("completions")
|
.long("completions")
|
||||||
.action(ArgAction::Append)
|
.action(ArgAction::Set)
|
||||||
.num_args(1..)
|
|
||||||
.value_name("SHELL")
|
.value_name("SHELL")
|
||||||
.value_parser(value_parser!(clap_complete::Shell))
|
.value_parser(value_parser!(completions::Shell))
|
||||||
.ignore_case(true)
|
.ignore_case(true)
|
||||||
.help("Print shell completion script for <SHELL>"),
|
.help("Print shell completion script for <SHELL>"),
|
||||||
)
|
)
|
||||||
@ -686,7 +685,7 @@ impl Config {
|
|||||||
arguments,
|
arguments,
|
||||||
overrides,
|
overrides,
|
||||||
}
|
}
|
||||||
} else if let Some(&shell) = matches.get_one::<clap_complete::Shell>(cmd::COMPLETIONS) {
|
} else if let Some(&shell) = matches.get_one::<completions::Shell>(cmd::COMPLETIONS) {
|
||||||
Subcommand::Completions { shell }
|
Subcommand::Completions { shell }
|
||||||
} else if matches.get_flag(cmd::EDIT) {
|
} else if matches.get_flag(cmd::EDIT) {
|
||||||
Subcommand::Edit
|
Subcommand::Edit
|
||||||
@ -1255,13 +1254,13 @@ mod tests {
|
|||||||
test! {
|
test! {
|
||||||
name: subcommand_completions,
|
name: subcommand_completions,
|
||||||
args: ["--completions", "bash"],
|
args: ["--completions", "bash"],
|
||||||
subcommand: Subcommand::Completions{ shell: clap_complete::Shell::Bash },
|
subcommand: Subcommand::Completions{ shell: completions::Shell::Bash },
|
||||||
}
|
}
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
name: subcommand_completions_uppercase,
|
name: subcommand_completions_uppercase,
|
||||||
args: ["--completions", "BASH"],
|
args: ["--completions", "BASH"],
|
||||||
subcommand: Subcommand::Completions{ shell: clap_complete::Shell::Bash },
|
subcommand: Subcommand::Completions{ shell: completions::Shell::Bash },
|
||||||
}
|
}
|
||||||
|
|
||||||
error! {
|
error! {
|
||||||
@ -1544,15 +1543,30 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
error_matches! {
|
error_matches! {
|
||||||
name: completions_arguments,
|
name: completions_argument,
|
||||||
args: ["--completions", "zsh", "foo"],
|
args: ["--completions", "foo"],
|
||||||
error: error,
|
error: error,
|
||||||
check: {
|
check: {
|
||||||
assert_eq!(error.kind(), clap::error::ErrorKind::InvalidValue);
|
assert_eq!(error.kind(), clap::error::ErrorKind::InvalidValue);
|
||||||
assert_eq!(error.context().collect::<Vec<_>>(), vec![
|
assert_eq!(error.context().collect::<Vec<_>>(), vec![
|
||||||
(ContextKind::InvalidArg, &ContextValue::String("--completions <SHELL>...".into())),
|
(
|
||||||
(ContextKind::InvalidValue, &ContextValue::String("foo".into())),
|
ContextKind::InvalidArg,
|
||||||
(ContextKind::ValidValue, &ContextValue::Strings(["bash".into(), "elvish".into(), "fish".into(), "powershell".into(), "zsh".into()].into())),
|
&ContextValue::String("--completions <SHELL>".into())),
|
||||||
|
(
|
||||||
|
ContextKind::InvalidValue,
|
||||||
|
&ContextValue::String("foo".into()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
ContextKind::ValidValue,
|
||||||
|
&ContextValue::Strings([
|
||||||
|
"bash".into(),
|
||||||
|
"elvish".into(),
|
||||||
|
"fish".into(),
|
||||||
|
"nushell".into(),
|
||||||
|
"powershell".into(),
|
||||||
|
"zsh".into()].into()
|
||||||
|
),
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
43
src/lib.rs
43
src/lib.rs
@ -39,27 +39,6 @@ pub(crate) use {
|
|||||||
unresolved_recipe::UnresolvedRecipe, use_color::UseColor, variables::Variables,
|
unresolved_recipe::UnresolvedRecipe, use_color::UseColor, variables::Variables,
|
||||||
verbosity::Verbosity, warning::Warning,
|
verbosity::Verbosity, warning::Warning,
|
||||||
},
|
},
|
||||||
std::{
|
|
||||||
borrow::Cow,
|
|
||||||
cmp,
|
|
||||||
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
|
||||||
env,
|
|
||||||
ffi::OsString,
|
|
||||||
fmt::{self, Debug, Display, Formatter},
|
|
||||||
fs,
|
|
||||||
io::{self, Write},
|
|
||||||
iter::{self, FromIterator},
|
|
||||||
mem,
|
|
||||||
ops::Deref,
|
|
||||||
ops::{Index, Range, RangeInclusive},
|
|
||||||
path::{self, Path, PathBuf},
|
|
||||||
process::{self, Command, ExitStatus, Stdio},
|
|
||||||
rc::Rc,
|
|
||||||
str::{self, Chars},
|
|
||||||
sync::{Mutex, MutexGuard, OnceLock},
|
|
||||||
vec,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
camino::Utf8Path,
|
camino::Utf8Path,
|
||||||
derivative::Derivative,
|
derivative::Derivative,
|
||||||
edit_distance::edit_distance,
|
edit_distance::edit_distance,
|
||||||
@ -72,10 +51,30 @@ pub(crate) use {
|
|||||||
Serialize, Serializer,
|
Serialize, Serializer,
|
||||||
},
|
},
|
||||||
snafu::{ResultExt, Snafu},
|
snafu::{ResultExt, Snafu},
|
||||||
|
std::{
|
||||||
|
borrow::Cow,
|
||||||
|
cmp,
|
||||||
|
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
||||||
|
env,
|
||||||
|
ffi::OsString,
|
||||||
|
fmt::{self, Debug, Display, Formatter},
|
||||||
|
fs,
|
||||||
|
io::{self, Read, Seek, Write},
|
||||||
|
iter::{self, FromIterator},
|
||||||
|
mem,
|
||||||
|
ops::Deref,
|
||||||
|
ops::{Index, Range, RangeInclusive},
|
||||||
|
path::{self, Path, PathBuf},
|
||||||
|
process::{self, Command, ExitStatus, Stdio},
|
||||||
|
rc::Rc,
|
||||||
|
str::{self, Chars},
|
||||||
|
sync::{Mutex, MutexGuard, OnceLock},
|
||||||
|
vec,
|
||||||
|
},
|
||||||
strum::{Display, EnumDiscriminants, EnumString, IntoStaticStr},
|
strum::{Display, EnumDiscriminants, EnumString, IntoStaticStr},
|
||||||
|
tempfile::tempfile,
|
||||||
typed_arena::Arena,
|
typed_arena::Arena,
|
||||||
unicode_width::{UnicodeWidthChar, UnicodeWidthStr},
|
unicode_width::{UnicodeWidthChar, UnicodeWidthStr},
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
use {
|
use {super::*, clap_mangen::Man};
|
||||||
super::*,
|
|
||||||
clap_mangen::Man,
|
|
||||||
std::io::{Read, Seek},
|
|
||||||
tempfile::tempfile,
|
|
||||||
};
|
|
||||||
|
|
||||||
const INIT_JUSTFILE: &str = "default:\n echo 'Hello, world!'\n";
|
const INIT_JUSTFILE: &str = "default:\n echo 'Hello, world!'\n";
|
||||||
|
|
||||||
@ -20,7 +15,7 @@ pub(crate) enum Subcommand {
|
|||||||
overrides: BTreeMap<String, String>,
|
overrides: BTreeMap<String, String>,
|
||||||
},
|
},
|
||||||
Completions {
|
Completions {
|
||||||
shell: clap_complete::Shell,
|
shell: completions::Shell,
|
||||||
},
|
},
|
||||||
Dump,
|
Dump,
|
||||||
Edit,
|
Edit,
|
||||||
@ -296,68 +291,8 @@ impl Subcommand {
|
|||||||
justfile.run(config, search, overrides, &recipes)
|
justfile.run(config, search, overrides, &recipes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn completions(shell: clap_complete::Shell) -> RunResult<'static, ()> {
|
fn completions(shell: completions::Shell) -> RunResult<'static, ()> {
|
||||||
use clap_complete::Shell;
|
println!("{}", shell.script()?);
|
||||||
|
|
||||||
fn replace(haystack: &mut String, needle: &str, replacement: &str) -> RunResult<'static, ()> {
|
|
||||||
if let Some(index) = haystack.find(needle) {
|
|
||||||
haystack.replace_range(index..index + needle.len(), replacement);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(Error::internal(format!(
|
|
||||||
"Failed to find text:\n{needle}\n…in completion script:\n{haystack}"
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut script = {
|
|
||||||
let mut tempfile = tempfile().map_err(|io_error| Error::TempfileIo { io_error })?;
|
|
||||||
|
|
||||||
clap_complete::generate(
|
|
||||||
shell,
|
|
||||||
&mut crate::config::Config::app(),
|
|
||||||
env!("CARGO_PKG_NAME"),
|
|
||||||
&mut tempfile,
|
|
||||||
);
|
|
||||||
|
|
||||||
tempfile
|
|
||||||
.rewind()
|
|
||||||
.map_err(|io_error| Error::TempfileIo { io_error })?;
|
|
||||||
|
|
||||||
let mut buffer = String::new();
|
|
||||||
|
|
||||||
tempfile
|
|
||||||
.read_to_string(&mut buffer)
|
|
||||||
.map_err(|io_error| Error::TempfileIo { io_error })?;
|
|
||||||
|
|
||||||
buffer
|
|
||||||
};
|
|
||||||
|
|
||||||
match shell {
|
|
||||||
Shell::Bash => {
|
|
||||||
for (needle, replacement) in completions::BASH_COMPLETION_REPLACEMENTS {
|
|
||||||
replace(&mut script, needle, replacement)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Shell::Fish => {
|
|
||||||
script.insert_str(0, completions::FISH_RECIPE_COMPLETIONS);
|
|
||||||
}
|
|
||||||
Shell::PowerShell => {
|
|
||||||
for (needle, replacement) in completions::POWERSHELL_COMPLETION_REPLACEMENTS {
|
|
||||||
replace(&mut script, needle, replacement)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Shell::Zsh => {
|
|
||||||
for (needle, replacement) in completions::ZSH_COMPLETION_REPLACEMENTS {
|
|
||||||
replace(&mut script, needle, replacement)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{}", script.trim());
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ fn bash() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn replacements() {
|
fn replacements() {
|
||||||
for shell in ["bash", "elvish", "fish", "powershell", "zsh"] {
|
for shell in ["bash", "elvish", "fish", "nushell", "powershell", "zsh"] {
|
||||||
let output = Command::new(executable_path("just"))
|
let output = Command::new(executable_path("just"))
|
||||||
.args(["--completions", shell])
|
.args(["--completions", shell])
|
||||||
.output()
|
.output()
|
||||||
|
Loading…
Reference in New Issue
Block a user