nvrim/plugins/scrolloff.rs
1//! Scrolloff configuration utilities.
2//!
3//! Provides functions to dynamically set the 'scrolloff' option based on window height,
4//! maintaining a proportional buffer zone around the cursor.
5
6use nvim_oxi::api::Window;
7use nvim_oxi::api::opts::CreateAutocmdOptsBuilder;
8use nvim_oxi::api::types::AutocmdCallbackArgs;
9
10/// Creates an autocmd to update scrolloff on window events.
11///
12/// Registers autocmds for `BufEnter`, `WinEnter`, `WinNew`, and `VimResized` events
13/// to recalculate and set the 'scrolloff' option dynamically.
14///
15/// # Rationale
16///
17/// Ensures scrolloff remains proportional to the visible window height, improving
18/// navigation UX by keeping context lines consistent relative to screen size.
19pub fn create_autocmd() {
20 crate::cmds::create_autocmd(
21 ["BufEnter", "WinEnter", "WinNew", "VimResized"],
22 "ScrolloffFraction",
23 CreateAutocmdOptsBuilder::default().patterns(["*"]).callback(callback),
24 );
25}
26
27/// Callback for scrolloff autocmd.
28///
29/// Retrieves the current window height, calculates scrolloff as 50% of height (floored),
30/// and sets the global 'scrolloff' option. Returns `false` to continue processing other autocmds.
31///
32/// # Errors
33/// Logs an error notification if window height cannot be retrieved; otherwise proceeds silently.
34fn callback(_: AutocmdCallbackArgs) -> bool {
35 let Ok(height) = Window::current().get_height().inspect_err(|err| {
36 ytil_noxi::notify::error(format!("error getting Neovim window height | error={err:#?}"));
37 }) else {
38 return false;
39 };
40 let scrolloff = height / 2;
41 crate::vim_opts::set("scrolloff", scrolloff, &crate::vim_opts::global_scope());
42 false
43}