Skip to content

Commit

Permalink
Merge pull request #72 from hendriknielaender/auto-completion
Browse files Browse the repository at this point in the history
feat: zsh & bash auto completion
  • Loading branch information
hendriknielaender authored Feb 3, 2025
2 parents e139cb3 + b767352 commit 45e9a11
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 2 deletions.
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,48 @@ irm https://raw.githubusercontent.com/hendriknielaender/zvm/master/install.ps1 |
powershell -c "irm https://raw.githubusercontent.com/hendriknielaender/zvm/master/install.ps1 | iex"
```

## Shell Completions

`zvm` provides built-in shell completion scripts for both Zsh and Bash. This enhances the command-line experience by allowing tab-completion of subcommands, flags, etc.

### Zsh

1. **Generate** the Zsh completion script:
```bash
zvm completions zsh > _zvm
```
2. **Move** `_zvm` into a directory that Zsh checks for autoloaded completion scripts. For example:
```bash
mkdir -p ~/.zsh/completions
mv _zvm ~/.zsh/completions
```
3. **Add** this to your `~/.zshrc`:
```bash
fpath+=(~/.zsh/completions)
autoload -U compinit && compinit
```
4. **Reload** your shell:
```bash
source ~/.zshrc
```
5. **Test**:
```bash
zvm <TAB>
```
You should see a list of subcommands like `ls`, `install`, `use`, etc.

### Bash

1. **Generate** the Bash completion script:
```bash
zvm completions bash > zvm.bash
```
2. **Source** it in your `~/.bashrc` (or `~/.bash_profile`):
```bash
echo "source $(pwd)/zvm.bash" >> ~/.bashrc
source ~/.bashrc
```

## Usage

**General Syntax:**
Expand Down
4 changes: 2 additions & 2 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const builtin = @import("builtin");
const Build = std.Build;

const min_zig_string = "0.13.0";
const semver = std.SemanticVersion{ .major = 0, .minor = 7, .patch = 0 };
const semver_string = "0.7.0";
const semver = std.SemanticVersion{ .major = 0, .minor = 8, .patch = 0 };
const semver_string = "0.8.0";

const CrossTargetInfo = struct {
crossTarget: std.zig.CrossTarget,
Expand Down
92 changes: 92 additions & 0 deletions src/command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub const Command = enum {
Clean,
Version,
Help,
Completions,
Unknown,
};

Expand All @@ -49,6 +50,7 @@ const command_opts = [_]CommandOption{
.{ .short_handle = null, .handle = "clean", .cmd = Command.Clean },
.{ .short_handle = "-v", .handle = "--version", .cmd = Command.Version },
.{ .short_handle = null, .handle = "--help", .cmd = Command.Help },
.{ .short_handle = null, .handle = "completions", .cmd = .Completions },
};

/// Parse and handle commands
Expand Down Expand Up @@ -122,6 +124,7 @@ pub fn handle_command(params: []const []const u8, root_node: std.Progress.Node)
.Clean => try clean_store(),
.Version => try get_version(),
.Help => try display_help(),
.Completions => try handle_completions(params),
.Unknown => try handle_unknown(),
}
}
Expand Down Expand Up @@ -526,6 +529,95 @@ fn display_help() !void {
try color.print(help_message);
}

fn handle_completions(params: []const []const u8) !void {
if (params.len < 3) {
std.debug.print("Usage: zvm completions [zsh|bash]\n", .{});
return;
}

const shell = params[2];

if (std.mem.eql(u8, shell, "zsh")) {
try handle_completions_zsh();
} else if (std.mem.eql(u8, shell, "bash")) {
try handle_completions_bash();
} else {
std.debug.print("Unsupported shell: {s}\n", .{shell});
std.debug.print("Usage: zvm completions [zsh|bash]\n", .{});
}
}

fn handle_completions_zsh() !void {
const zsh_script =
\\#compdef zvm
\\
\\# ZVM top-level commands (example)
\\local -a _zvm_commands
\\_zvm_commands=(
\\ 'ls:List local or remote versions'
\\ 'install:Install a version of Zig or zls'
\\ 'use:Switch to a local version of Zig or zls'
\\ 'remove:Remove a local version of Zig or zls'
\\ 'clean:Remove old artifacts'
\\ '--version:Show zvm version'
\\ '--help:Show help message'
\\ 'completions:Generate completion script'
\\)
\\
\\_arguments \
\\ '1: :->cmds' \
\\ '*:: :->args'
\\
\\case $state in
\\ cmds)
\\ _describe -t commands "zvm command" _zvm_commands
\\ ;;
\\ args)
\\ # Subcommand-specific completions if needed
\\ ;;
\\esac
;

const out = std.io.getStdOut().writer();
try out.print("{s}\n", .{zsh_script});
}

fn handle_completions_bash() !void {
const bash_script =
\\#!/usr/bin/env bash
\\# zvm Bash completion
\\
\\_zvm_completions() {
\\ local cur prev words cword
\\ _init_completion || return
\\
\\ local commands="ls install use remove clean --version --help completions"
\\
\\ if [[ $cword -eq 1 ]]; then
\\ COMPREPLY=( $( compgen -W "$commands" -- "$cur" ) )
\\ else
\\ # Add subcommand-specific logic here
\\ case "$prev" in
\\ install)
\\ # e.g. list remote versions
\\ ;;
\\ use)
\\ # e.g. list local versions
\\ ;;
\\ remove)
\\ # e.g. remove local versions
\\ ;;
\\ esac
\\ fi
\\}
\\
\\complete -F _zvm_completions zvm
;

const out = std.io.getStdOut().writer();
try out.print("{s}\n", .{bash_script});
}

fn handle_unknown() !void {
comptime var color = util_color.Color.ComptimeStyle.init();
try color.bold().red().print("Unknown command. Use 'zvm --help' for usage information.\n");
Expand Down

0 comments on commit 45e9a11

Please sign in to comment.