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

Feat/autocomplete run tasks #390

Merged
merged 11 commits into from
Oct 19, 2023
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ repos:
rev: v2.2.5
hooks:
- id: codespell
exclude: ".snap"
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ rattler_repodata_gateway = { version = "0.10.0", default-features = false, featu
rattler_shell = { version = "0.10.0", default-features = false, features = ["sysinfo"] }
rattler_solve = { version = "0.10.0", default-features = false, features = ["resolvo"] }
rattler_virtual_packages = { version = "0.10.0", default-features = false }
regex = "1.9.5"
reqwest = { version = "0.11.22", default-features = false }
serde = "1.0.188"
serde_json = "1.0.107"
Expand Down
124 changes: 124 additions & 0 deletions src/cli/completion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use crate::cli::{Args, CompletionCommand};
use clap::CommandFactory;
use miette::IntoDiagnostic;
use regex::Regex;
use std::borrow::Cow;
use std::io::Write;
use std::str::from_utf8_mut;

pub(crate) fn execute(args: CompletionCommand) -> miette::Result<()> {
let clap_shell = args
.shell
.or(clap_complete::Shell::from_env())
.unwrap_or(clap_complete::Shell::Bash);

let mut script = vec![];

// Generate the original completion script.
clap_complete::generate(
clap_shell,
&mut Args::command(),
"pixi",
&mut script, // &mut std::io::stdout(),
);

match clap_shell {
clap_complete::Shell::Bash => {
let script = replace_bash_completion(from_utf8_mut(&mut script).into_diagnostic()?);
std::io::stdout()
.write_all(script.as_ref().as_ref())
.into_diagnostic()?;
}
_ => {
// If no replacements needed write original script to stdout
std::io::stdout().write_all(&script).into_diagnostic()?;
}
}
baszalmstra marked this conversation as resolved.
Show resolved Hide resolved

Ok(())
}

fn replace_bash_completion(script: &str) -> Cow<str> {
let pattern = r#"(?s)pixi__run\).*?opts="(.*?)".*?(if.*?fi)"#;

let replacement = r#"pixi__run)
opts="$1"
if [[ $${cur} == -* ]] ; then
COMPREPLY=( $$(compgen -W "$${opts}" -- "$${cur}") )
return 0
elif [[ $${COMP_CWORD} -eq 2 ]]; then
local tasks=$$(pixi task list --summary 2> /dev/null)
if [[ $$? -eq 0 ]]; then
COMPREPLY=( $$(compgen -W "$${tasks}" -- "$${cur}") )
return 0
fi
fi"#;
let re = Regex::new(pattern).unwrap();
re.replace(script, replacement)
}
#[cfg(test)]
mod tests {
use super::*;

#[test]
pub fn test_completion() {
baszalmstra marked this conversation as resolved.
Show resolved Hide resolved
let mut script = r#"
pixi__project__help__help)
opts=""
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
pixi__run)
opts="-v -q -h --manifest-path --locked --frozen --verbose --quiet --color --help [TASK]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
--manifest-path)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--color)
COMPREPLY=($(compgen -W "always never auto" -- "${cur}"))
return 0
;;
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
pixi__search)
opts="-c -l -v -q -h --channel --color --help <PACKAGE>"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
fi
case "${prev}" in
--channel)
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )

;;
"#;
let pattern = r#"(?s)pixi__run\).*?opts="(.*?)".*?(if.*?fi)"#;

let replacement = r#"pixi__run)
opts="$1"
if [[ $${cur} == -* ]] ; then
COMPREPLY=( $$(compgen -W "$${opts}" -- "$${cur}") )
return 0
elif [[ $${COMP_CWORD} -eq 2 ]]; then
local tasks=$$(pixi task list --summary 2> /dev/null)
if [[ $$? -eq 0 ]]; then
COMPREPLY=( $$(compgen -W "$${tasks}" -- "$${cur}") )
return 0
fi
fi"#;

