neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

shared.lua (47691B)


      1 -- Functions shared by Nvim and its test-suite.
      2 --
      3 -- These are "pure" lua functions not depending of the state of the editor.
      4 -- Thus they should always be available whenever nvim-related lua code is run,
      5 -- regardless if it is code in the editor itself, or in worker threads/processes,
      6 -- or the test suite. (Eventually the test suite will be run in a worker process,
      7 -- so this wouldn't be a separate case to consider)
      8 
      9 ---@nodoc
     10 _G.vim = _G.vim or {} --[[@as table]]
     11 -- TODO(lewis6991): better fix for flaky luals
     12 
     13 ---@generic T
     14 ---@param orig T
     15 ---@param cache? table<any,any>
     16 ---@return T
     17 local function deepcopy(orig, cache)
     18  if orig == vim.NIL then
     19    return vim.NIL
     20  elseif type(orig) == 'userdata' or type(orig) == 'thread' then
     21    error('Cannot deepcopy object of type ' .. type(orig))
     22  elseif type(orig) ~= 'table' then
     23    return orig
     24  end
     25 
     26  --- @cast orig table<any,any>
     27 
     28  if cache and cache[orig] then
     29    return cache[orig]
     30  end
     31 
     32  local copy = {} --- @type table<any,any>
     33 
     34  if cache then
     35    cache[orig] = copy
     36  end
     37 
     38  for k, v in pairs(orig) do
     39    copy[deepcopy(k, cache)] = deepcopy(v, cache)
     40  end
     41 
     42  return setmetatable(copy, getmetatable(orig))
     43 end
     44 
     45 --- Returns a deep copy of the given object. Non-table objects are copied as
     46 --- in a typical Lua assignment, whereas table objects are copied recursively.
     47 --- Functions are naively copied, so functions in the copied table point to the
     48 --- same functions as those in the input table. Userdata and threads are not
     49 --- copied and will throw an error.
     50 ---
     51 --- Note: `noref=true` is much more performant on tables with unique table
     52 --- fields, while `noref=false` is more performant on tables that reuse table
     53 --- fields.
     54 ---
     55 ---@generic T: table
     56 ---@param orig T Table to copy
     57 ---@param noref? boolean
     58 --- When `false` (default) a contained table is only copied once and all
     59 --- references point to this single copy. When `true` every occurrence of a
     60 --- table results in a new copy. This also means that a cyclic reference can
     61 --- cause `deepcopy()` to fail.
     62 ---@return T Table of copied keys and (nested) values.
     63 function vim.deepcopy(orig, noref)
     64  return deepcopy(orig, not noref and {} or nil)
     65 end
     66 
     67 --- @class vim.gsplit.Opts
     68 --- @inlinedoc
     69 ---
     70 --- Use `sep` literally (as in string.find).
     71 --- @field plain? boolean
     72 ---
     73 --- Discard empty segments at start and end of the sequence.
     74 --- @field trimempty? boolean
     75 
     76 --- Gets an |iterator| that splits a string at each instance of a separator, in "lazy" fashion
     77 --- (as opposed to |vim.split()| which is "eager").
     78 ---
     79 --- Example:
     80 ---
     81 --- ```lua
     82 --- for s in vim.gsplit(':aa::b:', ':', {plain=true}) do
     83 ---   print(s)
     84 --- end
     85 --- ```
     86 ---
     87 --- If you want to also inspect the separator itself (instead of discarding it), use
     88 --- |string.gmatch()|. Example:
     89 ---
     90 --- ```lua
     91 --- for word, num in ('foo111bar222'):gmatch('([^0-9]*)(%d*)') do
     92 ---   print(('word: %s num: %s'):format(word, num))
     93 --- end
     94 --- ```
     95 ---
     96 --- @see |string.gmatch()|
     97 --- @see |vim.split()|
     98 --- @see |lua-pattern|s
     99 --- @see https://www.lua.org/pil/20.2.html
    100 --- @see http://lua-users.org/wiki/StringLibraryTutorial
    101 ---
    102 --- @param s string String to split
    103 --- @param sep string Separator or pattern
    104 --- @param opts? vim.gsplit.Opts Keyword arguments |kwargs|:
    105 --- @return fun():string? : Iterator over the split components
    106 function vim.gsplit(s, sep, opts)
    107  local plain --- @type boolean?
    108  local trimempty = false --- @type boolean?
    109  if type(opts) == 'boolean' then
    110    plain = opts -- For backwards compatibility.
    111  else
    112    vim.validate('s', s, 'string')
    113    vim.validate('sep', sep, 'string')
    114    vim.validate('opts', opts, 'table', true)
    115    opts = opts or {}
    116    plain, trimempty = opts.plain, opts.trimempty
    117  end
    118 
    119  local start = 1
    120  local done = false
    121 
    122  -- For `trimempty`: queue of collected segments, to be emitted at next pass.
    123  local segs = {}
    124  local empty_start = true -- Only empty segments seen so far.
    125 
    126  --- @param i integer?
    127  --- @param j integer
    128  --- @param ... unknown
    129  --- @return string
    130  --- @return ...
    131  local function _pass(i, j, ...)
    132    if i then
    133      assert(j + 1 > start, 'Infinite loop detected')
    134      local seg = s:sub(start, i - 1)
    135      start = j + 1
    136      return seg, ...
    137    else
    138      done = true
    139      return s:sub(start)
    140    end
    141  end
    142 
    143  return function()
    144    if trimempty and #segs > 0 then
    145      -- trimempty: Pop the collected segments.
    146      return table.remove(segs)
    147    elseif done or (s == '' and sep == '') then
    148      return nil
    149    elseif sep == '' then
    150      if start == #s then
    151        done = true
    152      end
    153      return _pass(start + 1, start)
    154    end
    155 
    156    local seg = _pass(s:find(sep, start, plain))
    157 
    158    -- Trim empty segments from start/end.
    159    if trimempty and seg ~= '' then
    160      empty_start = false
    161    elseif trimempty and seg == '' then
    162      while not done and seg == '' do
    163        table.insert(segs, 1, '')
    164        seg = _pass(s:find(sep, start, plain))
    165      end
    166      if done and seg == '' then
    167        return nil
    168      elseif empty_start then
    169        empty_start = false
    170        segs = {}
    171        return seg
    172      end
    173      if seg ~= '' then
    174        table.insert(segs, 1, seg)
    175      end
    176      return table.remove(segs)
    177    end
    178 
    179    return seg
    180  end
    181 end
    182 
    183 --- Splits a string at each instance of a separator and returns the result as a table (unlike
    184 --- |vim.gsplit()|).
    185 ---
    186 --- Examples:
    187 ---
    188 --- ```lua
    189 --- split(":aa::b:", ":")                   --> {'','aa','','b',''}
    190 --- split("axaby", "ab?")                   --> {'','x','y'}
    191 --- split("x*yz*o", "*", {plain=true})      --> {'x','yz','o'}
    192 --- split("|x|y|z|", "|", {trimempty=true}) --> {'x', 'y', 'z'}
    193 --- ```
    194 ---
    195 ---@see |vim.gsplit()|
    196 ---@see |string.gmatch()|
    197 ---
    198 ---@param s string String to split
    199 ---@param sep string Separator or pattern
    200 ---@param opts? vim.gsplit.Opts Keyword arguments |kwargs|:
    201 ---@return string[] : List of split components
    202 function vim.split(s, sep, opts)
    203  local t = {}
    204  for c in vim.gsplit(s, sep, opts) do
    205    table.insert(t, c)
    206  end
    207  return t
    208 end
    209 
    210 --- Return a list of all keys used in a table.
    211 --- However, the order of the return table of keys is not guaranteed.
    212 ---
    213 ---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
    214 ---
    215 ---@generic T
    216 ---@param t table<T, any> (table) Table
    217 ---@return T[] : List of keys
    218 function vim.tbl_keys(t)
    219  vim.validate('t', t, 'table')
    220  --- @cast t table<any,any>
    221 
    222  local keys = {}
    223  for k in pairs(t) do
    224    table.insert(keys, k)
    225  end
    226  return keys
    227 end
    228 
    229 --- Return a list of all values used in a table.
    230 --- However, the order of the return table of values is not guaranteed.
    231 ---
    232 ---@generic T
    233 ---@param t table<any, T> (table) Table
    234 ---@return T[] : List of values
    235 function vim.tbl_values(t)
    236  vim.validate('t', t, 'table')
    237 
    238  local values = {}
    239  for _, v in
    240    pairs(t --[[@as table<any,any>]])
    241  do
    242    table.insert(values, v)
    243  end
    244  return values
    245 end
    246 
    247 --- Applies function `fn` to all values of table `t`, in `pairs()` iteration order (which is not
    248 --- guaranteed to be stable, even when the data doesn't change).
    249 ---
    250 ---@generic T
    251 ---@param fn fun(value: T): any Function
    252 ---@param t table<any, T> Table
    253 ---@return table : Table of transformed values
    254 function vim.tbl_map(fn, t)
    255  vim.validate('fn', fn, 'callable')
    256  vim.validate('t', t, 'table')
    257  --- @cast t table<any,any>
    258 
    259  local rettab = {} --- @type table<any,any>
    260  for k, v in pairs(t) do
    261    rettab[k] = fn(v)
    262  end
    263  return rettab
    264 end
    265 
    266 --- Filter a table using a predicate function
    267 ---
    268 ---@generic T
    269 ---@param fn fun(value: T): boolean (function) Function
    270 ---@param t table<any, T> (table) Table
    271 ---@return T[] : Table of filtered values
    272 function vim.tbl_filter(fn, t)
    273  vim.validate('fn', fn, 'callable')
    274  vim.validate('t', t, 'table')
    275  --- @cast t table<any,any>
    276 
    277  local rettab = {} --- @type table<any,any>
    278  for _, entry in pairs(t) do
    279    if fn(entry) then
    280      rettab[#rettab + 1] = entry
    281    end
    282  end
    283  return rettab
    284 end
    285 
    286 --- @class vim.tbl_contains.Opts
    287 --- @inlinedoc
    288 ---
    289 --- `value` is a function reference to be checked (default false)
    290 --- @field predicate? boolean
    291 
    292 --- Checks if a table contains a given value, specified either directly or via
    293 --- a predicate that is checked for each value.
    294 ---
    295 --- Example:
    296 ---
    297 --- ```lua
    298 --- vim.tbl_contains({ 'a', { 'b', 'c' } }, function(v)
    299 ---   return vim.deep_equal(v, { 'b', 'c' })
    300 --- end, { predicate = true })
    301 --- -- true
    302 --- ```
    303 ---
    304 ---@see |vim.list_contains()| for checking values in list-like tables
    305 ---
    306 ---@param t table Table to check
    307 ---@param value any Value to compare or predicate function reference
    308 ---@param opts? vim.tbl_contains.Opts Keyword arguments |kwargs|:
    309 ---@return boolean `true` if `t` contains `value`
    310 function vim.tbl_contains(t, value, opts)
    311  vim.validate('t', t, 'table')
    312  vim.validate('opts', opts, 'table', true)
    313  --- @cast t table<any,any>
    314 
    315  local pred --- @type fun(v: any): boolean?
    316  if opts and opts.predicate then
    317    vim.validate('value', value, 'callable')
    318    pred = value
    319  else
    320    pred = function(v)
    321      return v == value
    322    end
    323  end
    324 
    325  for _, v in pairs(t) do
    326    if pred(v) then
    327      return true
    328    end
    329  end
    330  return false
    331 end
    332 
    333 --- Checks if a list-like table (integer keys without gaps) contains `value`.
    334 ---
    335 ---@see |vim.tbl_contains()| for checking values in general tables
    336 ---
    337 ---@param t table Table to check (must be list-like, not validated)
    338 ---@param value any Value to compare
    339 ---@return boolean `true` if `t` contains `value`
    340 function vim.list_contains(t, value)
    341  vim.validate('t', t, 'table')
    342  --- @cast t table<any,any>
    343 
    344  for _, v in ipairs(t) do
    345    if v == value then
    346      return true
    347    end
    348  end
    349  return false
    350 end
    351 
    352 vim.list = {}
    353 
    354 ---TODO(ofseed): memoize, string value support, type alias.
    355 ---@generic T
    356 ---@param v T
    357 ---@param key? fun(v: T): any
    358 ---@return any
    359 local function key_fn(v, key)
    360  return key and key(v) or v
    361 end
    362 
    363 --- Removes duplicate values from a list-like table in-place.
    364 ---
    365 --- Only the first occurrence of each value is kept.
    366 --- The operation is performed in-place and the input table is modified.
    367 ---
    368 --- Accepts an optional `key` argument, which if provided is called for each
    369 --- value in the list to compute a hash key for uniqueness comparison.
    370 --- This is useful for deduplicating table values or complex objects.
    371 --- If `key` returns `nil` for a value, that value will be considered unique,
    372 --- even if multiple values return `nil`.
    373 ---
    374 --- Example:
    375 --- ```lua
    376 ---
    377 --- local t = {1, 2, 2, 3, 1}
    378 --- vim.list.unique(t)
    379 --- -- t is now {1, 2, 3}
    380 ---
    381 --- local t = { {id=1}, {id=2}, {id=1} }
    382 --- vim.list.unique(t, function(x) return x.id end)
    383 --- -- t is now { {id=1}, {id=2} }
    384 --- ```
    385 ---
    386 --- @generic T
    387 --- @param t T[]
    388 --- @param key? fun(x: T): any Optional hash function to determine uniqueness of values
    389 --- @return T[] : The deduplicated list
    390 --- @see |Iter:unique()|
    391 function vim.list.unique(t, key)
    392  vim.validate('t', t, 'table')
    393  local seen = {} --- @type table<any,boolean>
    394 
    395  local finish = #t
    396 
    397  local j = 1
    398  for i = 1, finish do
    399    local v = t[i]
    400    local vh = key_fn(v, key)
    401    if not seen[vh] then
    402      t[j] = v
    403      if vh ~= nil then
    404        seen[vh] = true
    405      end
    406      j = j + 1
    407    end
    408  end
    409 
    410  for i = j, finish do
    411    t[i] = nil
    412  end
    413 
    414  return t
    415 end
    416 
    417 ---@class vim.list.bisect.Opts
    418 ---@inlinedoc
    419 ---
    420 --- Start index of the list.
    421 --- (default: `1`)
    422 ---@field lo? integer
    423 ---
    424 --- End index of the list, exclusive.
    425 --- (default: `#t + 1`)
    426 ---@field hi? integer
    427 ---
    428 --- Optional, compare the return value instead of the {val} itself if provided.
    429 ---@field key? fun(val: any): any
    430 ---
    431 --- Specifies the search variant.
    432 ---   - "lower": returns the first position
    433 ---     where inserting {val} keeps the list sorted.
    434 ---   - "upper": returns the last position
    435 ---     where inserting {val} keeps the list sorted..
    436 --- (default: `'lower'`)
    437 ---@field bound? 'lower' | 'upper'
    438 
    439 ---@generic T
    440 ---@param t T[]
    441 ---@param val T
    442 ---@param key? fun(val: any): any
    443 ---@param lo integer
    444 ---@param hi integer
    445 ---@return integer i in range such that `t[j]` < {val} for all j < i,
    446 ---                and `t[j]` >= {val} for all j >= i,
    447 ---                or return {hi} if no such index is found.
    448 local function lower_bound(t, val, lo, hi, key)
    449  local bit = require('bit') -- Load bitop on demand
    450  local val_key = key_fn(val, key)
    451  while lo < hi do
    452    local mid = bit.rshift(lo + hi, 1) -- Equivalent to floor((lo + hi) / 2)
    453    if key_fn(t[mid], key) < val_key then
    454      lo = mid + 1
    455    else
    456      hi = mid
    457    end
    458  end
    459  return lo
    460 end
    461 
    462 ---@generic T
    463 ---@param t T[]
    464 ---@param val T
    465 ---@param key? fun(val: any): any
    466 ---@param lo integer
    467 ---@param hi integer
    468 ---@return integer i in range such that `t[j]` <= {val} for all j < i,
    469 ---                and `t[j]` > {val} for all j >= i,
    470 ---                or return {hi} if no such index is found.
    471 local function upper_bound(t, val, lo, hi, key)
    472  local bit = require('bit') -- Load bitop on demand
    473  local val_key = key_fn(val, key)
    474  while lo < hi do
    475    local mid = bit.rshift(lo + hi, 1) -- Equivalent to floor((lo + hi) / 2)
    476    if val_key < key_fn(t[mid], key) then
    477      hi = mid
    478    else
    479      lo = mid + 1
    480    end
    481  end
    482  return lo
    483 end
    484 
    485 --- Search for a position in a sorted list {t}
    486 --- where {val} can be inserted while keeping the list sorted.
    487 ---
    488 --- Use {bound} to determine whether to return the first or the last position,
    489 --- defaults to "lower", i.e., the first position.
    490 ---
    491 --- NOTE: Behavior is undefined on unsorted lists!
    492 ---
    493 --- Example:
    494 --- ```lua
    495 ---
    496 --- local t = { 1, 2, 2, 3, 3, 3 }
    497 --- local first = vim.list.bisect(t, 3)
    498 --- -- `first` is `val`'s first index if found,
    499 --- -- useful for existence checks.
    500 --- print(t[first]) -- 3
    501 ---
    502 --- local last = vim.list.bisect(t, 3, { bound = 'upper' })
    503 --- -- Note that `last` is 7, not 6,
    504 --- -- this is suitable for insertion.
    505 ---
    506 --- table.insert(t, last, 4)
    507 --- -- t is now { 1, 2, 2, 3, 3, 3, 4 }
    508 ---
    509 --- -- You can use lower bound and upper bound together
    510 --- -- to obtain the range of occurrences of `val`.
    511 ---
    512 --- -- 3 is in [first, last)
    513 --- for i = first, last - 1 do
    514 ---   print(t[i]) -- { 3, 3, 3 }
    515 --- end
    516 --- ```
    517 ---@generic T
    518 ---@param t T[] A comparable list.
    519 ---@param val T The value to search.
    520 ---@param opts? vim.list.bisect.Opts
    521 ---@return integer index serves as either the lower bound or the upper bound position.
    522 function vim.list.bisect(t, val, opts)
    523  vim.validate('t', t, 'table')
    524  vim.validate('opts', opts, 'table', true)
    525 
    526  opts = opts or {}
    527  local lo = opts.lo or 1
    528  local hi = opts.hi or #t + 1
    529  local key = opts.key
    530 
    531  if opts.bound == 'upper' then
    532    return upper_bound(t, val, lo, hi, key)
    533  else
    534    return lower_bound(t, val, lo, hi, key)
    535  end
    536 end
    537 
    538 --- Checks if a table is empty.
    539 ---
    540 ---@see https://github.com/premake/premake-core/blob/master/src/base/table.lua
    541 ---
    542 ---@param t table Table to check
    543 ---@return boolean `true` if `t` is empty
    544 function vim.tbl_isempty(t)
    545  vim.validate('t', t, 'table')
    546  return next(t) == nil
    547 end
    548 
    549 --- We only merge empty tables or tables that are not list-like (indexed by consecutive integers
    550 --- starting from 1)
    551 local function can_merge(v)
    552  return type(v) == 'table' and (vim.tbl_isempty(v) or not vim.islist(v))
    553 end
    554 
    555 --- Recursive worker for tbl_extend
    556 --- @param behavior 'error'|'keep'|'force'|fun(key:any, prev_value:any?, value:any): any
    557 --- @param deep_extend boolean
    558 --- @param ... table<any,any>
    559 local function tbl_extend_rec(behavior, deep_extend, ...)
    560  local ret = {} --- @type table<any,any>
    561  if vim._empty_dict_mt ~= nil and getmetatable(select(1, ...)) == vim._empty_dict_mt then
    562    ret = vim.empty_dict()
    563  end
    564 
    565  for i = 1, select('#', ...) do
    566    local tbl = select(i, ...) --[[@as table<any,any>]]
    567    if tbl then
    568      for k, v in pairs(tbl) do
    569        if deep_extend and can_merge(v) and can_merge(ret[k]) then
    570          ret[k] = tbl_extend_rec(behavior, true, ret[k], v)
    571        elseif type(behavior) == 'function' then
    572          ret[k] = behavior(k, ret[k], v)
    573        elseif behavior ~= 'force' and ret[k] ~= nil then
    574          if behavior == 'error' then
    575            error('key found in more than one map: ' .. k)
    576          end -- Else behavior is "keep".
    577        else
    578          ret[k] = v
    579        end
    580      end
    581    end
    582  end
    583 
    584  return ret
    585 end
    586 
    587 --- @param behavior 'error'|'keep'|'force'|fun(key:any, prev_value:any?, value:any): any
    588 --- @param deep_extend boolean
    589 --- @param ... table<any,any>
    590 local function tbl_extend(behavior, deep_extend, ...)
    591  if
    592    behavior ~= 'error'
    593    and behavior ~= 'keep'
    594    and behavior ~= 'force'
    595    and type(behavior) ~= 'function'
    596  then
    597    error('invalid "behavior": ' .. tostring(behavior))
    598  end
    599 
    600  local nargs = select('#', ...)
    601 
    602  if nargs < 2 then
    603    error(('wrong number of arguments (given %d, expected at least 3)'):format(1 + nargs))
    604  end
    605 
    606  for i = 1, nargs do
    607    vim.validate('after the second argument', select(i, ...), 'table')
    608  end
    609 
    610  return tbl_extend_rec(behavior, deep_extend, ...)
    611 end
    612 
    613 --- Merges two or more tables.
    614 ---
    615 ---@see |extend()|
    616 ---
    617 ---@param behavior 'error'|'keep'|'force'|fun(key:any, prev_value:any?, value:any): any Decides what to do if a key is found in more than one map:
    618 ---      - "error": raise an error
    619 ---      - "keep":  use value from the leftmost map
    620 ---      - "force": use value from the rightmost map
    621 ---      - If a function, it receives the current key, the previous value in the currently merged table (if present), the current value and should
    622 ---        return the value for the given key in the merged table.
    623 ---@param ... table Two or more tables
    624 ---@return table : Merged table
    625 function vim.tbl_extend(behavior, ...)
    626  return tbl_extend(behavior, false, ...)
    627 end
    628 
    629 --- Merges recursively two or more tables.
    630 ---
    631 --- Only values that are empty tables or tables that are not |lua-list|s (indexed by consecutive
    632 --- integers starting from 1) are merged recursively. This is useful for merging nested tables
    633 --- like default and user configurations where lists should be treated as literals (i.e., are
    634 --- overwritten instead of merged).
    635 ---
    636 ---@see |vim.tbl_extend()|
    637 ---
    638 ---@generic T1: table
    639 ---@generic T2: table
    640 ---@param behavior 'error'|'keep'|'force'|fun(key:any, prev_value:any?, value:any): any Decides what to do if a key is found in more than one map:
    641 ---      - "error": raise an error
    642 ---      - "keep":  use value from the leftmost map
    643 ---      - "force": use value from the rightmost map
    644 ---      - If a function, it receives the current key, the previous value in the currently merged table (if present), the current value and should
    645 ---        return the value for the given key in the merged table.
    646 ---@param ... T2 Two or more tables
    647 ---@return T1|T2 (table) Merged table
    648 function vim.tbl_deep_extend(behavior, ...)
    649  return tbl_extend(behavior, true, ...)
    650 end
    651 
    652 --- Deep compare values for equality
    653 ---
    654 --- Tables are compared recursively unless they both provide the `eq` metamethod.
    655 --- All other types are compared using the equality `==` operator.
    656 ---@param a any First value
    657 ---@param b any Second value
    658 ---@return boolean `true` if values are equals, else `false`
    659 function vim.deep_equal(a, b)
    660  if a == b then
    661    return true
    662  end
    663  if type(a) ~= type(b) then
    664    return false
    665  end
    666  if type(a) == 'table' then
    667    --- @cast a table<any,any>
    668    --- @cast b table<any,any>
    669    for k, v in pairs(a) do
    670      if not vim.deep_equal(v, b[k]) then
    671        return false
    672      end
    673    end
    674    for k in pairs(b) do
    675      if a[k] == nil then
    676        return false
    677      end
    678    end
    679    return true
    680  end
    681  return false
    682 end
    683 
    684 --- Add the reverse lookup values to an existing table.
    685 --- For example:
    686 --- `tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }`
    687 ---
    688 --- Note that this *modifies* the input.
    689 ---@deprecated
    690 ---@param o table Table to add the reverse to
    691 ---@return table o
    692 function vim.tbl_add_reverse_lookup(o)
    693  vim.deprecate('vim.tbl_add_reverse_lookup', nil, '0.12')
    694 
    695  --- @cast o table<any,any>
    696  --- @type any[]
    697  local keys = vim.tbl_keys(o)
    698  for _, k in ipairs(keys) do
    699    local v = o[k]
    700    if o[v] then
    701      error(
    702        string.format(
    703          'The reverse lookup found an existing value for %q while processing key %q',
    704          tostring(v),
    705          tostring(k)
    706        )
    707      )
    708    end
    709    o[v] = k
    710  end
    711  return o
    712 end
    713 
    714 --- Index into a table (first argument) via string keys passed as subsequent arguments.
    715 --- Return `nil` if the key does not exist.
    716 ---
    717 --- Examples:
    718 ---
    719 --- ```lua
    720 --- vim.tbl_get({ key = { nested_key = true }}, 'key', 'nested_key') == true
    721 --- vim.tbl_get({ key = {}}, 'key', 'nested_key') == nil
    722 --- ```
    723 ---@see |unpack()|
    724 ---
    725 ---@param o table Table to index
    726 ---@param ... any Optional keys (0 or more, variadic) via which to index the table
    727 ---@return any # Nested value indexed by key (if it exists), else nil
    728 function vim.tbl_get(o, ...)
    729  local nargs = select('#', ...)
    730  if nargs == 0 then
    731    return nil
    732  end
    733  for i = 1, nargs do
    734    o = o[select(i, ...)] --- @type any
    735    if o == nil then
    736      return nil
    737    elseif type(o) ~= 'table' and i ~= nargs then
    738      return nil
    739    end
    740  end
    741  return o
    742 end
    743 
    744 --- Extends a list-like table with the values of another list-like table.
    745 ---
    746 --- NOTE: This mutates dst!
    747 ---
    748 ---@see |vim.tbl_extend()|
    749 ---
    750 ---@generic T: table
    751 ---@param dst T List which will be modified and appended to
    752 ---@param src table List from which values will be inserted
    753 ---@param start integer? Start index on src. Defaults to 1
    754 ---@param finish integer? Final index on src. Defaults to `#src`
    755 ---@return T dst
    756 function vim.list_extend(dst, src, start, finish)
    757  vim.validate('dst', dst, 'table')
    758  vim.validate('src', src, 'table')
    759  vim.validate('start', start, 'number', true)
    760  vim.validate('finish', finish, 'number', true)
    761  for i = start or 1, finish or #src do
    762    table.insert(dst, src[i])
    763  end
    764  return dst
    765 end
    766 
    767 --- @deprecated
    768 --- Creates a copy of a list-like table such that any nested tables are
    769 --- "unrolled" and appended to the result.
    770 ---
    771 ---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
    772 ---
    773 ---@param t table List-like table
    774 ---@return table Flattened copy of the given list-like table
    775 function vim.tbl_flatten(t)
    776  vim.deprecate('vim.tbl_flatten', 'vim.iter(…):flatten():totable()', '0.13')
    777  local result = {}
    778  --- @param _t table<any,any>
    779  local function _tbl_flatten(_t)
    780    local n = #_t
    781    for i = 1, n do
    782      local v = _t[i]
    783      if type(v) == 'table' then
    784        _tbl_flatten(v)
    785      elseif v then
    786        table.insert(result, v)
    787      end
    788    end
    789  end
    790  _tbl_flatten(t)
    791  return result
    792 end
    793 
    794 --- Enumerates key-value pairs of a table, ordered by key.
    795 ---
    796 ---@see Based on https://github.com/premake/premake-core/blob/master/src/base/table.lua
    797 ---
    798 ---@generic T: table, K, V
    799 ---@param t T Dict-like table
    800 ---@return fun(table: table<K, V>, index?: K):K, V # |for-in| iterator over sorted keys and their values
    801 ---@return T
    802 function vim.spairs(t)
    803  vim.validate('t', t, 'table')
    804  --- @cast t table<any,any>
    805 
    806  -- collect the keys
    807  local keys = {} --- @type string[]
    808  for k in pairs(t) do
    809    table.insert(keys, k)
    810  end
    811  table.sort(keys)
    812 
    813  -- Return the iterator function.
    814  local i = 0
    815  return function()
    816    i = i + 1
    817    if keys[i] then
    818      return keys[i], t[keys[i]]
    819    end
    820  end,
    821    t
    822 end
    823 
    824 --- Tests if `t` is an "array": a table indexed _only_ by integers (potentially non-contiguous).
    825 ---
    826 --- If the indexes start from 1 and are contiguous then the array is also a list. |vim.islist()|
    827 ---
    828 --- Empty table `{}` is an array, unless it was created by |vim.empty_dict()| or returned as
    829 --- a dict-like |API| or Vimscript result, for example from |rpcrequest()| or |vim.fn|.
    830 ---
    831 ---@see https://github.com/openresty/luajit2#tableisarray
    832 ---
    833 ---@param t? any
    834 ---@return boolean `true` if array-like table, else `false`.
    835 function vim.isarray(t)
    836  if type(t) ~= 'table' then
    837    return false
    838  end
    839 
    840  --- @cast t table<any,any>
    841 
    842  local count = 0
    843 
    844  for k, _ in pairs(t) do
    845    -- Check if the number k is an integer
    846    if type(k) == 'number' and k == math.floor(k) then
    847      count = count + 1
    848    else
    849      return false
    850    end
    851  end
    852 
    853  if count > 0 then
    854    return true
    855  else
    856    -- TODO(bfredl): in the future, we will always be inside nvim
    857    -- then this check can be deleted.
    858    if vim._empty_dict_mt == nil then
    859      return false
    860    end
    861    return getmetatable(t) ~= vim._empty_dict_mt
    862  end
    863 end
    864 
    865 --- @deprecated
    866 function vim.tbl_islist(t)
    867  vim.deprecate('vim.tbl_islist', 'vim.islist', '0.12')
    868  return vim.islist(t)
    869 end
    870 
    871 --- Tests if `t` is a "list": a table indexed _only_ by contiguous integers starting from 1 (what
    872 --- |lua-length| calls a "regular array").
    873 ---
    874 --- Empty table `{}` is a list, unless it was created by |vim.empty_dict()| or returned as
    875 --- a dict-like |API| or Vimscript result, for example from |rpcrequest()| or |vim.fn|.
    876 ---
    877 ---@see |vim.isarray()|
    878 ---
    879 ---@param t? any
    880 ---@return boolean `true` if list-like table, else `false`.
    881 function vim.islist(t)
    882  if type(t) ~= 'table' then
    883    return false
    884  end
    885 
    886  if next(t) == nil then
    887    return getmetatable(t) ~= vim._empty_dict_mt
    888  end
    889 
    890  local j = 1
    891  for _ in
    892    pairs(t--[[@as table<any,any>]])
    893  do
    894    if t[j] == nil then
    895      return false
    896    end
    897    j = j + 1
    898  end
    899 
    900  return true
    901 end
    902 
    903 --- Counts the number of non-nil values in table `t`.
    904 ---
    905 --- ```lua
    906 --- vim.tbl_count({ a=1, b=2 })  --> 2
    907 --- vim.tbl_count({ 1, 2 })      --> 2
    908 --- ```
    909 ---
    910 ---@see https://github.com/Tieske/Penlight/blob/master/lua/pl/tablex.lua
    911 ---@param t table Table
    912 ---@return integer : Number of non-nil values in table
    913 function vim.tbl_count(t)
    914  vim.validate('t', t, 'table')
    915  --- @cast t table<any,any>
    916 
    917  local count = 0
    918  for _ in pairs(t) do
    919    count = count + 1
    920  end
    921  return count
    922 end
    923 
    924 --- Creates a copy of a table containing only elements from start to end (inclusive)
    925 ---
    926 ---@generic T
    927 ---@param list T[] Table
    928 ---@param start integer|nil Start range of slice
    929 ---@param finish integer|nil End range of slice
    930 ---@return T[] Copy of table sliced from start to finish (inclusive)
    931 function vim.list_slice(list, start, finish)
    932  local new_list = {} --- @type `T`[]
    933  for i = start or 1, finish or #list do
    934    new_list[#new_list + 1] = list[i]
    935  end
    936  return new_list
    937 end
    938 
    939 --- Efficiently insert items into the middle of a list.
    940 ---
    941 --- Calling table.insert() in a loop will re-index the tail of the table on
    942 --- every iteration, instead this function will re-index  the table exactly
    943 --- once.
    944 ---
    945 --- Based on https://stackoverflow.com/questions/12394841/safely-remove-items-from-an-array-table-while-iterating/53038524#53038524
    946 ---
    947 ---@param t any[]
    948 ---@param first integer
    949 ---@param last integer
    950 ---@param v any
    951 function vim._list_insert(t, first, last, v)
    952  local n = #t
    953 
    954  -- Shift table forward
    955  for i = n - first, 0, -1 do
    956    t[last + 1 + i] = t[first + i]
    957  end
    958 
    959  -- Fill in new values
    960  for i = first, last do
    961    t[i] = v
    962  end
    963 end
    964 
    965 --- Efficiently remove items from middle of a list.
    966 ---
    967 --- Calling table.remove() in a loop will re-index the tail of the table on
    968 --- every iteration, instead this function will re-index  the table exactly
    969 --- once.
    970 ---
    971 --- Based on https://stackoverflow.com/questions/12394841/safely-remove-items-from-an-array-table-while-iterating/53038524#53038524
    972 ---
    973 ---@param t any[]
    974 ---@param first integer
    975 ---@param last integer
    976 function vim._list_remove(t, first, last)
    977  local n = #t
    978  for i = 0, n - first do
    979    t[first + i] = t[last + 1 + i]
    980    t[last + 1 + i] = nil
    981  end
    982 end
    983 
    984 --- Trim whitespace (Lua pattern "%s") from both sides of a string.
    985 ---
    986 ---@see |lua-pattern|s
    987 ---@see https://www.lua.org/pil/20.2.html
    988 ---@param s string String to trim
    989 ---@return string String with whitespace removed from its beginning and end
    990 function vim.trim(s)
    991  vim.validate('s', s, 'string')
    992  -- `s:match('^%s*(.*%S)')` is slow for long whitespace strings,
    993  -- so we are forced to split it into two parts to prevent this
    994  return s:gsub('^%s+', ''):match('^.*%S') or ''
    995 end
    996 
    997 --- Escapes magic chars in |lua-pattern|s.
    998 ---
    999 ---@see https://github.com/rxi/lume
   1000 ---@param s string String to escape
   1001 ---@return string %-escaped pattern string
   1002 function vim.pesc(s)
   1003  vim.validate('s', s, 'string')
   1004  return (s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1'))
   1005 end
   1006 
   1007 --- Tests if `s` starts with `prefix`.
   1008 ---
   1009 ---@param s string String
   1010 ---@param prefix string Prefix to match
   1011 ---@return boolean `true` if `prefix` is a prefix of `s`
   1012 function vim.startswith(s, prefix)
   1013  vim.validate('s', s, 'string')
   1014  vim.validate('prefix', prefix, 'string')
   1015  return s:sub(1, #prefix) == prefix
   1016 end
   1017 
   1018 --- Tests if `s` ends with `suffix`.
   1019 ---
   1020 ---@param s string String
   1021 ---@param suffix string Suffix to match
   1022 ---@return boolean `true` if `suffix` is a suffix of `s`
   1023 function vim.endswith(s, suffix)
   1024  vim.validate('s', s, 'string')
   1025  vim.validate('suffix', suffix, 'string')
   1026  return #suffix == 0 or s:sub(-#suffix) == suffix
   1027 end
   1028 
   1029 do
   1030  --- @alias vim.validate.Validator
   1031  --- | type
   1032  --- | 'callable'
   1033  --- | (type|'callable')[]
   1034  --- | fun(v:any):boolean, string?
   1035 
   1036  local type_aliases = {
   1037    b = 'boolean',
   1038    c = 'callable',
   1039    f = 'function',
   1040    n = 'number',
   1041    s = 'string',
   1042    t = 'table',
   1043  }
   1044 
   1045  --- @nodoc
   1046  --- @class vim.validate.Spec
   1047  --- @field [1] any Argument value
   1048  --- @field [2] vim.validate.Validator Argument validator
   1049  --- @field [3]? boolean|string Optional flag or error message
   1050 
   1051  local function is_type(val, t)
   1052    return type(val) == t or (t == 'callable' and vim.is_callable(val))
   1053  end
   1054 
   1055  --- @param param_name string
   1056  --- @param val any
   1057  --- @param validator vim.validate.Validator
   1058  --- @param message? string "Expected" message
   1059  --- @param allow_alias? boolean Allow short type names: 'n', 's', 't', 'b', 'f', 'c'
   1060  --- @return string?
   1061  local function is_valid(param_name, val, validator, message, allow_alias)
   1062    if type(validator) == 'string' then
   1063      local expected = allow_alias and type_aliases[validator] or validator
   1064 
   1065      if not expected then
   1066        return string.format('invalid type name: %s', validator)
   1067      end
   1068 
   1069      if not is_type(val, expected) then
   1070        return ('%s: expected %s, got %s'):format(param_name, message or expected, type(val))
   1071      end
   1072    elseif vim.is_callable(validator) then
   1073      -- Check user-provided validation function
   1074      local valid, opt_msg = validator(val)
   1075      if not valid then
   1076        local err_msg = ('%s: expected %s, got %s'):format(
   1077          param_name,
   1078          message or '?',
   1079          tostring(val)
   1080        )
   1081        err_msg = opt_msg and ('%s. Info: %s'):format(err_msg, opt_msg) or err_msg
   1082 
   1083        return err_msg
   1084      end
   1085    elseif type(validator) == 'table' then
   1086      for _, t in ipairs(validator) do
   1087        local expected = allow_alias and type_aliases[t] or t
   1088        if not expected then
   1089          return string.format('invalid type name: %s', t)
   1090        end
   1091 
   1092        if is_type(val, expected) then
   1093          return -- success
   1094        end
   1095      end
   1096 
   1097      -- Normalize validator types for error message
   1098      if allow_alias then
   1099        for i, t in ipairs(validator) do
   1100          validator[i] = type_aliases[t] or t
   1101        end
   1102      end
   1103 
   1104      return string.format(
   1105        '%s: expected %s, got %s',
   1106        param_name,
   1107        table.concat(validator, '|'),
   1108        type(val)
   1109      )
   1110    else
   1111      return string.format('invalid validator: %s', tostring(validator))
   1112    end
   1113  end
   1114 
   1115  --- @param opt table<type|'callable',vim.validate.Spec>
   1116  --- @return string?
   1117  local function validate_spec(opt)
   1118    local report --- @type table<string,string>?
   1119 
   1120    for param_name, spec in pairs(opt) do
   1121      local err_msg --- @type string?
   1122      if type(spec) ~= 'table' then
   1123        err_msg = string.format('opt[%s]: expected table, got %s', param_name, type(spec))
   1124      else
   1125        local value, validator = spec[1], spec[2]
   1126        local msg = type(spec[3]) == 'string' and spec[3] or nil --[[@as string?]]
   1127        local optional = spec[3] == true
   1128        if not (optional and value == nil) then
   1129          err_msg = is_valid(param_name, value, validator, msg, true)
   1130        end
   1131      end
   1132 
   1133      if err_msg then
   1134        report = report or {}
   1135        report[param_name] = err_msg
   1136      end
   1137    end
   1138 
   1139    if report then
   1140      for _, msg in vim.spairs(report) do -- luacheck: ignore
   1141        return msg
   1142      end
   1143    end
   1144  end
   1145 
   1146  --- Validate function arguments.
   1147  ---
   1148  --- This function has two valid forms:
   1149  ---
   1150  --- 1. `vim.validate(name, value, validator[, optional][, message])`
   1151  ---
   1152  ---     Validates that argument {name} with value {value} satisfies
   1153  ---     {validator}. If {optional} is given and is `true`, then {value} may be
   1154  ---     `nil`. If {message} is given, then it is used as the expected type in the
   1155  ---     error message.
   1156  ---
   1157  ---     Example:
   1158  ---
   1159  ---     ```lua
   1160  ---       function vim.startswith(s, prefix)
   1161  ---         vim.validate('s', s, 'string')
   1162  ---         vim.validate('prefix', prefix, 'string')
   1163  ---         -- ...
   1164  ---       end
   1165  ---     ```
   1166  ---
   1167  --- 2. `vim.validate(spec)` (deprecated)
   1168  ---     where `spec` is of type
   1169  ---    `table<string,[value:any, validator: vim.validate.Validator, optional_or_msg? : boolean|string]>)`
   1170  ---
   1171  ---     Validates a argument specification.
   1172  ---     Specs are evaluated in alphanumeric order, until the first failure.
   1173  ---
   1174  ---     Example:
   1175  ---
   1176  ---     ```lua
   1177  ---       function user.new(name, age, hobbies)
   1178  ---         vim.validate{
   1179  ---           name={name, 'string'},
   1180  ---           age={age, 'number'},
   1181  ---           hobbies={hobbies, 'table'},
   1182  ---         }
   1183  ---         -- ...
   1184  ---       end
   1185  ---     ```
   1186  ---
   1187  --- Examples with explicit argument values (can be run directly):
   1188  ---
   1189  --- ```lua
   1190  --- vim.validate('arg1', {'foo'}, 'table')
   1191  ---    --> NOP (success)
   1192  --- vim.validate('arg2', 'foo', 'string')
   1193  ---    --> NOP (success)
   1194  ---
   1195  --- vim.validate('arg1', 1, 'table')
   1196  ---    --> error('arg1: expected table, got number')
   1197  ---
   1198  --- vim.validate('arg1', 3, function(a) return (a % 2) == 0 end, 'even number')
   1199  ---    --> error('arg1: expected even number, got 3')
   1200  --- ```
   1201  ---
   1202  --- If multiple types are valid they can be given as a list.
   1203  ---
   1204  --- ```lua
   1205  --- vim.validate('arg1', {'foo'}, {'table', 'string'})
   1206  --- vim.validate('arg2', 'foo', {'table', 'string'})
   1207  --- -- NOP (success)
   1208  ---
   1209  --- vim.validate('arg1', 1, {'string', 'table'})
   1210  --- -- error('arg1: expected string|table, got number')
   1211  --- ```
   1212  ---
   1213  --- @note `validator` set to a value returned by |lua-type()| provides the
   1214  --- best performance.
   1215  ---
   1216  --- @param name string Argument name
   1217  --- @param value any Argument value
   1218  --- @param validator vim.validate.Validator :
   1219  ---   - (`string|string[]`): Any value that can be returned from |lua-type()| in addition to
   1220  ---     `'callable'`: `'boolean'`, `'callable'`, `'function'`, `'nil'`, `'number'`, `'string'`, `'table'`,
   1221  ---     `'thread'`, `'userdata'`.
   1222  ---   - (`fun(val:any): boolean, string?`) A function that returns a boolean and an optional
   1223  ---     string message.
   1224  --- @param optional? boolean Argument is optional (may be omitted)
   1225  --- @param message? string message when validation fails
   1226  --- @overload fun(name: string, val: any, validator: vim.validate.Validator, message: string)
   1227  --- @overload fun(spec: table<string,[any, vim.validate.Validator, boolean|string]>)
   1228  function vim.validate(name, value, validator, optional, message)
   1229    local err_msg --- @type string?
   1230    if validator then -- Form 1
   1231      -- Check validator as a string first to optimize the common case.
   1232      local ok = (type(value) == validator) or (value == nil and optional == true)
   1233      if not ok then
   1234        local msg = type(optional) == 'string' and optional or message --[[@as string?]]
   1235        -- Check more complicated validators
   1236        err_msg = is_valid(name, value, validator, msg, false)
   1237      end
   1238    elseif type(name) == 'table' then -- Form 2
   1239      vim.deprecate('vim.validate{<table>}', 'vim.validate(<params>)', '1.0')
   1240      err_msg = validate_spec(name)
   1241    else
   1242      error('invalid arguments')
   1243    end
   1244 
   1245    if err_msg then
   1246      error(err_msg, 2)
   1247    end
   1248  end
   1249 end
   1250 
   1251 --- Returns true if object `f` can be called as a function.
   1252 ---
   1253 ---@param f? any Any object
   1254 ---@return boolean `true` if `f` is callable, else `false`
   1255 function vim.is_callable(f)
   1256  if type(f) == 'function' then
   1257    return true
   1258  end
   1259  local m = getmetatable(f)
   1260  if m == nil then
   1261    return false
   1262  end
   1263  return type(rawget(m, '__call')) == 'function'
   1264 end
   1265 
   1266 --- Creates a table whose missing keys are provided by {createfn} (like Python's "defaultdict").
   1267 ---
   1268 --- If {createfn} is `nil` it defaults to defaulttable() itself, so accessing nested keys creates
   1269 --- nested tables:
   1270 ---
   1271 --- ```lua
   1272 --- local a = vim.defaulttable()
   1273 --- a.b.c = 1
   1274 --- ```
   1275 ---
   1276 ---@param createfn? fun(key:any):any Provides the value for a missing `key`.
   1277 ---@return table # Empty table with `__index` metamethod.
   1278 function vim.defaulttable(createfn)
   1279  createfn = createfn or function(_)
   1280    return vim.defaulttable()
   1281  end
   1282  return setmetatable({}, {
   1283    __index = function(tbl, key)
   1284      rawset(tbl, key, createfn(key))
   1285      return rawget(tbl, key)
   1286    end,
   1287  })
   1288 end
   1289 
   1290 do
   1291  ---@class vim.Ringbuf<T>
   1292  ---@field private _items table[]
   1293  ---@field private _idx_read integer
   1294  ---@field private _idx_write integer
   1295  ---@field private _size integer
   1296  ---@overload fun(self): table?
   1297  local Ringbuf = {}
   1298 
   1299  --- Clear all items
   1300  function Ringbuf.clear(self)
   1301    self._items = {}
   1302    self._idx_read = 0
   1303    self._idx_write = 0
   1304  end
   1305 
   1306  --- Adds an item, overriding the oldest item if the buffer is full.
   1307  ---@generic T
   1308  ---@param item T
   1309  function Ringbuf.push(self, item)
   1310    self._items[self._idx_write] = item
   1311    self._idx_write = (self._idx_write + 1) % self._size
   1312    if self._idx_write == self._idx_read then
   1313      self._idx_read = (self._idx_read + 1) % self._size
   1314    end
   1315  end
   1316 
   1317  --- Removes and returns the first unread item
   1318  ---@generic T
   1319  ---@return T?
   1320  function Ringbuf.pop(self)
   1321    local idx_read = self._idx_read
   1322    if idx_read == self._idx_write then
   1323      return nil
   1324    end
   1325    local item = self._items[idx_read]
   1326    self._items[idx_read] = nil
   1327    self._idx_read = (idx_read + 1) % self._size
   1328    return item
   1329  end
   1330 
   1331  --- Returns the first unread item without removing it
   1332  ---@generic T
   1333  ---@return T?
   1334  function Ringbuf.peek(self)
   1335    if self._idx_read == self._idx_write then
   1336      return nil
   1337    end
   1338    return self._items[self._idx_read]
   1339  end
   1340 
   1341  --- Create a ring buffer limited to a maximal number of items.
   1342  --- Once the buffer is full, adding a new entry overrides the oldest entry.
   1343  ---
   1344  --- ```lua
   1345  --- local ringbuf = vim.ringbuf(4)
   1346  --- ringbuf:push("a")
   1347  --- ringbuf:push("b")
   1348  --- ringbuf:push("c")
   1349  --- ringbuf:push("d")
   1350  --- ringbuf:push("e")    -- overrides "a"
   1351  --- print(ringbuf:pop()) -- returns "b"
   1352  --- print(ringbuf:pop()) -- returns "c"
   1353  ---
   1354  --- -- Can be used as iterator. Pops remaining items:
   1355  --- for val in ringbuf do
   1356  ---   print(val)
   1357  --- end
   1358  --- ```
   1359  ---
   1360  --- Returns a Ringbuf instance with the following methods:
   1361  ---
   1362  --- - |Ringbuf:push()|
   1363  --- - |Ringbuf:pop()|
   1364  --- - |Ringbuf:peek()|
   1365  --- - |Ringbuf:clear()|
   1366  ---
   1367  ---@param size integer
   1368  ---@return vim.Ringbuf ringbuf
   1369  function vim.ringbuf(size)
   1370    local ringbuf = {
   1371      _items = {},
   1372      _size = size + 1,
   1373      _idx_read = 0,
   1374      _idx_write = 0,
   1375    }
   1376    return setmetatable(ringbuf, {
   1377      __index = Ringbuf,
   1378      __call = function(self)
   1379        return self:pop()
   1380      end,
   1381    })
   1382  end
   1383 end
   1384 
   1385 --- @generic T
   1386 --- @param root string
   1387 --- @param mod T
   1388 --- @return T
   1389 function vim._defer_require(root, mod)
   1390  return setmetatable({ _submodules = mod }, {
   1391    ---@param t table<string, any>
   1392    ---@param k string
   1393    __index = function(t, k)
   1394      if not mod[k] then
   1395        return
   1396      end
   1397      local name = string.format('%s.%s', root, k)
   1398      t[k] = require(name)
   1399      return t[k]
   1400    end,
   1401  })
   1402 end
   1403 
   1404 --- Creates a module alias/shim that lazy-loads a target module.
   1405 ---
   1406 --- Unlike `vim.defaulttable()` this also:
   1407 --- - implements __call
   1408 --- - calls vim.deprecate()
   1409 ---
   1410 --- @param old_name string Name of the deprecated module, which will be shimmed.
   1411 --- @param new_name string Name of the new module, which will be loaded by require().
   1412 function vim._defer_deprecated_module(old_name, new_name)
   1413  return setmetatable({}, {
   1414    ---@param _ table<string, any>
   1415    ---@param k string
   1416    __index = function(_, k)
   1417      vim.deprecate(old_name, new_name, '2.0.0', nil, false)
   1418      --- @diagnostic disable-next-line:no-unknown
   1419      local target = require(new_name)
   1420      return target[k]
   1421    end,
   1422    __call = function(self)
   1423      vim.deprecate(old_name, new_name, '2.0.0', nil, false)
   1424      --- @diagnostic disable-next-line:no-unknown
   1425      local target = require(new_name)
   1426      return target(self)
   1427    end,
   1428  })
   1429 end
   1430 
   1431 --- @nodoc
   1432 --- @class vim.context.mods
   1433 --- @field bo? table<string, any>
   1434 --- @field buf? integer
   1435 --- @field emsg_silent? boolean
   1436 --- @field env? table<string, any>
   1437 --- @field go? table<string, any>
   1438 --- @field hide? boolean
   1439 --- @field keepalt? boolean
   1440 --- @field keepjumps? boolean
   1441 --- @field keepmarks? boolean
   1442 --- @field keeppatterns? boolean
   1443 --- @field lockmarks? boolean
   1444 --- @field noautocmd? boolean
   1445 --- @field o? table<string, any>
   1446 --- @field sandbox? boolean
   1447 --- @field silent? boolean
   1448 --- @field unsilent? boolean
   1449 --- @field win? integer
   1450 --- @field wo? table<string, any>
   1451 
   1452 --- @nodoc
   1453 --- @class vim.context.state
   1454 --- @field bo? table<string, any>
   1455 --- @field env? table<string, any>
   1456 --- @field go? table<string, any>
   1457 --- @field wo? table<string, any>
   1458 
   1459 local scope_map = { buf = 'bo', global = 'go', win = 'wo' }
   1460 local scope_order = { 'o', 'wo', 'bo', 'go', 'env' }
   1461 local state_restore_order = { 'bo', 'wo', 'go', 'env' }
   1462 
   1463 --- Gets data about current state, enough to properly restore specified options/env/etc.
   1464 --- @param context vim.context.mods
   1465 --- @return vim.context.state
   1466 local get_context_state = function(context)
   1467  --- @type vim.context.state
   1468  local res = { bo = {}, env = {}, go = {}, wo = {} }
   1469 
   1470  -- Use specific order from possibly most to least intrusive
   1471  for _, scope in ipairs(scope_order) do
   1472    for name, _ in
   1473      pairs(context[scope] or {} --[[@as table<string,any>]])
   1474    do
   1475      local sc = scope == 'o' and scope_map[vim.api.nvim_get_option_info2(name, {}).scope] or scope
   1476 
   1477      -- Do not override already set state and fall back to `vim.NIL` for
   1478      -- state `nil` values (which still needs restoring later)
   1479      res[sc][name] = vim.F.if_nil(res[sc][name], vim[sc][name], vim.NIL)
   1480 
   1481      -- Always track global option value to properly restore later.
   1482      -- This matters for at least `o` and `wo` (which might set either/both
   1483      -- local and global option values).
   1484      if sc ~= 'env' and res.go[name] == nil then
   1485        res.go[name] = vim.go[name]
   1486      end
   1487    end
   1488  end
   1489 
   1490  return res
   1491 end
   1492 
   1493 --- Executes function `f` with the given context specification.
   1494 ---
   1495 --- Notes:
   1496 --- - Context `{ buf = buf }` has no guarantees about current window when
   1497 ---   inside context.
   1498 --- - Context `{ buf = buf, win = win }` is yet not allowed, but this seems
   1499 ---   to be an implementation detail.
   1500 --- - There should be no way to revert currently set `context.sandbox = true`
   1501 ---   (like with nested `vim._with()` calls). Otherwise it kind of breaks the
   1502 ---   whole purpose of sandbox execution.
   1503 --- - Saving and restoring option contexts (`bo`, `go`, `o`, `wo`) trigger
   1504 ---   `OptionSet` events. This is an implementation issue because not doing it
   1505 ---   seems to mean using either 'eventignore' option or extra nesting with
   1506 ---   `{ noautocmd = true }` (which itself is a wrapper for 'eventignore').
   1507 ---   As `{ go = { eventignore = '...' } }` is a valid context which should be
   1508 ---   properly set and restored, this is not a good approach.
   1509 ---   Not triggering `OptionSet` seems to be a good idea, though. So probably
   1510 ---   only moving context save and restore to lower level might resolve this.
   1511 ---
   1512 --- @param context vim.context.mods
   1513 --- @param f function
   1514 --- @return any
   1515 function vim._with(context, f)
   1516  vim.validate('context', context, 'table')
   1517  vim.validate('f', f, 'function')
   1518 
   1519  vim.validate('context.bo', context.bo, 'table', true)
   1520  vim.validate('context.buf', context.buf, 'number', true)
   1521  vim.validate('context.emsg_silent', context.emsg_silent, 'boolean', true)
   1522  vim.validate('context.env', context.env, 'table', true)
   1523  vim.validate('context.go', context.go, 'table', true)
   1524  vim.validate('context.hide', context.hide, 'boolean', true)
   1525  vim.validate('context.keepalt', context.keepalt, 'boolean', true)
   1526  vim.validate('context.keepjumps', context.keepjumps, 'boolean', true)
   1527  vim.validate('context.keepmarks', context.keepmarks, 'boolean', true)
   1528  vim.validate('context.keeppatterns', context.keeppatterns, 'boolean', true)
   1529  vim.validate('context.lockmarks', context.lockmarks, 'boolean', true)
   1530  vim.validate('context.noautocmd', context.noautocmd, 'boolean', true)
   1531  vim.validate('context.o', context.o, 'table', true)
   1532  vim.validate('context.sandbox', context.sandbox, 'boolean', true)
   1533  vim.validate('context.silent', context.silent, 'boolean', true)
   1534  vim.validate('context.unsilent', context.unsilent, 'boolean', true)
   1535  vim.validate('context.win', context.win, 'number', true)
   1536  vim.validate('context.wo', context.wo, 'table', true)
   1537 
   1538  -- Check buffer exists
   1539  if context.buf then
   1540    if not vim.api.nvim_buf_is_valid(context.buf) then
   1541      error('Invalid buffer id: ' .. context.buf)
   1542    end
   1543  end
   1544 
   1545  -- Check window exists
   1546  if context.win then
   1547    if not vim.api.nvim_win_is_valid(context.win) then
   1548      error('Invalid window id: ' .. context.win)
   1549    end
   1550    -- TODO: Maybe allow it?
   1551    if context.buf and vim.api.nvim_win_get_buf(context.win) ~= context.buf then
   1552      error('Can not set both `buf` and `win` context.')
   1553    end
   1554  end
   1555 
   1556  -- Decorate so that save-set-restore options is done in correct window-buffer
   1557  local callback = function()
   1558    -- Cache current values to be changed by context
   1559    -- Abort early in case of bad context value
   1560    local ok, state = pcall(get_context_state, context)
   1561    if not ok then
   1562      error(state, 0)
   1563    end
   1564 
   1565    -- Apply some parts of the context in specific order
   1566    -- NOTE: triggers `OptionSet` event
   1567    for _, scope in ipairs(scope_order) do
   1568      for name, context_value in
   1569        pairs(context[scope] or {} --[[@as table<string,any>]])
   1570      do
   1571        --- @diagnostic disable-next-line:no-unknown
   1572        vim[scope][name] = context_value
   1573      end
   1574    end
   1575 
   1576    -- Execute
   1577    local res = { pcall(f) }
   1578 
   1579    -- Restore relevant cached values in specific order, global scope last
   1580    -- NOTE: triggers `OptionSet` event
   1581    for _, scope in ipairs(state_restore_order) do
   1582      for name, cached_value in
   1583        pairs(state[scope] --[[@as table<string,any>]])
   1584      do
   1585        --- @diagnostic disable-next-line:no-unknown
   1586        vim[scope][name] = cached_value
   1587      end
   1588    end
   1589 
   1590    -- Return
   1591    if not res[1] then
   1592      error(res[2], 0)
   1593    end
   1594    table.remove(res, 1)
   1595    return unpack(res, 1, table.maxn(res))
   1596  end
   1597 
   1598  return vim._with_c(context, callback)
   1599 end
   1600 
   1601 --- @param bufnr? integer
   1602 --- @return integer
   1603 function vim._resolve_bufnr(bufnr)
   1604  if bufnr == nil or bufnr == 0 then
   1605    return vim.api.nvim_get_current_buf()
   1606  end
   1607  vim.validate('bufnr', bufnr, 'number')
   1608  return bufnr
   1609 end
   1610 
   1611 --- @generic T
   1612 --- @param x T|T[]
   1613 --- @return T[]
   1614 function vim._ensure_list(x)
   1615  if type(x) == 'table' then
   1616    return x
   1617  end
   1618  return { x }
   1619 end
   1620 
   1621 -- Use max 32-bit signed int value to avoid overflow on 32-bit systems. #31633
   1622 vim._maxint = 2 ^ 32 - 1
   1623 
   1624 return vim