Skip to main content

CommandIndex

Struct CommandIndex 

Source
pub struct CommandIndex<A> { /* private fields */ }
Expand description

A name-to-action index with front-prefix completion.

Stores an arbitrary number of named commands, each mapped to a caller-defined action A. The primary use case is a vim-style command palette: bind names with bind, look up an exact name with get, and enumerate candidates for a partial name with complete.

Case sensitivity and whitespace are the caller’s concern: the index stores names byte-for-byte as given. Trim and case-fold before calling bind / get / complete if uniformity is desired.

Lexicographic order is a specification, not just an implementation detail. complete and iter both return results in ascending byte order (the order of the underlying BTreeMap), so callers may rely on this for stable, deterministic output.

Implementations§

Source§

impl<A> CommandIndex<A>

Source

pub fn new() -> Self

Creates an empty index.

Examples found in repository?
examples/command_palette.rs (line 36)
35fn main() {
36    let mut idx = CommandIndex::new();
37    idx.bind("write", Action::Write);
38    idx.bind("write-quit", Action::WriteQuit);
39    idx.bind("write-quit-all", Action::WriteQuitAll);
40    idx.bind("quit", Action::Quit);
41    idx.bind("quit-all", Action::QuitAll);
42
43    // --- Full palette listing (e.g. user opens the palette with no text yet) ---
44    println!("All commands:");
45    for (name, action) in idx.iter() {
46        println!("  {name:20} -> {action:?}");
47    }
48
49    // --- Prefix completion: user has typed "w" ---
50    println!("\nCompletions for \"w\":");
51    for (name, action) in idx.complete("w") {
52        println!("  {name:20} -> {action:?}");
53    }
54
55    // --- Prefix completion: user has typed "write-q" ---
56    println!("\nCompletions for \"write-q\":");
57    for (name, action) in idx.complete("write-q") {
58        println!("  {name:20} -> {action:?}");
59    }
60
61    // --- Exact lookup after the user presses Enter on "write" ---
62    println!("\nExact lookup:");
63    match idx.get("write") {
64        Some(action) => println!("  \"write\" -> {action:?}"),
65        None => println!("  \"write\" -> unknown"),
66    }
67
68    // --- Case normalization is the caller's responsibility ---
69    //
70    // The index stores names byte-for-byte. If the user typed "Write" (capital
71    // W), the caller normalizes to lowercase before calling get/complete:
72    let user_input = "Write";
73    let normalized = user_input.to_lowercase();
74    println!("\nUser typed {user_input:?}, normalized to {normalized:?}:");
75    match idx.get(&normalized) {
76        Some(action) => println!("  -> {action:?}"),
77        None => println!("  -> unknown"),
78    }
79
80    // --- Non-exclusive: ":w" can be both exact and a prefix ---
81    //
82    // In a vim-style command line `:w` executes "write" and `:wq` executes
83    // "write-quit". Both can coexist because get and complete are orthogonal:
84    // get(":w") is exact, complete(":w") enumerates ":w" and ":wq" and ":wqa".
85    let mut vim = CommandIndex::new();
86    vim.bind(":w", "write");
87    vim.bind(":wq", "write-quit");
88    vim.bind(":wqa", "write-quit-all");
89
90    println!("\nVim-style coexistence:");
91    println!("  get(\":w\") = {:?}", vim.get(":w"));
92    let completions: Vec<&str> = vim.complete(":w").map(|(n, _)| n).collect();
93    println!("  complete(\":w\") = {completions:?}");
94}
Source

pub fn bind(&mut self, name: impl Into<String>, action: A) -> Option<A>

Binds name to action, returning the action previously bound to that name, if any (last-wins — same semantic as Keymap::bind).

The name is stored byte-for-byte; no trimming or case-folding is applied.

use keymap_core::cmd::CommandIndex;

