ytil_noxi/
vim_ui_select.rs1use std::fmt::Debug;
4use std::fmt::Display;
5use std::rc::Rc;
6
7use nvim_oxi::mlua;
8use nvim_oxi::mlua::IntoLua;
9use nvim_oxi::mlua::ObjectLike;
10use rootcause::report;
11
12pub struct QuickfixConfig {
18 pub trigger_value: String,
20 pub all_items: Vec<(String, i64)>,
22}
23
24pub fn open<C, K, V>(
36 choices: impl IntoIterator<Item = C> + Debug,
37 opts: &(impl IntoIterator<Item = (K, V)> + Debug + Clone),
38 callback: impl Fn(usize) + 'static,
39 maybe_quickfix: Option<QuickfixConfig>,
40) -> rootcause::Result<()>
41where
42 C: Display,
43 K: IntoLua,
44 V: IntoLua,
45{
46 let lua = mlua::lua();
47
48 let vim_ui_select = lua
49 .globals()
50 .get_path::<mlua::Function>("vim.ui.select")
51 .map_err(|err| report!("cannot fetch vim.ui.select function from Lua globals").attach(err.to_string()))?;
52
53 let opts_table = lua.create_table_from(opts.clone()).map_err(|err| {
54 report!("cannot create opts table")
55 .attach(format!("opts={opts:#?}"))
56 .attach(err.to_string())
57 })?;
58
59 let quickfix = maybe_quickfix.map(Rc::new);
60
61 let vim_ui_select_callback = lua
62 .create_function(
63 move |_: &mlua::Lua, (selected_value, idx): (Option<String>, Option<usize>)| {
64 if let Some(quickfix) = &quickfix
65 && selected_value.is_some_and(|x| x == quickfix.trigger_value)
66 {
67 if let Err(err) = crate::quickfix::open(quickfix.all_items.iter().map(|(s, i)| (s.as_str(), *i))) {
68 crate::notify::error(format!("error opening quickfix: {err:#}"));
69 }
70 return Ok(());
71 }
72 if let Some(idx) = idx {
73 callback(idx.saturating_sub(1));
74 }
75 Ok(())
76 },
77 )
78 .map_err(|err| {
79 report!("cannot create vim.ui.select callback")
80 .attach(format!("choices={choices:#?} opts={opts_table:#?}"))
81 .attach(err.to_string())
82 })?;
83
84 let vim_ui_choices = choices.into_iter().map(|c| c.to_string()).collect::<Vec<_>>();
85
86 vim_ui_select
87 .call::<()>((vim_ui_choices.clone(), opts_table.clone(), vim_ui_select_callback))
88 .map_err(|err| {
89 report!("cannot call vim.ui.select")
90 .attach(format!("choices={vim_ui_choices:#?} opts={opts_table:#?}"))
91 .attach(err.to_string())
92 })?;
93
94 Ok(())
95}