···11+local M = {}
22+33+---@class Interval
44+---@field l integer
55+---@field r integer
66+---@field data any
77+local Interval = {}
88+99+---@param intervals Interval[]
1010+---@param point integer
1111+local function _partition(intervals, point)
1212+ local before = {}
1313+ local on = nil
1414+ local after = {}
1515+1616+ for _, interval in ipairs(intervals) do
1717+ if interval.l <= point and point < interval.r then
1818+ on = interval
1919+ goto continue
2020+ end
2121+ if interval.l < point then
2222+ table.insert(before, interval)
2323+ end
2424+ if interval.l > point then
2525+ table.insert(after, interval)
2626+ end
2727+ ::continue::
2828+ end
2929+3030+ return before, on, after
3131+end
3232+3333+---@class Intervals
3434+---@field intervals Interval[]
3535+local Intervals = {}
3636+3737+---@generic T
3838+---@param elements T[]
3939+---@param make_interval fun(element: T): Interval
4040+---@return Intervals
4141+function Intervals:new(elements, make_interval)
4242+ local obj = setmetatable({}, { __index = self })
4343+ obj.intervals = vim.iter(elements):map(make_interval):totable()
4444+ return obj
4545+end
4646+4747+---@generic T
4848+---@param elements T[]
4949+---@param make_interval fun(element: T): Interval
5050+function M.from_list(elements, make_interval)
5151+ return Intervals:new(elements, make_interval)
5252+end
5353+5454+---@param interval Interval?
5555+local function _data(interval)
5656+ if interval then
5757+ return interval.data
5858+ end
5959+ return nil
6060+end
6161+6262+--- Get intervals around a point.
6363+---@param point integer
6464+---@param offset integer
6565+function Intervals:find(point, offset)
6666+ local before, on, after = _partition(self.intervals, point)
6767+ if offset == 0 then
6868+ return _data(on)
6969+ elseif offset < 0 then
7070+ offset = -offset
7171+ return _data(before[#before - (offset - 1)] or before[1])
7272+ else
7373+ return _data(after[offset] or after[#after])
7474+ end
7575+end
7676+7777+return M