let mut idx: CommandIndex<&str> = CommandIndex::new();
assert_eq!(idx.bind(":w", "write"), None);
// Rebinding returns the old action.
assert_eq!(idx.bind(":w", "write-force"), Some("write"));
assert_eq!(idx.get(":w"), Some(&"write-force"));
Examples found in repository?
examples/command_palette.rs (line 37)
35fn main() {
36    let mut idx = CommandIndex::new();
37    idx.bind("write", Action::Write);
38    idx.bind("write-quit", Action::WriteQuit);
39    idx.bind("write-quit-all", Action::WriteQuitAll);
40    idx.bind("quit", Action::Quit);
41    idx.bind("quit-all", Action::QuitAll);
42
43    // --- Full palette listing (e.g. user opens the palette with no text yet) ---
44    println!("All commands:");
45    for (name, action) in idx.iter() {
46        println!("  {name:20} -> {action:?}");
47    }
48
49    // --- Prefix completion: user has typed "w" ---
50    println!("\nCompletions for \"w\":");
51    for (name, action) in idx.complete("w") {
52        println!("  {name:20} -> {action:?}");
53    }
54
55    // --- Prefix completion: user has typed "write-q" ---
56    println!("\nCompletions for \"write-q\":");
57    for (name, action) in idx.complete("write-q") {
58        println!("  {name:20} -> {action:?}");
59    }
60
61    // --- Exact lookup after the user presses Enter on "write" ---
62    println!("\nExact lookup:");
63    match idx.get("write") {
64        Some(action) => println!("  \"write\" -> {action:?}"),
65        None => println!("  \"write\" -> unknown"),
66    }
67
68    // --- Case normalization is the caller's responsibility ---
69    //
70    // The index stores names byte-for-byte. If the user typed "Write" (capital
71    // W), the caller normalizes to lowercase before calling get/complete:
72    let user_input = "Write";
73    let normalized = user_input.to_lowercase();
74    println!("\nUser typed {user_input:?}, normalized to {normalized:?}:");
75    match idx.get(&normalized) {
76        Some(action) => println!("  -> {action:?}"),
77        None => println!("  -> unknown"),
78    }
79
80    // --- Non-exclusive: ":w" can be both exact and a prefix ---
81    //
82    // In a vim-style command line `:w` executes "write" and `:wq` executes
83    // "write-quit". Both can coexist because get and complete are orthogonal:
84    // get(":w") is exact, complete(":w") enumerates ":w" and ":wq" and ":wqa".
85    let mut vim = CommandIndex::new();
86    vim.bind(":w", "write");
87    vim.bind(":wq", "write-quit");
88    vim.bind(":wqa", "write-quit-all");
89
90    println!("\nVim-style coexistence:");
91    println!("  get(\":w\") = {:?}", vim.get(":w"));
92    let completions: Vec<&str> = vim.complete(":w").map(|(n, _)| n).collect();
93    println!("  complete(\":w\") = {completions:?}");
94}
Source

pub fn get(&self, name: &str) -> Option<&A>

Returns the action bound to name, or None if no exact match exists.

This is a complete-match lookup. For prefix enumeration (e.g. :w<Tab>), use complete.

use keymap_core::cmd::CommandIndex;

let mut idx: CommandIndex<u8> = CommandIndex::new();
idx.bind(":w", 1);
idx.bind(":wq", 2);

assert_eq!(idx.get(":w"), Some(&1));
assert_eq!(idx.get(":wq"), Some(&2));
// Prefix is not an exact match.
assert_eq!(idx.get(":"), None);
Examples found in repository?
examples/command_palette.rs (line 63)
35fn main() {
36    let mut idx = CommandIndex::new();
37    idx.bind("write", Action::Write);
38    idx.bind("write-quit", Action::WriteQuit);
39    idx.bind("write-quit-all", Action::WriteQuitAll);
40    idx.bind("quit", Action::Quit);
41    idx.bind("quit-all", Action::QuitAll);
42
43    // --- Full palette listing (e.g. user opens the palette with no text yet) ---
44    println!("All commands:");
45    for (name, action) in idx.iter() {
46        println!("  {name:20} -> {action:?}");
47    }
48
49    // --- Prefix completion: user has typed "w" ---
50    println!("\nCompletions for \"w\":");
51    for (name, action) in idx.complete("w") {
52        println!("  {name:20} -> {action:?}");
53    }
54
55    // --- Prefix completion: user has typed "write-q" ---
56    println!("\nCompletions for \"write-q\":");
57    for (name, action) in idx.complete("write-q") {
58        println!("  {name:20} -> {action:?}");
59    }
60
61    // --- Exact lookup after the user presses Enter on "write" ---
62    println!("\nExact lookup:");
63    match idx.get("write") {
64        Some(action) => println!("  \"write\" -> {action:?}"),
65        None => println!("  \"write\" -> unknown"),
66    }
67
68    // --- Case normalization is the caller's responsibility ---
69    //
70    // The index stores names byte-for-byte. If the user typed "Write" (capital
71    // W), the caller normalizes to lowercase before calling get/complete:
72    let user_input = "Write";
73    let normalized = user_input.to_lowercase();
74    println!("\nUser typed {user_input:?}, normalized to {normalized:?}:");
75    match idx.get(&normalized) {
76        Some(action) => println!("  -> {action:?}"),
77        None => println!("  -> unknown"),
78    }
79
80    // --- Non-exclusive: ":w" can be both exact and a prefix ---
81    //
82    // In a vim-style command line `:w` executes "write" and `:wq` executes
83    // "write-quit". Both can coexist because get and complete are orthogonal:
84    // get(":w") is exact, complete(":w") enumerates ":w" and ":wq" and ":wqa".
85    let mut vim = CommandIndex::new();
86    vim.bind(":w", "write");
87    vim.bind(":wq", "write-quit");
88    vim.bind(":wqa", "write-quit-all");
89
90    println!("\nVim-style coexistence:");
91    println!("  get(\":w\") = {:?}", vim.get(":w"));
92    let completions: Vec<&str> = vim.complete(":w").map(|(n, _)| n).collect();
93    println!("  complete(\":w\") = {completions:?}");
94}
Source

