fix: fix definition of DecorationProviderOpts (#253)

This commit is contained in:
Riccardo Mazzarini 2025-06-01 02:05:23 +02:00 committed by GitHub
parent 5057f0ab05
commit ac38bb32db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 116 additions and 107 deletions

View file

@ -9,6 +9,12 @@
- `nvim_oxi::api::get_mode()` is now infallible and always returns a `GotMode`
([#247](https://github.com/noib3/nvim-oxi/pull/247));
### Fixed
- fixed the definition of `DecorationProviderOpts`, which was causing
the callbacks registered to `set_decoration_provider()` to panic on all
Neovim versions ([#253](https://github.com/noib3/nvim-oxi/pull/253));
### Added
- a `String::to_str()` method which returns a `&str` if the string contains

View file

@ -1,21 +1,32 @@
use types::Object;
use types::LuaRef;
use crate::ToFunction;
use crate::{Buffer, Window};
/// Arguments passed to the function registered to
/// [`on_start`](DecorationProviderOptsBuilder::on_start).
pub type OnStartArgs = (
String, // the string literal "start"
u32, // changedtick
);
// NOTE: docs say a third argument of changedtick is passed. I don't see it.
/// Arguments passed to the function registered to
/// [`on_buf`](DecorationProviderOptsBuilder::on_buf).
pub type OnBufArgs = (
String, // the string literal "buf"
Buffer, // buffer
u32, // changedtick
);
/// Arguments passed to the function registered to
/// [`on_end`](DecorationProviderOptsBuilder::on_end).
pub type OnEndArgs = (
String, // the string literal "end"
u32, // changedtick
/// [`on_win`](DecorationProviderOptsBuilder::on_win).
pub type OnWinArgs = (
String, // the string literal "win"
Window, // window
Buffer, // buffer
u32, // toprow
u32, // botrow
);
/// Arguments passed to the function registered to
@ -28,21 +39,10 @@ pub type OnLineArgs = (
);
/// Arguments passed to the function registered to
/// [`on_start`](DecorationProviderOptsBuilder::on_start).
pub type OnStartArgs = (
String, // the string literal "start"
/// [`on_end`](DecorationProviderOptsBuilder::on_end).
pub type OnEndArgs = (
String, // the string literal "end"
u32, // changedtick
u32, /* `type`, undocumented? (https://github.com/neovim/neovim/blob/master/src/nvim/decoration_provider.c#L68) */
);
/// Arguments passed to the function registered to
/// [`on_win`](DecorationProviderOptsBuilder::on_win).
pub type OnWinArgs = (
String, // the string literal "win"
Window, // window
Buffer, // buffer
u32, // topline
u32, // botline guess
);
/// The `on_start` callback can return `false` to disable the provider until
@ -55,77 +55,54 @@ pub type DontSkipOnLines = bool;
/// Options passed to
/// [`set_decoration_provider()`](crate::set_decoration_provider).
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, macros::OptsBuilder)]
#[repr(C)]
pub struct DecorationProviderOpts {
on_start: Object,
on_buf: Object,
on_win: Object,
on_line: Object,
on_end: Object,
_on_hl_def: Object,
_on_spell_nav: Object,
}
impl DecorationProviderOpts {
#[inline(always)]
/// Creates a new [`DecorationProviderOptsBuilder`].
pub fn builder() -> DecorationProviderOptsBuilder {
DecorationProviderOptsBuilder::default()
}
}
#[derive(Clone, Default)]
pub struct DecorationProviderOptsBuilder(DecorationProviderOpts);
impl DecorationProviderOptsBuilder {
#[inline]
pub fn on_buf<F>(&mut self, fun: F) -> &mut Self
where
F: ToFunction<OnBufArgs, ()>,
{
self.0.on_buf = Object::from_luaref(fun.into_luaref());
self
}
#[inline]
pub fn on_end<F>(&mut self, fun: F) -> &mut Self
where
F: ToFunction<OnEndArgs, ()>,
{
self.0.on_end = Object::from_luaref(fun.into_luaref());
self
}
#[inline]
pub fn on_line<F>(&mut self, fun: F) -> &mut Self
where
F: ToFunction<OnLineArgs, ()>,
{
self.0.on_line = Object::from_luaref(fun.into_luaref());
self
}
#[inline]
pub fn on_start<F>(&mut self, fun: F) -> &mut Self
where
F: ToFunction<OnStartArgs, DontSkipRedrawCycle>,
{
self.0.on_start = Object::from_luaref(fun.into_luaref());
self
}
#[inline]
pub fn on_win<F>(&mut self, fun: F) -> &mut Self
where
F: ToFunction<OnWinArgs, DontSkipOnLines>,
{
self.0.on_win = Object::from_luaref(fun.into_luaref());
self
}
#[inline]
pub fn build(&mut self) -> DecorationProviderOpts {
std::mem::take(&mut self.0)
}
#[builder(mask)]
mask: u64,
#[builder(
generics = "F: ToFunction<OnStartArgs, DontSkipRedrawCycle>",
argtype = "F",
inline = "{0}.into_luaref()"
)]
on_start: LuaRef,
#[builder(
generics = "F: ToFunction<OnBufArgs, ()>",
argtype = "F",
inline = "{0}.into_luaref()"
)]
on_buf: LuaRef,
#[builder(
generics = "F: ToFunction<OnWinArgs, DontSkipOnLines>",
argtype = "F",
inline = "{0}.into_luaref()"
)]
on_win: LuaRef,
#[builder(
generics = "F: ToFunction<OnLineArgs, ()>",
argtype = "F",
inline = "{0}.into_luaref()"
)]
on_line: LuaRef,
#[builder(
generics = "F: ToFunction<OnEndArgs, ()>",
argtype = "F",
inline = "{0}.into_luaref()"
)]
on_end: LuaRef,
#[builder(skip)]
_on_hl_def: LuaRef,
#[builder(skip)]
_on_spell_nav: LuaRef,
#[cfg(feature = "neovim-0-11")] // On 0.11 and Nightly.
#[builder(skip)]
_on_conceal_line: LuaRef,
}

