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