completers

Crates.iocompleters
lib.rscompleters
version0.0.5
created_at2025-05-02 07:52:54.005993+00
updated_at2025-08-25 06:36:38.149842+00
descriptionA tiny Rust-native shell completion solution.
homepage
repositoryhttps://github.com/PRO-2684/completers
max_upload_size
id1657400
size27,042
PRO (PRO-2684)

documentation

README

completers

GitHub License GitHub Workflow Status GitHub Release GitHub Downloads (all assets, all releases) Crates.io Version Crates.io Total Downloads docs.rs

[!WARNING] This crate is still a prototype, and is subject to BREAKING changes without notice.

A tiny Rust-native shell completion solution.

💡 Examples

See examples for a few examples of how to use this crate.

📖 Usage

Rust Part

Candidates

First, define a completion handler function that takes a [Completion] struct as an argument and returns a vector of completion candidates:

use completers::Completion;

fn handler(_completion: Completion) -> Vec<String> {
    vec![]
}

Then, call [handle_completion] BEFORE any other command that writes to stdout in your main function:

use completers::{Completion, handle_completion};

fn main() {
    handle_completion(handler);
    // Other logic
}
#
# fn handler(_completion: Completion) -> Vec<String> {
#     vec![]
# }

Delegate

To delegate completion, we should first match against [Completion::init()]:

use completers::{CompletersError, Completion};
use std::process::exit;

fn main() -> Result<(), CompletersError> {
    match Completion::init() {
        Ok(Some(completion)) => {
            delegate_completion(completion)?;
        }
        Ok(None) => {
            // No completion request, do nothing
        }
        Err(e) => {
            eprintln!("Error: {e}");
            exit(1);
        }
    };
    // Do your job
    Ok(())
}
#
# fn delegate_completion(mut comp: Completion) -> Result<(), CompletersError> {
#     Ok(())
# }

Then, construct or mutate the [Completion] object in the delegate function. We'll delegate to cargo build --example for example:

# use completers::{CompletersError, Completion};
# use std::process::exit;
#
/// Delegates completion to `cargo build --example`, exit if successful.
fn delegate_completion(mut comp: Completion) -> Result<(), CompletersError> {
    let old_words_count = comp.words.len();
    comp.words.remove(0); // Discard program name
    let mut new_words = vec![
        "cargo".to_string(),
        "build".to_string(),
        "--example".to_string(),
    ];
    new_words.append(&mut comp.words);
    comp.words = new_words;
    comp.word_index += comp.words.len();
    comp.word_index -= old_words_count;

    comp.line = comp.words.join(" ");
    comp.cursor_index = comp
        .words
        .iter()
        .take(comp.word_index)
        .map(|word| word.len())
        .sum::<usize>()
        + comp.word_index
        + comp.words[comp.word_index].len();

    comp.delegate();
    Ok(())
}

Shell Part

Bash

[!NOTE] By using completers, we assume that you've got bash-completion installed. Some features such as completion delegate won't work without it.

Generate and evaluate the shell code via:

source <(COMPLETE=bash my_binary)

You should be able to complete your commands now. To enable completion across all your terminal sessions, you can add the above code to your completions directory, like:

mkdir -p ~/.local/share/bash-completion/completions # Create the directory if it doesn't exist
echo 'source <(COMPLETE=bash my_binary)' > ~/.local/share/bash-completion/completions/my_binary

You can also use /usr/share/bash-completion/completions/ as the directory, if you want the completion to be available system-wise.

Nushell

Instructions for lazy loading completions will be updated once nushell/nushell#4874 is resolved. For now, you'll have to:

COMPLETE=nu my_binary o> somewhere/handy.nu

And then source the file from your ($nu.default-config-dir)/config.nu:

source somewhere/handy.nu

Note that completions will only work for my_binary, and not ./my_binary or /path/to/my_binary.

The completers Binary

Currently, the completers binary does nothing.

⚙️ Details

See CAVEATS.md for a list of known problems, and see MECHANISM.md for a detailed explanation of how this works, in case you're curious.

🎉 Credits

✅ TODO

  • Escape special characters in generated shell code & completion candidates
  • Completion delegation
    • Need to consider how to design the API
    • Prototypes available in prototype
  • Extensibility (API?)
Commit count: 40

cargo fmt