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.