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>
impl<A> CommandIndex<A>
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates an empty index.
Examples found in repository?
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}Sourcepub fn bind(&mut self, name: impl Into<String>, action: A) -> Option<A>
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?
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}Sourcepub fn get(&self, name: &str) -> Option<&A>
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?
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}Sourcepub fn complete<'a>(
&'a self,
prefix: &str,
) -> impl Iterator<Item = (&'a str, &'a A)>
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?
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}Sourcepub fn iter(&self) -> impl Iterator<Item = (&str, &A)>
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?
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}Trait Implementations§
Source§impl<A: Clone> Clone for CommandIndex<A>
impl<A: Clone> Clone for CommandIndex<A>
Source§fn clone(&self) -> CommandIndex<A>
fn clone(&self) -> CommandIndex<A>
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more