lotabout.skim/examples/custom_action_keybinding.rs
2026-05-21 18:19:40 +02:00

97 lines
3.1 KiB
Rust

//! Demonstrates binding custom action callbacks to keyboard shortcuts.
extern crate skim;
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use skim::prelude::*;
use skim::tui::event::{Action, ActionCallback, Event};
use std::io::Cursor;
/// Runs the custom action keybinding example.
///
/// It shows how to:
/// 1. Create custom action callbacks (both sync and async)
/// 2. Bind them to specific key combinations
/// 3. Use them interactively in skim
fn main() {
// Create a synchronous callback that adds a prefix to the query.
// Use `new_sync` for plain closures that do not need to await anything.
let add_prefix_callback = ActionCallback::new_sync(|app: &mut skim::tui::App| {
// Get current query and add prefix
let current_query = app.input.value.clone();
// Clear the line first, then add new content
let mut events = vec![Event::Action(Action::UnixLineDiscard)];
let prefix = "TODO: ";
for ch in prefix.chars() {
events.push(Event::Action(Action::AddChar(ch)));
}
// Add back the original query
for ch in current_query.chars() {
events.push(Event::Action(Action::AddChar(ch)));
}
Ok(events)
});
// Create an async callback that selects all and exits.
// Use `new` for async closures or blocks that may await futures.
let select_all_callback = ActionCallback::new(|app: &mut skim::tui::App| {
let count = app.item_pool.len();
async move {
// Async work could go here (e.g. HTTP requests, file I/O, …).
Ok(vec![
Event::Action(Action::SelectAll),
Event::Action(Action::Accept(Some(format!("Selected {count} items")))),
])
}
});
// Build basic options
let mut options = SkimOptionsBuilder::default()
.multi(true)
.prompt("Select> ")
.header("<C-p>: add prefix to prompt\t<C-a>: select all and exit with count")
.build()
.unwrap();
// Now manually add custom keybindings to the keymap
// We can access the keymap directly since it's public
// Bind Ctrl-P to add prefix
options.keymap.insert(
KeyEvent::new(KeyCode::Char('p'), KeyModifiers::CONTROL),
vec![Action::Custom(add_prefix_callback)],
);
// Bind Ctrl-A to select all with message
options.keymap.insert(
KeyEvent::new(KeyCode::Char('a'), KeyModifiers::CONTROL),
vec![Action::Custom(select_all_callback)],
);
// Create sample items
let items = [
"Write documentation",
"Fix bug #123",
"Implement feature X",
"Review pull request",
"Update dependencies",
"Refactor module Y",
"Add unit tests",
"Optimize performance",
];
let item_reader = SkimItemReader::default();
let input = items.join("\n");
let item_source = item_reader.of_bufread(Cursor::new(input));
// Run skim with our custom keybindings
if let Ok(output) = Skim::run_with(options, Some(item_source)) {
println!("output: {output:?}");
} else {
println!("\nAborted!");
}
}