ytil_noxi/
jumplist.rs

1//! Neovim jumplist utilities for accessing jump history.
2//!
3//! Provides types and functions to retrieve and parse the Neovim jumplist,
4//! which contains the history of cursor positions jumped to using commands
5//! like `Ctrl-I`, `Ctrl-O`, `:tag`, etc. The jumplist is represented as a
6//! vector of jump entries with an associated current position index.
7
8use nvim_oxi::Array;
9use nvim_oxi::Object;
10use nvim_oxi::conversion::FromObject;
11use nvim_oxi::lua::Poppable;
12use nvim_oxi::lua::ffi::State;
13use serde::Deserialize;
14
15/// Represents a single entry in Neovim's jumplist.
16///
17/// Contains the cursor position and buffer information for a specific jump
18/// location. All coordinates use Nvim's conventions (1-based for lines, 0-based
19/// for columns unless otherwise specified).
20///
21/// # Assumptions
22/// - Coordinates follow Nvim's internal conventions.
23/// - `coladd` is used for multi-byte character positioning in some contexts.
24///
25/// # Rationale
26/// Direct mapping of Nvim's jumplist entry structure to enable seamless
27/// conversion from Lua API responses.
28#[derive(Clone, Debug, Deserialize)]
29pub struct JumpEntry {
30    /// Buffer number where the jump occurred.
31    pub bufnr: i32,
32    /// Column position (0-based byte offset).
33    pub col: i32,
34    /// Column addition for virtual cursor positioning.
35    pub coladd: i32,
36    /// Line number (1-based).
37    pub lnum: i32,
38}
39
40impl FromObject for JumpList {
41    fn from_object(obj: Object) -> Result<Self, nvim_oxi::conversion::Error> {
42        Self::deserialize(nvim_oxi::serde::Deserializer::new(obj)).map_err(Into::into)
43    }
44}
45
46impl Poppable for JumpList {
47    unsafe fn pop(lstate: *mut State) -> Result<Self, nvim_oxi::lua::Error> {
48        unsafe {
49            let obj = Object::pop(lstate)?;
50            Self::from_object(obj).map_err(nvim_oxi::lua::Error::pop_error_from_err::<Self, _>)
51        }
52    }
53}
54
55/// Internal representation of Neovim's jumplist structure.
56///
57/// Wraps the raw jumplist data returned by Nvim's `getjumplist()` function,
58/// which consists of a vector of jump entries and the current position index.
59/// This type is used internally for deserialization and conversion.
60///
61/// # Fields
62/// - `Vec<JumpEntry>` All jump entries and the usize represents.
63/// - `usize` The current position index in the jumplist.
64///
65/// # Rationale
66/// Kept private to expose only the jump entries vector via the public API,
67/// hiding implementation details about position tracking.
68#[derive(Debug, Deserialize)]
69#[allow(dead_code)]
70struct JumpList(Vec<JumpEntry>, usize);
71
72/// Retrieves the current jumplist from Neovim.
73///
74/// Calls Nvim's `getjumplist()` function and extracts the jump entries vector.
75/// Errors are handled internally by notifying Nvim and returning `None`.
76///
77/// # Errors
78/// - Lua function call fails when invoking `getjumplist`.
79/// - Deserialization fails when parsing the jumplist structure.
80/// - All errors are notified to Nvim via [`crate::notify::error`] and converted to `None`.
81pub fn get() -> Option<Vec<JumpEntry>> {
82    Some(
83        nvim_oxi::api::call_function::<_, JumpList>("getjumplist", Array::new())
84            .inspect_err(|err| crate::notify::error(format!("error getting jumplist | error={err:?}")))
85            .ok()?
86            .0,
87    )
88}