shared.lua 41 KB

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