View file

@ -1,3 +1,6 @@
use core::cell::Cell;
use std::rc::Rc;
use nvim_oxi::api::{self, Buffer, opts::*, types::*};
#[nvim_oxi::test]
@ -86,35 +89,58 @@ fn get_namespaces() {
fn set_decoration_provider() {
let id = api::create_namespace("Foo");
let on_start_called = Rc::new(Cell::new(false));
let on_buf_called = Rc::new(Cell::new(false));
let on_win_called = Rc::new(Cell::new(false));
let on_line_called = Rc::new(Cell::new(false));
let on_end_called = Rc::new(Cell::new(false));
let opts = DecorationProviderOpts::builder()
.on_start(|args| {
nvim_oxi::print!("{args:?}");
true
.on_start({
let on_start_called = on_start_called.clone();
move |_| {
on_start_called.set(true);
true
}
})
.on_buf(|args| {
nvim_oxi::print!("{args:?}");
.on_buf({
let on_buf_called = on_buf_called.clone();
move |_| {
on_buf_called.set(true);
}
})
.on_win(|args| {
nvim_oxi::print!("{args:?}");
true
.on_win({
let on_win_called = on_win_called.clone();
move |_| {
on_win_called.set(true);
true
}
})
.on_line(|args| {
nvim_oxi::print!("{args:?}");
.on_line({
let on_line_called = on_line_called.clone();
move |_| {
on_line_called.set(true);
}
})
.on_end(|args| {
nvim_oxi::print!("{args:?}");
.on_end({
let on_end_called = on_end_called.clone();
move |_| {
on_end_called.set(true);
}
})
.build();
let res = api::set_decoration_provider(id, &opts);
assert_eq!(Ok(()), res);
// TODO: I don't think the callbacks are getting triggered. If they were
// `print!`'s output would be written to stdout, causing `test_all` to
// fail.
api::Buffer::current().set_lines(0..0, true, ["foo"]).unwrap();
api::command("redraw!").expect("redraw failed");
let bytes_written = api::input("ifoo<Esc>");
assert!(bytes_written.is_ok(), "{bytes_written:?}");
assert!(on_start_called.get());
assert!(on_buf_called.get());
assert!(on_win_called.get());
assert!(on_line_called.get());
assert!(on_end_called.get());
}
#[nvim_oxi::test]