diff --git a/README.md b/README.md index a4b0ca6..d4f4837 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,26 @@ nix profile install github:SwissDataScienceCenter/renku-cli For other installation methods (manual binary, NixOS integration), see the [Installation Guide](docs/install.md). +## Shell Completions (recommended!) + +The CLI can generate completions for bash, fish, zsh, and PowerShell. These can make it much easier +to use the CLI and pick entities to work with. +Add the following to your shell configuration: + +```bash +# Bash +echo "source <(COMPLETE=bash rnk)" >> ~/.bashrc + +# Fish +echo "COMPLETE=fish rnk | source" >> ~/.config/fish/config.fish + +# Zsh +echo "source <(COMPLETE=zsh rnk)" >> ~/.zshrc + +# PowerShell +echo '$env:COMPLETE = "powershell"; rnk | Out-String | Invoke-Expression; Remove-Item Env:\COMPLETE' >> $PROFILE +``` + ## Quick Start Get up and running in three steps: @@ -118,10 +138,6 @@ Global flags available on every command: For a full list of options, run `rnk --help`. -## Shell Completions - -See the [Installation Guide](docs/install.md) for shell completion setup (bash, fish, zsh, powershell). - ## Documentation Full documentation is available in the [docs/](docs/) directory. diff --git a/src/cli/cmd/project/activate.rs b/src/cli/cmd/project/activate.rs index ac75fa1..8e82304 100644 --- a/src/cli/cmd/project/activate.rs +++ b/src/cli/cmd/project/activate.rs @@ -1,6 +1,6 @@ use super::Context; use crate::{ - cli::sink::Error as SinkError, + cli::{complete::complete_project_id, sink::Error as SinkError}, data::{project_id::ProjectId, simple_message::SimpleMessage}, httpclient::{self}, project_config::{ProjectConfigError, ProjectInfo, RenkuProjectConfig}, @@ -8,6 +8,7 @@ use crate::{ use clap::{Parser, ValueHint}; +use clap_complete::ArgValueCompleter; use snafu::{ResultExt, Snafu}; /// Set a project as the currently active one [alias: a]. @@ -17,7 +18,7 @@ use snafu::{ResultExt, Snafu}; pub struct Input { /// The project to set as active, identified by either its id, the /// namespace/slug identifier or the complete url. - #[arg(value_hint=ValueHint::Other)] + #[arg(value_hint=ValueHint::Other,add = ArgValueCompleter::new(complete_project_id))] pub project_ref: ProjectId, } diff --git a/src/cli/complete.rs b/src/cli/complete.rs index cc6b46c..8486d75 100644 --- a/src/cli/complete.rs +++ b/src/cli/complete.rs @@ -5,7 +5,7 @@ use crate::{ data::project_id::ProjectId, httpclient::{ Client, - data::{SessionLauncher, SessionMode, SessionStartResponse}, + data::{ProjectDetails, SessionLauncher, SessionMode, SessionStartResponse}, }, }; @@ -221,3 +221,39 @@ async fn complete_session_name( } result } + +pub fn complete_project_id(current: &ffi::OsStr) -> Vec { + make_sync_completer(current, async |client, _| { + let projects = match client.list_projects(true, 100).await { + Err(msg) => { + eprintln!( + "Completions failed: Error getting list of projects: {}", + msg + ); + return vec![]; + } + Ok(res) => res, + }; + + let mut result: Vec = vec![]; + for project in projects.0.0.iter() { + let cc = make_project_completion_candidate(project).await; + result.push(cc); + } + if result.is_empty() { + eprintln!("No projects found."); + } + result + }) +} +async fn make_project_completion_candidate(project: &ProjectDetails) -> CompletionCandidate { + let mut help = StyledStr::new(); + help.push_str(&project.name); + if let Some(desc) = &project.description { + help.push_str(" - "); + help.push_str(desc); + } + let cc = CompletionCandidate::new(format!("{}/{}", project.namespace, project.slug)); + + cc.help(Some(help)) +}