From cabba0b1a26a3081733313d865fd118b86a9cd26 Mon Sep 17 00:00:00 2001 From: Oz Date: Wed, 1 Apr 2026 20:24:51 +0000 Subject: [PATCH] Add completion spec: SDKMAN! (sdk) Add JSON spec for the SDKMAN! SDK manager command with all subcommands: install, uninstall, list, use, default, home, current, upgrade, env, version, selfupdate, update, flush, config, and help (with aliases). Add three Rust generators: - candidates: reads local SDKMAN candidate cache - installed_versions: lists installed versions for a given candidate - available_versions: queries SDKMAN API for all available versions Co-Authored-By: Oz --- command-signatures/json/sdk.json | 231 +++++++++++++++++++++++ command-signatures/src/generators/mod.rs | 2 + command-signatures/src/generators/sdk.rs | 96 ++++++++++ 3 files changed, 329 insertions(+) create mode 100644 command-signatures/json/sdk.json create mode 100644 command-signatures/src/generators/sdk.rs diff --git a/command-signatures/json/sdk.json b/command-signatures/json/sdk.json new file mode 100644 index 00000000..649af9ad --- /dev/null +++ b/command-signatures/json/sdk.json @@ -0,0 +1,231 @@ +{ + "name": "sdk", + "description": "SDKMAN! - The Software Development Kit Manager", + "subcommands": [ + { + "name": [ + "install", + "i" + ], + "description": "Install a candidate version", + "args": [ + { + "name": "candidate", + "generatorName": "candidates" + }, + { + "name": "version", + "isOptional": true, + "generatorName": "available_versions" + }, + { + "name": "path", + "isOptional": true, + "template": "folders" + } + ] + }, + { + "name": [ + "uninstall", + "rm" + ], + "description": "Uninstall a candidate version", + "args": [ + { + "name": "candidate", + "generatorName": "candidates" + }, + { + "name": "version", + "generatorName": "installed_versions" + } + ] + }, + { + "name": [ + "list", + "ls" + ], + "description": "List available candidates or candidate versions", + "args": { + "name": "candidate", + "isOptional": true, + "generatorName": "candidates" + } + }, + { + "name": [ + "use", + "u" + ], + "description": "Use a specific version in the current shell", + "args": [ + { + "name": "candidate", + "generatorName": "candidates" + }, + { + "name": "version", + "generatorName": "installed_versions" + } + ] + }, + { + "name": [ + "default", + "d" + ], + "description": "Set the default candidate version for all shells", + "args": [ + { + "name": "candidate", + "generatorName": "candidates" + }, + { + "name": "version", + "isOptional": true, + "generatorName": "installed_versions" + } + ] + }, + { + "name": "home", + "description": "Output the path of a specific candidate version", + "args": [ + { + "name": "candidate", + "generatorName": "candidates" + }, + { + "name": "version", + "generatorName": "installed_versions" + } + ] + }, + { + "name": [ + "current", + "c" + ], + "description": "Display the current default installed versions", + "args": { + "name": "candidate", + "isOptional": true, + "generatorName": "candidates" + } + }, + { + "name": [ + "upgrade", + "ug" + ], + "description": "Upgrade installed candidate versions", + "args": { + "name": "candidate", + "isOptional": true, + "generatorName": "candidates" + } + }, + { + "name": "env", + "description": "Manage project-specific SDK versions via .sdkmanrc", + "args": { + "name": "command", + "isOptional": true, + "suggestions": [ + { + "name": "init", + "description": "Create a default .sdkmanrc file" + }, + { + "name": "install", + "description": "Install and switch to versions in .sdkmanrc" + }, + { + "name": "clear", + "description": "Reset all SDK versions to their defaults" + } + ] + } + }, + { + "name": [ + "version", + "v" + ], + "description": "Display the current version of SDKMAN!" + }, + { + "name": "selfupdate", + "description": "Update SDKMAN! itself", + "args": { + "name": "qualifier", + "isOptional": true, + "suggestions": [ + { + "name": "force", + "description": "Force a reinstallation of SDKMAN!" + } + ] + } + }, + { + "name": "update", + "description": "Refresh the candidate metadata cache" + }, + { + "name": "flush", + "description": "Flush SDKMAN! local state", + "args": { + "name": "target", + "isOptional": true, + "suggestions": [ + { + "name": "tmp", + "description": "Clean pre/post hooks and residual archives" + }, + { + "name": "metadata", + "description": "Remove header metadata" + }, + { + "name": "version", + "description": "Flush version files" + } + ] + } + }, + { + "name": "config", + "description": "Open the SDKMAN! configuration file" + }, + { + "name": [ + "help", + "h" + ], + "description": "Display help information", + "args": { + "name": "subcommand", + "isOptional": true, + "suggestions": [ + "install", + "uninstall", + "list", + "use", + "default", + "home", + "env", + "current", + "upgrade", + "version", + "selfupdate", + "update", + "flush", + "config" + ] + } + } + ] +} diff --git a/command-signatures/src/generators/mod.rs b/command-signatures/src/generators/mod.rs index b6100244..aa0ead76 100644 --- a/command-signatures/src/generators/mod.rs +++ b/command-signatures/src/generators/mod.rs @@ -41,6 +41,7 @@ mod powershell; mod pyenv; mod react_native; mod screen; +mod sdk; mod ssh; mod systemctl; mod tar; @@ -98,6 +99,7 @@ pub fn dynamic_command_signature_data() -> HashMap &'static str { + "${SDKMAN_DIR:-$HOME/.sdkman}" +} + +/// Extracts the candidate name from tokens. +/// +/// When `has_trailing_whitespace` is true, the candidate is the last token +/// (the user just finished typing the candidate and pressed space). +/// Otherwise, the candidate is the second-to-last token (the user is typing +/// the version prefix). +fn candidate_from_tokens<'a>(tokens: &'a [&str], has_trailing_whitespace: bool) -> Option<&'a str> { + if has_trailing_whitespace { + tokens.last().copied() + } else { + tokens.get(tokens.len().saturating_sub(2)).copied() + } +} + +pub fn generator() -> CommandSignatureGenerators { + CommandSignatureGenerators::new("sdk") + .add_generator( + "candidates", + Generator::script( + CommandBuilder::single_command(format!( + "cat {}/var/candidates | tr ',' '\\n'", + sdkman_dir() + )), + |output| { + output + .trim() + .lines() + .filter(|line| !line.is_empty()) + .map(|line| Suggestion::with_description(line.trim(), "SDK candidate")) + .collect_unordered_results() + }, + ), + ) + .add_generator( + "installed_versions", + Generator::command_from_tokens( + |tokens, has_trailing_whitespace, _| { + match candidate_from_tokens(tokens, has_trailing_whitespace) { + Some(candidate) => CommandBuilder::pipe( + CommandBuilder::single_command(format!( + "ls {}/candidates/{}/", + sdkman_dir(), + candidate + )), + CommandBuilder::single_command("grep -v current"), + ), + None => CommandBuilder::single_command(""), + } + }, + |output| { + output + .trim() + .lines() + .filter(|line| !line.is_empty()) + .map(|line| { + Suggestion::with_description(line.trim(), "Installed version") + }) + .collect_unordered_results() + }, + ), + ) + .add_generator( + "available_versions", + Generator::command_from_tokens( + |tokens, has_trailing_whitespace, _| { + match candidate_from_tokens(tokens, has_trailing_whitespace) { + Some(candidate) => CommandBuilder::single_command(format!( + "curl -s https://api.sdkman.io/2/candidates/{}/$(cat {}/var/platform)/versions/all | tr ',' '\\n'", + candidate, + sdkman_dir() + )), + None => CommandBuilder::single_command(""), + } + }, + |output| { + output + .trim() + .lines() + .filter(|line| !line.is_empty()) + .map(|line| { + Suggestion::with_description(line.trim(), "Available version") + }) + .collect_unordered_results() + }, + ), + ) +}