Expand description
§completers
[!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 gotbash-completioninstalled. 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_binaryYou 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.nuAnd then source the file from your ($nu.default-config-dir)/config.nu:
source somewhere/handy.nuNote 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
clap, whose code and API is used as a reference. Whenclap’s Rust-Native Completion Engine is stablized, this crate will be deprecated in favor of it.complete-alias, whose shell code helped a lot.
§✅ 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§
- Completers
Error - Possible errors that can occur.
- Completion
Type - The type of completion attempted. ref.
- Shell
Code Error - 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
matchCompletion::init()for yourself.