Skip to content

Commit b8cb670

Browse files
authored
feat: Implement shell completions (#697)
1 parent 05e1f9c commit b8cb670

39 files changed

Lines changed: 668 additions & 52 deletions

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ bump. Currently experimental: project bundling, project dependencies
77

88
# Unreleased
99

10+
* feat: `icp completions <SHELL>` prints a shell completion script for `bash`, `zsh`, `fish`, `powershell`, or `elvish` to stdout. See the [installation guide](docs/guides/installation.md#shell-completions) for where to put it.
1011
* fix: `icp canister logs` output formats are corrected. `--json` now emits machine-readable JSON and the default emits the human-readable lines (the two were swapped), and `--follow --json` emits newline-delimited JSON, one record per line, streamed as each record arrives. This is breaking for scripts: parsing the default output as JSON now requires `--json`, and consumers of `--follow --json` must read one JSON object per line.
1112

1213
# v1.3.0

‎Cargo.lock‎

Lines changed: 23 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ cargo-generate = "0.23.7"
3434
camino-tempfile = "1"
3535
candid = "0.10.19"
3636
candid_parser = "0.3.0"
37-
clap = { version = "4.5.3", features = ["derive", "env"] }
37+
clap = { version = "4.5.3", features = ["derive", "env", "unstable-ext"] }
3838
clap-markdown = "0.1.5"
39+
clap_complete = { version = "4.5.3", features = ["unstable-dynamic"] }
3940
cryptoki = "0.12.0"
4041
console = "0.16.3"
4142
dialoguer = "0.12.0"

‎crates/icp-cli/Cargo.toml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ candid.workspace = true
2828
cargo-generate.workspace = true
2929
clap-markdown.workspace = true
3030
clap.workspace = true
31+
clap_complete.workspace = true
3132
dialoguer.workspace = true
3233
dunce.workspace = true
3334
elliptic-curve.workspace = true
@@ -45,6 +46,7 @@ icp-canister-interfaces.workspace = true
4546
icp = { workspace = true, features = ["clap"] }
4647
icrc-ledger-types.workspace = true
4748
indicatif.workspace = true
49+
indoc.workspace = true
4850
itertools.workspace = true
4951
k256.workspace = true
5052
lazy_static.workspace = true
@@ -85,7 +87,6 @@ cargo-generate = { workspace = true, features = ["vendored-openssl"] }
8587
assert_cmd.workspace = true
8688
camino-tempfile.workspace = true
8789
cryptoki.workspace = true
88-
indoc.workspace = true
8990
predicates.workspace = true
9091
rand.workspace = true
9192
send_ctrlc.workspace = true

‎crates/icp-cli/src/commands/args.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use std::str::FromStr;
33

44
use anyhow::{Context as _, bail};
55
use candid::Principal;
6-
use clap::Args;
6+
use clap::{Args, ValueHint};
7+
use clap_complete::ArgValueCandidates;
78
use ic_ledger_types::AccountIdentifier;
89
use icp::context::{CanisterSelection, EnvironmentSelection, NetworkSelection};
910
use icp::identity::IdentitySelection;
@@ -27,6 +28,7 @@ pub(crate) struct CanisterCommandArgs {
2728
// Note: Could have flattened CanisterEnvironmentArg to avoid adding child field
2829
/// Name or principal of canister to target.
2930
/// When using a name an environment must be specified.
31+
#[arg(add = ArgValueCandidates::new(crate::complete::canisters))]
3032
pub(crate) canister: Canister,
3133

3234
#[command(flatten)]
@@ -87,6 +89,7 @@ impl OptionalCanisterCommandArgs {
8789
pub(crate) struct OptionalCanisterCommandArgs {
8890
/// Name or principal of canister to target.
8991
/// When using a name an environment must be specified.
92+
#[arg(add = ArgValueCandidates::new(crate::complete::canisters))]
9093
pub(crate) canister: Option<Canister>,
9194

9295
#[command(flatten)]
@@ -216,7 +219,7 @@ pub(crate) struct ArgsOpt {
216219
pub(crate) args: Option<String>,
217220

218221
/// Path to a file containing arguments.
219-
#[arg(long, conflicts_with = "args")]
222+
#[arg(long, conflicts_with = "args", value_hint = ValueHint::FilePath)]
220223
pub(crate) args_file: Option<PathBuf>,
221224

222225
/// Format of the arguments.

‎crates/icp-cli/src/commands/build.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use clap::Args;
2+
use clap_complete::ArgValueCandidates;
23
use futures::future::try_join_all;
34
use icp::context::{Context, EnvironmentSelection};
45

@@ -10,6 +11,7 @@ use crate::{operations::build::build_many_with_progress_bar, options::Environmen
1011
#[derive(Debug, Args)]
1112
pub(crate) struct BuildArgs {
1213
/// Canister names (if empty, build all canisters in environment)
14+
#[arg(add = ArgValueCandidates::new(crate::complete::canisters))]
1315
pub(crate) canisters: Vec<String>,
1416

1517
#[command(flatten)]

‎crates/icp-cli/src/commands/canister/call.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use candid::{IDLArgs, Principal, TypeEnv, types::Function};
44
use candid_parser::assist;
55
use candid_parser::parse_idl_args;
66
use candid_parser::utils::CandidSource;
7-
use clap::{Args, ValueEnum};
7+
use clap::{Args, ValueEnum, ValueHint};
88
use dialoguer::console::Term;
99
use ic_agent::Agent;
1010
use icp::context::Context;
@@ -51,7 +51,7 @@ pub(crate) struct CallArgs {
5151
pub(crate) args: Option<String>,
5252

5353
/// Path to a file containing call arguments.
54-
#[arg(long, conflicts_with = "args")]
54+
#[arg(long, conflicts_with = "args", value_hint = ValueHint::FilePath)]
5555
pub(crate) args_file: Option<PathBuf>,
5656

5757
/// Format of the call arguments.
@@ -63,7 +63,7 @@ pub(crate) struct CallArgs {
6363
/// When set, this interface is used to assist method selection, build
6464
/// arguments, and decode the response, instead of fetching the canister's
6565
/// Candid interface from the network.
66-
#[arg(long, value_name = "PATH")]
66+
#[arg(long, value_name = "PATH", value_hint = ValueHint::FilePath)]
6767
pub(crate) candid: Option<PathBuf>,
6868

6969
/// Principal of a proxy canister to route the call through.

‎crates/icp-cli/src/commands/canister/install.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::io::IsTerminal;
22

33
use anyhow::{Context as _, anyhow, bail};
44
use candid::Principal;
5-
use clap::Args;
5+
use clap::{Args, ValueHint};
66
use dialoguer::Confirm;
77
use ic_management_canister_types::CanisterInstallMode;
88
use icp::context::{CanisterSelection, Context};
@@ -42,7 +42,7 @@ pub(crate) struct InstallArgs {
4242
pub(crate) wasm_memory_persistence: Option<WasmMemoryPersistenceOpt>,
4343

4444
/// Path to the WASM file to install. Uses the build output if not explicitly provided.
45-
#[arg(long)]
45+
#[arg(long, value_hint = ValueHint::FilePath)]
4646
pub(crate) wasm: Option<PathBuf>,
4747

4848
#[command(flatten)]

‎crates/icp-cli/src/commands/canister/link.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use anyhow::bail;
22
use candid::Principal;
33
use clap::Args;
4+
use clap_complete::ArgValueCandidates;
45
use icp::context::{Context, EnvironmentSelection};
56
use tracing::info;
67

@@ -15,6 +16,7 @@ use crate::options::EnvironmentOpt;
1516
pub(crate) struct LinkArgs {
1617
/// Name of the project canister to associate the ID with.
1718
/// Must be declared in the target environment.
19+
#[arg(add = ArgValueCandidates::new(crate::complete::canisters))]
1820
pub(crate) name: String,
1921

2022
/// Principal of the existing canister to link.

‎crates/icp-cli/src/commands/canister/migrate_id.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::time::{Duration, Instant};
33

44
use anyhow::bail;
55
use clap::Args;
6+
use clap_complete::ArgValueCandidates;
67
use dialoguer::Confirm;
78
use ic_management_canister_types::{
89
CanisterIdRecord, CanisterSettings, CanisterStatusType, UpdateSettingsArgs,
@@ -33,7 +34,7 @@ pub(crate) struct MigrateIdArgs {
3334
pub(crate) cmd_args: args::CanisterCommandArgs,
3435

3536
/// The canister to replace with the source canister's ID
36-
#[arg(long)]
37+
#[arg(long, add = ArgValueCandidates::new(crate::complete::canisters))]
3738
replace: String,
3839

3940
/// Skip confirmation prompts

0 commit comments

Comments
 (0)