let re = Regex::new(pattern).unwrap();
let script = re.replace(&mut script, replacement);
insta::assert_snapshot!(script);
println!("{}", script)
}
}
19 changes: 3 additions & 16 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::util::IndicatifWriter;
use crate::progress;
use clap::{CommandFactory, Parser};
use clap::Parser;
use clap_complete;
use clap_verbosity_flag::Verbosity;
use miette::IntoDiagnostic;
Expand All @@ -9,6 +9,7 @@ use tracing_subscriber::{filter::LevelFilter, util::SubscriberInitExt, EnvFilter

pub mod add;
pub mod auth;
pub mod completion;
pub mod global;
pub mod info;
pub mod init;
Expand Down Expand Up @@ -67,20 +68,6 @@ pub enum Command {
Project(project::Args),
}

fn completion(args: CompletionCommand) -> miette::Result<()> {
let clap_shell = args
.shell
.or(clap_complete::Shell::from_env())
.unwrap_or(clap_complete::Shell::Bash);
clap_complete::generate(
clap_shell,
&mut Args::command(),
"pixi",
&mut std::io::stdout(),
);
Ok(())
}

pub async fn execute() -> miette::Result<()> {
let args = Args::parse();
let use_colors = use_color_output(&args);
Expand Down Expand Up @@ -135,7 +122,7 @@ pub async fn execute() -> miette::Result<()> {
/// Execute the actual command
pub async fn execute_command(command: Command) -> miette::Result<()> {
match command {
Command::Completion(cmd) => completion(cmd),
Command::Completion(cmd) => completion::execute(cmd),
Command::Init(cmd) => init::execute(cmd).await,
Command::Add(cmd) => add::execute(cmd).await,
Command::Run(cmd) => run::execute(cmd).await,
Expand Down
49 changes: 49 additions & 0 deletions src/cli/snapshots/pixi__cli__completion__tests__completion.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
source: src/cli/completion.rs
expression: script
---

pixi__project__help__help)
opts=""
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
pixi__run)
opts="-v -q -h --manifest-path --locked --frozen --verbose --quiet --color --help [TASK]..."
if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
elif [[ ${COMP_CWORD} -eq 2 ]]; then
local tasks=$(pixi task list --summary 2> /dev/null)
if [[ $? -eq 0 ]]; then
COMPREPLY=( $(compgen -W "${tasks}" -- "${cur}") )
return 0
fi
fi
case "${prev}" in
--manifest-path)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--color)
COMPREPLY=($(compgen -W "always never auto" -- "${cur}"))
return 0
;;
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
pixi__search)
opts="-c -l -v -q -h --channel --color --help <PACKAGE>"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
fi
case "${prev}" in
--channel)
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )

;;

27 changes: 20 additions & 7 deletions src/cli/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub enum Operation {

/// List all tasks
#[clap(alias = "l")]
List,
List(ListArgs),
}

#[derive(Parser, Debug)]
Expand Down Expand Up @@ -74,6 +74,12 @@ pub struct AliasArgs {
pub platform: Option<Platform>,
}

#[derive(Parser, Debug, Clone)]
pub struct ListArgs {
#[arg(long, short)]
pub summary: bool,
}

impl From<AddArgs> for Task {
fn from(value: AddArgs) -> Self {
let depends_on = value.depends_on.unwrap_or_default();
Expand Down Expand Up @@ -202,16 +208,23 @@ pub fn execute(args: Args) -> miette::Result<()> {
task,
);
}
Operation::List => {
Operation::List(args) => {
let tasks = project.task_names(Some(Platform::current()));
if tasks.is_empty() {
eprintln!("No tasks found",);
baszalmstra marked this conversation as resolved.
Show resolved Hide resolved
} else {
let mut formatted = String::new();
for name in tasks {
formatted.push_str(&format!("* {}\n", console::style(name).bold(),));
}
eprintln!("{}", formatted);
let formatted: String = tasks
.iter()
.map(|name| {
if args.summary {
format!("{} ", console::style(name))
} else {
format!("* {}\n", console::style(name).bold())
}
})
.collect();

println!("{}", formatted);
}
}
};
Expand Down
Loading