pub fn complete<'a>( &'a self, prefix: &str, ) -> impl Iterator<Item = (&'a str, &'a A)>

Enumerates every command whose name starts with prefix, in lexicographic (byte) order.

An empty prefix is equivalent to iter — it yields every bound command. Lexicographic order is a specification: callers may rely on it for stable, deterministic output.

Note that a name can be both an exact match for one call and a prefix for another: :w completes under the prefix : and is itself exact under get(":w"). There is no closed result enum merging these two cases.

use keymap_core::cmd::CommandIndex;

let mut idx: CommandIndex<u8> = CommandIndex::new();
idx.bind(":w", 1);
idx.bind(":wq", 2);
idx.bind(":wqa", 3);
idx.bind(":q", 4);

// Prefix ":w" matches ":w", ":wq", ":wqa" in lexicographic order.
let completions: Vec<(&str, &u8)> = idx.complete(":w").collect();
assert_eq!(completions, vec![(":w", &1), (":wq", &2), (":wqa", &3)]);

// Empty prefix enumerates everything.
assert_eq!(idx.complete("").count(), 4);
Examples found in repository?
examples/command_palette.rs (line 51)
35fn main() {
36    let mut idx = CommandIndex::new();
37    idx.bind("write", Action::Write);
38    idx.bind("write-quit", Action::WriteQuit);
39    idx.bind("write-quit-all", Action::WriteQuitAll);
40    idx.bind("quit", Action::Quit);
41    idx.bind("quit-all", Action::QuitAll);
42
43    // --- Full palette listing (e.g. user opens the palette with no text yet) ---
44    println!("All commands:");
45    for (name, action) in idx.iter() {
46        println!("  {name:20} -> {action:?}");
47    }
48
49    // --- Prefix completion: user has typed "w" ---
50    println!("\nCompletions for \"w\":");
51    for (name, action) in idx.complete("w") {
52        println!("  {name:20} -> {action:?}");
53    }
54
55    // --- Prefix completion: user has typed "write-q" ---
56    println!("\nCompletions for \"write-q\":");
57    for (name, action) in idx.complete("write-q") {
58        println!("  {name:20} -> {action:?}");
59    }
60
61    // --- Exact lookup after the user presses Enter on "write" ---
62    println!("\nExact lookup:");
63    match idx.get("write") {
64        Some(action) => println!("  \"write\" -> {action:?}"),
65        None => println!("  \"write\" -> unknown"),
66    }
67
68    // --- Case normalization is the caller's responsibility ---
69    //
70    // The index stores names byte-for-byte. If the user typed "Write" (capital
71    // W), the caller normalizes to lowercase before calling get/complete:
72    let user_input = "Write";
73    let normalized = user_input.to_lowercase();
74    println!("\nUser typed {user_input:?}, normalized to {normalized:?}:");
75    match idx.get(&normalized) {
76        Some(action) => println!("  -> {action:?}"),
77        None => println!("  -> unknown"),
78    }
79
80    // --- Non-exclusive: ":w" can be both exact and a prefix ---
81    //
82    // In a vim-style command line `:w` executes "write" and `:wq` executes
83    // "write-quit". Both can coexist because get and complete are orthogonal:
84    // get(":w") is exact, complete(":w") enumerates ":w" and ":wq" and ":wqa".
85    let mut vim = CommandIndex::new();
86    vim.bind(":w", "write");
87    vim.bind(":wq", "write-quit");
88    vim.bind(":wqa", "write-quit-all");
89
90    println!("\nVim-style coexistence:");
91    println!("  get(\":w\") = {:?}", vim.get(":w"));
92    let completions: Vec<&str> = vim.complete(":w").map(|(n, _)| n).collect();
93    println!("  complete(\":w\") = {completions:?}");
94}
Source

