2022-12-03 11:55:46 +00:00
|
|
|
use skim::prelude::*;
|
2022-12-14 15:45:00 +00:00
|
|
|
use term::terminfo::TermInfo;
|
2022-12-03 11:55:46 +00:00
|
|
|
use cxx::{CxxString, CxxVector};
|
|
|
|
|
|
|
|
#[cxx::bridge]
|
|
|
|
mod ffi {
|
|
|
|
extern "Rust" {
|
2022-12-14 15:45:00 +00:00
|
|
|
fn skim(words: &CxxVector<CxxString>) -> Result<String>;
|
2022-12-03 11:55:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Item {
|
|
|
|
text: String,
|
|
|
|
}
|
|
|
|
impl SkimItem for Item {
|
|
|
|
fn text(&self) -> Cow<str> {
|
|
|
|
return Cow::Borrowed(&self.text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-14 15:45:00 +00:00
|
|
|
fn skim(words: &CxxVector<CxxString>) -> Result<String, String> {
|
|
|
|
// Let's check is terminal available. To avoid panic.
|
|
|
|
if let Err(err) = TermInfo::from_env() {
|
|
|
|
return Err(format!("{}", err));
|
|
|
|
}
|
|
|
|
|
2022-12-03 11:55:46 +00:00
|
|
|
let options = SkimOptionsBuilder::default()
|
|
|
|
.height(Some("30%"))
|
|
|
|
.tac(true)
|
|
|
|
.tiebreak(Some("-score".to_string()))
|
|
|
|
.build()
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let (tx, rx): (SkimItemSender, SkimItemReceiver) = unbounded();
|
|
|
|
for word in words {
|
|
|
|
tx.send(Arc::new(Item{ text: word.to_string() })).unwrap();
|
|
|
|
}
|
|
|
|
// so that skim could know when to stop waiting for more items.
|
|
|
|
drop(tx);
|
|
|
|
|
|
|
|
let output = Skim::run_with(&options, Some(rx));
|
|
|
|
if output.is_none() {
|
2022-12-14 15:45:00 +00:00
|
|
|
return Err("skim return nothing".to_string());
|
2022-12-03 11:55:46 +00:00
|
|
|
}
|
|
|
|
let output = output.unwrap();
|
|
|
|
if output.is_abort {
|
2022-12-14 15:45:00 +00:00
|
|
|
return Ok("".to_string());
|
2022-12-03 11:55:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if output.selected_items.is_empty() {
|
2022-12-14 15:45:00 +00:00
|
|
|
return Err("No items had been selected".to_string());
|
2022-12-03 11:55:46 +00:00
|
|
|
}
|
2022-12-14 15:45:00 +00:00
|
|
|
return Ok(output.selected_items[0].output().to_string());
|
2022-12-03 11:55:46 +00:00
|
|
|
}
|