Skip to main content

Crate completers

Crate completers 

Source
Expand description

§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
}
§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(())
}

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

/// 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?)

Structs§

Completion
A completion request. ref.

Enums§

CompletersError
Possible errors that can occur.
CompletionType
The type of completion attempted. ref.
ShellCodeError
Possible errors that can occur when generating shell code.

Functions§

handle_completion
Helper function for handling completion requests with candidates. To delegate, you’ll have to match Completion::init() for yourself.