pub fn iter(&self) -> impl Iterator<Item = (&str, &A)>

Iterates over every (name, action) pair in lexicographic (byte) order.

This is the discovery dual of complete (with an empty prefix) and mirrors Keymap::iter in purpose.

use keymap_core::cmd::CommandIndex;

let mut idx: CommandIndex<u8> = CommandIndex::new();
idx.bind(":q", 2);
idx.bind(":w", 1);

let all: Vec<(&str, &u8)> = idx.iter().collect();
// Lexicographic order: ":q" before ":w".
assert_eq!(all, vec![(":q", &2), (":w", &1)]);
Examples found in repository?
examples/command_palette.rs (line 45)
35fn main() {
36    let mut idx = CommandIndex::new();
37    idx.bind("write", Action::Write);
38    idx.bind("write-quit", Action::WriteQuit);
39    idx.bind("write-quit-all", Action::WriteQuitAll);
40    idx.bind("quit", Action::Quit);
41    idx.bind("quit-all", Action::QuitAll);
42
43    // --- Full palette listing (e.g. user opens the palette with no text yet) ---
44    println!("All commands:");
45    for (name, action) in idx.iter() {
46        println!("  {name:20} -> {action:?}");
47    }
48
49    // --- Prefix completion: user has typed "w" ---
50    println!("\nCompletions for \"w\":");
51    for (name, action) in idx.complete("w") {
52        println!("  {name:20} -> {action:?}");
53    }
54
55    // --- Prefix completion: user has typed "write-q" ---
56    println!("\nCompletions for \"write-q\":");
57    for (name, action) in idx.complete("write-q") {
58        println!("  {name:20} -> {action:?}");
59    }
60
61    // --- Exact lookup after the user presses Enter on "write" ---
62    println!("\nExact lookup:");
63    match idx.get("write") {
64        Some(action) => println!("  \"write\" -> {action:?}"),
65        None => println!("  \"write\" -> unknown"),
66    }
67
68    // --- Case normalization is the caller's responsibility ---
69    //
70    // The index stores names byte-for-byte. If the user typed "Write" (capital
71    // W), the caller normalizes to lowercase before calling get/complete:
72    let user_input = "Write";
73    let normalized = user_input.to_lowercase();
74    println!("\nUser typed {user_input:?}, normalized to {normalized:?}:");
75    match idx.get(&normalized) {
76        Some(action) => println!("  -> {action:?}"),
77        None => println!("  -> unknown"),
78    }
79
80    // --- Non-exclusive: ":w" can be both exact and a prefix ---
81    //
82    // In a vim-style command line `:w` executes "write" and `:wq` executes
83    // "write-quit". Both can coexist because get and complete are orthogonal:
84    // get(":w") is exact, complete(":w") enumerates ":w" and ":wq" and ":wqa".
85    let mut vim = CommandIndex::new();
86    vim.bind(":w", "write");
87    vim.bind(":wq", "write-quit");
88    vim.bind(":wqa", "write-quit-all");
89
90    println!("\nVim-style coexistence:");
91    println!("  get(\":w\") = {:?}", vim.get(":w"));
92    let completions: Vec<&str> = vim.complete(":w").map(|(n, _)| n).collect();
93    println!("  complete(\":w\") = {completions:?}");
94}
Source

pub fn len(&self) -> usize

Returns the number of commands in the index.

Source

pub fn is_empty(&self) -> bool

Returns true if the index contains no commands.

Trait Implementations§

Source§

impl<A: Clone> Clone for CommandIndex<A>

Source§

fn clone(&self) -> CommandIndex<A>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<A: Debug> Debug for CommandIndex<A>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<A> Default for CommandIndex<A>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<A> Freeze for CommandIndex<A>

§

impl<A> RefUnwindSafe for CommandIndex<A>
where A: RefUnwindSafe,

§

impl<A> Send for CommandIndex<A>
where A: Send,

§

impl<A> Sync for CommandIndex<A>
where A: Sync,

§

impl<A> Unpin for CommandIndex<A>

§

impl<A> UnsafeUnpin for CommandIndex<A>

§

impl<A> UnwindSafe for CommandIndex<A>
where A: RefUnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.